mirror of
https://github.com/golang/go.git
synced 2026-06-27 19:30:52 +00:00
crypto/tls: implement MLKEM1024 key exchange
Fixes #78543 Change-Id: I26a70a64665c75e5116b83f73a75093f6a6a6964 Reviewed-on: https://go-review.googlesource.com/c/go/+/777221 Reviewed-by: David Chase <drchase@google.com> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Auto-Submit: Filippo Valsorda <filippo@golang.org> Reviewed-by: Roland Shoemaker <roland@golang.org>
This commit is contained in:
parent
97a57b481f
commit
6b0243ccf6
13 changed files with 117 additions and 27 deletions
2
api/next/78543.txt
Normal file
2
api/next/78543.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
pkg crypto/tls, const MLKEM1024 = 514 #78543
|
||||
pkg crypto/tls, const MLKEM1024 CurveID #78543
|
||||
2
doc/next/6-stdlib/99-minor/crypto/tls/78543.md
Normal file
2
doc/next/6-stdlib/99-minor/crypto/tls/78543.md
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
The [MLKEM1024] key exchange is now supported. It can be enabled by adding it to
|
||||
[Config.CurvePreferences].
|
||||
|
|
@ -34,7 +34,12 @@
|
|||
"TLS-ECH-Server-EarlyDataRejected": "Go does not support early (0-RTT) data",
|
||||
|
||||
"MLKEMKeyShareIncludedSecond": "BoGo wants us to order the key shares based on its preference, but we don't support that",
|
||||
"MLKEMKeyShareIncludedSecond-*": "BoGo wants us to order the key shares based on its preference, but we don't support that",
|
||||
"MLKEMKeyShareIncludedThird": "BoGo wants us to order the key shares based on its preference, but we don't support that",
|
||||
"MLKEMKeyShareIncludedThird-*": "BoGo wants us to order the key shares based on its preference, but we don't support that",
|
||||
"TwoMLKEMs": "BoGo wants us to order the key shares based on its preference, but we don't support that",
|
||||
"NotJustMLKEMKeyShare-MLKEM1024": "BoringSSL sends an ECC key share for fallback when the main key share is MLKEM1024, we currently don't",
|
||||
|
||||
"PostQuantumNotEnabledByDefaultInClients": "We do enable it by default!",
|
||||
"*-Kyber-TLS13": "We don't support Kyber, only ML-KEM (BoGo bug ignoring AllCurves?)",
|
||||
|
||||
|
|
@ -76,21 +81,6 @@
|
|||
"PAKE-Extension-*": "We don't support PAKE",
|
||||
"*TicketFlags": "We don't support draft-ietf-tls-tlsflags",
|
||||
|
||||
"BothMLKEMAndKyber-MLKEM1024": "We don't support ML-KEM 1024 KEX",
|
||||
"CurveTest-Client-MLKEM1024-TLS13": "We don't support ML-KEM 1024 KEX",
|
||||
"CurveTest-Invalid-MLKEMEncapKeyNotReduced-Server-MLKEM1024-TLS13": "We don't support ML-KEM 1024 KEX",
|
||||
"CurveTest-Invalid-PadKeyShare-Client-MLKEM1024-TLS13": "We don't support ML-KEM 1024 KEX",
|
||||
"CurveTest-Invalid-PadKeyShare-Server-MLKEM1024-TLS13": "We don't support ML-KEM 1024 KEX",
|
||||
"CurveTest-Invalid-TruncateKeyShare-Client-MLKEM1024-TLS13": "We don't support ML-KEM 1024 KEX",
|
||||
"CurveTest-Invalid-TruncateKeyShare-Server-MLKEM1024-TLS13": "We don't support ML-KEM 1024 KEX",
|
||||
"CurveTest-Server-MLKEM1024-TLS13": "We don't support ML-KEM 1024 KEX",
|
||||
"JustConfiguringMLKEMWorks-MLKEM1024": "We don't support ML-KEM 1024 KEX",
|
||||
"NotJustMLKEMKeyShare-MLKEM1024": "We don't support ML-KEM 1024 KEX",
|
||||
"TwoMLKEMs": "We don't support ML-KEM 1024 KEX",
|
||||
"MLKEMKeyShareIncludedSecond-MLKEM1024": "We don't support ML-KEM 1024 KEX",
|
||||
"MLKEMKeyShareIncludedSecond-X25519MLKEM768": "We don't support ML-KEM 1024 KEX",
|
||||
"MLKEMKeyShareIncludedThird-MLKEM1024": "We don't support ML-KEM 1024 KEX",
|
||||
|
||||
"MLKEMKeyShareIncludedThird-X25519MLKEM768": "We don't return key shares in client preference order",
|
||||
|
||||
"ECDSAKeyUsage-*": "We don't enforce ECDSA KU",
|
||||
|
|
|
|||
|
|
@ -625,6 +625,8 @@ func TestBogoSuite(t *testing.T) {
|
|||
assertResults := map[string]string{
|
||||
"CurveTest-Client-X25519MLKEM768-TLS13": "PASS",
|
||||
"CurveTest-Server-X25519MLKEM768-TLS13": "PASS",
|
||||
"CurveTest-Client-MLKEM1024-TLS13": "PASS",
|
||||
"CurveTest-Server-MLKEM1024-TLS13": "PASS",
|
||||
|
||||
// Various signature algorithm tests checking that we enforce our
|
||||
// preferences on the peer.
|
||||
|
|
|
|||
|
|
@ -155,11 +155,12 @@ const (
|
|||
X25519MLKEM768 CurveID = 4588
|
||||
SecP256r1MLKEM768 CurveID = 4587
|
||||
SecP384r1MLKEM1024 CurveID = 4589
|
||||
MLKEM1024 CurveID = 514
|
||||
)
|
||||
|
||||
func isTLS13OnlyKeyExchange(curve CurveID) bool {
|
||||
switch curve {
|
||||
case X25519MLKEM768, SecP256r1MLKEM768, SecP384r1MLKEM1024:
|
||||
case X25519MLKEM768, SecP256r1MLKEM768, SecP384r1MLKEM1024, MLKEM1024:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
|
@ -168,7 +169,7 @@ func isTLS13OnlyKeyExchange(curve CurveID) bool {
|
|||
|
||||
func isPQKeyExchange(curve CurveID) bool {
|
||||
switch curve {
|
||||
case X25519MLKEM768, SecP256r1MLKEM768, SecP384r1MLKEM1024:
|
||||
case X25519MLKEM768, SecP256r1MLKEM768, SecP384r1MLKEM1024, MLKEM1024:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
|
|
|||
|
|
@ -82,17 +82,19 @@ func _() {
|
|||
_ = x[X25519MLKEM768-4588]
|
||||
_ = x[SecP256r1MLKEM768-4587]
|
||||
_ = x[SecP384r1MLKEM1024-4589]
|
||||
_ = x[MLKEM1024-514]
|
||||
}
|
||||
|
||||
const (
|
||||
_CurveID_name_0 = "CurveP256CurveP384CurveP521"
|
||||
_CurveID_name_1 = "X25519"
|
||||
_CurveID_name_2 = "SecP256r1MLKEM768X25519MLKEM768SecP384r1MLKEM1024"
|
||||
_CurveID_name_2 = "MLKEM1024"
|
||||
_CurveID_name_3 = "SecP256r1MLKEM768X25519MLKEM768SecP384r1MLKEM1024"
|
||||
)
|
||||
|
||||
var (
|
||||
_CurveID_index_0 = [...]uint8{0, 9, 18, 27}
|
||||
_CurveID_index_2 = [...]uint8{0, 17, 31, 49}
|
||||
_CurveID_index_3 = [...]uint8{0, 17, 31, 49}
|
||||
)
|
||||
|
||||
func (i CurveID) String() string {
|
||||
|
|
@ -102,9 +104,11 @@ func (i CurveID) String() string {
|
|||
return _CurveID_name_0[_CurveID_index_0[i]:_CurveID_index_0[i+1]]
|
||||
case i == 29:
|
||||
return _CurveID_name_1
|
||||
case i == 514:
|
||||
return _CurveID_name_2
|
||||
case 4587 <= i && i <= 4589:
|
||||
i -= 4587
|
||||
return _CurveID_name_2[_CurveID_index_2[i]:_CurveID_index_2[i+1]]
|
||||
return _CurveID_name_3[_CurveID_index_3[i]:_CurveID_index_3[i+1]]
|
||||
default:
|
||||
return "CurveID(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ func defaultCurveEnabled(c CurveID) bool {
|
|||
// include every supported key exchange.
|
||||
func curvePreferenceOrder() []CurveID {
|
||||
return []CurveID{
|
||||
X25519MLKEM768, SecP256r1MLKEM768, SecP384r1MLKEM1024,
|
||||
X25519MLKEM768, SecP256r1MLKEM768, SecP384r1MLKEM1024, MLKEM1024,
|
||||
X25519, CurveP256, CurveP384, CurveP521,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ var (
|
|||
X25519MLKEM768,
|
||||
SecP256r1MLKEM768,
|
||||
SecP384r1MLKEM1024,
|
||||
MLKEM1024,
|
||||
CurveP256,
|
||||
CurveP384,
|
||||
CurveP521,
|
||||
|
|
|
|||
|
|
@ -151,7 +151,7 @@ func isFIPSCurve(id CurveID) bool {
|
|||
switch id {
|
||||
case CurveP256, CurveP384, CurveP521:
|
||||
return true
|
||||
case X25519MLKEM768, SecP256r1MLKEM768, SecP384r1MLKEM1024:
|
||||
case X25519MLKEM768, SecP256r1MLKEM768, SecP384r1MLKEM1024, MLKEM1024:
|
||||
// Only for the native module.
|
||||
return !boring.Enabled
|
||||
case X25519:
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echCli
|
|||
}
|
||||
|
||||
if len(hello.supportedCurves) == 0 {
|
||||
return nil, nil, nil, errors.New("tls: no supported elliptic curves for ECDHE")
|
||||
return nil, nil, nil, errors.New("tls: no supported key exchange methods (CurveIDs)")
|
||||
}
|
||||
// Since the order is fixed, the first one is always the one to send a
|
||||
// key share for. All the PQ hybrids sort first, and produce a fallback
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ func (hs *clientHandshakeStateTLS13) handshake() error {
|
|||
}
|
||||
|
||||
// Consistency check on the presence of a keyShare and its parameters.
|
||||
if hs.keyShareKeys == nil || hs.keyShareKeys.ecdhe == nil || len(hs.hello.keyShares) == 0 {
|
||||
if hs.keyShareKeys == nil || (hs.keyShareKeys.ecdhe == nil && hs.keyShareKeys.mlkem == nil) ||
|
||||
len(hs.hello.keyShares) == 0 {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,11 +107,40 @@ func keyExchangeForCurveID(id CurveID) (keyExchange, error) {
|
|||
return &hybridKeyExchange{id, ecdhKeyExchange{CurveP384, ecdh.P384()},
|
||||
97, mlkem.EncapsulationKeySize1024, mlkem.CiphertextSize1024,
|
||||
mlkemGenerateKey1024, mlkemNewPublicKey1024}, nil
|
||||
case MLKEM1024:
|
||||
return &mlkem1024KeyExchange{}, nil
|
||||
default:
|
||||
return nil, errors.New("tls: unsupported key exchange")
|
||||
}
|
||||
}
|
||||
|
||||
type mlkem1024KeyExchange struct{}
|
||||
|
||||
func (ke *mlkem1024KeyExchange) keyShares(_ io.Reader) (*keySharePrivateKeys, []keyShare, error) {
|
||||
priv, err := mlkem.GenerateKey1024()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return &keySharePrivateKeys{mlkem: priv}, []keyShare{{MLKEM1024, priv.EncapsulationKey().Bytes()}}, nil
|
||||
}
|
||||
|
||||
func (ke *mlkem1024KeyExchange) serverSharedSecret(_ io.Reader, clientKeyShare []byte) ([]byte, keyShare, error) {
|
||||
peerKey, err := mlkem.NewEncapsulationKey1024(clientKeyShare)
|
||||
if err != nil {
|
||||
return nil, keyShare{}, err
|
||||
}
|
||||
sharedKey, keyShareData := peerKey.Encapsulate()
|
||||
return sharedKey, keyShare{MLKEM1024, keyShareData}, nil
|
||||
}
|
||||
|
||||
func (ke *mlkem1024KeyExchange) clientSharedSecret(priv *keySharePrivateKeys, serverKeyShare []byte) ([]byte, error) {
|
||||
sharedKey, err := priv.mlkem.Decapsulate(serverKeyShare)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sharedKey, nil
|
||||
}
|
||||
|
||||
type ecdhKeyExchange struct {
|
||||
id CurveID
|
||||
curve ecdh.Curve
|
||||
|
|
|
|||
|
|
@ -2108,6 +2108,18 @@ func TestHandshakeMLKEM(t *testing.T) {
|
|||
expectClient: []CurveID{SecP256r1MLKEM768, CurveP256},
|
||||
expectSelected: CurveP256,
|
||||
},
|
||||
{
|
||||
name: "CurveP384HRR",
|
||||
clientConfig: func(config *Config) {
|
||||
config.CurvePreferences = []CurveID{SecP256r1MLKEM768, CurveP384}
|
||||
},
|
||||
serverConfig: func(config *Config) {
|
||||
config.CurvePreferences = []CurveID{CurveP384}
|
||||
},
|
||||
expectClient: []CurveID{SecP256r1MLKEM768, CurveP384},
|
||||
expectSelected: CurveP384,
|
||||
expectHRR: true,
|
||||
},
|
||||
{
|
||||
name: "ClientMLKEMOnly",
|
||||
clientConfig: func(config *Config) {
|
||||
|
|
@ -2163,14 +2175,60 @@ func TestHandshakeMLKEM(t *testing.T) {
|
|||
testenv.SetGODEBUG(t, "tlssecpmlkem=0")
|
||||
},
|
||||
clientConfig: func(config *Config) {
|
||||
config.CurvePreferences = []CurveID{CurveP256, SecP256r1MLKEM768}
|
||||
config.CurvePreferences = []CurveID{CurveP256, SecP256r1MLKEM768, MLKEM1024}
|
||||
},
|
||||
serverConfig: func(config *Config) {
|
||||
config.CurvePreferences = []CurveID{CurveP256, SecP256r1MLKEM768}
|
||||
config.CurvePreferences = []CurveID{CurveP256, SecP256r1MLKEM768, MLKEM1024}
|
||||
},
|
||||
expectClient: []CurveID{SecP256r1MLKEM768, CurveP256},
|
||||
expectClient: []CurveID{SecP256r1MLKEM768, MLKEM1024, CurveP256},
|
||||
expectSelected: SecP256r1MLKEM768,
|
||||
},
|
||||
{
|
||||
name: "ClientMLKEM1024Only",
|
||||
clientConfig: func(config *Config) {
|
||||
config.CurvePreferences = []CurveID{MLKEM1024}
|
||||
},
|
||||
serverConfig: func(config *Config) {
|
||||
config.CurvePreferences = append(defaultWithPQ, MLKEM1024)
|
||||
},
|
||||
expectClient: []CurveID{MLKEM1024},
|
||||
expectSelected: MLKEM1024,
|
||||
},
|
||||
{
|
||||
name: "ServerMLKEM1024Only",
|
||||
clientConfig: func(config *Config) {
|
||||
config.CurvePreferences = append(defaultWithPQ, MLKEM1024)
|
||||
},
|
||||
serverConfig: func(config *Config) {
|
||||
config.CurvePreferences = []CurveID{MLKEM1024}
|
||||
},
|
||||
expectClient: []CurveID{X25519MLKEM768, SecP256r1MLKEM768, SecP384r1MLKEM1024,
|
||||
MLKEM1024, X25519, CurveP256, CurveP384, CurveP521},
|
||||
expectSelected: MLKEM1024,
|
||||
expectHRR: true,
|
||||
},
|
||||
{
|
||||
name: "MLKEM1024NotPreferredOverHybrid",
|
||||
clientConfig: func(config *Config) {
|
||||
config.CurvePreferences = []CurveID{MLKEM1024, X25519MLKEM768}
|
||||
},
|
||||
serverConfig: func(config *Config) {
|
||||
config.CurvePreferences = []CurveID{MLKEM1024, X25519MLKEM768}
|
||||
},
|
||||
expectClient: []CurveID{X25519MLKEM768, MLKEM1024},
|
||||
expectSelected: X25519MLKEM768,
|
||||
},
|
||||
{
|
||||
name: "MLKEM1024PreferredOverECC",
|
||||
clientConfig: func(config *Config) {
|
||||
config.CurvePreferences = []CurveID{X25519, MLKEM1024}
|
||||
},
|
||||
serverConfig: func(config *Config) {
|
||||
config.CurvePreferences = []CurveID{X25519, MLKEM1024}
|
||||
},
|
||||
expectClient: []CurveID{MLKEM1024, X25519},
|
||||
expectSelected: MLKEM1024,
|
||||
},
|
||||
}
|
||||
|
||||
baseServerConfig := testConfigServer.Clone()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue