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