Elliptic curve + post-quantum key exchange

CECPQ1 is a new key exchange that concatenates the results of an X25519
key agreement and a NEWHOPE key agreement.

Change-Id: Ib919bdc2e1f30f28bf80c4c18f6558017ea386bb
Reviewed-on: https://boringssl-review.googlesource.com/7962
Reviewed-by: David Benjamin <davidben@google.com>
This commit is contained in:
Matt Braithwaite 2016-05-16 16:31:05 -07:00 committed by David Benjamin
parent 61d4cdc03d
commit e25775bcac
11 changed files with 338 additions and 48 deletions

View File

@ -946,3 +946,4 @@ dhSinglePass_cofactorDH_sha512kdf_scheme 945
dh_std_kdf 946
dh_cofactor_kdf 947
X25519 948
cecpq1 949

View File

@ -1333,3 +1333,6 @@ secg-scheme 14 3 : dhSinglePass-cofactorDH-sha512kdf-scheme
# NID for X25519 (no corresponding OID).
: X25519
# NID for CECPQ1 (no corresponding OID)
: cecpq1

View File

@ -4159,5 +4159,8 @@
#define SN_X25519 "X25519"
#define NID_X25519 948
#define SN_cecpq1 "cecpq1"
#define NID_cecpq1 949
#endif /* OPENSSL_HEADER_NID_H */

View File

@ -533,6 +533,7 @@ int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len);
#define SSL_CURVE_SECP384R1 24
#define SSL_CURVE_SECP521R1 25
#define SSL_CURVE_X25519 29
#define SSL_CURVE_CECPQ1 65165
/* An SSL_ECDH_METHOD is an implementation of ECDH-like key exchanges for
* TLS. */
@ -567,6 +568,15 @@ struct ssl_ecdh_method_st {
int (*finish)(SSL_ECDH_CTX *ctx, uint8_t **out_secret, size_t *out_secret_len,
uint8_t *out_alert, const uint8_t *peer_key,
size_t peer_key_len);
/* get_key initializes |out| with a length-prefixed key from |cbs|. It returns
* one on success and zero on error. */
int (*get_key)(CBS *cbs, CBS *out);
/* add_key initializes |out_contents| to receive a key. Typically it will then
* be passed to |offer| or |accept|. It returns one on success and zero on
* error. */
int (*add_key)(CBB *cbb, CBB *out_contents);
} /* SSL_ECDH_METHOD */;
/* ssl_nid_to_curve_id looks up the curve corresponding to |nid|. On success, it
@ -586,6 +596,12 @@ void SSL_ECDH_CTX_init_for_dhe(SSL_ECDH_CTX *ctx, DH *params);
* call it in the zero state. */
void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx);
/* SSL_ECDH_CTX_get_key calls the |get_key| method of |SSL_ECDH_METHOD|. */
int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out);
/* SSL_ECDH_CTX_add_key calls the |add_key| method of |SSL_ECDH_METHOD|. */
int SSL_ECDH_CTX_add_key(SSL_ECDH_CTX *ctx, CBB *cbb, CBB *out_contents);
/* SSL_ECDH_CTX_offer calls the |offer| method of |SSL_ECDH_METHOD|. */
int SSL_ECDH_CTX_offer(SSL_ECDH_CTX *ctx, CBB *out_public_key);

View File

