1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/security/nss/lib/ssl/dtlscon.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1141 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/* 1.9 + * DTLS Protocol 1.10 + */ 1.11 + 1.12 +#include "ssl.h" 1.13 +#include "sslimpl.h" 1.14 +#include "sslproto.h" 1.15 + 1.16 +#ifndef PR_ARRAY_SIZE 1.17 +#define PR_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) 1.18 +#endif 1.19 + 1.20 +static SECStatus dtls_TransmitMessageFlight(sslSocket *ss); 1.21 +static void dtls_RetransmitTimerExpiredCb(sslSocket *ss); 1.22 +static SECStatus dtls_SendSavedWriteData(sslSocket *ss); 1.23 + 1.24 +/* -28 adjusts for the IP/UDP header */ 1.25 +static const PRUint16 COMMON_MTU_VALUES[] = { 1.26 + 1500 - 28, /* Ethernet MTU */ 1.27 + 1280 - 28, /* IPv6 minimum MTU */ 1.28 + 576 - 28, /* Common assumption */ 1.29 + 256 - 28 /* We're in serious trouble now */ 1.30 +}; 1.31 + 1.32 +#define DTLS_COOKIE_BYTES 32 1.33 + 1.34 +/* List copied from ssl3con.c:cipherSuites */ 1.35 +static const ssl3CipherSuite nonDTLSSuites[] = { 1.36 +#ifndef NSS_DISABLE_ECC 1.37 + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 1.38 + TLS_ECDHE_RSA_WITH_RC4_128_SHA, 1.39 +#endif /* NSS_DISABLE_ECC */ 1.40 + TLS_DHE_DSS_WITH_RC4_128_SHA, 1.41 +#ifndef NSS_DISABLE_ECC 1.42 + TLS_ECDH_RSA_WITH_RC4_128_SHA, 1.43 + TLS_ECDH_ECDSA_WITH_RC4_128_SHA, 1.44 +#endif /* NSS_DISABLE_ECC */ 1.45 + TLS_RSA_WITH_RC4_128_MD5, 1.46 + TLS_RSA_WITH_RC4_128_SHA, 1.47 + TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, 1.48 + TLS_RSA_EXPORT_WITH_RC4_40_MD5, 1.49 + 0 /* End of list marker */ 1.50 +}; 1.51 + 1.52 +/* Map back and forth between TLS and DTLS versions in wire format. 1.53 + * Mapping table is: 1.54 + * 1.55 + * TLS DTLS 1.56 + * 1.1 (0302) 1.0 (feff) 1.57 + * 1.2 (0303) 1.2 (fefd) 1.58 + */ 1.59 +SSL3ProtocolVersion 1.60 +dtls_TLSVersionToDTLSVersion(SSL3ProtocolVersion tlsv) 1.61 +{ 1.62 + if (tlsv == SSL_LIBRARY_VERSION_TLS_1_1) { 1.63 + return SSL_LIBRARY_VERSION_DTLS_1_0_WIRE; 1.64 + } 1.65 + if (tlsv == SSL_LIBRARY_VERSION_TLS_1_2) { 1.66 + return SSL_LIBRARY_VERSION_DTLS_1_2_WIRE; 1.67 + } 1.68 + 1.69 + /* Anything other than TLS 1.1 or 1.2 is an error, so return 1.70 + * the invalid version 0xffff. */ 1.71 + return 0xffff; 1.72 +} 1.73 + 1.74 +/* Map known DTLS versions to known TLS versions. 1.75 + * - Invalid versions (< 1.0) return a version of 0 1.76 + * - Versions > known return a version one higher than we know of 1.77 + * to accomodate a theoretically newer version */ 1.78 +SSL3ProtocolVersion 1.79 +dtls_DTLSVersionToTLSVersion(SSL3ProtocolVersion dtlsv) 1.80 +{ 1.81 + if (MSB(dtlsv) == 0xff) { 1.82 + return 0; 1.83 + } 1.84 + 1.85 + if (dtlsv == SSL_LIBRARY_VERSION_DTLS_1_0_WIRE) { 1.86 + return SSL_LIBRARY_VERSION_TLS_1_1; 1.87 + } 1.88 + if (dtlsv == SSL_LIBRARY_VERSION_DTLS_1_2_WIRE) { 1.89 + return SSL_LIBRARY_VERSION_TLS_1_2; 1.90 + } 1.91 + 1.92 + /* Return a fictional higher version than we know of */ 1.93 + return SSL_LIBRARY_VERSION_TLS_1_2 + 1; 1.94 +} 1.95 + 1.96 +/* On this socket, Disable non-DTLS cipher suites in the argument's list */ 1.97 +SECStatus 1.98 +ssl3_DisableNonDTLSSuites(sslSocket * ss) 1.99 +{ 1.100 + const ssl3CipherSuite * suite; 1.101 + 1.102 + for (suite = nonDTLSSuites; *suite; ++suite) { 1.103 + SECStatus rv = ssl3_CipherPrefSet(ss, *suite, PR_FALSE); 1.104 + 1.105 + PORT_Assert(rv == SECSuccess); /* else is coding error */ 1.106 + } 1.107 + return SECSuccess; 1.108 +} 1.109 + 1.110 +/* Allocate a DTLSQueuedMessage. 1.111 + * 1.112 + * Called from dtls_QueueMessage() 1.113 + */ 1.114 +static DTLSQueuedMessage * 1.115 +dtls_AllocQueuedMessage(PRUint16 epoch, SSL3ContentType type, 1.116 + const unsigned char *data, PRUint32 len) 1.117 +{ 1.118 + DTLSQueuedMessage *msg = NULL; 1.119 + 1.120 + msg = PORT_ZAlloc(sizeof(DTLSQueuedMessage)); 1.121 + if (!msg) 1.122 + return NULL; 1.123 + 1.124 + msg->data = PORT_Alloc(len); 1.125 + if (!msg->data) { 1.126 + PORT_Free(msg); 1.127 + return NULL; 1.128 + } 1.129 + PORT_Memcpy(msg->data, data, len); 1.130 + 1.131 + msg->len = len; 1.132 + msg->epoch = epoch; 1.133 + msg->type = type; 1.134 + 1.135 + return msg; 1.136 +} 1.137 + 1.138 +/* 1.139 + * Free a handshake message 1.140 + * 1.141 + * Called from dtls_FreeHandshakeMessages() 1.142 + */ 1.143 +static void 1.144 +dtls_FreeHandshakeMessage(DTLSQueuedMessage *msg) 1.145 +{ 1.146 + if (!msg) 1.147 + return; 1.148 + 1.149 + PORT_ZFree(msg->data, msg->len); 1.150 + PORT_Free(msg); 1.151 +} 1.152 + 1.153 +/* 1.154 + * Free a list of handshake messages 1.155 + * 1.156 + * Called from: 1.157 + * dtls_HandleHandshake() 1.158 + * ssl3_DestroySSL3Info() 1.159 + */ 1.160 +void 1.161 +dtls_FreeHandshakeMessages(PRCList *list) 1.162 +{ 1.163 + PRCList *cur_p; 1.164 + 1.165 + while (!PR_CLIST_IS_EMPTY(list)) { 1.166 + cur_p = PR_LIST_TAIL(list); 1.167 + PR_REMOVE_LINK(cur_p); 1.168 + dtls_FreeHandshakeMessage((DTLSQueuedMessage *)cur_p); 1.169 + } 1.170 +} 1.171 + 1.172 +/* Called only from ssl3_HandleRecord, for each (deciphered) DTLS record. 1.173 + * origBuf is the decrypted ssl record content and is expected to contain 1.174 + * complete handshake records 1.175 + * Caller must hold the handshake and RecvBuf locks. 1.176 + * 1.177 + * Note that this code uses msg_len for two purposes: 1.178 + * 1.179 + * (1) To pass the length to ssl3_HandleHandshakeMessage() 1.180 + * (2) To carry the length of a message currently being reassembled 1.181 + * 1.182 + * However, unlike ssl3_HandleHandshake(), it is not used to carry 1.183 + * the state of reassembly (i.e., whether one is in progress). That 1.184 + * is carried in recvdHighWater and recvdFragments. 1.185 + */ 1.186 +#define OFFSET_BYTE(o) (o/8) 1.187 +#define OFFSET_MASK(o) (1 << (o%8)) 1.188 + 1.189 +SECStatus 1.190 +dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) 1.191 +{ 1.192 + /* XXX OK for now. 1.193 + * This doesn't work properly with asynchronous certificate validation. 1.194 + * because that returns a WOULDBLOCK error. The current DTLS 1.195 + * applications do not need asynchronous validation, but in the 1.196 + * future we will need to add this. 1.197 + */ 1.198 + sslBuffer buf = *origBuf; 1.199 + SECStatus rv = SECSuccess; 1.200 + 1.201 + PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); 1.202 + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); 1.203 + 1.204 + while (buf.len > 0) { 1.205 + PRUint8 type; 1.206 + PRUint32 message_length; 1.207 + PRUint16 message_seq; 1.208 + PRUint32 fragment_offset; 1.209 + PRUint32 fragment_length; 1.210 + PRUint32 offset; 1.211 + 1.212 + if (buf.len < 12) { 1.213 + PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); 1.214 + rv = SECFailure; 1.215 + break; 1.216 + } 1.217 + 1.218 + /* Parse the header */ 1.219 + type = buf.buf[0]; 1.220 + message_length = (buf.buf[1] << 16) | (buf.buf[2] << 8) | buf.buf[3]; 1.221 + message_seq = (buf.buf[4] << 8) | buf.buf[5]; 1.222 + fragment_offset = (buf.buf[6] << 16) | (buf.buf[7] << 8) | buf.buf[8]; 1.223 + fragment_length = (buf.buf[9] << 16) | (buf.buf[10] << 8) | buf.buf[11]; 1.224 + 1.225 +#define MAX_HANDSHAKE_MSG_LEN 0x1ffff /* 128k - 1 */ 1.226 + if (message_length > MAX_HANDSHAKE_MSG_LEN) { 1.227 + (void)ssl3_DecodeError(ss); 1.228 + PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); 1.229 + return SECFailure; 1.230 + } 1.231 +#undef MAX_HANDSHAKE_MSG_LEN 1.232 + 1.233 + buf.buf += 12; 1.234 + buf.len -= 12; 1.235 + 1.236 + /* This fragment must be complete */ 1.237 + if (buf.len < fragment_length) { 1.238 + PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); 1.239 + rv = SECFailure; 1.240 + break; 1.241 + } 1.242 + 1.243 + /* Sanity check the packet contents */ 1.244 + if ((fragment_length + fragment_offset) > message_length) { 1.245 + PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); 1.246 + rv = SECFailure; 1.247 + break; 1.248 + } 1.249 + 1.250 + /* There are three ways we could not be ready for this packet. 1.251 + * 1.252 + * 1. It's a partial next message. 1.253 + * 2. It's a partial or complete message beyond the next 1.254 + * 3. It's a message we've already seen 1.255 + * 1.256 + * If it's the complete next message we accept it right away. 1.257 + * This is the common case for short messages 1.258 + */ 1.259 + if ((message_seq == ss->ssl3.hs.recvMessageSeq) 1.260 + && (fragment_offset == 0) 1.261 + && (fragment_length == message_length)) { 1.262 + /* Complete next message. Process immediately */ 1.263 + ss->ssl3.hs.msg_type = (SSL3HandshakeType)type; 1.264 + ss->ssl3.hs.msg_len = message_length; 1.265 + 1.266 + /* At this point we are advancing our state machine, so 1.267 + * we can free our last flight of messages */ 1.268 + dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); 1.269 + ss->ssl3.hs.recvdHighWater = -1; 1.270 + dtls_CancelTimer(ss); 1.271 + 1.272 + /* Reset the timer to the initial value if the retry counter 1.273 + * is 0, per Sec. 4.2.4.1 */ 1.274 + if (ss->ssl3.hs.rtRetries == 0) { 1.275 + ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS; 1.276 + } 1.277 + 1.278 + rv = ssl3_HandleHandshakeMessage(ss, buf.buf, ss->ssl3.hs.msg_len); 1.279 + if (rv == SECFailure) { 1.280 + /* Do not attempt to process rest of messages in this record */ 1.281 + break; 1.282 + } 1.283 + } else { 1.284 + if (message_seq < ss->ssl3.hs.recvMessageSeq) { 1.285 + /* Case 3: we do an immediate retransmit if we're 1.286 + * in a waiting state*/ 1.287 + if (ss->ssl3.hs.rtTimerCb == NULL) { 1.288 + /* Ignore */ 1.289 + } else if (ss->ssl3.hs.rtTimerCb == 1.290 + dtls_RetransmitTimerExpiredCb) { 1.291 + SSL_TRC(30, ("%d: SSL3[%d]: Retransmit detected", 1.292 + SSL_GETPID(), ss->fd)); 1.293 + /* Check to see if we retransmitted recently. If so, 1.294 + * suppress the triggered retransmit. This avoids 1.295 + * retransmit wars after packet loss. 1.296 + * This is not in RFC 5346 but should be 1.297 + */ 1.298 + if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) > 1.299 + (ss->ssl3.hs.rtTimeoutMs / 4)) { 1.300 + SSL_TRC(30, 1.301 + ("%d: SSL3[%d]: Shortcutting retransmit timer", 1.302 + SSL_GETPID(), ss->fd)); 1.303 + 1.304 + /* Cancel the timer and call the CB, 1.305 + * which re-arms the timer */ 1.306 + dtls_CancelTimer(ss); 1.307 + dtls_RetransmitTimerExpiredCb(ss); 1.308 + rv = SECSuccess; 1.309 + break; 1.310 + } else { 1.311 + SSL_TRC(30, 1.312 + ("%d: SSL3[%d]: We just retransmitted. Ignoring.", 1.313 + SSL_GETPID(), ss->fd)); 1.314 + rv = SECSuccess; 1.315 + break; 1.316 + } 1.317 + } else if (ss->ssl3.hs.rtTimerCb == dtls_FinishedTimerCb) { 1.318 + /* Retransmit the messages and re-arm the timer 1.319 + * Note that we are not backing off the timer here. 1.320 + * The spec isn't clear and my reasoning is that this 1.321 + * may be a re-ordered packet rather than slowness, 1.322 + * so let's be aggressive. */ 1.323 + dtls_CancelTimer(ss); 1.324 + rv = dtls_TransmitMessageFlight(ss); 1.325 + if (rv == SECSuccess) { 1.326 + rv = dtls_StartTimer(ss, dtls_FinishedTimerCb); 1.327 + } 1.328 + if (rv != SECSuccess) 1.329 + return rv; 1.330 + break; 1.331 + } 1.332 + } else if (message_seq > ss->ssl3.hs.recvMessageSeq) { 1.333 + /* Case 2 1.334 + * 1.335 + * Ignore this message. This means we don't handle out of 1.336 + * order complete messages that well, but we're still 1.337 + * compliant and this probably does not happen often 1.338 + * 1.339 + * XXX OK for now. Maybe do something smarter at some point? 1.340 + */ 1.341 + } else { 1.342 + /* Case 1 1.343 + * 1.344 + * Buffer the fragment for reassembly 1.345 + */ 1.346 + /* Make room for the message */ 1.347 + if (ss->ssl3.hs.recvdHighWater == -1) { 1.348 + PRUint32 map_length = OFFSET_BYTE(message_length) + 1; 1.349 + 1.350 + rv = sslBuffer_Grow(&ss->ssl3.hs.msg_body, message_length); 1.351 + if (rv != SECSuccess) 1.352 + break; 1.353 + /* Make room for the fragment map */ 1.354 + rv = sslBuffer_Grow(&ss->ssl3.hs.recvdFragments, 1.355 + map_length); 1.356 + if (rv != SECSuccess) 1.357 + break; 1.358 + 1.359 + /* Reset the reassembly map */ 1.360 + ss->ssl3.hs.recvdHighWater = 0; 1.361 + PORT_Memset(ss->ssl3.hs.recvdFragments.buf, 0, 1.362 + ss->ssl3.hs.recvdFragments.space); 1.363 + ss->ssl3.hs.msg_type = (SSL3HandshakeType)type; 1.364 + ss->ssl3.hs.msg_len = message_length; 1.365 + } 1.366 + 1.367 + /* If we have a message length mismatch, abandon the reassembly 1.368 + * in progress and hope that the next retransmit will give us 1.369 + * something sane 1.370 + */ 1.371 + if (message_length != ss->ssl3.hs.msg_len) { 1.372 + ss->ssl3.hs.recvdHighWater = -1; 1.373 + PORT_SetError(SSL_ERROR_RX_MALFORMED_HANDSHAKE); 1.374 + rv = SECFailure; 1.375 + break; 1.376 + } 1.377 + 1.378 + /* Now copy this fragment into the buffer */ 1.379 + PORT_Assert((fragment_offset + fragment_length) <= 1.380 + ss->ssl3.hs.msg_body.space); 1.381 + PORT_Memcpy(ss->ssl3.hs.msg_body.buf + fragment_offset, 1.382 + buf.buf, fragment_length); 1.383 + 1.384 + /* This logic is a bit tricky. We have two values for 1.385 + * reassembly state: 1.386 + * 1.387 + * - recvdHighWater contains the highest contiguous number of 1.388 + * bytes received 1.389 + * - recvdFragments contains a bitmask of packets received 1.390 + * above recvdHighWater 1.391 + * 1.392 + * This avoids having to fill in the bitmask in the common 1.393 + * case of adjacent fragments received in sequence 1.394 + */ 1.395 + if (fragment_offset <= ss->ssl3.hs.recvdHighWater) { 1.396 + /* Either this is the adjacent fragment or an overlapping 1.397 + * fragment */ 1.398 + ss->ssl3.hs.recvdHighWater = fragment_offset + 1.399 + fragment_length; 1.400 + } else { 1.401 + for (offset = fragment_offset; 1.402 + offset < fragment_offset + fragment_length; 1.403 + offset++) { 1.404 + ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] |= 1.405 + OFFSET_MASK(offset); 1.406 + } 1.407 + } 1.408 + 1.409 + /* Now figure out the new high water mark if appropriate */ 1.410 + for (offset = ss->ssl3.hs.recvdHighWater; 1.411 + offset < ss->ssl3.hs.msg_len; offset++) { 1.412 + /* Note that this loop is not efficient, since it counts 1.413 + * bit by bit. If we have a lot of out-of-order packets, 1.414 + * we should optimize this */ 1.415 + if (ss->ssl3.hs.recvdFragments.buf[OFFSET_BYTE(offset)] & 1.416 + OFFSET_MASK(offset)) { 1.417 + ss->ssl3.hs.recvdHighWater++; 1.418 + } else { 1.419 + break; 1.420 + } 1.421 + } 1.422 + 1.423 + /* If we have all the bytes, then we are good to go */ 1.424 + if (ss->ssl3.hs.recvdHighWater == ss->ssl3.hs.msg_len) { 1.425 + ss->ssl3.hs.recvdHighWater = -1; 1.426 + 1.427 + rv = ssl3_HandleHandshakeMessage(ss, 1.428 + ss->ssl3.hs.msg_body.buf, 1.429 + ss->ssl3.hs.msg_len); 1.430 + if (rv == SECFailure) 1.431 + break; /* Skip rest of record */ 1.432 + 1.433 + /* At this point we are advancing our state machine, so 1.434 + * we can free our last flight of messages */ 1.435 + dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); 1.436 + dtls_CancelTimer(ss); 1.437 + 1.438 + /* If there have been no retries this time, reset the 1.439 + * timer value to the default per Section 4.2.4.1 */ 1.440 + if (ss->ssl3.hs.rtRetries == 0) { 1.441 + ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS; 1.442 + } 1.443 + } 1.444 + } 1.445 + } 1.446 + 1.447 + buf.buf += fragment_length; 1.448 + buf.len -= fragment_length; 1.449 + } 1.450 + 1.451 + origBuf->len = 0; /* So ssl3_GatherAppDataRecord will keep looping. */ 1.452 + 1.453 + /* XXX OK for now. In future handle rv == SECWouldBlock safely in order 1.454 + * to deal with asynchronous certificate verification */ 1.455 + return rv; 1.456 +} 1.457 + 1.458 +/* Enqueue a message (either handshake or CCS) 1.459 + * 1.460 + * Called from: 1.461 + * dtls_StageHandshakeMessage() 1.462 + * ssl3_SendChangeCipherSpecs() 1.463 + */ 1.464 +SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type, 1.465 + const SSL3Opaque *pIn, PRInt32 nIn) 1.466 +{ 1.467 + SECStatus rv = SECSuccess; 1.468 + DTLSQueuedMessage *msg = NULL; 1.469 + 1.470 + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); 1.471 + PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); 1.472 + 1.473 + msg = dtls_AllocQueuedMessage(ss->ssl3.cwSpec->epoch, type, pIn, nIn); 1.474 + 1.475 + if (!msg) { 1.476 + PORT_SetError(SEC_ERROR_NO_MEMORY); 1.477 + rv = SECFailure; 1.478 + } else { 1.479 + PR_APPEND_LINK(&msg->link, &ss->ssl3.hs.lastMessageFlight); 1.480 + } 1.481 + 1.482 + return rv; 1.483 +} 1.484 + 1.485 +/* Add DTLS handshake message to the pending queue 1.486 + * Empty the sendBuf buffer. 1.487 + * This function returns SECSuccess or SECFailure, never SECWouldBlock. 1.488 + * Always set sendBuf.len to 0, even when returning SECFailure. 1.489 + * 1.490 + * Called from: 1.491 + * ssl3_AppendHandshakeHeader() 1.492 + * dtls_FlushHandshake() 1.493 + */ 1.494 +SECStatus 1.495 +dtls_StageHandshakeMessage(sslSocket *ss) 1.496 +{ 1.497 + SECStatus rv = SECSuccess; 1.498 + 1.499 + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); 1.500 + PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); 1.501 + 1.502 + /* This function is sometimes called when no data is actually to 1.503 + * be staged, so just return SECSuccess. */ 1.504 + if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len) 1.505 + return rv; 1.506 + 1.507 + rv = dtls_QueueMessage(ss, content_handshake, 1.508 + ss->sec.ci.sendBuf.buf, ss->sec.ci.sendBuf.len); 1.509 + 1.510 + /* Whether we succeeded or failed, toss the old handshake data. */ 1.511 + ss->sec.ci.sendBuf.len = 0; 1.512 + return rv; 1.513 +} 1.514 + 1.515 +/* Enqueue the handshake message in sendBuf (if any) and then 1.516 + * transmit the resulting flight of handshake messages. 1.517 + * 1.518 + * Called from: 1.519 + * ssl3_FlushHandshake() 1.520 + */ 1.521 +SECStatus 1.522 +dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags) 1.523 +{ 1.524 + SECStatus rv = SECSuccess; 1.525 + 1.526 + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); 1.527 + PORT_Assert(ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); 1.528 + 1.529 + rv = dtls_StageHandshakeMessage(ss); 1.530 + if (rv != SECSuccess) 1.531 + return rv; 1.532 + 1.533 + if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { 1.534 + rv = dtls_TransmitMessageFlight(ss); 1.535 + if (rv != SECSuccess) 1.536 + return rv; 1.537 + 1.538 + if (!(flags & ssl_SEND_FLAG_NO_RETRANSMIT)) { 1.539 + ss->ssl3.hs.rtRetries = 0; 1.540 + rv = dtls_StartTimer(ss, dtls_RetransmitTimerExpiredCb); 1.541 + } 1.542 + } 1.543 + 1.544 + return rv; 1.545 +} 1.546 + 1.547 +/* The callback for when the retransmit timer expires 1.548 + * 1.549 + * Called from: 1.550 + * dtls_CheckTimer() 1.551 + * dtls_HandleHandshake() 1.552 + */ 1.553 +static void 1.554 +dtls_RetransmitTimerExpiredCb(sslSocket *ss) 1.555 +{ 1.556 + SECStatus rv = SECFailure; 1.557 + 1.558 + ss->ssl3.hs.rtRetries++; 1.559 + 1.560 + if (!(ss->ssl3.hs.rtRetries % 3)) { 1.561 + /* If one of the messages was potentially greater than > MTU, 1.562 + * then downgrade. Do this every time we have retransmitted a 1.563 + * message twice, per RFC 6347 Sec. 4.1.1 */ 1.564 + dtls_SetMTU(ss, ss->ssl3.hs.maxMessageSent - 1); 1.565 + } 1.566 + 1.567 + rv = dtls_TransmitMessageFlight(ss); 1.568 + if (rv == SECSuccess) { 1.569 + 1.570 + /* Re-arm the timer */ 1.571 + rv = dtls_RestartTimer(ss, PR_TRUE, dtls_RetransmitTimerExpiredCb); 1.572 + } 1.573 + 1.574 + if (rv == SECFailure) { 1.575 + /* XXX OK for now. In future maybe signal the stack that we couldn't 1.576 + * transmit. For now, let the read handle any real network errors */ 1.577 + } 1.578 +} 1.579 + 1.580 +/* Transmit a flight of handshake messages, stuffing them 1.581 + * into as few records as seems reasonable 1.582 + * 1.583 + * Called from: 1.584 + * dtls_FlushHandshake() 1.585 + * dtls_RetransmitTimerExpiredCb() 1.586 + */ 1.587 +static SECStatus 1.588 +dtls_TransmitMessageFlight(sslSocket *ss) 1.589 +{ 1.590 + SECStatus rv = SECSuccess; 1.591 + PRCList *msg_p; 1.592 + PRUint16 room_left = ss->ssl3.mtu; 1.593 + PRInt32 sent; 1.594 + 1.595 + ssl_GetXmitBufLock(ss); 1.596 + ssl_GetSpecReadLock(ss); 1.597 + 1.598 + /* DTLS does not buffer its handshake messages in 1.599 + * ss->pendingBuf, but rather in the lastMessageFlight 1.600 + * structure. This is just a sanity check that 1.601 + * some programming error hasn't inadvertantly 1.602 + * stuffed something in ss->pendingBuf 1.603 + */ 1.604 + PORT_Assert(!ss->pendingBuf.len); 1.605 + for (msg_p = PR_LIST_HEAD(&ss->ssl3.hs.lastMessageFlight); 1.606 + msg_p != &ss->ssl3.hs.lastMessageFlight; 1.607 + msg_p = PR_NEXT_LINK(msg_p)) { 1.608 + DTLSQueuedMessage *msg = (DTLSQueuedMessage *)msg_p; 1.609 + 1.610 + /* The logic here is: 1.611 + * 1.612 + * 1. If this is a message that will not fit into the remaining 1.613 + * space, then flush. 1.614 + * 2. If the message will now fit into the remaining space, 1.615 + * encrypt, buffer, and loop. 1.616 + * 3. If the message will not fit, then fragment. 1.617 + * 1.618 + * At the end of the function, flush. 1.619 + */ 1.620 + if ((msg->len + SSL3_BUFFER_FUDGE) > room_left) { 1.621 + /* The message will not fit into the remaining space, so flush */ 1.622 + rv = dtls_SendSavedWriteData(ss); 1.623 + if (rv != SECSuccess) 1.624 + break; 1.625 + 1.626 + room_left = ss->ssl3.mtu; 1.627 + } 1.628 + 1.629 + if ((msg->len + SSL3_BUFFER_FUDGE) <= room_left) { 1.630 + /* The message will fit, so encrypt and then continue with the 1.631 + * next packet */ 1.632 + sent = ssl3_SendRecord(ss, msg->epoch, msg->type, 1.633 + msg->data, msg->len, 1.634 + ssl_SEND_FLAG_FORCE_INTO_BUFFER | 1.635 + ssl_SEND_FLAG_USE_EPOCH); 1.636 + if (sent != msg->len) { 1.637 + rv = SECFailure; 1.638 + if (sent != -1) { 1.639 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.640 + } 1.641 + break; 1.642 + } 1.643 + 1.644 + room_left = ss->ssl3.mtu - ss->pendingBuf.len; 1.645 + } else { 1.646 + /* The message will not fit, so fragment. 1.647 + * 1.648 + * XXX OK for now. Arrange to coalesce the last fragment 1.649 + * of this message with the next message if possible. 1.650 + * That would be more efficient. 1.651 + */ 1.652 + PRUint32 fragment_offset = 0; 1.653 + unsigned char fragment[DTLS_MAX_MTU]; /* >= than largest 1.654 + * plausible MTU */ 1.655 + 1.656 + /* Assert that we have already flushed */ 1.657 + PORT_Assert(room_left == ss->ssl3.mtu); 1.658 + 1.659 + /* Case 3: We now need to fragment this message 1.660 + * DTLS only supports fragmenting handshaking messages */ 1.661 + PORT_Assert(msg->type == content_handshake); 1.662 + 1.663 + /* The headers consume 12 bytes so the smalles possible 1.664 + * message (i.e., an empty one) is 12 bytes 1.665 + */ 1.666 + PORT_Assert(msg->len >= 12); 1.667 + 1.668 + while ((fragment_offset + 12) < msg->len) { 1.669 + PRUint32 fragment_len; 1.670 + const unsigned char *content = msg->data + 12; 1.671 + PRUint32 content_len = msg->len - 12; 1.672 + 1.673 + /* The reason we use 8 here is that that's the length of 1.674 + * the new DTLS data that we add to the header */ 1.675 + fragment_len = PR_MIN(room_left - (SSL3_BUFFER_FUDGE + 8), 1.676 + content_len - fragment_offset); 1.677 + PORT_Assert(fragment_len < DTLS_MAX_MTU - 12); 1.678 + /* Make totally sure that we are within the buffer. 1.679 + * Note that the only way that fragment len could get 1.680 + * adjusted here is if 1.681 + * 1.682 + * (a) we are in release mode so the PORT_Assert is compiled out 1.683 + * (b) either the MTU table is inconsistent with DTLS_MAX_MTU 1.684 + * or ss->ssl3.mtu has become corrupt. 1.685 + */ 1.686 + fragment_len = PR_MIN(fragment_len, DTLS_MAX_MTU - 12); 1.687 + 1.688 + /* Construct an appropriate-sized fragment */ 1.689 + /* Type, length, sequence */ 1.690 + PORT_Memcpy(fragment, msg->data, 6); 1.691 + 1.692 + /* Offset */ 1.693 + fragment[6] = (fragment_offset >> 16) & 0xff; 1.694 + fragment[7] = (fragment_offset >> 8) & 0xff; 1.695 + fragment[8] = (fragment_offset) & 0xff; 1.696 + 1.697 + /* Fragment length */ 1.698 + fragment[9] = (fragment_len >> 16) & 0xff; 1.699 + fragment[10] = (fragment_len >> 8) & 0xff; 1.700 + fragment[11] = (fragment_len) & 0xff; 1.701 + 1.702 + PORT_Memcpy(fragment + 12, content + fragment_offset, 1.703 + fragment_len); 1.704 + 1.705 + /* 1.706 + * Send the record. We do this in two stages 1.707 + * 1. Encrypt 1.708 + */ 1.709 + sent = ssl3_SendRecord(ss, msg->epoch, msg->type, 1.710 + fragment, fragment_len + 12, 1.711 + ssl_SEND_FLAG_FORCE_INTO_BUFFER | 1.712 + ssl_SEND_FLAG_USE_EPOCH); 1.713 + if (sent != (fragment_len + 12)) { 1.714 + rv = SECFailure; 1.715 + if (sent != -1) { 1.716 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.717 + } 1.718 + break; 1.719 + } 1.720 + 1.721 + /* 2. Flush */ 1.722 + rv = dtls_SendSavedWriteData(ss); 1.723 + if (rv != SECSuccess) 1.724 + break; 1.725 + 1.726 + fragment_offset += fragment_len; 1.727 + } 1.728 + } 1.729 + } 1.730 + 1.731 + /* Finally, we need to flush */ 1.732 + if (rv == SECSuccess) 1.733 + rv = dtls_SendSavedWriteData(ss); 1.734 + 1.735 + /* Give up the locks */ 1.736 + ssl_ReleaseSpecReadLock(ss); 1.737 + ssl_ReleaseXmitBufLock(ss); 1.738 + 1.739 + return rv; 1.740 +} 1.741 + 1.742 +/* Flush the data in the pendingBuf and update the max message sent 1.743 + * so we can adjust the MTU estimate if we need to. 1.744 + * Wrapper for ssl_SendSavedWriteData. 1.745 + * 1.746 + * Called from dtls_TransmitMessageFlight() 1.747 + */ 1.748 +static 1.749 +SECStatus dtls_SendSavedWriteData(sslSocket *ss) 1.750 +{ 1.751 + PRInt32 sent; 1.752 + 1.753 + sent = ssl_SendSavedWriteData(ss); 1.754 + if (sent < 0) 1.755 + return SECFailure; 1.756 + 1.757 + /* We should always have complete writes b/c datagram sockets 1.758 + * don't really block */ 1.759 + if (ss->pendingBuf.len > 0) { 1.760 + ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); 1.761 + return SECFailure; 1.762 + } 1.763 + 1.764 + /* Update the largest message sent so we can adjust the MTU 1.765 + * estimate if necessary */ 1.766 + if (sent > ss->ssl3.hs.maxMessageSent) 1.767 + ss->ssl3.hs.maxMessageSent = sent; 1.768 + 1.769 + return SECSuccess; 1.770 +} 1.771 + 1.772 +/* Compress, MAC, encrypt a DTLS record. Allows specification of 1.773 + * the epoch using epoch value. If use_epoch is PR_TRUE then 1.774 + * we use the provided epoch. If use_epoch is PR_FALSE then 1.775 + * whatever the current value is in effect is used. 1.776 + * 1.777 + * Called from ssl3_SendRecord() 1.778 + */ 1.779 +SECStatus 1.780 +dtls_CompressMACEncryptRecord(sslSocket * ss, 1.781 + DTLSEpoch epoch, 1.782 + PRBool use_epoch, 1.783 + SSL3ContentType type, 1.784 + const SSL3Opaque * pIn, 1.785 + PRUint32 contentLen, 1.786 + sslBuffer * wrBuf) 1.787 +{ 1.788 + SECStatus rv = SECFailure; 1.789 + ssl3CipherSpec * cwSpec; 1.790 + 1.791 + ssl_GetSpecReadLock(ss); /********************************/ 1.792 + 1.793 + /* The reason for this switch-hitting code is that we might have 1.794 + * a flight of records spanning an epoch boundary, e.g., 1.795 + * 1.796 + * ClientKeyExchange (epoch = 0) 1.797 + * ChangeCipherSpec (epoch = 0) 1.798 + * Finished (epoch = 1) 1.799 + * 1.800 + * Thus, each record needs a different cipher spec. The information 1.801 + * about which epoch to use is carried with the record. 1.802 + */ 1.803 + if (use_epoch) { 1.804 + if (ss->ssl3.cwSpec->epoch == epoch) 1.805 + cwSpec = ss->ssl3.cwSpec; 1.806 + else if (ss->ssl3.pwSpec->epoch == epoch) 1.807 + cwSpec = ss->ssl3.pwSpec; 1.808 + else 1.809 + cwSpec = NULL; 1.810 + } else { 1.811 + cwSpec = ss->ssl3.cwSpec; 1.812 + } 1.813 + 1.814 + if (cwSpec) { 1.815 + rv = ssl3_CompressMACEncryptRecord(cwSpec, ss->sec.isServer, PR_TRUE, 1.816 + PR_FALSE, type, pIn, contentLen, 1.817 + wrBuf); 1.818 + } else { 1.819 + PR_NOT_REACHED("Couldn't find a cipher spec matching epoch"); 1.820 + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 1.821 + } 1.822 + ssl_ReleaseSpecReadLock(ss); /************************************/ 1.823 + 1.824 + return rv; 1.825 +} 1.826 + 1.827 +/* Start a timer 1.828 + * 1.829 + * Called from: 1.830 + * dtls_HandleHandshake() 1.831 + * dtls_FlushHAndshake() 1.832 + * dtls_RestartTimer() 1.833 + */ 1.834 +SECStatus 1.835 +dtls_StartTimer(sslSocket *ss, DTLSTimerCb cb) 1.836 +{ 1.837 + PORT_Assert(ss->ssl3.hs.rtTimerCb == NULL); 1.838 + 1.839 + ss->ssl3.hs.rtTimerStarted = PR_IntervalNow(); 1.840 + ss->ssl3.hs.rtTimerCb = cb; 1.841 + 1.842 + return SECSuccess; 1.843 +} 1.844 + 1.845 +/* Restart a timer with optional backoff 1.846 + * 1.847 + * Called from dtls_RetransmitTimerExpiredCb() 1.848 + */ 1.849 +SECStatus 1.850 +dtls_RestartTimer(sslSocket *ss, PRBool backoff, DTLSTimerCb cb) 1.851 +{ 1.852 + if (backoff) { 1.853 + ss->ssl3.hs.rtTimeoutMs *= 2; 1.854 + if (ss->ssl3.hs.rtTimeoutMs > MAX_DTLS_TIMEOUT_MS) 1.855 + ss->ssl3.hs.rtTimeoutMs = MAX_DTLS_TIMEOUT_MS; 1.856 + } 1.857 + 1.858 + return dtls_StartTimer(ss, cb); 1.859 +} 1.860 + 1.861 +/* Cancel a pending timer 1.862 + * 1.863 + * Called from: 1.864 + * dtls_HandleHandshake() 1.865 + * dtls_CheckTimer() 1.866 + */ 1.867 +void 1.868 +dtls_CancelTimer(sslSocket *ss) 1.869 +{ 1.870 + PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); 1.871 + 1.872 + ss->ssl3.hs.rtTimerCb = NULL; 1.873 +} 1.874 + 1.875 +/* Check the pending timer and fire the callback if it expired 1.876 + * 1.877 + * Called from ssl3_GatherCompleteHandshake() 1.878 + */ 1.879 +void 1.880 +dtls_CheckTimer(sslSocket *ss) 1.881 +{ 1.882 + if (!ss->ssl3.hs.rtTimerCb) 1.883 + return; 1.884 + 1.885 + if ((PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted) > 1.886 + PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs)) { 1.887 + /* Timer has expired */ 1.888 + DTLSTimerCb cb = ss->ssl3.hs.rtTimerCb; 1.889 + 1.890 + /* Cancel the timer so that we can call the CB safely */ 1.891 + dtls_CancelTimer(ss); 1.892 + 1.893 + /* Now call the CB */ 1.894 + cb(ss); 1.895 + } 1.896 +} 1.897 + 1.898 +/* The callback to fire when the holddown timer for the Finished 1.899 + * message expires and we can delete it 1.900 + * 1.901 + * Called from dtls_CheckTimer() 1.902 + */ 1.903 +void 1.904 +dtls_FinishedTimerCb(sslSocket *ss) 1.905 +{ 1.906 + ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE); 1.907 +} 1.908 + 1.909 +/* Cancel the Finished hold-down timer and destroy the 1.910 + * pending cipher spec. Note that this means that 1.911 + * successive rehandshakes will fail if the Finished is 1.912 + * lost. 1.913 + * 1.914 + * XXX OK for now. Figure out how to handle the combination 1.915 + * of Finished lost and rehandshake 1.916 + */ 1.917 +void 1.918 +dtls_RehandshakeCleanup(sslSocket *ss) 1.919 +{ 1.920 + dtls_CancelTimer(ss); 1.921 + ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE); 1.922 + ss->ssl3.hs.sendMessageSeq = 0; 1.923 + ss->ssl3.hs.recvMessageSeq = 0; 1.924 +} 1.925 + 1.926 +/* Set the MTU to the next step less than or equal to the 1.927 + * advertised value. Also used to downgrade the MTU by 1.928 + * doing dtls_SetMTU(ss, biggest packet set). 1.929 + * 1.930 + * Passing 0 means set this to the largest MTU known 1.931 + * (effectively resetting the PMTU backoff value). 1.932 + * 1.933 + * Called by: 1.934 + * ssl3_InitState() 1.935 + * dtls_RetransmitTimerExpiredCb() 1.936 + */ 1.937 +void 1.938 +dtls_SetMTU(sslSocket *ss, PRUint16 advertised) 1.939 +{ 1.940 + int i; 1.941 + 1.942 + if (advertised == 0) { 1.943 + ss->ssl3.mtu = COMMON_MTU_VALUES[0]; 1.944 + SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu)); 1.945 + return; 1.946 + } 1.947 + 1.948 + for (i = 0; i < PR_ARRAY_SIZE(COMMON_MTU_VALUES); i++) { 1.949 + if (COMMON_MTU_VALUES[i] <= advertised) { 1.950 + ss->ssl3.mtu = COMMON_MTU_VALUES[i]; 1.951 + SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu)); 1.952 + return; 1.953 + } 1.954 + } 1.955 + 1.956 + /* Fallback */ 1.957 + ss->ssl3.mtu = COMMON_MTU_VALUES[PR_ARRAY_SIZE(COMMON_MTU_VALUES)-1]; 1.958 + SSL_TRC(30, ("Resetting MTU to %d", ss->ssl3.mtu)); 1.959 +} 1.960 + 1.961 +/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a 1.962 + * DTLS hello_verify_request 1.963 + * Caller must hold Handshake and RecvBuf locks. 1.964 + */ 1.965 +SECStatus 1.966 +dtls_HandleHelloVerifyRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) 1.967 +{ 1.968 + int errCode = SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST; 1.969 + SECStatus rv; 1.970 + PRInt32 temp; 1.971 + SECItem cookie = {siBuffer, NULL, 0}; 1.972 + SSL3AlertDescription desc = illegal_parameter; 1.973 + 1.974 + SSL_TRC(3, ("%d: SSL3[%d]: handle hello_verify_request handshake", 1.975 + SSL_GETPID(), ss->fd)); 1.976 + PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); 1.977 + PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); 1.978 + 1.979 + if (ss->ssl3.hs.ws != wait_server_hello) { 1.980 + errCode = SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST; 1.981 + desc = unexpected_message; 1.982 + goto alert_loser; 1.983 + } 1.984 + 1.985 + /* The version */ 1.986 + temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); 1.987 + if (temp < 0) { 1.988 + goto loser; /* alert has been sent */ 1.989 + } 1.990 + 1.991 + if (temp != SSL_LIBRARY_VERSION_DTLS_1_0_WIRE && 1.992 + temp != SSL_LIBRARY_VERSION_DTLS_1_2_WIRE) { 1.993 + goto alert_loser; 1.994 + } 1.995 + 1.996 + /* The cookie */ 1.997 + rv = ssl3_ConsumeHandshakeVariable(ss, &cookie, 1, &b, &length); 1.998 + if (rv != SECSuccess) { 1.999 + goto loser; /* alert has been sent */ 1.1000 + } 1.1001 + if (cookie.len > DTLS_COOKIE_BYTES) { 1.1002 + desc = decode_error; 1.1003 + goto alert_loser; /* malformed. */ 1.1004 + } 1.1005 + 1.1006 + PORT_Memcpy(ss->ssl3.hs.cookie, cookie.data, cookie.len); 1.1007 + ss->ssl3.hs.cookieLen = cookie.len; 1.1008 + 1.1009 + 1.1010 + ssl_GetXmitBufLock(ss); /*******************************/ 1.1011 + 1.1012 + /* Now re-send the client hello */ 1.1013 + rv = ssl3_SendClientHello(ss, PR_TRUE); 1.1014 + 1.1015 + ssl_ReleaseXmitBufLock(ss); /*******************************/ 1.1016 + 1.1017 + if (rv == SECSuccess) 1.1018 + return rv; 1.1019 + 1.1020 +alert_loser: 1.1021 + (void)SSL3_SendAlert(ss, alert_fatal, desc); 1.1022 + 1.1023 +loser: 1.1024 + errCode = ssl_MapLowLevelError(errCode); 1.1025 + return SECFailure; 1.1026 +} 1.1027 + 1.1028 +/* Initialize the DTLS anti-replay window 1.1029 + * 1.1030 + * Called from: 1.1031 + * ssl3_SetupPendingCipherSpec() 1.1032 + * ssl3_InitCipherSpec() 1.1033 + */ 1.1034 +void 1.1035 +dtls_InitRecvdRecords(DTLSRecvdRecords *records) 1.1036 +{ 1.1037 + PORT_Memset(records->data, 0, sizeof(records->data)); 1.1038 + records->left = 0; 1.1039 + records->right = DTLS_RECVD_RECORDS_WINDOW - 1; 1.1040 +} 1.1041 + 1.1042 +/* 1.1043 + * Has this DTLS record been received? Return values are: 1.1044 + * -1 -- out of range to the left 1.1045 + * 0 -- not received yet 1.1046 + * 1 -- replay 1.1047 + * 1.1048 + * Called from: dtls_HandleRecord() 1.1049 + */ 1.1050 +int 1.1051 +dtls_RecordGetRecvd(DTLSRecvdRecords *records, PRUint64 seq) 1.1052 +{ 1.1053 + PRUint64 offset; 1.1054 + 1.1055 + /* Out of range to the left */ 1.1056 + if (seq < records->left) { 1.1057 + return -1; 1.1058 + } 1.1059 + 1.1060 + /* Out of range to the right; since we advance the window on 1.1061 + * receipt, that means that this packet has not been received 1.1062 + * yet */ 1.1063 + if (seq > records->right) 1.1064 + return 0; 1.1065 + 1.1066 + offset = seq % DTLS_RECVD_RECORDS_WINDOW; 1.1067 + 1.1068 + return !!(records->data[offset / 8] & (1 << (offset % 8))); 1.1069 +} 1.1070 + 1.1071 +/* Update the DTLS anti-replay window 1.1072 + * 1.1073 + * Called from ssl3_HandleRecord() 1.1074 + */ 1.1075 +void 1.1076 +dtls_RecordSetRecvd(DTLSRecvdRecords *records, PRUint64 seq) 1.1077 +{ 1.1078 + PRUint64 offset; 1.1079 + 1.1080 + if (seq < records->left) 1.1081 + return; 1.1082 + 1.1083 + if (seq > records->right) { 1.1084 + PRUint64 new_left; 1.1085 + PRUint64 new_right; 1.1086 + PRUint64 right; 1.1087 + 1.1088 + /* Slide to the right; this is the tricky part 1.1089 + * 1.1090 + * 1. new_top is set to have room for seq, on the 1.1091 + * next byte boundary by setting the right 8 1.1092 + * bits of seq 1.1093 + * 2. new_left is set to compensate. 1.1094 + * 3. Zero all bits between top and new_top. Since 1.1095 + * this is a ring, this zeroes everything as-yet 1.1096 + * unseen. Because we always operate on byte 1.1097 + * boundaries, we can zero one byte at a time 1.1098 + */ 1.1099 + new_right = seq | 0x07; 1.1100 + new_left = (new_right - DTLS_RECVD_RECORDS_WINDOW) + 1; 1.1101 + 1.1102 + for (right = records->right + 8; right <= new_right; right += 8) { 1.1103 + offset = right % DTLS_RECVD_RECORDS_WINDOW; 1.1104 + records->data[offset / 8] = 0; 1.1105 + } 1.1106 + 1.1107 + records->right = new_right; 1.1108 + records->left = new_left; 1.1109 + } 1.1110 + 1.1111 + offset = seq % DTLS_RECVD_RECORDS_WINDOW; 1.1112 + 1.1113 + records->data[offset / 8] |= (1 << (offset % 8)); 1.1114 +} 1.1115 + 1.1116 +SECStatus 1.1117 +DTLS_GetHandshakeTimeout(PRFileDesc *socket, PRIntervalTime *timeout) 1.1118 +{ 1.1119 + sslSocket * ss = NULL; 1.1120 + PRIntervalTime elapsed; 1.1121 + PRIntervalTime desired; 1.1122 + 1.1123 + ss = ssl_FindSocket(socket); 1.1124 + 1.1125 + if (!ss) 1.1126 + return SECFailure; 1.1127 + 1.1128 + if (!IS_DTLS(ss)) 1.1129 + return SECFailure; 1.1130 + 1.1131 + if (!ss->ssl3.hs.rtTimerCb) 1.1132 + return SECFailure; 1.1133 + 1.1134 + elapsed = PR_IntervalNow() - ss->ssl3.hs.rtTimerStarted; 1.1135 + desired = PR_MillisecondsToInterval(ss->ssl3.hs.rtTimeoutMs); 1.1136 + if (elapsed > desired) { 1.1137 + /* Timer expired */ 1.1138 + *timeout = PR_INTERVAL_NO_WAIT; 1.1139 + } else { 1.1140 + *timeout = desired - elapsed; 1.1141 + } 1.1142 + 1.1143 + return SECSuccess; 1.1144 +}