Skip to content

Commit e229e8c

Browse files
Lekensteynbwesterb
authored andcommitted
crypto/tls: add new X25519Kyber768Draft00 code point
* Point tls.X25519Kyber768Draft00 to the new 0x6399 identifier while the old 0xfe31 identifier is available as tls.X25519Kyber768Draft00Old. * Make sure that the kem.PrivateKey can always be mapped to the CurveID that was linked to it. This is needed since we now have two ID aliasing to the same scheme, and clients need to be able to detect whether the key share presented by the server actually matches the key share that the client originally sent. * Update tests, add the new identifier and remove unnecessary code. Link: https://mailarchive.ietf.org/arch/msg/tls/HAWpNpgptl--UZNSYuvsjB-Pc2k/ Link: https://datatracker.ietf.org/doc/draft-tls-westerbaan-xyber768d00/02/
1 parent ee1b22d commit e229e8c

File tree

4 files changed

+47
-75
lines changed

4 files changed

+47
-75
lines changed

src/crypto/tls/cfkem.go

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66
// To enable set CurvePreferences with the desired scheme as the first element:
77
//
88
// import (
9-
// "github.com/cloudflare/circl/kem/tls"
10-
// "github.com/cloudflare/circl/kem/hybrid"
9+
// "crypto/tls"
1110
//
1211
// [...]
1312
//
1413
// config.CurvePreferences = []tls.CurveID{
15-
// hybrid.X25519Kyber512Draft00().(tls.TLSScheme).TLSCurveID(),
14+
// tls.X25519Kyber768Draft00,
1615
// tls.X25519,
1716
// tls.P256,
1817
// }
@@ -29,38 +28,27 @@ import (
2928
"github.com/cloudflare/circl/kem/hybrid"
3029
)
3130

32-
// Either ecdheParameters or kem.PrivateKey
31+
// Either *ecdh.PrivateKey or *kemPrivateKey
3332
type clientKeySharePrivate interface{}
3433

34+
type kemPrivateKey struct {
35+
secretKey kem.PrivateKey
36+
curveID CurveID
37+
}
38+
3539
var (
36-
X25519Kyber512Draft00 = CurveID(0xfe30)
37-
X25519Kyber768Draft00 = CurveID(0xfe31)
38-
P256Kyber768Draft00 = CurveID(0xfe32)
39-
invalidCurveID = CurveID(0)
40+
X25519Kyber512Draft00 = CurveID(0xfe30)
41+
X25519Kyber768Draft00 = CurveID(0x6399)
42+
X25519Kyber768Draft00Old = CurveID(0xfe31)
43+
P256Kyber768Draft00 = CurveID(0xfe32)
44+
invalidCurveID = CurveID(0)
4045
)
4146

