-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.
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
#include <stdbool.h>
#include <openssl/obj_mac.h>
+#include <openssl/objects.h>
+
#include "log.h"
static bool
}
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
#ifndef SRC_ALGORITHM_H_
#define SRC_ALGORITHM_H_
+#include <stdbool.h>
+#include <openssl/x509.h>
#include "asn1/asn1c/AlgorithmIdentifier.h"
#include "asn1/asn1c/OBJECT_IDENTIFIER.h"
*/
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 *);
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,
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;
#include "thread_var.h"
#include "data_structure/array_list.h"
#include "object/name.h"
-#include "object/certificate.h"
enum defer_node_type {
DNT_SEPARATOR,
/** 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;
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;
* 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;
}
#include <openssl/x509.h>
#include "resource.h"
#include "uri.h"
+#include "object/certificate.h"
#include "object/name.h"
/*
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 *);
/** 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 {
.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:
*/
.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 */
{
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;
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.");
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 *
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);
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)
{
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 *);
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)
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;
}
{
return NID_autonomousSysIdsv2;
}
+
+int nid_bgpsecRouter(void)
+{
+ return NID_bgpsecRouter;
+}
int nid_certPolicyRpkiV2(void);
int nid_ipAddrBlocksv2(void);
int nid_autonomousSysIdsv2(void);
+int nid_bgpsecRouter(void);
#endif /* SRC_NID_H_ */
--- /dev/null
+#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;
+}
--- /dev/null
+#ifndef SRC_OBJECT_BGPSEC_H_
+#define SRC_OBJECT_BGPSEC_H_
+
+#include <openssl/x509.h>
+#include "resource.h"
+
+int handle_bgpsec(X509 *, unsigned char *, int, struct resources *);
+
+#endif /* SRC_OBJECT_BGPSEC_H_ */
#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"
struct rpki_uri **mft;
};
+struct bgpsec_ski {
+ X509 *cert;
+ int *ski_len;
+ unsigned char **ski_data;
+};
+
static int
validate_serial_number(X509 *cert)
{
}
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;
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;
* getting the message.
*/
- if (is_root) {
+ if (type == TA) {
error = validate_spki(pubkey);
if (error)
return error;
}
int
-certificate_validate_rfc6487(X509 *cert, bool is_root)
+certificate_validate_rfc6487(X509 *cert, enum cert_type type)
{
int error;
return error;
/* rfc6487#section-4.4 */
- error = validate_issuer(cert, is_root);
+ error = validate_issuer(cert, type == TA);
if (error)
return error;
/* 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;
}
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;
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;
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;
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;
}
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;
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);
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)
{
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.
*
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)
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)
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();
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));
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 */
/*
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)
#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 **);
/**
* 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 *);
* 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.
--- /dev/null
+#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_ */
#include "thread_var.h"
#include "resource/ip4.h"
#include "resource/ip6.h"
-#include "resource/asn.h"
#include <sys/socket.h>
}
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.");
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);
{
res->policy = policy;
}
+
+int
+resources_foreach_asn(struct resources *res, foreach_asn_cb cb, void *arg)
+{
+ return rasn_foreach(res->asns, cb, arg);
+}
#include <stdbool.h>
#include "address.h"
+#include "resource/asn.h"
#include "asn1/asn1c/ASIdentifiers.h"
#include "asn1/asn1c/IPAddressFamily.h"
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);
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_ */
#include "asn.h"
#include <errno.h>
+#include <limits.h>
#include "log.h"
#include "sorted_array.h"
unsigned long max;
};
+struct asn_cb {
+ foreach_asn_cb cb;
+ void *arg;
+};
+
static enum sarray_comparison
asn_cmp(void *arg1, void *arg2)
{
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;
+}
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_ */
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 {
struct deltas_v6 adds;
struct deltas_v6 removes;
} v6;
+ struct {
+ struct deltas_bgpsec adds;
+ struct deltas_bgpsec removes;
+ } bgpsec;
atomic_uint references;
};
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;
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);
}
}
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;
}
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;
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);
}
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_ */
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 *
#include <stdint.h>
#include <netinet/in.h>
+#include "object/router_key.h"
#define FLAG_WITHDRAWAL 0
#define FLAG_ANNOUNCEMENT 1
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_ */
#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"
DEFINE_ARRAY_LIST_FUNCTIONS(deltas_db, struct delta_group, )
struct vrp_node {
- struct delta delta;
+ struct delta_vrp delta;
SLIST_ENTRY(vrp_node) next;
};
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)
{
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);
* 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;
* @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;
*/
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;
}
* 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);
* 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. */
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)
{
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)
{
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);
}
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)
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 *);
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)) {
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_ */
? 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;
+}
#include "address.h"
#include "object/name.h"
+#include "object/router_key.h"
/**
* Functions that handle validation results.
/** 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_ */