summaryrefslogtreecommitdiff
path: root/source4/heimdal/lib/hx509/ks_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/heimdal/lib/hx509/ks_file.c')
-rw-r--r--source4/heimdal/lib/hx509/ks_file.c418
1 files changed, 131 insertions, 287 deletions
diff --git a/source4/heimdal/lib/hx509/ks_file.c b/source4/heimdal/lib/hx509/ks_file.c
index f9a3580880..269afd03b1 100644
--- a/source4/heimdal/lib/hx509/ks_file.c
+++ b/source4/heimdal/lib/hx509/ks_file.c
@@ -32,68 +32,16 @@
*/
#include "hx_locl.h"
-RCSID("$Id: ks_file.c 20776 2007-06-01 22:02:01Z lha $");
+RCSID("$Id: ks_file.c 21314 2007-06-25 18:45:07Z lha $");
+
+typedef enum { USE_PEM, USE_DER } outformat;
struct ks_file {
hx509_certs certs;
char *fn;
+ outformat format;
};
-struct header {
- char *header;
- char *value;
- struct header *next;
-};
-
-static int
-add_headers(struct header **headers, const char *header, const char *value)
-{
- struct 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;
-}
-
-static void
-free_headers(struct header *headers)
-{
- struct header *h;
- while (headers) {
- h = headers;
- headers = headers->next;
- free(h->header);
- free(h->value);
- free(h);
- }
-}
-
-static const char *
-find_header(const struct header *headers, const char *header)
-{
- while(headers) {
- if (strcmp(header, headers->header) == 0)
- return headers->value;
- headers = headers->next;
- }
- return NULL;
-}
-
/*
*
*/
@@ -101,24 +49,13 @@ find_header(const struct header *headers, const char *header)
static int
parse_certificate(hx509_context context, const char *fn,
struct hx509_collector *c,
- const struct header *headers,
+ const hx509_pem_header *headers,
const void *data, size_t len)
{
hx509_cert cert;
- Certificate t;
- size_t size;
int ret;
- ret = decode_Certificate(data, len, &t, &size);
- if (ret) {
- hx509_set_error_string(context, 0, ret,
- "Failed to parse certificate in %s",
- fn);
- return ret;
- }
-
- ret = hx509_cert_init(context, &t, &cert);
- free_Certificate(&t);
+ ret = hx509_cert_init_data(context, data, len, &cert);
if (ret)
return ret;
@@ -195,13 +132,13 @@ out:
static int
parse_rsa_private_key(hx509_context context, const char *fn,
struct hx509_collector *c,
- const struct header *headers,
+ const hx509_pem_header *headers,
const void *data, size_t len)
{
int ret = 0;
const char *enc;
- enc = find_header(headers, "Proc-Type");
+ enc = hx509_pem_find_header(headers, "Proc-Type");
if (enc) {
const char *dek;
char *type, *iv;
@@ -229,7 +166,7 @@ parse_rsa_private_key(hx509_context context, const char *fn,
return HX509_PARSING_KEY_FAILED;
}
- dek = find_header(headers, "DEK-Info");
+ dek = hx509_pem_find_header(headers, "DEK-Info");
if (dek == NULL) {
hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
"Encrypted RSA missing DEK-Info");
@@ -243,8 +180,14 @@ parse_rsa_private_key(hx509_context context, const char *fn,
}
iv = strchr(type, ',');
- if (iv)
- *iv++ = '\0';
+ if (iv == NULL) {
+ free(type);
+ hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED,
+ "IV missing");
+ return HX509_PARSING_KEY_FAILED;
+ }
+
+ *iv++ = '\0';
size = strlen(iv);
ivdata = malloc(size);
@@ -339,7 +282,7 @@ parse_rsa_private_key(hx509_context context, const char *fn,
struct pem_formats {
const char *name;
int (*func)(hx509_context, const char *, struct hx509_collector *,
- const struct header *, const void *, size_t);
+ const hx509_pem_header *, const void *, size_t);
} formats[] = {
{ "CERTIFICATE", parse_certificate },
{ "RSA PRIVATE KEY", parse_rsa_private_key }
@@ -347,152 +290,27 @@ struct pem_formats {
static int
-parse_pem_file(hx509_context context,
- const char *fn,
- struct hx509_collector *c,
- int *found_data)
+pem_func(hx509_context context, const char *type,
+ const hx509_pem_header *header,
+ const void *data, size_t len, void *ctx)
{
- struct header *headers = NULL;
- char *type = NULL;
- void *data = NULL;
- size_t len = 0;
- char buf[1024];
- int ret;
- FILE *f;
-
-
- enum { BEFORE, SEARCHHEADER, INHEADER, INDATA, DONE } where;
-
- where = BEFORE;
- *found_data = 0;
+ struct hx509_collector *c = ctx;
+ int ret, j;
- if ((f = fopen(fn, "r")) == NULL) {
- hx509_set_error_string(context, 0, ENOENT,
- "Failed to open PEM file \"%s\": %s",
- fn, strerror(errno));
- return ENOENT;
- }
- ret = 0;
-
- 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';
- *found_data = 1;
- where = SEARCHHEADER;
- }
+ for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) {
+ const char *q = formats[j].name;
+ if (strcasecmp(type, q) == 0) {
+ ret = (*formats[j].func)(context, NULL, c, header, data, len);
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++;
- add_headers(&headers, buf, p);
- }
- 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) {
- int j;
-
- for (j = 0; j < sizeof(formats)/sizeof(formats[0]); j++) {
- const char *q = formats[j].name;
- if (strcasecmp(type, q) == 0) {
- ret = (*formats[j].func)(context, fn, c,
- headers, data, len);
- break;
- }
- }
- if (j == sizeof(formats)/sizeof(formats[0])) {
- ret = HX509_UNSUPPORTED_OPERATION;
- hx509_set_error_string(context, 0, ret,
- "Found no matching PEM format for %s",
- type);
- }
- out:
- free(data);
- data = NULL;
- len = 0;
- free(type);
- type = NULL;
- where = BEFORE;
- free_headers(headers);
- headers = NULL;
- if (ret)
- break;
}
}
-
- fclose(f);
-
- 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 (j == sizeof(formats)/sizeof(formats[0])) {
+ ret = HX509_UNSUPPORTED_OPERATION;
+ hx509_set_error_string(context, 0, ret,
+ "Found no matching PEM format for %s", type);
+ return ret;
}
- if (data)
- free(data);
- if (type)
- free(type);
- if (headers)
- free_headers(headers);
-
- return ret;
+ return 0;
}
/*
@@ -500,9 +318,9 @@ parse_pem_file(hx509_context context,
*/
static int
-file_init(hx509_context context,
- hx509_certs certs, void **data, int flags,
- const char *residue, hx509_lock lock)
+file_init_common(hx509_context context,
+ hx509_certs certs, void **data, int flags,
+ const char *residue, hx509_lock lock, outformat format)
{
char *p, *pnext;
struct ks_file *f = NULL;
@@ -520,6 +338,7 @@ file_init(hx509_context context,
hx509_clear_error_string(context);
return ENOMEM;
}
+ f->format = format;
f->fn = strdup(residue);
if (f->fn == NULL) {
@@ -547,17 +366,26 @@ file_init(hx509_context context,
goto out;
for (p = f->fn; p != NULL; p = pnext) {
- int found_data;
+ FILE *f;
pnext = strchr(p, ',');
if (pnext)
*pnext++ = '\0';
- ret = parse_pem_file(context, p, c, &found_data);
- if (ret)
+
+ if ((f = fopen(p, "r")) == NULL) {
+ ret = ENOENT;
+ hx509_set_error_string(context, 0, ret,
+ "Failed to open PEM file \"%s\": %s",
+ p, strerror(errno));
goto out;
+ }
- if (!found_data) {
+ ret = hx509_pem_read(context, f, pem_func, c);
+ fclose(f);
+ if (ret != 0 && ret != HX509_PARSING_KEY_FAILED)
+ goto out;
+ else if (ret == HX509_PARSING_KEY_FAILED) {
size_t length;
void *ptr;
int i;
@@ -606,75 +434,40 @@ out:
}
static int
-file_free(hx509_certs certs, void *data)
+file_init_pem(hx509_context context,
+ hx509_certs certs, void **data, int flags,
+ const char *residue, hx509_lock lock)
{
- struct ks_file *f = data;
- hx509_certs_free(&f->certs);
- free(f->fn);
- free(f);
- return 0;
+ return file_init_common(context, certs, data, flags, residue, lock, USE_PEM);
}
-static void
-pem_header(FILE *f, const char *type, const char *str)
+static int
+file_init_der(hx509_context context,
+ hx509_certs certs, void **data, int flags,
+ const char *residue, hx509_lock lock)
{
- fprintf(f, "-----%s %s-----\n", type, str);
+ return file_init_common(context, certs, data, flags, residue, lock, USE_DER);
}
static int
-dump_pem_file(hx509_context context, const char *header,
- FILE *f, const void *data, size_t size)
+file_free(hx509_certs certs, void *data)
{
- const char *p = data;
- size_t length;
- char *line;
-
-#define ENCODE_LINE_LENGTH 54
-
- pem_header(f, "BEGIN", header);
-
- while (size > 0) {
- ssize_t l;
-
- length = size;
- if (length > ENCODE_LINE_LENGTH)
- length = ENCODE_LINE_LENGTH;
-
- l = base64_encode(p, length, &line);
- if (l < 0) {
- hx509_set_error_string(context, 0, ENOMEM,
- "malloc - out of memory");
- return ENOMEM;
- }
- size -= length;
- fprintf(f, "%s\n", line);
- p += length;
- free(line);
- }
-
- pem_header(f, "END", header);
-
+ struct ks_file *f = data;
+ hx509_certs_free(&f->certs);
+ free(f->fn);
+ free(f);
return 0;
}
-static int
-store_private_key(hx509_context context, FILE *f, hx509_private_key key)
-{
- heim_octet_string data;
- int ret;
-
- ret = _hx509_private_key_export(context, key, &data);
- if (ret == 0)
- dump_pem_file(context, _hx509_private_pem_name(key), f,
- data.data, data.length);
- free(data.data);
- return ret;
-}
+struct store_ctx {
+ FILE *f;
+ outformat format;
+};
static int
store_func(hx509_context context, void *ctx, hx509_cert c)
{
- FILE *f = (FILE *)ctx;
+ struct store_ctx *sc = ctx;
heim_octet_string data;
int ret;
@@ -682,11 +475,26 @@ store_func(hx509_context context, void *ctx, hx509_cert c)
if (ret)
return ret;
- dump_pem_file(context, "CERTIFICATE", f, data.data, data.length);
- free(data.data);
-
- if (_hx509_cert_private_key_exportable(c))
- store_private_key(context, f, _hx509_cert_private_key(c));
+ switch (sc->format) {
+ case USE_DER:
+ fwrite(data.data, data.length, 1, sc->f);
+ free(data.data);
+ break;
+ case USE_PEM:
+ hx509_pem_write(context, "CERTIFICATE", NULL, sc->f,
+ data.data, data.length);
+ free(data.data);
+ if (_hx509_cert_private_key_exportable(c)) {
+ hx509_private_key key = _hx509_cert_private_key(c);
+ ret = _hx509_private_key_export(context, key, &data);
+ if (ret)
+ break;
+ hx509_pem_write(context, _hx509_private_pem_name(key), NULL, sc->f,
+ data.data, data.length);
+ free(data.data);
+ }
+ break;
+ }
return 0;
}
@@ -696,18 +504,19 @@ file_store(hx509_context context,
hx509_certs certs, void *data, int flags, hx509_lock lock)
{
struct ks_file *f = data;
- FILE *fh;
+ struct store_ctx sc;
int ret;
- fh = fopen(f->fn, "w");
- if (fh == NULL) {
+ sc.f = fopen(f->fn, "w");
+ if (sc.f == NULL) {
hx509_set_error_string(context, 0, ENOENT,
"Failed to open file %s for writing");
return ENOENT;
}
+ sc.format = f->format;
- ret = hx509_certs_iter(context, f->certs, store_func, fh);
- fclose(fh);
+ ret = hx509_certs_iter(context, f->certs, store_func, &sc);
+ fclose(sc.f);
return ret;
}
@@ -767,7 +576,7 @@ file_addkey(hx509_context context,
static struct hx509_keyset_ops keyset_file = {
"FILE",
0,
- file_init,
+ file_init_pem,
file_store,
file_free,
file_add,
@@ -780,8 +589,43 @@ static struct hx509_keyset_ops keyset_file = {
file_addkey
};
+static struct hx509_keyset_ops keyset_pemfile = {
+ "PEM-FILE",
+ 0,
+ file_init_pem,
+ file_store,
+ file_free,
+ file_add,
+ NULL,
+ file_iter_start,
+ file_iter,
+ file_iter_end,
+ NULL,
+ file_getkeys,
+ file_addkey
+};
+
+static struct hx509_keyset_ops keyset_derfile = {
+ "DER-FILE",
+ 0,
+ file_init_der,
+ file_store,
+ file_free,
+ file_add,
+ NULL,
+ file_iter_start,
+ file_iter,
+ file_iter_end,
+ NULL,
+ file_getkeys,
+ file_addkey
+};
+
+
void
_hx509_ks_file_register(hx509_context context)
{
_hx509_ks_register(context, &keyset_file);
+ _hx509_ks_register(context, &keyset_pemfile);
+ _hx509_ks_register(context, &keyset_derfile);
}