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:
@@ -300,6 +300,26 @@ hx509_cert_init(hx509_context context, const Certificate *c, heim_error_t *error
|
|||||||
return cert;
|
return cert;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy a certificate object, but drop any private key assignment.
|
||||||
|
*
|
||||||
|
* @param context A hx509 context.
|
||||||
|
* @param src Certificate object
|
||||||
|
* @param error
|
||||||
|
*
|
||||||
|
* @return Returns an hx509 certificate
|
||||||
|
*
|
||||||
|
* @ingroup hx509_cert
|
||||||
|
*/
|
||||||
|
|
||||||
|
HX509_LIB_FUNCTION hx509_cert HX509_LIB_CALL
|
||||||
|
hx509_cert_copy_no_private_key(hx509_context context,
|
||||||
|
hx509_cert src,
|
||||||
|
heim_error_t *error)
|
||||||
|
{
|
||||||
|
return hx509_cert_init(context, src->data, error);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocate and init an hx509 certificate object containing only a private key
|
* Allocate and init an hx509 certificate object containing only a private key
|
||||||
* (but no Certificate).
|
* (but no Certificate).
|
||||||
|
@@ -154,6 +154,11 @@ typedef enum {
|
|||||||
/* flags to hx509_certs_init */
|
/* flags to hx509_certs_init */
|
||||||
#define HX509_CERTS_CREATE 0x01
|
#define HX509_CERTS_CREATE 0x01
|
||||||
#define HX509_CERTS_UNPROTECT_ALL 0x02
|
#define HX509_CERTS_UNPROTECT_ALL 0x02
|
||||||
|
#define HX509_CERTS_NO_PRIVATE_KEYS 0x04
|
||||||
|
|
||||||
|
/* flags to hx509_certs_store */
|
||||||
|
#define HX509_CERTS_STORE_NO_PRIVATE_KEYS 0x04
|
||||||
|
|
||||||
|
|
||||||
/* flags to hx509_set_error_string */
|
/* flags to hx509_set_error_string */
|
||||||
#define HX509_ERROR_APPEND 0x01
|
#define HX509_ERROR_APPEND 0x01
|
||||||
|
@@ -996,6 +996,16 @@ command = {
|
|||||||
argument = "datetime"
|
argument = "datetime"
|
||||||
help = "check that the certificate's notBefore is after the given time"
|
help = "check that the certificate's notBefore is after the given time"
|
||||||
}
|
}
|
||||||
|
option = {
|
||||||
|
long = "has-private-key"
|
||||||
|
type = "flag"
|
||||||
|
help = "check that the certificate has a private key"
|
||||||
|
}
|
||||||
|
option = {
|
||||||
|
long = "lacks-private-key"
|
||||||
|
type = "flag"
|
||||||
|
help = "check that the certificate does not have a private key"
|
||||||
|
}
|
||||||
name = "acert"
|
name = "acert"
|
||||||
min_args = "1"
|
min_args = "1"
|
||||||
max_args = "1"
|
max_args = "1"
|
||||||
|
@@ -2677,6 +2677,7 @@ acert1_validity(struct acert_options *opt, hx509_cert cert)
|
|||||||
time_t not_after_eq = 0;
|
time_t not_after_eq = 0;
|
||||||
time_t not_after_lt = 0;
|
time_t not_after_lt = 0;
|
||||||
time_t not_after_gt = 0;
|
time_t not_after_gt = 0;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (opt->valid_now_flag) {
|
if (opt->valid_now_flag) {
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
@@ -2684,12 +2685,12 @@ acert1_validity(struct acert_options *opt, hx509_cert cert)
|
|||||||
if (hx509_cert_get_notBefore(cert) > now) {
|
if (hx509_cert_get_notBefore(cert) > now) {
|
||||||
if (opt->verbose_flag)
|
if (opt->verbose_flag)
|
||||||
fprintf(stderr, "Certificate not valid yet\n");
|
fprintf(stderr, "Certificate not valid yet\n");
|
||||||
return -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
if (hx509_cert_get_notAfter(cert) < now) {
|
if (hx509_cert_get_notAfter(cert) < now) {
|
||||||
if (opt->verbose_flag)
|
if (opt->verbose_flag)
|
||||||
fprintf(stderr, "Certificate currently expired\n");
|
fprintf(stderr, "Certificate currently expired\n");
|
||||||
return -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (opt->valid_at_string) {
|
if (opt->valid_at_string) {
|
||||||
@@ -2699,13 +2700,13 @@ acert1_validity(struct acert_options *opt, hx509_cert cert)
|
|||||||
if (opt->verbose_flag)
|
if (opt->verbose_flag)
|
||||||
fprintf(stderr, "Certificate not valid yet at %s\n",
|
fprintf(stderr, "Certificate not valid yet at %s\n",
|
||||||
opt->valid_at_string);
|
opt->valid_at_string);
|
||||||
return -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
if (hx509_cert_get_notAfter(cert) < at) {
|
if (hx509_cert_get_notAfter(cert) < at) {
|
||||||
if (opt->verbose_flag)
|
if (opt->verbose_flag)
|
||||||
fprintf(stderr, "Certificate expired before %s\n",
|
fprintf(stderr, "Certificate expired before %s\n",
|
||||||
opt->valid_at_string);
|
opt->valid_at_string);
|
||||||
return -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2727,17 +2728,29 @@ acert1_validity(struct acert_options *opt, hx509_cert cert)
|
|||||||
(not_before_gt && hx509_cert_get_notBefore(cert) <= not_before_gt)) {
|
(not_before_gt && hx509_cert_get_notBefore(cert) <= not_before_gt)) {
|
||||||
if (opt->verbose_flag)
|
if (opt->verbose_flag)
|
||||||
fprintf(stderr, "Certificate notBefore not as requested\n");
|
fprintf(stderr, "Certificate notBefore not as requested\n");
|
||||||
return -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
if ((not_after_eq && hx509_cert_get_notAfter(cert) != not_after_eq) ||
|
if ((not_after_eq && hx509_cert_get_notAfter(cert) != not_after_eq) ||
|
||||||
(not_after_lt && hx509_cert_get_notAfter(cert) >= not_after_lt) ||
|
(not_after_lt && hx509_cert_get_notAfter(cert) >= not_after_lt) ||
|
||||||
(not_after_gt && hx509_cert_get_notAfter(cert) <= not_after_gt)) {
|
(not_after_gt && hx509_cert_get_notAfter(cert) <= not_after_gt)) {
|
||||||
if (opt->verbose_flag)
|
if (opt->verbose_flag)
|
||||||
fprintf(stderr, "Certificate notAfter not as requested\n");
|
fprintf(stderr, "Certificate notAfter not as requested\n");
|
||||||
return -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
if (opt->has_private_key_flag && !hx509_cert_have_private_key(cert)) {
|
||||||
|
if (opt->verbose_flag)
|
||||||
|
fprintf(stderr, "Certificate does not have a private key\n");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt->lacks_private_key_flag && hx509_cert_have_private_key(cert)) {
|
||||||
|
if (opt->verbose_flag)
|
||||||
|
fprintf(stderr, "Certificate does not have a private key\n");
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -2810,7 +2823,7 @@ acert1(struct acert_options *opt, size_t cert_num, hx509_cert cert, int *matched
|
|||||||
if (e == NULL) {
|
if (e == NULL) {
|
||||||
if (wanted)
|
if (wanted)
|
||||||
return -1;
|
return -1;
|
||||||
return acert1_validity(opt, cert);;
|
return acert1_validity(opt, cert);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < e->len; i++) {
|
for (i = 0; i < e->len; i++) {
|
||||||
|
@@ -63,6 +63,7 @@ struct hx509_certs_data {
|
|||||||
unsigned int ref;
|
unsigned int ref;
|
||||||
struct hx509_keyset_ops *ops;
|
struct hx509_keyset_ops *ops;
|
||||||
void *ops_data;
|
void *ops_data;
|
||||||
|
int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct hx509_keyset_ops *
|
static struct hx509_keyset_ops *
|
||||||
@@ -103,6 +104,7 @@ _hx509_ks_register(hx509_context context, struct hx509_keyset_ops *ops)
|
|||||||
* @param flags list of flags:
|
* @param flags list of flags:
|
||||||
* - HX509_CERTS_CREATE create a new keystore of the specific TYPE.
|
* - HX509_CERTS_CREATE create a new keystore of the specific TYPE.
|
||||||
* - HX509_CERTS_UNPROTECT_ALL fails if any private key failed to be extracted.
|
* - HX509_CERTS_UNPROTECT_ALL fails if any private key failed to be extracted.
|
||||||
|
* - HX509_CERTS_NO_PRIVATE_KEYS does not load or permit adding private keys
|
||||||
* @param lock a lock that unlocks the certificates store, use NULL to
|
* @param lock a lock that unlocks the certificates store, use NULL to
|
||||||
* select no password/certifictes/prompt lock (see @ref page_lock).
|
* select no password/certifictes/prompt lock (see @ref page_lock).
|
||||||
* @param certs return pointer, free with hx509_certs_free().
|
* @param certs return pointer, free with hx509_certs_free().
|
||||||
@@ -158,6 +160,7 @@ hx509_certs_init(hx509_context context,
|
|||||||
hx509_clear_error_string(context);
|
hx509_clear_error_string(context);
|
||||||
return ENOMEM;
|
return ENOMEM;
|
||||||
}
|
}
|
||||||
|
c->flags = flags;
|
||||||
c->ops = ops;
|
c->ops = ops;
|
||||||
c->ref = 1;
|
c->ref = 1;
|
||||||
|
|
||||||
@@ -201,9 +204,12 @@ hx509_certs_destroy(hx509_context context,
|
|||||||
/**
|
/**
|
||||||
* Write the certificate store to stable storage.
|
* Write the certificate store to stable storage.
|
||||||
*
|
*
|
||||||
|
* Use the HX509_CERTS_STORE_NO_PRIVATE_KEYS flag to ensure that no private
|
||||||
|
* keys are stored, even if added.
|
||||||
|
*
|
||||||
* @param context A hx509 context.
|
* @param context A hx509 context.
|
||||||
* @param certs a certificate store to store.
|
* @param certs a certificate store to store.
|
||||||
* @param flags currently unused, use 0.
|
* @param flags currently one flag is defined: HX509_CERTS_STORE_NO_PRIVATE_KEYS
|
||||||
* @param lock a lock that unlocks the certificates store, use NULL to
|
* @param lock a lock that unlocks the certificates store, use NULL to
|
||||||
* select no password/certifictes/prompt lock (see @ref page_lock).
|
* select no password/certifictes/prompt lock (see @ref page_lock).
|
||||||
*
|
*
|
||||||
@@ -485,6 +491,9 @@ hx509_ci_print_names(hx509_context context, void *ctx, hx509_cert c)
|
|||||||
HX509_LIB_FUNCTION int HX509_LIB_CALL
|
HX509_LIB_FUNCTION int HX509_LIB_CALL
|
||||||
hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert)
|
hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert)
|
||||||
{
|
{
|
||||||
|
hx509_cert copy = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (certs->ops->add == NULL) {
|
if (certs->ops->add == NULL) {
|
||||||
hx509_set_error_string(context, 0, ENOENT,
|
hx509_set_error_string(context, 0, ENOENT,
|
||||||
"Keyset type %s doesn't support add operation",
|
"Keyset type %s doesn't support add operation",
|
||||||
@@ -492,7 +501,20 @@ hx509_certs_add(hx509_context context, hx509_certs certs, hx509_cert cert)
|
|||||||
return ENOENT;
|
return ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (*certs->ops->add)(context, certs, certs->ops_data, cert);
|
if ((certs->flags & HX509_CERTS_NO_PRIVATE_KEYS) &&
|
||||||
|
hx509_cert_have_private_key(cert)) {
|
||||||
|
if ((copy = hx509_cert_copy_no_private_key(context, cert,
|
||||||
|
NULL)) == NULL) {
|
||||||
|
hx509_set_error_string(context, 0, ENOMEM,
|
||||||
|
"Could not add certificate to store");
|
||||||
|
return ENOMEM;
|
||||||
|
}
|
||||||
|
cert = copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = (*certs->ops->add)(context, certs, certs->ops_data, cert);
|
||||||
|
hx509_cert_free(copy);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -637,8 +659,7 @@ certs_merge_func(hx509_context context, void *ctx, hx509_cert c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge a certificate store into another. The from store is keep
|
* Merge one certificate store into another. The from store is kept intact.
|
||||||
* intact.
|
|
||||||
*
|
*
|
||||||
* @param context a hx509 context.
|
* @param context a hx509 context.
|
||||||
* @param to the store to merge into.
|
* @param to the store to merge into.
|
||||||
|
@@ -49,7 +49,7 @@ struct ks_file {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
parse_certificate(hx509_context context, const char *fn,
|
parse_certificate(hx509_context context, const char *fn, int flags,
|
||||||
struct hx509_collector *c,
|
struct hx509_collector *c,
|
||||||
const hx509_pem_header *headers,
|
const hx509_pem_header *headers,
|
||||||
const void *data, size_t len,
|
const void *data, size_t len,
|
||||||
@@ -74,6 +74,7 @@ parse_certificate(hx509_context context, const char *fn,
|
|||||||
static int
|
static int
|
||||||
try_decrypt(hx509_context context,
|
try_decrypt(hx509_context context,
|
||||||
struct hx509_collector *collector,
|
struct hx509_collector *collector,
|
||||||
|
int flags,
|
||||||
const AlgorithmIdentifier *alg,
|
const AlgorithmIdentifier *alg,
|
||||||
const EVP_CIPHER *c,
|
const EVP_CIPHER *c,
|
||||||
const void *ivdata,
|
const void *ivdata,
|
||||||
@@ -122,12 +123,9 @@ try_decrypt(hx509_context context,
|
|||||||
EVP_CIPHER_CTX_cleanup(&ctx);
|
EVP_CIPHER_CTX_cleanup(&ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = _hx509_collector_private_key_add(context,
|
if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS))
|
||||||
collector,
|
ret = _hx509_collector_private_key_add(context, collector, alg, NULL,
|
||||||
alg,
|
&clear, NULL);
|
||||||
NULL,
|
|
||||||
&clear,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
memset_s(clear.data, clear.length, 0, clear.length);
|
memset_s(clear.data, clear.length, 0, clear.length);
|
||||||
free(clear.data);
|
free(clear.data);
|
||||||
@@ -138,7 +136,7 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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,
|
struct hx509_collector *c,
|
||||||
const hx509_pem_header *headers,
|
const hx509_pem_header *headers,
|
||||||
const void *data, size_t length,
|
const void *data, size_t length,
|
||||||
@@ -146,28 +144,28 @@ parse_pkcs8_private_key(hx509_context context, const char *fn,
|
|||||||
{
|
{
|
||||||
PKCS8PrivateKeyInfo ki;
|
PKCS8PrivateKeyInfo ki;
|
||||||
heim_octet_string keydata;
|
heim_octet_string keydata;
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);
|
ret = decode_PKCS8PrivateKeyInfo(data, length, &ki, NULL);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) {
|
||||||
keydata.data = rk_UNCONST(data);
|
keydata.data = rk_UNCONST(data);
|
||||||
keydata.length = length;
|
keydata.length = length;
|
||||||
|
|
||||||
ret = _hx509_collector_private_key_add(context,
|
ret = _hx509_collector_private_key_add(context,
|
||||||
c,
|
c,
|
||||||
&ki.privateKeyAlgorithm,
|
&ki.privateKeyAlgorithm,
|
||||||
NULL,
|
NULL,
|
||||||
&ki.privateKey,
|
&ki.privateKey,
|
||||||
&keydata);
|
&keydata);
|
||||||
|
}
|
||||||
free_PKCS8PrivateKeyInfo(&ki);
|
free_PKCS8PrivateKeyInfo(&ki);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
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,
|
struct hx509_collector *c,
|
||||||
const hx509_pem_header *headers,
|
const hx509_pem_header *headers,
|
||||||
const void *data, size_t len,
|
const void *data, size_t len,
|
||||||
@@ -271,7 +269,7 @@ parse_pem_private_key(hx509_context context, const char *fn,
|
|||||||
password = pw->val[i];
|
password = pw->val[i];
|
||||||
passwordlen = strlen(password);
|
passwordlen = strlen(password);
|
||||||
|
|
||||||
ret = try_decrypt(context, c, ai, cipher, ivdata,
|
ret = try_decrypt(context, c, flags, ai, cipher, ivdata,
|
||||||
password, passwordlen, data, len);
|
password, passwordlen, data, len);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
decrypted = 1;
|
decrypted = 1;
|
||||||
@@ -292,14 +290,14 @@ parse_pem_private_key(hx509_context context, const char *fn,
|
|||||||
|
|
||||||
ret = hx509_lock_prompt(lock, &prompt);
|
ret = hx509_lock_prompt(lock, &prompt);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = try_decrypt(context, c, ai, cipher, ivdata, password,
|
ret = try_decrypt(context, c, flags, ai, cipher, ivdata,
|
||||||
strlen(password), data, len);
|
password, strlen(password), data, len);
|
||||||
/* XXX add password to lock password collection ? */
|
/* XXX add password to lock password collection ? */
|
||||||
memset_s(password, sizeof(password), 0, sizeof(password));
|
memset_s(password, sizeof(password), 0, sizeof(password));
|
||||||
}
|
}
|
||||||
free(ivdata);
|
free(ivdata);
|
||||||
|
|
||||||
} else {
|
} else if (!(flags & HX509_CERTS_NO_PRIVATE_KEYS)) {
|
||||||
heim_octet_string keydata;
|
heim_octet_string keydata;
|
||||||
|
|
||||||
keydata.data = rk_UNCONST(data);
|
keydata.data = rk_UNCONST(data);
|
||||||
@@ -315,7 +313,7 @@ parse_pem_private_key(hx509_context context, const char *fn,
|
|||||||
|
|
||||||
struct pem_formats {
|
struct pem_formats {
|
||||||
const char *name;
|
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 hx509_pem_header *, const void *, size_t,
|
||||||
const AlgorithmIdentifier *);
|
const AlgorithmIdentifier *);
|
||||||
const AlgorithmIdentifier *(*ai)(void);
|
const AlgorithmIdentifier *(*ai)(void);
|
||||||
@@ -347,10 +345,11 @@ pem_func(hx509_context context, const char *type,
|
|||||||
const char *q = formats[j].name;
|
const char *q = formats[j].name;
|
||||||
if (strcasecmp(type, q) == 0) {
|
if (strcasecmp(type, q) == 0) {
|
||||||
const AlgorithmIdentifier *ai = NULL;
|
const AlgorithmIdentifier *ai = NULL;
|
||||||
|
|
||||||
if (formats[j].ai != NULL)
|
if (formats[j].ai != NULL)
|
||||||
ai = (*formats[j].ai)();
|
ai = (*formats[j].ai)();
|
||||||
|
|
||||||
ret = (*formats[j].func)(context, NULL, pem_ctx->c,
|
ret = (*formats[j].func)(context, NULL, pem_ctx->flags, pem_ctx->c,
|
||||||
header, data, len, ai);
|
header, data, len, ai);
|
||||||
if (ret && (pem_ctx->flags & HX509_CERTS_UNPROTECT_ALL)) {
|
if (ret && (pem_ctx->flags & HX509_CERTS_UNPROTECT_ALL)) {
|
||||||
hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
|
hx509_set_error_string(context, HX509_ERROR_APPEND, ret,
|
||||||
@@ -468,10 +467,12 @@ file_init_common(hx509_context context,
|
|||||||
|
|
||||||
for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
|
for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
|
||||||
const AlgorithmIdentifier *ai = NULL;
|
const AlgorithmIdentifier *ai = NULL;
|
||||||
|
|
||||||
if (formats[i].ai != NULL)
|
if (formats[i].ai != NULL)
|
||||||
ai = (*formats[i].ai)();
|
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)
|
if (ret == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -539,6 +540,7 @@ file_free(hx509_certs certs, void *data)
|
|||||||
struct store_ctx {
|
struct store_ctx {
|
||||||
FILE *f;
|
FILE *f;
|
||||||
outformat format;
|
outformat format;
|
||||||
|
int store_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int HX509_LIB_CALL
|
static int HX509_LIB_CALL
|
||||||
@@ -563,7 +565,8 @@ store_func(hx509_context context, void *ctx, hx509_cert c)
|
|||||||
if (data.data) {
|
if (data.data) {
|
||||||
fwrite(data.data, data.length, 1, sc->f);
|
fwrite(data.data, data.length, 1, sc->f);
|
||||||
free(data.data);
|
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);
|
hx509_private_key key = _hx509_cert_private_key(c);
|
||||||
|
|
||||||
ret = _hx509_private_key_export(context, key,
|
ret = _hx509_private_key_export(context, key,
|
||||||
@@ -573,7 +576,8 @@ store_func(hx509_context context, void *ctx, hx509_cert c)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case USE_PEM:
|
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;
|
heim_octet_string priv_key;
|
||||||
hx509_private_key key = _hx509_cert_private_key(c);
|
hx509_private_key key = _hx509_cert_private_key(c);
|
||||||
|
|
||||||
@@ -658,6 +662,7 @@ file_store(hx509_context context,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
rk_cloexec_file(sc.f);
|
rk_cloexec_file(sc.f);
|
||||||
|
sc.store_flags = flags;
|
||||||
sc.format = ksf->format;
|
sc.format = ksf->format;
|
||||||
|
|
||||||
ret = hx509_certs_iter_f(context, ksf->certs, store_func, &sc);
|
ret = hx509_certs_iter_f(context, ksf->certs, store_func, &sc);
|
||||||
|
@@ -328,6 +328,13 @@ keychain_init(hx509_context context,
|
|||||||
{
|
{
|
||||||
struct ks_keychain *ctx;
|
struct ks_keychain *ctx;
|
||||||
|
|
||||||
|
if (flags & HX509_CERTS_NO_PRIVATE_KEYS) {
|
||||||
|
hx509_set_error_string(context, 0, ENOTSUP,
|
||||||
|
"KEYCHAIN store does not support not reading "
|
||||||
|
"private keys");
|
||||||
|
return ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
ctx = calloc(1, sizeof(*ctx));
|
ctx = calloc(1, sizeof(*ctx));
|
||||||
if (ctx == NULL) {
|
if (ctx == NULL) {
|
||||||
hx509_clear_error_string(context);
|
hx509_clear_error_string(context);
|
||||||
|
@@ -820,6 +820,13 @@ p11_init(hx509_context context,
|
|||||||
|
|
||||||
*data = NULL;
|
*data = NULL;
|
||||||
|
|
||||||
|
if (flags & HX509_CERTS_NO_PRIVATE_KEYS) {
|
||||||
|
hx509_set_error_string(context, 0, ENOTSUP,
|
||||||
|
"PKCS#11 store does not support "
|
||||||
|
"HX509_CERTS_NO_PRIVATE_KEYS flag");
|
||||||
|
return ENOTSUP;
|
||||||
|
}
|
||||||
|
|
||||||
if (residue == NULL || residue[0] == '\0') {
|
if (residue == NULL || residue[0] == '\0') {
|
||||||
hx509_set_error_string(context, 0, EINVAL,
|
hx509_set_error_string(context, 0, EINVAL,
|
||||||
"PKCS#11 store not specified");
|
"PKCS#11 store not specified");
|
||||||
|
@@ -36,10 +36,12 @@
|
|||||||
struct ks_pkcs12 {
|
struct ks_pkcs12 {
|
||||||
hx509_certs certs;
|
hx509_certs certs;
|
||||||
char *fn;
|
char *fn;
|
||||||
|
unsigned int store_no_priv_keys;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*collector_func)(hx509_context,
|
typedef int (*collector_func)(hx509_context,
|
||||||
struct hx509_collector *,
|
struct hx509_collector *,
|
||||||
|
int,
|
||||||
const void *, size_t,
|
const void *, size_t,
|
||||||
const PKCS12_Attributes *);
|
const PKCS12_Attributes *);
|
||||||
|
|
||||||
@@ -49,8 +51,9 @@ struct type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
parse_pkcs12_type(hx509_context, struct hx509_collector *, const heim_oid *,
|
parse_pkcs12_type(hx509_context, struct hx509_collector *, int,
|
||||||
const void *, size_t, const PKCS12_Attributes *);
|
const heim_oid *, const void *, size_t,
|
||||||
|
const PKCS12_Attributes *);
|
||||||
|
|
||||||
|
|
||||||
static const PKCS12_Attribute *
|
static const PKCS12_Attribute *
|
||||||
@@ -68,6 +71,7 @@ find_attribute(const PKCS12_Attributes *attrs, const heim_oid *oid)
|
|||||||
static int
|
static int
|
||||||
keyBag_parser(hx509_context context,
|
keyBag_parser(hx509_context context,
|
||||||
struct hx509_collector *c,
|
struct hx509_collector *c,
|
||||||
|
int flags,
|
||||||
const void *data, size_t length,
|
const void *data, size_t length,
|
||||||
const PKCS12_Attributes *attrs)
|
const PKCS12_Attributes *attrs)
|
||||||
{
|
{
|
||||||
@@ -76,6 +80,9 @@ keyBag_parser(hx509_context context,
|
|||||||
const heim_octet_string *os = NULL;
|
const heim_octet_string *os = NULL;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (flags & HX509_CERTS_NO_PRIVATE_KEYS)
|
||||||
|
return 0;
|
||||||
|
|
||||||
attr = find_attribute(attrs, &asn1_oid_id_pkcs_9_at_localKeyId);
|
attr = find_attribute(attrs, &asn1_oid_id_pkcs_9_at_localKeyId);
|
||||||
if (attr)
|
if (attr)
|
||||||
os = &attr->attrValues;
|
os = &attr->attrValues;
|
||||||
@@ -97,6 +104,7 @@ keyBag_parser(hx509_context context,
|
|||||||
static int
|
static int
|
||||||
ShroudedKeyBag_parser(hx509_context context,
|
ShroudedKeyBag_parser(hx509_context context,
|
||||||
struct hx509_collector *c,
|
struct hx509_collector *c,
|
||||||
|
int flags,
|
||||||
const void *data, size_t length,
|
const void *data, size_t length,
|
||||||
const PKCS12_Attributes *attrs)
|
const PKCS12_Attributes *attrs)
|
||||||
{
|
{
|
||||||
@@ -119,7 +127,8 @@ ShroudedKeyBag_parser(hx509_context context,
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = keyBag_parser(context, c, content.data, content.length, attrs);
|
ret = keyBag_parser(context, c, flags, content.data, content.length,
|
||||||
|
attrs);
|
||||||
der_free_octet_string(&content);
|
der_free_octet_string(&content);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -127,6 +136,7 @@ ShroudedKeyBag_parser(hx509_context context,
|
|||||||
static int
|
static int
|
||||||
certBag_parser(hx509_context context,
|
certBag_parser(hx509_context context,
|
||||||
struct hx509_collector *c,
|
struct hx509_collector *c,
|
||||||
|
int flags,
|
||||||
const void *data, size_t length,
|
const void *data, size_t length,
|
||||||
const PKCS12_Attributes *attrs)
|
const PKCS12_Attributes *attrs)
|
||||||
{
|
{
|
||||||
@@ -191,6 +201,7 @@ certBag_parser(hx509_context context,
|
|||||||
static int
|
static int
|
||||||
parse_safe_content(hx509_context context,
|
parse_safe_content(hx509_context context,
|
||||||
struct hx509_collector *c,
|
struct hx509_collector *c,
|
||||||
|
int flags,
|
||||||
const unsigned char *p, size_t len)
|
const unsigned char *p, size_t len)
|
||||||
{
|
{
|
||||||
PKCS12_SafeContents sc;
|
PKCS12_SafeContents sc;
|
||||||
@@ -206,6 +217,7 @@ parse_safe_content(hx509_context context,
|
|||||||
for (i = 0; i < sc.len ; i++)
|
for (i = 0; i < sc.len ; i++)
|
||||||
parse_pkcs12_type(context,
|
parse_pkcs12_type(context,
|
||||||
c,
|
c,
|
||||||
|
flags,
|
||||||
&sc.val[i].bagId,
|
&sc.val[i].bagId,
|
||||||
sc.val[i].bagValue.data,
|
sc.val[i].bagValue.data,
|
||||||
sc.val[i].bagValue.length,
|
sc.val[i].bagValue.length,
|
||||||
@@ -218,6 +230,7 @@ parse_safe_content(hx509_context context,
|
|||||||
static int
|
static int
|
||||||
safeContent_parser(hx509_context context,
|
safeContent_parser(hx509_context context,
|
||||||
struct hx509_collector *c,
|
struct hx509_collector *c,
|
||||||
|
int flags,
|
||||||
const void *data, size_t length,
|
const void *data, size_t length,
|
||||||
const PKCS12_Attributes *attrs)
|
const PKCS12_Attributes *attrs)
|
||||||
{
|
{
|
||||||
@@ -227,7 +240,7 @@ safeContent_parser(hx509_context context,
|
|||||||
ret = decode_PKCS12_OctetString(data, length, &os, NULL);
|
ret = decode_PKCS12_OctetString(data, length, &os, NULL);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
ret = parse_safe_content(context, c, os.data, os.length);
|
ret = parse_safe_content(context, c, flags, os.data, os.length);
|
||||||
der_free_octet_string(&os);
|
der_free_octet_string(&os);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -235,6 +248,7 @@ safeContent_parser(hx509_context context,
|
|||||||
static int
|
static int
|
||||||
encryptedData_parser(hx509_context context,
|
encryptedData_parser(hx509_context context,
|
||||||
struct hx509_collector *c,
|
struct hx509_collector *c,
|
||||||
|
int flags,
|
||||||
const void *data, size_t length,
|
const void *data, size_t length,
|
||||||
const PKCS12_Attributes *attrs)
|
const PKCS12_Attributes *attrs)
|
||||||
{
|
{
|
||||||
@@ -253,7 +267,8 @@ encryptedData_parser(hx509_context context,
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0)
|
if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0)
|
||||||
ret = parse_safe_content(context, c, content.data, content.length);
|
ret = parse_safe_content(context, c, flags,
|
||||||
|
content.data, content.length);
|
||||||
|
|
||||||
der_free_octet_string(&content);
|
der_free_octet_string(&content);
|
||||||
der_free_oid(&contentType);
|
der_free_oid(&contentType);
|
||||||
@@ -263,6 +278,7 @@ encryptedData_parser(hx509_context context,
|
|||||||
static int
|
static int
|
||||||
envelopedData_parser(hx509_context context,
|
envelopedData_parser(hx509_context context,
|
||||||
struct hx509_collector *c,
|
struct hx509_collector *c,
|
||||||
|
int flags,
|
||||||
const void *data, size_t length,
|
const void *data, size_t length,
|
||||||
const PKCS12_Attributes *attrs)
|
const PKCS12_Attributes *attrs)
|
||||||
{
|
{
|
||||||
@@ -290,7 +306,8 @@ envelopedData_parser(hx509_context context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0)
|
if (der_heim_oid_cmp(&contentType, &asn1_oid_id_pkcs7_data) == 0)
|
||||||
ret = parse_safe_content(context, c, content.data, content.length);
|
ret = parse_safe_content(context, c, flags,
|
||||||
|
content.data, content.length);
|
||||||
|
|
||||||
der_free_octet_string(&content);
|
der_free_octet_string(&content);
|
||||||
der_free_oid(&contentType);
|
der_free_oid(&contentType);
|
||||||
@@ -311,6 +328,7 @@ struct type bagtypes[] = {
|
|||||||
static void
|
static void
|
||||||
parse_pkcs12_type(hx509_context context,
|
parse_pkcs12_type(hx509_context context,
|
||||||
struct hx509_collector *c,
|
struct hx509_collector *c,
|
||||||
|
int flags,
|
||||||
const heim_oid *oid,
|
const heim_oid *oid,
|
||||||
const void *data, size_t length,
|
const void *data, size_t length,
|
||||||
const PKCS12_Attributes *attrs)
|
const PKCS12_Attributes *attrs)
|
||||||
@@ -319,7 +337,7 @@ parse_pkcs12_type(hx509_context context,
|
|||||||
|
|
||||||
for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++)
|
for (i = 0; i < sizeof(bagtypes)/sizeof(bagtypes[0]); i++)
|
||||||
if (der_heim_oid_cmp(bagtypes[i].oid, oid) == 0)
|
if (der_heim_oid_cmp(bagtypes[i].oid, oid) == 0)
|
||||||
(*bagtypes[i].func)(context, c, data, length, attrs);
|
(*bagtypes[i].func)(context, c, flags, data, length, attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@@ -429,6 +447,7 @@ p12_init(hx509_context context,
|
|||||||
for (i = 0; i < as.len; i++)
|
for (i = 0; i < as.len; i++)
|
||||||
parse_pkcs12_type(context,
|
parse_pkcs12_type(context,
|
||||||
c,
|
c,
|
||||||
|
flags,
|
||||||
&as.val[i].contentType,
|
&as.val[i].contentType,
|
||||||
as.val[i].content->data,
|
as.val[i].content->data,
|
||||||
as.val[i].content->length,
|
as.val[i].content->length,
|
||||||
@@ -492,10 +511,15 @@ addBag(hx509_context context,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct store_func_ctx {
|
||||||
|
PKCS12_AuthenticatedSafe as;
|
||||||
|
int store_flags;
|
||||||
|
};
|
||||||
|
|
||||||
static int HX509_LIB_CALL
|
static int HX509_LIB_CALL
|
||||||
store_func(hx509_context context, void *ctx, hx509_cert c)
|
store_func(hx509_context context, void *d, hx509_cert c)
|
||||||
{
|
{
|
||||||
PKCS12_AuthenticatedSafe *as = ctx;
|
struct store_func_ctx *ctx = d;
|
||||||
PKCS12_OctetString os;
|
PKCS12_OctetString os;
|
||||||
PKCS12_CertBag cb;
|
PKCS12_CertBag cb;
|
||||||
size_t size;
|
size_t size;
|
||||||
@@ -528,9 +552,11 @@ store_func(hx509_context context, void *ctx, hx509_cert c)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ret = addBag(context, as, &asn1_oid_id_pkcs12_certBag, os.data, os.length);
|
ret = addBag(context, &ctx->as, &asn1_oid_id_pkcs12_certBag, os.data,
|
||||||
|
os.length);
|
||||||
|
|
||||||
if (_hx509_cert_private_key_exportable(c)) {
|
if (_hx509_cert_private_key_exportable(c) &&
|
||||||
|
!(ctx->store_flags & HX509_CERTS_STORE_NO_PRIVATE_KEYS)) {
|
||||||
hx509_private_key key = _hx509_cert_private_key(c);
|
hx509_private_key key = _hx509_cert_private_key(c);
|
||||||
PKCS8PrivateKeyInfo pki;
|
PKCS8PrivateKeyInfo pki;
|
||||||
|
|
||||||
@@ -561,7 +587,8 @@ store_func(hx509_context context, void *ctx, hx509_cert c)
|
|||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = addBag(context, as, &asn1_oid_id_pkcs12_keyBag, os.data, os.length);
|
ret = addBag(context, &ctx->as, &asn1_oid_id_pkcs12_keyBag, os.data,
|
||||||
|
os.length);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -576,21 +603,22 @@ p12_store(hx509_context context,
|
|||||||
{
|
{
|
||||||
struct ks_pkcs12 *p12 = data;
|
struct ks_pkcs12 *p12 = data;
|
||||||
PKCS12_PFX pfx;
|
PKCS12_PFX pfx;
|
||||||
PKCS12_AuthenticatedSafe as;
|
struct store_func_ctx ctx;
|
||||||
PKCS12_OctetString asdata;
|
PKCS12_OctetString asdata;
|
||||||
size_t size;
|
size_t size;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
memset(&as, 0, sizeof(as));
|
memset(&ctx, 0, sizeof(ctx));
|
||||||
memset(&pfx, 0, sizeof(pfx));
|
memset(&pfx, 0, sizeof(pfx));
|
||||||
|
ctx.store_flags = flags;
|
||||||
|
|
||||||
ret = hx509_certs_iter_f(context, p12->certs, store_func, &as);
|
ret = hx509_certs_iter_f(context, p12->certs, store_func, &ctx);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length,
|
ASN1_MALLOC_ENCODE(PKCS12_AuthenticatedSafe, asdata.data, asdata.length,
|
||||||
&as, &size, ret);
|
&ctx.as, &size, ret);
|
||||||
free_PKCS12_AuthenticatedSafe(&as);
|
free_PKCS12_AuthenticatedSafe(&ctx.as);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@@ -642,7 +670,7 @@ p12_store(hx509_context context,
|
|||||||
free(asdata.data);
|
free(asdata.data);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
free_PKCS12_AuthenticatedSafe(&as);
|
free_PKCS12_AuthenticatedSafe(&ctx.as);
|
||||||
free_PKCS12_PFX(&pfx);
|
free_PKCS12_PFX(&pfx);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
Reference in New Issue
Block a user