#!/usr/bin/env python # # Copyright (C) 2016 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the 'License'); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an 'AS IS' BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. import random from OpenSSL import crypto from Crypto.PublicKey import RSA class Certificate(object): cert = None key = None def __init__(self, cert, key): self.cert = cert self.key = key def cert_pem(self): return crypto.dump_certificate(crypto.FILETYPE_PEM, self.cert) def key_pem(self): return crypto.dump_privatekey(crypto.FILETYPE_PEM, self.key) def save_to_file(self, path): with open(path, "w") as f: f.write(self.cert_pem()) f.write(self.key_pem()) def save_cert_to_file(self, path): with open(path, "w") as f: f.write(self.cert_pem()) @staticmethod def from_file(path): with open(path) as f: data = f.read() cert = crypto.load_certificate(crypto.FILETYPE_PEM, data) key = crypto.load_privatekey(crypto.FILETYPE_PEM, data) return Certificate(cert, key) @staticmethod def create(cn, issuer=None, key=None, keysize=2048, digest="sha256", notBefore="20150101000000+0000", notAfter="20300101000000+0000", additional_extensions=None): if key is None: key = crypto.PKey() key.generate_key(crypto.TYPE_RSA, keysize) cert = crypto.X509() cert.set_pubkey(key) cert.set_version(2) cert.set_serial_number(random.randint(0, 2**20)) cert.set_notBefore(notBefore) cert.set_notAfter(notAfter) cert.get_subject().CN = cn cert.set_issuer(cert.get_subject() if issuer is None else issuer.cert.get_subject()) # Add the CA=True basic constraint basicContraints = crypto.X509Extension("basicConstraints", True, "CA:TRUE") cert.add_extensions([basicContraints]) if additional_extensions is not None: cert.add_extensions(additional_extensions) signing_key = key if issuer is None else issuer.key cert.sign(signing_key, digest) return Certificate(cert, key) if __name__ == "__main__": # Generate test certificates. a = Certificate.create("Root A") a_sha1 = Certificate.create("Root A", key=a.key, digest="sha1") b = Certificate.create("Root B") a_to_b = Certificate.create("Root A", b, a.key) b_to_a = Certificate.create("Root B", a, b.key) leaf1 = Certificate.create("Leaf", a) intermediate_a = Certificate.create("intermediate", a) intermediate_b = Certificate.create("intermediate", b, intermediate_a.key) leaf2 = Certificate.create("Leaf 2", intermediate_a) # Save test certificates. a.save_cert_to_file("a.pem") a_sha1.save_cert_to_file("a_sha1.pem") b.save_cert_to_file("b.pem") a_to_b.save_cert_to_file("a_to_b.pem") b_to_a.save_cert_to_file("b_to_a.pem") leaf1.save_cert_to_file("leaf1.pem") leaf2.save_cert_to_file("leaf2.pem") intermediate_a.save_cert_to_file("intermediate_a.pem") intermediate_b.save_cert_to_file("intermediate_b.pem")