Skip to content

Commit d8bc7db

Browse files
JoTurkJulia-RomanJuliapixeltreejadey
committed
Add 1.3 cipher suite secret init
Co-authored-by: Julia <supa@juliaelena.ro> Co-authored-by: Julia <git@juliapixel.com> Co-authored-by: Jade <jadey@tutanota.com>
1 parent f7216c2 commit d8bc7db

5 files changed

Lines changed: 145 additions & 3 deletions

File tree

internal/ciphersuite/tls_13.go

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,25 @@ package ciphersuite
55

66
import (
77
"fmt"
8+
"sync/atomic"
89

910
dtlserrors "github.com/pion/dtls/v3/internal/errors"
1011
"github.com/pion/dtls/v3/pkg/crypto/clientcertificate"
1112
"github.com/pion/dtls/v3/pkg/protocol/recordlayer"
1213
)
1314

15+
// CipherSuiteTLS13 is the DTLS 1.3-specific cipher suite surface.
16+
type CipherSuiteTLS13 interface {
17+
CipherSuite
18+
InitFromTrafficSecrets13(clientSecret, serverSecret []byte, isClient bool) error
19+
}
20+
1421
// TLS13CipherSuite provides behavior common to TLS 1.3 cipher suites. TLS 1.3
1522
// cipher suites only identify the AEAD and hash; authentication and key
1623
// exchange are negotiated independently.
17-
type TLS13CipherSuite struct{}
24+
type TLS13CipherSuite struct {
25+
recordProtection atomic.Value // *recordProtection13
26+
}
1827

