]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Add certificate extensions to --mode=print
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Thu, 25 Apr 2024 00:00:58 +0000 (18:00 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Sat, 27 Apr 2024 00:44:41 +0000 (18:44 -0600)
Hmm. I think this bumps the minimum required LibreSSL to v3.5.0.

Progress for #122.

src/Makefile.am
src/asn1/asn1c/Certificate.c
src/extension.c
src/extension.h
src/libcrypto_util.c [new file with mode: 0644]
src/libcrypto_util.h [new file with mode: 0644]

index 8fb6b427f382ec5b756ced70a0489d0aaa289bfe..a6d44c5432795dba4bb5394294a8fa30c9377177 100644 (file)
@@ -19,6 +19,7 @@ fort_SOURCES += file.h file.c
 fort_SOURCES += init.h init.c
 fort_SOURCES += json_util.c json_util.h
 fort_SOURCES += line_file.h line_file.c
+fort_SOURCES += libcrypto_util.h libcrypto_util.c
 fort_SOURCES += log.h log.c
 fort_SOURCES += nid.h nid.c
 fort_SOURCES += output_printer.h output_printer.c
index 42158543e318b1c066cf91df27d00c8a22c5053a..8b4fbbe46de3467c4a4223e4d16b5b0f8f165848 100644 (file)
@@ -3,106 +3,8 @@
 #include <openssl/x509v3.h>
 #include <openssl/pem.h>
 #include "alloc.h"
-
-/* Swallows @bio. */
-static json_t *
-bio2json(BIO *bio)
-{
-       BUF_MEM *buffer;
-       json_t *json;
-
-       json = (BIO_get_mem_ptr(bio, &buffer) > 0)
-           ? json_stringn(buffer->data, buffer->length)
-           : NULL;
-
-       BIO_free_all(bio);
-       return json;
-}
-
-/* Swallows @bio. */
-static char *
-bio2str(BIO *bio)
-{
-       BUF_MEM *buffer;
-       char *str;
-
-       str = (BIO_get_mem_ptr(bio, &buffer) > 0)
-           ? pstrndup(buffer->data, buffer->length)
-           : NULL;
-
-       BIO_free_all(bio);
-       return str;
-}
-
-static json_t *
-asn1int2json(ASN1_INTEGER const *asn1int)
-{
-       BIGNUM *bignum;
-       char *str;
-       json_t *json;
-
-       if (asn1int == NULL)
-               return NULL;
-
-       bignum = ASN1_INTEGER_to_BN(asn1int, NULL);
-       str = BN_bn2hex(bignum);
-
-       json = json_string(str);
-
-       OPENSSL_free(str);
-       BN_free(bignum);
-
-       return json;
-}
-
-static json_t *
-name2json(X509_NAME const *name)
-{
-       json_t *root;
-       json_t *child;
-       int i;
-
-       root = json_object();
-       if (root == NULL)
-               return NULL;
-
-       for (i = 0; i < X509_NAME_entry_count(name); i++) {
-               X509_NAME_ENTRY *entry;
-               int nid;
-               const ASN1_STRING *data;
-
-               entry = X509_NAME_get_entry(name, i);
-               nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry));
-
-               data = X509_NAME_ENTRY_get_data(entry);
-               if (data == NULL)
-                       goto fail;
-               child = json_stringn((char *)data->data, data->length);
-
-               if (json_object_set_new(root, OBJ_nid2ln(nid), child) < 0)
-                       goto fail;
-       }
-
-       return root;
-
-fail:  json_decref(root);
-       return NULL;
-}
-
-static json_t *
-asn1time2json(ASN1_TIME const *time)
-{
-       BIO *bio = BIO_new(BIO_s_mem());
-       if (bio == NULL)
-               return NULL;
-
-       if (!ASN1_TIME_print_ex(bio, time, ASN1_DTFLGS_ISO8601)) {
-               BIO_free_all(bio);
-               return NULL;
-       }
-
-       return bio2json(bio);
-}
+#include "extension.h"
+#include "libcrypto_util.h"
 
 static json_t *
 validity2json(X509 *x)
@@ -170,47 +72,72 @@ fail:      json_decref(root);
 }
 
 static json_t *
-bitstr2json(ASN1_BIT_STRING const *bitstr)
+iuid2json(X509 const *x)
 {
-       BIO *bio;
-       unsigned char *data;
-       int length;
-       int i;
+       const ASN1_BIT_STRING *iuid;
+       X509_get0_uids(x, &iuid, NULL);
+       return asn1str2json(iuid);
+}
 
