From: Alberto Leiva Popper Date: Fri, 18 Jan 2019 20:09:12 +0000 (-0600) Subject: More misc tweaks: X-Git-Tag: v0.0.2~111 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=004a23588ec9990cde21931584f0e0a15d3659ad;p=thirdparty%2FFORT-validator.git More misc tweaks: - Validate more certificate extensions - Ensure there is only one visible CRL and manifest per publication point. - Validate ROA's max length more thoroughly. --- diff --git a/src/asn1/signed_data.c b/src/asn1/signed_data.c index 25650b29..2081f8bd 100644 --- a/src/asn1/signed_data.c +++ b/src/asn1/signed_data.c @@ -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; diff --git a/src/crypto/hash.c b/src/crypto/hash.c index 1d998842..d533cb51 100644 --- a/src/crypto/hash.c +++ b/src/crypto/hash.c @@ -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); } diff --git a/src/crypto/hash.h b/src/crypto/hash.h index 3e771c5f..9232caa6 100644 --- a/src/crypto/hash.h +++ b/src/crypto/hash.h @@ -2,12 +2,15 @@ #define SRC_HASH_H_ #include +#include #include #include -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_ */ diff --git a/src/main.c b/src/main.c index 72e95f95..e7eface4 100644 --- a/src/main.c +++ b/src/main.c @@ -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; diff --git a/src/object/certificate.c b/src/object/certificate.c index da744fe7..cb18e7ba 100644 --- a/src/object/certificate.c +++ b/src/object/certificate.c @@ -1,6 +1,7 @@ #include "certificate.h" #include +#include /* SIZE_MAX */ #include #include #include @@ -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); } diff --git a/src/object/manifest.c b/src/object/manifest.c index 4a31e5d8..cf95506f 100644 --- a/src/object/manifest.c +++ b/src/object/manifest.c @@ -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; diff --git a/src/object/roa.c b/src/object/roa.c index 4cd1d923..3fbf2181 100644 --- a/src/object/roa.c +++ b/src/object/roa.c @@ -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 diff --git a/src/state.c b/src/state.c index e2205f97..f0a8e62e 100644 --- a/src/state.c +++ b/src/state.c @@ -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) { diff --git a/src/state.h b/src/state.h index 0172ead3..0c97b0f4 100644 --- a/src/state.h +++ b/src/state.h @@ -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 *);