Add initial HRSS support.

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>
This commit is contained in:
Adam Langley 2018-11-12 13:53:42 -08:00 committed by Adam Langley
parent 602f4669ab
commit 7b935937b1
32 changed files with 17414 additions and 65 deletions

View File

@ -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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2265
crypto/hrss/hrss.c Normal file

File diff suppressed because it is too large Load Diff

475
crypto/hrss/hrss_test.cc Normal file
View File

@ -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));
}

50
crypto/hrss/internal.h Normal file
View File

@ -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

View File

@ -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 */,

View File

@ -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

View File

@ -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

102
include/openssl/hrss.h Normal file
View File

@ -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

View File

@ -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 */

View File

@ -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.

View File

@ -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;
} }

View File

@ -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); hs->key_shares[0] = SSLKeyShare::Create(group_id);
if (!hs->key_share || 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

View File

@ -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); hs->key_shares[0] = SSLKeyShare::Create(group_id);
if (!hs->key_share || 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);

View File

@ -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 // and sets |*out_secret| to the shared secret. On failure, it returns false
// sets |*out_alert| to an alert to send to the peer. // 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. // key_shares are the current key exchange instances. The second is only used
UniquePtr<SSLKeyShare> key_share; // 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;

View File

@ -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;
} }

View File

@ -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",
{ {

View File

@ -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) { 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; *out_alert = SSL_AD_ILLEGAL_PARAMETER;
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE); OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_CURVE);
return false; 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;
} }

View File

@ -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;

View File

@ -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.

View File

@ -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 {

View File

@ -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 {

View File

@ -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

1230
ssl/test/runner/hrss/hrss.go Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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
} }

View File

@ -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:",
}) })

View File

@ -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 }, {"-signing-prefs", &TestConfig::signing_prefs},
{ "-verify-prefs", &TestConfig::verify_prefs }, {"-verify-prefs", &TestConfig::verify_prefs},
{ "-expect-peer-verify-pref", {"-expect-peer-verify-pref", &TestConfig::expected_peer_verify_prefs},
&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) { if (!curves.empty()) {
int nid = NID_secp384r1; std::vector<int> nids;
if (!SSL_set1_curves(ssl.get(), &nid, 1)) { 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; 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))) {

View File

@ -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;

View File

@ -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 // Check that the HelloRetryRequest does not request a key share that was
// was provided in the initial ClientHello. // provided in the initial ClientHello.
if (hs->key_share->GroupID() == group_id) { 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;
} }

View File

@ -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;
} }

View File

@ -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',
], ],
} }