diff --git a/gestion/cert_utils.py b/gestion/cert_utils.py new file mode 100644 index 00000000..32b64913 --- /dev/null +++ b/gestion/cert_utils.py @@ -0,0 +1,201 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +from OpenSSL import crypto, SSL +from socket import gethostname +from pprint import pprint +import time +from os.path import exists, join + +def crt_import(str): + return crypto.load_certificate(crypto.FILETYPE_PEM, open(str).read()) + +def key_import(str): + return crypto.load_privatekey(crypto.FILETYPE_PEM, open(str).read()) + +def crt_write(crt, file): + open(file, "wt").write( + crypto.dump_certificate(crypto.FILETYPE_PEM, crt)) + +def key_write(key, file, cipher=None, passphrase=None): + open(file, "wt").write( + crypto.dump_privatekey(crypto.FILETYPE_PEM, key, cipher, passphrase) if cipher else crypto.dump_privatekey(crypto.FILETYPE_PEM, key)) + +def write((cert, key), cert_dir="."): + common_name = cert.get_subject().CN + CERT_FILE = "%s.crt" % common_name + KEY_FILE = "%s.key" % common_name + C_F = join(cert_dir, CERT_FILE) + K_F = join(cert_dir, KEY_FILE) + if not exists(C_F) or not exists(K_F): + crt_write(cert,C_F) + key_write(key,K_F) + else: + print "Les fichiers %s et %s existent déjà" % (C_F, K_F) + +def crl_gen(crl=None, add_crt=[]): + if not crl: + crl=crypto.CRL() + for crt in add_crt: + revoked = crypto.Revoked() + revoked.set_serial(hex(crt.get_serial_number())) + crl.add_revoked(revoked) + return crl + +def crl_export(crl, (ca_cert, ca_key)): + return crl.export(ca_cert, ca_key) + +def crt_create( + common_name, + params={}, + not_after=365*24*3600, + size=4096, + key=None, + parent=None, + extentions=[] + ): + """ +@param parent: tuple (X509 certificate, private key) +@return: (X509 certificate, private key) +""" + params["CN"] = common_name # common name + params.setdefault("C", "FR") # country + params.setdefault("ST", "Val de Marne") # state + params.setdefault("L", "Cachan") # city + params.setdefault("O", "Association CRANS") # organization + params.setdefault("OU", "") # organization unit + + if not key: + # create a key pair + k = crypto.PKey() + k.generate_key(crypto.TYPE_RSA, size) + else: + k = key + if k.bits() != size: + raise ValueError("Key of %s bits but requesting %s bits" % (k.bits, size)) + + # create a certificate + cert = crypto.X509() + cert.get_subject().C = params["C"] + cert.get_subject().ST = params["ST"] + cert.get_subject().L = params["L"] + cert.get_subject().O = params["O"] + if params["OU"]: + cert.get_subject().OU = params["OU"] + cert.get_subject().CN = params["CN"] + + cert.set_serial_number(int((time.time() - 1386340000)*100)) + cert.gmtime_adj_notBefore(0) + cert.gmtime_adj_notAfter(not_after) + cert.set_pubkey(k) + cert.add_extensions(extentions) + if parent: + cert.set_issuer(parent[0].get_subject()) + cert.sign(parent[1], 'sha1') + else: + cert.set_issuer(cert.get_subject()) + cert.sign(k, 'sha1') + + return (cert, k) + + +def crt_ca_root_create( + common_name, + params={}, + size=4096, + key=None, + not_after=365*24*3600*10, + ): + extentions=[ + crypto.X509Extension("basicConstraints", True, "CA:TRUE"), + crypto.X509Extension("keyUsage", True, "keyCertSign, cRLSign"), + ] + return crt_create( + common_name, + params, + not_after, + size, + key, + extentions=extentions + ) + + +def crt_ca_subroot_create( + common_name, + parent, + params={}, + size=4096, + key=None, + not_after=365*24*3600*10, + ): + extentions=[ + crypto.X509Extension("basicConstraints", True, "CA:TRUE, pathlen:0"), + crypto.X509Extension("keyUsage", True, "keyCertSign, cRLSign"), + ] + return crt_create( + common_name, + params, + not_after, + size, + key, + parent=parent, + extentions=extentions + ) + +def crt_client_create( + common_name, + parent, + params={}, + size=4096, + key=None, + not_after=365*24*3600, + alt_names=[] + ): + extentions=[ + crypto.X509Extension("basicConstraints", True, "CA:FALSE"), + crypto.X509Extension("keyUsage", True, "digitalSignature, nonRepudiation, keyEncipherment"), + crypto.X509Extension("nsCertType", True, "sslCA"), + crypto.X509Extension("extendedKeyUsage", True, "clientAuth"), +# crypto.X509Extension("crlDistributionPoints", False, "URI:http://myhost.com/myca.crl"), + ] + for name in alt_names: + extentions.append(crypto.X509Extension("subjectAltName", True, "%s" % name)) + return crt_create( + common_name, + params, + not_after, + size, + key, + parent=parent, + extentions=extentions + ) + + +def createCertRequest(pkey, digest="sha1", subjectAltName=[], **name): + """ + Create a certificate request. + Arguments: pkey - The key to associate with the request + digest - Digestion method to use for signing, default is md5 + **name - The name of the subject of the request, possible + arguments are: + C - Country name + ST - State or province name + L - Locality name + O - Organization name + OU - Organizational unit name + CN - Common name + emailAddress - E-mail address + Returns: The certificate request in an X509Req object + """ + req = crypto.X509Req() + subj = req.get_subject() + for (key,value) in name.items(): + setattr(subj, key, value) + if subjectAltName: + exts = [] + for altName in subjectAltName: + exts.append(crypto.X509Extension("subjectAltName", True, "DNS:%s" % altName)) + req.add_extensions(exts) + req.set_pubkey(pkey) + req.sign(pkey, digest) + return req +