aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Benjamin <davidben@google.com>2016-12-30 02:17:24 -0500
committerAdam Langley <alangley@gmail.com>2017-01-11 01:25:14 +0000
commit9d0e7fb6e7a0e22a6f507fc260fb96cdc8a3e3b9 (patch)
treebc1dbf55f8169736dac8017b5547a9ed29c97b91
parent314d81420c7aae3495d59d590b39d8d1b222ebba (diff)
downloadboringssl-9d0e7fb6e7a0e22a6f507fc260fb96cdc8a3e3b9.zip
boringssl-9d0e7fb6e7a0e22a6f507fc260fb96cdc8a3e3b9.tar.gz
boringssl-9d0e7fb6e7a0e22a6f507fc260fb96cdc8a3e3b9.tar.bz2
Rework PKCS{5,8,12} code.
Avoid the X509_ALGOR dependency entirely. The public API is still using the legacy ASN.1 structures for now, but the conversions are lifted to the API boundary. Once we resolve that and the OID table dependency, this module will no longer block unshipping crypto/asn1 and friends from Chromium. This changes the calling convention around the two kinds of PBE suites we support. Each PBE suite provides a free-form encrypt_init function to setup an EVP_CIPHER_CTX and write the AlgorithmIdentifer to a CBB. It then provides a common decrypt_init function which sets up an EVP_CIPHER_CTX given a CBS of the parameter. The common encrypt code determines how to call which encrypt_init function. The common decrypt code parses the OID out of the AlgorithmIdentifer and then dispatches to decrypt_init. Note this means the encryption codepath no longer involves parsing back out a AlgorithmIdentifier it just serialized. We don't have a good story to access an already serialized piece of a CBB in progress (reallocs can invalidate the pointer in a CBS), so it's easier to cut this step out entirely. Also note this renames the "PBES1" schemes from PKCS#5 to PKCS#12. This makes it easier to get at the PKCS#12 key derivation hooks. Although PKCS#12 claims these are variants of PKCS#5's PBES1, they're not very related. PKCS#12 swaps out the key derivation and even defines its own AlgorithmIdentifier parameter structure (identical to the PKCS#5 PBES1 one). The only thing of PBES1 that survives is the CBC mode padding scheme, which is deep in EVP_CIPHER for us. (Of course, all this musing on layering is moot because we don't implement non-PKCS#12 PBES1 schemes anyway.) This also moves some of the random API features (default iteration count, default salt generation) out of the PBE suites and into the common code. BUG=54 Change-Id: Ie96924c73a229be2915be98eab680cadd17326db Reviewed-on: https://boringssl-review.googlesource.com/13069 Reviewed-by: Adam Langley <alangley@gmail.com>
-rw-r--r--crypto/pkcs8/CMakeLists.txt1
-rw-r--r--crypto/pkcs8/internal.h38
-rw-r--r--crypto/pkcs8/p5_pbe.c122
-rw-r--r--crypto/pkcs8/p5_pbev2.c121
-rw-r--r--crypto/pkcs8/pkcs8.c422
5 files changed, 277 insertions, 427 deletions
diff --git a/crypto/pkcs8/CMakeLists.txt b/crypto/pkcs8/CMakeLists.txt
index ffb3821..a2e52e1 100644
--- a/crypto/pkcs8/CMakeLists.txt
+++ b/crypto/pkcs8/CMakeLists.txt
@@ -7,7 +7,6 @@ add_library(
pkcs8.c
p8_pkey.c
- p5_pbe.c
p5_pbev2.c
)
diff --git a/crypto/pkcs8/internal.h b/crypto/pkcs8/internal.h
index 7a6f057..9cebe29 100644
--- a/crypto/pkcs8/internal.h
+++ b/crypto/pkcs8/internal.h
@@ -63,22 +63,36 @@ extern "C" {
#endif
+#define PBE_UCS2_CONVERT_PASSWORD 0x1
+
+struct pbe_suite {
+ int pbe_nid;
+ const EVP_CIPHER *(*cipher_func)(void);
+ const EVP_MD *(*md_func)(void);
+ /* decrypt_init initialize |ctx| for decrypting. The password is specified by
+ * |pass_raw| and |pass_raw_len|. |param| contains the serialized parameters
+ * field of the AlgorithmIdentifier.
+ *
+ * It returns one on success and zero on error. */
+ int (*decrypt_init)(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx,
+ const uint8_t *pass_raw, size_t pass_raw_len, CBS *param);
+ int flags;
+};
+
#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);
+int PKCS5_pbe2_decrypt_init(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx,
+ const uint8_t *pass_raw, size_t pass_raw_len,
+ CBS *param);
-X509_ALGOR *PKCS5_pbe_set(int alg, int iter, const uint8_t *salt,
- size_t salt_len);
-X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter,
- const uint8_t *salt, size_t salt_len);
+/* PKCS5_pbe2_encrypt_init configures |ctx| for encrypting with PKCS #5 PBES2,
+ * as defined in RFC 2998, with the specified parameters. It writes the
+ * corresponding AlgorithmIdentifier to |out|. */
+int PKCS5_pbe2_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx,
+ const EVP_CIPHER *cipher, unsigned iterations,
+ const uint8_t *pass_raw, size_t pass_raw_len,
+ const uint8_t *salt, size_t salt_len);
#if defined(__cplusplus)
diff --git a/crypto/pkcs8/p5_pbe.c b/crypto/pkcs8/p5_pbe.c
deleted file mode 100644
index eff2e40..0000000
--- a/crypto/pkcs8/p5_pbe.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
- * project 1999.
- */
-/* ====================================================================
- * Copyright (c) 1999 The OpenSSL Project. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * 3. All advertising materials mentioning features or use of this
- * software must display the following acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
- *
- * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
- * endorse or promote products derived from this software without
- * prior written permission. For written permission, please contact
- * licensing@OpenSSL.org.
- *
- * 5. Products derived from this software may not be called "OpenSSL"
- * nor may "OpenSSL" appear in their names without prior written
- * permission of the OpenSSL Project.
- *
- * 6. Redistributions of any form whatsoever must retain the following
- * acknowledgment:
- * "This product includes software developed by the OpenSSL Project
- * for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
- *
- * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
- * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
- * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- * ====================================================================
- *
- * This product includes cryptographic software written by Eric Young
- * (eay@cryptsoft.com). This product includes software written by Tim
- * Hudson (tjh@cryptsoft.com). */
-
-#include <openssl/asn1.h>
-#include <openssl/err.h>
-#include <openssl/mem.h>
-#include <openssl/obj.h>
-#include <openssl/pkcs8.h>
-#include <openssl/rand.h>
-#include <openssl/x509.h>
-
-#include "../internal.h"
-#include "internal.h"
-
-
-X509_ALGOR *PKCS5_pbe_set(int alg, int iter, const uint8_t *salt,
- size_t salt_len) {
- if (iter <= 0) {
- iter = PKCS5_DEFAULT_ITERATIONS;
- }
-
- CBB cbb;
- CBB_zero(&cbb);
-
- /* Generate a random salt if necessary. This will be parsed back out of the
- * serialized |X509_ALGOR|. */
- X509_ALGOR *ret = NULL;
- uint8_t *salt_buf = NULL, *der = NULL;
- size_t der_len;
- if (salt == NULL) {
- if (salt_len == 0) {
- salt_len = PKCS5_SALT_LEN;
- }
-
- salt_buf = OPENSSL_malloc(salt_len);
- if (salt_buf == NULL ||
- !RAND_bytes(salt_buf, salt_len)) {
- goto err;
- }
-
- salt = salt_buf;
- }
-
- /* See RFC 2898, appendix A.3. */
- CBB algorithm, param, salt_cbb;
- if (!CBB_init(&cbb, 16) ||
- !CBB_add_asn1(&cbb, &algorithm, CBS_ASN1_SEQUENCE) ||
- !OBJ_nid2cbb(&algorithm, alg) ||
- !CBB_add_asn1(&algorithm, &param, CBS_ASN1_SEQUENCE) ||
- !CBB_add_asn1(&param, &salt_cbb, CBS_ASN1_OCTETSTRING) ||
- !CBB_add_bytes(&salt_cbb, salt, salt_len) ||
- !CBB_add_asn1_uint64(&param, iter) ||
- !CBB_finish(&cbb, &der, &der_len)) {
- goto err;
- }
-
- const uint8_t *ptr = der;
- ret = d2i_X509_ALGOR(NULL, &ptr, der_len);
- if (ret == NULL || ptr != der + der_len) {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_INTERNAL_ERROR);
- X509_ALGOR_free(ret);
- ret = NULL;
- }
-
-err:
- OPENSSL_free(der);
- OPENSSL_free(salt_buf);
- CBB_cleanup(&cbb);
- return ret;
-}
diff --git a/crypto/pkcs8/p5_pbev2.c b/crypto/pkcs8/p5_pbev2.c
index ae187ac..59e2067 100644
--- a/crypto/pkcs8/p5_pbev2.c
+++ b/crypto/pkcs8/p5_pbev2.c
@@ -58,63 +58,55 @@
#include <limits.h>
#include <string.h>
-#include <openssl/asn1.h>
#include <openssl/bytestring.h>
#include <openssl/cipher.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
#include <openssl/rand.h>
-#include <openssl/x509.h>
#include "internal.h"
#include "../internal.h"
-X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter,
- const uint8_t *salt, size_t salt_len) {
+static int pkcs5_pbe2_cipher_init(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher,
+ unsigned iterations, const uint8_t *pass_raw,
+ size_t pass_raw_len, const uint8_t *salt,
+ size_t salt_len, const uint8_t *iv,
+ size_t iv_len, int enc) {
+ if (iv_len != EVP_CIPHER_iv_length(cipher)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS);
+ return 0;
+ }
+
+ uint8_t key[EVP_MAX_KEY_LENGTH];
+ int ret = PKCS5_PBKDF2_HMAC_SHA1((const char *)pass_raw, pass_raw_len, salt,
+ salt_len, iterations,
+ EVP_CIPHER_key_length(cipher), key) &&
+ EVP_CipherInit_ex(ctx, cipher, NULL /* engine */, key, iv, enc);
+ OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH);
+ return ret;
+}
+
+int PKCS5_pbe2_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx,
+ const EVP_CIPHER *cipher, unsigned iterations,
+ const uint8_t *pass_raw, size_t pass_raw_len,
+ const uint8_t *salt, size_t salt_len) {
int cipher_nid = EVP_CIPHER_nid(cipher);
if (cipher_nid == NID_undef) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER);
- return NULL;
- }
-
- if (iter <= 0) {
- iter = PKCS5_DEFAULT_ITERATIONS;
+ return 0;
}
/* Generate a random IV. */
uint8_t iv[EVP_MAX_IV_LENGTH];
if (!RAND_bytes(iv, EVP_CIPHER_iv_length(cipher))) {
- return NULL;
- }
-
- CBB cbb;
- CBB_zero(&cbb);
-
- /* Generate a random PBKDF2 salt if necessary. This will be parsed back out of
- * the serialized |X509_ALGOR|. */
- X509_ALGOR *ret = NULL;
- uint8_t *salt_buf = NULL, *der = NULL;
- size_t der_len;
- if (salt == NULL) {
- if (salt_len == 0) {
- salt_len = PKCS5_SALT_LEN;
- }
-
- salt_buf = OPENSSL_malloc(salt_len);
- if (salt_buf == NULL ||
- !RAND_bytes(salt_buf, salt_len)) {
- goto err;
- }
-
- salt = salt_buf;
+ return 0;
}
/* See RFC 2898, appendix A. */
CBB algorithm, param, kdf, kdf_param, salt_cbb, cipher_cbb, iv_cbb;
- if (!CBB_init(&cbb, 16) ||
- !CBB_add_asn1(&cbb, &algorithm, CBS_ASN1_SEQUENCE) ||
+ if (!CBB_add_asn1(out, &algorithm, CBS_ASN1_SEQUENCE) ||
!OBJ_nid2cbb(&algorithm, NID_pbes2) ||
!CBB_add_asn1(&algorithm, &param, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&param, &kdf, CBS_ASN1_SEQUENCE) ||
@@ -122,7 +114,7 @@ X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter,
!CBB_add_asn1(&kdf, &kdf_param, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1(&kdf_param, &salt_cbb, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&salt_cbb, salt, salt_len) ||
- !CBB_add_asn1_uint64(&kdf_param, iter) ||
+ !CBB_add_asn1_uint64(&kdf_param, iterations) ||
/* Specify a key length for RC2. */
(cipher_nid == NID_rc2_cbc &&
!CBB_add_asn1_uint64(&kdf_param, EVP_CIPHER_key_length(cipher))) ||
@@ -133,40 +125,21 @@ X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter,
* IV, but OpenSSL always uses an OCTET STRING IV, so we do the same. */
!CBB_add_asn1(&cipher_cbb, &iv_cbb, CBS_ASN1_OCTETSTRING) ||
!CBB_add_bytes(&iv_cbb, iv, EVP_CIPHER_iv_length(cipher)) ||
- !CBB_finish(&cbb, &der, &der_len)) {
- goto err;
- }
-
- const uint8_t *ptr = der;
- ret = d2i_X509_ALGOR(NULL, &ptr, der_len);
- if (ret == NULL || ptr != der + der_len) {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_INTERNAL_ERROR);
- X509_ALGOR_free(ret);
- ret = NULL;
+ !CBB_flush(out)) {
+ return 0;
}
-err:
- OPENSSL_free(der);
- OPENSSL_free(salt_buf);
- CBB_cleanup(&cbb);
- return ret;
+ return pkcs5_pbe2_cipher_init(ctx, cipher, iterations, pass_raw, pass_raw_len,
+ salt, salt_len, iv,
+ EVP_CIPHER_iv_length(cipher), 1 /* encrypt */);
}
-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) {
- if (param == NULL ||
- param->type != V_ASN1_SEQUENCE ||
- param->value.sequence == NULL) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- return 0;
- }
-
- CBS cbs, pbe_param, kdf, kdf_obj, enc_scheme, enc_obj;
- CBS_init(&cbs, param->value.sequence->data, param->value.sequence->length);
- if (!CBS_get_asn1(&cbs, &pbe_param, CBS_ASN1_SEQUENCE) ||
- CBS_len(&cbs) != 0 ||
+int PKCS5_pbe2_decrypt_init(const struct pbe_suite *suite, EVP_CIPHER_CTX *ctx,
+ const uint8_t *pass_raw, size_t pass_raw_len,
+ CBS *param) {
+ CBS pbe_param, kdf, kdf_obj, enc_scheme, enc_obj;
+ if (!CBS_get_asn1(param, &pbe_param, CBS_ASN1_SEQUENCE) ||
+ CBS_len(param) != 0 ||
!CBS_get_asn1(&pbe_param, &kdf, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1(&pbe_param, &enc_scheme, CBS_ASN1_SEQUENCE) ||
CBS_len(&pbe_param) != 0 ||
@@ -247,19 +220,7 @@ int PKCS5_v2_PBE_keyivgen(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw,
return 0;
}
- if (CBS_len(&iv) != EVP_CIPHER_iv_length(cipher)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS);
- return 0;
- }
-
- uint8_t key[EVP_MAX_KEY_LENGTH];
- if (!PKCS5_PBKDF2_HMAC_SHA1(
- (const char *)pass_raw, pass_raw_len, CBS_data(&salt), CBS_len(&salt),
- (unsigned)iterations, EVP_CIPHER_key_length(cipher), key) ||
- !EVP_CipherInit_ex(ctx, cipher, NULL /* engine */, key, CBS_data(&iv),
- enc)) {
- return 0;
- }
-
- return 1;
+ return pkcs5_pbe2_cipher_init(ctx, cipher, (unsigned)iterations, pass_raw,
+ pass_raw_len, CBS_data(&salt), CBS_len(&salt),
+ CBS_data(&iv), CBS_len(&iv), 0 /* decrypt */);
}
diff --git a/crypto/pkcs8/pkcs8.c b/crypto/pkcs8/pkcs8.c
index 22d6369..6f63436 100644
--- a/crypto/pkcs8/pkcs8.c
+++ b/crypto/pkcs8/pkcs8.c
@@ -68,6 +68,7 @@
#include <openssl/hmac.h>
#include <openssl/mem.h>
#include <openssl/obj.h>
+#include <openssl/rand.h>
#include <openssl/x509.h>
#include "internal.h"
@@ -107,7 +108,7 @@ static int ascii_to_ucs2(const char *ascii, size_t ascii_len,
static int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len,
const uint8_t *salt, size_t salt_len,
- uint8_t id, int iterations,
+ uint8_t id, unsigned iterations,
size_t out_len, uint8_t *out,
const EVP_MD *md) {
/* See https://tools.ietf.org/html/rfc7292#appendix-B. Quoted parts of the
@@ -177,7 +178,7 @@ static int pkcs12_key_gen_raw(const uint8_t *pass_raw, size_t pass_raw_len,
!EVP_DigestFinal_ex(&ctx, A, &A_len)) {
goto err;
}
- for (int iter = 1; iter < iterations; iter++) {
+ for (unsigned iter = 1; iter < iterations; iter++) {
if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
!EVP_DigestUpdate(&ctx, A, A_len) ||
!EVP_DigestFinal_ex(&ctx, A, &A_len)) {
@@ -223,45 +224,25 @@ err:
return ret;
}
-static int pkcs12_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 is_encrypt) {
- /* Extract useful info from parameter */
- if (param == NULL || param->type != V_ASN1_SEQUENCE ||
- param->value.sequence == NULL) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- return 0;
- }
-
- CBS cbs, pbe_param, salt;
- uint64_t iterations;
- CBS_init(&cbs, param->value.sequence->data, param->value.sequence->length);
- if (!CBS_get_asn1(&cbs, &pbe_param, CBS_ASN1_SEQUENCE) ||
- !CBS_get_asn1(&pbe_param, &salt, CBS_ASN1_OCTETSTRING) ||
- !CBS_get_asn1_uint64(&pbe_param, &iterations) ||
- CBS_len(&pbe_param) != 0 ||
- CBS_len(&cbs) != 0) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- return 0;
- }
-
- if (iterations == 0 || iterations > INT_MAX) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT);
- return 0;
- }
+static int pkcs12_pbe_cipher_init(const struct pbe_suite *suite,
+ EVP_CIPHER_CTX *ctx, unsigned iterations,
+ const uint8_t *pass_raw, size_t pass_raw_len,
+ const uint8_t *salt, size_t salt_len,
+ int is_encrypt) {
+ const EVP_CIPHER *cipher = suite->cipher_func();
+ const EVP_MD *md = suite->md_func();
uint8_t key[EVP_MAX_KEY_LENGTH];
- if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, CBS_data(&salt),
- CBS_len(&salt), PKCS12_KEY_ID, iterations,
+ if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt,
+ salt_len, PKCS12_KEY_ID, iterations,
EVP_CIPHER_key_length(cipher), key, md)) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR);
return 0;
}
uint8_t iv[EVP_MAX_IV_LENGTH];
- if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, CBS_data(&salt),
- CBS_len(&salt), PKCS12_IV_ID, iterations,
+ if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt,
+ salt_len, PKCS12_IV_ID, iterations,
EVP_CIPHER_iv_length(cipher), iv, md)) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEY_GEN_ERROR);
return 0;
@@ -273,36 +254,45 @@ static int pkcs12_pbe_keyivgen(EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw,
return ret;
}
-typedef int (*keygen_func)(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 is_encrypt);
-
-struct pbe_suite {
- int pbe_nid;
- const EVP_CIPHER* (*cipher_func)(void);
- const EVP_MD* (*md_func)(void);
- keygen_func keygen;
- int flags;
-};
+static int pkcs12_pbe_decrypt_init(const struct pbe_suite *suite,
+ EVP_CIPHER_CTX *ctx, const uint8_t *pass_raw,
+ size_t pass_raw_len, CBS *param) {
+ CBS pbe_param, salt;
+ uint64_t iterations;
+ if (!CBS_get_asn1(param, &pbe_param, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1(&pbe_param, &salt, CBS_ASN1_OCTETSTRING) ||
+ !CBS_get_asn1_uint64(&pbe_param, &iterations) ||
+ CBS_len(&pbe_param) != 0 ||
+ CBS_len(param) != 0) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+ return 0;
+ }
+
+ if (iterations == 0 || iterations > UINT_MAX) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT);
+ return 0;
+ }
-#define PBE_UCS2_CONVERT_PASSWORD 0x1
+ return pkcs12_pbe_cipher_init(suite, ctx, (unsigned)iterations, pass_raw,
+ pass_raw_len, CBS_data(&salt), CBS_len(&salt),
+ 0 /* decrypt */);
+}
static const struct pbe_suite kBuiltinPBE[] = {
{
- NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1,
- pkcs12_pbe_keyivgen, PBE_UCS2_CONVERT_PASSWORD
+ NID_pbe_WithSHA1And40BitRC2_CBC, EVP_rc2_40_cbc, EVP_sha1,
+ pkcs12_pbe_decrypt_init, PBE_UCS2_CONVERT_PASSWORD,
},
{
- NID_pbe_WithSHA1And128BitRC4, EVP_rc4, EVP_sha1, pkcs12_pbe_keyivgen,
- PBE_UCS2_CONVERT_PASSWORD
+ NID_pbe_WithSHA1And128BitRC4, EVP_rc4, EVP_sha1,
+ pkcs12_pbe_decrypt_init, PBE_UCS2_CONVERT_PASSWORD,
},
{
- NID_pbe_WithSHA1And3_Key_TripleDES_CBC, EVP_des_ede3_cbc, EVP_sha1,
- pkcs12_pbe_keyivgen, PBE_UCS2_CONVERT_PASSWORD
+ NID_pbe_WithSHA1And3_Key_TripleDES_CBC, EVP_des_ede3_cbc, EVP_sha1,
+ pkcs12_pbe_decrypt_init, PBE_UCS2_CONVERT_PASSWORD,
},
{
- NID_pbes2, NULL, NULL, PKCS5_v2_PBE_keyivgen, 0
+ NID_pbes2, NULL, NULL, PKCS5_pbe2_decrypt_init, 0,
},
};
@@ -359,130 +349,85 @@ static int pass_to_pass_raw(int pbe_nid, const char *pass, int 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;
-
- const struct pbe_suite *suite = get_pbe_suite(OBJ_obj2nid(pbe_obj));
+static int pkcs12_pbe_encrypt_init(CBB *out, EVP_CIPHER_CTX *ctx, int alg,
+ unsigned iterations, const uint8_t *pass_raw,
+ size_t pass_raw_len, const uint8_t *salt,
+ size_t salt_len) {
+ const struct pbe_suite *suite = get_pbe_suite(alg);
if (suite == NULL) {
- char obj_str[80];
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_ALGORITHM);
- if (!pbe_obj) {
- strncpy(obj_str, "NULL", sizeof(obj_str));
- } else {
- i2t_ASN1_OBJECT(obj_str, sizeof(obj_str), pbe_obj);
- }
- ERR_add_error_data(2, "TYPE=", obj_str);
return 0;
}
- if (suite->cipher_func == NULL) {
- cipher = NULL;
- } else {
- cipher = suite->cipher_func();
- if (!cipher) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_CIPHER);
- return 0;
- }
- }
-
- if (suite->md_func == NULL) {
- md = NULL;
- } else {
- md = suite->md_func();
- if (!md) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_DIGEST);
- return 0;
- }
- }
-
- if (!suite->keygen(ctx, pass_raw, pass_raw_len, param, cipher, md,
- is_encrypt)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEYGEN_FAILURE);
+ /* See RFC 2898, appendix A.3. */
+ CBB algorithm, param, salt_cbb;
+ if (!CBB_add_asn1(out, &algorithm, CBS_ASN1_SEQUENCE) ||
+ !OBJ_nid2cbb(&algorithm, alg) ||
+ !CBB_add_asn1(&algorithm, &param, CBS_ASN1_SEQUENCE) ||
+ !CBB_add_asn1(&param, &salt_cbb, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&salt_cbb, salt, salt_len) ||
+ !CBB_add_asn1_uint64(&param, iterations) ||
+ !CBB_flush(out)) {
return 0;
}
- return 1;
+ return pkcs12_pbe_cipher_init(suite, ctx, iterations, pass_raw, pass_raw_len,
+ salt, salt_len, 1 /* encrypt */);
}
-static int pbe_crypt(const X509_ALGOR *algor,
- const uint8_t *pass_raw, size_t pass_raw_len,
- const uint8_t *in, size_t in_len,
- uint8_t **out, size_t *out_len,
- int is_encrypt) {
- uint8_t *buf;
- int n, ret = 0;
+static int pbe_decrypt(uint8_t **out, size_t *out_len, CBS *algorithm,
+ const uint8_t *pass_raw, size_t pass_raw_len,
+ const uint8_t *in, size_t in_len) {
+ int ret = 0;
+ uint8_t *buf = NULL;;
EVP_CIPHER_CTX ctx;
- unsigned block_size;
-
EVP_CIPHER_CTX_init(&ctx);
- if (!pbe_cipher_init(algor->algorithm, pass_raw, pass_raw_len,
- algor->parameter, &ctx, is_encrypt)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_CIPHER_ALGORITHM);
- return 0;
+ CBS obj;
+ if (!CBS_get_asn1(algorithm, &obj, CBS_ASN1_OBJECT)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+ goto err;
}
- block_size = EVP_CIPHER_CTX_block_size(&ctx);
- if (in_len + block_size < in_len) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_TOO_LONG);
+ const struct pbe_suite *suite = get_pbe_suite(OBJ_cbs2nid(&obj));
+ if (suite == NULL) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNKNOWN_ALGORITHM);
+ goto err;
+ }
+
+ if (!suite->decrypt_init(suite, &ctx, pass_raw, pass_raw_len, algorithm)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_KEYGEN_FAILURE);
goto err;
}
- buf = OPENSSL_malloc(in_len + block_size);
+ buf = OPENSSL_malloc(in_len);
if (buf == NULL) {
OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
goto err;
}
- if (!EVP_CipherUpdate(&ctx, buf, &n, in, in_len)) {
- OPENSSL_free(buf);
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_EVP_LIB);
+ if (in_len > INT_MAX) {
+ OPENSSL_PUT_ERROR(PKCS8, ERR_R_OVERFLOW);
goto err;
}
- *out_len = n;
- if (!EVP_CipherFinal_ex(&ctx, buf + n, &n)) {
- OPENSSL_free(buf);
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_EVP_LIB);
+ int n1, n2;
+ if (!EVP_DecryptUpdate(&ctx, buf, &n1, in, (int)in_len) ||
+ !EVP_DecryptFinal_ex(&ctx, buf + n1, &n2)) {
goto err;
}
- *out_len += n;
+
*out = buf;
+ *out_len = n1 + n2;
ret = 1;
+ buf = NULL;
err:
+ OPENSSL_free(buf);
EVP_CIPHER_CTX_cleanup(&ctx);
return ret;
}
-static void *pkcs12_item_decrypt_d2i(X509_ALGOR *algor, const ASN1_ITEM *it,
- const uint8_t *pass_raw,
- size_t pass_raw_len,
- ASN1_OCTET_STRING *oct) {
- uint8_t *out;
- const uint8_t *p;
- void *ret;
- size_t out_len;
-
- if (!pbe_crypt(algor, pass_raw, pass_raw_len, oct->data, oct->length,
- &out, &out_len, 0 /* decrypt */)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_CRYPT_ERROR);
- return NULL;
- }
- p = out;
- ret = ASN1_item_d2i(NULL, &p, out_len, it);
- OPENSSL_cleanse(out, out_len);
- if (!ret) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- }
- OPENSSL_free(out);
- return ret;
-}
-
PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, const char *pass,
int pass_len) {
uint8_t *pass_raw = NULL;
@@ -503,40 +448,53 @@ PKCS8_PRIV_KEY_INFO *PKCS8_decrypt(X509_SIG *pkcs8, const char *pass,
PKCS8_PRIV_KEY_INFO *PKCS8_decrypt_pbe(X509_SIG *pkcs8, const uint8_t *pass_raw,
size_t pass_raw_len) {
- return pkcs12_item_decrypt_d2i(pkcs8->algor,
- ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass_raw,
- pass_raw_len, pkcs8->digest);
-}
+ PKCS8_PRIV_KEY_INFO *ret = NULL;
+ uint8_t *in = NULL, *out = NULL;
+ size_t out_len = 0;
-static ASN1_OCTET_STRING *pkcs12_item_i2d_encrypt(X509_ALGOR *algor,
- const ASN1_ITEM *it,
- const uint8_t *pass_raw,
- size_t pass_raw_len, void *obj) {
- ASN1_OCTET_STRING *oct;
- uint8_t *in = NULL;
- int in_len;
- size_t crypt_len;
-
- oct = M_ASN1_OCTET_STRING_new();
- if (oct == NULL) {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
- return NULL;
+ /* Convert the legacy ASN.1 object to a byte string. */
+ int in_len = i2d_X509_SIG(pkcs8, &in);
+ if (in_len < 0) {
+ goto err;
}
- in_len = ASN1_item_i2d(obj, &in, it);
- if (!in) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCODE_ERROR);
- return NULL;
+
+ /* See RFC 5208, section 6. */
+ CBS cbs, epki, algorithm, ciphertext;
+ CBS_init(&cbs, in, in_len);
+ if (!CBS_get_asn1(&cbs, &epki, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1(&epki, &algorithm, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1(&epki, &ciphertext, CBS_ASN1_OCTETSTRING) ||
+ CBS_len(&epki) != 0 ||
+ CBS_len(&cbs) != 0) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+ goto err;
}
- if (!pbe_crypt(algor, pass_raw, pass_raw_len, in, in_len, &oct->data, &crypt_len,
- 1 /* encrypt */)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCRYPT_ERROR);
- OPENSSL_free(in);
- return NULL;
+
+ if (!pbe_decrypt(&out, &out_len, &algorithm, pass_raw, pass_raw_len,
+ CBS_data(&ciphertext), CBS_len(&ciphertext))) {
+ goto err;
+ }
+
+ if (out_len > LONG_MAX) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+ goto err;
+ }
+
+ /* Convert back to legacy ASN.1 objects. */
+ const uint8_t *ptr = out;
+ ret = d2i_PKCS8_PRIV_KEY_INFO(NULL, &ptr, (long)out_len);
+ OPENSSL_cleanse(out, out_len);
+ if (ret == NULL || ptr != out + out_len) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+ PKCS8_PRIV_KEY_INFO_free(ret);
+ ret = NULL;
}
- oct->length = crypt_len;
- OPENSSL_cleanse(in, in_len);
+
+err:
OPENSSL_free(in);
- return oct;
+ OPENSSL_cleanse(out, out_len);
+ OPENSSL_free(out);
+ return ret;
}
X509_SIG *PKCS8_encrypt(int pbe_nid, const EVP_CIPHER *cipher, const char *pass,
@@ -562,40 +520,95 @@ X509_SIG *PKCS8_encrypt_pbe(int pbe_nid, const EVP_CIPHER *cipher,
const uint8_t *pass_raw, size_t pass_raw_len,
const uint8_t *salt, size_t salt_len,
int iterations, PKCS8_PRIV_KEY_INFO *p8inf) {
- X509_SIG *pkcs8 = NULL;
- X509_ALGOR *pbe;
+ X509_SIG *ret = NULL;
+ uint8_t *plaintext = NULL, *salt_buf = NULL, *der = NULL;
+ int plaintext_len = -1;
+ size_t der_len;
+ CBB cbb;
+ CBB_zero(&cbb);
+ EVP_CIPHER_CTX ctx;
+ EVP_CIPHER_CTX_init(&ctx);
- pkcs8 = X509_SIG_new();
- if (pkcs8 == NULL) {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
+ /* Generate a random salt if necessary. */
+ if (salt == NULL) {
+ if (salt_len == 0) {
+ salt_len = PKCS5_SALT_LEN;
+ }
+
+ salt_buf = OPENSSL_malloc(salt_len);
+ if (salt_buf == NULL ||
+ !RAND_bytes(salt_buf, salt_len)) {
+ goto err;
+ }
+
+ salt = salt_buf;
+ }
+
+ if (iterations <= 0) {
+ iterations = PKCS5_DEFAULT_ITERATIONS;
+ }
+
+ /* Convert the input from the legacy ASN.1 format. */
+ plaintext_len = i2d_PKCS8_PRIV_KEY_INFO(p8inf, &plaintext);
+ if (plaintext_len < 0) {
goto err;
}
+ CBB epki;
+ if (!CBB_init(&cbb, 128) ||
+ !CBB_add_asn1(&cbb, &epki, CBS_ASN1_SEQUENCE)) {
+ goto err;
+ }
+
+ int alg_ok;
if (pbe_nid == -1) {
- pbe = PKCS5_pbe2_set(cipher, iterations, salt, salt_len);
+ alg_ok = PKCS5_pbe2_encrypt_init(&epki, &ctx, cipher, (unsigned)iterations,
+ pass_raw, pass_raw_len, salt, salt_len);
} else {
- pbe = PKCS5_pbe_set(pbe_nid, iterations, salt, salt_len);
+ alg_ok = pkcs12_pbe_encrypt_init(&epki, &ctx, pbe_nid, (unsigned)iterations,
+ pass_raw, pass_raw_len, salt, salt_len);
+ }
+ if (!alg_ok) {
+ goto err;
}
- if (!pbe) {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_ASN1_LIB);
+
+ size_t max_out = (size_t)plaintext_len + EVP_CIPHER_CTX_block_size(&ctx);
+ if (max_out < (size_t)plaintext_len) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_TOO_LONG);
goto err;
}
- X509_ALGOR_free(pkcs8->algor);
- pkcs8->algor = pbe;
- M_ASN1_OCTET_STRING_free(pkcs8->digest);
- pkcs8->digest = pkcs12_item_i2d_encrypt(
- pbe, ASN1_ITEM_rptr(PKCS8_PRIV_KEY_INFO), pass_raw, pass_raw_len, p8inf);
- if (!pkcs8->digest) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCRYPT_ERROR);
+ CBB ciphertext;
+ uint8_t *out;
+ int n1, n2;
+ if (!CBB_add_asn1(&epki, &ciphertext, CBS_ASN1_OCTETSTRING) ||
+ !CBB_reserve(&ciphertext, &out, max_out) ||
+ !EVP_CipherUpdate(&ctx, out, &n1, plaintext, plaintext_len) ||
+ !EVP_CipherFinal_ex(&ctx, out + n1, &n2) ||
+ !CBB_did_write(&ciphertext, n1 + n2) ||
+ !CBB_finish(&cbb, &der, &der_len)) {
goto err;
}
- return pkcs8;
+ /* Convert back to legacy ASN.1 objects. */
+ const uint8_t *ptr = der;
+ ret = d2i_X509_SIG(NULL, &ptr, der_len);
+ if (ret == NULL || ptr != der + der_len) {
+ OPENSSL_PUT_ERROR(PKCS8, ERR_R_INTERNAL_ERROR);
+ X509_SIG_free(ret);
+ ret = NULL;
+ }
err:
- X509_SIG_free(pkcs8);
- return NULL;
+ if (plaintext_len > 0) {
+ OPENSSL_cleanse(plaintext, plaintext_len);
+ }
+ OPENSSL_free(plaintext);
+ OPENSSL_free(salt_buf);
+ OPENSSL_free(der);
+ CBB_cleanup(&cbb);
+ EVP_CIPHER_CTX_cleanup(&ctx);
+ return ret;
}
EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) {
@@ -742,8 +755,6 @@ static int PKCS12_handle_content_info(CBS *content_info, unsigned depth,
* encrypted certificate bag and it's generally encrypted with 40-bit
* RC2-CBC. */
CBS version_bytes, eci, contents_type, ai, encrypted_contents;
- X509_ALGOR *algor = NULL;
- const uint8_t *inp;
uint8_t *out;
size_t out_len;
@@ -755,7 +766,7 @@ static int PKCS12_handle_content_info(CBS *content_info, unsigned depth,
!CBS_get_asn1(&eci, &contents_type, CBS_ASN1_OBJECT) ||
/* AlgorithmIdentifier, see
* https://tools.ietf.org/html/rfc5280#section-4.1.1.2 */
- !CBS_get_asn1_element(&eci, &ai, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1(&eci, &ai, CBS_ASN1_SEQUENCE) ||
!CBS_get_asn1_implicit_string(
&eci, &encrypted_contents, &storage,
CBS_ASN1_CONTEXT_SPECIFIC | 0, CBS_ASN1_OCTETSTRING)) {
@@ -763,30 +774,16 @@ static int PKCS12_handle_content_info(CBS *content_info, unsigned depth,
goto err;
}
- if (OBJ_cbs2nid(&contents_type) != NID_pkcs7_data ||
- CBS_len(&ai) > LONG_MAX) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- inp = CBS_data(&ai);
- algor = d2i_X509_ALGOR(NULL, &inp, (long)CBS_len(&ai));
- if (algor == NULL) {
- goto err;
- }
- if (inp != CBS_data(&ai) + CBS_len(&ai)) {
- X509_ALGOR_free(algor);
+ if (OBJ_cbs2nid(&contents_type) != NID_pkcs7_data) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
goto err;
}
- if (!pbe_crypt(algor, ctx->password, ctx->password_len,
- CBS_data(&encrypted_contents), CBS_len(&encrypted_contents),
- &out, &out_len, 0 /* decrypt */)) {
- X509_ALGOR_free(algor);
+ if (!pbe_decrypt(&out, &out_len, &ai, ctx->password, ctx->password_len,
+ CBS_data(&encrypted_contents),
+ CBS_len(&encrypted_contents))) {
goto err;
}
- X509_ALGOR_free(algor);
CBS_init(&content_infos, out, out_len);
ret = PKCS12_handle_content_infos(&content_infos, depth + 1, ctx);
@@ -995,7 +992,7 @@ int PKCS12_get_key_and_certs(EVP_PKEY **out_key, STACK_OF(X509) *out_certs,
iterations = 1;
if (CBS_len(&mac_data) > 0) {
if (!CBS_get_asn1_uint64(&mac_data, &iterations) ||
- iterations > INT_MAX) {
+ iterations > UINT_MAX) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
goto err;
}
@@ -1054,7 +1051,8 @@ struct pkcs12_st {
size_t ber_len;
};
-PKCS12* d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes, size_t ber_len) {
+PKCS12 *d2i_PKCS12(PKCS12 **out_p12, const uint8_t **ber_bytes,
+ size_t ber_len) {
PKCS12 *p12;
p12 = OPENSSL_malloc(sizeof(PKCS12));