00001 """ 00002 Cross-certification tool to issue a new certificate based on an old 00003 one that was issued by somebody else. The point of the exercise is to 00004 end up with a valid certificate in our own BPKI which has the same 00005 subject name and subject public key as the one we're replacing. 00006 00007 Much of this code lifted from rpki.x509.X509.issue(), but this is a 00008 sufficiently different purpose that it's probably not worth 00009 refactoring. 00010 00011 Usage: python cross_certify.py { -i | --in } input_cert 00012 { -c | --ca } issuing_cert 00013 { -k | --key } issuing_cert_key 00014 { -s | --serial } serial_filename 00015 [ { -h | --help } ] 00016 [ { -o | --out } filename (default: stdout) ] 00017 [ { -l | --lifetime } timedelta (default: 30 days) ] 00018 00019 $Id: cross_certify.py 1995 2008-07-15 17:38:45Z sra $ 00020 00021 Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") 00022 00023 Permission to use, copy, modify, and distribute this software for any 00024 purpose with or without fee is hereby granted, provided that the above 00025 copyright notice and this permission notice appear in all copies. 00026 00027 THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH 00028 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00029 AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT, 00030 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 00031 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 00032 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00033 PERFORMANCE OF THIS SOFTWARE. 00034 """ 00035 00036 import os, time, getopt, sys, POW 00037 import rpki.x509, rpki.sundial 00038 00039 os.environ["TZ"] = "UTC" 00040 time.tzset() 00041 00042 def usage(code): 00043 print __doc__ 00044 sys.exit(code) 00045 00046 output = None 00047 lifetime = rpki.sundial.timedelta(days = 30) 00048 00049 opts,argv = getopt.getopt(sys.argv[1:], "h?i:o:c:k:s:l:", 00050 ["help", "in=", "out=", "ca=", "key=", "serial=", "lifetime="]) 00051 for o,a in opts: 00052 if o in ("-h", "--help", "-?"): 00053 usage(0) 00054 elif o in ("-i", "--in"): 00055 child = rpki.x509.X509(Auto_file = a) 00056 elif o in ("-o", "--out"): 00057 output = a 00058 elif o in ("-c", "--ca"): 00059 parent = rpki.x509.X509(Auto_file = a) 00060 elif o in ("-k", "--key"): 00061 keypair = rpki.x509.RSA(Auto_file = a) 00062 elif o in ("-s", "--serial"): 00063 serial_file = a 00064 elif o in ("-l", "--lifetime"): 00065 lifetime = rpki.sundial.timedelta.parse(a) 00066 if argv: 00067 usage(1) 00068 00069 now = rpki.sundial.now() 00070 notAfter = now + lifetime 00071 00072 try: 00073 f = open(serial_file, "r") 00074 serial = f.read() 00075 f.close() 00076 serial = int(serial.splitlines()[0], 16) 00077 except IOError: 00078 serial = 1 00079 00080 x = POW.pkix.Certificate() 00081 x.setVersion(2) 00082 x.setSerial(serial) 00083 x.setIssuer(parent.get_POWpkix().getSubject()) 00084 x.setSubject(child.get_POWpkix().getSubject()) 00085 x.setNotBefore(now.toASN1tuple()) 00086 x.setNotAfter(notAfter.toASN1tuple()) 00087 x.tbs.subjectPublicKeyInfo.set(child.get_POWpkix().tbs.subjectPublicKeyInfo.get()) 00088 x.setExtensions(((rpki.oids.name2oid["subjectKeyIdentifier"], False, 00089 child.get_SKI()), 00090 (rpki.oids.name2oid["authorityKeyIdentifier"], False, 00091 (parent.get_SKI(), (), None)), 00092 (rpki.oids.name2oid["basicConstraints"], True, 00093 (1, 0)))) 00094 x.sign(keypair.get_POW(), POW.SHA256_DIGEST) 00095 00096 cert = rpki.x509.X509(POWpkix = x) 00097 00098 f = open(serial_file, "w") 00099 f.write("%02x\n" % (serial + 1)) 00100 f.close() 00101 00102 if output is None: 00103 print cert.get_PEM() 00104 else: 00105 f = open(output, "w") 00106 f.write(cert.get_PEM()) 00107 f.close() 00108