Easy CA management
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

228 lines
6.2 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import cmd
  4. import hashlib
  5. import json
  6. import os
  7. import os.path
  8. import shutil
  9. import sqlite3
  10. import subprocess
  11. import tempfile
  12. from certificate_requests import *
  13. from paths import *
  14. class CAManager(object):
  15. """
  16. Middleware to interact with ssh-keygen
  17. """
  18. def __init__(self, path):
  19. self.path = path
  20. def __enter__(self):
  21. """
  22. Enter a context block, connect to database
  23. """
  24. self.conn = sqlite3.connect(self._get_db_path())
  25. return self
  26. def __exit__(self, exc_type, exc_value, traceback):
  27. """
  28. Exit a context block, disconnect from database
  29. """
  30. if exc_type is not None:
  31. print(exc_type, exc_value)
  32. print(traceback)
  33. self.conn.close()
  34. def _get_db_path(self):
  35. return os.path.join(self.path, 'ca_manager.db')
  36. def _get_ssh_cas_dir(self):
  37. return os.path.join(self.path, 'ssh_cas')
  38. def _get_ssh_ca_path(self, ca_id):
  39. cas_dir = self._get_ssh_cas_dir()
  40. return os.path.join(cas_dir, ca_id)
  41. def _get_ssl_cas_dir(self):
  42. return os.path.join(self.path, 'ssl_cas')
  43. def _get_ssl_ca_path(self, ca_id):
  44. cas_dir = self._get_ssl_cas_dir()
  45. return os.path.join(cas_dir, ca_id)
  46. def create_ssh_ca(self, ca_id, ca_name):
  47. """
  48. Create a new ssh certification authority, insert
  49. it into the database
  50. """
  51. ca_path = self._get_ssh_ca_path(ca_id)
  52. authority = SSHAuthority(ca_id, ca_name, ca_path)
  53. authority.generate()
  54. c = self.conn.cursor()
  55. c.execute("""INSERT INTO cas VALUES (?, ?, 'ssh')""",
  56. (ca_id, ca_name))
  57. self.conn.commit()
  58. def create_ssl_ca(self, ca_id, ca_name):
  59. """
  60. Create a new ssl certification authority, insert
  61. it into the database
  62. """
  63. ca_path = self._get_ssl_ca_path(ca_id)
  64. authority = SSLAuthority(ca_id, ca_name, ca_path)
  65. authority.generate()
  66. c = self.conn.cursor()
  67. c.execute("""INSERT INTO cas VALUES (?, ?, 'ssl')""",
  68. (ca_id, ca_name))
  69. self.conn.commit()
  70. def get_cas_list(self):
  71. """
  72. Get all the certification authorities saved in
  73. the database
  74. """
  75. c = self.conn.cursor()
  76. c.execute("""SELECT id, name, type FROM cas""")
  77. return c.fetchall()
  78. def get_ca(self, ca_id):
  79. """
  80. Get a specific certification authority from the database
  81. """
  82. c = self.conn.cursor()
  83. c.execute("""SELECT name, type FROM cas WHERE id = ?""", (ca_id, ))
  84. ca_name, ca_type = c.fetchone()
  85. if ca_type == 'ssh':
  86. ca_path = self._get_ssh_ca_path(ca_id)
  87. return SSHAuthority(ca_id, ca_name, ca_path)
  88. elif ca_type == 'ssl':
  89. ca_path = self._get_ssl_ca_path(ca_id)
  90. return SSLAuthority(ca_id, ca_name, ca_path)
  91. def get_requests(self):
  92. req_objs = []
  93. for request_name in os.listdir(REQUESTS_PATH):
  94. request_path = os.path.join(REQUESTS_PATH, request_name)
  95. with open(request_path, 'r') as stream:
  96. req = json.load(stream)
  97. if req['keyType'] == 'ssh_user':
  98. user_name = req['userName']
  99. root_requested = req['rootRequested']
  100. key_data = req['keyData']
  101. req_objs.append(
  102. UserSSHRequest(
  103. request_name, user_name, root_requested, key_data))
  104. elif req['keyType'] == 'ssh_host':
  105. host_name = req['hostName']
  106. key_data = req['keyData']
  107. req_objs.append(
  108. HostSSHRequest(
  109. request_name, host_name, key_data))
  110. elif req['keyType'] == 'ssl_host':
  111. host_name = req['hostName']
  112. key_data = req['keyData']
  113. req_objs.append(
  114. HostSSLRequest(
  115. request_name, host_name, key_data))
  116. return req_objs
  117. def drop_request(self, request):
  118. os.unlink(os.path.join(REQUESTS_PATH, request.req_id))
  119. def init_manager(paths):
  120. """
  121. Initiate the manager by creating the
  122. directories to store CAs and requests.
  123. Create a database to store the information
  124. """
  125. db_path = os.path.join(paths[0], 'ca_manager.db')
  126. directories = ['ssh_cas', 'ssl_cas']
  127. # ensure the directories needed by CAManager
  128. # exists
  129. for dirpath in paths:
  130. if not os.path.exists(dirpath):
  131. os.makedirs(dirpath)
  132. # ensure ssh_cas ad ssl_cas directories
  133. # exists in MANAGER_PATH
  134. for dirname in directories:
  135. dirpath = os.path.join(paths[0], dirname)
  136. if not os.path.exists(dirpath):
  137. os.mkdir(dirpath)
  138. # ensure the database exists
  139. # in MANAGER_PATH
  140. if not os.path.exists(db_path):
  141. conn = sqlite3.connect(db_path)
  142. c = conn.cursor()
  143. c.execute("""CREATE TABLE cas (id text, name text, type text)""")
  144. conn.commit()
  145. conn.close()
  146. def list_cas(ca_manager):
  147. for ca_id, ca_name, ca_type in ca_manager.get_cas_list():
  148. print("- [%3s] %-15s (%s)" % (ca_type, ca_id, ca_name))
  149. def sign_request(ca_manager, choosen_request, choosen_ca):
  150. authorities = ca_manager.get_cas_list()
  151. try:
  152. ca_selection = int(choosen_ca)
  153. (authority_id, authority_name, authority_type) = authorities[ca_selection]
  154. authority = ca_manager.get_ca(authority_name)
  155. except IndexError:
  156. print("Could not find CA '%d'" % choosen_ca)
  157. return
  158. requests = ca_manager.get_requests()
  159. try:
  160. req_selection = int(choosen_request)
  161. request = requests[req_selection]
  162. except IndexError:
  163. return
  164. h = hashlib.sha256()
  165. h.update(request.key_data.encode('utf-8'))
  166. print("Request hash: %s" % h.hexdigest())
  167. print("You are about to sign this request with the following CA:")
  168. print("- %s (%s)" % (authority.ca_id, authority.name))
  169. cert_path = authority.sign(request)
  170. ca_manager.drop_request(request)
  171. shutil.copy(cert_path, os.path.join(RESULTS_PATH, request.req_id))