]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Implement about 80% of RFC 6482 (ROAs)
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Wed, 26 Sep 2018 18:49:45 +0000 (13:49 -0500)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Wed, 26 Sep 2018 18:49:45 +0000 (13:49 -0500)
17 files changed:
src/Makefile.am
src/asn1/content_info.c [new file with mode: 0644]
src/asn1/content_info.h [moved from src/content_info.h with 100% similarity]
src/asn1/decode.c [new file with mode: 0644]
src/asn1/decode.h [new file with mode: 0644]
src/asn1/oid.c [new file with mode: 0644]
src/asn1/oid.h [new file with mode: 0644]
src/asn1/roa.c [new file with mode: 0644]
src/asn1/roa.h [new file with mode: 0644]
src/asn1/signed_data.c [moved from src/signed_data.c with 61% similarity]
src/asn1/signed_data.h [moved from src/signed_data.h with 50% similarity]
src/common.h
src/content_info.c [deleted file]
src/main.c
src/oid.c [deleted file]
src/oid.h [deleted file]
test/tal_test.c

index 8e0f5e77cb189e69a0afbf0598ccb41556200a2a..54878e0f1f33375b4345b0864ffe9ae6d929db0e 100644 (file)
@@ -1,11 +1,14 @@
 bin_PROGRAMS = rpki_validator
 
 rpki_validator_SOURCES  = main.c
+
 rpki_validator_SOURCES += common.h
-rpki_validator_SOURCES += content_info.h content_info.c
 rpki_validator_SOURCES += file.h file.c
-rpki_validator_SOURCES += oid.h oid.c
-rpki_validator_SOURCES += signed_data.h signed_data.c
+rpki_validator_SOURCES += asn1/content_info.h asn1/content_info.c
+rpki_validator_SOURCES += asn1/decode.h asn1/decode.c
+rpki_validator_SOURCES += asn1/oid.h asn1/oid.c
+rpki_validator_SOURCES += asn1/roa.h asn1/roa.c
+rpki_validator_SOURCES += asn1/signed_data.h asn1/signed_data.c
 
 rpki_validator_CFLAGS = -pedantic -Wall -std=gnu11 -O0 -g ${OPENSSL_CFLAGS}
 rpki_validator_LDADD = ${OPENSSL_LIBS}
