From aa1e57cd27494aad4ea3d5dac0175f8df6021320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Fri, 21 Apr 2006 11:24:02 +0000 Subject: [PATCH] Add support for parsing unencrypted RSA PRIVATE KEY git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@17119 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/hx509/ks_file.c | 274 +++++++++++++++++++++++++++----------------- 1 file changed, 170 insertions(+), 104 deletions(-) diff --git a/lib/hx509/ks_file.c b/lib/hx509/ks_file.c index 16b8150b5..421795913 100644 --- a/lib/hx509/ks_file.c +++ b/lib/hx509/ks_file.c @@ -39,20 +39,79 @@ struct ks_file { }; static int -parse_file_pem(const char *fn, Certificate *t) +parse_certificate(hx509_context context, struct hx509_collector *c, + const void *data, size_t len) { - char buf[1024]; - void *data = NULL; - size_t size, len = 0; - int in_cert = 0; - FILE *f; - int i, ret; + hx509_cert cert; + Certificate t; + size_t size; + int ret; - memset(t, 0, sizeof(*t)); + ret = decode_Certificate(data, len, &t, &size); + if (ret) + return ret; + + ret = hx509_cert_init(context, &t, &cert); + free_Certificate(&t); + if (ret) + return ret; + + ret = _hx509_collector_certs_add(context, c, cert); + hx509_cert_free(cert); + return ret; +} + +static int +parse_rsa_private_key(hx509_context context, struct hx509_collector *c, + const void *data, size_t len) +{ + heim_octet_string keydata; + int ret; + + keydata.data = rk_UNCONST(data); + keydata.length = len; + + ret = _hx509_collector_private_key_add(c, + hx509_signature_rsa(), + NULL, + &keydata, + NULL); + return ret; +} + + +struct pem_formats { + const char *name; + int (*func)(hx509_context, struct hx509_collector *, const void *, size_t); +} formats[] = { + { "CERTIFICATE", parse_certificate }, + { "RSA PRIVATE KEY", parse_rsa_private_key } +}; + + +static int +parse_pem_file(hx509_context context, + const char *fn, + struct hx509_collector *c, + int *found_data) +{ + char *type = NULL; + void *data = NULL; + size_t len = 0; + char buf[1024]; + int i, ret; + FILE *f; + + enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where; + + where = BEFORE; + *found_data = 0; if ((f = fopen(fn, "r")) == NULL) return ENOENT; + ret = 0; + while (fgets(buf, sizeof(buf), f) != NULL) { char *p; @@ -68,86 +127,94 @@ parse_file_pem(const char *fn, Certificate *t) i--; } - if (i == 26 - && strcmp("-----BEGIN CERTIFICATE-----", buf) == 0) - { - in_cert = 1; - continue; - } else if (i == 24 && - strcmp("-----END CERTIFICATE-----", buf) == 0) - { - in_cert = 0; - continue; - } - if (in_cert == 0) - continue; + switch (where) { + case BEFORE: + if (strncmp("-----BEGIN ", buf, 11) == 0) { + type = strdup(buf + 11); + if (type == NULL) + break; + *found_data = 1; + 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) { + printf("Add header: %.*s <- %s\n", + (int)(p - buf) - 1, buf, p + 1); + } + break; + case INDATA: + indata: + if (strncmp("-----END ", buf, 9) == 0) { + where = DONE; + break; + } - p = malloc(i); - i = base64_decode(buf, p); + p = malloc(i); + i = base64_decode(buf, p); - data = erealloc(data, len + i); - memcpy(((char *)data) + len, p, i); - free(p); - len += i; + data = erealloc(data, len + i); + memcpy(((char *)data) + len, p, i); + free(p); + len += i; + break; + case DONE: + abort(); + } + + if (where == DONE) { + int i; + + ret = EINVAL; + for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) { + const char *p = formats[i].name; + if (strncmp(type, p, strlen(p)) == 0) + ret = (*formats[i].func)(context, c, data, len); + } + free(data); + data = NULL; + free(type); + type = NULL; + where = BEFORE; + if (ret) + break; + } } + if (where != BEFORE) + ret = EINVAL; + if (data) + free(data); + if (type) + free(type); + fclose(f); - if (data == NULL) - return ENOENT; - - if (data && in_cert) { - free(data); - return EINVAL; - } - - ret = decode_Certificate(data, len, t, &size); - free(data); - return ret; -} - -static int -parse_file_der(const char *fn, Certificate *t) -{ - size_t length, size; - void *data; - int ret; - - ret = _hx509_map_file(fn, &data, &length, NULL); - if (ret) - return ret; - - ret = decode_Certificate(data, length, t, &size); - _hx509_unmap_file(data, length); - return ret; -} - -int -_hx509_file_to_cert(hx509_context context, const char *certfn, hx509_cert *cert) -{ - Certificate t; - int ret; - - ret = parse_file_pem(certfn, &t); - if (ret) - ret = parse_file_der(certfn, &t); - if (ret) - return ret; - - ret = hx509_cert_init(context, &t, cert); - free_Certificate(&t); - return ret; } +/* + * + */ static int file_init(hx509_context context, hx509_certs certs, void **data, int flags, const char *residue, hx509_lock lock) { - char *certfn = NULL, *keyfn, *friendlyname = NULL; - hx509_cert cert = NULL; + char *files = NULL, *p, *pnext; int ret; struct ks_file *f; struct hx509_collector *c; @@ -167,48 +234,47 @@ file_init(hx509_context context, goto out; } - certfn = strdup(residue); - if (certfn == NULL) - return ENOMEM; - keyfn = strchr(certfn, ','); - if (keyfn) { - *keyfn++ = '\0'; - friendlyname = strchr(keyfn, ','); - if (friendlyname) - *friendlyname++ = '\0'; - } - - ret = _hx509_file_to_cert(context, certfn, &cert); - if (ret) + files = strdup(residue); + if (files == NULL) { + ret = ENOMEM; goto out; - - _hx509_collector_certs_add(context, c, cert); - - if (keyfn) { - ret = _hx509_cert_assign_private_key_file(cert, lock, keyfn); - if (ret) - goto out; } - if (friendlyname) { - ret = hx509_cert_set_friendly_name(cert, friendlyname); + + for (p = files; p != NULL; p = pnext) { + int found_data; + + pnext = strchr(p, ','); + if (pnext) + *pnext++ = '\0'; + + ret = parse_pem_file(context, p, c, &found_data); if (ret) goto out; + + if (!found_data) { + size_t length; + void *data; + int ret; + + ret = _hx509_map_file(p, &data, &length, NULL); + if (ret) + goto out; + + ret = parse_certificate(context, c, data, length); + _hx509_unmap_file(data, length); + if (ret) + goto out; + } } ret = _hx509_collector_collect(context, c, &f->certs); if (ret == 0) *data = f; out: - hx509_cert_free(cert); - _hx509_collector_free(c); - if (certfn) - free(certfn); + ret = 0; + free(files); - if (ret) { - if (f->certs) - hx509_certs_free(&f->certs); - free(f); - } + _hx509_collector_free(c); return ret; }