@@ -43,6 +43,23 @@ type srtcpSSRCState struct {
4343 replayDetector replaydetector.ReplayDetector
4444}
4545
46+ // RCCMode is the mode of Roll-over Counter Carrying Transform from RFC 4771.
47+ type RCCMode int
48+
49+ const (
50+ // RCCModeNone is the default mode.
51+ RCCModeNone RCCMode = iota
52+ // RCCMode1 is RCCm1 mode from RFC 4771. In this mode ROC and truncated auth tag is sent every R-th packet,
53+ // and no auth tag in other ones. This mode is not supported by pion/srtp.
54+ RCCMode1
55+ // RCCMode2 is RCCm2 mode from RFC 4771. In this mode ROC and truncated auth tag is sent every R-th packet,
56+ // and full auth tag in other ones. This mode is supported for AES-CM and NULL profiles only.
57+ RCCMode2
58+ // RCCMode3 is RCCm3 mode from RFC 4771. In this mode ROC is sent every R-th packet (without truncated auth tag),
59+ // and no auth tag in other ones. This mode is supported for AES-GCM profiles only.
60+ RCCMode3
61+ )
62+
4663// Context represents a SRTP cryptographic context.
4764// Context can only be used for one-way operations.
4865// it must either used ONLY for encryption or ONLY for decryption.
@@ -67,6 +84,11 @@ type Context struct {
6784
6885 encryptSRTP bool
6986 encryptSRTCP bool
87+
88+ rccMode RCCMode
89+ rocTransmitRate uint16
90+
91+ authTagRTPLen * int
7092}
7193
7294// CreateContext creates a new SRTP Context.
@@ -102,6 +124,21 @@ func CreateContext(
102124 }
103125 }
104126
127+ if err = c .checkRCCMode (); err != nil {
128+ return nil , err
129+ }
130+
131+ if c .authTagRTPLen != nil {
132+ var authKeyLen int
133+ authKeyLen , err = c .profile .AuthKeyLen ()
134+ if err != nil {
135+ return nil , err
136+ }
137+ if * c .authTagRTPLen > authKeyLen {
138+ return nil , errTooLongSRTPAuthTag
139+ }
140+ }
141+
105142 c .cipher , err = c .createCipher (c .sendMKI , masterKey , masterSalt , c .encryptSRTP , c .encryptSRTCP )
106143 if err != nil {
107144 return nil , err
@@ -154,16 +191,21 @@ func (c *Context) createCipher(mki, masterKey, masterSalt []byte, encryptSRTP, e
154191 return nil , fmt .Errorf ("%w expected(%d) actual(%d)" , errShortSrtpMasterSalt , saltLen , masterSaltLen )
155192 }
156193
194+ profileWithArgs := protectionProfileWithArgs {
195+ ProtectionProfile : c .profile ,
196+ authTagRTPLen : c .authTagRTPLen ,
197+ }
198+
157199 switch c .profile {
158200 case ProtectionProfileAeadAes128Gcm , ProtectionProfileAeadAes256Gcm :
159- return newSrtpCipherAeadAesGcm (c . profile , masterKey , masterSalt , mki , encryptSRTP , encryptSRTCP )
201+ return newSrtpCipherAeadAesGcm (profileWithArgs , masterKey , masterSalt , mki , encryptSRTP , encryptSRTCP )
160202 case ProtectionProfileAes128CmHmacSha1_32 ,
161203 ProtectionProfileAes128CmHmacSha1_80 ,
162204 ProtectionProfileAes256CmHmacSha1_32 ,
163205 ProtectionProfileAes256CmHmacSha1_80 :
164- return newSrtpCipherAesCmHmacSha1 (c . profile , masterKey , masterSalt , mki , encryptSRTP , encryptSRTCP )
206+ return newSrtpCipherAesCmHmacSha1 (profileWithArgs , masterKey , masterSalt , mki , encryptSRTP , encryptSRTCP )
165207 case ProtectionProfileNullHmacSha1_32 , ProtectionProfileNullHmacSha1_80 :
166- return newSrtpCipherAesCmHmacSha1 (c . profile , masterKey , masterSalt , mki , false , false )
208+ return newSrtpCipherAesCmHmacSha1 (profileWithArgs , masterKey , masterSalt , mki , false , false )
167209 default :
168210 return nil , fmt .Errorf ("%w: %#v" , errNoSuchSRTPProfile , c .profile )
169211 }
@@ -197,7 +239,7 @@ func (c *Context) SetSendMKI(mki []byte) error {
197239}
198240
199241// https://tools.ietf.org/html/rfc3550#appendix-A.1
200- func (s * srtpSSRCState ) nextRolloverCount (sequenceNumber uint16 ) (roc uint32 , diff int32 , overflow bool ) {
242+ func (s * srtpSSRCState ) nextRolloverCount (sequenceNumber uint16 ) (roc uint32 , diff int64 , overflow bool ) {
201243 seq := int32 (sequenceNumber )
202244 localRoc := uint32 (s .index >> 16 ) //nolint:gosec // G115
203245 localSeq := int32 (s .index & (seqNumMax - 1 )) //nolint:gosec // G115
@@ -232,17 +274,20 @@ func (s *srtpSSRCState) nextRolloverCount(sequenceNumber uint16) (roc uint32, di
232274 }
233275 }
234276
235- return guessRoc , difference , (guessRoc == 0 && localRoc == maxROC )
277+ return guessRoc , int64 ( difference ) , (guessRoc == 0 && localRoc == maxROC )
236278}
237279
238- func (s * srtpSSRCState ) updateRolloverCount (sequenceNumber uint16 , difference int32 ) {
239- if ! s .rolloverHasProcessed {
280+ func (s * srtpSSRCState ) updateRolloverCount (sequenceNumber uint16 , difference int64 , hasRemoteRoc bool ,
281+ remoteRoc uint32 ,
282+ ) {
283+ switch {
284+ case hasRemoteRoc :
285+ s .index = (uint64 (remoteRoc ) << 16 ) | uint64 (sequenceNumber )
286+ s .rolloverHasProcessed = true
287+ case ! s .rolloverHasProcessed :
240288 s .index |= uint64 (sequenceNumber )
241289 s .rolloverHasProcessed = true
242-
243- return
244- }
245- if difference > 0 {
290+ case difference > 0 :
246291 s .index += uint64 (difference )
247292 }
248293}
@@ -309,3 +354,49 @@ func (c *Context) SetIndex(ssrc uint32, index uint32) {
309354 s := c .getSRTCPSSRCState (ssrc )
310355 s .srtcpIndex = index % (maxSRTCPIndex + 1 )
311356}
357+
358+ //nolint:cyclop
359+ func (c * Context ) checkRCCMode () error {
360+ if c .rccMode == RCCModeNone {
361+ return nil
362+ }
363+
364+ if c .rocTransmitRate == 0 {
365+ return errZeroRocTransmitRate
366+ }
367+
368+ switch c .profile {
369+ case ProtectionProfileAeadAes128Gcm , ProtectionProfileAeadAes256Gcm :
370+ // AEAD profiles support RCCMode3 only
371+ if c .rccMode != RCCMode3 {
372+ return errUnsupportedRccMode
373+ }
374+
375+ case ProtectionProfileAes128CmHmacSha1_32 ,
376+ ProtectionProfileAes256CmHmacSha1_32 ,
377+ ProtectionProfileNullHmacSha1_32 :
378+ if c .authTagRTPLen == nil {
379+ // ROC completely replaces auth tag for _32 profiles. If you really want to use 4-byte
380+ // SRTP auth tag with RCC, use SRTPAuthenticationTagLength(4) option.
381+ return errTooShortSRTPAuthTag
382+ }
383+
384+ fallthrough // Checks below are common for _32 and _80 profiles.
385+
386+ case ProtectionProfileAes128CmHmacSha1_80 ,
387+ ProtectionProfileAes256CmHmacSha1_80 ,
388+ ProtectionProfileNullHmacSha1_80 :
389+ // AES-CM and NULL profiles support RCCMode2 only
390+ if c .rccMode != RCCMode2 {
391+ return errUnsupportedRccMode
392+ }
393+ if c .authTagRTPLen != nil && * c .authTagRTPLen < 4 {
394+ return errTooShortSRTPAuthTag
395+ }
396+
397+ default :
398+ return errUnsupportedRccMode
399+ }
400+
401+ return nil
402+ }
0 commit comments