-       if (bitstr == NULL)
-               return json_null();
+static json_t *
+suid2json(X509 const *x)
+{
+       const ASN1_BIT_STRING *suid;
+       X509_get0_uids(x, NULL, &suid);
+       return asn1str2json(suid);
+}
 
-       bio = BIO_new(BIO_s_mem());
-       if (bio == NULL)
-               return NULL;
+static json_t *
+ext2json_known(struct extension_metadata const *meta, X509_EXTENSION *ext)
+{
+       void *decoded;
+       json_t *json;
 
-       data = bitstr->data;
-       length = bitstr->length;
+       decoded = X509V3_EXT_d2i(ext);
+       if (decoded == NULL)
+               return NULL;
 
-       for (i = 0; i < length; i++) {
-               if (BIO_printf(bio, "%02x", data[i]) <= 0) {
-                       BIO_free_all(bio);
-                       return NULL;
-               }
-       }
+       json = meta->to_json(decoded);
 
-       return bio2json(bio);
+       meta->destructor(decoded);
+       return json;
 }
 
 static json_t *
-iuid2json(X509 const *x)
+ext2json_unknown(X509_EXTENSION *ext)
 {
-       const ASN1_BIT_STRING *iuid;
-       X509_get0_uids(x, &iuid, NULL);
-       return bitstr2json(iuid);
+       BIO *bio = BIO_new(BIO_s_mem());
+       if (bio == NULL)
+               return NULL;
+
+       /* TODO Those flags are kinda interesting */
+       if (!X509V3_EXT_print(bio, ext, 0, 0)) {
+               BIO_free_all(bio);
+               return NULL;
+       }
+
+       return bio2json(bio);
 }
 
 static json_t *
-suid2json(X509 const *x)
+ext2json(X509_EXTENSION *ext)
 {
-       const ASN1_BIT_STRING *suid;
-       X509_get0_uids(x, NULL, &suid);
-       return bitstr2json(suid);
+       struct extension_metadata const **array, *meta;
+       int nid;
+
+       array = ext_metadatas();
+       nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext));
+
+       for (meta = *array; meta != NULL; array++, meta = *array) {
+               if (meta->nid == nid) {
+                       if (meta->to_json != NULL)
+                               return ext2json_known(meta, ext);
+                       else
+                               break;
+               }
+       }
+
+       return ext2json_unknown(ext);
 }
 
 static json_t *
@@ -254,17 +181,8 @@ exts2json(const STACK_OF(X509_EXTENSION) *exts)
                /* Child 1: Critical */
                if (json_object_set_new(node, "critical", X509_EXTENSION_get_critical(ex) ? json_true() : json_false()) < 0)
                        goto fail;
-
                /* Child 2: Value */
-               bio = BIO_new(BIO_s_mem());
-               if (bio == NULL)
-                       goto fail;
-               /* TODO Those flags are kinda interesting */
-               if (!X509V3_EXT_print(bio, ex, 0, 0)) {
-                       BIO_free_all(bio);
-                       goto fail;
-               }
-               if (json_object_set_new(node, "value", bio2json(bio)) < 0)
+               if (json_object_set_new(node, "value", ext2json(ex)))
                        goto fail;
        }
 
@@ -287,7 +205,7 @@ tbsCert2json(X509 *x)
                goto fail;
        if (json_object_set_new(tbsCert, "serialNumber", asn1int2json(X509_get0_serialNumber(x))) < 0)
                goto fail;
-       if (json_object_set_new(tbsCert, "signature", json_string(OBJ_nid2ln(X509_get_signature_nid(x)))) < 0)
+       if (json_object_set_new(tbsCert, "signature", json_string(OBJ_nid2sn(X509_get_signature_nid(x)))) < 0)
                goto fail;
        if (json_object_set_new(tbsCert, "issuer", name2json(X509_get_issuer_name(x))) < 0)
                goto fail;
@@ -320,7 +238,7 @@ sigAlgorithm2json(X509 *cert)
        X509_get0_signature(NULL, &palg, cert);
        X509_ALGOR_get0(&paobj, NULL, NULL, palg);
 
-       return json_string(OBJ_nid2ln(OBJ_obj2nid(paobj)));
+       return oid2json(paobj);
 }
 
 static json_t *
@@ -328,7 +246,7 @@ sigValue2json(X509 *cert)
 {
        const ASN1_BIT_STRING *signature;
        X509_get0_signature(&signature, NULL, cert);
-       return bitstr2json(signature);
+       return asn1str2json(signature);
 }
 
 static json_t *
