| 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);
|
|
|