4 Certificate generation module.
7 from OpenSSL import crypto
8 from os import chmod, remove
9 from os.path import join
11 from myap.tools import execute_cmd
12 from myap.config import config
14 TYPE_RSA = crypto.TYPE_RSA
15 TYPE_DSA = crypto.TYPE_DSA
19 X509Attr = ( 'C', 'ST', 'L', 'O', 'OU', 'CN', 'emailAddress' )
20 X509WinAttr = { 'C' : 'C',
26 'emailAddress' : 'E' }
28 def createKeyPair(type, bits):
30 Create a public/private key pair.
32 Arguments: type - Key type, must be one of TYPE_RSA and TYPE_DSA
33 bits - Number of bits to use in the key
35 Returns: The public/private key pair in a PKey object
39 pkey.generate_key(type, bits)
43 def createCertRequest(pkey, subject, digest='md5'):
45 Create a certificate request.
47 Arguments: pkey - The key to associate with the request
48 subject - A dictionary with the subject of the request, possible
51 ST - State or province name
54 OU - Organizational unit name
56 emailAddress - E-mail address
57 digest - Digestion method to use for signing, default is md5
59 Returns: The certificate request in an X509Req object
62 req = crypto.X509Req()
63 subj = req.get_subject()
65 # Storing attributes in the correct order
67 if subject.has_key(attr):
68 setattr(subj, attr, subject[attr])
71 req.sign(pkey, digest)
75 def createCertificate(req, (issuerKey, issuerCert), serial, (notBefore, notAfter), extensions=[], digest='md5'):
77 Generate a certificate given a certificate request.
79 Arguments: req - Certificate reqeust to use
80 issuerCert - The certificate of the issuer
81 issuerKey - The private key of the issuer
82 serial - Serial number for the certificate
83 notBefore - Timestamp (relative to now) when the certificate
85 notAfter - Timestamp (relative to now) when the certificate
87 digest - Digest method to use for signing, default is md5
88 isca - The certificate is a CA
90 Returns: The signed certificate in an X509 object
98 for name, critical, value in extensions:
99 X509Extensions.append(crypto.X509Extension(name, critical, value))
101 cert.add_extensions(X509Extensions)
103 cert.set_serial_number(serial)
104 cert.gmtime_adj_notBefore(notBefore)
105 cert.gmtime_adj_notAfter(notAfter)
106 cert.set_issuer(issuerCert.get_subject())
107 cert.set_subject(req.get_subject())
108 cert.set_pubkey(req.get_pubkey())
109 cert.sign(issuerKey, digest)
113 def createSignedCertificate(subject, serial, extensions=[], type=TYPE_RSA, bits=2048, cipher='DES-EDE3-CBC', passphrase='', years=5, capkey='', cacert='', capassphrase=''):
115 Generate a Signed Certificate.
117 Arguments: subject - The subject of the request, see createCertRequest()
118 type - (optional) Key type, see createKeyPair()
119 bits - (optional) Number of bits to use in the key
120 cipher - (optional) if encrypted PEM format, the cipher to use, see dump_privatekey()
121 passphrase - (optional) if encrypted PEM format, the passphrase to use, see dump_privatekey()
122 years - (optional) Number of years to use for validity, see X509()
123 capkey - (optional) CA's private key (PEM formated string)
124 cacert - (optional) CA's certificate (PEM formated string)
125 capassphrase - (optional) if CA private key is in encrypted PEM format,
126 the passphrase to use, see load_privatekey()
128 Returns: Two PEM formated strings containing private key and signed certificate
131 pkey = createKeyPair(type, bits)
132 req = createCertRequest(pkey, subject)
134 if capkey and cacert:
135 # Certificate will be signed by an Autority
136 capkey = crypto.load_privatekey(crypto.FILETYPE_PEM, capkey, capassphrase)
137 cacert = crypto.load_certificate(crypto.FILETYPE_PEM, cacert)
139 # Self signed certificate
143 cert = createCertificate(req, (capkey, cacert), serial, (0, years*YEAR), extensions=extensions)
146 pkey = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey, cipher, passphrase)
148 pkey = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)
150 cert = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
154 def getSubject(cert, for_win=False):
156 cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
157 subj = cert.get_subject()
160 for attr in X509Attr:
161 value = getattr(subj, attr)
164 # Converting Attr to Windows Attr
165 attr = X509WinAttr[attr]
166 subject += '%s=%s, ' % (attr, value)
168 subject = subject[:-2]
172 def convertPemToDer(pkey, cert, cipher='DES-EDE3-CBC', passphrase=''):
174 Convert two PEM formated strings (pkey, cert) onto two DER formated strings.
176 Arguments: pkey - private key (PEM formated string)
177 cert - certificate (PEM formated string)
178 cipher - (optional) if encrypted PEM format, the cipher to use, see dump_privatekey()
179 passphrase - (optional) if encrypted PEM format, the passphrase to use, see dump_privatekey()
181 Returns: Two DER formated strings containing private key and signed certificate
184 pkey = crypto.load_privatekey(crypto.FILETYPE_PEM, pkey, passphrase)
185 cert = crypto.load_certificate(crypto.FILETYPE_PEM, cert)
188 pkey = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pkey, cipher, passphrase)
190 pkey = crypto.dump_privatekey(crypto.FILETYPE_ASN1, pkey)
192 cert = crypto.dump_certificate(crypto.FILETYPE_ASN1, cert)
196 def convertDerToPem(pkey, cert, cipher='DES-EDE3-CBC', passphrase=''):
198 Convert two DER formated strings (pkey, cert) onto two PEM formated strings.
200 Arguments: pkey - private key (DER formated string)
201 cert - certificate (DER formated string)
202 cipher - (optional) if encrypted DER format, the cipher to use, see dump_privatekey()
203 passphrase - (optional) if encrypted DER format, the passphrase to use, see dump_privatekey()
205 Returns: Two PEM formated strings containing private key and signed certificate
208 pkey = crypto.load_privatekey(crypto.FILETYPE_ASN1, pkey, passphrase)
209 cert = crypto.load_certificate(crypto.FILETYPE_ASN1, cert)
212 pkey = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey, cipher, passphrase)
214 pkey = crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)
216 cert = crypto.dump_certificate(crypto.FILETYPE_PEM, cert)
220 def dump_pkcs12(pkey, cert, cacert='', passphrase=''):
225 # Storing all the params to a temp file
226 temp_file = '/tmp/pkcs12'
228 pkcs12 = pkey + cert + cacert
230 f = open(temp_file, 'w')
233 chmod(temp_file, 0600)
235 # Create pkcs12 file with openssl
236 cmd = 'openssl pkcs12 -export -in %s -passout pass:"%s"' % (temp_file, passphrase)
238 exitcode, pkcs12 = execute_cmd(cmd)
246 def newCertificate(db, ip):
248 serial = db.get_last_serial_cert()
249 ca = db.get_certificate(serial=0)
251 # Creating the certificate for the ip
253 subject = config['SSL_DEFAULT']
255 extensions = (('nsCertType', False, 'client'),
256 ('keyUsage', False, 'dataEncipherment'),
257 ('extendedKeyUsage', False, 'clientAuth,1.3.6.1.4.1.311.10.3.4.1'))
258 pkey, cert = createSignedCertificate(subject, serial, extensions=extensions, bits=1024, capkey=ca['private_key'], cacert=ca['certificate'], capassphrase=config['SSL_CA_PASS'])
260 # Adding it to the database
262 db_cert['serial'] = serial
263 db_cert['private_key'] = pkey
264 db_cert['certificate'] = cert
266 return db.set_certificate(db_cert)
268 def getPKCS12(db, reservation_id):
270 ca = db.get_certificate(serial=0)
271 reservation = db.get_reservation(reservation_id=reservation_id)
272 certificate = db.get_certificate(certificate_id=reservation['certificate_id'])
274 pkcs12 = dump_pkcs12(certificate['private_key'], certificate['certificate'], ca['certificate'])
278 def revokeCertificate(db, certificate_id):
284 db.delete_certificates()
288 subject = config['SSL_DEFAULT']
289 extensions = (('basicConstraints', True, 'CA:true'),
290 ('nsCertType', False, 'objCA,sslCA,objsign,client,server'),
291 ('keyUsage', False, 'keyCertSign,cRLSign,nonRepudiation,keyEncipherment,dataEncipherment'),
292 ('extendedKeyUsage', False, 'clientAuth,serverAuth,1.3.6.1.4.1.311.10.3.4.1')) # 1.3.6.1.4.1.311.10.3.4.1 is for VPN
294 capkey, cacert = createSignedCertificate(subject, serial, extensions=extensions, passphrase=config['SSL_CA_PASS'])
296 # Adding it to the database
298 db_cert['serial'] = serial
299 db_cert['private_key'] = capkey
300 db_cert['certificate'] = cacert
301 if not db.set_certificate(db_cert):
304 # Creating the certificate for the WebServer
306 subject['CN'] = config['SERVER_NAME']
307 extensions = (('nsCertType', False, 'server'),
308 ('keyUsage', False, 'keyEncipherment'),
309 ('extendedKeyUsage', False, 'serverAuth'))
311 pkey, cert = createSignedCertificate(subject, serial, extensions=extensions, bits=1024, capkey=capkey, cacert=cacert, capassphrase=config['SSL_CA_PASS'])
313 # Adding it to the database
315 db_cert['serial'] = serial
316 db_cert['private_key'] = pkey
317 db_cert['certificate'] = cert
318 if not db.set_certificate(db_cert):
322 f = open(config['MYAP_HTTPD_PKEY'], 'w')
325 chmod(config['MYAP_HTTPD_PKEY'], 0600)
327 f = open(config['MYAP_HTTPD_CERT'], 'w')
334 # Creating the certificate for Racoon
336 subject['CN'] = 'Racoon Server'
337 extensions = (('nsCertType', False, 'client,server'),
338 ('keyUsage', False, 'keyEncipherment'),
339 ('extendedKeyUsage', False, 'clientAuth,serverAuth,1.3.6.1.4.1.311.10.3.4.1'))
341 pkey, cert = createSignedCertificate(subject, serial, extensions=extensions, bits=1024, capkey=capkey, cacert=cacert, capassphrase=config['SSL_CA_PASS'])
343 # Adding it to the database
345 db_cert['serial'] = serial
346 db_cert['private_key'] = pkey
347 db_cert['certificate'] = cert
348 if not db.set_certificate(db_cert):
352 pkey_file = join(config['SSL_TOP_DIR'], config['RACOON_PKEY'])
353 cert_file = join(config['SSL_TOP_DIR'], config['RACOON_CERT'])
355 f = open(pkey_file, 'w')
358 chmod(pkey_file, 0600)
360 f = open(cert_file, 'w')