diff options
author | Robert Sloan <varomodt@google.com> | 2018-01-16 15:48:33 -0800 |
---|---|---|
committer | Rob Sloan <varomodt@google.com> | 2018-01-17 17:29:34 +0000 |
commit | 0db7f543e9eb4209a3124ef956229ed0e942193d (patch) | |
tree | 3586ad210d439fd1afb10f66782babac5af5fe64 /src/crypto | |
parent | a450c925ed2a37469bf75ff6c1d69e48fd6c3d26 (diff) | |
download | boringssl-0db7f543e9eb4209a3124ef956229ed0e942193d.tar.gz |
NO PARTIAL RERUN external/boringssl: Sync to 37c6eb4284bea36be9fa41d35b582008f2023dcf.
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/9770532afa91dd1441ba0d3e9d4bb86d7e501f19..37c6eb4284bea36be9fa41d35b582008f2023dcf
Test: BoringSSL CTS Presubmits.
Change-Id: I3d9ce9a10f8867d20753ff226501ca8c30d0f290
Diffstat (limited to 'src/crypto')
-rw-r--r-- | src/crypto/fipsmodule/bcm.c | 1 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/ec.c | 12 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/ec_key.c | 43 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/ec_test.cc | 13 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/internal.h | 12 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/oct.c | 73 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/p224-64.c | 69 | ||||
-rw-r--r-- | src/crypto/fipsmodule/ec/simple.c | 26 | ||||
-rw-r--r-- | src/crypto/fipsmodule/tls/internal.h | 39 | ||||
-rw-r--r-- | src/crypto/fipsmodule/tls/kdf.c | 160 | ||||
-rw-r--r-- | src/crypto/test/file_test.cc | 39 | ||||
-rw-r--r-- | src/crypto/test/file_test.h | 9 | ||||
-rw-r--r-- | src/crypto/test/file_test_gtest.cc | 2 |
13 files changed, 313 insertions, 185 deletions
diff --git a/src/crypto/fipsmodule/bcm.c b/src/crypto/fipsmodule/bcm.c index fb16215f..1e5742b1 100644 --- a/src/crypto/fipsmodule/bcm.c +++ b/src/crypto/fipsmodule/bcm.c @@ -87,6 +87,7 @@ #include "rsa/blinding.c" #include "rsa/padding.c" #include "rsa/rsa.c" +#include "tls/kdf.c" #include "rsa/rsa_impl.c" #include "sha/sha1-altivec.c" #include "sha/sha1.c" diff --git a/src/crypto/fipsmodule/ec/ec.c b/src/crypto/fipsmodule/ec/ec.c index 47a90ce4..c9687a61 100644 --- a/src/crypto/fipsmodule/ec/ec.c +++ b/src/crypto/fipsmodule/ec/ec.c @@ -908,18 +908,6 @@ int ec_point_mul_scalar(const EC_GROUP *group, EC_POINT *r, return group->meth->mul(group, r, g_scalar, p, p_scalar, ctx); } -int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group, - EC_POINT *point, const BIGNUM *x, - const BIGNUM *y, const BIGNUM *z, - BN_CTX *ctx) { - if (EC_GROUP_cmp(group, point->group, NULL) != 0) { - OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); - return 0; - } - return ec_GFp_simple_set_Jprojective_coordinates_GFp(group, point, x, y, z, - ctx); -} - void EC_GROUP_set_asn1_flag(EC_GROUP *group, int flag) {} const EC_METHOD *EC_GROUP_method_of(const EC_GROUP *group) { diff --git a/src/crypto/fipsmodule/ec/ec_key.c b/src/crypto/fipsmodule/ec/ec_key.c index 4e0bcb22..084d33b7 100644 --- a/src/crypto/fipsmodule/ec/ec_key.c +++ b/src/crypto/fipsmodule/ec/ec_key.c @@ -390,8 +390,6 @@ int EC_KEY_check_fips(const EC_KEY *key) { int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, BIGNUM *y) { - BN_CTX *ctx = NULL; - BIGNUM *tx, *ty; EC_POINT *point = NULL; int ok = 0; @@ -399,51 +397,18 @@ int EC_KEY_set_public_key_affine_coordinates(EC_KEY *key, BIGNUM *x, OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); return 0; } - ctx = BN_CTX_new(); - - if (ctx == NULL) { - return 0; - } - BN_CTX_start(ctx); point = EC_POINT_new(key->group); - - if (point == NULL) { - goto err; - } - - tx = BN_CTX_get(ctx); - ty = BN_CTX_get(ctx); - if (tx == NULL || - ty == NULL) { - goto err; - } - - if (!EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, ctx) || - !EC_POINT_get_affine_coordinates_GFp(key->group, point, tx, ty, ctx)) { - goto err; - } - - // Check if retrieved coordinates match originals: if not values - // are out of range. - if (BN_cmp(x, tx) || BN_cmp(y, ty)) { - OPENSSL_PUT_ERROR(EC, EC_R_COORDINATES_OUT_OF_RANGE); - goto err; - } - - if (!EC_KEY_set_public_key(key, point)) { - goto err; - } - - if (EC_KEY_check_key(key) == 0) { + if (point == NULL || + !EC_POINT_set_affine_coordinates_GFp(key->group, point, x, y, NULL) || + !EC_KEY_set_public_key(key, point) || + !EC_KEY_check_key(key)) { goto err; } ok = 1; err: - BN_CTX_end(ctx); - BN_CTX_free(ctx); EC_POINT_free(point); return ok; } diff --git a/src/crypto/fipsmodule/ec/ec_test.cc b/src/crypto/fipsmodule/ec/ec_test.cc index d2cd2afb..e69f8d72 100644 --- a/src/crypto/fipsmodule/ec/ec_test.cc +++ b/src/crypto/fipsmodule/ec/ec_test.cc @@ -352,8 +352,12 @@ TEST_P(ECCurveTest, SetAffine) { ASSERT_TRUE(x); bssl::UniquePtr<BIGNUM> y(BN_new()); ASSERT_TRUE(y); + bssl::UniquePtr<BIGNUM> p(BN_new()); + ASSERT_TRUE(p); EXPECT_TRUE(EC_POINT_get_affine_coordinates_GFp( group, EC_KEY_get0_public_key(key.get()), x.get(), y.get(), nullptr)); + EXPECT_TRUE( + EC_GROUP_get_curve_GFp(group, p.get(), nullptr, nullptr, nullptr)); // Points on the curve should be accepted. auto point = bssl::UniquePtr<EC_POINT>(EC_POINT_new(group)); @@ -369,6 +373,15 @@ TEST_P(ECCurveTest, SetAffine) { ASSERT_TRUE(invalid_point); EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group, invalid_point.get(), x.get(), y.get(), nullptr)); + + // Coordinates out of range should be rejected. + EXPECT_TRUE(BN_add(y.get(), y.get(), BN_value_one())); + EXPECT_TRUE(BN_add(y.get(), y.get(), p.get())); + + EXPECT_FALSE(EC_POINT_set_affine_coordinates_GFp(group, invalid_point.get(), + x.get(), y.get(), nullptr)); + EXPECT_FALSE( + EC_KEY_set_public_key_affine_coordinates(key.get(), x.get(), y.get())); } TEST_P(ECCurveTest, GenerateFIPS) { diff --git a/src/crypto/fipsmodule/ec/internal.h b/src/crypto/fipsmodule/ec/internal.h index 145c5c40..06fa3711 100644 --- a/src/crypto/fipsmodule/ec/internal.h +++ b/src/crypto/fipsmodule/ec/internal.h @@ -223,16 +223,9 @@ int ec_GFp_simple_point_init(EC_POINT *); void ec_GFp_simple_point_finish(EC_POINT *); int ec_GFp_simple_point_copy(EC_POINT *, const EC_POINT *); int ec_GFp_simple_point_set_to_infinity(const EC_GROUP *, EC_POINT *); -int ec_GFp_simple_set_Jprojective_coordinates_GFp(const EC_GROUP *, EC_POINT *, - const BIGNUM *x, - const BIGNUM *y, - const BIGNUM *z, BN_CTX *); int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *, EC_POINT *, const BIGNUM *x, const BIGNUM *y, BN_CTX *); -int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *, EC_POINT *, - const BIGNUM *x, int y_bit, - BN_CTX *); int ec_GFp_simple_add(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *); int ec_GFp_simple_dbl(const EC_GROUP *, EC_POINT *r, const EC_POINT *a, @@ -264,11 +257,6 @@ int ec_GFp_mont_field_encode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, int ec_GFp_mont_field_decode(const EC_GROUP *, BIGNUM *r, const BIGNUM *a, BN_CTX *); -int ec_point_set_Jprojective_coordinates_GFp(const EC_GROUP *group, - EC_POINT *point, const BIGNUM *x, - const BIGNUM *y, const BIGNUM *z, - BN_CTX *ctx); - void ec_GFp_nistp_recode_scalar_bits(uint8_t *sign, uint8_t *digit, uint8_t in); const EC_METHOD *EC_GFp_nistp224_method(void); diff --git a/src/crypto/fipsmodule/ec/oct.c b/src/crypto/fipsmodule/ec/oct.c index 7d623956..96c138a1 100644 --- a/src/crypto/fipsmodule/ec/oct.c +++ b/src/crypto/fipsmodule/ec/oct.c @@ -268,16 +268,20 @@ size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point, return ec_GFp_simple_point2oct(group, point, form, buf, len, ctx); } -int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, - EC_POINT *point, const BIGNUM *x, - int y_bit, BN_CTX *ctx) { +int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x, + int y_bit, BN_CTX *ctx) { + if (EC_GROUP_cmp(group, point->group, NULL) != 0) { + OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); + return 0; + } + if (BN_is_negative(x) || BN_cmp(x, &group->field) >= 0) { OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT); return 0; } BN_CTX *new_ctx = NULL; - BIGNUM *tmp1, *tmp2, *y; int ret = 0; ERR_clear_error(); @@ -292,10 +296,13 @@ int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, y_bit = (y_bit != 0); BN_CTX_start(ctx); - tmp1 = BN_CTX_get(ctx); - tmp2 = BN_CTX_get(ctx); - y = BN_CTX_get(ctx); - if (y == NULL) { + BIGNUM *tmp1 = BN_CTX_get(ctx); + BIGNUM *tmp2 = BN_CTX_get(ctx); + BIGNUM *a = BN_CTX_get(ctx); + BIGNUM *b = BN_CTX_get(ctx); + BIGNUM *y = BN_CTX_get(ctx); + if (y == NULL || + !EC_GROUP_get_curve_GFp(group, NULL, a, b, ctx)) { goto err; } @@ -304,17 +311,9 @@ int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, // so y is one of the square roots of x^3 + a*x + b. // tmp1 := x^3 - if (group->meth->field_decode == 0) { - // field_{sqr,mul} work on standard representation - if (!group->meth->field_sqr(group, tmp2, x, ctx) || - !group->meth->field_mul(group, tmp1, tmp2, x, ctx)) { - goto err; - } - } else { - if (!BN_mod_sqr(tmp2, x, &group->field, ctx) || - !BN_mod_mul(tmp1, tmp2, x, &group->field, ctx)) { - goto err; - } + if (!BN_mod_sqr(tmp2, x, &group->field, ctx) || + !BN_mod_mul(tmp1, tmp2, x, &group->field, ctx)) { + goto err; } // tmp1 := tmp1 + a*x @@ -325,33 +324,15 @@ int ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group, goto err; } } else { - if (group->meth->field_decode) { - if (!group->meth->field_decode(group, tmp2, &group->a, ctx) || - !BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) { - goto err; - } - } else { - // field_mul works on standard representation - if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) { - goto err; - } - } - - if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) { + if (!BN_mod_mul(tmp2, a, x, &group->field, ctx) || + !BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) { goto err; } } // tmp1 := tmp1 + b - if (group->meth->field_decode) { - if (!group->meth->field_decode(group, tmp2, &group->b, ctx) || - !BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) { - goto err; - } - } else { - if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) { - goto err; - } + if (!BN_mod_add_quick(tmp1, tmp1, b, &group->field)) { + goto err; } if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) { @@ -392,13 +373,3 @@ err: BN_CTX_free(new_ctx); return ret; } - -int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, - EC_POINT *point, const BIGNUM *x, - int y_bit, BN_CTX *ctx) { - if (EC_GROUP_cmp(group, point->group, NULL) != 0) { - OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS); - return 0; - } - return ec_GFp_simple_set_compressed_coordinates(group, point, x, y_bit, ctx); -} diff --git a/src/crypto/fipsmodule/ec/p224-64.c b/src/crypto/fipsmodule/ec/p224-64.c index 00972097..71a8af0a 100644 --- a/src/crypto/fipsmodule/ec/p224-64.c +++ b/src/crypto/fipsmodule/ec/p224-64.c @@ -1015,22 +1015,27 @@ static int ec_GFp_nistp224_point_get_affine_coordinates(const EC_GROUP *group, p224_felem_inv(z2, z1); p224_felem_square(tmp, z2); p224_felem_reduce(z1, tmp); - p224_felem_mul(tmp, x_in, z1); - p224_felem_reduce(x_in, tmp); - p224_felem_contract(x_out, x_in); - if (x != NULL && !p224_felem_to_BN(x, x_out)) { - OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); - return 0; + + if (x != NULL) { + p224_felem_mul(tmp, x_in, z1); + p224_felem_reduce(x_in, tmp); + p224_felem_contract(x_out, x_in); + if (!p224_felem_to_BN(x, x_out)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + return 0; + } } - p224_felem_mul(tmp, z1, z2); - p224_felem_reduce(z1, tmp); - p224_felem_mul(tmp, y_in, z1); - p224_felem_reduce(y_in, tmp); - p224_felem_contract(y_out, y_in); - if (y != NULL && !p224_felem_to_BN(y, y_out)) { - OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); - return 0; + if (y != NULL) { + p224_felem_mul(tmp, z1, z2); + p224_felem_reduce(z1, tmp); + p224_felem_mul(tmp, y_in, z1); + p224_felem_reduce(y_in, tmp); + p224_felem_contract(y_out, y_in); + if (!p224_felem_to_BN(y, y_out)) { + OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); + return 0; + } } return 1; @@ -1040,28 +1045,9 @@ static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r, const EC_SCALAR *g_scalar, const EC_POINT *p, const EC_SCALAR *p_scalar, BN_CTX *ctx) { - int ret = 0; - BN_CTX *new_ctx = NULL; - BIGNUM *x, *y, *z, *tmp_scalar; p224_felem p_pre_comp[17][3]; p224_felem x_in, y_in, z_in, x_out, y_out, z_out; - if (ctx == NULL) { - ctx = BN_CTX_new(); - new_ctx = ctx; - if (ctx == NULL) { - return 0; - } - } - - BN_CTX_start(ctx); - if ((x = BN_CTX_get(ctx)) == NULL || - (y = BN_CTX_get(ctx)) == NULL || - (z = BN_CTX_get(ctx)) == NULL || - (tmp_scalar = BN_CTX_get(ctx)) == NULL) { - goto err; - } - if (p != NULL && p_scalar != NULL) { // We treat NULL scalars as 0, and NULL points as points at infinity, i.e., // they contribute nothing to the linear combination. @@ -1070,7 +1056,7 @@ static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r, if (!p224_BN_to_felem(x_out, &p->X) || !p224_BN_to_felem(y_out, &p->Y) || !p224_BN_to_felem(z_out, &p->Z)) { - goto err; + return 0; } p224_felem_assign(p_pre_comp[1][0], x_out); @@ -1100,18 +1086,13 @@ static int ec_GFp_nistp224_points_mul(const EC_GROUP *group, EC_POINT *r, p224_felem_contract(x_in, x_out); p224_felem_contract(y_in, y_out); p224_felem_contract(z_in, z_out); - if (!p224_felem_to_BN(x, x_in) || - !p224_felem_to_BN(y, y_in) || - !p224_felem_to_BN(z, z_in)) { + if (!p224_felem_to_BN(&r->X, x_in) || + !p224_felem_to_BN(&r->Y, y_in) || + !p224_felem_to_BN(&r->Z, z_in)) { OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB); - goto err; + return 0; } - ret = ec_point_set_Jprojective_coordinates_GFp(group, r, x, y, z, ctx); - -err: - BN_CTX_end(ctx); - BN_CTX_free(new_ctx); - return ret; + return 1; } DEFINE_METHOD_FUNCTION(EC_METHOD, EC_GFp_nistp224_method) { diff --git a/src/crypto/fipsmodule/ec/simple.c b/src/crypto/fipsmodule/ec/simple.c index bc395252..ab011ca3 100644 --- a/src/crypto/fipsmodule/ec/simple.c +++ b/src/crypto/fipsmodule/ec/simple.c @@ -269,9 +269,14 @@ static int set_Jprojective_coordinate_GFp(const EC_GROUP *group, BIGNUM *out, return BN_copy(out, in) != NULL; } -int ec_GFp_simple_set_Jprojective_coordinates_GFp( - const EC_GROUP *group, EC_POINT *point, const BIGNUM *x, const BIGNUM *y, - const BIGNUM *z, BN_CTX *ctx) { +int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group, + EC_POINT *point, const BIGNUM *x, + const BIGNUM *y, BN_CTX *ctx) { + if (x == NULL || y == NULL) { + OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + BN_CTX *new_ctx = NULL; int ret = 0; @@ -284,7 +289,7 @@ int ec_GFp_simple_set_Jprojective_coordinates_GFp( if (!set_Jprojective_coordinate_GFp(group, &point->X, x, ctx) || !set_Jprojective_coordinate_GFp(group, &point->Y, y, ctx) || - !set_Jprojective_coordinate_GFp(group, &point->Z, z, ctx)) { + !BN_copy(&point->Z, &group->one)) { goto err; } @@ -295,19 +300,6 @@ err: return ret; } -int ec_GFp_simple_point_set_affine_coordinates(const EC_GROUP *group, - EC_POINT *point, const BIGNUM *x, - const BIGNUM *y, BN_CTX *ctx) { - if (x == NULL || y == NULL) { - // unlike for projective coordinates, we do not tolerate this - OPENSSL_PUT_ERROR(EC, ERR_R_PASSED_NULL_PARAMETER); - return 0; - } - - return ec_point_set_Jprojective_coordinates_GFp(group, point, x, y, - BN_value_one(), ctx); -} - int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) { int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, diff --git a/src/crypto/fipsmodule/tls/internal.h b/src/crypto/fipsmodule/tls/internal.h new file mode 100644 index 00000000..ef642a6c --- /dev/null +++ b/src/crypto/fipsmodule/tls/internal.h @@ -0,0 +1,39 @@ +/* Copyright (c) 2018, 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. */ + +#ifndef OPENSSL_HEADER_CRYPTO_FIPSMODULE_TLS_INTERNAL_H +#define OPENSSL_HEADER_CRYPTO_FIPSMODULE_TLS_INTERNAL_H + +#include <openssl/base.h> + +#if defined(__cplusplus) +extern "C" { +#endif + + +// tls1_prf calculates |out_len| bytes of the TLS PDF, using |digest|, and +// writes them to |out|. It returns one on success and zero on error. +OPENSSL_EXPORT int CRYPTO_tls1_prf(const EVP_MD *digest, + uint8_t *out, size_t out_len, + const uint8_t *secret, size_t secret_len, + const char *label, size_t label_len, + const uint8_t *seed1, size_t seed1_len, + const uint8_t *seed2, size_t seed2_len); + + +#if defined(__cplusplus) +} +#endif + +#endif // OPENSSL_HEADER_CRYPTO_FIPSMODULE_TLS_INTERNAL_H diff --git a/src/crypto/fipsmodule/tls/kdf.c b/src/crypto/fipsmodule/tls/kdf.c new file mode 100644 index 00000000..120553f9 --- /dev/null +++ b/src/crypto/fipsmodule/tls/kdf.c @@ -0,0 +1,160 @@ +/* ==================================================================== + * Copyright (c) 1998-2007 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 + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). */ + +#include <openssl/hmac.h> + +#include "internal.h" + + +// tls1_P_hash computes the TLS P_<hash> function as described in RFC 5246, +// section 5. It XORs |out_len| bytes to |out|, using |md| as the hash and +// |secret| as the secret. |label|, |seed1|, and |seed2| are concatenated to +// form the seed parameter. It returns true on success and false on failure. +static int tls1_P_hash(uint8_t *out, size_t out_len, + const EVP_MD *md, + const uint8_t *secret, size_t secret_len, + const char *label, size_t label_len, + const uint8_t *seed1, size_t seed1_len, + const uint8_t *seed2, size_t seed2_len) { + HMAC_CTX ctx, ctx_tmp, ctx_init; + uint8_t A1[EVP_MAX_MD_SIZE]; + unsigned A1_len; + int ret = 0; + + const size_t chunk = EVP_MD_size(md); + HMAC_CTX_init(&ctx); + HMAC_CTX_init(&ctx_tmp); + HMAC_CTX_init(&ctx_init); + + if (!HMAC_Init_ex(&ctx_init, secret, secret_len, md, NULL) || + !HMAC_CTX_copy_ex(&ctx, &ctx_init) || + !HMAC_Update(&ctx, (const uint8_t *) label, label_len) || + !HMAC_Update(&ctx, seed1, seed1_len) || + !HMAC_Update(&ctx, seed2, seed2_len) || + !HMAC_Final(&ctx, A1, &A1_len)) { + goto err; + } + + for (;;) { + unsigned len; + uint8_t hmac[EVP_MAX_MD_SIZE]; + if (!HMAC_CTX_copy_ex(&ctx, &ctx_init) || + !HMAC_Update(&ctx, A1, A1_len) || + // Save a copy of |ctx| to compute the next A1 value below. + (out_len > chunk && !HMAC_CTX_copy_ex(&ctx_tmp, &ctx)) || + !HMAC_Update(&ctx, (const uint8_t *) label, label_len) || + !HMAC_Update(&ctx, seed1, seed1_len) || + !HMAC_Update(&ctx, seed2, seed2_len) || + !HMAC_Final(&ctx, hmac, &len)) { + goto err; + } + assert(len == chunk); + + // XOR the result into |out|. + if (len > out_len) { + len = out_len; + } + for (unsigned i = 0; i < len; i++) { + out[i] ^= hmac[i]; + } + out += len; + out_len -= len; + + if (out_len == 0) { + break; + } + + // Calculate the next A1 value. + if (!HMAC_Final(&ctx_tmp, A1, &A1_len)) { + goto err; + } + } + + ret = 1; + +err: + OPENSSL_cleanse(A1, sizeof(A1)); + HMAC_CTX_cleanup(&ctx); + HMAC_CTX_cleanup(&ctx_tmp); + HMAC_CTX_cleanup(&ctx_init); + return ret; +} + +int CRYPTO_tls1_prf(const EVP_MD *digest, + uint8_t *out, size_t out_len, + const uint8_t *secret, size_t secret_len, + const char *label, size_t label_len, + const uint8_t *seed1, size_t seed1_len, + const uint8_t *seed2, size_t seed2_len) { + if (out_len == 0) { + return 1; + } + + OPENSSL_memset(out, 0, out_len); + + if (digest == EVP_md5_sha1()) { + // If using the MD5/SHA1 PRF, |secret| is partitioned between MD5 and SHA-1. + size_t secret_half = secret_len - (secret_len / 2); + if (!tls1_P_hash(out, out_len, EVP_md5(), secret, secret_half, label, + label_len, seed1, seed1_len, seed2, seed2_len)) { + return 0; + } + + // Note that, if |secret_len| is odd, the two halves share a byte. + secret += secret_len - secret_half; + secret_len = secret_half; + digest = EVP_sha1(); + } + + return tls1_P_hash(out, out_len, digest, secret, secret_len, label, label_len, + seed1, seed1_len, seed2, seed2_len); +} diff --git a/src/crypto/test/file_test.cc b/src/crypto/test/file_test.cc index ea1fc3c5..cbb9f7f8 100644 --- a/src/crypto/test/file_test.cc +++ b/src/crypto/test/file_test.cc @@ -31,8 +31,10 @@ FileTest::FileTest(std::unique_ptr<FileTest::LineReader> reader, - std::function<void(const std::string &)> comment_callback) + std::function<void(const std::string &)> comment_callback, + bool is_kas_test) : reader_(std::move(reader)), + is_kas_test_(is_kas_test), comment_callback_(std::move(comment_callback)) {} FileTest::~FileTest() {} @@ -122,9 +124,16 @@ FileTest::ReadResult FileTest::ReadNext() { in_instruction_block = false; // Delimit instruction block from test with a blank line. current_test_ += "\r\n"; + } else if (is_kas_test_) { + // KAS tests have random blank lines scattered around. + current_test_ += "\r\n"; } } else if (buf[0] == '#') { - if (comment_callback_) { + if (is_kas_test_ && seen_non_comment_) { + // KAS tests have comments after the initial comment block which need + // to be included in the corresponding place in the output. + current_test_ += std::string(buf.get()); + } else if (comment_callback_) { comment_callback_(buf.get()); } // Otherwise ignore comments. @@ -134,6 +143,7 @@ FileTest::ReadResult FileTest::ReadNext() { // request files are hopelessly inconsistent. } else if (buf[0] == '[') { // Inside an instruction block. is_at_new_instruction_block_ = true; + seen_non_comment_ = true; if (start_line_ != 0) { // Instructions should be separate blocks. fprintf(stderr, "Line %u is an instruction in a test case.\n", line_); @@ -145,12 +155,25 @@ FileTest::ReadResult FileTest::ReadNext() { } // Parse the line as an instruction ("[key = value]" or "[key]"). - std::string kv = StripSpace(buf.get(), len); - if (kv[kv.size() - 1] != ']') { - fprintf(stderr, "Line %u, invalid instruction: %s\n", line_, - kv.c_str()); - return kReadError; + + // KAS tests contain invalid syntax. + std::string kv = buf.get(); + const bool is_broken_kas_instruction = + is_kas_test_ && + (kv == "[SHA(s) supported (Used for hashing Z): SHA512 \r\n"); + + if (!is_broken_kas_instruction) { + kv = StripSpace(buf.get(), len); + if (kv[kv.size() - 1] != ']') { + fprintf(stderr, "Line %u, invalid instruction: '%s'\n", line_, + kv.c_str()); + return kReadError; + } + } else { + // Just remove the newline for the broken instruction. + kv = kv.substr(0, kv.size() - 2); } + current_test_ += kv + "\r\n"; kv = std::string(kv.begin() + 1, kv.end() - 1); @@ -422,7 +445,7 @@ int FileTestMain(const FileTest::Options &opts) { return 1; } - FileTest t(std::move(reader), opts.comment_callback); + FileTest t(std::move(reader), opts.comment_callback, opts.is_kas_test); bool failed = false; while (true) { diff --git a/src/crypto/test/file_test.h b/src/crypto/test/file_test.h index 204ef9cb..002b350f 100644 --- a/src/crypto/test/file_test.h +++ b/src/crypto/test/file_test.h @@ -114,10 +114,15 @@ class FileTest { bool silent = false; // comment_callback is called after each comment in the input is parsed. std::function<void(const std::string&)> comment_callback; + // is_kas_test is true if a NIST “KAS” test is being parsed. These tests + // are inconsistent with the other NIST files to such a degree that they + // need their own boolean. + bool is_kas_test = false; }; explicit FileTest(std::unique_ptr<LineReader> reader, - std::function<void(const std::string &)> comment_callback); + std::function<void(const std::string &)> comment_callback, + bool is_kas_test); ~FileTest(); // ReadNext reads the next test from the file. It returns |kReadSuccess| if @@ -217,6 +222,8 @@ class FileTest { std::string current_test_; bool is_at_new_instruction_block_ = false; + bool seen_non_comment_ = false; + bool is_kas_test_ = false; // comment_callback_, if set, is a callback function that is called with the // contents of each comment as they are parsed. diff --git a/src/crypto/test/file_test_gtest.cc b/src/crypto/test/file_test_gtest.cc index bfa8d27d..8ff7a2bf 100644 --- a/src/crypto/test/file_test_gtest.cc +++ b/src/crypto/test/file_test_gtest.cc @@ -68,7 +68,7 @@ class StringLineReader : public FileTest::LineReader { void FileTestGTest(const char *path, std::function<void(FileTest *)> run_test) { std::unique_ptr<StringLineReader> reader( new StringLineReader(GetTestData(path))); - FileTest t(std::move(reader), nullptr); + FileTest t(std::move(reader), nullptr, false); while (true) { switch (t.ReadNext()) { |