#!/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")