@@ -359,6 +277,7 @@ Certificate_encode_json(ANY_t *ber)
 {
        const unsigned char *tmp;
        X509 *cert;
+       json_t *root;
 
        /*
         * "If the call is successful *in is incremented to the byte following
@@ -372,7 +291,7 @@ Certificate_encode_json(ANY_t *ber)
        if (cert == NULL)
                return NULL;
 
-       json_t *root = x509_to_json(cert);
+       root = x509_to_json(cert);
        if (root == NULL)
                goto fail;
 
index 11d3e3c32b7b8239acbaee1fda9fc5b336ea7ea7..b0657abd4ee27e41ecad7deb22665c390bae00eb 100644 (file)
 #include <openssl/x509v3.h>
 #include "cert_stack.h"
 #include "common.h"
+#include "libcrypto_util.h"
 #include "log.h"
 #include "nid.h"
 #include "thread_var.h"
 #include "crypto/hash.h"
 
-static struct extension_metadata IR2 = {
-       "Amended IP Resources",
-       -1,
+static json_t *
+unimplemented(void const *arg)
+{
+       return arg ? json_string("<Not implemented for now>") : json_null();
+}
+
+static json_t *
+bc2json(void const *ext)
+{
+       BASIC_CONSTRAINTS const *bc = ext;
+       json_t *root;
+
+       root = json_object();
+       if (root == NULL)
+               return NULL;
+
+       if (json_object_set_new(root, "cA", json_boolean(bc->ca)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "pathLenConstraint", asn1int2json(bc->pathlen)) < 0)
+               goto fail;
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
+}
+
+static void
+bc_destroy(void *bc)
+{
+       BASIC_CONSTRAINTS_free(bc);
+}
+
+static const struct extension_metadata BC = {
+       "Basic Constraints",
+       NID_basic_constraints,
        true,
+       bc2json,
+       bc_destroy,
 };
 
-static struct extension_metadata AR2 = {
-       "Amended AS Resources",
-       -1,
+static json_t *
+ski2json(void const *ext)
+{
+       return asn1str2json(ext);
+}
+
+static void
+ski_destroy(void *ski)
+{
+       ASN1_OCTET_STRING_free(ski);
+}
+
+static const struct extension_metadata SKI = {
+       "Subject Key Identifier",
+       NID_subject_key_identifier,
+       false,
+       ski2json,
+       ski_destroy,
+};
+
+static json_t *
+aki2json(void const *ext)
+{
+       AUTHORITY_KEYID const *aki = ext;
+       json_t *root;
+
+       root = json_object();
+       if (root == NULL)
+               return NULL;
+
+       if (json_object_set_new(root, "keyIdentifier", asn1str2json(aki->keyid)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "authorityCertIssuer", unimplemented(aki->issuer)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "authorityCertSerialNumber", asn1int2json(aki->serial)) < 0)
+               goto fail;
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
+}
+
+static void
+aki_destroy(void *aki)
+{
+       AUTHORITY_KEYID_free(aki);
+}
+
+static const struct extension_metadata AKI = {
+       "Authority Key Identifier",
+       NID_authority_key_identifier,
+       false,
+       aki2json,
+       aki_destroy,
+};
+
+static json_t *
+ku2json(void const *ext)
+{
+       ASN1_BIT_STRING const *ku = ext;
+       unsigned char data[2];
+       json_t *root;
+
+       if (ku->length < 1 || 2 < ku->length)
+               return NULL;
+       memset(data, 0, sizeof(data));
+       memcpy(data, ku->data, ku->length);
+
+       root = json_object();
+       if (root == NULL)
+               return NULL;
+
+       if (json_object_set_new(root, "digitalSignature", json_boolean(ku->data[0] & 0x80u)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "contentCommitment", json_boolean(ku->data[0] & 0x40u)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "keyEncipherment", json_boolean(ku->data[0] & 0x20u)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "dataEncipherment", json_boolean(ku->data[0] & 0x10u)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "keyAgreement", json_boolean(ku->data[0] & 0x08u)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "keyCertSign", json_boolean(ku->data[0] & 0x04u)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "cRLSign", json_boolean(ku->data[0] & 0x02u)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "encipherOnly", json_boolean(ku->data[0] & 0x01u)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "decipherOnly", json_boolean(ku->data[1] & 0x80u)) < 0)
+               goto fail;
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
+}
+
+static void
+ku_destroy(void *ku)
+{
+       ASN1_BIT_STRING_free(ku);
+}
+
+static const struct extension_metadata KU = {
+       "Key Usage",
+       NID_key_usage,
        true,
+       ku2json,
+       ku_destroy,
 };
 
-int extension_init(void)
+static json_t *
+dpname2json(DIST_POINT_NAME const *dpn)
 {
-       IR2.nid = nid_ipAddrBlocksv2();
-       AR2.nid = nid_autonomousSysIdsv2();
-       return 0;
+       if (dpn == NULL)
+               return json_null();
+       if (dpn->type) /* if relativename */
+               return name2json(dpn->dpname);
+       return gns2json(dpn->name.fullname);
 }
 
