aboutsummaryrefslogtreecommitdiff
path: root/rpkid/rpki
diff options
context:
space:
mode:
Diffstat (limited to 'rpkid/rpki')
-rw-r--r--rpkid/rpki/gctx.py33
-rw-r--r--rpkid/rpki/https.py48
-rw-r--r--rpkid/rpki/left_right.py24
-rw-r--r--rpkid/rpki/relaxng.py12
-rw-r--r--rpkid/rpki/sql.py2
-rw-r--r--rpkid/rpki/x509.py104
6 files changed, 105 insertions, 118 deletions
diff --git a/rpkid/rpki/gctx.py b/rpkid/rpki/gctx.py
index 2bdc5daf..127205f7 100644
--- a/rpkid/rpki/gctx.py
+++ b/rpkid/rpki/gctx.py
@@ -36,10 +36,11 @@ class global_context(object):
passwd = cfg.get("sql-password"))
self.cur = self.db.cursor()
- self.ta_irdb = rpki.x509.X509(Auto_file = cfg.get("ta-irdb"))
- self.ta_irbe = rpki.x509.X509(Auto_file = cfg.get("ta-irbe"))
- self.ee_key = rpki.x509.RSA(Auto_file = cfg.get("ee-key"))
- self.cert_chain = rpki.x509.X509_chain(Auto_files = cfg.multiget("cert-chain"))
+ self.bpki_ta = rpki.x509.X509(Auto_file = cfg.get("bpki-ta"))
+ self.irdb_cert = rpki.x509.X509(Auto_file = cfg.get("irdb-cert"))
+ self.irbe_cert = rpki.x509.X509(Auto_file = cfg.get("irbe-cert"))
+ self.rpkid_cert = rpki.x509.X509(Auto_file = cfg.get("rpkid-cert"))
+ self.rpkid_key = rpki.x509.RSA( Auto_file = cfg.get("rpkid-key"))
self.irdb_url = cfg.get("irdb-url")
@@ -69,14 +70,14 @@ class global_context(object):
q_msg[0].type = "query"
q_msg[0].self_id = self_id
q_msg[0].child_id = child_id
- q_cms = rpki.left_right.cms_msg.wrap(q_msg, self.ee_key, self.cert_chain)
+ q_cms = rpki.left_right.cms_msg.wrap(q_msg, self.rpkid_key, self.rpkid_cert)
der = rpki.https.client(
- client_key = self.ee_key,
- client_certs = self.cert_chain,
- server_ta = self.ta_irdb,
+ client_key = self.rpkid_key,
+ client_cert = self.rpkid_cert,
+ server_ta = self.irdb_cert,
url = self.irdb_url,
msg = q_cms)
- r_msg = rpki.left_right.cms_msg.unwrap(der, self.ta_irdb)
+ r_msg = rpki.left_right.cms_msg.unwrap(der, self.irdb_cert)
if len(r_msg) == 0 or not isinstance(r_msg[0], rpki.left_right.list_resources_elt) or r_msg[0].type != "reply":
raise rpki.exceptions.BadIRDBReply, "Unexpected response to IRDB query: %s" % lxml.etree.tostring(r_msg.toXML(), pretty_print = True, encoding = "us-ascii")
return rpki.resource_set.resource_bag(
@@ -107,9 +108,9 @@ class global_context(object):
"""Process one left-right PDU."""
rpki.log.trace()
try:
- q_msg = rpki.left_right.cms_msg.unwrap(query, self.ta_irbe)
+ q_msg = rpki.left_right.cms_msg.unwrap(query, self.bpki_ta)
r_msg = q_msg.serve_top_level(self)
- reply = rpki.left_right.cms_msg.wrap(r_msg, self.ee_key, self.cert_chain)
+ reply = rpki.left_right.cms_msg.wrap(r_msg, self.rpkid_key, self.rpkid_cert)
self.sql_sweep()
return 200, reply
except Exception, data:
@@ -155,7 +156,7 @@ class global_context(object):
"""Clear cached HTTPS trust anchor X509Store."""
if self.https_ta_cache is not None:
- rpki.log.debug("Clearing HTTPS trust anchor cache")
+ rpki.log.debug("Clearing HTTPS trusted cert cache")
self.https_ta_cache = None
def build_x509store(self):
@@ -168,15 +169,17 @@ class global_context(object):
"""
if self.https_ta_cache is None:
-
store = POW.X509Store()
+ selves = rpki.left_right.self_elt.sql_fetch_all(self)
children = rpki.left_right.child_elt.sql_fetch_all(self)
certs = [c.peer_biz_cert for c in children if c.peer_biz_cert is not None] + \
[c.peer_biz_glue for c in children if c.peer_biz_glue is not None] + \
- [ self.ta_irbe ]
+ [s.biz_cert for s in selves if s.biz_cert is not None] + \
+ [s.biz_glue for s in selves if s.biz_glue is not None] + \
+ [self.irbe_cert, self.irdb_cert, self.bpki_ta]
for x in certs:
if rpki.https.debug_tls_certs:
- rpki.log.debug("HTTPS dynamic trust anchor %s" % x.getSubject())
+ rpki.log.debug("HTTPS dynamic trusted cert %s" % x.getSubject())
store.addTrust(x.get_POW())
self.https_ta_cache = store
diff --git a/rpkid/rpki/https.py b/rpkid/rpki/https.py
index db94e721..b5338f5d 100644
--- a/rpkid/rpki/https.py
+++ b/rpkid/rpki/https.py
@@ -31,10 +31,17 @@ import POW
disable_tls_certificate_validation_exceptions = False
# Chatter suppression
-debug_tls_certs = False
+debug_tls_certs = True
rpki_content_type = "application/x-rpki"
+def tlslite_certChain(x509):
+ """Utility function to construct tlslite certChains."""
+ if isinstance(x509, rpki.x509.X509):
+ return tlslite.api.X509CertChain([x509.get_tlslite()])
+ else:
+ return tlslite.api.X509CertChain([x.get_tlslite() for x in x509])
+
class Checker(tlslite.api.Checker):
"""Derived class to handle X.509 client certificate checking."""
@@ -43,13 +50,18 @@ class Checker(tlslite.api.Checker):
self.dynamic_x509store = dynamic_x509store
- if dynamic_x509store is None:
- self.x509store = POW.X509Store()
+ if dynamic_x509store is not None:
+ return
+
+ self.x509store = POW.X509Store()
+
+ if isinstance(trust_anchor, rpki.x509.X509):
+ trust_anchor = (trust_anchor,)
+
+ for x in trust_anchor:
if debug_tls_certs:
- rpki.log.debug("HTTPS trust anchor %s" % trust_anchor.getSubject())
- self.x509store.addTrust(trust_anchor.get_POW())
- elif debug_tls_certs:
- rpki.log.debug("HTTPS dynamic trust anchors")
+ rpki.log.debug("HTTPS trusted cert %s" % x.getSubject())
+ self.x509store.addTrust(x.get_POW())
def x509store_thunk(self):
if self.dynamic_x509store is not None:
@@ -83,17 +95,17 @@ class httpsClient(tlslite.api.HTTPTLSConnection):
"""Derived class to let us replace the default Checker."""
def __init__(self, host, port = None,
- client_certs = None, client_key = None,
+ client_cert = None, client_key = None,
server_ta = None, settings = None):
"""Create a new httpsClient."""
tlslite.api.HTTPTLSConnection.__init__(
self, host = host, port = port, settings = settings,
- certChain = client_certs, privateKey = client_key)
+ certChain = client_cert, privateKey = client_key)
self.checker = Checker(trust_anchor = server_ta)
-def client(msg, client_key, client_certs, server_ta, url, timeout = 300):
+def client(msg, client_key, client_cert, server_ta, url, timeout = 300):
"""Open client HTTPS connection, send a message, wait for response.
This function wraps most of what one needs to do to send a message
@@ -112,8 +124,8 @@ def client(msg, client_key, client_certs, server_ta, url, timeout = 300):
u.fragment == ""
if debug_tls_certs:
- for client_cert in client_certs:
- rpki.log.debug("Sending client TLS cert %s" % client_cert.getSubject())
+ for cert in (client_cert,) if isinstance(client_cert, rpki.x509.X509) else client_cert:
+ rpki.log.debug("Sending client TLS cert %s" % cert.getSubject())
# We could add a "settings = foo" argument to the following call to
# pass in a tlslite.HandshakeSettings object that would let us
@@ -122,7 +134,7 @@ def client(msg, client_key, client_certs, server_ta, url, timeout = 300):
httpc = httpsClient(host = u.hostname or "localhost",
port = u.port or 443,
client_key = client_key.get_tlslite(),
- client_certs = client_certs.tlslite_certChain(),
+ client_cert = tlslite_certChain(client_cert),
server_ta = server_ta)
httpc.connect()
httpc.sock.settimeout(timeout)
@@ -179,12 +191,12 @@ class httpsServer(tlslite.api.TLSSocketServerMixIn, BaseHTTPServer.HTTPServer):
rpki_sessionCache = None
rpki_server_key = None
- rpki_server_certs = None
+ rpki_server_cert = None
rpki_checker = None
def handshake(self, tlsConnection):
"""TLS handshake handler."""
- assert self.rpki_server_certs is not None
+ assert self.rpki_server_cert is not None
assert self.rpki_server_key is not None
assert self.rpki_sessionCache is not None
@@ -194,7 +206,7 @@ class httpsServer(tlslite.api.TLSSocketServerMixIn, BaseHTTPServer.HTTPServer):
# to pass in a tlslite.HandshakeSettings object that would let
# us insist on, eg, particular SSL/TLS versions.
#
- tlsConnection.handshakeServer(certChain = self.rpki_server_certs,
+ tlsConnection.handshakeServer(certChain = self.rpki_server_cert,
privateKey = self.rpki_server_key,
sessionCache = self.rpki_sessionCache,
checker = self.rpki_checker,
@@ -205,7 +217,7 @@ class httpsServer(tlslite.api.TLSSocketServerMixIn, BaseHTTPServer.HTTPServer):
rpki.log.warn("TLS handshake failure: " + str(error))
return False
-def server(handlers, server_key, server_certs, port = 4433, host = "", client_ta = None, dynamic_x509store = None):
+def server(handlers, server_key, server_cert, port = 4433, host = "", client_ta = None, dynamic_x509store = None):
"""Run an HTTPS server and wait (forever) for connections."""
if not isinstance(handlers, (tuple, list)):
@@ -217,7 +229,7 @@ def server(handlers, server_key, server_certs, port = 4433, host = "", client_ta
httpd = httpsServer((host, port), boundRequestHandler)
httpd.rpki_server_key = server_key.get_tlslite()
- httpd.rpki_server_certs = server_certs.tlslite_certChain()
+ httpd.rpki_server_cert = tlslite_certChain(server_cert)
httpd.rpki_sessionCache = tlslite.api.SessionCache()
httpd.rpki_checker = Checker(trust_anchor = client_ta, dynamic_x509store = dynamic_x509store)
diff --git a/rpkid/rpki/left_right.py b/rpkid/rpki/left_right.py
index 3361ac5e..db7f9191 100644
--- a/rpkid/rpki/left_right.py
+++ b/rpkid/rpki/left_right.py
@@ -215,15 +215,18 @@ class self_elt(data_elt):
element_name = "self"
attributes = ("action", "type", "tag", "self_id", "crl_interval", "regen_margin")
- elements = ("extension_preference",)
+ elements = ("extension_preference", "biz_cert", "biz_glue")
booleans = ("rekey", "reissue", "revoke", "run_now", "publish_world_now", "clear_extension_preferences")
- sql_template = rpki.sql.template("self", "self_id", "use_hsm", "crl_interval", "regen_margin")
+ sql_template = rpki.sql.template("self", "self_id", "use_hsm", "crl_interval", "regen_margin",
+ ("biz_cert", rpki.x509.X509), ("biz_glue", rpki.x509.X509))
self_id = None
use_hsm = False
crl_interval = None
regen_margin = None
+ biz_cert = None
+ biz_glue = None
def __init__(self):
"""Initialize a self_elt."""
@@ -322,14 +325,19 @@ class self_elt(data_elt):
self.prefs.append(pref)
stack.append(pref)
pref.startElement(stack, name, attrs)
- else:
+ elif name not in ("biz_cert", "biz_glue"):
assert name == "self", "Unexpected name %s, stack %s" % (name, stack)
self.read_attrs(attrs)
def endElement(self, stack, name, text):
"""Handle <self/> element."""
- assert name == "self", "Unexpected name %s, stack %s" % (name, stack)
- stack.pop()
+ if name == "biz_cert":
+ self.biz_cert = rpki.x509.X509(Base64 = text)
+ elif name == "biz_glue":
+ self.biz_glue = rpki.x509.X509(Base64 = text)
+ else:
+ assert name == "self", "Unexpected name %s, stack %s" % (name, stack)
+ stack.pop()
def toXML(self):
"""Generate <self/> element."""
@@ -443,12 +451,12 @@ class bsc_elt(data_elt):
def __init__(self):
"""Initialize bsc_elt."""
- self.signing_cert = rpki.x509.X509_chain()
+ self.signing_cert = []
def sql_fetch_hook(self):
"""Extra SQL fetch actions for bsc_elt -- handle signing certs."""
self.gctx.cur.execute("SELECT cert FROM bsc_cert WHERE bsc_id = %s", (self.bsc_id,))
- self.signing_cert[:] = [rpki.x509.X509(DER = x) for (x,) in self.gctx.cur.fetchall()]
+ self.signing_cert = [rpki.x509.X509(DER = x) for (x,) in self.gctx.cur.fetchall()]
def sql_insert_hook(self):
"""Extra SQL insert actions for bsc_elt -- handle signing certs."""
@@ -613,7 +621,7 @@ class parent_elt(data_elt):
der = rpki.https.client(server_ta = self.peer_biz_cert,
client_key = bsc.private_key_id,
- client_certs = bsc.signing_cert,
+ client_cert = bsc.signing_cert,
msg = q_cms,
url = self.peer_contact_uri)
diff --git a/rpkid/rpki/relaxng.py b/rpkid/rpki/relaxng.py
index c04a3158..8b3ab862 100644
--- a/rpkid/rpki/relaxng.py
+++ b/rpkid/rpki/relaxng.py
@@ -6,7 +6,7 @@ import lxml.etree
## Parsed RelaxNG left_right schema
left_right = lxml.etree.RelaxNG(lxml.etree.fromstring('''<?xml version="1.0" encoding="UTF-8"?>
<!--
- $Id: left-right-schema.rng 1668 2008-04-16 04:58:58Z sra $
+ $Id: left-right-schema.rnc 1668 2008-04-16 04:58:58Z sra $
RelaxNG (Compact Syntax) Schema for RPKI left-right protocol.
@@ -227,6 +227,16 @@ left_right = lxml.etree.RelaxNG(lxml.etree.fromstring('''<?xml version="1.0" enc
</data>
</element>
</zeroOrMore>
+ <optional>
+ <element name="biz_cert">
+ <ref name="base64"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="biz_glue">
+ <ref name="base64"/>
+ </element>
+ </optional>
</define>
<define name="self_id">
<attribute name="self_id">
diff --git a/rpkid/rpki/sql.py b/rpkid/rpki/sql.py
index 892e99b7..85c85a6a 100644
--- a/rpkid/rpki/sql.py
+++ b/rpkid/rpki/sql.py
@@ -675,7 +675,7 @@ class ca_detail_obj(sql_persistant):
nextUpdate = nextUpdate,
names_and_objs = certs,
keypair = self.manifest_private_key_id,
- certs = rpki.x509.X509_chain(self.latest_manifest_cert))
+ certs = self.latest_manifest_cert)
repository.publish(self.latest_manifest, self.manifest_uri(ca))
diff --git a/rpkid/rpki/x509.py b/rpkid/rpki/x509.py
index a74fc429..71ff4d53 100644
--- a/rpkid/rpki/x509.py
+++ b/rpkid/rpki/x509.py
@@ -356,74 +356,6 @@ class X509(DER_object):
return X509(POWpkix = cert)
-class X509_chain(list):
- """Collections of certs.
-
- This class provides sorting and conversion functions for various
- packages.
- """
-
- def __init__(self, *args, **kw):
- """Initialize an X509_chain."""
- if args:
- self[:] = args
- elif "PEM_files" in kw:
- self.load_from_PEM(kw["PEM_files"])
- elif "DER_files" in kw:
- self.load_from_DER(kw["DER_files"])
- elif "Auto_files" in kw:
- self.load_from_Auto(kw["Auto_files"])
- elif kw:
- raise TypeError
-
- def chainsort(self):
- """Sort a bag of certs into a chain, leaf first.
-
- Various other routines want their certs presented in this order.
- """
- if len(self) > 1:
- bag = self[:]
- issuer_names = [x.getIssuer() for x in bag]
- subject_map = dict([(x.getSubject(), x) for x in bag])
- chain = []
- for subject in subject_map:
- if subject not in issuer_names:
- cert = subject_map[subject]
- chain.append(cert)
- bag.remove(cert)
- if len(chain) != 1:
- raise rpki.exceptions.NotACertificateChain, "Certificates in bag don't form a proper chain"
- while bag:
- cert = subject_map[chain[-1].getIssuer()]
- chain.append(cert)
- bag.remove(cert)
- self[:] = chain
-
- def tlslite_certChain(self):
- """Return a certChain in the format tlslite likes."""
- self.chainsort()
- return tlslite.api.X509CertChain([x.get_tlslite() for x in self])
-
- def tlslite_trustList(self):
- """Return a trustList in the format tlslite likes."""
- return [x.get_tlslite() for x in self]
-
- def clear(self):
- """Drop all certs from this bag onto the floor."""
- self[:] = []
-
- def load_from_PEM(self, files):
- """Load a set of certs from a list of PEM files."""
- self.extend([X509(PEM_file=f) for f in files])
-
- def load_from_DER(self, files):
- """Load a set of certs from a list of DER files."""
- self.extend([X509(DER_file=f) for f in files])
-
- def load_from_Auto(self, files):
- """Load a set of certs from a list of DER or PEM files (guessing)."""
- self.extend([X509(Auto_file=f) for f in files])
-
class PKCS10(DER_object):
"""Class to hold a PKCS #10 request."""
@@ -622,6 +554,7 @@ class CMS_object(DER_object):
econtent_oid = POWify("id-data")
dump_on_verify_failure = False
+ debug_cms_certs = True
def get_DER(self):
"""Get the DER value of this CMS_object."""
@@ -644,14 +577,27 @@ class CMS_object(DER_object):
"""Verify CMS wrapper and store inner content."""
cms = POW.derRead(POW.CMS_MESSAGE, self.get_DER())
+
if cms.eContentType() != self.econtent_oid:
raise rpki.exceptions.WrongEContentType, "Got CMS eContentType %s, expected %s" % (cms.eContentType(), self.econtent_oid)
+
store = POW.X509Store()
- if isinstance(ta, (tuple, list)):
- for x in ta:
- store.addTrust(x.get_POW())
- else:
- store.addTrust(ta.get_POW())
+
+ if isinstance(ta, X509):
+ ta = (ta,)
+
+ for x in ta:
+ if self.debug_cms_certs:
+ rpki.log.debug("CMS trusted cert %s" % x.getSubject())
+ store.addTrust(x.get_POW())
+
+ if self.debug_cms_certs:
+ try:
+ for x in cms.certs():
+ rpki.log.debug("Received CMS cert %s" % x.getSubject())
+ except:
+ pass
+
try:
content = cms.verify(store)
except:
@@ -659,17 +605,25 @@ class CMS_object(DER_object):
print "CMS verification failed, dumping ASN.1:"
self.dumpasn1()
raise rpki.exceptions.CMSVerificationFailed, "CMS verification failed"
+
self.decode(content)
return self.get_content()
def sign(self, keypair, certs, crls = None, no_certs = False):
"""Sign and wrap inner content."""
+ if isinstance(certs, X509):
+ cert = certs
+ certs = ()
+ else:
+ cert = certs[0]
+ certs = certs[1:]
+
cms = POW.CMS()
- cms.sign(certs[0].get_POW(),
+ cms.sign(cert.get_POW(),
keypair.get_POW(),
self.encode(),
- [x.get_POW() for x in certs[1:]],
+ [x.get_POW() for x in certs],
crls,
self.econtent_oid,
POW.CMS_NOCERTS if no_certs else 0)