aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rpkid/ext/POW.c261
1 files changed, 256 insertions, 5 deletions
diff --git a/rpkid/ext/POW.c b/rpkid/ext/POW.c
index 80e2b517..3ed40917 100644
--- a/rpkid/ext/POW.c
+++ b/rpkid/ext/POW.c
@@ -180,7 +180,41 @@ static char pow_module__doc__ [] =
"obsolete due to recent or impending API changes. Once the new API is\n" \
"stable, this documentation should be rewritten to provide such examples.\n"
+/*
+ * Handle NIDs we wish OpenSSL knew about. This is carefully (we
+ * hope) written to do nothing at all for any NID that OpenSSL knows
+ * about; the intent is just to add definitions for things OpenSSL
+ * doesn't know about yet. Of necessity, this is a bit gross, since
+ * it confounds runtime static variables with predefined macro names,
+ * but we try to put all the magic associated with this in one place.
+ */
+
+#ifndef NID_rpkiManifest
+static int NID_rpkiManifest;
+#endif
+
+#ifndef NID_signedObject
+static int NID_signedObject;
+#endif
+
+static const struct {
+ int *nid;
+ const char *oid;
+ const char *name;
+} missing_nids[] = {
+
+#ifndef NID_rpkiManifest
+ {&NID_rpkiManifest, "1.3.6.1.5.5.7.48.10", "id-ad-rpkiManifest"},
+#endif
+
+#ifndef NID_signedObject
+ {&NID_signedObject, "1.3.6.1.5.5.7.48.9", "id-ad-signedObjectRepository"}
+#endif
+
+};
+
/*========== Pre-definitions ==========*/
+
static PyObject
*ErrorObject,
*OpenSSLErrorObject,
@@ -736,6 +770,25 @@ Python_Long_to_ASN1_INTEGER(PyObject *arg)
return NULL;
}
+/*
+ * Handle missing NIDs.
+ */
+
+static int
+create_missing_nids(void)
+{
+ int i;
+
+ for (i = 0; i < sizeof(missing_nids) / sizeof(*missing_nids); i++)
+ if ((*missing_nids[i].nid = OBJ_txt2nid(missing_nids[i].oid)) == NID_undef &&
+ (*missing_nids[i].nid = OBJ_create(missing_nids[i].oid,
+ missing_nids[i].name,
+ missing_nids[i].name)) == NID_undef)
+ return 0;
+
+ return 1;
+}
+
/*========== helper functions ==========*/
/*========== IPAddress code ==========*/
@@ -1831,7 +1884,7 @@ static char x509_object_get_key_usage__doc__[] =
;
static PyObject *
-x509_object_get_key_usage(x509_object *self, PyObject *args)
+x509_object_get_key_usage(x509_object *self)
{
extern X509V3_EXT_METHOD v3_key_usage;
BIT_STRING_BITNAME *bit_name;
@@ -2279,14 +2332,18 @@ static PyObject *
x509_object_get_basic_constraints(x509_object *self)
{
BASIC_CONSTRAINTS *ext = NULL;
+ PyObject *result;
if ((ext = X509_get_ext_d2i(self->x509, NID_basic_constraints, NULL, NULL)) == NULL)
Py_RETURN_NONE;
if (ext->pathlen == NULL)
- return Py_BuildValue("(NO)", PyBool_FromLong(ext->ca), Py_None);
+ result = Py_BuildValue("(NO)", PyBool_FromLong(ext->ca), Py_None);
else
- return Py_BuildValue("(Nl)", PyBool_FromLong(ext->ca), ASN1_INTEGER_get(ext->pathlen));
+ result = Py_BuildValue("(Nl)", PyBool_FromLong(ext->ca), ASN1_INTEGER_get(ext->pathlen));
+
+ BASIC_CONSTRAINTS_free(ext);
+ return result;
}
static char x509_object_set_basic_constraints__doc__[] =
@@ -2345,7 +2402,196 @@ x509_object_set_basic_constraints(x509_object *self, PyObject *args)
return NULL;
}
-#warning Need SIA handlers
+static char x509_object_get_sia__doc__[] =
+ "Get SIA values for this certificate. If the certificate\n"
+ "has no BasicConstraints extension, this method returns None.\n"
+ "Otherwise, it returns a tuple containing three sequences:\n"
+ "caRepository URIs, rpkiManifest URIs, and signedObject URIs.\n"
+ "Any other accessMethods are ignored, as are any non-URI\n"
+ "accessLocations.\n"
+ ;
+
+static PyObject *
+x509_object_get_sia(x509_object *self)
+{
+ AUTHORITY_INFO_ACCESS *ext = NULL;
+ PyObject *result = NULL;
+ PyObject *result_caRepository = NULL;
+ PyObject *result_rpkiManifest = NULL;
+ PyObject *result_signedObject = NULL;
+ int n_caRepository = 0;
+ int n_rpkiManifest = 0;
+ int n_signedObject = 0;
+ const char *uri;
+ PyObject *obj;
+ int i, nid;
+
+ if ((ext = X509_get_ext_d2i(self->x509, NID_sinfo_access, NULL, NULL)) == NULL)
+ Py_RETURN_NONE;
+
+ /*
+ * Easiest to do this in two passes, first pass just counts URIs.
+ */
+
+ for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ext); i++) {
+ ACCESS_DESCRIPTION *a = sk_ACCESS_DESCRIPTION_value(ext, i);
+ if (a->location->type != GEN_URI)
+ continue;
+ nid = OBJ_obj2nid(a->method);
+ if (nid == NID_caRepository) {
+ n_caRepository++;
+ continue;
+ }
+ if (nid == NID_rpkiManifest) {
+ n_rpkiManifest++;
+ continue;
+ }
+ if (nid == NID_signedObject) {
+ n_signedObject++;
+ continue;
+ }
+ }
+
+ if (((result_caRepository = PyTuple_New(n_caRepository)) == NULL) ||
+ ((result_rpkiManifest = PyTuple_New(n_rpkiManifest)) == NULL) ||
+ ((result_signedObject = PyTuple_New(n_signedObject)) == NULL))
+ goto error;
+
+ n_caRepository = n_rpkiManifest = n_signedObject = 0;
+
+ for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ext); i++) {
+ ACCESS_DESCRIPTION *a = sk_ACCESS_DESCRIPTION_value(ext, i);
+ if (a->location->type != GEN_URI)
+ continue;
+ nid = OBJ_obj2nid(a->method);
+ uri = ASN1_STRING_data(a->location->d.uniformResourceIdentifier);
+ if (nid == NID_caRepository) {
+ if ((obj = PyString_FromString(uri)) == NULL)
+ goto error;
+ PyTuple_SET_ITEM(result_caRepository, n_caRepository++, obj);
+ continue;
+ }
+ if (nid == NID_rpkiManifest) {
+ if ((obj = PyString_FromString(uri)) == NULL)
+ goto error;
+ PyTuple_SET_ITEM(result_rpkiManifest, n_rpkiManifest++, obj);
+ continue;
+ }
+ if (nid == NID_signedObject) {
+ if ((obj = PyString_FromString(uri)) == NULL)
+ goto error;
+ PyTuple_SET_ITEM(result_signedObject, n_signedObject++, obj);
+ continue;
+ }
+ }
+
+ result = Py_BuildValue("(OOO)",
+ result_caRepository,
+ result_rpkiManifest,
+ result_signedObject);
+
+ error:
+ AUTHORITY_INFO_ACCESS_free(ext);
+ Py_XDECREF(result_caRepository);
+ Py_XDECREF(result_rpkiManifest);
+ Py_XDECREF(result_signedObject);
+ return result;
+}
+
+static char x509_object_set_sia__doc__[] =
+ "Set SIA values for this certificate. Takes three arguments:\n"
+ "caRepository URIs, rpkiManifest URIs, and signedObject URIs.\n"
+ "Each of these should be an iterable which returns URIs.\n"
+ "None is acceptable as an alternate way of specifying an empty\n"
+ "sequence of URIs for a particular argument.\n"
+ ;
+
+static PyObject *
+x509_object_set_sia(x509_object *self, PyObject *args)
+{
+ AUTHORITY_INFO_ACCESS *ext = NULL;
+ PyObject *caRepository = NULL;
+ PyObject *rpkiManifest = NULL;
+ PyObject *signedObject = NULL;
+ PyObject *iterator = NULL;
+ ASN1_OBJECT *oid = NULL;
+ PyObject **pobj = NULL;
+ PyObject *item = NULL;
+ ACCESS_DESCRIPTION *a;
+ int i, nid, ok = 0;
+ size_t urilen;
+ char *uri;
+
+ if (!PyArg_ParseTuple(args, "OOO", &caRepository, &rpkiManifest, &signedObject))
+ goto error;
+
+ if ((ext = AUTHORITY_INFO_ACCESS_new()) == NULL)
+ lose_no_memory();
+
+ /*
+ * This is going to want refactoring, because it's ugly, because we
+ * want to reuse code for AIA, and because it'd be nice to support a
+ * single URI as an abbreviation for a sequence containing one URI.
+ */
+
+ for (i = 0; i < 3; 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;
+ }
+
+ if (*pobj == Py_None)
+ continue;
+
+ if ((oid = OBJ_nid2obj(nid)) == NULL)
+ lose_openssl_error("Couldn't find SIA accessMethod OID");
+
+ if ((iterator = PyObject_GetIter(*pobj)) == NULL)
+ goto error;
+
+ while ((item = PyIter_Next(iterator)) != NULL) {
+
+ if (PyString_AsStringAndSize(item, &uri, &urilen) < 0)
+ goto error;
+
+ 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, uri, urilen))
+ lose_no_memory();
+
+ a->location->type = GEN_URI;
+
+ if (!sk_ACCESS_DESCRIPTION_push(ext, a))
+ lose_no_memory();
+
+ a = NULL;
+ Py_XDECREF(item);
+ item = NULL;
+ }
+
+ Py_XDECREF(iterator);
+ iterator = NULL;
+ }
+
+ if (!X509_add1_ext_i2d(self->x509, NID_sinfo_access, ext, 0, X509V3_ADD_REPLACE))
+ lose_openssl_error("Couldn't add SIA extension to certificate");
+
+ ok = 1;
+
+ error:
+ AUTHORITY_INFO_ACCESS_free(ext);
+ ACCESS_DESCRIPTION_free(a);
+ Py_XDECREF(item);
+ Py_XDECREF(iterator);
+
+ if (ok)
+ Py_RETURN_NONE;
+ else
+ return NULL;
+}
+
#warning Need AIA handlers
#warning Need CRLDP handlers
#warning Need Certificate Policies handlers
@@ -2406,6 +2652,8 @@ static struct PyMethodDef x509_object_methods[] = {
Define_Method(setRFC3779, x509_object_set_rfc3779, METH_KEYWORDS),
Define_Method(getBasicConstraints, x509_object_get_basic_constraints, METH_NOARGS),
Define_Method(setBasicConstraints, x509_object_set_basic_constraints, METH_VARARGS),
+ Define_Method(getSIA, x509_object_get_sia, METH_NOARGS),
+ Define_Method(setSIA, x509_object_set_sia, METH_VARARGS),
{NULL}
};
@@ -4933,6 +5181,7 @@ void
init_POW(void)
{
PyObject *m = Py_InitModule3("_POW", pow_module_methods, pow_module__doc__);
+ int OpenSSL_ok = 1;
#define Define_Class(__type__) \
do { \
@@ -5033,7 +5282,9 @@ init_POW(void)
OpenSSL_add_all_algorithms();
ERR_load_crypto_strings();
- if (PyErr_Occurred())
+ OpenSSL_ok &= create_missing_nids();
+
+ if (PyErr_Occurred() || !OpenSSL_ok)
Py_FatalError("Can't initialize module POW");
}