@ -1142,8 +1142,7 @@ int ssl3_get_server_key_exchange(SSL *ssl) {
CBS point;
if (!CBS_get_u8(&server_key_exchange, &curve_type) ||
curve_type != NAMED_CURVE_TYPE ||
!CBS_get_u16(&server_key_exchange, &curve_id) ||
!CBS_get_u8_length_prefixed(&server_key_exchange, &point)) {
!CBS_get_u16(&server_key_exchange, &curve_id)) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
@ -1157,13 +1156,22 @@ int ssl3_get_server_key_exchange(SSL *ssl) {
goto f_err;
}
/* Initialize ECDH and save the peer public key for later. */
size_t peer_key_len;
if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, curve_id) ||
!CBS_stow(&point, &ssl->s3->tmp.peer_key, &peer_key_len)) {
if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, curve_id)) {
goto err;
}
/* |point| has a u8 length prefix, so this fits in a |uint16_t|. */
if (!SSL_ECDH_CTX_get_key(&ssl->s3->tmp.ecdh_ctx, &server_key_exchange,
&point)) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;
}
/* Initialize ECDH and save the peer public key for later. */
size_t peer_key_len;
if (!CBS_stow(&point, &ssl->s3->tmp.peer_key, &peer_key_len)) {
goto err;
}
/* |point| has a u8 or u16 length prefix, so this fits in a |uint16_t|. */
assert(sizeof(ssl->s3->tmp.peer_key_len) == 2 && peer_key_len <= 0xffff);
ssl->s3->tmp.peer_key_len = (uint16_t)peer_key_len;
} else if (!(alg_k & SSL_kPSK)) {
@ -1616,17 +1624,9 @@ int ssl3_send_client_key_exchange(SSL *ssl) {
goto err;
}
} else if (alg_k & (SSL_kECDHE|SSL_kDHE)) {
/* Generate a keypair and serialize the public half. ECDHE uses a u8 length
* prefix while DHE uses u16. */
/* Generate a keypair and serialize the public half. */
CBB child;
int child_ok;
if (alg_k & SSL_kECDHE) {
child_ok = CBB_add_u8_length_prefixed(&cbb, &child);
} else {
child_ok = CBB_add_u16_length_prefixed(&cbb, &child);
}
if (!child_ok) {
if (!SSL_ECDH_CTX_add_key(&ssl->s3->tmp.ecdh_ctx, &cbb, &child)) {
goto err;
}

View File

@ -1209,7 +1209,7 @@ int ssl3_send_server_key_exchange(SSL *ssl) {
!BN_bn2cbb_padded(&child, BN_num_bytes(params->p), params->p) ||
!CBB_add_u16_length_prefixed(&cbb, &child) ||
!BN_bn2cbb_padded(&child, BN_num_bytes(params->g), params->g) ||
!CBB_add_u16_length_prefixed(&cbb, &child) ||
!SSL_ECDH_CTX_add_key(&ssl->s3->tmp.ecdh_ctx, &cbb, &child) ||
!SSL_ECDH_CTX_offer(&ssl->s3->tmp.ecdh_ctx, &child)) {
goto err;
}
@ -1227,7 +1227,7 @@ int ssl3_send_server_key_exchange(SSL *ssl) {
if (!SSL_ECDH_CTX_init(&ssl->s3->tmp.ecdh_ctx, curve_id) ||
!CBB_add_u8(&cbb, NAMED_CURVE_TYPE) ||
!CBB_add_u16(&cbb, curve_id) ||
!CBB_add_u8_length_prefixed(&cbb, &child) ||
!SSL_ECDH_CTX_add_key(&ssl->s3->tmp.ecdh_ctx, &cbb, &child) ||
!SSL_ECDH_CTX_offer(&ssl->s3->tmp.ecdh_ctx, &child)) {
goto err;
}
@ -1591,18 +1591,11 @@ int ssl3_get_client_key_exchange(SSL *ssl) {
OPENSSL_free(decrypt_buf);
decrypt_buf = NULL;
} else if (alg_k & (SSL_kECDHE|SSL_kDHE)) {
/* Parse the ClientKeyExchange. ECDHE uses a u8 length prefix while DHE uses
* u16. */
/* Parse the ClientKeyExchange. */
CBS peer_key;
int peer_key_ok;
if (alg_k & SSL_kECDHE) {
peer_key_ok = CBS_get_u8_length_prefixed(&client_key_exchange, &peer_key);
} else {
peer_key_ok =
CBS_get_u16_length_prefixed(&client_key_exchange, &peer_key);
}
if (!peer_key_ok || CBS_len(&client_key_exchange) != 0) {
if (!SSL_ECDH_CTX_get_key(&ssl->s3->tmp.ecdh_ctx, &client_key_exchange,
&peer_key) ||
CBS_len(&client_key_exchange) != 0) {
al = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
goto f_err;

View File

@ -23,6 +23,7 @@
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include <openssl/newhope.h>
#include <openssl/nid.h>
#include "internal.h"
@ -220,6 +221,154 @@ static int ssl_x25519_accept(SSL_ECDH_CTX *ctx, CBB *out_public_key,
return 1;
}
/* Combined X25119 + New Hope (post-quantum) implementation. */
typedef struct {
uint8_t x25519_key[32];
NEWHOPE_POLY *newhope_sk;
} cecpq1_data;
#define CECPQ1_OFFERMSG_LENGTH (32 + NEWHOPE_OFFERMSG_LENGTH)
#define CECPQ1_ACCEPTMSG_LENGTH (32 + NEWHOPE_ACCEPTMSG_LENGTH)
#define CECPQ1_SECRET_LENGTH (32 + SHA256_DIGEST_LENGTH)
static void ssl_cecpq1_cleanup(SSL_ECDH_CTX *ctx) {
if (ctx->data == NULL) {
return;
}
cecpq1_data *data = ctx->data;
NEWHOPE_POLY_free(data->newhope_sk);
OPENSSL_cleanse(data, sizeof(cecpq1_data));
OPENSSL_free(data);
}
static int ssl_cecpq1_offer(SSL_ECDH_CTX *ctx, CBB *out) {
assert(ctx->data == NULL);
cecpq1_data *data = OPENSSL_malloc(sizeof(cecpq1_data));
if (data == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
ctx->data = data;
data->newhope_sk = NEWHOPE_POLY_new();
if (data->newhope_sk == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
uint8_t x25519_public_key[32];
X25519_keypair(x25519_public_key, data->x25519_key);
uint8_t newhope_offermsg[NEWHOPE_OFFERMSG_LENGTH];
NEWHOPE_offer(newhope_offermsg, data->newhope_sk);
if (!CBB_add_bytes(out, x25519_public_key, sizeof(x25519_public_key)) ||
!CBB_add_bytes(out, newhope_offermsg, sizeof(newhope_offermsg))) {
return 0;
}
return 1;
}
static int ssl_cecpq1_accept(SSL_ECDH_CTX *ctx, CBB *cbb, uint8_t **out_secret,
size_t *out_secret_len, uint8_t *out_alert,
const uint8_t *peer_key, size_t peer_key_len) {
if (peer_key_len != CECPQ1_OFFERMSG_LENGTH) {
*out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
*out_alert = SSL_AD_INTERNAL_ERROR;
assert(ctx->data == NULL);
cecpq1_data *data = OPENSSL_malloc(sizeof(cecpq1_data));
if (data == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
data->newhope_sk = NULL;
ctx->data = data;
uint8_t *secret = OPENSSL_malloc(CECPQ1_SECRET_LENGTH);
if (secret == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
/* Generate message to server, and secret key, at once. */
uint8_t x25519_public_key[32];
X25519_keypair(x25519_public_key, data->x25519_key);
if (!X25519(secret, data->x25519_key, peer_key)) {
*out_alert = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
goto err;
}
uint8_t newhope_acceptmsg[NEWHOPE_ACCEPTMSG_LENGTH];
if (!NEWHOPE_accept(secret + 32, newhope_acceptmsg, peer_key + 32,
NEWHOPE_OFFERMSG_LENGTH)) {
*out_alert = SSL_AD_DECODE_ERROR;
goto err;
}
if (!CBB_add_bytes(cbb, x25519_public_key, sizeof(x25519_public_key)) ||
!CBB_add_bytes(cbb, newhope_acceptmsg, sizeof(newhope_acceptmsg))) {
goto err;
}
*out_secret = secret;
*out_secret_len = CECPQ1_SECRET_LENGTH;
return 1;
err:
OPENSSL_cleanse(secret, CECPQ1_SECRET_LENGTH);
OPENSSL_free(secret);
return 0;
}
static int ssl_cecpq1_finish(SSL_ECDH_CTX *ctx, uint8_t **out_secret,
size_t *out_secret_len, uint8_t *out_alert,
const uint8_t *peer_key, size_t peer_key_len) {
if (peer_key_len != CECPQ1_ACCEPTMSG_LENGTH) {
*out_alert = SSL_AD_DECODE_ERROR;
return 0;
}
*out_alert = SSL_AD_INTERNAL_ERROR;
assert(ctx->data != NULL);
cecpq1_data *data = ctx->data;
uint8_t *secret = OPENSSL_malloc(CECPQ1_SECRET_LENGTH);
if (secret == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
if (!X25519(secret, data->x25519_key, peer_key)) {
*out_alert = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ECPOINT);
goto err;
}
if (!NEWHOPE_finish(secret + 32, data->newhope_sk, peer_key + 32,
NEWHOPE_ACCEPTMSG_LENGTH)) {
*out_alert = SSL_AD_DECODE_ERROR;
goto err;
}
*out_secret = secret;
*out_secret_len = CECPQ1_SECRET_LENGTH;
return 1;
err:
OPENSSL_cleanse(secret, CECPQ1_SECRET_LENGTH);
OPENSSL_free(secret);
return 0;
}
/* Legacy DHE-based implementation. */
static void ssl_dhe_cleanup(SSL_ECDH_CTX *ctx) {
@ -295,6 +444,8 @@ static const SSL_ECDH_METHOD kDHEMethod = {
ssl_dhe_offer,
ssl_dhe_accept,
ssl_dhe_finish,
CBS_get_u16_length_prefixed,
CBB_add_u16_length_prefixed,
};
static const SSL_ECDH_METHOD kMethods[] = {
@ -306,6 +457,8 @@ static const SSL_ECDH_METHOD kMethods[] = {
ssl_ec_point_offer,
ssl_ec_point_accept,
ssl_ec_point_finish,
CBS_get_u8_length_prefixed,
CBB_add_u8_length_prefixed,
},
{
NID_secp384r1,
@ -315,6 +468,8 @@ static const SSL_ECDH_METHOD kMethods[] = {
ssl_ec_point_offer,
ssl_ec_point_accept,
ssl_ec_point_finish,
CBS_get_u8_length_prefixed,
CBB_add_u8_length_prefixed,
},
{
NID_secp521r1,
@ -324,6 +479,8 @@ static const SSL_ECDH_METHOD kMethods[] = {
ssl_ec_point_offer,
ssl_ec_point_accept,
ssl_ec_point_finish,
CBS_get_u8_length_prefixed,
CBB_add_u8_length_prefixed,
},
{
NID_X25519,
@ -333,6 +490,19 @@ static const SSL_ECDH_METHOD kMethods[] = {
ssl_x25519_offer,
ssl_x25519_accept,
ssl_x25519_finish,
CBS_get_u8_length_prefixed,
CBB_add_u8_length_prefixed,
},
{
NID_cecpq1,
SSL_CURVE_CECPQ1,
"CECPQ1",
ssl_cecpq1_cleanup,
ssl_cecpq1_offer,
ssl_cecpq1_accept,
ssl_cecpq1_finish,
CBS_get_u16_length_prefixed,
CBB_add_u16_length_prefixed,
},
};
@ -392,6 +562,20 @@ void SSL_ECDH_CTX_init_for_dhe(SSL_ECDH_CTX *ctx, DH *params) {
ctx->data = params;
}
int SSL_ECDH_CTX_get_key(SSL_ECDH_CTX *ctx, CBS *cbs, CBS *out) {
if (ctx->method == NULL) {
return 0;
}
return ctx->method->get_key(cbs, out);
}
int SSL_ECDH_CTX_add_key(SSL_ECDH_CTX *ctx, CBB *cbb, CBB *out_contents) {
if (ctx->method == NULL) {
return 0;
}
return ctx->method->add_key(cbb, out_contents);
}
void SSL_ECDH_CTX_cleanup(SSL_ECDH_CTX *ctx) {
if (ctx->method == NULL) {
return;

View File

@ -1310,7 +1310,7 @@ static bool DoExchange(ScopedSSL_SESSION *out_session, SSL_CTX *ssl_ctx,
}
if (config->enable_all_curves) {
static const int kAllCurves[] = {
NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, NID_X25519,
NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, NID_X25519, NID_cecpq1
};
if (!SSL_set1_curves(ssl.get(), kAllCurves,
sizeof(kAllCurves) / sizeof(kAllCurves[0]))) {

View File

@ -103,6 +103,7 @@ const (
CurveP384 CurveID = 24
CurveP521 CurveID = 25
CurveX25519 CurveID = 29
CurveCECPQ1 CurveID = 65165
)
// TLS Elliptic Curve Point Formats

View File

@ -21,6 +21,7 @@ import (
"math/big"
"./curve25519"
"./newhope"
)
var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
@ -348,6 +349,66 @@ func (e *x25519ECDHCurve) finish(peerKey []byte) (preMasterSecret []byte, err er
return out[:], nil
}
// cecpq1Curve is combined elliptic curve (X25519) and post-quantum (new hope) key
// agreement.
type cecpq1Curve struct {
x25519 *x25519ECDHCurve
newhope *newhope.Poly
}
func (e *cecpq1Curve) offer(rand io.Reader) (publicKey []byte, err error) {
var x25519OfferMsg, newhopeOfferMsg []byte
e.x25519 = new(x25519ECDHCurve)
if x25519OfferMsg, err = e.x25519.offer(rand); err != nil {
return nil, err
}
newhopeOfferMsg, e.newhope = newhope.Offer(rand)
return append(x25519OfferMsg, newhopeOfferMsg[:]...), nil
}
func (e *cecpq1Curve) accept(rand io.Reader, peerKey []byte) (publicKey []byte, preMasterSecret []byte, err error) {
if len(peerKey) != 32+newhope.OfferMsgLen {
return nil, nil, errors.New("cecpq1: invalid offer message")
}
var x25519AcceptMsg, newhopeAcceptMsg []byte
var x25519Secret []byte
var newhopeSecret newhope.Key
x25519 := new(x25519ECDHCurve)
if x25519AcceptMsg, x25519Secret, err = x25519.accept(rand, peerKey[:32]); err != nil {
return nil, nil, err
}
if newhopeSecret, newhopeAcceptMsg, err = newhope.Accept(rand, peerKey[32:]); err != nil {
return nil, nil, err
}
return append(x25519AcceptMsg, newhopeAcceptMsg[:]...), append(x25519Secret, newhopeSecret[:]...), nil
}
func (e *cecpq1Curve) finish(peerKey []byte) (preMasterSecret []byte, err error) {
if len(peerKey) != 32+newhope.AcceptMsgLen {
return nil, errors.New("cecpq1: invalid accept message")
}
var x25519Secret []byte
var newhopeSecret newhope.Key
if x25519Secret, err = e.x25519.finish(peerKey[:32]); err != nil {
return nil, err
}
if newhopeSecret, err = e.newhope.Finish(peerKey[32:]); err != nil {
return nil, err
}
return append(x25519Secret, newhopeSecret[:]...), nil
}
func curveForCurveID(id CurveID) (ecdhCurve, bool) {
switch id {
case CurveP224:
@ -360,6 +421,8 @@ func curveForCurveID(id CurveID) (ecdhCurve, bool) {
return &ellipticECDHCurve{curve: elliptic.P521()}, true
case CurveX25519:
return &x25519ECDHCurve{}, true
case CurveCECPQ1:
return &cecpq1Curve{}, true
default:
return nil, false
}
@ -584,15 +647,19 @@ NextCandidate:
}
// http://tools.ietf.org/html/rfc4492#section-5.4
serverECDHParams := make([]byte, 1+2+1+len(publicKey))
serverECDHParams[0] = 3 // named curve
serverECDHParams[1] = byte(curveid >> 8)
serverECDHParams[2] = byte(curveid)
var serverECDHParams []byte
serverECDHParams = append(serverECDHParams, byte(3)) // named curve
serverECDHParams = append(serverECDHParams, byte(curveid>>8))
serverECDHParams = append(serverECDHParams, byte(curveid))
if config.Bugs.InvalidSKXCurve {
serverECDHParams[2] ^= 0xff
}
serverECDHParams[3] = byte(len(publicKey))
copy(serverECDHParams[4:], publicKey)
if curveid == CurveCECPQ1 {
// The larger key size requires an extra length byte.
serverECDHParams = append(serverECDHParams, byte(len(publicKey)>>8))
}
serverECDHParams = append(serverECDHParams, byte(len(publicKey)&0xff))
serverECDHParams = append(serverECDHParams, publicKey[:]...)
if config.Bugs.InvalidECDHPoint {
serverECDHParams[4] ^= 0xff
}
@ -601,10 +668,21 @@ NextCandidate:
}
func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
if len(ckx.ciphertext) == 0 {
return nil, errClientKeyExchange
}
return ka.curve.finish(ckx.ciphertext[1:])
peerKeyLen := int(ckx.ciphertext[0])
offset := 1
if _, postQuantum := ka.curve.(*cecpq1Curve); postQuantum {
// The larger key size requires an extra length byte.
peerKeyLen = int(ckx.ciphertext[0])<<8 + int(ckx.ciphertext[1])
offset = 2
}
peerKey := ckx.ciphertext[offset:]
if peerKeyLen != len(peerKey) {
return nil, errClientKeyExchange
}
return ka.curve.finish(peerKey)
}
func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
@ -622,15 +700,22 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
}
publicLen := int(skx.key[3])
if publicLen+4 > len(skx.key) {
publicOffset := 4
if curveid == CurveCECPQ1 {
// The larger key size requires an extra length byte.
publicLen = int(skx.key[3])<<8 + int(skx.key[4])
publicOffset += 1
}
if publicLen+publicOffset > len(skx.key) {
return errServerKeyExchange
}
// Save the peer key for later.
ka.peerKey = skx.key[4 : 4+publicLen]
ka.peerKey = skx.key[publicOffset : publicOffset+publicLen]
// Check the signature.
serverECDHParams := skx.key[:4+publicLen]
sig := skx.key[4+publicLen:]
serverECDHParams := skx.key[:publicOffset+publicLen]
sig := skx.key[publicOffset+publicLen:]
return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig)
}
@ -645,12 +730,15 @@ func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHel
}
ckx := new(clientKeyExchangeMsg)
ckx.ciphertext = make([]byte, 1+len(publicKey))
ckx.ciphertext[0] = byte(len(publicKey))
copy(ckx.ciphertext[1:], publicKey)
if config.Bugs.InvalidECDHPoint {
ckx.ciphertext[1] ^= 0xff
if _, postQuantum := ka.curve.(*cecpq1Curve); postQuantum {
// The larger key size requires an extra length byte.
ckx.ciphertext = append(ckx.ciphertext, byte(len(publicKey)>>8))
}
ckx.ciphertext = append(ckx.ciphertext, byte(len(publicKey)&0xff))
if config.Bugs.InvalidECDHPoint {
publicKey[0] ^= 0xff
}
ckx.ciphertext = append(ckx.ciphertext, publicKey[:]...)
return preMasterSecret, ckx, nil
}

View File

@ -5006,6 +5006,7 @@ var testCurves = []struct {
{"P-384", CurveP384},
{"P-521", CurveP521},
{"X25519", CurveX25519},
{"CECPQ1", CurveCECPQ1},
}
func addCurveTests() {