Index: net/third_party/nss/ssl/ssl3con.c |
=================================================================== |
--- net/third_party/nss/ssl/ssl3con.c (revision 127709) |
+++ net/third_party/nss/ssl/ssl3con.c (working copy) |
@@ -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_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 @@ |
#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 @@ |
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 @@ |
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_DestroySSL3Info |
** Caller must hold SpecWriteLock. |
*/ |
-static void |
+void |
ssl3_DestroyCipherSpec(ssl3CipherSpec *spec, PRBool freeSrvName) |
{ |
PRBool freeit = (PRBool)(!spec->bypassCiphers); |
@@ -1228,6 +1216,12 @@ |
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 @@ |
ssl3_InitPendingCipherSpec(sslSocket *ss, PK11SymKey *pms) |
{ |
ssl3CipherSpec * pwSpec; |
+ ssl3CipherSpec * cwSpec; |
SECStatus rv; |
PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); |
@@ -1763,6 +1758,7 @@ |
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,7 +1790,32 @@ |
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); /******************************/ |
if (rv != SECSuccess) |
@@ -1834,6 +1855,7 @@ |
ssl3_ComputeRecordMAC( |
ssl3CipherSpec * spec, |
PRBool useServerMacKey, |
+ PRBool isDTLS, |
SSL3ContentType type, |
SSL3ProtocolVersion version, |
SSL3SequenceNumber seq_num, |
@@ -1871,8 +1893,16 @@ |
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 @@ |
} |
/* 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 @@ |
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 @@ |
* 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 @@ |
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 @@ |
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 @@ |
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 @@ |
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,15 +2196,33 @@ |
} |
PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024); |
+ wrBuf->len = cipherBytes + headerLen; |
+ wrBuf->buf[0] = type; |
+ 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); |
- wrBuf->len = cipherBytes + SSL3_RECORD_HEADER_LENGTH; |
- 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); |
- |
return SECSuccess; |
} |
@@ -2194,10 +2244,13 @@ |
* 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 @@ |
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 @@ |
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 @@ |
} |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
/* |
* 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 @@ |
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 @@ |
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 @@ |
* (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 @@ |
/* 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 @@ |
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 @@ |
{ |
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 @@ |
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 @@ |
/* 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 @@ |
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 @@ |
} |
#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 @@ |
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 @@ |
} |
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 @@ |
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 @@ |
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 @@ |
} |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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_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 @@ |
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 @@ |
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 @@ |
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,9 +7803,17 @@ |
} |
/* 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 @@ |
} 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 @@ |
} |
} |
+ 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 @@ |
* 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 @@ |
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 @@ |
} |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
/* 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,19 +9843,27 @@ |
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; |
+ } |
} |
+ if (!IS_DTLS(ss)) { |
+ ssl3_BumpSequenceNumber(&crSpec->read_seq_num); |
+ } else { |
+ dtls_RecordSetRecvd(&crSpec->recvdRecords, dtls_seq_num); |
+ } |
- |
- ssl3_BumpSequenceNumber(&crSpec->read_seq_num); |
- |
ssl_ReleaseSpecReadLock(ss); /*****************************************/ |
/* |
@@ -9615,7 +9967,11 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
/* 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_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); |