hx509: private key exclusion options

Add two ways to exclude private keys when dealing with an hx509
certificate store.  One as a load option (load no private keys, never
add private keys), one as a store option (store no private keys).

This is useful for CA code so it can have a single store with the
issuer's credentials _and_ the chain for it, and copy those to a store
with the issued certificate and _not_ accidentally include the issuer's
private key.

It would be much safer still to flip the default for this flag, but that
could break out-of-tree libhx509 dependents.
This commit is contained in:
Nicolas Williams
2019-12-06 17:11:01 -06:00
parent 3c0d1258ce
commit e515745996
9 changed files with 177 additions and 61 deletions

View File

@@ -49,7 +49,7 @@ struct ks_file {
*/
static int
parse_certificate(hx509_context context, const char *fn,
parse_certificate(hx509_context context, const char *fn, int flags,
struct hx509_collector *c,
const hx509_pem_header *headers,
const void *data, size_t len,
@@ -74,6 +74,7 @@ parse_certificate(hx509_context context, const char *fn,
static int
try_decrypt(hx509_context context,
struct hx509_collector *collector,
int flags,
const AlgorithmIdentifier *alg,
const EVP_CIPHER *c,
const void *ivdata,
@@ -122,12 +123,9 @@ try_decrypt(hx509_context context,
EVP_CIPHER_CTX_cleanup(&ctx);
}
ret = _hx509_collector_private_key_add(context,
collector,
alg,
NULL,
&clear,
NULL);
if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS))
ret = _hx509_collector_private_key_add(context, collector, alg, NULL,
&clear, NULL);
memset_s(clear.data, clear.length, 0, clear.length);
free(clear.data);
@@ -138,7 +136,7 @@ out:
}
static int
parse_pkcs8_private_key(hx509_context context, const char *fn,
parse_pkcs8_private_key(hx509_context context, const char *fn, int flags,
struct hx509_collector *c,
const hx509_pem_header *headers,
const void *data, size_t length,
@@ -146,28 +144,28 @@ parse_pkcs8_private_key(hx509_context context, const char *fn,
{
PKCS8PrivateKeyInfo ki;
heim_octet_string keydata;
int ret;
ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);
if (ret)
return ret;
keydata.data = rk_UNCONST(data);
keydata.length = length;
ret = _hx509_collector_private_key_add(context,
c,
&ki.privateKeyAlgorithm,
NULL,
&ki.privateKey,
&keydata);
if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) {
keydata.data = rk_UNCONST(data);
keydata.length = length;
ret = _hx509_collector_private_key_add(context,
c,
&ki.privateKeyAlgorithm,
NULL,
&ki.privateKey,
&keydata);
}
free_PKCS8PrivateKeyInfo(&ki);
return ret;
}
static int
parse_pem_private_key(hx509_context context, const char *fn,
parse_pem_private_key(hx509_context context, const char *fn, int flags,
struct hx509_collector *c,
const hx509_pem_header *headers,
const void *data, size_t len,
@@ -271,7 +269,7 @@ parse_pem_private_key(hx509_context context, const char *fn,
password = pw->val[i];
passwordlen = strlen(password);
ret = try_decrypt(context, c, ai, cipher, ivdata,
ret = try_decrypt(context, c, flags, ai, cipher, ivdata,
password, passwordlen, data, len);
if (ret == 0) {
decrypted = 1;
@@ -292,21 +290,21 @@ parse_pem_private_key(hx509_context context, const char *fn,
ret = hx509_lock_prompt(lock, &prompt);
if (ret == 0)
ret = try_decrypt(context, c, ai, cipher, ivdata, password,
strlen(password), data, len);
ret = try_decrypt(context, c, flags, ai, cipher, ivdata,
password, strlen(password), data, len);
/* XXX add password to lock password collection ? */
memset_s(password, sizeof(password), 0, sizeof(password));
}
free(ivdata);
} else {
} else if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) {
heim_octet_string keydata;
keydata.data = rk_UNCONST(data);
keydata.length = len;
ret = _hx509_collector_private_key_add(context, c, ai, NULL,
&keydata, NULL);
ret = _hx509_collector_private_key_add(context, c, ai, NULL,
&keydata, NULL);
}
return ret;
@@ -315,7 +313,7 @@ parse_pem_private_key(hx509_context context, const char *fn,
struct pem_formats {
const char *name;
int (*func)(hx509_context, const char *, struct hx509_collector *,
int (*func)(hx509_context, const char *, int, struct hx509_collector *,
const hx509_pem_header *, const void *, size_t,
const AlgorithmIdentifier *);
const AlgorithmIdentifier *(*ai)(void);
@@ -347,11 +345,12 @@ pem_func(hx509_context context, const char *type,
const char *q = formats[j].name;
if (strcasecmp(type, q) == 0) {
const AlgorithmIdentifier *ai = NULL;
if (formats[j].ai != NULL)
ai = (*formats[j].ai)();
ret = (*formats[j].func)(context, NULL, pem_ctx->c,
header, data, len, ai);
ret = (*formats[j].func)(context, NULL, pem_ctx->flags, pem_ctx->c,
header, data, len, ai);
if (ret && (pem_ctx->flags & HX509_CERTS_UNPROTECT_ALL)) {
hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
"Failed parseing PEM format %s", type);
@@ -468,10 +467,12 @@ file_init_common(hx509_context context,
for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
const AlgorithmIdentifier *ai = NULL;
if (formats[i].ai != NULL)
ai = (*formats[i].ai)();
ret = (*formats[i].func)(context, p, pem_ctx.c, NULL, ptr, length, ai);
ret = (*formats[i].func)(context, p, pem_ctx.flags, pem_ctx.c,
NULL, ptr, length, ai);
if (ret == 0)
break;
}
@@ -539,6 +540,7 @@ file_free(hx509_certs certs, void *data)
struct store_ctx {
FILE *f;
outformat format;
int store_flags;
};
static int HX509_LIB_CALL
@@ -563,7 +565,8 @@ store_func(hx509_context context, void *ctx, hx509_cert c)
if (data.data) {
fwrite(data.data, data.length, 1, sc->f);
free(data.data);
} else if (_hx509_cert_private_key_exportable(c)) {
} else if (_hx509_cert_private_key_exportable(c) &&
!(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) {
hx509_private_key key = _hx509_cert_private_key(c);
ret = _hx509_private_key_export(context, key,
@@ -573,7 +576,8 @@ store_func(hx509_context context, void *ctx, hx509_cert c)
}
break;
case USE_PEM:
if (_hx509_cert_private_key_exportable(c)) {
if (_hx509_cert_private_key_exportable(c) &&
!(sc->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) {
heim_octet_string priv_key;
hx509_private_key key = _hx509_cert_private_key(c);
@@ -658,6 +662,7 @@ file_store(hx509_context context,
return ret;
}
rk_cloexec_file(sc.f);
sc.store_flags = flags;
sc.format = ksf->format;
ret = hx509_certs_iter_f(context, ksf->certs, store_func, &sc);