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} | chacha/chacha-armv4.${ASM_EXT} | ||||
curve25519/asm/x25519-asm-arm.S | curve25519/asm/x25519-asm-arm.S | ||||
poly1305/poly1305_arm_asm.S | poly1305/poly1305_arm_asm.S | ||||
hrss/asm/poly_mul_vec_armv7_neon.S | |||||
) | ) | ||||
endif() | endif() | ||||
@@ -131,6 +132,7 @@ if(${ARCH} STREQUAL "x86_64") | |||||
chacha/chacha-x86_64.${ASM_EXT} | chacha/chacha-x86_64.${ASM_EXT} | ||||
cipher_extra/aes128gcmsiv-x86_64.${ASM_EXT} | cipher_extra/aes128gcmsiv-x86_64.${ASM_EXT} | ||||
cipher_extra/chacha20_poly1305_x86_64.${ASM_EXT} | cipher_extra/chacha20_poly1305_x86_64.${ASM_EXT} | ||||
hrss/asm/poly_rq_mul.S | |||||
) | ) | ||||
endif() | endif() | ||||
@@ -275,6 +277,7 @@ add_library( | |||||
evp/sign.c | evp/sign.c | ||||
ex_data.c | ex_data.c | ||||
hkdf/hkdf.c | hkdf/hkdf.c | ||||
hrss/hrss.c | |||||
lhash/lhash.c | lhash/lhash.c | ||||
mem.c | mem.c | ||||
obj/obj.c | obj/obj.c | ||||
@@ -455,6 +458,7 @@ add_executable( | |||||
fipsmodule/rand/ctrdrbg_test.cc | fipsmodule/rand/ctrdrbg_test.cc | ||||
hkdf/hkdf_test.cc | hkdf/hkdf_test.cc | ||||
hmac_extra/hmac_test.cc | hmac_extra/hmac_test.cc | ||||
hrss/hrss_test.cc | |||||
lhash/lhash_test.cc | lhash/lhash_test.cc | ||||
obj/obj_test.cc | obj/obj_test.cc | ||||
pem/pem_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. */ | /* This file is generated by crypto/obj/objects.go. */ | ||||
#define NUM_NID 959 | |||||
#define NUM_NID 960 | |||||
static const uint8_t kObjectData[] = { | static const uint8_t kObjectData[] = { | ||||
/* NID_rsadsi */ | /* NID_rsadsi */ | ||||
@@ -8755,6 +8755,7 @@ static const ASN1_OBJECT kObjects[NUM_NID] = { | |||||
{"AuthPSK", "auth-psk", NID_auth_psk, 0, NULL, 0}, | {"AuthPSK", "auth-psk", NID_auth_psk, 0, NULL, 0}, | ||||
{"KxANY", "kx-any", NID_kx_any, 0, NULL, 0}, | {"KxANY", "kx-any", NID_kx_any, 0, NULL, 0}, | ||||
{"AuthANY", "auth-any", NID_auth_any, 0, NULL, 0}, | {"AuthANY", "auth-any", NID_auth_any, 0, NULL, 0}, | ||||
{"CECPQ2", "CECPQ2", NID_CECPQ2, 0, NULL, 0}, | |||||
}; | }; | ||||
static const unsigned kNIDsInShortNameOrder[] = { | static const unsigned kNIDsInShortNameOrder[] = { | ||||
@@ -8816,6 +8817,7 @@ static const unsigned kNIDsInShortNameOrder[] = { | |||||
110 /* CAST5-CFB */, | 110 /* CAST5-CFB */, | ||||
109 /* CAST5-ECB */, | 109 /* CAST5-ECB */, | ||||
111 /* CAST5-OFB */, | 111 /* CAST5-OFB */, | ||||
959 /* CECPQ2 */, | |||||
894 /* CMAC */, | 894 /* CMAC */, | ||||
13 /* CN */, | 13 /* CN */, | ||||
141 /* CRLReason */, | 141 /* CRLReason */, | ||||
@@ -9720,6 +9722,7 @@ static const unsigned kNIDsInLongNameOrder[] = { | |||||
285 /* Biometric Info */, | 285 /* Biometric Info */, | ||||
179 /* CA Issuers */, | 179 /* CA Issuers */, | ||||
785 /* CA Repository */, | 785 /* CA Repository */, | ||||
959 /* CECPQ2 */, | |||||
131 /* Code Signing */, | 131 /* Code Signing */, | ||||
783 /* Diffie-Hellman based MAC */, | 783 /* Diffie-Hellman based MAC */, | ||||
382 /* Directory */, | 382 /* Directory */, | ||||
@@ -947,3 +947,4 @@ auth_ecdsa 955 | |||||
auth_psk 956 | auth_psk 956 | ||||
kx_any 957 | kx_any 957 | ||||
auth_any 958 | auth_any 958 | ||||
CECPQ2 959 |
@@ -559,7 +559,7 @@ id-cmc 19 : id-cmc-responseInfo | |||||
id-cmc 21 : id-cmc-queryPending | id-cmc 21 : id-cmc-queryPending | ||||
id-cmc 22 : id-cmc-popLinkRandom | id-cmc 22 : id-cmc-popLinkRandom | ||||
id-cmc 23 : id-cmc-popLinkWitness | id-cmc 23 : id-cmc-popLinkWitness | ||||
id-cmc 24 : id-cmc-confirmCertAcceptance | |||||
id-cmc 24 : id-cmc-confirmCertAcceptance | |||||
# other names | # other names | ||||
id-on 1 : id-on-personalData | 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 | # Definitions for Camellia cipher - ECB, CFB, OFB MODE | ||||
!Alias ntt-ds 0 3 4401 5 | !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 | camellia 1 : CAMELLIA-128-ECB : camellia-128-ecb | ||||
!Cname camellia-128-ofb128 | !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 11 : brainpoolP384r1 | ||||
1 3 36 3 3 2 8 1 1 12 : brainpoolP384t1 | 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 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 | # ECDH schemes from RFC5753 | ||||
!Alias x9-63-scheme 1 3 133 16 840 63 0 | !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). | # NID for X25519 (no corresponding OID). | ||||
: X25519 | : X25519 | ||||
# NID for CECPQ2 (no corresponding OID). | |||||
: CECPQ2 | |||||
# See RFC 8410. | # See RFC 8410. | ||||
1 3 101 112 : ED25519 | 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 LN_auth_any "auth-any" | ||||
#define NID_auth_any 958 | #define NID_auth_any 958 | ||||
#define SN_CECPQ2 "CECPQ2" | |||||
#define NID_CECPQ2 959 | |||||
#if defined(__cplusplus) | #if defined(__cplusplus) | ||||
} /* extern C */ | } /* 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_SECP384R1 24 | ||||
#define SSL_CURVE_SECP521R1 25 | #define SSL_CURVE_SECP521R1 25 | ||||
#define SSL_CURVE_X25519 29 | #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 | // SSL_get_curve_id returns the ID of the curve used by |ssl|'s most recently | ||||
// completed handshake or 0 if not applicable. | // completed handshake or 0 if not applicable. | ||||
@@ -307,7 +307,7 @@ bool SSL_serialize_handback(const SSL *ssl, CBB *out) { | |||||
return false; | return false; | ||||
} | } | ||||
if (type == handback_after_ecdhe && | if (type == handback_after_ecdhe && | ||||
!s3->hs->key_share->Serialize(&key_share)) { | |||||
!s3->hs->key_shares[0]->Serialize(&key_share)) { | |||||
return false; | return false; | ||||
} | } | ||||
return CBB_flush(out); | return CBB_flush(out); | ||||
@@ -471,7 +471,7 @@ bool SSL_apply_handback(SSL *ssl, Span<const uint8_t> handback) { | |||||
return false; | return false; | ||||
} | } | ||||
if (type == handback_after_ecdhe && | 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; | 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. | // 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(); | hs->key_share_bytes.Reset(); | ||||
// A TLS 1.2 server would not know to skip the early data we offered. Report | // 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. | // 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)) { | !hs->peer_key.CopyFrom(point)) { | ||||
return ssl_hs_error; | 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. | // Compute the premaster. | ||||
uint8_t alert = SSL_AD_DECODE_ERROR; | 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); | ssl_send_alert(ssl, SSL3_AL_FATAL, alert); | ||||
return ssl_hs_error; | 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. | // 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(); | hs->peer_key.Reset(); | ||||
} else if (alg_k & SSL_kPSK) { | } else if (alg_k & SSL_kPSK) { | ||||
// For plain PSK, other_secret is a block of 0s with the same length as | // 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; | hs->new_session->group_id = group_id; | ||||
// Set up ECDH, generate a key, and emit the public half. | // 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_u8(cbb.get(), NAMED_CURVE_TYPE) || | ||||
!CBB_add_u16(cbb.get(), group_id) || | !CBB_add_u16(cbb.get(), group_id) || | ||||
!CBB_add_u8_length_prefixed(cbb.get(), &child) || | !CBB_add_u8_length_prefixed(cbb.get(), &child) || | ||||
!hs->key_share->Offer(&child)) { | |||||
!hs->key_shares[0]->Offer(&child)) { | |||||
return ssl_hs_error; | return ssl_hs_error; | ||||
} | } | ||||
} else { | } else { | ||||
@@ -1275,13 +1275,14 @@ static enum ssl_hs_wait_t do_read_client_key_exchange(SSL_HANDSHAKE *hs) { | |||||
// Compute the premaster. | // Compute the premaster. | ||||
uint8_t alert = SSL_AD_DECODE_ERROR; | 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); | ssl_send_alert(ssl, SSL3_AL_FATAL, alert); | ||||
return ssl_hs_error; | return ssl_hs_error; | ||||
} | } | ||||
// The key exchange state may now be discarded. | // 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)) { | } else if (!(alg_k & SSL_kPSK)) { | ||||
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); | ||||
ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE); | 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. | // |out_public_key|. It returns true on success and false on error. | ||||
virtual bool Offer(CBB *out_public_key) PURE_VIRTUAL; | 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|, | // 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 | // The default implementation calls |Offer| and then |Finish|, assuming a key | ||||
// exchange protocol where the peers are symmetric. | // exchange protocol where the peers are symmetric. | ||||
@@ -986,7 +986,7 @@ class SSLKeyShare { | |||||
// Finish performs a key exchange against the |peer_key| generated by | // Finish performs a key exchange against the |peer_key| generated by | ||||
// |Accept|. On success, it returns true and sets |*out_secret| to the shared | // |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. | // send to the peer. | ||||
virtual bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert, | virtual bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert, | ||||
Span<const uint8_t> peer_key) PURE_VIRTUAL; | 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. | // error, if |wait| is |ssl_hs_error|, is the error the handshake failed on. | ||||
UniquePtr<ERR_SAVE_STATE> error; | 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. | // transcript is the current handshake transcript. | ||||
SSLTranscript transcript; | SSLTranscript transcript; | ||||
@@ -24,8 +24,10 @@ | |||||
#include <openssl/curve25519.h> | #include <openssl/curve25519.h> | ||||
#include <openssl/ec.h> | #include <openssl/ec.h> | ||||
#include <openssl/err.h> | #include <openssl/err.h> | ||||
#include <openssl/hrss.h> | |||||
#include <openssl/mem.h> | #include <openssl/mem.h> | ||||
#include <openssl/nid.h> | #include <openssl/nid.h> | ||||
#include <openssl/rand.h> | |||||
#include "internal.h" | #include "internal.h" | ||||
#include "../crypto/internal.h" | #include "../crypto/internal.h" | ||||
@@ -207,12 +209,104 @@ class X25519KeyShare : public SSLKeyShare { | |||||
uint8_t private_key_[32]; | 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[] = { | CONSTEXPR_ARRAY NamedGroup kNamedGroups[] = { | ||||
{NID_secp224r1, SSL_CURVE_SECP224R1, "P-224", "secp224r1"}, | {NID_secp224r1, SSL_CURVE_SECP224R1, "P-224", "secp224r1"}, | ||||
{NID_X9_62_prime256v1, SSL_CURVE_SECP256R1, "P-256", "prime256v1"}, | {NID_X9_62_prime256v1, SSL_CURVE_SECP256R1, "P-256", "prime256v1"}, | ||||
{NID_secp384r1, SSL_CURVE_SECP384R1, "P-384", "secp384r1"}, | {NID_secp384r1, SSL_CURVE_SECP384R1, "P-384", "secp384r1"}, | ||||
{NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", "secp521r1"}, | {NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", "secp521r1"}, | ||||
{NID_X25519, SSL_CURVE_X25519, "X25519", "x25519"}, | {NID_X25519, SSL_CURVE_X25519, "X25519", "x25519"}, | ||||
{NID_CECPQ2, SSL_CURVE_CECPQ2, "CECPQ2", "CECPQ2"}, | |||||
}; | }; | ||||
} // namespace | } // namespace | ||||
@@ -237,6 +331,8 @@ UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) { | |||||
New<ECKeyShare>(NID_secp521r1, SSL_CURVE_SECP521R1)); | New<ECKeyShare>(NID_secp521r1, SSL_CURVE_SECP521R1)); | ||||
case SSL_CURVE_X25519: | case SSL_CURVE_X25519: | ||||
return UniquePtr<SSLKeyShare>(New<X25519KeyShare>()); | return UniquePtr<SSLKeyShare>(New<X25519KeyShare>()); | ||||
case SSL_CURVE_CECPQ2: | |||||
return UniquePtr<SSLKeyShare>(New<CECPQ2KeyShare>()); | |||||
default: | default: | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
@@ -394,6 +394,11 @@ static const CurveTest kCurveTests[] = { | |||||
"P-256", | "P-256", | ||||
{ SSL_CURVE_SECP256R1 }, | { SSL_CURVE_SECP256R1 }, | ||||
}, | }, | ||||
{ | |||||
"P-256:CECPQ2", | |||||
{ SSL_CURVE_SECP256R1, SSL_CURVE_CECPQ2 }, | |||||
}, | |||||
{ | { | ||||
"P-256:P-384:P-521:X25519", | "P-256:P-384:P-521:X25519", | ||||
{ | { | ||||
@@ -292,10 +292,23 @@ static const uint16_t kDefaultGroups[] = { | |||||
SSL_CURVE_SECP384R1, | 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) { | Span<const uint16_t> tls1_get_grouplist(const SSL_HANDSHAKE *hs) { | ||||
if (!hs->config->supported_group_list.empty()) { | if (!hs->config->supported_group_list.empty()) { | ||||
return hs->config->supported_group_list; | return hs->config->supported_group_list; | ||||
} | } | ||||
if (hs->ssl->server) { | |||||
return Span<const uint16_t>(kDefaultGroupsServer); | |||||
} | |||||
return Span<const uint16_t>(kDefaultGroups); | 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 pref_group : pref) { | ||||
for (uint16_t supp_group : supp) { | 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; | *out_group_id = pref_group; | ||||
return true; | 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) { | 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)) { | for (uint16_t supported : tls1_get_grouplist(hs)) { | ||||
if (supported == group_id) { | if (supported == group_id) { | ||||
return true; | 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 group_id = hs->retry_group; | ||||
uint16_t second_group_id = 0; | |||||
if (hs->received_hello_retry_request) { | if (hs->received_hello_retry_request) { | ||||
// We received a HelloRetryRequest without a new curve, so there is no new | // We received a HelloRetryRequest without a new curve, so there is no new | ||||
// share to append. Leave |hs->key_share| as-is. | // 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]; | 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; | 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(&kse_bytes, group_id) || | ||||
!CBB_add_u16_length_prefixed(&kse_bytes, &key_exchange) || | !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)) { | !CBB_flush(&kse_bytes)) { | ||||
return false; | 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 && | if (!hs->received_hello_retry_request && | ||||
!hs->key_share_bytes.CopyFrom( | !hs->key_share_bytes.CopyFrom( | ||||
MakeConstSpan(CBB_data(&kse_bytes), CBB_len(&kse_bytes)))) { | 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; | 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; | *out_alert = SSL_AD_INTERNAL_ERROR; | ||||
return false; | return false; | ||||
} | } | ||||
hs->new_session->group_id = group_id; | hs->new_session->group_id = group_id; | ||||
hs->key_share.reset(); | |||||
hs->key_shares[0].reset(); | |||||
hs->key_shares[1].reset(); | |||||
return true; | 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)) { | 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)) { | if (!CBB_add_u16(&groups_bytes, group)) { | ||||
return false; | return false; | ||||
} | } | ||||
@@ -649,7 +649,6 @@ static bool DoConnection(bssl::UniquePtr<SSL_SESSION> *out_session, | |||||
SSL_set_connect_state(ssl.get()); | SSL_set_connect_state(ssl.get()); | ||||
} | } | ||||
int sock = Connect(config->port); | int sock = Connect(config->port); | ||||
if (sock == -1) { | if (sock == -1) { | ||||
return false; | return false; | ||||
@@ -26,7 +26,7 @@ type keyAgreement interface { | |||||
// In the case that the key agreement protocol doesn't use a | // In the case that the key agreement protocol doesn't use a | ||||
// ServerKeyExchange message, generateServerKeyExchange can return nil, | // ServerKeyExchange message, generateServerKeyExchange can return nil, | ||||
// nil. | // nil. | ||||
generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error) | |||||
generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg, uint16) (*serverKeyExchangeMsg, error) | |||||
processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error) | processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error) | ||||
// On the client side, the next two methods are called in order. | // On the client side, the next two methods are called in order. | ||||
@@ -163,6 +163,7 @@ const ( | |||||
CurveP384 CurveID = 24 | CurveP384 CurveID = 24 | ||||
CurveP521 CurveID = 25 | CurveP521 CurveID = 25 | ||||
CurveX25519 CurveID = 29 | CurveX25519 CurveID = 29 | ||||
CurveCECPQ2 CurveID = 16696 | |||||
) | ) | ||||
// TLS Elliptic Curve Point Formats | // TLS Elliptic Curve Point Formats | ||||
@@ -1645,6 +1646,18 @@ type ProtocolBugs struct { | |||||
// ExpectJDK11DowngradeRandom is whether the client should expect the | // ExpectJDK11DowngradeRandom is whether the client should expect the | ||||
// server to send the JDK 11 downgrade signal. | // server to send the JDK 11 downgrade signal. | ||||
ExpectJDK11DowngradeRandom bool | 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() { | func (c *Config) serverInit() { | ||||
@@ -1724,7 +1737,7 @@ func (c *Config) maxVersion(isDTLS bool) uint16 { | |||||
return ret | return ret | ||||
} | } | ||||
var defaultCurvePreferences = []CurveID{CurveX25519, CurveP256, CurveP384, CurveP521} | |||||
var defaultCurvePreferences = []CurveID{CurveCECPQ2, CurveX25519, CurveP256, CurveP384, CurveP521} | |||||
func (c *Config) curvePreferences() []CurveID { | func (c *Config) curvePreferences() []CurveID { | ||||
if c == nil || len(c.CurvePreferences) == 0 { | if c == nil || len(c.CurvePreferences) == 0 { | ||||
@@ -549,6 +549,9 @@ NextCipherSuite: | |||||
helloRetryRequest, haveHelloRetryRequest := msg.(*helloRetryRequestMsg) | helloRetryRequest, haveHelloRetryRequest := msg.(*helloRetryRequestMsg) | ||||
var secondHelloBytes []byte | var secondHelloBytes []byte | ||||
if haveHelloRetryRequest { | if haveHelloRetryRequest { | ||||
if c.config.Bugs.FailIfHelloRetryRequested { | |||||
return errors.New("tls: unexpected HelloRetryRequest") | |||||
} | |||||
// Explicitly read the ChangeCipherSpec now; it should | // Explicitly read the ChangeCipherSpec now; it should | ||||
// be attached to the first flight, not the second flight. | // be attached to the first flight, not the second flight. | ||||
if err := c.readTLS13ChangeCipherSpec(); err != nil { | 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 | c.clientVersion = hs.clientHello.vers | ||||
// Use the versions extension if supplied, otherwise use the legacy ClientHello version. | // 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() | preferredCurves := config.curvePreferences() | ||||
Curves: | Curves: | ||||
for _, curve := range hs.clientHello.supportedCurves { | for _, curve := range hs.clientHello.supportedCurves { | ||||
if curve == CurveCECPQ2 && c.vers < VersionTLS13 { | |||||
// CECPQ2 is TLS 1.3-only. | |||||
continue | |||||
} | |||||
for _, supported := range preferredCurves { | for _, supported := range preferredCurves { | ||||
if supported == curve { | if supported == curve { | ||||
supportedCurve = true | supportedCurve = true | ||||
@@ -1621,7 +1646,7 @@ func (hs *serverHandshakeState) doFullHandshake() error { | |||||
} | } | ||||
keyAgreement := hs.suite.ka(c.vers) | 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 { | if err != nil { | ||||
c.sendAlert(alertHandshakeFailure) | c.sendAlert(alertHandshakeFailure) | ||||
return err | return err | ||||
@@ -17,6 +17,7 @@ import ( | |||||
"boringssl.googlesource.com/boringssl/ssl/test/runner/curve25519" | "boringssl.googlesource.com/boringssl/ssl/test/runner/curve25519" | ||||
"boringssl.googlesource.com/boringssl/ssl/test/runner/ed25519" | "boringssl.googlesource.com/boringssl/ssl/test/runner/ed25519" | ||||
"boringssl.googlesource.com/boringssl/ssl/test/runner/hrss" | |||||
) | ) | ||||
type keyType int | type keyType int | ||||
@@ -37,7 +38,7 @@ type rsaKeyAgreement struct { | |||||
exportKey *rsa.PrivateKey | 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. | // Save the client version for comparison later. | ||||
ka.clientVersion = clientHello.vers | ka.clientVersion = clientHello.vers | ||||
@@ -347,6 +348,90 @@ func (e *x25519ECDHCurve) finish(peerKey []byte) (preMasterSecret []byte, err er | |||||
return out[:], nil | 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) { | func curveForCurveID(id CurveID, config *Config) (ecdhCurve, bool) { | ||||
switch id { | switch id { | ||||
case CurveP224: | case CurveP224: | ||||
@@ -359,6 +444,8 @@ func curveForCurveID(id CurveID, config *Config) (ecdhCurve, bool) { | |||||
return &ellipticECDHCurve{curve: elliptic.P521(), sendCompressed: config.Bugs.SendCompressedCoordinates}, true | return &ellipticECDHCurve{curve: elliptic.P521(), sendCompressed: config.Bugs.SendCompressedCoordinates}, true | ||||
case CurveX25519: | case CurveX25519: | ||||
return &x25519ECDHCurve{setHighBit: config.Bugs.SetX25519HighBit}, true | return &x25519ECDHCurve{setHighBit: config.Bugs.SetX25519HighBit}, true | ||||
case CurveCECPQ2: | |||||
return &cecpq2Curve{}, true | |||||
default: | default: | ||||
return nil, false | return nil, false | ||||
} | } | ||||
@@ -501,12 +588,17 @@ type ecdheKeyAgreement struct { | |||||
peerKey []byte | 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 | var curveid CurveID | ||||
preferredCurves := config.curvePreferences() | preferredCurves := config.curvePreferences() | ||||
NextCandidate: | NextCandidate: | ||||
for _, candidate := range preferredCurves { | for _, candidate := range preferredCurves { | ||||
if candidate == CurveCECPQ2 && version < VersionTLS13 { | |||||
// CECPQ2 is TLS 1.3-only. | |||||
continue | |||||
} | |||||
for _, c := range clientHello.supportedCurves { | for _, c := range clientHello.supportedCurves { | ||||
if candidate == c { | if candidate == c { | ||||
curveid = c | curveid = c | ||||
@@ -614,7 +706,7 @@ func (ka *ecdheKeyAgreement) peerSignatureAlgorithm() signatureAlgorithm { | |||||
// exchange. | // exchange. | ||||
type nilKeyAgreement struct{} | 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 | return nil, nil | ||||
} | } | ||||
@@ -666,7 +758,7 @@ type pskKeyAgreement struct { | |||||
identityHint string | 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. | // Assemble the identity hint. | ||||
bytes := make([]byte, 2+len(config.PreSharedKeyIdentity)) | bytes := make([]byte, 2+len(config.PreSharedKeyIdentity)) | ||||
bytes[0] = byte(len(config.PreSharedKeyIdentity) >> 8) | 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 | // If there is one, append the base key agreement's | ||||
// ServerKeyExchange. | // ServerKeyExchange. | ||||
baseSkx, err := ka.base.generateServerKeyExchange(config, cert, clientHello, hello) | |||||
baseSkx, err := ka.base.generateServerKeyExchange(config, cert, clientHello, hello, version) | |||||
if err != nil { | if err != nil { | ||||
return nil, err | return nil, err | ||||
} | } | ||||
@@ -9619,7 +9619,7 @@ func addSignatureAlgorithmTests() { | |||||
CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, | ||||
Certificates: []Certificate{ecdsaP256Certificate}, | Certificates: []Certificate{ecdsaP256Certificate}, | ||||
}, | }, | ||||
flags: []string{"-p384-only"}, | |||||
flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, | |||||
shouldFail: true, | shouldFail: true, | ||||
expectedError: ":BAD_ECC_CERT:", | expectedError: ":BAD_ECC_CERT:", | ||||
}) | }) | ||||
@@ -9631,7 +9631,7 @@ func addSignatureAlgorithmTests() { | |||||
MaxVersion: VersionTLS13, | MaxVersion: VersionTLS13, | ||||
Certificates: []Certificate{ecdsaP256Certificate}, | 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. | // In TLS 1.2, the ECDSA curve is not in the signature algorithm. | ||||
@@ -10711,6 +10711,7 @@ var testCurves = []struct { | |||||
{"P-384", CurveP384}, | {"P-384", CurveP384}, | ||||
{"P-521", CurveP521}, | {"P-521", CurveP521}, | ||||
{"X25519", CurveX25519}, | {"X25519", CurveX25519}, | ||||
{"CECPQ2", CurveCECPQ2}, | |||||
} | } | ||||
const bogusCurve = 0x1234 | const bogusCurve = 0x1234 | ||||
@@ -10718,6 +10719,10 @@ const bogusCurve = 0x1234 | |||||
func addCurveTests() { | func addCurveTests() { | ||||
for _, curve := range testCurves { | for _, curve := range testCurves { | ||||
for _, ver := range tlsVersions { | for _, ver := range tlsVersions { | ||||
if curve.id == CurveCECPQ2 && ver.version < VersionTLS13 { | |||||
continue | |||||
} | |||||
suffix := curve.name + "-" + ver.name | suffix := curve.name + "-" + ver.name | ||||
testCases = append(testCases, testCase{ | testCases = append(testCases, testCase{ | ||||
@@ -10758,7 +10763,7 @@ func addCurveTests() { | |||||
expectedCurveID: curve.id, | expectedCurveID: curve.id, | ||||
}) | }) | ||||
if curve.id != CurveX25519 { | |||||
if curve.id != CurveX25519 && curve.id != CurveCECPQ2 { | |||||
testCases = append(testCases, testCase{ | testCases = append(testCases, testCase{ | ||||
name: "CurveTest-Client-Compressed-" + suffix, | name: "CurveTest-Client-Compressed-" + suffix, | ||||
config: Config{ | config: Config{ | ||||
@@ -10902,7 +10907,7 @@ func addCurveTests() { | |||||
IgnorePeerCurvePreferences: true, | IgnorePeerCurvePreferences: true, | ||||
}, | }, | ||||
}, | }, | ||||
flags: []string{"-p384-only"}, | |||||
flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, | |||||
shouldFail: true, | shouldFail: true, | ||||
expectedError: ":WRONG_CURVE:", | expectedError: ":WRONG_CURVE:", | ||||
}) | }) | ||||
@@ -10918,7 +10923,7 @@ func addCurveTests() { | |||||
SendCurve: CurveP256, | SendCurve: CurveP256, | ||||
}, | }, | ||||
}, | }, | ||||
flags: []string{"-p384-only"}, | |||||
flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, | |||||
shouldFail: true, | shouldFail: true, | ||||
expectedError: ":WRONG_CURVE:", | 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() { | func addTLS13RecordTests() { | ||||
@@ -12706,7 +12817,7 @@ func addTLS13HandshakeTests() { | |||||
}, | }, | ||||
}, | }, | ||||
tls13Variant: variant, | tls13Variant: variant, | ||||
flags: []string{"-p384-only"}, | |||||
flags: []string{"-curves", strconv.Itoa(int(CurveP384))}, | |||||
shouldFail: true, | shouldFail: true, | ||||
expectedError: ":WRONG_CURVE:", | expectedError: ":WRONG_CURVE:", | ||||
}) | }) | ||||
@@ -104,7 +104,6 @@ const Flag<bool> kBoolFlags[] = { | |||||
{ "-renegotiate-ignore", &TestConfig::renegotiate_ignore }, | { "-renegotiate-ignore", &TestConfig::renegotiate_ignore }, | ||||
{ "-forbid-renegotiation-after-handshake", | { "-forbid-renegotiation-after-handshake", | ||||
&TestConfig::forbid_renegotiation_after_handshake }, | &TestConfig::forbid_renegotiation_after_handshake }, | ||||
{ "-p384-only", &TestConfig::p384_only }, | |||||
{ "-enable-all-curves", &TestConfig::enable_all_curves }, | { "-enable-all-curves", &TestConfig::enable_all_curves }, | ||||
{ "-use-old-client-cert-callback", | { "-use-old-client-cert-callback", | ||||
&TestConfig::use_old_client_cert_callback }, | &TestConfig::use_old_client_cert_callback }, | ||||
@@ -147,6 +146,7 @@ const Flag<bool> kBoolFlags[] = { | |||||
{ "-handshaker-resume", &TestConfig::handshaker_resume }, | { "-handshaker-resume", &TestConfig::handshaker_resume }, | ||||
{ "-reverify-on-resume", &TestConfig::reverify_on_resume }, | { "-reverify-on-resume", &TestConfig::reverify_on_resume }, | ||||
{ "-jdk11-workaround", &TestConfig::jdk11_workaround }, | { "-jdk11-workaround", &TestConfig::jdk11_workaround }, | ||||
{ "-server-preference", &TestConfig::server_preference }, | |||||
}; | }; | ||||
const Flag<std::string> kStringFlags[] = { | const Flag<std::string> kStringFlags[] = { | ||||
@@ -220,10 +220,10 @@ const Flag<int> kIntFlags[] = { | |||||
}; | }; | ||||
const Flag<std::vector<int>> kIntVectorFlags[] = { | 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, | 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; | return nullptr; | ||||
} | } | ||||
if (install_cert_compression_algs && | if (install_cert_compression_algs && | ||||
(!SSL_CTX_add_cert_compression_alg( | (!SSL_CTX_add_cert_compression_alg( | ||||
ssl_ctx.get(), 0xff02, | ssl_ctx.get(), 0xff02, | ||||
@@ -1341,6 +1340,10 @@ bssl::UniquePtr<SSL_CTX> TestConfig::SetupCtx(SSL_CTX *old_ctx) const { | |||||
abort(); | abort(); | ||||
} | } | ||||
if (server_preference) { | |||||
SSL_CTX_set_options(ssl_ctx.get(), SSL_OP_CIPHER_SERVER_PREFERENCE); | |||||
} | |||||
return ssl_ctx; | return ssl_ctx; | ||||
} | } | ||||
@@ -1589,16 +1592,43 @@ bssl::UniquePtr<SSL> TestConfig::NewSSL( | |||||
if (!check_close_notify) { | if (!check_close_notify) { | ||||
SSL_set_quiet_shutdown(ssl.get(), 1); | 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) { | if (enable_all_curves) { | ||||
static const int kAllCurves[] = { | static const int kAllCurves[] = { | ||||
NID_secp224r1, NID_X9_62_prime256v1, NID_secp384r1, | 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, | if (!SSL_set1_curves(ssl.get(), kAllCurves, | ||||
OPENSSL_ARRAY_SIZE(kAllCurves))) { | OPENSSL_ARRAY_SIZE(kAllCurves))) { | ||||
@@ -33,6 +33,7 @@ struct TestConfig { | |||||
std::vector<int> signing_prefs; | std::vector<int> signing_prefs; | ||||
std::vector<int> verify_prefs; | std::vector<int> verify_prefs; | ||||
std::vector<int> expected_peer_verify_prefs; | std::vector<int> expected_peer_verify_prefs; | ||||
std::vector<int> curves; | |||||
std::string key_file; | std::string key_file; | ||||
std::string cert_file; | std::string cert_file; | ||||
std::string expected_server_name; | std::string expected_server_name; | ||||
@@ -122,7 +123,6 @@ struct TestConfig { | |||||
bool renegotiate_ignore = false; | bool renegotiate_ignore = false; | ||||
bool forbid_renegotiation_after_handshake = false; | bool forbid_renegotiation_after_handshake = false; | ||||
int expect_peer_signature_algorithm = 0; | int expect_peer_signature_algorithm = 0; | ||||
bool p384_only = false; | |||||
bool enable_all_curves = false; | bool enable_all_curves = false; | ||||
int expect_curve_id = 0; | int expect_curve_id = 0; | ||||
bool use_old_client_cert_callback = false; | bool use_old_client_cert_callback = false; | ||||
@@ -170,6 +170,7 @@ struct TestConfig { | |||||
bool handshaker_resume = false; | bool handshaker_resume = false; | ||||
std::string handshaker_path; | std::string handshaker_path; | ||||
bool jdk11_workaround = false; | bool jdk11_workaround = false; | ||||
bool server_preference = false; | |||||
int argc; | int argc; | ||||
char **argv; | char **argv; | ||||
@@ -165,15 +165,17 @@ static enum ssl_hs_wait_t do_read_hello_retry_request(SSL_HANDSHAKE *hs) { | |||||
return ssl_hs_error; | 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); | ssl_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_ILLEGAL_PARAMETER); | ||||
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); | OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); | ||||
return ssl_hs_error; | return ssl_hs_error; | ||||
} | } | ||||
hs->key_share.reset(); | |||||
hs->key_shares[0].reset(); | |||||
hs->key_shares[1].reset(); | |||||
hs->retry_group = group_id; | hs->retry_group = group_id; | ||||
} | } | ||||
@@ -32,6 +32,7 @@ | |||||
#include <openssl/ecdsa.h> | #include <openssl/ecdsa.h> | ||||
#include <openssl/ec_key.h> | #include <openssl/ec_key.h> | ||||
#include <openssl/evp.h> | #include <openssl/evp.h> | ||||
#include <openssl/hrss.h> | |||||
#include <openssl/nid.h> | #include <openssl/nid.h> | ||||
#include <openssl/rand.h> | #include <openssl/rand.h> | ||||
#include <openssl/rsa.h> | #include <openssl/rsa.h> | ||||
@@ -744,6 +745,61 @@ static bool SpeedScrypt(const std::string &selected) { | |||||
return true; | 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[] = { | static const struct argument kArguments[] = { | ||||
{ | { | ||||
"-filter", kOptionalArgument, | "-filter", kOptionalArgument, | ||||
@@ -817,7 +873,8 @@ bool Speed(const std::vector<std::string> &args) { | |||||
!Speed25519(selected) || | !Speed25519(selected) || | ||||
!SpeedSPAKE2(selected) || | !SpeedSPAKE2(selected) || | ||||
!SpeedScrypt(selected) || | !SpeedScrypt(selected) || | ||||
!SpeedRSAKeyGen(selected)) { | |||||
!SpeedRSAKeyGen(selected) || | |||||
!SpeedHRSS(selected)) { | |||||
return false; | return false; | ||||
} | } | ||||
@@ -43,6 +43,10 @@ NON_PERL_FILES = { | |||||
('linux', 'arm'): [ | ('linux', 'arm'): [ | ||||
'src/crypto/curve25519/asm/x25519-asm-arm.S', | 'src/crypto/curve25519/asm/x25519-asm-arm.S', | ||||
'src/crypto/poly1305/poly1305_arm_asm.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', | |||||
], | ], | ||||
} | } | ||||