Drop CECPQ2 support.

HRSS itself remains in libcrypto because there are some direct users of
it. But this will let it be dropped by the linker in many cases.

Change-Id: I870eda30c9ed1d08693c770e9e7df45a2711b7df
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/58645
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
fips-20230428
Adam Langley 2 years ago committed by Boringssl LUCI CQ
parent 298e6c2b9c
commit 4ae4fb76c8
  1. 4
      crypto/obj/obj_dat.h
  2. 1
      crypto/obj/obj_mac.num
  3. 1
      crypto/obj/objects.txt
  4. 3
      include/openssl/nid.h
  5. 1
      include/openssl/ssl.h
  6. 3
      ssl/extensions.cc
  7. 98
      ssl/ssl_key_share.cc
  8. 4
      ssl/ssl_test.cc
  9. 5
      ssl/test/fuzzer.h
  10. 18
      ssl/test/runner/common.go
  11. 6
      ssl/test/runner/handshake_server.go
  12. 1212
      ssl/test/runner/hrss/hrss.go
  13. 89
      ssl/test/runner/key_agreement.go
  14. 68
      ssl/test/runner/runner.go
  15. 4
      ssl/test/test_config.cc

@ -8777,7 +8777,7 @@ static const ASN1_OBJECT kObjects[NUM_NID] = {
{"AuthPSK", "auth-psk", NID_auth_psk, 0, NULL, 0},
{"KxANY", "kx-any", NID_kx_any, 0, NULL, 0},
{"AuthANY", "auth-any", NID_auth_any, 0, NULL, 0},
{"CECPQ2", "CECPQ2", NID_CECPQ2, 0, NULL, 0},
{NULL, NULL, NID_undef, 0, NULL, 0},
{"ED448", "ED448", NID_ED448, 3, &kObjectData[6181], 0},
{"X448", "X448", NID_X448, 3, &kObjectData[6184], 0},
{"SHA512-256", "sha512-256", NID_sha512_256, 9, &kObjectData[6187], 0},
@ -8846,7 +8846,6 @@ static const uint16_t kNIDsInShortNameOrder[] = {
110 /* CAST5-CFB */,
109 /* CAST5-ECB */,
111 /* CAST5-OFB */,
959 /* CECPQ2 */,
894 /* CMAC */,
13 /* CN */,
141 /* CRLReason */,
@ -9758,7 +9757,6 @@ static const uint16_t kNIDsInLongNameOrder[] = {
285 /* Biometric Info */,
179 /* CA Issuers */,
785 /* CA Repository */,
959 /* CECPQ2 */,
131 /* Code Signing */,
783 /* Diffie-Hellman based MAC */,
382 /* Directory */,

@ -947,7 +947,6 @@ auth_ecdsa 955
auth_psk 956
kx_any 957
auth_any 958
CECPQ2 959
ED448 960
X448 961
sha512_256 962

@ -1333,7 +1333,6 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme
: dh-cofactor-kdf
# NIDs for post quantum key agreements (no corresponding OIDs).
: CECPQ2
: X25519Kyber768
: P256Kyber768
: P384Kyber768

@ -4235,9 +4235,6 @@ extern "C" {
#define LN_auth_any "auth-any"
#define NID_auth_any 958
#define SN_CECPQ2 "CECPQ2"
#define NID_CECPQ2 959
#define SN_ED448 "ED448"
#define NID_ED448 960
#define OBJ_ED448 1L, 3L, 101L, 113L

@ -2334,7 +2334,6 @@ OPENSSL_EXPORT int SSL_set1_curves_list(SSL *ssl, const char *curves);
#define SSL_CURVE_SECP384R1 24
#define SSL_CURVE_SECP521R1 25
#define SSL_CURVE_X25519 29
#define SSL_CURVE_CECPQ2 16696
#define SSL_CURVE_X25519KYBER768 0x6399
#define SSL_CURVE_P256KYBER768 0xfe32

@ -206,7 +206,6 @@ static bool tls1_check_duplicate_extensions(const CBS *cbs) {
static bool is_post_quantum_group(uint16_t id) {
switch (id) {
case SSL_CURVE_CECPQ2:
case SSL_CURVE_X25519KYBER768:
case SSL_CURVE_P256KYBER768:
return true;
@ -414,7 +413,7 @@ bool tls1_set_curves_list(Array<uint16_t> *out_group_ids, const char *curves) {
bool tls1_check_group_id(const SSL_HANDSHAKE *hs, uint16_t group_id) {
if (is_post_quantum_group(group_id) &&
ssl_protocol_version(hs->ssl) < TLS1_3_VERSION) {
// CECPQ2(b) requires TLS 1.3.
// Post-quantum "groups" require TLS 1.3.
return false;
}

@ -192,101 +192,6 @@ class X25519KeyShare : public SSLKeyShare {
uint8_t private_key_[32];
};
class CECPQ2KeyShare : public SSLKeyShare {
public:
CECPQ2KeyShare() {}
uint16_t GroupID() const override { return SSL_CURVE_CECPQ2; }
bool Generate(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];
HRSS_public_key hrss_public_key;
RAND_bytes(hrss_entropy, sizeof(hrss_entropy));
if (!HRSS_generate_key(&hrss_public_key, &hrss_private_key_,
hrss_entropy)) {
return false;
}
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 Encap(CBB *out_ciphertext, 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)) {
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));
if (!HRSS_encap(ciphertext, secret.data() + 32, &peer_public_key,
entropy) ||
!CBB_add_bytes(out_ciphertext, x25519_public_key,
sizeof(x25519_public_key)) ||
!CBB_add_bytes(out_ciphertext, ciphertext, sizeof(ciphertext))) {
return false;
}
*out_secret = std::move(secret);
return true;
}
bool Decap(Array<uint8_t> *out_secret, uint8_t *out_alert,
Span<const uint8_t> ciphertext) override {
*out_alert = SSL_AD_INTERNAL_ERROR;
Array<uint8_t> secret;
if (!secret.Init(32 + HRSS_KEY_BYTES)) {
return false;
}
if (ciphertext.size() != 32 + HRSS_CIPHERTEXT_BYTES ||
!X25519(secret.data(), x25519_private_key_, ciphertext.data())) {
*out_alert = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
return false;
}
if (!HRSS_decap(secret.data() + 32, &hrss_private_key_,
ciphertext.data() + 32, ciphertext.size() - 32)) {
return false;
}
*out_secret = std::move(secret);
return true;
}
private:
uint8_t x25519_private_key_[32];
HRSS_private_key hrss_private_key_;
};
class X25519Kyber768KeyShare : public SSLKeyShare {
public:
X25519Kyber768KeyShare() {}
@ -405,7 +310,6 @@ constexpr NamedGroup kNamedGroups[] = {
{NID_secp384r1, SSL_CURVE_SECP384R1, "P-384", "secp384r1"},
{NID_secp521r1, SSL_CURVE_SECP521R1, "P-521", "secp521r1"},
{NID_X25519, SSL_CURVE_X25519, "X25519", "x25519"},
{NID_CECPQ2, SSL_CURVE_CECPQ2, "CECPQ2", "CECPQ2"},
{NID_X25519Kyber768, SSL_CURVE_X25519KYBER768, "X25519KYBER",
"X25519Kyber"},
{NID_P256Kyber768, SSL_CURVE_P256KYBER768, "P256KYBER", "P256Kyber"},
@ -429,8 +333,6 @@ UniquePtr<SSLKeyShare> SSLKeyShare::Create(uint16_t group_id) {
return MakeUnique<ECKeyShare>(NID_secp521r1, SSL_CURVE_SECP521R1);
case SSL_CURVE_X25519:
return MakeUnique<X25519KeyShare>();
case SSL_CURVE_CECPQ2:
return MakeUnique<CECPQ2KeyShare>();
case SSL_CURVE_X25519KYBER768:
return MakeUnique<X25519Kyber768KeyShare>();
case SSL_CURVE_P256KYBER768:

@ -401,8 +401,8 @@ static const CurveTest kCurveTests[] = {
{ SSL_CURVE_SECP256R1 },
},
{
"P-256:CECPQ2",
{ SSL_CURVE_SECP256R1, SSL_CURVE_CECPQ2 },
"P-256:X25519KYBER",
{ SSL_CURVE_SECP256R1, SSL_CURVE_X25519KYBER768 },
},
{

@ -418,8 +418,9 @@ class TLSFuzzer {
return false;
}
static const int kCurves[] = {NID_CECPQ2, NID_X25519, NID_X9_62_prime256v1,
NID_secp384r1, NID_secp521r1};
static const int kCurves[] = {NID_X25519Kyber768, NID_X25519,
NID_X9_62_prime256v1, NID_secp384r1,
NID_secp521r1};
if (!SSL_CTX_set1_curves(ctx_.get(), kCurves,
OPENSSL_ARRAY_SIZE(kCurves))) {
return false;

@ -148,12 +148,12 @@ var tls13HelloRetryRequest = []uint8{
type CurveID uint16
const (
CurveP224 CurveID = 21
CurveP256 CurveID = 23
CurveP384 CurveID = 24
CurveP521 CurveID = 25
CurveX25519 CurveID = 29
CurveCECPQ2 CurveID = 16696
CurveP224 CurveID = 21
CurveP256 CurveID = 23
CurveP384 CurveID = 24
CurveP521 CurveID = 25
CurveX25519 CurveID = 29
CurveX25519Kyber768 CurveID = 0x6399
)
// TLS Elliptic Curve Point Formats
@ -1890,9 +1890,9 @@ type ProtocolBugs struct {
// hello retry.
FailIfHelloRetryRequested bool
// FailedIfCECPQ2Offered will cause a server to reject a ClientHello if CECPQ2
// FailedIfKyberOffered will cause a server to reject a ClientHello if Kyber
// is supported.
FailIfCECPQ2Offered bool
FailIfKyberOffered bool
// ExpectKeyShares, if not nil, lists (in order) the curves that a ClientHello
// should have key shares for.
@ -1996,7 +1996,7 @@ func (c *Config) maxVersion(isDTLS bool) uint16 {
return ret
}
var defaultCurvePreferences = []CurveID{CurveCECPQ2, CurveX25519, CurveP256, CurveP384, CurveP521}
var defaultCurvePreferences = []CurveID{CurveX25519, CurveP256, CurveP384, CurveP521}
func (c *Config) curvePreferences() []CurveID {
if c == nil || len(c.CurvePreferences) == 0 {

@ -280,10 +280,10 @@ func (hs *serverHandshakeState) readClientHello() error {
}
}
if config.Bugs.FailIfCECPQ2Offered {
if config.Bugs.FailIfKyberOffered {
for _, offeredCurve := range hs.clientHello.supportedCurves {
if isPqGroup(offeredCurve) {
return errors.New("tls: CECPQ2 was offered")
return errors.New("tls: X25519Kyber768 was offered")
}
}
}
@ -1467,7 +1467,7 @@ func (hs *serverHandshakeState) processClientHello() (isResume bool, err error)
Curves:
for _, curve := range hs.clientHello.supportedCurves {
if isPqGroup(curve) && c.vers < VersionTLS13 {
// CECPQ2 is TLS 1.3-only.
// Post-quantum is TLS 1.3 only.
continue
}

File diff suppressed because it is too large Load Diff

@ -17,7 +17,6 @@ import (
"io"
"math/big"
"boringssl.googlesource.com/boringssl/ssl/test/runner/hrss"
"golang.org/x/crypto/curve25519"
)
@ -341,90 +340,6 @@ func (e *x25519KEM) decap(ciphertext []byte) (secret []byte, err error) {
return out[:], nil
}
// cecpq2KEM implements CECPQ2, which is HRSS+SXY combined with X25519.
type cecpq2KEM struct {
x25519PrivateKey [32]byte
hrssPrivateKey hrss.PrivateKey
}
func (e *cecpq2KEM) generate(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 *cecpq2KEM) encap(rand io.Reader, peerKey []byte) (ciphertext []byte, secret []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)
ciphertext = append(ciphertext, x25519Public[:]...)
ciphertext = append(ciphertext, hrssCiphertext...)
secret = append(secret, x25519Shared[:]...)
secret = append(secret, hrssShared...)
return ciphertext, secret, nil
}
func (e *cecpq2KEM) decap(ciphertext []byte) (secret []byte, err error) {
if len(ciphertext) != 32+hrss.CiphertextSize {
return nil, errors.New("tls: bad length CECPQ2 reply")
}
var x25519Shared, x25519PeerKey [32]byte
copy(x25519PeerKey[:], ciphertext)
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(ciphertext[32:])
if !ok {
return nil, errors.New("tls: invalid HRSS ciphertext")
}
secret = append(secret, x25519Shared[:]...)
secret = append(secret, hrssShared...)
return secret, nil
}
func kemForCurveID(id CurveID, config *Config) (kemImplementation, bool) {
switch id {
case CurveP224:
@ -437,8 +352,6 @@ func kemForCurveID(id CurveID, config *Config) (kemImplementation, bool) {
return &ecdhKEM{curve: elliptic.P521(), sendCompressed: config.Bugs.SendCompressedCoordinates}, true
case CurveX25519:
return &x25519KEM{setHighBit: config.Bugs.SetX25519HighBit}, true
case CurveCECPQ2:
return &cecpq2KEM{}, true
default:
return nil, false
}
@ -587,7 +500,7 @@ func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Cer
NextCandidate:
for _, candidate := range preferredCurves {
if isPqGroup(candidate) && version < VersionTLS13 {
// CECPQ2 is TLS 1.3-only.
// Post-quantum "groups" require TLS 1.3.
continue
}

@ -11371,13 +11371,12 @@ var testCurves = []struct {
{"P-384", CurveP384},
{"P-521", CurveP521},
{"X25519", CurveX25519},
{"CECPQ2", CurveCECPQ2},
}
const bogusCurve = 0x1234
func isPqGroup(r CurveID) bool {
return r == CurveCECPQ2
return r == CurveX25519Kyber768
}
func addCurveTests() {
@ -11841,78 +11840,79 @@ func addCurveTests() {
},
})
// CECPQ2 should not be offered by a TLS < 1.3 client.
// Kyber should not be offered by a TLS < 1.3 client.
testCases = append(testCases, testCase{
name: "CECPQ2NotInTLS12",
name: "KyberNotInTLS12",
config: Config{
Bugs: ProtocolBugs{
FailIfCECPQ2Offered: true,
FailIfKyberOffered: true,
},
},
flags: []string{
"-max-version", strconv.Itoa(VersionTLS12),
"-curves", strconv.Itoa(int(CurveCECPQ2)),
"-curves", strconv.Itoa(int(CurveX25519Kyber768)),
"-curves", strconv.Itoa(int(CurveX25519)),
},
})
// CECPQ2 should not crash a TLS < 1.3 client if the server mistakenly
// Kyber should not crash a TLS < 1.3 client if the server mistakenly
// selects it.
testCases = append(testCases, testCase{
name: "CECPQ2NotAcceptedByTLS12Client",
name: "KyberNotAcceptedByTLS12Client",
config: Config{
Bugs: ProtocolBugs{
SendCurve: CurveCECPQ2,
SendCurve: CurveX25519Kyber768,
},
},
flags: []string{
"-max-version", strconv.Itoa(VersionTLS12),
"-curves", strconv.Itoa(int(CurveCECPQ2)),
"-curves", strconv.Itoa(int(CurveX25519Kyber768)),
"-curves", strconv.Itoa(int(CurveX25519)),
},
shouldFail: true,
expectedError: ":WRONG_CURVE:",
})
// CECPQ2 should not be offered by default as a client.
// Kyber should not be offered by default as a client.
testCases = append(testCases, testCase{
name: "CECPQ2NotEnabledByDefaultInClients",
name: "KyberNotEnabledByDefaultInClients",
config: Config{
MinVersion: VersionTLS13,
Bugs: ProtocolBugs{
FailIfCECPQ2Offered: true,
FailIfKyberOffered: true,
},
},
})
// If CECPQ2 is offered, both X25519 and CECPQ2 should have a key-share.
// If Kyber is offered, both X25519 and Kyber should have a key-share.
testCases = append(testCases, testCase{
name: "NotJustCECPQ2KeyShare",
name: "NotJustKyberKeyShare",
config: Config{
MinVersion: VersionTLS13,
Bugs: ProtocolBugs{
ExpectedKeyShares: []CurveID{CurveCECPQ2, CurveX25519},
ExpectedKeyShares: []CurveID{CurveX25519Kyber768, CurveX25519},
},
},
flags: []string{
"-curves", strconv.Itoa(int(CurveCECPQ2)),
"-curves", strconv.Itoa(int(CurveX25519Kyber768)),
"-curves", strconv.Itoa(int(CurveX25519)),
"-expect-curve-id", strconv.Itoa(int(CurveCECPQ2)),
// Cannot expect Kyber until we have a Go implementation of it.
// "-expect-curve-id", strconv.Itoa(int(CurveX25519Kyber768)),
},
})
// ... and the other way around
testCases = append(testCases, testCase{
name: "CECPQ2KeyShareIncludedSecond",
name: "KyberKeyShareIncludedSecond",
config: Config{
MinVersion: VersionTLS13,
Bugs: ProtocolBugs{
ExpectedKeyShares: []CurveID{CurveX25519, CurveCECPQ2},
ExpectedKeyShares: []CurveID{CurveX25519, CurveX25519Kyber768},
},
},
flags: []string{
"-curves", strconv.Itoa(int(CurveX25519)),
"-curves", strconv.Itoa(int(CurveCECPQ2)),
"-curves", strconv.Itoa(int(CurveX25519Kyber768)),
"-expect-curve-id", strconv.Itoa(int(CurveX25519)),
},
})
@ -11921,44 +11921,46 @@ func addCurveTests() {
// first classical and first post-quantum "curves" that get key shares
// included.
testCases = append(testCases, testCase{
name: "CECPQ2KeyShareIncludedThird",
name: "KyberKeyShareIncludedThird",
config: Config{
MinVersion: VersionTLS13,
Bugs: ProtocolBugs{
ExpectedKeyShares: []CurveID{CurveX25519, CurveCECPQ2},
ExpectedKeyShares: []CurveID{CurveX25519, CurveX25519Kyber768},
},
},
flags: []string{
"-curves", strconv.Itoa(int(CurveX25519)),
"-curves", strconv.Itoa(int(CurveP256)),
"-curves", strconv.Itoa(int(CurveCECPQ2)),
"-curves", strconv.Itoa(int(CurveX25519Kyber768)),
"-expect-curve-id", strconv.Itoa(int(CurveX25519)),
},
})
// If CECPQ2 is the only configured curve, the key share is sent.
// If Kyber is the only configured curve, the key share is sent.
testCases = append(testCases, testCase{
name: "JustConfiguringCECPQ2Works",
name: "JustConfiguringKyberWorks",
config: Config{
MinVersion: VersionTLS13,
Bugs: ProtocolBugs{
ExpectedKeyShares: []CurveID{CurveCECPQ2},
ExpectedKeyShares: []CurveID{CurveX25519Kyber768},
},
},
flags: []string{
"-curves", strconv.Itoa(int(CurveCECPQ2)),
"-expect-curve-id", strconv.Itoa(int(CurveCECPQ2)),
"-curves", strconv.Itoa(int(CurveX25519Kyber768)),
"-expect-curve-id", strconv.Itoa(int(CurveX25519Kyber768)),
},
shouldFail: true,
expectedLocalError: "no curve supported by both client and server",
})
// As a server, CECPQ2 is not yet supported by default.
// As a server, Kyber is not yet supported by default.
testCases = append(testCases, testCase{
testType: serverTest,
name: "CECPQ2NotEnabledByDefaultForAServer",
name: "KyberNotEnabledByDefaultForAServer",
config: Config{
MinVersion: VersionTLS13,
CurvePreferences: []CurveID{CurveCECPQ2, CurveX25519},
DefaultCurves: []CurveID{CurveCECPQ2},
CurvePreferences: []CurveID{CurveX25519Kyber768, CurveX25519},
DefaultCurves: []CurveID{CurveX25519Kyber768},
},
flags: []string{
"-server-preference",

@ -1909,8 +1909,8 @@ bssl::UniquePtr<SSL> TestConfig::NewSSL(
nids.push_back(NID_X25519);
break;
case SSL_CURVE_CECPQ2:
nids.push_back(NID_CECPQ2);
case SSL_CURVE_X25519KYBER768:
nids.push_back(NID_X25519Kyber768);
break;
}
if (!SSL_set1_curves(ssl.get(), &nids[0], nids.size())) {

Loading…
Cancel
Save