From: Alberto Leiva Popper Date: Wed, 7 Nov 2018 16:14:20 +0000 (-0600) Subject: Implement address block parsing (rfc3779, section 2.1) X-Git-Tag: v0.0.2~123 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=648215d577e20ae0b09d63c02cc86a1772ad3678;p=thirdparty%2FFORT-validator.git Implement address block parsing (rfc3779, section 2.1) Also, move the signed code decoding to its own module to prevent duplicate code elsewhere --- diff --git a/src/Makefile.am b/src/Makefile.am index 78c13a2f..c3b4faf2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,21 +1,26 @@ +# Comment these out during releases. +CFLAGS_DEBUG = -DDEBUG +LDFLAGS_DEBUG = -rdynamic + bin_PROGRAMS = rpki_validator rpki_validator_SOURCES = main2.c -rpki_validator_SOURCES += certificate.h certificate.c rpki_validator_SOURCES += common.h common.c rpki_validator_SOURCES += debug.h debug.c rpki_validator_SOURCES += file.h file.c rpki_validator_SOURCES += line_file.h line_file.c -rpki_validator_SOURCES += manifest.h manifest.c -rpki_validator_SOURCES += tal.h tal.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/manifest.h asn1/manifest.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 -# Remove -rdynamic during the release. -rpki_validator_LDFLAGS = -rdynamic +rpki_validator_SOURCES += object/certificate.h object/certificate.c +rpki_validator_SOURCES += object/manifest.h object/manifest.c +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_CFLAGS = -pedantic -Wall -std=gnu11 -O0 -g $(CFLAGS_DEBUG) +rpki_validator_LDFLAGS = $(LDFLAGS_DEBUG) diff --git a/src/asn1/content_info.c b/src/asn1/content_info.c index fb79850d..a9de4350 100644 --- a/src/asn1/content_info.c +++ b/src/asn1/content_info.c @@ -10,6 +10,7 @@ static int validate(struct ContentInfo *info) { + static const OID oid_sdata = OID_SIGNED_DATA; struct oid_arcs arcs; int error; @@ -19,7 +20,7 @@ validate(struct ContentInfo *info) if (error) return error; - if (!ARCS_EQUAL_OIDS(&arcs, SIGNED_DATA_OID)) { + if (!ARCS_EQUAL_OIDS(&arcs, oid_sdata)) { fprintf(stderr, "Incorrect content-type."); return -EINVAL; } diff --git a/src/asn1/decode.c b/src/asn1/decode.c index d0f9e4c9..0e6c2a93 100644 --- a/src/asn1/decode.c +++ b/src/asn1/decode.c @@ -5,7 +5,7 @@ #include "common.h" static int -validate(asn_TYPE_descriptor_t *descriptor, void *result) +validate(asn_TYPE_descriptor_t const *descriptor, void *result) { char error_msg[256]; size_t error_msg_size; @@ -25,7 +25,7 @@ validate(asn_TYPE_descriptor_t *descriptor, void *result) int asn1_decode(const void *buffer, size_t buffer_size, - asn_TYPE_descriptor_t *descriptor, void **result) + asn_TYPE_descriptor_t const *descriptor, void **result) { asn_dec_rval_t rval; int error; @@ -34,6 +34,7 @@ asn1_decode(const void *buffer, size_t buffer_size, rval = ber_decode(0, descriptor, result, buffer, buffer_size); if (rval.code != RC_OK) { + /* TODO if rval.code == RC_WMORE (1), more work is needed */ warnx("Error decoding ASN.1 object: %d", rval.code); /* Must free partial object according to API contracts. */ ASN_STRUCT_FREE(*descriptor, *result); @@ -50,20 +51,24 @@ asn1_decode(const void *buffer, size_t buffer_size, } int -asn1_decode_any(ANY_t *any, asn_TYPE_descriptor_t *descriptor, void **result) +asn1_decode_any(ANY_t *any, + asn_TYPE_descriptor_t const *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) + asn_TYPE_descriptor_t const *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, +asn1_decode_fc(struct file_contents *fc, + asn_TYPE_descriptor_t const *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 index 8c9c8d96..e20f878d 100644 --- a/src/asn1/decode.h +++ b/src/asn1/decode.h @@ -5,10 +5,11 @@ #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 **); +int asn1_decode(const void *, size_t, asn_TYPE_descriptor_t const *, void **); +int asn1_decode_any(ANY_t *, asn_TYPE_descriptor_t const *, void **); +int asn1_decode_octet_string(OCTET_STRING_t *, asn_TYPE_descriptor_t const *, + void **); +int asn1_decode_fc(struct file_contents *, asn_TYPE_descriptor_t const *, + void **); #endif /* SRC_ASN1_DECODE_H_ */ diff --git a/src/asn1/manifest.h b/src/asn1/manifest.h deleted file mode 100644 index 48434cee..00000000 --- a/src/asn1/manifest.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef SRC_ASN1_MANIFEST_H_ -#define SRC_ASN1_MANIFEST_H_ - -#include -#include - -int manifest_decode(struct SignedData *sdata, struct Manifest **mf); -void manifest_free(struct Manifest *mf); - -#endif /* SRC_ASN1_MANIFEST_H_ */ diff --git a/src/asn1/oid.c b/src/asn1/oid.c index 3a2fb3cb..6089ba93 100644 --- a/src/asn1/oid.c +++ b/src/asn1/oid.c @@ -83,7 +83,7 @@ static bool __arcs_equal(asn_oid_arc_t const *a, size_t a_count, return true; } -bool arcs_equal(struct oid_arcs *a, struct oid_arcs *b) +bool arcs_equal(struct oid_arcs const *a, struct oid_arcs const *b) { return __arcs_equal(a->arcs, a->count, b->arcs, b->count); } @@ -93,9 +93,3 @@ bool arcs_equal_oids(struct oid_arcs *arcs, asn_oid_arc_t const *oids, { 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 index 187bc0b5..8dbc630b 100644 --- a/src/asn1/oid.h +++ b/src/asn1/oid.h @@ -11,6 +11,8 @@ struct oid_arcs { size_t count; }; +#define OID2ARCS(oid) { .arcs = oid, .count = ARRAY_LEN(oid) } + void free_arcs(struct oid_arcs *); typedef asn_oid_arc_t OID[]; @@ -21,25 +23,24 @@ typedef asn_oid_arc_t OID[]; * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -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 }; +#define OID_SIGNED_DATA { 1, 2, 840, 113549, 1, 7, 2 } +#define OID_CONTENT_TYPE_ATTR { 1, 2, 840, 113549, 1, 9, 3 } +#define OID_MESSAGE_DIGEST_ATTR { 1, 2, 840, 113549, 1, 9, 4 } +#define OID_SIGNING_TIME_ATTR { 1, 2, 840, 113549, 1, 9, 5 } +#define OID_BINARY_SIGNING_TIME_ATTR { 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 MANIFEST_OID = { 1, 2, 840, 113549, 1, 9, 16, 1, 26 }; +#define OID_ROA { 1, 2, 840, 113549, 1, 9, 16, 1, 24 } +#define OID_MANIFEST { 1, 2, 840, 113549, 1, 9, 16, 1, 26 } -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 }; +#define OID_SHA224 { 2, 16, 840, 1, 101, 3, 4, 2, 4 } +#define OID_SHA256 { 2, 16, 840, 1, 101, 3, 4, 2, 1 } +#define OID_SHA384 { 2, 16, 840, 1, 101, 3, 4, 2, 2 } +#define 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 *); +bool arcs_equal(struct oid_arcs const *, struct oid_arcs const *); /* Use ARCS_EQUAL_OID() instead. */ bool arcs_equal_oids(struct oid_arcs *, asn_oid_arc_t const *, size_t); @@ -49,6 +50,4 @@ bool arcs_equal_oids(struct oid_arcs *, asn_oid_arc_t const *, size_t); */ #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 deleted file mode 100644 index 3417d456..00000000 --- a/src/asn1/roa.c +++ /dev/null @@ -1,137 +0,0 @@ -#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 deleted file mode 100644 index 14047348..00000000 --- a/src/asn1/roa.h +++ /dev/null @@ -1,10 +0,0 @@ -#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/asn1/signed_data.c b/src/asn1/signed_data.c index c07fca6c..9d20ef90 100644 --- a/src/asn1/signed_data.c +++ b/src/asn1/signed_data.c @@ -8,6 +8,15 @@ /* TODO more consistent and informative error/warning messages.*/ +static const OID oid_sha224 = OID_SHA224; +static const OID oid_sha256 = OID_SHA256; +static const OID oid_sha384 = OID_SHA384; +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; + /* * The correctness of this function depends on @MAX_ARCS being faithful to all * the known OIDs declared *in the project*. @@ -22,10 +31,10 @@ is_digest_algorithm(AlgorithmIdentifier_t *aid, bool *result) 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); + *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; @@ -107,7 +116,7 @@ validate_signed_attrs(struct SignerInfo *sinfo, EncapsulatedContentInfo_t *eci) if (error) return error; - if (ARCS_EQUAL_OIDS(&attrType, CONTENT_TYPE_ATTR_OID)) { + if (ARCS_EQUAL_OIDS(&attrType, oid_cta)) { if (content_type_found) { warnx("Multiple ContentTypes found."); goto illegal_attrType; @@ -115,7 +124,7 @@ validate_signed_attrs(struct SignerInfo *sinfo, EncapsulatedContentInfo_t *eci) error = validate_content_type_attribute(attr->attrValues.list.array[0], eci); content_type_found = true; - } else if (ARCS_EQUAL_OIDS(&attrType, MESSAGE_DIGEST_ATTR_OID)) { + } else if (ARCS_EQUAL_OIDS(&attrType, oid_mda)) { if (message_digest_found) { warnx("Multiple MessageDigests found."); goto illegal_attrType; @@ -123,7 +132,7 @@ validate_signed_attrs(struct SignerInfo *sinfo, EncapsulatedContentInfo_t *eci) error = validate_message_digest_attribute(attr->attrValues.list.array[0]); message_digest_found = true; - } else if (ARCS_EQUAL_OIDS(&attrType, SIGNING_TIME_ATTR_OID)) { + } else if (ARCS_EQUAL_OIDS(&attrType, oid_sta)) { if (signing_time_found) { warnx("Multiple SigningTimes found."); goto illegal_attrType; @@ -131,7 +140,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, BINARY_SIGNING_TIME_ATTR_OID)) { + } else if (ARCS_EQUAL_OIDS(&attrType, oid_bst)) { if (binary_signing_time_found) { warnx("Multiple BinarySigningTimes found."); goto illegal_attrType; @@ -298,8 +307,9 @@ validate(struct SignedData *sdata) return -EINVAL; } - /* rfc6488#section-3.2 TODO */ - /* rfc6488#section-3.3 TODO */ + /* rfc6488#section-3.2 */ + /* rfc6488#section-3.3 */ + /* TODO */ return 0; } @@ -360,7 +370,7 @@ get_content_type_attr(struct SignedData *sdata, OBJECT_IDENTIFIER_t **result) error = oid2arcs(&attr->attrType, &arcs); if (error) return -EINVAL; - equal = ARCS_EQUAL_OIDS(&arcs, CONTENT_TYPE_ATTR_OID); + equal = ARCS_EQUAL_OIDS(&arcs, oid_cta); free_arcs(&arcs); if (equal) { if (attr->attrValues.list.array == NULL) diff --git a/src/certificate.h b/src/certificate.h deleted file mode 100644 index e5a88692..00000000 --- a/src/certificate.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef SRC_CERTIFICATE_H_ -#define SRC_CERTIFICATE_H_ - -#include - -bool is_certificate(char const *file_name); -int handle_certificate(char const *); - -#endif /* SRC_CERTIFICATE_H_ */ diff --git a/src/common.h b/src/common.h index d51bf6eb..d37cb306 100644 --- a/src/common.h +++ b/src/common.h @@ -26,6 +26,8 @@ extern int NID_rpkiNotify; #define warnxerrno(msg, ...) \ warnxerror(errno, msg, ##__VA_ARGS__) +#ifdef DEBUG + #define pr_debug(msg, ...) { \ printf("DBG: "); \ pr_indent(); \ @@ -54,6 +56,17 @@ extern int NID_rpkiNotify; pr_debug0(msg); \ } +#else /* #ifdef DEBUG */ + +#define pr_debug(msg, ...) +#define pr_debug_add(msg, ...) +#define pr_debug_rm(msg, ...) +#define pr_debug0(msg) +#define pr_debug0_add(msg) +#define pr_debug0_rm(msg) + +#endif /* #ifdef DEBUG */ + void pr_indent(void); void pr_add_indent(void); void pr_rm_indent(void); diff --git a/src/main.c b/src/main.c deleted file mode 100644 index a5a20697..00000000 --- a/src/main.c +++ /dev/null @@ -1,117 +0,0 @@ -#include - -#include "common.h" -#include "manifest.h" -#include "asn1/certificate.h" -#include "asn1/content_info.h" -#include "asn1/manifest.h" -#include "asn1/roa.h" -#include "asn1/signed_data.h" - -int -try_roa(char *file_name) -{ - struct ContentInfo *cinfo; - struct SignedData *sdata; - struct RouteOriginAttestation *roa; - int error; - - error = content_info_load(file_name, &cinfo); - if (error) - return error; - - error = signed_data_decode(&cinfo->content, &sdata); - if (error) { - content_info_free(cinfo); - return error; - } - - 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; -} - -int -try_manifest(char *file_name) -{ - struct ContentInfo *cinfo; - struct SignedData *sdata; - struct Manifest *manifest; - int error; - - error = content_info_load(file_name, &cinfo); - if (error) - return error; - - error = signed_data_decode(&cinfo->content, &sdata); - if (error) { - content_info_free(cinfo); - return error; - } - - error = manifest_decode(sdata, &manifest); - if (error) { - signed_data_free(sdata); - content_info_free(cinfo); - return error; - } - - asn_fprint(stdout, &asn_DEF_Manifest, manifest); - - manifest_free(manifest); - signed_data_free(sdata); - content_info_free(cinfo); - return 0; -} - -int -try_certificate(char *file_name) -{ - struct Certificate *cert; - int error; - - error = certificate_load(file_name, &cert); - if (error) - return error; - - asn_fprint(stdout, &asn_DEF_Certificate, cert); - - certificate_free(cert); - return 0; -} - -int -main(int argc, char **argv) -{ - int error; - - if (argc < 5) { - pr_debug0("argc < 5"); - return -EINVAL; - } - - error = try_roa(argv[1]); - if (error) - return error; - error = try_manifest(argv[2]); - if (error) - return error; - error = try_manifest(argv[3]); - if (error) - return error; - error = try_certificate(argv[4]); - if (error) - return error; - - return 0; -} diff --git a/src/main2.c b/src/main2.c index f06d65ce..c3e1a2c3 100644 --- a/src/main2.c +++ b/src/main2.c @@ -3,11 +3,11 @@ #include #include -#include "certificate.h" #include "common.h" #include "debug.h" -#include "manifest.h" -#include "tal.h" +#include "object/certificate.h" +#include "object/manifest.h" +#include "object/tal.h" /** * Registers the RPKI-specific OIDs in the SSL library. diff --git a/src/manifest.c b/src/manifest.c deleted file mode 100644 index 3571b43e..00000000 --- a/src/manifest.c +++ /dev/null @@ -1,127 +0,0 @@ -#include "manifest.h" - -#include -#include -#include -#include -#include - -#include "certificate.h" -#include "common.h" -#include "asn1/content_info.h" -#include "asn1/signed_data.h" -#include "asn1/manifest.h" - -bool -is_manifest(char const *file_name) -{ - return file_has_extension(file_name, "mft"); -} - -/** - * Given manifest path @mft and its referenced file @file, returns a path - * @file can be accessed with. - * - * ie. if @mft is "a/b/c.mft" and @file is "d/e/f.cer", returns "a/b/d/e/f.cer". - * - * The result needs to be freed in the end. - */ -static int -get_relative_file(char const *mft, char const *file, char **result) -{ - char *joined; - char *slash_pos; - int dir_len; - - slash_pos = strrchr(mft, '/'); - if (slash_pos == NULL) { - joined = malloc(strlen(file) + 1); - if (!joined) - return -ENOMEM; - strcpy(joined, file); - goto succeed; - } - - dir_len = (slash_pos + 1) - mft; - joined = malloc(dir_len + strlen(file) + 1); - if (!joined) - return -ENOMEM; - - strncpy(joined, mft, dir_len); - strcpy(joined + dir_len, file); - -succeed: - *result = joined; - return 0; -} - -static int -handle_file(char const *mft, IA5String_t *string) -{ - char *luri; - int error; - - /* TODO This is probably not correct. */ - pr_debug_add("File %s {", string->buf); - - error = get_relative_file(mft, (char const *) string->buf, &luri); - if (error) - goto end; - - if (is_certificate(luri)) - error = handle_certificate(luri); - else - pr_debug0("Unhandled file type."); - - free(luri); -end: - pr_debug0_rm("}"); - return error; -} - -static int -__handle_manifest(char const *mft, struct Manifest *manifest) -{ - int i; - int error; - - for (i = 0; i < manifest->fileList.list.count; i++) { - error = handle_file(mft, - &manifest->fileList.list.array[i]->file); - if (error) - return error; - } - - return 0; -} - -int -handle_manifest(char const *file_path) -{ - struct ContentInfo *cinfo; - struct SignedData *sdata; - struct Manifest *manifest; - int error; - - pr_debug_add("Manifest %s {", file_path); - - error = content_info_load(file_path, &cinfo); - if (error) - goto end1; - - error = signed_data_decode(&cinfo->content, &sdata); - if (error) - goto end2; - - error = manifest_decode(sdata, &manifest); - if (error) - goto end3; - - error = __handle_manifest(file_path, manifest); - - manifest_free(manifest); -end3: signed_data_free(sdata); -end2: content_info_free(cinfo); -end1: pr_debug0_rm("}"); - return error; -} diff --git a/src/manifest.h b/src/manifest.h deleted file mode 100644 index a26c879d..00000000 --- a/src/manifest.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef SRC_MANIFEST_H_ -#define SRC_MANIFEST_H_ - -#include - -bool is_manifest(char const *); -int handle_manifest(char const *); - -#endif /* SRC_MANIFEST_H_ */ diff --git a/src/certificate.c b/src/object/certificate.c similarity index 98% rename from src/certificate.c rename to src/object/certificate.c index 78cef2f5..a09ee6e1 100644 --- a/src/certificate.c +++ b/src/object/certificate.c @@ -99,7 +99,7 @@ handle_extensions(X509 *cert) } else if (nid == NID_rpkiNotify) { /* TODO Another fucking RFC... */ - pr_debug0("rpkiNotify"); + pr_debug0("Unimplemented thingy: rpkiNotify"); } else if (nid == NID_caRepository) { error = gn2uri(ad->location, &uri); diff --git a/src/object/certificate.h b/src/object/certificate.h new file mode 100644 index 00000000..9e89fc24 --- /dev/null +++ b/src/object/certificate.h @@ -0,0 +1,9 @@ +#ifndef SRC_OBJECT_CERTIFICATE_H_ +#define SRC_OBJECT_CERTIFICATE_H_ + +#include + +bool is_certificate(char const *); +int handle_certificate(char const *); + +#endif /* SRC_OBJECT_CERTIFICATE_H_ */ diff --git a/src/asn1/manifest.c b/src/object/manifest.c similarity index 57% rename from src/asn1/manifest.c rename to src/object/manifest.c index 88b5fb90..8bc79101 100644 --- a/src/asn1/manifest.c +++ b/src/object/manifest.c @@ -1,54 +1,18 @@ -#include "asn1/manifest.h" +#include "manifest.h" -#include #include -#include "asn1/decode.h" +#include + +#include "common.h" #include "asn1/oid.h" -#include "asn1/signed_data.h" +#include "object/certificate.h" +#include "object/roa.h" +#include "object/signed_object.h" -static int -validate_eContentType(struct SignedData *sdata) +bool +is_manifest(char const *file_name) { - struct oid_arcs arcs; - bool equals; - int error; - - error = oid2arcs(&sdata->encapContentInfo.eContentType, &arcs); - if (error) - return error; - equals = ARCS_EQUAL_OIDS(&arcs, MANIFEST_OID); - free_arcs(&arcs); - if (!equals) { - warnx("SignedObject lacks the OID of a Manifest."); - 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, MANIFEST_OID); - free_arcs(&arcs); - if (!equals) { - warnx("SignedObject's content type doesn't match its encapContentInfo's eContent."); - return -EINVAL; - } - - return 0; + return file_has_extension(file_name, "mft"); } static int @@ -61,6 +25,7 @@ validate_dates(GeneralizedTime_t *this, GeneralizedTime_t *next) static int is_hash_algorithm(OBJECT_IDENTIFIER_t *aid, bool *result) { + static const OID sha_oid = OID_SHA256; struct oid_arcs arcs; int error; @@ -68,13 +33,13 @@ is_hash_algorithm(OBJECT_IDENTIFIER_t *aid, bool *result) if (error) return error; - *result = ARCS_EQUAL_OIDS(&arcs, OID_SHA256); + *result = ARCS_EQUAL_OIDS(&arcs, sha_oid); free_arcs(&arcs); return 0; } -int +static int validate_manifest(struct Manifest *manifest) { int error; @@ -150,40 +115,102 @@ validate_manifest(struct Manifest *manifest) return 0; } -int -manifest_decode(struct SignedData *sdata, struct Manifest **result) +/** + * Given manifest path @mft and its referenced file @file, returns a path + * @file can be accessed with. + * + * ie. if @mft is "a/b/c.mft" and @file is "d/e/f.cer", returns "a/b/d/e/f.cer". + * + * The result needs to be freed in the end. + */ +static int +get_relative_file(char const *mft, char const *file, char **result) { - struct Manifest *manifest; + char *joined; + char *slash_pos; + int dir_len; + + slash_pos = strrchr(mft, '/'); + if (slash_pos == NULL) { + joined = malloc(strlen(file) + 1); + if (!joined) + return -ENOMEM; + strcpy(joined, file); + goto succeed; + } + + dir_len = (slash_pos + 1) - mft; + joined = malloc(dir_len + strlen(file) + 1); + if (!joined) + return -ENOMEM; + + strncpy(joined, mft, dir_len); + strcpy(joined + dir_len, file); + +succeed: + *result = joined; + return 0; +} + +static int +handle_file(char const *mft, IA5String_t *string) +{ + char *luri; int error; - /* rfc6486#section-4.1 */ - /* rfc6486#section-4.4.1 */ - error = validate_eContentType(sdata); - if (error) - return error; + /* TODO Treating string->buf as a C string is probably not correct. */ + pr_debug_add("File %s {", string->buf); - /* rfc6486#section-4.3 */ - error = validate_content_type(sdata); + error = get_relative_file(mft, (char const *) string->buf, &luri); if (error) - return error; + goto end; + + if (is_certificate(luri)) + error = handle_certificate(luri); + else if (is_roa(luri)) + error = handle_roa(luri); + else + pr_debug0("Unhandled file type."); + + free(luri); +end: + pr_debug0_rm("}"); + return error; +} - error = asn1_decode_octet_string(sdata->encapContentInfo.eContent, - &asn_DEF_Manifest, (void **) &manifest); - if (error) - return -EINVAL; +static int +__handle_manifest(char const *mft, struct Manifest *manifest) +{ + int i; + int error; - error = validate_manifest(manifest); - if (error) { - ASN_STRUCT_FREE(asn_DEF_Manifest, manifest); - return error; + for (i = 0; i < manifest->fileList.list.count; i++) { + error = handle_file(mft, + &manifest->fileList.list.array[i]->file); + if (error) + return error; } - *result = manifest; return 0; } -void -manifest_free(struct Manifest *manifest) +int +handle_manifest(char const *file_path) { + static OID oid = OID_MANIFEST; + struct oid_arcs arcs = OID2ARCS(oid); + struct Manifest *manifest; + int error; + + error = signed_object_decode(file_path, &asn_DEF_Manifest, &arcs, + (void **) &manifest); + if (error) + return error; + + error = validate_manifest(manifest); + if (!error) + error = __handle_manifest(file_path, manifest); + ASN_STRUCT_FREE(asn_DEF_Manifest, manifest); + return error; } diff --git a/src/object/manifest.h b/src/object/manifest.h new file mode 100644 index 00000000..00156fa4 --- /dev/null +++ b/src/object/manifest.h @@ -0,0 +1,9 @@ +#ifndef SRC_OBJECT_MANIFEST_H_ +#define SRC_OBJECT_MANIFEST_H_ + +#include + +bool is_manifest(char const *); +int handle_manifest(char const *); + +#endif /* SRC_OBJECT_MANIFEST_H_ */ diff --git a/src/object/roa.c b/src/object/roa.c new file mode 100644 index 00000000..c2a4a7fe --- /dev/null +++ b/src/object/roa.c @@ -0,0 +1,143 @@ +#include "object/roa.h" + +#include +#include +#include +#include + +#include "common.h" +#include "asn1/oid.h" +#include "object/signed_object.h" + +bool is_roa(char const *file_name) +{ + return file_has_extension(file_name, "roa"); +} + +static int +validate_roa(struct RouteOriginAttestation *roa) +{ + /* 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; + + return 0; +} + +static int +print_addr(long asn, uint8_t family, 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; + const char *str2; + int error; + + switch (family) { + case 1: + family = AF_INET; + break; + case 2: + family = AF_INET6; + break; + default: + warnx("Unknown family value: %u", family); + 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) { + error = errno; + warnxerrno0("Could not parse IP address"); + return error; + } + + prefix_len = 8 * roa_addr->address.size - roa_addr->address.bits_unused; + + printf("%ld,%s/%d,", asn, str2, prefix_len); + + if (roa_addr->maxLength != NULL) + printf("%ld", *roa_addr->maxLength); + else + printf("%d", prefix_len); + + printf("\n"); + return 0; +} + +static int +__handle_roa(struct RouteOriginAttestation *roa) +{ + struct ROAIPAddressFamily *block; + int b; + int a; + int error; + + for (b = 0; b < roa->ipAddrBlocks.list.count; b++) { + block = roa->ipAddrBlocks.list.array[0]; + if (block == NULL) + return -EINVAL; + + if (block->addressFamily.size != 2) + return -EINVAL; + if (block->addressFamily.buf[0] != 0) + return -EINVAL; + if (block->addressFamily.buf[1] != 1 + && block->addressFamily.buf[1] != 2) + return -EINVAL; + + if (block->addresses.list.array == NULL) + return -EINVAL; + for (a = 0; a < block->addresses.list.count; a++) { + error = print_addr(roa->asID, + block->addressFamily.buf[1], + block->addresses.list.array[a]); + if (error) + return error; + } + } + + return 0; +} + +int handle_roa(char const *file) +{ + static OID oid = OID_ROA; + struct oid_arcs arcs = OID2ARCS(oid); + struct RouteOriginAttestation *roa; + int error; + + error = signed_object_decode(file, &asn_DEF_RouteOriginAttestation, + &arcs, (void **) &roa); + if (error) + return error; + + error = validate_roa(roa); + if (!error) + error = __handle_roa(roa); + + ASN_STRUCT_FREE(asn_DEF_RouteOriginAttestation, roa); + return error; +} diff --git a/src/object/roa.h b/src/object/roa.h new file mode 100644 index 00000000..9795c397 --- /dev/null +++ b/src/object/roa.h @@ -0,0 +1,9 @@ +#ifndef SRC_OBJECT_ROA_H_ +#define SRC_OBJECT_ROA_H_ + +#include + +bool is_roa(char const *); +int handle_roa(char const *); + +#endif /* SRC_OBJECT_ROA_H_ */ diff --git a/src/object/signed_object.c b/src/object/signed_object.c new file mode 100644 index 00000000..3fe3062d --- /dev/null +++ b/src/object/signed_object.c @@ -0,0 +1,97 @@ +#include "signed_object.h" + +#include +#include +#include "asn1/content_info.h" +#include "asn1/decode.h" +#include "asn1/signed_data.h" + +static int +validate_eContentType(struct SignedData *sdata, + asn_TYPE_descriptor_t const *descriptor, + struct oid_arcs const *oid) +{ + struct oid_arcs arcs; + bool equals; + int error; + + error = oid2arcs(&sdata->encapContentInfo.eContentType, &arcs); + if (error) + return error; + equals = arcs_equal(&arcs, oid); + free_arcs(&arcs); + if (!equals) { + warnx("SignedObject's encapContentInfo lacks the OID of a %s.", + descriptor->name); + return -EINVAL; + } + + return 0; +} + +static int +validate_content_type(struct SignedData *sdata, + asn_TYPE_descriptor_t const *descriptor, + struct oid_arcs const *oid) +{ + 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(&arcs, oid); + free_arcs(&arcs); + if (!equals) { + warnx("SignedObject's content type attribute lacks the OID of a %s.", + descriptor->name); + return -EINVAL; + } + + return 0; +} + +int +signed_object_decode(char const *file, + asn_TYPE_descriptor_t const *descriptor, + struct oid_arcs const *oid, + void **result) +{ + struct ContentInfo *cinfo; + struct SignedData *sdata; + int error; + + error = content_info_load(file, &cinfo); + if (error) + goto end1; + + error = signed_data_decode(&cinfo->content, &sdata); + if (error) + goto end2; + + /* rfc6482#section-2 */ + /* rfc6486#section-4.1 */ + /* rfc6486#section-4.4.1 */ + error = validate_eContentType(sdata, descriptor, oid); + if (error) + goto end3; + + /* rfc6482#section-2 */ + /* rfc6486#section-4.3 */ + error = validate_content_type(sdata, descriptor, oid); + if (error) + goto end3; + + error = asn1_decode_octet_string(sdata->encapContentInfo.eContent, + descriptor, result); + +end3: signed_data_free(sdata); +end2: content_info_free(cinfo); +end1: return error; +} diff --git a/src/object/signed_object.h b/src/object/signed_object.h new file mode 100644 index 00000000..9311d1f6 --- /dev/null +++ b/src/object/signed_object.h @@ -0,0 +1,9 @@ +#ifndef SRC_OBJECT_SIGNED_OBJECT_H_ +#define SRC_OBJECT_SIGNED_OBJECT_H_ + +#include "asn1/oid.h" + +int signed_object_decode(char const *, asn_TYPE_descriptor_t const *, + struct oid_arcs const *, void **); + +#endif /* SRC_OBJECT_SIGNED_OBJECT_H_ */ diff --git a/src/tal.c b/src/object/tal.c similarity index 100% rename from src/tal.c rename to src/object/tal.c diff --git a/src/tal.h b/src/object/tal.h similarity index 74% rename from src/tal.h rename to src/object/tal.h index 6ef5ad24..9e897042 100644 --- a/src/tal.h +++ b/src/object/tal.h @@ -1,5 +1,5 @@ -#ifndef TAL_H_ -#define TAL_H_ +#ifndef TAL_OBJECT_H_ +#define TAL_OBJECT_H_ /* This is RFC 7730. */ @@ -11,4 +11,4 @@ void tal_destroy(struct tal *); typedef int (*foreach_uri_cb)(char const *); int foreach_uri(struct tal *, foreach_uri_cb); -#endif /* TAL_H_ */ +#endif /* TAL_OBJECT_H_ */