pkcs8.c: Add PBES2 to list of password-based encryption methods. This consists mostly of re-adding OpenSSL's implementation of PBKDF2 (very loosely based upon e0d26bb3). The meat of it, namely |PKCS5_PBKDF2_HMAC|, was already present, but unused. In addition, |PKCS8_encrypt| and |PKCS8_decrypt| must be changed to not perform UCS-2 conversion in the PBES2 case. Change-Id: Id170ecabc43c79491600051147d1d6d3c7273dbc Reviewed-on: https://boringssl-review.googlesource.com/5745 Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/pkcs8/CMakeLists.txt b/crypto/pkcs8/CMakeLists.txt index f0452e9..ce5bce1 100644 --- a/crypto/pkcs8/CMakeLists.txt +++ b/crypto/pkcs8/CMakeLists.txt
@@ -19,4 +19,11 @@ $<TARGET_OBJECTS:test_support> ) +add_executable( + pkcs8_test + + pkcs8_test.cc +) + +target_link_libraries(pkcs8_test crypto) target_link_libraries(pkcs12_test crypto)
diff --git a/crypto/pkcs8/internal.h b/crypto/pkcs8/internal.h index 44ca4f7..7995e78 100644 --- a/crypto/pkcs8/internal.h +++ b/crypto/pkcs8/internal.h
@@ -66,6 +66,15 @@ #define PKCS5_DEFAULT_ITERATIONS 2048 #define PKCS5_SALT_LEN 8 +/* PKCS5_v2_PBE_keyivgen intializes the supplied |ctx| for PBKDF v2, which must + * be specified by |param|. The password is specified by |pass_raw| and + * |pass_raw_len|. |cipher| and |md| are ignored. + * + * It returns one on success and zero on error. */ +int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw, + size_t pass_raw_len, ASN1_TYPE *param, + const EVP_CIPHER *cipher, const EVP_MD *md, int enc); + #if defined(__cplusplus) } /* extern C */
diff --git a/crypto/pkcs8/p5_pbev2.c b/crypto/pkcs8/p5_pbev2.c index beeb336..f58aae7 100644 --- a/crypto/pkcs8/p5_pbev2.c +++ b/crypto/pkcs8/p5_pbev2.c
@@ -53,6 +53,8 @@ * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). */ +#include <assert.h> +#include <limits.h> #include <string.h> #include <openssl/asn1t.h> @@ -301,3 +303,137 @@ return NULL; } +static int PKCS5_v2_PBKDF2_keyivgen(EVP_CIPHER_CTX *ctx, + const uint8_t *pass_raw, + size_t pass_raw_len, const ASN1_TYPE *param, + const ASN1_TYPE *iv, int enc) { + int rv = 0; + PBKDF2PARAM *pbkdf2param = NULL; + + if (EVP_CIPHER_CTX_cipher(ctx) == NULL) { + OPENSSL_PUT_ERROR(PKCS8, CIPHER_R_NO_CIPHER_SET); + goto err; + } + + /* Decode parameters. */ + if (param == NULL || param->type != V_ASN1_SEQUENCE) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + goto err; + } + + const uint8_t *pbuf = param->value.sequence->data; + int plen = param->value.sequence->length; + pbkdf2param = d2i_PBKDF2PARAM(NULL, &pbuf, plen); + if (pbkdf2param == NULL || pbuf != param->value.sequence->data + plen) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + goto err; + } + + /* Now check the parameters. */ + uint8_t key[EVP_MAX_KEY_LENGTH]; + const size_t key_len = EVP_CIPHER_CTX_key_length(ctx); + assert(key_len <= sizeof(key)); + + if (pbkdf2param->keylength != NULL && + ASN1_INTEGER_get(pbkdf2param->keylength) != (int) key_len) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_KEYLENGTH); + goto err; + } + + if (pbkdf2param->prf != NULL && + OBJ_obj2nid(pbkdf2param->prf->algorithm) != NID_hmacWithSHA1) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRF); + goto err; + } + + if (pbkdf2param->salt->type != V_ASN1_OCTET_STRING) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_SALT_TYPE); + goto err; + } + + if (pbkdf2param->iter->type != V_ASN1_INTEGER) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT); + goto err; + } + long iterations = ASN1_INTEGER_get(pbkdf2param->iter); + if (iterations < 0 || iterations > UINT_MAX) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT); + goto err; + } + + if (iv->type != V_ASN1_OCTET_STRING || iv->value.octet_string == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS); + goto err; + } + + const size_t iv_len = EVP_CIPHER_CTX_iv_length(ctx); + if (iv->value.octet_string->length != iv_len) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS); + goto err; + } + + if (!PKCS5_PBKDF2_HMAC_SHA1((const char *) pass_raw, pass_raw_len, + pbkdf2param->salt->value.octet_string->data, + pbkdf2param->salt->value.octet_string->length, + iterations, key_len, key)) { + goto err; + } + + rv = EVP_CipherInit_ex(ctx, NULL /* cipher */, NULL /* engine */, key, + iv->value.octet_string->data, enc); + + err: + PBKDF2PARAM_free(pbkdf2param); + return rv; +} + +int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw, + size_t pass_raw_len, ASN1_TYPE *param, + const EVP_CIPHER *unused, const EVP_MD *unused2, + int enc) { + PBE2PARAM *pbe2param = NULL; + int rv = 0; + + if (param == NULL || + param->type != V_ASN1_SEQUENCE || + param->value.sequence == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + goto err; + } + + const uint8_t *pbuf = param->value.sequence->data; + int plen = param->value.sequence->length; + pbe2param = d2i_PBE2PARAM(NULL, &pbuf, plen); + if (pbe2param == NULL || pbuf != param->value.sequence->data + plen) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + goto err; + } + + /* Check that the key derivation function is PBKDF2. */ + if (OBJ_obj2nid(pbe2param->keyfunc->algorithm) != NID_id_pbkdf2) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION); + goto err; + } + + /* See if we recognise the encryption algorithm. */ + const EVP_CIPHER *cipher = + EVP_get_cipherbynid(OBJ_obj2nid(pbe2param->encryption->algorithm)); + if (cipher == NULL) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_CIPHER); + goto err; + } + + /* Fixup cipher based on AlgorithmIdentifier. */ + if (!EVP_CipherInit_ex(ctx, cipher, NULL /* engine */, NULL /* key */, + NULL /* iv */, enc)) { + goto err; + } + + rv = PKCS5_v2_PBKDF2_keyivgen(ctx, pass_raw, pass_raw_len, + pbe2param->keyfunc->parameter, + pbe2param->encryption->parameter, enc); + + err: + PBE2PARAM_free(pbe2param); + return rv; +}
diff --git a/crypto/pkcs8/pkcs8.c b/crypto/pkcs8/pkcs8.c index 8ac203d..8067c91 100644 --- a/crypto/pkcs8/pkcs8.c +++ b/crypto/pkcs8/pkcs8.c
@@ -69,6 +69,7 @@ #include <openssl/mem.h> #include <openssl/x509.h> +#include "internal.h" #include "../bytestring/internal.h" #include "../evp/internal.h" @@ -274,39 +275,90 @@ const EVP_CIPHER* (*cipher_func)(void); const EVP_MD* (*md_func)(void); keygen_func keygen; + int flags; }; +#define PBE_UCS2_CONVERT_PASSWORD 0x1 + static const struct pbe_suite kBuiltinPBE[] = { { - NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1, pkcs12_pbe_keyivgen, + NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1, + pkcs12_pbe_keyivgen, PBE_UCS2_CONVERT_PASSWORD }, { NID_pbe_WithSHA1And128BitRC4, EVP_rc4, EVP_sha1, pkcs12_pbe_keyivgen, + PBE_UCS2_CONVERT_PASSWORD }, { NID_pbe_WithSHA1And3_Key_TripleDES_CBC, EVP_des_ede3_cbc, EVP_sha1, - pkcs12_pbe_keyivgen, + pkcs12_pbe_keyivgen, PBE_UCS2_CONVERT_PASSWORD + }, + { + NID_pbes2, NULL, NULL, PKCS5_v2_PBE_keyivgen, 0 }, }; +static const struct pbe_suite *get_pbe_suite(int pbe_nid) { + unsigned i; + for (i = 0; i < sizeof(kBuiltinPBE) / sizeof(kBuiltinPBE[0]); i++) { + if (kBuiltinPBE[i].pbe_nid == pbe_nid) { + return &kBuiltinPBE[i]; + } + } + + return NULL; +} + +/* pass_to_pass_raw performs a password conversion (possibly a no-op) + * appropriate to the supplied |pbe_nid|. The input |pass| is treated as a + * NUL-terminated string if |pass_len| is -1, otherwise it is treated as a + * buffer of the specified length. If the supplied PBE NID sets the + * |PBE_UCS2_CONVERT_PASSWORD| flag, the supplied |pass| will be converted to + * UCS-2. + * + * It sets |*out_pass_raw| to a new buffer that must be freed by the caller. It + * returns one on success and zero on error. */ +static int pass_to_pass_raw(int pbe_nid, const char *pass, int pass_len, + uint8_t **out_pass_raw, size_t *out_pass_raw_len) { + if (pass == NULL) { + *out_pass_raw = NULL; + *out_pass_raw_len = 0; + return 1; + } + + if (pass_len == -1) { + pass_len = strlen(pass); + } else if (pass_len < 0 || pass_len > 2000000000) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW); + return 0; + } + + const struct pbe_suite *suite = get_pbe_suite(pbe_nid); + if (suite != NULL && (suite->flags & PBE_UCS2_CONVERT_PASSWORD)) { + if (!ascii_to_ucs2(pass, pass_len, out_pass_raw, out_pass_raw_len)) { + OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); + return 0; + } + } else { + *out_pass_raw = BUF_memdup(pass, pass_len); + if (*out_pass_raw == NULL) { + OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE); + return 0; + } + *out_pass_raw_len = (size_t)pass_len; + } + + return 1; +} + static int pbe_cipher_init(ASN1_OBJECT *pbe_obj, const uint8_t *pass_raw, size_t pass_raw_len, ASN1_TYPE *param, EVP_CIPHER_CTX *ctx, int is_encrypt) { const EVP_CIPHER *cipher; const EVP_MD *md; - unsigned i; - const struct pbe_suite *suite = NULL; - const int pbe_nid = OBJ_obj2nid(pbe_obj); - - for (i = 0; i < sizeof(kBuiltinPBE) / sizeof(struct pbe_suite); i++) { - if (kBuiltinPBE[i].pbe_nid == pbe_nid) { - suite = &kBuiltinPBE[i]; - break; - } - } - + const struct pbe_suite *suite = get_pbe_suite(OBJ_obj2nid(pbe_obj)); if (suite == NULL) { char obj_str[80]; OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_ALGORITHM); @@ -427,19 +479,12 @@ int pass_len) { uint8_t *pass_raw = NULL; size_t pass_raw_len = 0; - PKCS8_PRIV_KEY_INFO *ret; - - if (pass) { - if (pass_len == -1) { - pass_len = strlen(pass); - } - if (!ascii_to_ucs2(pass, pass_len, &pass_raw, &pass_raw_len)) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); - return NULL; - } + if (!pass_to_pass_raw(OBJ_obj2nid(pkcs8->algor->algorithm), pass, pass_len, + &pass_raw, &pass_raw_len)) { + return NULL; } - ret = PKCS8_decrypt_pbe(pkcs8, pass_raw, pass_raw_len); + PKCS8_PRIV_KEY_INFO *ret = PKCS8_decrypt_pbe(pkcs8, pass_raw, pass_raw_len); if (pass_raw) { OPENSSL_cleanse(pass_raw, pass_raw_len); @@ -491,20 +536,12 @@ int iterations, PKCS8_PRIV_KEY_INFO *p8inf) { uint8_t *pass_raw = NULL; size_t pass_raw_len = 0; - X509_SIG *ret; - - if (pass) { - if (pass_len == -1) { - pass_len = strlen(pass); - } - if (!ascii_to_ucs2(pass, pass_len, &pass_raw, &pass_raw_len)) { - OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR); - return NULL; - } + if (!pass_to_pass_raw(pbe_nid, pass, pass_len, &pass_raw, &pass_raw_len)) { + return NULL; } - ret = PKCS8_encrypt_pbe(pbe_nid, pass_raw, pass_raw_len, - salt, salt_len, iterations, p8inf); + X509_SIG *ret = PKCS8_encrypt_pbe(pbe_nid, cipher, pass_raw, pass_raw_len, + salt, salt_len, iterations, p8inf); if (pass_raw) { OPENSSL_cleanse(pass_raw, pass_raw_len); @@ -513,7 +550,7 @@ return ret; } -X509_SIG *PKCS8_encrypt_pbe(int pbe_nid, +X509_SIG *PKCS8_encrypt_pbe(int pbe_nid, const EVP_CIPHER *cipher, const uint8_t *pass_raw, size_t pass_raw_len, uint8_t *salt, size_t salt_len, int iterations, PKCS8_PRIV_KEY_INFO *p8inf) { @@ -526,7 +563,11 @@ goto err; } - pbe = PKCS5_pbe_set(pbe_nid, iterations, salt, salt_len); + if (pbe_nid == -1) { + pbe = PKCS5_pbe2_set(cipher, iterations, salt, salt_len); + } else { + pbe = PKCS5_pbe_set(pbe_nid, iterations, salt, salt_len); + } if (!pbe) { OPENSSL_PUT_ERROR(PKCS8, ERR_R_ASN1_LIB); goto err;
diff --git a/crypto/pkcs8/pkcs8_test.cc b/crypto/pkcs8/pkcs8_test.cc new file mode 100644 index 0000000..7a88ddf --- /dev/null +++ b/crypto/pkcs8/pkcs8_test.cc
@@ -0,0 +1,91 @@ +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <openssl/crypto.h> +#include <openssl/err.h> +#include <openssl/pkcs8.h> +#include <openssl/x509.h> + +#include "../test/scoped_types.h" + + +/* kDER is a PKCS#8 encrypted private key. It was generated with: + * + * openssl genrsa 512 > test.key + * openssl pkcs8 -topk8 -in test.key -out test.key.encrypted -v2 des3 -outform der + * hexdump -Cv test.key.encrypted + * + * The password is "testing". + */ +static const uint8_t kDER[] = { + 0x30, 0x82, 0x01, 0x9e, 0x30, 0x40, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, + 0x0d, 0x30, 0x33, 0x30, 0x1b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x05, 0x0c, + 0x30, 0x0e, 0x04, 0x08, 0x06, 0xa5, 0x4b, 0x0c, 0x0c, 0x50, 0x8c, 0x19, 0x02, 0x02, 0x08, 0x00, + 0x30, 0x14, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x03, 0x07, 0x04, 0x08, 0x3a, 0xd0, + 0x70, 0x4b, 0x26, 0x50, 0x13, 0x7b, 0x04, 0x82, 0x01, 0x58, 0xa6, 0xee, 0x02, 0xf2, 0xf2, 0x7c, + 0x19, 0x91, 0xe3, 0xce, 0x32, 0x85, 0xc5, 0x01, 0xd9, 0xe3, 0x5e, 0x14, 0xb6, 0xb8, 0x78, 0xad, + 0xda, 0x01, 0xec, 0x9e, 0x42, 0xe8, 0xbf, 0x0b, 0x46, 0x03, 0xbc, 0x92, 0x6f, 0xe4, 0x0f, 0x0f, + 0x48, 0x30, 0x10, 0x10, 0x9b, 0xfb, 0x4b, 0xb9, 0x45, 0xf8, 0xcf, 0xab, 0xa1, 0x18, 0xdd, 0x19, + 0xa4, 0xa4, 0xe1, 0xf0, 0xa1, 0x8d, 0xc2, 0x23, 0xe7, 0x0d, 0x7a, 0x64, 0x21, 0x6b, 0xfa, 0x48, + 0xb9, 0x41, 0xc1, 0x0c, 0x4b, 0xce, 0x6f, 0x1a, 0x91, 0x9b, 0x9f, 0xdd, 0xcf, 0xa9, 0x8d, 0x33, + 0x2c, 0x45, 0x81, 0x5c, 0x5e, 0x67, 0xc6, 0x68, 0x43, 0x62, 0xff, 0x5e, 0x9b, 0x1a, 0x15, 0x3a, + 0x9d, 0x71, 0x3f, 0xbe, 0x32, 0x2f, 0xe5, 0x90, 0x65, 0x65, 0x9c, 0x22, 0xf6, 0x29, 0x2e, 0xcf, + 0x26, 0x16, 0x7b, 0x66, 0x48, 0x55, 0xad, 0x9a, 0x8d, 0x89, 0xf4, 0x48, 0x4f, 0x1f, 0x9d, 0xb8, + 0xfa, 0xe1, 0xf1, 0x3b, 0x39, 0x5c, 0x72, 0xc6, 0xb8, 0x3e, 0x98, 0xe8, 0x77, 0xe8, 0xb6, 0x71, + 0x84, 0xa8, 0x6e, 0xca, 0xaf, 0x62, 0x96, 0x49, 0x8a, 0x21, 0x6f, 0x9e, 0x78, 0x07, 0x97, 0x38, + 0x40, 0x66, 0x42, 0x5a, 0x1b, 0xe0, 0x9b, 0xe9, 0x91, 0x82, 0xe4, 0xea, 0x8f, 0x2a, 0xb2, 0x80, + 0xce, 0xe8, 0x57, 0xd3, 0xac, 0x11, 0x9d, 0xb2, 0x39, 0x0f, 0xe1, 0xce, 0x18, 0x96, 0x38, 0xa1, + 0x19, 0x80, 0x88, 0x81, 0x3d, 0xda, 0xaa, 0x8e, 0x15, 0x27, 0x19, 0x73, 0x0c, 0xf3, 0xaf, 0x45, + 0xe9, 0x1b, 0xad, 0x6c, 0x3d, 0xbf, 0x95, 0xf7, 0xa0, 0x87, 0x0e, 0xde, 0xf1, 0xd8, 0xee, 0xaa, + 0x92, 0x76, 0x8d, 0x32, 0x45, 0xa1, 0xe7, 0xf5, 0x05, 0xd6, 0x2c, 0x67, 0x63, 0x10, 0xfa, 0xde, + 0x80, 0xc7, 0x5b, 0x96, 0x0f, 0x24, 0x50, 0x78, 0x30, 0xe5, 0x89, 0xf3, 0x73, 0xfa, 0x40, 0x11, + 0xd5, 0x26, 0xb8, 0x36, 0x96, 0x98, 0xe6, 0xbd, 0x73, 0x62, 0x56, 0xb9, 0xea, 0x28, 0x16, 0x93, + 0x5b, 0x33, 0xae, 0x83, 0xf9, 0x1f, 0xee, 0xef, 0xc8, 0xbf, 0xc7, 0xb1, 0x47, 0x43, 0xa1, 0xc6, + 0x1a, 0x64, 0x47, 0x02, 0x40, 0x3e, 0xbc, 0x0f, 0x80, 0x71, 0x5c, 0x44, 0x60, 0xbc, 0x78, 0x2e, + 0xd2, 0x77, 0xf8, 0x6e, 0x12, 0x51, 0x89, 0xdb, 0x90, 0x64, 0xcd, 0x76, 0x10, 0x29, 0x73, 0xc2, + 0x2f, 0x94, 0x7b, 0x98, 0xcd, 0xbb, 0x61, 0x16, 0x1d, 0x52, 0x11, 0x73, 0x48, 0xe6, 0x39, 0xfc, + 0xd6, 0x2d, +}; + +static bool test(const uint8_t *der, size_t der_len) { + const uint8_t *data = der; + ScopedX509_SIG sig(d2i_X509_SIG(NULL, &data, der_len)); + if (sig.get() == NULL || data != der + der_len) { + fprintf(stderr, "d2i_X509_SIG failed or did not consume all bytes.\n"); + return false; + } + + static const char kPassword[] = "testing"; + ScopedPKCS8_PRIV_KEY_INFO keypair(PKCS8_decrypt(sig.get(), kPassword, -1)); + if (!keypair) { + fprintf(stderr, "PKCS8_decrypt failed.\n"); + ERR_print_errors_fp(stderr); + return false; + } + + return true; +} + +int main(int argc, char **argv) { + if (!test(kDER, sizeof(kDER))) { + return 1; + } + + printf("PASS\n"); + return 0; +}
diff --git a/crypto/test/scoped_types.h b/crypto/test/scoped_types.h index d9eaad2..e44c6ed 100644 --- a/crypto/test/scoped_types.h +++ b/crypto/test/scoped_types.h
@@ -113,6 +113,7 @@ using ScopedRSA = ScopedOpenSSLType<RSA, RSA_free>; using ScopedX509 = ScopedOpenSSLType<X509, X509_free>; using ScopedX509_ALGOR = ScopedOpenSSLType<X509_ALGOR, X509_ALGOR_free>; +using ScopedX509_SIG = ScopedOpenSSLType<X509_SIG, X509_SIG_free>; using ScopedX509Stack = ScopedOpenSSLStack<STACK_OF(X509), X509, X509_free>;
diff --git a/include/openssl/pkcs8.h b/include/openssl/pkcs8.h index 677b46f..bb6b03c 100644 --- a/include/openssl/pkcs8.h +++ b/include/openssl/pkcs8.h
@@ -66,13 +66,15 @@ #endif -/* PKCS8_encrypt_pbe serializes and encrypts a PKCS8_PRIV_KEY_INFO with PBES1 as - * defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, +/* PKCS8_encrypt_pbe serializes and encrypts a PKCS8_PRIV_KEY_INFO with PBES1 or + * PBES2 as defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, defined in PKCS - * #12, are supported. The |pass_raw_len| bytes pointed to by |pass_raw| are - * used as the password. Note that any conversions from the password as - * supplied in a text string (such as those specified in B.1 of PKCS #12) must - * be performed by the caller. + * #12, and PBES2, are supported. PBES2 is selected by setting |cipher| and + * passing -1 for |pbe_nid|. Otherwise, PBES1 is used and |cipher| is ignored. + * + * The |pass_raw_len| bytes pointed to by |pass_raw| are used as the password. + * Note that any conversions from the password as supplied in a text string + * (such as those specified in B.1 of PKCS #12) must be performed by the caller. * * If |salt| is NULL, a random salt of |salt_len| bytes is generated. If * |salt_len| is zero, a default salt length is used instead. @@ -83,19 +85,21 @@ * TODO(davidben): Really? An X509_SIG? OpenSSL probably did that because it has * the same structure as EncryptedPrivateKeyInfo. */ OPENSSL_EXPORT X509_SIG *PKCS8_encrypt_pbe(int pbe_nid, + const EVP_CIPHER *cipher, const uint8_t *pass_raw, size_t pass_raw_len, uint8_t *salt, size_t salt_len, int iterations, PKCS8_PRIV_KEY_INFO *p8inf); -/* PKCS8_decrypt_pbe decrypts and decodes a PKCS8_PRIV_KEY_INFO with PBES1 as - * defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, - * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, defined in PKCS - * #12, are supported. The |pass_raw_len| bytes pointed to by |pass_raw| are - * used as the password. Note that any conversions from the password as - * supplied in a text string (such as those specified in B.1 of PKCS #12) must - * be performed by the caller. +/* PKCS8_decrypt_pbe decrypts and decodes a PKCS8_PRIV_KEY_INFO with PBES1 or + * PBES2 as defined in PKCS #5. Only pbeWithSHAAnd128BitRC4, + * pbeWithSHAAnd3-KeyTripleDES-CBC and pbeWithSHA1And40BitRC2, and PBES2, + * defined in PKCS #12, are supported. + * + * The |pass_raw_len| bytes pointed to by |pass_raw| are used as the password. + * Note that any conversions from the password as supplied in a text string + * (such as those specified in B.1 of PKCS #12) must be performed by the caller. * * The resulting structure must be freed by the caller. */ OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt_pbe(X509_SIG *pkcs8, @@ -105,18 +109,20 @@ /* Deprecated functions. */ -/* PKCS8_encrypt calls PKCS8_encrypt_pbe after treating |pass| as an ASCII - * string, appending U+0000, and converting to UCS-2. (So the empty password - * encodes as two NUL bytes.) The |cipher| argument is ignored. */ +/* PKCS8_encrypt calls |PKCS8_encrypt_pbe| after (in the PKCS#12 case) treating + * |pass| as an ASCII string, appending U+0000, and converting to UCS-2. (So the + * empty password encodes as two NUL bytes.) In the PBES2 case, the password is + * unchanged. */ OPENSSL_EXPORT X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, const char *pass, int pass_len, uint8_t *salt, size_t salt_len, int iterations, PKCS8_PRIV_KEY_INFO *p8inf); -/* PKCS8_decrypt calls PKCS8_decrypt_pbe after treating |pass| as an ASCII - * string, appending U+0000, and converting to UCS-2. (So the empty password - * encodes as two NUL bytes.) */ +/* PKCS8_decrypt calls PKCS8_decrypt_pbe after (in the PKCS#12 case) treating + * |pass| as an ASCII string, appending U+0000, and converting to UCS-2. (So the + * empty password encodes as two NUL bytes.) In the PBES2 case, the password is + * unchanged. */ OPENSSL_EXPORT PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, const char *pass, int pass_len); @@ -195,5 +201,11 @@ #define PKCS8_R_UNKNOWN_DIGEST 122 #define PKCS8_R_UNKNOWN_HASH 123 #define PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM 124 +#define PKCS8_R_UNSUPPORTED_KEYLENGTH 125 +#define PKCS8_R_UNSUPPORTED_SALT_TYPE 126 +#define PKCS8_R_UNSUPPORTED_CIPHER 127 +#define PKCS8_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION 128 +#define PKCS8_R_BAD_ITERATION_COUNT 129 +#define PKCS8_R_UNSUPPORTED_PRF 130 #endif /* OPENSSL_HEADER_PKCS8_H */
diff --git a/util/all_tests.json b/util/all_tests.json index 77ffa0a..a6daa2f 100644 --- a/util/all_tests.json +++ b/util/all_tests.json
@@ -44,6 +44,7 @@ ["crypto/hmac/hmac_test", "crypto/hmac/hmac_tests.txt"], ["crypto/lhash/lhash_test"], ["crypto/modes/gcm_test"], + ["crypto/pkcs8/pkcs8_test"], ["crypto/pkcs8/pkcs12_test"], ["crypto/poly1305/poly1305_test", "crypto/poly1305/poly1305_test.txt"], ["crypto/refcount_test"],