|
8 | 8 | #include "content/browser/renderer_host/p2p/socket_host_tcp.h"
|
9 | 9 | #include "content/browser/renderer_host/p2p/socket_host_tcp_server.h"
|
10 | 10 | #include "content/browser/renderer_host/p2p/socket_host_udp.h"
|
11 |
| -#include "crypto/hmac.h" |
12 |
| -#include "third_party/libjingle/source/talk/base/asyncpacketsocket.h" |
13 |
| -#include "third_party/libjingle/source/talk/base/byteorder.h" |
14 |
| -#include "third_party/libjingle/source/talk/base/messagedigest.h" |
15 |
| -#include "third_party/libjingle/source/talk/p2p/base/stun.h" |
16 | 11 |
|
17 | 12 | namespace {
|
18 |
| - |
19 | 13 | const uint32 kStunMagicCookie = 0x2112A442;
|
20 |
| -const int kMinRtpHdrLen = 12; |
21 |
| -const int kRtpExtnHdrLen = 4; |
22 |
| -const int kDtlsRecordHeaderLen = 13; |
23 |
| -const int kTurnChannelHdrLen = 4; |
24 |
| -const int kAbsSendTimeExtnLen = 3; |
25 |
| -const int kOneByteHdrLen = 1; |
26 |
| - |
27 |
| -// Fake auth tag written by the render process if external authentication is |
28 |
| -// enabled. HMAC in packet will be compared against this value before updating |
29 |
| -// packet with actual HMAC value. |
30 |
| -static const unsigned char kFakeAuthTag[10] = { |
31 |
| - 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd |
32 |
| -}; |
33 |
| - |
34 |
| -bool IsTurnChannelData(const char* data) { |
35 |
| - return ((*data & 0xC0) == 0x40); |
36 |
| -} |
37 |
| - |
38 |
| -bool IsDtlsPacket(const char* data, int len) { |
39 |
| - const uint8* u = reinterpret_cast<const uint8*>(data); |
40 |
| - return (len >= kDtlsRecordHeaderLen && (u[0] > 19 && u[0] < 64)); |
41 |
| -} |
42 |
| - |
43 |
| -bool IsRtcpPacket(const char* data) { |
44 |
| - int type = (static_cast<uint8>(data[1]) & 0x7F); |
45 |
| - return (type >= 64 && type < 96); |
46 |
| -} |
47 |
| - |
48 |
| -bool IsTurnSendIndicationPacket(const char* data) { |
49 |
| - uint16 type = talk_base::GetBE16(data); |
50 |
| - return (type == cricket::TURN_SEND_INDICATION); |
51 |
| -} |
52 |
| - |
53 |
| -bool IsRtpPacket(const char* data, int len) { |
54 |
| - return ((*data & 0xC0) == 0x80); |
55 |
| -} |
56 |
| - |
57 |
| -// Verifies rtp header and message length. |
58 |
| -bool ValidateRtpHeader(char* rtp, int length) { |
59 |
| - int cc_count = rtp[0] & 0x0F; |
60 |
| - int rtp_hdr_len_without_extn = kMinRtpHdrLen + 4 * cc_count; |
61 |
| - if (rtp_hdr_len_without_extn > length) { |
62 |
| - return false; |
63 |
| - } |
64 |
| - |
65 |
| - // If extension bit is not set, we are done with header processing, as input |
66 |
| - // length is verified above. |
67 |
| - if (!(rtp[0] & 0x10)) { |
68 |
| - return true; |
69 |
| - } |
70 |
| - |
71 |
| - rtp += rtp_hdr_len_without_extn; |
72 |
| - |
73 |
| - // Getting extension profile length. |
74 |
| - // Length is in 32 bit words. |
75 |
| - uint16 extn_length = talk_base::GetBE16(rtp + 2) * 4; |
76 |
| - |
77 |
| - // Verify input length against total header size. |
78 |
| - if (rtp_hdr_len_without_extn + kRtpExtnHdrLen + extn_length > length) { |
79 |
| - return false; |
80 |
| - } |
81 |
| - return true; |
82 |
| -} |
83 |
| - |
84 |
| -void UpdateAbsSendTimeExtnValue(char* extn_data, int len, |
85 |
| - uint32 abs_send_time) { |
86 |
| - // Absolute send time in RTP streams. |
87 |
| - // |
88 |
| - // The absolute send time is signaled to the receiver in-band using the |
89 |
| - // general mechanism for RTP header extensions [RFC5285]. The payload |
90 |
| - // of this extension (the transmitted value) is a 24-bit unsigned integer |
91 |
| - // containing the sender's current time in seconds as a fixed point number |
92 |
| - // with 18 bits fractional part. |
93 |
| - // |
94 |
| - // The form of the absolute send time extension block: |
95 |
| - // |
96 |
| - // 0 1 2 3 |
97 |
| - // 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 |
98 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
99 |
| - // | ID | len=2 | absolute send time | |
100 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
101 |
| - DCHECK_EQ(len, kAbsSendTimeExtnLen); |
102 |
| - // Now() has resolution ~1-15ms, using HighResNow(). But it is warned not to |
103 |
| - // use it unless necessary, as it is expensive than Now(). |
104 |
| - uint32 now_second = abs_send_time; |
105 |
| - if (!now_second) { |
106 |
| - uint64 now_us = |
107 |
| - (base::TimeTicks::HighResNow() - base::TimeTicks()).InMicroseconds(); |
108 |
| - // Convert second to 24-bit unsigned with 18 bit fractional part |
109 |
| - now_second = |
110 |
| - ((now_us << 18) / base::Time::kMicrosecondsPerSecond) & 0x00FFFFFF; |
111 |
| - } |
112 |
| - // TODO(mallinath) - Add SetBE24 to byteorder.h in libjingle. |
113 |
| - extn_data[0] = static_cast<uint8>(now_second >> 16); |
114 |
| - extn_data[1] = static_cast<uint8>(now_second >> 8); |
115 |
| - extn_data[2] = static_cast<uint8>(now_second); |
116 |
| -} |
117 |
| - |
118 |
| -// Assumes |len| is actual packet length + tag length. Updates HMAC at end of |
119 |
| -// the RTP packet. |
120 |
| -void UpdateRtpAuthTag(char* rtp, int len, |
121 |
| - const talk_base::PacketOptions& options) { |
122 |
| - // If there is no key, return. |
123 |
| - if (options.packet_time_params.srtp_auth_key.empty()) |
124 |
| - return; |
125 |
| - |
126 |
| - size_t tag_length = options.packet_time_params.srtp_auth_tag_len; |
127 |
| - char* auth_tag = rtp + (len - tag_length); |
128 |
| - |
129 |
| - // We should have a fake HMAC value @ auth_tag. |
130 |
| - DCHECK_EQ(0, memcmp(auth_tag, kFakeAuthTag, tag_length)); |
131 |
| - |
132 |
| - crypto::HMAC hmac(crypto::HMAC::SHA1); |
133 |
| - if (!hmac.Init(reinterpret_cast<const unsigned char*>( |
134 |
| - &options.packet_time_params.srtp_auth_key[0]), |
135 |
| - options.packet_time_params.srtp_auth_key.size())) { |
136 |
| - NOTREACHED(); |
137 |
| - return; |
138 |
| - } |
139 |
| - |
140 |
| - if (hmac.DigestLength() < tag_length) { |
141 |
| - NOTREACHED(); |
142 |
| - return; |
143 |
| - } |
144 |
| - |
145 |
| - // Copy ROC after end of rtp packet. |
146 |
| - memcpy(auth_tag, &options.packet_time_params.srtp_packet_index, 4); |
147 |
| - // Authentication of a RTP packet will have RTP packet + ROC size. |
148 |
| - int auth_required_length = len - tag_length + 4; |
149 |
| - |
150 |
| - unsigned char output[64]; |
151 |
| - if (!hmac.Sign(base::StringPiece(rtp, auth_required_length), |
152 |
| - output, sizeof(output))) { |
153 |
| - NOTREACHED(); |
154 |
| - return; |
155 |
| - } |
156 |
| - // Copy HMAC from output to packet. This is required as auth tag length |
157 |
| - // may not be equal to the actual HMAC length. |
158 |
| - memcpy(auth_tag, output, tag_length); |
159 |
| -} |
160 |
| - |
161 | 14 | } // namespace
|
162 | 15 |
|
163 | 16 | namespace content {
|
164 | 17 |
|
165 |
| -namespace packet_processing_helpers { |
166 |
| - |
167 |
| -bool ApplyPacketOptions(char* data, int length, |
168 |
| - const talk_base::PacketOptions& options, |
169 |
| - uint32 abs_send_time) { |
170 |
| - DCHECK(data != NULL); |
171 |
| - DCHECK(length > 0); |
172 |
| - // if there is no valid |rtp_sendtime_extension_id| and |srtp_auth_key| in |
173 |
| - // PacketOptions, nothing to be updated in this packet. |
174 |
| - if (options.packet_time_params.rtp_sendtime_extension_id == -1 && |
175 |
| - options.packet_time_params.srtp_auth_key.empty()) { |
176 |
| - return true; |
177 |
| - } |
178 |
| - |
179 |
| - DCHECK(!IsDtlsPacket(data, length)); |
180 |
| - DCHECK(!IsRtcpPacket(data)); |
181 |
| - |
182 |
| - // If there is a srtp auth key present then packet must be a RTP packet. |
183 |
| - // RTP packet may have been wrapped in a TURN Channel Data or |
184 |
| - // TURN send indication. |
185 |
| - int rtp_start_pos; |
186 |
| - int rtp_length; |
187 |
| - if (!GetRtpPacketStartPositionAndLength( |
188 |
| - data, length, &rtp_start_pos, &rtp_length)) { |
189 |
| - // This method should never return false. |
190 |
| - NOTREACHED(); |
191 |
| - return false; |
192 |
| - } |
193 |
| - |
194 |
| - // Skip to rtp packet. |
195 |
| - char* start = data + rtp_start_pos; |
196 |
| - // If packet option has non default value (-1) for sendtime extension id, |
197 |
| - // then we should parse the rtp packet to update the timestamp. Otherwise |
198 |
| - // just calculate HMAC and update packet with it. |
199 |
| - if (options.packet_time_params.rtp_sendtime_extension_id != -1) { |
200 |
| - UpdateRtpAbsSendTimeExtn( |
201 |
| - start, rtp_length, |
202 |
| - options.packet_time_params.rtp_sendtime_extension_id, abs_send_time); |
203 |
| - } |
204 |
| - |
205 |
| - UpdateRtpAuthTag(start, rtp_length, options); |
206 |
| - return true; |
207 |
| -} |
208 |
| - |
209 |
| -bool GetRtpPacketStartPositionAndLength( |
210 |
| - char* packet, int length, int* rtp_start_pos, int* rtp_packet_length) { |
211 |
| - int rtp_begin, rtp_length; |
212 |
| - if (IsTurnChannelData(packet)) { |
213 |
| - // Turn Channel Message header format. |
214 |
| - // 0 1 2 3 |
215 |
| - // 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 |
216 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
217 |
| - // | Channel Number | Length | |
218 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
219 |
| - // | | |
220 |
| - // / Application Data / |
221 |
| - // / / |
222 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
223 |
| - if (length < kTurnChannelHdrLen) { |
224 |
| - return false; |
225 |
| - } |
226 |
| - |
227 |
| - rtp_begin = kTurnChannelHdrLen; |
228 |
| - rtp_length = talk_base::GetBE16(&packet[2]); |
229 |
| - if (length < rtp_length + kTurnChannelHdrLen) { |
230 |
| - return false; |
231 |
| - } |
232 |
| - } else if (IsTurnSendIndicationPacket(packet)) { |
233 |
| - if (length <= P2PSocketHost::kStunHeaderSize) { |
234 |
| - // Message must be greater than 20 bytes, if it's carrying any payload. |
235 |
| - return false; |
236 |
| - } |
237 |
| - // Validate STUN message length. |
238 |
| - int stun_msg_len = talk_base::GetBE16(&packet[2]); |
239 |
| - if (stun_msg_len + P2PSocketHost::kStunHeaderSize != length) { |
240 |
| - return false; |
241 |
| - } |
242 |
| - |
243 |
| - // First skip mandatory stun header which is of 20 bytes. |
244 |
| - rtp_begin = P2PSocketHost::kStunHeaderSize; |
245 |
| - // Loop through STUN attributes until we find STUN DATA attribute. |
246 |
| - char* start = packet + rtp_begin; |
247 |
| - bool data_attr_present = false; |
248 |
| - while ((packet + rtp_begin) - start < length) { |
249 |
| - // Keep reading STUN attributes until we hit DATA attribute. |
250 |
| - // Attribute will be a TLV structure. |
251 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
252 |
| - // | Type | Length | |
253 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
254 |
| - // | Value (variable) .... |
255 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
256 |
| - // The value in the length field MUST contain the length of the Value |
257 |
| - // part of the attribute, prior to padding, measured in bytes. Since |
258 |
| - // STUN aligns attributes on 32-bit boundaries, attributes whose content |
259 |
| - // is not a multiple of 4 bytes are padded with 1, 2, or 3 bytes of |
260 |
| - // padding so that its value contains a multiple of 4 bytes. The |
261 |
| - // padding bits are ignored, and may be any value. |
262 |
| - uint16 attr_type, attr_length; |
263 |
| - // Getting attribute type and length. |
264 |
| - attr_type = talk_base::GetBE16(&packet[rtp_begin]); |
265 |
| - attr_length = talk_base::GetBE16( |
266 |
| - &packet[rtp_begin + sizeof(attr_type)]); |
267 |
| - // Checking for bogus attribute length. |
268 |
| - if (length < attr_length + rtp_begin) { |
269 |
| - return false; |
270 |
| - } |
271 |
| - |
272 |
| - if (attr_type != cricket::STUN_ATTR_DATA) { |
273 |
| - rtp_begin += sizeof(attr_type) + sizeof(attr_length) + attr_length; |
274 |
| - if ((attr_length % 4) != 0) { |
275 |
| - rtp_begin += (4 - (attr_length % 4)); |
276 |
| - } |
277 |
| - continue; |
278 |
| - } |
279 |
| - |
280 |
| - data_attr_present = true; |
281 |
| - rtp_begin += 4; // Skip STUN_DATA_ATTR header. |
282 |
| - rtp_length = attr_length; |
283 |
| - // One final check of length before exiting. |
284 |
| - if (length < rtp_length + rtp_begin) { |
285 |
| - return false; |
286 |
| - } |
287 |
| - // We found STUN_DATA_ATTR. We can skip parsing rest of the packet. |
288 |
| - break; |
289 |
| - } |
290 |
| - |
291 |
| - if (!data_attr_present) { |
292 |
| - // There is no data attribute present in the message. We can't do anything |
293 |
| - // with the message. |
294 |
| - return false; |
295 |
| - } |
296 |
| - |
297 |
| - } else { |
298 |
| - // This is a raw RTP packet. |
299 |
| - rtp_begin = 0; |
300 |
| - rtp_length = length; |
301 |
| - } |
302 |
| - |
303 |
| - // Making sure we have a valid RTP packet at the end. |
304 |
| - if (IsRtpPacket(packet + rtp_begin, rtp_length) && |
305 |
| - ValidateRtpHeader(packet + rtp_begin, rtp_length)) { |
306 |
| - *rtp_start_pos = rtp_begin; |
307 |
| - *rtp_packet_length = rtp_length; |
308 |
| - return true; |
309 |
| - } |
310 |
| - return false; |
311 |
| -} |
312 |
| - |
313 |
| -// ValidateRtpHeader must be called before this method to make sure, we have |
314 |
| -// a sane rtp packet. |
315 |
| -bool UpdateRtpAbsSendTimeExtn(char* rtp, int length, |
316 |
| - int extension_id, uint32 abs_send_time) { |
317 |
| - // 0 1 2 3 |
318 |
| - // 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 |
319 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
320 |
| - // |V=2|P|X| CC |M| PT | sequence number | |
321 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
322 |
| - // | timestamp | |
323 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
324 |
| - // | synchronization source (SSRC) identifier | |
325 |
| - // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ |
326 |
| - // | contributing source (CSRC) identifiers | |
327 |
| - // | .... | |
328 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
329 |
| - |
330 |
| - // Return if extension bit is not set. |
331 |
| - if (!(rtp[0] & 0x10)) { |
332 |
| - return true; |
333 |
| - } |
334 |
| - |
335 |
| - int cc_count = rtp[0] & 0x0F; |
336 |
| - int rtp_hdr_len_without_extn = kMinRtpHdrLen + 4 * cc_count; |
337 |
| - |
338 |
| - rtp += rtp_hdr_len_without_extn; |
339 |
| - |
340 |
| - // Getting extension profile ID and length. |
341 |
| - uint16 profile_id = talk_base::GetBE16(rtp); |
342 |
| - // Length is in 32 bit words. |
343 |
| - uint16 extn_length = talk_base::GetBE16(rtp + 2) * 4; |
344 |
| - |
345 |
| - rtp += kRtpExtnHdrLen; // Moving past extn header. |
346 |
| - |
347 |
| - bool found = false; |
348 |
| - // WebRTC is using one byte header extension. |
349 |
| - // TODO(mallinath) - Handle two byte header extension. |
350 |
| - if (profile_id == 0xBEDE) { // OneByte extension header |
351 |
| - // 0 |
352 |
| - // 0 1 2 3 4 5 6 7 |
353 |
| - // +-+-+-+-+-+-+-+-+ |
354 |
| - // | ID | len | |
355 |
| - // +-+-+-+-+-+-+-+-+ |
356 |
| - |
357 |
| - // 0 1 2 3 |
358 |
| - // 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 |
359 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
360 |
| - // | 0xBE | 0xDE | length=3 | |
361 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
362 |
| - // | ID | L=0 | data | ID | L=1 | data... |
363 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
364 |
| - // ...data | 0 (pad) | 0 (pad) | ID | L=3 | |
365 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
366 |
| - // | data | |
367 |
| - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
368 |
| - char* extn_start = rtp; |
369 |
| - while (rtp - extn_start < extn_length) { |
370 |
| - const int id = (*rtp & 0xF0) >> 4; |
371 |
| - const int len = (*rtp & 0x0F) + 1; |
372 |
| - // The 4-bit length is the number minus one of data bytes of this header |
373 |
| - // extension element following the one-byte header. |
374 |
| - if (id == extension_id) { |
375 |
| - UpdateAbsSendTimeExtnValue(rtp + kOneByteHdrLen, len, abs_send_time); |
376 |
| - found = true; |
377 |
| - break; |
378 |
| - } |
379 |
| - rtp += kOneByteHdrLen + len; |
380 |
| - // Counting padding bytes. |
381 |
| - while ((*rtp == 0) && (rtp - extn_start < extn_length)) { |
382 |
| - ++rtp; |
383 |
| - } |
384 |
| - } |
385 |
| - } |
386 |
| - return found; |
387 |
| -} |
388 |
| - |
389 |
| -} // packet_processing_helpers |
390 |
| - |
391 | 18 | P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender,
|
392 | 19 | int id)
|
393 | 20 | : message_sender_(message_sender),
|
|
0 commit comments