]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
More misc tweaks:
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 18 Jan 2019 20:09:12 +0000 (14:09 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Fri, 18 Jan 2019 20:09:46 +0000 (14:09 -0600)
- Validate more certificate extensions
- Ensure there is only one visible CRL and manifest per publication
  point.
- Validate ROA's max length more thoroughly.

src/asn1/signed_data.c
src/crypto/hash.c
src/crypto/hash.h
src/main.c
src/object/certificate.c
src/object/manifest.c
src/object/roa.c
src/state.c
src/state.h

index 25650b29c19802c9ba40e488f32362548a800673..2081f8bddb4362ddd666a2ecbacb2c15f7044f7a 100644 (file)
@@ -24,7 +24,7 @@ is_digest_algorithm(AlgorithmIdentifier_t *id, char *what)
        if (id == NULL)
                return pr_err("The %s algorithm is NULL.", what);
 
-       error = hash_is_valid_algorithm(&id->algorithm, &is_hash);
+       error = hash_is_sha256(&id->algorithm, &is_hash);
        if (error)
                return error;
        if (!is_hash)
@@ -135,7 +135,9 @@ validate_message_digest_attribute(CMSAttributeValue_t *value,
        if (error)
                return error;
 
-       error = hash_validate_octet_string(eci->eContent, digest);
+       error = hash_validate_octet_string("sha256", digest, eci->eContent);
+       if (error)
+               pr_err("The content's hash does not match the Message-Digest Attribute.");
 
        free(digest);
        return error;
index 1d9988420a8120ab0d5c1a989a1e31f45e8d1dab..d533cb5139a803252370af49e0b3d49c98e4537f 100644 (file)
@@ -8,23 +8,8 @@
 #include "log.h"
 #include "asn1/oid.h"
 
-#define ALGORITHM "sha256"
-static EVP_MD const *md;
-
 int
-hash_init(void)
-{
-       md = EVP_get_digestbyname(ALGORITHM);
-       if (md == NULL) {
-               printf("Unknown message digest %s\n", ALGORITHM);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-int
-hash_is_valid_algorithm(OBJECT_IDENTIFIER_t *oid, bool *result)
+hash_is_sha256(OBJECT_IDENTIFIER_t *oid, bool *result)
 {
        static const OID sha_oid = OID_SHA256;
        struct oid_arcs arcs;
@@ -40,17 +25,34 @@ hash_is_valid_algorithm(OBJECT_IDENTIFIER_t *oid, bool *result)
        return 0;
 }
 
+static int
+get_md(char const *algorithm, EVP_MD const **result)
+{
+       EVP_MD const *md;
+
+       md = EVP_get_digestbyname(algorithm);
+       if (md == NULL) {
+               printf("Unknown message digest %s\n", algorithm);
+               return -EINVAL;
+       }
+
+       *result = md;
+       return 0;
+}
+
 static bool
-hash_matches(unsigned char *expected, size_t expected_len,
-    unsigned char *actual, unsigned int actual_len)
+hash_matches(unsigned char const *expected, size_t expected_len,
+    unsigned char const *actual, unsigned int actual_len)
 {
        return (expected_len == actual_len)
            && (memcmp(expected, actual, expected_len) == 0);
 }
 
 static int
-hash_file(char *filename, unsigned char *result, unsigned int *result_len)
+hash_file(char const *algorithm, char const *filename, unsigned char *result,
+    unsigned int *result_len)
 {
+       EVP_MD const *md;
        FILE *file;
        struct stat stat;
        unsigned char *buffer;
@@ -59,6 +61,10 @@ hash_file(char *filename, unsigned char *result, unsigned int *result_len)
        EVP_MD_CTX *ctx;
        int error;
 
+       error = get_md(algorithm, &md);
+       if (error)
+               return error;
+
        error = file_open(filename, &file, &stat);
        if (error)
                return error;
@@ -115,7 +121,8 @@ end1:
  * hashes match.
  */
 int
-hash_validate_file(char *filename, BIT_STRING_t *expected)
+hash_validate_file(char const *algorithm, char const *filename,
+    BIT_STRING_t const *expected)
 {
        unsigned char actual[EVP_MAX_MD_SIZE];
        unsigned int actual_len;
@@ -124,7 +131,7 @@ hash_validate_file(char *filename, BIT_STRING_t *expected)
        if (expected->bits_unused != 0)
                return pr_err("Hash string has unused bits.");
 
-       error = hash_file(filename, actual, &actual_len);
+       error = hash_file(algorithm, filename, actual, &actual_len);
        if (error)
                return error;
 
@@ -135,12 +142,18 @@ hash_validate_file(char *filename, BIT_STRING_t *expected)
 }
 
 static int
-hash_buffer(unsigned char *content, size_t content_len, unsigned char *hash,
-    unsigned int *hash_len)
+hash_buffer(char const *algorithm,
+    unsigned char const *content, size_t content_len,
+    unsigned char *hash, unsigned int *hash_len)
 {
+       EVP_MD const *md;
        EVP_MD_CTX *ctx;
        int error = 0;
 
+       error = get_md(algorithm, &md);
+       if (error)
+               return error;
+
        ctx = EVP_MD_CTX_new();
        if (ctx == NULL)
                return pr_enomem();
@@ -155,19 +168,32 @@ hash_buffer(unsigned char *content, size_t content_len, unsigned char *hash,
        return error;
 }
 
+/*
+ * Returns 0 if @data's hash is @expected. Returns error code otherwise.
+ */
 int
-hash_validate_octet_string(OCTET_STRING_t *content, OCTET_STRING_t *expected)
+hash_validate(char const *algorithm,
+    unsigned char const *expected, size_t expected_len,
+    unsigned char const *data, size_t data_len)
 {
        unsigned char actual[EVP_MAX_MD_SIZE];
        unsigned int actual_len;
        int error;
 
-       error = hash_buffer(content->buf, content->size, actual, &actual_len);
+       error = hash_buffer(algorithm, data, data_len, actual, &actual_len);
        if (error)
                return error;
 
-       if (!hash_matches(expected->buf, expected->size, actual, actual_len))
-               return pr_err("File does not match its hash.");
+       return hash_matches(expected, expected_len, actual, actual_len)
+           ? 0
+           : -EINVAL;
+}
 
-       return 0;
+int
+hash_validate_octet_string(char const *algorithm,
+    OCTET_STRING_t const *expected,
+    OCTET_STRING_t const *data)
+{
+       return hash_validate(algorithm, expected->buf, expected->size,
+           data->buf, data->size);
 }
index 3e771c5fb82157a77585c7d2908df8a25d63271a..9232caa662adf1ed4ff74d4d89ec81eaca2303be 100644 (file)
@@ -2,12 +2,15 @@
 #define SRC_HASH_H_
 
 #include <stdbool.h>
+#include <stddef.h>
 #include <libcmscodec/BIT_STRING.h>
 #include <libcmscodec/OBJECT_IDENTIFIER.h>
 
-int hash_init(void);
-int hash_is_valid_algorithm(OBJECT_IDENTIFIER_t *, bool *);
-int hash_validate_file(char *, BIT_STRING_t *);
-int hash_validate_octet_string(OCTET_STRING_t *, OCTET_STRING_t *);
+int hash_is_sha256(OBJECT_IDENTIFIER_t *, bool *);
+int hash_validate_file(char const *, char const *, BIT_STRING_t const *);
+int hash_validate(char const *, unsigned char const *, size_t,
+    unsigned char const *, size_t);
+int hash_validate_octet_string(char const *, OCTET_STRING_t const*,
+    OCTET_STRING_t const *);
 
 #endif /* SRC_HASH_H_ */
index 72e95f955670743e4309a7714ae083197f61f8f8..e7eface4cad9b07dec262e1653cd747f166e71c8 100644 (file)
@@ -6,7 +6,6 @@
 #include "debug.h"
 #include "log.h"
 #include "thread_var.h"
-#include "crypto/hash.h"
 #include "object/certificate.h"
 #include "object/tal.h"
 #include "rsync/rsync.h"
@@ -143,9 +142,6 @@ main(int argc, char **argv)
        if (argc >= 5)
                shuffle_uris = true; /* TODO lol fix this */
 
-       error = hash_init();
-       if (error)
-               return error;
        error = rsync_init(is_rsync_active);
        if (error)
                return error;
index da744fe7de069195fbe5675c371a7ab46c2d54f7..cb18e7ba71a2ce00d39d8e2c126916cfcfc84bdb 100644 (file)
@@ -1,6 +1,7 @@
 #include "certificate.h"
 
 #include <errno.h>
+#include <stdint.h> /* SIZE_MAX */
 #include <libcmscodec/SubjectInfoAccessSyntax.h>
 #include <libcmscodec/SubjectPublicKeyInfo.h>
 #include <libcmscodec/IPAddrBlocks.h>
@@ -11,6 +12,7 @@
 #include "thread_var.h"
 #include "asn1/decode.h"
 #include "asn1/oid.h"
+#include "crypto/hash.h"
 #include "rsync/rsync.h"
 
 /*
@@ -89,6 +91,11 @@ struct extension_handler {
        bool found;
 };
 
+struct ski_arguments {
+       X509 *cert;
+       OCTET_STRING_t *sid;
+};
+
 struct sia_arguments {
        X509 *cert;
        STACK_OF(X509_CRL) *crls;
@@ -252,16 +259,12 @@ validate_public_key(X509 *cert, bool is_root)
        int error;
 
        pubkey = X509_get_X509_PUBKEY(cert);
-       if (pubkey == NULL) {
-               crypto_err("X509_get_X509_PUBKEY() returned NULL");
-               return -EINVAL;
-       }
+       if (pubkey == NULL)
+               return crypto_err("X509_get_X509_PUBKEY() returned NULL");
 
        ok = X509_PUBKEY_get0_param(&alg, &bytes, &bytes_len, NULL, pubkey);
-       if (!ok) {
-               crypto_err("X509_PUBKEY_get0_param() returned %d", ok);
-               return -EINVAL;
-       }
+       if (!ok)
+               return crypto_err("X509_PUBKEY_get0_param() returned %d", ok);
 
        alg_nid = OBJ_obj2nid(alg);
        /*
@@ -722,81 +725,180 @@ handle_bc(X509_EXTENSION *ext, void *arg)
        return error;
 }
 
+/**
+ * Returns 0 if the identifier (ie. SHA-1 hash) of @cert's public key is @hash.
+ * Otherwise returns error code.
+ */
 static int
-handle_ski(X509_EXTENSION *ext, void *arg)
+validate_public_key_hash(X509 *cert, ASN1_OCTET_STRING *hash)
 {
        X509_PUBKEY *pubkey;
        const unsigned char *spk;
        int spk_len;
        int ok;
+       int error;
 
        /*
+        * I really can't tell if this validation needs to be performed.
+        * Probably not.
+        *
         * "Applications are not required to verify that key identifiers match
         * when performing certification path validation."
         * (rfc5280#section-4.2.1.2)
-        * I think "match" refers to the "parent's SKI must match the
-        * children's AKI" requirement, not "The SKI must match the SHA-1 of the
-        * SPK" requirement.
-        * So I guess we're only supposed to check the SHA-1.
+        *
+        * From its context, my reading is that the quote refers to the
+        * "parent's SKI must equal the children's AKI" requirement, not the
+        * "child's SKI must equal the SHA-1 of its own's SPK" requirement. So
+        * I think that we're only supposed to check the SHA-1. Or nothing at
+        * all, because we only care about the keys, not their identifiers.
+        *
+        * But the two requirements actually have a lot in common:
+        *
+        * The quote is from 5280, not 6487. 6487 chooses to enforce the SKI's
+        * "SHA-1 as identifier" option, even for the AKI. And if I'm validating
+        * the AKI's SHA-1, then I'm also indirectly checking the children vs
+        * parent relationship.
+        *
+        * Also, what's with using a hash as identifier? That's an accident
+        * waiting to happen...
+        *
+        * Bottom line, I don't know. But better be safe than sorry, so here's
+        * the validation.
+        *
+        * Shit. I feel like I'm losing so much performance because the RFCs
+        * are so wishy-washy about what is our realm and what is not.
         */
 
-       pubkey = X509_get_X509_PUBKEY((X509 *) arg);
-       if (pubkey == NULL) {
-               crypto_err("X509_get_X509_PUBKEY() returned NULL");
-               return -EINVAL;
-       }
+       /* Get the SPK (ask libcrypto) */
+       pubkey = X509_get_X509_PUBKEY(cert);
+       if (pubkey == NULL)
+               return crypto_err("X509_get_X509_PUBKEY() returned NULL");
 
        ok = X509_PUBKEY_get0_param(NULL, &spk, &spk_len, NULL, pubkey);
-       if (!ok) {
-               crypto_err("X509_PUBKEY_get0_param() returned %d", ok);
-               return -EINVAL;
+       if (!ok)
+               return crypto_err("X509_PUBKEY_get0_param() returned %d", ok);
+
+       /* Hash the SPK, compare SPK hash with the SKI */
+       if (hash->length < 0 || SIZE_MAX < hash->length) {
+               return pr_err("%s length (%d) is out of bounds. (0-%zu)",
+                   SKI.name, hash->length, SIZE_MAX);
+       }
+       if (spk_len < 0 || SIZE_MAX < spk_len) {
+               return pr_err("Subject Public Key length (%d) is out of bounds. (0-%zu)",
+                   spk_len, SIZE_MAX);
        }
 
-       /* Get the SHA-1 of spk */
-       /* TODO (certext) ... */
+       error = hash_validate("sha1", hash->data, hash->length, spk, spk_len);
+       if (error) {
+               pr_err("The Subject Public Key's hash does not match the %s.",
+                   SKI.name);
+       }
 
-       /* Decode ext */
+       return error;
+}
 
-       /* Compare the SHA and the decoded ext */
+static int
+handle_ski_ca(X509_EXTENSION *ext, void *arg)
+{
+       ASN1_OCTET_STRING *ski;
+       int error;
 
-       /* Free the decoded ext */
+       ski = X509V3_EXT_d2i(ext);
+       if (ski == NULL)
+               return cannot_decode(&SKI);
 
-       return 0;
+       error = validate_public_key_hash(arg, ski);
+
+       ASN1_OCTET_STRING_free(ski);
+       return error;
 }
 
 static int
 handle_ski_ee(X509_EXTENSION *ext, void *arg)
 {
+       struct ski_arguments *args;
        ASN1_OCTET_STRING *ski;
-       OCTET_STRING_t *sid = arg;
-       int error = 0;
+       OCTET_STRING_t *sid;
+       int error;
 
        ski = X509V3_EXT_d2i(ext);
        if (ski == NULL)
                return cannot_decode(&SKI);
 
+       args = arg;
+       error = validate_public_key_hash(args->cert, ski);
+       if (error)
+               goto end;
+
        /* rfc6488#section-2.1.6.2 */
        /* rfc6488#section-3.1.c 2/2 */
+       sid = args->sid;
        if (ski->length != sid->size
            || memcmp(ski->data, sid->buf, sid->size) != 0) {
                error = pr_err("The EE certificate's subjectKeyIdentifier does not equal the Signed Object's sid.");
        }
 
+end:
        ASN1_OCTET_STRING_free(ski);
        return error;
 }
 
+static bool
+extension_equals(X509_EXTENSION *ext1, X509_EXTENSION *ext2)
+{
+       int crit1;
+       int crit2;
+       ASN1_OCTET_STRING *data1;
+       ASN1_OCTET_STRING *data2;
+
+       crit1 = X509_EXTENSION_get_critical(ext1);
+       crit2 = X509_EXTENSION_get_critical(ext2);
+       if (crit1 != crit2)
+               return false;
+
+       data1 = X509_EXTENSION_get_data(ext1);
+       data2 = X509_EXTENSION_get_data(ext2);
+       if (data1->length != data2->length)
+               return false;
+       if (data1->type != data2->type)
+               return false;
+       if (data1->flags != data2->flags)
+               return false;
+       if (memcmp(data1->data, data2->data, data1->length) != 0)
+               return false;
+
+       return true;
+}
+
 static int
-handle_aki_ta(X509_EXTENSION *ext, void *arg)
+handle_aki_ta(X509_EXTENSION *aki, void *arg)
 {
-       return 0; /* TODO (certext) implement. */
+       X509 *cert = arg;
+       X509_EXTENSION *other;
+       int i;
+
+       for (i = 0; i < X509_get_ext_count(cert); i++) {
+               other = X509_get_ext(cert, i);
+               if (OBJ_obj2nid(X509_EXTENSION_get_object(other)) == SKI.nid) {
+                       if (extension_equals(aki, other))
+                               return 0;
+
+                       return pr_err("The %s is not equal to the %s.",
+                           AKI.name, SKI.name);
+               }
+       }
+
+       pr_err("Certificate lacks the '%s' extension.", SKI.name);
+       return -ESRCH;
 }
 
 static int
 handle_aki(X509_EXTENSION *ext, void *arg)
 {
        AUTHORITY_KEYID *aki;
-       int error = 0;
+       struct validation *state;
+       X509 *parent;
+       int error;
 
        aki = X509V3_EXT_d2i(ext);
        if (aki == NULL)
@@ -813,7 +915,19 @@ handle_aki(X509_EXTENSION *ext, void *arg)
                goto end;
        }
 
-       /* TODO (certext) stuff */
+       state = state_retrieve();
+       if (state == NULL) {
+               error = -EINVAL;
+               goto end;
+       }
+
+       parent = validation_peek_cert(state);
+       if (parent == NULL) {
+               error = pr_err("Certificate has no parent.");
+               goto end;
+       }
+
+       error = validate_public_key_hash(parent, aki->keyid);
 
 end:
        AUTHORITY_KEYID_free(aki);
@@ -1009,7 +1123,7 @@ handle_sia_ca(X509_EXTENSION *ext, void *arg)
        }
 
        if (!rsync_found) {
-               pr_err("SIA extension lacks an RSYNC URI caRepository.");
+               pr_err("SIA extension lacks a caRepository RSYNC URI.");
                error = -ESRCH;
                goto end1;
        }
@@ -1018,6 +1132,19 @@ handle_sia_ca(X509_EXTENSION *ext, void *arg)
        for (i = 0; i < sk_ACCESS_DESCRIPTION_num(sia); i++) {
                ad = sk_ACCESS_DESCRIPTION_value(sia, i);
                if (OBJ_obj2nid(ad->method) == NID_rpkiManifest) {
+                       /*
+                        * rfc6481#section-2.2
+                        * This validation is naive.
+                        * The fact that only one manifest is listed in the SIA
+                        * does not mean that there aren't more or them in the
+                        * publication point.
+                        * But it's all we can do methinks.
+                        */
+                       if (manifest_found) {
+                               error = pr_err("SIA defines more than one manifest.");
+                               goto end1;
+                       }
+
                        error = handle_rpkiManifest(ad, args->crls);
                        if (error)
                                goto end1;
@@ -1043,27 +1170,39 @@ handle_sia_ee(X509_EXTENSION *ext, void *arg)
 {
        SIGNATURE_INFO_ACCESS *sia;
        ACCESS_DESCRIPTION *ad;
+       bool signedObject_found = false;
+       int nid;
        int i;
        int error = 0;
 
+       /* TODO this is getting convoluted. Make a generic AD foreach. */
+
        sia = X509V3_EXT_d2i(ext);
        if (sia == NULL)
                return cannot_decode(&SIA);
 
        for (i = 0; i < sk_ACCESS_DESCRIPTION_num(sia); i++) {
                ad = sk_ACCESS_DESCRIPTION_value(sia, i);
-               if (OBJ_obj2nid(ad->method) == NID_signedObject) {
+               nid = OBJ_obj2nid(ad->method);
+
+               if (nid == NID_signedObject) {
                        error = handle_signedObject(ad);
+                       /* TODO Unknown signedObjects are allowed. */
                        if (error)
                                goto end;
+                       signedObject_found = true;
 
                } else {
                        /* rfc6487#section-4.8.8.2 */
-                       error = pr_err("EE Certificate has an non-signedObject access description.");
+                       error = pr_err("EE Certificate has an non-signedObject access description. (NID: %d)",
+                           nid);
                        goto end;
                }
        }
 
+       if (!signedObject_found)
+               error = pr_err("EE Certificate's SIA lacks a signedObject access description.");
+
 end:
        AUTHORITY_INFO_ACCESS_free(sia);
        return error;
@@ -1158,8 +1297,8 @@ certificate_traverse_ta(X509 *cert, STACK_OF(X509_CRL) *crls)
        struct extension_handler handlers[] = {
           /* ext   reqd   handler        arg       */
            { &BC,  true,  handle_bc,               },
-           { &SKI, true,  handle_ski,    &cert     },
-           { &AKI, false, handle_aki_ta,           },
+           { &SKI, true,  handle_ski_ca, cert      },
+           { &AKI, false, handle_aki_ta, cert      },
            { &KU,  true,  handle_ku_ca,            },
            { &SIA, true,  handle_sia_ca, &sia_args },
            { &CP,  true,  handle_cp,               },
@@ -1180,8 +1319,8 @@ certificate_traverse_ca(X509 *cert, STACK_OF(X509_CRL) *crls)
        struct sia_arguments sia_args;
        struct extension_handler handlers[] = {
           /* ext   reqd   handler        arg       */
-           { &BC,  true,  handle_bc,            },
-           { &SKI, true,  handle_ski,    &cert     },
+           { &BC,  true,  handle_bc,               },
+           { &SKI, true,  handle_ski_ca, cert      },
            { &AKI, true,  handle_aki,              },
            { &KU,  true,  handle_ku_ca,            },
            { &CDP, true,  handle_cdp,              },
@@ -1202,19 +1341,23 @@ certificate_traverse_ca(X509 *cert, STACK_OF(X509_CRL) *crls)
 int
 certificate_traverse_ee(X509 *cert, OCTET_STRING_t *sid)
 {
+       struct ski_arguments ski_args;
        struct extension_handler handlers[] = {
           /* ext   reqd   handler        arg */
-           { &SKI, true,  handle_ski_ee, sid },
-           { &AKI, true,  handle_aki,        },
-           { &KU,  true,  handle_ku_ee,      },
-           { &CDP, true,  handle_cdp,        },
-           { &AIA, true,  handle_aia,        },
-           { &SIA, true,  handle_sia_ee,     },
-           { &CP,  true,  handle_cp,         },
-           { &IR,  false, handle_ir,         },
-           { &AR,  false, handle_ar,         },
+           { &SKI, true,  handle_ski_ee, &ski_args },
+           { &AKI, true,  handle_aki,              },
+           { &KU,  true,  handle_ku_ee,            },
+           { &CDP, true,  handle_cdp,              },
+           { &AIA, true,  handle_aia,              },
+           { &SIA, true,  handle_sia_ee,           },
+           { &CP,  true,  handle_cp,               },
+           { &IR,  false, handle_ir,               },
+           { &AR,  false, handle_ar,               },
            { NULL },
        };
 
+       ski_args.cert = cert;
+       ski_args.sid = sid;
+
        return handle_cert_extensions(handlers, cert);
 }
index 4a31e5d81418580d1d5faf3f5adfff29d0236f6a..cf95506f1b58eee7af9db70c841d2108aa1e567f 100644 (file)
@@ -28,7 +28,7 @@ validate_dates(GeneralizedTime_t *this, GeneralizedTime_t *next)
 static int
 validate_manifest(struct Manifest *manifest)
 {
-       bool is_hash;
+       bool is_sha256;
        int error;
 
        /* rfc6486#section-4.2.1 */
@@ -91,10 +91,10 @@ validate_manifest(struct Manifest *manifest)
                return error;
 
        /* rfc6486#section-6.6 (I guess) */
-       error = hash_is_valid_algorithm(&manifest->fileHashAlg, &is_hash);
+       error = hash_is_sha256(&manifest->fileHashAlg, &is_sha256);
        if (error)
                return error;
-       if (!is_hash)
+       if (!is_sha256)
                return pr_err("The hash algorithm is not SHA256.");
 
        /* The file hashes will be validated during the traversal. */
@@ -171,7 +171,7 @@ foreach_file(struct manifest *mft, char *extension, foreach_cb cb, void *arg)
                        if (error)
                                return error;
 
-                       error = hash_validate_file(luri, &fah->hash);
+                       error = hash_validate_file("sha256", luri, &fah->hash);
                        if (error) {
                                free(luri);
                                continue;
@@ -195,6 +195,10 @@ pile_crls(char *file, void *crls)
        int error;
        int idx;
 
+       /* rfc6481#section-2.2 */
+       if (sk_X509_CRL_num(crls) != 0)
+               return pr_err("The Manifest defines more than one CRL.");
+
        fnstack_push(file);
 
        error = crl_load(file, &crl);
@@ -275,7 +279,7 @@ __handle_manifest(struct manifest *mft)
        if (crls == NULL)
                return pr_enomem();
 
-       /* Get CRLs as a stack. There will usually only be one. */
+       /* Get the one CRL as a stack. */
        error = foreach_file(mft, ".crl", pile_crls, crls);
        if (error)
                goto end;
index 4cd1d9238fe868f7de3484014023f0b51b777a2d..3fbf2181a87a5951768f53b3539d9c68a91c0526 100644 (file)
@@ -13,6 +13,7 @@ static int
 print_addr4(struct resources *parent, long asn, struct ROAIPAddress *roa_addr)
 {
        struct ipv4_prefix prefix;
+       long max_length;
        char str[INET_ADDRSTRLEN];
        const char *str2;
        int error;
@@ -21,28 +22,44 @@ print_addr4(struct resources *parent, long asn, struct ROAIPAddress *roa_addr)
        if (error)
                return error;
 
+       if (roa_addr->maxLength != NULL) {
+               max_length = *roa_addr->maxLength;
+
+               if (max_length < 0 || 32 < max_length) {
+                       return pr_err("maxLength (%ld) is out of bounds (0-32).",
+                           max_length);
+               }
+
+               if (prefix.len > max_length) {
+                       return pr_err("Prefix length (%u) > maxLength (%ld)",
+                           prefix.len, max_length);
+               }
+       }
+
        str2 = inet_ntop(AF_INET, &prefix.addr, str, sizeof(str));
        if (str2 == NULL)
                return pr_err("inet_ntop() returned NULL.");
 
+       if (!resources_contains_ipv4(parent, &prefix)) {
+               return pr_err("ROA is not allowed to advertise %s/%u.", str2,
+                   prefix.len);
+       }
+
+       printf("%ld,%s/%u", asn, str2, prefix.len);
        if (roa_addr->maxLength != NULL)
-               if (prefix.len > *roa_addr->maxLength)
-                       goto unallowed;
-       if (!resources_contains_ipv4(parent, &prefix))
-               goto unallowed;
+               printf("-%ld", max_length);
+       else
+               printf("-%u", prefix.len);
+       printf("\n");
 
-       printf("%ld,%s/%u\n", asn, str2, prefix.len);
        return 0;
-
-unallowed:
-       return pr_err("ROA is not allowed to advertise %s/%u.", str2,
-           prefix.len);
 }
 
 static int
 print_addr6(struct resources *parent, long asn, struct ROAIPAddress *roa_addr)
 {
        struct ipv6_prefix prefix;
+       long max_length;
        char str[INET6_ADDRSTRLEN];
        const char *str2;
        int error;
@@ -51,22 +68,37 @@ print_addr6(struct resources *parent, long asn, struct ROAIPAddress *roa_addr)
        if (error)
                return error;
 
+       if (roa_addr->maxLength != NULL) {
+               max_length = *roa_addr->maxLength;
+
+               if (max_length < 0 || 128 < max_length) {
+                       return pr_err("maxLength (%ld) is out of bounds (0-128).",
+                           max_length);
+               }
+
+               if (prefix.len > max_length) {
+                       return pr_err("Prefix length (%u) > maxLength (%ld)",
+                           prefix.len, max_length);
+               }
+       }
+
        str2 = inet_ntop(AF_INET6, &prefix.addr, str, sizeof(str));
        if (str2 == NULL)
                return pr_err("inet_ntop() returned NULL.");
 
+       if (!resources_contains_ipv6(parent, &prefix)) {
+               return pr_err("ROA is not allowed to advertise %s/%u.", str2,
+                   prefix.len);
+       }
+
+       printf("%ld,%s/%u", asn, str2, prefix.len);
        if (roa_addr->maxLength != NULL)
-               if (prefix.len > *roa_addr->maxLength)
-                       goto unallowed;
-       if (!resources_contains_ipv6(parent, &prefix))
-               goto unallowed;
+               printf("-%ld", max_length);
+       else
+               printf("-%u", prefix.len);
+       printf("\n");
 
-       printf("%ld,%s/%u\n", asn, str2, prefix.len);
        return 0;
-
-unallowed:
-       return pr_err("ROA is not allowed to advertise %s/%u.", str2,
-           prefix.len);
 }
 
 static int
index e2205f97859528b6f3c9721fe9108b63a03341b1..f0a8e62efd84795154ab80fcaff59f84c8a60909 100644 (file)
@@ -236,6 +236,12 @@ validation_pop_cert(struct validation *state)
        return 0;
 }
 
+X509 *
+validation_peek_cert(struct validation *state)
+{
+       return sk_X509_value(state->trusted, sk_X509_num(state->trusted) - 1);
+}
+
 struct resources *
 validation_peek_resource(struct validation *state)
 {
index 0172ead3b19aff349743b02e92e9c58f421b2c90..0c97b0f4520fb98bd4677e221713ecf8a7cbe5a3 100644 (file)
@@ -27,6 +27,7 @@ enum pubkey_state validation_pubkey_state(struct validation *);
 
 int validation_push_cert(struct validation *, X509 *, bool);
 int validation_pop_cert(struct validation *);
+X509 *validation_peek_cert(struct validation *);
 
 struct resources *validation_peek_resource(struct validation *);