libsrtp_fuzzer.cc 6.4 KB

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