diff --git a/lib/hx509/file.c b/lib/hx509/file.c index f63a1afaa..b076b74f4 100644 --- a/lib/hx509/file.c +++ b/lib/hx509/file.c @@ -135,6 +135,10 @@ _hx509_write_file(const char *fn, const void *data, size_t length) return 0; } +/* + * + */ + static void header(FILE *f, const char *type, const char *str) { @@ -143,22 +147,23 @@ header(FILE *f, const char *type, const char *str) int hx509_pem_write(hx509_context context, const char *type, - char **headers, FILE *f, + hx509_pem_header *headers, FILE *f, const void *data, size_t size) { const char *p = data; size_t length; char *line; - int i; #define ENCODE_LINE_LENGTH 54 header(f, "BEGIN", type); - for(i = 0; headers && headers[i]; i++) - fprintf(f, "%s\n", headers[i]); - if (i > 0) - fprintf(f, "\n"); + while (headers) { + fprintf(f, "%s: %s\n%s", + headers->header, headers->value, + headers->next ? "" : "\n"); + headers = headers->next; + } while (size > 0) { ssize_t l; @@ -183,3 +188,189 @@ hx509_pem_write(hx509_context context, const char *type, return 0; } + +/* + * + */ + +int +hx509_pem_add_header(hx509_pem_header **headers, + const char *header, const char *value) +{ + hx509_pem_header *h; + + h = calloc(1, sizeof(*h)); + if (h == NULL) + return ENOMEM; + h->header = strdup(header); + if (h->header == NULL) { + free(h); + return ENOMEM; + } + h->value = strdup(value); + if (h->value == NULL) { + free(h->header); + free(h); + return ENOMEM; + } + + h->next = *headers; + *headers = h; + + return 0; +} + +void +hx509_pem_free_header(hx509_pem_header *headers) +{ + hx509_pem_header *h; + while (headers) { + h = headers; + headers = headers->next; + free(h->header); + free(h->value); + free(h); + } +} + +/* + * + */ + +const char * +hx509_pem_find_header(const hx509_pem_header *h, const char *header) +{ + while(h) { + if (strcmp(header, h->header) == 0) + return h->value; + h = h->next; + } + return NULL; +} + + +/* + * + */ + +int +hx509_pem_read(hx509_context context, + FILE *f, + hx509_pem_read_func func, + void *ctx) +{ + hx509_pem_header *headers = NULL; + char *type = NULL; + void *data = NULL; + size_t len = 0; + char buf[1024]; + int ret = HX509_PARSING_KEY_FAILED; + + enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where; + + where = BEFORE; + + while (fgets(buf, sizeof(buf), f) != NULL) { + char *p; + int i; + + i = strcspn(buf, "\n"); + if (buf[i] == '\n') { + buf[i] = '\0'; + if (i > 0) + i--; + } + if (buf[i] == '\r') { + buf[i] = '\0'; + if (i > 0) + i--; + } + + switch (where) { + case BEFORE: + if (strncmp("-----BEGIN ", buf, 11) == 0) { + type = strdup(buf + 11); + if (type == NULL) + break; + p = strchr(type, '-'); + if (p) + *p = '\0'; + where = SEARCHHEADER; + } + break; + case SEARCHHEADER: + p = strchr(buf, ':'); + if (p == NULL) { + where = INDATA; + goto indata; + } + /* FALLTHOUGH */ + case INHEADER: + if (buf[0] == '\0') { + where = INDATA; + break; + } + p = strchr(buf, ':'); + if (p) { + *p++ = '\0'; + while (isspace((int)*p)) + p++; + ret = hx509_pem_add_header(&headers, buf, p); + if (ret) + abort(); + } + break; + case INDATA: + indata: + + if (strncmp("-----END ", buf, 9) == 0) { + where = DONE; + break; + } + + p = emalloc(i); + i = base64_decode(buf, p); + if (i < 0) { + free(p); + goto out; + } + + data = erealloc(data, len + i); + memcpy(((char *)data) + len, p, i); + free(p); + len += i; + break; + case DONE: + abort(); + } + + if (where == DONE) { + ret = (*func)(context, type, headers, data, len, ctx); + out: + free(data); + data = NULL; + len = 0; + free(type); + type = NULL; + where = BEFORE; + hx509_pem_free_header(headers); + headers = NULL; + if (ret) + break; + } + } + + if (where != BEFORE) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "File ends before end of PEM end tag"); + ret = HX509_PARSING_KEY_FAILED; + } + if (data) + free(data); + if (type) + free(type); + if (headers) + hx509_pem_free_header(headers); + + return ret; +}