]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Adds:
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Sat, 8 Dec 2018 03:26:15 +0000 (21:26 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Sat, 8 Dec 2018 03:26:15 +0000 (21:26 -0600)
- IP ranges
- Bunch of ROA validation
- Bunch of certificate validation

I clearly don't understand how EE certificates validate AS numbers.
They never seem to have the AS extension.
Back to reading...

34 files changed:
src/Makefile.am
src/address.c
src/address.h
src/asn1/oid.h
src/asn1/signed_data.c
src/asn1/signed_data.h
src/common.c
src/debug.c
src/file.c
src/line_file.c
src/log.c
src/main.c
src/object/certificate.c
src/object/crl.c
src/object/crl.h
src/object/manifest.c
src/object/manifest.h
src/object/roa.c
src/object/roa.h
src/object/signed_object.c
src/object/signed_object.h
src/object/tal.c
src/resource.c
src/resource.h
src/resource/asn.c [new file with mode: 0644]
src/resource/asn.h [new file with mode: 0644]
src/resource/ip4.c [new file with mode: 0644]
src/resource/ip4.h [new file with mode: 0644]
src/resource/ip6.c [new file with mode: 0644]
src/resource/ip6.h [new file with mode: 0644]
src/sorted_array.c
src/sorted_array.h
src/state.c
test/address_test.c

index 0dd1f32ae3d3c8d2c6563f5f284fbdfe646754fd..f43b7314cdc835b980e2ca11326ca9f68e10da5e 100644 (file)
@@ -28,5 +28,9 @@ rpki_validator_SOURCES += object/roa.h object/roa.c
 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)
index 1c26cbd649bd043036e0b9ad9e530a9a5b44e016..e49874994a86a39339f4491f1b9973c76f6cbcf9 100644 (file)
@@ -1,6 +1,154 @@
 #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)
index abf44d7f238a53beb77dae4938d9e73375508548..32357bad596170fd07dd9d3b801e50dad42473c6 100644 (file)
@@ -3,17 +3,37 @@
 
 #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 *);
 
index 8dbc630bcae968e39f19750f814378af5cddedd2..ba73b1eedc8d43c6e67d0beabe3cd4a0786817e5 100644 (file)
@@ -2,7 +2,8 @@
 #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. */
index fdc3f9b4ff34c6553dbf404e4ff4a654bb6558f6..8ae8d683885a5c9094aa49aacac198b4cd5e49c1 100644 (file)
@@ -5,6 +5,7 @@
 #include "log.h"
 #include "oid.h"
 #include "asn1/decode.h"
+#include "object/certificate.h"
 
 /* TODO more consistent and informative error/warning messages.*/
 
@@ -15,7 +16,7 @@ static const OID oid_sha512 = OID_SHA512;
 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
@@ -40,6 +41,50 @@ is_digest_algorithm(AlgorithmIdentifier_t *aid, bool *result)
        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)
@@ -49,6 +94,7 @@ validate_content_type_attribute(CMSAttributeValue_t *value,
        int error;
 
        /* rfc6488#section-3.1.h */
+       /* TODO (performance) Can't we just do a memcmp? */
 
        error = any2arcs(value, &attrValue_arcs);
        if (error)
@@ -143,7 +189,7 @@ validate_signed_attrs(struct SignerInfo *sinfo, EncapsulatedContentInfo_t *eci)
                        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;
@@ -181,7 +227,8 @@ illegal_attrType:
 }
 
 static int
