From b26085ffac0cfe6cb869b4fbef83a6237a68fabf Mon Sep 17 00:00:00 2001 From: Alberto Leiva Popper Date: Wed, 26 Sep 2018 13:49:45 -0500 Subject: [PATCH] Implement about 80% of RFC 6482 (ROAs) --- src/Makefile.am | 9 +- src/asn1/content_info.c | 70 +++++++++++++ src/{ => asn1}/content_info.h | 0 src/asn1/decode.c | 70 +++++++++++++ src/asn1/decode.h | 14 +++ src/asn1/oid.c | 101 +++++++++++++++++++ src/asn1/oid.h | 46 +++++++++ src/asn1/roa.c | 137 +++++++++++++++++++++++++ src/asn1/roa.h | 10 ++ src/{ => asn1}/signed_data.c | 181 ++++++++++++++++++++++++++-------- src/{ => asn1}/signed_data.h | 6 +- src/common.h | 3 +- src/content_info.c | 115 --------------------- src/main.c | 31 ++++-- src/oid.c | 55 ----------- src/oid.h | 39 -------- test/tal_test.c | 4 +- 17 files changed, 625 insertions(+), 266 deletions(-) create mode 100644 src/asn1/content_info.c rename src/{ => asn1}/content_info.h (100%) create mode 100644 src/asn1/decode.c create mode 100644 src/asn1/decode.h create mode 100644 src/asn1/oid.c create mode 100644 src/asn1/oid.h create mode 100644 src/asn1/roa.c create mode 100644 src/asn1/roa.h rename src/{ => asn1}/signed_data.c (61%) rename src/{ => asn1}/signed_data.h (50%) delete mode 100644 src/content_info.c delete mode 100644 src/oid.c delete mode 100644 src/oid.h diff --git a/src/Makefile.am b/src/Makefile.am index 8e0f5e77..54878e0f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 index 00000000..fb79850d --- /dev/null +++ b/src/asn1/content_info.c @@ -0,0 +1,70 @@ +#include "content_info.h" + +#include +#include +#include +#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); +} diff --git a/src/content_info.h b/src/asn1/content_info.h 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 index 00000000..d0f9e4c9 --- /dev/null +++ b/src/asn1/decode.c @@ -0,0 +1,70 @@ +#include "decode.h" + +#include +#include +#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 index 00000000..8c9c8d96 --- /dev/null +++ b/src/asn1/decode.h @@ -0,0 +1,14 @@ +#ifndef SRC_ASN1_DECODE_H_ +#define SRC_ASN1_DECODE_H_ + +#include +#include +#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 index 00000000..3a2fb3cb --- /dev/null +++ b/src/asn1/oid.c @@ -0,0 +1,101 @@ +#include "oid.h" + +#include +#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 index 00000000..c14c5adb --- /dev/null +++ b/src/asn1/oid.h @@ -0,0 +1,46 @@ +#ifndef SRC_OID_H_ +#define SRC_OID_H_ + +#include +#include +#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 index 00000000..3417d456 --- /dev/null +++ b/src/asn1/roa.c @@ -0,0 +1,137 @@ +#include "roa.h" + +#include +#include +#include +#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 index 00000000..14047348 --- /dev/null +++ b/src/asn1/roa.h @@ -0,0 +1,10 @@ +#ifndef SRC_ROA_H_ +#define SRC_ROA_H_ + +#include +#include + +int roa_decode(struct SignedData *, struct RouteOriginAttestation **); +void roa_free(struct RouteOriginAttestation *); + +#endif /* SRC_ROA_H_ */ diff --git a/src/signed_data.c b/src/asn1/signed_data.c similarity index 61% rename from src/signed_data.c rename to src/asn1/signed_data.c index 187047f2..c07fca6c 100644 --- a/src/signed_data.c +++ b/src/asn1/signed_data.c @@ -4,18 +4,61 @@ #include #include #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; } diff --git a/src/signed_data.h b/src/asn1/signed_data.h similarity index 50% rename from src/signed_data.h rename to src/asn1/signed_data.h index 22923d4d..f35d2c6b 100644 --- a/src/signed_data.h +++ b/src/asn1/signed_data.h @@ -5,7 +5,9 @@ #include -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_ */ diff --git a/src/common.h b/src/common.h index c682919a..1d7d9ccd 100644 --- a/src/common.h +++ b/src/common.h @@ -3,7 +3,7 @@ #include -#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 index 6bb3295e..00000000 --- a/src/content_info.c +++ /dev/null @@ -1,115 +0,0 @@ -#include "content_info.h" - -#include -#include -#include -#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); -} diff --git a/src/main.c b/src/main.c index 19c52108..2cc95662 100644 --- a/src/main.c +++ b/src/main.c @@ -1,17 +1,24 @@ -#include "content_info.h" -#include "signed_data.h" +#include -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 index b0867bf4..00000000 --- a/src/oid.c +++ /dev/null @@ -1,55 +0,0 @@ -#include "oid.h" - -#include -#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 index f8985042..00000000 --- a/src/oid.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef SRC_OID_H_ -#define SRC_OID_H_ - -#include -#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_ */ diff --git a/test/tal_test.c b/test/tal_test.c index b6015de7..4bc0f35a 100644 --- a/test/tal_test.c +++ b/test/tal_test.c @@ -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); -- 2.47.3