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.

168 lines
4.8 KiB

  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. import os
  4. import os.path
  5. import sqlite3
  6. import subprocess
  7. from paths import *
  8. from request import UserSSHRequest, HostSSHRequest, HostSSLRequest
  9. __doc__= """
  10. Module of classes to handle certificate requests
  11. """
  12. class Authority(object):
  13. ca_type = None
  14. request_allowed = []
  15. def __init__(self, ca_id, name, ca_dir):
  16. self.ca_id = ca_id
  17. self.name = name
  18. self.ca_dir = ca_dir
  19. @property
  20. def path(self):
  21. return os.path.join(self.ca_dir, self.ca_id)
  22. def generate(self):
  23. raise NotImplementedError()
  24. def sign(self, request):
  25. raise NotImplementedError()
  26. def __repr__(self):
  27. return ( "%s %s" % ( self.__class__.__name__, self.ca_type ) )
  28. class SSHAuthority(Authority):
  29. ca_type = 'ssh'
  30. request_allowed = [ UserSSHRequest, HostSSHRequest, ]
  31. key_algorithm = 'ed25519'
  32. user_validity = '+52w'
  33. host_validity = '+52w'
  34. def generate(self):
  35. if os.path.exists(self.path):
  36. raise ValueError("A CA with the same id and type already exists")
  37. subprocess.check_output(['ssh-keygen',
  38. '-f', self.path,
  39. '-t', self.key_algorithm,
  40. '-C', self.name])
  41. with open(self.path + '.serial', 'w') as stream:
  42. stream.write(str(0))
  43. def sign(self, request):
  44. assert type(request) in self.request_allowed
  45. pub_key_path = os.path.join(OUTPUT_PATH, request.req_id + '.pub')
  46. cert_path = os.path.join(OUTPUT_PATH, request.req_id + '-cert.pub')
  47. with open(self.path + '.serial', 'r') as stream:
  48. next_serial = int(stream.read())
  49. with open(self.path + '.serial', 'w') as stream:
  50. stream.write(str(next_serial + 1))
  51. with open(pub_key_path, 'w') as stream:
  52. stream.write(request.key_data)
  53. ca_private_key = self.path
  54. if type(request) == UserSSHRequest:
  55. login_names = [ request.user_name, ]
  56. if request.root_requested:
  57. login_names.append('root')
  58. subprocess.check_output(['ssh-keygen',
  59. '-s', ca_private_key,
  60. '-I', 'user_%s' % request.user_name,
  61. '-n', ','.join(login_names),
  62. '-V', self.user_validity,
  63. '-z', str(next_serial),
  64. pub_key_path])
  65. elif type(request) == HostSSHRequest:
  66. subprocess.check_output(['ssh-keygen',
  67. '-s', ca_private_key,
  68. '-I', 'host_%s' % request.host_name.replace('.', '_'),
  69. '-h',
  70. '-n', request.host_name,
  71. '-V', self.host_validity,
  72. '-z', str(next_serial),
  73. pub_key_path])
  74. return cert_path
  75. class SSLAuthority(Authority):
  76. ca_type = 'ssl'
  77. request_allowed = [ HostSSLRequest, ]
  78. ca_key_algorithm = 'des3'
  79. key_length = '4096'
  80. key_algorithm = 'sha256'
  81. ca_validity = '365'
  82. cert_validity = '365'
  83. def generate(self):
  84. if os.path.exists(self.path):
  85. raise ValueError("A CA with the same id and type already exists")
  86. subprocess.check_output(['openssl',
  87. 'genrsa',
  88. '-%s'%self.ca_key_algorithm,
  89. '-out', '%s'%(self.path),
  90. self.key_length])
  91. subprocess.check_output(['openssl',
  92. 'req',
  93. '-new',
  94. '-x509',
  95. '-days', self.ca_validity,
  96. '-key', self.path,
  97. # '-extensions', 'v3_ca'
  98. '-out', "%s.pub"%self.path,
  99. # '-config', "%s.conf"%self.path
  100. ])
  101. with open(self.path + '.serial', 'w') as stream:
  102. stream.write(str(0))
  103. def sign(self, request):
  104. OUTPUT_PATH
  105. assert type(request) in [HostSSLRequest]
  106. pub_key_path = os.path.join(OUTPUT_PATH, request.req_id + '.pub')
  107. cert_path = os.path.join(OUTPUT_PATH, request.req_id + '-cert.pub')
  108. with open(self.path + '.serial', 'r') as stream:
  109. next_serial = int(stream.read())
  110. with open(self.path + '.serial', 'w') as stream:
  111. stream.write(str(next_serial + 1))
  112. with open(pub_key_path, 'w') as stream:
  113. stream.write(request.key_data)
  114. ca_private_key = self.path
  115. # openssl x509 -req -days 360 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt # print()
  116. subprocess.check_output(['openssl',
  117. 'x509',
  118. '-req',
  119. '-days', self.ca_validity,
  120. '-in', pub_key_path,
  121. '-CA', "%s.pub"%self.path,
  122. '-CAkey', self.path,
  123. '-CAcreateserial',
  124. '-out', cert_path,
  125. '-%s'%self.key_algorithm])
  126. return cert_path