• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include <assert.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 
14 #include <algorithm>
15 #include <vector>
16 
17 #include "third_party/libsrtp/include/srtp.h"
18 #include "third_party/libsrtp/include/srtp_priv.h"
19 #include "third_party/libsrtp/test/rtp.h"
20 
21 // TODO(katrielc) Also test the authenticated path, which is what
22 // WebRTC uses.  This is nontrivial because you need to bypass the MAC
23 // check. Two options: add a UNSAFE_FUZZER_MODE flag to libsrtp (or
24 // the chromium fork of it), or compute the HMAC of whatever gibberish
25 // the fuzzer produces and write it into the packet manually.
26 
27 namespace LibSrtpFuzzer {
28 enum CryptoPolicy {
29   NONE,
30   LIKE_WEBRTC,
31   LIKE_WEBRTC_SHORT_AUTH,
32   LIKE_WEBRTC_WITHOUT_AUTH,
33   AES_128_GCM,
34   AES_256_GCM,
35   NUMBER_OF_POLICIES,
36 };
37 }
38 
GetKeyLength(LibSrtpFuzzer::CryptoPolicy crypto_policy)39 static size_t GetKeyLength(LibSrtpFuzzer::CryptoPolicy crypto_policy) {
40   switch (crypto_policy) {
41     case LibSrtpFuzzer::NUMBER_OF_POLICIES:
42     case LibSrtpFuzzer::NONE:
43       return SRTP_AES_ICM_128_KEY_LEN_WSALT;
44     case LibSrtpFuzzer::LIKE_WEBRTC:
45     case LibSrtpFuzzer::LIKE_WEBRTC_SHORT_AUTH:
46     case LibSrtpFuzzer::LIKE_WEBRTC_WITHOUT_AUTH:
47       return SRTP_AES_ICM_128_KEY_LEN_WSALT;
48     case LibSrtpFuzzer::AES_128_GCM:
49       return SRTP_AES_GCM_128_KEY_LEN_WSALT;
50     case LibSrtpFuzzer::AES_256_GCM:
51       return SRTP_AES_GCM_256_KEY_LEN_WSALT;
52   }
53 }
54 
55 struct Environment {
GetCryptoPolicyEnvironment56   srtp_policy_t GetCryptoPolicy(LibSrtpFuzzer::CryptoPolicy crypto_policy,
57                                 const unsigned char* replacement_key,
58                                 size_t key_length) {
59     switch (crypto_policy) {
60       case LibSrtpFuzzer::NUMBER_OF_POLICIES:
61       case LibSrtpFuzzer::NONE:
62         srtp_crypto_policy_set_null_cipher_hmac_null(&policy.rtp);
63         srtp_crypto_policy_set_null_cipher_hmac_null(&policy.rtcp);
64         break;
65       case LibSrtpFuzzer::LIKE_WEBRTC:
66         srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtp);
67         srtp_crypto_policy_set_aes_cm_128_hmac_sha1_80(&policy.rtcp);
68         break;
69       case LibSrtpFuzzer::LIKE_WEBRTC_SHORT_AUTH:
70         srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtp);
71         srtp_crypto_policy_set_aes_cm_128_hmac_sha1_32(&policy.rtcp);
72         break;
73       case LibSrtpFuzzer::LIKE_WEBRTC_WITHOUT_AUTH:
74         srtp_crypto_policy_set_aes_cm_128_null_auth(&policy.rtp);
75         srtp_crypto_policy_set_aes_cm_128_null_auth(&policy.rtcp);
76         break;
77       case LibSrtpFuzzer::AES_128_GCM:
78         // There was a security bug in the GCM mode in libsrtp 1.5.2.
79         srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtp);
80         srtp_crypto_policy_set_aes_gcm_128_16_auth(&policy.rtcp);
81         break;
82       case LibSrtpFuzzer::AES_256_GCM:
83         // WebRTC uses AES-256-GCM by default if GCM ciphers are enabled.
84         srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtp);
85         srtp_crypto_policy_set_aes_gcm_256_16_auth(&policy.rtcp);
86         break;
87     }
88 
89     assert(static_cast<size_t>(policy.rtp.cipher_key_len) == key_length);
90     assert(static_cast<size_t>(policy.rtcp.cipher_key_len) == key_length);
91     memcpy(key, replacement_key, key_length);
92     return policy;
93   }
94 
EnvironmentEnvironment95   Environment() {
96     srtp_init();
97 
98     memset(&policy, 0, sizeof(policy));
99     policy.allow_repeat_tx = 1;
100     policy.key = key;
101     policy.next = nullptr;
102     policy.ssrc.type = ssrc_any_inbound;
103     policy.ssrc.value = 0xdeadbeef;
104     policy.window_size = 1024;
105   }
106 
107  private:
108   srtp_policy_t policy;
109   unsigned char key[SRTP_MAX_KEY_LEN] = {0};
110 
111 };
112 
ReadLength(const uint8_t * data,size_t size)113 size_t ReadLength(const uint8_t* data, size_t size) {
114   // Read one byte of input and interpret it as a length to read from
115   // data. Don't return more bytes than are available.
116   size_t n = static_cast<size_t>(data[0]);
117   return std::min(n, size - 1);
118 }
119 
120 Environment* env = new Environment();
121 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)122 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
123   // Read one byte and use it to choose a crypto policy.
124   if (size <= 2 + SRTP_MAX_KEY_LEN)
125     return 0;
126   LibSrtpFuzzer::CryptoPolicy policy = static_cast<LibSrtpFuzzer::CryptoPolicy>(
127       data[0] % LibSrtpFuzzer::NUMBER_OF_POLICIES);
128   data += 1;
129   size -= 1;
130 
131   // Read some more bytes to use as a key.
132   size_t key_length = GetKeyLength(policy);
133   srtp_policy_t srtp_policy = env->GetCryptoPolicy(policy, data, key_length);
134   data += SRTP_MAX_KEY_LEN;
135   size -= SRTP_MAX_KEY_LEN;
136 
137   // Read one byte and use as number of encrypted header extensions.
138   uint8_t num_encrypted_headers = data[0];
139   data += 1;
140   size -= 1;
141   if (num_encrypted_headers > 0) {
142     // Use next bytes as extension ids.
143     if (size <= num_encrypted_headers)
144       return 0;
145     srtp_policy.enc_xtn_hdr_count = static_cast<int>(num_encrypted_headers);
146     srtp_policy.enc_xtn_hdr =
147         static_cast<int*>(malloc(srtp_policy.enc_xtn_hdr_count * sizeof(int)));
148     assert(srtp_policy.enc_xtn_hdr);
149     for (int i = 0; i < srtp_policy.enc_xtn_hdr_count; ++i) {
150       srtp_policy.enc_xtn_hdr[i] = static_cast<int>(data[i]);
151     }
152     data += srtp_policy.enc_xtn_hdr_count;
153     size -= srtp_policy.enc_xtn_hdr_count;
154   }
155 
156   srtp_t session;
157   srtp_err_status_t error = srtp_create(&session, &srtp_policy);
158   free(srtp_policy.enc_xtn_hdr);
159   if (error != srtp_err_status_ok) {
160     assert(false);
161     return 0;
162   }
163 
164   // Read one byte as a packet length N, then feed the next N bytes
165   // into srtp_unprotect. Keep going until we run out of data.
166   size_t packet_size;
167   while (size > 0 && (packet_size = ReadLength(data, size)) > 0) {
168     // One byte was used by ReadLength.
169     data++;
170     size--;
171 
172     size_t header_size = std::min(sizeof(srtp_hdr_t), packet_size);
173     size_t body_size = packet_size - header_size;
174 
175     // We deliberately do not initialise this struct. MSAN will catch
176     // usage of the uninitialised memory.
177     rtp_msg_t message;
178     memcpy(&message.header, data, header_size);
179     memcpy(&message.body, data + header_size, body_size);
180 
181     int out_len = static_cast<int>(packet_size);
182     srtp_unprotect(session, &message, &out_len);
183 
184     // |packet_size| bytes were used above.
185     data += packet_size;
186     size -= packet_size;
187   }
188 
189   srtp_dealloc(session);
190   return 0;
191 }
192