-struct extension_metadata const *ext_bc(void)
+static json_t *
+cdp2json(void const *ext)
 {
-       static const struct extension_metadata BC = {
-               "Basic Constraints",
-               NID_basic_constraints,
-               true,
-       };
-       return &BC;
+       STACK_OF(DIST_POINT) const *crldp = ext;
+       json_t *root, *child;
+       DIST_POINT *dp;
+       int d;
+
+       root = json_array();
+       if (root == NULL)
+               return NULL;
+
+       for (d = 0; d < sk_DIST_POINT_num(crldp); d++) {
+               dp = sk_DIST_POINT_value(crldp, 0);
+               if (json_array_append_new(root, child = json_object()) < 0)
+                       goto fail;
+               if (json_object_set_new(child, "distributionPoint", dpname2json(dp->distpoint)) < 0)
+                       goto fail;
+               if (json_object_set_new(child, "reasons", unimplemented(dp->reasons)) < 0)
+                       goto fail;
+               if (json_object_set_new(child, "cRLIssuer", gns2json(dp->CRLissuer)) < 0)
+                       goto fail;
+       }
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
 }
 
-struct extension_metadata const *ext_ski(void)
+static void
+cdp_destroy(void *crldp)
 {
-       static const struct extension_metadata SKI = {
-               "Subject Key Identifier",
-               NID_subject_key_identifier,
-               false,
-       };
-       return &SKI;
+       sk_DIST_POINT_pop_free(crldp, DIST_POINT_free);
 }
 
-struct extension_metadata const *ext_aki(void)
+static const struct extension_metadata CDP = {
+       "CRL Distribution Points",
+       NID_crl_distribution_points,
+       false,
+       cdp2json,
+       cdp_destroy,
+};
+
+static json_t *
+aia2json(void const *ext)
 {
-       static const struct extension_metadata AKI = {
-               "Authority Key Identifier",
-               NID_authority_key_identifier,
-               false,
-       };
-       return &AKI;
+       AUTHORITY_INFO_ACCESS const *ia = ext;
+       ACCESS_DESCRIPTION *ad;
+       json_t *root, *child;
+       int i;
+
+       root = json_array();
+       if (root == NULL)
+               return NULL;
+
+       for (i = 0; i < sk_ACCESS_DESCRIPTION_num(ia); i++) {
+               ad = sk_ACCESS_DESCRIPTION_value(ia, i);
+               if (json_array_append_new(root, child = json_object()) < 0)
+                       goto fail;
+               if (json_object_set_new(child, "accessMethod", oid2json(ad->method)) < 0)
+                       goto fail;
+               if (json_object_set_new(child, "accessLocation", gn2json(ad->location)) < 0)
+                       goto fail;
+       }
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
 }
 
-struct extension_metadata const *ext_ku(void)
+static void
+aia_destroy(void *aia)
 {
-       static const struct extension_metadata KU = {
-               "Key Usage",
-               NID_key_usage,
-               true,
-       };
-       return &KU;
+       AUTHORITY_INFO_ACCESS_free(aia);
 }
 
-struct extension_metadata const *ext_cdp(void)
+static const struct extension_metadata AIA = {
+       "Authority Information Access",
+       NID_info_access,
+       false,
+       aia2json,
+       aia_destroy,
+};
+
+static const struct extension_metadata SIA = {
+       "Subject Information Access",
+       NID_sinfo_access ,
+       false,
+       aia2json,
+       aia_destroy,
+};
+
+static json_t *
+pq2json(POLICYQUALINFO const *pqi)
 {
-       static const struct extension_metadata CDP = {
-               "CRL Distribution Points",
-               NID_crl_distribution_points,
-               false,
-       };
-       return &CDP;
+       json_t *root;
+
+       if (pqi == NULL)
+               return json_null();
+
+       root = json_object();
+       if (root == NULL)
+               return NULL;
+
+       if (json_object_set_new(root, "policyQualifierId", oid2json(pqi->pqualid)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "qualifier", unimplemented(&pqi->d)) < 0)
+               goto fail;
+
+       return NULL;
+
+fail:  json_decref(root);
+       return NULL;
 }
 
