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 /* TODO(ekr@rtfm.com): 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)); |
| 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 * TODO(ekr@rtfm.com): OK for now. Maybe do something smarter |
| 361 * at some point? |
| 362 */ |
| 363 } else { |
| 364 /* Case 1 |
| 365 * |
| 366 * Buffer the fragment for reassembly |
| 367 */ |
| 368 /* Make room for the message */ |
| 369 if (ss->ssl3.hs.recvdHighWater == -1) { |
| 370 PRUint32 map_length = OFFSET_BYTE(message_length) + 1; |
| 371 |
| 372 rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, message_length); |
| 373 if (rv != SECSuccess) |
| 374 break; |
| 375 /* Make room for the fragment map */ |
| 376 rv = sslBuffer_Grow(&ss->ssl3.hs.recvdFragments, |
| 377 map_length); |
| 378 if (rv != SECSuccess) |
| 379 break; |
| 380 |
| 381 /* Reset the reassembly map */ |
| 382 ss->ssl3.hs.recvdHighWater = 0; |
| 383 PORT_Memset(ss->ssl3.hs.recvdFragments.buf, 0, |
| 384 ss->ssl3.hs.recvdFragments.space); |
| 385 ss->ssl3.hs.msg_type = (SSL3HandshakeType)type; |
| 386 ss->ssl3.hs.msg_len = message_length; |
| 387 } |
| 388 |
| 389 /* If we have a message length mismatch, abandon the reassembly |
| 390 * in progress and hope that the next retransmit will give us |
| 391 * something sane |
| 392 */ |
| 393 if (message_length != ss->ssl3.hs.msg_len) { |
| 394 ss->ssl3.hs.recvdHighWater = -1; |
| 395 PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); |
| 396 rv = SECFailure; |
| 397 break; |
| 398 } |
| 399 |
| 400 /* Now copy this fragment into the buffer */ |
| 401 PORT_Assert((fragment_offset + fragment_length) <= |
| 402 ss->ssl3.hs.msg_body.space); |
| 403 PORT_Memcpy(ss->ssl3.hs.msg_body.buf + fragment_offset, |
| 404 buf.buf, fragment_length); |
| 405 |
| 406 /* This logic is a bit tricky. We have two values for |
| 407 * reassembly state: |
| 408 * |
| 409 * - recvdHighWater contains the highest contiguous number of |
| 410 * bytes received |
| 411 * - recvdFragments contains a bitmask of packets received |
| 412 * above recvdHighWater |
| 413 * |
| 414 * This avoids having to fill in the bitmask in the common |
| 415 * case of adjacent fragments received in sequence |
| 416 */ |
| 417 if (fragment_offset <= ss->ssl3.hs.recvdHighWater) { |
| 418 /* Either this is the adjacent fragment or an overlapping |
| 419 * fragment */ |
| 420 ss->ssl3.hs.recvdHighWater = fragment_offset + |
| 421 fragment_length; |
| 422 } else { |
| 423 for (offset = fragment_offset; |
| 424 offset < fragment_offset + fragment_length; |
| 425 offset++) { |
| 426 ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] |= |
| 427 OFFSET_MASK(offset); |
| 428 } |
| 429 } |
| 430 |
| 431 /* Now figure out the new high water mark if appropriate */ |
| 432 for (offset = ss->ssl3.hs.recvdHighWater; |
| 433 offset < ss->ssl3.hs.msg_len; offset++) { |
| 434 /* Note that this loop is not efficient, since it counts |
| 435 * bit by bit. If we have a lot of out-of-order packets, |
| 436 * we should optimize this */ |
| 437 if (ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] & |
| 438 OFFSET_MASK(offset)) { |
| 439 ss->ssl3.hs.recvdHighWater++; |
| 440 } else { |
| 441 break; |
| 442 } |
| 443 } |
| 444 |
| 445 /* If we have all the bytes, then we are good to go */ |
| 446 if (ss->ssl3.hs.recvdHighWater == ss->ssl3.hs.msg_len) { |
| 447 ss->ssl3.hs.recvdHighWater = -1; |
| 448 |
| 449 rv = ssl3_HandleHandshakeMessage(ss, |
| 450 ss->ssl3.hs.msg_body.buf, |
| 451 ss->ssl3.hs.msg_len); |
| 452 if (rv == SECFailure) |
| 453 break; /* Skip rest of record */ |
| 454 |
| 455 /* At this point we are advancing our state machine, so |
| 456 * we can free our last flight of messages */ |
| 457 dtls_FreeHandshakeMessages(ss->ssl3.hs.lastMessageFlight); |
| 458 dtls_CancelTimer(ss); |
| 459 |
| 460 /* If there have been no retries this time, reset the |
| 461 * timer value to the default per Section 4.2.4.1 */ |
| 462 if (ss->ssl3.hs.rtRetries == 0) { |
| 463 ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS; |
| 464 } |
| 465 } |
| 466 } |
| 467 } |
| 468 |
| 469 buf.buf += fragment_length; |
| 470 buf.len -= fragment_length; |
| 471 } |
| 472 |
| 473 origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */ |
| 474 |
| 475 /* TODO(ekr@rtfm.com): OK for now. In future handle rv == SECWouldBlock |
| 476 * safely in order to deal with asynchronous certificate verification */ |
| 477 return rv; |
| 478 } |
| 479 |
| 480 /* Enqueue a message (either handshake or CCS) |
| 481 * |
| 482 * Called from: |
| 483 * dtls_StageHandshakeMessage() |
| 484 * ssl3_SendChangeCipherSpecs() |
| 485 */ |
| 486 SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type, |
| 487 const SSL3Opaque *pIn, PRInt32 nIn) |
| 488 { |
| 489 SECStatus rv = SECSuccess; |
| 490 DTLSQueuedMessage *msg = NULL; |
| 491 |
| 492 PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
| 493 PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); |
| 494 |
| 495 msg = dtls_AllocQueuedMessage(ss->ssl3.cwSpec->epoch, type, pIn, nIn); |
| 496 |
| 497 if (!msg) { |
| 498 PORT_SetError(SEC_ERROR_NO_MEMORY); |
| 499 rv = SECFailure; |
| 500 } else { |
| 501 PR_APPEND_LINK(&msg->link, ss->ssl3.hs.lastMessageFlight); |
| 502 } |
| 503 |
| 504 return rv; |
| 505 } |
| 506 |
| 507 /* Add DTLS handshake message to the pending queue |
| 508 * Empty the sendBuf buffer. |
| 509 * This function returns SECSuccess or SECFailure, never SECWouldBlock. |
| 510 * Always set sendBuf.len to 0, even when returning SECFailure. |
| 511 * |
| 512 * Called from: |
| 513 * ssl3_AppendHandshakeHeader() |
| 514 * dtls_FlushHandshake() |
| 515 */ |
| 516 SECStatus |
| 517 dtls_StageHandshakeMessage(sslSocket *ss) |
| 518 { |
| 519 SECStatus rv = SECSuccess; |
| 520 |
| 521 PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
| 522 PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); |
| 523 |
| 524 /* This function is sometimes called when no data is actually to |
| 525 * be staged, so just return SECSuccess. */ |
| 526 if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len) |
| 527 return rv; |
| 528 |
| 529 rv = dtls_QueueMessage(ss, content_handshake, |
| 530 ss->sec.ci.sendBuf.buf, ss->sec.ci.sendBuf.len); |
| 531 |
| 532 /* Whether we succeeded or failed, toss the old handshake data. */ |
| 533 ss->sec.ci.sendBuf.len = 0; |
| 534 return rv; |
| 535 } |
| 536 |
| 537 /* Enqueue the handshake message in sendBuf (if any) and then |
| 538 * transmit the resulting flight of handshake messages. |
| 539 * |
| 540 * Called from: |
| 541 * ssl3_FlushHandshake() |
| 542 */ |
| 543 SECStatus |
| 544 dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags) |
| 545 { |
| 546 SECStatus rv = SECSuccess; |
| 547 |
| 548 PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
| 549 PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); |
| 550 |
| 551 rv = dtls_StageHandshakeMessage(ss); |
| 552 if (rv != SECSuccess) |
| 553 return rv; |
| 554 |
| 555 if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { |
| 556 rv = dtls_TransmitMessageFlight(ss); |
| 557 if (rv != SECSuccess) |
| 558 return rv; |
| 559 |
| 560 if (!(flags & ssl_SEND_FLAG_NO_RETRANSMIT)) { |
| 561 ss->ssl3.hs.rtRetries = 0; |
| 562 rv = dtls_StartTimer(ss, dtls_RetransmitTimerExpiredCb); |
| 563 } |
| 564 } |
| 565 |
| 566 return rv; |
| 567 } |
| 568 |
| 569 /* The callback for when the retransmit timer expires |
| 570 * |
| 571 * Called from: |
| 572 * dtls_CheckTimer() |
| 573 * dtls_HandleHandshake() |
| 574 */ |
| 575 static void |
| 576 dtls_RetransmitTimerExpiredCb(sslSocket *ss) |
| 577 { |
| 578 SECStatus rv = SECFailure; |
| 579 |
| 580 ss->ssl3.hs.rtRetries++; |
| 581 |
| 582 if (!(ss->ssl3.hs.rtRetries % 3)) { |
| 583 /* If one of the messages was potentially greater than > MTU, |
| 584 * then downgrade. Do this every time we have retransmitted a |
| 585 * message twice, per RFC 6347 Sec. 4.1.1 */ |
| 586 dtls_SetMTU(ss, ss->ssl3.hs.maxMessageSent - 1); |
| 587 } |
| 588 |
| 589 rv = dtls_TransmitMessageFlight(ss); |
| 590 if (rv == SECSuccess) { |
| 591 |
| 592 /* Re-arm the timer */ |
| 593 rv = dtls_RestartTimer(ss, PR_TRUE, dtls_RetransmitTimerExpiredCb); |
| 594 } |
| 595 |
| 596 if (rv == SECFailure) { |
| 597 /* TODO(ekr@rtfm.com): OK for now. In future maybe signal the stack |
| 598 * that we couldn't transmit. For now, let the read handle any real |
| 599 * network errors */ |
| 600 } |
| 601 } |
| 602 |
| 603 /* Transmit a flight of handshake messages, stuffing them |
| 604 * into as few records as seems reasonable |
| 605 * |
| 606 * Called from: |
| 607 * dtls_FlushHandshake() |
| 608 * dtls_RetransmitTimerExpiredCb() |
| 609 */ |
| 610 static SECStatus |
| 611 dtls_TransmitMessageFlight(sslSocket *ss) |
| 612 { |
| 613 SECStatus rv = SECSuccess; |
| 614 PRCList *msg_p; |
| 615 PRUint16 room_left = ss->ssl3.mtu; |
| 616 PRInt32 sent; |
| 617 |
| 618 ssl_GetXmitBufLock(ss); |
| 619 ssl_GetSpecReadLock(ss); |
| 620 |
| 621 /* DTLS does not buffer its handshake messages in |
| 622 * ss->pendingBuf, but rather in the lastMessageFlight |
| 623 * structure. This is just a sanity check that |
| 624 * some programming error hasn't inadvertantly |
| 625 * stuffed something in ss->pendingBuf |
| 626 */ |
| 627 PORT_Assert(!ss->pendingBuf.len); |
| 628 for (msg_p = PR_LIST_HEAD(ss->ssl3.hs.lastMessageFlight); |
| 629 msg_p != ss->ssl3.hs.lastMessageFlight; |
| 630 msg_p = PR_NEXT_LINK(msg_p)) { |
| 631 DTLSQueuedMessage *msg = (DTLSQueuedMessage *)msg_p; |
| 632 |
| 633 /* The logic here is: |
| 634 * |
| 635 * 1. If this is a message that will not fit into the remaining |
| 636 * space, then flush. |
| 637 * 2. If the message will now fit into the remaining space, |
| 638 * encrypt, buffer, and loop. |
| 639 * 3. If the message will not fit, then fragment. |
| 640 * |
| 641 * At the end of the function, flush. |
| 642 */ |
| 643 if ((msg->len + SSL3_BUFFER_FUDGE) > room_left) { |
| 644 /* The message will not fit into the remaining space, so flush */ |
| 645 rv = dtls_SendSavedWriteData(ss); |
| 646 if (rv != SECSuccess) |
| 647 break; |
| 648 |
| 649 room_left = ss->ssl3.mtu; |
| 650 } |
| 651 |
| 652 if ((msg->len + SSL3_BUFFER_FUDGE) <= room_left) { |
| 653 /* The message will fit, so encrypt and then continue with the |
| 654 * next packet */ |
| 655 sent = ssl3_SendRecord(ss, msg->epoch, msg->type, |
| 656 msg->data, msg->len, |
| 657 ssl_SEND_FLAG_FORCE_INTO_BUFFER | |
| 658 ssl_SEND_FLAG_USE_EPOCH); |
| 659 if (sent != msg->len) { |
| 660 rv = SECFailure; |
| 661 if (sent != -1) { |
| 662 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 663 } |
| 664 break; |
| 665 } |
| 666 |
| 667 room_left = ss->ssl3.mtu - ss->pendingBuf.len; |
| 668 } else { |
| 669 /* The message will not fit, so fragment. |
| 670 * |
| 671 * TODO(ekr@rtfm.com): OK for now. Arrange to coalesce the |
| 672 * last fragment of this message with the next message |
| 673 * if possible. That would be more efficient. |
| 674 */ |
| 675 PRUint32 fragment_offset = 0; |
| 676 unsigned char fragment[DTLS_MAX_MTU]; /* >= than largest |
| 677 * plausible MTU */ |
| 678 |
| 679 /* Assert that we have already flushed */ |
| 680 PORT_Assert(room_left == ss->ssl3.mtu); |
| 681 |
| 682 /* Case 3: We now need to fragment this message |
| 683 * DTLS only supports fragmenting handshaking messages */ |
| 684 PORT_Assert(msg->type == content_handshake); |
| 685 |
| 686 /* The headers consume 12 bytes so the smalles possible |
| 687 * message (i.e., an empty one) is 12 bytes |
| 688 */ |
| 689 PORT_Assert(msg->len >= 12); |
| 690 |
| 691 while ((fragment_offset + 12) < msg->len) { |
| 692 PRUint32 fragment_len; |
| 693 const unsigned char *content = msg->data + 12; |
| 694 PRUint32 content_len = msg->len - 12; |
| 695 |
| 696 /* The reason we use 8 here is that that's the length of |
| 697 * the new DTLS data that we add to the header */ |
| 698 fragment_len = PR_MIN(room_left - (SSL3_BUFFER_FUDGE + 8), |
| 699 content_len - fragment_offset); |
| 700 PORT_Assert(fragment_len < DTLS_MAX_MTU - 12); |
| 701 /* Make totally sure that we are within the buffer. |
| 702 * Note that the only way that fragment len could get |
| 703 * adjusted here is if |
| 704 * |
| 705 * (a) we are in release mode so the PORT_Assert is compiled out |
| 706 * (b) either the MTU table is inconsistent with DTLS_MAX_MTU |
| 707 * or ss->ssl3.mtu has become corrupt. |
| 708 */ |
| 709 fragment_len = PR_MIN(fragment_len, DTLS_MAX_MTU - 12); |
| 710 |
| 711 /* Construct an appropriate-sized fragment */ |
| 712 /* Type, length, sequence */ |
| 713 PORT_Memcpy(fragment, msg->data, 6); |
| 714 |
| 715 /* Offset */ |
| 716 fragment[6] = (fragment_offset >> 16) & 0xff; |
| 717 fragment[7] = (fragment_offset >> 8) & 0xff; |
| 718 fragment[8] = (fragment_offset) & 0xff; |
| 719 |
| 720 /* Fragment length */ |
| 721 fragment[9] = (fragment_len >> 16) & 0xff; |
| 722 fragment[10] = (fragment_len >> 8) & 0xff; |
| 723 fragment[11] = (fragment_len) & 0xff; |
| 724 |
| 725 PORT_Memcpy(fragment + 12, content + fragment_offset, |
| 726 fragment_len); |
| 727 |
| 728 /* |
| 729 * Send the record. We do this in two stages |
| 730 * 1. Encrypt |
| 731 */ |
| 732 sent = ssl3_SendRecord(ss, msg->epoch, msg->type, |
| 733 fragment, fragment_len + 12, |
| 734 ssl_SEND_FLAG_FORCE_INTO_BUFFER | |
| 735 ssl_SEND_FLAG_USE_EPOCH); |
| 736 if (sent != (fragment_len + 12)) { |
| 737 rv = SECFailure; |
| 738 if (sent != -1) { |
| 739 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 740 } |
| 741 break; |
| 742 } |
| 743 |
| 744 /* 2. Flush */ |
| 745 rv = dtls_SendSavedWriteData(ss); |
| 746 if (rv != SECSuccess) |
| 747 break; |
| 748 |
| 749 fragment_offset += fragment_len; |
| 750 } |
| 751 } |
| 752 } |
| 753 |
| 754 /* Finally, we need to flush */ |
| 755 if (rv == SECSuccess) |
| 756 rv = dtls_SendSavedWriteData(ss); |
| 757 |
| 758 /* Give up the locks */ |
| 759 ssl_ReleaseSpecReadLock(ss); |
| 760 ssl_ReleaseXmitBufLock(ss); |
| 761 |
| 762 return rv; |
| 763 } |
| 764 |
| 765 /* Flush the data in the pendingBuf and update the max message sent |
| 766 * so we can adjust the MTU estimate if we need to. |
| 767 * Wrapper for ssl_SendSavedWriteData. |
| 768 * |
| 769 * Called from dtls_TransmitMessageFlight() |
| 770 */ |
| 771 static |
| 772 SECStatus dtls_SendSavedWriteData(sslSocket *ss) |
| 773 { |
| 774 PRInt32 sent; |
| 775 |
| 776 sent = ssl_SendSavedWriteData(ss); |
| 777 if (sent < 0) |
| 778 return SECFailure; |
| 779 |
| 780 /* We should always have complete writes b/c datagram sockets |
| 781 * don't really block */ |
| 782 if (ss->pendingBuf.len > 0) { |
| 783 ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); |
| 784 return SECFailure; |
| 785 } |
| 786 |
| 787 /* Update the largest message sent so we can adjust the MTU |
| 788 * estimate if necessary */ |
| 789 if (sent > ss->ssl3.hs.maxMessageSent) |
| 790 ss->ssl3.hs.maxMessageSent = sent; |
| 791 |
| 792 return SECSuccess; |
| 793 } |
| 794 |
| 795 /* Compress, MAC, encrypt a DTLS record. Allows specification of |
| 796 * the epoch using epoch value. If use_epoch is PR_TRUE then |
| 797 * we use the provided epoch. If use_epoch is PR_FALSE then |
| 798 * whatever the current value is in effect is used. |
| 799 * |
| 800 * Called from ssl3_SendRecord() |
| 801 */ |
| 802 SECStatus |
| 803 dtls_CompressMACEncryptRecord(sslSocket * ss, |
| 804 DTLSEpoch epoch, |
| 805 PRBool use_epoch, |
| 806 SSL3ContentType type, |
| 807 const SSL3Opaque * pIn, |
| 808 PRUint32 contentLen, |
| 809 sslBuffer * wrBuf) |
| 810 { |
| 811 SECStatus rv = SECFailure; |
| 812 ssl3CipherSpec * cwSpec; |
| 813 |
| 814 ssl_GetSpecReadLock(ss); /********************************/ |
| 815 |
| 816 /* The reason for this switch-hitting code is that we might have |
| 817 * a flight of records spanning an epoch boundary, e.g., |
| 818 * |
| 819 * ClientKeyExchange (epoch = 0) |
| 820 * ChangeCipherSpec (epoch = 0) |
| 821 * Finished (epoch = 1) |
| 822 * |
| 823 * Thus, each record needs a different cipher spec. The information |
| 824 * about which epoch to use is carried with the record. |
| 825 */ |
| 826 if (use_epoch) { |
| 827 if (ss->ssl3.cwSpec->epoch == epoch) |
| 828 cwSpec = ss->ssl3.cwSpec; |
| 829 else if (ss->ssl3.pwSpec->epoch == epoch) |
| 830 cwSpec = ss->ssl3.pwSpec; |
| 831 else |
| 832 cwSpec = NULL; |
| 833 } else { |
| 834 cwSpec = ss->ssl3.cwSpec; |
| 835 } |
| 836 |
| 837 if (cwSpec) { |
| 838 rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, PR_TRUE, |
| 839 type, pIn, contentLen, wrBuf); |
| 840 } else { |
| 841 PR_NOT_REACHED("Couldn't find a cipher spec matching epoch"); |
| 842 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); |
| 843 } |
| 844 ssl_ReleaseSpecReadLock(ss); /************************************/ |
| 845 |
| 846 return rv; |
| 847 } |
| 848 |
| 849 /* Start a timer |
| 850 * |
| 851 * Called from: |
| 852 * dtls_HandleHandshake() |
| 853 * dtls_FlushHAndshake() |
| 854 * dtls_RestartTimer() |
| 855 */ |
| 856 SECStatus |
| 857 dtls_StartTimer(sslSocket *ss, DTLSTimerCb cb) |
| 858 { |
| 859 PORT_Assert(ss->ssl3.hs.rtTimerCb == NULL); |
| 860 |
| 861 ss->ssl3.hs.rtTimerStarted = PR_IntervalNow(); |
| 862 ss->ssl3.hs.rtTimerCb = cb; |
| 863 |
| 864 return SECSuccess; |
| 865 } |
| 866 |
| 867 /* Restart a timer with optional backoff |
| 868 * |
| 869 * Called from dtls_RetransmitTimerExpiredCb() |
| 870 */ |
| 871 SECStatus |
| 872 dtls_RestartTimer(sslSocket *ss, PRBool backoff, DTLSTimerCb cb) |
| 873 { |
| 874 if (backoff) { |
| 875 ss->ssl3.hs.rtTimeoutMs *= 2; |
| 876 if (ss->ssl3.hs.rtTimeoutMs > MAX_DTLS_TIMEOUT_MS) |
| 877 ss->ssl3.hs.rtTimeoutMs = MAX_DTLS_TIMEOUT_MS; |
| 878 } |
| 879 |
| 880 return dtls_StartTimer(ss, cb); |
| 881 } |
| 882 |
| 883 /* Cancel a pending timer |
| 884 * |
| 885 * Called from: |
| 886 * dtls_HandleHandshake() |
| 887 * dtls_CheckTimer() |
| 888 */ |
| 889 void |
| 890 dtls_CancelTimer(sslSocket *ss) |
| 891 { |
| 892 PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); |
| 893 |
| 894 ss->ssl3.hs.rtTimerCb = NULL; |
| 895 } |
| 896 |
| 897 /* Check the pending timer and fire the callback if it expired |
| 898 * |
| 899 * Called from ssl3_GatherCompleteHandshake() |
| 900 */ |
| 901 void |
| 902 dtls_CheckTimer(sslSocket *ss) |
| 903 { |
| 904 if (!ss->ssl3.hs.rtTimerCb) |
| 905 return; |
| 906 |
| 907 if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) > |
| 908 PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs)) { |
| 909 /* Timer has expired */ |
| 910 DTLSTimerCb cb = ss->ssl3.hs.rtTimerCb; |
| 911 |
| 912 /* Cancel the timer so that we can call the CB safely */ |
| 913 dtls_CancelTimer(ss); |
| 914 |
| 915 /* Now call the CB */ |
| 916 cb(ss); |
| 917 } |
| 918 } |
| 919 |
| 920 /* The callback to fire when the holddown timer for the Finished |
| 921 * message expires and we can delete it |
| 922 * |
| 923 * Called from dtls_CheckTimer() |
| 924 */ |
| 925 void |
| 926 dtls_FinishedTimerCb(sslSocket *ss) |
| 927 { |
| 928 ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE); |
| 929 } |
| 930 |
| 931 /* Cancel the Finished hold-down timer and destroy the |
| 932 * pending cipher spec. Note that this means that |
| 933 * successive rehandshakes will fail if the Finished is |
| 934 * lost. |
| 935 * |
| 936 * TODO(ekr@rtfm.com): OK for now. Figure out how to |
| 937 * handle the combination of Finished lost and rehandshake |
| 938 */ |
| 939 void |
| 940 dtls_RehandshakeCleanup(sslSocket *ss) |
| 941 { |
| 942 dtls_CancelTimer(ss); |
| 943 ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE); |
| 944 } |
| 945 |
| 946 /* Set the MTU to the next step less than or equal to the |
| 947 * advertised value. Also used to downgrade the MTU by |
| 948 * doing dtls_SetMTU(ss, biggest packet set). |
| 949 * |
| 950 * Passing 0 means set this to the largest MTU known |
| 951 * (effectively resetting the PMTU backoff value). |
| 952 * |
| 953 * Called by: |
| 954 * ssl3_InitState() |
| 955 * dtls_RetransmitTimerExpiredCb() |
| 956 */ |
| 957 void |
| 958 dtls_SetMTU(sslSocket *ss, PRUint16 advertised) |
| 959 { |
| 960 int i; |
| 961 |
| 962 if (advertised == 0) { |
| 963 ss->ssl3.mtu = COMMON_MTU_VALUES[0]; |
| 964 SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu)); |
| 965 return; |
| 966 } |
| 967 |
| 968 for (i = 0; i < PR_ARRAY_SIZE(COMMON_MTU_VALUES); i++) { |
| 969 if (COMMON_MTU_VALUES[i] <= advertised) { |
| 970 ss->ssl3.mtu = COMMON_MTU_VALUES[i]; |
| 971 SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu)); |
| 972 return; |
| 973 } |
| 974 } |
| 975 |
| 976 /* Fallback */ |
| 977 ss->ssl3.mtu = COMMON_MTU_VALUES[PR_ARRAY_SIZE(COMMON_MTU_VALUES)-1]; |
| 978 SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu)); |
| 979 } |
| 980 |
| 981 /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a |
| 982 * DTLS hello_verify_request |
| 983 * Caller must hold Handshake and RecvBuf locks. |
| 984 */ |
| 985 SECStatus |
| 986 dtls_HandleHelloVerifyRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) |
| 987 { |
| 988 int errCode = SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST; |
| 989 SECStatus rv; |
| 990 PRInt32 temp; |
| 991 SECItem cookie = {siBuffer, NULL, 0}; |
| 992 SSL3AlertDescription desc = illegal_parameter; |
| 993 |
| 994 SSL_TRC(3, ("%d: SSL3[%d]: handle hello_verify_request handshake", |
| 995 SSL_GETPID(), ss->fd)); |
| 996 PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); |
| 997 PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
| 998 |
| 999 if (ss->ssl3.hs.ws != wait_server_hello) { |
| 1000 errCode = SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST; |
| 1001 desc = unexpected_message; |
| 1002 goto alert_loser; |
| 1003 } |
| 1004 |
| 1005 /* The version */ |
| 1006 temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); |
| 1007 if (temp < 0) { |
| 1008 goto loser; /* alert has been sent */ |
| 1009 } |
| 1010 |
| 1011 if (temp != SSL_LIBRARY_VERSION_DTLS_1_0_WIRE) { |
| 1012 /* Note: this will need adjustment for DTLS 1.2 per Section 4.2.1 */ |
| 1013 goto alert_loser; |
| 1014 } |
| 1015 |
| 1016 /* The cookie */ |
| 1017 rv = ssl3_ConsumeHandshakeVariable(ss, &cookie, 1, &b, &length); |
| 1018 if (rv != SECSuccess) { |
| 1019 goto loser; /* alert has been sent */ |
| 1020 } |
| 1021 if (cookie.len > DTLS_COOKIE_BYTES) { |
| 1022 desc = decode_error; |
| 1023 goto alert_loser; /* malformed. */ |
| 1024 } |
| 1025 |
| 1026 PORT_Memcpy(ss->ssl3.hs.cookie, cookie.data, cookie.len); |
| 1027 ss->ssl3.hs.cookieLen = cookie.len; |
| 1028 |
| 1029 |
| 1030 ssl_GetXmitBufLock(ss); /*******************************/ |
| 1031 |
| 1032 /* Now re-send the client hello */ |
| 1033 rv = ssl3_SendClientHello(ss, PR_TRUE); |
| 1034 |
| 1035 ssl_ReleaseXmitBufLock(ss); /*******************************/ |
| 1036 |
| 1037 if (rv == SECSuccess) |
| 1038 return rv; |
| 1039 |
| 1040 alert_loser: |
| 1041 (void)SSL3_SendAlert(ss, alert_fatal, desc); |
| 1042 |
| 1043 loser: |
| 1044 errCode = ssl_MapLowLevelError(errCode); |
| 1045 return SECFailure; |
| 1046 } |
| 1047 |
| 1048 /* Initialize the DTLS anti-replay window |
| 1049 * |
| 1050 * Called from: |
| 1051 * ssl3_SetupPendingCipherSpec() |
| 1052 * ssl3_InitCipherSpec() |
| 1053 */ |
| 1054 void |
| 1055 dtls_InitRecvdRecords(DTLSRecvdRecords *records) |
| 1056 { |
| 1057 PORT_Memset(records->data, 0, sizeof(records->data)); |
| 1058 records->left = 0; |
| 1059 records->right = DTLS_RECVD_RECORDS_WINDOW - 1; |
| 1060 } |
| 1061 |
| 1062 /* |
| 1063 * Has this DTLS record been received? Return values are: |
| 1064 * -1 -- out of range to the left |
| 1065 * 0 -- not received yet |
| 1066 * 1 -- replay |
| 1067 * |
| 1068 * Called from: dtls_HandleRecord() |
| 1069 */ |
| 1070 int |
| 1071 dtls_RecordGetRecvd(DTLSRecvdRecords *records, PRUint64 seq) |
| 1072 { |
| 1073 PRUint64 offset; |
| 1074 |
| 1075 /* Out of range to the left */ |
| 1076 if (seq < records->left) { |
| 1077 return -1; |
| 1078 } |
| 1079 |
| 1080 /* Out of range to the right; since we advance the window on |
| 1081 * receipt, that means that this packet has not been received |
| 1082 * yet */ |
| 1083 if (seq > records->right) |
| 1084 return 0; |
| 1085 |
| 1086 offset = seq % DTLS_RECVD_RECORDS_WINDOW; |
| 1087 |
| 1088 return !!(records->data[offset / 8] & (1 << (offset % 8))); |
| 1089 } |
| 1090 |
| 1091 /* Update the DTLS anti-replay window |
| 1092 * |
| 1093 * Called from ssl3_HandleRecord() |
| 1094 */ |
| 1095 void |
| 1096 dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq) |
| 1097 { |
| 1098 PRUint64 offset; |
| 1099 |
| 1100 if (seq < records->left) |
| 1101 return; |
| 1102 |
| 1103 if (seq > records->right) { |
| 1104 PRUint64 new_left; |
| 1105 PRUint64 new_right; |
| 1106 PRUint64 right; |
| 1107 |
| 1108 /* Slide to the right; this is the tricky part |
| 1109 * |
| 1110 * 1. new_top is set to have room for seq, on the |
| 1111 * next byte boundary by setting the right 8 |
| 1112 * bits of seq |
| 1113 * 2. new_left is set to compensate. |
| 1114 * 3. Zero all bits between top and new_top. Since |
| 1115 * this is a ring, this zeroes everything as-yet |
| 1116 * unseen. Because we always operate on byte |
| 1117 * boundaries, we can zero one byte at a time |
| 1118 */ |
| 1119 new_right = seq | 0x07; |
| 1120 new_left = (new_right - DTLS_RECVD_RECORDS_WINDOW) + 1; |
| 1121 |
| 1122 for (right = records->right + 8; right <= new_right; right += 8) { |
| 1123 offset = right % DTLS_RECVD_RECORDS_WINDOW; |
| 1124 records->data[offset / 8] = 0; |
| 1125 } |
| 1126 |
| 1127 records->right = new_right; |
| 1128 records->left = new_left; |
| 1129 } |
| 1130 |
| 1131 offset = seq % DTLS_RECVD_RECORDS_WINDOW; |
| 1132 |
| 1133 records->data[offset / 8] |= (1 << (offset % 8)); |
| 1134 } |
| 1135 |
| 1136 SECStatus |
| 1137 DTLS_GetTimeout(PRFileDesc *socket, PRIntervalTime *timeout) |
| 1138 { |
| 1139 sslSocket * ss = NULL; |
| 1140 PRIntervalTime elapsed; |
| 1141 PRIntervalTime desired; |
| 1142 |
| 1143 ss = ssl_FindSocket(socket); |
| 1144 |
| 1145 if (!ss) |
| 1146 return SECFailure; |
| 1147 |
| 1148 if (!IS_DTLS(ss)) |
| 1149 return SECFailure; |
| 1150 |
| 1151 if (!ss->ssl3.hs.rtTimerCb) |
| 1152 return SECFailure; |
| 1153 |
| 1154 elapsed = PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted; |
| 1155 desired = PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs); |
| 1156 if (elapsed > desired) { |
| 1157 /* Timer expired */ |
| 1158 *timeout = PR_INTERVAL_NO_WAIT; |
| 1159 } else { |
| 1160 *timeout = desired - elapsed; |
| 1161 } |
| 1162 |
| 1163 return SECSuccess; |
| 1164 } |
OLD | NEW |