Created
November 16, 2016 14:01
-
-
Save bluec0re/232e76fd6edb43783b70aac20a5d2293 to your computer and use it in GitHub Desktop.
Python2 script to clone ssl certificates (chains). Requires M2Crypto.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python2 | |
# encoding: utf-8 | |
from M2Crypto import X509, EVP, RSA, m2 | |
import sys | |
import argparse | |
def clone_to_req(crt, *args): | |
req = X509.Request() | |
req.set_version(crt.get_version()) | |
key = clone_pubkey(crt.get_pubkey()) | |
pkey = EVP.PKey() | |
pkey.assign_rsa(key) | |
req.set_pubkey(pkey) | |
req.set_subject_name(crt.get_subject()) | |
extstack = X509.X509_Extension_Stack() | |
for extid in range(crt.get_ext_count()): | |
extstack.push(crt.get_ext_at(extid)) | |
req.add_extensions(extstack) | |
req.sign(pkey, 'sha1') # TODO: read hash algo from cert? | |
return req, key | |
def clone(crt, self_sign, out): | |
cert = X509.X509() | |
cert.set_version(crt.get_version()) | |
cert.set_serial_number(crt.get_serial_number()) | |
cert.set_not_before(crt.get_not_before()) | |
cert.set_not_after(crt.get_not_after()) | |
key = clone_pubkey(crt.get_pubkey()) | |
pkey = EVP.PKey() | |
pkey.assign_rsa(key) | |
cert.set_pubkey(pkey) | |
cert.set_subject_name(crt.get_subject()) | |
if self_sign: | |
cert.set_issuer(cert.get_subject()) | |
else: | |
cert.set_issuer(crt.get_issuer()) | |
for extid in range(crt.get_ext_count()): | |
cert.add_ext(crt.get_ext_at(extid)) | |
if self_sign: | |
cert.sign(pkey, 'sha1') # TODO: read hash algo from cert? | |
# segfaults outside of this function?? | |
key.save_pem('{0}.key'.format(out), None) | |
return cert, key | |
def clone_pubkey(pubkey): | |
key = RSA.gen_key(pubkey.size()*8, m2.RSA_F4) | |
return key | |
def main(): | |
parser = argparse.ArgumentParser() | |
parser.add_argument('CERT_TO_CLONE') | |
parser.add_argument('-o', '--out', help="name of output files (w/o extension)", default="cloned_cert") | |
xor = parser.add_mutually_exclusive_group(required=True) | |
xor.add_argument('-s', '--self-signed', action='store_true', dest='self_signed') | |
xor.add_argument('CA_CERT', nargs='?') | |
parser.add_argument('CA_KEY', nargs='?') | |
args = parser.parse_args() | |
if args.self_signed and (args.CA_CERT or args.CA_KEY): | |
print "-s and CA_* couldn't be used together" | |
exit(1) | |
if (args.CA_CERT and not args.CA_KEY) or (not args.CA_CERT and args.CA_KEY): | |
print "CA_CERT and CA_KEY required" | |
exit(1) | |
crt = X509.load_cert(args.CERT_TO_CLONE) | |
newcrt, key = clone(crt, args.self_signed, args.out) | |
if args.CA_CERT: | |
ca = X509.load_cert(args.CA_CERT) | |
newcrt.set_issuer_name(ca.get_subject()) | |
cakey = EVP.load_key(args.CA_KEY) | |
newcrt.sign(cakey, 'sha1') | |
print newcrt.as_text() | |
newcrt.save_pem('{0}.pem'.format(args.out)) | |
print "Saved as {0}.pem and {0}.key".format(args.out) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment