diff --git a/lib/hx509/collector.c b/lib/hx509/collector.c index ab36fe2dc..1a44de00a 100644 --- a/lib/hx509/collector.c +++ b/lib/hx509/collector.c @@ -145,6 +145,7 @@ _hx509_collector_private_key_add(hx509_context context, } else { ret = _hx509_parse_private_key(context, alg, key_data->data, key_data->length, + HX509_KEY_FORMAT_DER, &key->private_key); if (ret) goto out; diff --git a/lib/hx509/crypto.c b/lib/hx509/crypto.c index 875b09cf7..a38226d94 100644 --- a/lib/hx509/crypto.c +++ b/lib/hx509/crypto.c @@ -53,9 +53,11 @@ struct hx509_private_key_ops { SubjectPublicKeyInfo *); int (*export)(hx509_context context, const hx509_private_key, + hx509_key_format_t, heim_octet_string *); int (*import)(hx509_context, const AlgorithmIdentifier *, - const void *, size_t, hx509_private_key); + const void *, size_t, hx509_key_format_t, + hx509_private_key); int (*generate_private_key)(hx509_context, struct hx509_generate_private_context *, hx509_private_key); @@ -750,18 +752,27 @@ rsa_private_key_import(hx509_context context, const AlgorithmIdentifier *keyai, const void *data, size_t len, + hx509_key_format_t format, hx509_private_key private_key) { - const unsigned char *p = data; + switch (format) { + case HX509_KEY_FORMAT_DER: { + const unsigned char *p = data; + + private_key->private_key.rsa = + d2i_RSAPrivateKey(NULL, &p, len); + if (private_key->private_key.rsa == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to parse RSA key"); + return HX509_PARSING_KEY_FAILED; + } + private_key->signature_alg = ASN1_OID_ID_PKCS1_SHA1WITHRSAENCRYPTION; + break; - private_key->private_key.rsa = - d2i_RSAPrivateKey(NULL, &p, len); - if (private_key->private_key.rsa == NULL) { - hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, - "Failed to parse RSA key"); - return HX509_PARSING_KEY_FAILED; } - private_key->signature_alg = ASN1_OID_ID_PKCS1_SHA1WITHRSAENCRYPTION; + default: + return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; + } return 0; } @@ -844,6 +855,7 @@ rsa_generate_private_key(hx509_context context, static int rsa_private_key_export(hx509_context context, const hx509_private_key key, + hx509_key_format_t format, heim_octet_string *data) { int ret; @@ -851,25 +863,32 @@ rsa_private_key_export(hx509_context context, data->data = NULL; data->length = 0; - ret = i2d_RSAPrivateKey(key->private_key.rsa, NULL); - if (ret <= 0) { - ret = EINVAL; - hx509_set_error_string(context, 0, ret, + switch (format) { + case HX509_KEY_FORMAT_DER: + + ret = i2d_RSAPrivateKey(key->private_key.rsa, NULL); + if (ret <= 0) { + ret = EINVAL; + hx509_set_error_string(context, 0, ret, "Private key is not exportable"); - return ret; - } + return ret; + } - data->data = malloc(ret); - if (data->data == NULL) { - ret = ENOMEM; - hx509_set_error_string(context, 0, ret, "malloc out of memory"); - return ret; - } - data->length = ret; + data->data = malloc(ret); + if (data->data == NULL) { + ret = ENOMEM; + hx509_set_error_string(context, 0, ret, "malloc out of memory"); + return ret; + } + data->length = ret; - { - unsigned char *p = data->data; - i2d_RSAPrivateKey(key->private_key.rsa, &p); + { + unsigned char *p = data->data; + i2d_RSAPrivateKey(key->private_key.rsa, &p); + } + break; + default: + return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; } return 0; @@ -915,9 +934,10 @@ ecdsa_private_key2SPKI(hx509_context context, static int ecdsa_private_key_export(hx509_context context, const hx509_private_key key, + hx509_key_format_t format, heim_octet_string *data) { - return ENOMEM; + return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; } static int @@ -925,6 +945,7 @@ ecdsa_private_key_import(hx509_context context, const AlgorithmIdentifier *keyai, const void *data, size_t len, + hx509_key_format_t format, hx509_private_key private_key) { const unsigned char *p = data; @@ -959,13 +980,21 @@ ecdsa_private_key_import(hx509_context context, pkey = &key; } - private_key->private_key.ecdsa = d2i_ECPrivateKey(pkey, &p, len); - if (private_key->private_key.ecdsa == NULL) { - hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, - "Failed to parse EC private key"); - return HX509_PARSING_KEY_FAILED; + switch (format) { + case HX509_KEY_FORMAT_DER: + + private_key->private_key.ecdsa = d2i_ECPrivateKey(pkey, &p, len); + if (private_key->private_key.ecdsa == NULL) { + hx509_set_error_string(context, 0, HX509_PARSING_KEY_FAILED, + "Failed to parse EC private key"); + return HX509_PARSING_KEY_FAILED; + } + private_key->signature_alg = ASN1_OID_ID_ECDSA_WITH_SHA256; + break; + + default: + return HX509_CRYPTO_KEY_FORMAT_UNSUPPORTED; } - private_key->signature_alg = ASN1_OID_ID_ECDSA_WITH_SHA256; return 0; } @@ -1733,6 +1762,7 @@ _hx509_parse_private_key(hx509_context context, const AlgorithmIdentifier *keyai, const void *data, size_t len, + hx509_key_format_t format, hx509_private_key *private_key) { struct hx509_private_key_ops *ops; @@ -1752,7 +1782,7 @@ _hx509_parse_private_key(hx509_context context, return ret; } - ret = (*ops->import)(context, keyai, data, len, *private_key); + ret = (*ops->import)(context, keyai, data, len, format, *private_key); if (ret) _hx509_private_key_free(private_key); @@ -2045,13 +2075,14 @@ _hx509_private_key_get_internal(hx509_context context, int _hx509_private_key_export(hx509_context context, const hx509_private_key key, + hx509_key_format_t format, heim_octet_string *data) { if (key->ops->export == NULL) { hx509_clear_error_string(context); return HX509_UNIMPLEMENTED_OPERATION; } - return (*key->ops->export)(context, key, data); + return (*key->ops->export)(context, key, format, data); } /* diff --git a/lib/hx509/hx509.h b/lib/hx509/hx509.h index b6eeac9d1..e93df16d6 100644 --- a/lib/hx509/hx509.h +++ b/lib/hx509/hx509.h @@ -76,6 +76,13 @@ enum { HX509_CRYPTO_PADDING_NONE = 1 }; +enum { + HX509_KEY_FORMAT_GUESS = 0, + HX509_KEY_FORMAT_DER = 1, + HX509_KEY_FORMAT_WIN_BACKUPKEY = 2 +}; +typedef uint32_t hx509_key_format_t; + struct hx509_cert_attribute_data { heim_oid oid; heim_octet_string data; diff --git a/lib/hx509/hx509_err.et b/lib/hx509/hx509_err.et index 76bbfaeab..6225f125f 100644 --- a/lib/hx509/hx509_err.et +++ b/lib/hx509/hx509_err.et @@ -66,6 +66,7 @@ error_code RSA_PRIVATE_ENCRYPT, "RSA private encyption failed" error_code RSA_PUBLIC_DECRYPT, "RSA public decryption failed" error_code RSA_PRIVATE_DECRYPT, "RSA private decryption failed" error_code ALGORITHM_BEST_BEFORE, "Algorithm has passed its best before date" +error_code KEY_FORMAT_UNSUPPORTED, "Key format is unsupported" # revoke related errors index 96 diff --git a/lib/hx509/ks_file.c b/lib/hx509/ks_file.c index 645dc405a..ecd3a6eda 100644 --- a/lib/hx509/ks_file.c +++ b/lib/hx509/ks_file.c @@ -541,7 +541,8 @@ store_func(hx509_context context, void *ctx, hx509_cert c) 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); + ret = _hx509_private_key_export(context, key, + HX509_KEY_FORMAT_DER, &data); if (ret) break; hx509_pem_write(context, _hx509_private_pem_name(key), NULL, sc->f, diff --git a/lib/hx509/ks_p12.c b/lib/hx509/ks_p12.c index d94ab197c..704cf071d 100644 --- a/lib/hx509/ks_p12.c +++ b/lib/hx509/ks_p12.c @@ -535,6 +535,7 @@ store_func(hx509_context context, void *ctx, hx509_cert c) } ret = _hx509_private_key_export(context, _hx509_cert_private_key(c), + HX509_KEY_FORMAT_DER, &pki.privateKey); if (ret) { free_PKCS8PrivateKeyInfo(&pki);