diff options
author | Petr Štetiar <ynezz@true.cz> | 2019-12-09 15:28:25 +0300 |
---|---|---|
committer | Petr Štetiar <ynezz@true.cz> | 2019-12-25 12:31:58 +0300 |
commit | 09ee90f8d6ed1ff997a555aae8ee44ac3e20b317 (patch) | |
tree | 4945e2fa599b4d67b9f774ba043795891a150164 /tests/test-blob-parse.c | |
parent | 436d6363a10bbb41ab92602b4eb0030992bb1785 (diff) |
tests: add test cases for blob parsing
Increasing test coverage.
Signed-off-by: Petr Štetiar <ynezz@true.cz>
Diffstat (limited to 'tests/test-blob-parse.c')
-rw-r--r-- | tests/test-blob-parse.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/tests/test-blob-parse.c b/tests/test-blob-parse.c new file mode 100644 index 0000000..6b1fb56 --- /dev/null +++ b/tests/test-blob-parse.c @@ -0,0 +1,175 @@ +/* + * Based on certificate dump functionality from ucert.c: + * + * Copyright (C) 2018 Daniel Golle <daniel@makrotopia.org> + * SPDX-License-Identifier: GPL-3.0 + * + */ + +#include <stdio.h> +#include <stdint.h> +#include <stddef.h> +#include <libgen.h> + +#include "blob.h" +#include "list.h" +#include "blobmsg_json.h" + +#define CERT_BUF_LEN 4096 + +/* + * ucert structure + * | BLOB | + * | SIGNATURE | PAYLOAD | + * | |[ BLOBMSG CONTAINER ]| + * | |[[T,i,v,e,f,pubkey ]]| + */ +enum cert_attr { + CERT_ATTR_SIGNATURE, + CERT_ATTR_PAYLOAD, + CERT_ATTR_MAX +}; + +static const struct blob_attr_info cert_policy[CERT_ATTR_MAX] = { + [CERT_ATTR_SIGNATURE] = { .type = BLOB_ATTR_BINARY }, + [CERT_ATTR_PAYLOAD] = { .type = BLOB_ATTR_NESTED }, +}; + +enum cert_cont_attr { + CERT_CT_ATTR_PAYLOAD, + CERT_CT_ATTR_MAX +}; + +enum cert_payload_attr { + CERT_PL_ATTR_CERTTYPE, + CERT_PL_ATTR_CERTID, + CERT_PL_ATTR_VALIDFROMTIME, + CERT_PL_ATTR_EXPIRETIME, + CERT_PL_ATTR_PUBKEY, + CERT_PL_ATTR_KEY_FINGERPRINT, + CERT_PL_ATTR_MAX +}; + +enum certtype_id { + CERTTYPE_UNSPEC, + CERTTYPE_AUTH, + CERTTYPE_REVOKE +}; + +/* list to store certificate chain at runtime */ +struct cert_object { + struct list_head list; + struct blob_attr *cert[CERT_ATTR_MAX]; +}; + +static int cert_load(const char *certfile, struct list_head *chain) +{ + FILE *f; + struct blob_attr *certtb[CERT_ATTR_MAX]; + struct blob_attr *bufpt; + struct cert_object *cobj; + char filebuf[CERT_BUF_LEN]; + int ret = 0, pret = 0; + size_t len, pos = 0; + + f = fopen(certfile, "r"); + if (!f) + return 1; + + len = fread(&filebuf, 1, CERT_BUF_LEN - 1, f); + if (len < 64) + return 1; + + ret = ferror(f) || !feof(f); + fclose(f); + if (ret) + return 1; + + bufpt = (struct blob_attr *)filebuf; + do { + pret = blob_parse(bufpt, certtb, cert_policy, CERT_ATTR_MAX); + if (pret <= 0) + /* no attributes found */ + break; + + if (pos + blob_pad_len(bufpt) > len) + /* blob exceeds filebuffer */ + break; + else + pos += blob_pad_len(bufpt); + + if (!certtb[CERT_ATTR_SIGNATURE]) + /* no signature -> drop */ + break; + + cobj = calloc(1, sizeof(*cobj)); + cobj->cert[CERT_ATTR_SIGNATURE] = blob_memdup(certtb[CERT_ATTR_SIGNATURE]); + if (certtb[CERT_ATTR_PAYLOAD]) + cobj->cert[CERT_ATTR_PAYLOAD] = blob_memdup(certtb[CERT_ATTR_PAYLOAD]); + + list_add_tail(&cobj->list, chain); + ret += pret; + /* repeat parsing while there is still enough remaining data in buffer */ + } while(len > pos + sizeof(struct blob_attr) && (bufpt = blob_next(bufpt))); + + return (ret <= 0); +} + +/* dump single chain element to console */ +static void cert_dump_blob(struct blob_attr *cert[CERT_ATTR_MAX]) +{ + int i; + char *json = NULL; + + for (i = 0; i < CERT_ATTR_MAX; i++) { + struct blob_attr *v = cert[i]; + + if (!v) + continue; + + switch(cert_policy[i].type) { + case BLOB_ATTR_BINARY: + fprintf(stdout, "signature:\n---\n%s---\n", (char *) blob_data(v)); + break; + case BLOB_ATTR_NESTED: + json = blobmsg_format_json_indent(blob_data(v), false, 0); + if (!json) + continue; + + fprintf(stdout, "payload:\n---\n%s\n---\n", json); + free(json); + break; + } + } +} + +static int cert_dump(const char *certfile) +{ + struct cert_object *cobj; + static LIST_HEAD(certchain); + unsigned int count = 0; + + if (cert_load(certfile, &certchain)) { + fprintf(stderr, "cannot parse cert %s\n", basename((char *) certfile)); + return 1; + } + + list_for_each_entry(cobj, &certchain, list) { + fprintf(stdout, "=== CHAIN ELEMENT %02u ===\n", ++count); + cert_dump_blob(cobj->cert); + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + if (argc != 2) { + fprintf(stderr, "Usage: %s <cert.ucert>\n", argv[0]); + return 3; + } + + cert_dump(argv[1]); + + return 0; +} |