OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/renderer_host/p2p/socket_host.h" | 5 #include "content/browser/renderer_host/p2p/socket_host.h" |
6 | 6 |
7 #include "base/sys_byteorder.h" | 7 #include "base/sys_byteorder.h" |
8 #include "content/browser/renderer_host/p2p/socket_host_tcp.h" | 8 #include "content/browser/renderer_host/p2p/socket_host_tcp.h" |
9 #include "content/browser/renderer_host/p2p/socket_host_tcp_server.h" | 9 #include "content/browser/renderer_host/p2p/socket_host_tcp_server.h" |
10 #include "content/browser/renderer_host/p2p/socket_host_udp.h" | 10 #include "content/browser/renderer_host/p2p/socket_host_udp.h" |
11 #include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" | |
12 #include "third_party/libjingle/source/talk/base/byteorder.h" | |
13 #include "third_party/libjingle/source/talk/base/messagedigest.h" | |
14 #include "third_party/libjingle/source/talk/p2p/base/stun.h" | |
11 | 15 |
12 namespace { | 16 namespace { |
17 | |
13 const uint32 kStunMagicCookie = 0x2112A442; | 18 const uint32 kStunMagicCookie = 0x2112A442; |
19 const int kMinRtpHdrLen = 12; | |
20 const int kDtlsRecordHeaderLen = 13; | |
21 const int kTurnChannelHdrLen = 4; | |
22 const int kRtpExtnHdrLen = 4; | |
23 const int kAbsSendTimeExtnLen = 3; | |
24 const int kOneByteHdrLen = 1; | |
25 | |
26 bool IsTurnChannelData(const char* data) { | |
27 uint16 type = talk_base::GetBE16(data); | |
28 return ((type & 0xC000) == 0x4000); // MSB are 0b01 | |
29 } | |
30 | |
31 bool IsDtlsPacket(const char* data, int len) { | |
32 const uint8* u = reinterpret_cast<const uint8*>(data); | |
33 return (len >= kDtlsRecordHeaderLen && (u[0] > 19 && u[0] < 64)); | |
34 } | |
35 | |
36 bool IsRtcpPacket(const char* data) { | |
37 int type = (static_cast<uint8>(data[1]) & 0x7F); | |
38 return (type >= 64 && type < 96); | |
39 } | |
40 | |
41 bool IsStunPacket(const char* data) { | |
42 uint16 type = talk_base::GetBE16(data); | |
43 return !(type & 0xC000); | |
44 } | |
45 | |
46 bool IsStunDataIndicationPacket(const char* data) { | |
47 uint16 type = talk_base::GetBE16(data); | |
48 return (type == cricket::TURN_SEND_INDICATION); | |
49 } | |
50 | |
51 const size_t kBlockSize = 64; // valid for SHA-256 and down | |
52 | |
53 class HMAC { | |
54 public: | |
55 HMAC(); | |
56 ~HMAC() {} | |
57 | |
58 bool Init(const void* key, size_t key_len); | |
59 void Update(const void* input, size_t in_len); | |
60 void Compute(void* output, size_t out_len); | |
61 | |
62 private: | |
63 size_t block_len; | |
64 scoped_ptr<uint8[]> o_pad_; | |
65 scoped_ptr<uint8[]> i_pad_; | |
66 scoped_ptr<uint8[]> inner_; | |
67 scoped_ptr<talk_base::MessageDigest> digest_; | |
68 }; | |
69 | |
70 HMAC::HMAC() | |
71 : digest_(talk_base::MessageDigestFactory::Create( | |
72 talk_base::DIGEST_SHA_1)) { | |
73 } | |
74 | |
75 bool HMAC::Init(const void* key, size_t key_len) { | |
76 if (!digest_) { | |
77 return false; | |
78 } | |
79 block_len = kBlockSize; | |
80 if (digest_->Size() > 32) { | |
81 return false; | |
82 } | |
83 | |
84 // Copy the key to a block-sized buffer to simplify padding. | |
85 // If the key is longer than a block, hash it and use the result instead. | |
86 talk_base::scoped_ptr<uint8[]> new_key(new uint8[block_len]); | |
87 if (key_len > block_len) { | |
88 talk_base::ComputeDigest(digest_.get(), key, key_len, | |
89 new_key.get(), block_len); | |
90 memset(new_key.get() + digest_->Size(), 0, block_len - digest_->Size()); | |
91 } else { | |
92 memcpy(new_key.get(), key, key_len); | |
93 memset(new_key.get() + key_len, 0, block_len - key_len); | |
94 } | |
95 | |
96 // Set up the padding from the key, salting appropriately for each padding. | |
97 o_pad_.reset(new uint8[block_len]); | |
98 i_pad_.reset(new uint8[block_len]); | |
99 for (size_t i = 0; i < block_len; ++i) { | |
100 o_pad_[i] = 0x5c ^ new_key[i]; | |
101 i_pad_[i] = 0x36 ^ new_key[i]; | |
102 } | |
103 // Inner hash; hash the inner padding, and then the input buffer. | |
104 inner_.reset(new uint8[digest_->Size()]); | |
105 digest_->Update(i_pad_.get(), block_len); | |
106 return true; | |
107 } | |
108 | |
109 void HMAC::Update(const void* input, size_t in_len) { | |
110 digest_->Update(input, in_len); | |
111 } | |
112 | |
113 void HMAC::Compute(void* output, size_t out_len) { | |
114 // Outer hash; hash the outer padding, and then the result of the inner hash. | |
115 digest_->Update(o_pad_.get(), block_len); | |
116 digest_->Update(inner_.get(), digest_->Size()); | |
117 digest_->Finish(output, out_len); | |
118 } | |
119 | |
14 } // namespace | 120 } // namespace |
15 | 121 |
16 namespace content { | 122 namespace content { |
17 | 123 |
18 P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender, | 124 P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender, |
19 int id) | 125 int id) |
20 : message_sender_(message_sender), | 126 : message_sender_(message_sender), |
21 id_(id), | 127 id_(id), |
22 state_(STATE_UNINITIALIZED) { | 128 state_(STATE_UNINITIALIZED) { |
23 } | 129 } |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
95 case P2P_SOCKET_STUN_TCP_CLIENT: | 201 case P2P_SOCKET_STUN_TCP_CLIENT: |
96 case P2P_SOCKET_STUN_SSLTCP_CLIENT: | 202 case P2P_SOCKET_STUN_SSLTCP_CLIENT: |
97 case P2P_SOCKET_STUN_TLS_CLIENT: | 203 case P2P_SOCKET_STUN_TLS_CLIENT: |
98 return new P2PSocketHostStunTcp(message_sender, id, type, url_context); | 204 return new P2PSocketHostStunTcp(message_sender, id, type, url_context); |
99 } | 205 } |
100 | 206 |
101 NOTREACHED(); | 207 NOTREACHED(); |
102 return NULL; | 208 return NULL; |
103 } | 209 } |
104 | 210 |
211 void P2PSocketHost::MaybeUpdateRtpSendTimeExtn( | |
212 char* data, int len, const talk_base::PacketOptions& options) { | |
Stefan
2014/02/19 08:17:32
len -> length
Mallinath (Gone from Chromium)
2014/02/19 18:52:24
Done.
| |
213 // if there is no valid |rtp_sendtime_extension_id| or |srtp_auth_key| in | |
214 // PacketOptions, nothing to be updated in this packet. | |
215 if (options.packet_time_params.rtp_sendtime_extension_id == -1 && | |
216 options.packet_time_params.srtp_auth_key.empty()) { | |
217 return; | |
218 } | |
219 | |
220 char* start = data; | |
221 int raw_packet_len = options.packet_time_params.payload_len; | |
222 // If the packet is wrapped in any protocol like TURN/GTURN/ICE-TCP, |len| | |
223 // will be larger than actuan payload len. Skipping wrapper to point to the | |
Stefan
2014/02/19 08:17:32
actual payload length
Mallinath (Gone from Chromium)
2014/02/19 18:52:24
Done.
| |
224 // actual payload. | |
225 int wrapper_len = len - raw_packet_len; | |
226 start += wrapper_len; | |
227 | |
228 // If there is no valid Absolute sendtime extension id present in options, | |
229 // we should just update the HMAC and return, if srtp auth key is present. | |
230 if (options.packet_time_params.rtp_sendtime_extension_id == -1) { | |
231 // If the packet is a regular STUN packet or a DTLS packet or a RTCP | |
232 // packet |srtp_auth_key| will be empty. | |
233 // We may have written a fake HMAC, if it's rtp packet. | |
234 if (!options.packet_time_params.srtp_auth_key.empty()) { | |
235 // Should we check if there is fake hmac written and if so, then update | |
236 // HMAC? | |
237 UpdateHmac(start, raw_packet_len, options); | |
238 } | |
239 return; | |
240 } | |
241 | |
242 // Skip if the wrapped packet is RTCP packet. | |
243 if (IsRtcpPacket(start)) { | |
244 // Update the HMAC and return | |
245 // RTCP packet must have rtp_sendtime_extension_id == -1 and empty | |
246 // srtp_auth_key. | |
247 DCHECK(false); | |
248 return; | |
249 } | |
250 | |
251 if (!FindAndUpdateRtpAbsSendTimeExtension(start, raw_packet_len, options)) { | |
252 // We should find extension id in rtp packet. | |
Stefan
2014/02/19 08:17:32
We should find an extension id in the rtp packet.
Mallinath (Gone from Chromium)
2014/02/19 18:52:24
Done.
| |
253 DCHECK(false); | |
254 } | |
255 UpdateHmac(start, raw_packet_len, options); | |
256 } | |
257 | |
258 bool P2PSocketHost::FindAndUpdateRtpAbsSendTimeExtension( | |
259 char* data, int in_len, const talk_base::PacketOptions& options) { | |
260 // 0 1 2 3 | |
261 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
262 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
263 // |V=2|P|X| CC |M| PT | sequence number | | |
264 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
265 // | timestamp | | |
266 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
267 // | synchronization source (SSRC) identifier | | |
268 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ | |
269 // | contributing source (CSRC) identifiers | | |
270 // | .... | | |
271 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
272 | |
273 int cc_count = data[0] & 0x0F; | |
274 int rtp_hdr_len_without_extn = kMinRtpHdrLen + 4 * cc_count; | |
275 if (rtp_hdr_len_without_extn > in_len) { | |
276 DCHECK(false); | |
277 return false; | |
278 } | |
279 | |
280 bool X = (data[0] & 0x10); | |
281 if (!X) // Return if extension bit is not set. | |
282 return true; | |
283 | |
284 data += rtp_hdr_len_without_extn; | |
285 | |
286 // Getting extension profile ID and length. | |
287 uint16 profile_id = talk_base::GetBE16(data); | |
288 // Length is in 32 bit words. | |
289 uint16 extn_length = talk_base::GetBE16(data + 2) * 4; | |
290 | |
291 // Verify input length against total header size. | |
292 if (rtp_hdr_len_without_extn + kRtpExtnHdrLen + extn_length > in_len) { | |
293 DCHECK(false); | |
294 return false; | |
295 } | |
296 | |
297 data += kRtpExtnHdrLen; // Moving past extn header. | |
298 | |
299 // WebRTC is using one byte header extension. | |
300 // TODO(mallinath) - Handle two byte header extension. | |
301 if (profile_id == 0xBEDE) { // OneByte extension header | |
302 // 0 | |
303 // 0 1 2 3 4 5 6 7 | |
304 // +-+-+-+-+-+-+-+-+ | |
305 // | ID | len | | |
306 // +-+-+-+-+-+-+-+-+ | |
307 | |
308 // 0 1 2 3 | |
309 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
310 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
311 // | 0xBE | 0xDE | length=3 | | |
312 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
313 // | ID | L=0 | data | ID | L=1 | data... | |
314 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
315 // ...data | 0 (pad) | 0 (pad) | ID | L=3 | | |
316 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
317 // | data | | |
318 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
319 uint16 consumed = 0; | |
320 while(extn_length - consumed > 0) { | |
321 const int id = (*data & 0xF0) >> 4; | |
322 const int len = (*data & 0x0F) + 1; | |
323 // The 4-bit length is the number minus one of data bytes of this header | |
324 // extension element following the one-byte header. | |
325 if (id == options.packet_time_params.rtp_sendtime_extension_id) { | |
326 UpdateRtpAbsSendTimeExtension(data + kOneByteHdrLen, len); | |
327 return true; | |
328 } | |
329 consumed += kOneByteHdrLen + len; | |
330 data += consumed; | |
331 // Count padding bytes | |
332 while(*data != 0) { | |
333 ++data; | |
334 ++consumed; | |
335 } | |
336 } | |
337 } | |
338 return true; | |
339 } | |
340 | |
341 void P2PSocketHost::UpdateRtpAbsSendTimeExtension(char* data, int len) { | |
342 // Absolute send time in RTP streams. | |
343 // | |
344 // The absolute send time is signaled to the receiver in-band using the | |
345 // general mechanism for RTP header extensions [RFC5285]. The payload | |
346 // of this extension (the transmitted value) is a 24-bit unsigned integer | |
347 // containing the sender's current time in seconds as a fixed point number | |
348 // with 18 bits fractional part. | |
349 // | |
350 // The form of the absolute send time extension block: | |
351 // | |
352 // 0 1 2 3 | |
353 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
354 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
355 // | ID | len=2 | absolute send time | | |
356 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
357 DCHECK_EQ(len, kAbsSendTimeExtnLen); | |
358 uint64 now_ms = base::Time::Now().ToInternalValue(); | |
359 // Convert second to 24-bit unsigned with 18 bit fractional part | |
360 uint32 now_second = ((now_ms << 18) / base::Time::kMicrosecondsPerSecond) & | |
361 0x00FFFFFF; | |
362 // TODO(mallinath) - Add SetBE24 to byteorder.h in libjingle. | |
363 data[0] = static_cast<uint8>(now_second >> 16); | |
364 data[1] = static_cast<uint8>(now_second >> 8); | |
365 data[2] = static_cast<uint8>(now_second); | |
366 } | |
367 | |
368 // Assumes |len| is actual packet length + tag length. | |
369 void P2PSocketHost::UpdateHmac(char* packet, int len, | |
370 const talk_base::PacketOptions& options) { | |
371 char* auth_tag = packet + | |
372 (len - options.packet_time_params.srtp_auth_tag_len); | |
373 HMAC hmac; | |
374 if (!hmac.Init(&options.packet_time_params.srtp_auth_key[0], | |
375 options.packet_time_params.srtp_auth_key.size())) { | |
376 DCHECK(false); | |
377 return; | |
378 } | |
379 | |
380 char output[20]; | |
381 size_t out_len = sizeof(output); | |
382 | |
383 // First we should compute on the message and then packet index. | |
384 hmac.Update(packet, len - options.packet_time_params.srtp_auth_tag_len); | |
385 hmac.Update(reinterpret_cast<void*>( | |
386 options.packet_time_params.srtp_packet_index), 4); // Use only ROC. | |
387 | |
388 hmac.Compute(output, out_len); | |
389 // Copy HMAC from output to packet. This is required as auth tag lenth | |
390 // may not be equal to the actual HMAC length. | |
391 memcpy(auth_tag, output, options.packet_time_params.srtp_auth_tag_len); | |
392 } | |
393 | |
105 } // namespace content | 394 } // namespace content |
OLD | NEW |