00001 """ 00002 Trivial RPKI up-down protocol root server, for testing. Not suitable 00003 for production use. Overrides a bunch of method definitions from the 00004 rpki.* classes in order to reuse as much code as possible. 00005 00006 Usage: python rootd.py [ { -c | --config } configfile ] [ { -h | --help } ] 00007 00008 Default configuration file is rootd.conf, override with --config option. 00009 00010 $Id: rootd.py 1912 2008-06-21 07:55:01Z sra $ 00011 00012 Copyright (C) 2007--2008 American Registry for Internet Numbers ("ARIN") 00013 00014 Permission to use, copy, modify, and distribute this software for any 00015 purpose with or without fee is hereby granted, provided that the above 00016 copyright notice and this permission notice appear in all copies. 00017 00018 THE SOFTWARE IS PROVIDED "AS IS" AND ARIN DISCLAIMS ALL WARRANTIES WITH 00019 REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00020 AND FITNESS. IN NO EVENT SHALL ARIN BE LIABLE FOR ANY SPECIAL, DIRECT, 00021 INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 00022 LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 00023 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00024 PERFORMANCE OF THIS SOFTWARE. 00025 """ 00026 00027 import traceback, os, time, getopt, sys, lxml 00028 import rpki.resource_set, rpki.up_down, rpki.left_right, rpki.x509 00029 import rpki.https, rpki.config, rpki.exceptions, rpki.relaxng 00030 import rpki.sundial, rpki.log 00031 00032 rpki_subject_lifetime = rpki.sundial.timedelta(days = 30) 00033 00034 def get_subject_cert(): 00035 try: 00036 x = rpki.x509.X509(Auto_file = rpki_root_dir + rpki_subject_cert) 00037 return x 00038 except IOError: 00039 return None 00040 00041 def set_subject_cert(cert): 00042 f = open(rpki_root_dir + rpki_subject_cert, "wb") 00043 f.write(cert.get_DER()) 00044 f.close() 00045 00046 def del_subject_cert(): 00047 os.remove(rpki_root_dir + rpki_subject_cert) 00048 00049 def stash_subject_pkcs10(pkcs10): 00050 if rpki_subject_pkcs10: 00051 f = open(rpki_subject_pkcs10, "wb") 00052 f.write(pkcs10.get_DER()) 00053 f.close() 00054 00055 def compose_response(r_msg): 00056 rc = rpki.up_down.class_elt() 00057 rc.class_name = rpki_class_name 00058 rc.cert_url = rpki.up_down.multi_uri(rpki_root_cert_uri) 00059 rc.from_resource_bag(rpki_root_cert.get_3779resources()) 00060 rc.issuer = rpki_root_cert 00061 r_msg.payload.classes.append(rc) 00062 subject_cert = get_subject_cert() 00063 if subject_cert is not None: 00064 rc.certs.append(rpki.up_down.certificate_elt()) 00065 rc.certs[0].cert_url = rpki.up_down.multi_uri(rpki_base_uri + rpki_subject_cert) 00066 rc.certs[0].cert = subject_cert 00067 00068 class list_pdu(rpki.up_down.list_pdu): 00069 def serve_pdu(self, q_msg, r_msg, ignored): 00070 r_msg.payload = rpki.up_down.list_response_pdu() 00071 compose_response(r_msg) 00072 00073 class issue_pdu(rpki.up_down.issue_pdu): 00074 def serve_pdu(self, q_msg, r_msg, ignored): 00075 stash_subject_pkcs10(self.pkcs10) 00076 self.pkcs10.check_valid_rpki() 00077 r_msg.payload = rpki.up_down.issue_response_pdu() 00078 subject_cert = get_subject_cert() 00079 if subject_cert is None: 00080 resources = rpki_root_cert.get_3779resources() 00081 rpki.log.info("Generating subject cert with resources " + str(resources)) 00082 req_key = self.pkcs10.getPublicKey() 00083 req_sia = self.pkcs10.get_SIA() 00084 crldp = rpki_base_uri + rpki_root_crl 00085 now = rpki.sundial.now() 00086 subject_cert = rpki_root_cert.issue( 00087 keypair = rpki_root_key, 00088 subject_key = req_key, 00089 serial = int(time.time()), 00090 sia = req_sia, 00091 aia = rpki_root_cert_uri, 00092 crldp = crldp, 00093 resources = resources, 00094 notAfter = now + rpki_subject_lifetime) 00095 set_subject_cert(subject_cert) 00096 crl = rpki.x509.CRL.generate( 00097 keypair = rpki_root_key, 00098 issuer = rpki_root_cert, 00099 serial = 1, 00100 thisUpdate = now, 00101 nextUpdate = now + rpki_subject_lifetime, 00102 revokedCertificates = ()) 00103 f = open(rpki_root_dir + rpki_root_crl, "wb") 00104 f.write(crl.get_DER()) 00105 f.close() 00106 manifest_resources = rpki.resource_set.resource_bag( 00107 asn = rpki.resource_set.resource_set_as("<inherit>"), 00108 v4 = rpki.resource_set.resource_set_ipv4("<inherit>"), 00109 v6 = rpki.resource_set.resource_set_ipv6("<inherit>")) 00110 manifest_keypair = rpki.x509.RSA.generate() 00111 manifest_cert = rpki_root_cert.issue( 00112 keypair = rpki_root_key, 00113 subject_key = manifest_keypair.get_RSApublic(), 00114 serial = int(time.time()) + 1, 00115 sia = None, 00116 aia = rpki_root_cert_uri, 00117 crldp = crldp, 00118 resources = manifest_resources, 00119 notAfter = now + rpki_subject_lifetime, 00120 is_ca = False) 00121 manifest = rpki.x509.SignedManifest.build( 00122 serial = int(time.time()), 00123 thisUpdate = now, 00124 nextUpdate = now + rpki_subject_lifetime, 00125 names_and_objs = [(rpki_subject_cert, subject_cert), (rpki_root_crl, crl)], 00126 keypair = manifest_keypair, 00127 certs = manifest_cert) 00128 f = open(rpki_root_dir + rpki_root_manifest, "wb") 00129 f.write(manifest.get_DER()) 00130 f.close() 00131 compose_response(r_msg) 00132 00133 class revoke_pdu(rpki.up_down.revoke_pdu): 00134 def serve_pdu(self, q_msg, r_msg, ignored): 00135 subject_cert = get_subject_cert() 00136 if subject_cert is None or subject_cert.gSKI() != self.ski: 00137 raise rpki.exceptions.NotInDatabase 00138 del_subject_cert() 00139 r_msg.payload = rpki.up_down.revoke_response_pdu() 00140 r_msg.payload.class_name = self.class_name 00141 r_msg.payload.ski = self.ski 00142 00143 class message_pdu(rpki.up_down.message_pdu): 00144 name2type = { 00145 "list" : list_pdu, 00146 "list_response" : rpki.up_down.list_response_pdu, 00147 "issue" : issue_pdu, 00148 "issue_response" : rpki.up_down.issue_response_pdu, 00149 "revoke" : revoke_pdu, 00150 "revoke_response" : rpki.up_down.revoke_response_pdu, 00151 "error_response" : rpki.up_down.error_response_pdu } 00152 type2name = dict((v,k) for k,v in name2type.items()) 00153 00154 class sax_handler(rpki.up_down.sax_handler): 00155 pdu = message_pdu 00156 00157 class cms_msg(rpki.up_down.cms_msg): 00158 saxify = sax_handler.saxify 00159 00160 def up_down_handler(query, path): 00161 try: 00162 q_msg = cms_msg.unwrap(query, (bpki_ta, child_bpki_cert)) 00163 except Exception, data: 00164 rpki.log.error(traceback.format_exc()) 00165 return 400, "Could not process PDU: %s" % data 00166 try: 00167 r_msg = q_msg.serve_top_level(None) 00168 r_cms = cms_msg.wrap(r_msg, rootd_bpki_key, rootd_bpki_cert, rootd_bpki_crl) 00169 return 200, r_cms 00170 except Exception, data: 00171 rpki.log.error(traceback.format_exc()) 00172 try: 00173 r_msg = q_msg.serve_error(data) 00174 r_cms = cms_msg.wrap(r_msg, rootd_bpki_key, rootd_bpki_cert, rootd_bpki_crl) 00175 return 200, r_cms 00176 except Exception, data: 00177 rpki.log.error(traceback.format_exc()) 00178 return 500, "Could not process PDU: %s" % data 00179 00180 os.environ["TZ"] = "UTC" 00181 time.tzset() 00182 00183 rpki.log.init("rootd") 00184 00185 cfg_file = "rootd.conf" 00186 00187 opts,argv = getopt.getopt(sys.argv[1:], "c:h?", ["config=", "help"]) 00188 for o,a in opts: 00189 if o in ("-h", "--help", "-?"): 00190 print __doc__ 00191 sys.exit(0) 00192 if o in ("-c", "--config"): 00193 cfg_file = a 00194 if argv: 00195 raise RuntimeError, "Unexpected arguments %s" % argv 00196 00197 cfg = rpki.config.parser(cfg_file, "rootd") 00198 00199 bpki_ta = rpki.x509.X509(Auto_file = cfg.get("bpki-ta")) 00200 rootd_bpki_key = rpki.x509.RSA( Auto_file = cfg.get("rootd-bpki-key")) 00201 rootd_bpki_cert = rpki.x509.X509(Auto_file = cfg.get("rootd-bpki-cert")) 00202 rootd_bpki_crl = rpki.x509.CRL( Auto_file = cfg.get("rootd-bpki-crl")) 00203 child_bpki_cert = rpki.x509.X509(Auto_file = cfg.get("child-bpki-cert")) 00204 00205 https_server_host = cfg.get("server-host", "") 00206 https_server_port = int(cfg.get("server-port")) 00207 00208 rpki_class_name = cfg.get("rpki-class-name", "wombat") 00209 00210 rpki_root_dir = cfg.get("rpki-root-dir") 00211 rpki_base_uri = cfg.get("rpki-base-uri", "rsync://" + rpki_class_name + ".invalid/") 00212 00213 rpki_root_key = rpki.x509.RSA( Auto_file = cfg.get("rpki-root-key")) 00214 rpki_root_cert = rpki.x509.X509(Auto_file = cfg.get("rpki-root-cert")) 00215 rpki_root_cert_uri = cfg.get("rpki-root-cert-uri", rpki_base_uri + "Root.cer") 00216 00217 rpki_root_manifest = cfg.get("rpki-root-manifest", "Root.mnf") 00218 rpki_root_crl = cfg.get("rpki-root-crl", "Root.crl") 00219 rpki_subject_cert = cfg.get("rpki-subject-cert", "Subroot.cer") 00220 rpki_subject_pkcs10 = cfg.get("rpki-subject-pkcs10", "") 00221 00222 rpki.https.server(server_key = rootd_bpki_key, 00223 server_cert = rootd_bpki_cert, 00224 client_ta = (bpki_ta, child_bpki_cert), 00225 host = https_server_host, 00226 port = https_server_port, 00227 handlers = up_down_handler)