-struct extension_metadata const *ext_aia(void)
+static json_t *
+pqs2json(STACK_OF(POLICYQUALINFO) const *pqs)
 {
-       static const struct extension_metadata AIA = {
-               "Authority Information Access",
-               NID_info_access,
-               false,
-       };
-       return &AIA;
+       json_t *root;
+       int i;
+
+       if (pqs == NULL)
+               return json_null();
+
+       root = json_array();
+       if (root == NULL)
+               return NULL;
+
+       for (i = 0; i < sk_POLICYQUALINFO_num(pqs); i++)
+               if (json_array_append_new(root, pq2json(sk_POLICYQUALINFO_value(pqs, i))) < 0)
+                       goto fail;
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
 }
 
-struct extension_metadata const *ext_sia(void)
+static json_t *
+pi2json(POLICYINFO const *pi)
 {
-       static const struct extension_metadata SIA = {
-               "Subject Information Access",
-               NID_sinfo_access ,
-               false,
-       };
-       return &SIA;
+       json_t *root;
+
+       if (pi == NULL)
+               return json_null();
+
+       root = json_object();
+       if (root == NULL)
+               return NULL;
+
+       if (json_object_set_new(root, "policyIdentifier", oid2json(pi->policyid)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "policyQualifiers", pqs2json(pi->qualifiers)) < 0)
+               goto fail;
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
 }
 
-struct extension_metadata const *ext_cp(void)
+static json_t *
+cp2json(void const *ext)
 {
-       static const struct extension_metadata CP = {
-               "Certificate Policies",
-               NID_certificate_policies,
-               true,
-       };
-       return &CP;
+       CERTIFICATEPOLICIES const *cp = ext;
+       json_t *root;
+       int i;
+
+       root = json_array();
+       if (root == NULL)
+               return NULL;
+
+       for (i = 0; i < sk_POLICYINFO_num(cp); i++)
+               if (json_array_append_new(root, pi2json(sk_POLICYINFO_value(cp, i))) < 0)
+                       goto fail;
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
 }
 
-struct extension_metadata const *ext_ir(void)
+static void
+cp_destroy(void *cp)
 {
-       static const struct extension_metadata IR = {
-               "IP Resources",
-               NID_sbgp_ipAddrBlock,
-               true,
-       };
-       return &IR;
+       CERTIFICATEPOLICIES_free(cp);
 }
 
-struct extension_metadata const *ext_ar(void)
+static const struct extension_metadata CP = {
+       "Certificate Policies",
+       NID_certificate_policies,
+       true,
+       cp2json,
+       cp_destroy,
+};
+
+static json_t *
+p2json(ASN1_BIT_STRING const *ap, int af)
 {
-       static const struct extension_metadata AR = {
-               "AS Resources",
-               NID_sbgp_autonomousSysNum,
-               true,
-       };
-       return &AR;
+       unsigned char bin[16];
+       char str[INET6_ADDRSTRLEN];
+       unsigned int length;
+       json_t *root;
+
+       if (ap == NULL)
+               return json_null();
+
+       memset(bin, 0, sizeof(bin));
+       memcpy(bin, ap->data, ap->length);
+       if (inet_ntop(af, bin, str, INET6_ADDRSTRLEN) == NULL)
+               return NULL;
+
+       length = 8 * ap->length;
+       if (ap->flags & ASN1_STRING_FLAG_BITS_LEFT)
+               length -= ap->flags & 7;
+
+       root = json_object();
+       if (root == NULL)
+               return NULL;
+       if (json_object_set_new(root, "address", json_string(str)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "length", json_integer(length)) < 0)
+               goto fail;
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
+}
+
+static json_t *
+iaor2json(IPAddressOrRange const *iaor, int af)
+{
+       json_t *root;
+
+       if (iaor == NULL)
+               return json_null();
+
+       switch (iaor->type) {
+       case IPAddressOrRange_addressPrefix:
+               return p2json(iaor->u.addressPrefix, af);
+       case IPAddressOrRange_addressRange:
+               return unimplemented(iaor->u.addressRange);
+       }
+
+       json_decref(root);
+       return NULL;
 }
 
-struct extension_metadata const *ext_ir2(void)
+static json_t *
+iac2json(IPAddressChoice const *iac, int af)
 {
-       return &IR2;
+       json_t *root;
+       IPAddressOrRanges *iaor;
+       int i;
+
+       if (iac == NULL)
+               return json_null();
+
+       switch (iac->type) {
+       case IPAddressChoice_inherit:
+               return json_string("inherit");
+
+       case IPAddressChoice_addressesOrRanges:
+               iaor = iac->u.addressesOrRanges;
+               if (iaor == NULL)
+                       return json_null();
+               root = json_array();
+               if (root == NULL)
+                       goto fail;
+               for (i = 0; i < sk_IPAddressOrRange_num(iaor); i++)
+                       if (json_array_append_new(root, iaor2json(sk_IPAddressOrRange_value(iaor, i), af)) < 0)
+                               goto fail;
+               return root;
+       }
+
+       return NULL;
+
+fail:  json_decref(root);
+       return NULL;
 }
 
