rpki_validator_SOURCES += object/signed_object.h object/signed_object.c
rpki_validator_SOURCES += object/tal.h object/tal.c
+rpki_validator_SOURCES += resource/ip4.h resource/ip4.c
+rpki_validator_SOURCES += resource/ip6.h resource/ip6.c
+rpki_validator_SOURCES += resource/asn.h resource/asn.c
+
rpki_validator_CFLAGS = -pedantic -Wall -std=gnu11 -O0 -g $(CFLAGS_DEBUG)
rpki_validator_LDFLAGS = $(LDFLAGS_DEBUG)
#include "address.h"
#include <string.h>
+#include <errno.h>
+#include "log.h"
+
+/**
+ * Returns a mask you can use to extract the suffix bits of an address whose
+ * prefix lengths @prefix_len.
+ * For example: Suppose that your address is 192.0.2.0/24.
+ * addr4_suffix_mask(24) returns 0.0.0.255.
+ */
+uint32_t
+ipv4_suffix_mask(unsigned int prefix_len)
+{
+ return htonl(0xFFFFFFFFu >> prefix_len);
+}
+
+void
+ipv6_suffix_mask(unsigned int prefix_len, struct in6_addr *result)
+{
+ if (prefix_len < 32) {
+ result->s6_addr32[0] |= htonl(0xFFFFFFFFu >> prefix_len);
+ result->s6_addr32[1] = 0xFFFFFFFFu;
+ result->s6_addr32[2] = 0xFFFFFFFFu;
+ result->s6_addr32[3] = 0xFFFFFFFFu;
+ } else if (prefix_len < 64) {
+ result->s6_addr32[1] |= htonl(0xFFFFFFFFu >> (prefix_len - 32));
+ result->s6_addr32[2] = 0xFFFFFFFFu;
+ result->s6_addr32[3] = 0xFFFFFFFFu;
+ } else if (prefix_len < 96) {
+ result->s6_addr32[2] |= htonl(0xFFFFFFFFu >> (prefix_len - 64));
+ result->s6_addr32[3] = 0xFFFFFFFFu;
+ } else {
+ result->s6_addr32[3] |= htonl(0xFFFFFFFFu >> (prefix_len - 96));
+ }
+}
+
+int
+prefix4_decode(IPAddress2_t *str, struct ipv4_prefix *result)
+{
+ int len;
+
+ if (str->size > 4) {
+ pr_err("IPv4 address has too many octets. (%u)", str->size);
+ return -EINVAL;
+ }
+ if (str->bits_unused < 0 || 7 < str->bits_unused) {
+ pr_err("Bit string IPv4 address's unused bits count (%d) is out of range (0-7).",
+ str->bits_unused);
+ return -EINVAL;
+ }
+
+ memset(&result->addr, 0, sizeof(result->addr));
+ memcpy(&result->addr, str->buf, str->size);
+ len = 8 * str->size - str->bits_unused;
+
+ if (len < 0 || 32 < len) {
+ pr_err("IPv4 prefix length (%d) is out of bounds (0-32).", len);
+ return -EINVAL;
+ }
+
+ result->len = len;
+
+ if ((result->addr.s_addr & ipv4_suffix_mask(result->len)) != 0) {
+ pr_err("IPv4 prefix has enabled suffix bits.");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int
+prefix6_decode(IPAddress2_t *str, struct ipv6_prefix *result)
+{
+ struct in6_addr suffix;
+ int len;
+
+ if (str->size > 16) {
+ pr_err("IPv6 address has too many octets. (%u)", str->size);
+ return -EINVAL;
+ }
+ if (str->bits_unused < 0 || 7 < str->bits_unused) {
+ pr_err("Bit string IPv6 address's unused bits count (%d) is out of range (0-7).",
+ str->bits_unused);
+ return -EINVAL;
+ }
+
+ memset(&result->addr, 0, sizeof(result->addr));
+ memcpy(&result->addr, str->buf, str->size);
+ len = 8 * str->size - str->bits_unused;
+
+ if (len < 0 || 128 < len) {
+ pr_err("IPv6 prefix length (%u) is out of bounds (0-128).",
+ len);
+ return -EINVAL;
+ }
+
+ result->len = len;
+
+ memset(&suffix, 0, sizeof(suffix));
+ ipv6_suffix_mask(result->len, &suffix);
+ if ( (result->addr.s6_addr32[0] & suffix.s6_addr32[0])
+ || (result->addr.s6_addr32[1] & suffix.s6_addr32[1])
+ || (result->addr.s6_addr32[2] & suffix.s6_addr32[2])
+ || (result->addr.s6_addr32[3] & suffix.s6_addr32[3])) {
+ pr_err("IPv6 prefix has enabled suffix bits.");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int
+range4_decode(IPAddressRange_t *input, struct ipv4_range *result)
+{
+ struct ipv4_prefix prefix;
+ int error;
+
+ error = prefix4_decode(&input->min, &prefix);
+ if (error)
+ return error;
+ result->min = prefix.addr;
+
+ error = prefix4_decode(&input->max, &prefix);
+ if (error)
+ return error;
+ result->max.s_addr = prefix.addr.s_addr | ipv4_suffix_mask(prefix.len);
+
+ return 0;
+}
+
+int
+range6_decode(IPAddressRange_t *input, struct ipv6_range *result)
+{
+ struct ipv6_prefix prefix;
+ int error;
+
+ error = prefix6_decode(&input->min, &prefix);
+ if (error)
+ return error;
+ result->min = prefix.addr;
+
+ error = prefix6_decode(&input->max, &prefix);
+ if (error)
+ return error;
+ result->max = prefix.addr;
+ ipv6_suffix_mask(prefix.len, &result->max);
+
+ return 0;
+}
bool
prefix4_contains(const struct ipv4_prefix *a, const struct ipv4_prefix *b)
#include <stdbool.h>
#include <netinet/in.h>
+#include <libcmscodec/IPAddress2.h>
+#include <libcmscodec/IPAddressRange.h>
struct ipv4_prefix {
struct in_addr addr;
- int len;
+ unsigned int len;
};
struct ipv6_prefix {
struct in6_addr addr;
- int len;
+ unsigned int len;
};
+struct ipv4_range {
+ struct in_addr min;
+ struct in_addr max;
+};
+
+struct ipv6_range {
+ struct in6_addr min;
+ struct in6_addr max;
+};
+
+uint32_t ipv4_suffix_mask(unsigned int);
+void ipv6_suffix_mask(unsigned int, struct in6_addr *);
+
+int prefix4_decode(IPAddress2_t *, struct ipv4_prefix *);
+int prefix6_decode(IPAddress2_t *, struct ipv6_prefix *);
+int range4_decode(IPAddressRange_t *, struct ipv4_range *);
+int range6_decode(IPAddressRange_t *, struct ipv6_range *);
+
bool prefix4_contains(const struct ipv4_prefix *, const struct ipv4_prefix *);
bool prefix6_contains(const struct ipv6_prefix *, const struct ipv6_prefix *);
#define SRC_OID_H_
#include <stdbool.h>
-#include <libcmscodec/AlgorithmIdentifier.h>
+#include <libcmscodec/ANY.h>
+#include <libcmscodec/OBJECT_IDENTIFIER.h>
#include "common.h"
/* These objects are expected to live on the stack. */
#include "log.h"
#include "oid.h"
#include "asn1/decode.h"
+#include "object/certificate.h"
/* TODO more consistent and informative error/warning messages.*/
static const OID oid_cta = OID_CONTENT_TYPE_ATTR;
static const OID oid_mda = OID_MESSAGE_DIGEST_ATTR;
static const OID oid_sta = OID_SIGNING_TIME_ATTR;
-static const OID oid_bst = OID_BINARY_SIGNING_TIME_ATTR;
+static const OID oid_bsta = OID_BINARY_SIGNING_TIME_ATTR;
/*
* The correctness of this function depends on @MAX_ARCS being faithful to all
return 0;
}
+static int
+handle_sdata_certificate(struct validation *state, ANY_t *any,
+ struct resources *res)
+{
+ const unsigned char *tmp;
+ X509 *cert;
+ int error;
+
+ pr_debug_add("Certificate (embedded) {");
+
+ /*
+ * "If the call is successful *in is incremented to the byte following
+ * the parsed data."
+ * (https://www.openssl.org/docs/man1.0.2/crypto/d2i_X509_fp.html)
+ * We definitely don't want @any->buf to be modified, so use a dummy
+ * pointer.
+ */
+ tmp = (const unsigned char *) any->buf;
+
+ cert = d2i_X509(NULL, &tmp, any->size);
+ if (cert == NULL) {
+ error = crypto_err(state, "Signed object's 'certificate' element does not decode into a Certificate");
+ goto end1;
+ }
+
+ error = certificate_validate(state, cert, NULL); /* TODO crls */
+ if (error)
+ goto end2;
+
+ if (res != NULL) {
+ error = certificate_get_resources(state, cert, res);
+ if (error)
+ goto end2;
+ }
+
+ /* TODO maybe spill a warning if the certificate has children? */
+
+end2:
+ X509_free(cert);
+end1:
+ pr_debug_rm("}");
+ return error;
+}
+
static int
validate_content_type_attribute(CMSAttributeValue_t *value,
EncapsulatedContentInfo_t *eci)
int error;
/* rfc6488#section-3.1.h */
+ /* TODO (performance) Can't we just do a memcmp? */
error = any2arcs(value, &attrValue_arcs);
if (error)
error = 0; /* No validations needed for now. */
signing_time_found = true;
- } else if (ARCS_EQUAL_OIDS(&attrType, oid_bst)) {
+ } else if (ARCS_EQUAL_OIDS(&attrType, oid_bsta)) {
if (binary_signing_time_found) {
pr_err("Multiple BinarySigningTimes found.");
goto illegal_attrType;
}
static int
-validate(struct SignedData *sdata)
+validate(struct validation *state, struct SignedData *sdata,
+ struct resources *res)
{
struct SignerInfo *sinfo;
bool is_digest;
* AlgorithmIdentifier instead. There's no API.
* This seems to work fine.
*/
- error = is_digest_algorithm((AlgorithmIdentifier_t *) sdata->digestAlgorithms.list.array[0],
+ error = is_digest_algorithm(
+ (AlgorithmIdentifier_t *) sdata->digestAlgorithms.list.array[0],
&is_digest);
if (error)
return error;
/* Specific sub-validations will be performed later by calling code. */
/* rfc6488#section-2.1.4 */
- /* rfc6488#section-3.1.c TODO missing half of the requirement. */
+ /* rfc6488#section-3.1.c 1/2 */
if (sdata->certificates == NULL) {
pr_err("The SignedData does not contain certificates.");
return -EINVAL;
return -EINVAL;
}
+ error = handle_sdata_certificate(state,
+ sdata->certificates->list.array[0], res);
+ if (error)
+ return error;
+
/* rfc6488#section-2.1.5 */
/* rfc6488#section-3.1.d */
if (sdata->crls != NULL && sdata->crls->list.count > 0) {
}
/* rfc6488#section-2.1.6.2 */
+ /* rfc6488#section-3.1.c 2/2 */
/*
* TODO need the "EE certificate carried in the CMS certificates field."
*/
/* rfc6488#section-2.1.6.3 */
/* rfc6488#section-3.1.j 2/2 */
- error = is_digest_algorithm((AlgorithmIdentifier_t *) &sinfo->digestAlgorithm,
- &is_digest);
+ error = is_digest_algorithm(
+ (AlgorithmIdentifier_t *) &sinfo->digestAlgorithm, &is_digest);
if (error)
return error;
if (!is_digest) {
}
int
-signed_data_decode(ANY_t *coded, struct SignedData **result)
+signed_data_decode(struct validation *state, ANY_t *coded,
+ struct SignedData **result, struct resources *res)
{
struct SignedData *sdata;
int error;
if (error)
return error;
- error = validate(sdata);
+ error = validate(state, sdata, res);
if (error) {
signed_data_free(sdata);
return error;
/* Some wrappers for libcmscodec's SignedData. */
#include <libcmscodec/SignedData.h>
+#include "resource.h"
+#include "state.h"
-int signed_data_decode(ANY_t *, struct SignedData **);
+int signed_data_decode(struct validation *, ANY_t *, struct SignedData **,
+ struct resources *);
void signed_data_free(struct SignedData *);
int get_content_type_attr(struct SignedData *, OBJECT_IDENTIFIER_t **);
#include "common.h"
-#include <err.h>
#include <errno.h>
-#include <string.h>
-#include <openssl/err.h>
#include "log.h"
char const *repository;
* function names. See rpki_validator_LDFLAGS in Makefile.am.
* Also: Only non-static functions will be labeled.
*
- * I think that the first three printed entries are usually not meaningful.
+ * During a segfault, the first three printed entries are usually not
+ * meaningful. Outside of a segfault, the first entry is not meaningful.
*/
void print_stack_trace(void)
{
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
-#include "common.h"
#include "log.h"
/*
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include "log.h"
struct line_file {
FILE *file;
return err;
if (feof(lfile->file))
return 0;
- warnx("Supposedly unreachable code reached. ferror:%d feof:%d",
+ pr_err("Supposedly unreachable code reached. ferror:%d feof:%d",
ferror(lfile->file), feof(lfile->file));
return -EINVAL;
}
*/
for (i = 0; i < len; i++) {
if (string[i] == '\0') {
- warnx("File '%s' has an illegal null character in its body. Please remove it.",
+ pr_err("File '%s' has an illegal null character in its body. Please remove it.",
lfile_name(lfile));
free(string);
return -EINVAL;
#include "log.h"
-#include <string.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <err.h>
#include <errno.h>
-#include <stdlib.h>
#include <openssl/objects.h>
#include "common.h"
#include "debug.h"
#include "log.h"
#include "object/certificate.h"
-#include "object/manifest.h"
#include "object/tal.h"
/**
print_stack_trace_on_segfault();
if (argc < 3) {
- warnx("Repository path as first argument and TAL file as second argument, please.");
+ pr_err("Repository path as first argument and TAL file as second argument, please.");
return -EINVAL;
}
#include "certificate.h"
+#include <errno.h>
#include <libcmscodec/SubjectInfoAccessSyntax.h>
-#include <openssl/err.h>
-#include <openssl/x509v3.h>
-#include <libcmscodec/ASIdentifiers.h>
#include <libcmscodec/IPAddrBlocks.h>
#include "common.h"
return file_has_extension(file_name, "cer");
}
+static int
+validate_signature_algorithm(X509 *cert)
+{
+ int nid;
+
+ nid = OBJ_obj2nid(X509_get0_tbs_sigalg(cert)->algorithm);
+ if (nid != NID_sha256WithRSAEncryption) {
+ pr_err("Certificate's Signature Algorithm is not RSASSA-PKCS1-v1_5.");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+validate_name(X509_NAME *name, char *what)
+{
+ X509_NAME_ENTRY *entry;
+ int nid;
+ int i;
+
+ for (i = 0; i < X509_NAME_entry_count(name); i++) {
+ entry = X509_NAME_get_entry(name, i);
+ nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry));
+ if (nid == NID_commonName)
+ return 0;
+ }
+
+ pr_err("Certificate's %s lacks the CommonName atribute.", what);
+ return -ESRCH;
+}
+
+static int
+validate_public_key(struct validation *state, X509 *cert)
+{
+ X509_PUBKEY *pubkey;
+ ASN1_OBJECT *algorithm;
+ int nid;
+ int ok;
+
+ pubkey = X509_get_X509_PUBKEY(cert);
+ if (pubkey == NULL) {
+ crypto_err(state, "X509_get_X509_PUBKEY() returned NULL.");
+ return -EINVAL;
+ }
+
+ ok = X509_PUBKEY_get0_param(&algorithm, NULL, NULL, NULL, pubkey);
+ if (!ok) {
+ crypto_err(state, "X509_PUBKEY_get0_param() returned %d.", ok);
+ return -EINVAL;
+ }
+
+ nid = OBJ_obj2nid(algorithm);
+ /*
+ * TODO Everyone uses this algorithm, but at a quick glance, it doesn't
+ * seem to match RFC 7935's public key algorithm. Wtf?
+ */
+ if (nid != NID_rsaEncryption) {
+ pr_err("Certificate's public key format is %d, not RSA PKCS#1 v1.5 with SHA-256.",
+ nid);
+ return -EINVAL;
+ }
+
+ /*
+ * BTW: WTF.
+ *
+ * RFC 6485: "The value for the associated parameters from that clause
+ * [RFC4055] MUST also be used for the parameters field."
+ * RFC 4055: "Implementations MUST accept the parameters being absent as
+ * well as present."
+ *
+ * Either the RFCs found a convoluted way of saying nothing, or I'm not
+ * getting the message.
+ */
+
+ return 0;
+}
+
+static int
+validate_extensions(X509 *cert)
+{
+ /* TODO */
+ return 0;
+}
+
+static int
+rfc6487_validate(struct validation *state, X509 *cert)
+{
+ int error;
+
+ /*
+ * I'm simply assuming that libcrypto implements RFC 5280. (I mean, it's
+ * not really stated anywhere AFAIK, but since OpenSSL is supposedly the
+ * quintessential crypto lib implementation, and RFC 5280 is supposedly
+ * the generic certificate RFC, it's fair to say it does a well enough
+ * job for all practical purposes.)
+ *
+ * But it's obvious that we can't assume that LibreSSL implements RFC
+ * 6487. It clearly doesn't.
+ *
+ * So here we go.
+ */
+
+ /* rfc6487#section-4.1 */
+ if (X509_get_version(cert) != 2) {
+ pr_err("Certificate version is not v3.");
+ return -EINVAL;
+ }
+
+ /* TODO rfc6487#section-4.2 */
+
+ /* rfc6487#section-4.3 */
+ error = validate_signature_algorithm(cert);
+ if (error)
+ return error;
+
+ /* rfc6487#section-4.4 */
+ error = validate_name(X509_get_issuer_name(cert), "issuer");
+ if (error)
+ return error;
+
+ /*
+ * rfc6487#section-4.5
+ *
+ * TODO "Each distinct subordinate CA and
+ * EE certified by the issuer MUST be identified using a subject name
+ * that is unique per issuer. In this context, "distinct" is defined as
+ * an entity and a given public key."
+ */
+ error = validate_name(X509_get_subject_name(cert), "subject");
+ if (error)
+ return error;
+
+ /* rfc6487#section-4.6 */
+ /* libcrypto already does this. */
+
+ /* rfc6487#section-4.7 */
+ error = validate_public_key(state, cert);
+ if (error)
+ return error;
+
+ return validate_extensions(cert);
+}
+
int
certificate_load(struct validation *state, const char *file, X509 **result)
{
return crypto_err(state, "BIO_new(BIO_s_file()) returned NULL");
if (BIO_read_filename(bio, file) <= 0) {
error = crypto_err(state, "Error reading certificate '%s'", file);
- goto end;
+ goto abort1;
}
cert = d2i_X509_bio(bio, NULL);
if (cert == NULL) {
error = crypto_err(state, "Error parsing certificate '%s'", file);
- goto end;
+ goto abort1;
}
+ error = rfc6487_validate(state, cert);
+ if (error)
+ goto abort2;
+
*result = cert;
- error = 0;
+ BIO_free(bio);
+ return 0;
-end:
+abort2:
+ X509_free(cert);
+abort1:
BIO_free(bio);
return error;
}
int error = 0;
/* Reference: X509_get_ext_d2i */
- /* TODO ensure that each extension can only be found once. */
+ /*
+ * TODO ensure that each extension can only be found once.
+ * TODO rfc6487#section-2 also ensure that at least one IP or ASN
+ * extension is found.
+ * TODO rfc6487#section-2 ensure that the IP/ASN extensions are
+ * critical.
+ */
for (i = 0; i < X509_get_ext_count(cert); i++) {
ext = X509_get_ext(cert, i);
#include "crl.h"
-#include <libcmscodec/SubjectInfoAccessSyntax.h>
-#include <openssl/err.h>
-#include <openssl/x509v3.h>
-
-#include "common.h"
#include "log.h"
-#include "manifest.h"
-#include "asn1/decode.h"
static int
__crl_load(struct validation *state, const char *file, X509_CRL **result)
#ifndef SRC_OBJECT_CRL_H_
#define SRC_OBJECT_CRL_H_
-#include <stdbool.h>
#include <openssl/x509.h>
#include "state.h"
#include "manifest.h"
#include <errno.h>
+#include <libcmscodec/GeneralizedTime.h>
#include <libcmscodec/Manifest.h>
-#include "common.h"
#include "log.h"
-#include "resource.h"
#include "asn1/oid.h"
#include "object/certificate.h"
#include "object/crl.h"
static int
print_roa(struct validation *state, char *file, void *arg)
{
- /* TODO */
- handle_roa(file);
+ /*
+ * TODO to validate the ROA's cert, the parent cert must not have been
+ * popped at this point.
+ */
+ handle_roa(state, file);
return 0;
}
struct manifest mft;
int error;
+ pr_debug_add("Manifest %s {", file_path);
+
mft.file_path = file_path;
- error = signed_object_decode(file_path, &asn_DEF_Manifest, &arcs,
- (void **) &mft.obj);
+ /*
+ * TODO about those NULL resources: Maybe print a warning if the
+ * certificate contains some.
+ */
+ error = signed_object_decode(state, file_path, &asn_DEF_Manifest, &arcs,
+ (void **) &mft.obj, NULL);
if (error)
- return error;
+ goto end;
error = validate_manifest(mft.obj);
if (!error)
error = __handle_manifest(state, &mft);
ASN_STRUCT_FREE(asn_DEF_Manifest, mft.obj);
+end:
+ pr_debug_rm("}");
return error;
}
#ifndef SRC_OBJECT_MANIFEST_H_
#define SRC_OBJECT_MANIFEST_H_
-#include <stdbool.h>
#include "state.h"
int handle_manifest(struct validation *, char const *);
#include <arpa/inet.h>
#include <libcmscodec/RouteOriginAttestation.h>
-#include "common.h"
#include "log.h"
#include "asn1/oid.h"
#include "object/signed_object.h"
static int
-validate_roa(struct RouteOriginAttestation *roa)
+print_addr4(struct resources *parent, long asn, struct ROAIPAddress *roa_addr)
{
- /* rfc6482#section-3.1 */
- if (roa->version != 0) {
- pr_err("ROA's version (%ld) is nonzero.", roa->version);
+ struct ipv4_prefix prefix;
+ char str[INET_ADDRSTRLEN];
+ const char *str2;
+ int error;
+
+ error = prefix4_decode(&roa_addr->address, &prefix);
+ if (error)
+ return error;
+
+ str2 = inet_ntop(AF_INET, &prefix.addr, str, sizeof(str));
+ if (str2 == NULL) {
+ pr_err("inet_ntop() returned NULL.");
return -EINVAL;
}
- /* rfc6482#section-3.2 */
- if (roa->ipAddrBlocks.list.array == NULL)
- return -EINVAL;
+ if (roa_addr->maxLength != NULL)
+ if (prefix.len > *roa_addr->maxLength)
+ goto unallowed;
+ if (!resources_contains_ipv4(parent, &prefix))
+ goto unallowed;
+ printf("%ld,%s/%u\n", asn, str2, prefix.len);
return 0;
+
+unallowed:
+ pr_err("ROA is not allowed to advertise %s/%u.", str2, prefix.len);
+ return -EINVAL;
}
static int
-print_addr(long asn, uint8_t family, struct ROAIPAddress *roa_addr)
+print_addr6(struct resources *parent, long asn, struct ROAIPAddress *roa_addr)
{
- union {
- struct in6_addr ip6;
- struct in_addr ip4;
- } addr;
- union {
- char ip6[INET6_ADDRSTRLEN];
- char ip4[INET_ADDRSTRLEN];
- } str;
- int prefix_len;
+ struct ipv6_prefix prefix;
+ char str[INET6_ADDRSTRLEN];
const char *str2;
+ int error;
- switch (family) {
- case 1:
- family = AF_INET;
- break;
- case 2:
- family = AF_INET6;
- break;
- default:
- pr_err("Unknown family value: %u", family);
+ error = prefix6_decode(&roa_addr->address, &prefix);
+ if (error)
+ return error;
+
+ str2 = inet_ntop(AF_INET6, &prefix.addr, str, sizeof(str));
+ if (str2 == NULL) {
+ pr_err("inet_ntop() returned NULL.");
return -EINVAL;
}
- /*
- * TODO maybe validate roa_addr->address.size > 0,
- * roa_addr->address.size <= actual address max size,
- * roa_addr->address.bits_unused < 8,
- * and roa_addr->address.buf lacks nonzero unused bits.
- * Also test 0/0.
- */
-
- memset(&addr, 0, sizeof(addr));
- memcpy(&addr, roa_addr->address.buf, roa_addr->address.size);
- str2 = inet_ntop(family, &addr, str.ip6, sizeof(str));
- if (str2 == NULL)
- return pr_errno(errno, "Cannot parse IP address");
+ if (roa_addr->maxLength != NULL)
+ if (prefix.len > *roa_addr->maxLength)
+ goto unallowed;
+ if (!resources_contains_ipv6(parent, &prefix))
+ goto unallowed;
- prefix_len = 8 * roa_addr->address.size - roa_addr->address.bits_unused;
+ printf("%ld,%s/%u\n", asn, str2, prefix.len);
+ return 0;
- printf("%ld,%s/%d,", asn, str2, prefix_len);
+unallowed:
+ pr_err("ROA is not allowed to advertise %s/%u.", str2, prefix.len);
+ return -EINVAL;
+}
- if (roa_addr->maxLength != NULL)
- printf("%ld", *roa_addr->maxLength);
- else
- printf("%d", prefix_len);
+static int
+print_addr(struct resources *parent, long asn, uint8_t family,
+ struct ROAIPAddress *roa_addr)
+{
+ switch (family) {
+ case 1: /* IPv4 */
+ return print_addr4(parent, asn, roa_addr);
+ case 2: /* IPv6 */
+ return print_addr6(parent, asn, roa_addr);
+ }
- printf("\n");
- return 0;
+ pr_err("Unknown family value: %u", family);
+ return -EINVAL;
}
static int
-__handle_roa(struct RouteOriginAttestation *roa)
+__handle_roa(struct RouteOriginAttestation *roa, struct resources *parent)
{
struct ROAIPAddressFamily *block;
int b;
int a;
int error;
+ /* rfc6482#section-3.1 */
+ if (roa->version != 0) {
+ pr_err("ROA's version (%ld) is nonzero.", roa->version);
+ return -EINVAL;
+ }
+
+ /* rfc6482#section-3.2 */
+ if (roa->ipAddrBlocks.list.array == NULL)
+ return -EINVAL;
+
+ /* rfc6482#section-3.3 */
+ if (!resources_contains_asn(parent, roa->asID)) {
+ pr_err("ROA is not allowed to attest for AS %d", roa->asID);
+ return -EINVAL;
+ }
+
for (b = 0; b < roa->ipAddrBlocks.list.count; b++) {
block = roa->ipAddrBlocks.list.array[0];
- if (block == NULL)
+ if (block == NULL) {
+ pr_err("Address block array element is NULL.");
return -EINVAL;
+ }
if (block->addressFamily.size != 2)
- return -EINVAL;
+ goto family_error;
if (block->addressFamily.buf[0] != 0)
- return -EINVAL;
+ goto family_error;
if (block->addressFamily.buf[1] != 1
&& block->addressFamily.buf[1] != 2)
- return -EINVAL;
+ goto family_error;
- if (block->addresses.list.array == NULL)
+ if (block->addresses.list.array == NULL) {
+ pr_err("ROA's address list array is NULL.");
return -EINVAL;
+ }
for (a = 0; a < block->addresses.list.count; a++) {
- error = print_addr(roa->asID,
+ error = print_addr(parent, roa->asID,
block->addressFamily.buf[1],
block->addresses.list.array[a]);
if (error)
}
return 0;
+
+family_error:
+ pr_err("ROA's IP family is not v4 or v6.");
+ return -EINVAL;
}
-int handle_roa(char const *file)
+int handle_roa(struct validation *state, char const *file)
{
static OID oid = OID_ROA;
struct oid_arcs arcs = OID2ARCS(oid);
struct RouteOriginAttestation *roa;
+ /* Resources contained in the ROA certificate, not in the ROA itself. */
+ struct resources *cert_resources;
int error;
pr_debug_add("ROA {");
- error = signed_object_decode(file, &asn_DEF_RouteOriginAttestation,
- &arcs, (void **) &roa);
- if (error)
- goto end;
-
- error = validate_roa(roa);
- if (!error)
- error = __handle_roa(roa);
+ cert_resources = resources_create();
+ if (cert_resources == NULL) {
+ pr_err("Out of memory");
+ error = -ENOMEM;
+ goto end1;
+ }
+ error = signed_object_decode(state, file,
+ &asn_DEF_RouteOriginAttestation, &arcs, (void **) &roa,
+ cert_resources);
+ if (error)
+ goto end2;
+ error = __handle_roa(roa, cert_resources);
ASN_STRUCT_FREE(asn_DEF_RouteOriginAttestation, roa);
-end:
+
+end2:
+ resources_destroy(cert_resources);
+end1:
pr_debug_rm("}");
return error;
}
#ifndef SRC_OBJECT_ROA_H_
#define SRC_OBJECT_ROA_H_
-#include <stdbool.h>
+#include "state.h"
-int handle_roa(char const *);
+int handle_roa(struct validation *, char const *);
#endif /* SRC_OBJECT_ROA_H_ */
}
int
-signed_object_decode(char const *file,
+signed_object_decode(struct validation *state,
+ char const *file,
asn_TYPE_descriptor_t const *descriptor,
struct oid_arcs const *oid,
- void **result)
+ void **result,
+ struct resources *res)
{
struct ContentInfo *cinfo;
struct SignedData *sdata;
if (error)
goto end1;
- error = signed_data_decode(&cinfo->content, &sdata);
+ error = signed_data_decode(state, &cinfo->content, &sdata, res);
if (error)
goto end2;
#define SRC_OBJECT_SIGNED_OBJECT_H_
#include "asn1/oid.h"
+#include "resource.h"
+#include "state.h"
-int signed_object_decode(char const *, asn_TYPE_descriptor_t const *,
- struct oid_arcs const *, void **);
+int signed_object_decode(struct validation *, char const *,
+ asn_TYPE_descriptor_t const *, struct oid_arcs const *, void **,
+ struct resources *);
#endif /* SRC_OBJECT_SIGNED_OBJECT_H_ */
#include "tal.h"
#include <sys/queue.h>
-#include <sys/stat.h>
-#include <err.h>
#include <errno.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
-#include <stdio.h>
-
-#include "common.h"
#include "line_file.h"
+#include "log.h"
struct uri {
char *string;
uri = malloc(sizeof(struct uri));
if (uri == NULL) {
- warnx("Out of memory");
+ pr_err("Out of memory.");
return -ENOMEM;
}
if (strcmp(uri->string, "") == 0) {
uri_destroy(uri);
- warnx("TAL file %s contains no URIs", lfile_name(lfile));
+ pr_err("TAL file %s contains no URIs", lfile_name(lfile));
return -EINVAL;
}
#include "resource.h"
#include <errno.h>
-#include <stdlib.h>
#include <arpa/inet.h>
+#include <sys/queue.h>
#include "address.h"
#include "log.h"
#include "sorted_array.h"
-
-struct resource4 {
- struct ipv4_prefix prefix;
-};
-
-struct resource6 {
- struct ipv6_prefix prefix;
-};
-
-struct resource_asn {
- ASId_t min;
- ASId_t max;
-};
+#include "resource/ip4.h"
+#include "resource/ip6.h"
+#include "resource/asn.h"
/* The resources we extracted from one certificate. */
struct resources {
- struct sorted_array *ip4s;
- struct sorted_array *ip6s;
- struct sorted_array *asns;
+ struct resources_ipv4 *ip4s;
+ struct resources_ipv6 *ip6s;
+ struct resources_asn *asns;
/*
* Used by restack. Points to the resources of the parent certificate.
*/
SLIST_HEAD(restack, resources);
-static enum sarray_comparison
-ip4_cmp(void *arg1, void *arg2)
-{
- struct ipv4_prefix *p1 = &((struct resource4 *) arg1)->prefix;
- struct ipv4_prefix *p2 = &((struct resource4 *) arg2)->prefix;
- uint32_t a1;
- uint32_t a2;
-
- if (p1->addr.s_addr == p2->addr.s_addr && p1->len == p2->len)
- return SACMP_EQUAL;
- if (prefix4_contains(p1, p2))
- return SACMP_CHILD;
- if (prefix4_contains(p2, p1))
- return SACMP_PARENT;
-
- a1 = ntohl(p1->addr.s_addr);
- a2 = ntohl(p2->addr.s_addr);
- if (a1 < a2)
- return SACMP_RIGHT;
- if (a2 < a1)
- return SACMP_LEFT;
-
- /* TODO Actually an error. Do something about it? */
- return SACMP_INTERSECTION;
-}
-
-static enum sarray_comparison
-ip6_cmp(void *arg1, void *arg2)
-{
- struct ipv6_prefix *p1 = &((struct resource6 *) arg1)->prefix;
- struct ipv6_prefix *p2 = &((struct resource6 *) arg2)->prefix;
- struct in6_addr *a1 = &p1->addr;
- struct in6_addr *a2 = &p2->addr;
- uint32_t q1;
- uint32_t q2;
- unsigned int q;
-
- if (memcmp(a1, a2, sizeof(*a1)) == 0 && p1->len == p2->len)
- return SACMP_EQUAL;
- if (prefix6_contains(p1, p2))
- return SACMP_CHILD;
- if (prefix6_contains(p2, p1))
- return SACMP_PARENT;
-
- for (q = 0; q < 4; q++) {
- q1 = ntohl(p1->addr.s6_addr32[q]);
- q2 = ntohl(p2->addr.s6_addr32[q]);
- if (q1 < q2)
- return SACMP_RIGHT;
- if (q2 < q1)
- return SACMP_LEFT;
- }
-
- /* TODO Actually an error. Do something about it? */
- return SACMP_INTERSECTION;
-}
-
-static enum sarray_comparison
-asn_cmp(void *arg1, void *arg2)
-{
- struct resource_asn *asn1 = arg1;
- struct resource_asn *asn2 = arg2;
-
- if (asn1->min == asn2->min && asn1->max == asn2->max)
- return SACMP_EQUAL;
- if (asn1->min <= asn2->min && asn2->max <= asn1->max)
- return SACMP_CHILD;
- if (asn2->min <= asn1->min && asn1->max <= asn2->max)
- return SACMP_PARENT;
- if (asn1->max < asn2->min)
- return SACMP_RIGHT;
- if (asn2->max < asn1->min)
- return SACMP_LEFT;
-
- return SACMP_INTERSECTION;
-}
-
-SARRAY_API(r4array, resource4, ip4_cmp)
-SARRAY_API(r6array, resource6, ip6_cmp)
-SARRAY_API(asnarray, resource_asn, asn_cmp)
-
struct resources *
resources_create(void)
{
resources_destroy(struct resources *resources)
{
if (resources->ip4s != NULL)
- r4array_put(resources->ip4s);
+ res4_put(resources->ip4s);
if (resources->ip6s != NULL)
- r6array_put(resources->ip6s);
+ res6_put(resources->ip6s);
if (resources->asns != NULL)
- asnarray_put(resources->asns);
+ rasn_put(resources->asns);
free(resources);
}
}
static void
-pr_debug_prefix(int family, void *addr, int length)
+pr_debug_prefix(int family, void *addr, unsigned int length)
{
#ifdef DEBUG
char buffer[INET6_ADDRSTRLEN];
#endif
}
+static void
+pr_debug_range(int family, void *min, void *max)
+{
+#ifdef DEBUG
+ char buffer_min[INET6_ADDRSTRLEN];
+ char buffer_max[INET6_ADDRSTRLEN];
+ char const *string_min;
+ char const *string_max;
+
+ string_min = inet_ntop(family, min, buffer_min, sizeof(buffer_min));
+ if (string_min == NULL)
+ goto fail;
+
+ string_max = inet_ntop(family, max, buffer_max, sizeof(buffer_max));
+ if (string_max == NULL)
+ goto fail;
+
+ pr_debug("Range: %s-%s", string_min, string_max);
+ return;
+
+fail:
+ pr_debug("Range: (Cannot convert to string. Errcode %d)", errno);
+#endif
+}
+
static int
inherit_aors(struct resources *resources, int family, struct resources *parent)
{
switch (family) {
case AF_INET:
if (resources->ip4s != NULL) {
- pr_err("Oh noes4"); /* TODO */
+ pr_err("Certificate inherits IPv4 resources while also defining others of its own.");
return -EINVAL;
}
if (parent->ip4s == NULL) {
return -EINVAL;
}
resources->ip4s = parent->ip4s;
- r4array_get(resources->ip4s);
+ res4_get(resources->ip4s);
return 0;
case AF_INET6:
if (resources->ip6s != NULL) {
- pr_err("Oh noes6"); /* TODO */
+ pr_err("Certificate inherits IPv6 resources while also defining others of its own.");
return -EINVAL;
}
if (parent->ip6s == NULL) {
return -EINVAL;
}
resources->ip6s = parent->ip6s;
- r6array_get(resources->ip6s);
+ res6_get(resources->ip6s);
return 0;
}
- pr_err("Programming error: Unknown IP family: %d", family);
+ pr_err("Programming error: Unknown address family '%d'", family);
return -EINVAL;
}
static int
-decode_prefix4(BIT_STRING_t *str, struct ipv4_prefix *result)
+add_prefix4(struct resources *resources, IPAddress2_t *addr,
+ struct resources *parent)
{
- /* TODO validate bits unused and stuff */
- if (str->size > 4) {
- pr_err("IPv4 address has too many octets. (%u)", str->size);
+ struct ipv4_prefix prefix;
+ int error;
+
+ if ((parent != NULL) && (resources->ip4s == parent->ip4s)) {
+ pr_err("Certificate defines IPv4 prefixes while also inheriting his parent's.");
return -EINVAL;
}
- memset(&result->addr, 0, sizeof(result->addr));
- memcpy(&result->addr, str->buf, str->size);
- result->len = 8 * str->size - str->bits_unused;
+ error = prefix4_decode(addr, &prefix);
+ if (error)
+ return error;
+
+ if (parent && !res4_contains_prefix(parent->ip4s, &prefix)) {
+ pr_err("Parent certificate doesn't own child's IPv4 resource.");
+ return -EINVAL;
+ }
+
+ if (resources->ip4s == NULL) {
+ resources->ip4s = res4_create();
+ if (resources->ip4s == NULL) {
+ pr_err("Out of memory.");
+ return -ENOMEM;
+ }
+ }
+
+ error = res4_add_prefix(resources->ip4s, &prefix);
+ if (error) {
+ pr_err("Error adding IPv4 prefix to certificate resources: %s",
+ sarray_err2str(error));
+ return error;
+ }
+
+ pr_debug_prefix(AF_INET, &prefix.addr, prefix.len);
return 0;
}
static int
-decode_prefix6(BIT_STRING_t *str, struct ipv6_prefix *result)
+add_prefix6(struct resources *resources, IPAddress2_t *addr,
+ struct resources *parent)
{
- if (str->size > 16) {
- pr_err("IPv6 address has too many octets. (%u)", str->size);
+ struct ipv6_prefix prefix;
+ int error;
+
+ if ((parent != NULL) && (resources->ip6s == parent->ip6s)) {
+ pr_err("Certificate defines IPv6 prefixes while also inheriting his parent's.");
+ return -EINVAL;
+ }
+
+ error = prefix6_decode(addr, &prefix);
+ if (error)
+ return error;
+
+ if (parent && !res6_contains_prefix(parent->ip6s, &prefix)) {
+ pr_err("Parent certificate doesn't own child's IPv6 resource.");
return -EINVAL;
}
- memset(&result->addr, 0, sizeof(result->addr));
- memcpy(&result->addr, str->buf, str->size);
- result->len = 8 * str->size - str->bits_unused;
+ if (resources->ip6s == NULL) {
+ resources->ip6s = res6_create();
+ if (resources->ip6s == NULL) {
+ pr_err("Out of memory.");
+ return -ENOMEM;
+ }
+ }
+
+ error = res6_add_prefix(resources->ip6s, &prefix);
+ if (error) {
+ pr_err("Error adding IPv6 prefix to certificate resources: %s",
+ sarray_err2str(error));
+ return error;
+ }
+
+ pr_debug_prefix(AF_INET6, &prefix.addr, prefix.len);
return 0;
}
static int
-add_prefix4(struct resources *resources, IPAddress2_t *addr,
+add_prefix(struct resources *resources, int family, IPAddress2_t *addr,
struct resources *parent)
{
- struct resource4 r4;
+ switch (family) {
+ case AF_INET:
+ return add_prefix4(resources, addr, parent);
+ case AF_INET6:
+ return add_prefix6(resources, addr, parent);
+ }
+
+ pr_err("Programming error: Unknown address family '%d'", family);
+ return -EINVAL;
+}
+
+static int
+add_range4(struct resources *resources, IPAddressRange_t *input,
+ struct resources *parent)
+{
+ struct ipv4_range range;
int error;
- error = decode_prefix4(addr, &r4.prefix);
+ if ((parent != NULL) && (resources->ip4s == parent->ip4s)) {
+ pr_err("Certificate defines IPv4 ranges while also inheriting his parent's.");
+ return -EINVAL;
+ }
+
+ error = range4_decode(input, &range);
if (error)
return error;
- if (parent && !r4array_contains(parent->ip4s, &r4)) {
+ if (parent && !res4_contains_range(parent->ip4s, &range)) {
pr_err("Parent certificate doesn't own child's IPv4 resource.");
return -EINVAL;
}
if (resources->ip4s == NULL) {
- resources->ip4s = r4array_create();
+ resources->ip4s = res4_create();
if (resources->ip4s == NULL) {
pr_err("Out of memory.");
return -ENOMEM;
}
}
- error = r4array_add(resources->ip4s, &r4);
- if (error)
- return error; /* TODO error message */
+ error = res4_add_range(resources->ip4s, &range);
+ if (error) {
+ pr_err("Error adding IPv4 range to certificate resources: %s",
+ sarray_err2str(error));
+ return error;
+ }
- pr_debug_prefix(AF_INET, &r4.prefix.addr, r4.prefix.len);
+ pr_debug_range(AF_INET, &range.min, &range.max);
return 0;
}
static int
-add_prefix6(struct resources *resources, IPAddress2_t *addr,
+add_range6(struct resources *resources, IPAddressRange_t *input,
struct resources *parent)
{
- struct resource6 r6;
+ struct ipv6_range range;
int error;
- error = decode_prefix6(addr, &r6.prefix);
+ if ((parent != NULL) && (resources->ip6s == parent->ip6s)) {
+ pr_err("Certificate defines IPv6 ranges while also inheriting his parent's.");
+ return -EINVAL;
+ }
+
+ error = range6_decode(input, &range);
if (error)
return error;
- if (parent && !r6array_contains(parent->ip6s, &r6)) {
+ if (parent && !res6_contains_range(parent->ip6s, &range)) {
pr_err("Parent certificate doesn't own child's IPv6 resource.");
return -EINVAL;
}
if (resources->ip6s == NULL) {
- resources->ip6s = r6array_create();
+ resources->ip6s = res6_create();
if (resources->ip6s == NULL) {
pr_err("Out of memory.");
return -ENOMEM;
}
}
- error = r6array_add(resources->ip6s, &r6);
- if (error)
- return error; /* TODO error message */
+ error = res6_add_range(resources->ip6s, &range);
+ if (error) {
+ pr_err("Error adding IPv6 range to certificate resources: %s",
+ sarray_err2str(error));
+ return error;
+ }
- pr_debug_prefix(AF_INET6, &r6.prefix.addr, r6.prefix.len);
+ pr_debug_range(AF_INET6, &range.min, &range.max);
return 0;
}
static int
-add_prefix(struct resources *resources, int family, IPAddress2_t *addr,
+add_range(struct resources *resources, int family, IPAddressRange_t *range,
struct resources *parent)
{
switch (family) {
case AF_INET:
- return add_prefix4(resources, addr, parent);
+ return add_range4(resources, range, parent);
case AF_INET6:
- return add_prefix6(resources, addr, parent);
+ return add_range6(resources, range, parent);
}
- pr_err("Unknown address family: %d", family);
- return 0;
+ pr_err("Programming error: Unknown address family '%d'", family);
+ return -EINVAL;
}
static int
int i;
int error = 0;
- /*
- * TODO The addressPrefix and addressRange elements MUST be sorted
- * using the binary representation of (...)
- * TODO Any pair of IPAddressOrRange choices in
- * an extension MUST NOT overlap each other.
- */
-
for (i = 0; i < aors->list.count; i++) {
aor = aors->list.array[i];
switch (aor->present) {
return error;
break;
case IPAddressOrRange_PR_addressRange:
- /*
- * We're definitely not supposed to support this.
- *
- * rfc3779#section-2.2.3.7 says "This specification
- * requires that any range of addresses that can be
- * encoded as a prefix MUST be encoded using an
- * IPAddress element (...), and any range that cannot be
- * encoded as a prefix MUST be encoded using an
- * IPAddressRange (...).
- *
- * rfc6482#section-3.3 says "Note that the syntax here
- * is more restrictive than that used in the IP address
- * delegation extension defined in RFC 3779. That
- * extension can represent arbitrary address ranges,
- * whereas ROAs need to represent only prefixes."
- */
- pr_err("IPAddressOrRange is a range. This is unsupported.");
- return -EINVAL;
+ error = add_range(resources, family,
+ &aor->choice.addressRange, parent);
+ if (error)
+ return error;
+ break;
case IPAddressOrRange_PR_NOTHING:
/* rfc3779#section-2.2.3.7 */
pr_err("Unknown IPAddressOrRange type: %d",
inherit_asiors(struct resources *resources, struct resources *parent)
{
if (resources->asns != NULL) {
- pr_err("Oh noesa"); /* TODO */
+ pr_err("Certificate inherits ASN resources while also defining others of its own.");
return -EINVAL;
}
if (parent->asns == NULL) {
return -EINVAL;
}
resources->asns = parent->asns;
- asnarray_get(resources->asns);
+ rasn_get(resources->asns);
return 0;
}
add_asn(struct resources *resources, ASId_t min, ASId_t max,
struct resources *parent)
{
- struct resource_asn ra;
int error;
+ if (parent && !rasn_contains(parent->asns, min, max)) {
+ pr_err("Parent certificate doesn't own child's ASN resource.");
+ return -EINVAL;
+ }
+
if (resources->asns == NULL) {
- resources->asns = asnarray_create();
+ resources->asns = rasn_create();
if (resources->asns == NULL) {
pr_err("Out of memory.");
return -ENOMEM;
}
}
- ra.min = min;
- ra.max = max;
- error = asnarray_add(resources->asns, &ra);
- if (error)
- return error; /* TODO error msg */
+ error = rasn_add(resources->asns, min, max);
+ if (error){
+ pr_err("Error adding ASN range to certificate resources: %s",
+ sarray_err2str(error));
+ return error;
+ }
if (min == max)
pr_debug("ASN: %ld", min);
add_asior(struct resources *resources, struct ASIdOrRange *obj,
struct resources *parent)
{
+ if ((parent != NULL) && (resources->asns == parent->asns)) {
+ pr_err("Certificate defines ASN resources while also inheriting his parent's.");
+ return -EINVAL;
+ }
+
switch (obj->present) {
case ASIdOrRange_PR_NOTHING:
break;
case ASIdentifierChoice_PR_inherit:
return inherit_asiors(resources, parent);
case ASIdentifierChoice_PR_asIdsOrRanges:
- /*
- * TODO
- * Any pair of items in the asIdsOrRanges SEQUENCE MUST NOT
- * overlap. Any contiguous series of AS identifiers MUST be
- * combined into a single range whenever possible. The AS
- * identifiers in the asIdsOrRanges element MUST be sorted by
- * increasing numeric value.
- */
iors = &ids->asnum->choice.asIdsOrRanges;
for (i = 0; i < iors->list.count; i++) {
error = add_asior(resources, iors->list.array[i],
return -EINVAL;
}
+bool
+resources_contains_asn(struct resources *res, ASId_t asn)
+{
+ return rasn_contains(res->asns, asn, asn);
+}
+
+bool
+resources_contains_ipv4(struct resources *res, struct ipv4_prefix *prefix)
+{
+ return res4_contains_prefix(res->ip4s, prefix);
+}
+
+bool
+resources_contains_ipv6(struct resources *res, struct ipv6_prefix *prefix)
+{
+ return res6_contains_prefix(res->ip6s, prefix);
+}
+
int
resources_join(struct resources *r1, struct resources *r2)
{
int error;
if (r1->ip4s != NULL) {
- error = r4array_join(r1->ip4s, r2->ip4s);
+ error = res4_join(r1->ip4s, r2->ip4s);
if (error)
return error;
}
if (r1->ip6s != NULL) {
- error = r6array_join(r1->ip6s, r2->ip6s);
+ error = res6_join(r1->ip6s, r2->ip6s);
if (error)
return error;
}
if (r1->asns != NULL) {
- error = asnarray_join(r1->asns, r2->asns);
+ error = rasn_join(r1->asns, r2->asns);
if (error)
return error;
}
#ifndef SRC_RESOURCE_H_
#define SRC_RESOURCE_H_
+#include <stdbool.h>
#include <libcmscodec/ASIdentifiers.h>
-#include <libcmscodec/ASIdOrRange.h>
#include <libcmscodec/IPAddressFamily.h>
-#include <openssl/safestack.h>
-#include <sys/queue.h>
+#include "address.h"
struct resources;
-struct restack;
struct resources *resources_create(void);
void resources_destroy(struct resources *);
int resources_add_asn(struct resources *, struct ASIdentifiers *,
struct resources *);
+bool resources_contains_asn(struct resources *, ASId_t);
+bool resources_contains_ipv4(struct resources *, struct ipv4_prefix *);
+bool resources_contains_ipv6(struct resources *, struct ipv6_prefix *);
+
int resources_join(struct resources *, struct resources *);
+struct restack;
+
struct restack *restack_create(void);
void restack_destroy(struct restack *);
--- /dev/null
+#include "asn.h"
+
+#include "sorted_array.h"
+
+struct asn_node {
+ ASId_t min;
+ ASId_t max;
+};
+
+static enum sarray_comparison
+asn_cmp(void *arg1, void *arg2)
+{
+ ASId_t n1min = ((struct asn_node *) arg1)->min;
+ ASId_t n2min = ((struct asn_node *) arg2)->min;
+ ASId_t n1max = ((struct asn_node *) arg1)->max;
+ ASId_t n2max = ((struct asn_node *) arg2)->max;
+
+ if (n1min == n2min && n1max == n2max)
+ return SACMP_EQUAL;
+ if (n1min <= n2min && n2max <= n1max)
+ return SACMP_CHILD;
+ if (n2min <= n1min && n1max <= n2max)
+ return SACMP_PARENT;
+ if (n1max == n2min - 1)
+ return SACMP_ADJACENT_RIGHT;
+ if (n1max < n2min)
+ return SACMP_RIGHT;
+ if (n2max == n1min - 1)
+ return SACMP_ADJACENT_LEFT;
+ if (n2max < n1min)
+ return SACMP_LEFT;
+
+ return SACMP_INTERSECTION;
+}
+
+struct resources_asn *
+rasn_create(void)
+{
+ return (struct resources_asn *)
+ sarray_create(sizeof(struct asn_node), asn_cmp);
+}
+
+void
+rasn_get(struct resources_asn *asns)
+{
+ sarray_get((struct sorted_array *) asns);
+}
+
+void
+rasn_put(struct resources_asn *asns)
+{
+ sarray_put((struct sorted_array *) asns);
+}
+
+int
+rasn_add(struct resources_asn *asns, ASId_t min, ASId_t max)
+{
+ struct asn_node n = { min, max };
+ return sarray_add((struct sorted_array *) asns, &n);
+}
+
+bool
+rasn_contains(struct resources_asn *asns, ASId_t min, ASId_t max)
+{
+ struct asn_node n = { min, max };
+ return sarray_contains((struct sorted_array *) asns, &n);
+}
+
+int
+rasn_join(struct resources_asn *r1, struct resources_asn *r2)
+{
+ return sarray_join((struct sorted_array *) r1,
+ (struct sorted_array *) r2);
+}
--- /dev/null
+#ifndef SRC_RESOURCE_ASN_H_
+#define SRC_RESOURCE_ASN_H_
+
+#include <stdbool.h>
+#include <libcmscodec/ASId.h>
+
+struct resources_asn;
+
+struct resources_asn *rasn_create(void);
+void rasn_get(struct resources_asn *);
+void rasn_put(struct resources_asn *);
+
+int rasn_add(struct resources_asn *, ASId_t, ASId_t);
+bool rasn_contains(struct resources_asn *, ASId_t, ASId_t);
+int rasn_join(struct resources_asn *, struct resources_asn *);
+
+#endif /* SRC_RESOURCE_ASN_H_ */
--- /dev/null
+#include "ip4.h"
+
+#include "sorted_array.h"
+
+struct r4_node {
+ uint32_t min; /* This is an IPv4 address in host byte order */
+ uint32_t max; /* This is an IPv4 address in host byte order */
+};
+
+static enum sarray_comparison
+r4_cmp(void *arg1, void *arg2)
+{
+ uint32_t n1min = ((struct r4_node *) arg1)->min;
+ uint32_t n2min = ((struct r4_node *) arg2)->min;
+ uint32_t n1max = ((struct r4_node *) arg1)->max;
+ uint32_t n2max = ((struct r4_node *) arg2)->max;
+
+ if (n1min == n2min && n1max == n2max)
+ return SACMP_EQUAL;
+ if (n1min <= n2min && n2max <= n1max)
+ return SACMP_CHILD;
+ if (n2min <= n1min && n1max <= n2max)
+ return SACMP_PARENT;
+ if (n1max < n2min)
+ return SACMP_RIGHT;
+ if (n2max < n1min)
+ return SACMP_LEFT;
+ return SACMP_INTERSECTION;
+}
+
+static void
+pton(struct ipv4_prefix *p, struct r4_node *n)
+{
+ n->min = ntohl(p->addr.s_addr);
+ n->max = n->min | (0xFFFFFFFFu >> p->len);
+}
+
+static void
+rton(struct ipv4_range *r, struct r4_node *n)
+{
+ n->min = ntohl(r->min.s_addr);
+ n->max = ntohl(r->max.s_addr);
+}
+
+struct resources_ipv4 *
+res4_create(void)
+{
+ return (struct resources_ipv4 *)
+ sarray_create(sizeof(struct r4_node), r4_cmp);
+}
+
+void
+res4_get(struct resources_ipv4 *ips)
+{
+ sarray_get((struct sorted_array *) ips);
+}
+
+void
+res4_put(struct resources_ipv4 *ips)
+{
+ sarray_put((struct sorted_array *) ips);
+}
+
+int
+res4_add_prefix(struct resources_ipv4 *ips, struct ipv4_prefix *prefix)
+{
+ struct r4_node n;
+ pton(prefix, &n);
+ return sarray_add((struct sorted_array *) ips, &n);
+}
+
+int
+res4_add_range(struct resources_ipv4 *ips, struct ipv4_range *range)
+{
+ struct r4_node n;
+ rton(range, &n);
+ return sarray_add((struct sorted_array *) ips, &n);
+}
+
+bool
+res4_contains_prefix(struct resources_ipv4 *ips, struct ipv4_prefix *prefix)
+{
+ struct r4_node n;
+
+ if (ips == NULL)
+ return false;
+
+ pton(prefix, &n);
+ return sarray_contains((struct sorted_array *) ips, &n);
+}
+
+bool
+res4_contains_range(struct resources_ipv4 *ips, struct ipv4_range *range)
+{
+ struct r4_node n;
+ rton(range, &n);
+ return sarray_contains((struct sorted_array *) ips, &n);
+}
+
+int
+res4_join(struct resources_ipv4 *r1, struct resources_ipv4 *r2)
+{
+ return sarray_join((struct sorted_array *) r1,
+ (struct sorted_array *) r2);
+}
--- /dev/null
+#ifndef SRC_RESOURCE_IP4_H_
+#define SRC_RESOURCE_IP4_H_
+
+#include <stdbool.h>
+#include "address.h"
+
+struct resources_ipv4;
+
+struct resources_ipv4 *res4_create(void);
+void res4_get(struct resources_ipv4 *);
+void res4_put(struct resources_ipv4 *);
+
+int res4_add_prefix(struct resources_ipv4 *, struct ipv4_prefix *);
+int res4_add_range(struct resources_ipv4 *, struct ipv4_range *);
+bool res4_contains_prefix(struct resources_ipv4 *, struct ipv4_prefix *);
+bool res4_contains_range(struct resources_ipv4 *, struct ipv4_range *);
+int res4_join(struct resources_ipv4 *, struct resources_ipv4 *);
+
+#endif /* SRC_RESOURCE_IP4_H_ */
--- /dev/null
+#include "ip6.h"
+
+#include <string.h>
+#include "sorted_array.h"
+
+static int
+addr_cmp(struct in6_addr const *a, struct in6_addr const *b)
+{
+ /* The addresses are stored in big endian. */
+ return memcmp(a, b, sizeof(uint32_t[4]));
+}
+
+/* a == b? */
+static bool
+addr_equals(struct in6_addr const *a, struct in6_addr const *b)
+{
+ return addr_cmp(a, b) == 0;
+}
+
+/* a <= b? */
+static bool
+addr_le(struct in6_addr const *a, struct in6_addr const *b)
+{
+ return addr_cmp(a, b) <= 0;
+}
+
+/* a < b? */
+static bool
+addr_lt(struct in6_addr const *a, struct in6_addr const *b)
+{
+ return addr_cmp(a, b) < 0;
+}
+
+static enum sarray_comparison
+r6_cmp(void *arg1, void *arg2)
+{
+ struct in6_addr const *a1min = &((struct ipv6_range *) arg1)->min;
+ struct in6_addr const *a2min = &((struct ipv6_range *) arg2)->min;
+ struct in6_addr const *a1max = &((struct ipv6_range *) arg1)->max;
+ struct in6_addr const *a2max = &((struct ipv6_range *) arg2)->max;
+
+ if (addr_equals(a1min, a2min) && addr_equals(a1max, a2max))
+ return SACMP_EQUAL;
+ if (addr_le(a1min, a2min) && addr_le(a2max, a1max))
+ return SACMP_CHILD;
+ if (addr_le(a2min, a1min) && addr_le(a1max, a2max))
+ return SACMP_PARENT;
+ if (addr_lt(a1max, a2min))
+ return SACMP_RIGHT;
+ if (addr_lt(a2max, a1min))
+ return SACMP_LEFT;
+ return SACMP_INTERSECTION;
+}
+
+static void
+ptor(struct ipv6_prefix const *p, struct ipv6_range *r)
+{
+ r->min = p->addr;
+ r->max = p->addr;
+ ipv6_suffix_mask(p->len, &r->max);
+}
+
+struct resources_ipv6 *
+res6_create(void)
+{
+ return (struct resources_ipv6 *)
+ sarray_create(sizeof(struct ipv6_range), r6_cmp);
+}
+
+void
+res6_get(struct resources_ipv6 *ips)
+{
+ sarray_get((struct sorted_array *) ips);
+}
+
+void
+res6_put(struct resources_ipv6 *ips)
+{
+ sarray_put((struct sorted_array *) ips);
+}
+
+int
+res6_add_prefix(struct resources_ipv6 *ips, struct ipv6_prefix *prefix)
+{
+ struct ipv6_range r;
+ ptor(prefix, &r);
+ return sarray_add((struct sorted_array *) ips, &r);
+}
+
+int
+res6_add_range(struct resources_ipv6 *ips, struct ipv6_range *range)
+{
+ return sarray_add((struct sorted_array *) ips, range);
+}
+
+bool
+res6_contains_prefix(struct resources_ipv6 *ips, struct ipv6_prefix *prefix)
+{
+ struct ipv6_range r;
+ ptor(prefix, &r);
+ return sarray_contains((struct sorted_array *) ips, &r);
+}
+
+bool
+res6_contains_range(struct resources_ipv6 *ips, struct ipv6_range *range)
+{
+ return sarray_contains((struct sorted_array *) ips, range);
+}
+
+int
+res6_join(struct resources_ipv6 *r1, struct resources_ipv6 *r2)
+{
+ return sarray_join((struct sorted_array *) r1,
+ (struct sorted_array *) r2);
+}
--- /dev/null
+#ifndef SRC_RESOURCE_IP6_H_
+#define SRC_RESOURCE_IP6_H_
+
+#include <stdbool.h>
+#include "address.h"
+
+struct resources_ipv6;
+
+struct resources_ipv6 *res6_create(void);
+void res6_get(struct resources_ipv6 *);
+void res6_put(struct resources_ipv6 *);
+
+int res6_add_prefix(struct resources_ipv6 *ps, struct ipv6_prefix *);
+int res6_add_range(struct resources_ipv6 *, struct ipv6_range *);
+bool res6_contains_prefix(struct resources_ipv6 *, struct ipv6_prefix *);
+bool res6_contains_range(struct resources_ipv6 *, struct ipv6_range *);
+int res6_join(struct resources_ipv6 *, struct resources_ipv6 *);
+
+#endif /* SRC_RESOURCE_IP6_H_ */
case SACMP_EQUAL:
return -EEQUAL;
case SACMP_CHILD:
- return -ECHILD;
+ return -ECHILD2;
case SACMP_PARENT:
return -EPARENT;
case SACMP_LEFT:
return -ELEFT;
case SACMP_RIGHT:
return 0;
+ case SACMP_ADJACENT_LEFT:
+ return -EADJLEFT;
+ case SACMP_ADJACENT_RIGHT:
+ return -EADJRIGHT;
case SACMP_INTERSECTION:
return -EINTERSECTION;
}
cmp = sarray->cmp(get_nth_element(sarray, mid), elem);
switch (cmp) {
case SACMP_LEFT:
+ case SACMP_ADJACENT_LEFT:
right = mid - 1;
continue;
case SACMP_RIGHT:
+ case SACMP_ADJACENT_RIGHT:
left = mid + 1;
continue;
case SACMP_EQUAL:
return false;
}
+
+char const *sarray_err2str(int error)
+{
+ switch (abs(error)) {
+ case EEQUAL:
+ return "Resource equals an already existing resource";
+ case ECHILD2:
+ return "Resource is a subset of an already existing resource";
+ case EPARENT:
+ return "Resource is a superset of an already existing resource";
+ case ELEFT:
+ return "Resource sequence is not properly sorted";
+ case EADJLEFT:
+ case EADJRIGHT:
+ return "Resource is adjacent to an existing resource (they are supposed to be aggregated)";
+ case EINTERSECTION:
+ return "Resource intersects with an already existing resource";
+ }
+
+ return strerror(error);
+}
SACMP_PARENT,
SACMP_LEFT,
SACMP_RIGHT,
+ SACMP_ADJACENT_LEFT,
+ SACMP_ADJACENT_RIGHT,
SACMP_INTERSECTION,
};
#define ECHILD2 7895
#define EPARENT 7896
#define ELEFT 7897
-#define EINTERSECTION 7898
+#define EADJLEFT 7898
+#define EADJRIGHT 7899
+#define EINTERSECTION 7900
int sarray_add(struct sorted_array *, void *);
int sarray_join(struct sorted_array *, struct sorted_array *);
-
bool sarray_contains(struct sorted_array *, void *);
-
-#define SARRAY_API(name, type, cmp) \
-static struct sorted_array * \
-name##_create(void) \
-{ \
- return sarray_create(sizeof(struct type), cmp); \
-} \
-static void \
-name##_get(struct sorted_array *sarray) \
-{ \
- sarray_get(sarray); \
-} \
-static void \
-name##_put(struct sorted_array *sarray) \
-{ \
- sarray_put(sarray); \
-} \
-static int \
-name##_add(struct sorted_array *sarray, struct type *element) \
-{ \
- return sarray_add(sarray, element); \
-} \
-static int \
-name##_join(struct sorted_array *sarray, struct sorted_array *addend) \
-{ \
- return sarray_join(sarray, addend); \
-} \
-static bool \
-name##_contains(struct sorted_array *sarray, struct type *element) \
-{ \
- return sarray_contains(sarray, element); \
-}
-
+char const *sarray_err2str(int);
#endif /* SRC_SORTED_ARRAY_H_ */
#include "state.h"
#include <errno.h>
-#include <openssl/err.h>
-#include <openssl/x509v3.h>
-#include <sys/queue.h>
-#include "common.h"
#include "log.h"
#include "object/certificate.h"
#include <stdio.h>
static bool
-p4test(uint32_t a1, int l1, uint32_t a2, int l2)
+p4test(uint32_t a1, unsigned int l1, uint32_t a2, unsigned int l2)
{
struct ipv4_prefix a, b;
static void
p6init(struct ipv6_prefix *p, uint32_t q1, uint32_t q2, uint32_t q3,
- uint32_t q4, int len)
+ uint32_t q4, unsigned int len)
{
p->addr.s6_addr32[0] = htonl(q1);
p->addr.s6_addr32[1] = htonl(q2);