|
OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * DTLS Protocol | |
3 * | |
4 * ***** BEGIN LICENSE BLOCK ***** | |
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1 | |
6 * | |
7 * The contents of this file are subject to the Mozilla Public License Version | |
8 * 1.1 (the "License"); you may not use this file except in compliance with | |
9 * the License. You may obtain a copy of the License at | |
10 * http://www.mozilla.org/MPL/ | |
11 * | |
12 * Software distributed under the License is distributed on an "AS IS" basis, | |
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License | |
14 * for the specific language governing rights and limitations under the | |
15 * License. | |
16 * | |
17 * The Original Code is the Netscape security libraries. | |
18 * | |
19 * The Initial Developer of the Original Code is | |
20 * Netscape Communications Corporation. | |
21 * Portions created by the Initial Developer are Copyright (C) 1994-2000 | |
22 * the Initial Developer. All Rights Reserved. | |
23 * | |
24 * Contributor(s): | |
25 * Eric Rescorla <ekr@rtfm.com> | |
26 * | |
27 * Alternatively, the contents of this file may be used under the terms of | |
28 * either the GNU General Public License Version 2 or later (the "GPL"), or | |
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), | |
30 * in which case the provisions of the GPL or the LGPL are applicable instead | |
31 * of those above. If you wish to allow use of your version of this file only | |
32 * under the terms of either the GPL or the LGPL, and not to allow others to | |
33 * use your version of this file under the terms of the MPL, indicate your | |
34 * decision by deleting the provisions above and replace them with the notice | |
35 * and other provisions required by the GPL or the LGPL. If you do not delete | |
36 * the provisions above, a recipient may use your version of this file under | |
37 * the terms of any one of the MPL, the GPL or the LGPL. | |
38 * | |
39 * ***** END LICENSE BLOCK ***** */ | |
40 /* $Id: $ */ | |
41 | |
42 #include "ssl.h" | |
43 #include "sslimpl.h" | |
44 #include "sslproto.h" | |
45 | |
46 #ifndef PR_ARRAY_SIZE | |
47 #define PR_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) | |
48 #endif | |
49 | |
50 static SECStatus dtls_TransmitMessageFlight(sslSocket *ss); | |
51 static void dtls_RetransmitTimerExpiredCb(sslSocket *ss); | |
52 static SECStatus dtls_SendSavedWriteData(sslSocket *ss); | |
53 | |
54 /* -28 adjusts for the IP/UDP header */ | |
55 static const PRUint16 COMMON_MTU_VALUES[] = { | |
56 1500 - 28, /* Ethernet MTU */ | |
57 1280 - 28, /* IPv6 minimum MTU */ | |
58 576 - 28, /* Common assumption */ | |
59 256 - 28 /* We're in serious trouble now */ | |
60 }; | |
61 | |
62 #define DTLS_COOKIE_BYTES 32 | |
63 | |
64 /* List copied from ssl3con.c:cipherSuites */ | |
65 static const ssl3CipherSuite nonDTLSSuites[] = { | |
66 #ifdef NSS_ENABLE_ECC | |
67 TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, | |
68 TLS_ECDHE_RSA_WITH_RC4_128_SHA, | |
69 #endif /* NSS_ENABLE_ECC */ | |
70 TLS_DHE_DSS_WITH_RC4_128_SHA, | |
71 #ifdef NSS_ENABLE_ECC | |
72 TLS_ECDH_RSA_WITH_RC4_128_SHA, | |
73 TLS_ECDH_ECDSA_WITH_RC4_128_SHA, | |
74 #endif /* NSS_ENABLE_ECC */ | |
75 SSL_RSA_WITH_RC4_128_MD5, | |
76 SSL_RSA_WITH_RC4_128_SHA, | |
77 TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, | |
78 SSL_RSA_EXPORT_WITH_RC4_40_MD5, | |
79 0 /* End of list marker */ | |
80 }; | |
81 | |
82 /* Map back and forth between TLS and DTLS versions in wire format. | |
83 * Mapping table is: | |
84 * | |
85 * TLS DTLS | |
86 * 1.1 (0302) 1.0 (feff) | |
87 */ | |
88 SSL3ProtocolVersion | |
89 dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv) | |
90 { | |
91 /* Anything other than TLS 1.1 is an error, so return | |
92 * the invalid version ffff. */ | |
93 if (tlsv != SSL_LIBRARY_VERSION_TLS_1_1) | |
94 return 0xffff; | |
95 | |
96 return SSL_LIBRARY_VERSION_DTLS_1_0_WIRE; | |
97 } | |
98 | |
99 /* Map known DTLS versions to known TLS versions. | |
100 * - Invalid versions (< 1.0) return a version of 0 | |
101 * - Versions > known return a version one higher than we know of | |
102 * to accomodate a theoretically newer version */ | |
103 SSL3ProtocolVersion | |
104 dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv) | |
105 { | |
106 if (MSB(dtlsv) == 0xff) { | |
107 return 0; | |
108 } | |
109 | |
110 if (dtlsv == SSL_LIBRARY_VERSION_DTLS_1_0_WIRE) | |
111 return SSL_LIBRARY_VERSION_TLS_1_1; | |
112 | |
113 /* Return a fictional higher version than we know of */ | |
114 return SSL_LIBRARY_VERSION_TLS_1_1 + 1; | |
115 } | |
116 | |
117 /* On this socket, Disable non-DTLS cipher suites in the argument's list */ | |
118 SECStatus | |
119 ssl3_DisableNonDTLSSuites(sslSocket * ss) | |
120 { | |
121 const ssl3CipherSuite * suite; | |
122 | |
123 for (suite = nonDTLSSuites; *suite; ++suite) { | |
124 SECStatus rv = ssl3_CipherPrefSet(ss, *suite, PR_FALSE); | |
125 | |
126 PORT_Assert(rv == SECSuccess); /* else is coding error */ | |
127 } | |
128 return SECSuccess; | |
129 } | |
130 | |
131 /* Allocate a DTLSQueuedMessage. | |
132 * | |
133 * Called from dtls_QueueMessage() | |
134 */ | |
135 static DTLSQueuedMessage * | |
136 dtls_AllocQueuedMessage(PRUint16 epoch, SSL3ContentType type, | |
137 const unsigned char *data, PRUint32 len) | |
138 { | |
139 DTLSQueuedMessage *msg = NULL; | |
140 | |
141 msg = PORT_ZAlloc(sizeof(DTLSQueuedMessage)); | |
142 if (!msg) | |
143 return NULL; | |
144 | |
145 msg->data = PORT_Alloc(len); | |
146 if (!msg->data) { | |
147 PORT_Free(msg); | |
148 return NULL; | |
149 } | |
150 PORT_Memcpy(msg->data, data, len); | |
151 | |
152 msg->len = len; | |
153 msg->epoch = epoch; | |
154 msg->type = type; | |
155 | |
156 return msg; | |
157 } | |
158 | |
159 /* | |
160 * Free a handshake message | |
161 * | |
162 * Called from dtls_FreeHandshakeMessages() | |
163 */ | |
164 static void | |
165 dtls_FreeHandshakeMessage(DTLSQueuedMessage *msg) | |
166 { | |
167 if (!msg) | |
168 return; | |
169 | |
170 PORT_ZFree(msg->data, msg->len); | |
171 PORT_Free(msg); | |
172 } | |
173 | |
174 /* | |
175 * Free a list of handshake messages | |
176 * | |
177 * Called from: | |
178 * dtls_HandleHandshake() | |
179 * ssl3_DestroySSL3Info() | |
180 */ | |
181 void | |
182 dtls_FreeHandshakeMessages(PRCList *list) | |
183 { | |
184 PRCList *cur_p; | |
185 | |
186 while (!PR_CLIST_IS_EMPTY(list)) { | |
187 cur_p = PR_LIST_TAIL(list); | |
188 PR_REMOVE_LINK(cur_p); | |
189 dtls_FreeHandshakeMessage((DTLSQueuedMessage *)cur_p); | |
190 } | |
191 } | |
192 | |
193 /* Called only from ssl3_HandleRecord, for each (deciphered) DTLS record. | |
194 * origBuf is the decrypted ssl record content and is expected to contain | |
195 * complete handshake records | |
196 * Caller must hold the handshake and RecvBuf locks. | |
197 * | |
198 * Note that this code uses msg_len for two purposes: | |
199 * | |
200 * (1) To pass the length to ssl3_HandleHandshakeMessage() | |
201 * (2) To carry the length of a message currently being reassembled | |
202 * | |
203 * However, unlike ssl3_HandleHandshake(), it is not used to carry | |
204 * the state of reassembly (i.e., whether one is in progress). That | |
205 * is carried in recvdHighWater and recvdFragments. | |
206 */ | |
207 #define OFFSET_BYTE(o) (o/8) | |
208 #define OFFSET_MASK(o) (1 << (o%8)) | |
209 | |
210 SECStatus | |
211 dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) | |
212 { | |
213 /* XXX OK for now. | |
214 * This doesn't work properly with asynchronous certificate validation. | |
215 * because that returns a WOULDBLOCK error. The current DTLS | |
216 * applications do not need asynchronous validation, but in the | |
217 * future we will need to add this. | |
218 */ | |
219 sslBuffer buf = *origBuf; | |
220 SECStatus rv = SECSuccess; | |
221 | |
222 PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); | |
223 PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); | |
ekr
2012/03/26 21:49:18
A lot of the existing code has these extra spaces
| |
224 | |
225 while (buf.len > 0) { | |
226 PRUint8 type; | |
227 PRUint32 message_length; | |
228 PRUint16 message_seq; | |
229 PRUint32 fragment_offset; | |
230 PRUint32 fragment_length; | |
231 PRUint32 offset; | |
232 | |
233 if (buf.len < 12) { | |
234 PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); | |
235 rv = SECFailure; | |
236 break; | |
237 } | |
238 | |
239 /* Parse the header */ | |
240 type = buf.buf[0]; | |
241 message_length = (buf.buf[1] << 16) | (buf.buf[2] << 8) | buf.buf[3]; | |
242 message_seq = (buf.buf[4] << 8) | buf.buf[5]; | |
243 fragment_offset = (buf.buf[6] << 16) | (buf.buf[7] << 8) | buf.buf[8]; | |
244 fragment_length = (buf.buf[9] << 16) | (buf.buf[10] << 8) | buf.buf[11]; | |
245 | |
246 #define MAX_HANDSHAKE_MSG_LEN 0x1ffff /* 128k - 1 */ | |
247 if (message_length > MAX_HANDSHAKE_MSG_LEN) { | |
248 (void)ssl3_DecodeError(ss); | |
249 PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); | |
250 return SECFailure; | |
251 } | |
252 #undef MAX_HANDSHAKE_MSG_LEN | |
253 | |
254 buf.buf += 12; | |
255 buf.len -= 12; | |
256 | |
257 /* This fragment must be complete */ | |
258 if (buf.len < fragment_length) { | |
259 PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); | |
260 rv = SECFailure; | |
261 break; | |
262 } | |
263 | |
264 /* Sanity check the packet contents */ | |
265 if ((fragment_length + fragment_offset) > message_length) { | |
266 PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); | |
267 rv = SECFailure; | |
268 break; | |
269 } | |
270 | |
271 /* There are three ways we could not be ready for this packet. | |
272 * | |
273 * 1. It's a partial next message. | |
274 * 2. It's a partial or complete message beyond the next | |
275 * 3. It's a message we've already seen | |
276 * | |
277 * If it's the complete next message we accept it right away. | |
278 * This is the common case for short messages | |
279 */ | |
280 if ((message_seq == ss->ssl3.hs.recvMessageSeq) | |
281 && (fragment_offset == 0) | |
282 && (fragment_length == message_length)) { | |
283 /* Complete next message. Process immediately */ | |
284 ss->ssl3.hs.msg_type = (SSL3HandshakeType)type; | |
285 ss->ssl3.hs.msg_len = message_length; | |
286 | |
287 /* At this point we are advancing our state machine, so | |
288 * we can free our last flight of messages */ | |
289 dtls_FreeHandshakeMessages(ss->ssl3.hs.lastMessageFlight); | |
290 ss->ssl3.hs.recvdHighWater = -1; | |
291 dtls_CancelTimer(ss); | |
292 | |
293 /* Reset the timer to the initial value if the retry counter | |
294 * is 0, per Sec. 4.2.4.1 */ | |
295 if (ss->ssl3.hs.rtRetries == 0) { | |
296 ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS; | |
297 } | |
298 | |
299 rv = ssl3_HandleHandshakeMessage(ss, buf.buf, ss->ssl3.hs.msg_len); | |
300 if (rv == SECFailure) { | |
301 /* Do not attempt to process rest of messages in this record */ | |
302 break; | |
303 } | |
304 } else { | |
305 if (message_seq < ss->ssl3.hs.recvMessageSeq) { | |
306 /* Case 3: we do an immediate retransmit if we're | |
307 * in a waiting state*/ | |
308 if (ss->ssl3.hs.rtTimerCb == NULL) { | |
309 /* Ignore */ | |
310 } else if (ss->ssl3.hs.rtTimerCb == | |
311 dtls_RetransmitTimerExpiredCb) { | |
312 SSL_TRC(30, ("%d: SSL3[%d]: Retransmit detected", | |
313 SSL_GETPID(), ss->fd)); | |
314 /* Check to see if we retransmitted recently. If so, | |
315 * suppress the triggered retransmit. This avoids | |
316 * retransmit wars after packet loss. | |
317 * This is not in RFC 5346 but should be | |
318 */ | |
319 if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) > | |
320 (ss->ssl3.hs.rtTimeoutMs / 4)) { | |
321 SSL_TRC(30, | |
322 ("%d: SSL3[%d]: Shortcutting retransmit timer", | |
323 SSL_GETPID(), ss->fd)); | |
324 | |
325 /* Cancel the timer and call the CB, | |
326 * which re-arms the timer */ | |
327 dtls_CancelTimer(ss); | |
328 dtls_RetransmitTimerExpiredCb(ss); | |
329 rv = SECSuccess; | |
330 break; | |
331 } else { | |
332 SSL_TRC(30, | |
333 ("%d: SSL3[%d]: We just retransmitted. Ignoring.", | |
334 SSL_GETPID(), ss->fd)); | |
335 rv = SECSuccess; | |
336 break; | |
337 } | |
338 } else if (ss->ssl3.hs.rtTimerCb == dtls_FinishedTimerCb) { | |
339 /* Retransmit the messages and re-arm the timer | |
340 * Note that we are not backing off the timer here. | |
341 * The spec isn't clear and my reasoning is that this | |
342 * may be a re-ordered packet rather than slowness, | |
343 * so let's be aggressive. */ | |
344 dtls_CancelTimer(ss); | |
345 rv = dtls_TransmitMessageFlight(ss); | |
346 if (rv == SECSuccess) { | |
347 rv = dtls_StartTimer(ss, dtls_FinishedTimerCb); | |
348 } | |
349 if (rv != SECSuccess) | |
350 return rv; | |
351 break; | |
352 } | |
353 } else if (message_seq > ss->ssl3.hs.recvMessageSeq) { | |
354 /* Case 2 | |
355 * | |
356 * Ignore this message. This means we don't handle out of | |
357 * order complete messages that well, but we're still | |
358 * compliant and this probably does not happen often | |
359 * | |
360 * XXX OK for now. Maybe do something smarter at some point? | |
361 */ | |
362 } else { | |
363 /* Case 1 | |
364 * | |
365 * Buffer the fragment for reassembly | |
366 */ | |
367 /* Make room for the message */ | |
368 if (ss->ssl3.hs.recvdHighWater == -1) { | |
369 PRUint32 map_length = OFFSET_BYTE(message_length) + 1; | |
370 | |
371 rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, message_length); | |
372 if (rv != SECSuccess) | |
373 break; | |
374 /* Make room for the fragment map */ | |
375 rv = sslBuffer_Grow(&ss->ssl3.hs.recvdFragments, | |
376 map_length); | |
377 if (rv != SECSuccess) | |
378 break; | |
379 | |
380 /* Reset the reassembly map */ | |
381 ss->ssl3.hs.recvdHighWater = 0; | |
382 PORT_Memset(ss->ssl3.hs.recvdFragments.buf, 0, | |
383 ss->ssl3.hs.recvdFragments.space); | |
384 ss->ssl3.hs.msg_type = (SSL3HandshakeType)type; | |
385 ss->ssl3.hs.msg_len = message_length; | |
386 } | |
387 | |
388 /* If we have a message length mismatch, abandon the reassembly | |
389 * in progress and hope that the next retransmit will give us | |
390 * something sane | |
391 */ | |
392 if (message_length != ss->ssl3.hs.msg_len) { | |
393 ss->ssl3.hs.recvdHighWater = -1; | |
394 PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); | |
395 rv = SECFailure; | |
396 break; | |
397 } | |
398 | |
399 /* Now copy this fragment into the buffer */ | |
400 PORT_Assert((fragment_offset + fragment_length) <= | |
401 ss->ssl3.hs.msg_body.space); | |
402 PORT_Memcpy(ss->ssl3.hs.msg_body.buf + fragment_offset, | |
403 buf.buf, fragment_length); | |
404 | |
405 /* This logic is a bit tricky. We have two values for | |
406 * reassembly state: | |
407 * | |
408 * - recvdHighWater contains the highest contiguous number of | |
409 * bytes received | |
410 * - recvdFragments contains a bitmask of packets received | |
411 * above recvdHighWater | |
412 * | |
413 * This avoids having to fill in the bitmask in the common | |
414 * case of adjacent fragments received in sequence | |
415 */ | |
416 if (fragment_offset <= ss->ssl3.hs.recvdHighWater) { | |
417 /* Either this is the adjacent fragment or an overlapping | |
418 * fragment */ | |
419 ss->ssl3.hs.recvdHighWater = fragment_offset + | |
420 fragment_length; | |
421 } else { | |
422 for (offset = fragment_offset; | |
423 offset < fragment_offset + fragment_length; | |
424 offset++) { | |
425 ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] |= | |
426 OFFSET_MASK(offset); | |
427 } | |
428 } | |
429 | |
430 /* Now figure out the new high water mark if appropriate */ | |
431 for (offset = ss->ssl3.hs.recvdHighWater; | |
432 offset < ss->ssl3.hs.msg_len; offset++) { | |
433 /* Note that this loop is not efficient, since it counts | |
434 * bit by bit. If we have a lot of out-of-order packets, | |
435 * we should optimize this */ | |
436 if (ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] & | |
437 OFFSET_MASK(offset)) { | |
438 ss->ssl3.hs.recvdHighWater++; | |
439 } else { | |
440 break; | |
441 } | |
442 } | |
443 | |
444 /* If we have all the bytes, then we are good to go */ | |
445 if (ss->ssl3.hs.recvdHighWater == ss->ssl3.hs.msg_len) { | |
446 ss->ssl3.hs.recvdHighWater = -1; | |
447 | |
448 rv = ssl3_HandleHandshakeMessage(ss, | |
449 ss->ssl3.hs.msg_body.buf, | |
450 ss->ssl3.hs.msg_len); | |
451 if (rv == SECFailure) | |
452 break; /* Skip rest of record */ | |
453 | |
454 /* At this point we are advancing our state machine, so | |
455 * we can free our last flight of messages */ | |
456 dtls_FreeHandshakeMessages(ss->ssl3.hs.lastMessageFlight); | |
457 dtls_CancelTimer(ss); | |
458 | |
459 /* If there have been no retries this time, reset the | |
460 * timer value to the default per Section 4.2.4.1 */ | |
461 if (ss->ssl3.hs.rtRetries == 0) { | |
462 ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS; | |
463 } | |
464 } | |
465 } | |
466 } | |
467 | |
ekr
2012/03/26 21:49:18
Did you reverse these for a technical reason or is
wtc
2012/03/27 00:28:25
It is just aesthetic.
| |
468 buf.buf += fragment_length; | |
469 buf.len -= fragment_length; | |
470 } | |
471 | |
472 origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */ | |
473 | |
474 /* XXX OK for now. In future handle rv == SECWouldBlock safely in order | |
475 * to deal with asynchronous certificate verification */ | |
476 return rv; | |
477 } | |
478 | |
479 /* Enqueue a message (either handshake or CCS) | |
480 * | |
481 * Called from: | |
482 * dtls_StageHandshakeMessage() | |
483 * ssl3_SendChangeCipherSpecs() | |
484 */ | |
485 SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type, | |
486 const SSL3Opaque *pIn, PRInt32 nIn) | |
487 { | |
488 SECStatus rv = SECSuccess; | |
489 DTLSQueuedMessage *msg = NULL; | |
490 | |
491 PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); | |
492 PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); | |
493 | |
494 msg = dtls_AllocQueuedMessage(ss->ssl3.cwSpec->epoch, type, pIn, nIn); | |
495 | |
496 if (!msg) { | |
497 PORT_SetError(SEC_ERROR_NO_MEMORY); | |
498 rv = SECFailure; | |
499 } else { | |
500 PR_APPEND_LINK(&msg->link, ss->ssl3.hs.lastMessageFlight); | |
501 } | |
502 | |
503 return rv; | |
504 } | |
505 | |
506 /* Add DTLS handshake message to the pending queue | |
507 * Empty the sendBuf buffer. | |
508 * This function returns SECSuccess or SECFailure, never SECWouldBlock. | |
509 * Always set sendBuf.len to 0, even when returning SECFailure. | |
510 * | |
511 * Called from: | |
512 * ssl3_AppendHandshakeHeader() | |
513 * dtls_FlushHandshake() | |
514 */ | |
515 SECStatus | |
516 dtls_StageHandshakeMessage(sslSocket *ss) | |
517 { | |
518 SECStatus rv = SECSuccess; | |
519 | |
520 PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); | |
521 PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); | |
522 | |
523 /* This function is sometimes called when no data is actually to | |
524 * be staged, so just return SECSuccess. */ | |
525 if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len) | |
526 return rv; | |
527 | |
528 rv = dtls_QueueMessage(ss, content_handshake, | |
529 ss->sec.ci.sendBuf.buf, ss->sec.ci.sendBuf.len); | |
530 | |
531 /* Whether we succeeded or failed, toss the old handshake data. */ | |
532 ss->sec.ci.sendBuf.len = 0; | |
533 return rv; | |
534 } | |
535 | |
536 /* Enqueue the handshake message in sendBuf (if any) and then | |
537 * transmit the resulting flight of handshake messages. | |
538 * | |
539 * Called from: | |
540 * ssl3_FlushHandshake() | |
541 */ | |
542 SECStatus | |
543 dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags) | |
544 { | |
545 SECStatus rv = SECSuccess; | |
546 | |
547 PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); | |
548 PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); | |
549 | |
550 rv = dtls_StageHandshakeMessage(ss); | |
551 if (rv != SECSuccess) | |
552 return rv; | |
553 | |
554 if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { | |
555 rv = dtls_TransmitMessageFlight(ss); | |
556 if (rv != SECSuccess) | |
557 return rv; | |
558 | |
559 if (!(flags & ssl_SEND_FLAG_NO_RETRANSMIT)) { | |
560 ss->ssl3.hs.rtRetries = 0; | |
561 rv = dtls_StartTimer(ss, dtls_RetransmitTimerExpiredCb); | |
562 } | |
563 } | |
564 | |
565 return rv; | |
566 } | |
567 | |
568 /* The callback for when the retransmit timer expires | |
569 * | |
570 * Called from: | |
571 * dtls_CheckTimer() | |
572 * dtls_HandleHandshake() | |
573 */ | |
574 static void | |
575 dtls_RetransmitTimerExpiredCb(sslSocket *ss) | |
576 { | |
577 SECStatus rv = SECFailure; | |
578 | |
579 ss->ssl3.hs.rtRetries++; | |
580 | |
581 if (!(ss->ssl3.hs.rtRetries % 3)) { | |
582 /* If one of the messages was potentially greater than > MTU, | |
583 * then downgrade. Do this every time we have retransmitted a | |
584 * message twice, per RFC 6347 Sec. 4.1.1 */ | |
585 dtls_SetMTU(ss, ss->ssl3.hs.maxMessageSent - 1); | |
586 } | |
587 | |
588 rv = dtls_TransmitMessageFlight(ss); | |
589 if (rv == SECSuccess) { | |
590 | |
591 /* Re-arm the timer */ | |
592 rv = dtls_RestartTimer(ss, PR_TRUE, dtls_RetransmitTimerExpiredCb); | |
593 } | |
594 | |
595 if (rv == SECFailure) { | |
596 /* XXX OK for now. In future maybe signal the stack that we couldn't | |
597 * transmit. For now, let the read handle any real network errors */ | |
598 } | |
599 } | |
600 | |
601 /* Transmit a flight of handshake messages, stuffing them | |
602 * into as few records as seems reasonable | |
603 * | |
604 * Called from: | |
605 * dtls_FlushHandshake() | |
606 * dtls_RetransmitTimerExpiredCb() | |
607 */ | |
608 static SECStatus | |
609 dtls_TransmitMessageFlight(sslSocket *ss) | |
610 { | |
611 SECStatus rv = SECSuccess; | |
612 PRCList *msg_p; | |
613 PRUint16 room_left = ss->ssl3.mtu; | |
614 PRInt32 sent; | |
615 | |
616 ssl_GetXmitBufLock(ss); | |
617 ssl_GetSpecReadLock(ss); | |
618 | |
619 /* DTLS does not buffer its handshake messages in | |
620 * ss->pendingBuf, but rather in the lastMessageFlight | |
621 * structure. This is just a sanity check that | |
622 * some programming error hasn't inadvertantly | |
623 * stuffed something in ss->pendingBuf | |
624 */ | |
625 PORT_Assert(!ss->pendingBuf.len); | |
626 for (msg_p = PR_LIST_HEAD(ss->ssl3.hs.lastMessageFlight); | |
627 msg_p != ss->ssl3.hs.lastMessageFlight; | |
628 msg_p = PR_NEXT_LINK(msg_p)) { | |
629 DTLSQueuedMessage *msg = (DTLSQueuedMessage *)msg_p; | |
630 | |
631 /* The logic here is: | |
632 * | |
633 * 1. If this is a message that will not fit into the remaining | |
634 * space, then flush. | |
635 * 2. If the message will now fit into the remaining space, | |
636 * encrypt, buffer, and loop. | |
637 * 3. If the message will not fit, then fragment. | |
638 * | |
639 * At the end of the function, flush. | |
640 */ | |
641 if ((msg->len + SSL3_BUFFER_FUDGE) > room_left) { | |
642 /* The message will not fit into the remaining space, so flush */ | |
643 rv = dtls_SendSavedWriteData(ss); | |
644 if (rv != SECSuccess) | |
645 break; | |
646 | |
647 room_left = ss->ssl3.mtu; | |
648 } | |
649 | |
650 if ((msg->len + SSL3_BUFFER_FUDGE) <= room_left) { | |
651 /* The message will fit, so encrypt and then continue with the | |
652 * next packet */ | |
653 sent = ssl3_SendRecord(ss, msg->epoch, msg->type, | |
654 msg->data, msg->len, | |
655 ssl_SEND_FLAG_FORCE_INTO_BUFFER | | |
656 ssl_SEND_FLAG_USE_EPOCH); | |
657 if (sent != msg->len) { | |
658 rv = SECFailure; | |
659 if (sent != -1) { | |
660 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
661 } | |
662 break; | |
663 } | |
664 | |
665 room_left = ss->ssl3.mtu - ss->pendingBuf.len; | |
666 } else { | |
667 /* The message will not fit, so fragment. | |
668 * | |
669 * XXX OK for now. Arrange to coalesce the last fragment | |
670 * of this message with the next message if possible. | |
671 * That would be more efficient. | |
672 */ | |
673 PRUint32 fragment_offset = 0; | |
674 unsigned char fragment[DTLS_MAX_MTU]; /* >= than largest | |
675 * plausible MTU */ | |
676 | |
677 /* Assert that we have already flushed */ | |
678 PORT_Assert(room_left == ss->ssl3.mtu); | |
679 | |
680 /* Case 3: We now need to fragment this message | |
681 * DTLS only supports fragmenting handshaking messages */ | |
682 PORT_Assert(msg->type == content_handshake); | |
683 | |
684 /* The headers consume 12 bytes so the smalles possible | |
685 * message (i.e., an empty one) is 12 bytes | |
686 */ | |
687 PORT_Assert(msg->len >= 12); | |
688 | |
689 while ((fragment_offset + 12) < msg->len) { | |
690 PRUint32 fragment_len; | |
691 const unsigned char *content = msg->data + 12; | |
692 PRUint32 content_len = msg->len - 12; | |
693 | |
694 /* The reason we use 8 here is that that's the length of | |
695 * the new DTLS data that we add to the header */ | |
696 fragment_len = PR_MIN(room_left - (SSL3_BUFFER_FUDGE + 8), | |
697 content_len - fragment_offset); | |
698 PORT_Assert(fragment_len < DTLS_MAX_MTU - 12); | |
699 /* Make totally sure that we are within the buffer. | |
700 * Note that the only way that fragment len could get | |
701 * adjusted here is if | |
702 * | |
703 * (a) we are in release mode so the PORT_Assert is compiled out | |
704 * (b) either the MTU table is inconsistent with DTLS_MAX_MTU | |
705 * or ss->ssl3.mtu has become corrupt. | |
706 */ | |
707 fragment_len = PR_MIN(fragment_len, DTLS_MAX_MTU - 12); | |
708 | |
709 /* Construct an appropriate-sized fragment */ | |
710 /* Type, length, sequence */ | |
711 PORT_Memcpy(fragment, msg->data, 6); | |
712 | |
713 /* Offset */ | |
714 fragment[6] = (fragment_offset >> 16) & 0xff; | |
715 fragment[7] = (fragment_offset >> 8) & 0xff; | |
716 fragment[8] = (fragment_offset) & 0xff; | |
717 | |
718 /* Fragment length */ | |
719 fragment[9] = (fragment_len >> 16) & 0xff; | |
720 fragment[10] = (fragment_len >> 8) & 0xff; | |
721 fragment[11] = (fragment_len) & 0xff; | |
722 | |
723 PORT_Memcpy(fragment + 12, content + fragment_offset, | |
724 fragment_len); | |
725 | |
726 /* | |
727 * Send the record. We do this in two stages | |
728 * 1. Encrypt | |
729 */ | |
730 sent = ssl3_SendRecord(ss, msg->epoch, msg->type, | |
731 fragment, fragment_len + 12, | |
732 ssl_SEND_FLAG_FORCE_INTO_BUFFER | | |
733 ssl_SEND_FLAG_USE_EPOCH); | |
734 if (sent != (fragment_len + 12)) { | |
735 rv = SECFailure; | |
736 if (sent != -1) { | |
737 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
738 } | |
739 break; | |
740 } | |
741 | |
742 /* 2. Flush */ | |
743 rv = dtls_SendSavedWriteData(ss); | |
744 if (rv != SECSuccess) | |
745 break; | |
746 | |
747 fragment_offset += fragment_len; | |
748 } | |
749 } | |
750 } | |
751 | |
752 /* Finally, we need to flush */ | |
753 if (rv == SECSuccess) | |
754 rv = dtls_SendSavedWriteData(ss); | |
755 | |
756 /* Give up the locks */ | |
757 ssl_ReleaseSpecReadLock(ss); | |
758 ssl_ReleaseXmitBufLock(ss); | |
759 | |
760 return rv; | |
761 } | |
762 | |
763 /* Flush the data in the pendingBuf and update the max message sent | |
764 * so we can adjust the MTU estimate if we need to. | |
765 * Wrapper for ssl_SendSavedWriteData. | |
766 * | |
767 * Called from dtls_TransmitMessageFlight() | |
768 */ | |
769 static | |
770 SECStatus dtls_SendSavedWriteData(sslSocket *ss) | |
771 { | |
772 PRInt32 sent; | |
773 | |
774 sent = ssl_SendSavedWriteData(ss); | |
775 if (sent < 0) | |
776 return SECFailure; | |
777 | |
778 /* We should always have complete writes b/c datagram sockets | |
779 * don't really block */ | |
780 if (ss->pendingBuf.len > 0) { | |
781 ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); | |
782 return SECFailure; | |
783 } | |
784 | |
785 /* Update the largest message sent so we can adjust the MTU | |
786 * estimate if necessary */ | |
787 if (sent > ss->ssl3.hs.maxMessageSent) | |
788 ss->ssl3.hs.maxMessageSent = sent; | |
789 | |
790 return SECSuccess; | |
791 } | |
792 | |
793 /* Compress, MAC, encrypt a DTLS record. Allows specification of | |
794 * the epoch using epoch value. If use_epoch is PR_TRUE then | |
795 * we use the provided epoch. If use_epoch is PR_FALSE then | |
796 * whatever the current value is in effect is used. | |
797 * | |
798 * Called from ssl3_SendRecord() | |
799 */ | |
800 SECStatus | |
801 dtls_CompressMACEncryptRecord(sslSocket * ss, | |
802 DTLSEpoch epoch, | |
803 PRBool use_epoch, | |
804 SSL3ContentType type, | |
805 const SSL3Opaque * pIn, | |
806 PRUint32 contentLen, | |
807 sslBuffer * wrBuf) | |
808 { | |
809 SECStatus rv = SECFailure; | |
810 ssl3CipherSpec * cwSpec; | |
811 | |
812 ssl_GetSpecReadLock(ss); /********************************/ | |
813 | |
814 /* The reason for this switch-hitting code is that we might have | |
815 * a flight of records spanning an epoch boundary, e.g., | |
816 * | |
817 * ClientKeyExchange (epoch = 0) | |
818 * ChangeCipherSpec (epoch = 0) | |
819 * Finished (epoch = 1) | |
820 * | |
821 * Thus, each record needs a different cipher spec. The information | |
822 * about which epoch to use is carried with the record. | |
823 */ | |
824 if (use_epoch) { | |
825 if (ss->ssl3.cwSpec->epoch == epoch) | |
826 cwSpec = ss->ssl3.cwSpec; | |
827 else if (ss->ssl3.pwSpec->epoch == epoch) | |
828 cwSpec = ss->ssl3.pwSpec; | |
829 else | |
830 cwSpec = NULL; | |
831 } else { | |
832 cwSpec = ss->ssl3.cwSpec; | |
833 } | |
834 | |
835 if (cwSpec) { | |
836 rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, PR_TRUE, | |
837 type, pIn, contentLen, wrBuf); | |
838 } else { | |
839 PR_NOT_REACHED("Couldn't find a cipher spec matching epoch"); | |
840 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); | |
841 } | |
842 ssl_ReleaseSpecReadLock(ss); /************************************/ | |
843 | |
844 return rv; | |
845 } | |
846 | |
847 /* Start a timer | |
848 * | |
849 * Called from: | |
850 * dtls_HandleHandshake() | |
851 * dtls_FlushHAndshake() | |
852 * dtls_RestartTimer() | |
853 */ | |
854 SECStatus | |
855 dtls_StartTimer(sslSocket *ss, DTLSTimerCb cb) | |
856 { | |
857 PORT_Assert(ss->ssl3.hs.rtTimerCb == NULL); | |
858 | |
859 ss->ssl3.hs.rtTimerStarted = PR_IntervalNow(); | |
860 ss->ssl3.hs.rtTimerCb = cb; | |
861 | |
862 return SECSuccess; | |
863 } | |
864 | |
865 /* Restart a timer with optional backoff | |
866 * | |
867 * Called from dtls_RetransmitTimerExpiredCb() | |
868 */ | |
869 SECStatus | |
870 dtls_RestartTimer(sslSocket *ss, PRBool backoff, DTLSTimerCb cb) | |
871 { | |
872 if (backoff) { | |
873 ss->ssl3.hs.rtTimeoutMs *= 2; | |
874 if (ss->ssl3.hs.rtTimeoutMs > MAX_DTLS_TIMEOUT_MS) | |
875 ss->ssl3.hs.rtTimeoutMs = MAX_DTLS_TIMEOUT_MS; | |
876 } | |
877 | |
878 return dtls_StartTimer(ss, cb); | |
879 } | |
880 | |
881 /* Cancel a pending timer | |
882 * | |
883 * Called from: | |
884 * dtls_HandleHandshake() | |
885 * dtls_CheckTimer() | |
886 */ | |
887 void | |
888 dtls_CancelTimer(sslSocket *ss) | |
889 { | |
890 PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); | |
891 | |
892 ss->ssl3.hs.rtTimerCb = NULL; | |
893 } | |
894 | |
895 /* Check the pending timer and fire the callback if it expired | |
896 * | |
897 * Called from ssl3_GatherCompleteHandshake() | |
898 */ | |
899 void | |
900 dtls_CheckTimer(sslSocket *ss) | |
901 { | |
902 if (!ss->ssl3.hs.rtTimerCb) | |
903 return; | |
904 | |
905 if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) > | |
906 PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs)) { | |
907 /* Timer has expired */ | |
908 DTLSTimerCb cb = ss->ssl3.hs.rtTimerCb; | |
909 | |
910 /* Cancel the timer so that we can call the CB safely */ | |
911 dtls_CancelTimer(ss); | |
912 | |
913 /* Now call the CB */ | |
914 cb(ss); | |
915 } | |
916 } | |
917 | |
918 /* The callback to fire when the holddown timer for the Finished | |
919 * message expires and we can delete it | |
920 * | |
921 * Called from dtls_CheckTimer() | |
922 */ | |
923 void | |
924 dtls_FinishedTimerCb(sslSocket *ss) | |
925 { | |
926 ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE); | |
927 } | |
928 | |
929 /* Cancel the Finished hold-down timer and destroy the | |
930 * pending cipher spec. Note that this means that | |
931 * successive rehandshakes will fail if the Finished is | |
932 * lost. | |
933 * | |
934 * XXX OK for now. Figure out how to handle the combination | |
935 * of Finished lost and rehandshake | |
936 */ | |
937 void | |
938 dtls_RehandshakeCleanup(sslSocket *ss) | |
939 { | |
940 dtls_CancelTimer(ss); | |
941 ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE); | |
942 } | |
943 | |
944 /* Set the MTU to the next step less than or equal to the | |
945 * advertised value. Also used to downgrade the MTU by | |
946 * doing dtls_SetMTU(ss, biggest packet set). | |
947 * | |
948 * Passing 0 means set this to the largest MTU known | |
949 * (effectively resetting the PMTU backoff value). | |
950 * | |
951 * Called by: | |
952 * ssl3_InitState() | |
953 * dtls_RetransmitTimerExpiredCb() | |
954 */ | |
955 void | |
956 dtls_SetMTU(sslSocket *ss, PRUint16 advertised) | |
957 { | |
958 int i; | |
959 | |
960 if (advertised == 0) { | |
961 ss->ssl3.mtu = COMMON_MTU_VALUES[0]; | |
962 SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu)); | |
963 return; | |
964 } | |
965 | |
966 for (i = 0; i < PR_ARRAY_SIZE(COMMON_MTU_VALUES); i++) { | |
967 if (COMMON_MTU_VALUES[i] <= advertised) { | |
968 ss->ssl3.mtu = COMMON_MTU_VALUES[i]; | |
969 SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu)); | |
970 return; | |
971 } | |
972 } | |
973 | |
974 /* Fallback */ | |
975 ss->ssl3.mtu = COMMON_MTU_VALUES[PR_ARRAY_SIZE(COMMON_MTU_VALUES)-1]; | |
976 SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu)); | |
977 } | |
978 | |
979 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a | |
980 * DTLS hello_verify_request | |
981 * Caller must hold Handshake and RecvBuf locks. | |
982 */ | |
983 SECStatus | |
984 dtls_HandleHelloVerifyRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) | |
985 { | |
986 int errCode = SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST; | |
987 SECStatus rv; | |
988 PRInt32 temp; | |
989 SECItem cookie = {siBuffer, NULL, 0}; | |
990 SSL3AlertDescription desc = illegal_parameter; | |
991 | |
992 SSL_TRC(3, ("%d: SSL3[%d]: handle hello_verify_request handshake", | |
993 SSL_GETPID(), ss->fd)); | |
994 PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); | |
995 PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); | |
996 | |
997 if (ss->ssl3.hs.ws != wait_server_hello) { | |
998 errCode = SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST; | |
999 desc = unexpected_message; | |
1000 goto alert_loser; | |
1001 } | |
1002 | |
1003 /* The version */ | |
1004 temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); | |
1005 if (temp < 0) { | |
1006 goto loser; /* alert has been sent */ | |
1007 } | |
1008 | |
1009 if (temp != SSL_LIBRARY_VERSION_DTLS_1_0_WIRE) { | |
1010 /* Note: this will need adjustment for DTLS 1.2 per Section 4.2.1 */ | |
1011 goto alert_loser; | |
1012 } | |
1013 | |
1014 /* The cookie */ | |
1015 rv = ssl3_ConsumeHandshakeVariable(ss, &cookie, 1, &b, &length); | |
1016 if (rv != SECSuccess) { | |
1017 goto loser; /* alert has been sent */ | |
1018 } | |
1019 if (cookie.len > DTLS_COOKIE_BYTES) { | |
1020 desc = decode_error; | |
1021 goto alert_loser; /* malformed. */ | |
1022 } | |
1023 | |
1024 PORT_Memcpy(ss->ssl3.hs.cookie, cookie.data, cookie.len); | |
1025 ss->ssl3.hs.cookieLen = cookie.len; | |
1026 | |
1027 | |
1028 ssl_GetXmitBufLock(ss); /*******************************/ | |
1029 | |
1030 /* Now re-send the client hello */ | |
1031 rv = ssl3_SendClientHello(ss, PR_TRUE); | |
1032 | |
1033 ssl_ReleaseXmitBufLock(ss); /*******************************/ | |
1034 | |
1035 if (rv == SECSuccess) | |
1036 return rv; | |
1037 | |
1038 alert_loser: | |
1039 (void)SSL3_SendAlert(ss, alert_fatal, desc); | |
1040 | |
1041 loser: | |
1042 errCode = ssl_MapLowLevelError(errCode); | |
1043 return SECFailure; | |
1044 } | |
1045 | |
1046 /* Initialize the DTLS anti-replay window | |
1047 * | |
1048 * Called from: | |
1049 * ssl3_SetupPendingCipherSpec() | |
1050 * ssl3_InitCipherSpec() | |
1051 */ | |
1052 void | |
1053 dtls_InitRecvdRecords(DTLSRecvdRecords *records) | |
1054 { | |
1055 PORT_Memset(records->data, 0, sizeof(records->data)); | |
1056 records->left = 0; | |
1057 records->right = DTLS_RECVD_RECORDS_WINDOW - 1; | |
1058 } | |
1059 | |
1060 /* | |
1061 * Has this DTLS record been received? Return values are: | |
1062 * -1 -- out of range to the left | |
1063 * 0 -- not received yet | |
1064 * 1 -- replay | |
1065 * | |
1066 * Called from: dtls_HandleRecord() | |
1067 */ | |
1068 int | |
1069 dtls_RecordGetRecvd(DTLSRecvdRecords *records, PRUint64 seq) | |
1070 { | |
1071 PRUint64 offset; | |
1072 | |
1073 /* Out of range to the left */ | |
1074 if (seq < records->left) { | |
1075 return -1; | |
1076 } | |
1077 | |
1078 /* Out of range to the right; since we advance the window on | |
1079 * receipt, that means that this packet has not been received | |
1080 * yet */ | |
1081 if (seq > records->right) | |
1082 return 0; | |
1083 | |
1084 offset = seq % DTLS_RECVD_RECORDS_WINDOW; | |
1085 | |
1086 return !!(records->data[offset / 8] & (1 << (offset % 8))); | |
1087 } | |
1088 | |
1089 /* Update the DTLS anti-replay window | |
1090 * | |
1091 * Called from ssl3_HandleRecord() | |
1092 */ | |
1093 void | |
1094 dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq) | |
1095 { | |
1096 PRUint64 offset; | |
1097 | |
1098 if (seq < records->left) | |
1099 return; | |
1100 | |
1101 if (seq > records->right) { | |
1102 PRUint64 new_left; | |
1103 PRUint64 new_right; | |
1104 PRUint64 right; | |
1105 | |
1106 /* Slide to the right; this is the tricky part | |
1107 * | |
1108 * 1. new_top is set to have room for seq, on the | |
1109 * next byte boundary by setting the right 8 | |
1110 * bits of seq | |
1111 * 2. new_left is set to compensate. | |
1112 * 3. Zero all bits between top and new_top. Since | |
1113 * this is a ring, this zeroes everything as-yet | |
1114 * unseen. Because we always operate on byte | |
1115 * boundaries, we can zero one byte at a time | |
1116 */ | |
1117 new_right = seq | 0x07; | |
1118 new_left = (new_right - DTLS_RECVD_RECORDS_WINDOW) + 1; | |
1119 | |
1120 for (right = records->right + 8; right <= new_right; right += 8) { | |
1121 offset = right % DTLS_RECVD_RECORDS_WINDOW; | |
1122 records->data[offset / 8] = 0; | |
1123 } | |
1124 | |
1125 records->right = new_right; | |
1126 records->left = new_left; | |
1127 } | |
1128 | |
1129 offset = seq % DTLS_RECVD_RECORDS_WINDOW; | |
1130 | |
1131 records->data[offset / 8] |= (1 << (offset % 8)); | |
1132 } | |
1133 | |
1134 SECStatus | |
1135 DTLS_GetTimeout(PRFileDesc *socket, PRIntervalTime *timeout) | |
1136 { | |
1137 sslSocket * ss = NULL; | |
1138 PRIntervalTime elapsed; | |
1139 PRIntervalTime desired; | |
1140 | |
1141 ss = ssl_FindSocket(socket); | |
1142 | |
1143 if (!ss) | |
1144 return SECFailure; | |
1145 | |
1146 if (!IS_DTLS(ss)) | |
1147 return SECFailure; | |
1148 | |
1149 if (!ss->ssl3.hs.rtTimerCb) | |
1150 return SECFailure; | |
1151 | |
1152 elapsed = PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted; | |
1153 desired = PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs); | |
1154 if (elapsed > desired) { | |
1155 /* Timer expired */ | |
1156 *timeout = PR_INTERVAL_NO_WAIT; | |
1157 } else { | |
1158 *timeout = desired - elapsed; | |
1159 } | |
1160 | |
1161 return SECSuccess; | |
1162 } | |
OLD | NEW |