1928
func (c *TLS13CipherSuite) CertificateType() clientcertificate.Type {
2029
return 0
@@ -33,7 +42,33 @@ func (c *TLS13CipherSuite) AuthenticationType() AuthenticationType {
3342
}
3443

3544
func (c *TLS13CipherSuite) IsInitialized() bool {
36-
return false
45+
return c.recordProtection.Load() != nil
46+
}
47+
48+
func (c *TLS13CipherSuite) initFromTrafficSecrets13(
49+
clientSecret, serverSecret []byte,
50+
isClient bool,
51+
newRecordProtection func(localTrafficSecret, remoteTrafficSecret []byte) (*recordProtection13, error),
52+
) error {
53+
if newRecordProtection == nil {
54+
return dtlserrors.ErrCipherSuiteRecordProtectionNotImplemented
55+
}
56+
57+
localSecret, remoteSecret := localRemoteTrafficSecrets13(clientSecret, serverSecret, isClient)
58+
protection, err := newRecordProtection(localSecret, remoteSecret)
59+
if err != nil {
60+
return err
61+
}
62+
63+
c.recordProtection.Store(protection)
64+
65+
return nil
66+
}
67+
68+
func (c *TLS13CipherSuite) getRecordProtection13() (*recordProtection13, bool) {
69+
protection, ok := c.recordProtection.Load().(*recordProtection13)
70+
71+
return protection, ok
3772
}
3873

3974
func (c *TLS13CipherSuite) Init(_, _, _ []byte, _ bool) error {
@@ -47,3 +82,14 @@ func (c *TLS13CipherSuite) Encrypt(_ *recordlayer.RecordLayer, _ []byte) ([]byte
4782
func (c *TLS13CipherSuite) Decrypt(_ recordlayer.Header, _ []byte) ([]byte, error) {
4883
return nil, fmt.Errorf("%w, unable to decrypt", dtlserrors.ErrCipherSuiteRecordProtectionNotImplemented)
4984
}
85+
86+
func localRemoteTrafficSecrets13(
87+
clientSecret, serverSecret []byte,
88+
isClient bool,
89+
) (localSecret, remoteSecret []byte) {
90+
if isClient {
91+
return clientSecret, serverSecret
92+
}
93+
94+
return serverSecret, clientSecret
95+
}

internal/ciphersuite/tls_13_record_protection_test.go

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ type recordProtection13TestCase struct {
2828
}
2929

3030
type tls13RecordProtectionSuite interface {
31-
CipherSuite
31+
CipherSuiteTLS13
3232
newRecordProtection(localTrafficSecret, remoteTrafficSecret []byte) (*recordProtection13, error)
3333
}
3434

@@ -89,6 +89,46 @@ func trafficSecret13(suite tls13RecordProtectionSuite, fill byte) []byte {
8989
return bytes.Repeat([]byte{fill}, hashFunc().Size())
9090
}
9191

92+
func newRecordProtection13TestSuite(t *testing.T, name string) tls13RecordProtectionSuite {
93+
t.Helper()
94+
95+
for _, testCase := range recordProtection13TestCases() {
96+
if testCase.name == name {
97+
return testCase.suite
98+
}
99+
}
100+
101+
assert.FailNowf(t, "unknown TLS 1.3 test suite", "name: %s", name)
102+
103+
return nil
104+
}
105+
106+
func requireRecordProtection13(t *testing.T, suite tls13RecordProtectionSuite) *recordProtection13 {
107+
t.Helper()
108+
109+
switch s := suite.(type) {
110+
case *TLSAes128GcmSha256:
111+
protection, ok := s.getRecordProtection13()
112+
require.True(t, ok)
113+
114+
return protection
115+
case *TLSAes256GcmSha384:
116+
protection, ok := s.getRecordProtection13()
117+
require.True(t, ok)
118+
119+
return protection
120+
case *TLSChacha20Poly1305Sha256:
121+
protection, ok := s.getRecordProtection13()
122+
require.True(t, ok)
123+
124+
return protection
125+
default:
126+
assert.FailNowf(t, "unknown TLS 1.3 test suite", "suite: %T", suite)
127+
128+
return nil
129+
}
130+
}
131+
92132
func TestDeriveRecordTrafficKeys13Suites(t *testing.T) {
93133
for _, testCase := range recordProtection13TestCases() {
94134
t.Run(testCase.name, func(t *testing.T) {
@@ -171,6 +211,44 @@ func TestTLS13CipherSuiteNewRecordProtectionSuites(t *testing.T) {
171211
}
172212
}
173213

214+
func TestTLS13CipherSuiteInitFromTrafficSecrets13(t *testing.T) {
215+
for _, testCase := range recordProtection13TestCases() {
216+
t.Run(testCase.name, func(t *testing.T) {
217+
clientSuite := testCase.suite
218+
serverSuite := newRecordProtection13TestSuite(t, testCase.name)
219+
220+
clientSecret := trafficSecret13(testCase.suite, 0xa6)
221+
serverSecret := trafficSecret13(testCase.suite, 0xb6)
222+
223+
require.False(t, clientSuite.IsInitialized())
224+
require.False(t, serverSuite.IsInitialized())
225+
226+
require.NoError(t, clientSuite.InitFromTrafficSecrets13(clientSecret, serverSecret, true))
227+
require.NoError(t, serverSuite.InitFromTrafficSecrets13(clientSecret, serverSecret, false))
228+
229+
require.True(t, clientSuite.IsInitialized())
230+
require.True(t, serverSuite.IsInitialized())
231+
232+
clientProtection := requireRecordProtection13(t, clientSuite)
233+
serverProtection := requireRecordProtection13(t, serverSuite)
234+
header := recordlayer.UnifiedHeader{
235+
SequenceNumber: 0x1234,
236+
EpochLow: 2,
237+
}
238+
sequenceNumber := uint64(0x0102030405060708)
239+
plaintext := []byte("traffic-secret initialized payload")
240+
241+
record, err := clientProtection.seal(header, sequenceNumber, protocol.ContentTypeApplicationData, plaintext)
242+
require.NoError(t, err)
243+
244+
innerPlaintext, err := serverProtection.open(record.Header, sequenceNumber, record.EncryptedRecord)
245+
require.NoError(t, err)
246+
assert.Equal(t, plaintext, innerPlaintext.Content)
247+
assert.Equal(t, protocol.ContentTypeApplicationData, innerPlaintext.RealType)
248+
})
249+
}
250+
}
251+
174252
func TestRecordProtection13SealOpenSyntheticTrafficSecret(t *testing.T) {
175253
for _, testCase := range recordProtection13TestCases() {
176254
t.Run(testCase.name, func(t *testing.T) {

internal/ciphersuite/tls_aes_128_gcm_sha256.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ func (c *TLSAes128GcmSha256) HashFunc() func() hash.Hash {
3232
return sha256.New
3333
}
3434

35+
// InitFromTrafficSecrets13 initializes DTLS 1.3 record protection from the
36+
// negotiated client and server handshake/application traffic secrets.
37+
func (c *TLSAes128GcmSha256) InitFromTrafficSecrets13(clientSecret, serverSecret []byte, isClient bool) error {
38+
return c.initFromTrafficSecrets13(clientSecret, serverSecret, isClient, c.newRecordProtection)
39+
}
40+
3541
func (c *TLSAes128GcmSha256) newRecordProtection(
3642
localTrafficSecret, remoteTrafficSecret []byte,
3743
) (*recordProtection13, error) {

internal/ciphersuite/tls_aes_256_gcm_sha384.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ func (c *TLSAes256GcmSha384) HashFunc() func() hash.Hash {
3232
return sha512.New384
3333
}
3434

35+
// InitFromTrafficSecrets13 initializes DTLS 1.3 record protection from the
36+
// negotiated client and server handshake/application traffic secrets.
37+
func (c *TLSAes256GcmSha384) InitFromTrafficSecrets13(clientSecret, serverSecret []byte, isClient bool) error {
38+
return c.initFromTrafficSecrets13(clientSecret, serverSecret, isClient, c.newRecordProtection)
39+
}
40+
3541
func (c *TLSAes256GcmSha384) newRecordProtection(
3642
localTrafficSecret, remoteTrafficSecret []byte,
3743
) (*recordProtection13, error) {

internal/ciphersuite/tls_chacha20_poly1305_sha256.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ func (c *TLSChacha20Poly1305Sha256) HashFunc() func() hash.Hash {
3232
return sha256.New
3333
}
3434

35+
// InitFromTrafficSecrets13 initializes DTLS 1.3 record protection from the
36+
// negotiated client and server handshake/application traffic secrets.
37+
func (c *TLSChacha20Poly1305Sha256) InitFromTrafficSecrets13(clientSecret, serverSecret []byte, isClient bool) error {
38+
return c.initFromTrafficSecrets13(clientSecret, serverSecret, isClient, c.newRecordProtection)
39+
}
40+
3541
func (c *TLSChacha20Poly1305Sha256) newRecordProtection(
3642
localTrafficSecret, remoteTrafficSecret []byte,
3743
) (*recordProtection13, error) {

0 commit comments

Comments
 (0)