From: pcarana Date: Tue, 23 Jul 2019 22:28:10 +0000 (-0500) Subject: Fix some BGPsec issues and complete output printing. X-Git-Tag: v1.1.0~1^2~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=43c7412d6fc27585c1a44ff36cac65c4dcbe2ebf;p=thirdparty%2FFORT-validator.git Fix some BGPsec issues and complete output printing. -The SLURM BGPsec arrays were loading only 1 element, and the AS wasn't set when filtering router keys (programmer errors ¬¬). -Validate SLURM routerPublicKey as a SubjectPublicKeyInfo struct, including the expected algorithms for BGPsec certificates. -Print router key info as base64url encoded strings, and update headers. --- diff --git a/src/crypto/base64.c b/src/crypto/base64.c index 6f8394b2..3366e72b 100644 --- a/src/crypto/base64.c +++ b/src/crypto/base64.c @@ -2,8 +2,10 @@ #include #include +#include #include #include +#include "log.h" /** * Converts error from libcrypto representation to this project's @@ -198,3 +200,79 @@ free_copy: free(str_copy); return error; } + +static int +to_base64url(char *base, size_t base_len, char **out) +{ + char *pad, *tmp; + size_t len; + int i; + + /* Remove padding, if present */ + len = base_len; + do { + pad = strchr(base, '='); + if (pad == NULL) + break; + len = pad - base; + } while(0); + + tmp = malloc(len + 1); + if (tmp == NULL) + return pr_enomem(); + + memcpy(tmp, base, len); + tmp[len] = '\0'; + + for (i = 0; i < len; i++) { + if (tmp[i] == '+') + tmp[i] = '-'; + else if (tmp[i] == '/') + tmp[i] = '_'; + } + + *out = tmp; + return 0; +} + +/* + * Encode @in (with size @in_len) as base64url without trailing pad, and + * allocate at @result. + */ +int +base64url_encode(unsigned char const *in, int in_len, char **result) +{ + BIO *b64, *mem; + BUF_MEM *mem_buf; + int error; + + ERR_clear_error(); + + mem = BIO_new(BIO_s_mem()); + if (mem == NULL) { + error = ERR_peek_last_error(); + return error ? error_ul2i(error) : -ENOMEM; + } + + b64 = BIO_new(BIO_f_base64()); + if (b64 == NULL) { + error = ERR_peek_last_error(); + goto free_mem; + } + mem = BIO_push(b64, mem); + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + + BIO_write(b64, in, in_len); + BIO_flush(b64); + BIO_get_mem_ptr(mem, &mem_buf); + + error = to_base64url(mem_buf->data, mem_buf->length, result); + if (error) + goto free_mem; + + BIO_free_all(b64); + return 0; +free_mem: + BIO_free_all(b64); + return error ? error_ul2i(error) : -ENOMEM;; +} diff --git a/src/crypto/base64.h b/src/crypto/base64.h index a3d83ddd..a545b0f9 100644 --- a/src/crypto/base64.h +++ b/src/crypto/base64.h @@ -8,4 +8,6 @@ int base64_decode(BIO *, unsigned char *, bool, size_t, size_t *); int base64url_decode(char const *, unsigned char **, size_t *); +int base64url_encode(unsigned char const *, int, char **); + #endif /* SRC_BASE64_H_ */ diff --git a/src/output_printer.c b/src/output_printer.c index a73319d5..37a44909 100644 --- a/src/output_printer.c +++ b/src/output_printer.c @@ -6,6 +6,7 @@ #include "config.h" #include "file.h" #include "log.h" +#include "crypto/base64.h" #include "rtr/db/vrp.h" char addr_buf[INET6_ADDRSTRLEN]; @@ -74,51 +75,28 @@ print_roa(struct vrp const *vrp, void *arg) return 0; } -static int -print_to_hex(unsigned char const *data, size_t len, char **out) -{ - char *tmp; - char *init; - int i; - - tmp = malloc(len * 3 + 1); - if (tmp == NULL) - return pr_enomem(); - - init = tmp; - for (i = 0; i < len * 3; i+=3) { - *tmp = ':'; - tmp++; - tmp += sprintf(tmp, "%02X", data[i/3]); - } - *tmp = '\0'; - - *out = init; - return 0; -} - -/* - * FIXME Improve this calls, maybe base64 encode and print? - */ +/* Print as base64url strings without trailing pad */ static int print_router_key(struct router_key const *key, void *arg) { FILE *out = arg; - char *buf1; - char *buf2; + char *buf1, *buf2; int error; - error = print_to_hex(key->ski, RK_SKI_LEN, &buf1); + error = base64url_encode(key->ski, RK_SKI_LEN, &buf1); if (error) return error; - error = print_to_hex(key->spk, RK_SPKI_LEN, &buf2); + + error = base64url_encode(key->spk, RK_SPKI_LEN, &buf2); if (error) - return error; + goto free1; + fprintf(out, "AS%u,%s,%s\n", key->as, buf1, buf2); - free(buf1); - free(buf2); - return 0; + free(buf2); +free1: + free(buf1); + return error; } static int @@ -169,7 +147,7 @@ print_router_keys(struct db_table *db) if (error) return; - fprintf(out, "ASN,SKI,SPK\n"); + fprintf(out, "ASN,Subject Key Identifier,Subject Public Key Info\n"); error = db_table_foreach_router_key(db, print_router_key, out); if (fopen) file_close(out); diff --git a/src/slurm/slurm_db.c b/src/slurm/slurm_db.c index 55410d6f..5f683be9 100644 --- a/src/slurm/slurm_db.c +++ b/src/slurm/slurm_db.c @@ -202,6 +202,7 @@ slurm_db_bgpsec_is_filtered(struct router_key const *key) return false; } slurm_bgpsec.data_flag = SLURM_COM_FLAG_ASN | SLURM_BGPS_FLAG_SKI; + slurm_bgpsec.asn = key->as; memcpy(tmp, key->ski, RK_SKI_LEN); slurm_bgpsec.ski = tmp; /* Router public key isn't used at filters */ diff --git a/src/slurm/slurm_parser.c b/src/slurm/slurm_parser.c index ab19bb65..a432de27 100644 --- a/src/slurm/slurm_parser.c +++ b/src/slurm/slurm_parser.c @@ -4,10 +4,12 @@ #include #include #include +#include #include /* AF_INET, AF_INET6 (needed in OpenBSD) */ #include /* AF_INET, AF_INET6 (needed in OpenBSD) */ #include "crypto/base64.h" +#include "algorithm.h" #include "log.h" #include "address.h" #include "json_parser.h" @@ -264,6 +266,36 @@ set_ski(json_t *object, bool is_assertion, struct slurm_bgpsec *result, return 0; } +/* + * Use the provided X509_PUBKEY struct, and validate expected algorithms for a + * BGPsec certificate. + */ +static int +validate_router_spki(unsigned char *data, size_t len) +{ + unsigned char const *tmp; + X509_PUBKEY *spki; + X509_ALGOR *pa; + ASN1_OBJECT *alg; + int ok; + int error; + + tmp = data; + spki = d2i_X509_PUBKEY(NULL, &tmp, len); + if (spki == NULL) + return crypto_err("Not a valid router public key"); + + ok = X509_PUBKEY_get0_param(&alg, NULL, NULL, &pa, spki); + if (!ok) { + X509_PUBKEY_free(spki); + return crypto_err("X509_PUBKEY_get0_param() returned %d", ok); + } + + error = validate_certificate_public_key_algorithm(pa, true); + X509_PUBKEY_free(spki); + return error; /* Error 0 is ok */ +} + static int set_router_pub_key(json_t *object, bool is_assertion, struct slurm_bgpsec *result, size_t *members_loaded) @@ -297,20 +329,15 @@ set_router_pub_key(json_t *object, bool is_assertion, return pr_err("'%s' couldn't be decoded", str_encoded); /* - * TODO (next iteration) Reuse the functions to validate that - * 'routerPublicKey' is: "the equivalent to the subjectPublicKeyInfo - * value of the router certificate's public key, as described in - * [RFC8208]. This is the full ASN.1 DER encoding of the + * Validate that "is the full ASN.1 DER encoding of the * subjectPublicKeyInfo, including the ASN.1 tag and length values - * of the subjectPublicKeyInfo SEQUENCE. - * - * #include - * #include "asn1/decode.h" - * struct SubjectPublicKeyInfo *router_pki; - * error = asn1_decode(result->router_public_key, - * result->router_public_key_len, &asn_DEF_SubjectPublicKeyInfo, - * (void **) &router_pki); + * of the subjectPublicKeyInfo SEQUENCE." (RFC 8416 section 3.4.2) */ + error = validate_router_spki(result->router_public_key, spk_len); + if (error) { + free(result->router_public_key); + return error; + } result->data_flag = result->data_flag | SLURM_BGPS_FLAG_ROUTER_KEY; (*members_loaded)++; @@ -554,7 +581,7 @@ load_bgpsec_array(json_t *array, bool is_assertion) json_array_foreach(array, index, element) { error = load_single_bgpsec(element, is_assertion); if (!error) - break; + continue; if (error == -EEXIST) pr_err( "The bgpsec %s element #%d, is duplicated or covered by another %s; SLURM loading will be stopped", diff --git a/test/rtr/db/vrps_test.c b/test/rtr/db/vrps_test.c index 39a17766..b3c9c621 100644 --- a/test/rtr/db/vrps_test.c +++ b/test/rtr/db/vrps_test.c @@ -3,6 +3,7 @@ #include #include "crypto/base64.c" +#include "algorithm.c" #include "common.c" #include "file.c" #include "impersonator.c" diff --git a/test/rtr/pdu_handler_test.c b/test/rtr/pdu_handler_test.c index d1424bc9..da04f9bd 100644 --- a/test/rtr/pdu_handler_test.c +++ b/test/rtr/pdu_handler_test.c @@ -3,6 +3,7 @@ #include #include +#include "algorithm.c" #include "common.c" #include "file.c" #include "impersonator.c"