1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
|
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
// SPDX-License-Identifier: MIT
package recordlayer
import (
"encoding/binary"
"github.com/pion/dtls/v3/internal/util"
"github.com/pion/dtls/v3/pkg/protocol"
)
// Header implements a TLS RecordLayer header.
type Header struct {
ContentType protocol.ContentType
ContentLen uint16
Version protocol.Version
Epoch uint16
SequenceNumber uint64 // uint48 in spec
// Optional Fields
ConnectionID []byte
}
// RecordLayer enums.
const (
// FixedHeaderSize is the size of a DTLS record header when connection IDs
// are not in use.
FixedHeaderSize = 13
MaxSequenceNumber = 0x0000FFFFFFFFFFFF
)
// Marshal encodes a TLS RecordLayer Header to binary.
func (h *Header) Marshal() ([]byte, error) {
if h.SequenceNumber > MaxSequenceNumber {
return nil, errSequenceNumberOverflow
}
hs := FixedHeaderSize + len(h.ConnectionID)
out := make([]byte, hs)
out[0] = byte(h.ContentType)
out[1] = h.Version.Major
out[2] = h.Version.Minor
binary.BigEndian.PutUint16(out[3:], h.Epoch)
util.PutBigEndianUint48(out[5:], h.SequenceNumber)
copy(out[11:11+len(h.ConnectionID)], h.ConnectionID)
binary.BigEndian.PutUint16(out[hs-2:], h.ContentLen)
return out, nil
}
// Unmarshal populates a TLS RecordLayer Header from binary.
func (h *Header) Unmarshal(data []byte) error {
if len(data) < FixedHeaderSize {
return errBufferTooSmall
}
h.ContentType = protocol.ContentType(data[0])
if h.ContentType == protocol.ContentTypeConnectionID {
// If a CID was expected the ConnectionID should have been initialized.
if len(data) < FixedHeaderSize+len(h.ConnectionID) {
return errBufferTooSmall
}
h.ConnectionID = data[11 : 11+len(h.ConnectionID)]
}
h.Version.Major = data[1]
h.Version.Minor = data[2]
h.Epoch = binary.BigEndian.Uint16(data[3:])
// SequenceNumber is stored as uint48, make into uint64
seqCopy := make([]byte, 8)
copy(seqCopy[2:], data[5:11])
h.SequenceNumber = binary.BigEndian.Uint64(seqCopy)
if !h.Version.Equal(protocol.Version1_0) && !h.Version.Equal(protocol.Version1_2) {
return errUnsupportedProtocolVersion
}
return nil
}
// Size returns the total size of the header.
func (h *Header) Size() int {
return FixedHeaderSize + len(h.ConnectionID)
}
|