From: Alberto Leiva Popper Date: Fri, 1 Feb 2019 19:16:06 +0000 (-0600) Subject: Certificate serial number uniqueness validation X-Git-Tag: v0.0.2~104 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9913c35e60f83cec136bd98065a22efb6ca853c9;p=thirdparty%2FFORT-validator.git Certificate serial number uniqueness validation --- diff --git a/src/array_list.h b/src/array_list.h index e199414e..213e322a 100644 --- a/src/array_list.h +++ b/src/array_list.h @@ -51,23 +51,12 @@ \ list->array[list->len - 1] = *elem; \ return 0; \ - } \ - \ - static int \ - name##_foreach(struct name *list, \ - int (*cb)(elem_type const *, void *), \ - void *arg) \ - { \ - unsigned int i; \ - int error; \ - \ - for (i = 0; i < list->len; i++) { \ - error = cb(&list->array[i], arg); \ - if (error) \ - return error; \ - } \ - \ - return 0; \ } +#define ARRAYLIST_FOREACH(list, cursor) for ( \ + cursor = (list)->array; \ + (cursor - ((typeof(cursor)) ((list)->array))) < (list)->len; \ + cursor++ \ +) + #endif /* SRC_ARRAY_LIST_H_ */ diff --git a/src/log.c b/src/log.c index 727a3e56..a1343da2 100644 --- a/src/log.c +++ b/src/log.c @@ -8,19 +8,13 @@ #define STDOUT stdout #define STDERR stderr -#define INDENT_MAX 10 static unsigned int indent; static void pr_indent(FILE *stream) { - unsigned int __indent = indent; unsigned int i; - -// if (__indent > INDENT_MAX) -// __indent = INDENT_MAX; - - for (i = 0; i < __indent; i++) + for (i = 0; i < indent; i++) fprintf(stream, " "); } diff --git a/src/main.c b/src/main.c index 511faa46..5fddc47e 100644 --- a/src/main.c +++ b/src/main.c @@ -32,18 +32,18 @@ static void add_rpki_oids(void) { NID_rpkiManifest = OBJ_create("1.3.6.1.5.5.7.48.10", - "id-ad-rpkiManifest (RFC 6487)", - "Resource Public Key Infrastructure (RPKI) manifest access method"); + "rpkiManifest", + "RPKI Manifest (RFC 6487)"); printf("rpkiManifest registered. Its nid is %d.\n", NID_rpkiManifest); NID_signedObject = OBJ_create("1.3.6.1.5.5.7.48.11", - "id-ad-signedObject (RFC 6487)", - /* TODO */ ""); + "signedObject", + "RPKI Signed Object (RFC 6487)"); printf("signedObject registered. Its nid is %d.\n", NID_signedObject); NID_rpkiNotify = OBJ_create("1.3.6.1.5.5.7.48.13", - "id-ad-rpkiNotify (RFC 8182)", - /* TODO */ "Blah blah"); + "rpkiNotify", + "RPKI Update Notification File (RFC 8182)"); printf("rpkiNotify registered. Its nid is %d.\n", NID_rpkiNotify); } @@ -66,14 +66,11 @@ handle_tal_uri(struct tal *tal, struct rpki_uri const *uri) * key." (RFC 7730) * * A "hard error" is any other error. - * - * TODO this will probably need an update after the merge. */ struct validation *state; int error; - /* TODO this probably needs the state... */ error = download_files(uri); if (error) return 0; diff --git a/src/object/certificate.c b/src/object/certificate.c index a9527989..1c4fbedc 100644 --- a/src/object/certificate.c +++ b/src/object/certificate.c @@ -102,23 +102,30 @@ struct ski_arguments { static int validate_serial_number(X509 *cert) { - /* TODO (field) implement this properly. */ - + struct validation *state; BIGNUM *number; + int error; + + state = state_retrieve(); + if (state == NULL) + return -EINVAL; number = ASN1_INTEGER_to_BN(X509_get0_serialNumber(cert), NULL); - if (number == NULL) { - crypto_err("Could not parse certificate serial number"); - return 0; - } + if (number == NULL) + return crypto_err("Could not parse certificate serial number"); +#ifdef DEBUG pr_debug_prefix(); fprintf(stdout, "serial Number: "); BN_print_fp(stdout, number); fprintf(stdout, "\n"); - BN_free(number); +#endif - return 0; + error = validation_store_serial_number(state, number); + if (error) + BN_free(number); + + return error; } static int diff --git a/src/rpp.c b/src/rpp.c index 7f4c5e48..23594c32 100644 --- a/src/rpp.c +++ b/src/rpp.c @@ -23,11 +23,6 @@ struct rpp { struct uris roas; /* Route Origin Attestations */ }; -struct foreach_args { - struct rpp *pp; - STACK_OF(X509_CRL) *crls; -}; - struct rpp * rpp_create(void) { @@ -112,21 +107,6 @@ end: return error; } -static int -traverse_ca_certs(struct rpki_uri const *uri, void *arg) -{ - struct foreach_args *args = arg; - return certificate_traverse(args->pp, uri, args->crls, false); -} - -static int -print_roa(struct rpki_uri const *uri, void *arg) -{ - struct foreach_args *args = arg; - handle_roa(uri, args->pp, args->crls); - return 0; -} - struct rpki_uri const * rpp_get_crl(struct rpp const *pp) { @@ -140,26 +120,30 @@ rpp_traverse(struct rpp *pp) * TODO is the stack supposed to have only the CRLs of this layer, * or all of them? */ - struct foreach_args args; + STACK_OF(X509_CRL) *crls; + struct rpki_uri *uri; int error; - args.pp = pp; - args.crls = sk_X509_CRL_new_null(); - if (args.crls == NULL) + crls = sk_X509_CRL_new_null(); + if (crls == NULL) return pr_enomem(); - error = add_crl_to_stack(pp, args.crls); + error = add_crl_to_stack(pp, crls); if (error) goto end; /* Use CRL stack to validate certificates, and also traverse them. */ - error = uris_foreach(&pp->certs, traverse_ca_certs, &args); - if (error) - goto end; + ARRAYLIST_FOREACH(&pp->certs, uri) { + /* TODO should we really goto end? */ + error = certificate_traverse(pp, uri, crls, false); + if (error) + goto end; + } /* Use valid address ranges to print ROAs that match them. */ - error = uris_foreach(&pp->roas, print_roa, &args); + ARRAYLIST_FOREACH(&pp->roas, uri) + handle_roa(uri, pp, crls); end: - sk_X509_CRL_pop_free(args.crls, X509_CRL_free); + sk_X509_CRL_pop_free(crls, X509_CRL_free); return error; } diff --git a/src/state.c b/src/state.c index 1f038197..c8f559e2 100644 --- a/src/state.c +++ b/src/state.c @@ -2,16 +2,25 @@ #include #include +#include "array_list.h" #include "log.h" #include "thread_var.h" #include "object/certificate.h" +ARRAY_LIST(serial_numbers, BIGNUM *) + /** * Cached certificate data. */ struct certificate { struct rpki_uri uri; struct resources *resources; + /* + * Serial numbers of the children. + * This is an unsorted array list for two reasons: Certificates usually + * don't have many children, and I'm running out of time. + */ + struct serial_numbers serials; /** Used by certstack. Points to the next stacked certificate. */ SLIST_ENTRY(certificate) next; @@ -131,6 +140,12 @@ abort1: return error; } +static void +serial_cleanup(BIGNUM **serial) +{ + BN_free(*serial); +} + void validation_destroy(struct validation *state) { @@ -149,6 +164,7 @@ validation_destroy(struct validation *state) cert = SLIST_FIRST(&state->certs); SLIST_REMOVE_HEAD(&state->certs, next); resources_destroy(cert->resources); + serial_numbers_cleanup(&cert->serials, serial_cleanup); free(cert); c++; } @@ -211,15 +227,18 @@ validation_push_cert(struct validation *state, struct rpki_uri const *cert_uri, } cert->uri = *cert_uri; + error = serial_numbers_init(&cert->serials); + if (error) + goto end2; cert->resources = resources_create(); if (cert->resources == NULL) { error = pr_enomem(); - goto end2; + goto end3; } error = certificate_get_resources(x509, cert->resources); if (error) - goto end3; + goto end4; /* * rfc7730#section-2.2 @@ -230,21 +249,22 @@ validation_push_cert(struct validation *state, struct rpki_uri const *cert_uri, */ if (is_ta && resources_empty(cert->resources)) { error = pr_err("Trust Anchor certificate does not define any number resources."); - goto end3; + goto end4; } ok = sk_X509_push(state->trusted, x509); if (ok <= 0) { error = crypto_err( "Couldn't add certificate to trusted stack: %d", ok); - goto end3; + goto end4; } SLIST_INSERT_HEAD(&state->certs, cert, next); return 0; -end3: resources_destroy(cert->resources); +end4: resources_destroy(cert->resources); +end3: serial_numbers_cleanup(&cert->serials, serial_cleanup); end2: free(cert); end1: return error; } @@ -262,6 +282,7 @@ validation_pop_cert(struct validation *state) return pr_crit("Attempted to pop empty certificate stack (2)"); SLIST_REMOVE_HEAD(&state->certs, next); resources_destroy(cert->resources); + serial_numbers_cleanup(&cert->serials, serial_cleanup); free(cert); return 0; @@ -286,3 +307,30 @@ validation_peek_resource(struct validation *state) struct certificate *cert = SLIST_FIRST(&state->certs); return (cert != NULL) ? cert->resources : NULL; } + +int +validation_store_serial_number(struct validation *state, BIGNUM *number) +{ + struct certificate *cert; + BIGNUM **cursor; + BIGNUM *duplicate; + int error; + + cert = SLIST_FIRST(&state->certs); + if (cert == NULL) + return 0; /* The TA lacks siblings, so serial is unique. */ + + ARRAYLIST_FOREACH(&cert->serials, cursor) + if (BN_cmp(*cursor, number) == 0) + return pr_err("Serial number is not unique."); + + duplicate = BN_dup(number); + if (duplicate == NULL) + return crypto_err("Could not duplicate a BIGNUM"); + + error = serial_numbers_add(&cert->serials, &duplicate); + if (error) + BN_free(duplicate); + + return error; +} diff --git a/src/state.h b/src/state.h index 44e4f3fe..142d3abc 100644 --- a/src/state.h +++ b/src/state.h @@ -32,4 +32,6 @@ struct rpki_uri const *validation_peek_cert_uri(struct validation *); struct resources *validation_peek_resource(struct validation *); +int validation_store_serial_number(struct validation *, BIGNUM *); + #endif /* SRC_STATE_H_ */