-validate(struct SignedData *sdata)
+validate(struct validation *state, struct SignedData *sdata,
+    struct resources *res)
 {
        struct SignerInfo *sinfo;
        bool is_digest;
@@ -216,7 +263,8 @@ validate(struct SignedData *sdata)
         * 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;
@@ -229,7 +277,7 @@ validate(struct SignedData *sdata)
        /* 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;
@@ -241,6 +289,11 @@ validate(struct SignedData *sdata)
                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) {
@@ -262,14 +315,15 @@ validate(struct SignedData *sdata)
        }
 
        /* 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) {
@@ -318,7 +372,8 @@ validate(struct SignedData *sdata)
 }
 
 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;
@@ -328,7 +383,7 @@ signed_data_decode(ANY_t *coded, struct SignedData **result)
        if (error)
                return error;
 
-       error = validate(sdata);
+       error = validate(state, sdata, res);
        if (error) {
                signed_data_free(sdata);
                return error;
index f35d2c6b55cf4ee22afe41ab192b196252633084..3d722cb0d996c0c1c6eed05abeb23d290415067b 100644 (file)
@@ -4,8 +4,11 @@
 /* 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 **);
index 48f857d31bab4cfde0d36edcb0992073a6d0b008..4aaf4b4511a52ba8099ef5e60a395e2284092613 100644 (file)
@@ -1,9 +1,6 @@
 #include "common.h"
 
-#include <err.h>
 #include <errno.h>
-#include <string.h>
-#include <openssl/err.h>
 #include "log.h"
 
 char const *repository;
index 1415e0ec9c49740bba0ea0c9727c40e66b3ddb83..536810545d6e110c605f0223b9ba95ef0449be99 100644 (file)
@@ -10,7 +10,8 @@
  * 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)
 {
index e896c37fb09c0f210f01a1dbffe4db6eb12cf791..c00944b531e3e7cb54e629e8585fcde1478bbdfd 100644 (file)
@@ -3,7 +3,6 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include "common.h"
 #include "log.h"
 
 /*
index ea2aee7a8c66b3dcb741950377f9b70c37896a94..f98cb88a0871f1ccae769d9fba97586b7666431d 100644 (file)
@@ -4,6 +4,7 @@
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include "log.h"
 
 struct line_file {
        FILE *file;
@@ -105,7 +106,7 @@ lfile_read(struct line_file *lfile, char **result)
                        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;
        }
@@ -119,7 +120,7 @@ lfile_read(struct line_file *lfile, char **result)
         */
        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;
index c491ee5135a721fc6b1b4fa737a9978619c6926c..23254c38c6e8b420aa4ea33b6ece5388057b5423 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -1,6 +1,5 @@
 #include "log.h"
 
-#include <string.h>
 #include <openssl/bio.h>
 #include <openssl/err.h>
 
index 7e8812b31bb01eed3274412de9348c66245b0b70..201f9139b0bfded5fb168b243cf48b3321802fdc 100644 (file)
@@ -1,13 +1,11 @@
 #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"
 
 /**
@@ -75,7 +73,7 @@ main(int argc, char **argv)
        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;
        }
 
index 6b8f0f3a34071dcd06081956060565e25fa9951a..9247af9d564553f0d6acc0bba4ffc363171bffb6 100644 (file)
@@ -1,9 +1,7 @@
 #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"
@@ -23,6 +21,150 @@ bool is_certificate(char const *file_name)
        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)
 {
@@ -35,19 +177,26 @@ 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;
 }
@@ -202,7 +351,13 @@ certificate_get_resources(struct validation *state, X509 *cert,
        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);
index 81d84de4ee678144c606eff050e9e1d1833043b8..cb9fd464be489b03d208d93bf97fa6fb44f12ac7 100644 (file)
@@ -1,13 +1,6 @@
 #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)
index ed80a37a7ad0c02e5ccec695c1110ef16829c9be..b288dd9e6ffe923abd6c7bdd958355012c71a5ff 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef SRC_OBJECT_CRL_H_
 #define SRC_OBJECT_CRL_H_
 
-#include <stdbool.h>
 #include <openssl/x509.h>
 #include "state.h"
 
index f614f4264b0b59475a2983d57e442e2bc280e662..d1d3b2d9f84dcc27230f74277eff8a9de50d3cb5 100644 (file)
@@ -1,11 +1,10 @@
 #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"
@@ -266,8 +265,11 @@ end:
 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;
 }
 
@@ -320,17 +322,25 @@ handle_manifest(struct validation *state, char const *file_path)
        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;
 }
index c49f28af1937ddabe3b7837cbc83aeda512e930e..573bcb6f30fd2eb16635af91f0db1a7031924d27 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef SRC_OBJECT_MANIFEST_H_
 #define SRC_OBJECT_MANIFEST_H_
 
-#include <stdbool.h>
 #include "state.h"
 
 int handle_manifest(struct validation *, char const *);
index f918d40146b8d3d43c2907f706260c47c25e4ff2..32b24e4bf447d5d6bca2ac2d80f48fb3fe3f20e1 100644 (file)
 #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)
@@ -111,28 +140,41 @@ __handle_roa(struct RouteOriginAttestation *roa)
        }
 
        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;
 }
index 40b5cd0f43ed8a96e81a7943065af4a3097aa202..2d86e657374b7fa1128961793475d8546b005dcf 100644 (file)
@@ -1,8 +1,8 @@
 #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_ */
index 90e930a615f1bc8dcdef074a7ca9c0657b5698d6..31af62813d244e009f20903e209951ec5ee802e0 100644 (file)
@@ -58,10 +58,12 @@ validate_content_type(struct SignedData *sdata,
 }
 
 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;
@@ -71,7 +73,7 @@ signed_object_decode(char const *file,
        if (error)
                goto end1;
 
-       error = signed_data_decode(&cinfo->content, &sdata);
+       error = signed_data_decode(state, &cinfo->content, &sdata, res);
        if (error)
                goto end2;
 
index 9311d1f62337cd3280fe5afdb0833b46bfdd8d04..a50095774cd0af07c18337d9e2c7f72dcd0def12 100644 (file)
@@ -2,8 +2,11 @@
 #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_ */
index a5e8c6d167e0532c166d60115317a0cf8577d76c..1aaa1b62a1b7cfe37da4856835e1dcc9aa50930e 100644 (file)
@@ -1,17 +1,13 @@
 #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;
@@ -54,7 +50,7 @@ read_uri(struct line_file *lfile, struct uri **result)
 
        uri = malloc(sizeof(struct uri));
        if (uri == NULL) {
-               warnx("Out of memory");
+               pr_err("Out of memory.");
                return -ENOMEM;
        }
 
@@ -81,7 +77,7 @@ read_uris(struct line_file *lfile, struct uri_list *uris)
 
        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;
        }
 
index cf1dec1cfc884bd0fb8c534c6f359684796f59b4..59a94f4f38e68c35646d4289122dca1c1f974bf2 100644 (file)
@@ -1,31 +1,21 @@
 #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.
@@ -39,87 +29,6 @@ struct resources {
  */
 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)
 {
@@ -142,11 +51,11 @@ 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);
 }
 
