From: Alberto Leiva Popper Date: Wed, 8 May 2024 16:48:09 +0000 (-0600) Subject: Add sequence BIO X-Git-Tag: 1.6.2~26 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=501a1481eacdbace7bd1d347ba6428f5175fc6f5;p=thirdparty%2FFORT-validator.git Add sequence BIO It's a BIO that concatenates two other BIOs when reading. Needed so the file parser can read the file header twice, without using rewind(3). (Which can't be used while piping, as it turns out.) This allows printing a subfile from a delta or snapshot: $ xmlstarlet sel -t -v "//_:publish[2]" delta.xml | base64 --decode | fort --mode=print --- diff --git a/src/Makefile.am b/src/Makefile.am index 8c0aa1fb..987acb4b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -40,6 +40,7 @@ fort_SOURCES += asn1/oid.h asn1/oid.c fort_SOURCES += asn1/signed_data.h asn1/signed_data.c fort_SOURCES += types/address.h types/address.c +fort_SOURCES += types/bio_seq.c types/bio_seq.h fort_SOURCES += types/delta.c types/delta.h fort_SOURCES += types/router_key.c types/router_key.h fort_SOURCES += types/serial.h types/serial.c diff --git a/src/asn1/asn1c/CRL.c b/src/asn1/asn1c/CRL.c index f84ac734..e0c3a055 100644 --- a/src/asn1/asn1c/CRL.c +++ b/src/asn1/asn1c/CRL.c @@ -108,12 +108,12 @@ fail: json_decref(root); } json_t * -CRL_file2json(FILE *file) +CRL_bio2json(BIO *bio) { X509_CRL *crl; json_t *root; - crl = d2i_X509_CRL_fp(file, NULL); + crl = d2i_X509_CRL_bio(bio, NULL); if (crl == NULL) return NULL; diff --git a/src/asn1/asn1c/CRL.h b/src/asn1/asn1c/CRL.h index c49c8b8c..7f7c7d23 100644 --- a/src/asn1/asn1c/CRL.h +++ b/src/asn1/asn1c/CRL.h @@ -1,9 +1,9 @@ #ifndef SRC_ASN1_ASN1C_CRL_H_ #define SRC_ASN1_ASN1C_CRL_H_ -#include #include +#include -json_t *CRL_file2json(FILE *); +json_t *CRL_bio2json(BIO *bio); #endif /* SRC_ASN1_ASN1C_CRL_H_ */ diff --git a/src/asn1/asn1c/Certificate.c b/src/asn1/asn1c/Certificate.c index 0defcac8..571f487d 100644 --- a/src/asn1/asn1c/Certificate.c +++ b/src/asn1/asn1c/Certificate.c @@ -190,12 +190,12 @@ Certificate_any2json(ANY_t *ber) } json_t * -Certificate_file2json(FILE *file) +Certificate_bio2json(BIO *bio) { X509 *cert; json_t *root; - cert = d2i_X509_fp(file, NULL); + cert = d2i_X509_bio(bio, NULL); if (cert == NULL) return NULL; diff --git a/src/asn1/asn1c/Certificate.h b/src/asn1/asn1c/Certificate.h index 6400f31a..1eeac081 100644 --- a/src/asn1/asn1c/Certificate.h +++ b/src/asn1/asn1c/Certificate.h @@ -1,11 +1,11 @@ #ifndef SRC_ASN1_ASN1C_CERTIFICATE_H_ #define SRC_ASN1_ASN1C_CERTIFICATE_H_ -#include #include +#include #include "asn1/asn1c/ANY.h" json_t *Certificate_any2json(ANY_t *); -json_t *Certificate_file2json(FILE *); +json_t *Certificate_bio2json(BIO *); #endif /* SRC_ASN1_ASN1C_CERTIFICATE_H_ */ diff --git a/src/asn1/asn1c/ROAIPAddressFamily.c b/src/asn1/asn1c/ROAIPAddressFamily.c index 3b78b14f..c62ae1e0 100644 --- a/src/asn1/asn1c/ROAIPAddressFamily.c +++ b/src/asn1/asn1c/ROAIPAddressFamily.c @@ -61,23 +61,16 @@ AddrBlock2json(struct ROAIPAddressFamily const *riaf, char const *ipname, json_t *(*pref2json)(struct ROAIPAddress *)) { json_t *root; - json_t *family, *addresses; + json_t *addrs; int i; root = json_object(); if (root == NULL) return NULL; - family = json_string(ipname); - if (family == NULL) + if (json_object_set_new(root, "addressFamily", json_string(ipname)) < 0) 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) + if (json_object_set_new(root, "addresses", addrs = json_array()) < 0) goto fail; for (i = 0; i < riaf->addresses.list.count; i++) { @@ -85,14 +78,10 @@ AddrBlock2json(struct ROAIPAddressFamily const *riaf, char const *ipname, json_t *prefix, *maxlen; prefix = pref2json(src); - if (prefix == NULL) - goto fail; - if (json_array_append_new(addresses, prefix)) + if (json_array_append_new(addrs, 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; } diff --git a/src/print_file.c b/src/print_file.c index 7bb4572c..c5d92e61 100644 --- a/src/print_file.c +++ b/src/print_file.c @@ -8,6 +8,7 @@ #include "asn1/content_info.h" #include "asn1/asn1c/Certificate.h" #include "asn1/asn1c/CRL.h" +#include "types/bio_seq.h" #define HDRSIZE 32 @@ -31,34 +32,33 @@ skip_integer(unsigned char *buf, unsigned char *cursor) ssize_t len_len; len_len = ber_fetch_length(0, cursor, HDRSIZE - (cursor - buf), &len); - if (len_len <= 0) { - pr_op_debug("aoe"); + if (len_len <= 0) return NULL; - } cursor += len_len + len; return (cursor <= (buf + HDRSIZE)) ? cursor : NULL; } static int -guess_file_type(FILE *file) +guess_file_type(BIO **bio, unsigned char *hdrbuf) { - unsigned char buf[HDRSIZE]; unsigned char *ptr; + size_t consumed; if (config_get_file_type() != FT_UNK) return config_get_file_type(); - if (fread(buf, 1, HDRSIZE, file) != HDRSIZE) { - pr_op_debug("File is too small or generic IO error."); - return FT_UNK; - } - rewind(file); + if (!BIO_read_ex(*bio, hdrbuf, HDRSIZE, &consumed)) + return op_crypto_err("Cannot guess file type; IO error."); + + *bio = BIO_new_seq(BIO_new_mem_buf(hdrbuf, consumed), *bio); + if ((*bio) == NULL) + return op_crypto_err("BIO_new_seq() returned NULL."); - if (buf[0] != 0x30) { + if (hdrbuf[0] != 0x30) { pr_op_debug("File doesn't start with a SEQUENCE."); return FT_UNK; } - ptr = skip_sequence(buf, buf + 1); + ptr = skip_sequence(hdrbuf, hdrbuf + 1); if (ptr == NULL) { pr_op_debug("Cannot skip first sequence length."); return FT_UNK; @@ -73,12 +73,12 @@ guess_file_type(FILE *file) return FT_UNK; } - ptr = skip_sequence(buf, ptr + 1); + ptr = skip_sequence(hdrbuf, ptr + 1); if (ptr == NULL) { pr_op_debug("Cannot skip second sequence length."); return FT_UNK; } - ptr = skip_integer(buf, ptr + 1); + ptr = skip_integer(hdrbuf, ptr + 1); if (ptr == NULL) { pr_op_debug("Cannot skip version number."); return FT_UNK; @@ -98,44 +98,37 @@ guess_file_type(FILE *file) } static struct ContentInfo * -file2ci(FILE *file) +bio2ci(BIO *bio) { -#define BUFFER_SIZE 1024 +#define BUFFER_SIZE 4096 struct ContentInfo *ci = NULL; unsigned char buffer[BUFFER_SIZE]; size_t consumed; - bool eof; +// bool eof; asn_dec_rval_t res; - eof = false; +// eof = false; do { - consumed = fread(buffer, 1, BUFFER_SIZE, file); - if (consumed < BUFFER_SIZE) { - if (feof(file)) { - eof = true; - } else if (ferror(file)) { - pr_op_err("ferror."); - return NULL; - } else { - pr_op_err("?"); - return NULL; - } + if (!BIO_read_ex(bio, buffer, BUFFER_SIZE, &consumed)) { + op_crypto_err("IO error."); + return NULL; } - res = ber_decode(NULL, &asn_DEF_ContentInfo, (void **)&ci, buffer, consumed); + res = ber_decode(NULL, &asn_DEF_ContentInfo, (void **)&ci, + buffer, consumed); pr_op_debug("Consumed: %zu", res.consumed); switch (res.code) { case RC_OK: - if (!eof) - pr_op_warn("File has trailing bytes."); +// if (!buf->eof) +// pr_op_warn("File has trailing bytes."); return ci; case RC_WMORE: - if (eof) { - pr_op_err("File ended prematurely."); - return NULL; - } +// if (buf->eof) { +// pr_op_err("File ended prematurely."); +// return NULL; +// } break; case RC_FAIL: @@ -146,12 +139,12 @@ file2ci(FILE *file) } static json_t * -asn1c2json(FILE *file) +asn1c2json(BIO *bio) { struct ContentInfo *ci; json_t *json; - ci = file2ci(file); + ci = bio2ci(bio); if (ci == NULL) return NULL; @@ -161,43 +154,41 @@ asn1c2json(FILE *file) return json; } -int -print_file(void) +static int +__print_file(void) { - char const *filename = config_get_payload(); - FILE *file; + char const *filename; + BIO *bio; + unsigned char hdrbuf[HDRSIZE]; json_t *json = NULL; - int error = 0; + int error; - if (filename == NULL || strcmp(filename, "-") == 0) { - file = stdin; - } else { - file = fopen(filename, "rb"); - if (file == NULL) - return pr_op_err("Cannot open file: %s", strerror(errno)); - } + filename = config_get_payload(); + bio = (filename == NULL || strcmp(filename, "-") == 0) + ? BIO_new_fp(stdin, BIO_NOCLOSE) + : BIO_new_file(filename, "rb"); + if (bio == NULL) + return pr_op_err("BIO_new_*() returned NULL."); - switch (guess_file_type(file)) { + switch (guess_file_type(&bio, hdrbuf)) { case FT_UNK: - error = pr_op_err("Unrecognized file type."); - break; + BIO_free_all(bio); + return pr_op_err("Unrecognized file type."); + case FT_ROA: case FT_MFT: case FT_GBR: - json = asn1c2json(file); + json = asn1c2json(bio); break; case FT_CER: - json = Certificate_file2json(file); + json = Certificate_bio2json(bio); break; case FT_CRL: - json = CRL_file2json(file); + json = CRL_bio2json(bio); break; } - if (file != stdin) - fclose(file); - if (error) - return error; + BIO_free_all(bio); if (json == NULL) return pr_op_err("Unable to parse."); @@ -208,11 +199,27 @@ print_file(void) pr_op_err("Error writing JSON to file: %s", strerror(error)); else pr_op_err("Unknown error writing JSON to file."); - goto end; + + } else { + error = 0; + printf("\n"); } - error = 0; - printf("\n"); -end: json_decref(json); + json_decref(json); + return error; +} + +int +print_file(void) +{ + int error; + + error = bioseq_setup(); + if (error) + return error; + + error = __print_file(); + + bioseq_teardown(); return error; } diff --git a/src/types/bio_seq.c b/src/types/bio_seq.c new file mode 100644 index 00000000..c11c377e --- /dev/null +++ b/src/types/bio_seq.c @@ -0,0 +1,99 @@ +#include "types/bio_seq.h" + +#include "log.h" +#include "alloc.h" + +static BIO_METHOD *method; + +struct bioseq_priv { + BIO *prefix; + BIO *suffix; +}; + +static int +bioseq_read_ex(BIO *bio, char *data, size_t len, size_t *consumed) +{ + struct bioseq_priv *priv = BIO_get_data(bio); + int res; + + if (priv->prefix != NULL) { + res = BIO_read_ex(priv->prefix, data, len, consumed); + if (res == 1 && BIO_eof(priv->prefix)) { + BIO_free_all(priv->prefix); + priv->prefix = NULL; + } + return res; + } + + return BIO_read_ex(priv->suffix, data, len, consumed); +} + +static int +bioseq_destroy(BIO *bio) +{ + struct bioseq_priv *priv; + + if (bio == NULL) + return 0; + + priv = BIO_get_data(bio); + BIO_free(priv->prefix); + BIO_free(priv->suffix); + free(priv); + + BIO_set_data(bio, NULL); + BIO_set_init(bio, 0); + + return 1; +} + +int +bioseq_setup(void) +{ + int type; + + type = BIO_get_new_index(); + if (type == -1) + return op_crypto_err("BIO_get_new_index() returned -1."); + + method = BIO_meth_new(type | BIO_TYPE_FILTER, "seq"); + if (method == NULL) + return op_crypto_err("BIO_meth_new() returned NULL."); + + if (!BIO_meth_set_read_ex(method, bioseq_read_ex) || + !BIO_meth_set_destroy(method, bioseq_destroy)) { + BIO_meth_free(method); + method = NULL; + return op_crypto_err("BIO_meth_set_*() returned 0."); + } + + return 0; +} + +void +bioseq_teardown(void) +{ + BIO_meth_free(method); +} + +BIO * +BIO_new_seq(BIO *prefix, BIO *suffix) +{ + BIO *bio; + struct bioseq_priv *priv; + + if (prefix == NULL || suffix == NULL) + return NULL; + + bio = BIO_new(method); + if (bio == NULL) + return NULL; + + priv = pmalloc(sizeof(struct bioseq_priv)); + priv->prefix = prefix; + priv->suffix = suffix; + + BIO_set_data(bio, priv); + BIO_set_init(bio, 1); + return bio; +} diff --git a/src/types/bio_seq.h b/src/types/bio_seq.h new file mode 100644 index 00000000..ad3ba819 --- /dev/null +++ b/src/types/bio_seq.h @@ -0,0 +1,11 @@ +#ifndef TEST_TYPES_BIO_SEQ_H_ +#define TEST_TYPES_BIO_SEQ_H_ + +#include + +int bioseq_setup(void); +void bioseq_teardown(void); + +BIO *BIO_new_seq(BIO *, BIO *); + +#endif /* TEST_TYPES_BIO_SEQ_H_ */