-struct extension_metadata const *ext_ar2(void)
+static json_t *
+iaf2json(IPAddressFamily const *iaf)
 {
-       return &AR2;
+       json_t *root;
+       ASN1_OCTET_STRING *af;
+       char const *family;
+       int afid;
+
+       if (iaf == NULL)
+               return json_null();
+
+       root = json_object();
+       if (root == NULL)
+               return NULL;
+
+       af = iaf->addressFamily;
+       if (af->length != 2)
+               goto fail;
+
+       if (af->data[0] == 0 && af->data[1] == 1) {
+               family = "IPv4";
+               afid = AF_INET;
+       } else if (af->data[0] == 0 && af->data[1] == 2) {
+               family = "IPv6";
+               afid = AF_INET6;
+       } else {
+               goto fail;
+       }
+
+       if (json_object_set_new(root, "addressFamily", json_string(family)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "ipAddressChoice", iac2json(iaf->ipAddressChoice, afid)) < 0)
+               goto fail;
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
 }
 
-struct extension_metadata const *ext_cn(void)
+static json_t *
+ir2json(void const *ext)
 {
-       static const struct extension_metadata CN = {
-               "CRL Number",
-               NID_crl_number,
-               false,
-       };
-       return &CN;
+       STACK_OF(IPAddressFamily) const *iafs = ext;
+       json_t *root;
+       int i;
+
+       root = json_array();
+       if (root == NULL)
+               return NULL;
+
+       for (i = 0; i < sk_IPAddressFamily_num(iafs); i++)
+               if (json_array_append_new(root, iaf2json(sk_IPAddressFamily_value(iafs, i))) < 0)
+                       goto fail;
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
+}
+
+static void
+ir_destroy(void *ir)
+{
+       sk_IPAddressFamily_pop_free(ir, IPAddressFamily_free);
+}
+
+static const struct extension_metadata IR = {
+       "IP Resources",
+       NID_sbgp_ipAddrBlock,
+       true,
+       ir2json,
+       ir_destroy,
+};
+
+static json_t *
+asr2json(ASRange const *range)
+{
+       json_t *root;
+
+       if (range == NULL)
+               return json_null();
+
+       root = json_object();
+       if (root == NULL)
+               return NULL;
+       if (json_object_set_new(root, "min", asn1int2json(range->min)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "max", asn1int2json(range->max)) < 0)
+               goto fail;
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
+}
+
+static json_t *
+aor2json(ASIdOrRange const *aor)
+{
+       json_t *root;
+
+       if (aor == NULL)
+               return json_null();
+
+       switch (aor->type) {
+       case ASIdOrRange_id:
+               return asn1int2json(aor->u.id);
+       case ASIdOrRange_range:
+               return asr2json(aor->u.range);
+       }
+
+       json_decref(root);
+       return NULL;
+}
+
+static json_t *
+asidc2json(ASIdentifierChoice const *asidc)
+{
+       json_t *root;
+       ASIdOrRanges *iaor;
+       int i;
+
+       if (asidc == NULL)
+               return json_null();
+
+       switch (asidc->type) {
+       case ASIdentifierChoice_inherit:
+               return json_string("inherit");
+
+       case ASIdentifierChoice_asIdsOrRanges:
+               iaor = asidc->u.asIdsOrRanges;
+               if (iaor == NULL)
+                       return json_null();
+               root = json_array();
+               if (root == NULL)
+                       goto fail;
+               for (i = 0; i < sk_ASIdOrRange_num(iaor); i++)
+                       if (json_array_append_new(root, aor2json(sk_ASIdOrRange_value(iaor, i))) < 0)
+                               goto fail;
+               return root;
+       }
+
+       return NULL;
+
+fail:  json_decref(root);
+       return NULL;
+}
+
+static json_t *
+ar2json(void const *ext)
+{
+       ASIdentifiers const *asid = ext;
+       json_t *root;
+
+       if (asid == NULL)
+               return json_null();
+
+       root = json_object();
+       if (root == NULL)
+               return NULL;
+       if (json_object_set_new(root, "asnum", asidc2json(asid->asnum)) < 0)
+               goto fail;
+       if (json_object_set_new(root, "rdi", asidc2json(asid->rdi)) < 0)
+               goto fail;
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
+}
+
+static void
+ar_destroy(void *ar)
+{
+       ASIdentifiers_free(ar);
+}
+
+static const struct extension_metadata AR = {
+       "AS Resources",
+       NID_sbgp_autonomousSysNum,
+       true,
+       ar2json,
+       ar_destroy,
+};
+
+static struct extension_metadata IR2 = {
+       "Amended IP Resources",
+       -1,
+       true,
+       ir2json,
+       ir_destroy,
+};
+
+static struct extension_metadata AR2 = {
+       "Amended AS Resources",
+       -1,
+       true,
+       ar2json,
+       ir_destroy,
+};
+
+static const struct extension_metadata CN = {
+       "CRL Number",
+       NID_crl_number,
+       false,
+};
+
+static const struct extension_metadata EKU = {
+       "Extended Key Usage",
+       NID_ext_key_usage,
+       false,
+};
+
+int extension_init(void)
+{
+       IR2.nid = nid_ipAddrBlocksv2();
+       AR2.nid = nid_autonomousSysIdsv2();
+       return 0;
 }
 