diff --git a/src/asn1/content_info.c b/src/asn1/content_info.c
new file mode 100644 (file)
index 0000000..fb79850
--- /dev/null
@@ -0,0 +1,70 @@
+#include "content_info.h"
+
+#include <err.h>
+#include <errno.h>
+#include <libcmscodec/ContentType.h>
+#include "file.h"
+#include "oid.h"
+#include "asn1/decode.h"
+
+static int
+validate(struct ContentInfo *info)
+{
+       struct oid_arcs arcs;
+       int error;
+
+       /* rfc6488#section-2 */
+       /* rfc6488#section-3.1.a */
+       error = oid2arcs(&info->contentType, &arcs);
+       if (error)
+               return error;
+
+       if (!ARCS_EQUAL_OIDS(&arcs, SIGNED_DATA_OID)) {
+               fprintf(stderr, "Incorrect content-type.");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+decode(struct file_contents *fc, struct ContentInfo **result)
+{
+       struct ContentInfo *cinfo;
+       int error;
+
+       error = asn1_decode_fc(fc, &asn_DEF_ContentInfo, (void **) &cinfo);
+       if (error)
+               return error;
+
+       error = validate(cinfo);
+       if (error) {
+               content_info_free(cinfo);
+               return error;
+       }
+
+       *result = cinfo;
+       return 0;
+}
+
+int
+content_info_load(const char *file_name, struct ContentInfo **result)
+{
+       struct file_contents fc;
+       int error;
+
+       error = file_load(file_name, &fc);
+       if (error)
+               return error;
+
+       error = decode(&fc, result);
+
+       file_free(&fc);
+       return error;
+}
+
+void
+content_info_free(struct ContentInfo *info)
+{
+       ASN_STRUCT_FREE(asn_DEF_ContentInfo, info);
+}
similarity index 100%
rename from src/content_info.h
rename to src/asn1/content_info.h
diff --git a/src/asn1/decode.c b/src/asn1/decode.c
new file mode 100644 (file)
index 0000000..d0f9e4c
--- /dev/null
@@ -0,0 +1,70 @@
+#include "decode.h"
+
+#include <err.h>
+#include <errno.h>
+#include "common.h"
+
+static int
+validate(asn_TYPE_descriptor_t *descriptor, void *result)
+{
+       char error_msg[256];
+       size_t error_msg_size;
+       int error;
+
+       /* The lib's inbuilt validations. (Probably not much.) */
+       error_msg_size = sizeof(error_msg);
+       error = asn_check_constraints(descriptor, result, error_msg,
+           &error_msg_size);
+       if (error == -1) {
+               warnx("Error validating ASN.1 object: %s", error_msg);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int
+asn1_decode(const void *buffer, size_t buffer_size,
+    asn_TYPE_descriptor_t *descriptor, void **result)
+{
+       asn_dec_rval_t rval;
+       int error;
+
+       *result = NULL;
+
+       rval = ber_decode(0, descriptor, result, buffer, buffer_size);
+       if (rval.code != RC_OK) {
+               warnx("Error decoding ASN.1 object: %d", rval.code);
+               /* Must free partial object according to API contracts. */
+               ASN_STRUCT_FREE(*descriptor, *result);
+               return -EINVAL;
+       }
+
+       error = validate(descriptor, *result);
+       if (error) {
+               ASN_STRUCT_FREE(*descriptor, *result);
+               return error;
+       }
+
+       return 0;
+}
+
+int
+asn1_decode_any(ANY_t *any, asn_TYPE_descriptor_t *descriptor, void **result)
+{
+       return asn1_decode(any->buf, any->size, descriptor, result);
+}
+
+int
+asn1_decode_octet_string(OCTET_STRING_t *string,
+    asn_TYPE_descriptor_t *descriptor, void **result)
+{
+       return asn1_decode(string->buf, string->size, descriptor, result);
+}
+
+int
+asn1_decode_fc(struct file_contents *fc, asn_TYPE_descriptor_t *descriptor,
+    void **result)
+{
+       return asn1_decode(fc->buffer, fc->buffer_size, descriptor, result);
+}
diff --git a/src/asn1/decode.h b/src/asn1/decode.h
new file mode 100644 (file)
index 0000000..8c9c8d9
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef SRC_ASN1_DECODE_H_
+#define SRC_ASN1_DECODE_H_
+
+#include <libcmscodec/ANY.h>
+#include <libcmscodec/constr_TYPE.h>
+#include "file.h"
+
+/* TODO use this more. */
+int asn1_decode(const void *, size_t, asn_TYPE_descriptor_t *, void **);
+int asn1_decode_any(ANY_t *, asn_TYPE_descriptor_t *, void **);
+int asn1_decode_octet_string(OCTET_STRING_t *, asn_TYPE_descriptor_t *, void **);
+int asn1_decode_fc(struct file_contents *, asn_TYPE_descriptor_t *, void **);
+
+#endif /* SRC_ASN1_DECODE_H_ */
diff --git a/src/asn1/oid.c b/src/asn1/oid.c
new file mode 100644 (file)
index 0000000..3a2fb3c
--- /dev/null
@@ -0,0 +1,101 @@
+#include "oid.h"
+
+#include <errno.h>
+#include "common.h"
+#include "asn1/decode.h"
+
+#define MAX_ARCS 9
+
+void
+free_arcs(struct oid_arcs *arcs)
+{
+       free(arcs->arcs);
+}
+
+/*
+ * Wrapper for OBJECT_IDENTIFIER_get_arcs().
+ *
+ * Callers must free @result.
+ */
+int
+oid2arcs(OBJECT_IDENTIFIER_t *oid, struct oid_arcs *result)
+{
+       ssize_t count, count2;
+
+       result->arcs = malloc(MAX_ARCS * sizeof(asn_oid_arc_t));
+       if (result->arcs == NULL)
+               return -ENOMEM;
+
+       count = OBJECT_IDENTIFIER_get_arcs(oid, result->arcs, MAX_ARCS);
+       if (count < 0) {
+               free(result->arcs);
+               return count;
+       }
+
+       result->count = count;
+
+       /* If necessary, reallocate arcs array and try again. */
+       if (count > MAX_ARCS) {
+               result->arcs = realloc(result->arcs, count * sizeof(asn_oid_arc_t));
+               if (!result->arcs)
+                       return -ENOMEM;
+               count2 = OBJECT_IDENTIFIER_get_arcs(oid, result->arcs, count);
+               if (count != count2) {
+                       free(result->arcs);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+/* Callers must free @result. */
+int
+any2arcs(ANY_t *any, struct oid_arcs *result)
+{
+       OBJECT_IDENTIFIER_t *oid;
+       int error;
+
+       error = asn1_decode_any(any, &asn_DEF_OBJECT_IDENTIFIER,
+           (void **) &oid);
+       if (error)
+               return error;
+
+       error = oid2arcs(oid, result);
+       ASN_STRUCT_FREE(asn_DEF_OBJECT_IDENTIFIER, oid);
+       return error;
+}
+
+static bool __arcs_equal(asn_oid_arc_t const *a, size_t a_count,
+    asn_oid_arc_t const *b, size_t b_count)
+{
+       long int i;
+
+       if (a_count != b_count)
+               return false;
+
+       /* Most OIDs start with the same numbers, so iterate backwards. */
+       for (i = a_count - 1; i >= 0; i--) {
+               if (a[i] != b[i])
+                       return false;
+       }
+
+       return true;
+}
+
+bool arcs_equal(struct oid_arcs *a, struct oid_arcs *b)
+{
+       return __arcs_equal(a->arcs, a->count, b->arcs, b->count);
+}
+
+bool arcs_equal_oids(struct oid_arcs *arcs, asn_oid_arc_t const *oids,
+    size_t oids_len)
+{
+       return __arcs_equal(arcs->arcs, arcs->count, oids, oids_len);
+}
+
+void
+oid_print(OBJECT_IDENTIFIER_t *oid)
+{
+       asn_fprint(stdout, &asn_DEF_OBJECT_IDENTIFIER, oid);
+}
diff --git a/src/asn1/oid.h b/src/asn1/oid.h
new file mode 100644 (file)
index 0000000..c14c5ad
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef SRC_OID_H_
+#define SRC_OID_H_
+
+#include <stdbool.h>
+#include <libcmscodec/AlgorithmIdentifier.h>
+#include "common.h"
+
+/* These objects are expected to live on the stack. */
+struct oid_arcs {
+       asn_oid_arc_t *arcs;
+       size_t count;
+};
+
+void free_arcs(struct oid_arcs *);
+
+typedef asn_oid_arc_t OID[];
+
+/* Please update MAX_ARCS if you add an OID that has more arcs. */
+static const OID SIGNED_DATA_OID = { 1, 2, 840, 113549, 1, 7, 2 };
+static const OID CONTENT_TYPE_ATTR_OID = { 1, 2, 840, 113549, 1, 9, 3 };
+static const OID MESSAGE_DIGEST_ATTR_OID = { 1, 2, 840, 113549, 1, 9, 4 };
+static const OID SIGNING_TIME_ATTR_OID = { 1, 2, 840, 113549, 1, 9, 5 };
+static const OID BINARY_SIGNING_TIME_ATTR_OID = { 1, 2, 840, 113549, 1, 9, 16,
+    2, 46 };
+static const OID ROA_OID = { 1, 2, 840, 113549, 1, 9, 16, 1, 24 };
+static const OID OID_SHA224 = { 2, 16, 840, 1, 101, 3, 4, 2, 4 };
+static const OID OID_SHA256 = { 2, 16, 840, 1, 101, 3, 4, 2, 1 };
+static const OID OID_SHA384 = { 2, 16, 840, 1, 101, 3, 4, 2, 2 };
+static const OID OID_SHA512 = { 2, 16, 840, 1, 101, 3, 4, 2, 3 };
+
+int oid2arcs(OBJECT_IDENTIFIER_t *, struct oid_arcs *);
+int any2arcs(ANY_t *, struct oid_arcs *);
+
+bool arcs_equal(struct oid_arcs *, struct oid_arcs *);
+/* Use ARCS_EQUAL_OID() instead. */
+bool arcs_equal_oids(struct oid_arcs *, asn_oid_arc_t const *, size_t);
+
+/*
+ * a is supposed to be a OBJECT_IDENTIFIER_t (from libcmscodec.)
+ * b is supposed to be an OID.
+ */
+#define ARCS_EQUAL_OIDS(a, b) arcs_equal_oids(a, b, ARRAY_LEN(b))
+
+void oid_print(OBJECT_IDENTIFIER_t *oid);
+
+#endif /* SRC_OID_H_ */
diff --git a/src/asn1/roa.c b/src/asn1/roa.c
new file mode 100644 (file)
index 0000000..3417d45
--- /dev/null
@@ -0,0 +1,137 @@
+#include "roa.h"
+
+#include <err.h>
+#include <errno.h>
+#include <stdbool.h>
+#include "oid.h"
+#include "asn1/decode.h"
+#include "asn1/signed_data.h"
+
+static int
+validate_eContentType(struct SignedData *sdata)
+{
+       struct oid_arcs arcs;
+       bool equals;
+       int error;
+
+       error = oid2arcs(&sdata->encapContentInfo.eContentType, &arcs);
+       if (error)
+               return error;
+       equals = ARCS_EQUAL_OIDS(&arcs, ROA_OID);
+       free_arcs(&arcs);
+       if (!equals) {
+               warnx("SignedObject lacks the OID of a ROA.");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+validate_content_type(struct SignedData *sdata)
+{
+       OBJECT_IDENTIFIER_t *ctype;
+       struct oid_arcs arcs;
+       bool equals;
+       int error;
+
+       error = get_content_type_attr(sdata, &ctype);
+       if (error)
+               return error;
+       error = oid2arcs(ctype, &arcs);
+       ASN_STRUCT_FREE(asn_DEF_OBJECT_IDENTIFIER, ctype);
+       if (error)
+               return error;
+       equals = ARCS_EQUAL_OIDS(&arcs, ROA_OID);
+       free_arcs(&arcs);
+       if (!equals) {
+               warnx("SignedObject's content type doesn't match its encapContentInfo's eContent.");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int
+validate_roa(struct RouteOriginAttestation *roa)
+{
+       struct ROAIPAddressFamily *family;
+       struct ROAIPAddress *addr;
+       int b; /* block counter */
+       int a; /* address counter */
+
+       /* rfc6482#section-3.1 */
+       if (roa->version != 0) {
+               warnx("ROA's version (%ld) is not zero.", roa->version);
+               return -EINVAL;
+       }
+
+       /* rfc6482#section-3.2 */
+       if (roa->ipAddrBlocks.list.array == NULL)
+               return -EINVAL;
+
+       for (b = 0; b < roa->ipAddrBlocks.list.count; b++) {
+               family = roa->ipAddrBlocks.list.array[0];
+               if (family == NULL)
+                       return -EINVAL;
+
+               if (family->addressFamily.size != 2)
+                       return -EINVAL;
+               if (family->addressFamily.buf[0] != 0)
+                       return -EINVAL;
+               if (family->addressFamily.buf[1] != 1
+                   && family->addressFamily.buf[1] != 2)
+                       return -EINVAL;
+
+               if (family->addresses.list.array == NULL)
+                       return -EINVAL;
+               for (a = 0; a < family->addresses.list.count; a++) {
+                       addr = family->addresses.list.array[a];
+                       /*
+                        * TODO I don't understand where the prefix length is.
+                        * The bit string's size is measured in bytes...
+                        */
+                       printf("%ld\n", addr->maxLength
+                           ? (*addr->maxLength)
+                           : -1);
+               }
+       }
+
+       return 0;
+}
+
+int
+roa_decode(struct SignedData *sdata, struct RouteOriginAttestation **result)
+{
+       struct RouteOriginAttestation *roa;
+       int error;
+
+       /* rfc6482#section-2: eContentType */
+       error = validate_eContentType(sdata);
+       if (error)
+               return error;
+
+       /* rfc6482#section-2: content-type */
+       error = validate_content_type(sdata);
+       if (error)
+               return error;
+
+       error = asn1_decode_octet_string(sdata->encapContentInfo.eContent,
+           &asn_DEF_RouteOriginAttestation, (void **) &roa);
+       if (error)
+               return -EINVAL;
+
+       error = validate_roa(roa);
+       if (error) {
+               ASN_STRUCT_FREE(asn_DEF_RouteOriginAttestation, roa);
+               return error;
+       }
+
+       *result = roa;
+       return 0;
+}
+
+void roa_free(struct RouteOriginAttestation *roa)
+{
+       ASN_STRUCT_FREE(asn_DEF_RouteOriginAttestation, roa);
+}
diff --git a/src/asn1/roa.h b/src/asn1/roa.h
new file mode 100644 (file)
index 0000000..1404734
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef SRC_ROA_H_
+#define SRC_ROA_H_
+
+#include <libcmscodec/RouteOriginAttestation.h>
+#include <libcmscodec/SignedData.h>
+
+int roa_decode(struct SignedData *, struct RouteOriginAttestation **);
+void roa_free(struct RouteOriginAttestation *);
+
+#endif /* SRC_ROA_H_ */
similarity index 61%
rename from src/signed_data.c
rename to src/asn1/signed_data.c
index 187047f2d1d849cb024e8b0d8eeb854c55466a72..c07fca6c3d6ef069989dc337879030195e6bca8d 100644 (file)
@@ -4,18 +4,61 @@
 #include <errno.h>
 #include <libcmscodec/ContentType.h>
 #include "oid.h"
+#include "asn1/decode.h"
 
 /* TODO more consistent and informative error/warning messages.*/
 
+/*
+ * The correctness of this function depends on @MAX_ARCS being faithful to all
+ * the known OIDs declared *in the project*.
+ */
+static int
+is_digest_algorithm(AlgorithmIdentifier_t *aid, bool *result)
+{
+       struct oid_arcs arcs;
+       int error;
+
+       error = oid2arcs(&aid->algorithm, &arcs);
+       if (error)
+               return error;
+
+       *result = ARCS_EQUAL_OIDS(&arcs, OID_SHA224)
+              || ARCS_EQUAL_OIDS(&arcs, OID_SHA256)
+              || ARCS_EQUAL_OIDS(&arcs, OID_SHA384)
+              || ARCS_EQUAL_OIDS(&arcs, OID_SHA512);
+
+       free_arcs(&arcs);
+       return 0;
+}
+
 static int
 validate_content_type_attribute(CMSAttributeValue_t *value,
     EncapsulatedContentInfo_t *eci)
 {
-       /* TODO need to decode value. */
+       struct oid_arcs attrValue_arcs;
+       struct oid_arcs EncapContentInfo_arcs;
+       int error;
 
-       /* eci->eContentType*/
+       /* rfc6488#section-3.1.h */
 
-       return 0;
+       error = any2arcs(value, &attrValue_arcs);
+       if (error)
+               return error;
+
+       error = oid2arcs(&eci->eContentType, &EncapContentInfo_arcs);
+       if (error) {
+               free_arcs(&attrValue_arcs);
+               return error;
+       }
+
+       if (!arcs_equal(&attrValue_arcs, &EncapContentInfo_arcs)) {
+               warnx("The eContentType in the EncapsulatedContentInfo does not match the attrValues in the content-type attribute.");
+               error = -EINVAL;
+       }
+
+       free_arcs(&EncapContentInfo_arcs);
+       free_arcs(&attrValue_arcs);
+       return error;
 }
 
 static int
@@ -29,6 +72,7 @@ validate_signed_attrs(struct SignerInfo *sinfo, EncapsulatedContentInfo_t *eci)
 {
        struct CMSAttribute *attr;
        struct CMSAttribute__attrValues *attrs;
+       struct oid_arcs attrType;
        unsigned int i;
        bool content_type_found = false;
        bool message_digest_found = false;
@@ -59,47 +103,55 @@ validate_signed_attrs(struct SignerInfo *sinfo, EncapsulatedContentInfo_t *eci)
                        return -EINVAL;
                }
 
-               if (OID_EQUALS(&attr->attrType, CONTENT_TYPE_ATTR_OID)) {
+               error = oid2arcs(&attr->attrType, &attrType);
+               if (error)
+                       return error;
+
+               if (ARCS_EQUAL_OIDS(&attrType, CONTENT_TYPE_ATTR_OID)) {
                        if (content_type_found) {
                                warnx("Multiple ContentTypes found.");
-                               return -EINVAL;
+                               goto illegal_attrType;
                        }
                        error = validate_content_type_attribute(attr->attrValues.list.array[0], eci);
                        content_type_found = true;
 
-               } else if (OID_EQUALS(&attr->attrType, MESSAGE_DIGEST_ATTR_OID)) {
+               } else if (ARCS_EQUAL_OIDS(&attrType, MESSAGE_DIGEST_ATTR_OID)) {
                        if (message_digest_found) {
                                warnx("Multiple MessageDigests found.");
-                               return -EINVAL;
+                               goto illegal_attrType;
                        }
                        error = validate_message_digest_attribute(attr->attrValues.list.array[0]);
                        message_digest_found = true;
 
-               } else if (OID_EQUALS(&attr->attrType, SIGNING_TIME_ATTR_OID)) {
+               } else if (ARCS_EQUAL_OIDS(&attrType, SIGNING_TIME_ATTR_OID)) {
                        if (signing_time_found) {
                                warnx("Multiple SigningTimes found.");
-                               return -EINVAL;
+                               goto illegal_attrType;
                        }
                        error = 0; /* No validations needed for now. */
                        signing_time_found = true;
 
-               } else if (OID_EQUALS(&attr->attrType, BINARY_SIGNING_TIME_ATTR_OID)) {
+               } else if (ARCS_EQUAL_OIDS(&attrType, BINARY_SIGNING_TIME_ATTR_OID)) {
                        if (binary_signing_time_found) {
                                warnx("Multiple BinarySigningTimes found.");
-                               return -EINVAL;
+                               goto illegal_attrType;
                        }
                        error = 0; /* No validations needed for now. */
                        binary_signing_time_found = true;
 
                } else {
+                       /* rfc6488#section-3.1.g */
                        warnx("Illegal attrType OID in SignerInfo.");
-                       return -EINVAL;
+                       goto illegal_attrType;
                }
 
+               free_arcs(&attrType);
+
                if (error)
                        return error;
        }
 
+       /* rfc6488#section-3.1.f */
        if (!content_type_found) {
                warnx("SignerInfo lacks a ContentType attribute.");
                return -EINVAL;
@@ -110,24 +162,18 @@ validate_signed_attrs(struct SignerInfo *sinfo, EncapsulatedContentInfo_t *eci)
        }
 
        return 0;
+
+illegal_attrType:
+       free_arcs(&attrType);
+       return -EINVAL;
 }
 
 static int
 validate(struct SignedData *sdata)
 {
-       char error_msg[256];
-       size_t error_msg_size;
-       int error;
        struct SignerInfo *sinfo;
-
-       /* The lib's inbuilt validations. (Probably not much.) */
-       error_msg_size = sizeof(error_msg);
-       error = asn_check_constraints(&asn_DEF_SignedData, sdata, error_msg,
-           &error_msg_size);
-       if (error == -1) {
-               warnx("Error validating SignedData object: %s", error_msg);
-               return -EINVAL;
-       }
+       bool is_digest;
+       int error;
 
        /* rfc6488#section-2.1 */
        if (sdata->signerInfos.list.count != 1) {
@@ -137,6 +183,7 @@ validate(struct SignedData *sdata)
        }
 
        /* rfc6488#section-2.1.1 */
+       /* rfc6488#section-3.1.b */
        if (sdata->version != 3) {
                warnx("The SignedData version is only allowed to be 3. (Was %ld.)",
                    sdata->version);
@@ -144,6 +191,7 @@ validate(struct SignedData *sdata)
        }
 
        /* rfc6488#section-2.1.2 */
+       /* rfc6488#section-3.1.j 1/2 */
        if (sdata->digestAlgorithms.list.count != 1) {
                warnx("The SignedData's digestAlgorithms set is supposed to have only one element. (%d given.)",
                    sdata->digestAlgorithms.list.count);
@@ -156,15 +204,20 @@ validate(struct SignedData *sdata)
         * AlgorithmIdentifier instead. There's no API.
         * This seems to work fine.
         */
-       if (!is_digest_algorithm((DigestAlgorithmIdentifier_t *) sdata->digestAlgorithms.list.array[0])) {
+       error = is_digest_algorithm((AlgorithmIdentifier_t *) sdata->digestAlgorithms.list.array[0],
+           &is_digest);
+       if (error)
+               return error;
+       if (!is_digest) {
                warnx("The SignedData's digestAlgorithm OID is not listed in RFC 5754.");
                return -EINVAL;
        }
 
        /* section-2.1.3 */
-       /* TODO need a callback for specific signed object types */
+       /* 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. */
        if (sdata->certificates == NULL) {
                warnx("The SignedData does not contain certificates.");
                return -EINVAL;
@@ -177,12 +230,14 @@ validate(struct SignedData *sdata)
        }
 
        /* rfc6488#section-2.1.5 */
+       /* rfc6488#section-3.1.d */
        if (sdata->crls != NULL && sdata->crls->list.count > 0) {
                warnx("The SignedData contains at least one crls.");
                return -EINVAL;
        }
 
        /* rfc6488#section-2.1.6.1 */
+       /* rfc6488#section-3.1.e */
        sinfo = sdata->signerInfos.list.array[0];
        if (sinfo == NULL) {
                warnx("The SignerInfo object is NULL.");
@@ -200,7 +255,12 @@ validate(struct SignedData *sdata)
         */
 
        /* rfc6488#section-2.1.6.3 */
-       if (!is_digest_algorithm((AlgorithmIdentifier_t *) &sinfo->digestAlgorithm)) {
+       /* rfc6488#section-3.1.j 2/2 */
+       error = is_digest_algorithm((AlgorithmIdentifier_t *) &sinfo->digestAlgorithm,
+           &is_digest);
+       if (error)
+               return error;
+       if (!is_digest) {
                warnx("The SignerInfo digestAlgorithm OID is not listed in RFC 5754.");
                return -EINVAL;
        }
@@ -211,6 +271,7 @@ validate(struct SignedData *sdata)
                return error;
 
        /* rfc6488#section-2.1.6.5 */
+       /* rfc6488#section-3.1.k */
        /*
         * RFC 6485 was obsoleted by 7935. 7935 simply refers to 5652.
         *
@@ -231,12 +292,14 @@ validate(struct SignedData *sdata)
        /* Again, nothing to do for now. */
 
        /* rfc6488#section-2.1.6.7 */
+       /* rfc6488#section-3.1.i */
        if (sinfo->unsignedAttrs != NULL && sinfo->unsignedAttrs->list.count > 0) {
                warnx("SignerInfo has at least one unsignedAttr.");
                return -EINVAL;
        }
 
-       /* TODO section 3 */
+       /* rfc6488#section-3.2 TODO */
+       /* rfc6488#section-3.3 TODO */
 
        return 0;
 }
@@ -244,18 +307,13 @@ validate(struct SignedData *sdata)
 int
 signed_data_decode(ANY_t *coded, struct SignedData **result)
 {
-       struct SignedData *sdata = NULL;
-       asn_dec_rval_t rval;
+       struct SignedData *sdata;
        int error;
 
-       rval = ber_decode(0, &asn_DEF_SignedData, (void **) &sdata, coded->buf,
-           coded->size);
-       if (rval.code != RC_OK) {
-               warnx("Error decoding signed data object: %d", rval.code);
-               /* Must free partial signed data according to API contracts. */
-               signed_data_free(sdata);
-               return -EINVAL;
-       }
+       /* rfc6488#section-3.1.l TODO this is BER, not guaranteed to be DER. */
+       error = asn1_decode_any(coded, &asn_DEF_SignedData, (void **) &sdata);
+       if (error)
+               return error;
 
        error = validate(sdata);
        if (error) {
@@ -270,6 +328,49 @@ signed_data_decode(ANY_t *coded, struct SignedData **result)
 void
 signed_data_free(struct SignedData *sdata)
 {
-       asn_DEF_SignedData.op->free_struct(&asn_DEF_SignedData, sdata,
-           ASFM_FREE_EVERYTHING);
+       ASN_STRUCT_FREE(asn_DEF_SignedData, sdata);
+}
+
+/* Caller must free *@result. */
+int
+get_content_type_attr(struct SignedData *sdata, OBJECT_IDENTIFIER_t **result)
+{
+       struct SignedAttributes *signedAttrs;
+       struct CMSAttribute *attr;
+       int i;
+       int error;
+       struct oid_arcs arcs;
+       bool equal;
+
+       if (sdata == NULL)
+               return -EINVAL;
+       if (sdata->signerInfos.list.array == NULL)
+               return -EINVAL;
+       if (sdata->signerInfos.list.array[0] == NULL)
+               return -EINVAL;
+
+       signedAttrs = sdata->signerInfos.list.array[0]->signedAttrs;
+       if (signedAttrs->list.array == NULL)
+               return -EINVAL;
+
+       for (i = 0; i < signedAttrs->list.count; i++) {
+               attr = signedAttrs->list.array[i];
+               if (!attr)
+                       return -EINVAL;
+               error = oid2arcs(&attr->attrType, &arcs);
+               if (error)
+                       return -EINVAL;
+               equal = ARCS_EQUAL_OIDS(&arcs, CONTENT_TYPE_ATTR_OID);
+               free_arcs(&arcs);
+               if (equal) {
+                       if (attr->attrValues.list.array == NULL)
+                               return -EINVAL;
+                       if (attr->attrValues.list.array[0] == NULL)
+                               return -EINVAL;
+                       return asn1_decode_any(attr->attrValues.list.array[0],
+                           &asn_DEF_OBJECT_IDENTIFIER, (void **) result);
+               }
+       }
+
+       return -EINVAL;
 }
similarity index 50%
rename from src/signed_data.h
rename to src/asn1/signed_data.h
index 22923d4ddf3330deb1c78bfcd1f7f2503400cc82..f35d2c6b55cf4ee22afe41ab192b196252633084 100644 (file)
@@ -5,7 +5,9 @@
 
 #include <libcmscodec/SignedData.h>
 
-int signed_data_decode(ANY_t *coded, struct SignedData **result);
-void signed_data_free(struct SignedData *sdata);
+int signed_data_decode(ANY_t *, struct SignedData **);
+void signed_data_free(struct SignedData *);
+
+int get_content_type_attr(struct SignedData *, OBJECT_IDENTIFIER_t **);
 
 #endif /* SRC_SIGNED_DATA_H_ */
index c682919ac623411432e20b88d3d2fc4000d23654..1d7d9ccd0fb0a0d8f903a5a429f19992ad9f0cdd 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <string.h>
 
-#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
+#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
 
 #define warnxerror0(error, msg) \
        warnx(msg ": %s", strerror(error))
@@ -14,6 +14,7 @@
 #define warnxerrno(msg, ...) \
        warnxerror(errno, msg, ##__VA_ARGS__)
 
+#define pr_debug0(msg) printf("Debug: " msg "\n");
 #define pr_debug(msg, ...) printf("Debug: " msg "\n", ##__VA_ARGS__);
 
 #endif /* SRC_RTR_COMMON_H_ */
diff --git a/src/content_info.c b/src/content_info.c
deleted file mode 100644 (file)
index 6bb3295..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-#include "content_info.h"
-
-#include <err.h>
-#include <errno.h>
-#include <libcmscodec/ContentType.h>
-#include "common.h"
-#include "file.h"
-
-static void
-content_type_print(FILE *stream, asn_oid_arc_t *arcs, unsigned int arc_count)
-{
-       unsigned int i;
-
-       for (i = 0; i < arc_count; i++) {
-               fprintf(stream, "%u", arcs[i]);
-               if (i != arc_count - 1)
-                       fprintf(stream, ".");
-       }
-}
-
-int
-content_type_validate(ContentType_t *ctype)
-{
-       asn_oid_arc_t expected[] = { 1, 2, 840, 113549, 1, 7, 2 };
-       asn_oid_arc_t actual[ARRAY_SIZE(expected)];
-       const unsigned int SLOTS = ARRAY_SIZE(expected);
-       ssize_t result;
-       unsigned int i;
-
-       result = OBJECT_IDENTIFIER_get_arcs(ctype, actual, SLOTS);
-       if (result != SLOTS)
-               goto failure;
-
-       for (i = 0; i < SLOTS; i++) {
-               if (expected[i] != actual[i])
-                       goto failure;
-       }
-
-       return 0;
-
-failure:
-       fprintf(stderr, "Incorrect content-type; expected ");
-       content_type_print(stderr, expected, SLOTS);
-       fprintf(stderr, ", got ");
-       content_type_print(stderr, actual, (result < SLOTS) ? result : SLOTS);
-       fprintf(stderr, ".\n");
-       return -EINVAL;
-}
-
-static int
-validate(struct ContentInfo *info)
-{
-       char error_msg[256];
-       size_t error_msg_size;
-       int error;
-
-       error_msg_size = sizeof(error_msg);
-       error = asn_check_constraints(&asn_DEF_ContentInfo, info, error_msg,
-           &error_msg_size);
-       if (error == -1) {
-               warnx("Error validating content info object: %s", error_msg);
-               return -EINVAL;
-       }
-
-       return content_type_validate(&info->contentType);
-}
-
-static int
-decode(struct file_contents *fc, struct ContentInfo **result)
-{
-       struct ContentInfo *info = NULL;
-       asn_dec_rval_t rval;
-       int error;
-
-       rval = ber_decode(0, &asn_DEF_ContentInfo, (void **) &info, fc->buffer,
-           fc->buffer_size);
-       if (rval.code != RC_OK) {
-               warnx("Error decoding content info object: %d", rval.code);
-               /* Must free partial content info according to API contracts. */
-               content_info_free(info);
-               return -EINVAL;
-       }
-
-       error = validate(info);
-       if (error) {
-               content_info_free(info);
-               return error;
-       }
-
-       *result = info;
-       return 0;
-}
-
-int
-content_info_load(const char *file_name, struct ContentInfo **result)
-{
-       struct file_contents fc;
-       int error;
-
-       error = file_load(file_name, &fc);
-       if (error)
-               return error;
-
-       error = decode(&fc, result);
-
-       file_free(&fc);
-       return error;
-}
-
-void
-content_info_free(struct ContentInfo *info)
-{
-       asn_DEF_ContentInfo.op->free_struct(&asn_DEF_ContentInfo, info,
-           ASFM_FREE_EVERYTHING);
-}
index 19c521089954e5c34d75da12dbbe49fb9d219b3d..2cc956625d220217d79087ceadb4cbf0568e8c76 100644 (file)
@@ -1,17 +1,24 @@
-#include "content_info.h"
-#include "signed_data.h"
+#include <errno.h>
 
-const char *FILE_NAME = "/home/ydahhrk/rpki-cache/repository/"
-               "ca.rg.net/rpki/RGnet/IZt-j9P0XqJjzM2Xi4RZKS60gOc.roa";
+#include "common.h"
+#include "asn1/content_info.h"
+#include "asn1/roa.h"
+#include "asn1/signed_data.h"
 
 int
-main(void)
+main(int argc, char **argv)
 {
        struct ContentInfo *cinfo;
        struct SignedData *sdata;
+       struct RouteOriginAttestation *roa;
        int error;
 
-       error = content_info_load(FILE_NAME, &cinfo);
+       if (argc < 2) {
+               pr_debug0("argc < 2");
+               return -EINVAL;
+       }
+
+       error = content_info_load(argv[1], &cinfo);
        if (error)
                return error;
 
@@ -21,10 +28,16 @@ main(void)
                return error;
        }
 
-//     asn_fprint(stdout, &asn_DEF_ContentInfo, cinfo);
-//     printf("---------------------------------------------\n");
-//     asn_fprint(stdout, &asn_DEF_SignedData, sdata);
+       error = roa_decode(sdata, &roa);
+       if (error) {
+               signed_data_free(sdata);
+               content_info_free(cinfo);
+               return error;
+       }
+
+       asn_fprint(stdout, &asn_DEF_RouteOriginAttestation, roa);
 
+       roa_free(roa);
        signed_data_free(sdata);
        content_info_free(cinfo);
        return 0;
diff --git a/src/oid.c b/src/oid.c
deleted file mode 100644 (file)
index b0867bf..0000000
--- a/src/oid.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include "oid.h"
-
-#include <errno.h>
-#include "common.h"
-
-#define MAX_ARCS 9
-
-/* Please update MAX_ARCS if you add an OID that has more arcs. */
-static asn_oid_arc_t OID_SHA224[] = { 2, 16, 840, 1, 101, 3, 4, 2, 4 };
-static asn_oid_arc_t OID_SHA256[] = { 2, 16, 840, 1, 101, 3, 4, 2, 1 };
-static asn_oid_arc_t OID_SHA384[] = { 2, 16, 840, 1, 101, 3, 4, 2, 2 };
-static asn_oid_arc_t OID_SHA512[] = { 2, 16, 840, 1, 101, 3, 4, 2, 3 };
-
-/*
- * @a_oid is the original OID that's being tested.
- * @a_arcs must be a stack-allocated array of size @len.
- * @b_arcs is the expected array of arcs that needs to be compared to @a_oid.
- * Its length must be @len.
- */
-bool
-oid_equals(OBJECT_IDENTIFIER_t *const actual_oid,
-    asn_oid_arc_t const *expected_arcs,
-    size_t len)
-{
-       asn_oid_arc_t actual_arcs[MAX_ARCS];
-       ssize_t count;
-       long int i;
-
-       count = OBJECT_IDENTIFIER_get_arcs(actual_oid, actual_arcs, len);
-       if (count != len)
-               return false;
-
-       /* Most OIDs start with the same numbers, so iterate backwards. */
-       for (i = len - 1; i >= 0; i--) {
-               if (actual_arcs[i] != expected_arcs[i])
-                       return false;
-       }
-
-       return true;
-}
-
-void
-oid_print(OBJECT_IDENTIFIER_t *oid)
-{
-       asn_fprint(stdout, &asn_DEF_OBJECT_IDENTIFIER, oid);
-}
-
-bool
-is_digest_algorithm(AlgorithmIdentifier_t *algorithm)
-{
-       return OID_EQUALS(&algorithm->algorithm, OID_SHA224)
-           || OID_EQUALS(&algorithm->algorithm, OID_SHA256)
-           || OID_EQUALS(&algorithm->algorithm, OID_SHA384)
-           || OID_EQUALS(&algorithm->algorithm, OID_SHA512);
-}
diff --git a/src/oid.h b/src/oid.h
deleted file mode 100644 (file)
index f898504..0000000
--- a/src/oid.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef SRC_OID_H_
-#define SRC_OID_H_
-
-#include <stdbool.h>
-#include "libcmscodec/AlgorithmIdentifier.h"
-
-#include "common.h"
-
-typedef asn_oid_arc_t OID[];
-
-/* Please update MAX_ARCS if you add an OID that has more arcs. */
-static const OID CONTENT_TYPE_ATTR_OID = {
-    1, 2, 840, 113549, 1, 9, 3
-};
-static const OID MESSAGE_DIGEST_ATTR_OID = {
-    1, 2, 840, 113549, 1, 9, 4
-};
-static const OID SIGNING_TIME_ATTR_OID = {
-    1, 2, 840, 113549, 1, 9, 5
-};
-static const OID BINARY_SIGNING_TIME_ATTR_OID = {
-    1, 2, 840, 113549, 1, 9, 16, 2, 46
-};
-
-/* Use OID_EQUALS() instead. */
-bool oid_equals(OBJECT_IDENTIFIER_t *const actual_oid,
-    asn_oid_arc_t const *expected_arcs, size_t len);
-
-/*
- * a is supposed to be a OBJECT_IDENTIFIER_t (from libcmscodec.)
- * b is supposed to be an OID (from the typedef above.)
- */
-#define OID_EQUALS(a, b) oid_equals(a, b, ARRAY_SIZE(b))
-
-void oid_print(OBJECT_IDENTIFIER_t *oid);
-
-bool is_digest_algorithm(AlgorithmIdentifier_t *algorithm);
-
-#endif /* SRC_OID_H_ */
index b6015de7a9b09a816555da732924a318b3d50199..4bc0f35ac140f616d4861d72d00127b322007461 100644 (file)
@@ -51,8 +51,8 @@ START_TEST(tal_load_normal)
        uri = SLIST_NEXT(uri, next);
        ck_assert(uri == NULL);
 
-       ck_assert_uint_eq(ARRAY_SIZE(decoded), tal->spki_size);
-       for (i = 0; i < ARRAY_SIZE(decoded); i++)
+       ck_assert_uint_eq(ARRAY_LEN(decoded), tal->spki_size);
+       for (i = 0; i < ARRAY_LEN(decoded); i++)
                ck_assert_uint_eq(tal->spki[i], decoded[i]);
 
        tal_destroy(tal);