This change includes support for a variant of [HRSS], a post-quantum KEM based on NTRU. It includes changes suggested in [SXY]. This is not yet ready for any deployment: some breaking changes, like removing the confirmation hash, are still planned. (CLA for HRSS's assembly code noted in b/119426559.) [HRSS] https://eprint.iacr.org/2017/667.pdf [SXY] https://eprint.iacr.org/2017/1005.pdf Change-Id: I85d813733b066d5c578484bdd248de3f764194db Reviewed-on: https://boringssl-review.googlesource.com/c/33105 Reviewed-by: David Benjamin <davidben@google.com>kris/onging/CECPQ3_patch15
@@ -105,6 +105,7 @@ if(${ARCH} STREQUAL "arm") | |||
chacha/chacha-armv4.${ASM_EXT} | |||
curve25519/asm/x25519-asm-arm.S | |||
poly1305/poly1305_arm_asm.S | |||
hrss/asm/poly_mul_vec_armv7_neon.S | |||
) | |||
endif() | |||
@@ -131,6 +132,7 @@ if(${ARCH} STREQUAL "x86_64") | |||
chacha/chacha-x86_64.${ASM_EXT} | |||
cipher_extra/aes128gcmsiv-x86_64.${ASM_EXT} | |||
cipher_extra/chacha20_poly1305_x86_64.${ASM_EXT} | |||
hrss/asm/poly_rq_mul.S | |||
) | |||
endif() | |||
@@ -275,6 +277,7 @@ add_library( | |||
evp/sign.c | |||
ex_data.c | |||
hkdf/hkdf.c | |||
hrss/hrss.c | |||
lhash/lhash.c | |||
mem.c | |||
obj/obj.c | |||
@@ -455,6 +458,7 @@ add_executable( | |||
fipsmodule/rand/ctrdrbg_test.cc | |||
hkdf/hkdf_test.cc | |||
hmac_extra/hmac_test.cc | |||
hrss/hrss_test.cc | |||
lhash/lhash_test.cc | |||
obj/obj_test.cc | |||
pem/pem_test.cc | |||
@@ -0,0 +1,475 @@ | |||
/* 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. */ | |||
#include <gtest/gtest.h> | |||
#include <openssl/hrss.h> | |||
#include <openssl/rand.h> | |||
#include "../test/test_util.h" | |||
#include "internal.h" | |||
// poly2_from_bits takes the least-significant bit from each byte of |in| and | |||
// sets the bits of |*out| to match. | |||
static void poly2_from_bits(struct poly2 *out, const uint8_t in[N]) { | |||
crypto_word_t *words = out->v; | |||
unsigned shift = 0; | |||
crypto_word_t word = 0; | |||
for (unsigned i = 0; i < N; i++) { | |||
word >>= 1; | |||
word |= (crypto_word_t)(in[i] & 1) << (BITS_PER_WORD - 1); | |||
shift++; | |||
if (shift == BITS_PER_WORD) { | |||
*words = word; | |||
words++; | |||
word = 0; | |||
shift = 0; | |||
} | |||
} | |||
word >>= BITS_PER_WORD - shift; | |||
*words = word; | |||
} | |||
TEST(HRSS, Poly2RotateRight) { | |||
uint8_t bits[N]; | |||
RAND_bytes(bits, sizeof(bits)); | |||
for (size_t i = 0; i < N; i++) { | |||
bits[i] &= 1; | |||
}; | |||
struct poly2 p, orig, shifted; | |||
poly2_from_bits(&p, bits); | |||
OPENSSL_memcpy(&orig, &p, sizeof(orig)); | |||
// Test |HRSS_poly2_rotr_consttime| by manually rotating |bits| step-by-step | |||
// and testing every possible shift to ensure that it produces the correct | |||
// answer. | |||
for (size_t shift = 0; shift <= N; shift++) { | |||
SCOPED_TRACE(shift); | |||
OPENSSL_memcpy(&p, &orig, sizeof(orig)); | |||
HRSS_poly2_rotr_consttime(&p, shift); | |||
poly2_from_bits(&shifted, bits); | |||
ASSERT_EQ( | |||
Bytes(reinterpret_cast<const uint8_t *>(&shifted), sizeof(shifted)), | |||
Bytes(reinterpret_cast<const uint8_t *>(&p), sizeof(p))); | |||
const uint8_t least_significant_bit = bits[0]; | |||
OPENSSL_memmove(bits, &bits[1], N-1); | |||
bits[N-1] = least_significant_bit; | |||
} | |||
} | |||
// poly3_rand sets |r| to a random value (albeit with bias). | |||
static void poly3_rand(poly3 *p) { | |||
RAND_bytes(reinterpret_cast<uint8_t *>(p), sizeof(p)); | |||
p->s.v[WORDS_PER_POLY - 1] &= (UINT64_C(1) << BITS_IN_LAST_WORD) - 1; | |||
p->a.v[WORDS_PER_POLY - 1] &= (UINT64_C(1) << BITS_IN_LAST_WORD) - 1; | |||
// (s, a) = (1, 1) is invalid. Map those to one. | |||
for (size_t j = 0; j < WORDS_PER_POLY; j++) { | |||
p->s.v[j] ^= p->s.v[j] & p->a.v[j]; | |||
} | |||
} | |||
// poly3_word_add sets (|s1|, |a1|) += (|s2|, |a2|). | |||
static void poly3_word_add(crypto_word_t *s1, crypto_word_t *a1, | |||
const crypto_word_t s2, const crypto_word_t a2) { | |||
const crypto_word_t x = *a1 ^ a2; | |||
const crypto_word_t y = (*s1 ^ s2) ^ (*a1 & a2); | |||
const crypto_word_t z = *s1 & s2; | |||
*s1 = y & ~x; | |||
*a1 = z | (x & ~y); | |||
} | |||
TEST(HRSS, Poly3Invert) { | |||
poly3 p, inverse, result; | |||
memset(&p, 0, sizeof(p)); | |||
memset(&inverse, 0, sizeof(inverse)); | |||
memset(&result, 0, sizeof(result)); | |||
// The inverse of -1 is -1. | |||
p.s.v[0] = 1; | |||
HRSS_poly3_invert(&inverse, &p); | |||
EXPECT_EQ(Bytes(reinterpret_cast<const uint8_t*>(&p), sizeof(p)), | |||
Bytes(reinterpret_cast<const uint8_t*>(&inverse), sizeof(inverse))); | |||
// The inverse of 1 is 1. | |||
p.s.v[0] = 0; | |||
p.a.v[0] = 1; | |||
HRSS_poly3_invert(&inverse, &p); | |||
EXPECT_EQ(Bytes(reinterpret_cast<const uint8_t*>(&p), sizeof(p)), | |||
Bytes(reinterpret_cast<const uint8_t*>(&inverse), sizeof(inverse))); | |||
for (size_t i = 0; i < 500; i++) { | |||
poly3 r; | |||
poly3_rand(&r); | |||
HRSS_poly3_invert(&inverse, &r); | |||
HRSS_poly3_mul(&result, &inverse, &r); | |||
// r×r⁻¹ = 1, and |p| contains 1. | |||
EXPECT_EQ( | |||
Bytes(reinterpret_cast<const uint8_t *>(&p), sizeof(p)), | |||
Bytes(reinterpret_cast<const uint8_t *>(&result), sizeof(result))); | |||
} | |||
} | |||
TEST(HRSS, Poly3UnreducedInput) { | |||
// Check that |poly3_mul| works correctly with inputs that aren't reduced mod | |||
// Φ(N). | |||
poly3 r, inverse, result, one; | |||
poly3_rand(&r); | |||
HRSS_poly3_invert(&inverse, &r); | |||
HRSS_poly3_mul(&result, &inverse, &r); | |||
memset(&one, 0, sizeof(one)); | |||
one.a.v[0] = 1; | |||
EXPECT_EQ(Bytes(reinterpret_cast<const uint8_t *>(&one), sizeof(one)), | |||
Bytes(reinterpret_cast<const uint8_t *>(&result), sizeof(result))); | |||
// |r| is probably already not reduced mod Φ(N), but add x^701 - 1 and | |||
// recompute to ensure that we get the same answer. (Since (x^701 - 1) ≡ 0 mod | |||
// Φ(N).) | |||
poly3_word_add(&r.s.v[0], &r.a.v[0], 1, 0); | |||
poly3_word_add(&r.s.v[WORDS_PER_POLY - 1], &r.a.v[WORDS_PER_POLY - 1], 0, | |||
UINT64_C(1) << BITS_IN_LAST_WORD); | |||
HRSS_poly3_mul(&result, &inverse, &r); | |||
EXPECT_EQ(Bytes(reinterpret_cast<const uint8_t *>(&one), sizeof(one)), | |||
Bytes(reinterpret_cast<const uint8_t *>(&result), sizeof(result))); | |||
// Check that x^700 × 1 gives -x^699 - x^698 … -1. | |||
poly3 x700; | |||
memset(&x700, 0, sizeof(x700)); | |||
x700.a.v[WORDS_PER_POLY-1] = UINT64_C(1) << (BITS_IN_LAST_WORD - 1); | |||
HRSS_poly3_mul(&result, &one, &x700); | |||
for (size_t i = 0; i < WORDS_PER_POLY-1; i++) { | |||
EXPECT_EQ(CONSTTIME_TRUE_W, result.s.v[i]); | |||
EXPECT_EQ(0u, result.a.v[i]); | |||
} | |||
EXPECT_EQ((UINT64_C(1) << (BITS_IN_LAST_WORD - 1)) - 1, | |||
result.s.v[WORDS_PER_POLY - 1]); | |||
EXPECT_EQ(0u, result.a.v[WORDS_PER_POLY - 1]); | |||
} | |||
TEST(HRSS, Basic) { | |||
uint8_t generate_key_entropy[HRSS_GENERATE_KEY_BYTES]; | |||
for (unsigned i = 0; i < sizeof(generate_key_entropy); i++) { | |||
generate_key_entropy[i] = i; | |||
} | |||
HRSS_public_key pub; | |||
HRSS_private_key priv; | |||
HRSS_generate_key(&pub, &priv, generate_key_entropy); | |||
uint8_t encap_entropy[HRSS_ENCAP_BYTES]; | |||
for (unsigned i = 0; i < sizeof(encap_entropy); i++) { | |||
encap_entropy[i] = i; | |||
} | |||
uint8_t ciphertext[HRSS_CIPHERTEXT_BYTES]; | |||
uint8_t shared_key[HRSS_KEY_BYTES]; | |||
HRSS_encap(ciphertext, shared_key, &pub, encap_entropy); | |||
HRSS_public_key pub2; | |||
uint8_t pub_bytes[HRSS_PUBLIC_KEY_BYTES]; | |||
HRSS_marshal_public_key(pub_bytes, &pub); | |||
ASSERT_TRUE(HRSS_parse_public_key(&pub2, pub_bytes)); | |||
uint8_t shared_key2[HRSS_KEY_BYTES]; | |||
HRSS_decap(shared_key2, &pub2, &priv, ciphertext, sizeof(ciphertext)); | |||
EXPECT_EQ(Bytes(shared_key), Bytes(shared_key2)); | |||
} | |||
TEST(HRSS, Random) { | |||
for (unsigned i = 0; i < 10; i++) { | |||
uint8_t generate_key_entropy[HRSS_GENERATE_KEY_BYTES]; | |||
RAND_bytes(generate_key_entropy, sizeof(generate_key_entropy)); | |||
SCOPED_TRACE(Bytes(generate_key_entropy)); | |||
HRSS_public_key pub; | |||
HRSS_private_key priv; | |||
HRSS_generate_key(&pub, &priv, generate_key_entropy); | |||
for (unsigned j = 0; j < 10; j++) { | |||
uint8_t encap_entropy[HRSS_ENCAP_BYTES]; | |||
RAND_bytes(encap_entropy, sizeof(encap_entropy)); | |||
SCOPED_TRACE(Bytes(generate_key_entropy)); | |||
uint8_t ciphertext[HRSS_CIPHERTEXT_BYTES]; | |||
uint8_t shared_key[HRSS_KEY_BYTES]; | |||
HRSS_encap(ciphertext, shared_key, &pub, encap_entropy); | |||
uint8_t shared_key2[HRSS_KEY_BYTES]; | |||
HRSS_decap(shared_key2, &pub, &priv, ciphertext, sizeof(ciphertext)); | |||
EXPECT_EQ(Bytes(shared_key), Bytes(shared_key2)); | |||
} | |||
} | |||
} | |||
TEST(HRSS, Golden) { | |||
uint8_t generate_key_entropy[HRSS_GENERATE_KEY_BYTES]; | |||
for (unsigned i = 0; i < HRSS_SAMPLE_BYTES; i++) { | |||
generate_key_entropy[i] = i; | |||
} | |||
for (unsigned i = HRSS_SAMPLE_BYTES; i < 2 * HRSS_SAMPLE_BYTES; i++) { | |||
generate_key_entropy[i] = 2 + i; | |||
} | |||
for (unsigned i = 2 * HRSS_SAMPLE_BYTES; i < sizeof(generate_key_entropy); | |||
i++) { | |||
generate_key_entropy[i] = 4 + i; | |||
} | |||
HRSS_public_key pub; | |||
HRSS_private_key priv; | |||
OPENSSL_memset(&pub, 0, sizeof(pub)); | |||
OPENSSL_memset(&priv, 0, sizeof(priv)); | |||
HRSS_generate_key(&pub, &priv, generate_key_entropy); | |||
static const uint8_t kExpectedPub[HRSS_PUBLIC_KEY_BYTES] = { | |||
0xf8, 0x9f, 0xa0, 0xfc, 0xf1, 0xd4, 0xfa, 0x4d, 0x8f, 0x35, 0x28, 0x73, | |||
0x0e, 0x37, 0x18, 0x1d, 0x09, 0xf3, 0x9e, 0x16, 0x0d, 0x7f, 0x9c, 0x82, | |||
0x17, 0xa1, 0xa1, 0x88, 0x6b, 0x29, 0x5b, 0x3a, 0x30, 0xcd, 0x6f, 0x8e, | |||
0x0c, 0xd3, 0x38, 0x0c, 0x05, 0x68, 0x6e, 0x4c, 0xcc, 0x20, 0xd4, 0x06, | |||
0x77, 0x0c, 0xac, 0x1c, 0x49, 0x14, 0x00, 0xd6, 0x9b, 0x1c, 0xde, 0x43, | |||
0x0a, 0x59, 0x37, 0xd6, 0x46, 0x68, 0x1f, 0x04, 0xcb, 0x73, 0x92, 0x37, | |||
0x2d, 0x7f, 0x57, 0x70, 0x16, 0xe8, 0x06, 0x48, 0x3b, 0x66, 0xb3, 0x63, | |||
0x02, 0x5a, 0x71, 0x46, 0xdd, 0xa4, 0xee, 0xb8, 0x78, 0x44, 0xfd, 0x9e, | |||
0xd0, 0x71, 0x16, 0x00, 0xbd, 0x01, 0x1e, 0x27, 0x2e, 0xa0, 0xc6, 0x8d, | |||
0x55, 0x89, 0x7c, 0x2a, 0x01, 0x2b, 0x1b, 0x75, 0xa2, 0xc2, 0xd1, 0x5a, | |||
0x67, 0xfa, 0xdd, 0x3b, 0x70, 0x9d, 0xdb, 0xcd, 0x73, 0x32, 0x5e, 0x24, | |||
0xb1, 0xcf, 0x23, 0xbe, 0x3c, 0x56, 0xcc, 0xbe, 0x61, 0xdb, 0xe7, 0x3c, | |||
0xc7, 0xf5, 0x09, 0xe6, 0x87, 0xa0, 0x09, 0x52, 0x9d, 0x61, 0x5b, 0xc6, | |||
0xd4, 0xc5, 0x2e, 0xc2, 0x6c, 0x87, 0x30, 0x36, 0x49, 0x6f, 0x04, 0xaa, | |||
0xb3, 0x26, 0xd5, 0x63, 0xcf, 0xd4, 0x74, 0x1e, 0xc7, 0x79, 0xb3, 0xfc, | |||
0x8c, 0x41, 0x36, 0x79, 0xaa, 0xd5, 0xba, 0x64, 0x49, 0x48, 0xdb, 0xeb, | |||
0xe8, 0x33, 0x7d, 0xbe, 0x3b, 0x67, 0xd7, 0xfd, 0x93, 0x1e, 0x80, 0x8d, | |||
0x17, 0xab, 0x6f, 0xfd, 0x1c, 0x4b, 0x2d, 0x5b, 0x90, 0xf0, 0xf0, 0x5d, | |||
0xbe, 0x8f, 0x81, 0x18, 0x29, 0x08, 0x9a, 0x47, 0x1b, 0xc2, 0x2d, 0xa2, | |||
0x22, 0x5a, 0x4f, 0xe9, 0x81, 0x64, 0xdd, 0x53, 0x2e, 0x67, 0xe5, 0x07, | |||
0x1a, 0xf0, 0x0c, 0x54, 0x9b, 0xe2, 0xf8, 0xe6, 0xb3, 0xb6, 0xe0, 0x5a, | |||
0x74, 0xfa, 0x8d, 0x9c, 0xa5, 0x7c, 0x6e, 0x73, 0xba, 0xee, 0x6e, 0x6e, | |||
0x31, 0xcb, 0x59, 0xd7, 0xfd, 0x94, 0x1c, 0x4d, 0x62, 0xc6, 0x87, 0x0b, | |||
0x38, 0x54, 0xc6, 0x35, 0xac, 0xc8, 0x8c, 0xc0, 0xd9, 0x99, 0xee, 0xfc, | |||
0xa9, 0xde, 0xc4, 0x50, 0x88, 0x8e, 0x24, 0xf6, 0xd6, 0x04, 0x54, 0x3e, | |||
0x81, 0xc4, 0x96, 0x9a, 0x40, 0xe5, 0xef, 0x8b, 0xec, 0x41, 0x50, 0x1d, | |||
0x14, 0xae, 0xa4, 0x5a, 0xac, 0xd4, 0x73, 0x31, 0xc3, 0x1d, 0xc1, 0x96, | |||
0x89, 0xd8, 0x62, 0x97, 0x60, 0x3f, 0x58, 0x2a, 0x5f, 0xcf, 0xcb, 0x26, | |||
0x99, 0x69, 0x81, 0x13, 0x9c, 0xaf, 0x17, 0x91, 0xa8, 0xeb, 0x9a, 0xf9, | |||
0xd3, 0x83, 0x47, 0x66, 0xc7, 0xf8, 0xd8, 0xe3, 0xd2, 0x7e, 0x58, 0xa9, | |||
0xf5, 0xb2, 0x03, 0xbe, 0x7e, 0xa5, 0x29, 0x9d, 0xff, 0xd1, 0xd8, 0x55, | |||
0x39, 0xc7, 0x2c, 0xce, 0x03, 0x64, 0xdc, 0x18, 0xe7, 0xb0, 0x60, 0x46, | |||
0x26, 0xeb, 0xb7, 0x61, 0x4b, 0x91, 0x2c, 0xd8, 0xa2, 0xee, 0x63, 0x2e, | |||
0x15, 0x0a, 0x58, 0x88, 0x04, 0xb1, 0xed, 0x6d, 0xf1, 0x5c, 0xc7, 0xee, | |||
0x60, 0x38, 0x26, 0xc9, 0x31, 0x7e, 0x69, 0xe4, 0xac, 0x3c, 0x72, 0x09, | |||
0x3e, 0xe6, 0x24, 0x30, 0x44, 0x6e, 0x66, 0x83, 0xb9, 0x2a, 0x22, 0xaf, | |||
0x26, 0x1e, 0xaa, 0xa3, 0xf4, 0xb1, 0xa1, 0x5c, 0xfa, 0x5f, 0x0d, 0x71, | |||
0xac, 0xe3, 0xe0, 0xc3, 0xdd, 0x4f, 0x96, 0x57, 0x8b, 0x58, 0xac, 0xe3, | |||
0x42, 0x8e, 0x47, 0x72, 0xb1, 0xe4, 0x19, 0x68, 0x3e, 0xbb, 0x19, 0x14, | |||
0xdf, 0x16, 0xb5, 0xde, 0x7f, 0x37, 0xaf, 0xd8, 0xd3, 0x3d, 0x6a, 0x16, | |||
0x1b, 0x26, 0xd3, 0xcc, 0x53, 0x82, 0x57, 0x90, 0x89, 0xc5, 0x7e, 0x6d, | |||
0x7e, 0x99, 0x5b, 0xcd, 0xd3, 0x18, 0xbb, 0x89, 0xef, 0x76, 0xbd, 0xd2, | |||
0x62, 0xf0, 0xe8, 0x25, 0x2a, 0x8d, 0xe2, 0x21, 0xea, 0xde, 0x6e, 0xa5, | |||
0xa4, 0x3d, 0x58, 0xee, 0xdf, 0x90, 0xc1, 0xa1, 0x38, 0x5d, 0x11, 0x50, | |||
0xb5, 0xac, 0x9d, 0xb4, 0xfd, 0xef, 0x53, 0xe8, 0xc0, 0x17, 0x6c, 0x4f, | |||
0x31, 0xe0, 0xcc, 0x8f, 0x80, 0x7a, 0x84, 0x14, 0xde, 0xee, 0xec, 0xdd, | |||
0x6a, 0xad, 0x29, 0x65, 0xa5, 0x72, 0xc3, 0x73, 0x5f, 0xe3, 0x6f, 0x60, | |||
0xb1, 0xfb, 0x0f, 0xaa, 0xc6, 0xda, 0x53, 0x4a, 0xb1, 0x92, 0x2a, 0xb7, | |||
0x02, 0xbe, 0xf9, 0xdf, 0x37, 0x16, 0xe7, 0x5c, 0x38, 0x0b, 0x3c, 0xe2, | |||
0xdd, 0x90, 0xb8, 0x7b, 0x48, 0x69, 0x79, 0x81, 0xc5, 0xae, 0x9a, 0x0d, | |||
0x78, 0x95, 0x52, 0x63, 0x80, 0xda, 0x46, 0x69, 0x20, 0x57, 0x9b, 0x27, | |||
0xe2, 0xe8, 0xbd, 0x2f, 0x45, 0xe6, 0x46, 0x40, 0xae, 0x50, 0xd5, 0xa2, | |||
0x53, 0x93, 0xe1, 0x99, 0xfd, 0x13, 0x7c, 0xf6, 0x22, 0xc4, 0x6c, 0xab, | |||
0xe3, 0xc9, 0x55, 0x0a, 0x16, 0x67, 0x68, 0x26, 0x6b, 0xd6, 0x7d, 0xde, | |||
0xd3, 0xae, 0x71, 0x32, 0x02, 0xf1, 0x27, 0x67, 0x47, 0x74, 0xd9, 0x40, | |||
0x35, 0x1d, 0x25, 0x72, 0x32, 0xdf, 0x75, 0xd5, 0x60, 0x26, 0xab, 0x90, | |||
0xfa, 0xeb, 0x26, 0x11, 0x4b, 0xb4, 0xc5, 0xc2, 0x3e, 0xa9, 0x23, 0x3a, | |||
0x4e, 0x6a, 0xb1, 0xbb, 0xb3, 0xea, 0xf9, 0x1e, 0xe4, 0x10, 0xf5, 0xdc, | |||
0x35, 0xde, 0xb5, 0xee, 0xf0, 0xde, 0xa1, 0x18, 0x80, 0xc7, 0x13, 0x68, | |||
0x46, 0x94, 0x0e, 0x2a, 0x8e, 0xf8, 0xe9, 0x26, 0x84, 0x42, 0x0f, 0x56, | |||
0xed, 0x67, 0x7f, 0xeb, 0x7d, 0x35, 0x07, 0x01, 0x11, 0x81, 0x8b, 0x56, | |||
0x88, 0xc6, 0x58, 0x61, 0x65, 0x3c, 0x5d, 0x9c, 0x58, 0x25, 0xd6, 0xdf, | |||
0x4e, 0x3b, 0x93, 0xbf, 0x82, 0xe1, 0x19, 0xb8, 0xda, 0xde, 0x26, 0x38, | |||
0xf2, 0xd9, 0x95, 0x24, 0x98, 0xde, 0x58, 0xf7, 0x0c, 0xe9, 0x32, 0xbb, | |||
0xcc, 0xf7, 0x92, 0x69, 0xa2, 0xf0, 0xc3, 0xfa, 0xd2, 0x31, 0x8b, 0x43, | |||
0x4e, 0x03, 0xe2, 0x13, 0x79, 0x6e, 0x73, 0x63, 0x3b, 0x45, 0xde, 0x80, | |||
0xf4, 0x26, 0xb1, 0x38, 0xed, 0x62, 0x55, 0xc6, 0x6a, 0x67, 0x00, 0x2d, | |||
0xba, 0xb2, 0xc5, 0xb6, 0x97, 0x62, 0x28, 0x64, 0x30, 0xb9, 0xfb, 0x3f, | |||
0x94, 0x03, 0x48, 0x36, 0x2c, 0x5d, 0xfd, 0x08, 0x96, 0x40, 0xd1, 0x6c, | |||
0xe5, 0xd0, 0xf8, 0x99, 0x40, 0x82, 0x87, 0xd7, 0xdc, 0x2f, 0x8b, 0xaa, | |||
0x31, 0x96, 0x0a, 0x34, 0x33, 0xa6, 0xf1, 0x84, 0x6e, 0x33, 0x73, 0xc5, | |||
0xe3, 0x26, 0xad, 0xd0, 0xcb, 0x62, 0x71, 0x82, 0xab, 0xd1, 0x82, 0x33, | |||
0xe6, 0xca, 0xd0, 0x3e, 0xf5, 0x4d, 0x12, 0x6e, 0xf1, 0x83, 0xbd, 0xdc, | |||
0x4d, 0xdf, 0x49, 0xbc, 0x63, 0xae, 0x7e, 0x59, 0xe8, 0x3c, 0x0d, 0xd6, | |||
0x1d, 0x41, 0x89, 0x72, 0x52, 0xc0, 0xae, 0xd1, 0x2f, 0x0a, 0x8a, 0xce, | |||
0x26, 0xd0, 0x3e, 0x0c, 0x71, 0x32, 0x52, 0xb2, 0xe4, 0xee, 0xa2, 0xe5, | |||
0x28, 0xb6, 0x33, 0x69, 0x97, 0x5a, 0x53, 0xdb, 0x56, 0x63, 0xe9, 0xb3, | |||
0x6d, 0x60, 0xf4, 0x7a, 0xce, 0xec, 0x36, 0x65, 0xd5, 0xca, 0x63, 0x2a, | |||
0x19, 0x90, 0x14, 0x7b, 0x02, 0x33, 0xfa, 0x11, 0x58, 0x5a, 0xd9, 0xc5, | |||
0x54, 0xf3, 0x28, 0xd5, 0x6e, 0xea, 0x85, 0xf5, 0x09, 0xbb, 0x81, 0x44, | |||
0x1c, 0x63, 0x66, 0x81, 0xc5, 0x96, 0x2d, 0x7c, 0x0e, 0x75, 0x7b, 0xb4, | |||
0x7e, 0x4e, 0x0c, 0xfd, 0x3c, 0xc5, 0x5a, 0x22, 0x85, 0x5c, 0xc8, 0xf3, | |||
0x97, 0x98, 0x2c, 0xe9, 0x46, 0xb4, 0x02, 0xcf, 0x7d, 0xa4, 0xf2, 0x44, | |||
0x7a, 0x89, 0x71, 0xa0, 0xfa, 0xb6, 0xa3, 0xaf, 0x13, 0x25, 0x46, 0xe2, | |||
0x64, 0xe3, 0x69, 0xba, 0xf9, 0x68, 0x5c, 0xc0, 0xb7, 0xa8, 0xa6, 0x4b, | |||
0xe1, 0x42, 0xe9, 0xb5, 0xc7, 0x84, 0xbb, 0xa6, 0x4b, 0x10, 0x4e, 0xd4, | |||
0x68, 0x70, 0x0a, 0x75, 0x2a, 0xbb, 0x9d, 0xa0, 0xcb, 0xf0, 0x36, 0x4c, | |||
0x70, 0x6c, 0x60, 0x4d, 0xfe, 0xe8, 0xc8, 0x66, 0x80, 0x1b, 0xf7, 0xcc, | |||
0x1a, 0xdd, 0x6b, 0xa7, 0xa7, 0x25, 0x61, 0x0c, 0x31, 0xf0, 0x34, 0x63, | |||
0x00, 0x0e, 0x48, 0x6a, 0x5a, 0x8d, 0x47, 0x94, 0x3f, 0x14, 0x16, 0xa8, | |||
0x8a, 0x49, 0xbb, 0x0c, 0x43, 0x21, 0xda, 0xf2, 0xc5, 0xd0, 0xff, 0x19, | |||
0x3e, 0x36, 0x64, 0x20, 0xb3, 0x70, 0xae, 0x54, 0xca, 0x73, 0x05, 0x56, | |||
0x7a, 0x49, 0x45, 0xe9, 0x46, 0xbc, 0xc2, 0x61, 0x70, 0x40, 0x7c, 0xb0, | |||
0xf7, 0xea, 0xc0, 0xd1, 0xb0, 0x77, 0x2c, 0xc7, 0xdd, 0x88, 0xcb, 0x9d, | |||
0xea, 0x55, 0x6c, 0x5c, 0x28, 0xb8, 0x84, 0x1c, 0x2c, 0x06, | |||
}; | |||
uint8_t pub_bytes[HRSS_PUBLIC_KEY_BYTES]; | |||
HRSS_marshal_public_key(pub_bytes, &pub); | |||
EXPECT_EQ(Bytes(pub_bytes), Bytes(kExpectedPub)); | |||
uint8_t ciphertext[HRSS_CIPHERTEXT_BYTES]; | |||
uint8_t shared_key[HRSS_KEY_BYTES]; | |||
OPENSSL_STATIC_ASSERT( | |||
sizeof(kExpectedPub) >= HRSS_ENCAP_BYTES, | |||
"Private key too small to use as input to HRSS encapsulation"); | |||
HRSS_encap(ciphertext, shared_key, &pub, kExpectedPub); | |||
static const uint8_t kExpectedCiphertext[HRSS_CIPHERTEXT_BYTES] = { | |||
0x8e, 0x6b, 0x46, 0x9d, 0x4a, 0xef, 0xa6, 0x8c, 0x28, 0x7b, 0xec, 0x6f, | |||
0x13, 0x2d, 0x7f, 0x6c, 0xca, 0x7d, 0x9e, 0x6b, 0x54, 0x62, 0xa3, 0x13, | |||
0xe1, 0x1e, 0x8f, 0x5f, 0x71, 0x67, 0xc4, 0x85, 0xdf, 0xd5, 0x6b, 0xbd, | |||
0x86, 0x0f, 0x98, 0xec, 0xa5, 0x04, 0xf7, 0x7b, 0x2a, 0xbe, 0xcb, 0xac, | |||
0x29, 0xbe, 0xe1, 0x0f, 0xbc, 0x62, 0x87, 0x85, 0x7f, 0x05, 0xae, 0xe4, | |||
0x3f, 0x87, 0xfc, 0x1f, 0xf7, 0x45, 0x1e, 0xa3, 0xdb, 0xb1, 0xa0, 0x25, | |||
0xba, 0x82, 0xec, 0xca, 0x8d, 0xab, 0x7a, 0x20, 0x03, 0xeb, 0xe5, 0x5c, | |||
0x9f, 0xd0, 0x46, 0x78, 0xf1, 0x5a, 0xc7, 0x9e, 0xb4, 0x10, 0x6d, 0x37, | |||
0xc0, 0x75, 0x08, 0xfb, 0xeb, 0xcb, 0xd8, 0x35, 0x21, 0x9b, 0x89, 0xa0, | |||
0xaa, 0x87, 0x00, 0x66, 0x38, 0x37, 0x68, 0xa4, 0xa3, 0x93, 0x8e, 0x2b, | |||
0xca, 0xf7, 0x7a, 0x43, 0xb2, 0x15, 0x79, 0x81, 0xce, 0xa9, 0x09, 0xcb, | |||
0x29, 0xd4, 0xcc, 0xef, 0xf1, 0x9b, 0xbd, 0xe6, 0x63, 0xd5, 0x26, 0x0f, | |||
0xe8, 0x8b, 0xdf, 0xf1, 0xc3, 0xb4, 0x18, 0x0e, 0xf2, 0x1d, 0x5d, 0x82, | |||
0x9b, 0x1f, 0xf3, 0xca, 0x36, 0x2a, 0x26, 0x0a, 0x7f, 0xc4, 0x0d, 0xbd, | |||
0x5b, 0x15, 0x1c, 0x18, 0x6c, 0x11, 0x4e, 0xec, 0x36, 0x01, 0xc1, 0x15, | |||
0xab, 0xf7, 0x0b, 0x1a, 0xd3, 0xa1, 0xbd, 0x68, 0xc8, 0x59, 0xe7, 0x49, | |||
0x5c, 0xd5, 0x4b, 0x8c, 0x31, 0xdb, 0xb3, 0xea, 0x88, 0x09, 0x2f, 0xb9, | |||
0x8b, 0xfd, 0x96, 0x35, 0x88, 0x53, 0x72, 0x40, 0xcd, 0x89, 0x75, 0xb4, | |||
0x20, 0xf6, 0xf6, 0xe5, 0x74, 0x19, 0x48, 0xaf, 0x4b, 0xaa, 0x42, 0xa4, | |||
0xc8, 0x90, 0xee, 0xf3, 0x12, 0x04, 0x63, 0x90, 0x92, 0x8a, 0x89, 0xc3, | |||
0xa0, 0x7e, 0xfe, 0x19, 0xb3, 0x54, 0x53, 0x83, 0xe9, 0xc1, 0x6c, 0xe3, | |||
0x97, 0xa6, 0x27, 0xc3, 0x20, 0x9a, 0x79, 0x35, 0xc9, 0xb5, 0xc0, 0x90, | |||
0xe1, 0x56, 0x84, 0x69, 0xc2, 0x54, 0x77, 0x52, 0x48, 0x55, 0x71, 0x3e, | |||
0xcd, 0xa7, 0xd6, 0x25, 0x5d, 0x49, 0x13, 0xd2, 0x59, 0xd7, 0xe1, 0xd1, | |||
0x70, 0x46, 0xa0, 0xd4, 0xee, 0x59, 0x13, 0x1f, 0x1a, 0xd3, 0x39, 0x7d, | |||
0xb0, 0x79, 0xf7, 0xc0, 0x73, 0x5e, 0xbb, 0x08, 0xf7, 0x5c, 0xb0, 0x31, | |||
0x41, 0x3d, 0x7b, 0x1e, 0xf0, 0xe6, 0x47, 0x5c, 0x37, 0xd5, 0x54, 0xf1, | |||
0xbb, 0x64, 0xd7, 0x41, 0x8b, 0x34, 0x55, 0xaa, 0xc3, 0x5a, 0x9c, 0xa0, | |||
0xcc, 0x29, 0x8e, 0x5a, 0x1a, 0x93, 0x5a, 0x49, 0xd3, 0xd0, 0xa0, 0x56, | |||
0xda, 0x32, 0xa2, 0xa9, 0xa7, 0x13, 0x42, 0x93, 0x9b, 0x20, 0x32, 0x37, | |||
0x5c, 0x3e, 0x03, 0xa5, 0x28, 0x10, 0x93, 0xdd, 0xa0, 0x04, 0x7b, 0x2a, | |||
0xbd, 0x31, 0xc3, 0x6a, 0x89, 0x58, 0x6e, 0x55, 0x0e, 0xc9, 0x5c, 0x70, | |||
0x07, 0x10, 0xf1, 0x9a, 0xbd, 0xfb, 0xd2, 0xb7, 0x94, 0x5b, 0x4f, 0x8d, | |||
0x90, 0xfa, 0xee, 0xae, 0x37, 0x48, 0xc5, 0xf8, 0x16, 0xa1, 0x3b, 0x70, | |||
0x03, 0x1f, 0x0e, 0xb8, 0xbd, 0x8d, 0x30, 0x4f, 0x95, 0x31, 0x0b, 0x9f, | |||
0xfc, 0x80, 0xf8, 0xef, 0xa3, 0x3c, 0xbc, 0xe2, 0x23, 0x23, 0x3e, 0x2a, | |||
0x55, 0x11, 0xe8, 0x2c, 0x17, 0xea, 0x1c, 0xbd, 0x1d, 0x2d, 0x1b, 0xd5, | |||
0x16, 0x9e, 0x05, 0xfc, 0x89, 0x64, 0x50, 0x4d, 0x9a, 0x22, 0x50, 0xc6, | |||
0x5a, 0xd9, 0x58, 0x99, 0x8f, 0xbd, 0xf2, 0x4f, 0x2c, 0xdb, 0x51, 0x6a, | |||
0x86, 0xe2, 0xc6, 0x64, 0x8f, 0x54, 0x1a, 0xf2, 0xcb, 0x34, 0x88, 0x08, | |||
0xbd, 0x2a, 0x8f, 0xec, 0x29, 0xf5, 0x22, 0x36, 0x83, 0x99, 0xb9, 0x71, | |||
0x8c, 0x99, 0x5c, 0xec, 0x91, 0x78, 0xc1, 0xe2, 0x2d, 0xe9, 0xd1, 0x4d, | |||
0xf5, 0x15, 0x93, 0x4d, 0x93, 0x92, 0x9f, 0x0f, 0x33, 0x5e, 0xcd, 0x58, | |||
0x5f, 0x3d, 0x52, 0xb9, 0x38, 0x6a, 0x85, 0x63, 0x8b, 0x63, 0x29, 0xcb, | |||
0x67, 0x12, 0x25, 0xc2, 0x44, 0xd7, 0xab, 0x1a, 0x24, 0xca, 0x3d, 0xca, | |||
0x77, 0xce, 0x28, 0x68, 0x1a, 0x91, 0xed, 0x7b, 0xc9, 0x70, 0x84, 0xab, | |||
0xe2, 0xd4, 0xf4, 0xac, 0x58, 0xf6, 0x70, 0x99, 0xfc, 0x99, 0x4d, 0xbd, | |||
0xb4, 0x1b, 0x4f, 0x15, 0x86, 0x95, 0x08, 0xd1, 0x4e, 0x73, 0xa9, 0xbc, | |||
0x6a, 0x8c, 0xbc, 0xb5, 0x4b, 0xe0, 0xee, 0x35, 0x24, 0xf9, 0x12, 0xf5, | |||
0x88, 0x70, 0x50, 0x6c, 0xfe, 0x0d, 0x35, 0xbd, 0xf7, 0xc4, 0x2e, 0x39, | |||
0x16, 0x30, 0x6c, 0xf3, 0xb2, 0x19, 0x44, 0xaa, 0xcb, 0x4a, 0xf6, 0x75, | |||
0xb7, 0x09, 0xb9, 0xe1, 0x47, 0x71, 0x70, 0x5c, 0x05, 0x5f, 0x50, 0x50, | |||
0x9c, 0xd0, 0xe3, 0xc7, 0x91, 0xee, 0x6b, 0xc7, 0x0f, 0x71, 0x1b, 0xc3, | |||
0x48, 0x8b, 0xed, 0x15, 0x26, 0x8c, 0xc3, 0xd5, 0x54, 0x08, 0xcc, 0x33, | |||
0x79, 0xc0, 0x9f, 0x49, 0xc8, 0x75, 0xef, 0xb6, 0xf3, 0x29, 0x89, 0xfd, | |||
0x75, 0xd1, 0xda, 0x92, 0xc3, 0x13, 0xc6, 0x76, 0x51, 0x11, 0x40, 0x7b, | |||
0x82, 0xf7, 0x30, 0x79, 0x49, 0x04, 0xe3, 0xbb, 0x61, 0x34, 0xa6, 0x58, | |||
0x0b, 0x7d, 0xef, 0x3e, 0xf9, 0xb3, 0x8d, 0x2a, 0xba, 0xe9, 0xbc, 0xc0, | |||
0xa7, 0xe6, 0x6c, 0xda, 0xf8, 0x8c, 0xdf, 0x8d, 0x96, 0x83, 0x2d, 0x80, | |||
0x4f, 0x21, 0x81, 0xde, 0x57, 0x9d, 0x0a, 0x3c, 0xcc, 0xec, 0x3b, 0xb2, | |||
0x25, 0x96, 0x3c, 0xea, 0xfd, 0x46, 0x26, 0xbe, 0x1c, 0x79, 0x82, 0x1d, | |||
0xe0, 0x14, 0x22, 0x7c, 0x80, 0x3d, 0xbd, 0x05, 0x90, 0xfa, 0xaf, 0x7d, | |||
0x70, 0x13, 0x43, 0x0f, 0x3d, 0xa0, 0x7f, 0x92, 0x3a, 0x53, 0x69, 0xe4, | |||
0xb0, 0x10, 0x0d, 0xa7, 0x73, 0xa8, 0x8c, 0x74, 0xab, 0xd7, 0x78, 0x15, | |||
0x45, 0xec, 0x6e, 0xc8, 0x8b, 0xa0, 0xba, 0x21, 0x6f, 0xf3, 0x08, 0xb8, | |||
0xc7, 0x4f, 0x14, 0xf5, 0xcc, 0xfd, 0x39, 0xbc, 0x11, 0xf5, 0xb9, 0x11, | |||
0xba, 0xf3, 0x11, 0x24, 0x74, 0x3e, 0x0c, 0x07, 0x4f, 0xac, 0x2a, 0xb2, | |||
0xb1, 0x3c, 0x00, 0xfa, 0xbb, 0x8c, 0xd8, 0x7d, 0x17, 0x5b, 0x8d, 0x39, | |||
0xc6, 0x23, 0x31, 0x32, 0x7d, 0x6e, 0x20, 0x38, 0xd0, 0xc3, 0x58, 0xe2, | |||
0xb1, 0xfe, 0x53, 0x6b, 0xc7, 0x10, 0x13, 0x7e, 0xc6, 0x7c, 0x67, 0x59, | |||
0x43, 0x70, 0x4a, 0x2d, 0x7f, 0x76, 0xde, 0xbd, 0x45, 0x43, 0x56, 0x60, | |||
0xcd, 0xe9, 0x24, 0x7b, 0xb7, 0x41, 0xce, 0x56, 0xed, 0xd3, 0x74, 0x75, | |||
0xcc, 0x9d, 0x48, 0x61, 0xc8, 0x19, 0x66, 0x08, 0xfb, 0x28, 0x60, 0x1f, | |||
0x83, 0x11, 0xc0, 0x9b, 0xbd, 0x71, 0x53, 0x36, 0x01, 0x76, 0xa8, 0xc0, | |||
0xdc, 0x1d, 0x18, 0x85, 0x19, 0x65, 0xce, 0xcf, 0x14, 0x2e, 0x6c, 0x32, | |||
0x15, 0xbc, 0x2c, 0x5e, 0x8f, 0xfc, 0x3c, 0xf0, 0x2d, 0xf5, 0x5c, 0x04, | |||
0xc9, 0x22, 0xf4, 0xc3, 0xb8, 0x57, 0x79, 0x52, 0x41, 0xfd, 0xff, 0xcd, | |||
0x26, 0xa8, 0xc0, 0xd2, 0xe1, 0x71, 0xd6, 0xf1, 0xf4, 0x0c, 0xa8, 0xeb, | |||
0x0c, 0x33, 0x40, 0x25, 0x73, 0xbb, 0x31, 0xda, 0x0c, 0xa6, 0xee, 0x0c, | |||
0x41, 0x51, 0x94, 0x3c, 0x24, 0x27, 0x65, 0xe9, 0xb5, 0xc4, 0xe2, 0x88, | |||
0xc0, 0x82, 0xd0, 0x72, 0xd9, 0x10, 0x4d, 0x7f, 0xc0, 0x88, 0x94, 0x41, | |||
0x2d, 0x05, 0x09, 0xfb, 0x97, 0x31, 0x6e, 0xc1, 0xe9, 0xf4, 0x50, 0x70, | |||
0xdc, 0x3f, 0x0a, 0x90, 0x46, 0x37, 0x60, 0x8c, 0xfb, 0x06, 0x6e, 0xde, | |||
0x6f, 0xa7, 0x6b, 0xa3, 0x88, 0x18, 0x96, 0x93, 0x19, 0x87, 0xe7, 0x0a, | |||
0x98, 0xf0, 0x13, 0x01, 0xab, 0x7c, 0xeb, 0x25, 0xa5, 0xe2, 0x98, 0x44, | |||
0x7d, 0x09, 0xe2, 0x42, 0x33, 0xd4, 0xeb, 0xcc, 0x9b, 0x70, 0xf6, 0x0f, | |||
0xf0, 0xb2, 0x99, 0xcc, 0x4f, 0x64, 0xc4, 0x69, 0x12, 0xea, 0x56, 0xfe, | |||
0x50, 0x0e, 0x02, 0x1f, 0x6d, 0x7a, 0x79, 0x62, 0xaa, 0x2e, 0x52, 0xaf, | |||
0xa3, 0xed, 0xcd, 0xa7, 0x45, 0xe6, 0x86, 0xed, 0xa1, 0x73, 0x5b, 0x1e, | |||
0x49, 0x4f, 0x92, 0x50, 0x83, 0x99, 0x3c, 0xf4, 0xf6, 0xa8, 0x49, 0xd7, | |||
0x08, 0xf7, 0xdc, 0x28, 0x2c, 0xe6, 0x22, 0x6f, 0xf8, 0xfa, 0xba, 0x9e, | |||
0x0a, 0xcf, 0x72, 0x74, 0x76, 0x75, 0x99, 0x4d, 0x3d, 0x9a, 0x4c, 0x54, | |||
0xcd, 0xf8, 0x54, 0xf0, 0xbd, 0x73, 0xe9, 0x4f, 0x29, 0xd0, 0xe1, 0x24, | |||
0x94, 0x52, 0xd6, 0x60, 0x80, 0x71, 0x24, 0x95, 0x92, 0x01, 0x0e, 0xa9, | |||
0x7e, 0x64, 0x2e, 0xed, 0x51, 0xcc, 0xd2, 0xff, 0xfd, 0x0b, 0xf4, 0x1d, | |||
0x25, 0x5d, 0x10, 0x87, 0x09, 0x55, 0x06, 0x95, 0xae, 0xb3, 0xef, 0xe9, | |||
0xaa, 0x36, 0x15, 0x97, 0xe6, 0xf2, 0x24, 0xcf, 0x7d, 0xcd, 0x55, 0x11, | |||
0xba, 0x20, 0xd0, 0xd7, 0xdc, 0xa6, | |||
}; | |||
EXPECT_EQ(Bytes(ciphertext), Bytes(kExpectedCiphertext)); | |||
static const uint8_t kExpectedSharedKey[HRSS_KEY_BYTES] = { | |||
0x04, 0x5a, 0x1a, 0xbc, 0x4c, 0x76, 0x47, 0x1f, 0xbf, 0xc9, 0x23, | |||
0xec, 0xcb, 0x6e, 0x4d, 0x59, 0x8d, 0x3f, 0x90, 0x3e, 0x53, 0x73, | |||
0x3c, 0x2c, 0x71, 0xcc, 0xac, 0xc5, 0xe0, 0xf2, 0xbc, 0xe8, | |||
}; | |||
EXPECT_EQ(Bytes(shared_key), Bytes(kExpectedSharedKey)); | |||
HRSS_decap(shared_key, &pub, &priv, ciphertext, sizeof(ciphertext)); | |||
EXPECT_EQ(Bytes(shared_key, sizeof(shared_key)), | |||
Bytes(kExpectedSharedKey, sizeof(kExpectedSharedKey))); | |||
// Corrupt the ciphertext and ensure that the failure key is constant. | |||
ciphertext[50] ^= 4; | |||
HRSS_decap(shared_key, &pub, &priv, ciphertext, sizeof(ciphertext)); | |||
static const uint8_t kExpectedFailureKey[HRSS_KEY_BYTES] = { | |||
0x3a, 0xec, 0xc0, 0x38, 0x4f, 0xa7, 0x17, 0xb2, 0x77, 0x61, 0xb1, | |||
0xf8, 0x12, 0x7f, 0xd9, 0x61, 0x67, 0x70, 0x63, 0xbe, 0xa2, 0x72, | |||
0xfe, 0x1a, 0x82, 0x8d, 0x1d, 0x90, 0xe0, 0x36, 0x69, 0x2d, | |||
}; | |||
EXPECT_EQ(Bytes(shared_key), Bytes(kExpectedFailureKey)); | |||
} |
@@ -0,0 +1,50 @@ | |||
/* 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_HRSS_INTERNAL_H | |||
#define OPENSSL_HEADER_HRSS_INTERNAL_H | |||
#include <openssl/base.h> | |||
#include "../internal.h" | |||
#if defined(__cplusplus) | |||
extern "C" { | |||
#endif | |||
#define N 701 | |||
#define BITS_PER_WORD (sizeof(crypto_word_t) * 8) | |||
#define WORDS_PER_POLY ((N + BITS_PER_WORD - 1) / BITS_PER_WORD) | |||
#define BITS_IN_LAST_WORD (N % BITS_PER_WORD) | |||
struct poly2 { | |||
crypto_word_t v[WORDS_PER_POLY]; | |||
}; | |||
struct poly3 { | |||
struct poly2 s, a; | |||
}; | |||
OPENSSL_EXPORT void HRSS_poly2_rotr_consttime(struct poly2 *p, size_t bits); | |||
OPENSSL_EXPORT void HRSS_poly3_mul(struct poly3 *out, const struct poly3 *x, | |||
const struct poly3 *y); | |||
OPENSSL_EXPORT void HRSS_poly3_invert(struct poly3 *out, | |||
const struct poly3 *in); | |||
#if defined(__cplusplus) | |||
} // extern "C" | |||
#endif | |||
#endif // !OPENSSL_HEADER_HRSS_INTERNAL_H |
@@ -57,7 +57,7 @@ | |||
/* This file is generated by crypto/obj/objects.go. */ | |||
#define NUM_NID 959 | |||
#define NUM_NID 960 | |||
static const uint8_t kObjectData[] = { | |||
/* NID_rsadsi */ | |||
@@ -8755,6 +8755,7 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { | |||
{"AuthPSK", "auth-psk", NID_auth_psk, 0, NULL, 0}, | |||
{"KxANY", "kx-any", NID_kx_any, 0, NULL, 0}, | |||
{"AuthANY", "auth-any", NID_auth_any, 0, NULL, 0}, | |||
{"CECPQ2", "CECPQ2", NID_CECPQ2, 0, NULL, 0}, | |||
}; | |||
static const unsigned kNIDsInShortNameOrder[] = { | |||
@@ -8816,6 +8817,7 @@ static const unsigned kNIDsInShortNameOrder[] = { | |||
110 /* CAST5-CFB */, | |||
109 /* CAST5-ECB */, | |||
111 /* CAST5-OFB */, | |||
959 /* CECPQ2 */, | |||
894 /* CMAC */, | |||
13 /* CN */, | |||
141 /* CRLReason */, | |||
@@ -9720,6 +9722,7 @@ static const unsigned kNIDsInLongNameOrder[] = { | |||
285 /* Biometric Info */, | |||
179 /* CA Issuers */, | |||
785 /* CA Repository */, | |||
959 /* CECPQ2 */, | |||
131 /* Code Signing */, | |||
783 /* Diffie-Hellman based MAC */, | |||
382 /* Directory */, | |||
@@ -947,3 +947,4 @@ auth_ecdsa 955 | |||
auth_psk 956 | |||
kx_any 957 | |||
auth_any 958 | |||
CECPQ2 959 |
@@ -559,7 +559,7 @@ id-cmc 19 : id-cmc-responseInfo | |||
id-cmc 21 : id-cmc-queryPending | |||
id-cmc 22 : id-cmc-popLinkRandom | |||
id-cmc 23 : id-cmc-popLinkWitness | |||
id-cmc 24 : id-cmc-confirmCertAcceptance | |||
id-cmc 24 : id-cmc-confirmCertAcceptance | |||
# other names | |||
id-on 1 : id-on-personalData | |||
@@ -1239,7 +1239,7 @@ cryptocom 1 8 1 : id-GostR3410-2001-ParamSet-cc : GOST R 3410-2001 Parameter Se | |||
# Definitions for Camellia cipher - ECB, CFB, OFB MODE | |||
!Alias ntt-ds 0 3 4401 5 | |||
!Alias camellia ntt-ds 3 1 9 | |||
!Alias camellia ntt-ds 3 1 9 | |||
camellia 1 : CAMELLIA-128-ECB : camellia-128-ecb | |||
!Cname camellia-128-ofb128 | |||
@@ -1310,7 +1310,7 @@ ISO-US 10046 2 1 : dhpublicnumber : X9.42 DH | |||
1 3 36 3 3 2 8 1 1 11 : brainpoolP384r1 | |||
1 3 36 3 3 2 8 1 1 12 : brainpoolP384t1 | |||
1 3 36 3 3 2 8 1 1 13 : brainpoolP512r1 | |||
1 3 36 3 3 2 8 1 1 14 : brainpoolP512t1 | |||
1 3 36 3 3 2 8 1 1 14 : brainpoolP512t1 | |||
# ECDH schemes from RFC5753 | |||
!Alias x9-63-scheme 1 3 133 16 840 63 0 | |||
@@ -1334,6 +1334,9 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme | |||
# NID for X25519 (no corresponding OID). | |||
: X25519 | |||
# NID for CECPQ2 (no corresponding OID). | |||
: CECPQ2 | |||
# See RFC 8410. | |||
1 3 101 112 : ED25519 | |||
@@ -0,0 +1,102 @@ | |||
/* 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_HRSS_H | |||
#define OPENSSL_HEADER_HRSS_H | |||
#include <openssl/base.h> | |||
#if defined(__cplusplus) | |||
extern "C" { | |||
#endif | |||
// HRSS | |||
// | |||
// HRSS is a structured-lattice-based post-quantum key encapsulation mechanism. | |||
// The best exposition is https://eprint.iacr.org/2017/667.pdf although this | |||
// implementation uses a different KEM construction based on | |||
// https://eprint.iacr.org/2017/1005.pdf. | |||
struct HRSS_private_key { | |||
uint8_t opaque[1808]; | |||
}; | |||
struct HRSS_public_key { | |||
uint8_t opaque[1424]; | |||
}; | |||
// HRSS_SAMPLE_BYTES is the number of bytes of entropy needed to generate a | |||
// short vector. There are 701 coefficients, but the final one is always set to | |||
// zero when sampling. Otherwise, one byte of input is enough to generate two | |||
// coefficients. | |||
#define HRSS_SAMPLE_BYTES ((701 - 1) / 2) | |||
// HRSS_GENERATE_KEY_BYTES is the number of bytes of entropy needed to generate | |||
// an HRSS key pair. | |||
#define HRSS_GENERATE_KEY_BYTES (HRSS_SAMPLE_BYTES + HRSS_SAMPLE_BYTES + 32) | |||
// HRSS_ENCAP_BYTES is the number of bytes of entropy needed to encapsulate a | |||
// session key. | |||
#define HRSS_ENCAP_BYTES (HRSS_SAMPLE_BYTES + HRSS_SAMPLE_BYTES) | |||
// HRSS_PUBLIC_KEY_BYTES is the number of bytes in a public key. | |||
#define HRSS_PUBLIC_KEY_BYTES 1138 | |||
// HRSS_CIPHERTEXT_BYTES is the number of bytes in a ciphertext. | |||
#define HRSS_CIPHERTEXT_BYTES (1138 + 32) | |||
// HRSS_KEY_BYTES is the number of bytes in a shared key. | |||
#define HRSS_KEY_BYTES 32 | |||
// HRSS_POLY3_BYTES is the number of bytes needed to serialise a mod 3 | |||
// polynomial. | |||
#define HRSS_POLY3_BYTES 140 | |||
#define HRSS_PRIVATE_KEY_BYTES \ | |||
(HRSS_POLY3_BYTES * 2 + HRSS_PUBLIC_KEY_BYTES + 2 + 32) | |||
// HRSS_generate_key is a deterministic function that outputs a public and | |||
// private key based on the given entropy. | |||
OPENSSL_EXPORT void HRSS_generate_key( | |||
struct HRSS_public_key *out_pub, struct HRSS_private_key *out_priv, | |||
const uint8_t input[HRSS_GENERATE_KEY_BYTES]); | |||
// HRSS_encap is a deterministic function the generates and encrypts a random | |||
// session key from the given entropy, writing those values to |out_shared_key| | |||
// and |out_ciphertext|, respectively. | |||
OPENSSL_EXPORT void HRSS_encap(uint8_t out_ciphertext[HRSS_CIPHERTEXT_BYTES], | |||
uint8_t out_shared_key[HRSS_KEY_BYTES], | |||
const struct HRSS_public_key *in_pub, | |||
const uint8_t in[HRSS_ENCAP_BYTES]); | |||
// HRSS_decap decrypts a session key from |ciphertext_len| bytes of | |||
// |ciphertext|. If the ciphertext is valid, the decrypted key is written to | |||
// |out_shared_key|. Otherwise the HMAC of |ciphertext| under a secret key (kept | |||
// in |in_priv|) is written. If the ciphertext is the wrong length then it will | |||
// leak which was done via side-channels. Otherwise it should perform either | |||
// action in constant-time. | |||
OPENSSL_EXPORT void HRSS_decap(uint8_t out_shared_key[HRSS_KEY_BYTES], | |||
const struct HRSS_public_key *in_pub, | |||
const struct HRSS_private_key *in_priv, | |||
const uint8_t *ciphertext, | |||
size_t ciphertext_len); | |||
// HRSS_marshal_public_key serialises |in_pub| to |out|. | |||
OPENSSL_EXPORT void HRSS_marshal_public_key( | |||
uint8_t out[HRSS_PUBLIC_KEY_BYTES], const struct HRSS_public_key *in_pub); | |||
// HRSS_parse_public_key sets |*out| to the public-key encoded in |in|. It | |||
// returns true on success and zero on error. | |||
OPENSSL_EXPORT int HRSS_parse_public_key( | |||
struct HRSS_public_key *out, const uint8_t in[HRSS_PUBLIC_KEY_BYTES]); | |||
#if defined(__cplusplus) | |||
} // extern C | |||
#endif | |||
#endif // OPENSSL_HEADER_HRSS_H |
@@ -4234,6 +4234,9 @@ extern "C" { | |||
#define LN_auth_any "auth-any" | |||
#define NID_auth_any 958 | |||
#define SN_CECPQ2 "CECPQ2" | |||
#define NID_CECPQ2 959 | |||
#if defined(__cplusplus) | |||
} /* extern C */ | |||
@@ -2177,6 +2177,7 @@ OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves); | |||
#define SSL_CURVE_SECP384R1 24 | |||
#define SSL_CURVE_SECP521R1 25 | |||
#define SSL_CURVE_X25519 29 | |||
#define SSL_CURVE_CECPQ2 16696 | |||
// SSL_get_curve_id returns the ID of the curve used by |ssl|'s most recently | |||
// completed handshake or 0 if not applicable. | |||
@@ -307,7 +307,7 @@ bool SSL_serialize_handback(const SSL *ssl, CBB *out) { | |||
return false; | |||
} | |||
if (type == handback_after_ecdhe && | |||
!s3->hs->key_share->Serialize(&key_share)) { | |||
!s3->hs->key_shares[0]->Serialize(&key_share)) { | |||
return false; | |||
} | |||
return CBB_flush(out); | |||
@@ -471,7 +471,7 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) { | |||
return false; | |||
} | |||
if (type == handback_after_ecdhe && | |||
(s3->hs->key_share = SSLKeyShare::Create(&key_share)) == nullptr) { | |||
(s3->hs->key_shares[0] = SSLKeyShare::Create(&key_share)) == nullptr) { | |||
return false; | |||
} | |||
@@ -590,7 +590,8 @@ static enum ssl_hs_wait_t do_read_server_hello(SSL_HANDSHAKE *hs) { | |||
} | |||
// Clear some TLS 1.3 state that no longer needs to be retained. | |||
hs->key_share.reset(); | |||
hs->key_shares[0].reset(); | |||
hs->key_shares[1].reset(); | |||
hs->key_share_bytes.Reset(); | |||
// A TLS 1.2 server would not know to skip the early data we offered. Report | |||
@@ -1006,8 +1007,8 @@ static enum ssl_hs_wait_t do_read_server_key_exchange(SSL_HANDSHAKE *hs) { | |||
} | |||
// Initialize ECDH and save the peer public key for later. | |||
hs->key_share = SSLKeyShare::Create(group_id); | |||
if (!hs->key_share || | |||
hs->key_shares[0] = SSLKeyShare::Create(group_id); | |||
if (!hs->key_shares[0] || | |||
!hs->peer_key.CopyFrom(point)) { | |||
return ssl_hs_error; | |||
} | |||
@@ -1324,7 +1325,7 @@ static enum ssl_hs_wait_t do_send_client_key_exchange(SSL_HANDSHAKE *hs) { | |||
// Compute the premaster. | |||
uint8_t alert = SSL_AD_DECODE_ERROR; | |||
if (!hs->key_share->Accept(&child, &pms, &alert, hs->peer_key)) { | |||
if (!hs->key_shares[0]->Accept(&child, &pms, &alert, hs->peer_key)) { | |||
ssl_send_alert(ssl, SSL3_AL_FATAL, alert); | |||
return ssl_hs_error; | |||
} | |||
@@ -1333,7 +1334,8 @@ static enum ssl_hs_wait_t do_send_client_key_exchange(SSL_HANDSHAKE *hs) { | |||
} | |||
// The key exchange state may now be discarded. | |||
hs->key_share.reset(); | |||
hs->key_shares[0].reset(); | |||
hs->key_shares[1].reset(); | |||
hs->peer_key.Reset(); | |||
} else if (alg_k & SSL_kPSK) { | |||
// For plain PSK, other_secret is a block of 0s with the same length as | |||
@@ -932,12 +932,12 @@ static enum ssl_hs_wait_t do_send_server_certificate(SSL_HANDSHAKE *hs) { | |||
hs->new_session->group_id = group_id; | |||
// Set up ECDH, generate a key, and emit the public half. | |||
hs->key_share = SSLKeyShare::Create(group_id); | |||
if (!hs->key_share || | |||
hs->key_shares[0] = SSLKeyShare::Create(group_id); | |||
if (!hs->key_shares[0] || | |||
!CBB_add_u8(cbb.get(), NAMED_CURVE_TYPE) || | |||
!CBB_add_u16(cbb.get(), group_id) || | |||
!CBB_add_u8_length_prefixed(cbb.get(), &child) || | |||
!hs->key_share->Offer(&child)) { | |||
!hs->key_shares[0]->Offer(&child)) { | |||
return ssl_hs_error; | |||
} | |||
} else { | |||
@@ -1275,13 +1275,14 @@ static enum ssl_hs_wait_t do_read_client_key_exchange(SSL_HANDSHAKE *hs) { | |||
// Compute the premaster. | |||
uint8_t alert = SSL_AD_DECODE_ERROR; | |||
if (!hs->key_share->Finish(&premaster_secret, &alert, peer_key)) { | |||
if (!hs->key_shares[0]->Finish(&premaster_secret, &alert, peer_key)) { | |||
ssl_send_alert(ssl, SSL3_AL_FATAL, alert); | |||
return ssl_hs_error; | |||
} | |||
// The key exchange state may now be discarded. | |||
hs->key_share.reset(); | |||
hs->key_shares[0].reset(); | |||
hs->key_shares[1].reset(); | |||
} else if (!(alg_k & SSL_kPSK)) { | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | |||
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); | |||
@@ -974,10 +974,10 @@ class SSLKeyShare { | |||
// |out_public_key|. It returns true on success and false on error. | |||
virtual bool Offer(CBB *out_public_key) PURE_VIRTUAL; | |||
// Accept performs a key exchange against the |peer_key| generated by |offer|. | |||
// Accept performs a key exchange against the |peer_key| generated by |Offer|. | |||
// On success, it returns true, writes the public value to |out_public_key|, | |||
// and sets |*out_secret| the shared secret. On failure, it returns false and | |||
// sets |*out_alert| to an alert to send to the peer. | |||
// and sets |*out_secret| to the shared secret. On failure, it returns false | |||
// and sets |*out_alert| to an alert to send to the peer. | |||
// | |||
// The default implementation calls |Offer| and then |Finish|, assuming a key | |||
// exchange protocol where the peers are symmetric. | |||
@@ -986,7 +986,7 @@ class SSLKeyShare { | |||
// Finish performs a key exchange against the |peer_key| generated by | |||
// |Accept|. On success, it returns true and sets |*out_secret| to the shared | |||
// secret. On failure, it returns zero and sets |*out_alert| to an alert to | |||
// secret. On failure, it returns false and sets |*out_alert| to an alert to | |||
// send to the peer. | |||
virtual bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert, | |||
Span<const uint8_t> peer_key) PURE_VIRTUAL; | |||
@@ -1436,8 +1436,10 @@ struct SSL_HANDSHAKE { | |||
// error, if |wait| is |ssl_hs_error|, is the error the handshake failed on. | |||
UniquePtr<ERR_SAVE_STATE> error; | |||
// key_share is the current key exchange instance. | |||
UniquePtr<SSLKeyShare> key_share; | |||
// key_shares are the current key exchange instances. The second is only used | |||
// as a client if we believe that we should offer two key shares in a | |||
// ClientHello. | |||
UniquePtr<SSLKeyShare> key_shares[2]; | |||
// transcript is the current handshake transcript. | |||
SSLTranscript transcript; | |||
@@ -24,8 +24,10 @@ | |||
#include <openssl/curve25519.h> | |||
#include <openssl/ec.h> | |||
#include <openssl/err.h> | |||
#include <openssl/hrss.h> | |||
#include <openssl/mem.h> | |||
#include <openssl/nid.h> | |||
#include <openssl/rand.h> | |||
#include "internal.h" | |||
#include "../crypto/internal.h" | |||
@@ -207,12 +209,104 @@ class X25519KeyShare : public SSLKeyShare { | |||
uint8_t private_key_[32]; | |||
}; | |||
class CECPQ2KeyShare : public SSLKeyShare { | |||
public: | |||
CECPQ2KeyShare() {} | |||
uint16_t GroupID() const override { return SSL_CURVE_CECPQ2; } | |||
bool Offer(CBB *out) override { | |||
uint8_t x25519_public_key[32]; | |||
X25519_keypair(x25519_public_key, x25519_private_key_); | |||
uint8_t hrss_entropy[HRSS_GENERATE_KEY_BYTES]; | |||
RAND_bytes(hrss_entropy, sizeof(hrss_entropy)); | |||
HRSS_generate_key(&hrss_public_key_, &hrss_private_key_, hrss_entropy); | |||
uint8_t hrss_public_key_bytes[HRSS_PUBLIC_KEY_BYTES]; | |||
HRSS_marshal_public_key(hrss_public_key_bytes, &hrss_public_key_); | |||
if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) || | |||
!CBB_add_bytes(out, hrss_public_key_bytes, | |||
sizeof(hrss_public_key_bytes))) { | |||
return false; | |||
} | |||
return true; | |||
}; | |||
bool Accept(CBB *out_public_key, Array<uint8_t> *out_secret, | |||
uint8_t *out_alert, Span<const uint8_t> peer_key) override { | |||
Array<uint8_t> secret; | |||
if (!secret.Init(32 + HRSS_KEY_BYTES)) { | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||
return false; | |||
} | |||
uint8_t x25519_public_key[32]; | |||
X25519_keypair(x25519_public_key, x25519_private_key_); | |||
HRSS_public_key peer_public_key; | |||
if (peer_key.size() != 32 + HRSS_PUBLIC_KEY_BYTES || | |||
!HRSS_parse_public_key(&peer_public_key, peer_key.data() + 32) || | |||
!X25519(secret.data(), x25519_private_key_, peer_key.data())) { | |||
*out_alert = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); | |||
return false; | |||
} | |||
uint8_t ciphertext[HRSS_CIPHERTEXT_BYTES]; | |||
uint8_t entropy[HRSS_ENCAP_BYTES]; | |||
RAND_bytes(entropy, sizeof(entropy)); | |||
HRSS_encap(ciphertext, secret.data() + 32, &peer_public_key, entropy); | |||
if (!CBB_add_bytes(out_public_key, x25519_public_key, | |||
sizeof(x25519_public_key)) || | |||
!CBB_add_bytes(out_public_key, ciphertext, sizeof(ciphertext))) { | |||
return false; | |||
} | |||
*out_secret = std::move(secret); | |||
return true; | |||
} | |||
bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert, | |||
Span<const uint8_t> peer_key) override { | |||
*out_alert = SSL_AD_INTERNAL_ERROR; | |||
Array<uint8_t> secret; | |||
if (!secret.Init(32 + HRSS_KEY_BYTES)) { | |||
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); | |||
return false; | |||
} | |||
if (peer_key.size() != 32 + HRSS_CIPHERTEXT_BYTES || | |||
!X25519(secret.data(), x25519_private_key_, peer_key.data())) { | |||
*out_alert = SSL_AD_DECODE_ERROR; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT); | |||
return false; | |||
} | |||
HRSS_decap(secret.data() + 32, &hrss_public_key_, &hrss_private_key_, | |||
peer_key.data() + 32, peer_key.size() - 32); | |||
*out_secret = std::move(secret); | |||
return true; | |||
}; | |||
private: | |||
uint8_t x25519_private_key_[32]; | |||
HRSS_public_key hrss_public_key_; | |||
HRSS_private_key hrss_private_key_; | |||
}; | |||
CONSTEXPR_ARRAY NamedGroup kNamedGroups[] = { | |||
{NID_secp224r1, SSL_CURVE_SECP224R1, "P-224", "secp224r1"}, | |||
{NID_X9_62_prime256v1, SSL_CURVE_SECP256R1, "P-256", "prime256v1"}, | |||
{NID_secp384r1, SSL_CURVE_SECP384R1, "P-384", "secp384r1"}, | |||
{NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", "secp521r1"}, | |||
{NID_X25519, SSL_CURVE_X25519, "X25519", "x25519"}, | |||
{NID_CECPQ2, SSL_CURVE_CECPQ2, "CECPQ2", "CECPQ2"}, | |||
}; | |||
} // namespace | |||
@@ -237,6 +331,8 @@ UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) { | |||
New<ECKeyShare>(NID_secp521r1, SSL_CURVE_SECP521R1)); | |||
case SSL_CURVE_X25519: | |||
return UniquePtr<SSLKeyShare>(New<X25519KeyShare>()); | |||
case SSL_CURVE_CECPQ2: | |||
return UniquePtr<SSLKeyShare>(New<CECPQ2KeyShare>()); | |||
default: | |||
return nullptr; | |||
} | |||
@@ -394,6 +394,11 @@ static const CurveTest kCurveTests[] = { | |||
"P-256", | |||
{ SSL_CURVE_SECP256R1 }, | |||
}, | |||
{ | |||
"P-256:CECPQ2", | |||
{ SSL_CURVE_SECP256R1, SSL_CURVE_CECPQ2 }, | |||
}, | |||
{ | |||
"P-256:P-384:P-521:X25519", | |||
{ | |||
@@ -292,10 +292,23 @@ static const uint16_t kDefaultGroups[] = { | |||
SSL_CURVE_SECP384R1, | |||
}; | |||
// TLS 1.3 servers will pick CECPQ2 if offered by a client, but it's not enabled | |||
// by default for clients. | |||
static const uint16_t kDefaultGroupsServer[] = { | |||
// CECPQ2 is not yet enabled by default. | |||
// SSL_CURVE_CECPQ2, | |||
SSL_CURVE_X25519, | |||
SSL_CURVE_SECP256R1, | |||
SSL_CURVE_SECP384R1, | |||
};; | |||
Span<const uint16_t> tls1_get_grouplist(const SSL_HANDSHAKE *hs) { | |||
if (!hs->config->supported_group_list.empty()) { | |||
return hs->config->supported_group_list; | |||
} | |||
if (hs->ssl->server) { | |||
return Span<const uint16_t>(kDefaultGroupsServer); | |||
} | |||
return Span<const uint16_t>(kDefaultGroups); | |||
} | |||
@@ -324,7 +337,11 @@ bool tls1_get_shared_group(SSL_HANDSHAKE *hs, uint16_t *out_group_id) { | |||
for (uint16_t pref_group : pref) { | |||
for (uint16_t supp_group : supp) { | |||
if (pref_group == supp_group) { | |||
if (pref_group == supp_group && | |||
// CECPQ2 doesn't fit in the u8-length-prefixed ECPoint field in TLS | |||
// 1.2 and below. | |||
(ssl_protocol_version(ssl) >= TLS1_3_VERSION || | |||
pref_group != SSL_CURVE_CECPQ2)) { | |||
*out_group_id = pref_group; | |||
return true; | |||
} | |||
@@ -386,6 +403,12 @@ bool tls1_set_curves_list(Array<uint16_t> *out_group_ids, const char *curves) { | |||
} | |||
bool tls1_check_group_id(const SSL_HANDSHAKE *hs, uint16_t group_id) { | |||
if (group_id == SSL_CURVE_CECPQ2 && | |||
ssl_protocol_version(hs->ssl) < TLS1_3_VERSION) { | |||
// CECPQ2 requires TLS 1.3. | |||
return false; | |||
} | |||
for (uint16_t supported : tls1_get_grouplist(hs)) { | |||
if (supported == group_id) { | |||
return true; | |||
@@ -2144,6 +2167,7 @@ static bool ext_key_share_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { | |||
} | |||
uint16_t group_id = hs->retry_group; | |||
uint16_t second_group_id = 0; | |||
if (hs->received_hello_retry_request) { | |||
// We received a HelloRetryRequest without a new curve, so there is no new | |||
// share to append. Leave |hs->key_share| as-is. | |||
@@ -2174,19 +2198,38 @@ static bool ext_key_share_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { | |||
} | |||
group_id = groups[0]; | |||
if (group_id == SSL_CURVE_CECPQ2 && groups.size() >= 2) { | |||
// CECPQ2 is not sent as the only initial key share. We'll include the | |||
// 2nd preference group too to avoid round-trips. | |||
second_group_id = groups[1]; | |||
assert(second_group_id != group_id); | |||
} | |||
} | |||
hs->key_share = SSLKeyShare::Create(group_id); | |||
CBB key_exchange; | |||
if (!hs->key_share || | |||
hs->key_shares[0] = SSLKeyShare::Create(group_id); | |||
if (!hs->key_shares[0] || | |||
!CBB_add_u16(&kse_bytes, group_id) || | |||
!CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange) || | |||
!hs->key_share->Offer(&key_exchange) || | |||
!hs->key_shares[0]->Offer(&key_exchange) || | |||
!CBB_flush(&kse_bytes)) { | |||
return false; | |||
} | |||
// Save the contents of the extension to repeat it in the second ClientHello. | |||
if (second_group_id != 0) { | |||
hs->key_shares[1] = SSLKeyShare::Create(second_group_id); | |||
if (!hs->key_shares[1] || | |||
!CBB_add_u16(&kse_bytes, second_group_id) || | |||
!CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange) || | |||
!hs->key_shares[1]->Offer(&key_exchange) || | |||
!CBB_flush(&kse_bytes)) { | |||
return false; | |||
} | |||
} | |||
// Save the contents of the extension to repeat it in the second | |||
// ClientHello. | |||
if (!hs->received_hello_retry_request && | |||
!hs->key_share_bytes.CopyFrom( | |||
MakeConstSpan(CBB_data(&kse_bytes), CBB_len(&kse_bytes)))) { | |||
@@ -2209,19 +2252,24 @@ bool ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs, | |||
return false; | |||
} | |||
if (hs->key_share->GroupID() != group_id) { | |||
*out_alert = SSL_AD_ILLEGAL_PARAMETER; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); | |||
return false; | |||
SSLKeyShare *key_share = hs->key_shares[0].get(); | |||
if (key_share->GroupID() != group_id) { | |||
if (!hs->key_shares[1] || hs->key_shares[1]->GroupID() != group_id) { | |||
*out_alert = SSL_AD_ILLEGAL_PARAMETER; | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); | |||
return false; | |||
} | |||
key_share = hs->key_shares[1].get(); | |||
} | |||
if (!hs->key_share->Finish(out_secret, out_alert, peer_key)) { | |||
if (!key_share->Finish(out_secret, out_alert, peer_key)) { | |||
*out_alert = SSL_AD_INTERNAL_ERROR; | |||
return false; | |||
} | |||
hs->new_session->group_id = group_id; | |||
hs->key_share.reset(); | |||
hs->key_shares[0].reset(); | |||
hs->key_shares[1].reset(); | |||
return true; | |||
} | |||
@@ -2389,6 +2437,10 @@ static bool ext_supported_groups_add_clienthello(SSL_HANDSHAKE *hs, CBB *out) { | |||
} | |||
for (uint16_t group : tls1_get_grouplist(hs)) { | |||
if (group == SSL_CURVE_CECPQ2 && | |||
hs->max_version < TLS1_3_VERSION) { | |||
continue; | |||
} | |||
if (!CBB_add_u16(&groups_bytes, group)) { | |||
return false; | |||
} | |||
@@ -649,7 +649,6 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session, | |||
SSL_set_connect_state(ssl.get()); | |||
} | |||
int sock = Connect(config->port); | |||
if (sock == -1) { | |||
return false; | |||
@@ -26,7 +26,7 @@ type keyAgreement interface { | |||
// In the case that the key agreement protocol doesn't use a | |||
// ServerKeyExchange message, generateServerKeyExchange can return nil, | |||
// nil. | |||
generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error) | |||
generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg, uint16) (*serverKeyExchangeMsg, error) | |||
processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error) | |||
// On the client side, the next two methods are called in order. | |||
@@ -163,6 +163,7 @@ const ( | |||
CurveP384 CurveID = 24 | |||
CurveP521 CurveID = 25 | |||
CurveX25519 CurveID = 29 | |||
CurveCECPQ2 CurveID = 16696 | |||
) | |||
// TLS Elliptic Curve Point Formats | |||
@@ -1645,6 +1646,18 @@ type ProtocolBugs struct { | |||
// ExpectJDK11DowngradeRandom is whether the client should expect the | |||
// server to send the JDK 11 downgrade signal. | |||
ExpectJDK11DowngradeRandom bool | |||
// FailIfHelloRetryRequested causes a handshake failure if a server requests a | |||
// hello retry. | |||
FailIfHelloRetryRequested bool | |||
// FailedIfCECPQ2Offered will cause a server to reject a ClientHello if CECPQ2 | |||
// is supported. | |||
FailIfCECPQ2Offered bool | |||
// ExpectKeyShares, if not nil, lists (in order) the curves that a ClientHello | |||
// should have key shares for. | |||
ExpectedKeyShares []CurveID | |||
} | |||
func (c *Config) serverInit() { | |||
@@ -1724,7 +1737,7 @@ func (c *Config) maxVersion(isDTLS bool) uint16 { | |||
return ret | |||
} | |||
var defaultCurvePreferences = []CurveID{CurveX25519, CurveP256, CurveP384, CurveP521} | |||
var defaultCurvePreferences = []CurveID{CurveCECPQ2, CurveX25519, CurveP256, CurveP384, CurveP521} | |||
func (c *Config) curvePreferences() []CurveID { | |||
if c == nil || len(c.CurvePreferences) == 0 { | |||
@@ -549,6 +549,9 @@ NextCipherSuite: | |||
helloRetryRequest, haveHelloRetryRequest := msg.(*helloRetryRequestMsg) | |||
var secondHelloBytes []byte | |||
if haveHelloRetryRequest { | |||
if c.config.Bugs.FailIfHelloRetryRequested { | |||
return errors.New("tls: unexpected HelloRetryRequest") | |||
} | |||
// Explicitly read the ChangeCipherSpec now; it should | |||
// be attached to the first flight, not the second flight. | |||
if err := c.readTLS13ChangeCipherSpec(); err != nil { | |||
@@ -208,6 +208,26 @@ func (hs *serverHandshakeState) readClientHello() error { | |||
} | |||
} | |||
if config.Bugs.FailIfCECPQ2Offered { | |||
for _, offeredCurve := range hs.clientHello.supportedCurves { | |||
if offeredCurve == CurveCECPQ2 { | |||
return errors.New("tls: CECPQ2 was offered") | |||
} | |||
} | |||
} | |||
if expected := config.Bugs.ExpectedKeyShares; expected != nil { | |||
if len(expected) != len(hs.clientHello.keyShares) { | |||
return fmt.Errorf("tls: expected %d key shares, but found %d", len(expected), len(hs.clientHello.keyShares)) | |||
} | |||
for i, group := range expected { | |||
if found := hs.clientHello.keyShares[i].group; found != group { | |||
return fmt.Errorf("tls: key share #%d is for group %d, not %d", i, found, group) | |||
} | |||
} | |||
} | |||
c.clientVersion = hs.clientHello.vers | |||
// Use the versions extension if supplied, otherwise use the legacy ClientHello version. | |||
@@ -1212,6 +1232,11 @@ func (hs *serverHandshakeState) processClientHello() (isResume bool, err error) | |||
preferredCurves := config.curvePreferences() | |||
Curves: | |||
for _, curve := range hs.clientHello.supportedCurves { | |||
if curve == CurveCECPQ2 && c.vers < VersionTLS13 { | |||
// CECPQ2 is TLS 1.3-only. | |||
continue | |||
} | |||
for _, supported := range preferredCurves { | |||
if supported == curve { | |||
supportedCurve = true | |||
@@ -1621,7 +1646,7 @@ func (hs *serverHandshakeState) doFullHandshake() error { | |||
} | |||
keyAgreement := hs.suite.ka(c.vers) | |||
skx, err := keyAgreement.generateServerKeyExchange(config, hs.cert, hs.clientHello, hs.hello) | |||
skx, err := keyAgreement.generateServerKeyExchange(config, hs.cert, hs.clientHello, hs.hello, c.vers) | |||
if err != nil { | |||
c.sendAlert(alertHandshakeFailure) | |||
return err | |||
@@ -17,6 +17,7 @@ import ( | |||
"boringssl.googlesource.com/boringssl/ssl/test/runner/curve25519" | |||
"boringssl.googlesource.com/boringssl/ssl/test/runner/ed25519" | |||
"boringssl.googlesource.com/boringssl/ssl/test/runner/hrss" | |||
) | |||
type keyType int | |||
@@ -37,7 +38,7 @@ type rsaKeyAgreement struct { | |||
exportKey *rsa.PrivateKey | |||
} | |||
func (ka *rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { | |||
func (ka *rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, version uint16) (*serverKeyExchangeMsg, error) { | |||
// Save the client version for comparison later. | |||
ka.clientVersion = clientHello.vers | |||
@@ -347,6 +348,90 @@ func (e *x25519ECDHCurve) finish(peerKey []byte) (preMasterSecret []byte, err er | |||
return out[:], nil | |||
} | |||
// cecpq2Curve implements CECPQ2, which is HRSS+SXY combined with X25519. | |||
type cecpq2Curve struct { | |||
x25519PrivateKey [32]byte | |||
hrssPrivateKey hrss.PrivateKey | |||
} | |||
func (e *cecpq2Curve) offer(rand io.Reader) (publicKey []byte, err error) { | |||
if _, err := io.ReadFull(rand, e.x25519PrivateKey[:]); err != nil { | |||
return nil, err | |||
} | |||
var x25519Public [32]byte | |||
curve25519.ScalarBaseMult(&x25519Public, &e.x25519PrivateKey) | |||
e.hrssPrivateKey = hrss.GenerateKey(rand) | |||
hrssPublic := e.hrssPrivateKey.PublicKey.Marshal() | |||
var ret []byte | |||
ret = append(ret, x25519Public[:]...) | |||
ret = append(ret, hrssPublic...) | |||
return ret, nil | |||
} | |||
func (e *cecpq2Curve) accept(rand io.Reader, peerKey []byte) (publicKey []byte, preMasterSecret []byte, err error) { | |||
if len(peerKey) != 32+hrss.PublicKeySize { | |||
return nil, nil, errors.New("tls: bad length CECPQ2 offer") | |||
} | |||
if _, err := io.ReadFull(rand, e.x25519PrivateKey[:]); err != nil { | |||
return nil, nil, err | |||
} | |||
var x25519Shared, x25519PeerKey, x25519Public [32]byte | |||
copy(x25519PeerKey[:], peerKey) | |||
curve25519.ScalarBaseMult(&x25519Public, &e.x25519PrivateKey) | |||
curve25519.ScalarMult(&x25519Shared, &e.x25519PrivateKey, &x25519PeerKey) | |||
// Per RFC 7748, reject the all-zero value in constant time. | |||
var zeros [32]byte | |||
if subtle.ConstantTimeCompare(zeros[:], x25519Shared[:]) == 1 { | |||
return nil, nil, errors.New("tls: X25519 value with wrong order") | |||
} | |||
hrssPublicKey, ok := hrss.ParsePublicKey(peerKey[32:]) | |||
if !ok { | |||
return nil, nil, errors.New("tls: bad CECPQ2 offer") | |||
} | |||
hrssCiphertext, hrssShared := hrssPublicKey.Encap(rand) | |||
publicKey = append(publicKey, x25519Public[:]...) | |||
publicKey = append(publicKey, hrssCiphertext...) | |||
preMasterSecret = append(preMasterSecret, x25519Shared[:]...) | |||
preMasterSecret = append(preMasterSecret, hrssShared...) | |||
return publicKey, preMasterSecret, nil | |||
} | |||
func (e *cecpq2Curve) finish(peerKey []byte) (preMasterSecret []byte, err error) { | |||
if len(peerKey) != 32+hrss.CiphertextSize { | |||
return nil, errors.New("tls: bad length CECPQ2 reply") | |||
} | |||
var x25519Shared, x25519PeerKey [32]byte | |||
copy(x25519PeerKey[:], peerKey) | |||
curve25519.ScalarMult(&x25519Shared, &e.x25519PrivateKey, &x25519PeerKey) | |||
// Per RFC 7748, reject the all-zero value in constant time. | |||
var zeros [32]byte | |||
if subtle.ConstantTimeCompare(zeros[:], x25519Shared[:]) == 1 { | |||
return nil, errors.New("tls: X25519 value with wrong order") | |||
} | |||
hrssShared, ok := e.hrssPrivateKey.Decap(peerKey[32:]) | |||
if !ok { | |||
return nil, errors.New("tls: invalid HRSS ciphertext") | |||
} | |||
preMasterSecret = append(preMasterSecret, x25519Shared[:]...) | |||
preMasterSecret = append(preMasterSecret, hrssShared...) | |||
return preMasterSecret, nil | |||
} | |||
func curveForCurveID(id CurveID, config *Config) (ecdhCurve, bool) { | |||
switch id { | |||
case CurveP224: | |||
@@ -359,6 +444,8 @@ func curveForCurveID(id CurveID, config *Config) (ecdhCurve, bool) { | |||
return &ellipticECDHCurve{curve: elliptic.P521(), sendCompressed: config.Bugs.SendCompressedCoordinates}, true | |||
case CurveX25519: | |||
return &x25519ECDHCurve{setHighBit: config.Bugs.SetX25519HighBit}, true | |||
case CurveCECPQ2: | |||
return &cecpq2Curve{}, true | |||
default: | |||
return nil, false | |||
} | |||
@@ -501,12 +588,17 @@ type ecdheKeyAgreement struct { | |||
peerKey []byte | |||
} | |||
func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { | |||
func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, version uint16) (*serverKeyExchangeMsg, error) { | |||
var curveid CurveID | |||
preferredCurves := config.curvePreferences() | |||
NextCandidate: | |||
for _, candidate := range preferredCurves { | |||
if candidate == CurveCECPQ2 && version < VersionTLS13 { | |||
// CECPQ2 is TLS 1.3-only. | |||
continue | |||
} | |||
for _, c := range clientHello.supportedCurves { | |||
if candidate == c { | |||
curveid = c | |||
@@ -614,7 +706,7 @@ func (ka *ecdheKeyAgreement) peerSignatureAlgorithm() signatureAlgorithm { | |||
// exchange. | |||
type nilKeyAgreement struct{} | |||
func (ka *nilKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { | |||
func (ka *nilKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, version uint16) (*serverKeyExchangeMsg, error) { | |||
return nil, nil | |||
} | |||
@@ -666,7 +758,7 @@ type pskKeyAgreement struct { | |||
identityHint string | |||
} | |||
func (ka *pskKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { | |||
func (ka *pskKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg, version uint16) (*serverKeyExchangeMsg, error) { | |||
// Assemble the identity hint. | |||
bytes := make([]byte, 2+len(config.PreSharedKeyIdentity)) | |||
bytes[0] = byte(len(config.PreSharedKeyIdentity) >> 8) | |||
@@ -675,7 +767,7 @@ func (ka *pskKeyAgreement) generateServerKeyExchange(config *Config, cert *Certi | |||
// If there is one, append the base key agreement's | |||
// ServerKeyExchange. | |||
baseSkx, err := ka.base.generateServerKeyExchange(config, cert, clientHello, hello) | |||
baseSkx, err := ka.base.generateServerKeyExchange(config, cert, clientHello, hello, version) | |||
if err != nil { | |||
return nil, err | |||
} | |||
@@ -9619,7 +9619,7 @@ func addSignatureAlgorithmTests() { | |||
CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | |||
Certificates: []Certificate{ecdsaP256Certificate}, | |||
}, | |||
flags: []string{"-p384-only"}, | |||
flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, | |||
shouldFail: true, | |||
expectedError: ":BAD_ECC_CERT:", | |||
}) | |||
@@ -9631,7 +9631,7 @@ func addSignatureAlgorithmTests() { | |||
MaxVersion: VersionTLS13, | |||
Certificates: []Certificate{ecdsaP256Certificate}, | |||
}, | |||
flags: []string{"-p384-only"}, | |||
flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, | |||
}) | |||
// In TLS 1.2, the ECDSA curve is not in the signature algorithm. | |||
@@ -10711,6 +10711,7 @@ var testCurves = []struct { | |||
{"P-384", CurveP384}, | |||
{"P-521", CurveP521}, | |||
{"X25519", CurveX25519}, | |||
{"CECPQ2", CurveCECPQ2}, | |||
} | |||
const bogusCurve = 0x1234 | |||
@@ -10718,6 +10719,10 @@ const bogusCurve = 0x1234 | |||
func addCurveTests() { | |||
for _, curve := range testCurves { | |||
for _, ver := range tlsVersions { | |||
if curve.id == CurveCECPQ2 && ver.version < VersionTLS13 { | |||
continue | |||
} | |||
suffix := curve.name + "-" + ver.name | |||
testCases = append(testCases, testCase{ | |||
@@ -10758,7 +10763,7 @@ func addCurveTests() { | |||
expectedCurveID: curve.id, | |||
}) | |||
if curve.id != CurveX25519 { | |||
if curve.id != CurveX25519 && curve.id != CurveCECPQ2 { | |||
testCases = append(testCases, testCase{ | |||
name: "CurveTest-Client-Compressed-" + suffix, | |||
config: Config{ | |||
@@ -10902,7 +10907,7 @@ func addCurveTests() { | |||
IgnorePeerCurvePreferences: true, | |||
}, | |||
}, | |||
flags: []string{"-p384-only"}, | |||
flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, | |||
shouldFail: true, | |||
expectedError: ":WRONG_CURVE:", | |||
}) | |||
@@ -10918,7 +10923,7 @@ func addCurveTests() { | |||
SendCurve: CurveP256, | |||
}, | |||
}, | |||
flags: []string{"-p384-only"}, | |||
flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, | |||
shouldFail: true, | |||
expectedError: ":WRONG_CURVE:", | |||
}) | |||
@@ -11169,6 +11174,112 @@ func addCurveTests() { | |||
}, | |||
}, | |||
}) | |||
// CECPQ2 should not be offered by a TLS < 1.3 client. | |||
testCases = append(testCases, testCase{ | |||
name: "CECPQ2NotInTLS12", | |||
config: Config{ | |||
Bugs: ProtocolBugs{ | |||
FailIfCECPQ2Offered: true, | |||
}, | |||
}, | |||
flags: []string{ | |||
"-max-version", strconv.Itoa(VersionTLS12), | |||
"-curves", strconv.Itoa(int(CurveCECPQ2)), | |||
"-curves", strconv.Itoa(int(CurveX25519)), | |||
}, | |||
}) | |||
// CECPQ2 should not crash a TLS < 1.3 client if the server mistakenly | |||
// selects it. | |||
testCases = append(testCases, testCase{ | |||
name: "CECPQ2NotAcceptedByTLS12Client", | |||
config: Config{ | |||
Bugs: ProtocolBugs{ | |||
SendCurve: CurveCECPQ2, | |||
}, | |||
}, | |||
flags: []string{ | |||
"-max-version", strconv.Itoa(VersionTLS12), | |||
"-curves", strconv.Itoa(int(CurveCECPQ2)), | |||
"-curves", strconv.Itoa(int(CurveX25519)), | |||
}, | |||
shouldFail: true, | |||
expectedError: ":WRONG_CURVE:", | |||
}) | |||
// CECPQ2 should not be offered by default as a client. | |||
testCases = append(testCases, testCase{ | |||
name: "CECPQ2NotEnabledByDefaultInClients", | |||
config: Config{ | |||
MinVersion: VersionTLS13, | |||
Bugs: ProtocolBugs{ | |||
FailIfCECPQ2Offered: true, | |||
}, | |||
}, | |||
}) | |||
// If CECPQ2 is offered, both X25519 and CECPQ2 should have a key-share. | |||
testCases = append(testCases, testCase{ | |||
name: "NotJustCECPQ2KeyShare", | |||
config: Config{ | |||
MinVersion: VersionTLS13, | |||
Bugs: ProtocolBugs{ | |||
ExpectedKeyShares: []CurveID{CurveCECPQ2, CurveX25519}, | |||
}, | |||
}, | |||
flags: []string{ | |||
"-curves", strconv.Itoa(int(CurveCECPQ2)), | |||
"-curves", strconv.Itoa(int(CurveX25519)), | |||
"-expect-curve-id", strconv.Itoa(int(CurveCECPQ2)), | |||
}, | |||
}) | |||
// ... but only if CECPQ2 is listed first. | |||
testCases = append(testCases, testCase{ | |||
name: "CECPQ2KeyShareNotIncludedSecond", | |||
config: Config{ | |||
MinVersion: VersionTLS13, | |||
Bugs: ProtocolBugs{ | |||
ExpectedKeyShares: []CurveID{CurveX25519}, | |||
}, | |||
}, | |||
flags: []string{ | |||
"-curves", strconv.Itoa(int(CurveX25519)), | |||
"-curves", strconv.Itoa(int(CurveCECPQ2)), | |||
"-expect-curve-id", strconv.Itoa(int(CurveX25519)), | |||
}, | |||
}) | |||
// If CECPQ2 is the only configured curve, the key share is sent. | |||
testCases = append(testCases, testCase{ | |||
name: "JustConfiguringCECPQ2Works", | |||
config: Config{ | |||
MinVersion: VersionTLS13, | |||
Bugs: ProtocolBugs{ | |||
ExpectedKeyShares: []CurveID{CurveCECPQ2}, | |||
}, | |||
}, | |||
flags: []string{ | |||
"-curves", strconv.Itoa(int(CurveCECPQ2)), | |||
"-expect-curve-id", strconv.Itoa(int(CurveCECPQ2)), | |||
}, | |||
}) | |||
// As a server, CECPQ2 is not yet supported by default. | |||
testCases = append(testCases, testCase{ | |||
testType: serverTest, | |||
name: "CECPQ2NotEnabledByDefaultForAServer", | |||
config: Config{ | |||
MinVersion: VersionTLS13, | |||
CurvePreferences: []CurveID{CurveCECPQ2, CurveX25519}, | |||
DefaultCurves: []CurveID{CurveCECPQ2}, | |||
}, | |||
flags: []string{ | |||
"-server-preference", | |||
"-expect-curve-id", strconv.Itoa(int(CurveX25519)), | |||
}, | |||
}) | |||
} | |||
func addTLS13RecordTests() { | |||
@@ -12706,7 +12817,7 @@ func addTLS13HandshakeTests() { | |||
}, | |||
}, | |||
tls13Variant: variant, | |||
flags: []string{"-p384-only"}, | |||
flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, | |||
shouldFail: true, | |||
expectedError: ":WRONG_CURVE:", | |||
}) | |||
@@ -104,7 +104,6 @@ const Flag<bool> kBoolFlags[] = { | |||
{ "-renegotiate-ignore", &TestConfig::renegotiate_ignore }, | |||
{ "-forbid-renegotiation-after-handshake", | |||
&TestConfig::forbid_renegotiation_after_handshake }, | |||
{ "-p384-only", &TestConfig::p384_only }, | |||
{ "-enable-all-curves", &TestConfig::enable_all_curves }, | |||
{ "-use-old-client-cert-callback", | |||
&TestConfig::use_old_client_cert_callback }, | |||
@@ -147,6 +146,7 @@ const Flag<bool> kBoolFlags[] = { | |||
{ "-handshaker-resume", &TestConfig::handshaker_resume }, | |||
{ "-reverify-on-resume", &TestConfig::reverify_on_resume }, | |||
{ "-jdk11-workaround", &TestConfig::jdk11_workaround }, | |||
{ "-server-preference", &TestConfig::server_preference }, | |||
}; | |||
const Flag<std::string> kStringFlags[] = { | |||
@@ -220,10 +220,10 @@ const Flag<int> kIntFlags[] = { | |||
}; | |||
const Flag<std::vector<int>> kIntVectorFlags[] = { | |||
{ "-signing-prefs", &TestConfig::signing_prefs }, | |||
{ "-verify-prefs", &TestConfig::verify_prefs }, | |||
{ "-expect-peer-verify-pref", | |||
&TestConfig::expected_peer_verify_prefs }, | |||
{"-signing-prefs", &TestConfig::signing_prefs}, | |||
{"-verify-prefs", &TestConfig::verify_prefs}, | |||
{"-expect-peer-verify-pref", &TestConfig::expected_peer_verify_prefs}, | |||
{"-curves", &TestConfig::curves}, | |||
}; | |||
bool ParseFlag(char *flag, int argc, char **argv, int *i, | |||
@@ -1294,7 +1294,6 @@ bssl::UniquePtr<SSL_CTX> TestConfig::SetupCtx(SSL_CTX *old_ctx) const { | |||
return nullptr; | |||
} | |||
if (install_cert_compression_algs && | |||
(!SSL_CTX_add_cert_compression_alg( | |||
ssl_ctx.get(), 0xff02, | |||
@@ -1341,6 +1340,10 @@ bssl::UniquePtr<SSL_CTX> TestConfig::SetupCtx(SSL_CTX *old_ctx) const { | |||
abort(); | |||
} | |||
if (server_preference) { | |||
SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_CIPHER_SERVER_PREFERENCE); | |||
} | |||
return ssl_ctx; | |||
} | |||
@@ -1589,16 +1592,43 @@ bssl::UniquePtr<SSL> TestConfig::NewSSL( | |||
if (!check_close_notify) { | |||
SSL_set_quiet_shutdown(ssl.get(), 1); | |||
} | |||
if (p384_only) { | |||
int nid = NID_secp384r1; | |||
if (!SSL_set1_curves(ssl.get(), &nid, 1)) { | |||
return nullptr; | |||
if (!curves.empty()) { | |||
std::vector<int> nids; | |||
for (auto curve : curves) { | |||
switch (curve) { | |||
case SSL_CURVE_SECP224R1: | |||
nids.push_back(NID_secp224r1); | |||
break; | |||
case SSL_CURVE_SECP256R1: | |||
nids.push_back(NID_X9_62_prime256v1); | |||
break; | |||
case SSL_CURVE_SECP384R1: | |||
nids.push_back(NID_secp384r1); | |||
break; | |||
case SSL_CURVE_SECP521R1: | |||
nids.push_back(NID_secp521r1); | |||
break; | |||
case SSL_CURVE_X25519: | |||
nids.push_back(NID_X25519); | |||
break; | |||
case SSL_CURVE_CECPQ2: | |||
nids.push_back(NID_CECPQ2); | |||
break; | |||
} | |||
if (!SSL_set1_curves(ssl.get(), &nids[0], nids.size())) { | |||
return nullptr; | |||
} | |||
} | |||
} | |||
if (enable_all_curves) { | |||
static const int kAllCurves[] = { | |||
NID_secp224r1, NID_X9_62_prime256v1, NID_secp384r1, | |||
NID_secp521r1, NID_X25519, | |||
NID_secp521r1, NID_X25519, NID_CECPQ2, | |||
}; | |||
if (!SSL_set1_curves(ssl.get(), kAllCurves, | |||
OPENSSL_ARRAY_SIZE(kAllCurves))) { | |||
@@ -33,6 +33,7 @@ struct TestConfig { | |||
std::vector<int> signing_prefs; | |||
std::vector<int> verify_prefs; | |||
std::vector<int> expected_peer_verify_prefs; | |||
std::vector<int> curves; | |||
std::string key_file; | |||
std::string cert_file; | |||
std::string expected_server_name; | |||
@@ -122,7 +123,6 @@ struct TestConfig { | |||
bool renegotiate_ignore = false; | |||
bool forbid_renegotiation_after_handshake = false; | |||
int expect_peer_signature_algorithm = 0; | |||
bool p384_only = false; | |||
bool enable_all_curves = false; | |||
int expect_curve_id = 0; | |||
bool use_old_client_cert_callback = false; | |||
@@ -170,6 +170,7 @@ struct TestConfig { | |||
bool handshaker_resume = false; | |||
std::string handshaker_path; | |||
bool jdk11_workaround = false; | |||
bool server_preference = false; | |||
int argc; | |||
char **argv; | |||
@@ -165,15 +165,17 @@ static enum ssl_hs_wait_t do_read_hello_retry_request(SSL_HANDSHAKE *hs) { | |||
return ssl_hs_error; | |||
} | |||
// Check that the HelloRetryRequest does not request the key share that | |||
// was provided in the initial ClientHello. | |||
if (hs->key_share->GroupID() == group_id) { | |||
// Check that the HelloRetryRequest does not request a key share that was | |||
// provided in the initial ClientHello. | |||
if (hs->key_shares[0]->GroupID() == group_id || | |||
(hs->key_shares[1] && hs->key_shares[1]->GroupID() == group_id)) { | |||
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); | |||
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); | |||
return ssl_hs_error; | |||
} | |||
hs->key_share.reset(); | |||
hs->key_shares[0].reset(); | |||
hs->key_shares[1].reset(); | |||
hs->retry_group = group_id; | |||
} | |||
@@ -32,6 +32,7 @@ | |||
#include <openssl/ecdsa.h> | |||
#include <openssl/ec_key.h> | |||
#include <openssl/evp.h> | |||
#include <openssl/hrss.h> | |||
#include <openssl/nid.h> | |||
#include <openssl/rand.h> | |||
#include <openssl/rsa.h> | |||
@@ -744,6 +745,61 @@ static bool SpeedScrypt(const std::string &selected) { | |||
return true; | |||
} | |||
static bool SpeedHRSS(const std::string &selected) { | |||
if (!selected.empty() && selected != "HRSS") { | |||
return true; | |||
} | |||
TimeResults results; | |||
if (!TimeFunction(&results, []() -> bool { | |||
struct HRSS_public_key pub; | |||
struct HRSS_private_key priv; | |||
uint8_t entropy[HRSS_GENERATE_KEY_BYTES]; | |||
RAND_bytes(entropy, sizeof(entropy)); | |||
HRSS_generate_key(&pub, &priv, entropy); | |||
return true; | |||
})) { | |||
fprintf(stderr, "Failed to time HRSS_generate_key.\n"); | |||
return false; | |||
} | |||
results.Print("HRSS generate"); | |||
struct HRSS_public_key pub; | |||
struct HRSS_private_key priv; | |||
uint8_t key_entropy[HRSS_GENERATE_KEY_BYTES]; | |||
RAND_bytes(key_entropy, sizeof(key_entropy)); | |||
HRSS_generate_key(&pub, &priv, key_entropy); | |||
uint8_t ciphertext[HRSS_CIPHERTEXT_BYTES]; | |||
if (!TimeFunction(&results, [&pub, &ciphertext]() -> bool { | |||
uint8_t entropy[HRSS_ENCAP_BYTES]; | |||
uint8_t shared_key[HRSS_KEY_BYTES]; | |||
RAND_bytes(entropy, sizeof(entropy)); | |||
HRSS_encap(ciphertext, shared_key, &pub, entropy); | |||
return true; | |||
})) { | |||
fprintf(stderr, "Failed to time HRSS_encap.\n"); | |||
return false; | |||
} | |||
results.Print("HRSS encap"); | |||
if (!TimeFunction(&results, [&pub, &priv, &ciphertext]() -> bool { | |||
uint8_t shared_key[HRSS_KEY_BYTES]; | |||
HRSS_decap(shared_key, &pub, &priv, ciphertext, sizeof(ciphertext)); | |||
return true; | |||
})) { | |||
fprintf(stderr, "Failed to time HRSS_encap.\n"); | |||
return false; | |||
} | |||
results.Print("HRSS decap"); | |||
return true; | |||
} | |||
static const struct argument kArguments[] = { | |||
{ | |||
"-filter", kOptionalArgument, | |||
@@ -817,7 +873,8 @@ bool Speed(const std::vector<std::string> &args) { | |||
!Speed25519(selected) || | |||
!SpeedSPAKE2(selected) || | |||
!SpeedScrypt(selected) || | |||
!SpeedRSAKeyGen(selected)) { | |||
!SpeedRSAKeyGen(selected) || | |||
!SpeedHRSS(selected)) { | |||
return false; | |||
} | |||
@@ -43,6 +43,10 @@ NON_PERL_FILES = { | |||
('linux', 'arm'): [ | |||
'src/crypto/curve25519/asm/x25519-asm-arm.S', | |||
'src/crypto/poly1305/poly1305_arm_asm.S', | |||
'src/crypto/hrss/asm/poly_mul_vec_armv7_neon.S', | |||
], | |||
('linux', 'x86_64'): [ | |||
'src/crypto/hrss/asm/poly_rq_mul.S', | |||
], | |||
} | |||