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.

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