external/boringssl: Sync to 0726fb76ebe7f422e3c4fb2e25a0064926975770.
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/9c33ae85621ef8e00a42309b5101e0bedd02b816..0726fb76ebe7f422e3c4fb2e25a0064926975770
Test: cts-tradefed run cts -m CtsLibcoreOkHttpTestCases -a arm64-v8a
Test: cts-tradefed run cts -m CtsLibcoreTestCases -a arm64-v8a
Change-Id: I6da679b1bbebffd35568794c7f6e45e2d620287b
diff --git a/src/crypto/bn/bn.c b/src/crypto/bn/bn.c
index 31bb937..e3c55f2 100644
--- a/src/crypto/bn/bn.c
+++ b/src/crypto/bn/bn.c
@@ -172,12 +172,6 @@
return &kOne;
}
-void BN_with_flags(BIGNUM *out, const BIGNUM *in, int flags) {
- OPENSSL_memcpy(out, in, sizeof(BIGNUM));
- out->flags &= ~BN_FLG_MALLOCED;
- out->flags |= BN_FLG_STATIC_DATA | flags;
-}
-
/* BN_num_bits_word returns the minimum number of bits needed to represent the
* value in |l|. */
unsigned BN_num_bits_word(BN_ULONG l) {
@@ -369,11 +363,3 @@
bn->neg = 0;
}
}
-
-int BN_get_flags(const BIGNUM *bn, int flags) {
- return bn->flags & flags;
-}
-
-void BN_set_flags(BIGNUM *bn, int flags) {
- bn->flags |= flags;
-}
diff --git a/src/crypto/bn/bn_test.cc b/src/crypto/bn/bn_test.cc
index 4f544a7..8f93ad0 100644
--- a/src/crypto/bn/bn_test.cc
+++ b/src/crypto/bn/bn_test.cc
@@ -632,15 +632,6 @@
return false;
}
- BN_set_flags(a.get(), BN_FLG_CONSTTIME);
-
- if (!ret ||
- !BN_mod_inverse(ret.get(), a.get(), m.get(), ctx) ||
- !ExpectBIGNUMsEqual(t, "inv(A) (mod M) (constant-time)", mod_inv.get(),
- ret.get())) {
- return false;
- }
-
return true;
}
diff --git a/src/crypto/bn/exponentiation.c b/src/crypto/bn/exponentiation.c
index 3161a2a..933a731 100644
--- a/src/crypto/bn/exponentiation.c
+++ b/src/crypto/bn/exponentiation.c
@@ -140,12 +140,6 @@
int i, bits, ret = 0;
BIGNUM *v, *rr;
- if ((p->flags & BN_FLG_CONSTTIME) != 0) {
- /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
- OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return 0;
- }
-
BN_CTX_start(ctx);
if (r == a || r == p) {
rr = BN_CTX_get(ctx);
@@ -437,12 +431,6 @@
BIGNUM *val[TABLE_SIZE];
BN_RECP_CTX recp;
- if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
- /* BN_FLG_CONSTTIME only supported by BN_mod_exp_mont() */
- OPENSSL_PUT_ERROR(BN, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return 0;
- }
-
bits = BN_num_bits(p);
if (bits == 0) {
@@ -593,10 +581,6 @@
BIGNUM *val[TABLE_SIZE];
BN_MONT_CTX *new_mont = NULL;
- if (BN_get_flags(p, BN_FLG_CONSTTIME) != 0) {
- return BN_mod_exp_mont_consttime(rr, a, p, m, ctx, mont);
- }
-
if (!BN_is_odd(m)) {
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
return 0;
diff --git a/src/crypto/bn/gcd.c b/src/crypto/bn/gcd.c
index 9e62da0..7c20b8e 100644
--- a/src/crypto/bn/gcd.c
+++ b/src/crypto/bn/gcd.c
@@ -399,10 +399,6 @@
BIGNUM *BN_mod_inverse(BIGNUM *out, const BIGNUM *a, const BIGNUM *n,
BN_CTX *ctx) {
- int no_inverse;
-
- BIGNUM *a_reduced = NULL;
-
BIGNUM *new_out = NULL;
if (out == NULL) {
new_out = BN_new();
@@ -414,10 +410,7 @@
}
int ok = 0;
-
- int no_branch =
- (a->flags & BN_FLG_CONSTTIME) != 0 || (n->flags & BN_FLG_CONSTTIME) != 0;
-
+ BIGNUM *a_reduced = NULL;
if (a->neg || BN_ucmp(a, n) >= 0) {
a_reduced = BN_dup(a);
if (a_reduced == NULL) {
@@ -429,7 +422,8 @@
a = a_reduced;
}
- if (no_branch || !BN_is_odd(n)) {
+ int no_inverse;
+ if (!BN_is_odd(n)) {
if (!bn_mod_inverse_general(out, &no_inverse, a, n, ctx)) {
goto err;
}
diff --git a/src/crypto/bn/montgomery.c b/src/crypto/bn/montgomery.c
index 70f0585..aa5bc42 100644
--- a/src/crypto/bn/montgomery.c
+++ b/src/crypto/bn/montgomery.c
@@ -187,9 +187,6 @@
OPENSSL_PUT_ERROR(BN, ERR_R_INTERNAL_ERROR);
return 0;
}
- if (BN_get_flags(mod, BN_FLG_CONSTTIME)) {
- BN_set_flags(&mont->N, BN_FLG_CONSTTIME);
- }
/* Find n0 such that n0 * N == -1 (mod r).
*
diff --git a/src/crypto/dh/dh.c b/src/crypto/dh/dh.c
index 69a7ec8..33c36f3 100644
--- a/src/crypto/dh/dh.c
+++ b/src/crypto/dh/dh.c
@@ -258,7 +258,6 @@
int generate_new_key = 0;
BN_CTX *ctx = NULL;
BIGNUM *pub_key = NULL, *priv_key = NULL;
- BIGNUM local_priv;
if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) {
OPENSSL_PUT_ERROR(DH, DH_R_MODULUS_TOO_LARGE);
@@ -317,8 +316,7 @@
}
}
- BN_with_flags(&local_priv, priv_key, BN_FLG_CONSTTIME);
- if (!BN_mod_exp_mont_consttime(pub_key, dh->g, &local_priv, dh->p, ctx,
+ if (!BN_mod_exp_mont_consttime(pub_key, dh->g, priv_key, dh->p, ctx,
dh->method_mont_p)) {
goto err;
}
@@ -347,7 +345,6 @@
BIGNUM *shared_key;
int ret = -1;
int check_result;
- BIGNUM local_priv;
if (BN_num_bits(dh->p) > OPENSSL_DH_MAX_MODULUS_BITS) {
OPENSSL_PUT_ERROR(DH, DH_R_MODULUS_TOO_LARGE);
@@ -379,9 +376,8 @@
goto err;
}
- BN_with_flags(&local_priv, dh->priv_key, BN_FLG_CONSTTIME);
- if (!BN_mod_exp_mont_consttime(shared_key, peers_key, &local_priv, dh->p, ctx,
- dh->method_mont_p)) {
+ if (!BN_mod_exp_mont_consttime(shared_key, peers_key, dh->priv_key, dh->p,
+ ctx, dh->method_mont_p)) {
OPENSSL_PUT_ERROR(DH, ERR_R_BN_LIB);
goto err;
}
diff --git a/src/crypto/digest/digests.c b/src/crypto/digest/digests.c
index 351e031..9656027 100644
--- a/src/crypto/digest/digests.c
+++ b/src/crypto/digest/digests.c
@@ -59,9 +59,10 @@
#include <assert.h>
#include <string.h>
+#include <openssl/asn1.h>
#include <openssl/md4.h>
#include <openssl/md5.h>
-#include <openssl/obj.h>
+#include <openssl/nid.h>
#include <openssl/sha.h>
#include "internal.h"
@@ -306,8 +307,36 @@
return NULL;
}
-const EVP_MD* EVP_get_digestbyobj(const ASN1_OBJECT *obj) {
- return EVP_get_digestbynid(OBJ_obj2nid(obj));
+static const struct {
+ uint8_t oid[9];
+ uint8_t oid_len;
+ const EVP_MD *(*md_func) (void);
+} kMDOIDs[] = {
+ /* 1.2.840.113549.2.4 */
+ { {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x04}, 8, EVP_md4 },
+ /* 1.2.840.113549.2.5 */
+ { {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05}, 8, EVP_md5 },
+ /* 1.3.14.3.2.26 */
+ { {0x2b, 0x0e, 0x03, 0x02, 0x1a}, 5, EVP_sha1 },
+ /* 2.16.840.1.101.3.4.2.1 */
+ { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01}, 9, EVP_sha256 },
+ /* 2.16.840.1.101.3.4.2.2 */
+ { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02}, 9, EVP_sha384 },
+ /* 2.16.840.1.101.3.4.2.3 */
+ { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03}, 9, EVP_sha512 },
+ /* 2.16.840.1.101.3.4.2.4 */
+ { {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04}, 9, EVP_sha224 },
+};
+
+const EVP_MD *EVP_get_digestbyobj(const ASN1_OBJECT *obj) {
+ for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(kMDOIDs); i++) {
+ if (obj->length == kMDOIDs[i].oid_len &&
+ memcmp(obj->data, kMDOIDs[i].oid, obj->length) == 0) {
+ return kMDOIDs[i].md_func();
+ }
+ }
+
+ return NULL;
}
const EVP_MD *EVP_get_digestbyname(const char *name) {
diff --git a/src/crypto/dsa/dsa.c b/src/crypto/dsa/dsa.c
index 15583be..e2b6695 100644
--- a/src/crypto/dsa/dsa.c
+++ b/src/crypto/dsa/dsa.c
@@ -434,7 +434,6 @@
int ok = 0;
BN_CTX *ctx = NULL;
BIGNUM *pub_key = NULL, *priv_key = NULL;
- BIGNUM prk;
ctx = BN_CTX_new();
if (ctx == NULL) {
@@ -461,12 +460,9 @@
}
}
- BN_init(&prk);
- BN_with_flags(&prk, priv_key, BN_FLG_CONSTTIME);
-
if (!BN_MONT_CTX_set_locked(&dsa->method_mont_p, &dsa->method_mont_lock,
dsa->p, ctx) ||
- !BN_mod_exp_mont_consttime(pub_key, dsa->g, &prk, dsa->p, ctx,
+ !BN_mod_exp_mont_consttime(pub_key, dsa->g, priv_key, dsa->p, ctx,
dsa->method_mont_p)) {
goto err;
}
@@ -844,8 +840,6 @@
goto err;
}
- BN_set_flags(&k, BN_FLG_CONSTTIME);
-
if (!BN_MONT_CTX_set_locked((BN_MONT_CTX **)&dsa->method_mont_p,
(CRYPTO_MUTEX *)&dsa->method_mont_lock, dsa->p,
ctx) ||
@@ -873,7 +867,6 @@
goto err;
}
- BN_set_flags(&kq, BN_FLG_CONSTTIME);
if (!BN_mod_exp_mont_consttime(r, dsa->g, &kq, dsa->p, ctx,
dsa->method_mont_p)) {
goto err;
diff --git a/src/crypto/ec/asm/p256-x86_64-asm.pl b/src/crypto/ec/asm/p256-x86_64-asm.pl
index a0b4b18..3cd7b01 100755
--- a/src/crypto/ec/asm/p256-x86_64-asm.pl
+++ b/src/crypto/ec/asm/p256-x86_64-asm.pl
@@ -78,57 +78,12 @@
___
{
-################################################################################
-# void ecp_nistz256_mul_by_2(uint64_t res[4], uint64_t a[4]);
-
my ($a0,$a1,$a2,$a3)=map("%r$_",(8..11));
my ($t0,$t1,$t2,$t3,$t4)=("%rax","%rdx","%rcx","%r12","%r13");
my ($r_ptr,$a_ptr,$b_ptr)=("%rdi","%rsi","%rdx");
$code.=<<___;
-.type ecp_nistz256_mul_by_2,\@function,2
-.align 64
-ecp_nistz256_mul_by_2:
- push %r12
- push %r13
-
- mov 8*0($a_ptr), $a0
- xor $t4,$t4
- mov 8*1($a_ptr), $a1
- add $a0, $a0 # a0:a3+a0:a3
- mov 8*2($a_ptr), $a2
- adc $a1, $a1
- mov 8*3($a_ptr), $a3
- lea .Lpoly(%rip), $a_ptr
- mov $a0, $t0
- adc $a2, $a2
- adc $a3, $a3
- mov $a1, $t1
- adc \$0, $t4
-
- sub 8*0($a_ptr), $a0
- mov $a2, $t2
- sbb 8*1($a_ptr), $a1
- sbb 8*2($a_ptr), $a2
- mov $a3, $t3
- sbb 8*3($a_ptr), $a3
- sbb \$0, $t4
-
- cmovc $t0, $a0
- cmovc $t1, $a1
- mov $a0, 8*0($r_ptr)
- cmovc $t2, $a2
- mov $a1, 8*1($r_ptr)
- cmovc $t3, $a3
- mov $a2, 8*2($r_ptr)
- mov $a3, 8*3($r_ptr)
-
- pop %r13
- pop %r12
- ret
-.size ecp_nistz256_mul_by_2,.-ecp_nistz256_mul_by_2
-
################################################################################
# void ecp_nistz256_neg(uint64_t res[4], uint64_t a[4]);
.globl ecp_nistz256_neg
@@ -990,110 +945,6 @@
}
}
{
-my ($r_ptr,$in_ptr)=("%rdi","%rsi");
-my ($acc0,$acc1,$acc2,$acc3)=map("%r$_",(8..11));
-my ($t0,$t1,$t2)=("%rcx","%r12","%r13");
-
-$code.=<<___;
-################################################################################
-# void ecp_nistz256_from_mont(
-# uint64_t res[4],
-# uint64_t in[4]);
-# This one performs Montgomery multiplication by 1, so we only need the reduction
-
-.globl ecp_nistz256_from_mont
-.type ecp_nistz256_from_mont,\@function,2
-.align 32
-ecp_nistz256_from_mont:
- push %r12
- push %r13
-
- mov 8*0($in_ptr), %rax
- mov .Lpoly+8*3(%rip), $t2
- mov 8*1($in_ptr), $acc1
- mov 8*2($in_ptr), $acc2
- mov 8*3($in_ptr), $acc3
- mov %rax, $acc0
- mov .Lpoly+8*1(%rip), $t1
-
- #########################################
- # First iteration
- mov %rax, $t0
- shl \$32, $acc0
- mulq $t2
- shr \$32, $t0
- add $acc0, $acc1
- adc $t0, $acc2
- adc %rax, $acc3
- mov $acc1, %rax
- adc \$0, %rdx
-
- #########################################
- # Second iteration
- mov $acc1, $t0
- shl \$32, $acc1
- mov %rdx, $acc0
- mulq $t2
- shr \$32, $t0
- add $acc1, $acc2
- adc $t0, $acc3
- adc %rax, $acc0
- mov $acc2, %rax
- adc \$0, %rdx
-
- ##########################################
- # Third iteration
- mov $acc2, $t0
- shl \$32, $acc2
- mov %rdx, $acc1
- mulq $t2
- shr \$32, $t0
- add $acc2, $acc3
- adc $t0, $acc0
- adc %rax, $acc1
- mov $acc3, %rax
- adc \$0, %rdx
-
- ###########################################
- # Last iteration
- mov $acc3, $t0
- shl \$32, $acc3
- mov %rdx, $acc2
- mulq $t2
- shr \$32, $t0
- add $acc3, $acc0
- adc $t0, $acc1
- mov $acc0, $t0
- adc %rax, $acc2
- mov $acc1, $in_ptr
- adc \$0, %rdx
-
- ###########################################
- # Branch-less conditional subtraction
- sub \$-1, $acc0
- mov $acc2, %rax
- sbb $t1, $acc1
- sbb \$0, $acc2
- mov %rdx, $acc3
- sbb $t2, %rdx
- sbb $t2, $t2
-
- cmovnz $t0, $acc0
- cmovnz $in_ptr, $acc1
- mov $acc0, 8*0($r_ptr)
- cmovnz %rax, $acc2
- mov $acc1, 8*1($r_ptr)
- cmovz %rdx, $acc3
- mov $acc2, 8*2($r_ptr)
- mov $acc3, 8*3($r_ptr)
-
- pop %r13
- pop %r12
- ret
-.size ecp_nistz256_from_mont,.-ecp_nistz256_from_mont
-___
-}
-{
my ($val,$in_t,$index)=$win64?("%rcx","%rdx","%r8d"):("%rdi","%rsi","%edx");
my ($ONE,$INDEX,$Ra,$Rb,$Rc,$Rd,$Re,$Rf)=map("%xmm$_",(0..7));
my ($M0,$T0a,$T0b,$T0c,$T0d,$T0e,$T0f,$TMP0)=map("%xmm$_",(8..15));
diff --git a/src/crypto/ec/p256-x86_64.c b/src/crypto/ec/p256-x86_64.c
index 2400740..652d10c 100644
--- a/src/crypto/ec/p256-x86_64.c
+++ b/src/crypto/ec/p256-x86_64.c
@@ -515,13 +515,15 @@
ecp_nistz256_mod_inverse_mont(z_inv3, point_z);
ecp_nistz256_sqr_mont(z_inv2, z_inv3);
- /* TODO(davidben): The two calls to |ecp_nistz256_from_mont| may be factored
- * into one call now that other operations also reduce mod P. */
+ /* Instead of using |ecp_nistz256_from_mont| to convert the |x| coordinate
+ * and then calling |ecp_nistz256_from_mont| again to convert the |y|
+ * coordinate below, convert the common factor |z_inv2| once now, saving one
+ * reduction. */
+ ecp_nistz256_from_mont(z_inv2, z_inv2);
if (x != NULL) {
BN_ULONG x_aff[P256_LIMBS];
ecp_nistz256_mul_mont(x_aff, z_inv2, point_x);
- ecp_nistz256_from_mont(x_aff, x_aff);
if (!bn_set_words(x, x_aff, P256_LIMBS)) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
return 0;
@@ -532,7 +534,6 @@
BN_ULONG y_aff[P256_LIMBS];
ecp_nistz256_mul_mont(z_inv3, z_inv3, z_inv2);
ecp_nistz256_mul_mont(y_aff, z_inv3, point_y);
- ecp_nistz256_from_mont(y_aff, y_aff);
if (!bn_set_words(y, y_aff, P256_LIMBS)) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
return 0;
diff --git a/src/crypto/ec/p256-x86_64.h b/src/crypto/ec/p256-x86_64.h
index 9897699..0132348 100644
--- a/src/crypto/ec/p256-x86_64.h
+++ b/src/crypto/ec/p256-x86_64.h
@@ -51,8 +51,11 @@
/* ecp_nistz256_from_mont sets |res| to |in|, converted from Montgomery domain
* by multiplying with 1. */
-void ecp_nistz256_from_mont(BN_ULONG res[P256_LIMBS],
- const BN_ULONG in[P256_LIMBS]);
+static inline void ecp_nistz256_from_mont(BN_ULONG res[P256_LIMBS],
+ const BN_ULONG in[P256_LIMBS]) {
+ static const BN_ULONG ONE[P256_LIMBS] = { 1 };
+ ecp_nistz256_mul_mont(res, in, ONE);
+}
/* P-256 point operations.
diff --git a/src/crypto/ec/wnaf.c b/src/crypto/ec/wnaf.c
index 1594354..67b7f34 100644
--- a/src/crypto/ec/wnaf.c
+++ b/src/crypto/ec/wnaf.c
@@ -242,7 +242,7 @@
BN_CTX *new_ctx = NULL;
const EC_POINT *generator = NULL;
EC_POINT *tmp = NULL;
- size_t total_num;
+ size_t total_num = 0;
size_t i, j;
int k;
int r_is_inverted = 0;
@@ -251,7 +251,7 @@
int8_t **wNAF = NULL; /* individual wNAFs */
size_t *wNAF_len = NULL;
size_t max_len = 0;
- size_t num_val;
+ size_t num_val = 0;
EC_POINT **val = NULL; /* precomputation */
EC_POINT **v;
EC_POINT ***val_sub = NULL; /* pointers to sub-arrays of 'val' */
@@ -284,15 +284,14 @@
}
- wsize = OPENSSL_malloc(total_num * sizeof wsize[0]);
- wNAF_len = OPENSSL_malloc(total_num * sizeof wNAF_len[0]);
- wNAF = OPENSSL_malloc((total_num + 1) *
- sizeof wNAF[0]); /* includes space for pivot */
- val_sub = OPENSSL_malloc(total_num * sizeof val_sub[0]);
+ wsize = OPENSSL_malloc(total_num * sizeof(wsize[0]));
+ wNAF_len = OPENSSL_malloc(total_num * sizeof(wNAF_len[0]));
+ wNAF = OPENSSL_malloc(total_num * sizeof(wNAF[0]));
+ val_sub = OPENSSL_malloc(total_num * sizeof(val_sub[0]));
/* Ensure wNAF is initialised in case we end up going to err. */
- if (wNAF) {
- wNAF[0] = NULL; /* preliminary pivot */
+ if (wNAF != NULL) {
+ OPENSSL_memset(wNAF, 0, total_num * sizeof(wNAF[0]));
}
if (!wsize || !wNAF_len || !wNAF || !val_sub) {
@@ -309,7 +308,6 @@
bits = i < num ? BN_num_bits(scalars[i]) : BN_num_bits(g_scalar);
wsize[i] = window_bits_for_scalar_size(bits);
num_val += (size_t)1 << (wsize[i] - 1);
- wNAF[i + 1] = NULL; /* make sure we always have a pivot */
wNAF[i] =
compute_wNAF((i < num ? scalars[i] : g_scalar), wsize[i], &wNAF_len[i]);
if (wNAF[i] == NULL) {
@@ -322,12 +320,12 @@
/* All points we precompute now go into a single array 'val'. 'val_sub[i]' is
* a pointer to the subarray for the i-th point. */
- val = OPENSSL_malloc((num_val + 1) * sizeof val[0]);
+ val = OPENSSL_malloc(num_val * sizeof(val[0]));
if (val == NULL) {
OPENSSL_PUT_ERROR(EC, ERR_R_MALLOC_FAILURE);
goto err;
}
- val[num_val] = NULL; /* pivot element */
+ OPENSSL_memset(val, 0, num_val * sizeof(val[0]));
/* allocate points for precomputation */
v = val;
@@ -442,17 +440,15 @@
OPENSSL_free(wsize);
OPENSSL_free(wNAF_len);
if (wNAF != NULL) {
- int8_t **w;
-
- for (w = wNAF; *w != NULL; w++) {
- OPENSSL_free(*w);
+ for (i = 0; i < total_num; i++) {
+ OPENSSL_free(wNAF[i]);
}
OPENSSL_free(wNAF);
}
if (val != NULL) {
- for (v = val; *v != NULL; v++) {
- EC_POINT_clear_free(*v);
+ for (i = 0; i < num_val; i++) {
+ EC_POINT_clear_free(val[i]);
}
OPENSSL_free(val);
diff --git a/src/crypto/modes/asm/aesni-gcm-x86_64.pl b/src/crypto/modes/asm/aesni-gcm-x86_64.pl
index f777a6e..e329741 100644
--- a/src/crypto/modes/asm/aesni-gcm-x86_64.pl
+++ b/src/crypto/modes/asm/aesni-gcm-x86_64.pl
@@ -41,17 +41,24 @@
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
-# This must be kept in sync with |$avx| in ghash-x86_64.pl; otherwise tags will
+# |$avx| in ghash-x86_64.pl must be set to at least 1; otherwise tags will
# be computed incorrectly.
#
# In upstream, this is controlled by shelling out to the compiler to check
# versions, but BoringSSL is intended to be used with pre-generated perlasm
# output, so this isn't useful anyway.
-$avx = 0;
+#
+# The upstream code uses the condition |$avx>1| even though no AVX2
+# instructions are used, because it assumes MOVBE is supported by the assembler
+# if and only if AVX2 is also supported by the assembler; see
+# https://marc.info/?l=openssl-dev&m=146567589526984&w=2.
+$avx = 2;
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
*STDOUT=*OUT;
+# See the comment above regarding why the condition is ($avx>1) when there are
+# no AVX2 instructions being used.
if ($avx>1) {{{
($inp,$out,$len,$key,$ivp,$Xip)=("%rdi","%rsi","%rdx","%rcx","%r8","%r9");
diff --git a/src/crypto/modes/asm/ghash-x86.pl b/src/crypto/modes/asm/ghash-x86.pl
index db6eeae..182c29a 100644
--- a/src/crypto/modes/asm/ghash-x86.pl
+++ b/src/crypto/modes/asm/ghash-x86.pl
@@ -258,245 +258,17 @@
&mov (&DWP($bias+56,"esp"),0xA9C0<<16);
&mov (&DWP($bias+60,"esp"),0xB5E0<<16);
}
-
-$suffix = $x86only ? "" : "_x86";
-&function_begin("gcm_gmult_4bit".$suffix);
- &stack_push(16+4+1); # +1 for stack alignment
- &mov ($inp,&wparam(0)); # load Xi
- &mov ($Htbl,&wparam(1)); # load Htable
-
- &mov ($Zhh,&DWP(0,$inp)); # load Xi[16]
- &mov ($Zhl,&DWP(4,$inp));
- &mov ($Zlh,&DWP(8,$inp));
- &mov ($Zll,&DWP(12,$inp));
-
- &deposit_rem_4bit(16);
-
- &mov (&DWP(0,"esp"),$Zhh); # copy Xi[16] on stack
- &mov (&DWP(4,"esp"),$Zhl);
- &mov (&DWP(8,"esp"),$Zlh);
- &mov (&DWP(12,"esp"),$Zll);
- &shr ($Zll,20);
- &and ($Zll,0xf0);
-
- if ($unroll) {
- &call ("_x86_gmult_4bit_inner");
- } else {
- &x86_loop(0);
- &mov ($inp,&wparam(0));
- }
-
- &mov (&DWP(12,$inp),$Zll);
- &mov (&DWP(8,$inp),$Zlh);
- &mov (&DWP(4,$inp),$Zhl);
- &mov (&DWP(0,$inp),$Zhh);
- &stack_pop(16+4+1);
-&function_end("gcm_gmult_4bit".$suffix);
-
-&function_begin("gcm_ghash_4bit".$suffix);
- &stack_push(16+4+1); # +1 for 64-bit alignment
- &mov ($Zll,&wparam(0)); # load Xi
- &mov ($Htbl,&wparam(1)); # load Htable
- &mov ($inp,&wparam(2)); # load in
- &mov ("ecx",&wparam(3)); # load len
- &add ("ecx",$inp);
- &mov (&wparam(3),"ecx");
-
- &mov ($Zhh,&DWP(0,$Zll)); # load Xi[16]
- &mov ($Zhl,&DWP(4,$Zll));
- &mov ($Zlh,&DWP(8,$Zll));
- &mov ($Zll,&DWP(12,$Zll));
-
- &deposit_rem_4bit(16);
-
- &set_label("x86_outer_loop",16);
- &xor ($Zll,&DWP(12,$inp)); # xor with input
- &xor ($Zlh,&DWP(8,$inp));
- &xor ($Zhl,&DWP(4,$inp));
- &xor ($Zhh,&DWP(0,$inp));
- &mov (&DWP(12,"esp"),$Zll); # dump it on stack
- &mov (&DWP(8,"esp"),$Zlh);
- &mov (&DWP(4,"esp"),$Zhl);
- &mov (&DWP(0,"esp"),$Zhh);
-
- &shr ($Zll,20);
- &and ($Zll,0xf0);
-
- if ($unroll) {
- &call ("_x86_gmult_4bit_inner");
- } else {
- &x86_loop(0);
- &mov ($inp,&wparam(2));
- }
- &lea ($inp,&DWP(16,$inp));
- &cmp ($inp,&wparam(3));
- &mov (&wparam(2),$inp) if (!$unroll);
- &jb (&label("x86_outer_loop"));
-
- &mov ($inp,&wparam(0)); # load Xi
- &mov (&DWP(12,$inp),$Zll);
- &mov (&DWP(8,$inp),$Zlh);
- &mov (&DWP(4,$inp),$Zhl);
- &mov (&DWP(0,$inp),$Zhh);
- &stack_pop(16+4+1);
-&function_end("gcm_ghash_4bit".$suffix);
-
if (!$x86only) {{{
&static_label("rem_4bit");
if (!$sse2) {{ # pure-MMX "May" version...
-$S=12; # shift factor for rem_4bit
+ # This code was removed since SSE2 is required for BoringSSL. The
+ # outer structure of the code was retained to minimize future merge
+ # conflicts.
-&function_begin_B("_mmx_gmult_4bit_inner");
-# MMX version performs 3.5 times better on P4 (see comment in non-MMX
-# routine for further details), 100% better on Opteron, ~70% better
-# on Core2 and PIII... In other words effort is considered to be well
-# spent... Since initial release the loop was unrolled in order to
-# "liberate" register previously used as loop counter. Instead it's
-# used to optimize critical path in 'Z.hi ^= rem_4bit[Z.lo&0xf]'.
-# The path involves move of Z.lo from MMX to integer register,
-# effective address calculation and finally merge of value to Z.hi.
-# Reference to rem_4bit is scheduled so late that I had to >>4
-# rem_4bit elements. This resulted in 20-45% procent improvement
-# on contemporary µ-archs.
-{
- my $cnt;
- my $rem_4bit = "eax";
- my @rem = ($Zhh,$Zll);
- my $nhi = $Zhl;
- my $nlo = $Zlh;
-
- my ($Zlo,$Zhi) = ("mm0","mm1");
- my $tmp = "mm2";
-
- &xor ($nlo,$nlo); # avoid partial register stalls on PIII
- &mov ($nhi,$Zll);
- &mov (&LB($nlo),&LB($nhi));
- &shl (&LB($nlo),4);
- &and ($nhi,0xf0);
- &movq ($Zlo,&QWP(8,$Htbl,$nlo));
- &movq ($Zhi,&QWP(0,$Htbl,$nlo));
- &movd ($rem[0],$Zlo);
-
- for ($cnt=28;$cnt>=-2;$cnt--) {
- my $odd = $cnt&1;
- my $nix = $odd ? $nlo : $nhi;
-
- &shl (&LB($nlo),4) if ($odd);
- &psrlq ($Zlo,4);
- &movq ($tmp,$Zhi);
- &psrlq ($Zhi,4);
- &pxor ($Zlo,&QWP(8,$Htbl,$nix));
- &mov (&LB($nlo),&BP($cnt/2,$inp)) if (!$odd && $cnt>=0);
- &psllq ($tmp,60);
- &and ($nhi,0xf0) if ($odd);
- &pxor ($Zhi,&QWP(0,$rem_4bit,$rem[1],8)) if ($cnt<28);
- &and ($rem[0],0xf);
- &pxor ($Zhi,&QWP(0,$Htbl,$nix));
- &mov ($nhi,$nlo) if (!$odd && $cnt>=0);
- &movd ($rem[1],$Zlo);
- &pxor ($Zlo,$tmp);
-
- push (@rem,shift(@rem)); # "rotate" registers
- }
-
- &mov ($inp,&DWP(4,$rem_4bit,$rem[1],8)); # last rem_4bit[rem]
-
- &psrlq ($Zlo,32); # lower part of Zlo is already there
- &movd ($Zhl,$Zhi);
- &psrlq ($Zhi,32);
- &movd ($Zlh,$Zlo);
- &movd ($Zhh,$Zhi);
- &shl ($inp,4); # compensate for rem_4bit[i] being >>4
-
- &bswap ($Zll);
- &bswap ($Zhl);
- &bswap ($Zlh);
- &xor ($Zhh,$inp);
- &bswap ($Zhh);
-
- &ret ();
-}
-&function_end_B("_mmx_gmult_4bit_inner");
-
-&function_begin("gcm_gmult_4bit_mmx");
- &mov ($inp,&wparam(0)); # load Xi
- &mov ($Htbl,&wparam(1)); # load Htable
-
- &call (&label("pic_point"));
- &set_label("pic_point");
- &blindpop("eax");
- &lea ("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax"));
-
- &movz ($Zll,&BP(15,$inp));
-
- &call ("_mmx_gmult_4bit_inner");
-
- &mov ($inp,&wparam(0)); # load Xi
- &emms ();
- &mov (&DWP(12,$inp),$Zll);
- &mov (&DWP(4,$inp),$Zhl);
- &mov (&DWP(8,$inp),$Zlh);
- &mov (&DWP(0,$inp),$Zhh);
-&function_end("gcm_gmult_4bit_mmx");
-
-# Streamed version performs 20% better on P4, 7% on Opteron,
-# 10% on Core2 and PIII...
-&function_begin("gcm_ghash_4bit_mmx");
- &mov ($Zhh,&wparam(0)); # load Xi
- &mov ($Htbl,&wparam(1)); # load Htable
- &mov ($inp,&wparam(2)); # load in
- &mov ($Zlh,&wparam(3)); # load len
-
- &call (&label("pic_point"));
- &set_label("pic_point");
- &blindpop("eax");
- &lea ("eax",&DWP(&label("rem_4bit")."-".&label("pic_point"),"eax"));
-
- &add ($Zlh,$inp);
- &mov (&wparam(3),$Zlh); # len to point at the end of input
- &stack_push(4+1); # +1 for stack alignment
-
- &mov ($Zll,&DWP(12,$Zhh)); # load Xi[16]
- &mov ($Zhl,&DWP(4,$Zhh));
- &mov ($Zlh,&DWP(8,$Zhh));
- &mov ($Zhh,&DWP(0,$Zhh));
- &jmp (&label("mmx_outer_loop"));
-
- &set_label("mmx_outer_loop",16);
- &xor ($Zll,&DWP(12,$inp));
- &xor ($Zhl,&DWP(4,$inp));
- &xor ($Zlh,&DWP(8,$inp));
- &xor ($Zhh,&DWP(0,$inp));
- &mov (&wparam(2),$inp);
- &mov (&DWP(12,"esp"),$Zll);
- &mov (&DWP(4,"esp"),$Zhl);
- &mov (&DWP(8,"esp"),$Zlh);
- &mov (&DWP(0,"esp"),$Zhh);
-
- &mov ($inp,"esp");
- &shr ($Zll,24);
-
- &call ("_mmx_gmult_4bit_inner");
-
- &mov ($inp,&wparam(2));
- &lea ($inp,&DWP(16,$inp));
- &cmp ($inp,&wparam(3));
- &jb (&label("mmx_outer_loop"));
-
- &mov ($inp,&wparam(0)); # load Xi
- &emms ();
- &mov (&DWP(12,$inp),$Zll);
- &mov (&DWP(4,$inp),$Zhl);
- &mov (&DWP(8,$inp),$Zlh);
- &mov (&DWP(0,$inp),$Zhh);
-
- &stack_pop(4+1);
-&function_end("gcm_ghash_4bit_mmx");
-
}} else {{ # "June" MMX version...
# ... has slower "April" gcm_gmult_4bit_mmx with folded
# loop. This is done to conserve code size...
diff --git a/src/crypto/modes/asm/ghash-x86_64.pl b/src/crypto/modes/asm/ghash-x86_64.pl
index df8546c..d7471e2 100644
--- a/src/crypto/modes/asm/ghash-x86_64.pl
+++ b/src/crypto/modes/asm/ghash-x86_64.pl
@@ -90,13 +90,13 @@
( $xlate="${dir}../../perlasm/x86_64-xlate.pl" and -f $xlate) or
die "can't locate x86_64-xlate.pl";
-# This must be kept in sync with |$avx| in aesni-gcm-x86_64.pl; otherwise tags
-# will be computed incorrectly.
+# See the notes about |$avx| in aesni-gcm-x86_64.pl; otherwise tags will be
+# computed incorrectly.
#
# In upstream, this is controlled by shelling out to the compiler to check
# versions, but BoringSSL is intended to be used with pre-generated perlasm
# output, so this isn't useful anyway.
-$avx = 0;
+$avx = 1;
open OUT,"| \"$^X\" \"$xlate\" $flavour \"$output\"";
*STDOUT=*OUT;
diff --git a/src/crypto/modes/gcm.c b/src/crypto/modes/gcm.c
index df68c40..1330ad6 100644
--- a/src/crypto/modes/gcm.c
+++ b/src/crypto/modes/gcm.c
@@ -255,19 +255,16 @@
#if defined(GHASH_ASM)
+
#if defined(OPENSSL_X86) || defined(OPENSSL_X86_64)
-#define GHASH_ASM_X86_OR_64
#define GCM_FUNCREF_4BIT
void gcm_init_clmul(u128 Htable[16], const uint64_t Xi[2]);
void gcm_gmult_clmul(uint64_t Xi[2], const u128 Htable[16]);
void gcm_ghash_clmul(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
size_t len);
-#if defined(OPENSSL_X86)
-#define gcm_init_avx gcm_init_clmul
-#define gcm_gmult_avx gcm_gmult_clmul
-#define gcm_ghash_avx gcm_ghash_clmul
-#else
+#if defined(OPENSSL_X86_64)
+#define GHASH_ASM_X86_64
void gcm_init_avx(u128 Htable[16], const uint64_t Xi[2]);
void gcm_gmult_avx(uint64_t Xi[2], const u128 Htable[16]);
void gcm_ghash_avx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *in,
@@ -289,11 +286,8 @@
void gcm_gmult_4bit_mmx(uint64_t Xi[2], const u128 Htable[16]);
void gcm_ghash_4bit_mmx(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
size_t len);
-
-void gcm_gmult_4bit_x86(uint64_t Xi[2], const u128 Htable[16]);
-void gcm_ghash_4bit_x86(uint64_t Xi[2], const u128 Htable[16], const uint8_t *inp,
- size_t len);
#endif
+
#elif defined(OPENSSL_ARM) || defined(OPENSSL_AARCH64)
#include <openssl/arm_arch.h>
#if __ARM_ARCH__ >= 7
@@ -357,7 +351,8 @@
#endif
void CRYPTO_ghash_init(gmult_func *out_mult, ghash_func *out_hash,
- u128 out_table[16], const uint8_t *gcm_key) {
+ u128 *out_key, u128 out_table[16],
+ const uint8_t *gcm_key) {
union {
uint64_t u[2];
uint8_t c[16];
@@ -369,7 +364,9 @@
H.u[0] = CRYPTO_bswap8(H.u[0]);
H.u[1] = CRYPTO_bswap8(H.u[1]);
-#if defined(GHASH_ASM_X86_OR_64)
+ OPENSSL_memcpy(out_key, H.c, 16);
+
+#if defined(GHASH_ASM_X86_64)
if (crypto_gcm_clmul_enabled()) {
if (((OPENSSL_ia32cap_P[1] >> 22) & 0x41) == 0x41) { /* AVX+MOVBE */
gcm_init_avx(out_table, H.u);
@@ -377,20 +374,18 @@
*out_hash = gcm_ghash_avx;
return;
}
-
gcm_init_clmul(out_table, H.u);
*out_mult = gcm_gmult_clmul;
*out_hash = gcm_ghash_clmul;
return;
}
-#if defined(GHASH_ASM_X86) /* x86 only */
- if (OPENSSL_ia32cap_P[0] & (1 << 25)) { /* check SSE bit */
- gcm_init_4bit(out_table, H.u);
- *out_mult = gcm_gmult_4bit_mmx;
- *out_hash = gcm_ghash_4bit_mmx;
+#elif defined(GHASH_ASM_X86)
+ if (crypto_gcm_clmul_enabled()) {
+ gcm_init_clmul(out_table, H.u);
+ *out_mult = gcm_gmult_clmul;
+ *out_hash = gcm_ghash_clmul;
return;
}
-#endif
#elif defined(GHASH_ASM_ARM)
if (pmull_capable()) {
gcm_init_v8(out_table, H.u);
@@ -416,8 +411,8 @@
gcm_init_4bit(out_table, H.u);
#if defined(GHASH_ASM_X86)
- *out_mult = gcm_gmult_4bit_x86;
- *out_hash = gcm_ghash_4bit_x86;
+ *out_mult = gcm_gmult_4bit_mmx;
+ *out_hash = gcm_ghash_4bit_mmx;
#else
*out_mult = gcm_gmult_4bit;
*out_hash = gcm_ghash_4bit;
@@ -433,7 +428,7 @@
OPENSSL_memset(gcm_key, 0, sizeof(gcm_key));
(*block)(gcm_key, gcm_key, aes_key);
- CRYPTO_ghash_init(&ctx->gmult, &ctx->ghash, ctx->Htable, gcm_key);
+ CRYPTO_ghash_init(&ctx->gmult, &ctx->ghash, &ctx->H, ctx->Htable, gcm_key);
}
void CRYPTO_gcm128_setiv(GCM128_CONTEXT *ctx, const void *key,
diff --git a/src/crypto/modes/internal.h b/src/crypto/modes/internal.h
index 9b579fa..94072ec 100644
--- a/src/crypto/modes/internal.h
+++ b/src/crypto/modes/internal.h
@@ -150,6 +150,9 @@
size_t t[16 / sizeof(size_t)];
} Yi, EKi, EK0, len, Xi;
+ /* Note that the order of |Xi|, |H| and |Htable| is fixed by the MOVBE-based,
+ * x86-64, GHASH assembly. */
+ u128 H;
u128 Htable[16];
gmult_func gmult;
ghash_func ghash;
@@ -211,7 +214,8 @@
* |out_table| and sets |*out_mult| and |*out_hash| to (potentially hardware
* accelerated) functions for performing operations in the GHASH field. */
void CRYPTO_ghash_init(gmult_func *out_mult, ghash_func *out_hash,
- u128 out_table[16], const uint8_t *gcm_key);
+ u128 *out_key, u128 out_table[16],
+ const uint8_t *gcm_key);
/* CRYPTO_gcm128_init initialises |ctx| to use |block| (typically AES) with
* the given key. */
@@ -348,7 +352,10 @@
} polyval_block;
struct polyval_ctx {
+ /* Note that the order of |S|, |H| and |Htable| is fixed by the MOVBE-based,
+ * x86-64, GHASH assembly. */
polyval_block S;
+ u128 H;
u128 Htable[16];
gmult_func gmult;
ghash_func ghash;
diff --git a/src/crypto/modes/polyval.c b/src/crypto/modes/polyval.c
index 125b256..33d37eb 100644
--- a/src/crypto/modes/polyval.c
+++ b/src/crypto/modes/polyval.c
@@ -57,7 +57,7 @@
OPENSSL_memcpy(H.c, key, 16);
reverse_and_mulX_ghash(&H);
- CRYPTO_ghash_init(&ctx->gmult, &ctx->ghash, ctx->Htable, H.c);
+ CRYPTO_ghash_init(&ctx->gmult, &ctx->ghash, &ctx->H, ctx->Htable, H.c);
OPENSSL_memset(&ctx->S, 0, sizeof(ctx->S));
}
diff --git a/src/crypto/pkcs8/CMakeLists.txt b/src/crypto/pkcs8/CMakeLists.txt
index ffb3821..a2e52e1 100644
--- a/src/crypto/pkcs8/CMakeLists.txt
+++ b/src/crypto/pkcs8/CMakeLists.txt
@@ -7,7 +7,6 @@
pkcs8.c
p8_pkey.c
- p5_pbe.c
p5_pbev2.c
)
diff --git a/src/crypto/pkcs8/internal.h b/src/crypto/pkcs8/internal.h
index 7995e78..9cebe29 100644
--- a/src/crypto/pkcs8/internal.h
+++ b/src/crypto/pkcs8/internal.h
@@ -63,17 +63,36 @@
#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);
+
+/* 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/src/crypto/pkcs8/p5_pbe.c b/src/crypto/pkcs8/p5_pbe.c
deleted file mode 100644
index eee2e00..0000000
--- a/src/crypto/pkcs8/p5_pbe.c
+++ /dev/null
@@ -1,152 +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 <string.h>
-
-#include <openssl/asn1t.h>
-#include <openssl/err.h>
-#include <openssl/obj.h>
-#include <openssl/pkcs8.h>
-#include <openssl/rand.h>
-#include <openssl/x509.h>
-
-#include "../internal.h"
-#include "internal.h"
-
-
-/* PKCS#5 password based encryption structure */
-
-ASN1_SEQUENCE(PBEPARAM) = {
- ASN1_SIMPLE(PBEPARAM, salt, ASN1_OCTET_STRING),
- ASN1_SIMPLE(PBEPARAM, iter, ASN1_INTEGER)
-} ASN1_SEQUENCE_END(PBEPARAM)
-
-IMPLEMENT_ASN1_FUNCTIONS(PBEPARAM)
-
-
-/* Set an algorithm identifier for a PKCS#5 PBE algorithm */
-
-int PKCS5_pbe_set0_algor(X509_ALGOR *algor, int alg, int iter,
- const unsigned char *salt, int saltlen)
- {
- PBEPARAM *pbe=NULL;
- ASN1_STRING *pbe_str=NULL;
- unsigned char *sstr;
-
- pbe = PBEPARAM_new();
- if (!pbe)
- {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if(iter <= 0)
- iter = PKCS5_DEFAULT_ITERATIONS;
- if (!ASN1_INTEGER_set(pbe->iter, iter))
- {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if (!saltlen)
- saltlen = PKCS5_SALT_LEN;
- if (!ASN1_STRING_set(pbe->salt, NULL, saltlen))
- {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- sstr = ASN1_STRING_data(pbe->salt);
- if (salt)
- OPENSSL_memcpy(sstr, salt, saltlen);
- else if (!RAND_bytes(sstr, saltlen))
- goto err;
-
- if(!ASN1_item_pack(pbe, ASN1_ITEM_rptr(PBEPARAM), &pbe_str))
- {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
- goto err;
- }
-
- PBEPARAM_free(pbe);
- pbe = NULL;
-
- if (X509_ALGOR_set0(algor, OBJ_nid2obj(alg), V_ASN1_SEQUENCE, pbe_str))
- return 1;
-
-err:
- if (pbe != NULL)
- PBEPARAM_free(pbe);
- if (pbe_str != NULL)
- ASN1_STRING_free(pbe_str);
- return 0;
- }
-
-/* Return an algorithm identifier for a PKCS#5 PBE algorithm */
-
-X509_ALGOR *PKCS5_pbe_set(int alg, int iter,
- const unsigned char *salt, int saltlen)
- {
- X509_ALGOR *ret;
- ret = X509_ALGOR_new();
- if (!ret)
- {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
-
- if (PKCS5_pbe_set0_algor(ret, alg, iter, salt, saltlen))
- return ret;
-
- X509_ALGOR_free(ret);
- return NULL;
- }
diff --git a/src/crypto/pkcs8/p5_pbev2.c b/src/crypto/pkcs8/p5_pbev2.c
index c16b83f..59e2067 100644
--- a/src/crypto/pkcs8/p5_pbev2.c
+++ b/src/crypto/pkcs8/p5_pbev2.c
@@ -53,390 +53,174 @@
* (eay@cryptsoft.com). This product includes software written by Tim
* Hudson (tjh@cryptsoft.com). */
-#include <assert.h>
+#include <openssl/pkcs8.h>
+
#include <limits.h>
#include <string.h>
-#include <openssl/asn1t.h>
+#include <openssl/bytestring.h>
#include <openssl/cipher.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"
-/* PKCS#5 v2.0 password based encryption structures */
-
-ASN1_SEQUENCE(PBE2PARAM) = {
- ASN1_SIMPLE(PBE2PARAM, keyfunc, X509_ALGOR),
- ASN1_SIMPLE(PBE2PARAM, encryption, X509_ALGOR)
-} ASN1_SEQUENCE_END(PBE2PARAM)
-
-IMPLEMENT_ASN1_FUNCTIONS(PBE2PARAM)
-
-ASN1_SEQUENCE(PBKDF2PARAM) = {
- ASN1_SIMPLE(PBKDF2PARAM, salt, ASN1_ANY),
- ASN1_SIMPLE(PBKDF2PARAM, iter, ASN1_INTEGER),
- ASN1_OPT(PBKDF2PARAM, keylength, ASN1_INTEGER),
- ASN1_OPT(PBKDF2PARAM, prf, X509_ALGOR)
-} ASN1_SEQUENCE_END(PBKDF2PARAM)
-
-IMPLEMENT_ASN1_FUNCTIONS(PBKDF2PARAM)
-
-static int ASN1_TYPE_set_octetstring(ASN1_TYPE *a, unsigned char *data, int len)
- {
- ASN1_STRING *os;
-
- if ((os=M_ASN1_OCTET_STRING_new()) == NULL) return(0);
- if (!M_ASN1_OCTET_STRING_set(os,data,len))
- {
- M_ASN1_OCTET_STRING_free(os);
- return 0;
- }
- ASN1_TYPE_set(a,V_ASN1_OCTET_STRING,os);
- return(1);
- }
-
-static int param_to_asn1(EVP_CIPHER_CTX *c, ASN1_TYPE *type)
- {
- unsigned iv_len;
-
- iv_len = EVP_CIPHER_CTX_iv_length(c);
- return ASN1_TYPE_set_octetstring(type, c->oiv, iv_len);
- }
-
-/* Return an algorithm identifier for a PKCS#5 v2.0 PBE algorithm:
- * yes I know this is horrible!
- *
- * Extended version to allow application supplied PRF NID and IV. */
-
-X509_ALGOR *PKCS5_pbe2_set_iv(const EVP_CIPHER *cipher, int iter,
- unsigned char *salt, int saltlen,
- unsigned char *aiv, int prf_nid)
-{
- X509_ALGOR *scheme = NULL, *kalg = NULL, *ret = NULL;
- int alg_nid, keylen;
- EVP_CIPHER_CTX ctx;
- unsigned char iv[EVP_MAX_IV_LENGTH];
- PBE2PARAM *pbe2 = NULL;
- const ASN1_OBJECT *obj;
-
- alg_nid = EVP_CIPHER_nid(cipher);
- if(alg_nid == NID_undef) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_CIPHER_HAS_NO_OBJECT_IDENTIFIER);
- goto err;
- }
- obj = OBJ_nid2obj(alg_nid);
-
- if(!(pbe2 = PBE2PARAM_new())) goto merr;
-
- /* Setup the AlgorithmIdentifier for the encryption scheme */
- scheme = pbe2->encryption;
-
- scheme->algorithm = (ASN1_OBJECT*) obj;
- if(!(scheme->parameter = ASN1_TYPE_new())) goto merr;
-
- /* Create random IV */
- if (EVP_CIPHER_iv_length(cipher))
- {
- if (aiv)
- OPENSSL_memcpy(iv, aiv, EVP_CIPHER_iv_length(cipher));
- else if (!RAND_bytes(iv, EVP_CIPHER_iv_length(cipher)))
- goto err;
- }
-
- EVP_CIPHER_CTX_init(&ctx);
-
- /* Dummy cipherinit to just setup the IV, and PRF */
- if (!EVP_CipherInit_ex(&ctx, cipher, NULL, NULL, iv, 0))
- goto err;
- if(param_to_asn1(&ctx, scheme->parameter) < 0) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ERROR_SETTING_CIPHER_PARAMS);
- EVP_CIPHER_CTX_cleanup(&ctx);
- goto err;
- }
- /* If prf NID unspecified see if cipher has a preference.
- * An error is OK here: just means use default PRF.
- */
- if ((prf_nid == -1) &&
- EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_PBE_PRF_NID, 0, &prf_nid) <= 0)
- {
- ERR_clear_error();
- prf_nid = NID_hmacWithSHA1;
- }
- EVP_CIPHER_CTX_cleanup(&ctx);
-
- /* If its RC2 then we'd better setup the key length */
-
- if(alg_nid == NID_rc2_cbc)
- keylen = EVP_CIPHER_key_length(cipher);
- else
- keylen = -1;
-
- /* Setup keyfunc */
-
- X509_ALGOR_free(pbe2->keyfunc);
-
- pbe2->keyfunc = PKCS5_pbkdf2_set(iter, salt, saltlen, prf_nid, keylen);
-
- if (!pbe2->keyfunc)
- goto merr;
-
- /* Now set up top level AlgorithmIdentifier */
-
- if(!(ret = X509_ALGOR_new())) goto merr;
- if(!(ret->parameter = ASN1_TYPE_new())) goto merr;
-
- ret->algorithm = (ASN1_OBJECT*) OBJ_nid2obj(NID_pbes2);
-
- /* Encode PBE2PARAM into parameter */
-
- if(!ASN1_item_pack(pbe2, ASN1_ITEM_rptr(PBE2PARAM),
- &ret->parameter->value.sequence)) goto merr;
- ret->parameter->type = V_ASN1_SEQUENCE;
-
- PBE2PARAM_free(pbe2);
- pbe2 = NULL;
-
- return ret;
-
- merr:
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
-
- err:
- PBE2PARAM_free(pbe2);
- /* Note 'scheme' is freed as part of pbe2 */
- X509_ALGOR_free(kalg);
- X509_ALGOR_free(ret);
-
- return NULL;
-
-}
-
-X509_ALGOR *PKCS5_pbe2_set(const EVP_CIPHER *cipher, int iter,
- unsigned char *salt, int saltlen)
- {
- return PKCS5_pbe2_set_iv(cipher, iter, salt, saltlen, NULL, -1);
- }
-
-X509_ALGOR *PKCS5_pbkdf2_set(int iter, unsigned char *salt, int saltlen,
- int prf_nid, int keylen)
- {
- X509_ALGOR *keyfunc = NULL;
- PBKDF2PARAM *kdf = NULL;
- ASN1_OCTET_STRING *osalt = NULL;
-
- if(!(kdf = PBKDF2PARAM_new()))
- goto merr;
- if(!(osalt = M_ASN1_OCTET_STRING_new()))
- goto merr;
-
- kdf->salt->value.octet_string = osalt;
- kdf->salt->type = V_ASN1_OCTET_STRING;
-
- if (!saltlen)
- saltlen = PKCS5_SALT_LEN;
- if (!(osalt->data = OPENSSL_malloc (saltlen)))
- goto merr;
-
- osalt->length = saltlen;
-
- if (salt)
- OPENSSL_memcpy (osalt->data, salt, saltlen);
- else if (!RAND_bytes(osalt->data, saltlen))
- goto merr;
-
- if(iter <= 0)
- iter = PKCS5_DEFAULT_ITERATIONS;
-
- if(!ASN1_INTEGER_set(kdf->iter, iter))
- goto merr;
-
- /* If have a key len set it up */
-
- if(keylen > 0)
- {
- if(!(kdf->keylength = M_ASN1_INTEGER_new()))
- goto merr;
- if(!ASN1_INTEGER_set (kdf->keylength, keylen))
- goto merr;
- }
-
- /* prf can stay NULL if we are using hmacWithSHA1 */
- if (prf_nid > 0 && prf_nid != NID_hmacWithSHA1)
- {
- kdf->prf = X509_ALGOR_new();
- if (!kdf->prf)
- goto merr;
- X509_ALGOR_set0(kdf->prf, OBJ_nid2obj(prf_nid),
- V_ASN1_NULL, NULL);
- }
-
- /* Finally setup the keyfunc structure */
-
- keyfunc = X509_ALGOR_new();
- if (!keyfunc)
- goto merr;
-
- keyfunc->algorithm = (ASN1_OBJECT*) OBJ_nid2obj(NID_id_pbkdf2);
-
- /* Encode PBKDF2PARAM into parameter of pbe2 */
-
- if(!(keyfunc->parameter = ASN1_TYPE_new()))
- goto merr;
-
- if(!ASN1_item_pack(kdf, ASN1_ITEM_rptr(PBKDF2PARAM),
- &keyfunc->parameter->value.sequence))
- goto merr;
- keyfunc->parameter->type = V_ASN1_SEQUENCE;
-
- PBKDF2PARAM_free(kdf);
- return keyfunc;
-
- merr:
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
- PBKDF2PARAM_free(kdf);
- X509_ALGOR_free(keyfunc);
- 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;
+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;
}
- /* 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 ||
- (sizeof(long) > sizeof(unsigned) && iterations > (long)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 ((size_t) 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 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_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;
+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 0;
}
- 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) {
+ /* Generate a random IV. */
+ uint8_t iv[EVP_MAX_IV_LENGTH];
+ if (!RAND_bytes(iv, EVP_CIPHER_iv_length(cipher))) {
+ return 0;
+ }
+
+ /* See RFC 2898, appendix A. */
+ CBB algorithm, param, kdf, kdf_param, salt_cbb, cipher_cbb, iv_cbb;
+ if (!CBB_add_asn1(out, &algorithm, CBS_ASN1_SEQUENCE) ||
+ !OBJ_nid2cbb(&algorithm, NID_pbes2) ||
+ !CBB_add_asn1(&algorithm, ¶m, CBS_ASN1_SEQUENCE) ||
+ !CBB_add_asn1(¶m, &kdf, CBS_ASN1_SEQUENCE) ||
+ !OBJ_nid2cbb(&kdf, NID_id_pbkdf2) ||
+ !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, iterations) ||
+ /* Specify a key length for RC2. */
+ (cipher_nid == NID_rc2_cbc &&
+ !CBB_add_asn1_uint64(&kdf_param, EVP_CIPHER_key_length(cipher))) ||
+ /* Omit the PRF. We use the default hmacWithSHA1. */
+ !CBB_add_asn1(¶m, &cipher_cbb, CBS_ASN1_SEQUENCE) ||
+ !OBJ_nid2cbb(&cipher_cbb, cipher_nid) ||
+ /* RFC 2898 says RC2-CBC and RC5-CBC-Pad use a SEQUENCE with version and
+ * 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_flush(out)) {
+ return 0;
+ }
+
+ 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_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 ||
+ !CBS_get_asn1(&kdf, &kdf_obj, CBS_ASN1_OBJECT) ||
+ !CBS_get_asn1(&enc_scheme, &enc_obj, CBS_ASN1_OBJECT)) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- goto err;
+ return 0;
}
/* Check that the key derivation function is PBKDF2. */
- if (OBJ_obj2nid(pbe2param->keyfunc->algorithm) != NID_id_pbkdf2) {
+ if (OBJ_cbs2nid(&kdf_obj) != NID_id_pbkdf2) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_KEY_DERIVATION_FUNCTION);
- goto err;
+ return 0;
}
/* See if we recognise the encryption algorithm. */
- const EVP_CIPHER *cipher =
- EVP_get_cipherbynid(OBJ_obj2nid(pbe2param->encryption->algorithm));
+ const EVP_CIPHER *cipher = EVP_get_cipherbynid(OBJ_cbs2nid(&enc_obj));
if (cipher == NULL) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_CIPHER);
- goto err;
+ return 0;
}
- /* Fixup cipher based on AlgorithmIdentifier. */
- if (!EVP_CipherInit_ex(ctx, cipher, NULL /* engine */, NULL /* key */,
- NULL /* iv */, enc)) {
- goto err;
+ /* Parse the KDF parameters. */
+ CBS pbkdf2_params, salt;
+ uint64_t iterations;
+ if (!CBS_get_asn1(&kdf, &pbkdf2_params, CBS_ASN1_SEQUENCE) ||
+ CBS_len(&kdf) != 0 ||
+ !CBS_get_asn1(&pbkdf2_params, &salt, CBS_ASN1_OCTETSTRING) ||
+ !CBS_get_asn1_uint64(&pbkdf2_params, &iterations)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+ return 0;
}
- rv = PKCS5_v2_PBKDF2_keyivgen(ctx, pass_raw, pass_raw_len,
- pbe2param->keyfunc->parameter,
- pbe2param->encryption->parameter, enc);
+ if (iterations == 0 || iterations > UINT_MAX) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_ITERATION_COUNT);
+ return 0;
+ }
- err:
- PBE2PARAM_free(pbe2param);
- return rv;
+ /* The optional keyLength parameter, if present, must match the key length of
+ * the cipher. */
+ if (CBS_peek_asn1_tag(&pbkdf2_params, CBS_ASN1_INTEGER)) {
+ uint64_t key_len;
+ if (!CBS_get_asn1_uint64(&pbkdf2_params, &key_len)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+ return 0;
+ }
+
+ if (key_len != EVP_CIPHER_key_length(cipher)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_KEYLENGTH);
+ return 0;
+ }
+ }
+
+ if (CBS_len(&pbkdf2_params) != 0) {
+ CBS prf;
+ if (!CBS_get_asn1(&pbkdf2_params, &prf, CBS_ASN1_OBJECT) ||
+ CBS_len(&pbkdf2_params) != 0) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+ return 0;
+ }
+
+ /* We only support hmacWithSHA1. It is the DEFAULT, so DER requires it be
+ * omitted, but we match OpenSSL in tolerating it being present. */
+ if (OBJ_cbs2nid(&prf) != NID_hmacWithSHA1) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRF);
+ return 0;
+ }
+ }
+
+ /* Parse the encryption scheme parameters. Note OpenSSL does not match the
+ * specification. Per RFC 2898, this should depend on the encryption scheme.
+ * In particular, RC2-CBC and RC5-CBC-Pad use a SEQUENCE with version and IV.
+ * We align with OpenSSL. */
+ CBS iv;
+ if (!CBS_get_asn1(&enc_scheme, &iv, CBS_ASN1_OCTETSTRING) ||
+ CBS_len(&enc_scheme) != 0) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRF);
+ return 0;
+ }
+
+ 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/src/crypto/pkcs8/pkcs8.c b/src/crypto/pkcs8/pkcs8.c
index e965bc9..efad81d 100644
--- a/src/crypto/pkcs8/pkcs8.c
+++ b/src/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"
@@ -81,23 +82,21 @@
static int ascii_to_ucs2(const char *ascii, size_t ascii_len,
uint8_t **out, size_t *out_len) {
- uint8_t *unitmp;
- size_t ulen, i;
-
- ulen = ascii_len * 2 + 2;
- if (ulen < ascii_len) {
+ size_t ulen = ascii_len * 2 + 2;
+ if (ascii_len * 2 < ascii_len || ulen < ascii_len * 2) {
return 0;
}
- unitmp = OPENSSL_malloc(ulen);
+
+ uint8_t *unitmp = OPENSSL_malloc(ulen);
if (unitmp == NULL) {
return 0;
}
- for (i = 0; i < ulen - 2; i += 2) {
+ for (size_t i = 0; i < ulen - 2; i += 2) {
unitmp[i] = 0;
unitmp[i + 1] = ascii[i >> 1];
}
- /* Make result double null terminated */
+ /* Terminate the result with a UCS-2 NUL. */
unitmp[ulen - 2] = 0;
unitmp[ulen - 1] = 0;
*out_len = ulen;
@@ -107,7 +106,7 @@
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 +176,7 @@
!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,86 +222,75 @@
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) {
- PBEPARAM *pbe;
- int salt_len, iterations, ret;
- uint8_t *salt;
- const uint8_t *pbuf;
- uint8_t key[EVP_MAX_KEY_LENGTH], iv[EVP_MAX_IV_LENGTH];
+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();
- /* 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;
- }
-
- pbuf = param->value.sequence->data;
- pbe = d2i_PBEPARAM(NULL, &pbuf, param->value.sequence->length);
- if (pbe == NULL) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
- return 0;
- }
-
- if (!pbe->iter) {
- iterations = 1;
- } else {
- iterations = ASN1_INTEGER_get(pbe->iter);
- }
- salt = pbe->salt->data;
- salt_len = pbe->salt->length;
- if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, salt_len, PKCS12_KEY_ID,
- iterations, EVP_CIPHER_key_length(cipher), key, md)) {
+ uint8_t key[EVP_MAX_KEY_LENGTH];
+ 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);
- PBEPARAM_free(pbe);
return 0;
}
- if (!pkcs12_key_gen_raw(pass_raw, pass_raw_len, salt, salt_len, PKCS12_IV_ID,
- iterations, EVP_CIPHER_iv_length(cipher), iv, md)) {
+
+ uint8_t iv[EVP_MAX_IV_LENGTH];
+ 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);
- PBEPARAM_free(pbe);
return 0;
}
- PBEPARAM_free(pbe);
- ret = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, is_encrypt);
+
+ int ret = EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, is_encrypt);
OPENSSL_cleanse(key, EVP_MAX_KEY_LENGTH);
OPENSSL_cleanse(iv, EVP_MAX_IV_LENGTH);
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);
+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;
+ }
-struct pbe_suite {
- int pbe_nid;
- const EVP_CIPHER* (*cipher_func)(void);
- const EVP_MD* (*md_func)(void);
- keygen_func keygen;
- int flags;
-};
+ 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 +347,85 @@
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, ¶m, CBS_ASN1_SEQUENCE) ||
+ !CBB_add_asn1(¶m, &salt_cbb, CBS_ASN1_OCTETSTRING) ||
+ !CBB_add_bytes(&salt_cbb, salt, salt_len) ||
+ !CBB_add_asn1_uint64(¶m, 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;
- }
- block_size = EVP_CIPHER_CTX_block_size(&ctx);
-
- if (in_len + block_size < in_len) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_TOO_LONG);
+ CBS obj;
+ if (!CBS_get_asn1(algorithm, &obj, CBS_ASN1_OBJECT)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
goto err;
}
- buf = OPENSSL_malloc(in_len + block_size);
+ 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);
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,44 +446,57 @@
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;
+ /* Convert the legacy ASN.1 object to a byte string. */
+ int in_len = i2d_X509_SIG(pkcs8, &in);
+ if (in_len < 0) {
+ goto err;
+ }
- oct = M_ASN1_OCTET_STRING_new();
- if (oct == NULL) {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
- 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;
}
- in_len = ASN1_item_i2d(obj, &in, it);
- if (!in) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCODE_ERROR);
- return NULL;
+
+ if (!pbe_decrypt(&out, &out_len, &algorithm, pass_raw, pass_raw_len,
+ CBS_data(&ciphertext), CBS_len(&ciphertext))) {
+ 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 (out_len > LONG_MAX) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+ goto err;
}
- oct->length = crypt_len;
- OPENSSL_cleanse(in, in_len);
+
+ /* 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;
+ }
+
+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,
- int pass_len, uint8_t *salt, size_t salt_len,
+ int pass_len, const uint8_t *salt, size_t salt_len,
int iterations, PKCS8_PRIV_KEY_INFO *p8inf) {
uint8_t *pass_raw = NULL;
size_t pass_raw_len = 0;
@@ -560,42 +516,97 @@
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,
+ 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 (!pbe) {
- OPENSSL_PUT_ERROR(PKCS8, ERR_R_ASN1_LIB);
+ if (!alg_ok) {
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);
+ 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;
}
- return pkcs8;
+ 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;
+ }
+
+ /* 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) {
@@ -655,32 +666,21 @@
size_t password_len;
};
-static int PKCS12_handle_content_info(CBS *content_info, unsigned depth,
- struct pkcs12_context *ctx);
-
-/* PKCS12_handle_content_infos parses a series of PKCS#7 ContentInfos in a
- * SEQUENCE. */
-static int PKCS12_handle_content_infos(CBS *content_infos,
- unsigned depth,
- struct pkcs12_context *ctx) {
+/* PKCS12_handle_sequence parses a BER-encoded SEQUENCE of elements in a PKCS#12
+ * structure. */
+static int PKCS12_handle_sequence(
+ CBS *sequence, struct pkcs12_context *ctx,
+ int (*handle_element)(CBS *cbs, struct pkcs12_context *ctx)) {
uint8_t *der_bytes = NULL;
size_t der_len;
CBS in;
int ret = 0;
- /* Generally we only expect depths 0 (the top level, with a
- * pkcs7-encryptedData and a pkcs7-data) and depth 1 (the various PKCS#12
- * bags). */
- if (depth > 3) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PKCS12_TOO_DEEPLY_NESTED);
- return 0;
- }
-
/* Although a BER->DER conversion is done at the beginning of |PKCS12_parse|,
* the ASN.1 data gets wrapped in OCTETSTRINGs and/or encrypted and the
* conversion cannot see through those wrappings. So each time we step
* through one we need to convert to DER again. */
- if (!CBS_asn1_ber_to_der(content_infos, &der_bytes, &der_len)) {
+ if (!CBS_asn1_ber_to_der(sequence, &der_bytes, &der_len)) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
return 0;
}
@@ -688,30 +688,28 @@
if (der_bytes != NULL) {
CBS_init(&in, der_bytes, der_len);
} else {
- CBS_init(&in, CBS_data(content_infos), CBS_len(content_infos));
+ CBS_init(&in, CBS_data(sequence), CBS_len(sequence));
}
- if (!CBS_get_asn1(&in, &in, CBS_ASN1_SEQUENCE)) {
+ CBS child;
+ if (!CBS_get_asn1(&in, &child, CBS_ASN1_SEQUENCE) ||
+ CBS_len(&in) != 0) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
goto err;
}
- while (CBS_len(&in) > 0) {
- CBS content_info;
- if (!CBS_get_asn1(&in, &content_info, CBS_ASN1_SEQUENCE)) {
+ while (CBS_len(&child) > 0) {
+ CBS element;
+ if (!CBS_get_asn1(&child, &element, CBS_ASN1_SEQUENCE)) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
goto err;
}
- if (!PKCS12_handle_content_info(&content_info, depth + 1, ctx)) {
+ if (!handle_element(&element, ctx)) {
goto err;
}
}
- /* NSS includes additional data after the SEQUENCE, but it's an (unwrapped)
- * copy of the same encrypted private key (with the same IV and
- * ciphertext)! */
-
ret = 1;
err:
@@ -719,17 +717,116 @@
return ret;
}
+/* PKCS12_handle_safe_bag parses a single SafeBag element in a PKCS#12
+ * structure. */
+static int PKCS12_handle_safe_bag(CBS *safe_bag, struct pkcs12_context *ctx) {
+ CBS bag_id, wrapped_value;
+ if (!CBS_get_asn1(safe_bag, &bag_id, CBS_ASN1_OBJECT) ||
+ !CBS_get_asn1(safe_bag, &wrapped_value,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)
+ /* Ignore the bagAttributes field. */) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ return 0;
+ }
+
+ int nid = OBJ_cbs2nid(&bag_id);
+ if (nid == NID_pkcs8ShroudedKeyBag) {
+ /* See RFC 7292, section 4.2.2. */
+ if (*ctx->out_key) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12);
+ return 0;
+ }
+
+ if (CBS_len(&wrapped_value) > LONG_MAX) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ return 0;
+ }
+
+ /* |encrypted| isn't actually an X.509 signature, but it has the same
+ * structure as one and so |X509_SIG| is reused to store it. */
+ const uint8_t *inp = CBS_data(&wrapped_value);
+ X509_SIG *encrypted =
+ d2i_X509_SIG(NULL, &inp, (long)CBS_len(&wrapped_value));
+ if (encrypted == NULL) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ return 0;
+ }
+ if (inp != CBS_data(&wrapped_value) + CBS_len(&wrapped_value)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ X509_SIG_free(encrypted);
+ return 0;
+ }
+
+ PKCS8_PRIV_KEY_INFO *pki =
+ PKCS8_decrypt_pbe(encrypted, ctx->password, ctx->password_len);
+ X509_SIG_free(encrypted);
+ if (pki == NULL) {
+ return 0;
+ }
+
+ *ctx->out_key = EVP_PKCS82PKEY(pki);
+ PKCS8_PRIV_KEY_INFO_free(pki);
+ return ctx->out_key != NULL;
+ }
+
+ if (nid == NID_certBag) {
+ /* See RFC 7292, section 4.2.3. */
+ CBS cert_bag, cert_type, wrapped_cert, cert;
+ if (!CBS_get_asn1(&wrapped_value, &cert_bag, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1(&cert_bag, &cert_type, CBS_ASN1_OBJECT) ||
+ !CBS_get_asn1(&cert_bag, &wrapped_cert,
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
+ !CBS_get_asn1(&wrapped_cert, &cert, CBS_ASN1_OCTETSTRING)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ return 0;
+ }
+
+ if (OBJ_cbs2nid(&cert_type) != NID_x509Certificate) {
+ return 1;
+ }
+
+ if (CBS_len(&cert) > LONG_MAX) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ return 0;
+ }
+
+ const uint8_t *inp = CBS_data(&cert);
+ X509 *x509 = d2i_X509(NULL, &inp, (long)CBS_len(&cert));
+ if (!x509) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ return 0;
+ }
+
+ if (inp != CBS_data(&cert) + CBS_len(&cert)) {
+ OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ X509_free(x509);
+ return 0;
+ }
+
+ if (0 == sk_X509_push(ctx->out_certs, x509)) {
+ X509_free(x509);
+ return 0;
+ }
+
+ return 1;
+ }
+
+ /* Unknown element type - ignore it. */
+ return 1;
+}
+
/* PKCS12_handle_content_info parses a single PKCS#7 ContentInfo element in a
* PKCS#12 structure. */
-static int PKCS12_handle_content_info(CBS *content_info, unsigned depth,
+static int PKCS12_handle_content_info(CBS *content_info,
struct pkcs12_context *ctx) {
- CBS content_type, wrapped_contents, contents, content_infos;
+ CBS content_type, wrapped_contents, contents;
int nid, ret = 0;
uint8_t *storage = NULL;
if (!CBS_get_asn1(content_info, &content_type, CBS_ASN1_OBJECT) ||
!CBS_get_asn1(content_info, &wrapped_contents,
- CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0)) {
+ CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
+ CBS_len(content_info) != 0) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
goto err;
}
@@ -742,8 +839,6 @@
* 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 +850,7 @@
!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,122 +858,32 @@
goto err;
}
- if (OBJ_cbs2nid(&contents_type) != NID_pkcs7_data ||
- CBS_len(&ai) > LONG_MAX) {
+ if (OBJ_cbs2nid(&contents_type) != NID_pkcs7_data) {
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);
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
+ if (!pbe_decrypt(&out, &out_len, &ai, ctx->password, ctx->password_len,
+ CBS_data(&encrypted_contents),
+ CBS_len(&encrypted_contents))) {
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);
- goto err;
- }
- X509_ALGOR_free(algor);
-
- CBS_init(&content_infos, out, out_len);
- ret = PKCS12_handle_content_infos(&content_infos, depth + 1, ctx);
+ CBS safe_contents;
+ CBS_init(&safe_contents, out, out_len);
+ ret = PKCS12_handle_sequence(&safe_contents, ctx, PKCS12_handle_safe_bag);
OPENSSL_free(out);
} else if (nid == NID_pkcs7_data) {
CBS octet_string_contents;
if (!CBS_get_asn1(&wrapped_contents, &octet_string_contents,
- CBS_ASN1_OCTETSTRING)) {
+ CBS_ASN1_OCTETSTRING)) {
OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
goto err;
}
- ret = PKCS12_handle_content_infos(&octet_string_contents, depth + 1, ctx);
- } else if (nid == NID_pkcs8ShroudedKeyBag) {
- /* See ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf, section
- * 4.2.2. */
- const uint8_t *inp = CBS_data(&wrapped_contents);
- PKCS8_PRIV_KEY_INFO *pki = NULL;
- X509_SIG *encrypted = NULL;
-
- if (*ctx->out_key) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_MULTIPLE_PRIVATE_KEYS_IN_PKCS12);
- goto err;
- }
-
- if (CBS_len(&wrapped_contents) > LONG_MAX) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- /* encrypted isn't actually an X.509 signature, but it has the same
- * structure as one and so |X509_SIG| is reused to store it. */
- encrypted = d2i_X509_SIG(NULL, &inp, (long)CBS_len(&wrapped_contents));
- if (encrypted == NULL) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
- if (inp != CBS_data(&wrapped_contents) + CBS_len(&wrapped_contents)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- X509_SIG_free(encrypted);
- goto err;
- }
-
- pki = PKCS8_decrypt_pbe(encrypted, ctx->password, ctx->password_len);
- X509_SIG_free(encrypted);
- if (pki == NULL) {
- goto err;
- }
-
- *ctx->out_key = EVP_PKCS82PKEY(pki);
- PKCS8_PRIV_KEY_INFO_free(pki);
-
- if (ctx->out_key == NULL) {
- goto err;
- }
- ret = 1;
- } else if (nid == NID_certBag) {
- CBS cert_bag, cert_type, wrapped_cert, cert;
-
- if (!CBS_get_asn1(&wrapped_contents, &cert_bag, CBS_ASN1_SEQUENCE) ||
- !CBS_get_asn1(&cert_bag, &cert_type, CBS_ASN1_OBJECT) ||
- !CBS_get_asn1(&cert_bag, &wrapped_cert,
- CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | 0) ||
- !CBS_get_asn1(&wrapped_cert, &cert, CBS_ASN1_OCTETSTRING)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
-
- if (OBJ_cbs2nid(&cert_type) == NID_x509Certificate) {
- if (CBS_len(&cert) > LONG_MAX) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
- const uint8_t *inp = CBS_data(&cert);
- X509 *x509 = d2i_X509(NULL, &inp, (long)CBS_len(&cert));
- if (!x509) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- goto err;
- }
- if (inp != CBS_data(&cert) + CBS_len(&cert)) {
- OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_BAD_PKCS12_DATA);
- X509_free(x509);
- goto err;
- }
-
- if (0 == sk_X509_push(ctx->out_certs, x509)) {
- X509_free(x509);
- goto err;
- }
- }
- ret = 1;
+ ret = PKCS12_handle_sequence(&octet_string_contents, ctx,
+ PKCS12_handle_safe_bag);
} else {
/* Unknown element type - ignore it. */
ret = 1;
@@ -995,7 +1000,7 @@
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;
}
@@ -1026,7 +1031,7 @@
}
/* authsafes contains a series of PKCS#7 ContentInfos. */
- if (!PKCS12_handle_content_infos(&authsafes, 0, &ctx)) {
+ if (!PKCS12_handle_sequence(&authsafes, &ctx, PKCS12_handle_content_info)) {
goto err;
}
@@ -1054,7 +1059,8 @@
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));
diff --git a/src/crypto/pkcs8/pkcs8_test.cc b/src/crypto/pkcs8/pkcs8_test.cc
index cbb2043..1196f9f 100644
--- a/src/crypto/pkcs8/pkcs8_test.cc
+++ b/src/crypto/pkcs8/pkcs8_test.cc
@@ -21,6 +21,8 @@
#include <openssl/pkcs8.h>
#include <openssl/x509.h>
+#include "../internal.h"
+
/* kDER is a PKCS#8 encrypted private key. It was generated with:
*
@@ -60,7 +62,89 @@
0xd6, 0x2d,
};
-static bool test(const uint8_t *der, size_t der_len) {
+/* kNullPassword is a PKCS#8 encrypted private key using the null password. */
+static const uint8_t kNullPassword[] = {
+ 0x30, 0x81, 0xb0, 0x30, 0x1b, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0d, 0x04, 0x08, 0xb2, 0xfe, 0x68,
+ 0xc2, 0xea, 0x0f, 0x10, 0x9c, 0x02, 0x01, 0x01, 0x04, 0x81, 0x90, 0xe2,
+ 0xf6, 0x1c, 0xca, 0xad, 0x64, 0x30, 0xbf, 0x88, 0x04, 0x35, 0xe5, 0x0f,
+ 0x11, 0x49, 0x06, 0x01, 0x14, 0x33, 0x80, 0xa2, 0x78, 0x44, 0x5b, 0xaa,
+ 0x0d, 0xd7, 0x00, 0x36, 0x9d, 0x91, 0x97, 0x37, 0x20, 0x7b, 0x27, 0xc1,
+ 0xa0, 0xa2, 0x73, 0x06, 0x15, 0xdf, 0xc8, 0x13, 0x9b, 0xc9, 0x8c, 0x9c,
+ 0xce, 0x00, 0xd0, 0xc8, 0x42, 0xc1, 0xda, 0x2b, 0x07, 0x2b, 0x12, 0xa3,
+ 0xce, 0x10, 0x39, 0x7a, 0xf1, 0x55, 0x69, 0x8d, 0xa5, 0xc4, 0x2a, 0x00,
+ 0x0d, 0x94, 0xc6, 0xde, 0x6a, 0x3d, 0xb7, 0xe5, 0x6d, 0x59, 0x3e, 0x09,
+ 0xb5, 0xe3, 0x3e, 0xfc, 0x50, 0x56, 0xe9, 0x50, 0x42, 0x7c, 0xe7, 0xf0,
+ 0x19, 0xbd, 0x31, 0xa7, 0x85, 0x47, 0xb3, 0xe9, 0xb3, 0x50, 0x3c, 0xc9,
+ 0x32, 0x37, 0x1a, 0x93, 0x78, 0x48, 0x78, 0x82, 0xde, 0xad, 0x5c, 0xf2,
+ 0xcf, 0xf2, 0xbb, 0x2c, 0x44, 0x05, 0x7f, 0x4a, 0xf9, 0xb1, 0x2b, 0xdd,
+ 0x49, 0xf6, 0x7e, 0xd0, 0x42, 0xaa, 0x14, 0x3c, 0x24, 0x77, 0xb4,
+};
+
+/* kNullPasswordNSS is a PKCS#8 encrypted private key using the null password
+ * and generated by NSS. */
+static const uint8_t kNullPasswordNSS[] = {
+ 0x30, 0x81, 0xb8, 0x30, 0x23, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86, 0xf7,
+ 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x15, 0x04, 0x10, 0x3f, 0xac, 0xe9,
+ 0x38, 0xdb, 0x40, 0x6b, 0x26, 0x89, 0x09, 0x73, 0x18, 0x8d, 0x7f, 0x1c,
+ 0x82, 0x02, 0x01, 0x01, 0x04, 0x81, 0x90, 0x5e, 0x5e, 0x11, 0xef, 0xbb,
+ 0x7c, 0x4d, 0xec, 0xc0, 0xdc, 0xc7, 0x23, 0xd2, 0xc4, 0x77, 0xbc, 0xf4,
+ 0x5d, 0x59, 0x4c, 0x07, 0xc2, 0x8a, 0x26, 0xfa, 0x25, 0x1c, 0xaa, 0x42,
+ 0xed, 0xd0, 0xed, 0xbb, 0x5c, 0xe9, 0x13, 0x07, 0xaa, 0xdd, 0x52, 0x3c,
+ 0x65, 0x25, 0xbf, 0x94, 0x02, 0xaf, 0xd6, 0x97, 0xe9, 0x33, 0x00, 0x76,
+ 0x64, 0x4a, 0x73, 0xab, 0xfb, 0x99, 0x6e, 0x83, 0x12, 0x05, 0x86, 0x72,
+ 0x6c, 0xd5, 0xa4, 0xcf, 0xb1, 0xd5, 0x4d, 0x54, 0x87, 0x8b, 0x4b, 0x95,
+ 0x1d, 0xcd, 0xf3, 0xfe, 0xa8, 0xda, 0xe0, 0xb6, 0x72, 0x13, 0x3f, 0x2e,
+ 0x66, 0xe0, 0xb9, 0x2e, 0xfa, 0x69, 0x40, 0xbe, 0xd7, 0x67, 0x6e, 0x53,
+ 0x2b, 0x3f, 0x53, 0xe5, 0x39, 0x54, 0x77, 0xe1, 0x1d, 0xe6, 0x81, 0x92,
+ 0x58, 0x82, 0x14, 0xfb, 0x47, 0x85, 0x3c, 0xc3, 0xdf, 0xdd, 0xcc, 0x79,
+ 0x9f, 0x41, 0x83, 0x72, 0xf2, 0x0a, 0xe9, 0xe1, 0x2c, 0x12, 0xb0, 0xb0,
+ 0x0a, 0xb2, 0x1d, 0xca, 0x15, 0xb2, 0xca,
+};
+
+/* kEmptyPasswordOpenSSL is a PKCS#8 encrypted private key using the empty
+ * password and generated by OpenSSL. */
+static const uint8_t kEmptyPasswordOpenSSL[] = {
+ 0x30, 0x82, 0x01, 0xa1, 0x30, 0x1b, 0x06, 0x0a, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x0c, 0x01, 0x03, 0x30, 0x0d, 0x04, 0x08, 0x86, 0xaa,
+ 0xd7, 0xdf, 0x3b, 0x91, 0x97, 0x60, 0x02, 0x01, 0x01, 0x04, 0x82, 0x01,
+ 0x80, 0xcb, 0x2a, 0x14, 0xaa, 0x4f, 0x38, 0x4c, 0xe1, 0x49, 0x00, 0xe2,
+ 0x1a, 0x3a, 0x75, 0x87, 0x7e, 0x3d, 0xea, 0x4d, 0x53, 0xd4, 0x46, 0x47,
+ 0x23, 0x8f, 0xa1, 0x72, 0x51, 0x92, 0x86, 0x8b, 0xeb, 0x53, 0xe6, 0x6a,
+ 0x0a, 0x6b, 0xb6, 0xa0, 0xdc, 0x0f, 0xdc, 0x20, 0xc3, 0x45, 0x85, 0xf1,
+ 0x95, 0x90, 0x5c, 0xf4, 0xfa, 0xee, 0x47, 0xaf, 0x35, 0xd0, 0xd0, 0xd3,
+ 0x14, 0xde, 0x0d, 0xca, 0x1b, 0xd3, 0xbb, 0x20, 0xec, 0x9d, 0x6a, 0xd4,
+ 0xc1, 0xce, 0x60, 0x81, 0xab, 0x0c, 0x72, 0x10, 0xfa, 0x28, 0x3c, 0xac,
+ 0x87, 0x7b, 0x82, 0x85, 0x00, 0xb8, 0x58, 0x9c, 0x07, 0xc4, 0x7d, 0xa9,
+ 0xc5, 0x94, 0x95, 0xf7, 0x23, 0x93, 0x3f, 0xed, 0xef, 0x92, 0x55, 0x25,
+ 0x74, 0xbb, 0xd3, 0xd1, 0x67, 0x3b, 0x3d, 0x5a, 0xfe, 0x84, 0xf8, 0x97,
+ 0x7d, 0x7c, 0x01, 0xc7, 0xd7, 0x0d, 0xf8, 0xc3, 0x6d, 0xd6, 0xf1, 0xaa,
+ 0x9d, 0x1f, 0x69, 0x97, 0x45, 0x06, 0xc4, 0x1c, 0x95, 0x3c, 0xe0, 0xef,
+ 0x11, 0xb2, 0xb3, 0x72, 0x91, 0x9e, 0x7d, 0x0f, 0x7f, 0xc8, 0xf6, 0x64,
+ 0x49, 0x5e, 0x3c, 0x53, 0x37, 0x79, 0x03, 0x1c, 0x3f, 0x29, 0x6c, 0x6b,
+ 0xea, 0x4c, 0x35, 0x9b, 0x6d, 0x1b, 0x59, 0x43, 0x4c, 0x14, 0x47, 0x2a,
+ 0x36, 0x39, 0x2a, 0xd8, 0x96, 0x90, 0xdc, 0xfc, 0xd2, 0xdd, 0x23, 0x0e,
+ 0x2c, 0xb3, 0x83, 0xf9, 0xf2, 0xe3, 0xe6, 0x99, 0x53, 0x57, 0x33, 0xc5,
+ 0x5f, 0xf9, 0xfd, 0x56, 0x0b, 0x32, 0xd4, 0xf3, 0x9d, 0x5b, 0x34, 0xe5,
+ 0x94, 0xbf, 0xb6, 0xc0, 0xce, 0xe1, 0x73, 0x5c, 0x02, 0x7a, 0x4c, 0xed,
+ 0xde, 0x23, 0x38, 0x89, 0x9f, 0xcd, 0x51, 0xf3, 0x90, 0x80, 0xd3, 0x4b,
+ 0x83, 0xd3, 0xee, 0xf2, 0x9e, 0x35, 0x91, 0xa5, 0xa3, 0xc0, 0x5c, 0xce,
+ 0xdb, 0xaa, 0x70, 0x1e, 0x1d, 0xc1, 0x44, 0xea, 0x3b, 0xa7, 0x5a, 0x11,
+ 0xd1, 0xf3, 0xf3, 0xd0, 0xf4, 0x5a, 0xc4, 0x99, 0xaf, 0x8d, 0xe2, 0xbc,
+ 0xa2, 0xb9, 0x3d, 0x86, 0x5e, 0xba, 0xa0, 0xdf, 0x78, 0x81, 0x7c, 0x54,
+ 0x31, 0xe3, 0x98, 0xb5, 0x46, 0xcb, 0x4d, 0x26, 0x4b, 0xf8, 0xac, 0x3a,
+ 0x54, 0x1b, 0x77, 0x5a, 0x18, 0xa5, 0x43, 0x0e, 0x14, 0xde, 0x7b, 0xb7,
+ 0x4e, 0x45, 0x99, 0x03, 0xd1, 0x3d, 0x18, 0xb2, 0x36, 0x00, 0x48, 0x07,
+ 0x72, 0xbb, 0x4f, 0x21, 0x25, 0x3e, 0xda, 0x25, 0x24, 0x5b, 0xc8, 0xa0,
+ 0x28, 0xd5, 0x9b, 0x96, 0x87, 0x07, 0x77, 0x84, 0xff, 0xd7, 0xac, 0x71,
+ 0xf6, 0x61, 0x63, 0x0b, 0xfb, 0x42, 0xfd, 0x52, 0xf4, 0xc4, 0x35, 0x0c,
+ 0xc2, 0xc1, 0x55, 0x22, 0x42, 0x2f, 0x13, 0x7d, 0x93, 0x27, 0xc8, 0x11,
+ 0x35, 0xc5, 0xe3, 0xc5, 0xaa, 0x15, 0x3c, 0xac, 0x30, 0xbc, 0x45, 0x16,
+ 0xed,
+};
+
+static bool TestDecrypt(const uint8_t *der, size_t der_len,
+ const char *password) {
const uint8_t *data = der;
bssl::UniquePtr<X509_SIG> sig(d2i_X509_SIG(NULL, &data, der_len));
if (sig.get() == NULL || data != der + der_len) {
@@ -68,8 +152,8 @@
return false;
}
- static const char kPassword[] = "testing";
- bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> keypair(PKCS8_decrypt(sig.get(), kPassword, -1));
+ bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> keypair(
+ PKCS8_decrypt(sig.get(), password, -1));
if (!keypair) {
fprintf(stderr, "PKCS8_decrypt failed.\n");
ERR_print_errors_fp(stderr);
@@ -79,8 +163,92 @@
return true;
}
+static bool TestRoundTrip(int pbe_nid, const EVP_CIPHER *cipher,
+ const char *password, const uint8_t *salt,
+ size_t salt_len, int iterations) {
+ static const uint8_t kSampleKey[] = {
+ 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
+ 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d,
+ 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20,
+ 0x8a, 0x87, 0x2f, 0xb6, 0x28, 0x93, 0xc4, 0xd1, 0xff, 0xc5, 0xb9, 0xf0,
+ 0xf9, 0x17, 0x58, 0x06, 0x9f, 0x83, 0x52, 0xe0, 0x8f, 0xa0, 0x5a, 0x49,
+ 0xf8, 0xdb, 0x92, 0x6c, 0xb5, 0x72, 0x87, 0x25, 0xa1, 0x44, 0x03, 0x42,
+ 0x00, 0x04, 0x2c, 0x15, 0x0f, 0x42, 0x9c, 0xe7, 0x0f, 0x21, 0x6c, 0x25,
+ 0x2c, 0xf5, 0xe0, 0x62, 0xce, 0x1f, 0x63, 0x9c, 0xd5, 0xd1, 0x65, 0xc7,
+ 0xf8, 0x94, 0x24, 0x07, 0x2c, 0x27, 0x19, 0x7d, 0x78, 0xb3, 0x3b, 0x92,
+ 0x0e, 0x95, 0xcd, 0xb6, 0x64, 0xe9, 0x90, 0xdc, 0xf0, 0xcf, 0xea, 0x0d,
+ 0x94, 0xe2, 0xa8, 0xe6, 0xaf, 0x9d, 0x0e, 0x58, 0x05, 0x6e, 0x65, 0x31,
+ 0x04, 0x92, 0x5b, 0x9f, 0xe6, 0xc9,
+ };
+
+ const uint8_t *ptr = kSampleKey;
+ bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> key(
+ d2i_PKCS8_PRIV_KEY_INFO(nullptr, &ptr, sizeof(kSampleKey)));
+ if (!key || ptr != kSampleKey + sizeof(kSampleKey)) {
+ return false;
+ }
+
+ bssl::UniquePtr<X509_SIG> encrypted(PKCS8_encrypt(
+ pbe_nid, cipher, password, -1, salt, salt_len, iterations, key.get()));
+ if (!encrypted) {
+ fprintf(stderr, "Failed to encrypt private key.\n");
+ return false;
+ }
+
+ bssl::UniquePtr<PKCS8_PRIV_KEY_INFO> key2(
+ PKCS8_decrypt(encrypted.get(), password, -1));
+ if (!key2) {
+ fprintf(stderr, "Failed to decrypt private key.\n");
+ return false;
+ }
+
+ uint8_t *encoded = nullptr;
+ int len = i2d_PKCS8_PRIV_KEY_INFO(key2.get(), &encoded);
+ bssl::UniquePtr<uint8_t> free_encoded(encoded);
+ if (len < 0 ||
+ static_cast<size_t>(len) != sizeof(kSampleKey) ||
+ OPENSSL_memcmp(encoded, kSampleKey, sizeof(kSampleKey)) != 0) {
+ fprintf(stderr, "Decrypted private key did not round-trip.");
+ return false;
+ }
+
+ return true;
+}
+
int main(int argc, char **argv) {
- if (!test(kDER, sizeof(kDER))) {
+ CRYPTO_library_init();
+
+ if (!TestDecrypt(kDER, sizeof(kDER), "testing") ||
+ !TestDecrypt(kNullPassword, sizeof(kNullPassword), NULL) ||
+ !TestDecrypt(kNullPasswordNSS, sizeof(kNullPasswordNSS), NULL) ||
+ !TestDecrypt(kEmptyPasswordOpenSSL, sizeof(kEmptyPasswordOpenSSL), "") ||
+ !TestRoundTrip(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, nullptr,
+ "password", nullptr, 0, 10) ||
+ // Vary the salt
+ !TestRoundTrip(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, nullptr,
+ "password", nullptr, 4, 10) ||
+ !TestRoundTrip(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, nullptr,
+ "password", (const uint8_t *)"salt", 4, 10) ||
+ // Vary the iteration count.
+ !TestRoundTrip(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, nullptr,
+ "password", nullptr, 0, 1) ||
+ // Vary the password.
+ !TestRoundTrip(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, nullptr, "",
+ nullptr, 0, 1) ||
+ !TestRoundTrip(NID_pbe_WithSHA1And3_Key_TripleDES_CBC, nullptr, nullptr,
+ nullptr, 0, 1) ||
+ // Vary the PBE suite.
+ !TestRoundTrip(NID_pbe_WithSHA1And40BitRC2_CBC, nullptr, "password",
+ nullptr, 0, 10) ||
+ !TestRoundTrip(NID_pbe_WithSHA1And128BitRC4, nullptr, "password", nullptr,
+ 0, 10) ||
+ // Test PBES2.
+ !TestRoundTrip(-1, EVP_aes_128_cbc(), "password", nullptr, 0, 10) ||
+ !TestRoundTrip(-1, EVP_aes_128_cbc(), "password", nullptr, 4, 10) ||
+ !TestRoundTrip(-1, EVP_aes_128_cbc(), "password", (const uint8_t *)"salt",
+ 4, 10) ||
+ !TestRoundTrip(-1, EVP_aes_128_cbc(), "password", nullptr, 0, 1) ||
+ !TestRoundTrip(-1, EVP_rc2_cbc(), "password", nullptr, 0, 10)) {
return 1;
}
diff --git a/src/crypto/rand/CMakeLists.txt b/src/crypto/rand/CMakeLists.txt
index c66d2ee..f7c11f1 100644
--- a/src/crypto/rand/CMakeLists.txt
+++ b/src/crypto/rand/CMakeLists.txt
@@ -14,6 +14,7 @@
OBJECT
deterministic.c
+ fuchsia.c
rand.c
urandom.c
windows.c
diff --git a/src/crypto/rand/fuchsia.c b/src/crypto/rand/fuchsia.c
new file mode 100644
index 0000000..2e138d0
--- /dev/null
+++ b/src/crypto/rand/fuchsia.c
@@ -0,0 +1,43 @@
+/* Copyright (c) 2017, 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 <openssl/rand.h>
+
+#if defined(OPENSSL_FUCHSIA) && !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
+
+#include <limits.h>
+#include <stdlib.h>
+
+#include <magenta/syscalls.h>
+
+#include "internal.h"
+
+void CRYPTO_sysrand(uint8_t *out, size_t requested) {
+ while (requested > 0) {
+ size_t output_bytes_this_pass = MX_CPRNG_DRAW_MAX_LEN;
+ if (requested < output_bytes_this_pass) {
+ output_bytes_this_pass = requested;
+ }
+ size_t bytes_drawn;
+ mx_status_t status =
+ mx_cprng_draw(out, output_bytes_this_pass, &bytes_drawn);
+ if (status != NO_ERROR) {
+ abort();
+ }
+ requested -= bytes_drawn;
+ out += bytes_drawn;
+ }
+}
+
+#endif /* OPENSSL_FUCHSIA && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE */
diff --git a/src/crypto/rand/urandom.c b/src/crypto/rand/urandom.c
index 2233203..3ccd940 100644
--- a/src/crypto/rand/urandom.c
+++ b/src/crypto/rand/urandom.c
@@ -16,7 +16,8 @@
#include <openssl/rand.h>
-#if !defined(OPENSSL_WINDOWS) && !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
+#if !defined(OPENSSL_WINDOWS) && !defined(OPENSSL_FUCHSIA) && \
+ !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE)
#include <assert.h>
#include <errno.h>
@@ -328,4 +329,5 @@
}
}
-#endif /* !OPENSSL_WINDOWS && !BORINGSSL_UNSAFE_DETERMINISTIC_MODE */
+#endif /* !OPENSSL_WINDOWS && !defined(OPENSSL_FUCHSIA) && \
+ !BORINGSSL_UNSAFE_DETERMINISTIC_MODE */
diff --git a/src/crypto/rsa/rsa_impl.c b/src/crypto/rsa/rsa_impl.c
index 3834be5..8e0aa9c 100644
--- a/src/crypto/rsa/rsa_impl.c
+++ b/src/crypto/rsa/rsa_impl.c
@@ -769,8 +769,6 @@
int rsa_default_multi_prime_keygen(RSA *rsa, int bits, int num_primes,
BIGNUM *e_value, BN_GENCB *cb) {
BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *r3 = NULL, *tmp;
- BIGNUM local_r0, local_p;
- BIGNUM *pr0, *p;
int prime_bits, ok = -1, n = 0, i, j;
BN_CTX *ctx = NULL;
STACK_OF(RSA_additional_prime) *additional_primes = NULL;
@@ -999,9 +997,7 @@
goto err;
}
}
- pr0 = &local_r0;
- BN_with_flags(pr0, r0, BN_FLG_CONSTTIME);
- if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) {
+ if (!BN_mod_inverse(rsa->d, rsa->e, r0, ctx)) {
goto err; /* d */
}
@@ -1019,10 +1015,9 @@
* from constant-time, |bn_mod_inverse_secret_prime| uses the same modular
* exponentation logic as in RSA private key operations and, if the RSAZ-1024
* code is enabled, will be optimized for common RSA prime sizes. */
- p = &local_p;
- BN_with_flags(p, rsa->p, BN_FLG_CONSTTIME);
if (!BN_MONT_CTX_set_locked(&rsa->mont_p, &rsa->lock, rsa->p, ctx) ||
- !bn_mod_inverse_secret_prime(rsa->iqmp, rsa->q, p, ctx, rsa->mont_p)) {
+ !bn_mod_inverse_secret_prime(rsa->iqmp, rsa->q, rsa->p, ctx,
+ rsa->mont_p)) {
goto err;
}
diff --git a/src/crypto/x509/t_x509.c b/src/crypto/x509/t_x509.c
index d5d48ba..d4f6bba 100644
--- a/src/crypto/x509/t_x509.c
+++ b/src/crypto/x509/t_x509.c
@@ -54,6 +54,7 @@
* copied and put under another distribution licence
* [including the GNU Public Licence.] */
+#include <ctype.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/digest.h>
@@ -415,45 +416,84 @@
return (0);
}
-int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm)
-{
- const char *v;
- int gmt = 0;
- int i;
- int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0;
+// consume_two_digits is a helper function for ASN1_UTCTIME_print. If |*v|,
+// assumed to be |*len| bytes long, has two leading digits, updates |*out| with
+// their value, updates |v| and |len|, and returns one. Otherwise, returns
+// zero.
+static int consume_two_digits(int* out, const char **v, int *len) {
+ if (*len < 2|| !isdigit((*v)[0]) || !isdigit((*v)[1])) {
+ return 0;
+ }
+ *out = ((*v)[0] - '0') * 10 + ((*v)[1] - '0');
+ *len -= 2;
+ *v += 2;
+ return 1;
+}
- i = tm->length;
- v = (const char *)tm->data;
+// consume_zulu_timezone is a helper function for ASN1_UTCTIME_print. If |*v|,
+// assumed to be |*len| bytes long, starts with "Z" then it updates |*v| and
+// |*len| and returns one. Otherwise returns zero.
+static int consume_zulu_timezone(const char **v, int *len) {
+ if (*len == 0 || (*v)[0] != 'Z') {
+ return 0;
+ }
- if (i < 10)
- goto err;
- if (v[i - 1] == 'Z')
- gmt = 1;
- for (i = 0; i < 10; i++)
- if ((v[i] > '9') || (v[i] < '0'))
- goto err;
- y = (v[0] - '0') * 10 + (v[1] - '0');
- if (y < 50)
- y += 100;
- M = (v[2] - '0') * 10 + (v[3] - '0');
- if ((M > 12) || (M < 1))
- goto err;
- d = (v[4] - '0') * 10 + (v[5] - '0');
- h = (v[6] - '0') * 10 + (v[7] - '0');
- m = (v[8] - '0') * 10 + (v[9] - '0');
- if (tm->length >= 12 &&
- (v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9'))
- s = (v[10] - '0') * 10 + (v[11] - '0');
+ *len -= 1;
+ *v += 1;
+ return 1;
+}
- if (BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s",
- mon[M - 1], d, h, m, s, y + 1900,
- (gmt) ? " GMT" : "") <= 0)
- return (0);
- else
- return (1);
- err:
- BIO_write(bp, "Bad time value", 14);
- return (0);
+int ASN1_UTCTIME_print(BIO *bp, const ASN1_UTCTIME *tm) {
+ const char *v = (const char *)tm->data;
+ int len = tm->length;
+ int Y = 0, M = 0, D = 0, h = 0, m = 0, s = 0;
+
+ // YYMMDDhhmm are required to be present.
+ if (!consume_two_digits(&Y, &v, &len) ||
+ !consume_two_digits(&M, &v, &len) ||
+ !consume_two_digits(&D, &v, &len) ||
+ !consume_two_digits(&h, &v, &len) ||
+ !consume_two_digits(&m, &v, &len)) {
+ goto err;
+ }
+ // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, requires seconds
+ // to be present, but historically this code has forgiven its absence.
+ consume_two_digits(&s, &v, &len);
+
+ // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, specifies this
+ // interpretation of the year.
+ if (Y < 50) {
+ Y += 2000;
+ } else {
+ Y += 1900;
+ }
+ if (M > 12 || M == 0) {
+ goto err;
+ }
+ if (D > 31 || D == 0) {
+ goto err;
+ }
+ if (h > 23 || m > 59 || s > 60) {
+ goto err;
+ }
+
+ // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, requires the "Z"
+ // to be present, but historically this code has forgiven its absence.
+ const int is_gmt = consume_zulu_timezone(&v, &len);
+
+ // https://tools.ietf.org/html/rfc5280, section 4.1.2.5.1, does not permit
+ // the specification of timezones using the +hhmm / -hhmm syntax, which is
+ // the only other thing that might legitimately be found at the end.
+ if (len) {
+ goto err;
+ }
+
+ return BIO_printf(bp, "%s %2d %02d:%02d:%02d %d%s", mon[M - 1], D, h, m, s, Y,
+ is_gmt ? " GMT" : "") > 0;
+
+err:
+ BIO_write(bp, "Bad time value", 14);
+ return 0;
}
int X509_NAME_print(BIO *bp, X509_NAME *name, int obase)
diff --git a/src/crypto/x509/x509_test.cc b/src/crypto/x509/x509_test.cc
index 3629c13..4b80af8 100644
--- a/src/crypto/x509/x509_test.cc
+++ b/src/crypto/x509/x509_test.cc
@@ -17,6 +17,7 @@
#include <assert.h>
#include <string.h>
+#include <openssl/bio.h>
#include <openssl/bytestring.h>
#include <openssl/crypto.h>
#include <openssl/digest.h>
@@ -1011,6 +1012,73 @@
return true;
}
+static bool TestPrintUTCTIME() {
+ static const struct {
+ const char *val, *want;
+ } asn1_utctime_tests[] = {
+ {"", "Bad time value"},
+
+ // Correct RFC 5280 form. Test years < 2000 and > 2000.
+ {"090303125425Z", "Mar 3 12:54:25 2009 GMT"},
+ {"900303125425Z", "Mar 3 12:54:25 1990 GMT"},
+ {"000303125425Z", "Mar 3 12:54:25 2000 GMT"},
+
+ // Correct form, bad values.
+ {"000000000000Z", "Bad time value"},
+ {"999999999999Z", "Bad time value"},
+
+ // Missing components. Not legal RFC 5280, but permitted.
+ {"090303125425", "Mar 3 12:54:25 2009"},
+ {"9003031254", "Mar 3 12:54:00 1990"},
+ {"9003031254Z", "Mar 3 12:54:00 1990 GMT"},
+
+ // GENERALIZEDTIME confused for UTCTIME.
+ {"20090303125425Z", "Bad time value"},
+
+ // Legal ASN.1, but not legal RFC 5280.
+ {"9003031254+0800", "Bad time value"},
+ {"9003031254-0800", "Bad time value"},
+
+ // Trailing garbage.
+ {"9003031254Z ", "Bad time value"},
+ };
+
+ for (auto t : asn1_utctime_tests) {
+ bssl::UniquePtr<ASN1_UTCTIME> tm(ASN1_UTCTIME_new());
+ bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+
+ // Use this instead of ASN1_UTCTIME_set() because some callers get
+ // type-confused and pass ASN1_GENERALIZEDTIME to ASN1_UTCTIME_print().
+ // ASN1_UTCTIME_set_string() is stricter, and would reject the inputs in
+ // question.
+ if (!ASN1_STRING_set(tm.get(), t.val, strlen(t.val))) {
+ fprintf(stderr, "ASN1_STRING_set\n");
+ return false;
+ }
+ const int ok = ASN1_UTCTIME_print(bio.get(), tm.get());
+
+ const uint8_t *contents;
+ size_t len;
+ if (!BIO_mem_contents(bio.get(), &contents, &len)) {
+ fprintf(stderr, "BIO_mem_contents\n");
+ return false;
+ }
+
+ if (ok != (strcmp(t.want, "Bad time value") != 0)) {
+ fprintf(stderr, "ASN1_UTCTIME_print(%s): bad return value\n", t.val);
+ return false;
+ }
+ if (len != strlen(t.want) || memcmp(contents, t.want, len)) {
+ fprintf(stderr, "ASN1_UTCTIME_print(%s): got %.*s, want %s\n", t.val,
+ static_cast<int>(len),
+ reinterpret_cast<const char *>(contents), t.want);
+ return false;
+ }
+ }
+
+ return true;
+}
+
int main() {
CRYPTO_library_init();
@@ -1023,7 +1091,8 @@
!TestFromBufferTrailingData() ||
!TestFromBufferModified() ||
!TestFromBufferReused() ||
- !TestFailedParseFromBuffer()) {
+ !TestFailedParseFromBuffer() ||
+ !TestPrintUTCTIME()) {
return 1;
}