diff options
Diffstat (limited to 'net/third_party/nss/ssl/ssl3con.c')
-rw-r--r-- | net/third_party/nss/ssl/ssl3con.c | 584 |
1 files changed, 487 insertions, 97 deletions
diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c index 322e502..e8a7f017 100644 --- a/net/third_party/nss/ssl/ssl3con.c +++ b/net/third_party/nss/ssl/ssl3con.c @@ -42,6 +42,8 @@ * ***** END LICENSE BLOCK ***** */ /* $Id: ssl3con.c,v 1.173 2012/03/18 00:31:19 wtc%google.com Exp $ */ +/* TODO(ekr): Implement HelloVerifyRequest on server side. OK for now. */ + #include "cert.h" #include "ssl.h" #include "cryptohi.h" /* for DSAU_ stuff */ @@ -92,6 +94,7 @@ static SECStatus ssl3_NewHandshakeHashes( sslSocket *ss); static SECStatus ssl3_UpdateHandshakeHashes( sslSocket *ss, const unsigned char *b, unsigned int l); +static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen, const unsigned char *input, @@ -221,22 +224,6 @@ static const /*SSL3ClientCertificateType */ uint8 certificate_types [] = { #endif /* NSS_ENABLE_ECC */ }; -#ifdef NSS_ENABLE_ZLIB -/* - * The DEFLATE algorithm can result in an expansion of 0.1% + 12 bytes. For a - * maximum TLS record payload of 2**14 bytes, that's 29 bytes. - */ -#define SSL3_COMPRESSION_MAX_EXPANSION 29 -#else /* !NSS_ENABLE_ZLIB */ -#define SSL3_COMPRESSION_MAX_EXPANSION 0 -#endif - -/* - * make sure there is room in the write buffer for padding and - * other compression and cryptographic expansions. - */ -#define SSL3_BUFFER_FUDGE 100 + SSL3_COMPRESSION_MAX_EXPANSION - #define EXPORT_RSA_KEY_LENGTH 64 /* bytes */ @@ -517,6 +504,7 @@ ssl3_DecodeHandshakeType(int msgType) case hello_request: rv = "hello_request (0)"; break; case client_hello: rv = "client_hello (1)"; break; case server_hello: rv = "server_hello (2)"; break; + case hello_verify_request: rv = "hello_verify_request (3)"; break; case certificate: rv = "certificate (11)"; break; case server_key_exchange: rv = "server_key_exchange (12)"; break; case certificate_request: rv = "certificate_request (13)"; break; @@ -656,7 +644,7 @@ ssl3_config_match_init(sslSocket *ss) suite->isPresent = PR_FALSE; continue; } - cipher_alg=bulk_cipher_defs[cipher_def->bulk_cipher_alg ].calg; + cipher_alg = bulk_cipher_defs[cipher_def->bulk_cipher_alg].calg; PORT_Assert( alg2Mech[cipher_alg].calg == cipher_alg); cipher_mech = alg2Mech[cipher_alg].cmech; exchKeyType = @@ -1148,7 +1136,7 @@ ssl3_CleanupKeyMaterial(ssl3KeyMaterial *mat) ** ssl3_DestroySSL3Info ** Caller must hold SpecWriteLock. */ -static void +void ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName) { PRBool freeit = (PRBool)(!spec->bypassCiphers); @@ -1228,6 +1216,12 @@ ssl3_SetupPendingCipherSpec(sslSocket *ss) return SECFailure; /* error code set by ssl_LookupCipherSuiteDef */ } + if (IS_DTLS(ss)) { + /* Double-check that we did not pick an RC4 suite */ + PORT_Assert((suite_def->bulk_cipher_alg != cipher_rc4) && + (suite_def->bulk_cipher_alg != cipher_rc4_40) && + (suite_def->bulk_cipher_alg != cipher_rc4_56)); + } cipher = suite_def->bulk_cipher_alg; kea = suite_def->key_exchange_alg; @@ -1754,6 +1748,7 @@ SECStatus ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms) { ssl3CipherSpec * pwSpec; + ssl3CipherSpec * cwSpec; SECStatus rv; PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); @@ -1763,6 +1758,7 @@ ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms) PORT_Assert(ss->ssl3.prSpec == ss->ssl3.pwSpec); pwSpec = ss->ssl3.pwSpec; + cwSpec = ss->ssl3.cwSpec; if (pms || (!pwSpec->msItem.len && !pwSpec->master_secret)) { rv = ssl3_DeriveMasterSecret(ss, pms); @@ -1794,6 +1790,31 @@ ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms) PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); rv = SECFailure; } + if (rv != SECSuccess) { + goto done; + } + + /* Generic behaviors -- common to all crypto methods */ + if (!IS_DTLS(ss)) { + pwSpec->read_seq_num.high = pwSpec->write_seq_num.high = 0; + } else { + if (cwSpec->epoch == PR_UINT16_MAX) { + /* The problem here is that we have rehandshaked too many + * times (you are not allowed to wrap the epoch). The + * spec says you should be discarding the connection + * and start over, so not much we can do here. */ + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + rv = SECFailure; + goto done; + } + /* The sequence number has the high 16 bits as the epoch. */ + pwSpec->epoch = cwSpec->epoch + 1; + pwSpec->read_seq_num.high = pwSpec->write_seq_num.high = + pwSpec->epoch << 16; + + dtls_InitRecvdRecords(&pwSpec->recvdRecords); + } + pwSpec->read_seq_num.low = pwSpec->write_seq_num.low = 0; done: ssl_ReleaseSpecWriteLock(ss); /******************************/ @@ -1834,6 +1855,7 @@ static SECStatus ssl3_ComputeRecordMAC( ssl3CipherSpec * spec, PRBool useServerMacKey, + PRBool isDTLS, SSL3ContentType type, SSL3ProtocolVersion version, SSL3SequenceNumber seq_num, @@ -1871,8 +1893,16 @@ ssl3_ComputeRecordMAC( isTLS = PR_FALSE; } else { /* New TLS hash includes version. */ - temp[9] = MSB(version); - temp[10] = LSB(version); + if (isDTLS) { + SSL3ProtocolVersion dtls_version; + + dtls_version = dtls_TLSVersionToDTLSVersion(version); + temp[9] = MSB(dtls_version); + temp[10] = LSB(dtls_version); + } else { + temp[9] = MSB(version); + temp[10] = LSB(version); + } temp[11] = MSB(inputLength); temp[12] = LSB(inputLength); tempLen = 13; @@ -2022,9 +2052,10 @@ ssl3_ClientAuthTokenPresent(sslSessionID *sid) { } /* Caller must hold the spec read lock. */ -static SECStatus +SECStatus ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, PRBool isServer, + PRBool isDTLS, SSL3ContentType type, const SSL3Opaque * pIn, PRUint32 contentLen, @@ -2035,10 +2066,12 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, PRUint32 macLen = 0; PRUint32 fragLen; PRUint32 p1Len, p2Len, oddLen = 0; + PRUint16 headerLen; int ivLen = 0; int cipherBytes = 0; cipher_def = cwSpec->cipher_def; + headerLen = isDTLS ? DTLS_RECORD_HEADER_LENGTH : SSL3_RECORD_HEADER_LENGTH; if (cipher_def->type == type_block && cwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { @@ -2048,20 +2081,20 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, * record. */ ivLen = cipher_def->iv_size; - if (ivLen > wrBuf->space - SSL3_RECORD_HEADER_LENGTH) { + if (ivLen > wrBuf->space - headerLen) { PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; } - rv = PK11_GenerateRandom(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH, ivLen); + rv = PK11_GenerateRandom(wrBuf->buf + headerLen, ivLen); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_GENERATE_RANDOM_FAILURE); return rv; } rv = cwSpec->encode( cwSpec->encodeContext, - wrBuf->buf + SSL3_RECORD_HEADER_LENGTH, + wrBuf->buf + headerLen, &cipherBytes, /* output and actual outLen */ ivLen, /* max outlen */ - wrBuf->buf + SSL3_RECORD_HEADER_LENGTH, + wrBuf->buf + headerLen, ivLen); /* input and inputLen*/ if (rv != SECSuccess || cipherBytes != ivLen) { PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); @@ -2073,20 +2106,20 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, int outlen; rv = cwSpec->compressor( cwSpec->compressContext, - wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen, &outlen, - wrBuf->space - SSL3_RECORD_HEADER_LENGTH - ivLen, pIn, contentLen); + wrBuf->buf + headerLen + ivLen, &outlen, + wrBuf->space - headerLen - ivLen, pIn, contentLen); if (rv != SECSuccess) return rv; - pIn = wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen; + pIn = wrBuf->buf + headerLen + ivLen; contentLen = outlen; } /* * Add the MAC */ - rv = ssl3_ComputeRecordMAC( cwSpec, isServer, + rv = ssl3_ComputeRecordMAC( cwSpec, isServer, isDTLS, type, cwSpec->version, cwSpec->write_seq_num, pIn, contentLen, - wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen + contentLen, &macLen); + wrBuf->buf + headerLen + ivLen + contentLen, &macLen); if (rv != SECSuccess) { ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); return SECFailure; @@ -2113,7 +2146,7 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, PORT_Assert((fragLen % cipher_def->block_size) == 0); /* Pad according to TLS rules (also acceptable to SSL3). */ - pBuf = &wrBuf->buf[SSL3_RECORD_HEADER_LENGTH + ivLen + fragLen - 1]; + pBuf = &wrBuf->buf[headerLen + ivLen + fragLen - 1]; for (i = padding_length + 1; i > 0; --i) { *pBuf-- = padding_length; } @@ -2130,13 +2163,12 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, p2Len += oddLen; PORT_Assert( (cipher_def->block_size < 2) || \ (p2Len % cipher_def->block_size) == 0); - memmove(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen + p1Len, - pIn + p1Len, oddLen); + memmove(wrBuf->buf + headerLen + ivLen + p1Len, pIn + p1Len, oddLen); } if (p1Len > 0) { int cipherBytesPart1 = -1; rv = cwSpec->encode( cwSpec->encodeContext, - wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen, /* output */ + wrBuf->buf + headerLen + ivLen, /* output */ &cipherBytesPart1, /* actual outlen */ p1Len, /* max outlen */ pIn, p1Len); /* input, and inputlen */ @@ -2150,10 +2182,10 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, if (p2Len > 0) { int cipherBytesPart2 = -1; rv = cwSpec->encode( cwSpec->encodeContext, - wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen + p1Len, + wrBuf->buf + headerLen + ivLen + p1Len, &cipherBytesPart2, /* output and actual outLen */ p2Len, /* max outlen */ - wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + ivLen + p1Len, + wrBuf->buf + headerLen + ivLen + p1Len, p2Len); /* input and inputLen*/ PORT_Assert(rv == SECSuccess && cipherBytesPart2 == (int) p2Len); if (rv != SECSuccess || cipherBytesPart2 != (int) p2Len) { @@ -2164,14 +2196,32 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, } PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024); - ssl3_BumpSequenceNumber(&cwSpec->write_seq_num); - - wrBuf->len = cipherBytes + SSL3_RECORD_HEADER_LENGTH; + wrBuf->len = cipherBytes + headerLen; wrBuf->buf[0] = type; - wrBuf->buf[1] = MSB(cwSpec->version); - wrBuf->buf[2] = LSB(cwSpec->version); - wrBuf->buf[3] = MSB(cipherBytes); - wrBuf->buf[4] = LSB(cipherBytes); + if (isDTLS) { + SSL3ProtocolVersion version; + + version = dtls_TLSVersionToDTLSVersion(cwSpec->version); + wrBuf->buf[1] = MSB(version); + wrBuf->buf[2] = LSB(version); + wrBuf->buf[3] = (unsigned char)(cwSpec->write_seq_num.high >> 24); + wrBuf->buf[4] = (unsigned char)(cwSpec->write_seq_num.high >> 16); + wrBuf->buf[5] = (unsigned char)(cwSpec->write_seq_num.high >> 8); + wrBuf->buf[6] = (unsigned char)(cwSpec->write_seq_num.high >> 0); + wrBuf->buf[7] = (unsigned char)(cwSpec->write_seq_num.low >> 24); + wrBuf->buf[8] = (unsigned char)(cwSpec->write_seq_num.low >> 16); + wrBuf->buf[9] = (unsigned char)(cwSpec->write_seq_num.low >> 8); + wrBuf->buf[10] = (unsigned char)(cwSpec->write_seq_num.low >> 0); + wrBuf->buf[11] = MSB(cipherBytes); + wrBuf->buf[12] = LSB(cipherBytes); + } else { + wrBuf->buf[1] = MSB(cwSpec->version); + wrBuf->buf[2] = LSB(cwSpec->version); + wrBuf->buf[3] = MSB(cipherBytes); + wrBuf->buf[4] = LSB(cipherBytes); + } + + ssl3_BumpSequenceNumber(&cwSpec->write_seq_num); return SECSuccess; } @@ -2194,10 +2244,13 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec * cwSpec, * ssl_SEND_FLAG_FORCE_INTO_BUFFER * As above, except this suppresses all write attempts, and forces * all ciphertext into the pending ciphertext buffer. + * ssl_SEND_FLAG_USE_EPOCH (for DTLS) + * Forces the use of the provided epoch * */ -static PRInt32 +PRInt32 ssl3_SendRecord( sslSocket * ss, + DTLSEpoch epoch, /* DTLS only */ SSL3ContentType type, const SSL3Opaque * pIn, /* input buffer */ PRInt32 nIn, /* bytes of input */ @@ -2269,8 +2322,8 @@ ssl3_SendRecord( sslSocket * ss, sslBuffer secondRecord; rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec, - ss->sec.isServer, type, pIn, 1, - wrBuf); + ss->sec.isServer, IS_DTLS(ss), + type, pIn, 1, wrBuf); if (rv != SECSuccess) goto spec_locked_loser; @@ -2282,17 +2335,28 @@ ssl3_SendRecord( sslSocket * ss, secondRecord.space = wrBuf->space - wrBuf->len; rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec, - ss->sec.isServer, type, pIn + 1, - contentLen - 1, &secondRecord); + ss->sec.isServer, IS_DTLS(ss), + type, pIn + 1, contentLen - 1, + &secondRecord); if (rv == SECSuccess) { PRINT_BUF(50, (ss, "send (encrypted) record data [2/2]:", secondRecord.buf, secondRecord.len)); wrBuf->len += secondRecord.len; } } else { - rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec, - ss->sec.isServer, type, pIn, - contentLen, wrBuf); + if (!IS_DTLS(ss)) { + rv = ssl3_CompressMACEncryptRecord(ss->ssl3.cwSpec, + ss->sec.isServer, + IS_DTLS(ss), + type, pIn, + contentLen, wrBuf); + } else { + rv = dtls_CompressMACEncryptRecord(ss, epoch, + !!(flags & ssl_SEND_FLAG_USE_EPOCH), + type, pIn, + contentLen, wrBuf); + } + if (rv == SECSuccess) { PRINT_BUF(50, (ss, "send (encrypted) record data:", wrBuf->buf, wrBuf->len)); @@ -2350,6 +2414,11 @@ spec_locked_loser: } wrBuf->len -= sent; if (wrBuf->len) { + if (IS_DTLS(ss)) { + /* DTLS just says no in this case. No buffering */ + PR_SetError(PR_WOULD_BLOCK_ERROR, 0); + return SECFailure; + } /* now take all the remaining unsent new ciphertext and * append it to the buffer of previously unsent ciphertext. */ @@ -2378,6 +2447,9 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, PRInt32 discarded = 0; PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); + /* These flags for internal use only */ + PORT_Assert(!(flags & (ssl_SEND_FLAG_USE_EPOCH | + ssl_SEND_FLAG_NO_RETRANSMIT))); if (len < 0 || !in) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); return SECFailure; @@ -2415,7 +2487,11 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, ssl_GetXmitBufLock(ss); } toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH); - sent = ssl3_SendRecord(ss, content_application_data, + /* + * Note that the 0 epoch is OK because flags will never require + * its use, as guaranteed by the PORT_Assert above. + */ + sent = ssl3_SendRecord(ss, 0, content_application_data, in + totalSent, toSend, flags); if (sent < 0) { if (totalSent > 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR) { @@ -2450,10 +2526,15 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, return totalSent + discarded; } -/* Attempt to send the content of sendBuf buffer in an SSL handshake record. +/* Attempt to send buffered handshake messages. * This function returns SECSuccess or SECFailure, never SECWouldBlock. * Always set sendBuf.len to 0, even when returning SECFailure. * + * Depending on whether we are doing DTLS or not, this either calls + * + * - ssl3_FlushHandshakeMessages if non-DTLS + * - dtls_FlushHandshakeMessages if DTLS + * * Called from SSL3_SendAlert(), ssl3_SendChangeCipherSpecs(), * ssl3_AppendHandshake(), ssl3_SendClientHello(), * ssl3_SendHelloRequest(), ssl3_SendServerHelloDone(), @@ -2462,6 +2543,22 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, static SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags) { + if (IS_DTLS(ss)) { + return dtls_FlushHandshakeMessages(ss, flags); + } else { + return ssl3_FlushHandshakeMessages(ss, flags); + } +} + +/* Attempt to send the content of sendBuf buffer in an SSL handshake record. + * This function returns SECSuccess or SECFailure, never SECWouldBlock. + * Always set sendBuf.len to 0, even when returning SECFailure. + * + * Called from ssl3_FlushHandshake + */ +static SECStatus +ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags) +{ PRInt32 rv = SECSuccess; PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); @@ -2476,7 +2573,7 @@ ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags) PORT_SetError(SEC_ERROR_INVALID_ARGS); rv = SECFailure; } else { - rv = ssl3_SendRecord(ss, content_handshake, ss->sec.ci.sendBuf.buf, + rv = ssl3_SendRecord(ss, 0, content_handshake, ss->sec.ci.sendBuf.buf, ss->sec.ci.sendBuf.len, flags); } if (rv < 0) { @@ -2593,7 +2690,7 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc) rv = ssl3_FlushHandshake(ss, ssl_SEND_FLAG_FORCE_INTO_BUFFER); if (rv == SECSuccess) { PRInt32 sent; - sent = ssl3_SendRecord(ss, content_alert, bytes, 2, + sent = ssl3_SendRecord(ss, 0, content_alert, bytes, 2, desc == no_certificate ? ssl_SEND_FLAG_FORCE_INTO_BUFFER : 0); rv = (sent >= 0) ? SECSuccess : (SECStatus)sent; @@ -2667,7 +2764,7 @@ ssl3_SendAlertForCertError(sslSocket * ss, PRErrorCode errCode) /* * Send handshake_Failure alert. Set generic error number. */ -static SECStatus +SECStatus ssl3_DecodeError(sslSocket *ss) { (void)SSL3_SendAlert(ss, alert_fatal, @@ -2755,7 +2852,8 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) default: error = SSL_ERROR_RX_UNKNOWN_ALERT; break; } if (level == alert_fatal) { - ss->sec.uncache(ss->sec.ci.sid); + if (!ss->opt.noCache) + ss->sec.uncache(ss->sec.ci.sid); if ((ss->ssl3.hs.ws == wait_server_hello) && (desc == handshake_failure)) { /* XXX This is a hack. We're assuming that any handshake failure @@ -2806,17 +2904,22 @@ ssl3_SendChangeCipherSpecs(sslSocket *ss) if (rv != SECSuccess) { return rv; /* error code set by ssl3_FlushHandshake */ } - sent = ssl3_SendRecord(ss, content_change_cipher_spec, &change, 1, - ssl_SEND_FLAG_FORCE_INTO_BUFFER); - if (sent < 0) { - return (SECStatus)sent; /* error code set by ssl3_SendRecord */ + if (!IS_DTLS(ss)) { + sent = ssl3_SendRecord(ss, 0, content_change_cipher_spec, &change, 1, + ssl_SEND_FLAG_FORCE_INTO_BUFFER); + if (sent < 0) { + return (SECStatus)sent; /* error code set by ssl3_SendRecord */ + } + } else { + rv = dtls_QueueMessage(ss, content_change_cipher_spec, &change, 1); + if (rv != SECSuccess) { + return rv; + } } /* swap the pending and current write specs. */ ssl_GetSpecWriteLock(ss); /**************************************/ pwSpec = ss->ssl3.pwSpec; - pwSpec->write_seq_num.high = 0; - pwSpec->write_seq_num.low = 0; ss->ssl3.pwSpec = ss->ssl3.cwSpec; ss->ssl3.cwSpec = pwSpec; @@ -2829,7 +2932,14 @@ ssl3_SendChangeCipherSpecs(sslSocket *ss) * (Both the read and write sides have changed) destroy it. */ if (ss->ssl3.prSpec == ss->ssl3.pwSpec) { - ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE/*freeSrvName*/); + if (!IS_DTLS(ss)) { + ssl3_DestroyCipherSpec(ss->ssl3.pwSpec, PR_FALSE/*freeSrvName*/); + } else { + /* With DTLS, we need to set a holddown timer in case the final + * message got lost */ + ss->ssl3.hs.rtTimeoutMs = DTLS_FINISHED_TIMER_MS; + dtls_StartTimer(ss, dtls_FinishedTimerCb); + } } ssl_ReleaseSpecWriteLock(ss); /**************************************/ @@ -2878,7 +2988,6 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) /* Swap the pending and current read specs. */ ssl_GetSpecWriteLock(ss); /*************************************/ prSpec = ss->ssl3.prSpec; - prSpec->read_seq_num.high = prSpec->read_seq_num.low = 0; ss->ssl3.prSpec = ss->ssl3.crSpec; ss->ssl3.crSpec = prSpec; @@ -2981,6 +3090,11 @@ ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms) if (!isDH && pwSpec->master_secret && ss->opt.detectRollBack) { SSL3ProtocolVersion client_version; client_version = pms_version.major << 8 | pms_version.minor; + + if (IS_DTLS(ss)) { + client_version = dtls_DTLSVersionToTLSVersion(client_version); + } + if (client_version != ss->clientHelloVersion) { /* Destroy it. Version roll-back detected. */ PK11_FreeSymKey(pwSpec->master_secret); @@ -3405,6 +3519,17 @@ ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length) { SECStatus rv; + /* If we already have a message in place, we need to enqueue it. + * This empties the buffer. This is a convenient place to call + * dtls_StageHandshakeMessage to mark the message boundary. + */ + if (IS_DTLS(ss)) { + rv = dtls_StageHandshakeMessage(ss); + if (rv != SECSuccess) { + return rv; + } + } + SSL_TRC(30,("%d: SSL3[%d]: append handshake header: type %s", SSL_GETPID(), ss->fd, ssl3_DecodeHandshakeType(t))); PRINT_BUF(60, (ss, "MD5 handshake hash:", @@ -3417,6 +3542,32 @@ ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length) return rv; /* error code set by AppendHandshake, if applicable. */ } rv = ssl3_AppendHandshakeNumber(ss, length, 3); + if (rv != SECSuccess) { + return rv; /* error code set by AppendHandshake, if applicable. */ + } + + if (IS_DTLS(ss)) { + /* Note that we make an unfragmented message here. We fragment in the + * transmission code, if necessary */ + rv = ssl3_AppendHandshakeNumber(ss, ss->ssl3.hs.sendMessageSeq, 2); + if (rv != SECSuccess) { + return rv; /* error code set by AppendHandshake, if applicable. */ + } + ss->ssl3.hs.sendMessageSeq++; + + /* 0 is the fragment offset, because it's not fragmented yet */ + rv = ssl3_AppendHandshakeNumber(ss, 0, 3); + if (rv != SECSuccess) { + return rv; /* error code set by AppendHandshake, if applicable. */ + } + + /* Fragment length -- set to the packet length because not fragmented */ + rv = ssl3_AppendHandshakeNumber(ss, length, 3); + if (rv != SECSuccess) { + return rv; /* error code set by AppendHandshake, if applicable. */ + } + } + return rv; /* error code set by AppendHandshake, if applicable. */ } @@ -3823,9 +3974,10 @@ done: /* Called from ssl3_HandleHelloRequest(), * ssl3_RedoHandshake() * ssl2_BeginClientHandshake (when resuming ssl3 session) + * dtls_HandleHelloVerifyRequest(with resending=PR_TRUE) */ SECStatus -ssl3_SendClientHello(sslSocket *ss) +ssl3_SendClientHello(sslSocket *ss, PRBool resending) { sslSessionID * sid; ssl3CipherSpec * cwSpec; @@ -3849,6 +4001,7 @@ ssl3_SendClientHello(sslSocket *ss) return rv; /* ssl3_InitState has set the error code. */ } ss->ssl3.hs.sendingSCSV = PR_FALSE; /* Must be reset every handshake */ + PORT_Assert(IS_DTLS(ss) || !resending); /* We might be starting a session renegotiation in which case we should * clear previous state. @@ -4008,6 +4161,10 @@ ssl3_SendClientHello(sslSocket *ss) } #endif + if (IS_DTLS(ss)) { + ssl3_DisableNonDTLSSuites(ss); + } + /* how many suites are permitted by policy and user preference? */ num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE); if (!num_suites) @@ -4027,6 +4184,9 @@ ssl3_SendClientHello(sslSocket *ss) 1 + ((sid == NULL) ? 0 : sid->u.ssl3.sessionIDLength) + 2 + num_suites*sizeof(ssl3CipherSuite) + 1 + numCompressionMethods + total_exten_len; + if (IS_DTLS(ss)) { + length += 1 + ss->ssl3.hs.cookieLen; + } rv = ssl3_AppendHandshakeHeader(ss, client_hello, length); if (rv != SECSuccess) { @@ -4034,13 +4194,23 @@ ssl3_SendClientHello(sslSocket *ss) } ss->clientHelloVersion = ss->version; - rv = ssl3_AppendHandshakeNumber(ss, ss->clientHelloVersion, 2); + if (IS_DTLS(ss)) { + PRUint16 version; + + version = dtls_TLSVersionToDTLSVersion(ss->clientHelloVersion); + rv = ssl3_AppendHandshakeNumber(ss, version, 2); + } else { + rv = ssl3_AppendHandshakeNumber(ss, ss->clientHelloVersion, 2); + } if (rv != SECSuccess) { return rv; /* err set by ssl3_AppendHandshake* */ } - rv = ssl3_GetNewRandom(&ss->ssl3.hs.client_random); - if (rv != SECSuccess) { - return rv; /* err set by GetNewRandom. */ + + if (!resending) { /* Don't re-generate if we are in DTLS re-sending mode */ + rv = ssl3_GetNewRandom(&ss->ssl3.hs.client_random); + if (rv != SECSuccess) { + return rv; /* err set by GetNewRandom. */ + } } rv = ssl3_AppendHandshake(ss, &ss->ssl3.hs.client_random, SSL3_RANDOM_LENGTH); @@ -4057,6 +4227,14 @@ ssl3_SendClientHello(sslSocket *ss) return rv; /* err set by ssl3_AppendHandshake* */ } + if (IS_DTLS(ss)) { + rv = ssl3_AppendHandshakeVariable( + ss, ss->ssl3.hs.cookie, ss->ssl3.hs.cookieLen, 1); + if (rv != SECSuccess) { + return rv; /* err set by ssl3_AppendHandshake* */ + } + } + rv = ssl3_AppendHandshakeNumber(ss, num_suites*sizeof(ssl3CipherSuite), 2); if (rv != SECSuccess) { return rv; /* err set by ssl3_AppendHandshake* */ @@ -4180,8 +4358,12 @@ ssl3_HandleHelloRequest(sslSocket *ss) ss->sec.ci.sid = NULL; } + if (IS_DTLS(ss)) { + dtls_RehandshakeCleanup(ss); + } + ssl_GetXmitBufLock(ss); - rv = ssl3_SendClientHello(ss); + rv = ssl3_SendClientHello(ss, PR_FALSE); ssl_ReleaseXmitBufLock(ss); return rv; @@ -5036,6 +5218,23 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } version = (SSL3ProtocolVersion)temp; + if (IS_DTLS(ss)) { + /* RFC 4347 required that you verify that the server versions + * match (Section 4.2.1) in the HelloVerifyRequest and the + * ServerHello. + * + * RFC 6347 suggests (SHOULD) that servers always use 1.0 + * in HelloVerifyRequest and allows the versions not to match, + * especially when 1.2 is being negotiated. + * + * Therefore we do not check for matching here. + */ + version = dtls_DTLSVersionToTLSVersion(version); + if (version == 0) { /* Insane version number */ + goto alert_loser; + } + } + rv = ssl3_NegotiateVersion(ss, version, PR_FALSE); if (rv != SECSuccess) { desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version @@ -6264,6 +6463,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SSL3AlertLevel level = alert_fatal; SSL3ProtocolVersion version; SECItem sidBytes = {siBuffer, NULL, 0}; + SECItem cookieBytes = {siBuffer, NULL, 0}; SECItem suites = {siBuffer, NULL, 0}; SECItem comps = {siBuffer, NULL, 0}; PRBool haveSpecWriteLock = PR_FALSE; @@ -6281,6 +6481,20 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) return rv; /* error code is set. */ } + /* Clearing the handshake pointers so that ssl_Do1stHandshake won't + * call ssl2_HandleMessage. + * + * The issue here is that TLS ordinarily starts out in + * ssl2_HandleV3HandshakeRecord() because of the backward-compatibility + * code paths. That function zeroes these next pointers. But with DTLS, + * we don't even try to do the v2 ClientHello so we skip that function + * and need to reset these values here. + */ + if (IS_DTLS(ss)) { + ss->nextHandshake = 0; + ss->securityHandshake = 0; + } + /* We might be starting session renegotiation in which case we should * clear previous state. */ @@ -6306,10 +6520,22 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto alert_loser; } + if (IS_DTLS(ss)) { + dtls_RehandshakeCleanup(ss); + } + tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); if (tmp < 0) goto loser; /* malformed, alert already sent */ - ss->clientHelloVersion = version = (SSL3ProtocolVersion)tmp; + + /* Translate the version */ + if (IS_DTLS(ss)) { + ss->clientHelloVersion = version = + dtls_DTLSVersionToTLSVersion((SSL3ProtocolVersion)tmp); + } else { + ss->clientHelloVersion = version = (SSL3ProtocolVersion)tmp; + } + rv = ssl3_NegotiateVersion(ss, version, PR_TRUE); if (rv != SECSuccess) { desc = (version > SSL_LIBRARY_VERSION_3_0) ? protocol_version @@ -6331,6 +6557,14 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto loser; /* malformed */ } + /* grab the client's cookie, if present. */ + if (IS_DTLS(ss)) { + rv = ssl3_ConsumeHandshakeVariable(ss, &cookieBytes, 1, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed */ + } + } + /* grab the list of cipher suites. */ rv = ssl3_ConsumeHandshakeVariable(ss, &suites, 2, &b, &length); if (rv != SECSuccess) { @@ -6479,6 +6713,10 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ssl3_FilterECCipherSuitesByServerCerts(ss); #endif + if (IS_DTLS(ss)) { + ssl3_DisableNonDTLSSuites(ss); + } + #ifdef PARANOID /* Look for a matching cipher suite. */ j = ssl3_config_match_init(ss); @@ -7166,17 +7404,28 @@ ssl3_SendServerHello(sslSocket *ss) PRUint32 maxBytes = 65535; PRUint32 length; PRInt32 extensions_len = 0; + SSL3ProtocolVersion version; SSL_TRC(3, ("%d: SSL3[%d]: send server_hello handshake", SSL_GETPID(), ss->fd)); PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert( MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_3_0)); - if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_3_0)) { - PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); - return SECFailure; + if (!IS_DTLS(ss)) { + PORT_Assert(MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_3_0)); + + if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_3_0)) { + PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); + return SECFailure; + } + } else { + PORT_Assert(MSB(ss->version) == MSB(SSL_LIBRARY_VERSION_DTLS_1_0)); + + if (MSB(ss->version) != MSB(SSL_LIBRARY_VERSION_DTLS_1_0)) { + PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); + return SECFailure; + } } sid = ss->sec.ci.sid; @@ -7194,7 +7443,13 @@ ssl3_SendServerHello(sslSocket *ss) return rv; /* err set by AppendHandshake. */ } - rv = ssl3_AppendHandshakeNumber(ss, ss->version, 2); + if (IS_DTLS(ss)) { + version = dtls_TLSVersionToDTLSVersion(ss->version); + } else { + version = ss->version; + } + + rv = ssl3_AppendHandshakeNumber(ss, version, 2); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } @@ -7379,11 +7634,8 @@ ssl3_SendCertificateRequest(sslSocket *ss) nnames = ca_list->nnames; } - if (!nnames) { - PORT_SetError(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA); - return SECFailure; - } - + /* There used to be a test here to require a CA, but there + * are cases where you want to have no CAs offered. */ for (i = 0, name = names; i < nnames; i++, name++) { calen += 2 + name->len; } @@ -7551,8 +7803,16 @@ ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, } /* Generate the pre-master secret ... */ - version.major = MSB(ss->clientHelloVersion); - version.minor = LSB(ss->clientHelloVersion); + if (IS_DTLS(ss)) { + SSL3ProtocolVersion temp; + + temp = dtls_TLSVersionToDTLSVersion(ss->clientHelloVersion); + version.major = MSB(temp); + version.minor = LSB(temp); + } else { + version.major = MSB(ss->clientHelloVersion); + version.minor = LSB(ss->clientHelloVersion); + } param.data = (unsigned char *)&version; param.len = sizeof version; @@ -7635,6 +7895,11 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss, } else if (ss->opt.detectRollBack) { SSL3ProtocolVersion client_version = (rsaPmsBuf[0] << 8) | rsaPmsBuf[1]; + + if (IS_DTLS(ss)) { + client_version = dtls_DTLSVersionToTLSVersion(client_version); + } + if (client_version != ss->clientHelloVersion) { /* Version roll-back detected. ensure failure. */ rv = PK11_GenerateRandom(rsaPmsBuf, sizeof rsaPmsBuf); @@ -8851,6 +9116,10 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, } } + if (IS_DTLS(ss)) { + flags |= ssl_SEND_FLAG_NO_RETRANSMIT; + } + rv = ssl3_SendFinished(ss, flags); if (rv != SECSuccess) { goto xmit_loser; /* err is set. */ @@ -8980,13 +9249,14 @@ ssl3_MaybeHandlePendingCertificateMessage(sslSocket *ss) * hanshake message. * Caller must hold Handshake and RecvBuf locks. */ -static SECStatus +SECStatus ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length) { SECStatus rv = SECSuccess; SSL3HandshakeType type = ss->ssl3.hs.msg_type; SSL3Hashes hashes; /* computed hashes are put here. */ PRUint8 hdr[4]; + PRUint8 dtlsData[8]; PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); @@ -9032,10 +9302,35 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length) return rv; } } - /* We should not include hello_request messages in the handshake hashes */ - if (ss->ssl3.hs.msg_type != hello_request) { + /* We should not include hello_request and hello_verify_request messages + * in the handshake hashes */ + if ((ss->ssl3.hs.msg_type != hello_request) && + (ss->ssl3.hs.msg_type != hello_verify_request)) { rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char*) hdr, 4); if (rv != SECSuccess) return rv; /* err code already set. */ + + /* Extra data to simulate a complete DTLS handshake fragment */ + if (IS_DTLS(ss)) { + /* Sequence number */ + dtlsData[0] = MSB(ss->ssl3.hs.recvMessageSeq); + dtlsData[1] = LSB(ss->ssl3.hs.recvMessageSeq); + + /* Fragment offset */ + dtlsData[2] = 0; + dtlsData[3] = 0; + dtlsData[4] = 0; + + /* Fragment length */ + dtlsData[5] = (PRUint8)(length >> 16); + dtlsData[6] = (PRUint8)(length >> 8); + dtlsData[7] = (PRUint8)(length ); + + rv = ssl3_UpdateHandshakeHashes(ss, (unsigned char*) dtlsData, + sizeof(dtlsData)); + if (rv != SECSuccess) return rv; /* err code already set. */ + } + + /* The message body */ rv = ssl3_UpdateHandshakeHashes(ss, b, length); if (rv != SECSuccess) return rv; /* err code already set. */ } @@ -9071,6 +9366,14 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } rv = ssl3_HandleServerHello(ss, b, length); break; + case hello_verify_request: + if (!IS_DTLS(ss) || ss->sec.isServer) { + (void)SSL3_SendAlert(ss, alert_fatal, unexpected_message); + PORT_SetError(SSL_ERROR_RX_UNEXPECTED_HELLO_VERIFY_REQUEST); + return SECFailure; + } + rv = dtls_HandleHelloVerifyRequest(ss, b, length); + break; case certificate: if (ss->ssl3.hs.may_get_cert_status) { /* If we might get a CertificateStatus then we want to postpone the @@ -9169,6 +9472,12 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length) PORT_SetError(SSL_ERROR_RX_UNKNOWN_HANDSHAKE); rv = SECFailure; } + + if (IS_DTLS(ss) && (rv == SECSuccess)) { + /* Increment the expected sequence number */ + ss->ssl3.hs.recvMessageSeq++; + } + return rv; } @@ -9331,6 +9640,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) SSL3Opaque hash[MAX_MAC_LENGTH]; sslBuffer *plaintext; sslBuffer temp_buf; + PRUint64 dtls_seq_num; unsigned int ivLen = 0; PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); @@ -9366,6 +9676,39 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) crSpec = ss->ssl3.crSpec; cipher_def = crSpec->cipher_def; + /* + * DTLS relevance checks: + * Note that this code currently ignores all out-of-epoch packets, + * which means we lose some in the case of rehandshake + + * loss/reordering. Since DTLS is explicitly unreliable, this + * seems like a good tradeoff for implementation effort and is + * consistent with the guidance of RFC 6347 Sections 4.1 and 4.2.4.1 + */ + if (IS_DTLS(ss)) { + DTLSEpoch epoch = (cText->seq_num.high >> 16) & 0xffff; + + if (crSpec->epoch != epoch) { + ssl_ReleaseSpecReadLock(ss); + SSL_DBG(("%d: SSL3[%d]: HandleRecord, received packet " + "from irrelevant epoch %d", SSL_GETPID(), ss->fd, epoch)); + /* Silently drop the packet */ + databuf->len = 0; /* Needed to ensure data not left around */ + return SECSuccess; + } + + dtls_seq_num = (((PRUint64)(cText->seq_num.high & 0xffff)) << 32) | + ((PRUint64)cText->seq_num.low); + + if (dtls_RecordGetRecvd(&crSpec->recvdRecords, dtls_seq_num) != 0) { + ssl_ReleaseSpecReadLock(ss); + SSL_DBG(("%d: SSL3[%d]: HandleRecord, rejecting " + "potentially replayed packet", SSL_GETPID(), ss->fd)); + /* Silently drop the packet */ + databuf->len = 0; /* Needed to ensure data not left around */ + return SECSuccess; + } + } + if (cipher_def->type == type_block && crSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) { /* Consume the per-record explicit IV. RFC 4346 Section 6.2.3.2 states @@ -9487,7 +9830,8 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) /* compute the MAC */ rType = cText->type; rv = ssl3_ComputeRecordMAC( crSpec, (PRBool)(!ss->sec.isServer), - rType, cText->version, crSpec->read_seq_num, + IS_DTLS(ss), rType, cText->version, + IS_DTLS(ss) ? cText->seq_num : crSpec->read_seq_num, plaintext->buf, plaintext->len, hash, &hashBytes); if (rv != SECSuccess) { padIsBad = PR_TRUE; /* really macIsBad */ @@ -9499,18 +9843,26 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) crSpec->mac_size) != 0) { /* must not hold spec lock when calling SSL3_SendAlert. */ ssl_ReleaseSpecReadLock(ss); - SSL3_SendAlert(ss, alert_fatal, bad_record_mac); - /* always log mac error, in case attacker can read server logs. */ - PORT_SetError(SSL_ERROR_BAD_MAC_READ); SSL_DBG(("%d: SSL3[%d]: mac check failed", SSL_GETPID(), ss->fd)); - return SECFailure; + if (!IS_DTLS(ss)) { + SSL3_SendAlert(ss, alert_fatal, bad_record_mac); + /* always log mac error, in case attacker can read server logs. */ + PORT_SetError(SSL_ERROR_BAD_MAC_READ); + return SECFailure; + } else { + /* Silently drop the packet */ + databuf->len = 0; /* Needed to ensure data not left around */ + return SECSuccess; + } } - - - ssl3_BumpSequenceNumber(&crSpec->read_seq_num); + if (!IS_DTLS(ss)) { + ssl3_BumpSequenceNumber(&crSpec->read_seq_num); + } else { + dtls_RecordSetRecvd(&crSpec->recvdRecords, dtls_seq_num); + } ssl_ReleaseSpecReadLock(ss); /*****************************************/ @@ -9615,7 +9967,11 @@ process_it: rv = ssl3_HandleAlert(ss, databuf); break; case content_handshake: - rv = ssl3_HandleHandshake(ss, databuf); + if (!IS_DTLS(ss)) { + rv = ssl3_HandleHandshake(ss, databuf); + } else { + rv = dtls_HandleHandshake(ss, databuf); + } break; /* case content_application_data is handled before this switch @@ -9675,6 +10031,9 @@ ssl3_InitCipherSpec(sslSocket *ss, ssl3CipherSpec *spec) spec->read_seq_num.high = 0; spec->read_seq_num.low = 0; + spec->epoch = 0; + dtls_InitRecvdRecords(&spec->recvdRecords); + spec->version = ss->vrange.max; } @@ -9716,6 +10075,21 @@ ssl3_InitState(sslSocket *ss) PORT_Memset(&ss->xtnData, 0, sizeof(TLSExtensionData)); + if (IS_DTLS(ss)) { + ss->ssl3.hs.sendMessageSeq = 0; + ss->ssl3.hs.recvMessageSeq = 0; + ss->ssl3.hs.rtTimeoutMs = INITIAL_DTLS_TIMEOUT_MS; + ss->ssl3.hs.rtRetries = 0; + + /* Have to allocate this because ssl_FreeSocket relocates + * this structure in DEBUG mode */ + if (!(ss->ssl3.hs.lastMessageFlight = PORT_New(PRCList))) + return SECFailure; + ss->ssl3.hs.recvdHighWater = -1; + PR_INIT_CLIST(ss->ssl3.hs.lastMessageFlight); + dtls_SetMTU(ss, 0); /* Set the MTU to the highest plateau */ + } + rv = ssl3_NewHandshakeHashes(ss); if (rv == SECSuccess) { ss->ssl3.initialized = PR_TRUE; @@ -9968,6 +10342,11 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache) PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); return SECFailure; } + + if (IS_DTLS(ss)) { + dtls_RehandshakeCleanup(ss); + } + if (ss->opt.enableRenegotiation == SSL_RENEGOTIATE_NEVER) { PORT_SetError(SSL_ERROR_RENEGOTIATION_NOT_ALLOWED); return SECFailure; @@ -9982,7 +10361,7 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache) /* start off a new handshake. */ rv = (ss->sec.isServer) ? ssl3_SendHelloRequest(ss) - : ssl3_SendClientHello(ss); + : ssl3_SendClientHello(ss, PR_FALSE); ssl_ReleaseXmitBufLock(ss); /**************************************/ return rv; @@ -10042,6 +10421,17 @@ ssl3_DestroySSL3Info(sslSocket *ss) ssl3_DestroyCipherSpec(&ss->ssl3.specs[0], PR_TRUE/*freeSrvName*/); ssl3_DestroyCipherSpec(&ss->ssl3.specs[1], PR_TRUE/*freeSrvName*/); + /* Destroy the DTLS data */ + if (IS_DTLS(ss)) { + if (ss->ssl3.hs.lastMessageFlight) { + dtls_FreeHandshakeMessages(ss->ssl3.hs.lastMessageFlight); + PORT_Free(ss->ssl3.hs.lastMessageFlight); + } + if (ss->ssl3.hs.recvdFragments.buf) { + PORT_Free(ss->ssl3.hs.recvdFragments.buf); + } + } + ss->ssl3.initialized = PR_FALSE; SECITEM_FreeItem(&ss->ssl3.nextProto, PR_FALSE); |