purr-c/read_certs.c

212 lines
6.0 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "read_certs.h"
#include "translation.h"
struct append_dn_status {
uint8_t *dn;
size_t n, size;
};
void bearssl_read_certs_help(FILE *stream)
{
fprintf(stream,
" %s\n",
_("CA_CERT_SSL_FILE: certificates file, default is /etc/ssl/certs.pem")
);
}
void bearssl_free_certs(struct trust_anchors tas)
{
for (size_t i = 0; i < tas.n; i++) {
br_x509_trust_anchor ta = tas.ta[i];
free(ta.dn.data);
if (ta.pkey.key_type == BR_KEYTYPE_RSA) {
free(ta.pkey.key.rsa.n);
free(ta.pkey.key.rsa.e);
} else if (ta.pkey.key_type == BR_KEYTYPE_EC) {
free(ta.pkey.key.ec.q);
}
}
free(tas.ta);
}
static int append_ta(struct trust_anchors *ct, br_x509_trust_anchor ta)
{
if (ct->n + 1 > ct->size) {
size_t tmp = ct->size * 2;
if (tmp == 0) tmp = 64;
ct->ta = realloc(ct->ta, tmp * sizeof(ta));
if (ct->ta == NULL) {
perror("realloc()");
return -1;
}
ct->size = tmp;
}
ct->ta[ct->n++] = ta;
return 0;
}
static void append_dn(void *ctx, const void *buf, size_t len)
{
struct append_dn_status *s = ctx;
if (s->n + len > s->size) {
size_t tmp = s->size;
if (tmp == 0) tmp = 256;
while (s->n + len > tmp) {
tmp *= 2;
}
s->dn = realloc(s->dn, tmp);
if (s->dn == NULL) {
perror("realloc()");
return;
}
s->size = tmp;
}
memcpy(s->dn + s->n, buf, len);
s->n += len;
}
static void push_x509(void *dest_ctx, const void *src, size_t len)
{
br_x509_decoder_context *dest = dest_ctx;
br_x509_decoder_push(dest, src, len);
}
/*
* Reads certs from file if set, otherwise from default location.
*/
size_t bearssl_read_certs(struct trust_anchors *tas, FILE *file)
{
size_t rv = 0;
if (file == NULL) {
const char *cert_path = getenv("CA_CERT_SSL_FILE");
if (cert_path == NULL) {
cert_path = "/etc/ssl/certs.pem";
}
file = fopen(cert_path, "re");
if (file == NULL) {
perror("fopen()");
return rv;
}
}
br_pem_decoder_context pem;
br_x509_decoder_context x509;
br_pem_decoder_init(&pem);
br_pem_decoder_setdest(&pem, push_x509, &x509);
struct append_dn_status dn_status;
uint8_t data[512];
uint8_t *datap;
size_t len = 0;
while (1) {
if (len == 0) {
len = fread(data, 1, 512, file);
if (len == 0) {
break;
}
datap = data;
}
size_t pushed = br_pem_decoder_push(&pem, datap, len);
len -= pushed;
datap += pushed;
switch(br_pem_decoder_event(&pem)) {
const char *name;
int err;
case 0:
break;
case BR_PEM_BEGIN_OBJ:
name = br_pem_decoder_name(&pem);
if (strcmp(name, "CERTIFICATE") == 0) {
memset(&dn_status, 0, sizeof dn_status);
br_x509_decoder_init(&x509, append_dn, &dn_status);
}
break;
case BR_PEM_ERROR:
fputs("br_pem_error!\n", stderr);
break;
case BR_PEM_END_OBJ:
err = br_x509_decoder_last_error(&x509);
if (err) {
fprintf(stderr, _("X509 err code: %d\n"), err);
} else {
// decoded succesfully, now to get the data
br_x509_trust_anchor ta =
{.flags = br_x509_decoder_isCA(&x509) ? BR_X509_TA_CA : 0};
// DN
uint8_t *old = dn_status.dn;
// shorten the DN, if possible
dn_status.dn = realloc(dn_status.dn, dn_status.n);
if (dn_status.dn == NULL) {
perror("realloc()");
dn_status.dn = old;
}
br_x500_name dn = {.data = dn_status.dn, .len = dn_status.n};
// copy into final struct
ta.dn = dn;
br_x509_pkey *pkey = br_x509_decoder_get_pkey(&x509);
br_x509_pkey new_key = { 0 };
if (pkey->key_type == BR_KEYTYPE_RSA) {
br_rsa_public_key k = pkey->key.rsa;
br_rsa_public_key rsa =
{.n = malloc(k.nlen), .nlen = k.nlen,
.e = malloc(k.elen), .elen = k.elen};
if (rsa.n == NULL || rsa.e == NULL) {
perror("malloc()");
goto out;
}
memcpy(rsa.n, k.n, k.nlen);
memcpy(rsa.e, k.e, k.elen);
new_key.key_type = BR_KEYTYPE_RSA;
new_key.key.rsa = rsa;
} else if (pkey->key_type == BR_KEYTYPE_EC) {
br_ec_public_key k = pkey->key.ec;
br_ec_public_key ec =
{.curve = k.curve,
.q = malloc(k.qlen), .qlen = k.qlen};
if (ec.q == NULL) {
perror("malloc()");
goto out;
}
memcpy(ec.q, k.q, k.qlen);
new_key.key_type = BR_KEYTYPE_EC;
new_key.key.ec = ec;
} else {
fputs(_("non supported key\n"), stderr);
}
ta.pkey = new_key;
if (append_ta(tas, ta) == -1) {
goto out;
}
}
break;
}
}
rv = tas->n;
out:
fclose(file);
return rv;
}