From: pcarana Date: Wed, 10 Jul 2019 22:48:31 +0000 (-0500) Subject: Read and validate BGPsec router certificates X-Git-Tag: v1.1.0~1^2~19 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5933cd8c492f07bff8e761fa90e7c0424e67e9b6;p=thirdparty%2FFORT-validator.git Read and validate BGPsec router certificates -Prepare structs and functions to send RTRv1 router key PDUs. -Basic preparation to store router keys, still needs more work. -Validate BGPsec certificates based on RFCs 8209 and 8608. -Configure RTRv1 intervals (refresh, retry, expire), more validations and logic are pending. -Update sorted array to allow iterations on its elements. --- diff --git a/src/Makefile.am b/src/Makefile.am index 1155489e..7aea1e14 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -61,12 +61,14 @@ fort_SOURCES += data_structure/uthash_nonfatal.h fort_SOURCES += incidence/incidence.h incidence/incidence.c +fort_SOURCES += object/bgpsec.h object/bgpsec.c fort_SOURCES += object/certificate.h object/certificate.c fort_SOURCES += object/crl.h object/crl.c fort_SOURCES += object/ghostbusters.h object/ghostbusters.c fort_SOURCES += object/manifest.h object/manifest.c fort_SOURCES += object/name.h object/name.c fort_SOURCES += object/roa.h object/roa.c +fort_SOURCES += object/router_key.h fort_SOURCES += object/signed_object.h object/signed_object.c fort_SOURCES += object/tal.h object/tal.c fort_SOURCES += object/vcard.h object/vcard.c diff --git a/src/algorithm.c b/src/algorithm.c index 02e93eb9..98254f73 100644 --- a/src/algorithm.c +++ b/src/algorithm.c @@ -2,6 +2,8 @@ #include #include +#include + #include "log.h" static bool @@ -30,18 +32,40 @@ validate_certificate_signature_algorithm(int nid, char const *what) } int -validate_certificate_public_key_algorithm(int nid) +validate_certificate_public_key_algorithm(X509_ALGOR *pa, bool is_bgpsec) { + int nid; + /* * RFC says sha256WithRSAEncryption, but current IETF concensus (and * practice) say that the right one is rsaEncryption. * https://mailarchive.ietf.org/arch/browse/sidr/ */ - if (nid == NID_rsaEncryption) - return 0; + nid = OBJ_obj2nid(pa->algorithm); + if (!is_bgpsec) { + if (nid == NID_rsaEncryption) + return 0; + return pr_err("Certificate's public key format is NID '%s', not rsaEncryption.", + OBJ_nid2sn(nid)); + } + + /* Validate algorithm and parameters (RFC 8608#section-3.1.1) */ + if (nid != NID_X9_62_id_ecPublicKey) + return pr_err("Certificate's public key format is NID '%s', not id-ecPublicKey.", + OBJ_nid2sn(nid)); - return pr_err("Certificate's public key format is NID '%d', not rsaEncryption.", - nid); + if (pa->parameter == NULL) + return pr_err("Certificate's public key algorithm MUST have parameters"); + + if (pa->parameter->type != V_ASN1_OBJECT) + return pr_err("Certificate's public key parameter type isn't valid"); + + nid = OBJ_obj2nid((ASN1_OBJECT *)pa->parameter->value.object); + if (nid != NID_X9_62_prime256v1) + return pr_err("Certificate's public key format is NID '%s', not secp256r1 (a.k.a prime256v1).", + OBJ_nid2sn(nid)); + + return 0; } int diff --git a/src/algorithm.h b/src/algorithm.h index 1ab5201c..460620f3 100644 --- a/src/algorithm.h +++ b/src/algorithm.h @@ -1,6 +1,8 @@ #ifndef SRC_ALGORITHM_H_ #define SRC_ALGORITHM_H_ +#include +#include #include "asn1/asn1c/AlgorithmIdentifier.h" #include "asn1/asn1c/OBJECT_IDENTIFIER.h" @@ -9,7 +11,7 @@ */ int validate_certificate_signature_algorithm(int, char const *); -int validate_certificate_public_key_algorithm(int); +int validate_certificate_public_key_algorithm(X509_ALGOR *, bool); int validate_cms_hashing_algorithm(AlgorithmIdentifier_t *, char const *); int validate_cms_hashing_algorithm_oid(OBJECT_IDENTIFIER_t *, char const *); diff --git a/src/asn1/signed_data.c b/src/asn1/signed_data.c index d4a1a7ef..732ffd40 100644 --- a/src/asn1/signed_data.c +++ b/src/asn1/signed_data.c @@ -93,7 +93,7 @@ handle_sdata_certificate(ANY_t *cert_encoded, struct signed_object_args *args, error = certificate_validate_chain(cert, args->crls); if (error) goto end2; - error = certificate_validate_rfc6487(cert, false); + error = certificate_validate_rfc6487(cert, EE); if (error) goto end2; error = certificate_validate_extensions_ee(cert, sid, &args->refs, @@ -105,7 +105,7 @@ handle_sdata_certificate(ANY_t *cert_encoded, struct signed_object_args *args, goto end2; resources_set_policy(args->res, policy); - error = certificate_get_resources(cert, args->res); + error = certificate_get_resources(cert, args->res, EE); if (error) goto end2; diff --git a/src/cert_stack.c b/src/cert_stack.c index cd70e470..61943e44 100644 --- a/src/cert_stack.c +++ b/src/cert_stack.c @@ -7,7 +7,6 @@ #include "thread_var.h" #include "data_structure/array_list.h" #include "object/name.h" -#include "object/certificate.h" enum defer_node_type { DNT_SEPARATOR, @@ -265,7 +264,7 @@ deferstack_is_empty(struct cert_stack *stack) /** Steals ownership of @x509 on success. */ int x509stack_push(struct cert_stack *stack, struct rpki_uri *uri, X509 *x509, - enum rpki_policy policy, bool is_ta) + enum rpki_policy policy, enum cert_type type) { struct metadata_node *meta; struct defer_node *defer_separator; @@ -287,7 +286,7 @@ x509stack_push(struct cert_stack *stack, struct rpki_uri *uri, X509 *x509, goto end4; } resources_set_policy(meta->resources, policy); - error = certificate_get_resources(x509, meta->resources); + error = certificate_get_resources(x509, meta->resources, type); if (error) goto end5; @@ -298,7 +297,7 @@ x509stack_push(struct cert_stack *stack, struct rpki_uri *uri, X509 *x509, * The "It MUST NOT use the "inherit" form of the INR extension(s)" * part is already handled in certificate_get_resources(). */ - if (is_ta && resources_empty(meta->resources)) { + if (type == TA && resources_empty(meta->resources)) { error = pr_err("Trust Anchor certificate does not define any number resources."); goto end5; } diff --git a/src/cert_stack.h b/src/cert_stack.h index 6e0533c3..4ff617c3 100644 --- a/src/cert_stack.h +++ b/src/cert_stack.h @@ -4,6 +4,7 @@ #include #include "resource.h" #include "uri.h" +#include "object/certificate.h" #include "object/name.h" /* @@ -41,7 +42,7 @@ int deferstack_pop(struct cert_stack *, struct deferred_cert *cert); bool deferstack_is_empty(struct cert_stack *); int x509stack_push(struct cert_stack *, struct rpki_uri *, X509 *, - enum rpki_policy, bool); + enum rpki_policy, enum cert_type); void x509stack_cancel(struct cert_stack *); X509 *x509stack_peek(struct cert_stack *); struct rpki_uri *x509stack_peek_uri(struct cert_stack *); diff --git a/src/config.c b/src/config.c index d1440dfd..a7737683 100644 --- a/src/config.c +++ b/src/config.c @@ -58,15 +58,13 @@ struct rpki_config { /** Outstanding connections in the socket's listen queue */ unsigned int backlog; - /** Interval used to look for updates at VRPs location */ - unsigned int validation_interval; - - /* - * TODO (next iteration) Intervals used at End of data PDU - * uint32_t refresh_interval; - * uint32_t retry_interval; - * uint32_t expire_interval; - */ + struct { + /** Interval used to look for updates at VRPs location */ + unsigned int validation; + unsigned int refresh; + unsigned int retry; + unsigned int expire; + } interval; } server; struct { @@ -226,10 +224,10 @@ static const struct option_field options[] = { .max = SOMAXCONN, }, { .id = 5003, - .name = "server.validation-interval", + .name = "server.interval.validation", .type = >_uint, .offset = offsetof(struct rpki_config, - server.validation_interval), + server.interval.validation), .doc = "Interval used to look for updates at VRPs location", /* * RFC 6810 and 8210: @@ -240,13 +238,55 @@ static const struct option_field options[] = { */ .min = 60, .max = UINT_MAX, + }, { + .id = 5004, + .name = "server.interval.refresh", + .type = >_uint, + .offset = offsetof(struct rpki_config, + server.interval.refresh), + .doc = "Interval between normal cache polls", // TODO + /* + * RFC 6810 and 8210: + * "The cache MUST rate-limit Serial Notifies to no more + * frequently than one per minute." + * We do this by not getting new information more than once per + * minute. + */ + .min = 1, + .max = 86400, + }, { + .id = 5005, + .name = "server.interval.retry", + .type = >_uint, + .offset = offsetof(struct rpki_config, + server.interval.retry), + .doc = "Interval between cache poll retries after a failed cache poll", // TODO + /* + * RFC 6810 and 8210: + * "The cache MUST rate-limit Serial Notifies to no more + * frequently than one per minute." + * We do this by not getting new information more than once per + * minute. + */ + .min = 1, + .max = 7200, + }, { + .id = 5006, + .name = "server.interval.expire", + .type = >_uint, + .offset = offsetof(struct rpki_config, + server.interval.expire), + .doc = "Interval during which data fetched from a cache remains valid in the absence of a successful subsequent cache poll", // TODO + /* + * RFC 6810 and 8210: + * "The cache MUST rate-limit Serial Notifies to no more + * frequently than one per minute." + * We do this by not getting new information more than once per + * minute. + */ + .min = 600, + .max = 172800, }, - /* - * TODO (next iteration) RTRv1 intervals with values: - * - refresh: min = 1, max = 86400, default = 3600 - * - retry: min = 1, max = 7200, default = 600 - * - expire: min = 600, max = 172800, default = 7200 - */ /* RSYNC fields */ { @@ -469,7 +509,10 @@ set_default_values(void) return pr_enomem(); rpki_config.server.backlog = SOMAXCONN; - rpki_config.server.validation_interval = 3600; + rpki_config.server.interval.validation = 3600; + rpki_config.server.interval.refresh = 3600; + rpki_config.server.interval.retry = 600; + rpki_config.server.interval.expire = 7200; rpki_config.tal = NULL; rpki_config.slurm = NULL; @@ -522,6 +565,12 @@ revert_port: static int validate_config(void) { + if (rpki_config.server.interval.expire < + rpki_config.server.interval.refresh || + rpki_config.server.interval.expire < + rpki_config.server.interval.retry) + return pr_err("Expire interval must be greater than refresh and retry intervals"); + return (rpki_config.tal != NULL) ? 0 : pr_err("The TAL file/directory (--tal) is mandatory."); @@ -666,7 +715,25 @@ config_get_server_queue(void) unsigned int config_get_validation_interval(void) { - return rpki_config.server.validation_interval; + return rpki_config.server.interval.validation; +} + +unsigned int +config_get_interval_refresh(void) +{ + return rpki_config.server.interval.refresh; +} + +unsigned int +config_get_interval_retry(void) +{ + return rpki_config.server.interval.retry; +} + +unsigned int +config_get_interval_expire(void) +{ + return rpki_config.server.interval.expire; } char const * diff --git a/src/config.h b/src/config.h index 581cc382..ad6a9c34 100644 --- a/src/config.h +++ b/src/config.h @@ -19,6 +19,9 @@ char const *config_get_server_address(void); char const *config_get_server_port(void); int config_get_server_queue(void); unsigned int config_get_validation_interval(void); +unsigned int config_get_interval_refresh(void); +unsigned int config_get_interval_retry(void); +unsigned int config_get_interval_expire(void); char const *config_get_slurm(void); char const *config_get_tal(void); diff --git a/src/extension.c b/src/extension.c index 2baa428f..3301d95a 100644 --- a/src/extension.c +++ b/src/extension.c @@ -146,6 +146,16 @@ struct extension_metadata const *ext_cn(void) return &CN; } +struct extension_metadata const *ext_eku(void) +{ + static const struct extension_metadata EKU = { + "Extended Key Usage", + NID_ext_key_usage, + false, + }; + return &EKU; +} + static int handle_extension(struct extension_handler *handlers, X509_EXTENSION *ext) { diff --git a/src/extension.h b/src/extension.h index 74817ff6..54373186 100644 --- a/src/extension.h +++ b/src/extension.h @@ -36,6 +36,7 @@ struct extension_metadata const *ext_ar(void); struct extension_metadata const *ext_ir2(void); struct extension_metadata const *ext_ar2(void); struct extension_metadata const *ext_cn(void); +struct extension_metadata const *ext_eku(void); int handle_extensions(struct extension_handler *, STACK_OF(X509_EXTENSION) const *); diff --git a/src/nid.c b/src/nid.c index 7bbb148c..eb279830 100644 --- a/src/nid.c +++ b/src/nid.c @@ -12,6 +12,7 @@ static int NID_certPolicyRpki; static int NID_certPolicyRpkiV2; static int NID_ipAddrBlocksv2; static int NID_autonomousSysIdsv2; +static int NID_bgpsecRouter; static int register_oid(const char *oid, const char *sn, const char *ln) @@ -75,6 +76,12 @@ nid_init(void) if (NID_autonomousSysIdsv2 == 0) return -EINVAL; + NID_bgpsecRouter = register_oid("1.3.6.1.5.5.7.3.30", + "id-kp-bgpsec-router", + "BGPsec Extended Key Usage (RFC 8209)"); + if (NID_bgpsecRouter == 0) + return -EINVAL; + return 0; } @@ -118,3 +125,8 @@ int nid_autonomousSysIdsv2(void) { return NID_autonomousSysIdsv2; } + +int nid_bgpsecRouter(void) +{ + return NID_bgpsecRouter; +} diff --git a/src/nid.h b/src/nid.h index 2b34afc1..3d0f643d 100644 --- a/src/nid.h +++ b/src/nid.h @@ -11,5 +11,6 @@ int nid_certPolicyRpki(void); int nid_certPolicyRpkiV2(void); int nid_ipAddrBlocksv2(void); int nid_autonomousSysIdsv2(void); +int nid_bgpsecRouter(void); #endif /* SRC_NID_H_ */ diff --git a/src/object/bgpsec.c b/src/object/bgpsec.c new file mode 100644 index 00000000..e5bc894c --- /dev/null +++ b/src/object/bgpsec.c @@ -0,0 +1,64 @@ +#include "bgpsec.h" + +#include "log.h" +#include "validation_handler.h" + +struct resource_params { + struct router_key *router_key; + struct resources *resources; +}; + +static int +asn_cb(unsigned long asn, void *arg) +{ + struct resource_params *params = arg; + struct router_key router_key; + + if (!resources_contains_asn(params->resources, asn)) + return pr_err("BGPsec certificate is not allowed for ASN %lu.", + asn); + + memcpy(&router_key, params->router_key, sizeof(*params->router_key)); + router_key.asn = asn; + + return vhandler_handle_bgpsec(&router_key); +} + +int +handle_bgpsec(X509 *cert, unsigned char *ski, int ski_len, + struct resources *resources) +{ + /* + * FIXME: Store the public key, SKI, and the resources + */ + struct resource_params res_params; + struct router_key router_key; + ASN1_OBJECT *cert_alg; + X509_PUBKEY *pub_key; + unsigned char const *cert_spk; + int cert_spk_len; + int ok; + + pub_key = X509_get_X509_PUBKEY(cert); + if (pub_key == NULL) + return crypto_err("X509_get_X509_PUBKEY() returned NULL at BGPsec"); + + ok = X509_PUBKEY_get0_param(&cert_alg, &cert_spk, &cert_spk_len, NULL, + pub_key); + if (!ok) + return crypto_err("X509_PUBKEY_get0_param() returned %d at BGPsec", + ok); + + router_key.spk = cert_spk; + router_key.spk_len = cert_spk_len; + router_key.ski = ski; + router_key.ski_len = ski_len; + + res_params.router_key = &router_key; + res_params.resources = resources; + + ok = resources_foreach_asn(resources, asn_cb, &res_params); + /* FIXME Maybe this should be released elsewhere.. */ + free(ski); + return ok; +} diff --git a/src/object/bgpsec.h b/src/object/bgpsec.h new file mode 100644 index 00000000..c34eba40 --- /dev/null +++ b/src/object/bgpsec.h @@ -0,0 +1,9 @@ +#ifndef SRC_OBJECT_BGPSEC_H_ +#define SRC_OBJECT_BGPSEC_H_ + +#include +#include "resource.h" + +int handle_bgpsec(X509 *, unsigned char *, int, struct resources *); + +#endif /* SRC_OBJECT_BGPSEC_H_ */ diff --git a/src/object/certificate.c b/src/object/certificate.c index 37bc077c..dc27a79f 100644 --- a/src/object/certificate.c +++ b/src/object/certificate.c @@ -16,6 +16,7 @@ #include "asn1/asn1c/IPAddrBlocks.h" #include "crypto/hash.h" #include "object/name.h" +#include "object/bgpsec.h" #include "object/manifest.h" #include "rsync/rsync.h" @@ -39,6 +40,12 @@ struct sia_uris { struct rpki_uri **mft; }; +struct bgpsec_ski { + X509 *cert; + int *ski_len; + unsigned char **ski_data; +}; + static int validate_serial_number(X509 *cert) { @@ -211,9 +218,10 @@ fail1: } static int -validate_public_key(X509 *cert, bool is_root) +validate_public_key(X509 *cert, enum cert_type type) { X509_PUBKEY *pubkey; + X509_ALGOR *pa; ASN1_OBJECT *alg; int ok; int error; @@ -223,11 +231,11 @@ validate_public_key(X509 *cert, bool is_root) if (pubkey == NULL) return crypto_err("X509_get_X509_PUBKEY() returned NULL"); - ok = X509_PUBKEY_get0_param(&alg, NULL, NULL, NULL, pubkey); + ok = X509_PUBKEY_get0_param(&alg, NULL, NULL, &pa, pubkey); if (!ok) return crypto_err("X509_PUBKEY_get0_param() returned %d", ok); - error = validate_certificate_public_key_algorithm(OBJ_obj2nid(alg)); + error = validate_certificate_public_key_algorithm(pa, type == BGPSEC); if (error) return error; @@ -243,7 +251,7 @@ validate_public_key(X509 *cert, bool is_root) * getting the message. */ - if (is_root) { + if (type == TA) { error = validate_spki(pubkey); if (error) return error; @@ -253,7 +261,7 @@ validate_public_key(X509 *cert, bool is_root) } int -certificate_validate_rfc6487(X509 *cert, bool is_root) +certificate_validate_rfc6487(X509 *cert, enum cert_type type) { int error; @@ -285,7 +293,7 @@ certificate_validate_rfc6487(X509 *cert, bool is_root) return error; /* rfc6487#section-4.4 */ - error = validate_issuer(cert, is_root); + error = validate_issuer(cert, type == TA); if (error) return error; @@ -304,7 +312,7 @@ certificate_validate_rfc6487(X509 *cert, bool is_root) /* rfc6487#section-4.7 */ /* Fragment of rfc7730#section-2.2 */ - error = validate_public_key(cert, is_root); + error = validate_public_key(cert, type); if (error) return error; @@ -702,7 +710,8 @@ end: } static int -handle_asn_extension(X509_EXTENSION *ext, struct resources *resources) +handle_asn_extension(X509_EXTENSION *ext, struct resources *resources, + bool allow_inherit) { ASN1_OCTET_STRING *string; struct ASIdentifiers *ids; @@ -714,7 +723,7 @@ handle_asn_extension(X509_EXTENSION *ext, struct resources *resources) if (error) return error; - error = resources_add_asn(resources, ids); + error = resources_add_asn(resources, ids, allow_inherit); ASN_STRUCT_FREE(asn_DEF_ASIdentifiers, ids); return error; @@ -723,7 +732,7 @@ handle_asn_extension(X509_EXTENSION *ext, struct resources *resources) int __certificate_get_resources(X509 *cert, struct resources *resources, int addr_nid, int asn_nid, int bad_addr_nid, int bad_asn_nid, - char const *policy_rfc, char const *bad_ext_rfc) + char const *policy_rfc, char const *bad_ext_rfc, bool allow_asn_inherit) { X509_EXTENSION *ext; int nid; @@ -760,7 +769,8 @@ __certificate_get_resources(X509 *cert, struct resources *resources, return pr_err("The AS extension is not marked as critical."); pr_debug_add("ASN {"); - error = handle_asn_extension(ext, resources); + error = handle_asn_extension(ext, resources, + allow_asn_inherit); pr_debug_rm("}"); asn_ext_found = true; @@ -783,7 +793,8 @@ __certificate_get_resources(X509 *cert, struct resources *resources, } int -certificate_get_resources(X509 *cert, struct resources *resources) +certificate_get_resources(X509 *cert, struct resources *resources, + enum cert_type type) { enum rpki_policy policy; @@ -793,12 +804,12 @@ certificate_get_resources(X509 *cert, struct resources *resources) return __certificate_get_resources(cert, resources, NID_sbgp_ipAddrBlock, NID_sbgp_autonomousSysNum, nid_ipAddrBlocksv2(), nid_autonomousSysIdsv2(), - "6484", "8360"); + "6484", "8360", type != BGPSEC); case RPKI_POLICY_RFC8360: return __certificate_get_resources(cert, resources, nid_ipAddrBlocksv2(), nid_autonomousSysIdsv2(), NID_sbgp_ipAddrBlock, NID_sbgp_autonomousSysNum, - "8360", "6484"); + "8360", "6484", type != BGPSEC); } pr_crit("Unknown policy: %u", policy); @@ -921,6 +932,36 @@ end: return error; } +static int +handle_ski_bgpsec(X509_EXTENSION *ext, void *arg) +{ + ASN1_OCTET_STRING *ski; + struct bgpsec_ski *params; + unsigned char *tmp; + int error; + + ski = X509V3_EXT_d2i(ext); + if (ski == NULL) + return cannot_decode(ext_ski()); + + params = arg; + error = validate_public_key_hash(params->cert, ski); + if (error) + goto end; + + tmp = malloc(ski->length + 1); + if (tmp == NULL) + goto end; + + (*params->ski_len) = ski->length; + memcpy(tmp, ski->data, ski->length); + *params->ski_data = tmp; + +end: + ASN1_OCTET_STRING_free(ski); + return error; +} + static int handle_aki_ta(X509_EXTENSION *ext, void *arg) { @@ -1313,6 +1354,37 @@ handle_ar(X509_EXTENSION *ext, void *arg) return 0; /* Handled in certificate_get_resources(). */ } +static int +handle_eku(X509_EXTENSION *ext, void *arg) +{ + EXTENDED_KEY_USAGE *eku; + int nid; + int error; + + eku = X509V3_EXT_d2i(ext); + if (eku == NULL) + return cannot_decode(ext_eku()); + + /* + * RFC 8209 allows multiple KeyPurposeId, so look only for the one + * required and specified at section 3.1.3.2 + */ + error = -ENOENT; + while (sk_ASN1_OBJECT_num(eku) > 0) { + nid = OBJ_obj2nid(sk_ASN1_OBJECT_pop(eku)); + if (nid == nid_bgpsecRouter()) { + error = 0; + goto end; + } + } + + if (error) + pr_err("Extended Key Usage doesn't include id-kp-bgpsec-router."); +end: + EXTENDED_KEY_USAGE_free(eku); + return error; +} + /** * Validates the certificate extensions, Trust Anchor style. * @@ -1383,6 +1455,32 @@ certificate_validate_extensions_ca(X509 *cert, struct rpki_uri **mft, return handle_extensions(handlers, X509_get0_extensions(cert)); } +static int +certificate_validate_extensions_bgpsec(X509 *cert, unsigned char **ski, + int *ski_len, struct certificate_refs *refs, enum rpki_policy *policy) +{ + struct bgpsec_ski ski_param; + struct extension_handler handlers[] = { + /* ext reqd handler arg */ + { ext_ski(), true, handle_ski_bgpsec, &ski_param }, + { ext_aki(), true, handle_aki, }, + { ext_ku(), true, handle_ku_ee, }, + { ext_cdp(), true, handle_cdp, refs }, + { ext_aia(), true, handle_aia, refs }, + { ext_cp(), true, handle_cp, policy }, + { ext_eku(), true, handle_eku, }, + { ext_ar(), false, handle_ar, }, + { ext_ar2(), false, handle_ar, }, + { NULL }, + }; + + ski_param.cert = cert; + ski_param.ski_data = ski; + ski_param.ski_len = ski_len; + + return handle_extensions(handlers, X509_get0_extensions(cert)); +} + int certificate_validate_extensions_ee(X509 *cert, OCTET_STRING_t *sid, struct certificate_refs *refs, enum rpki_policy *policy) @@ -1410,6 +1508,18 @@ certificate_validate_extensions_ee(X509 *cert, OCTET_STRING_t *sid, return handle_extensions(handlers, X509_get0_extensions(cert)); } +static enum cert_type +get_certificate_type(X509 *cert, bool is_ta) +{ + if (is_ta) + return TA; + if (X509_get_ext_by_NID(cert, ext_bc()->nid, -1) >= 0) + return CA; + if (X509_get_ext_by_NID(cert, NID_ext_key_usage, -1) >= 0) + return BGPSEC; + return EE; +} + /** Boilerplate code for CA certificate validation and recursive traversal. */ int certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri) @@ -1424,9 +1534,12 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri) struct rpki_uri *mft; struct rpki_uri *caRepository; struct certificate_refs refs; + unsigned char *ski; enum rpki_policy policy; + enum cert_type type; struct rpp *pp; bool mft_retry; + int ski_len; int error; state = state_retrieve(); @@ -1436,8 +1549,14 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri) if (total_parents >= config_get_max_cert_depth()) return pr_err("Certificate chain maximum depth exceeded."); - pr_debug_add("%s Certificate '%s' {", IS_TA ? "TA" : "CA", - uri_get_printable(cert_uri)); +#ifdef DEBUG + if (IS_TA) + pr_debug_add("TA Certificate '%s' {", + uri_get_printable(cert_uri)); + else + pr_debug_add("Certificate '%s' {", + uri_get_printable(cert_uri)); +#endif fnstack_push_uri(cert_uri); memset(&refs, 0, sizeof(refs)); @@ -1452,26 +1571,63 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri) error = certificate_validate_chain(cert, rpp_parent_crl); if (error) goto revert_cert; - error = certificate_validate_rfc6487(cert, IS_TA); + + type = get_certificate_type(cert, IS_TA); +#ifdef DEBUG + switch(type) { + case TA: + break; + case CA: + pr_debug("Type: CA"); + break; + case BGPSEC: + pr_debug("Type: BGPsec EE"); + break; + case EE: + pr_debug("Type: unexpected, validated as CA"); + break; + } +#endif + error = certificate_validate_rfc6487(cert, type); if (error) goto revert_cert; - error = IS_TA - ? certificate_validate_extensions_ta(cert, &mft, &caRepository, - &policy) - : certificate_validate_extensions_ca(cert, &mft, &caRepository, - &refs, &policy); + switch (type) { + case TA: + error = certificate_validate_extensions_ta(cert, &mft, + &caRepository, &policy); + break; + case BGPSEC: + error = certificate_validate_extensions_bgpsec(cert, &ski, + &ski_len, &refs, &policy); + break; + default: + /* Validate as a CA */ + error = certificate_validate_extensions_ca(cert, &mft, + &caRepository, &refs, &policy); + break; + } if (error) goto revert_cert; error = refs_validate_ca(&refs, rpp_parent); if (error) - goto revert_uri_and_refs; + goto revert_uris; /* -- Validate the manifest (@mft) pointed by the certificate -- */ error = x509stack_push(validation_certstack(state), cert_uri, cert, - policy, IS_TA); + policy, type); if (error) - goto revert_uri_and_refs; + goto revert_uris; + + if (type == BGPSEC) { + /* This is an EE, so there's no manifest to process */ + error = handle_bgpsec(cert, ski, ski_len, + x509stack_peek_resources(validation_certstack(state))); + cert = NULL; /* Ownership stolen at x509stack_push */ + x509stack_cancel(validation_certstack(state)); + + goto revert_refs; + } cert = NULL; /* Ownership stolen */ /* @@ -1502,16 +1658,17 @@ certificate_traverse(struct rpp *rpp_parent, struct rpki_uri *cert_uri) if (error) { x509stack_cancel(validation_certstack(state)); - goto revert_uri_and_refs; + goto revert_uris; } /* -- Validate & traverse the RPP (@pp) described by the manifest -- */ rpp_traverse(pp); rpp_refput(pp); -revert_uri_and_refs: +revert_uris: uri_refput(caRepository); uri_refput(mft); +revert_refs: refs_cleanup(&refs); revert_cert: if (cert != NULL) diff --git a/src/object/certificate.h b/src/object/certificate.h index 5167cf80..758a469d 100644 --- a/src/object/certificate.h +++ b/src/object/certificate.h @@ -10,6 +10,14 @@ #include "asn1/asn1c/ANY.h" #include "asn1/asn1c/SignatureValue.h" +/* Certificate types in the RPKI */ +enum cert_type { + TA, /* Trust Anchor */ + CA, /* Certificate Authority */ + BGPSEC, /* BGPsec certificates */ + EE, /* End Entity certificates */ +}; + int certificate_load(struct rpki_uri *, X509 **); /** @@ -21,7 +29,7 @@ int certificate_validate_chain(X509 *, STACK_OF(X509_CRL) *); * Validates RFC 6487 compliance. * (Except extensions.) */ -int certificate_validate_rfc6487(X509 *, bool); +int certificate_validate_rfc6487(X509 *, enum cert_type); int certificate_validate_signature(X509 *, ANY_t *coded, SignatureValue_t *); @@ -34,7 +42,7 @@ int certificate_validate_signature(X509 *, ANY_t *coded, SignatureValue_t *); * not care about order. I don't know if you'll find other reasons if you choose * to migrate it. */ -int certificate_get_resources(X509 *, struct resources *); +int certificate_get_resources(X509 *, struct resources *, enum cert_type); /** * Validates the certificate extensions, End-Entity style. diff --git a/src/object/router_key.h b/src/object/router_key.h new file mode 100644 index 00000000..622be74f --- /dev/null +++ b/src/object/router_key.h @@ -0,0 +1,15 @@ +#ifndef SRC_OBJECT_ROUTER_KEY_H_ +#define SRC_OBJECT_ROUTER_KEY_H_ + +/* + * Roouter Key representation + */ +struct router_key { + unsigned char *ski; + size_t ski_len; + uint32_t asn; + unsigned char *spk; + size_t spk_len; +}; + +#endif /* SRC_OBJECT_ROUTER_KEY_H_ */ diff --git a/src/resource.c b/src/resource.c index fcbe7b96..fd655f2c 100644 --- a/src/resource.c +++ b/src/resource.c @@ -9,7 +9,6 @@ #include "thread_var.h" #include "resource/ip4.h" #include "resource/ip6.h" -#include "resource/asn.h" #include @@ -535,7 +534,8 @@ add_asiors(struct resources *resources, struct ASIdentifiers *ids) } int -resources_add_asn(struct resources *resources, struct ASIdentifiers *ids) +resources_add_asn(struct resources *resources, struct ASIdentifiers *ids, + bool allow_inherit) { if (ids->asnum == NULL) return pr_err("ASN extension lacks 'asnum' element."); @@ -544,6 +544,9 @@ resources_add_asn(struct resources *resources, struct ASIdentifiers *ids) switch (ids->asnum->present) { case ASIdentifierChoice_PR_inherit: + if (!allow_inherit) + return pr_err("ASIdentifierChoice %u isn't allowed", + ids->asnum->present); return inherit_asiors(resources); case ASIdentifierChoice_PR_asIdsOrRanges: return add_asiors(resources, ids); @@ -591,3 +594,9 @@ resources_set_policy(struct resources *res, enum rpki_policy policy) { res->policy = policy; } + +int +resources_foreach_asn(struct resources *res, foreach_asn_cb cb, void *arg) +{ + return rasn_foreach(res->asns, cb, arg); +} diff --git a/src/resource.h b/src/resource.h index 57ee2365..450c8c2e 100644 --- a/src/resource.h +++ b/src/resource.h @@ -3,6 +3,7 @@ #include #include "address.h" +#include "resource/asn.h" #include "asn1/asn1c/ASIdentifiers.h" #include "asn1/asn1c/IPAddressFamily.h" @@ -27,7 +28,7 @@ struct resources *resources_create(bool); void resources_destroy(struct resources *); int resources_add_ip(struct resources *, struct IPAddressFamily *); -int resources_add_asn(struct resources *, struct ASIdentifiers *); +int resources_add_asn(struct resources *, struct ASIdentifiers *, bool); bool resources_empty(struct resources *); bool resources_contains_asn(struct resources *, unsigned long); @@ -37,4 +38,6 @@ bool resources_contains_ipv6(struct resources *, struct ipv6_prefix *); enum rpki_policy resources_get_policy(struct resources *); void resources_set_policy(struct resources *, enum rpki_policy); +int resources_foreach_asn(struct resources *, foreach_asn_cb, void *); + #endif /* SRC_RESOURCE_H_ */ diff --git a/src/resource/asn.c b/src/resource/asn.c index d63803ac..62e5757d 100644 --- a/src/resource/asn.c +++ b/src/resource/asn.c @@ -1,6 +1,7 @@ #include "asn.h" #include +#include #include "log.h" #include "sorted_array.h" @@ -10,6 +11,11 @@ struct asn_node { unsigned long max; }; +struct asn_cb { + foreach_asn_cb cb; + void *arg; +}; + static enum sarray_comparison asn_cmp(void *arg1, void *arg2) { @@ -74,3 +80,39 @@ rasn_contains(struct resources_asn *asns, unsigned long min, unsigned long max) struct asn_node n = { min, max }; return sarray_contains((struct sorted_array *) asns, &n); } + +static int +asn_node_cb(void *elem, void *arg) +{ + struct asn_node *node = elem; + struct asn_cb *param = arg; + unsigned long index; + int error; + + for(index = node->min; index <= node->max; index++) { + error = param->cb(index, param->arg); + if (error) + return error; + if (index == ULONG_MAX) + break; + } + + return 0; +} + +int +rasn_foreach(struct resources_asn *asns, foreach_asn_cb cb, void *arg) +{ + struct asn_cb param; + int error; + + param.cb = cb; + param.arg = arg; + + rasn_get(asns); + error = sarray_foreach((struct sorted_array *) asns, asn_node_cb, + ¶m); + rasn_put(asns); + + return error; +} diff --git a/src/resource/asn.h b/src/resource/asn.h index 34f3733b..42c9dc44 100644 --- a/src/resource/asn.h +++ b/src/resource/asn.h @@ -14,4 +14,7 @@ int rasn_add(struct resources_asn *, unsigned long, unsigned long); bool rasn_empty(struct resources_asn *); bool rasn_contains(struct resources_asn *, unsigned long, unsigned long); +typedef int (*foreach_asn_cb)(unsigned long, void *); +int rasn_foreach(struct resources_asn *, foreach_asn_cb, void *); + #endif /* SRC_RESOURCE_ASN_H_ */ diff --git a/src/rtr/db/delta.c b/src/rtr/db/delta.c index 691bdc69..0fd087cc 100644 --- a/src/rtr/db/delta.c +++ b/src/rtr/db/delta.c @@ -17,8 +17,17 @@ struct delta_v6 { uint8_t max_length; }; +struct delta_bsec { + unsigned char *ski; + int *ski_len; + uint32_t as; + unsigned char *spk; + int *spk_len; +}; + ARRAY_LIST(deltas_v6, struct delta_v6) ARRAY_LIST(deltas_v4, struct delta_v4) +ARRAY_LIST(deltas_bgpsec, struct delta_bsec) struct deltas { struct { @@ -29,6 +38,10 @@ struct deltas { struct deltas_v6 adds; struct deltas_v6 removes; } v6; + struct { + struct deltas_bgpsec adds; + struct deltas_bgpsec removes; + } bgpsec; atomic_uint references; }; @@ -46,6 +59,8 @@ deltas_create(struct deltas **_result) deltas_v4_init(&result->v4.removes); deltas_v6_init(&result->v6.adds); deltas_v6_init(&result->v6.removes); + deltas_bgpsec_init(&result->bgpsec.adds); + deltas_bgpsec_init(&result->bgpsec.removes); atomic_init(&result->references, 1); *_result = result; @@ -70,6 +85,8 @@ deltas_refput(struct deltas *deltas) deltas_v4_cleanup(&deltas->v4.removes, NULL); deltas_v6_cleanup(&deltas->v6.adds, NULL); deltas_v6_cleanup(&deltas->v6.removes, NULL); + deltas_bgpsec_cleanup(&deltas->bgpsec.adds, NULL); + deltas_bgpsec_cleanup(&deltas->bgpsec.removes, NULL); free(deltas); } } @@ -114,20 +131,44 @@ deltas_add_roa_v6(struct deltas *deltas, uint32_t as, struct v6_address *addr, pr_crit("Unknown delta operation: %d", op); } +int +deltas_add_bgpsec(struct deltas *deltas, unsigned char *ski, int ski_len, + uint32_t as, unsigned char *spk, int spk_len, int op) +{ + struct delta_bsec delta = { + .ski = ski, + .ski_len = ski_len, + .as = as, + .spk = spk, + .spk_len = spk_len, + }; + + switch (op) { + case FLAG_ANNOUNCEMENT: + return deltas_bgpsec_add(&deltas->bgpsec.adds, &delta); + case FLAG_WITHDRAWAL: + return deltas_bgpsec_add(&deltas->bgpsec.removes, &delta); + } + + pr_crit("Unknown delta operation: %d", op); +} + bool deltas_is_empty(struct deltas *deltas) { return (deltas->v4.adds.len == 0) && (deltas->v4.removes.len == 0) && (deltas->v6.adds.len == 0) - && (deltas->v6.removes.len == 0); + && (deltas->v6.removes.len == 0) + && (deltas->bgpsec.adds.len == 0) + && (deltas->bgpsec.removes.len == 0); } static int -__foreach_v4(struct deltas_v4 *array, delta_foreach_cb cb, void *arg, +__foreach_v4(struct deltas_v4 *array, delta_vrp_foreach_cb cb, void *arg, serial_t serial, uint8_t flags) { - struct delta delta; + struct delta_vrp delta; struct delta_v4 *d; array_index i; int error; @@ -150,10 +191,10 @@ __foreach_v4(struct deltas_v4 *array, delta_foreach_cb cb, void *arg, } static int -__foreach_v6(struct deltas_v6 *array, delta_foreach_cb cb, void *arg, +__foreach_v6(struct deltas_v6 *array, delta_vrp_foreach_cb cb, void *arg, serial_t serial, uint8_t flags) { - struct delta delta; + struct delta_vrp delta; struct delta_v6 *d; array_index i; int error; @@ -175,27 +216,67 @@ __foreach_v6(struct deltas_v6 *array, delta_foreach_cb cb, void *arg, return 0; } +static int +__foreach_bgpsec(struct deltas_bgpsec *array, delta_bgpsec_foreach_cb cb, + void *arg, serial_t serial, uint8_t flags) +{ + struct delta_bgpsec delta; + struct delta_bsec *d; + array_index i; + int error; + + delta.serial = serial; + delta.flags = flags; + + ARRAYLIST_FOREACH(array, d, i) { + delta.router_key.ski = d->ski; + delta.router_key.ski_len = d->ski_len; + delta.router_key.asn = d->as; + delta.router_key.spk = d->spk; + delta.router_key.spk_len = d->spk_len; + error = cb(&delta, arg); + if (error) + return error; + } + + return 0; +} + int -deltas_foreach(serial_t serial, struct deltas *deltas, delta_foreach_cb cb, - void *arg) +deltas_foreach(serial_t serial, struct deltas *deltas, + delta_vrp_foreach_cb cb_vrp, delta_bgpsec_foreach_cb cb_bgpsec, void *arg) { int error; - error = __foreach_v4(&deltas->v4.adds, cb, arg, serial, + error = __foreach_v4(&deltas->v4.adds, cb_vrp, arg, serial, + FLAG_ANNOUNCEMENT); + if (error) + return error; + + error = __foreach_v4(&deltas->v4.removes, cb_vrp, arg, serial, + FLAG_WITHDRAWAL); + if (error) + return error; + + error = __foreach_v6(&deltas->v6.adds, cb_vrp, arg, serial, FLAG_ANNOUNCEMENT); if (error) return error; - error = __foreach_v4(&deltas->v4.removes, cb, arg, serial, + error = __foreach_v6(&deltas->v6.removes, cb_vrp, arg, serial, FLAG_WITHDRAWAL); if (error) return error; - error = __foreach_v6(&deltas->v6.adds, cb, arg, serial, + /* FIXME Temporary, this must not be null */ + if (cb_bgpsec == NULL) + return 0; + + error = __foreach_bgpsec(&deltas->bgpsec.adds, cb_bgpsec, arg, serial, FLAG_ANNOUNCEMENT); if (error) return error; - return __foreach_v6(&deltas->v6.removes, cb, arg, serial, + return __foreach_bgpsec(&deltas->bgpsec.removes, cb_bgpsec, arg, serial, FLAG_WITHDRAWAL); } diff --git a/src/rtr/db/delta.h b/src/rtr/db/delta.h index a3d66ae6..7512b317 100644 --- a/src/rtr/db/delta.h +++ b/src/rtr/db/delta.h @@ -12,8 +12,11 @@ void deltas_refput(struct deltas *); int deltas_add_roa_v4(struct deltas *, uint32_t, struct v4_address *, int); int deltas_add_roa_v6(struct deltas *, uint32_t, struct v6_address *, int); +int deltas_add_bgpsec(struct deltas *, unsigned char *, int, uint32_t, + unsigned char *, int, int); bool deltas_is_empty(struct deltas *); -int deltas_foreach(serial_t, struct deltas *, delta_foreach_cb , void *); +int deltas_foreach(serial_t, struct deltas *, delta_vrp_foreach_cb, + delta_bgpsec_foreach_cb, void *); #endif /* SRC_DELTA_H_ */ diff --git a/src/rtr/db/roa_table.c b/src/rtr/db/roa_table.c index e69b85ff..3229069d 100644 --- a/src/rtr/db/roa_table.c +++ b/src/rtr/db/roa_table.c @@ -9,8 +9,15 @@ struct hashable_roa { UT_hash_handle hh; }; +/* FIXME Update whole roa_table logic */ +struct hashable_keys { + struct router_key data; + UT_hash_handle hh; +}; + struct roa_table { struct hashable_roa *roas; + struct hashable_keys *router_keys; }; struct roa_table * diff --git a/src/rtr/db/vrp.h b/src/rtr/db/vrp.h index 70d5503c..5b1f0c4e 100644 --- a/src/rtr/db/vrp.h +++ b/src/rtr/db/vrp.h @@ -3,6 +3,7 @@ #include #include +#include "object/router_key.h" #define FLAG_WITHDRAWAL 0 #define FLAG_ANNOUNCEMENT 1 @@ -44,13 +45,22 @@ struct vrp { uint8_t addr_fam; }; -struct delta { +struct delta_vrp { serial_t serial; struct vrp vrp; uint8_t flags; }; +struct delta_bgpsec { + serial_t serial; + struct router_key router_key; + uint8_t flags; +}; + typedef int (*vrp_foreach_cb)(struct vrp const *, void *); -typedef int (*delta_foreach_cb)(struct delta const *, void *); +typedef int (*router_key_foreach_cb)(struct router_key const *, void *); + +typedef int (*delta_vrp_foreach_cb)(struct delta_vrp const *, void *); +typedef int (*delta_bgpsec_foreach_cb)(struct delta_bgpsec const *, void *); #endif /* SRC_RTR_DB_VRP_H_ */ diff --git a/src/rtr/db/vrps.c b/src/rtr/db/vrps.c index df75bd4d..f1ffb0c1 100644 --- a/src/rtr/db/vrps.c +++ b/src/rtr/db/vrps.c @@ -9,6 +9,7 @@ #include "output_printer.h" #include "validation_handler.h" #include "data_structure/array_list.h" +#include "object/router_key.h" #include "object/tal.h" #include "rtr/db/roa_table.h" #include "slurm/slurm_loader.h" @@ -23,7 +24,7 @@ DEFINE_ARRAY_LIST_FUNCTIONS(deltas_db, struct delta_group, ) struct vrp_node { - struct delta delta; + struct delta_vrp delta; SLIST_ENTRY(vrp_node) next; }; @@ -112,6 +113,17 @@ __handle_roa_v6(uint32_t as, struct ipv6_prefix const * prefix, return rtrhandler_handle_roa_v6(arg, as, prefix, max_length); } +int +__handle_bgpsec(struct router_key const *router_key, void *arg) +{ + pr_debug("Handling BGPsec for ASN %u", router_key->asn); + /* + * FIXME Add RTR handler + * return rtrhandler_handle_router_key(arg, as, prefix, max_length); + */ + return 0; +} + static int __perform_standalone_validation(struct roa_table **result) { @@ -125,6 +137,7 @@ __perform_standalone_validation(struct roa_table **result) validation_handler.handle_roa_v4 = __handle_roa_v4; validation_handler.handle_roa_v6 = __handle_roa_v6; + validation_handler.handle_bgpsec = __handle_bgpsec; validation_handler.arg = roas; error = perform_standalone_validation(&validation_handler); @@ -346,7 +359,7 @@ vrps_foreach_base_roa(vrp_foreach_cb cb, void *arg) * hash table.) */ static int -vrp_ovrd_remove(struct delta const *delta, void *arg) +vrp_ovrd_remove(struct delta_vrp const *delta, void *arg) { struct vrp_node *ptr; struct vrp_slist *filtered_vrps = arg; @@ -373,7 +386,7 @@ vrp_ovrd_remove(struct delta const *delta, void *arg) * @arg) on each element of the resultant delta. */ int -vrps_foreach_filtered_delta(struct deltas_db *deltas, delta_foreach_cb cb, +vrps_foreach_filtered_delta(struct deltas_db *deltas, delta_vrp_foreach_cb cb, void *arg) { struct vrp_slist filtered_vrps; @@ -389,8 +402,9 @@ vrps_foreach_filtered_delta(struct deltas_db *deltas, delta_foreach_cb cb, */ SLIST_INIT(&filtered_vrps); ARRAYLIST_FOREACH(deltas, group, i) { + /* FIXME Add function for router keys */ error = deltas_foreach(group->serial, group->deltas, - vrp_ovrd_remove, &filtered_vrps); + vrp_ovrd_remove, NULL, &filtered_vrps); if (error) goto release_list; } diff --git a/src/rtr/db/vrps.h b/src/rtr/db/vrps.h index 67116c5e..347a5fba 100644 --- a/src/rtr/db/vrps.h +++ b/src/rtr/db/vrps.h @@ -28,11 +28,15 @@ int vrps_update(bool *); * been called, or while it's still building the database. * Handle gracefully. */ + +/* FIXME Also add BGPSEC */ int vrps_foreach_base_roa(vrp_foreach_cb, void *); int vrps_get_deltas_from(serial_t, serial_t *, struct deltas_db *); int get_last_serial_number(serial_t *); -int vrps_foreach_filtered_delta(struct deltas_db *, delta_foreach_cb, void *); +/* FIXME Also filter BGPSEC */ +int vrps_foreach_filtered_delta(struct deltas_db *, delta_vrp_foreach_cb, + void *); uint16_t get_current_session_id(uint8_t); diff --git a/src/rtr/pdu_handler.c b/src/rtr/pdu_handler.c index fa5bfd4e..469e2795 100644 --- a/src/rtr/pdu_handler.c +++ b/src/rtr/pdu_handler.c @@ -142,6 +142,7 @@ handle_reset_query_pdu(int fd, struct rtr_request const *request) * queries than reset queries. */ + /* FIXME Apply to router keys as well */ error = vrps_foreach_base_roa(send_base_roa, &args); /* See handle_serial_query_pdu() for some comments. */ diff --git a/src/rtr/pdu_sender.c b/src/rtr/pdu_sender.c index b2ec8155..bd7cb00e 100644 --- a/src/rtr/pdu_sender.c +++ b/src/rtr/pdu_sender.c @@ -18,21 +18,12 @@ static void set_header_values(struct pdu_header *header, uint8_t type, uint16_t reserved) { + /* FIXME Remove to support RTR_V1 */ header->protocol_version = RTR_V0; header->pdu_type = type; header->m.reserved = reserved; } -/* TODO (next iteration) Include Router Key PDU serials */ -/** - * static uint32_t - * length_router_key_pdu(struct router_key_pdu *pdu) - * { - * return HEADER_LENGTH + - * pdu->ski_len + sizeof(pdu->asn) + pdu->spki_len; - * } - */ - static int send_response(int fd, unsigned char *data, size_t data_len) { @@ -163,13 +154,64 @@ send_prefix_pdu(int fd, struct vrp const *vrp, uint8_t flags) return -EINVAL; } +int +send_router_key_pdu(int fd, struct router_key const *router_key, uint8_t flags) +{ + struct router_key_pdu pdu; + unsigned char *data; + size_t len; + uint16_t reserved; + int error; + + /* TODO Sanity check: this can't be sent on RTRv0 */ + + reserved = 0; + /* Set the flags at the first 8 bits of reserved field */ + reserved += (flags << 8); + set_header_values(&pdu.header, PDU_TYPE_ROUTER_KEY, reserved); + + pdu.ski = router_key->ski; + pdu.ski_len = router_key->ski_len; + pdu.asn = router_key->asn; + pdu.spki = router_key->spk; + pdu.spki_len = router_key->spk_len; + pdu.header.length = RTRPDU_HDR_LEN + + router_key->ski_len + + sizeof(router_key->asn) + + router_key->spk_len; + + data = malloc(pdu.header.length); + if (data == NULL) + return pr_enomem(); + + len = serialize_router_key_pdu(&pdu, data); + if (len != pdu.header.length) + pr_crit("Serialized Router Key PDU is %zu bytes, not the expected %u.", + len, pdu.header.length); + + error = send_response(fd, data, len); + + free(data); + return error; +} + static int -vrp_simply_send(struct delta const *delta, void *arg) +vrp_simply_send(struct delta_vrp const *delta, void *arg) { int *fd = arg; + return send_prefix_pdu(*fd, &delta->vrp, delta->flags); } +static int +router_key_simply_send(struct delta_bgpsec const *delta, void *arg) +{ + int *fd = arg; + + return send_router_key_pdu(*fd, &delta->router_key, + delta->flags); +} + int send_delta_pdus(int fd, struct deltas_db *deltas) { @@ -182,9 +224,10 @@ send_delta_pdus(int fd, struct deltas_db *deltas) if (deltas->len == 1) { group = &deltas->array[0]; return deltas_foreach(group->serial, group->deltas, - vrp_simply_send, &fd); + vrp_simply_send, router_key_simply_send, &fd); } + /* FIXME Apply to router keys as well */ return vrps_foreach_filtered_delta(deltas, vrp_simply_send, &fd); } @@ -201,7 +244,12 @@ send_end_of_data_pdu(int fd, serial_t end_serial) pdu.header.length = RTRPDU_END_OF_DATA_LEN; pdu.serial_number = end_serial; - /* TODO (next iteration) Add RTRv1 intervals */ + /* FIXME WRONG!! Check for the real version */ + if (pdu.header.protocol_version == RTR_V1) { + pdu.refresh_interval = config_get_interval_refresh(); + pdu.retry_interval = config_get_interval_retry(); + pdu.expire_interval = config_get_interval_expire(); + } len = serialize_end_of_data_pdu(&pdu, data); if (len != RTRPDU_END_OF_DATA_LEN) diff --git a/src/rtr/pdu_sender.h b/src/rtr/pdu_sender.h index 83464718..413061d8 100644 --- a/src/rtr/pdu_sender.h +++ b/src/rtr/pdu_sender.h @@ -10,6 +10,7 @@ int send_serial_notify_pdu(int, serial_t); int send_cache_reset_pdu(int); int send_cache_response_pdu(int); int send_prefix_pdu(int, struct vrp const *, uint8_t); +int send_router_key_pdu(int, struct router_key const *, uint8_t); int send_delta_pdus(int, struct deltas_db *); int send_end_of_data_pdu(int, serial_t); int send_error_report_pdu(int, uint16_t, struct rtr_request const *, char *); diff --git a/src/sorted_array.c b/src/sorted_array.c index 2200331b..73ed0dc0 100644 --- a/src/sorted_array.c +++ b/src/sorted_array.c @@ -179,6 +179,21 @@ sarray_contains(struct sorted_array *sarray, void *elem) return false; } +int +sarray_foreach(struct sorted_array *sarray, sarray_foreach_cb cb, void *arg) +{ + unsigned int index; + int error; + + for (index = 0; index < sarray->count; index++) { + error = cb(get_nth_element(sarray, index), arg); + if (error) + return error; + } + + return 0; +} + char const *sarray_err2str(int error) { switch (abs(error)) { diff --git a/src/sorted_array.h b/src/sorted_array.h index 4198b5f6..41fd9d1e 100644 --- a/src/sorted_array.h +++ b/src/sorted_array.h @@ -42,6 +42,9 @@ int sarray_add(struct sorted_array *, void *); bool sarray_empty(struct sorted_array *); bool sarray_contains(struct sorted_array *, void *); +typedef int (*sarray_foreach_cb)(void *, void *); +int sarray_foreach(struct sorted_array *, sarray_foreach_cb, void *); + char const *sarray_err2str(int); #endif /* SRC_SORTED_ARRAY_H_ */ diff --git a/src/validation_handler.c b/src/validation_handler.c index 266658c8..ec17b127 100644 --- a/src/validation_handler.c +++ b/src/validation_handler.c @@ -52,3 +52,18 @@ vhandler_handle_roa_v6(uint32_t as, struct ipv6_prefix const *prefix, ? handler->handle_roa_v6(as, prefix, max_length, handler->arg) : 0; } + +int +vhandler_handle_bgpsec(struct router_key const *router_key) +{ + struct validation_handler const *handler; + int error; + + error = get_current_threads_handler(&handler); + if (error) + return error; + + return (handler->handle_bgpsec != NULL) + ? handler->handle_bgpsec(router_key, handler->arg) + : 0; +} diff --git a/src/validation_handler.h b/src/validation_handler.h index fc557a20..85cebf0d 100644 --- a/src/validation_handler.h +++ b/src/validation_handler.h @@ -3,6 +3,7 @@ #include "address.h" #include "object/name.h" +#include "object/router_key.h" /** * Functions that handle validation results. @@ -28,11 +29,14 @@ struct validation_handler { /** Called every time Fort has successfully validated an IPv6 ROA. */ int (*handle_roa_v6)(uint32_t, struct ipv6_prefix const *, uint8_t, void *); + /** Called every time Fort has successfully a BGPsec certificate */ + int (*handle_bgpsec)(struct router_key const *, void *); /** Generic user-defined argument for the functions above. */ void *arg; }; int vhandler_handle_roa_v4(uint32_t, struct ipv4_prefix const *, uint8_t); int vhandler_handle_roa_v6(uint32_t, struct ipv6_prefix const *, uint8_t); +int vhandler_handle_bgpsec(struct router_key const *); #endif /* SRC_VALIDATION_HANDLER_H_ */