Skip to content

Commit 8922879

Browse files
committed
Update ciphersuites to support CIDs
Updates ciphersuites to add support for handling connection ID records. Signed-off-by: Daniel Mangum <georgedanielmangum@gmail.com>
1 parent 8ba47cb commit 8922879

8 files changed

Lines changed: 120 additions & 51 deletions

File tree

internal/ciphersuite/aes_ccm.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,11 @@ func (c *AesCcm) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, erro
103103
}
104104

105105
// Decrypt decrypts a single TLS RecordLayer
106-
func (c *AesCcm) Decrypt(raw []byte) ([]byte, error) {
106+
func (c *AesCcm) Decrypt(h recordlayer.Header, raw []byte) ([]byte, error) {
107107
cipherSuite, ok := c.ccm.Load().(*ciphersuite.CCM)
108108
if !ok {
109109
return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
110110
}
111111

112-
return cipherSuite.Decrypt(raw)
112+
return cipherSuite.Decrypt(h, raw)
113113
}

internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_128_gcm_sha256.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,11 @@ func (c *TLSEcdheEcdsaWithAes128GcmSha256) Encrypt(pkt *recordlayer.RecordLayer,
9898
}
9999

100100
// Decrypt decrypts a single TLS RecordLayer
101-
func (c *TLSEcdheEcdsaWithAes128GcmSha256) Decrypt(raw []byte) ([]byte, error) {
101+
func (c *TLSEcdheEcdsaWithAes128GcmSha256) Decrypt(h recordlayer.Header, raw []byte) ([]byte, error) {
102102
cipherSuite, ok := c.gcm.Load().(*ciphersuite.GCM)
103103
if !ok {
104104
return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
105105
}
106106

107-
return cipherSuite.Decrypt(raw)
107+
return cipherSuite.Decrypt(h, raw)
108108
}

internal/ciphersuite/tls_ecdhe_ecdsa_with_aes_256_cbc_sha.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,11 @@ func (c *TLSEcdheEcdsaWithAes256CbcSha) Encrypt(pkt *recordlayer.RecordLayer, ra
104104
}
105105

106106
// Decrypt decrypts a single TLS RecordLayer
107-
func (c *TLSEcdheEcdsaWithAes256CbcSha) Decrypt(raw []byte) ([]byte, error) {
107+
func (c *TLSEcdheEcdsaWithAes256CbcSha) Decrypt(h recordlayer.Header, raw []byte) ([]byte, error) {
108108
cipherSuite, ok := c.cbc.Load().(*ciphersuite.CBC)
109109
if !ok {
110110
return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
111111
}
112112

113-
return cipherSuite.Decrypt(raw)
113+
return cipherSuite.Decrypt(h, raw)
114114
}

internal/ciphersuite/tls_ecdhe_psk_with_aes_128_cbc_sha256.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,11 @@ func (c *TLSEcdhePskWithAes128CbcSha256) Encrypt(pkt *recordlayer.RecordLayer, r
108108
}
109109

110110
// Decrypt decrypts a single TLS RecordLayer
111-
func (c *TLSEcdhePskWithAes128CbcSha256) Decrypt(raw []byte) ([]byte, error) {
111+
func (c *TLSEcdhePskWithAes128CbcSha256) Decrypt(h recordlayer.Header, raw []byte) ([]byte, error) {
112112
cipherSuite, ok := c.cbc.Load().(*ciphersuite.CBC)
113113
if !ok { // !c.isInitialized()
114114
return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
115115
}
116116

117-
return cipherSuite.Decrypt(raw)
117+
return cipherSuite.Decrypt(h, raw)
118118
}

internal/ciphersuite/tls_psk_with_aes_128_cbc_sha256.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,11 @@ func (c *TLSPskWithAes128CbcSha256) Encrypt(pkt *recordlayer.RecordLayer, raw []
103103
}
104104

105105
// Decrypt decrypts a single TLS RecordLayer
106-
func (c *TLSPskWithAes128CbcSha256) Decrypt(raw []byte) ([]byte, error) {
106+
func (c *TLSPskWithAes128CbcSha256) Decrypt(h recordlayer.Header, raw []byte) ([]byte, error) {
107107
cipherSuite, ok := c.cbc.Load().(*ciphersuite.CBC)
108108
if !ok {
109109
return nil, fmt.Errorf("%w, unable to decrypt", errCipherSuiteNotInit)
110110
}
111111

112-
return cipherSuite.Decrypt(raw)
112+
return cipherSuite.Decrypt(h, raw)
113113
}

pkg/crypto/ciphersuite/cbc.go

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import ( //nolint:gci
1515
"github.com/pion/dtls/v2/pkg/crypto/prf"
1616
"github.com/pion/dtls/v2/pkg/protocol"
1717
"github.com/pion/dtls/v2/pkg/protocol/recordlayer"
18+
"golang.org/x/crypto/cryptobyte"
1819
)
1920

2021
// block ciphers using cipher block chaining.
@@ -64,18 +65,24 @@ func NewCBC(localKey, localWriteIV, localMac, remoteKey, remoteWriteIV, remoteMa
6465

6566
// Encrypt encrypt a DTLS RecordLayer message
6667
func (c *CBC) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
67-
payload := raw[recordlayer.HeaderSize:]
68-
raw = raw[:recordlayer.HeaderSize]
68+
payload := raw[pkt.Header.Size():]
69+
raw = raw[:pkt.Header.Size()]
6970
blockSize := c.writeCBC.BlockSize()
7071

7172
// Generate + Append MAC
7273
h := pkt.Header
7374

74-
MAC, err := c.hmac(h.Epoch, h.SequenceNumber, h.ContentType, h.Version, payload, c.writeMac, c.h)
75+
var err error
76+
var mac []byte
77+
if h.ContentType == protocol.ContentTypeConnectionID {
78+
mac, err = c.hmacCID(h.Epoch, h.SequenceNumber, h.Version, payload, c.writeMac, c.h, h.ConnectionID)
79+
} else {
80+
mac, err = c.hmac(h.Epoch, h.SequenceNumber, h.ContentType, h.Version, payload, c.writeMac, c.h)
81+
}
7582
if err != nil {
7683
return nil, err
7784
}
78-
payload = append(payload, MAC...)
85+
payload = append(payload, mac...)
7986

8087
// Generate + Append padding
8188
padding := make([]byte, blockSize-len(payload)%blockSize)
@@ -96,26 +103,26 @@ func (c *CBC) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error)
96103
c.writeCBC.CryptBlocks(payload, payload)
97104
payload = append(iv, payload...)
98105

99-
// Prepend unencrypte header with encrypted payload
106+
// Prepend unencrypted header with encrypted payload
100107
raw = append(raw, payload...)
101108

102109
// Update recordLayer size to include IV+MAC+Padding
103-
binary.BigEndian.PutUint16(raw[recordlayer.HeaderSize-2:], uint16(len(raw)-recordlayer.HeaderSize))
110+
binary.BigEndian.PutUint16(raw[pkt.Header.Size()-2:], uint16(len(raw)-pkt.Header.Size()))
104111

105112
return raw, nil
106113
}
107114

108115
// Decrypt decrypts a DTLS RecordLayer message
109-
func (c *CBC) Decrypt(in []byte) ([]byte, error) {
110-
body := in[recordlayer.HeaderSize:]
116+
func (c *CBC) Decrypt(h recordlayer.Header, in []byte) ([]byte, error) {
111117
blockSize := c.readCBC.BlockSize()
112118
mac := c.h()
113119

114-
var h recordlayer.Header
115-
err := h.Unmarshal(in)
116-
switch {
117-
case err != nil:
120+
if err := h.Unmarshal(in); err != nil {
118121
return nil, err
122+
}
123+
body := in[h.Size():]
124+
125+
switch {
119126
case h.ContentType == protocol.ContentTypeChangeCipherSpec:
120127
// Nothing to encrypt with ChangeCipherSpec
121128
return in, nil
@@ -145,14 +152,19 @@ func (c *CBC) Decrypt(in []byte) ([]byte, error) {
145152
dataEnd := len(body) - macSize - paddingLen
146153

147154
expectedMAC := body[dataEnd : dataEnd+macSize]
148-
actualMAC, err := c.hmac(h.Epoch, h.SequenceNumber, h.ContentType, h.Version, body[:dataEnd], c.readMac, c.h)
149-
155+
var err error
156+
var actualMAC []byte
157+
if h.ContentType == protocol.ContentTypeConnectionID {
158+
actualMAC, err = c.hmacCID(h.Epoch, h.SequenceNumber, h.Version, body[:dataEnd], c.readMac, c.h, h.ConnectionID)
159+
} else {
160+
actualMAC, err = c.hmac(h.Epoch, h.SequenceNumber, h.ContentType, h.Version, body[:dataEnd], c.readMac, c.h)
161+
}
150162
// Compute Local MAC and compare
151163
if err != nil || !hmac.Equal(actualMAC, expectedMAC) {
152164
return nil, errInvalidMAC
153165
}
154166

155-
return append(in[:recordlayer.HeaderSize], body[:dataEnd]...), nil
167+
return append(in[:h.Size()], body[:dataEnd]...), nil
156168
}
157169

158170
func (c *CBC) hmac(epoch uint16, sequenceNumber uint64, contentType protocol.ContentType, protocolVersion protocol.Version, payload []byte, key []byte, hf func() hash.Hash) ([]byte, error) {
@@ -169,7 +181,45 @@ func (c *CBC) hmac(epoch uint16, sequenceNumber uint64, contentType protocol.Con
169181

170182
if _, err := h.Write(msg); err != nil {
171183
return nil, err
172-
} else if _, err := h.Write(payload); err != nil {
184+
}
185+
if _, err := h.Write(payload); err != nil {
186+
return nil, err
187+
}
188+
189+
return h.Sum(nil), nil
190+
}
191+
192+
// hmacCID calculates a MAC according to
193+
// https://datatracker.ietf.org/doc/html/rfc9146#section-5.1
194+
func (c *CBC) hmacCID(epoch uint16, sequenceNumber uint64, protocolVersion protocol.Version, payload []byte, key []byte, hf func() hash.Hash, cid []byte) ([]byte, error) {
195+
// Must unmarshal inner plaintext in orde to perform MAC.
196+
ip := &recordlayer.InnerPlaintext{}
197+
if err := ip.Unmarshal(payload); err != nil {
198+
return nil, err
199+
}
200+
201+
h := hmac.New(hf, key)
202+
203+
var msg cryptobyte.Builder
204+
205+
msg.AddUint64(seqNumPlaceholder)
206+
msg.AddUint8(uint8(protocol.ContentTypeConnectionID))
207+
msg.AddUint8(uint8(len(cid)))
208+
msg.AddUint8(uint8(protocol.ContentTypeConnectionID))
209+
msg.AddUint8(protocolVersion.Major)
210+
msg.AddUint8(protocolVersion.Minor)
211+
msg.AddUint16(epoch)
212+
util.AddUint48(&msg, sequenceNumber)
213+
msg.AddBytes(cid)
214+
msg.AddUint16(uint16(len(payload)))
215+
msg.AddBytes(ip.Content)
216+
msg.AddUint8(uint8(ip.RealType))
217+
msg.AddBytes(make([]byte, ip.Zeros))
218+
219+
if _, err := h.Write(msg.BytesOrPanic()); err != nil {
220+
return nil, err
221+
}
222+
if _, err := h.Write(payload); err != nil {
173223
return nil, err
174224
}
175225

pkg/crypto/ciphersuite/ccm.go

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,46 +62,56 @@ func NewCCM(tagLen CCMTagLen, localKey, localWriteIV, remoteKey, remoteWriteIV [
6262

6363
// Encrypt encrypt a DTLS RecordLayer message
6464
func (c *CCM) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
65-
payload := raw[recordlayer.HeaderSize:]
66-
raw = raw[:recordlayer.HeaderSize]
65+
payload := raw[pkt.Header.Size():]
66+
raw = raw[:pkt.Header.Size()]
6767

6868
nonce := append(append([]byte{}, c.localWriteIV[:4]...), make([]byte, 8)...)
6969
if _, err := rand.Read(nonce[4:]); err != nil {
7070
return nil, err
7171
}
7272

73-
additionalData := generateAEADAdditionalData(&pkt.Header, len(payload))
73+
var additionalData []byte
74+
if pkt.Header.ContentType == protocol.ContentTypeConnectionID {
75+
additionalData = generateAEADAdditionalDataCID(&pkt.Header, len(payload))
76+
} else {
77+
additionalData = generateAEADAdditionalData(&pkt.Header, len(payload))
78+
}
7479
encryptedPayload := c.localCCM.Seal(nil, nonce, payload, additionalData)
7580

7681
encryptedPayload = append(nonce[4:], encryptedPayload...)
7782
raw = append(raw, encryptedPayload...)
7883

7984
// Update recordLayer size to include explicit nonce
80-
binary.BigEndian.PutUint16(raw[recordlayer.HeaderSize-2:], uint16(len(raw)-recordlayer.HeaderSize))
85+
binary.BigEndian.PutUint16(raw[pkt.Header.Size()-2:], uint16(len(raw)-pkt.Header.Size()))
8186
return raw, nil
8287
}
8388

8489
// Decrypt decrypts a DTLS RecordLayer message
85-
func (c *CCM) Decrypt(in []byte) ([]byte, error) {
86-
var h recordlayer.Header
87-
err := h.Unmarshal(in)
88-
switch {
89-
case err != nil:
90+
func (c *CCM) Decrypt(h recordlayer.Header, in []byte) ([]byte, error) {
91+
if err := h.Unmarshal(in); err != nil {
9092
return nil, err
93+
}
94+
switch {
9195
case h.ContentType == protocol.ContentTypeChangeCipherSpec:
9296
// Nothing to encrypt with ChangeCipherSpec
9397
return in, nil
94-
case len(in) <= (8 + recordlayer.HeaderSize):
98+
case len(in) <= (8 + h.Size()):
9599
return nil, errNotEnoughRoomForNonce
96100
}
97101

98-
nonce := append(append([]byte{}, c.remoteWriteIV[:4]...), in[recordlayer.HeaderSize:recordlayer.HeaderSize+8]...)
99-
out := in[recordlayer.HeaderSize+8:]
102+
nonce := append(append([]byte{}, c.remoteWriteIV[:4]...), in[h.Size():h.Size()+8]...)
103+
out := in[h.Size()+8:]
100104

101-
additionalData := generateAEADAdditionalData(&h, len(out)-int(c.tagLen))
105+
var additionalData []byte
106+
if h.ContentType == protocol.ContentTypeConnectionID {
107+
additionalData = generateAEADAdditionalDataCID(&h, len(out)-int(c.tagLen))
108+
} else {
109+
additionalData = generateAEADAdditionalData(&h, len(out)-int(c.tagLen))
110+
}
111+
var err error
102112
out, err = c.remoteCCM.Open(out[:0], nonce, out, additionalData)
103113
if err != nil {
104114
return nil, fmt.Errorf("%w: %v", errDecryptPacket, err) //nolint:errorlint
105115
}
106-
return append(in[:recordlayer.HeaderSize], out...), nil
116+
return append(in[:h.Size()], out...), nil
107117
}

pkg/crypto/ciphersuite/gcm.go

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -55,49 +55,58 @@ func NewGCM(localKey, localWriteIV, remoteKey, remoteWriteIV []byte) (*GCM, erro
5555

5656
// Encrypt encrypt a DTLS RecordLayer message
5757
func (g *GCM) Encrypt(pkt *recordlayer.RecordLayer, raw []byte) ([]byte, error) {
58-
payload := raw[recordlayer.HeaderSize:]
59-
raw = raw[:recordlayer.HeaderSize]
58+
payload := raw[pkt.Header.Size():]
59+
raw = raw[:pkt.Header.Size()]
6060

6161
nonce := make([]byte, gcmNonceLength)
6262
copy(nonce, g.localWriteIV[:4])
6363
if _, err := rand.Read(nonce[4:]); err != nil {
6464
return nil, err
6565
}
6666

67-
additionalData := generateAEADAdditionalData(&pkt.Header, len(payload))
67+
var additionalData []byte
68+
if pkt.Header.ContentType == protocol.ContentTypeConnectionID {
69+
additionalData = generateAEADAdditionalDataCID(&pkt.Header, len(payload))
70+
} else {
71+
additionalData = generateAEADAdditionalData(&pkt.Header, len(payload))
72+
}
6873
encryptedPayload := g.localGCM.Seal(nil, nonce, payload, additionalData)
6974
r := make([]byte, len(raw)+len(nonce[4:])+len(encryptedPayload))
7075
copy(r, raw)
7176
copy(r[len(raw):], nonce[4:])
7277
copy(r[len(raw)+len(nonce[4:]):], encryptedPayload)
7378

7479
// Update recordLayer size to include explicit nonce
75-
binary.BigEndian.PutUint16(r[recordlayer.HeaderSize-2:], uint16(len(r)-recordlayer.HeaderSize))
80+
binary.BigEndian.PutUint16(r[pkt.Header.Size()-2:], uint16(len(r)-pkt.Header.Size()))
7681
return r, nil
7782
}
7883

7984
// Decrypt decrypts a DTLS RecordLayer message
80-
func (g *GCM) Decrypt(in []byte) ([]byte, error) {
81-
var h recordlayer.Header
85+
func (g *GCM) Decrypt(h recordlayer.Header, in []byte) ([]byte, error) {
8286
err := h.Unmarshal(in)
8387
switch {
8488
case err != nil:
8589
return nil, err
8690
case h.ContentType == protocol.ContentTypeChangeCipherSpec:
8791
// Nothing to encrypt with ChangeCipherSpec
8892
return in, nil
89-
case len(in) <= (8 + recordlayer.HeaderSize):
93+
case len(in) <= (8 + h.Size()):
9094
return nil, errNotEnoughRoomForNonce
9195
}
9296

9397
nonce := make([]byte, 0, gcmNonceLength)
94-
nonce = append(append(nonce, g.remoteWriteIV[:4]...), in[recordlayer.HeaderSize:recordlayer.HeaderSize+8]...)
95-
out := in[recordlayer.HeaderSize+8:]
98+
nonce = append(append(nonce, g.remoteWriteIV[:4]...), in[h.Size():h.Size()+8]...)
99+
out := in[h.Size()+8:]
96100

97-
additionalData := generateAEADAdditionalData(&h, len(out)-gcmTagLength)
101+
var additionalData []byte
102+
if h.ContentType == protocol.ContentTypeConnectionID {
103+
additionalData = generateAEADAdditionalDataCID(&h, len(out)-gcmTagLength)
104+
} else {
105+
additionalData = generateAEADAdditionalData(&h, len(out)-gcmTagLength)
106+
}
98107
out, err = g.remoteGCM.Open(out[:0], nonce, out, additionalData)
99108
if err != nil {
100109
return nil, fmt.Errorf("%w: %v", errDecryptPacket, err) //nolint:errorlint
101110
}
102-
return append(in[:recordlayer.HeaderSize], out...), nil
111+
return append(in[:h.Size()], out...), nil
103112
}

0 commit comments

Comments
 (0)