Implement packet replay protection
This commit is contained in:
		
							parent
							
								
									326aaf8070
								
							
						
					
					
						commit
						793ab80fce
					
				|  | @ -10,6 +10,7 @@ | |||
| #endif | ||||
| 
 | ||||
| #include <cstdint> | ||||
| #include <unordered_set> | ||||
| #include <vector> | ||||
| 
 | ||||
| #include "../debug.hh" | ||||
|  | @ -109,6 +110,8 @@ namespace uvg_rtp { | |||
|         uint16_t s_l;    /* highest received sequence number */ | ||||
|         uint8_t *replay; /* list of recently received and authenticated SRTP packets */ | ||||
| 
 | ||||
|         int flags; /* context configuration flags */ | ||||
| 
 | ||||
|         srtp_key_ctx_t key_ctx; | ||||
|     } srtp_ctx_t; | ||||
| 
 | ||||
|  | @ -161,6 +164,10 @@ namespace uvg_rtp { | |||
|             /* SRTP context containing all session information and keys */ | ||||
|             srtp_ctx_t *srtp_ctx_; | ||||
| 
 | ||||
|             /* Map containing all authentication tags of received packets (separate for SRTP and SRTCP)
 | ||||
|              * Used to implement replay protection */ | ||||
|             std::unordered_set<uint32_t> replay_list_; | ||||
| 
 | ||||
|             /* If NULL cipher is enabled, it means that RTP packets are not
 | ||||
|              * encrypted but other security mechanisms described in RFC 3711 may be used */ | ||||
|             bool use_null_cipher_; | ||||
|  |  | |||
|  | @ -24,7 +24,9 @@ namespace uvg_rtp { | |||
|             /* Verify the authentication tag present in "buffer"
 | ||||
|              * | ||||
|              * Return RTP_OK on success | ||||
|              * Return RTP_AUTH_TAG_MISMATCH if authentication tags don't match */ | ||||
|              * Return RTP_AUTH_TAG_MISMATCH if authentication tags don't match | ||||
|              * Return RTP_INVALID_VALUE if received packet has already been received | ||||
|              *        and replay protection has been enabled */ | ||||
|             rtp_error_t verify_auth_tag(uint8_t *buffer, size_t len); | ||||
| 
 | ||||
|             /* Decrypt and verify the authenticity of the RTCP packet
 | ||||
|  |  | |||
|  | @ -16,6 +16,9 @@ namespace uvg_rtp { | |||
|             /* TODO:  */ | ||||
|             rtp_error_t decrypt(uint8_t *buffer, size_t len); | ||||
| 
 | ||||
|             /* TODO:  */ | ||||
|             bool is_replayed_packet(uint32_t digest); | ||||
| 
 | ||||
|             /* Decrypt the payload of an RTP packet and verify authentication tag (if enabled) */ | ||||
|             static rtp_error_t recv_packet_handler(void *arg, int flags, frame::rtp_frame **out); | ||||
| 
 | ||||
|  |  | |||
|  | @ -194,9 +194,12 @@ enum RTP_CTX_ENABLE_FLAGS { | |||
|      * NOTE: this flag must be coupled with at least RCE_SRTP */ | ||||
|     RCE_SRTP_AUTHENTICATE_RTP     = 1 << 13, | ||||
| 
 | ||||
|     /* Enable packet replay protection */ | ||||
|     RCE_SRTP_REPLAY_PROTECTION    = 1 << 14, | ||||
| 
 | ||||
|     /* Enable RTCP for the media stream.
 | ||||
|      * If SRTP is enabled, SRTCP is used instead */ | ||||
|     RCE_RTCP                      = 1 << 14, | ||||
|     RCE_RTCP                      = 1 << 15, | ||||
| 
 | ||||
|     RCE_LAST                      = 1 << 15, | ||||
| }; | ||||
|  |  | |||
|  | @ -52,6 +52,9 @@ uvg_rtp::media_stream *uvg_rtp::session::create_stream(int r_port, int s_port, r | |||
| 
 | ||||
| #ifdef __RTP_CRYPTO__ | ||||
|     if (flags & RCE_SRTP) { | ||||
|         if (flags & RCE_SRTP_REPLAY_PROTECTION) | ||||
|             flags |= RCE_SRTP_AUTHENTICATE_RTP; | ||||
| 
 | ||||
|         if (flags & RCE_SRTP_KMNGMNT_ZRTP) { | ||||
| 
 | ||||
|             if (!zrtp_) { | ||||
|  |  | |||
|  | @ -94,6 +94,8 @@ rtp_error_t uvg_rtp::base_srtp::init(int type, int flags) | |||
|     use_null_cipher_  = !!(flags & RCE_SRTP_NULL_CIPHER); | ||||
|     authenticate_rtp_ = !!(flags & RCE_SRTP_AUTHENTICATE_RTP); | ||||
| 
 | ||||
|     srtp_ctx_->flags  = flags; | ||||
| 
 | ||||
|     int label_enc  = 0; | ||||
|     int label_auth = 0; | ||||
|     int label_salt = 0; | ||||
|  |  | |||
|  | @ -55,8 +55,19 @@ rtp_error_t uvg_rtp::srtcp::verify_auth_tag(uint8_t *buffer, size_t len) | |||
|     hmac_sha1.update((uint8_t *)&srtp_ctx_->roc, sizeof(srtp_ctx_->roc)); | ||||
|     hmac_sha1.final((uint8_t *)&digest, AUTH_TAG_LENGTH); | ||||
| 
 | ||||
|     if (memcmp(&digest, &buffer[len - AUTH_TAG_LENGTH], AUTH_TAG_LENGTH)) | ||||
|     if (memcmp(&digest, &buffer[len - AUTH_TAG_LENGTH], AUTH_TAG_LENGTH)) { | ||||
|         LOG_ERROR("STCP authentication tag mismatch!"); | ||||
|         return RTP_AUTH_TAG_MISMATCH; | ||||
|     } | ||||
| 
 | ||||
|     if (srtp_ctx_->flags & RCE_SRTP_REPLAY_PROTECTION) { | ||||
|         if (replay_list_.find(digest) != replay_list_.end()) { | ||||
|             LOG_ERROR("Replayed packet received, discarding!"); | ||||
|             return RTP_INVALID_VALUE; | ||||
|         } | ||||
|         replay_list_.insert(digest); | ||||
|     } | ||||
| 
 | ||||
|     return RTP_OK; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -41,6 +41,20 @@ rtp_error_t uvg_rtp::srtp::encrypt(uint32_t ssrc, uint16_t seq, uint8_t *buffer, | |||
|     return RTP_OK; | ||||
| } | ||||
| 
 | ||||
| bool uvg_rtp::srtp::is_replayed_packet(uint32_t digest) | ||||
| { | ||||
|     if (!(srtp_ctx_->flags & RCE_SRTP_REPLAY_PROTECTION)) | ||||
|         return false; | ||||
| 
 | ||||
|     if (replay_list_.find(digest) != replay_list_.end()) { | ||||
|         LOG_ERROR("Replayed packet received, discarding!"); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     replay_list_.insert(digest); | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| rtp_error_t uvg_rtp::srtp::recv_packet_handler(void *arg, int flags, frame::rtp_frame **out) | ||||
| { | ||||
|     (void)flags; | ||||
|  | @ -63,6 +77,10 @@ rtp_error_t uvg_rtp::srtp::recv_packet_handler(void *arg, int flags, frame::rtp_ | |||
|             return RTP_GENERIC_ERROR; | ||||
|         } | ||||
| 
 | ||||
|         if (srtp->is_replayed_packet(digest)) { | ||||
|             LOG_ERROR("Replayed packet received, discarding!"); | ||||
|             return RTP_INVALID_VALUE; | ||||
|         } | ||||
|         frame->payload_len -= AUTH_TAG_LENGTH; | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue