X-Git-Url: http://git.openwrt.org/?p=project%2Fucert.git;a=blobdiff_plain;f=ucert.c;h=5523b02a7eb2b977ce4c28bfd3b4c082845d6513;hp=b9c5c889ddfad04fb81ab4cb882c45160355b10e;hb=HEAD;hpb=9dba44ddd4f5453d36e85a976dae567d8544d197 diff --git a/ucert.c b/ucert.c index b9c5c88..5523b02 100644 --- a/ucert.c +++ b/ucert.c @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -48,10 +49,10 @@ static enum { static bool quiet; #ifndef UCERT_STRIP_MESSAGES -#define DPRINTF(format, ...) \ - do { \ - if (!quiet) \ - fprintf(stderr, "%s(%d): " format, __func__, __LINE__, ## __VA_ARGS__); \ +#define DPRINTF(format, ...) \ + do { \ + if (!quiet) \ + fprintf(stderr, "%s: " format, __func__, ## __VA_ARGS__); \ } while (0) #else #define DPRINTF(format, ...) do { } while (0) @@ -116,54 +117,75 @@ struct cert_object { }; /* write buffer to file */ -static int write_file(const char *filename, void *buf, size_t len, bool append) { +static bool write_file(const char *filename, void *buf, size_t len, bool append) { FILE *f; size_t outlen; f = fopen(filename, append?"a":"w"); if (!f) - return 1; + return false; outlen = fwrite(buf, 1, len, f); fclose(f); return (outlen == len); } -/* load certfile into list */ -static int cert_load(const char *certfile, struct list_head *chain) { +/* reads a whole file to a buffer - returns -1 on errors and sets errno */ +static ssize_t read_file(const char *filename, void *buf, size_t len, size_t minlen) { 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; + ssize_t ret; - f = fopen(certfile, "r"); + f = fopen(filename, "r"); if (!f) - return 1; + return -1; - len = fread(&filebuf, 1, CERT_BUF_LEN - 1, f); - if (len < 64) - return 1; + ret = fread(buf, 1, len, f); + + /* Ensure that feof() yields the correct result when the file is exactly + * len bytes long */ + fgetc(f); + + if (ferror(f)) { + ret = -1; + } else if (!feof(f)) { + errno = EOVERFLOW; + ret = -1; + } else if ((size_t)ret < minlen) { + errno = EINVAL; + ret = -1; + } - ret = ferror(f) || !feof(f); fclose(f); - if (ret) + return ret; +} + +/* load certfile into list */ +static int cert_load(const char *certfile, struct list_head *chain) { + struct blob_attr *certtb[CERT_ATTR_MAX]; + struct blob_attr *bufpt; + struct cert_object *cobj; + char filebuf[CERT_BUF_LEN], *end; + int ret = 1; + ssize_t len; + + len = read_file(certfile, filebuf, sizeof(filebuf) - 1, 0); + if (len < 0) { + if (!quiet) + perror("Unable to load certificate file"); return 1; + } bufpt = (struct blob_attr *)filebuf; - do { - pret = blob_parse(bufpt, certtb, cert_policy, CERT_ATTR_MAX); - if (pret <= 0) - /* no attributes found */ + end = filebuf + len; + + while (true) { + len = end - (char *)bufpt; + if (len <= 0) break; - if (pos + blob_pad_len(bufpt) > len) - /* blob exceeds filebuffer */ + if (blob_parse_untrusted(bufpt, len, certtb, cert_policy, CERT_ATTR_MAX) <= 0) + /* no attributes found */ break; - else - pos += blob_pad_len(bufpt); if (!certtb[CERT_ATTR_SIGNATURE]) /* no signature -> drop */ @@ -175,31 +197,34 @@ static int cert_load(const char *certfile, struct list_head *chain) { 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))); + ret = 0; + + /* Repeat parsing while there is still enough remaining data in buffer + * + * Note that blob_next() is only valid for untrusted data because blob_parse_untrusted() + * verified that the buffer contains at least one blob, and that it is completely contained + * in the buffer */ + bufpt = blob_next(bufpt); + } - return (ret <= 0); + return ret; } #ifdef UCERT_FULL /* append signature to certfile */ static int cert_append(const char *certfile, const char *sigfile) { - FILE *fs; char filebuf[CERT_BUF_LEN]; struct blob_buf sigbuf = {0}; - int len; + ssize_t len; int ret; - fs = fopen(sigfile, "r"); - if (!fs) - return 1; + len = read_file(sigfile, filebuf, sizeof(filebuf) - 1, 64); + if (len < 0) { + if (!quiet) + perror("Unable to load signature file"); - len = fread(&filebuf, 1, CERT_BUF_LEN - 1, fs); - ret = ferror(fs) || !feof(fs) || (len < 64); - fclose(fs); - if (ret) return 1; + } blob_buf_init(&sigbuf, 0); blob_put(&sigbuf, CERT_ATTR_SIGNATURE, filebuf, len); @@ -328,7 +353,7 @@ static int chain_verify(const char *msgfile, const char *pubkeyfile, blobmsg_data_len(payloadtb[CERT_PL_ATTR_PUBKEY]), false); - if (usign_f_pubkey(chainedfp, chainedpubkey)) { + if (usign_f_pubkey(chainedfp, chainedpubkey, quiet)) { DPRINTF("cannot get fingerprint for chained key\n"); ret = 2; goto clean_and_return; @@ -371,6 +396,7 @@ clean_and_return: /* 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]; @@ -380,10 +406,16 @@ static void cert_dump_blob(struct blob_attr *cert[CERT_ATTR_MAX]) { switch(cert_policy[i].type) { case BLOB_ATTR_BINARY: - fprintf(stdout, "signature:\n---\n%s---\n", (char *) blob_data(v)); + printf("signature:\n---\n%s---\n", (char *) blob_data(v)); break; case BLOB_ATTR_NESTED: - fprintf(stdout, "payload:\n---\n%s\n---\n", blobmsg_format_json_indent(blob_data(v), false, 0)); + json = blobmsg_format_json_indent(blob_data(v), false, 0); + if (!json) { + DPRINTF("cannot parse payload\n"); + continue; + } + printf("payload:\n---\n%s\n---\n", json); + free(json); break; } } @@ -401,7 +433,7 @@ static int cert_dump(const char *certfile) { } list_for_each_entry(cobj, &certchain, list) { - fprintf(stdout, "=== CHAIN ELEMENT %02u ===\n", ++count); + printf("=== CHAIN ELEMENT %02u ===\n", ++count); cert_dump_blob(cobj->cert); } @@ -413,29 +445,26 @@ static int cert_issue(const char *certfile, const char *pubkeyfile, const char * struct blob_buf payloadbuf = {0}; struct blob_buf certbuf = {0}; struct timeval tv; - int pklen, siglen; + ssize_t pklen, siglen; int revoker = 1; void *c; - FILE *pkf, *sigf; char pkb[512]; char sigb[1024]; char fname[256], sfname[256]; char pkfp[17]; char tmpdir[] = "/tmp/ucert-XXXXXX"; - pkf = fopen(pubkeyfile, "r"); - if (!pkf) - return -1; - - pklen = fread(pkb, 1, 512, pkf); - pkb[pklen] = '\0'; + pklen = read_file(pubkeyfile, pkb, sizeof(pkb) - 1, 32); + if (pklen < 0) { + if (!quiet) + perror("Unable to load public key file"); - if (pklen < 32) return -1; + } - fclose(pkf); + pkb[pklen] = '\0'; - if (usign_f_pubkey(pkfp, pubkeyfile)) + if (usign_f_pubkey(pkfp, pubkeyfile, quiet)) return -1; gettimeofday(&tv, NULL); @@ -464,16 +493,15 @@ static int cert_issue(const char *certfile, const char *pubkeyfile, const char * if (usign_s(fname, seckeyfile, sfname, quiet)) return 1; - sigf = fopen(sfname, "r"); - if (!sigf) - return 1; + siglen = read_file(sfname, sigb, sizeof(sigb) - 1, 1); + if (siglen < 0) { + if (!quiet) + perror("Unable to load signature file"); - siglen = fread(sigb, 1, 1024, sigf); - if (siglen < 1) return 1; + } sigb[siglen] = '\0'; - fclose(sigf); unlink(fname); unlink(sfname);