42-
func kemSchemeKeyToCurveID(s kem.Scheme) CurveID {
43-
switch s.Name() {
44-
case "Kyber512-X25519":
45-
return X25519Kyber512Draft00
46-
case "Kyber768-X25519":
47-
return X25519Kyber768Draft00
48-
case "P256Kyber768Draft00":
49-
return P256Kyber768Draft00
50-
default:
51-
return invalidCurveID
52-
}
53-
}
54-
5547
// Extract CurveID from clientKeySharePrivate
5648
func clientKeySharePrivateCurveID(ks clientKeySharePrivate) CurveID {
5749
switch v := ks.(type) {
58-
case kem.PrivateKey:
59-
ret := kemSchemeKeyToCurveID(v.Scheme())
60-
if ret == invalidCurveID {
61-
panic("cfkem: internal error: don't know CurveID for this KEM")
62-
}
63-
return ret
50+
case *kemPrivateKey:
51+
return v.curveID
6452
case *ecdh.PrivateKey:
6553
ret, ok := curveIDForCurve(v.Curve())
6654
if !ok {
@@ -77,7 +65,7 @@ func curveIdToCirclScheme(id CurveID) kem.Scheme {
7765
switch id {
7866
case X25519Kyber512Draft00:
7967
return hybrid.Kyber512X25519()
80-
case X25519Kyber768Draft00:
68+
case X25519Kyber768Draft00, X25519Kyber768Draft00Old:
8169
return hybrid.Kyber768X25519()
8270
case P256Kyber768Draft00:
8371
return hybrid.P256Kyber768Draft00()
@@ -102,12 +90,12 @@ func encapsulateForKem(scheme kem.Scheme, rnd io.Reader, ppk []byte) (
10290
}
10391

10492
// Generate a new keypair using randomness from rnd.
105-
func generateKemKeyPair(scheme kem.Scheme, rnd io.Reader) (
106-
kem.PublicKey, kem.PrivateKey, error) {
93+
func generateKemKeyPair(scheme kem.Scheme, curveID CurveID, rnd io.Reader) (
94+
kem.PublicKey, *kemPrivateKey, error) {
10795
seed := make([]byte, scheme.SeedSize())
10896
if _, err := io.ReadFull(rnd, seed); err != nil {
10997
return nil, nil, err
11098
}
11199
pk, sk := scheme.DeriveKeyPair(seed)
112-
return pk, sk, nil
100+
return pk, &kemPrivateKey{sk, curveID}, nil
113101
}

src/crypto/tls/cfkem_test.go

Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,16 @@ import (
77
"context"
88
"fmt"
99
"testing"
10-
11-
"github.com/cloudflare/circl/kem"
12-
"github.com/cloudflare/circl/kem/hybrid"
1310
)
1411

15-
func testHybridKEX(t *testing.T, scheme kem.Scheme, clientPQ, serverPQ,
12+
func testHybridKEX(t *testing.T, curveID CurveID, clientPQ, serverPQ,
1613
clientTLS12, serverTLS12 bool) {
1714
var clientSelectedKEX *CurveID
1815
var retry bool
1916

20-
rsaCert := Certificate{
21-
Certificate: [][]byte{testRSACertificate},
22-
PrivateKey: testRSAPrivateKey,
23-
}
24-
serverCerts := []Certificate{rsaCert}
25-
2617
clientConfig := testConfig.Clone()
2718
if clientPQ {
28-
clientConfig.CurvePreferences = []CurveID{
29-
kemSchemeKeyToCurveID(scheme),
30-
X25519,
31-
}
19+
clientConfig.CurvePreferences = []CurveID{curveID, X25519}
3220
}
3321
clientCFEventHandler := func(ev CFEvent) {
3422
switch e := ev.(type) {
@@ -44,15 +32,13 @@ func testHybridKEX(t *testing.T, scheme kem.Scheme, clientPQ, serverPQ,
4432

4533
serverConfig := testConfig.Clone()
4634
if serverPQ {
47-
serverConfig.CurvePreferences = []CurveID{
48-
kemSchemeKeyToCurveID(scheme),
49-
X25519,
50-
}
35+
serverConfig.CurvePreferences = []CurveID{curveID, X25519}
36+
} else {
37+
serverConfig.CurvePreferences = []CurveID{X25519}
5138
}
5239
if serverTLS12 {
5340
serverConfig.MaxVersion = VersionTLS12
5441
}
55-
serverConfig.Certificates = serverCerts
5642

5743
c, s := localPipe(t)
5844
done := make(chan error)
@@ -78,44 +64,43 @@ func testHybridKEX(t *testing.T, scheme kem.Scheme, clientPQ, serverPQ,
7864
var expectedRetry bool
7965

8066
if clientPQ && serverPQ && !clientTLS12 && !serverTLS12 {
81-
expectedKEX = kemSchemeKeyToCurveID(scheme)
67+
expectedKEX = curveID
8268
} else {
8369
expectedKEX = X25519
8470
}
8571
if !clientTLS12 && clientPQ && !serverPQ {
8672
expectedRetry = true
8773
}
8874

75+
if expectedRetry != retry {
76+
t.Errorf("Expected retry=%v, got retry=%v", expectedRetry, retry)
77+
}
8978
if clientSelectedKEX == nil {
9079
t.Error("No KEX happened?")
91-
}
92-
93-
if *clientSelectedKEX != expectedKEX {
80+
} else if *clientSelectedKEX != expectedKEX {
9481
t.Errorf("failed to negotiate: expected %d, got %d",
9582
expectedKEX, *clientSelectedKEX)
9683
}
97-
if expectedRetry != retry {
98-
t.Errorf("Expected retry=%v, got retry=%v", expectedRetry, retry)
99-
}
10084
}
10185

10286
func TestHybridKEX(t *testing.T) {
103-
run := func(scheme kem.Scheme, clientPQ, serverPQ, clientTLS12, serverTLS12 bool) {
104-
t.Run(fmt.Sprintf("%s serverPQ:%v clientPQ:%v serverTLS12:%v clientTLS12:%v", scheme.Name(),
87+
run := func(curveID CurveID, clientPQ, serverPQ, clientTLS12, serverTLS12 bool) {
88+
t.Run(fmt.Sprintf("%#04x serverPQ:%v clientPQ:%v serverTLS12:%v clientTLS12:%v", uint16(curveID),
10589
serverPQ, clientPQ, serverTLS12, clientTLS12), func(t *testing.T) {
106-
testHybridKEX(t, scheme, clientPQ, serverPQ, clientTLS12, serverTLS12)
90+
testHybridKEX(t, curveID, clientPQ, serverPQ, clientTLS12, serverTLS12)
10791
})
10892
}
109-
for _, scheme := range []kem.Scheme{
110-
hybrid.Kyber512X25519(),
111-
hybrid.Kyber768X25519(),
112-
hybrid.P256Kyber768Draft00(),
93+
for _, curveID := range []CurveID{
94+
X25519Kyber512Draft00,
95+
X25519Kyber768Draft00,
96+
X25519Kyber768Draft00Old,
97+
P256Kyber768Draft00,
11398
} {
114-
run(scheme, true, true, false, false)
115-
run(scheme, true, false, false, false)
116-
run(scheme, false, true, false, false)
117-
run(scheme, true, true, true, false)
118-
run(scheme, true, true, false, true)
119-
run(scheme, true, true, true, true)
99+
run(curveID, true, true, false, false)
100+
run(curveID, true, false, false, false)
101+
run(curveID, false, true, false, false)
102+
run(curveID, true, true, true, false)
103+
run(curveID, true, true, false, true)
104+
run(curveID, true, true, true, true)
120105
}
121106
}

src/crypto/tls/handshake_client.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ func (c *Conn) makeClientHello(minVersion uint16) (*clientHelloMsg, clientKeySha
146146

147147
curveID := config.curvePreferences()[0]
148148
if scheme := curveIdToCirclScheme(curveID); scheme != nil {
149-
pk, sk, err := generateKemKeyPair(scheme, config.rand())
149+
pk, sk, err := generateKemKeyPair(scheme, curveID, config.rand())
150150
if err != nil {
151151
return nil, nil, fmt.Errorf("generateKemKeyPair %s: %w",
152152
scheme.Name(), err)

src/crypto/tls/handshake_client_tls13.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ import (
1616
"fmt"
1717
"hash"
1818
"time"
19-
20-
circlKem "github.com/cloudflare/circl/kem"
2119
)
2220

2321
type clientHandshakeStateTLS13 struct {
@@ -386,7 +384,7 @@ func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
386384
return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
387385
}
388386
if scheme := curveIdToCirclScheme(curveID); scheme != nil {
389-
pk, sk, err := generateKemKeyPair(scheme, c.config.rand())
387+
pk, sk, err := generateKemKeyPair(scheme, curveID, c.config.rand())
390388
if err != nil {
391389
c.sendAlert(alertInternalError)
392390
return fmt.Errorf("HRR generateKemKeyPair %s: %w",
@@ -620,7 +618,8 @@ func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
620618
if err == nil {
621619
sharedKey, _ = key.ECDH(peerKey)
622620
}
623-
} else if sk, ok := hs.keySharePrivate.(circlKem.PrivateKey); ok {
621+
} else if key, ok := hs.keySharePrivate.(*kemPrivateKey); ok {
622+
sk := key.secretKey
624623
sharedKey, err = sk.Scheme().Decapsulate(sk, hs.serverHello.serverShare.data)
625624
if err != nil {
626625
c.sendAlert(alertIllegalParameter)

0 commit comments

Comments
 (0)