package dtls
import (
"bytes"
"encoding/gob"
"sync/atomic"
"github.com/pion/dtls/v2/pkg/crypto/elliptic"
"github.com/pion/dtls/v2/pkg/crypto/prf"
"github.com/pion/dtls/v2/pkg/protocol/handshake"
"github.com/pion/transport/v2/replaydetector"
)
type State struct {
localEpoch, remoteEpoch atomic .Value
localSequenceNumber []uint64
localRandom, remoteRandom handshake .Random
masterSecret []byte
cipherSuite CipherSuite
srtpProtectionProfile atomic .Value
PeerCertificates [][]byte
IdentityHint []byte
SessionID []byte
isClient bool
preMasterSecret []byte
extendedMasterSecret bool
namedCurve elliptic .Curve
localKeypair *elliptic .Keypair
cookie []byte
handshakeSendSequence int
handshakeRecvSequence int
serverName string
remoteRequestedCertificate bool
localCertificatesVerify []byte
localVerifyData []byte
localKeySignature []byte
peerCertificatesVerified bool
replayDetector []replaydetector .ReplayDetector
peerSupportedProtocols []string
NegotiatedProtocol string
}
type serializedState struct {
LocalEpoch uint16
RemoteEpoch uint16
LocalRandom [handshake .RandomLength ]byte
RemoteRandom [handshake .RandomLength ]byte
CipherSuiteID uint16
MasterSecret []byte
SequenceNumber uint64
SRTPProtectionProfile uint16
PeerCertificates [][]byte
IdentityHint []byte
SessionID []byte
IsClient bool
}
func (s *State ) clone () *State {
serialized := s .serialize ()
state := &State {}
state .deserialize (*serialized )
return state
}
func (s *State ) serialize () *serializedState {
localRnd := s .localRandom .MarshalFixed ()
remoteRnd := s .remoteRandom .MarshalFixed ()
epoch := s .getLocalEpoch ()
return &serializedState {
LocalEpoch : s .getLocalEpoch (),
RemoteEpoch : s .getRemoteEpoch (),
CipherSuiteID : uint16 (s .cipherSuite .ID ()),
MasterSecret : s .masterSecret ,
SequenceNumber : atomic .LoadUint64 (&s .localSequenceNumber [epoch ]),
LocalRandom : localRnd ,
RemoteRandom : remoteRnd ,
SRTPProtectionProfile : uint16 (s .getSRTPProtectionProfile ()),
PeerCertificates : s .PeerCertificates ,
IdentityHint : s .IdentityHint ,
SessionID : s .SessionID ,
IsClient : s .isClient ,
}
}
func (s *State ) deserialize (serialized serializedState ) {
epoch := serialized .LocalEpoch
s .localEpoch .Store (serialized .LocalEpoch )
s .remoteEpoch .Store (serialized .RemoteEpoch )
for len (s .localSequenceNumber ) <= int (epoch ) {
s .localSequenceNumber = append (s .localSequenceNumber , uint64 (0 ))
}
localRandom := &handshake .Random {}
localRandom .UnmarshalFixed (serialized .LocalRandom )
s .localRandom = *localRandom
remoteRandom := &handshake .Random {}
remoteRandom .UnmarshalFixed (serialized .RemoteRandom )
s .remoteRandom = *remoteRandom
s .isClient = serialized .IsClient
s .masterSecret = serialized .MasterSecret
s .cipherSuite = cipherSuiteForID (CipherSuiteID (serialized .CipherSuiteID ), nil )
atomic .StoreUint64 (&s .localSequenceNumber [epoch ], serialized .SequenceNumber )
s .setSRTPProtectionProfile (SRTPProtectionProfile (serialized .SRTPProtectionProfile ))
s .PeerCertificates = serialized .PeerCertificates
s .IdentityHint = serialized .IdentityHint
s .SessionID = serialized .SessionID
}
func (s *State ) initCipherSuite () error {
if s .cipherSuite .IsInitialized () {
return nil
}
localRandom := s .localRandom .MarshalFixed ()
remoteRandom := s .remoteRandom .MarshalFixed ()
var err error
if s .isClient {
err = s .cipherSuite .Init (s .masterSecret , localRandom [:], remoteRandom [:], true )
} else {
err = s .cipherSuite .Init (s .masterSecret , remoteRandom [:], localRandom [:], false )
}
if err != nil {
return err
}
return nil
}
func (s *State ) MarshalBinary () ([]byte , error ) {
serialized := s .serialize ()
var buf bytes .Buffer
enc := gob .NewEncoder (&buf )
if err := enc .Encode (*serialized ); err != nil {
return nil , err
}
return buf .Bytes (), nil
}
func (s *State ) UnmarshalBinary (data []byte ) error {
enc := gob .NewDecoder (bytes .NewBuffer (data ))
var serialized serializedState
if err := enc .Decode (&serialized ); err != nil {
return err
}
s .deserialize (serialized )
return s .initCipherSuite ()
}
func (s *State ) ExportKeyingMaterial (label string , context []byte , length int ) ([]byte , error ) {
if s .getLocalEpoch () == 0 {
return nil , errHandshakeInProgress
} else if len (context ) != 0 {
return nil , errContextUnsupported
} else if _ , ok := invalidKeyingLabels ()[label ]; ok {
return nil , errReservedExportKeyingMaterial
}
localRandom := s .localRandom .MarshalFixed ()
remoteRandom := s .remoteRandom .MarshalFixed ()
seed := []byte (label )
if s .isClient {
seed = append (append (seed , localRandom [:]...), remoteRandom [:]...)
} else {
seed = append (append (seed , remoteRandom [:]...), localRandom [:]...)
}
return prf .PHash (s .masterSecret , seed , length , s .cipherSuite .HashFunc ())
}
func (s *State ) getRemoteEpoch () uint16 {
if remoteEpoch , ok := s .remoteEpoch .Load ().(uint16 ); ok {
return remoteEpoch
}
return 0
}
func (s *State ) getLocalEpoch () uint16 {
if localEpoch , ok := s .localEpoch .Load ().(uint16 ); ok {
return localEpoch
}
return 0
}
func (s *State ) setSRTPProtectionProfile (profile SRTPProtectionProfile ) {
s .srtpProtectionProfile .Store (profile )
}
func (s *State ) getSRTPProtectionProfile () SRTPProtectionProfile {
if val , ok := s .srtpProtectionProfile .Load ().(SRTPProtectionProfile ); ok {
return val
}
return 0
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .