5ac91f2dc9
Keep the original DER encoding around when decoding certificates so hx509_cert_binary() does not rewrite certificates unnecessarily. Add regression coverage for direct certificate binary output and keyless stores.
180 lines
4.0 KiB
C
180 lines
4.0 KiB
C
#include "hx_locl.h"
|
|
#include <err.h>
|
|
|
|
#ifndef SRCDIR
|
|
#define SRCDIR "."
|
|
#endif
|
|
|
|
struct pem_cert {
|
|
heim_octet_string der;
|
|
int found;
|
|
};
|
|
|
|
static int
|
|
pem_cert_reader(hx509_context context, const char *type,
|
|
const hx509_pem_header *headers,
|
|
const void *data, size_t length, void *ctx)
|
|
{
|
|
struct pem_cert *pem = ctx;
|
|
|
|
(void)context;
|
|
(void)headers;
|
|
|
|
if (strcmp(type, "CERTIFICATE") != 0)
|
|
return 0;
|
|
|
|
if (pem->found)
|
|
return 0;
|
|
|
|
pem->der.data = malloc(length);
|
|
if (pem->der.data == NULL)
|
|
return ENOMEM;
|
|
memcpy(pem->der.data, data, length);
|
|
pem->der.length = length;
|
|
pem->found = 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
read_cert_der(hx509_context context, const char *path, heim_octet_string *der)
|
|
{
|
|
struct pem_cert pem;
|
|
FILE *f;
|
|
int ret;
|
|
|
|
memset(&pem, 0, sizeof(pem));
|
|
|
|
f = fopen(path, "r");
|
|
if (f == NULL)
|
|
err(1, "fopen: %s", path);
|
|
|
|
ret = hx509_pem_read(context, f, pem_cert_reader, &pem);
|
|
fclose(f);
|
|
if (ret)
|
|
hx509_err(context, 1, ret, "hx509_pem_read: %s", path);
|
|
if (!pem.found)
|
|
errx(1, "did not find a certificate in %s", path);
|
|
|
|
*der = pem.der;
|
|
}
|
|
|
|
static void
|
|
compare_octet_string(const char *what,
|
|
const heim_octet_string *expected,
|
|
const heim_octet_string *actual)
|
|
{
|
|
if (actual->length != expected->length)
|
|
errx(1, "%s length changed from %lu to %lu",
|
|
what, (unsigned long)expected->length,
|
|
(unsigned long)actual->length);
|
|
if (memcmp(actual->data, expected->data, expected->length) != 0)
|
|
errx(1, "%s data changed", what);
|
|
}
|
|
|
|
static void
|
|
check_cert_binary(hx509_context context, const heim_octet_string *der)
|
|
{
|
|
heim_octet_string os;
|
|
hx509_cert cert;
|
|
int ret;
|
|
|
|
memset(&os, 0, sizeof(os));
|
|
|
|
cert = hx509_cert_init_data(context, der->data, der->length, NULL);
|
|
if (cert == NULL)
|
|
err(1, "hx509_cert_init_data");
|
|
|
|
ret = hx509_cert_binary(context, cert, &os);
|
|
if (ret)
|
|
hx509_err(context, 1, ret, "hx509_cert_binary");
|
|
compare_octet_string("certificate encoding", der, &os);
|
|
der_free_octet_string(&os);
|
|
|
|
hx509_cert_free(cert);
|
|
}
|
|
|
|
static char *
|
|
make_store_name(void)
|
|
{
|
|
char *store_name = NULL;
|
|
|
|
if (asprintf(&store_name, "FILE:%s/data/test.crt,%s/data/test.key",
|
|
SRCDIR, SRCDIR) == -1 || store_name == NULL)
|
|
err(1, "asprintf");
|
|
|
|
return store_name;
|
|
}
|
|
|
|
static void
|
|
check_keyless_store_cert_encoding(hx509_context context,
|
|
const heim_octet_string *der)
|
|
{
|
|
heim_octet_string os;
|
|
hx509_certs certs = NULL;
|
|
hx509_cert cert = NULL;
|
|
char *store_name;
|
|
int ret;
|
|
|
|
memset(&os, 0, sizeof(os));
|
|
|
|
ret = hx509_certs_init(context, "MEMORY:test-keyless-certs",
|
|
HX509_CERTS_NO_PRIVATE_KEYS, NULL, &certs);
|
|
if (ret)
|
|
hx509_err(context, 1, ret, "hx509_certs_init");
|
|
|
|
store_name = make_store_name();
|
|
ret = hx509_certs_append(context, certs, NULL, store_name);
|
|
free(store_name);
|
|
if (ret)
|
|
hx509_err(context, 1, ret, "hx509_certs_append");
|
|
|
|
ret = hx509_get_one_cert(context, certs, &cert);
|
|
if (ret)
|
|
hx509_err(context, 1, ret, "hx509_get_one_cert");
|
|
if (hx509_cert_have_private_key(cert))
|
|
errx(1, "HX509_CERTS_NO_PRIVATE_KEYS store kept a private key");
|
|
|
|
ret = hx509_cert_binary(context, cert, &os);
|
|
if (ret)
|
|
hx509_err(context, 1, ret, "hx509_cert_binary on keyless cert");
|
|
compare_octet_string("keyless store certificate encoding", der, &os);
|
|
|
|
der_free_octet_string(&os);
|
|
hx509_cert_free(cert);
|
|
hx509_certs_free(&certs);
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
heim_octet_string der;
|
|
hx509_context context;
|
|
char *cert_path = NULL;
|
|
int ret;
|
|
|
|
(void)argc;
|
|
(void)argv;
|
|
|
|
memset(&der, 0, sizeof(der));
|
|
|
|
ret = hx509_context_init(&context);
|
|
if (ret)
|
|
errx(1, "hx509_context_init failed with %d", ret);
|
|
|
|
if (asprintf(&cert_path, "%s/data/test.crt", SRCDIR) == -1 ||
|
|
cert_path == NULL)
|
|
err(1, "asprintf");
|
|
|
|
read_cert_der(context, cert_path, &der);
|
|
free(cert_path);
|
|
|
|
check_cert_binary(context, &der);
|
|
check_keyless_store_cert_encoding(context, &der);
|
|
|
|
der_free_octet_string(&der);
|
|
hx509_context_free(&context);
|
|
|
|
return 0;
|
|
}
|