-struct extension_metadata const *ext_eku(void)
+struct extension_metadata const *ext_bc(void)  { return &BC; }
+struct extension_metadata const *ext_ski(void) { return &SKI; }
+struct extension_metadata const *ext_aki(void) { return &AKI; }
+struct extension_metadata const *ext_ku(void)  { return &KU; }
+struct extension_metadata const *ext_cdp(void) { return &CDP; }
+struct extension_metadata const *ext_aia(void) { return &AIA; }
+struct extension_metadata const *ext_sia(void) { return &SIA; }
+struct extension_metadata const *ext_cp(void)  { return &CP; }
+struct extension_metadata const *ext_ir(void)  { return &IR; }
+struct extension_metadata const *ext_ar(void)  { return &AR; }
+struct extension_metadata const *ext_ir2(void) { return &IR2; }
+struct extension_metadata const *ext_ar2(void) { return &AR2; }
+struct extension_metadata const *ext_cn(void)  { return &CN; }
+struct extension_metadata const *ext_eku(void) { return &EKU; }
+
+struct extension_metadata const **
+ext_metadatas(void)
 {
-       static const struct extension_metadata EKU = {
-               "Extended Key Usage",
-               NID_ext_key_usage,
-               false,
+       static struct extension_metadata const *array[] = {
+               &BC,  &SKI, &AKI, &KU,
+               &CDP, &AIA, &SIA, &CP,
+               &IR,  &AR,  &IR2, &AR2,
+               &CN,  &EKU, NULL
        };
-       return &EKU;
+       return array;
 }
 
 static int
index 33a4022d39429cf103ca6aab6ea68f062219ba7a..e97e2b6ee21355a9d2f44f13c47df08f1b3347c2 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef SRC_EXTENSION_H_
 #define SRC_EXTENSION_H_
 
-#include <openssl/asn1.h>
+#include <jansson.h>
 #include <openssl/safestack.h>
 #include <openssl/x509.h>
 #include <stdbool.h>
@@ -10,6 +10,8 @@ struct extension_metadata {
        char const *name;
        int nid;
        bool critical;
+       json_t *(*to_json)(void const *);
+       void (*destructor)(void *); /* TODO use this more */
 };
 
 struct extension_handler {
@@ -40,6 +42,8 @@ struct extension_metadata const *ext_ar2(void);
 struct extension_metadata const *ext_cn(void);
 struct extension_metadata const *ext_eku(void);
 
+struct extension_metadata const **ext_metadatas(void);
+
 int handle_extensions(struct extension_handler *,
     STACK_OF(X509_EXTENSION) const *);
 
diff --git a/src/libcrypto_util.c b/src/libcrypto_util.c
new file mode 100644 (file)
index 0000000..c5d93e3
--- /dev/null
@@ -0,0 +1,181 @@
+#include "libcrypto_util.h"
+
+#include <stdlib.h>
+#include <openssl/asn1.h>
+
+#include "alloc.h"
+
+/* Swallows @bio. */
+char *
+bio2str(BIO *bio)
+{
+       BUF_MEM *buffer;
+       char *str;
+
+       str = (BIO_get_mem_ptr(bio, &buffer) > 0)
+           ? pstrndup(buffer->data, buffer->length)
+           : NULL;
+
+       BIO_free_all(bio);
+       return str;
+}
+
+/* Swallows @bio. */
+json_t *
+bio2json(BIO *bio)
+{
+       BUF_MEM *buffer;
+       json_t *json;
+
+       json = (BIO_get_mem_ptr(bio, &buffer) > 0)
+           ? json_stringn(buffer->data, buffer->length)
+           : NULL;
+
+       BIO_free_all(bio);
+       return json;
+}
+
+json_t *
+oid2json(ASN1_OBJECT const *oid)
+{
+       return oid ? json_string(OBJ_nid2sn(OBJ_obj2nid(oid))) : json_null();
+}
+
+json_t *
+asn1int2json(ASN1_INTEGER const *asn1int)
+{
+       BIGNUM *bignum;
+       char *str;
+       json_t *json;
+
+       if (asn1int == NULL)
+               return json_null();
+
+       bignum = ASN1_INTEGER_to_BN(asn1int, NULL);
+       str = BN_bn2hex(bignum);
+
+       json = json_string(str);
+
+       OPENSSL_free(str);
+       BN_free(bignum);
+
+       return json;
+}
+
+json_t *
+asn1str2json(ASN1_STRING const *str)
+{
+       BIO *bio;
+       int i;
+
+       if (str == NULL)
+               return json_null();
+
+       bio = BIO_new(BIO_s_mem());
+       if (bio == NULL)
+               return NULL;
+
+       for (i = 0; i < str->length; i++) {
+               if (BIO_printf(bio, "%02x", str->data[i]) <= 0) {
+                       BIO_free_all(bio);
+                       return NULL;
+               }
+       }
+
+       return bio2json(bio);
+}
+
+json_t *
+asn1time2json(ASN1_TIME const *time)
+{
+       BIO *bio;
+
+       if (time == NULL)
+               return json_null();
+
+       bio = BIO_new(BIO_s_mem());
+       if (bio == NULL)
+               return NULL;
+
+       if (!ASN1_TIME_print_ex(bio, time, ASN1_DTFLGS_ISO8601)) {
+               BIO_free_all(bio);
+               return NULL;
+       }
+
+       return bio2json(bio);
+}
+
+json_t *
+name2json(X509_NAME const *name)
+{
+       json_t *root;
+       json_t *child;
+       int i;
+
+       if (name == NULL)
+               return json_null();
+
+       root = json_object();
+       if (root == NULL)
+               return NULL;
+
+       for (i = 0; i < X509_NAME_entry_count(name); i++) {
+               X509_NAME_ENTRY *entry;
+               int nid;
+               const ASN1_STRING *data;
+
+               entry = X509_NAME_get_entry(name, i);
+               nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry));
+
+               data = X509_NAME_ENTRY_get_data(entry);
+               if (data == NULL)
+                       goto fail;
+               child = json_stringn((char *)data->data, data->length);
+
+               if (json_object_set_new(root, OBJ_nid2sn(nid), child) < 0)
+                       goto fail;
+       }
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
+}
+
+json_t *
+gn2json(GENERAL_NAME const *gn)
+{
+       ASN1_IA5STRING *str;
+       int type;
+
+       if (gn == NULL)
+               return json_null();
+
+       str = GENERAL_NAME_get0_value(gn, &type); // FIXME open call hierarchy FIXME getter review
+       return (type == GEN_URI)
+           ? json_stringn((char const *)str->data, str->length)
+           : json_string("<Not implemented for now>");
+}
+
+json_t *
+gns2json(GENERAL_NAMES const *gns)
+{
+       json_t *root;
+       int n;
+
+       if (gns == NULL)
+               return json_null();
+
+       root = json_array();
+       if (root == NULL)
+               return NULL;
+
+       for (n = 0; n < sk_GENERAL_NAME_num(gns); n++)
+               if (json_array_append_new(root, gn2json(sk_GENERAL_NAME_value(gns, n))) < 0)
+                       goto fail;
+
+       return root;
+
+fail:  json_decref(root);
+       return NULL;
+}
diff --git a/src/libcrypto_util.h b/src/libcrypto_util.h
new file mode 100644 (file)
index 0000000..e1da52f
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef SRC_LIBCRYPTO_UTIL_H_
+#define SRC_LIBCRYPTO_UTIL_H_
+
+#include <jansson.h>
+#include <openssl/asn1.h>
+#include <openssl/bio.h>
+#include <openssl/x509.h>
+
+char *bio2str(BIO *);
+json_t *bio2json(BIO *);
+json_t *oid2json(ASN1_OBJECT const *);
+json_t *asn1int2json(ASN1_INTEGER const *);
+json_t *asn1str2json(ASN1_STRING const *); /* octet string, bit string, etc */
+json_t *asn1time2json(ASN1_TIME const *);
+json_t *name2json(X509_NAME const *);
+json_t *gn2json(GENERAL_NAME const *);
+json_t *gns2json(GENERAL_NAMES const *);
+
+#endif /* SRC_LIBCRYPTO_UTIL_H_ */