blob: 157fdebff3d9ea4e5ca83b485a5a4ef503498b81 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander65c7f672016-02-12 00:05:01 -08002 * Copyright 2009 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander65c7f672016-02-12 00:05:01 -08004 * 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.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "pc/srtpfilter.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000012
pbos@webrtc.org371243d2014-03-07 15:22:04 +000013#include <string.h>
14
henrike@webrtc.org28e20752013-07-10 00:45:36 +000015#include <algorithm>
henrike@webrtc.org28e20752013-07-10 00:45:36 +000016
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "media/base/rtputils.h"
18#include "pc/srtpsession.h"
19#include "rtc_base/base64.h"
20#include "rtc_base/byteorder.h"
21#include "rtc_base/checks.h"
22#include "rtc_base/logging.h"
23#include "rtc_base/stringencode.h"
24#include "rtc_base/timeutils.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000025
henrike@webrtc.org28e20752013-07-10 00:45:36 +000026namespace cricket {
27
jbauchdfcab722017-03-06 00:14:10 -080028SrtpFilter::SrtpFilter() {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000029}
30
31SrtpFilter::~SrtpFilter() {
32}
33
34bool SrtpFilter::IsActive() const {
35 return state_ >= ST_ACTIVE;
36}
37
38bool SrtpFilter::SetOffer(const std::vector<CryptoParams>& offer_params,
39 ContentSource source) {
40 if (!ExpectOffer(source)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010041 RTC_LOG(LS_ERROR) << "Wrong state to update SRTP offer";
42 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000043 }
44 return StoreParams(offer_params, source);
45}
46
47bool SrtpFilter::SetAnswer(const std::vector<CryptoParams>& answer_params,
48 ContentSource source) {
49 return DoSetAnswer(answer_params, source, true);
50}
51
52bool SrtpFilter::SetProvisionalAnswer(
53 const std::vector<CryptoParams>& answer_params,
54 ContentSource source) {
55 return DoSetAnswer(answer_params, source, false);
56}
57
henrike@webrtc.org28e20752013-07-10 00:45:36 +000058bool SrtpFilter::ExpectOffer(ContentSource source) {
59 return ((state_ == ST_INIT) ||
60 (state_ == ST_ACTIVE) ||
61 (state_ == ST_SENTOFFER && source == CS_LOCAL) ||
62 (state_ == ST_SENTUPDATEDOFFER && source == CS_LOCAL) ||
63 (state_ == ST_RECEIVEDOFFER && source == CS_REMOTE) ||
64 (state_ == ST_RECEIVEDUPDATEDOFFER && source == CS_REMOTE));
65}
66
67bool SrtpFilter::StoreParams(const std::vector<CryptoParams>& params,
68 ContentSource source) {
69 offer_params_ = params;
70 if (state_ == ST_INIT) {
71 state_ = (source == CS_LOCAL) ? ST_SENTOFFER : ST_RECEIVEDOFFER;
pthatcher@webrtc.org2e7ee4b2014-10-27 16:10:29 +000072 } else if (state_ == ST_ACTIVE) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000073 state_ =
74 (source == CS_LOCAL) ? ST_SENTUPDATEDOFFER : ST_RECEIVEDUPDATEDOFFER;
75 }
76 return true;
77}
78
79bool SrtpFilter::ExpectAnswer(ContentSource source) {
80 return ((state_ == ST_SENTOFFER && source == CS_REMOTE) ||
81 (state_ == ST_RECEIVEDOFFER && source == CS_LOCAL) ||
82 (state_ == ST_SENTUPDATEDOFFER && source == CS_REMOTE) ||
83 (state_ == ST_RECEIVEDUPDATEDOFFER && source == CS_LOCAL) ||
84 (state_ == ST_SENTPRANSWER_NO_CRYPTO && source == CS_LOCAL) ||
85 (state_ == ST_SENTPRANSWER && source == CS_LOCAL) ||
86 (state_ == ST_RECEIVEDPRANSWER_NO_CRYPTO && source == CS_REMOTE) ||
87 (state_ == ST_RECEIVEDPRANSWER && source == CS_REMOTE));
88}
89
90bool SrtpFilter::DoSetAnswer(const std::vector<CryptoParams>& answer_params,
91 ContentSource source,
92 bool final) {
93 if (!ExpectAnswer(source)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010094 RTC_LOG(LS_ERROR) << "Invalid state for SRTP answer";
henrike@webrtc.org28e20752013-07-10 00:45:36 +000095 return false;
96 }
97
98 // If the answer doesn't requests crypto complete the negotiation of an
99 // unencrypted session.
100 // Otherwise, finalize the parameters and apply them.
101 if (answer_params.empty()) {
102 if (final) {
103 return ResetParams();
104 } else {
105 // Need to wait for the final answer to decide if
106 // we should go to Active state.
107 state_ = (source == CS_LOCAL) ? ST_SENTPRANSWER_NO_CRYPTO :
108 ST_RECEIVEDPRANSWER_NO_CRYPTO;
109 return true;
110 }
111 }
112 CryptoParams selected_params;
113 if (!NegotiateParams(answer_params, &selected_params))
114 return false;
Zhi Huangcf990f52017-09-22 12:12:30 -0700115
116 const CryptoParams& new_send_params =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000117 (source == CS_REMOTE) ? selected_params : answer_params[0];
Zhi Huangcf990f52017-09-22 12:12:30 -0700118 const CryptoParams& new_recv_params =
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000119 (source == CS_REMOTE) ? answer_params[0] : selected_params;
Zhi Huangcf990f52017-09-22 12:12:30 -0700120 if (!ApplySendParams(new_send_params) || !ApplyRecvParams(new_recv_params)) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000121 return false;
122 }
Zhi Huangcf990f52017-09-22 12:12:30 -0700123 applied_send_params_ = new_send_params;
124 applied_recv_params_ = new_recv_params;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000125
126 if (final) {
127 offer_params_.clear();
128 state_ = ST_ACTIVE;
129 } else {
130 state_ =
131 (source == CS_LOCAL) ? ST_SENTPRANSWER : ST_RECEIVEDPRANSWER;
132 }
133 return true;
134}
135
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000136bool SrtpFilter::NegotiateParams(const std::vector<CryptoParams>& answer_params,
137 CryptoParams* selected_params) {
138 // We're processing an accept. We should have exactly one set of params,
139 // unless the offer didn't mention crypto, in which case we shouldn't be here.
140 bool ret = (answer_params.size() == 1U && !offer_params_.empty());
141 if (ret) {
142 // We should find a match between the answer params and the offered params.
143 std::vector<CryptoParams>::const_iterator it;
144 for (it = offer_params_.begin(); it != offer_params_.end(); ++it) {
145 if (answer_params[0].Matches(*it)) {
146 break;
147 }
148 }
149
150 if (it != offer_params_.end()) {
151 *selected_params = *it;
152 } else {
153 ret = false;
154 }
155 }
156
157 if (!ret) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100158 RTC_LOG(LS_WARNING) << "Invalid parameters in SRTP answer";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000159 }
160 return ret;
161}
162
Zhi Huangcf990f52017-09-22 12:12:30 -0700163bool SrtpFilter::ResetParams() {
164 offer_params_.clear();
165 applied_send_params_ = CryptoParams();
166 applied_recv_params_ = CryptoParams();
Oskar Sundbom36f8f3e2017-11-16 10:54:27 +0100167 send_cipher_suite_ = rtc::nullopt;
168 recv_cipher_suite_ = rtc::nullopt;
Zhi Huangcf990f52017-09-22 12:12:30 -0700169 send_key_.Clear();
170 recv_key_.Clear();
171 state_ = ST_INIT;
172 return true;
173}
174
175bool SrtpFilter::ApplySendParams(const CryptoParams& send_params) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000176 if (applied_send_params_.cipher_suite == send_params.cipher_suite &&
Zhi Huangcf990f52017-09-22 12:12:30 -0700177 applied_send_params_.key_params == send_params.key_params) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100178 RTC_LOG(LS_INFO) << "Applying the same SRTP send parameters again. No-op.";
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000179
180 // We do not want to reset the ROC if the keys are the same. So just return.
181 return true;
182 }
jbauchcb560652016-08-04 05:20:32 -0700183
Oskar Sundbom36f8f3e2017-11-16 10:54:27 +0100184 send_cipher_suite_ = rtc::SrtpCryptoSuiteFromName(send_params.cipher_suite);
Zhi Huangcf990f52017-09-22 12:12:30 -0700185 if (send_cipher_suite_ == rtc::SRTP_INVALID_CRYPTO_SUITE) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100186 RTC_LOG(LS_WARNING) << "Unknown crypto suite(s) received:"
187 << " send cipher_suite " << send_params.cipher_suite;
jbauchcb560652016-08-04 05:20:32 -0700188 return false;
189 }
190
191 int send_key_len, send_salt_len;
Zhi Huangcf990f52017-09-22 12:12:30 -0700192 if (!rtc::GetSrtpKeyAndSaltLengths(*send_cipher_suite_, &send_key_len,
193 &send_salt_len)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100194 RTC_LOG(LS_WARNING) << "Could not get lengths for crypto suite(s):"
195 << " send cipher_suite " << send_params.cipher_suite;
Zhi Huangcf990f52017-09-22 12:12:30 -0700196 return false;
197 }
198
199 send_key_ = rtc::Buffer(send_key_len + send_salt_len);
200 return ParseKeyParams(send_params.key_params, send_key_.data(),
201 send_key_.size());
202}
203
204bool SrtpFilter::ApplyRecvParams(const CryptoParams& recv_params) {
205 if (applied_recv_params_.cipher_suite == recv_params.cipher_suite &&
206 applied_recv_params_.key_params == recv_params.key_params) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100207 RTC_LOG(LS_INFO) << "Applying the same SRTP recv parameters again. No-op.";
Zhi Huangcf990f52017-09-22 12:12:30 -0700208
209 // We do not want to reset the ROC if the keys are the same. So just return.
210 return true;
211 }
212
Oskar Sundbom36f8f3e2017-11-16 10:54:27 +0100213 recv_cipher_suite_ = rtc::SrtpCryptoSuiteFromName(recv_params.cipher_suite);
Zhi Huangcf990f52017-09-22 12:12:30 -0700214 if (recv_cipher_suite_ == rtc::SRTP_INVALID_CRYPTO_SUITE) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100215 RTC_LOG(LS_WARNING) << "Unknown crypto suite(s) received:"
216 << " recv cipher_suite " << recv_params.cipher_suite;
zhihuange683c682017-08-31 16:00:07 -0700217 return false;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000218 }
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000219
Zhi Huangcf990f52017-09-22 12:12:30 -0700220 int recv_key_len, recv_salt_len;
221 if (!rtc::GetSrtpKeyAndSaltLengths(*recv_cipher_suite_, &recv_key_len,
222 &recv_salt_len)) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100223 RTC_LOG(LS_WARNING) << "Could not get lengths for crypto suite(s):"
224 << " recv cipher_suite " << recv_params.cipher_suite;
Zhi Huangcf990f52017-09-22 12:12:30 -0700225 return false;
zhihuangeb23e172017-09-19 01:12:52 -0700226 }
zhihuangeb23e172017-09-19 01:12:52 -0700227
Zhi Huangcf990f52017-09-22 12:12:30 -0700228 recv_key_ = rtc::Buffer(recv_key_len + recv_salt_len);
229 return ParseKeyParams(recv_params.key_params, recv_key_.data(),
230 recv_key_.size());
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000231}
232
233bool SrtpFilter::ParseKeyParams(const std::string& key_params,
Peter Boström0c4e06b2015-10-07 12:23:21 +0200234 uint8_t* key,
jbauchcb560652016-08-04 05:20:32 -0700235 size_t len) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000236 // example key_params: "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2"
237
238 // Fail if key-method is wrong.
239 if (key_params.find("inline:") != 0) {
240 return false;
241 }
242
243 // Fail if base64 decode fails, or the key is the wrong size.
244 std::string key_b64(key_params.substr(7)), key_str;
zhihuange683c682017-08-31 16:00:07 -0700245 if (!rtc::Base64::Decode(key_b64, rtc::Base64::DO_STRICT, &key_str,
246 nullptr) ||
247 key_str.size() != len) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000248 return false;
249 }
250
251 memcpy(key, key_str.c_str(), len);
252 return true;
253}
254
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000255} // namespace cricket