crypto_options.cc (5363B)
1 /* 2 * Copyright 2018 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "api/crypto/crypto_options.h" 12 13 #include <cstdint> 14 #include <optional> 15 #include <set> 16 #include <string> 17 #include <utility> 18 #include <vector> 19 20 #include "absl/algorithm/container.h" 21 #include "api/field_trials_view.h" 22 #include "rtc_base/checks.h" 23 #include "rtc_base/ssl_stream_adapter.h" 24 25 namespace webrtc { 26 27 CryptoOptions::CryptoOptions() {} 28 29 // static 30 CryptoOptions CryptoOptions::NoGcm() { 31 CryptoOptions options; 32 options.srtp.enable_gcm_crypto_suites = false; 33 return options; 34 } 35 36 std::vector<int> CryptoOptions::GetSupportedDtlsSrtpCryptoSuites() const { 37 std::vector<int> crypto_suites; 38 // Note: kSrtpAes128CmSha1_80 is what is required to be supported (by 39 // draft-ietf-rtcweb-security-arch), but kSrtpAes128CmSha1_32 is allowed as 40 // well, and saves a few bytes per packet if it ends up selected. 41 // As the cipher suite is potentially insecure, it will only be used if 42 // enabled by both peers. 43 if (srtp.enable_aes128_sha1_32_crypto_cipher) { 44 crypto_suites.push_back(kSrtpAes128CmSha1_32); 45 } 46 if (srtp.enable_aes128_sha1_80_crypto_cipher) { 47 crypto_suites.push_back(kSrtpAes128CmSha1_80); 48 } 49 50 // Note: GCM cipher suites are not the top choice since they increase the 51 // packet size. In order to negotiate them the other side must not support 52 // kSrtpAes128CmSha1_80. 53 if (srtp.enable_gcm_crypto_suites) { 54 crypto_suites.push_back(kSrtpAeadAes256Gcm); 55 crypto_suites.push_back(kSrtpAeadAes128Gcm); 56 } 57 RTC_CHECK(!crypto_suites.empty()); 58 return crypto_suites; 59 } 60 61 bool CryptoOptions::operator==(const CryptoOptions& other) const { 62 struct data_being_tested_for_equality { 63 struct Srtp { 64 bool enable_gcm_crypto_suites; 65 bool enable_aes128_sha1_32_crypto_cipher; 66 bool enable_aes128_sha1_80_crypto_cipher; 67 bool enable_encrypted_rtp_header_extensions; 68 } srtp; 69 struct SFrame { 70 bool require_frame_encryption; 71 } sframe; 72 EphemeralKeyExchangeCipherGroups ephemeral_key_exchange_cipher_groups; 73 }; 74 static_assert(sizeof(data_being_tested_for_equality) == sizeof(*this), 75 "Did you add something to CryptoOptions and forget to " 76 "update operator==?"); 77 78 return srtp.enable_gcm_crypto_suites == other.srtp.enable_gcm_crypto_suites && 79 srtp.enable_aes128_sha1_32_crypto_cipher == 80 other.srtp.enable_aes128_sha1_32_crypto_cipher && 81 srtp.enable_aes128_sha1_80_crypto_cipher == 82 other.srtp.enable_aes128_sha1_80_crypto_cipher && 83 srtp.enable_encrypted_rtp_header_extensions == 84 other.srtp.enable_encrypted_rtp_header_extensions && 85 sframe.require_frame_encryption == 86 other.sframe.require_frame_encryption && 87 ephemeral_key_exchange_cipher_groups == 88 other.ephemeral_key_exchange_cipher_groups; 89 } 90 91 bool CryptoOptions::operator!=(const CryptoOptions& other) const { 92 return !(*this == other); 93 } 94 95 CryptoOptions::EphemeralKeyExchangeCipherGroups:: 96 EphemeralKeyExchangeCipherGroups() 97 : enabled_(SSLStreamAdapter::GetDefaultEphemeralKeyExchangeCipherGroups( 98 /* field_trials= */ nullptr)) {} 99 100 bool CryptoOptions::EphemeralKeyExchangeCipherGroups::operator==( 101 const CryptoOptions::EphemeralKeyExchangeCipherGroups& other) const { 102 return enabled_ == other.enabled_; 103 } 104 105 std::set<uint16_t> 106 CryptoOptions::EphemeralKeyExchangeCipherGroups::GetSupported() { 107 return SSLStreamAdapter::GetSupportedEphemeralKeyExchangeCipherGroups(); 108 } 109 110 std::optional<std::string> 111 CryptoOptions::EphemeralKeyExchangeCipherGroups::GetName(uint16_t group_id) { 112 return SSLStreamAdapter::GetEphemeralKeyExchangeCipherGroupName(group_id); 113 } 114 115 void CryptoOptions::EphemeralKeyExchangeCipherGroups::AddFirst(uint16_t group) { 116 std::erase(enabled_, group); 117 enabled_.insert(enabled_.begin(), group); 118 } 119 120 void CryptoOptions::EphemeralKeyExchangeCipherGroups::Update( 121 const FieldTrialsView* field_trials, 122 const std::vector<uint16_t>* disabled_groups) { 123 // Note: assumption is that these lists contains few elements...so converting 124 // to set<> is not worth it. 125 std::vector<uint16_t> default_groups = 126 SSLStreamAdapter::GetDefaultEphemeralKeyExchangeCipherGroups( 127 field_trials); 128 // Remove all disabled. 129 if (disabled_groups) { 130 std::erase_if(default_groups, [&](uint16_t val) { 131 return absl::c_linear_search(*disabled_groups, val); 132 }); 133 std::erase_if(enabled_, [&](uint16_t val) { 134 return absl::c_linear_search(*disabled_groups, val); 135 }); 136 } 137 138 // Add those enabled by field-trials first. 139 std::vector<uint16_t> current = std::move(enabled_); 140 enabled_.clear(); 141 for (auto val : default_groups) { 142 if (!absl::c_linear_search(current, val)) { 143 enabled_.push_back(val); 144 } 145 } 146 147 // Then re-add those present (unless already there). 148 for (auto val : current) { 149 if (!absl::c_linear_search(enabled_, val)) { 150 enabled_.push_back(val); 151 } 152 } 153 } 154 155 } // namespace webrtc