From: Alberto Leiva Popper Date: Sun, 21 Apr 2024 19:15:07 +0000 (-0600) Subject: Add --mode=print X-Git-Tag: 1.6.2~37 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d5c5dab70da23404073ea6a2ab4f3048f17017c7;p=thirdparty%2FFORT-validator.git Add --mode=print Prints an RPKI file in standard output. Only the asn1c signed objects (ROAs, Manifests and Ghostbusters) are implemented right now. In particular, it doesn't jsonify certificates nor CRLs yet, which includes the "certificate" field of the signed objects. Progress for #122. --- diff --git a/src/Makefile.am b/src/Makefile.am index f9b7d451..8fb6b427 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,6 +22,7 @@ fort_SOURCES += line_file.h line_file.c fort_SOURCES += log.h log.c fort_SOURCES += nid.h nid.c fort_SOURCES += output_printer.h output_printer.c +fort_SOURCES += print_file.h print_file.c fort_SOURCES += resource.h resource.c fort_SOURCES += rpp.h rpp.c fort_SOURCES += rrdp.h rrdp.c @@ -108,8 +109,6 @@ fort_SOURCES += thread/thread_pool.c thread/thread_pool.h fort_SOURCES += xml/relax_ng.c xml/relax_ng.h -# I'm placing these at the end because they rarely change, and I want warnings -# to appear as soon as possible. include asn1/asn1c/Makefile.include fort_SOURCES += $(ASN_MODULE_SRCS) $(ASN_MODULE_HDRS) diff --git a/src/asn1/asn1c/ANY.c b/src/asn1/asn1c/ANY.c index f48c9783..75240df4 100644 --- a/src/asn1/asn1c/ANY.c +++ b/src/asn1/asn1c/ANY.c @@ -18,6 +18,7 @@ asn_TYPE_operation_t asn_OP_ANY = { OCTET_STRING_compare, OCTET_STRING_decode_ber, OCTET_STRING_encode_der, + OCTET_STRING_encode_json, ANY_encode_xer, 0 /* Use generic outmost tag fetcher */ }; diff --git a/src/asn1/asn1c/BIT_STRING.c b/src/asn1/asn1c/BIT_STRING.c index 8e311a87..94f9d788 100644 --- a/src/asn1/asn1c/BIT_STRING.c +++ b/src/asn1/asn1c/BIT_STRING.c @@ -26,6 +26,7 @@ asn_TYPE_operation_t asn_OP_BIT_STRING = { BIT_STRING_compare, OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */ + OCTET_STRING_encode_json, /* Implemented in terms of OCTET STRING */ BIT_STRING_encode_xer, 0 /* Use generic outmost tag fetcher */ }; diff --git a/src/asn1/asn1c/BOOLEAN.c b/src/asn1/asn1c/BOOLEAN.c index b0fdef44..ba56217b 100644 --- a/src/asn1/asn1c/BOOLEAN.c +++ b/src/asn1/asn1c/BOOLEAN.c @@ -18,6 +18,7 @@ asn_TYPE_operation_t asn_OP_BOOLEAN = { BOOLEAN_compare, BOOLEAN_decode_ber, BOOLEAN_encode_der, + BOOLEAN_encode_json, BOOLEAN_encode_xer, 0 /* Use generic outmost tag fetcher */ }; @@ -131,6 +132,17 @@ BOOLEAN_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, ASN__ENCODED_OK(erval); } +json_t * +BOOLEAN_encode_json(const struct asn_TYPE_descriptor_s *td, const void *sptr) +{ + const BOOLEAN_t *st = (const BOOLEAN_t *)sptr; + + if (st == NULL) + return json_null(); + + return (*st) ? json_true() : json_false(); +} + asn_enc_rval_t BOOLEAN_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, enum xer_encoder_flags_e flags, diff --git a/src/asn1/asn1c/BOOLEAN.h b/src/asn1/asn1c/BOOLEAN.h index 0f5f8532..22f4272a 100644 --- a/src/asn1/asn1c/BOOLEAN.h +++ b/src/asn1/asn1c/BOOLEAN.h @@ -22,6 +22,7 @@ asn_struct_print_f BOOLEAN_print; asn_struct_compare_f BOOLEAN_compare; ber_type_decoder_f BOOLEAN_decode_ber; der_type_encoder_f BOOLEAN_encode_der; +json_type_encoder_f BOOLEAN_encode_json; xer_type_encoder_f BOOLEAN_encode_xer; #define BOOLEAN_constraint asn_generic_no_constraint diff --git a/src/asn1/asn1c/CMSAttribute.c b/src/asn1/asn1c/CMSAttribute.c index e66ee687..9eca5b08 100644 --- a/src/asn1/asn1c/CMSAttribute.c +++ b/src/asn1/asn1c/CMSAttribute.c @@ -7,6 +7,73 @@ #include "asn1/asn1c/CMSAttribute.h" +#include "asn1/asn1c/ContentType.h" +#include "asn1/asn1c/MessageDigest.h" +#include "asn1/asn1c/SigningTime.h" + +static json_t * +attr2json(asn_TYPE_descriptor_t const *td, struct CMSAttribute const *cattr) +{ + json_t *array, *node; + CMSAttributeValue_t *ber; + void *attr; + int i; + asn_dec_rval_t rval; + + array = json_array(); + if (array == NULL) + return NULL; + + for (i = 0; i < cattr->attrValues.list.count; i++) { + ber = cattr->attrValues.list.array[i]; + attr = NULL; + + rval = ber_decode(NULL, td, &attr, ber->buf, ber->size); + if (rval.code != RC_OK) + goto fail; + + node = td->op->json_encoder(td, attr); + + ASN_STRUCT_FREE(*td, attr); + + if (json_array_append_new(array, node) < 0) + goto fail; + } + + return array; + +fail: json_decref(array); + return NULL; +} + +json_t * +CMSAttribute_encode_json(const asn_TYPE_descriptor_t *td, const void *sptr) +{ + struct CMSAttribute const *cattr = sptr; + + if (!cattr) + return json_null(); + if (OBJECT_IDENTIFIER_is_ContentType(&cattr->attrType)) + return attr2json(&asn_DEF_ContentType, cattr); + if (OBJECT_IDENTIFIER_is_MessageDigest(&cattr->attrType)) + return attr2json(&asn_DEF_MessageDigest, cattr); + if (OBJECT_IDENTIFIER_is_SigningTime(&cattr->attrType)) + return attr2json(&asn_DEF_SigningTime, cattr); + + return SEQUENCE_encode_json(td, sptr); +} + +asn_TYPE_operation_t asn_OP_CMSAttribute = { + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_compare, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + CMSAttribute_encode_json, + SEQUENCE_encode_xer, + 0 /* Use generic outmost tag fetcher */ +}; + static asn_TYPE_member_t asn_MBR_attrValues_3[] = { { ATF_ANY_TYPE | ATF_POINTER, 0, 0, -1 /* Ambiguous tag (ANY?) */, @@ -80,7 +147,7 @@ asn_SEQUENCE_specifics_t asn_SPC_CMSAttribute_specs_1 = { asn_TYPE_descriptor_t asn_DEF_CMSAttribute = { "CMSAttribute", "CMSAttribute", - &asn_OP_SEQUENCE, + &asn_OP_CMSAttribute, asn_DEF_CMSAttribute_tags_1, sizeof(asn_DEF_CMSAttribute_tags_1) /sizeof(asn_DEF_CMSAttribute_tags_1[0]), /* 1 */ diff --git a/src/asn1/asn1c/ContentInfo.c b/src/asn1/asn1c/ContentInfo.c index c522bebb..94a321f5 100644 --- a/src/asn1/asn1c/ContentInfo.c +++ b/src/asn1/asn1c/ContentInfo.c @@ -7,6 +7,84 @@ #include "asn1/asn1c/ContentInfo.h" +#include "asn1/asn1c/SignedData.h" + +json_t * +content2json(const asn_TYPE_descriptor_t *td, ANY_t const *ber) +{ + void *decoded; + asn_dec_rval_t rval; + json_t *content; + + decoded = NULL; + rval = ber_decode(NULL, td, &decoded, ber->buf, ber->size); + if (rval.code != RC_OK) + return NULL; + + content = td->op->json_encoder(td, decoded); + + ASN_STRUCT_FREE(*td, decoded); + return content; +} + +json_t * +ContentInfo_encode_json(const asn_TYPE_descriptor_t *td, const void *sptr) +{ + struct ContentInfo const *ci = sptr; + json_t *parent; + json_t *content_type; + json_t *content; + + if (!ci) + return json_null(); + + parent = json_object(); + if (parent == NULL) + return NULL; + + td = &asn_DEF_ContentType; + content_type = td->op->json_encoder(td, &ci->contentType); + if (content_type == NULL) + goto fail; + if (json_object_set_new(parent, td->name, content_type)) + goto fail; + + if (OBJECT_IDENTIFIER_is_SignedData(&ci->contentType)) { + td = &asn_DEF_SignedData; + content = content2json(td, &ci->content); + + } else { +// printf("===========================\n"); +// for (ret = 0; ret < ci->contentType.size; ret++) +// printf("%u ", ci->contentType.buf[ret]); +// printf("\n==========================\n"); + + td = &asn_DEF_ANY; + content = td->op->json_encoder(td, &ci->content); + } + + if (content == NULL) + goto fail; + if (json_object_set_new(parent, td->name, content)) + goto fail; + + return parent; + +fail: json_decref(parent); + return NULL; +} + +asn_TYPE_operation_t asn_OP_ContentInfo = { + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_compare, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + ContentInfo_encode_json, + SEQUENCE_encode_xer, + 0 /* Use generic outmost tag fetcher */ +}; + static asn_TYPE_member_t asn_MBR_ContentInfo_1[] = { { ATF_NOFLAGS, 0, offsetof(struct ContentInfo, contentType), (ASN_TAG_CLASS_UNIVERSAL | (6 << 2)), @@ -44,7 +122,7 @@ static asn_SEQUENCE_specifics_t asn_SPC_ContentInfo_specs_1 = { asn_TYPE_descriptor_t asn_DEF_ContentInfo = { "ContentInfo", "ContentInfo", - &asn_OP_SEQUENCE, + &asn_OP_ContentInfo, asn_DEF_ContentInfo_tags_1, sizeof(asn_DEF_ContentInfo_tags_1) /sizeof(asn_DEF_ContentInfo_tags_1[0]), /* 1 */ diff --git a/src/asn1/asn1c/EncapsulatedContentInfo.c b/src/asn1/asn1c/EncapsulatedContentInfo.c index 6de83cae..77b335ab 100644 --- a/src/asn1/asn1c/EncapsulatedContentInfo.c +++ b/src/asn1/asn1c/EncapsulatedContentInfo.c @@ -7,6 +7,94 @@ #include "asn1/asn1c/EncapsulatedContentInfo.h" +#include "asn1/asn1c/Manifest.h" +#include "asn1/asn1c/RouteOriginAttestation.h" + +static json_t * +econtent2json(asn_TYPE_descriptor_t const *td, OCTET_STRING_t *eContent) +{ + void *decoded; + asn_dec_rval_t rval; + json_t *content; + + decoded = NULL; + rval = ber_decode(NULL, td, &decoded, eContent->buf, eContent->size); + if (rval.code != RC_OK) + return NULL; + + content = td->op->json_encoder(td, decoded); + + ASN_STRUCT_FREE(*td, decoded); + return content; +} + +json_t * +EncapsulatedContentInfo_encode_json(const asn_TYPE_descriptor_t *td, + const void *sptr) +{ + struct EncapsulatedContentInfo const *eci = sptr; + json_t *parent; + json_t *content_type; + json_t *content; + + if (!eci) + return json_null(); + + parent = json_object(); + if (parent == NULL) + return NULL; + + td = &asn_DEF_ContentType; + content_type = td->op->json_encoder(td, &eci->eContentType); + if (content_type == NULL) + goto fail; + if (json_object_set_new(parent, td->name, content_type)) + goto fail; + + if (OBJECT_IDENTIFIER_is_mft(&eci->eContentType)) { + td = &asn_DEF_Manifest; + content = econtent2json(td, eci->eContent); + + } else if (OBJECT_IDENTIFIER_is_roa(&eci->eContentType)) { + td = &asn_DEF_RouteOriginAttestation; + content = econtent2json(td, eci->eContent); + + } else if (OBJECT_IDENTIFIER_is_gbr(&eci->eContentType)) { + td = &asn_DEF_OCTET_STRING; + content = OCTET_STRING_encode_json_utf8(td, eci->eContent); + + } else { +// printf("===========================\n"); +// for (ret = 0; ret < eci->eContentType.size; ret++) +// printf("%u ", eci->eContentType.buf[ret]); +// printf("\n==========================\n"); + + td = &asn_DEF_OCTET_STRING; + content = td->op->json_encoder(td, eci->eContent); + } + + if (content == NULL) + goto fail; + if (json_object_set_new(parent, td->name, content)) + goto fail; + + return parent; + +fail: json_decref(parent); + return NULL; +} + +asn_TYPE_operation_t asn_OP_EncapsulatedContentInfo = { + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_compare, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + EncapsulatedContentInfo_encode_json, + SEQUENCE_encode_xer, + 0 /* Use generic outmost tag fetcher */ +}; + asn_TYPE_member_t asn_MBR_EncapsulatedContentInfo_1[] = { { ATF_NOFLAGS, 0, offsetof(struct EncapsulatedContentInfo, eContentType), (ASN_TAG_CLASS_UNIVERSAL | (6 << 2)), @@ -44,7 +132,7 @@ asn_SEQUENCE_specifics_t asn_SPC_EncapsulatedContentInfo_specs_1 = { asn_TYPE_descriptor_t asn_DEF_EncapsulatedContentInfo = { "EncapsulatedContentInfo", "EncapsulatedContentInfo", - &asn_OP_SEQUENCE, + &asn_OP_EncapsulatedContentInfo, asn_DEF_EncapsulatedContentInfo_tags_1, sizeof(asn_DEF_EncapsulatedContentInfo_tags_1) /sizeof(asn_DEF_EncapsulatedContentInfo_tags_1[0]), /* 1 */ diff --git a/src/asn1/asn1c/GeneralizedTime.c b/src/asn1/asn1c/GeneralizedTime.c index f8efc307..5d66e77a 100644 --- a/src/asn1/asn1c/GeneralizedTime.c +++ b/src/asn1/asn1c/GeneralizedTime.c @@ -58,6 +58,7 @@ asn_TYPE_operation_t asn_OP_GeneralizedTime = { GeneralizedTime_compare, OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ GeneralizedTime_encode_der, + GeneralizedTime_encode_json, GeneralizedTime_encode_xer, 0 /* Use generic outmost tag fetcher */ }; @@ -78,6 +79,17 @@ asn_TYPE_descriptor_t asn_DEF_GeneralizedTime = { #endif /* ASN___INTERNAL_TEST_MODE */ +static int +GeneralizedTime2str(const GeneralizedTime_t *st, char *str) +{ + struct tm tm; + + if (asn_GT2time(st, &tm) != 0) + return -1; + + return asn_tm2str(&tm, str); +} + /* * Check that the time looks like the time. */ @@ -124,6 +136,21 @@ GeneralizedTime_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, return erval; } +json_t * +GeneralizedTime_encode_json(const struct asn_TYPE_descriptor_s *td, const void *sptr) +{ + const GeneralizedTime_t *st = (const GeneralizedTime_t *)sptr; + char buf[ASN_TM_STR_MAXLEN]; + + if (st == NULL || st->buf == NULL) + return json_null(); + + if (GeneralizedTime2str(st, buf) < 0) + return NULL; + + return json_string(buf); +} + #ifndef ASN___INTERNAL_TEST_MODE asn_enc_rval_t @@ -157,29 +184,35 @@ GeneralizedTime_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int GeneralizedTime_print(const asn_TYPE_descriptor_t *td, const void *sptr, - int ilevel, asn_app_consume_bytes_f *cb, void *app_key) { - const GeneralizedTime_t *st = (const GeneralizedTime_t *)sptr; + int ilevel, asn_app_consume_bytes_f *cb, void *app_key) +{ + const GeneralizedTime_t *st = (const GeneralizedTime_t *)sptr; + char buf[ASN_TM_STR_MAXLEN]; + int ret; - (void)td; /* Unused argument */ - (void)ilevel; /* Unused argument */ + if (st == NULL || st->buf == NULL) + return (cb("", 8, app_key) < 0) ? -1 : 0; - if(st && st->buf) { - char buf[32]; - struct tm tm; - int ret; + ret = GeneralizedTime2str(st, buf); + if (ret < 0) + return (cb("", 11, app_key) < 0) ? -1 : 0; - if(asn_GT2time(st, &tm) != 0) - return (cb("", 11, app_key) < 0) ? -1 : 0; + return (cb(buf, ret, app_key) < 0) ? -1 : 0; +} - ret = snprintf(buf, sizeof(buf), - "%04d-%02d-%02d %02d:%02d:%02d (GMT)", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - assert(ret > 0 && ret < (int)sizeof(buf)); - return (cb(buf, ret, app_key) < 0) ? -1 : 0; - } else { - return (cb("", 8, app_key) < 0) ? -1 : 0; - } +/* Returns string length (ASN_TM_STR_MAXLEN - 1); no errors possible. */ +int +asn_tm2str(struct tm *tm, char *str) +{ + int ret; + + ret = snprintf(str, ASN_TM_STR_MAXLEN, + "%04d-%02d-%02dT%02d:%02d:%02dZ", + tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + assert(ret == ASN_TM_STR_MAXLEN - 1); + + return ret; } int diff --git a/src/asn1/asn1c/GeneralizedTime.h b/src/asn1/asn1c/GeneralizedTime.h index 5a974f4b..fa98755f 100644 --- a/src/asn1/asn1c/GeneralizedTime.h +++ b/src/asn1/asn1c/GeneralizedTime.h @@ -18,6 +18,7 @@ asn_struct_print_f GeneralizedTime_print; asn_struct_compare_f GeneralizedTime_compare; asn_constr_check_f GeneralizedTime_constraint; der_type_encoder_f GeneralizedTime_encode_der; +json_type_encoder_f GeneralizedTime_encode_json; xer_type_encoder_f GeneralizedTime_encode_xer; #define GeneralizedTime_free OCTET_STRING_free @@ -27,6 +28,10 @@ xer_type_encoder_f GeneralizedTime_encode_xer; * Some handy helpers. * ***********************/ +#define ASN_TM_STR_MAXLEN 21 + +int asn_tm2str(struct tm *tm, char *str); + /* * Convert a GeneralizedTime structure into time_t * and optionally into struct tm. diff --git a/src/asn1/asn1c/IA5String.c b/src/asn1/asn1c/IA5String.c index 29a9df29..5f574e83 100644 --- a/src/asn1/asn1c/IA5String.c +++ b/src/asn1/asn1c/IA5String.c @@ -18,6 +18,7 @@ asn_TYPE_operation_t asn_OP_IA5String = { OCTET_STRING_compare, OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ OCTET_STRING_encode_der, + OCTET_STRING_encode_json_utf8, OCTET_STRING_encode_xer_utf8, 0 /* Use generic outmost tag fetcher */ }; diff --git a/src/asn1/asn1c/INTEGER.c b/src/asn1/asn1c/INTEGER.c index 2d6d0dfa..ca0a984d 100644 --- a/src/asn1/asn1c/INTEGER.c +++ b/src/asn1/asn1c/INTEGER.c @@ -21,6 +21,7 @@ asn_TYPE_operation_t asn_OP_INTEGER = { INTEGER_compare, ber_decode_primitive, INTEGER_encode_der, + INTEGER_encode_json, INTEGER_encode_xer, 0 /* Use generic outmost tag fetcher */ }; @@ -217,6 +218,29 @@ INTEGER_map_value2enum(const asn_INTEGER_specifics_t *specs, long value) { INTEGER__compar_value2enum); } +json_t * +INTEGER_encode_json(const struct asn_TYPE_descriptor_s *td, const void *sptr) +{ + const INTEGER_t *st; + const asn_INTEGER_specifics_t *specs; + uintmax_t uint; + intmax_t sint; + + st = (const INTEGER_t *)sptr; + specs = (const asn_INTEGER_specifics_t *)td->specifics; + + if (specs && specs->field_unsigned) { + if (asn_INTEGER2umax(st, &uint) < 0) + return NULL; + return json_integer(uint); + + } else { + if (asn_INTEGER2imax(st, &sint) < 0) + return NULL; + return json_integer(sint); + } +} + asn_enc_rval_t INTEGER_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, enum xer_encoder_flags_e flags, diff --git a/src/asn1/asn1c/INTEGER.h b/src/asn1/asn1c/INTEGER.h index acc07ce3..584f8fc9 100644 --- a/src/asn1/asn1c/INTEGER.h +++ b/src/asn1/asn1c/INTEGER.h @@ -37,6 +37,7 @@ typedef struct asn_INTEGER_specifics_s { asn_struct_print_f INTEGER_print; asn_struct_compare_f INTEGER_compare; der_type_encoder_f INTEGER_encode_der; +json_type_encoder_f INTEGER_encode_json; xer_type_encoder_f INTEGER_encode_xer; /*********************************** diff --git a/src/asn1/asn1c/Makefile.include b/src/asn1/asn1c/Makefile.include index 5043095d..f9faea9d 100644 --- a/src/asn1/asn1c/Makefile.include +++ b/src/asn1/asn1c/Makefile.include @@ -179,5 +179,7 @@ ASN_MODULE_HDRS+=asn1/asn1c/constr_TYPE.h ASN_MODULE_SRCS+=asn1/asn1c/constr_TYPE.c ASN_MODULE_HDRS+=asn1/asn1c/constraints.h ASN_MODULE_SRCS+=asn1/asn1c/constraints.c +ASN_MODULE_HDRS+=asn1/asn1c/json_encoder.c +ASN_MODULE_HDRS+=asn1/asn1c/json_encoder.h ASN_MODULE_HDRS+=asn1/asn1c/xer_encoder.h ASN_MODULE_SRCS+=asn1/asn1c/xer_encoder.c \ No newline at end of file diff --git a/src/asn1/asn1c/NULL.c b/src/asn1/asn1c/NULL.c index 2811a846..b4bd1717 100644 --- a/src/asn1/asn1c/NULL.c +++ b/src/asn1/asn1c/NULL.c @@ -18,6 +18,7 @@ asn_TYPE_operation_t asn_OP_NULL = { NULL_compare, NULL_decode_ber, NULL_encode_der, /* Special handling of DER encoding */ + NULL_encode_json, NULL_encode_xer, 0 /* Use generic outmost tag fetcher */ }; @@ -107,6 +108,12 @@ NULL_encode_der(const asn_TYPE_descriptor_t *td, const void *ptr, int tag_mode, ASN__ENCODED_OK(erval); } +json_t * +NULL_encode_json(const struct asn_TYPE_descriptor_s *td, const void *sptr) +{ + return json_null(); +} + asn_enc_rval_t NULL_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb, diff --git a/src/asn1/asn1c/NULL.h b/src/asn1/asn1c/NULL.h index f93bd4ae..1c9bfec6 100644 --- a/src/asn1/asn1c/NULL.h +++ b/src/asn1/asn1c/NULL.h @@ -21,6 +21,7 @@ asn_struct_print_f NULL_print; asn_struct_compare_f NULL_compare; ber_type_decoder_f NULL_decode_ber; der_type_encoder_f NULL_encode_der; +json_type_encoder_f NULL_encode_json; xer_type_encoder_f NULL_encode_xer; #define NULL_constraint asn_generic_no_constraint diff --git a/src/asn1/asn1c/OBJECT_IDENTIFIER.c b/src/asn1/asn1c/OBJECT_IDENTIFIER.c index c964c809..04094ac4 100644 --- a/src/asn1/asn1c/OBJECT_IDENTIFIER.c +++ b/src/asn1/asn1c/OBJECT_IDENTIFIER.c @@ -22,6 +22,7 @@ asn_TYPE_operation_t asn_OP_OBJECT_IDENTIFIER = { OCTET_STRING_compare, /* Implemented in terms of a string comparison */ ber_decode_primitive, der_encode_primitive, + OBJECT_IDENTIFIER_encode_json, OBJECT_IDENTIFIER_encode_xer, 0 /* Use generic outmost tag fetcher */ }; @@ -210,6 +211,85 @@ OBJECT_IDENTIFIER_print(const asn_TYPE_descriptor_t *td, const void *sptr, return (cb(" }", 2, app_key) < 0) ? -1 : 0; } +struct string_buffer { + char *buf; + size_t len; +}; + +static int +bytes2str(const void *addend, size_t addlen, void *arg) +{ + struct string_buffer *buffer = arg; + + if (buffer->len + addlen + 1 > OID_STR_MAXLEN) + return -ENOSPC; + + strncpy(buffer->buf + buffer->len, addend, addlen); + buffer->len += addlen; + return 0; +} + +static char * +OBJECT_IDENTIFIER_to_literal(OBJECT_IDENTIFIER_t const *oid, char *buf) +{ + struct string_buffer buffer; + + buffer.buf = buf; + buffer.len = 0; + + if (OBJECT_IDENTIFIER__dump_body(oid, bytes2str, &buffer) < 0) + return NULL; + + buffer.buf[buffer.len] = '\0'; + return buf; +} + +char const * +OBJECT_IDENTIFIER_to_string(OBJECT_IDENTIFIER_t const *oid, char *buf) +{ +// printf("\n===========================\n"); +// for (ret = 0; ret < st->size; ret++) +// printf("%u ", st->buf[ret]); +// printf("\n===========================\n"); + + if (!oid || !oid->buf) + return NULL; + if (OBJECT_IDENTIFIER_is_rsaEncryption(oid)) + return "rsaEncryption"; + if (OBJECT_IDENTIFIER_is_sha256WithRSAEncryption(oid)) + return "sha256WithRSAEncryption"; + if (OBJECT_IDENTIFIER_is_SignedData(oid)) + return "signedData"; + if (OBJECT_IDENTIFIER_is_ContentType(oid)) + return "Content-Type"; + if (OBJECT_IDENTIFIER_is_MessageDigest(oid)) + return "Message-Digest"; + if (OBJECT_IDENTIFIER_is_SigningTime(oid)) + return "Signing-Time"; + if (OBJECT_IDENTIFIER_is_roa(oid)) + return "ROA"; + if (OBJECT_IDENTIFIER_is_mft(oid)) + return "Manifest"; + if (OBJECT_IDENTIFIER_is_gbr(oid)) + return "Ghostbusters"; + if (OBJECT_IDENTIFIER_is_sha256(oid)) + return "sha256"; + + return OBJECT_IDENTIFIER_to_literal(oid, buf); +} + +json_t * +OBJECT_IDENTIFIER_encode_json(const struct asn_TYPE_descriptor_s *td, + const void *sptr) +{ + const OBJECT_IDENTIFIER_t *oid = (const OBJECT_IDENTIFIER_t *)sptr; + char buf[OID_STR_MAXLEN]; + char const *string; + + string = OBJECT_IDENTIFIER_to_string(oid, buf); + return (string != NULL) ? json_string(string) : NULL; +} + ssize_t OBJECT_IDENTIFIER_get_arcs(const OBJECT_IDENTIFIER_t *st, asn_oid_arc_t *arcs, size_t arc_slots) { @@ -508,3 +588,97 @@ OBJECT_IDENTIFIER_parse_arcs(const char *oid_text, ssize_t oid_txt_length, errno = EINVAL; /* Broken OID */ return -1; } + +static bool +is_raw(OBJECT_IDENTIFIER_t const *oid, unsigned char const *raw, size_t size) +{ + return (oid->size == size) && memcmp(oid->buf, raw, size) == 0; +} + +bool +OBJECT_IDENTIFIER_is_rsaEncryption(OBJECT_IDENTIFIER_t const *oid) +{ + static const unsigned char RAW[] = { + 42, 134, 72, 134, 247, 13, 1, 1, 1 + }; + return is_raw(oid, RAW, sizeof(RAW)); +} + +bool +OBJECT_IDENTIFIER_is_sha256WithRSAEncryption(OBJECT_IDENTIFIER_t const *oid) +{ + static const unsigned char RAW[] = { + 42, 134, 72, 134, 247, 13, 1, 1, 11 + }; + return is_raw(oid, RAW, sizeof(RAW)); +} + +bool +OBJECT_IDENTIFIER_is_SignedData(OBJECT_IDENTIFIER_t const *oid) +{ + static const unsigned char RAW[] = { + 42, 134, 72, 134, 247, 13, 1, 7, 2 + }; + return is_raw(oid, RAW, sizeof(RAW)); +} + +bool +OBJECT_IDENTIFIER_is_ContentType(OBJECT_IDENTIFIER_t const *oid) +{ + static const unsigned char RAW[] = { + 42, 134, 72, 134, 247, 13, 1, 9, 3 + }; + return is_raw(oid, RAW, sizeof(RAW)); +} + +bool +OBJECT_IDENTIFIER_is_MessageDigest(OBJECT_IDENTIFIER_t const *oid) +{ + static const unsigned char RAW[] = { + 42, 134, 72, 134, 247, 13, 1, 9, 4 + }; + return is_raw(oid, RAW, sizeof(RAW)); +} + +bool +OBJECT_IDENTIFIER_is_SigningTime(OBJECT_IDENTIFIER_t const *oid) +{ + static const unsigned char RAW[] = { + 42, 134, 72, 134, 247, 13, 1, 9, 5 + }; + return is_raw(oid, RAW, sizeof(RAW)); +} + +bool +OBJECT_IDENTIFIER_is_roa(OBJECT_IDENTIFIER_t const *oid) +{ + static const unsigned char RAW[] = { + 42, 134, 72, 134, 247, 13, 1, 9, 16, 1, 24 + }; + return is_raw(oid, RAW, sizeof(RAW)); +} + +bool +OBJECT_IDENTIFIER_is_mft(OBJECT_IDENTIFIER_t const *oid) +{ + static const unsigned char RAW[] = { + 42, 134, 72, 134, 247, 13, 1, 9, 16, 1, 26 + }; + return is_raw(oid, RAW, sizeof(RAW)); +} + +bool +OBJECT_IDENTIFIER_is_gbr(OBJECT_IDENTIFIER_t const *oid) +{ + static const unsigned char RAW[] = { + 42, 134, 72, 134, 247, 13, 1, 9, 16, 1, 35 + }; + return is_raw(oid, RAW, sizeof(RAW)); +} + +bool +OBJECT_IDENTIFIER_is_sha256(OBJECT_IDENTIFIER_t const *oid) +{ + static const unsigned char RAW[] = { 96, 134, 72, 1, 101, 3, 4, 2, 1 }; + return is_raw(oid, RAW, sizeof(RAW)); +} diff --git a/src/asn1/asn1c/OBJECT_IDENTIFIER.h b/src/asn1/asn1c/OBJECT_IDENTIFIER.h index 78fcecd8..00acb6e1 100644 --- a/src/asn1/asn1c/OBJECT_IDENTIFIER.h +++ b/src/asn1/asn1c/OBJECT_IDENTIFIER.h @@ -5,6 +5,7 @@ #ifndef _OBJECT_IDENTIFIER_H_ #define _OBJECT_IDENTIFIER_H_ +#include #include "asn1/asn1c/asn_application.h" #include "asn1/asn1c/asn_codecs_prim.h" #include "asn1/asn1c/OCTET_STRING.h" @@ -20,6 +21,7 @@ extern asn_TYPE_operation_t asn_OP_OBJECT_IDENTIFIER; asn_struct_print_f OBJECT_IDENTIFIER_print; asn_constr_check_f OBJECT_IDENTIFIER_constraint; der_type_encoder_f OBJECT_IDENTIFIER_encode_der; +json_type_encoder_f OBJECT_IDENTIFIER_encode_json; xer_type_encoder_f OBJECT_IDENTIFIER_encode_xer; #define OBJECT_IDENTIFIER_free ASN__PRIMITIVE_TYPE_free @@ -31,6 +33,9 @@ xer_type_encoder_f OBJECT_IDENTIFIER_encode_xer; * Some handy conversion routines * **********************************/ +#define OID_STR_MAXLEN 64 /* Null char included */ +char const *OBJECT_IDENTIFIER_to_string(OBJECT_IDENTIFIER_t const *, char *); + /* * This function fills an (arcs) array with OBJECT IDENTIFIER arcs * up to specified (arc_slots) elements. @@ -137,4 +142,15 @@ ssize_t OBJECT_IDENTIFIER_get_single_arc(const uint8_t *arcbuf, ssize_t OBJECT_IDENTIFIER_set_single_arc(uint8_t *arcbuf, size_t arcbuf_len, asn_oid_arc_t arc_value); +bool OBJECT_IDENTIFIER_is_rsaEncryption(OBJECT_IDENTIFIER_t const *oid); +bool OBJECT_IDENTIFIER_is_sha256WithRSAEncryption(OBJECT_IDENTIFIER_t const *oid); +bool OBJECT_IDENTIFIER_is_SignedData(OBJECT_IDENTIFIER_t const *oid); +bool OBJECT_IDENTIFIER_is_ContentType(OBJECT_IDENTIFIER_t const *oid); +bool OBJECT_IDENTIFIER_is_MessageDigest(OBJECT_IDENTIFIER_t const *oid); +bool OBJECT_IDENTIFIER_is_SigningTime(OBJECT_IDENTIFIER_t const *oid); +bool OBJECT_IDENTIFIER_is_roa(OBJECT_IDENTIFIER_t const *oid); +bool OBJECT_IDENTIFIER_is_mft(OBJECT_IDENTIFIER_t const *oid); +bool OBJECT_IDENTIFIER_is_gbr(OBJECT_IDENTIFIER_t const *oid); +bool OBJECT_IDENTIFIER_is_sha256(OBJECT_IDENTIFIER_t const *oid); + #endif /* _OBJECT_IDENTIFIER_H_ */ diff --git a/src/asn1/asn1c/OCTET_STRING.c b/src/asn1/asn1c/OCTET_STRING.c index 377c8fcd..1dd9f799 100644 --- a/src/asn1/asn1c/OCTET_STRING.c +++ b/src/asn1/asn1c/OCTET_STRING.c @@ -9,6 +9,8 @@ #include #include +#include "alloc.h" + /* * OCTET STRING basic type description. */ @@ -27,6 +29,7 @@ asn_TYPE_operation_t asn_OP_OCTET_STRING = { OCTET_STRING_compare, OCTET_STRING_decode_ber, OCTET_STRING_encode_der, + OCTET_STRING_encode_json, OCTET_STRING_encode_xer, 0 /* Use generic outmost tag fetcher */ }; @@ -578,6 +581,37 @@ cb_failed: ASN__ENCODE_FAILED; } +json_t * +OCTET_STRING_encode_json(const struct asn_TYPE_descriptor_s *td, + const void *sptr) +{ + static const char * const H2C = "0123456789abcdef"; + const OCTET_STRING_t *os = sptr; + uint8_t *buf, *end; + char *result, *r; + + result = pmalloc(2 * os->size + 1); + + buf = os->buf; + end = buf + os->size; + r = result; + for (; buf < end; buf++) { + *r++ = H2C[(*buf >> 4) & 0x0F]; + *r++ = H2C[(*buf ) & 0x0F]; + } + *r = '\0'; + + return json_string(result); +} + +json_t * +OCTET_STRING_encode_json_utf8(const struct asn_TYPE_descriptor_s *td, + const void *sptr) +{ + const OCTET_STRING_t *os = sptr; + return json_stringn((char const *) os->buf, os->size); +} + asn_enc_rval_t OCTET_STRING_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, enum xer_encoder_flags_e flags, diff --git a/src/asn1/asn1c/OCTET_STRING.h b/src/asn1/asn1c/OCTET_STRING.h index c0568750..4647a803 100644 --- a/src/asn1/asn1c/OCTET_STRING.h +++ b/src/asn1/asn1c/OCTET_STRING.h @@ -31,6 +31,8 @@ asn_struct_print_f OCTET_STRING_print_utf8; asn_struct_compare_f OCTET_STRING_compare; ber_type_decoder_f OCTET_STRING_decode_ber; der_type_encoder_f OCTET_STRING_encode_der; +json_type_encoder_f OCTET_STRING_encode_json; +json_type_encoder_f OCTET_STRING_encode_json_utf8; xer_type_encoder_f OCTET_STRING_encode_xer; xer_type_encoder_f OCTET_STRING_encode_xer_utf8; diff --git a/src/asn1/asn1c/OPEN_TYPE.c b/src/asn1/asn1c/OPEN_TYPE.c index fb167a92..4fcee5a9 100644 --- a/src/asn1/asn1c/OPEN_TYPE.c +++ b/src/asn1/asn1c/OPEN_TYPE.c @@ -13,6 +13,7 @@ asn_TYPE_operation_t asn_OP_OPEN_TYPE = { OPEN_TYPE_compare, OPEN_TYPE_decode_ber, OPEN_TYPE_encode_der, + OPEN_TYPE_encode_json, OPEN_TYPE_encode_xer, 0, /* Use generic outmost tag fetcher */ }; diff --git a/src/asn1/asn1c/OPEN_TYPE.h b/src/asn1/asn1c/OPEN_TYPE.h index 5913ab1b..87ed5919 100644 --- a/src/asn1/asn1c/OPEN_TYPE.h +++ b/src/asn1/asn1c/OPEN_TYPE.h @@ -13,6 +13,7 @@ #define OPEN_TYPE_constraint CHOICE_constraint #define OPEN_TYPE_decode_ber NULL #define OPEN_TYPE_encode_der CHOICE_encode_der +#define OPEN_TYPE_encode_json CHOICE_encode_json #define OPEN_TYPE_encode_xer CHOICE_encode_xer extern asn_TYPE_operation_t asn_OP_OPEN_TYPE; diff --git a/src/asn1/asn1c/ROAIPAddressFamily.c b/src/asn1/asn1c/ROAIPAddressFamily.c index 80d165c3..23e59b6c 100644 --- a/src/asn1/asn1c/ROAIPAddressFamily.c +++ b/src/asn1/asn1c/ROAIPAddressFamily.c @@ -7,6 +7,131 @@ #include "asn1/asn1c/ROAIPAddressFamily.h" +#include "types/address.h" + +static json_t * +prefix2json(char *prefix, uint8_t length) +{ + json_t *root; + + root = json_object(); + if (root == NULL) + return NULL; + if (json_object_set_new(root, "prefix", json_string(prefix)) < 0) + goto fail; + if (json_object_set_new(root, "length", json_integer(length)) < 0) + goto fail; + + return root; + +fail: json_decref(root); + return NULL; +} + +static json_t * +prefix4_to_json(struct ROAIPAddress *addr) +{ + struct ipv4_prefix prefix4; + char buff[INET_ADDRSTRLEN]; + + if (prefix4_decode(&addr->address, &prefix4) != 0) + return NULL; + if (inet_ntop(AF_INET, &prefix4.addr, buff, INET_ADDRSTRLEN) == NULL) + return NULL; + + return prefix2json(buff, prefix4.len); +} + +static json_t * +prefix6_to_json(struct ROAIPAddress *addr) +{ + struct ipv6_prefix prefix6; + char buff[INET6_ADDRSTRLEN]; + + if (prefix6_decode(&addr->address, &prefix6) != 0) + return NULL; + if (inet_ntop(AF_INET6, &prefix6.addr, buff, INET6_ADDRSTRLEN) == NULL) + return NULL; + + return prefix2json(buff, prefix6.len); +} + +static json_t * +AddrBlock2json(struct ROAIPAddressFamily const *riaf, char const *ipname, + json_t *(*pref2json)(struct ROAIPAddress *)) +{ + json_t *root; + json_t *family, *addresses; + int i; + + root = json_object(); + if (root == NULL) + return NULL; + + family = json_string(ipname); + if (family == NULL) + goto fail; + if (json_object_set_new(root, "addressFamily", family) < 0) + goto fail; + + addresses = json_array(); + if (addresses == NULL) + goto fail; + if (json_object_set_new(root, "addresses", addresses) < 0) + goto fail; + + for (i = 0; i < riaf->addresses.list.count; i++) { + struct ROAIPAddress *src = riaf->addresses.list.array[i]; + json_t *prefix, *maxlen; + + prefix = pref2json(src); + if (prefix == NULL) + goto fail; + if (json_array_append(addresses, prefix)) + goto fail; + + maxlen = asn_DEF_INTEGER.op->json_encoder(&asn_DEF_INTEGER, src->maxLength); + if (maxlen == NULL) + goto fail; + if (json_object_set_new(prefix, "maxLength", maxlen)) + goto fail; + } + + return root; + +fail: json_decref(root); + return NULL; +} + +json_t * +ROAIPAddressFamily_encode_json(const asn_TYPE_descriptor_t *td, const void *sptr) +{ + struct ROAIPAddressFamily const *riaf = sptr; + OCTET_STRING_t const *af; + + if (!riaf) + return json_null(); + + af = &riaf->addressFamily; + if (af->size == 2 && af->buf[0] == 0 && af->buf[1] == 1) + return AddrBlock2json(riaf, "IPv4", prefix4_to_json); + if (af->size == 2 && af->buf[0] == 0 && af->buf[1] == 2) + return AddrBlock2json(riaf, "IPv6", prefix6_to_json); + + return SEQUENCE_encode_json(td, sptr); +} + +asn_TYPE_operation_t asn_OP_ROAIPAddressFamily = { + SEQUENCE_free, + SEQUENCE_print, + SEQUENCE_compare, + SEQUENCE_decode_ber, + SEQUENCE_encode_der, + ROAIPAddressFamily_encode_json, + SEQUENCE_encode_xer, + 0 /* Use generic outmost tag fetcher */ +}; + static int memb_addressFamily_constraint_1(const asn_TYPE_descriptor_t *td, const void *sptr, asn_app_constraint_failed_f *ctfailcb, void *app_key) { @@ -132,7 +257,7 @@ asn_SEQUENCE_specifics_t asn_SPC_ROAIPAddressFamily_specs_1 = { asn_TYPE_descriptor_t asn_DEF_ROAIPAddressFamily = { "ROAIPAddressFamily", "ROAIPAddressFamily", - &asn_OP_SEQUENCE, + &asn_OP_ROAIPAddressFamily, asn_DEF_ROAIPAddressFamily_tags_1, sizeof(asn_DEF_ROAIPAddressFamily_tags_1) /sizeof(asn_DEF_ROAIPAddressFamily_tags_1[0]), /* 1 */ diff --git a/src/asn1/asn1c/SignedAttributes.c b/src/asn1/asn1c/SignedAttributes.c index ef8f9f6c..dc33197a 100644 --- a/src/asn1/asn1c/SignedAttributes.c +++ b/src/asn1/asn1c/SignedAttributes.c @@ -7,6 +7,58 @@ #include "asn1/asn1c/SignedAttributes.h" +static json_t * +SignedAttributes_encode_json(const struct asn_TYPE_descriptor_s *td, + const void *sptr) +{ + json_t *result; + const asn_anonymous_set_ *list; + asn_TYPE_descriptor_t *type; + int i; + + if (!sptr) + return json_null(); + + result = json_object(); + if (result == NULL) + return NULL; + + list = _A_CSET_FROM_VOID(sptr); + type = &asn_DEF_CMSAttribute; + + for (i = 0; i < list->count; i++) { + CMSAttribute_t *attr; + json_t *node; + char buf[OID_STR_MAXLEN]; + char const *key; + + attr = list->array[i]; + node = type->op->json_encoder(type, attr); + if (node == NULL) + goto fail; + + key = OBJECT_IDENTIFIER_to_string(&attr->attrType, buf); + if (json_object_set_new(result, key, node) < 0) + goto fail; + } + + return result; + +fail: json_decref(result); + return NULL; +} + +asn_TYPE_operation_t asn_OP_SignedAttributes = { + SET_OF_free, + SET_OF_print, + SET_OF_compare, + SET_OF_decode_ber, + SET_OF_encode_der, + SignedAttributes_encode_json, + SET_OF_encode_xer, + 0 /* Use generic outmost tag fetcher */ +}; + asn_TYPE_member_t asn_MBR_SignedAttributes_1[] = { { ATF_POINTER, 0, 0, (ASN_TAG_CLASS_UNIVERSAL | (16 << 2)), @@ -29,7 +81,7 @@ asn_SET_OF_specifics_t asn_SPC_SignedAttributes_specs_1 = { asn_TYPE_descriptor_t asn_DEF_SignedAttributes = { "SignedAttributes", "SignedAttributes", - &asn_OP_SET_OF, + &asn_OP_SignedAttributes, asn_DEF_SignedAttributes_tags_1, sizeof(asn_DEF_SignedAttributes_tags_1) /sizeof(asn_DEF_SignedAttributes_tags_1[0]), /* 1 */ diff --git a/src/asn1/asn1c/UTCTime.c b/src/asn1/asn1c/UTCTime.c index 4e45451b..c7c9a4cc 100644 --- a/src/asn1/asn1c/UTCTime.c +++ b/src/asn1/asn1c/UTCTime.c @@ -26,6 +26,7 @@ asn_TYPE_operation_t asn_OP_UTCTime = { UTCTime_compare, OCTET_STRING_decode_ber, /* Implemented in terms of OCTET STRING */ OCTET_STRING_encode_der, /* Implemented in terms of OCTET STRING */ + UTCTime_encode_json, UTCTime_encode_xer, 0 /* Use generic outmost tag fetcher */ }; @@ -97,31 +98,48 @@ UTCTime_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, #endif /* ASN___INTERNAL_TEST_MODE */ +static int +UTCTime2str(const UTCTime_t *st, char *str) +{ + struct tm tm; + + if (asn_UT2time(st, &tm) != 0) + return -1; + + return asn_tm2str(&tm, str); +} + int UTCTime_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, - asn_app_consume_bytes_f *cb, void *app_key) { - const UTCTime_t *st = (const UTCTime_t *)sptr; + asn_app_consume_bytes_f *cb, void *app_key) +{ + const UTCTime_t *st = (const UTCTime_t *)sptr; + char buf[ASN_TM_STR_MAXLEN]; + int ret; - (void)td; /* Unused argument */ - (void)ilevel; /* Unused argument */ + if (st == NULL || st->buf == NULL) + return (cb("", 8, app_key) < 0) ? -1 : 0; - if(st && st->buf) { - char buf[32]; - struct tm tm; - int ret; + ret = UTCTime2str(st, buf); + if (ret < 0) + return (cb("", 11, app_key) < 0) ? -1 : 0; - if(asn_UT2time(st, &tm) != 0) - return (cb("", 11, app_key) < 0) ? -1 : 0; + return (cb(buf, ret, app_key) < 0) ? -1 : 0; +} - ret = snprintf(buf, sizeof(buf), - "%04d-%02d-%02d %02d:%02d:%02d (GMT)", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - assert(ret > 0 && ret < (int)sizeof(buf)); - return (cb(buf, ret, app_key) < 0) ? -1 : 0; - } else { - return (cb("", 8, app_key) < 0) ? -1 : 0; - } +json_t * +UTCTime_encode_json(const asn_TYPE_descriptor_t *td, const void *sptr) +{ + const UTCTime_t *st = (const UTCTime_t *)sptr; + char buf[ASN_TM_STR_MAXLEN]; + + if (st == NULL || st->buf == NULL) + return json_null(); + + if (UTCTime2str(st, buf) < 0) + return NULL; + + return json_string(buf); } time_t diff --git a/src/asn1/asn1c/UTCTime.h b/src/asn1/asn1c/UTCTime.h index 25f308e7..1e085cbf 100644 --- a/src/asn1/asn1c/UTCTime.h +++ b/src/asn1/asn1c/UTCTime.h @@ -17,6 +17,7 @@ extern asn_TYPE_operation_t asn_OP_UTCTime; asn_struct_print_f UTCTime_print; asn_struct_compare_f UTCTime_compare; asn_constr_check_f UTCTime_constraint; +json_type_encoder_f UTCTime_encode_json; xer_type_encoder_f UTCTime_encode_xer; #define UTCTime_free OCTET_STRING_free diff --git a/src/asn1/asn1c/asn_internal.h b/src/asn1/asn1c/asn_internal.h index 4d74313e..2bc3d9b5 100644 --- a/src/asn1/asn1c/asn_internal.h +++ b/src/asn1/asn1c/asn_internal.h @@ -21,9 +21,6 @@ int get_asn1c_environment_version(void); /* Run-time version */ #define REALLOC(oldptr, size) realloc(oldptr, size) #define FREEMEM(ptr) free(ptr) -#define asn_debug_indent 0 -#define ASN_DEBUG_INDENT_ADD(i) do{}while(0) - #ifdef EMIT_ASN_DEBUG #warning "Use ASN_EMIT_DEBUG instead of EMIT_ASN_DEBUG" #define ASN_EMIT_DEBUG EMIT_ASN_DEBUG @@ -35,33 +32,10 @@ int get_asn1c_environment_version(void); /* Run-time version */ */ #ifndef ASN_DEBUG /* If debugging code is not defined elsewhere... */ #if ASN_EMIT_DEBUG == 1 /* And it was asked to emit this code... */ -#if __STDC_VERSION__ >= 199901L -#ifdef ASN_THREAD_SAFE -/* Thread safety requires sacrifice in output indentation: - * Retain empty definition of ASN_DEBUG_INDENT_ADD. */ -#else /* !ASN_THREAD_SAFE */ -#undef ASN_DEBUG_INDENT_ADD -#undef asn_debug_indent -int asn_debug_indent; -#define ASN_DEBUG_INDENT_ADD(i) do { asn_debug_indent += i; } while(0) -#endif /* ASN_THREAD_SAFE */ -#define ASN_DEBUG(fmt, args...) do { \ - int adi = asn_debug_indent; \ - while(adi--) fprintf(stderr, " "); \ - fprintf(stderr, fmt, ##args); \ - fprintf(stderr, " (%s:%d)\n", \ - __FILE__, __LINE__); \ - } while(0) -#else /* !C99 */ void CC_PRINTFLIKE(1, 2) ASN_DEBUG_f(const char *fmt, ...); #define ASN_DEBUG ASN_DEBUG_f -#endif /* C99 */ #else /* ASN_EMIT_DEBUG != 1 */ -#if __STDC_VERSION__ >= 199901L -#define ASN_DEBUG(...) do{}while(0) -#else /* not C99 */ static void CC_PRINTFLIKE(1, 2) ASN_DEBUG(const char *fmt, ...) { (void)fmt; } -#endif /* C99 or better */ #endif /* ASN_EMIT_DEBUG */ #endif /* ASN_DEBUG */ diff --git a/src/asn1/asn1c/constr_CHOICE.c b/src/asn1/asn1c/constr_CHOICE.c index 05039e2e..df67ffa3 100644 --- a/src/asn1/asn1c/constr_CHOICE.c +++ b/src/asn1/asn1c/constr_CHOICE.c @@ -397,20 +397,16 @@ CHOICE_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, * Seek over the present member of the structure. */ elm = &td->elements[present-1]; - if(elm->flags & ATF_POINTER) { - memb_ptr = - *(const void *const *)((const char *)sptr + elm->memb_offset); - if(memb_ptr == 0) { - if(elm->optional) { - erval.encoded = 0; - ASN__ENCODED_OK(erval); - } - /* Mandatory element absent */ - ASN__ENCODE_FAILED; + + memb_ptr = get_member(sptr, elm); + if (memb_ptr == NULL) { + if(elm->optional) { + erval.encoded = 0; + ASN__ENCODED_OK(erval); } - } else { - memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); - } + /* Mandatory element absent */ + ASN__ENCODE_FAILED; + } /* * If the CHOICE itself is tagged EXPLICIT: @@ -468,17 +464,8 @@ CHOICE_outmost_tag(const asn_TYPE_descriptor_t *td, const void *ptr, int tag_mod if(present > 0 && present <= td->elements_count) { const asn_TYPE_member_t *elm = &td->elements[present-1]; - const void *memb_ptr; - if(elm->flags & ATF_POINTER) { - memb_ptr = *(const void * const *) - ((const char *)ptr + elm->memb_offset); - } else { - memb_ptr = (const void *) - ((const char *)ptr + elm->memb_offset); - } - - return asn_TYPE_outmost_tag(elm->type, memb_ptr, + return asn_TYPE_outmost_tag(elm->type, get_member(ptr, elm), elm->tag_mode, elm->tag); } else { return (ber_tlv_tag_t)-1; @@ -507,18 +494,14 @@ CHOICE_constraint(const asn_TYPE_descriptor_t *td, const void *sptr, asn_TYPE_member_t *elm = &td->elements[present-1]; const void *memb_ptr; - if(elm->flags & ATF_POINTER) { - memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); - if(!memb_ptr) { - if(elm->optional) - return 0; - ASN__CTFAIL(app_key, td, sptr, - "%s: mandatory CHOICE element %s absent (%s:%d)", - td->name, elm->name, __FILE__, __LINE__); - return -1; - } - } else { - memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + memb_ptr = get_member(sptr, elm); + if (memb_ptr == NULL) { + if(elm->optional) + return 0; + ASN__CTFAIL(app_key, td, sptr, + "%s: mandatory CHOICE element %s absent (%s:%d)", + td->name, elm->name, __FILE__, __LINE__); + return -1; } if(elm->encoding_constraints.general_constraints) { @@ -536,6 +519,33 @@ CHOICE_constraint(const asn_TYPE_descriptor_t *td, const void *sptr, } } +json_t * +CHOICE_encode_json(const asn_TYPE_descriptor_t *td, const void *sptr) +{ + const asn_CHOICE_specifics_t *specs = (const asn_CHOICE_specifics_t *)td->specifics; + unsigned present; + asn_TYPE_member_t *elm; + const void *memb_ptr; + + if (!sptr) + return json_null(); + + /* Figure out which CHOICE element is encoded. */ + present = _fetch_present_idx(sptr, specs->pres_offset, specs->pres_size); + + if (present <= 0 || td->elements_count < present) + return json_null(); + + /* Print that element. */ + elm = &td->elements[present-1]; + + memb_ptr = get_member(sptr, elm); + if (memb_ptr == NULL) + return json_null(); + + return elm->type->op->json_encoder(elm->type, memb_ptr); +} + asn_enc_rval_t CHOICE_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, enum xer_encoder_flags_e flags, asn_app_consume_bytes_f *cb, @@ -562,15 +572,11 @@ CHOICE_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, const char *mname = elm->name; unsigned int mlen = strlen(mname); - if(elm->flags & ATF_POINTER) { - memb_ptr = - *(const void *const *)((const char *)sptr + elm->memb_offset); - if(!memb_ptr) ASN__ENCODE_FAILED; - } else { - memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); - } + memb_ptr = get_member(sptr, elm); + if (!memb_ptr) + ASN__ENCODE_FAILED; - er.encoded = 0; + er.encoded = 0; if(!(flags & XER_F_CANONICAL)) ASN__TEXT_INDENT(1, ilevel); ASN__CALLBACK3("<", 1, mname, mlen, ">", 1); @@ -610,12 +616,9 @@ CHOICE_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_TYPE_member_t *elm = &td->elements[present-1]; const void *memb_ptr; - if(elm->flags & ATF_POINTER) { - memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); - if(!memb_ptr) return (cb("", 8, app_key) < 0) ? -1 : 0; - } else { - memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); - } + memb_ptr = get_member(sptr, elm); + if (!memb_ptr) + return (cb("", 8, app_key) < 0) ? -1 : 0; /* Print member's name and stuff */ if(0) { @@ -751,12 +754,7 @@ _get_member_ptr(const asn_TYPE_descriptor_t *td, const void *sptr, asn_TYPE_member_t *const elm = &td->elements[present - 1]; const void *memb_ptr; - if(elm->flags & ATF_POINTER) { - memb_ptr = - *(const void *const *)((const char *)sptr + elm->memb_offset); - } else { - memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); - } + memb_ptr = get_member(sptr, elm); *elm_ptr = elm; return memb_ptr; } else { @@ -843,6 +841,7 @@ asn_TYPE_operation_t asn_OP_CHOICE = { CHOICE_compare, CHOICE_decode_ber, CHOICE_encode_der, + CHOICE_encode_json, CHOICE_encode_xer, CHOICE_outmost_tag }; diff --git a/src/asn1/asn1c/constr_CHOICE.h b/src/asn1/asn1c/constr_CHOICE.h index f8101e8a..704a4d44 100644 --- a/src/asn1/asn1c/constr_CHOICE.h +++ b/src/asn1/asn1c/constr_CHOICE.h @@ -37,6 +37,7 @@ asn_struct_compare_f CHOICE_compare; asn_constr_check_f CHOICE_constraint; ber_type_decoder_f CHOICE_decode_ber; der_type_encoder_f CHOICE_encode_der; +json_type_encoder_f CHOICE_encode_json; xer_type_encoder_f CHOICE_encode_xer; asn_outmost_tag_f CHOICE_outmost_tag; extern asn_TYPE_operation_t asn_OP_CHOICE; diff --git a/src/asn1/asn1c/constr_SEQUENCE.c b/src/asn1/asn1c/constr_SEQUENCE.c index ce2ea37e..c4d177df 100644 --- a/src/asn1/asn1c/constr_SEQUENCE.c +++ b/src/asn1/asn1c/constr_SEQUENCE.c @@ -611,6 +611,43 @@ SEQUENCE_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, ASN__ENCODED_OK(erval); } +json_t * +SEQUENCE_encode_json(const struct asn_TYPE_descriptor_s *td, const void *sptr) +{ + json_t *parent, *child; + size_t c; + + if (!sptr) + return json_null(); + + parent = json_object(); + if (parent == NULL) + return NULL; + + for (c = 0; c < td->elements_count; c++) { + asn_TYPE_member_t *elm = &td->elements[c]; + const void *memb_ptr; + + memb_ptr = get_member(sptr, elm); + if (!memb_ptr) { + if (elm->optional) + continue; + /* Fall through */ + } + + child = elm->type->op->json_encoder(elm->type, memb_ptr); + if (child == NULL) + goto fail; + if (json_object_set_new(parent, elm->name, child)) + goto fail; + } + + return parent; + +fail: json_decref(parent); + return NULL; +} + asn_enc_rval_t SEQUENCE_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, enum xer_encoder_flags_e flags, @@ -632,9 +669,7 @@ SEQUENCE_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, const char *mname = elm->name; unsigned int mlen = strlen(mname); - if(elm->flags & ATF_POINTER) { - memb_ptr = - *(const void *const *)((const char *)sptr + elm->memb_offset); + memb_ptr = get_member(sptr, elm); if(!memb_ptr) { assert(tmp_def_val == 0); if(elm->default_value_set) { @@ -651,9 +686,6 @@ SEQUENCE_encode_xer(const asn_TYPE_descriptor_t *td, const void *sptr, ASN__ENCODE_FAILED; } } - } else { - memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); - } if(!xcan) ASN__TEXT_INDENT(1, ilevel); ASN__CALLBACK3("<", 1, mname, mlen, ">", 1); @@ -696,15 +728,12 @@ SEQUENCE_print(const asn_TYPE_descriptor_t *td, const void *sptr, int ilevel, asn_TYPE_member_t *elm = &td->elements[edx]; const void *memb_ptr; - if(elm->flags & ATF_POINTER) { - memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); - if(!memb_ptr) { - if(elm->optional) continue; - /* Print line */ - /* Fall through */ - } - } else { - memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + memb_ptr = get_member(sptr, elm); + if (!memb_ptr) { + if(elm->optional) + continue; + /* Print line */ + /* Fall through */ } /* Indentation */ @@ -790,18 +819,14 @@ SEQUENCE_constraint(const asn_TYPE_descriptor_t *td, const void *sptr, asn_TYPE_member_t *elm = &td->elements[edx]; const void *memb_ptr; - if(elm->flags & ATF_POINTER) { - memb_ptr = *(const void * const *)((const char *)sptr + elm->memb_offset); - if(!memb_ptr) { - if(elm->optional) - continue; - ASN__CTFAIL(app_key, td, sptr, - "%s: mandatory element %s absent (%s:%d)", - td->name, elm->name, __FILE__, __LINE__); - return -1; - } - } else { - memb_ptr = (const void *)((const char *)sptr + elm->memb_offset); + memb_ptr = get_member(sptr, elm); + if (!memb_ptr) { + if(elm->optional) + continue; + ASN__CTFAIL(app_key, td, sptr, + "%s: mandatory element %s absent (%s:%d)", + td->name, elm->name, __FILE__, __LINE__); + return -1; } if(elm->encoding_constraints.general_constraints) { @@ -867,6 +892,7 @@ asn_TYPE_operation_t asn_OP_SEQUENCE = { SEQUENCE_compare, SEQUENCE_decode_ber, SEQUENCE_encode_der, + SEQUENCE_encode_json, SEQUENCE_encode_xer, 0 /* Use generic outmost tag fetcher */ }; diff --git a/src/asn1/asn1c/constr_SEQUENCE.h b/src/asn1/asn1c/constr_SEQUENCE.h index e90c821d..c64142c1 100644 --- a/src/asn1/asn1c/constr_SEQUENCE.h +++ b/src/asn1/asn1c/constr_SEQUENCE.h @@ -38,6 +38,7 @@ asn_struct_compare_f SEQUENCE_compare; asn_constr_check_f SEQUENCE_constraint; ber_type_decoder_f SEQUENCE_decode_ber; der_type_encoder_f SEQUENCE_encode_der; +json_type_encoder_f SEQUENCE_encode_json; xer_type_encoder_f SEQUENCE_encode_xer; extern asn_TYPE_operation_t asn_OP_SEQUENCE; diff --git a/src/asn1/asn1c/constr_SEQUENCE_OF.c b/src/asn1/asn1c/constr_SEQUENCE_OF.c index 34d9e4ce..1e7475fa 100644 --- a/src/asn1/asn1c/constr_SEQUENCE_OF.c +++ b/src/asn1/asn1c/constr_SEQUENCE_OF.c @@ -174,6 +174,7 @@ asn_TYPE_operation_t asn_OP_SEQUENCE_OF = { SEQUENCE_OF_compare, SEQUENCE_OF_decode_ber, SEQUENCE_OF_encode_der, + SEQUENCE_OF_encode_json, SEQUENCE_OF_encode_xer, 0 /* Use generic outmost tag fetcher */ }; diff --git a/src/asn1/asn1c/constr_SEQUENCE_OF.h b/src/asn1/asn1c/constr_SEQUENCE_OF.h index fb15dd97..916f063c 100644 --- a/src/asn1/asn1c/constr_SEQUENCE_OF.h +++ b/src/asn1/asn1c/constr_SEQUENCE_OF.h @@ -21,5 +21,6 @@ extern asn_TYPE_operation_t asn_OP_SEQUENCE_OF; #define SEQUENCE_OF_print SET_OF_print #define SEQUENCE_OF_constraint SET_OF_constraint #define SEQUENCE_OF_decode_ber SET_OF_decode_ber +#define SEQUENCE_OF_encode_json SET_OF_encode_json #endif /* _CONSTR_SET_OF_H_ */ diff --git a/src/asn1/asn1c/constr_SET_OF.c b/src/asn1/asn1c/constr_SET_OF.c index ef4b3fee..e2162e13 100644 --- a/src/asn1/asn1c/constr_SET_OF.c +++ b/src/asn1/asn1c/constr_SET_OF.c @@ -489,6 +489,38 @@ SET_OF_encode_der(const asn_TYPE_descriptor_t *td, const void *sptr, } } +json_t * +SET_OF_encode_json(const struct asn_TYPE_descriptor_s *td, const void *sptr) +{ + json_t *result; + const asn_anonymous_set_ *list; + asn_TYPE_descriptor_t *type; + int i; + + if (!sptr) + return json_null(); + + result = json_array(); + if (result == NULL) + return NULL; + + list = _A_CSET_FROM_VOID(sptr); + type = td->elements->type; + + for (i = 0; i < list->count; i++) { + json_t *node = type->op->json_encoder(type, list->array[i]); + if (node == NULL) + goto fail; + if (json_array_append_new(result, node) < 0) + goto fail; + } + + return result; + +fail: json_decref(result); + return NULL; +} + typedef struct xer_tmp_enc_s { void *buffer; size_t offset; @@ -821,6 +853,7 @@ asn_TYPE_operation_t asn_OP_SET_OF = { SET_OF_compare, SET_OF_decode_ber, SET_OF_encode_der, + SET_OF_encode_json, SET_OF_encode_xer, 0 /* Use generic outmost tag fetcher */ }; diff --git a/src/asn1/asn1c/constr_SET_OF.h b/src/asn1/asn1c/constr_SET_OF.h index ee09914e..3d77f381 100644 --- a/src/asn1/asn1c/constr_SET_OF.h +++ b/src/asn1/asn1c/constr_SET_OF.h @@ -27,6 +27,7 @@ asn_struct_compare_f SET_OF_compare; asn_constr_check_f SET_OF_constraint; ber_type_decoder_f SET_OF_decode_ber; der_type_encoder_f SET_OF_encode_der; +json_type_encoder_f SET_OF_encode_json; xer_type_encoder_f SET_OF_encode_xer; extern asn_TYPE_operation_t asn_OP_SET_OF; diff --git a/src/asn1/asn1c/constr_TYPE.c b/src/asn1/asn1c/constr_TYPE.c index 02597a2e..602b2631 100644 --- a/src/asn1/asn1c/constr_TYPE.c +++ b/src/asn1/asn1c/constr_TYPE.c @@ -75,7 +75,16 @@ void ASN_DEBUG_f(const char *fmt, ...); void ASN_DEBUG_f(const char *fmt, ...) { va_list ap; va_start(ap, fmt); + fprintf(stderr, "\x1B[32m"); vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); + fprintf(stderr, "\x1B[0m\n"); va_end(ap); } + +void const * +get_member(const void *sptr, asn_TYPE_member_t const *elm) +{ + return (elm->flags & ATF_POINTER) + ? (*(const void * const *)((const char *)sptr + elm->memb_offset)) + : ((const void *)((const char *)sptr + elm->memb_offset)); +} diff --git a/src/asn1/asn1c/constr_TYPE.h b/src/asn1/asn1c/constr_TYPE.h index e1d9c982..758e6312 100644 --- a/src/asn1/asn1c/constr_TYPE.h +++ b/src/asn1/asn1c/constr_TYPE.h @@ -33,6 +33,7 @@ typedef struct asn_struct_ctx_s { #include "asn1/asn1c/ber_decoder.h" /* Basic Encoding Rules decoder */ #include "asn1/asn1c/der_encoder.h" /* Distinguished Encoding Rules encoder */ #include "asn1/asn1c/xer_encoder.h" /* Encoder into XER (XML, text) */ +#include "asn1/asn1c/json_encoder.h" /* Encoder into JSON */ #include "asn1/asn1c/constraints.h" /* Subtype constraints support */ /* @@ -130,6 +131,7 @@ typedef struct asn_TYPE_operation_s { asn_struct_compare_f *compare_struct; /* Compare two structures */ ber_type_decoder_f *ber_decoder; /* Generic BER decoder */ der_type_encoder_f *der_encoder; /* Canonical DER encoder */ + json_type_encoder_f *json_encoder; xer_type_encoder_f *xer_encoder; /* [Canonical] XER encoder */ asn_outmost_tag_f *outmost_tag; /* */ } asn_TYPE_operation_t; @@ -227,4 +229,6 @@ int asn_fprint(FILE *stream, /* Destination stream descriptor */ const asn_TYPE_descriptor_t *td, /* ASN.1 type descriptor */ const void *struct_ptr); /* Structure to be printed */ +void const *get_member(const void *sptr, asn_TYPE_member_t const *elm); + #endif /* _CONSTR_TYPE_H_ */ diff --git a/src/asn1/asn1c/json_encoder.c b/src/asn1/asn1c/json_encoder.c new file mode 100644 index 00000000..c7e7e2bd --- /dev/null +++ b/src/asn1/asn1c/json_encoder.c @@ -0,0 +1,14 @@ +#include "asn1/asn1c/json_encoder.h" + +#include "asn1/asn1c/asn_internal.h" + +json_t * +json_encode(const asn_TYPE_descriptor_t *td, const void *sptr) +{ + if (!td || !sptr) { + ASN_DEBUG("Failed to encode element %s", td ? td->name : ""); + return NULL; + } + + return td->op->json_encoder(td, sptr); +} diff --git a/src/asn1/asn1c/json_encoder.h b/src/asn1/asn1c/json_encoder.h new file mode 100644 index 00000000..0ecd83fe --- /dev/null +++ b/src/asn1/asn1c/json_encoder.h @@ -0,0 +1,21 @@ +#ifndef SRC_ASN1_ASN1C_JSON_ENCODER_H_ +#define SRC_ASN1_ASN1C_JSON_ENCODER_H_ + +#include + +struct asn_TYPE_descriptor_s; /* Forward declaration */ + +json_t *json_encode( + const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr /* Structure to be encoded */ +); + +/* + * Type of the generic JSON encoder. + */ +typedef json_t *(json_type_encoder_f)( + const struct asn_TYPE_descriptor_s *type_descriptor, + const void *struct_ptr /* Structure to be encoded */ +); + +#endif /* SRC_ASN1_ASN1C_JSON_ENCODER_H_ */ diff --git a/src/asn1/content_info.c b/src/asn1/content_info.c index 1e3e489f..1aacb793 100644 --- a/src/asn1/content_info.c +++ b/src/asn1/content_info.c @@ -49,12 +49,12 @@ decode(struct file_contents *fc, struct ContentInfo **result) } int -content_info_load(struct rpki_uri *uri, struct ContentInfo **result) +content_info_load(char const *file, struct ContentInfo **result) { struct file_contents fc; int error; - error = file_load(uri_get_local(uri), &fc); + error = file_load(file, &fc); if (error) return error; diff --git a/src/asn1/content_info.h b/src/asn1/content_info.h index 862510bd..89d7e722 100644 --- a/src/asn1/content_info.h +++ b/src/asn1/content_info.h @@ -3,10 +3,9 @@ /* Some wrappers for asn1/asn1c/ContentInfo.h. */ -#include "types/uri.h" #include "asn1/asn1c/ContentInfo.h" -int content_info_load(struct rpki_uri *, struct ContentInfo **); +int content_info_load(char const *, struct ContentInfo **); void content_info_free(struct ContentInfo *); #endif /* SRC_CONTENT_INFO_H_ */ diff --git a/src/config.c b/src/config.c index de54d908..224596d2 100644 --- a/src/config.c +++ b/src/config.c @@ -43,7 +43,7 @@ struct rpki_config { unsigned int maximum_certificate_depth; /** File or directory where the .slurm file(s) is(are) located */ char *slurm; - /* Run as RTR server or standalone validation */ + /* */ enum mode mode; /* * Disable outgoing requests (currently rsync and http supported), if @@ -192,6 +192,8 @@ struct rpki_config { unsigned int max; /* Deprecated */ } validation; } thread_pool; + + char *payload; }; static void print_usage(FILE *, bool); @@ -988,6 +990,15 @@ valid_output_file(char const *path) static int validate_config(void) { + if (rpki_config.mode == PRINT_FILE) + return (rpki_config.payload == NULL) + ? pr_op_err("Missing file name.") + : 0; + + if (rpki_config.payload != NULL) + return pr_op_err("I don't know what '%s' is.", + rpki_config.payload); + if (rpki_config.tal == NULL) return pr_op_err("The TAL(s) location (--tal) is mandatory."); @@ -1098,14 +1109,8 @@ handle_flags_config(int argc, char **argv) goto end; } - /* - * This triggers when the user runs something like `fort help` instead - * of `fort --help`. This program does not have unflagged payload. - */ - if (optind < argc) { - error = pr_op_err("I don't know what '%s' is.", argv[optind]); - goto end; - } + if (optind < argc) + rpki_config.payload = pstrdup(argv[optind]); error = validate_config(); if (error) @@ -1453,6 +1458,12 @@ config_get_thread_pool_server_max(void) return rpki_config.thread_pool.server.max; } +char const * +config_get_payload(void) +{ + return rpki_config.payload; +} + void config_set_rsync_enabled(bool value) { @@ -1473,4 +1484,5 @@ free_rpki_config(void) FOREACH_OPTION(options, option, 0xFFFF) if (is_rpki_config_field(option) && option->type->free != NULL) option->type->free(get_rpki_config_field(option)); + free(rpki_config.payload); } diff --git a/src/config.h b/src/config.h index 8f973814..18cfa23f 100644 --- a/src/config.h +++ b/src/config.h @@ -55,6 +55,7 @@ char const *config_get_output_bgpsec(void); enum output_format config_get_output_format(void); unsigned int config_get_asn1_decode_max_stack(void); unsigned int config_get_thread_pool_server_max(void); +char const *config_get_payload(void); /* Logging getters */ bool config_get_op_log_enabled(void); diff --git a/src/config/mode.c b/src/config/mode.c index c0eb3f4e..12d379fb 100644 --- a/src/config/mode.c +++ b/src/config/mode.c @@ -7,6 +7,7 @@ #define VALUE_SERVER "server" #define VALUE_STANDALONE "standalone" +#define VALUE_PRINT_FILE "print" #define DEREFERENCE(void_value) (*((enum mode *) void_value)) @@ -22,6 +23,9 @@ print_mode(struct option_field const *field, void *value) case STANDALONE: str = VALUE_STANDALONE; break; + case PRINT_FILE: + str = VALUE_PRINT_FILE; + break; } pr_op_info("%s: %s", field->name, str); @@ -35,6 +39,8 @@ parse_argv_mode(struct option_field const *field, char const *str, DEREFERENCE(result) = SERVER; else if (strcmp(str, VALUE_STANDALONE) == 0) DEREFERENCE(result) = STANDALONE; + else if (strcmp(str, VALUE_PRINT_FILE) == 0) + DEREFERENCE(result) = PRINT_FILE; else return pr_op_err("Unknown mode: '%s'", str); @@ -58,5 +64,5 @@ const struct global_type gt_mode = { .print = print_mode, .parse.argv = parse_argv_mode, .parse.json = parse_json_mode, - .arg_doc = VALUE_SERVER "|" VALUE_STANDALONE, + .arg_doc = VALUE_SERVER "|" VALUE_STANDALONE "|" VALUE_PRINT_FILE, }; diff --git a/src/config/mode.h b/src/config/mode.h index 2cfd6ef7..7dc3720a 100644 --- a/src/config/mode.h +++ b/src/config/mode.h @@ -7,14 +7,12 @@ * FORT Run mode */ enum mode { - /** - * Run as an RTR server - */ + /* Run as RTR server */ SERVER, - /* - * Run standalone validation (run validation once and exit) - */ + /* Run standalone validation (run validation once and exit) */ STANDALONE, + /* Print file in standard output */ + PRINT_FILE, }; extern const struct global_type gt_mode; diff --git a/src/main.c b/src/main.c index 62ac29de..1f88bd14 100644 --- a/src/main.c +++ b/src/main.c @@ -7,6 +7,7 @@ #include "thread_var.h" #include "http/http.h" #include "incidence/incidence.h" +#include "print_file.h" #include "rtr/rtr.h" #include "rtr/db/vrps.h" #include "xml/relax_ng.h" @@ -169,6 +170,9 @@ main(int argc, char **argv) case SERVER: error = fort_server(); break; + case PRINT_FILE: + error = print_file(); + break; } /* End */ diff --git a/src/object/signed_object.c b/src/object/signed_object.c index a5b6667e..5f00e538 100644 --- a/src/object/signed_object.c +++ b/src/object/signed_object.c @@ -8,7 +8,7 @@ signed_object_decode(struct signed_object *sobj, struct rpki_uri *uri) { int error; - error = content_info_load(uri, &sobj->cinfo); + error = content_info_load(uri_get_local(uri), &sobj->cinfo); if (error) return error; diff --git a/src/print_file.c b/src/print_file.c new file mode 100644 index 00000000..4999e832 --- /dev/null +++ b/src/print_file.c @@ -0,0 +1,43 @@ +#include "print_file.h" + +#include +#include "config.h" +#include "log.h" +#include "asn1/content_info.h" + +int +print_file(void) +{ + char const *filename; + struct ContentInfo *ci; + json_t *json; + int error; + + filename = config_get_payload(); +// if (str_starts_with(filename, "rsync://")) { +// +// } else { + error = content_info_load(filename, &ci); + if (error) + return error; +// } + + json = json_encode(&asn_DEF_ContentInfo, ci); + if (json == NULL) { + pr_op_err("Error parsing object."); + goto end; + } + + errno = 0; + if (json_dumpf(json, stdout, JSON_INDENT(4)) < 0) { + error = errno; + if (error) + pr_op_err("Error writing JSON to file: %s", strerror(error)); + else + pr_op_err("Unknown error writing JSON to file."); + } + + json_decref(json); +end: ASN_STRUCT_FREE(asn_DEF_ContentInfo, ci); + return error; +} diff --git a/src/print_file.h b/src/print_file.h new file mode 100644 index 00000000..571f631a --- /dev/null +++ b/src/print_file.h @@ -0,0 +1,6 @@ +#ifndef SRC_PRINT_FILE_H_ +#define SRC_PRINT_FILE_H_ + +int print_file(void); + +#endif /* SRC_PRINT_FILE_H_ */