Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(246)

Side by Side Diff: webrtc/pc/srtpfilter.cc

Issue 2997983002: Completed the functionalities of SrtpTransport. (Closed)
Patch Set: Create the SrtpTransport by default and reset it to nullptr if the insecure RTP protocol is used. Created 3 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2009 The WebRTC project authors. All Rights Reserved. 2 * Copyright 2009 The WebRTC project authors. All Rights Reserved.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license 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 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 6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may 7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree. 8 * be found in the AUTHORS file in the root of the source tree.
9 */ 9 */
10 10
11 #include "webrtc/pc/srtpfilter.h" 11 #include "webrtc/pc/srtpfilter.h"
12 12
13 #include <string.h> 13 #include <string.h>
14 14
15 #include <algorithm> 15 #include <algorithm>
16 16
17 #include "webrtc/media/base/rtputils.h" 17 #include "webrtc/media/base/rtputils.h"
18 #include "webrtc/pc/srtpsession.h" 18 #include "webrtc/pc/srtpsession.h"
19 #include "webrtc/pc/srtptransport.h"
Taylor Brandstetter 2017/08/26 02:40:39 What part of srtptransport.h does this use?
Zhi Huang 2017/08/29 18:40:35 Removed.
19 #include "webrtc/rtc_base/base64.h" 20 #include "webrtc/rtc_base/base64.h"
20 #include "webrtc/rtc_base/buffer.h"
21 #include "webrtc/rtc_base/byteorder.h" 21 #include "webrtc/rtc_base/byteorder.h"
22 #include "webrtc/rtc_base/checks.h" 22 #include "webrtc/rtc_base/checks.h"
23 #include "webrtc/rtc_base/logging.h" 23 #include "webrtc/rtc_base/logging.h"
24 #include "webrtc/rtc_base/stringencode.h" 24 #include "webrtc/rtc_base/stringencode.h"
25 #include "webrtc/rtc_base/timeutils.h" 25 #include "webrtc/rtc_base/timeutils.h"
26 26
27 namespace cricket { 27 namespace cricket {
28 28
29 // NOTE: This is called from ChannelManager D'tor. 29 // NOTE: This is called from ChannelManager D'tor.
30 void ShutdownSrtp() { 30 void ShutdownSrtp() {
(...skipping 25 matching lines...) Expand all
56 ContentSource source) { 56 ContentSource source) {
57 return DoSetAnswer(answer_params, source, true); 57 return DoSetAnswer(answer_params, source, true);
58 } 58 }
59 59
60 bool SrtpFilter::SetProvisionalAnswer( 60 bool SrtpFilter::SetProvisionalAnswer(
61 const std::vector<CryptoParams>& answer_params, 61 const std::vector<CryptoParams>& answer_params,
62 ContentSource source) { 62 ContentSource source) {
63 return DoSetAnswer(answer_params, source, false); 63 return DoSetAnswer(answer_params, source, false);
64 } 64 }
65 65
66 bool SrtpFilter::SetRtpParams(int send_cs,
67 const uint8_t* send_key,
68 int send_key_len,
69 int recv_cs,
70 const uint8_t* recv_key,
71 int recv_key_len) {
72 if (IsActive()) {
73 LOG(LS_ERROR) << "Tried to set SRTP Params when filter already active";
74 return false;
75 }
76 CreateSrtpSessions();
77 send_session_->SetEncryptedHeaderExtensionIds(
78 send_encrypted_header_extension_ids_);
79 if (!send_session_->SetSend(send_cs, send_key, send_key_len)) {
80 return false;
81 }
82
83 recv_session_->SetEncryptedHeaderExtensionIds(
84 recv_encrypted_header_extension_ids_);
85 if (!recv_session_->SetRecv(recv_cs, recv_key, recv_key_len)) {
86 return false;
87 }
88
89 state_ = ST_ACTIVE;
90
91 LOG(LS_INFO) << "SRTP activated with negotiated parameters:"
92 << " send cipher_suite " << send_cs
93 << " recv cipher_suite " << recv_cs;
94 return true;
95 }
96
97 bool SrtpFilter::UpdateRtpParams(int send_cs,
98 const uint8_t* send_key,
99 int send_key_len,
100 int recv_cs,
101 const uint8_t* recv_key,
102 int recv_key_len) {
103 if (!IsActive()) {
104 LOG(LS_ERROR) << "Tried to update SRTP Params when filter is not active";
105 return false;
106 }
107 send_session_->SetEncryptedHeaderExtensionIds(
108 send_encrypted_header_extension_ids_);
109 if (!send_session_->UpdateSend(send_cs, send_key, send_key_len)) {
110 return false;
111 }
112
113 recv_session_->SetEncryptedHeaderExtensionIds(
114 recv_encrypted_header_extension_ids_);
115 if (!recv_session_->UpdateRecv(recv_cs, recv_key, recv_key_len)) {
116 return false;
117 }
118
119 LOG(LS_INFO) << "SRTP updated with negotiated parameters:"
120 << " send cipher_suite " << send_cs
121 << " recv cipher_suite " << recv_cs;
122 return true;
123 }
124
125 // This function is provided separately because DTLS-SRTP behaves
126 // differently in RTP/RTCP mux and non-mux modes.
127 //
128 // - In the non-muxed case, RTP and RTCP are keyed with different
129 // keys (from different DTLS handshakes), and so we need a new
130 // SrtpSession.
131 // - In the muxed case, they are keyed with the same keys, so
132 // this function is not needed
133 bool SrtpFilter::SetRtcpParams(int send_cs,
134 const uint8_t* send_key,
135 int send_key_len,
136 int recv_cs,
137 const uint8_t* recv_key,
138 int recv_key_len) {
139 // This can only be called once, but can be safely called after
140 // SetRtpParams
141 if (send_rtcp_session_ || recv_rtcp_session_) {
142 LOG(LS_ERROR) << "Tried to set SRTCP Params when filter already active";
143 return false;
144 }
145
146 send_rtcp_session_.reset(new SrtpSession());
147 if (!send_rtcp_session_->SetRecv(send_cs, send_key, send_key_len)) {
148 return false;
149 }
150
151 recv_rtcp_session_.reset(new SrtpSession());
152 if (!recv_rtcp_session_->SetRecv(recv_cs, recv_key, recv_key_len)) {
153 return false;
154 }
155
156 LOG(LS_INFO) << "SRTCP activated with negotiated parameters:"
157 << " send cipher_suite " << send_cs
158 << " recv cipher_suite " << recv_cs;
159
160 return true;
161 }
162
163 bool SrtpFilter::ProtectRtp(void* p, int in_len, int max_len, int* out_len) {
164 if (!IsActive()) {
165 LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
166 return false;
167 }
168 RTC_CHECK(send_session_);
169 return send_session_->ProtectRtp(p, in_len, max_len, out_len);
170 }
171
172 bool SrtpFilter::ProtectRtp(void* p,
173 int in_len,
174 int max_len,
175 int* out_len,
176 int64_t* index) {
177 if (!IsActive()) {
178 LOG(LS_WARNING) << "Failed to ProtectRtp: SRTP not active";
179 return false;
180 }
181 RTC_CHECK(send_session_);
182 return send_session_->ProtectRtp(p, in_len, max_len, out_len, index);
183 }
184
185 bool SrtpFilter::ProtectRtcp(void* p, int in_len, int max_len, int* out_len) {
186 if (!IsActive()) {
187 LOG(LS_WARNING) << "Failed to ProtectRtcp: SRTP not active";
188 return false;
189 }
190 if (send_rtcp_session_) {
191 return send_rtcp_session_->ProtectRtcp(p, in_len, max_len, out_len);
192 } else {
193 RTC_CHECK(send_session_);
194 return send_session_->ProtectRtcp(p, in_len, max_len, out_len);
195 }
196 }
197
198 bool SrtpFilter::UnprotectRtp(void* p, int in_len, int* out_len) {
199 if (!IsActive()) {
200 LOG(LS_WARNING) << "Failed to UnprotectRtp: SRTP not active";
201 return false;
202 }
203 RTC_CHECK(recv_session_);
204 return recv_session_->UnprotectRtp(p, in_len, out_len);
205 }
206
207 bool SrtpFilter::UnprotectRtcp(void* p, int in_len, int* out_len) {
208 if (!IsActive()) {
209 LOG(LS_WARNING) << "Failed to UnprotectRtcp: SRTP not active";
210 return false;
211 }
212 if (recv_rtcp_session_) {
213 return recv_rtcp_session_->UnprotectRtcp(p, in_len, out_len);
214 } else {
215 RTC_CHECK(recv_session_);
216 return recv_session_->UnprotectRtcp(p, in_len, out_len);
217 }
218 }
219
220 bool SrtpFilter::GetRtpAuthParams(uint8_t** key, int* key_len, int* tag_len) {
221 if (!IsActive()) {
222 LOG(LS_WARNING) << "Failed to GetRtpAuthParams: SRTP not active";
223 return false;
224 }
225
226 RTC_CHECK(send_session_);
227 return send_session_->GetRtpAuthParams(key, key_len, tag_len);
228 }
229
230 bool SrtpFilter::GetSrtpOverhead(int* srtp_overhead) const {
231 if (!IsActive()) {
232 LOG(LS_WARNING) << "Failed to GetSrtpOverhead: SRTP not active";
233 return false;
234 }
235
236 RTC_CHECK(send_session_);
237 *srtp_overhead = send_session_->GetSrtpOverhead();
238 return true;
239 }
240
241 void SrtpFilter::EnableExternalAuth() {
242 RTC_DCHECK(!IsActive());
243 external_auth_enabled_ = true;
244 }
245
246 bool SrtpFilter::IsExternalAuthEnabled() const {
247 return external_auth_enabled_;
248 }
249
250 bool SrtpFilter::IsExternalAuthActive() const {
251 if (!IsActive()) {
252 LOG(LS_WARNING) << "Failed to check IsExternalAuthActive: SRTP not active";
253 return false;
254 }
255
256 RTC_CHECK(send_session_);
257 return send_session_->IsExternalAuthActive();
258 }
259
260 void SrtpFilter::SetEncryptedHeaderExtensionIds(ContentSource source,
261 const std::vector<int>& extension_ids) {
262 if (source == CS_LOCAL) {
263 recv_encrypted_header_extension_ids_ = extension_ids;
264 } else {
265 send_encrypted_header_extension_ids_ = extension_ids;
266 }
267 }
268
269 bool SrtpFilter::ExpectOffer(ContentSource source) { 66 bool SrtpFilter::ExpectOffer(ContentSource source) {
270 return ((state_ == ST_INIT) || 67 return ((state_ == ST_INIT) ||
271 (state_ == ST_ACTIVE) || 68 (state_ == ST_ACTIVE) ||
272 (state_ == ST_SENTOFFER && source == CS_LOCAL) || 69 (state_ == ST_SENTOFFER && source == CS_LOCAL) ||
273 (state_ == ST_SENTUPDATEDOFFER && source == CS_LOCAL) || 70 (state_ == ST_SENTUPDATEDOFFER && source == CS_LOCAL) ||
274 (state_ == ST_RECEIVEDOFFER && source == CS_REMOTE) || 71 (state_ == ST_RECEIVEDOFFER && source == CS_REMOTE) ||
275 (state_ == ST_RECEIVEDUPDATEDOFFER && source == CS_REMOTE)); 72 (state_ == ST_RECEIVEDUPDATEDOFFER && source == CS_REMOTE));
276 } 73 }
277 74
278 bool SrtpFilter::StoreParams(const std::vector<CryptoParams>& params, 75 bool SrtpFilter::StoreParams(const std::vector<CryptoParams>& params,
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
316 // Need to wait for the final answer to decide if 113 // Need to wait for the final answer to decide if
317 // we should go to Active state. 114 // we should go to Active state.
318 state_ = (source == CS_LOCAL) ? ST_SENTPRANSWER_NO_CRYPTO : 115 state_ = (source == CS_LOCAL) ? ST_SENTPRANSWER_NO_CRYPTO :
319 ST_RECEIVEDPRANSWER_NO_CRYPTO; 116 ST_RECEIVEDPRANSWER_NO_CRYPTO;
320 return true; 117 return true;
321 } 118 }
322 } 119 }
323 CryptoParams selected_params; 120 CryptoParams selected_params;
324 if (!NegotiateParams(answer_params, &selected_params)) 121 if (!NegotiateParams(answer_params, &selected_params))
325 return false; 122 return false;
326 const CryptoParams& send_params = 123
124 CryptoParams new_send_params =
Taylor Brandstetter 2017/08/26 02:40:39 Can't these still be const refs?
Zhi Huang 2017/08/29 18:40:35 Done.
327 (source == CS_REMOTE) ? selected_params : answer_params[0]; 125 (source == CS_REMOTE) ? selected_params : answer_params[0];
328 const CryptoParams& recv_params = 126 CryptoParams new_recv_params =
329 (source == CS_REMOTE) ? answer_params[0] : selected_params; 127 (source == CS_REMOTE) ? answer_params[0] : selected_params;
330 if (!ApplyParams(send_params, recv_params)) { 128 if (!ParseSendParams(new_send_params) || !ParseRecvParams(new_recv_params)) {
331 return false; 129 return false;
332 } 130 }
131 send_params_ = new_send_params;
132 recv_params_ = new_recv_params;
333 133
334 if (final) { 134 if (final) {
335 offer_params_.clear(); 135 offer_params_.clear();
336 state_ = ST_ACTIVE; 136 state_ = ST_ACTIVE;
337 } else { 137 } else {
338 state_ = 138 state_ =
339 (source == CS_LOCAL) ? ST_SENTPRANSWER : ST_RECEIVEDPRANSWER; 139 (source == CS_LOCAL) ? ST_SENTPRANSWER : ST_RECEIVEDPRANSWER;
340 } 140 }
341 return true; 141 return true;
342 } 142 }
343 143
344 void SrtpFilter::CreateSrtpSessions() {
345 send_session_.reset(new SrtpSession());
346 applied_send_params_ = CryptoParams();
347 recv_session_.reset(new SrtpSession());
348 applied_recv_params_ = CryptoParams();
349
350 if (external_auth_enabled_) {
351 send_session_->EnableExternalAuth();
352 }
353 }
354
355 bool SrtpFilter::NegotiateParams(const std::vector<CryptoParams>& answer_params, 144 bool SrtpFilter::NegotiateParams(const std::vector<CryptoParams>& answer_params,
356 CryptoParams* selected_params) { 145 CryptoParams* selected_params) {
357 // We're processing an accept. We should have exactly one set of params, 146 // We're processing an accept. We should have exactly one set of params,
358 // unless the offer didn't mention crypto, in which case we shouldn't be here. 147 // unless the offer didn't mention crypto, in which case we shouldn't be here.
359 bool ret = (answer_params.size() == 1U && !offer_params_.empty()); 148 bool ret = (answer_params.size() == 1U && !offer_params_.empty());
360 if (ret) { 149 if (ret) {
361 // We should find a match between the answer params and the offered params. 150 // We should find a match between the answer params and the offered params.
362 std::vector<CryptoParams>::const_iterator it; 151 std::vector<CryptoParams>::const_iterator it;
363 for (it = offer_params_.begin(); it != offer_params_.end(); ++it) { 152 for (it = offer_params_.begin(); it != offer_params_.end(); ++it) {
364 if (answer_params[0].Matches(*it)) { 153 if (answer_params[0].Matches(*it)) {
365 break; 154 break;
366 } 155 }
367 } 156 }
368 157
369 if (it != offer_params_.end()) { 158 if (it != offer_params_.end()) {
370 *selected_params = *it; 159 *selected_params = *it;
371 } else { 160 } else {
372 ret = false; 161 ret = false;
373 } 162 }
374 } 163 }
375 164
376 if (!ret) { 165 if (!ret) {
377 LOG(LS_WARNING) << "Invalid parameters in SRTP answer"; 166 LOG(LS_WARNING) << "Invalid parameters in SRTP answer";
378 } 167 }
379 return ret; 168 return ret;
380 } 169 }
381 170
382 bool SrtpFilter::ApplyParams(const CryptoParams& send_params, 171 bool SrtpFilter::ResetParams() {
383 const CryptoParams& recv_params) { 172 offer_params_.clear();
384 // TODO(jiayl): Split this method to apply send and receive CryptoParams 173 send_params_ = CryptoParams();
385 // independently, so that we can skip one method when either send or receive 174 recv_params_ = CryptoParams();
386 // CryptoParams is unchanged. 175 send_cipher_suite_ = rtc::Optional<int>();
387 if (applied_send_params_.cipher_suite == send_params.cipher_suite && 176 recv_cipher_suite_ = rtc::Optional<int>();
388 applied_send_params_.key_params == send_params.key_params && 177 send_key_.clear();
389 applied_recv_params_.cipher_suite == recv_params.cipher_suite && 178 recv_key_.clear();
390 applied_recv_params_.key_params == recv_params.key_params) { 179 state_ = ST_INIT;
391 LOG(LS_INFO) << "Applying the same SRTP parameters again. No-op."; 180 return true;
181 }
182
183 bool SrtpFilter::ParseSendParams(const CryptoParams& send_params) {
184 if (send_params_.cipher_suite == send_params.cipher_suite &&
185 send_params_.key_params == send_params.key_params) {
186 LOG(LS_INFO) << "Applying the same SRTP send parameters again. No-op.";
392 187
393 // We do not want to reset the ROC if the keys are the same. So just return. 188 // We do not want to reset the ROC if the keys are the same. So just return.
394 return true; 189 return true;
395 } 190 }
396 191
397 int send_suite = rtc::SrtpCryptoSuiteFromName(send_params.cipher_suite); 192 send_cipher_suite_ = rtc::Optional<int>(
398 int recv_suite = rtc::SrtpCryptoSuiteFromName(recv_params.cipher_suite); 193 rtc::SrtpCryptoSuiteFromName(send_params.cipher_suite));
399 if (send_suite == rtc::SRTP_INVALID_CRYPTO_SUITE || 194 if (send_cipher_suite_ == rtc::SRTP_INVALID_CRYPTO_SUITE) {
400 recv_suite == rtc::SRTP_INVALID_CRYPTO_SUITE) {
401 LOG(LS_WARNING) << "Unknown crypto suite(s) received:" 195 LOG(LS_WARNING) << "Unknown crypto suite(s) received:"
402 << " send cipher_suite " << send_params.cipher_suite 196 << " send cipher_suite " << send_params.cipher_suite;
197 return false;
198 }
199
200 int send_key_len, send_salt_len;
201 if (!rtc::GetSrtpKeyAndSaltLengths(*send_cipher_suite_, &send_key_len,
202 &send_salt_len)) {
203 LOG(LS_WARNING) << "Could not get lengths for crypto suite(s):"
204 << " send cipher_suite " << send_params.cipher_suite;
205 return false;
206 }
207
208 return ParseKeyParams(send_params.key_params, &send_key_,
209 send_key_len + send_salt_len);
210 }
211
212 bool SrtpFilter::ParseRecvParams(const CryptoParams& recv_params) {
213 if (recv_params_.cipher_suite == recv_params.cipher_suite &&
214 recv_params_.key_params == recv_params.key_params) {
215 LOG(LS_INFO) << "Applying the same SRTP recv parameters again. No-op.";
216
217 // We do not want to reset the ROC if the keys are the same. So just return.
218 return true;
219 }
220
221 recv_cipher_suite_ = rtc::Optional<int>(
222 rtc::SrtpCryptoSuiteFromName(recv_params.cipher_suite));
223 if (recv_cipher_suite_ == rtc::SRTP_INVALID_CRYPTO_SUITE) {
224 LOG(LS_WARNING) << "Unknown crypto suite(s) received:"
403 << " recv cipher_suite " << recv_params.cipher_suite; 225 << " recv cipher_suite " << recv_params.cipher_suite;
404 return false; 226 return false;
405 } 227 }
406 228
407 int send_key_len, send_salt_len;
408 int recv_key_len, recv_salt_len; 229 int recv_key_len, recv_salt_len;
409 if (!rtc::GetSrtpKeyAndSaltLengths(send_suite, &send_key_len, 230 if (!rtc::GetSrtpKeyAndSaltLengths(*recv_cipher_suite_, &recv_key_len,
410 &send_salt_len) ||
411 !rtc::GetSrtpKeyAndSaltLengths(recv_suite, &recv_key_len,
412 &recv_salt_len)) { 231 &recv_salt_len)) {
413 LOG(LS_WARNING) << "Could not get lengths for crypto suite(s):" 232 LOG(LS_WARNING) << "Could not get lengths for crypto suite(s):"
414 << " send cipher_suite " << send_params.cipher_suite
415 << " recv cipher_suite " << recv_params.cipher_suite; 233 << " recv cipher_suite " << recv_params.cipher_suite;
416 return false; 234 return false;
417 } 235 }
418 236
419 // TODO(juberti): Zero these buffers after use. 237 return ParseKeyParams(recv_params.key_params, &recv_key_,
420 bool ret; 238 recv_key_len + recv_salt_len);
421 rtc::Buffer send_key(send_key_len + send_salt_len);
422 rtc::Buffer recv_key(recv_key_len + recv_salt_len);
423 ret = (ParseKeyParams(send_params.key_params, send_key.data(),
424 send_key.size()) &&
425 ParseKeyParams(recv_params.key_params, recv_key.data(),
426 recv_key.size()));
427 if (ret) {
428 CreateSrtpSessions();
429 send_session_->SetEncryptedHeaderExtensionIds(
430 send_encrypted_header_extension_ids_);
431 recv_session_->SetEncryptedHeaderExtensionIds(
432 recv_encrypted_header_extension_ids_);
433 ret = (send_session_->SetSend(
434 rtc::SrtpCryptoSuiteFromName(send_params.cipher_suite),
435 send_key.data(), send_key.size()) &&
436 recv_session_->SetRecv(
437 rtc::SrtpCryptoSuiteFromName(recv_params.cipher_suite),
438 recv_key.data(), recv_key.size()));
439 }
440 if (ret) {
441 LOG(LS_INFO) << "SRTP activated with negotiated parameters:"
442 << " send cipher_suite " << send_params.cipher_suite
443 << " recv cipher_suite " << recv_params.cipher_suite;
444 applied_send_params_ = send_params;
445 applied_recv_params_ = recv_params;
446 } else {
447 LOG(LS_WARNING) << "Failed to apply negotiated SRTP parameters";
448 }
449 return ret;
450 }
451
452 bool SrtpFilter::ResetParams() {
453 offer_params_.clear();
454 state_ = ST_INIT;
455 send_session_ = nullptr;
456 recv_session_ = nullptr;
457 send_rtcp_session_ = nullptr;
458 recv_rtcp_session_ = nullptr;
459 LOG(LS_INFO) << "SRTP reset to init state";
460 return true;
461 } 239 }
462 240
463 bool SrtpFilter::ParseKeyParams(const std::string& key_params, 241 bool SrtpFilter::ParseKeyParams(const std::string& key_params,
464 uint8_t* key, 242 std::vector<unsigned char>* key,
Taylor Brandstetter 2017/08/26 02:40:39 Could this be an rtc::Buffer like before, instead
Zhi Huang 2017/08/29 18:40:35 Done.
465 size_t len) { 243 size_t len) {
466 // example key_params: "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2" 244 // example key_params: "inline:YUJDZGVmZ2hpSktMbW9QUXJzVHVWd3l6MTIzNDU2"
467 245
468 // Fail if key-method is wrong. 246 // Fail if key-method is wrong.
469 if (key_params.find("inline:") != 0) { 247 if (key_params.find("inline:") != 0) {
470 return false; 248 return false;
471 } 249 }
472 250
473 // Fail if base64 decode fails, or the key is the wrong size. 251 // Fail if base64 decode fails, or the key is the wrong size.
474 std::string key_b64(key_params.substr(7)), key_str; 252 std::string key_b64(key_params.substr(7)), key_str;
475 if (!rtc::Base64::Decode(key_b64, rtc::Base64::DO_STRICT, 253 if (!rtc::Base64::Decode(key_b64, rtc::Base64::DO_STRICT, &key_str,
476 &key_str, nullptr) || key_str.size() != len) { 254 nullptr) ||
255 key_str.size() != len) {
477 return false; 256 return false;
478 } 257 }
479 258
480 memcpy(key, key_str.c_str(), len); 259 std::vector<unsigned char> temp_key(key_str.c_str(), key_str.c_str() + len);
260 *key = temp_key;
481 return true; 261 return true;
482 } 262 }
483 263
484 } // namespace cricket 264 } // namespace cricket
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698