security/nss/lib/ssl/dtlscon.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial