fort_SOURCES += asn1/signed_data.h asn1/signed_data.c
fort_SOURCES += types/address.h types/address.c
+fort_SOURCES += types/aspa.h types/aspa.c
fort_SOURCES += types/bio_seq.c types/bio_seq.h
fort_SOURCES += types/delta.c types/delta.h
fort_SOURCES += types/router_key.c types/router_key.h
fort_SOURCES += incidence/incidence.h incidence/incidence.c
+fort_SOURCES += object/aspa.h object/aspa.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
--- /dev/null
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "RPKI-ASPA-2023"
+ * found in "aspa.asn1"
+ * `asn1c -Werror -fcompound-names -fwide-types -D asn1/asn1c -no-gen-PER -no-gen-example`
+ */
+
+#include "asn1/asn1c/ASProviderAttestation.h"
+
+static int asn_DFL_2_cmp_0(const void *sptr) {
+ const INTEGER_t *st = sptr;
+
+ if(!st) {
+ return -1; /* No value is not a default value */
+ }
+
+ /* Test default value 0 */
+ long value;
+ if(asn_INTEGER2long(st, &value))
+ return -1;
+ return (value != 0);
+}
+static int asn_DFL_2_set_0(void **sptr) {
+ INTEGER_t *st = *sptr;
+
+ if(!st) {
+ st = (*sptr = CALLOC(1, sizeof(*st)));
+ if(!st) return -1;
+ }
+
+ /* Install default value 0 */
+ return asn_long2INTEGER(st, 0);
+}
+static asn_TYPE_member_t asn_MBR_ASProviderAttestation_1[] = {
+ { ATF_POINTER, 1, offsetof(struct ASProviderAttestation, version),
+ (ASN_TAG_CLASS_CONTEXT | (0 << 2)),
+ +1, /* EXPLICIT tag at current level */
+ &asn_DEF_INTEGER,
+ 0,
+ { 0, 0, 0 },
+ &asn_DFL_2_cmp_0, /* Compare DEFAULT 0 */
+ &asn_DFL_2_set_0, /* Set DEFAULT 0 */
+ "version"
+ },
+ { ATF_NOFLAGS, 0, offsetof(struct ASProviderAttestation, customerASID),
+ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)),
+ 0,
+ &asn_DEF_ASId,
+ 0,
+ { 0, 0, 0 },
+ 0, 0, /* No default value */
+ "customerASID"
+ },
+ { ATF_NOFLAGS, 0, offsetof(struct ASProviderAttestation, providers),
+ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)),
+ 0,
+ &asn_DEF_ProviderASSet,
+ 0,
+ { 0, 0, 0 },
+ 0, 0, /* No default value */
+ "providers"
+ },
+};
+static const ber_tlv_tag_t asn_DEF_ASProviderAttestation_tags_1[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
+};
+static const asn_TYPE_tag2member_t asn_MAP_ASProviderAttestation_tag2el_1[] = {
+ { (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)), 1, 0, 0 }, /* customerASID */
+ { (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), 2, 0, 0 }, /* providers */
+ { (ASN_TAG_CLASS_CONTEXT | (0 << 2)), 0, 0, 0 } /* version */
+};
+static asn_SEQUENCE_specifics_t asn_SPC_ASProviderAttestation_specs_1 = {
+ sizeof(struct ASProviderAttestation),
+ offsetof(struct ASProviderAttestation, _asn_ctx),
+ asn_MAP_ASProviderAttestation_tag2el_1,
+ 3, /* Count of tags in the map */
+ -1, /* First extension addition */
+};
+asn_TYPE_descriptor_t asn_DEF_ASProviderAttestation = {
+ "ASProviderAttestation",
+ "ASProviderAttestation",
+ &asn_OP_SEQUENCE,
+ asn_DEF_ASProviderAttestation_tags_1,
+ sizeof(asn_DEF_ASProviderAttestation_tags_1)
+ /sizeof(asn_DEF_ASProviderAttestation_tags_1[0]), /* 1 */
+ asn_DEF_ASProviderAttestation_tags_1, /* Same as above */
+ sizeof(asn_DEF_ASProviderAttestation_tags_1)
+ /sizeof(asn_DEF_ASProviderAttestation_tags_1[0]), /* 1 */
+ { 0, 0, SEQUENCE_constraint },
+ asn_MBR_ASProviderAttestation_1,
+ 3, /* Elements count */
+ &asn_SPC_ASProviderAttestation_specs_1 /* Additional specs */
+};
+
--- /dev/null
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "RPKI-ASPA-2023"
+ * found in "aspa.asn1"
+ * `asn1c -Werror -fcompound-names -fwide-types -D asn1/asn1c -no-gen-PER -no-gen-example`
+ */
+
+#ifndef _ASProviderAttestation_H_
+#define _ASProviderAttestation_H_
+
+/* Including external dependencies */
+#include "asn1/asn1c/INTEGER.h"
+#include "asn1/asn1c/ASId.h"
+#include "asn1/asn1c/ProviderASSet.h"
+#include "asn1/asn1c/constr_SEQUENCE.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ASProviderAttestation */
+typedef struct ASProviderAttestation {
+ INTEGER_t *version /* DEFAULT 0 */;
+ ASId_t customerASID;
+ ProviderASSet_t providers;
+
+ /* Context for parsing across buffer boundaries */
+ asn_struct_ctx_t _asn_ctx;
+} ASProviderAttestation_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_ASProviderAttestation;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ASProviderAttestation_H_ */
+#include "asn1/asn1c/asn_internal.h"
asn1/asn1c/ASIdentifiers.c \
asn1/asn1c/ASIdentifierChoice.c \
asn1/asn1c/ASIdOrRange.c \
+ asn1/asn1c/ASProviderAttestation.c \
+ asn1/asn1c/ProviderASSet.c \
asn1/asn1c/ASRange.c \
asn1/asn1c/ASId.c \
asn1/asn1c/AttributeType.c \
asn1/asn1c/ASIdentifiers.h \
asn1/asn1c/ASIdentifierChoice.h \
asn1/asn1c/ASIdOrRange.h \
+ asn1/asn1c/ASProviderAttestation.h \
+ asn1/asn1c/ProviderASSet.h \
asn1/asn1c/ASRange.h \
asn1/asn1c/ASId.h \
asn1/asn1c/AttributeType.h \
--- /dev/null
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "RPKI-ASPA-2023"
+ * found in "aspa.asn1"
+ * `asn1c -Werror -fcompound-names -fwide-types -D asn1/asn1c -no-gen-PER -no-gen-example`
+ */
+
+#include "asn1/asn1c/ProviderASSet.h"
+
+asn_TYPE_member_t asn_MBR_ProviderASSet_1[] = {
+ { ATF_POINTER, 0, 0,
+ (ASN_TAG_CLASS_UNIVERSAL | (2 << 2)),
+ 0,
+ &asn_DEF_ASId,
+ 0,
+ { 0, 0, 0 },
+ 0, 0, /* No default value */
+ ""
+ },
+};
+static const ber_tlv_tag_t asn_DEF_ProviderASSet_tags_1[] = {
+ (ASN_TAG_CLASS_UNIVERSAL | (16 << 2))
+};
+asn_SET_OF_specifics_t asn_SPC_ProviderASSet_specs_1 = {
+ sizeof(struct ProviderASSet),
+ offsetof(struct ProviderASSet, _asn_ctx),
+ 0, /* XER encoding is XMLDelimitedItemList */
+};
+asn_TYPE_descriptor_t asn_DEF_ProviderASSet = {
+ "ProviderASSet",
+ "ProviderASSet",
+ &asn_OP_SEQUENCE_OF,
+ asn_DEF_ProviderASSet_tags_1,
+ sizeof(asn_DEF_ProviderASSet_tags_1)
+ /sizeof(asn_DEF_ProviderASSet_tags_1[0]), /* 1 */
+ asn_DEF_ProviderASSet_tags_1, /* Same as above */
+ sizeof(asn_DEF_ProviderASSet_tags_1)
+ /sizeof(asn_DEF_ProviderASSet_tags_1[0]), /* 1 */
+ { NULL, NULL, SEQUENCE_OF_constraint },
+ asn_MBR_ProviderASSet_1,
+ 1, /* Single element */
+ &asn_SPC_ProviderASSet_specs_1 /* Additional specs */
+};
+
--- /dev/null
+/*
+ * Generated by asn1c-0.9.29 (http://lionet.info/asn1c)
+ * From ASN.1 module "RPKI-ASPA-2023"
+ * found in "aspa.asn1"
+ * `asn1c -Werror -fcompound-names -fwide-types -D asn1/asn1c -no-gen-PER -no-gen-example`
+ */
+
+#ifndef _ProviderASSet_H_
+#define _ProviderASSet_H_
+
+/* Including external dependencies */
+#include "asn1/asn1c/ASId.h"
+#include "asn1/asn1c/asn_SEQUENCE_OF.h"
+#include "asn1/asn1c/constr_SEQUENCE_OF.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ProviderASSet */
+typedef struct ProviderASSet {
+ A_SEQUENCE_OF(ASId_t) list;
+
+ /* Context for parsing across buffer boundaries */
+ asn_struct_ctx_t _asn_ctx;
+} ProviderASSet_t;
+
+/* Implementation */
+extern asn_TYPE_descriptor_t asn_DEF_ProviderASSet;
+extern asn_SET_OF_specifics_t asn_SPC_ProviderASSet_specs_1;
+extern asn_TYPE_member_t asn_MBR_ProviderASSet_1[1];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ProviderASSet_H_ */
+#include "asn1/asn1c/asn_internal.h"
#define OID_ROA { 1, 2, 840, 113549, 1, 9, 16, 1, 24 }
#define OID_MANIFEST { 1, 2, 840, 113549, 1, 9, 16, 1, 26 }
#define OID_GHOSTBUSTERS { 1, 2, 840, 113549, 1, 9, 16, 1, 35 }
+#define OID_ASPA { 1, 2, 840, 113549, 1, 9, 16, 1, 49 }
int oid2arcs(OBJECT_IDENTIFIER_t *, struct oid_arcs *);
static const OID oid_sta = OID_SIGNING_TIME_ATTR;
void
-eecert_init(struct ee_cert *ee, STACK_OF(X509_CRL) *crls, bool force_inherit)
+eecert_init(struct ee_cert *ee, enum ee_type type, STACK_OF(X509_CRL) *crls,
+ bool force_inherit)
{
+ ee->type = type;
ee->res = resources_create(RPKI_POLICY_RFC6484, force_inherit);
ee->crls = crls;
memset(&ee->refs, 0, sizeof(ee->refs));
goto end2;
resources_set_policy(ee->res, policy);
- error = certificate_get_resources(cert, ee->res, CERTYPE_EE);
+ error = certificate_get_resources(cert, ee->res, CERTYPE_EE, ee->type);
if (error)
goto end2;
#include "certificate_refs.h"
#include "resource.h"
+enum ee_type {
+ EET_ROA = 1,
+ EET_ASPA,
+ EET_MFT,
+ EET_GBR,
+};
+
struct ee_cert {
+ enum ee_type type;
+
/** CRL that might or might not revoke the EE certificate. */
STACK_OF(X509_CRL) *crls;
/** A copy of the resources carried by the EE certificate. */
struct certificate_refs refs;
};
-void eecert_init(struct ee_cert *, STACK_OF(X509_CRL) *, bool);
+void eecert_init(struct ee_cert *, enum ee_type, STACK_OF(X509_CRL) *, bool);
void eecert_cleanup(struct ee_cert *);
int signed_data_decode(ANY_t *, struct SignedData **);
result = resources_create(policy, false);
- error = certificate_get_resources(x509, result, type);
+ error = certificate_get_resources(x509, result, type, 0);
if (error)
goto fail;
uint32_t facility;
} validation_log;
+ struct {
+ unsigned int max_providers; /* per customer */
+ } aspa;
+
struct {
/** File where the validated ROAs will be stored */
char *roa;
.doc = "Print ANSI color codes",
},
+ /* ASPA */
+ {
+ .id = 15000,
+ .name = "aspa.max-providers",
+ .type = >_uint,
+ .offset = offsetof(struct rpki_config, aspa.max_providers),
+ .doc = "Maximum allowed providers per customer",
+ .min = 0,
+ .max = 16380u,
+ },
+
/* Incidences */
{
.id = 7001,
"--contimeout=20", "--max-size=20MB", "--timeout=15",
- "--include=*/", "--include=*.cer", "--include=*.crl",
- "--include=*.gbr", "--include=*.mft", "--include=*.roa",
- "--exclude=*",
+ "--include=*/", "--include=*.cer", "--include=*.roa",
+ "--include=*.asa", "--include=*.mft", "--include=*.crl",
+ "--include=*.gbr", "--exclude=*",
"$REMOTE", "$LOCAL",
};
option->type->free(get_rpki_config_field(option));
free(rpki_config.payload);
}
+
+unsigned int
+config_get_max_aspa_providers(void)
+{
+ return rpki_config.aspa.max_providers;
+}
unsigned int config_get_thread_pool_server_max(void);
enum file_type config_get_file_type(void);
char const *config_get_payload(void);
+unsigned int config_get_max_aspa_providers(void);
/* Logging getters */
bool config_get_op_log_enabled(void);
--- /dev/null
+#include "object/aspa.h"
+
+#include "asn1/asn1c/ASProviderAttestation.h"
+#include "asn1/decode.h"
+#include "asn1/oid.h"
+#include "asn1/signed_data.h"
+#include "config.h"
+#include "log.h"
+#include "object/signed_object.h"
+#include "thread_var.h"
+
+#define ASID_MAX UINT32_MAX
+
+static int
+decode_aspa(struct signed_object *sobj, struct ASProviderAttestation **result)
+{
+ return asn1_decode_octet_string(
+ sobj->sdata->encapContentInfo.eContent,
+ &asn_DEF_ASProviderAttestation,
+ (void **) result,
+ true
+ );
+}
+
+static int
+validate_version(INTEGER_t *version)
+{
+ long primitive;
+
+ if (version == NULL)
+ return pr_val_err("Version number is NULL.");
+ if (asn_INTEGER2long(version, &primitive) < 0)
+ return pr_val_err("Version number %s", strerror(errno));
+ if (primitive != 1)
+ return pr_val_err("Version number is not 1: %ld", primitive);
+
+ return 0;
+}
+
+static int
+parse_asid(char const *what, ASId_t *asid, uint32_t *result)
+{
+ unsigned long primitive;
+
+ if (asid == NULL)
+ return pr_val_err("%s is NULL.", what);
+ if (asn_INTEGER2ulong(asid, &primitive) < 0)
+ return pr_val_err("%s %s", what, strerror(errno));
+ if (primitive > ASID_MAX)
+ return pr_val_err("%s out of range. (0-%u)", what, ASID_MAX);
+
+ *result = primitive;
+ return 0;
+}
+
+static int
+parse_customer(ASId_t *asid, struct resources *parent, uint32_t *result)
+{
+ int error;
+
+ error = parse_asid("customerASID", asid, result);
+ if (error)
+ return error;
+
+ if (!resources_matches_asn(parent, *result))
+ return pr_val_err(
+ "EE certificate's ASN extension does not exactly match customerASID %u.",
+ *result);
+
+ return 0;
+}
+
+static int
+parse_providers(ProviderASSet_t *set, struct aspa *aspa)
+{
+ uint32_t *providers;
+ unsigned int limit;
+ int i;
+ int error;
+
+ aspa->providers.asids = NULL;
+ aspa->providers.count = 0;
+
+ if (set == NULL)
+ return pr_val_err("Providers set is NULL.");
+
+ limit = config_get_max_aspa_providers();
+ if (set->list.count > limit)
+ return pr_val_err("Too many providers: %d > %u",
+ set->list.count, limit);
+
+ providers = pcalloc(set->list.count, sizeof(uint32_t));
+ for (i = 0; i < set->list.count; i++) {
+ error = parse_asid("Provider", set->list.array[i], &providers[i]);
+ if (error)
+ goto cancel;
+
+ if (providers[i] == aspa->customer) {
+ error = pr_val_err("The Providers list contains the customer's ASID (%u).",
+ aspa->customer);
+ goto cancel;
+ }
+ if (i != 0 && providers[i - 1] >= providers[i]) {
+ error = pr_val_err("The Provider ASIDs are not listed in ascending order.");
+ goto cancel;
+ }
+ }
+
+ aspa->providers.asids = providers;
+ aspa->providers.count = set->list.count;
+ return 0;
+
+cancel: free(providers);
+ return error;
+}
+
+static int
+__handle_aspa(struct ASProviderAttestation *asn1, struct resources *parent)
+{
+ struct aspa *aspa;
+ int error;
+
+ error = validate_version(asn1->version);
+ if (error)
+ return error;
+
+ aspa = pzalloc(sizeof(struct aspa));
+ aspa->refs = 1;
+
+ error = parse_customer(&asn1->customerASID, parent, &aspa->customer);
+ if (error)
+ goto end;
+
+ error = parse_providers(&asn1->providers, aspa);
+ if (error)
+ goto end;
+
+ error = vhandler_handle_aspa(aspa);
+
+end: aspa_refput(aspa);
+ return error;
+}
+
+int
+aspa_traverse(struct rpki_uri *uri, struct rpp *pp)
+{
+ static OID oid = OID_ASPA;
+ struct oid_arcs arcs = OID2ARCS("aspa", oid);
+ struct signed_object sobj;
+ struct ee_cert ee;
+ struct ASProviderAttestation *aspa;
+ STACK_OF(X509_CRL) *crl;
+ int error;
+
+ /* Prepare */
+ pr_val_debug("ASPA '%s' {", uri_val_get_printable(uri));
+ fnstack_push_uri(uri);
+
+ /* Decode */
+ error = signed_object_decode(&sobj, uri);
+ if (error)
+ goto revert_log;
+ error = decode_aspa(&sobj, &aspa);
+ if (error)
+ goto revert_sobj;
+
+ /* Prepare validation arguments */
+ error = rpp_crl(pp, &crl);
+ if (error)
+ goto revert_roa;
+ eecert_init(&ee, EET_ASPA, crl, false);
+
+ /* Validate and handle everything */
+ error = signed_object_validate(&sobj, &arcs, &ee);
+ if (error)
+ goto revert_args;
+ error = __handle_aspa(aspa, ee.res);
+ if (error)
+ goto revert_args;
+ error = refs_validate_ee(&ee.refs, pp, uri);
+
+revert_args:
+ eecert_cleanup(&ee);
+revert_roa:
+ ASN_STRUCT_FREE(asn_DEF_ASProviderAttestation, aspa);
+revert_sobj:
+ signed_object_cleanup(&sobj);
+revert_log:
+ fnstack_pop();
+ pr_val_debug("}");
+ return error;
+}
--- /dev/null
+#ifndef SRC_OBJECT_ASPA_H_
+#define SRC_OBJECT_ASPA_H_
+
+#include "rpp.h"
+
+int aspa_traverse(struct rpki_uri *, struct rpp *);
+
+#endif /* SRC_OBJECT_ASPA_H_ */
resources = resources_create(policy, false);
if (resources == NULL)
goto revert_ski;
- error = certificate_get_resources(cert, resources, CERTYPE_BGPSEC);
+ error = certificate_get_resources(cert, resources, CERTYPE_BGPSEC, 0);
if (error)
goto revert_resources;
int i;
int error;
+ if (!X509_EXTENSION_get_critical(ext))
+ return pr_val_err("IP extension is not marked critical.");
+
string = X509_EXTENSION_get_data(ext);
error = asn1_decode(string->data, string->length, &asn_DEF_IPAddrBlocks,
(void **) &blocks, true);
return error;
}
-static 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, bool allow_asn_inherit)
+/**
+ * Copies the resources from @cert to @resources.
+ */
+int
+certificate_get_resources(X509 *cert, struct resources *resources,
+ enum cert_type type, enum ee_type eet)
{
+ int allowed_ip_nid = NID_undef;
+ int allowed_as_nid = NID_undef;
+
+ int nid_ip1 = NID_sbgp_ipAddrBlock;
+ int nid_ip2 = nid_ipAddrBlocksv2();
+ int nid_as1 = NID_sbgp_autonomousSysNum;
+ int nid_as2 = nid_autonomousSysIdsv2();
+
X509_EXTENSION *ext;
- int nid;
- int i;
+ int extnid;
+ int e;
int error;
- bool ip_ext_found = false;
- bool asn_ext_found = false;
- /* Reference: X509_get_ext_d2i */
- /* rfc6487#section-2 */
+ switch (type) {
+ case CERTYPE_TA:
+ case CERTYPE_CA:
+ case CERTYPE_BGPSEC:
+ switch (resources_get_policy(resources)) {
+ case RPKI_POLICY_RFC6484:
+ allowed_ip_nid = nid_ip1;
+ allowed_as_nid = nid_as1;
+ break;
+ case RPKI_POLICY_RFC8360:
+ allowed_ip_nid = nid_ip2;
+ allowed_as_nid = nid_as2;
+ }
+ break;
+ case CERTYPE_EE:
+ switch (eet) {
+ case EET_ROA:
+ switch (resources_get_policy(resources)) {
+ case RPKI_POLICY_RFC6484:
+ allowed_ip_nid = nid_ip1; break;
+ case RPKI_POLICY_RFC8360:
+ allowed_ip_nid = nid_ip2;
+ }
+ break;
+ case EET_ASPA:
+ switch (resources_get_policy(resources)) {
+ case RPKI_POLICY_RFC6484:
+ allowed_as_nid = nid_as1; break;
+ case RPKI_POLICY_RFC8360:
+ allowed_as_nid = nid_as2;
+ }
+ break;
+ case EET_MFT:
+ case EET_GBR:
+ break;
+ }
+ break;
+ }
- for (i = 0; i < X509_get_ext_count(cert); i++) {
- ext = X509_get_ext(cert, i);
- nid = OBJ_obj2nid(X509_EXTENSION_get_object(ext));
+ for (e = 0; e < X509_get_ext_count(cert); e++) {
+ ext = X509_get_ext(cert, e);
+ extnid = OBJ_obj2nid(X509_EXTENSION_get_object(ext));
- if (nid == addr_nid) {
- if (ip_ext_found)
- return pr_val_err("Multiple IP extensions found.");
- if (!X509_EXTENSION_get_critical(ext))
- return pr_val_err("The IP extension is not marked as critical.");
+ if (extnid == nid_ip1 || extnid == nid_ip2) {
+ if (extnid != allowed_ip_nid)
+ return pr_val_err("Found an unexpected IP Resources extension.");
- pr_val_debug("IP {");
error = handle_ip_extension(ext, resources);
- pr_val_debug("}");
- ip_ext_found = true;
-
if (error)
return error;
+ allowed_ip_nid = NID_undef;
- } else if (nid == asn_nid) {
- if (asn_ext_found)
- return pr_val_err("Multiple AS extensions found.");
- if (!X509_EXTENSION_get_critical(ext))
- return pr_val_err("The AS extension is not marked as critical.");
-
- pr_val_debug("ASN {");
- error = handle_asn_extension(ext, resources,
- allow_asn_inherit);
- pr_val_debug("}");
- asn_ext_found = true;
+ } else if (extnid == nid_as1 || extnid == nid_as2) {
+ if (extnid != allowed_as_nid)
+ return pr_val_err("Found an unexpected AS Resources extension.");
+ error = handle_asn_extension(ext, resources, false);
if (error)
return error;
-
- } else if (nid == bad_addr_nid) {
- return pr_val_err("Certificate has an RFC%s policy, but contains an RFC%s IP extension.",
- policy_rfc, bad_ext_rfc);
- } else if (nid == bad_asn_nid) {
- return pr_val_err("Certificate has an RFC%s policy, but contains an RFC%s ASN extension.",
- policy_rfc, bad_ext_rfc);
+ allowed_as_nid = NID_undef;
}
}
- if (!ip_ext_found && !asn_ext_found)
- return pr_val_err("Certificate lacks both IP and AS extension.");
-
return 0;
}
-/**
- * Copies the resources from @cert to @resources.
- */
-int
-certificate_get_resources(X509 *cert, struct resources *resources,
- enum cert_type type)
-{
- enum rpki_policy policy;
-
- policy = resources_get_policy(resources);
- switch (policy) {
- case RPKI_POLICY_RFC6484:
- return __certificate_get_resources(cert, resources,
- NID_sbgp_ipAddrBlock, NID_sbgp_autonomousSysNum,
- nid_ipAddrBlocksv2(), nid_autonomousSysIdsv2(),
- "6484", "8360", type != CERTYPE_BGPSEC);
- case RPKI_POLICY_RFC8360:
- return __certificate_get_resources(cert, resources,
- nid_ipAddrBlocksv2(), nid_autonomousSysIdsv2(),
- NID_sbgp_ipAddrBlock, NID_sbgp_autonomousSysNum,
- "8360", "6484", type != CERTYPE_BGPSEC);
- }
-
- pr_crit("Unknown policy: %u", policy);
-}
-
static bool
is_rsync(ASN1_IA5STRING *uri)
{
#include "asn1/asn1c/ANY.h"
#include "asn1/asn1c/SignatureValue.h"
+#include "asn1/signed_data.h"
#include "certificate_refs.h"
#include "resource.h"
* 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 *, enum cert_type);
+int certificate_get_resources(X509 *, struct resources *,
+ enum cert_type, enum ee_type);
/**
* Validates the certificate extensions, End-Entity style.
error = rpp_crl(pp, &crl);
if (error)
goto revert_sobj;
- eecert_init(&ee, crl, true);
+ eecert_init(&ee, EET_GBR, crl, true);
/* Validate everything */
error = signed_object_validate(&sobj, &arcs, &ee);
rpp_add = rpp_add_cer;
else if (strncmp(ext, ".roa", 4) == 0)
rpp_add = rpp_add_roa;
+ else if (strncmp(ext, ".asa", 4) == 0)
+ rpp_add = rpp_add_asa;
else if (strncmp(ext, ".crl", 4) == 0)
rpp_add = rpp_add_crl;
else if (strncmp(ext, ".gbr", 4) == 0)
error = rpp_crl(*pp, &crl);
if (error)
goto revert_rpp;
- eecert_init(&ee, crl, false);
+ eecert_init(&ee, EET_MFT, crl, false);
/* Validate everything */
error = signed_object_validate(&sobj, &arcs, &ee);
error = rpp_crl(pp, &crl);
if (error)
goto revert_roa;
- eecert_init(&ee, crl, false);
+ eecert_init(&ee, EET_ROA, crl, false);
/* Validate and handle everything */
error = signed_object_validate(&sobj, &arcs, &ee);
validation_handler.handle_roa_v4 = handle_roa_v4;
validation_handler.handle_roa_v6 = handle_roa_v6;
validation_handler.handle_router_key = handle_router_key;
+ validation_handler.handle_aspa = handle_aspa;
validation_handler.arg = db;
error = validation_prepare(&state, tal, &validation_handler);
return rasn_contains(res->asns, range);
}
+bool
+resources_matches_asn(struct resources *res, uint32_t asid)
+{
+ return rasn_matches(res->asns, asid);
+}
+
bool
resources_contains_ipv4(struct resources *res, struct ipv4_prefix const *prefix)
{
bool resources_empty(struct resources *);
bool resources_contains_asns(struct resources *, struct asn_range const *);
+bool resources_matches_asn(struct resources *, uint32_t);
bool resources_contains_ipv4(struct resources *, struct ipv4_prefix const *);
bool resources_contains_ipv6(struct resources *, struct ipv6_prefix const *);
return sarray_contains((struct sorted_array *) asns, range);
}
+bool
+rasn_matches(struct resources_asn *_asns, uint32_t asn)
+{
+ struct sorted_array *asns = (struct sorted_array *)_asns;
+ struct asn_range range;
+
+ if (asns == NULL)
+ return false;
+ if (sarray_count(asns) != 1u)
+ return false;
+
+ range.min = range.max = asn;
+ return sarray_contains(asns, &range);
+}
+
static int
asn_range_cb(void *node, void *arg)
{
int rasn_add(struct resources_asn *, struct asn_range const *);
bool rasn_empty(struct resources_asn *);
bool rasn_contains(struct resources_asn *, struct asn_range const *);
+bool rasn_matches(struct resources_asn *, uint32_t);
typedef int (*foreach_asn_cb)(struct asn_range const *, void *);
int rasn_foreach(struct resources_asn *, foreach_asn_cb, void *);
#include "rpp.h"
#include "log.h"
+#include "object/aspa.h"
#include "object/crl.h"
#include "object/ghostbusters.h"
#include "object/roa.h"
struct uri_list roas; /* Route Origin Attestations */
+ struct uri_list aspas;
+
struct uri_list ghostbusters;
/*
return 0;
}
+int
+rpp_add_asa(struct rpp *pp, struct rpki_uri *uri)
+{
+ uris_add(&pp->aspas, uri);
+ return 0;
+}
+
/** Steals ownership of @uri. */
int
rpp_add_gbr(struct rpp *pp, struct rpki_uri *uri)
ARRAYLIST_FOREACH(&pp->roas, uri)
roa_traverse(*uri, pp);
+ ARRAYLIST_FOREACH(&pp->aspas, uri)
+ aspa_traverse(*uri, pp);
+
/*
* We don't do much with the ghostbusters right now.
* Just validate them.
int rpp_add_cer(struct rpp *, struct rpki_uri *);
int rpp_add_crl(struct rpp *, struct rpki_uri *);
int rpp_add_roa(struct rpp *, struct rpki_uri *);
+int rpp_add_asa(struct rpp *pp, struct rpki_uri *);
int rpp_add_gbr(struct rpp *, struct rpki_uri *);
struct rpki_uri *rpp_get_crl(struct rpp const *);
ext = uri_get_global(uri) + uri_get_global_len(uri) - 4;
return ((strcmp(ext, ".cer") == 0)
|| (strcmp(ext, ".roa") == 0)
+ || (strcmp(ext, ".asa") == 0)
|| (strcmp(ext, ".mft") == 0)
|| (strcmp(ext, ".crl") == 0)
|| (strcmp(ext, ".gbr") == 0));
#include <errno.h>
#include "alloc.h"
+#include "config.h"
#include "data_structure/uthash.h"
#include "log.h"
+#include "types/aspa.h"
struct hashable_roa {
struct vrp data;
UT_hash_handle hh;
};
+struct hashable_aspa {
+ struct aspa *v;
+ UT_hash_handle hh;
+};
+
struct db_table {
struct hashable_roa *roas;
struct hashable_key *router_keys;
+ struct hashable_aspa *aspas;
unsigned int total_roas_v4;
unsigned int total_roas_v6;
return 0;
}
+/* Assumes the lists are already sorted. Places the result in @new. */
+static struct aspa_providers
+merge_providers(struct aspa_providers *old, struct aspa_providers *new)
+{
+ struct aspa_providers result;
+ uint32_t *merge;
+ size_t o, n, m;
+
+ m = old->count + new->count;
+ if (!old->asids || m > config_get_max_aspa_providers()) {
+ result.asids = NULL;
+ result.count = 0;
+ return result;
+ }
+
+ merge = pcalloc(m, sizeof(uint32_t));
+
+ for (o = 0, n = 0, m = 0; o < old->count && n < new->count;) {
+ if (old->asids[o] < new->asids[n]) {
+ merge[m] = old->asids[o];
+ o++;
+ m++;
+ } else if (old->asids[o] > new->asids[n]) {
+ merge[m] = new->asids[n];
+ n++;
+ m++;
+ } else
+ o++;
+ }
+
+ for (; o < old->count; o++, m++)
+ merge[m] = old->asids[o];
+ for (; n < new->count; n++, m++)
+ merge[m] = new->asids[n];
+
+ result.asids = merge;
+ result.count = m;
+ return result;
+}
+
+static int
+add_aspa(struct db_table *table, struct hashable_aspa *new)
+{
+ struct hashable_aspa *old;
+ struct aspa_providers merge;
+ int error;
+
+ errno = 0;
+ HASH_REPLACE(hh, table->aspas, v->customer, sizeof(new->v->customer),
+ new, old);
+ error = errno;
+ if (error) {
+ pr_val_err("Cannot store ASPA: %s", strerror(error));
+ return -error;
+ }
+
+ if (old != NULL) {
+ merge = merge_providers(&old->v->providers, &new->v->providers);
+
+ free(new->v->providers.asids);
+ new->v->providers = merge;
+
+ free(old->v->providers.asids);
+ free(old);
+ }
+
+ return 0;
+}
+
/* Moves the content from @src into @dst. */
int
db_table_join(struct db_table *dst, struct db_table *src)
return 0;
}
+int
+db_table_foreach_aspa(struct db_table const *table, aspa_foreach_cb cb,
+ void *arg)
+{
+ struct hashable_aspa *node, *tmp;
+ int error;
+
+ HASH_ITER(hh, table->aspas, node, tmp) {
+ error = cb(node->v, arg);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
unsigned int
db_table_roa_count(struct db_table *table)
{
return error;
}
+int
+rtrhandler_handle_aspa(struct db_table *table, struct aspa *v)
+{
+ struct hashable_aspa *aspa;
+ int error;
+
+ aspa = pzalloc(sizeof(struct hashable_aspa));
+ aspa->v = v;
+
+ error = add_aspa(table, aspa);
+ if (error)
+ free(aspa);
+ else
+ aspa_refget(v);
+
+ return error;
+}
+
/*
* Copies `@roas1 - roas2` into @deltas.
*
return 0;
}
-static void
-add_router_key_delta(struct deltas *deltas, struct hashable_key *key, int op)
-{
- deltas_add_router_key(deltas, &key->data, op);
-}
-
/*
* Copies `@keys1 - keys2` into @deltas.
*
for (n1 = keys1; n1 != NULL; n1 = n1->hh.next) {
HASH_FIND(hh, keys2, &n1->data, sizeof(n1->data), n2);
if (n2 == NULL)
- add_router_key_delta(deltas, n1, op);
+ deltas_add_router_key(deltas, &n1->data, op);
+ }
+}
+
+static void
+add_aspa_announcements(struct hashable_aspa *old, struct hashable_aspa *new,
+ struct deltas *deltas)
+{
+ struct hashable_aspa *o, *n, *tmp;
+
+ HASH_ITER(hh, new, n, tmp) {
+ HASH_FIND(hh, old, &n->v->customer, sizeof(n->v->customer), o);
+ if (o == NULL || !providers_equal(&o->v->providers, &n->v->providers))
+ deltas_add_aspa(deltas, o->v, FLAG_ANNOUNCEMENT);
+ }
+}
+
+static void
+add_aspa_withdraws(struct hashable_aspa *old, struct hashable_aspa *new,
+ struct deltas *deltas)
+{
+ struct hashable_aspa *o, *n, *tmp;
+
+ HASH_ITER(hh, old, o, tmp) {
+ HASH_FIND(hh, new, &o->v->customer, sizeof(o->v->customer), n);
+ if (n == NULL)
+ deltas_add_aspa(deltas, o->v, FLAG_WITHDRAWAL);
}
}
FLAG_ANNOUNCEMENT);
add_router_key_deltas(old->router_keys, new->router_keys, deltas,
FLAG_WITHDRAWAL);
+ add_aspa_announcements(old->aspas, new->aspas, deltas);
+ add_aspa_withdraws(old->aspas, new->aspas, deltas);
if (deltas_is_empty(deltas)) {
deltas_refput(deltas);
#include "rtr/db/delta.h"
#include "types/address.h"
+#include "types/aspa.h"
struct db_table;
void *);
void db_table_remove_router_key(struct db_table *, struct router_key const *);
+int db_table_foreach_aspa(struct db_table const *, aspa_foreach_cb, void *);
+
int rtrhandler_handle_roa_v4(struct db_table *, uint32_t,
struct ipv4_prefix const *, uint8_t);
int rtrhandler_handle_roa_v6(struct db_table *, uint32_t,
struct ipv6_prefix const *, uint8_t);
int rtrhandler_handle_router_key(struct db_table *, unsigned char const *,
uint32_t, unsigned char const *);
+int rtrhandler_handle_aspa(struct db_table *, struct aspa *);
struct deltas *compute_deltas(struct db_table *, struct db_table *);
#endif /* SRC_RTR_DB_DB_TABLE_H_ */
unsigned char spk[RK_SPKI_LEN];
};
+struct _delta_aspa {
+ struct aspa *aspa;
+};
+
STATIC_ARRAY_LIST(deltas_v6, struct delta_v6)
STATIC_ARRAY_LIST(deltas_v4, struct delta_v4)
STATIC_ARRAY_LIST(deltas_rk, struct delta_rk)
+STATIC_ARRAY_LIST(deltas_aspa, struct _delta_aspa)
struct deltas {
struct {
struct deltas_rk adds;
struct deltas_rk removes;
} rk;
+ struct {
+ struct deltas_aspa adds;
+ struct deltas_aspa removes;
+ } aspa;
atomic_uint references;
};
deltas_v6_init(&result->v6.removes);
deltas_rk_init(&result->rk.adds);
deltas_rk_init(&result->rk.removes);
+ deltas_aspa_init(&result->aspa.adds);
+ deltas_aspa_init(&result->aspa.removes);
atomic_init(&result->references, 1);
return result;
deltas_v6_cleanup(&deltas->v6.removes, NULL);
deltas_rk_cleanup(&deltas->rk.adds, NULL);
deltas_rk_cleanup(&deltas->rk.removes, NULL);
+ deltas_aspa_cleanup(&deltas->aspa.adds, NULL);
+ deltas_aspa_cleanup(&deltas->aspa.removes, NULL);
free(deltas);
}
}
pr_crit("Unknown delta operation: %d", op);
}
+void
+deltas_add_aspa(struct deltas *deltas, struct aspa *aspa, int op)
+{
+ struct _delta_aspa delta;
+
+ delta.aspa = aspa;
+ aspa_refget(aspa);
+
+ switch (op) {
+ case FLAG_ANNOUNCEMENT:
+ deltas_aspa_add(&deltas->aspa.adds, &delta);
+ return;
+ case FLAG_WITHDRAWAL:
+ deltas_aspa_add(&deltas->aspa.removes, &delta);
+ return;
+ }
+
+ pr_crit("Unknown delta operation: %d", op);
+}
+
bool
deltas_is_empty(struct deltas *deltas)
{
&& (deltas->v6.adds.len == 0)
&& (deltas->v6.removes.len == 0)
&& (deltas->rk.adds.len == 0)
- && (deltas->rk.removes.len == 0);
+ && (deltas->rk.removes.len == 0)
+ && (deltas->aspa.adds.len == 0)
+ && (deltas->aspa.removes.len == 0);
}
static int
return 0;
}
+static int
+__foreach_aspa(struct deltas_aspa *array, delta_aspa_foreach_cb cb, void *arg,
+ uint8_t flags)
+{
+ struct delta_aspa delta;
+ struct _delta_aspa *d;
+ int error;
+
+ delta.flags = flags;
+
+ ARRAYLIST_FOREACH(array, d) {
+ delta.aspa = d->aspa;
+ error = cb(&delta, arg);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
int
deltas_foreach(struct deltas *deltas, delta_vrp_foreach_cb cb_vrp,
- delta_router_key_foreach_cb cb_rk, void *arg)
+ delta_router_key_foreach_cb cb_rk, delta_aspa_foreach_cb cb_aspa,
+ void *arg)
{
int error;
error = __foreach_v4(&deltas->v4.adds, cb_vrp, arg, FLAG_ANNOUNCEMENT);
if (error)
return error;
-
error = __foreach_v4(&deltas->v4.removes, cb_vrp, arg, FLAG_WITHDRAWAL);
if (error)
return error;
-
error = __foreach_v6(&deltas->v6.adds, cb_vrp, arg, FLAG_ANNOUNCEMENT);
if (error)
return error;
-
error = __foreach_v6(&deltas->v6.removes, cb_vrp, arg, FLAG_WITHDRAWAL);
if (error)
return error;
-
error = __foreach_rk(&deltas->rk.adds, cb_rk, arg, FLAG_ANNOUNCEMENT);
if (error)
return error;
-
- return __foreach_rk(&deltas->rk.removes, cb_rk, arg, FLAG_WITHDRAWAL);
+ error = __foreach_rk(&deltas->rk.removes, cb_rk, arg, FLAG_WITHDRAWAL);
+ if (error)
+ return error;
+ error = __foreach_aspa(&deltas->aspa.adds, cb_aspa, arg, FLAG_ANNOUNCEMENT);
+ if (error)
+ return error;
+ return __foreach_aspa(&deltas->aspa.removes, cb_aspa, arg, FLAG_WITHDRAWAL);
}
void
deltas_print(struct deltas *deltas)
{
- deltas_foreach(deltas, delta_vrp_print, delta_rk_print, NULL);
+ deltas_foreach(deltas, delta_vrp_print, delta_rk_print, delta_aspa_print, NULL);
}
#ifndef SRC_DELTA_H_
#define SRC_DELTA_H_
+#include "types/aspa.h"
#include "types/delta.h"
struct deltas;
void deltas_add_roa(struct deltas *, struct vrp const *, int,
char, unsigned int, unsigned int);
void deltas_add_router_key(struct deltas *, struct router_key const *, int);
+void deltas_add_aspa(struct deltas *, struct aspa *, int);
bool deltas_is_empty(struct deltas *);
int deltas_foreach(struct deltas *, delta_vrp_foreach_cb,
- delta_router_key_foreach_cb, void *);
+ delta_router_key_foreach_cb, delta_aspa_foreach_cb, void *);
void deltas_print(struct deltas *);
#endif /* SRC_DELTA_H_ */
SLIST_ENTRY(rk_node) next;
};
+struct aspa_node {
+ struct delta_aspa delta;
+ SLIST_ENTRY(aspa_node) next;
+};
+
/** Sorted list to filter deltas */
SLIST_HEAD(vrp_slist, vrp_node);
SLIST_HEAD(rk_slist, rk_node);
+SLIST_HEAD(aspa_slist, aspa_node);
struct sorted_lists {
struct vrp_slist prefixes;
struct rk_slist router_keys;
+ struct aspa_slist aspas;
};
struct state {
return 0;
}
+int
+handle_aspa(struct aspa *aspa, void *arg)
+{
+ return rtrhandler_handle_aspa(arg, aspa);
+}
+
/*
* High level validator function.
*
* 2. -EAGAIN: No data available; database still under construction.
*/
int
-vrps_foreach_base(vrp_foreach_cb cb_roa, router_key_foreach_cb cb_rk, void *arg)
+vrps_foreach_base(vrp_foreach_cb cb_roa, router_key_foreach_cb cb_rk,
+ aspa_foreach_cb cb_aspa, void *arg)
{
int error;
if (error)
goto end;
error = db_table_foreach_router_key(state.base, cb_rk, arg);
+ if (error)
+ goto end;
+ error = db_table_foreach_aspa(state.base, cb_aspa, arg);
} else
error = -EAGAIN;
&& memcmp(key->spk, ptr->delta.router_key.spk,
RK_SPKI_LEN) == 0 &&
delta->flags != ptr->delta.flags) {
+ /* TODO (rk) Shouldn't it be replaced? */
SLIST_REMOVE(filtered_keys, ptr, rk_node, next);
free(ptr);
return 0;
return 0;
}
+static int
+aspa_ovrd_remove(struct delta_aspa const *delta, void *arg)
+{
+ struct sorted_lists *lists = arg;
+ struct aspa_node *ptr;
+ struct aspa_slist *filtered_aspas;
+
+ filtered_aspas = &lists->aspas;
+ SLIST_FOREACH(ptr, filtered_aspas, next) {
+ if (delta->aspa->customer == ptr->delta.aspa->customer) {
+ SLIST_REMOVE(filtered_aspas, ptr, aspa_node, next);
+ ptr->delta = *delta;
+ SLIST_INSERT_HEAD(filtered_aspas, ptr, next);
+ return 0;
+ }
+ }
+
+ ptr = pmalloc(sizeof(struct aspa_node));
+ ptr->delta = *delta;
+ SLIST_INSERT_HEAD(filtered_aspas, ptr, next);
+ return 0;
+}
+
static int
__deltas_foreach(struct deltas *deltas, void *arg)
{
return deltas_foreach(deltas, vrp_ovrd_remove, router_key_ovrd_remove,
- arg);
+ aspa_ovrd_remove, arg);
}
/**
int
vrps_foreach_delta_since(serial_t from, serial_t *to,
delta_vrp_foreach_cb vrp_cb, delta_router_key_foreach_cb rk_cb,
- void *arg)
+ delta_aspa_foreach_cb aspa_cb, void *arg)
{
struct sorted_lists filtered_lists;
struct vrp_node *vnode;
struct rk_node *rnode;
+ struct aspa_node *anode;
int error;
error = rwlock_read_lock(&state_lock);
*/
SLIST_INIT(&filtered_lists.prefixes);
SLIST_INIT(&filtered_lists.router_keys);
+ SLIST_INIT(&filtered_lists.aspas);
error = darray_foreach_since(state.deltas, state.serial - from,
__deltas_foreach, &filtered_lists);
if (error)
break;
}
+ SLIST_FOREACH(anode, &filtered_lists.aspas, next) {
+ error = aspa_cb(&anode->delta, arg);
+ if (error)
+ break;
+ }
release_list:
while (!SLIST_EMPTY(&filtered_lists.prefixes)) {
SLIST_REMOVE_HEAD(&filtered_lists.router_keys, next);
free(rnode);
}
+ while (!SLIST_EMPTY(&filtered_lists.aspas)) {
+ anode = filtered_lists.aspas.slh_first;
+ SLIST_REMOVE_HEAD(&filtered_lists.aspas, next);
+ free(anode);
+ }
*to = state.serial;
rwlock_unlock(&state_lock);
void
vrps_print_base(void)
{
- vrps_foreach_base(vrp_print, router_key_print, NULL);
+ vrps_foreach_base(vrp_print, router_key_print, aspa_print, NULL);
}
#include "as_number.h"
#include "types/address.h"
+#include "types/aspa.h"
#include "types/delta.h"
#include "types/serial.h"
* Handle gracefully.
*/
-int vrps_foreach_base(vrp_foreach_cb, router_key_foreach_cb, void *);
+int vrps_foreach_base(vrp_foreach_cb, router_key_foreach_cb, aspa_foreach_cb,
+ void *);
int vrps_foreach_delta_since(serial_t, serial_t *, delta_vrp_foreach_cb,
- delta_router_key_foreach_cb, void *);
+ delta_router_key_foreach_cb, delta_aspa_foreach_cb, void *);
int get_last_serial_number(serial_t *);
int handle_roa_v4(uint32_t, struct ipv4_prefix const *, uint8_t, void *);
int handle_roa_v6(uint32_t, struct ipv6_prefix const *, uint8_t, void *);
int handle_router_key(unsigned char const *, struct asn_range const *,
unsigned char const *, void *);
+int handle_aspa(struct aspa *, void *);
uint16_t get_current_session_id(uint8_t);
return "Router Key PDU";
case PDU_TYPE_ERROR_REPORT:
return "Error Report PDU";
+ case PDU_TYPE_ASPA:
+ return "ASPA PDU";
}
return "unknown PDU";
enum rtr_version {
RTR_V0 = 0,
RTR_V1 = 1,
+ RTR_V2 = 2,
};
struct rtr_buffer {
PDU_TYPE_CACHE_RESET = 8,
PDU_TYPE_ROUTER_KEY = 9,
PDU_TYPE_ERROR_REPORT = 10,
+ PDU_TYPE_ASPA = 11,
};
char const *pdutype2str(enum pdu_type);
&delta->router_key, delta->flags);
}
+static int
+send_delta_aspa(struct delta_aspa const *delta, void *arg)
+{
+ struct send_delta_args *args = arg;
+ int error;
+
+ error = send_cache_response_maybe(args);
+ if (error)
+ return error;
+
+ return send_aspa_pdu(args->fd, args->rtr_version,
+ delta->aspa, delta->flags);
+}
+
int
handle_serial_query_pdu(struct rtr_request *request)
{
*/
error = vrps_foreach_delta_since(request->pdu.obj.sq.serial_number,
- &final_serial, send_delta_vrp, send_delta_rk, &args);
+ &final_serial, send_delta_vrp, send_delta_rk, send_delta_aspa,
+ &args);
switch (error) {
case 0:
/*
FLAG_ANNOUNCEMENT);
}
+static int
+send_base_aspa(struct aspa const *aspa, void *arg)
+{
+ struct base_roa_args *args = arg;
+ int error;
+
+ if (!args->started) {
+ error = send_cache_response_pdu(args->fd, args->version);
+ if (error)
+ return error;
+ args->started = true;
+ }
+
+ return send_aspa_pdu(args->fd, args->version, aspa, FLAG_ANNOUNCEMENT);
+}
+
int
handle_reset_query_pdu(struct rtr_request *request)
{
* queries than reset queries.
*/
- error = vrps_foreach_base(send_base_roa, send_base_router_key, &args);
+ error = vrps_foreach_base(send_base_roa, send_base_router_key,
+ send_base_aspa, &args);
/* See handle_serial_query_pdu() for some comments. */
switch (error) {
#include "alloc.h"
#include "config.h"
+#include "data_structure/common.h"
#include "log.h"
#include "rtr/db/vrps.h"
#include "rtr/primitive_writer.h"
unsigned char data[RTRPDU_ROUTER_KEY_LEN];
unsigned char *buf;
- if (version == RTR_V0)
+ if (version < RTR_V1)
return 0;
buf = serialize_hdr(data, version, type, flags << 8, len);
return send_response(fd, type, data, len);
}
+int
+send_aspa_pdu(int fd, uint8_t version, struct aspa const *aspa, uint8_t flags)
+{
+ static const uint8_t type = PDU_TYPE_ASPA;
+ unsigned char data[1024];
+ array_index i;
+ unsigned char *buf;
+ int error;
+
+ if (version < RTR_V2)
+ return 0;
+
+ if (flags & FLAG_ANNOUNCEMENT) {
+ buf = serialize_hdr(data, version, type, flags << 8,
+ 12 + 4 * aspa->providers.count);
+ buf = write_uint32(buf, aspa->customer);
+
+ for (i = 0; i < aspa->providers.count; i++) {
+ buf = write_uint32(buf, aspa->providers.asids[i]);
+
+ if (buf >= data + 1024) {
+ error = send_response(fd, type, data, buf - data);
+ if (error)
+ return error;
+ buf = data;
+ }
+ }
+
+ if (buf > data) {
+ error = send_response(fd, type, data, buf - data);
+ if (error)
+ return error;
+ }
+
+ } else {
+ buf = serialize_hdr(data, version, type, flags << 8, 12);
+ write_uint32(buf, aspa->customer);
+ error = send_response(fd, type, data, 12);
+ if (error)
+ return error;
+ }
+
+
+ return 0;
+}
+
#define MAX(a, b) ((a > b) ? a : b)
int
#define SRC_RTR_PDU_SENDER_H_
#include "rtr/pdu.h"
+#include "types/aspa.h"
#include "types/router_key.h"
#include "types/serial.h"
#include "types/vrp.h"
int send_cache_response_pdu(int, uint8_t);
int send_prefix_pdu(int, uint8_t, struct vrp const *, uint8_t);
int send_router_key_pdu(int, uint8_t, struct router_key const *, uint8_t);
+int send_aspa_pdu(int, uint8_t, struct aspa const *, uint8_t);
int send_end_of_data_pdu(int, uint8_t, serial_t);
int send_error_report_pdu(int, uint8_t, uint16_t, struct rtr_buffer const *,
char *);
return false;
}
+unsigned int
+sarray_count(struct sorted_array const *sarray)
+{
+ return sarray ? sarray->count : 0;
+}
+
int
sarray_foreach(struct sorted_array *sarray, sarray_foreach_cb cb, void *arg)
{
int sarray_add(struct sorted_array *, void const *);
bool sarray_empty(struct sorted_array const *);
bool sarray_contains(struct sorted_array const *, void const *);
+unsigned int sarray_count(struct sorted_array const *);
typedef int (*sarray_foreach_cb)(void *, void *);
int sarray_foreach(struct sorted_array *, sarray_foreach_cb, void *);
--- /dev/null
+#include "types/aspa.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "data_structure/common.h"
+
+void
+aspa_refget(struct aspa *aspa)
+{
+ aspa->refs++;
+}
+
+void
+aspa_refput(struct aspa *aspa)
+{
+ if ((aspa->refs--) <= 1) {
+ free(aspa->providers.asids);
+ free(aspa);
+ }
+}
+
+int
+aspa_print(struct aspa const *aspa, void *arg)
+{
+ array_index i;
+ printf("- [ASPA customerASID:%u\n", aspa->customer);
+ for (i = 0; i < aspa->providers.count; i++)
+ printf(" [Provider:%u]\n", aspa->providers.asids[i]);
+ printf(" ]\n");
+ return 0;
+}
+
+bool
+providers_equal(struct aspa_providers *a, struct aspa_providers *b)
+{
+ array_index i;
+
+ if (a == b)
+ return true;
+ if (!a || !b || (a->count != b->count))
+ return false;
+
+ for (i = 0; i < a->count; i++)
+ if (a->asids[i] != b->asids[i])
+ return false;
+
+ return true;
+}
--- /dev/null
+#ifndef SRC_TYPES_ASPA_H_
+#define SRC_TYPES_ASPA_H_
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+struct aspa_providers {
+ /* Can be NULL and zero. If this happens, just withdraw. */
+ uint32_t *asids;
+ size_t count;
+};
+
+struct aspa {
+ uint32_t customer;
+ struct aspa_providers providers;
+
+ int refs;
+};
+
+typedef int (*aspa_foreach_cb)(struct aspa const *, void *);
+
+void aspa_refget(struct aspa *);
+void aspa_refput(struct aspa *);
+int aspa_print(struct aspa const *, void *);
+
+bool providers_equal(struct aspa_providers *, struct aspa_providers *);
+
+#endif /* SRC_TYPES_ASPA_H_ */
print_flag(delta->flags);
return router_key_print(&delta->router_key, arg);
}
+
+int
+delta_aspa_print(struct delta_aspa const *delta, void *arg)
+{
+ print_flag(delta->flags);
+ return aspa_print(delta->aspa, arg);
+}
#ifndef SRC_TYPES_DELTA_H_
#define SRC_TYPES_DELTA_H_
+#include "types/aspa.h"
#include "types/router_key.h"
#include "types/vrp.h"
uint8_t flags;
};
+struct delta_aspa {
+ struct aspa *aspa;
+ uint8_t flags;
+};
+
typedef int (*delta_vrp_foreach_cb)(struct delta_vrp const *, void *);
typedef int (*delta_router_key_foreach_cb)(struct delta_router_key const *,
void *);
+typedef int (*delta_aspa_foreach_cb)(struct delta_aspa const *, void *);
int delta_vrp_print(struct delta_vrp const *, void *);
int delta_rk_print(struct delta_router_key const *, void *);
+int delta_aspa_print(struct delta_aspa const *, void *);
#endif /* SRC_TYPES_DELTA_H_ */
? handler->handle_router_key(ski, asns, spk, handler->arg)
: 0;
}
+
+int
+vhandler_handle_aspa(struct aspa *aspa)
+{
+ struct validation_handler const *handler;
+
+ handler = get_current_threads_handler();
+
+ return (handler->handle_aspa != NULL)
+ ? handler->handle_aspa(aspa, handler->arg)
+ : 0;
+}
/** Called every time Fort has successfully validated a BGPsec cert */
int (*handle_router_key)(unsigned char const *,
struct asn_range const *, unsigned char const *, void *);
+ /* Swallows the ASPA. */
+ int (*handle_aspa)(struct aspa *, void *);
/** Generic user-defined argument for the functions above. */
void *arg;
};
int vhandler_handle_roa_v6(uint32_t, struct ipv6_prefix const *, uint8_t);
int vhandler_handle_router_key(unsigned char const *, struct asn_range const *,
unsigned char const *);
+int vhandler_handle_aspa(struct aspa *);
#endif /* SRC_VALIDATION_HANDLER_H_ */
static unsigned int total_found;
__MOCK_ABORT(config_get_local_repository, char const *, "tmp/dbt", void)
+MOCK_UINT(config_get_max_aspa_providers, 10, void)
static bool
vrp_equals_v4(struct vrp const *vrp, uint8_t as, uint32_t addr,
}
END_TEST
+static void
+init_providers(struct aspa_providers *provs, ...)
+{
+ int asn;
+ size_t a;
+ va_list ap;
+
+ va_start(ap, provs);
+ for (a = 0; (asn = va_arg(ap, int)) != 0; a++)
+ ;
+ va_end(ap);
+
+ provs->asids = pcalloc(a, sizeof(uint32_t));
+ provs->count = a;
+
+ va_start(ap, provs);
+ for (a = 0; (asn = va_arg(ap, int)) != 0; a++)
+ provs->asids[a] = asn;
+ va_end(ap);
+}
+
+static void
+ck_merge(struct aspa_providers *a1, struct aspa_providers *a2, ...)
+{
+ struct aspa_providers res;
+ va_list ap;
+ size_t a;
+ int asn;
+
+ res = merge_providers(a1, a2);
+
+ va_start(ap, a2);
+ for (a = 0; (asn = va_arg(ap, int)) != 0; a++)
+ ck_assert_uint_eq(asn, res.asids[a]);
+ va_end(ap);
+ ck_assert_uint_eq(a, res.count);
+ free(res.asids);
+
+ res = merge_providers(a2, a1);
+ va_start(ap, a2);
+ for (a = 0; (asn = va_arg(ap, int)) != 0; a++)
+ ck_assert_uint_eq(asn, res.asids[a]);
+ va_end(ap);
+ ck_assert_uint_eq(a, res.count);
+ free(res.asids);
+}
+
+START_TEST(test_aspa_merge)
+{
+ struct aspa_providers a, b;
+
+ init_providers(&a, 1, 2, 3, 0);
+ init_providers(&b, 5, 6, 7, 0);
+ ck_merge(&a, &b, 1, 2, 3, 5, 6, 7, 0);
+
+ init_providers(&a, 1, 3, 5, 0);
+ init_providers(&b, 2, 4, 6, 0);
+ ck_merge(&a, &b, 1, 2, 3, 4, 5, 6, 0);
+
+ init_providers(&a, 2, 4, 10, 0);
+ init_providers(&b, 6, 8, 12, 0);
+ ck_merge(&a, &b, 2, 4, 6, 8, 10, 12, 0);
+
+ init_providers(&a, 1, 2, 3, 4, 0);
+ init_providers(&b, 1, 2, 3, 4, 0);
+ ck_merge(&a, &b, 1, 2, 3, 4, 0);
+
+ init_providers(&a, 1, 2, 3, 0);
+ init_providers(&b, 1, 2, 4, 6, 0);
+ ck_merge(&a, &b, 1, 2, 3, 4, 6, 0);
+
+ init_providers(&a, 1, 2, 3, 0);
+ init_providers(&b, 1, 2, 3, 4, 5, 0);
+ ck_merge(&a, &b, 1, 2, 3, 4, 5, 0);
+}
+END_TEST
+
static Suite *pdu_suite(void)
{
Suite *suite;
core = tcase_create("Core");
tcase_add_test(core, test_basic);
+ tcase_add_test(core, test_aspa_merge);
suite = suite_create("DB Table");
suite_add_tcase(suite, core);
MOCK_ABORT_INT(hash_local_file, char const *uri, unsigned char *result,
unsigned int *result_len)
__MOCK_ABORT(config_get_local_repository, char const *, "tmp/vrps", void)
+MOCK_UINT(config_get_max_aspa_providers, 10, void)
/* Test functions */
MOCK_ABORT_VOID(db_slurm_destroy, struct db_slurm *db)
MOCK_VOID(output_print_data, struct db_table const *db)
__MOCK_ABORT(config_get_local_repository, char const *, "tmp/pdu", void)
+MOCK_UINT(config_get_max_aspa_providers, 10, void)
/* Mocks end */