@@ -175,7 +84,7 @@ unknown:
 }
 
 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];
@@ -191,13 +100,38 @@ pr_debug_prefix(int family, void *addr, int length)
 #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) {
@@ -205,12 +139,12 @@ inherit_aors(struct resources *resources, int family, struct resources *parent)
                        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) {
@@ -218,120 +152,202 @@ inherit_aors(struct resources *resources, int family, struct resources *parent)
                        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
@@ -342,13 +358,6 @@ add_aors(struct resources *resources, int family,
        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) {
@@ -359,24 +368,11 @@ add_aors(struct resources *resources, int family,
                                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",
@@ -418,7 +414,7 @@ static int
 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) {
@@ -426,7 +422,7 @@ inherit_asiors(struct resources *resources, struct resources *parent)
                return -EINVAL;
        }
        resources->asns = parent->asns;
-       asnarray_get(resources->asns);
+       rasn_get(resources->asns);
        return 0;
 }
 
@@ -434,22 +430,27 @@ static int
 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);
@@ -462,6 +463,11 @@ static int
 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;
@@ -498,14 +504,6 @@ resources_add_asn(struct resources *resources, struct ASIdentifiers *ids,
        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],
@@ -523,23 +521,41 @@ resources_add_asn(struct resources *resources, struct ASIdentifiers *ids,
        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;
        }
index 5a9ae04b84f5fd0b06635f553e14c1b4df5217a6..bde82eaf972fe1a96a0042c0494c8f2d007ba9a0 100644 (file)
@@ -1,14 +1,12 @@
 #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 *);
@@ -18,8 +16,14 @@ int resources_add_ip(struct resources *, struct IPAddressFamily *,
 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 *);
 
diff --git a/src/resource/asn.c b/src/resource/asn.c
new file mode 100644 (file)
index 0000000..de51d4d
--- /dev/null
@@ -0,0 +1,74 @@
+#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);
+}
diff --git a/src/resource/asn.h b/src/resource/asn.h
new file mode 100644 (file)
index 0000000..5805d63
--- /dev/null
@@ -0,0 +1,17 @@
+#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_ */
diff --git a/src/resource/ip4.c b/src/resource/ip4.c
new file mode 100644 (file)
index 0000000..a81f500
--- /dev/null
@@ -0,0 +1,105 @@
+#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);
+}
diff --git a/src/resource/ip4.h b/src/resource/ip4.h
new file mode 100644 (file)
index 0000000..7d2fbf1
--- /dev/null
@@ -0,0 +1,19 @@
+#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_ */
diff --git a/src/resource/ip6.c b/src/resource/ip6.c
new file mode 100644 (file)
index 0000000..2dbfcf3
--- /dev/null
@@ -0,0 +1,115 @@
+#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);
+}
diff --git a/src/resource/ip6.h b/src/resource/ip6.h
new file mode 100644 (file)
index 0000000..96b39f4
--- /dev/null
@@ -0,0 +1,19 @@
+#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_ */
index 199dccc596ad6a1662e2877b17040333d212bf28..4d509821025c048be52d160bab285e822ff609d8 100644 (file)
@@ -84,13 +84,17 @@ compare(struct sorted_array *sarray, void *new)
        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;
        }
@@ -186,9 +190,11 @@ sarray_contains(struct sorted_array *sarray, void *elem)
                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:
@@ -207,3 +213,24 @@ sarray_contains(struct sorted_array *sarray, void *elem)
 
        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);
+}
index 41f633dcd1bb7d12c5aa77b404c5d58d37c09736..62d820d3c1b1b843e5b636f4dee2c26463e4ac97 100644 (file)
@@ -19,6 +19,8 @@ enum sarray_comparison {
        SACMP_PARENT,
        SACMP_LEFT,
        SACMP_RIGHT,
+       SACMP_ADJACENT_LEFT,
+       SACMP_ADJACENT_RIGHT,
        SACMP_INTERSECTION,
 };
 
@@ -32,45 +34,14 @@ void sarray_put(struct sorted_array *);
 #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_ */
index 02e7f0e04d3c0cfa388587727aacfc6bf1eb110e..52815fdc97d2b8a8f9d9846f2d742f793ee93f69 100644 (file)
@@ -1,10 +1,6 @@
 #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"
 
index 30e448d0415c6ad248b63504d3197a3600d9a734..459c6e9345f61cbd8facf86d57590a463666aaa0 100644 (file)
@@ -6,7 +6,7 @@
 #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;
 
@@ -54,7 +54,7 @@ END_TEST
 
 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);