aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Austein <sra@hactrn.net>2014-11-12 00:25:21 +0000
committerRob Austein <sra@hactrn.net>2014-11-12 00:25:21 +0000
commit41e89b412f7beb2c9d829495afdd92bb58f80c46 (patch)
tree3adb6b61d18bf263e066ad2aff75a4985a9b17c5
parenta11d65c56617104c874b93ef2c801e73f8597c0f (diff)
Initial (awful kludge) version of adding RRDP URIs to SIA extension.
This needs rewriting, but doing it properly requires a minor database schema change, and I'm trying to get a test case running by tomorrow morning. svn path=/branches/tk705/; revision=6015
-rw-r--r--ca/tests/yamlconf.py2
-rw-r--r--ca/tests/yamltest.py3
-rw-r--r--ext/POW.c64
-rw-r--r--rp/rcynic/rcynic.c45
-rwxr-xr-xrp/utils/uri13
-rw-r--r--rpki/oids.py1
-rw-r--r--rpki/pubdb/models.py2
-rw-r--r--rpki/publication.py5
-rw-r--r--rpki/rootd.py2
-rw-r--r--rpki/rpkid.py6
-rw-r--r--rpki/x509.py18
11 files changed, 110 insertions, 51 deletions
diff --git a/ca/tests/yamlconf.py b/ca/tests/yamlconf.py
index bb82ef74..4c003835 100644
--- a/ca/tests/yamlconf.py
+++ b/ca/tests/yamlconf.py
@@ -522,7 +522,7 @@ class allocation(object):
root_uri = "rsync://%s/rpki/" % self.rsync_server
- root_sia = (root_uri, root_uri + "root.mft", None)
+ root_sia = (root_uri, root_uri + "root.mft", None, rpki.publication.rrdp_sia_uri_kludge)
root_cert = rpki.x509.X509.self_certify(
keypair = root_key,
diff --git a/ca/tests/yamltest.py b/ca/tests/yamltest.py
index e727789d..f49968b3 100644
--- a/ca/tests/yamltest.py
+++ b/ca/tests/yamltest.py
@@ -681,7 +681,8 @@ def create_root_certificate(db_root):
root_uri = "rsync://localhost:%d/rpki/%s-root/root" % (db_root.pubd.rsync_port, db_root.name)
- root_sia = (root_uri + "/", root_uri + "/root.mft", None)
+ from rpki.publication import rrdp_sia_uri_kludge
+ root_sia = (root_uri + "/", root_uri + "/root.mft", None, rrdp_sia_uri_kludge)
root_cert = rpki.x509.X509.self_certify(
keypair = root_key,
diff --git a/ext/POW.c b/ext/POW.c
index 990d344d..6a9233d4 100644
--- a/ext/POW.c
+++ b/ext/POW.c
@@ -170,6 +170,10 @@ static int NID_rpkiManifest;
static int NID_signedObject;
#endif
+#ifndef NID_rpkiNotify
+static int NID_rpkiNotify;
+#endif
+
static const struct {
int *nid;
const char *oid;
@@ -182,7 +186,11 @@ static const struct {
#endif
#ifndef NID_signedObject
- {&NID_signedObject, "1.3.6.1.5.5.7.48.11", "id-ad-signedObject", "Signed Object"}
+ {&NID_signedObject, "1.3.6.1.5.5.7.48.11", "id-ad-signedObject", "Signed Object"},
+#endif
+
+#ifndef NID_rpkiNotify
+ {&NID_rpkiNotify, "1.3.6.1.5.5.7.48.13", "id-ad-rpkiNotify", "RPKI RRDP Notification"},
#endif
};
@@ -1295,8 +1303,8 @@ extension_set_basic_constraints(X509_EXTENSIONS **exts, PyObject *args)
#define EXTENSION_GET_SIA__DOC__ \
"If there is no SIA extension, this method returns None.\n" \
"\n" \
- "Otherwise, it returns a tuple containing three values:\n" \
- "caRepository URIs, rpkiManifest URIs, and signedObject URIs.\n" \
+ "Otherwise, it returns a tuple containing four values:\n" \
+ "caRepository URIs, rpkiManifest URIs, signedObject, and rpkiNotify URIs.\n" \
"Each of these values is a tuple of strings, representing an ordered\n" \
"sequence of URIs. Any or all of these sequences may be empty.\n" \
"\n" \
@@ -1310,9 +1318,11 @@ extension_get_sia(X509_EXTENSIONS **exts)
PyObject *result_caRepository = NULL;
PyObject *result_rpkiManifest = NULL;
PyObject *result_signedObject = NULL;
+ PyObject *result_rpkiNotify = NULL;
int n_caRepository = 0;
int n_rpkiManifest = 0;
int n_signedObject = 0;
+ int n_rpkiNotify = 0;
const char *uri;
PyObject *obj;
int i, nid;
@@ -1334,26 +1344,23 @@ extension_get_sia(X509_EXTENSIONS **exts)
if (a->location->type != GEN_URI)
continue;
nid = OBJ_obj2nid(a->method);
- if (nid == NID_caRepository) {
+ if (nid == NID_caRepository)
n_caRepository++;
- continue;
- }
- if (nid == NID_rpkiManifest) {
+ else if (nid == NID_rpkiManifest)
n_rpkiManifest++;
- continue;
- }
- if (nid == NID_signedObject) {
+ else if (nid == NID_signedObject)
n_signedObject++;
- continue;
- }
+ else if (nid == NID_rpkiNotify)
+ n_rpkiNotify++;
}
if (((result_caRepository = PyTuple_New(n_caRepository)) == NULL) ||
((result_rpkiManifest = PyTuple_New(n_rpkiManifest)) == NULL) ||
- ((result_signedObject = PyTuple_New(n_signedObject)) == NULL))
+ ((result_signedObject = PyTuple_New(n_signedObject)) == NULL) ||
+ ((result_rpkiNotify = PyTuple_New(n_rpkiNotify)) == NULL))
goto error;
- n_caRepository = n_rpkiManifest = n_signedObject = 0;
+ n_caRepository = n_rpkiManifest = n_signedObject = n_rpkiNotify = 0;
for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ext); i++) {
ACCESS_DESCRIPTION *a = sk_ACCESS_DESCRIPTION_value(ext, i);
@@ -1379,24 +1386,32 @@ extension_get_sia(X509_EXTENSIONS **exts)
PyTuple_SET_ITEM(result_signedObject, n_signedObject++, obj);
continue;
}
+ if (nid == NID_rpkiNotify) {
+ if ((obj = PyString_FromString(uri)) == NULL)
+ goto error;
+ PyTuple_SET_ITEM(result_rpkiNotify, n_rpkiNotify++, obj);
+ continue;
+ }
}
- result = Py_BuildValue("(OOO)",
+ result = Py_BuildValue("(OOOO)",
result_caRepository,
result_rpkiManifest,
- result_signedObject);
+ result_signedObject,
+ result_rpkiNotify);
error:
AUTHORITY_INFO_ACCESS_free(ext);
Py_XDECREF(result_caRepository);
Py_XDECREF(result_rpkiManifest);
Py_XDECREF(result_signedObject);
+ Py_XDECREF(result_rpkiNotify);
return result;
}
#define EXTENSION_SET_SIA__DOC__ \
- "This method Takes three arguments:\n" \
- "\"caRepository\", \"rpkiManifest\", and \"signedObject\".\n" \
+ "This method takes four arguments: \"caRepository\"\n," \
+ "\"rpkiManifest\", \"signedObject\", and \"rpkiNotify\".\n" \
"Each of these should be an iterable which returns URIs.\n" \
"\n" \
"None is acceptable as an alternate way of specifying an empty\n" \
@@ -1405,11 +1420,12 @@ extension_get_sia(X509_EXTENSIONS **exts)
static PyObject *
extension_set_sia(X509_EXTENSIONS **exts, PyObject *args, PyObject *kwds)
{
- static char *kwlist[] = {"caRepository", "rpkiManifest", "signedObject", NULL};
+ static char *kwlist[] = {"caRepository", "rpkiManifest", "signedObject", "rpkiNotify", NULL};
AUTHORITY_INFO_ACCESS *ext = NULL;
PyObject *caRepository = Py_None;
PyObject *rpkiManifest = Py_None;
PyObject *signedObject = Py_None;
+ PyObject *rpkiNotify = Py_None;
PyObject *iterator = NULL;
ASN1_OBJECT *oid = NULL;
PyObject **pobj = NULL;
@@ -1424,8 +1440,8 @@ extension_set_sia(X509_EXTENSIONS **exts, PyObject *args, PyObject *kwds)
if (!exts)
goto error;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOO", kwlist,
- &caRepository, &rpkiManifest, &signedObject))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOO", kwlist,
+ &caRepository, &rpkiManifest, &signedObject, &rpkiNotify))
goto error;
if ((ext = AUTHORITY_INFO_ACCESS_new()) == NULL)
@@ -1437,11 +1453,12 @@ extension_set_sia(X509_EXTENSIONS **exts, PyObject *args, PyObject *kwds)
* single URI as an abbreviation for a collection containing one URI.
*/
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 4; i++) {
switch (i) {
case 0: pobj = &caRepository; nid = NID_caRepository; break;
case 1: pobj = &rpkiManifest; nid = NID_rpkiManifest; break;
case 2: pobj = &signedObject; nid = NID_signedObject; break;
+ case 3: pobj = &rpkiNotify; nid = NID_rpkiNotify; break;
}
if (*pobj == Py_None)
@@ -1461,7 +1478,8 @@ extension_set_sia(X509_EXTENSIONS **exts, PyObject *args, PyObject *kwds)
if ((a = ACCESS_DESCRIPTION_new()) == NULL ||
(a->method = OBJ_dup(oid)) == NULL ||
(a->location->d.uniformResourceIdentifier = ASN1_IA5STRING_new()) == NULL ||
- !ASN1_OCTET_STRING_set(a->location->d.uniformResourceIdentifier, (unsigned char *) uri, urilen))
+ !ASN1_OCTET_STRING_set(a->location->d.uniformResourceIdentifier,
+ (unsigned char *) uri, urilen))
lose_no_memory();
a->location->type = GEN_URI;
diff --git a/rp/rcynic/rcynic.c b/rp/rcynic/rcynic.c
index 8db15e55..c5b82266 100644
--- a/rp/rcynic/rcynic.c
+++ b/rp/rcynic/rcynic.c
@@ -83,6 +83,9 @@
#define SCHEME_RSYNC ("rsync://")
#define SIZEOF_RSYNC (sizeof(SCHEME_RSYNC) - 1)
+#define SCHEME_HTTP ("http://")
+#define SIZEOF_HTTP (sizeof(SCHEME_HTTP) - 1)
+
/**
* Maximum length of a hostname.
*/
@@ -410,7 +413,7 @@ DECLARE_STACK_OF(validation_status_t)
typedef struct certinfo {
int ca, ta;
object_generation_t generation;
- uri_t uri, sia, aia, crldp, manifest, signedobject;
+ uri_t uri, sia, aia, crldp, manifest, signedobject, rrdpnotify;
} certinfo_t;
typedef struct rcynic_ctx rcynic_ctx_t;
@@ -592,6 +595,10 @@ static int NID_ad_rpkiManifest;
static int NID_ad_signedObject;
#endif
+#ifndef NID_ad_rpkiNotify
+static int NID_ad_rpkiNotify;
+#endif
+
#ifndef NID_ct_ROA
static int NID_ct_ROA;
#endif
@@ -630,6 +637,10 @@ static const struct {
{&NID_ad_signedObject, "1.3.6.1.5.5.7.48.11", "id-ad-signedObject", "Signed Object"},
#endif
+#ifndef NID_ad_rpkiNotify
+ {&NID_ad_rpkiNotify, "1.3.6.1.5.5.7.48.13", "id-ad-rpkiNotify", "RPKI RRDP Notification"},
+#endif
+
#ifndef NID_ct_ROA
{&NID_ct_ROA, "1.2.840.113549.1.9.16.1.24", "id-ct-routeOriginAttestation", "ROA eContent"},
#endif
@@ -1043,6 +1054,14 @@ static int is_rsync(const char *uri)
}
/**
+ * Is string an http URI?
+ */
+static int is_http(const char *uri)
+{
+ return uri && !strncmp(uri, SCHEME_HTTP, SIZEOF_HTTP);
+}
+
+/**
* Convert an rsync URI to a filename, checking for evil character
* sequences. NB: This routine can't call mib_increment(), because
* mib_increment() calls it, so errors detected here only go into
@@ -3155,7 +3174,8 @@ static int extract_access_uri(rcynic_ctx_t *rc,
const AUTHORITY_INFO_ACCESS *xia,
const int nid,
uri_t *result,
- int *count)
+ int *count,
+ int (*relevant)(const char *))
{
int i;
@@ -3168,9 +3188,9 @@ static int extract_access_uri(rcynic_ctx_t *rc,
if (OBJ_obj2nid(a->method) != nid)
continue;
++*count;
- if (!is_rsync((char *) a->location->d.uniformResourceIdentifier->data))
- log_validation_status(rc, uri, non_rsync_uri_in_extension, generation);
- else if (sizeof(result->s) <= a->location->d.uniformResourceIdentifier->length)
+ if (!relevant((char *) a->location->d.uniformResourceIdentifier->data))
+ continue;
+ if (sizeof(result->s) <= a->location->d.uniformResourceIdentifier->length)
log_validation_status(rc, uri, uri_too_long, generation);
else if (result->s[0])
log_validation_status(rc, uri, multiple_rsync_uris_in_extension, generation);
@@ -3685,7 +3705,7 @@ static int check_x509(rcynic_ctx_t *rc,
int n_caIssuers = 0;
ex_count--;
if (!extract_access_uri(rc, uri, generation, aia, NID_ad_ca_issuers,
- &certinfo->aia, &n_caIssuers) ||
+ &certinfo->aia, &n_caIssuers, is_rsync) ||
!certinfo->aia.s[0] ||
sk_ACCESS_DESCRIPTION_num(aia) != n_caIssuers) {
log_validation_status(rc, uri, malformed_aia_extension, generation);
@@ -3715,18 +3735,21 @@ static int check_x509(rcynic_ctx_t *rc,
if ((sia = X509_get_ext_d2i(x, NID_sinfo_access, NULL, NULL)) != NULL) {
int got_caDirectory, got_rpkiManifest, got_signedObject;
- int n_caDirectory = 0, n_rpkiManifest = 0, n_signedObject = 0;
+ int n_caDirectory = 0, n_rpkiManifest = 0, n_signedObject = 0, n_rpkiNotify = 0;
ex_count--;
ok = (extract_access_uri(rc, uri, generation, sia, NID_caRepository,
- &certinfo->sia, &n_caDirectory) &&
+ &certinfo->sia, &n_caDirectory, is_rsync) &&
extract_access_uri(rc, uri, generation, sia, NID_ad_rpkiManifest,
- &certinfo->manifest, &n_rpkiManifest) &&
+ &certinfo->manifest, &n_rpkiManifest, is_rsync) &&
extract_access_uri(rc, uri, generation, sia, NID_ad_signedObject,
- &certinfo->signedobject, &n_signedObject));
+ &certinfo->signedobject, &n_signedObject, is_rsync) &&
+ extract_access_uri(rc, uri, generation, sia, NID_ad_rpkiNotify,
+ &certinfo->rrdpnotify, &n_rpkiNotify, is_http));
got_caDirectory = certinfo->sia.s[0] != '\0';
got_rpkiManifest = certinfo->manifest.s[0] != '\0';
got_signedObject = certinfo->signedobject.s[0] != '\0';
- ok &= sk_ACCESS_DESCRIPTION_num(sia) == n_caDirectory + n_rpkiManifest + n_signedObject;
+ ok &= (sk_ACCESS_DESCRIPTION_num(sia) ==
+ n_caDirectory + n_rpkiManifest + n_signedObject + n_rpkiNotify);
if (certinfo->ca)
ok &= got_caDirectory && got_rpkiManifest && !got_signedObject;
else if (rc->allow_ee_without_signedObject)
diff --git a/rp/utils/uri b/rp/utils/uri
index e72d5e0d..df6e710b 100755
--- a/rp/utils/uri
+++ b/rp/utils/uri
@@ -30,13 +30,19 @@ import rpki.POW
class Certificate(object):
@staticmethod
- def first_rsync(uris):
+ def first_whatever(uris, prefix):
if uris is not None:
for uri in uris:
- if uri.startswith("rsync://"):
+ if uri.startswith(prefix):
return uri
return None
+ def first_rsync(self, uris):
+ return self.first_whatever(uris, "rsync://")
+
+ def first_http(self, uris):
+ return self.first_whatever(uris, "http://")
+
def __init__(self, fn):
try:
x = rpki.POW.X509.derReadFile(fn)
@@ -47,13 +53,14 @@ class Certificate(object):
x = cms.certs()[0]
except:
raise ValueError
- sia = x.getSIA() or (None, None, None)
+ sia = x.getSIA() or (None, None, None, None)
self.fn = fn
self.uris = (
("AIA:caIssuers", self.first_rsync(x.getAIA())),
("SIA:caRepository", self.first_rsync(sia[0])),
("SIA:rpkiManifest", self.first_rsync(sia[1])),
("SIA:signedObject", self.first_rsync(sia[2])),
+ ("SIA:rpkiNotify", self.first_http(sia[3])),
("CRLDP", self.first_rsync(x.getCRLDP())))
def __str__(self):
diff --git a/rpki/oids.py b/rpki/oids.py
index 9fa30a04..afb95020 100644
--- a/rpki/oids.py
+++ b/rpki/oids.py
@@ -57,6 +57,7 @@ id_ad_caRepository = "1.3.6.1.5.5.7.48.5"
id_ad_signedObjectRepository = "1.3.6.1.5.5.7.48.9"
id_ad_rpkiManifest = "1.3.6.1.5.5.7.48.10"
id_ad_signedObject = "1.3.6.1.5.5.7.48.11"
+id_ad_rpkiNotify = "1.3.6.1.5.5.7.48.13"
commonName = "2.5.4.3"
serialNumber = "2.5.4.5"
countryName = "2.5.4.6"
diff --git a/rpki/pubdb/models.py b/rpki/pubdb/models.py
index 5241ea45..ce42c688 100644
--- a/rpki/pubdb/models.py
+++ b/rpki/pubdb/models.py
@@ -139,7 +139,7 @@ class Session(models.Model):
@property
def notification_fn(self):
- return "updates.xml"
+ return "notify.xml"
@staticmethod
diff --git a/rpki/publication.py b/rpki/publication.py
index ec2dabd4..524b5a53 100644
--- a/rpki/publication.py
+++ b/rpki/publication.py
@@ -50,6 +50,11 @@ tag_withdraw = rpki.relaxng.publication.xmlns + "withdraw"
tag_report_error = rpki.relaxng.publication.xmlns + "report_error"
+logger.warning("Horrible kludge: static RRDP URI for testing, this needs to be fixed")
+from socket import getfqdn
+rrdp_sia_uri_kludge = "http://%s/rrdp/notify.xml" % getfqdn()
+
+
def raise_if_error(pdu):
"""
Raise an appropriate error if this is a <report_error/> PDU.
diff --git a/rpki/rootd.py b/rpki/rootd.py
index 987d8356..8f08e0dd 100644
--- a/rpki/rootd.py
+++ b/rpki/rootd.py
@@ -189,7 +189,7 @@ class main(object):
keypair = self.rpki_root_key,
subject_key = manifest_keypair.get_public(),
serial = self.serial_number,
- sia = (None, None, self.rpki_root_manifest_uri),
+ sia = (None, None, self.rpki_root_manifest_uri, rpki.publication.rrdp_sia_uri_kludge),
aia = self.rpki_root_cert_uri,
crldp = self.rpki_root_crl_uri,
resources = manifest_resources,
diff --git a/rpki/rpkid.py b/rpki/rpkid.py
index 64157663..cc7fbc5b 100644
--- a/rpki/rpkid.py
+++ b/rpki/rpkid.py
@@ -1184,7 +1184,7 @@ class ca_detail_obj(rpki.sql.sql_persistent):
ca = self.ca,
resources = resources,
subject_key = self.manifest_public_key,
- sia = (None, None, self.manifest_uri))
+ sia = (None, None, self.manifest_uri, rpki.publication.rrdp_sia_uri_kludge))
def issue(self, ca, child, subject_key, sia, resources, publisher, child_cert = None):
"""
@@ -1948,7 +1948,7 @@ class roa_obj(rpki.sql.sql_persistent):
ca = ca,
resources = resources,
subject_key = keypair.get_public(),
- sia = (None, None, self.uri_from_key(keypair)))
+ sia = (None, None, self.uri_from_key(keypair), rpki.publication.rrdp_sia_uri_kludge))
self.roa = rpki.x509.ROA.build(self.asn, self.ipv4, self.ipv6, keypair, (self.cert,))
self.published = rpki.sundial.now()
self.sql_store()
@@ -2158,7 +2158,7 @@ class ghostbuster_obj(rpki.sql.sql_persistent):
ca = ca,
resources = resources,
subject_key = keypair.get_public(),
- sia = (None, None, self.uri_from_key(keypair)))
+ sia = (None, None, self.uri_from_key(keypair), rpki.publication.rrdp_sia_uri_kludge))
self.ghostbuster = rpki.x509.Ghostbuster.build(self.vcard, keypair, (self.cert,))
self.published = rpki.sundial.now()
self.sql_store()
diff --git a/rpki/x509.py b/rpki/x509.py
index 89b598d4..9bc34e19 100644
--- a/rpki/x509.py
+++ b/rpki/x509.py
@@ -784,11 +784,12 @@ class X509(DER_object):
assert sia is not None or not is_ca
if sia is not None:
- caRepository, rpkiManifest, signedObject = sia
+ caRepository, rpkiManifest, signedObject, rpkiNotify = sia
cert.setSIA(
(caRepository,) if isinstance(caRepository, str) else caRepository,
(rpkiManifest,) if isinstance(rpkiManifest, str) else rpkiManifest,
- (signedObject,) if isinstance(signedObject, str) else signedObject)
+ (signedObject,) if isinstance(signedObject, str) else signedObject,
+ (rpkiNotify,) if isinstance(rpkiNotify, str) else rpkiNotify)
if resources is not None:
cert.setRFC3779(
@@ -1045,7 +1046,7 @@ class PKCS10(DER_object):
if sias is None:
raise rpki.exceptions.BadPKCS10("PKCS #10 CA SIA missing")
- caRepository, rpkiManifest, signedObject = sias
+ caRepository, rpkiManifest, signedObject, rpkiNotify = sias
if signedObject:
raise rpki.exceptions.BadPKCS10("PKCS #10 CA SIA must not have id-ad-signedObject")
@@ -1095,7 +1096,7 @@ class PKCS10(DER_object):
bc = self.get_POW().getBasicConstraints()
sia = self.get_POW().getSIA()
- caRepository, rpkiManifest, signedObject = sia or (None, None, None)
+ caRepository, rpkiManifest, signedObject, rpkiNotify = sia or (None, None, None, None)
if alg not in (rpki.oids.sha256WithRSAEncryption, rpki.oids.ecdsa_with_SHA256):
raise rpki.exceptions.BadPKCS10("PKCS #10 has bad signature algorithm for EE: %s" % alg)
@@ -1149,7 +1150,7 @@ class PKCS10(DER_object):
@classmethod
def create(cls, keypair, exts = None, is_ca = False,
caRepository = None, rpkiManifest = None, signedObject = None,
- cn = None, sn = None, eku = None):
+ cn = None, sn = None, eku = None, rpkiNotify = None):
"""
Create a new request for a given keypair.
"""
@@ -1168,6 +1169,9 @@ class PKCS10(DER_object):
if isinstance(signedObject, str):
signedObject = (signedObject,)
+ if isinstance(rpkiNotify, str):
+ rpkiNotify = (rpkiNotify,)
+
req = rpki.POW.PKCS10()
req.setVersion(0)
req.setSubject(X501DN.from_cn(cn, sn).get_POW())
@@ -1177,8 +1181,8 @@ class PKCS10(DER_object):
req.setBasicConstraints(True, None)
req.setKeyUsage(cls.expected_ca_keyUsage)
- if caRepository or rpkiManifest or signedObject:
- req.setSIA(caRepository, rpkiManifest, signedObject)
+ if caRepository or rpkiManifest or signedObject or rpkiNotify:
+ req.setSIA(caRepository, rpkiManifest, signedObject, rpkiNotify)
if eku:
req.setEKU(eku)