diff options
Diffstat (limited to 'security/nss/lib/ssl')
35 files changed, 2833 insertions, 2290 deletions
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h index b0319b86c..b73fb6bd0 100644 --- a/security/nss/lib/ssl/SSLerrs.h +++ b/security/nss/lib/ssl/SSLerrs.h @@ -504,4 +504,10 @@ ER3(SSL_ERROR_MALFORMED_PSK_KEY_EXCHANGE_MODES, (SSL_ERROR_BASE + 158), "SSL received a malformed PSK key exchange modes extension.") ER3(SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES, (SSL_ERROR_BASE + 159), - "SSL expected a missing PSK key exchange modes extension.") + "SSL expected a PSK key exchange modes extension.") + +ER3(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA, (SSL_ERROR_BASE + 160), + "SSL got a pre-TLS 1.3 version even though we sent early data.") + +ER3(SSL_ERROR_TOO_MUCH_EARLY_DATA, (SSL_ERROR_BASE + 161), + "SSL received more early data than permitted.") diff --git a/security/nss/lib/ssl/config.mk b/security/nss/lib/ssl/config.mk index 339cc80df..c8b053cab 100644 --- a/security/nss/lib/ssl/config.mk +++ b/security/nss/lib/ssl/config.mk @@ -62,10 +62,6 @@ DEFINES += -DNSS_SSL_ENABLE_ZLIB include $(CORE_DEPTH)/coreconf/zlib.mk endif -ifndef NSS_ENABLE_TLS_1_3 -NSS_DISABLE_TLS_1_3=1 -endif - ifdef NSS_DISABLE_TLS_1_3 DEFINES += -DNSS_DISABLE_TLS_1_3 endif diff --git a/security/nss/lib/ssl/dtlscon.c b/security/nss/lib/ssl/dtlscon.c index 09ceeac23..fbd1779db 100644 --- a/security/nss/lib/ssl/dtlscon.c +++ b/security/nss/lib/ssl/dtlscon.c @@ -235,6 +235,26 @@ dtls_RetransmitDetected(sslSocket *ss) return rv; } +static SECStatus +dtls_HandleHandshakeMessage(sslSocket *ss, PRUint8 *data, PRBool last) +{ + + /* At this point we are advancing our state machine, so we can free our last + * flight of messages. */ + dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); + ss->ssl3.hs.recvdHighWater = -1; + + /* Reset the timer to the initial value if the retry counter + * is 0, per Sec. 4.2.4.1 */ + dtls_CancelTimer(ss); + if (ss->ssl3.hs.rtRetries == 0) { + ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS; + } + + return ssl3_HandleHandshakeMessage(ss, data, ss->ssl3.hs.msg_len, + last); +} + /* Called only from ssl3_HandleRecord, for each (deciphered) DTLS record. * origBuf is the decrypted ssl record content and is expected to contain * complete handshake records @@ -329,23 +349,10 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) ss->ssl3.hs.msg_type = (SSL3HandshakeType)type; ss->ssl3.hs.msg_len = message_length; - /* At this point we are advancing our state machine, so - * we can free our last flight of messages */ - dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); - ss->ssl3.hs.recvdHighWater = -1; - dtls_CancelTimer(ss); - - /* Reset the timer to the initial value if the retry counter - * is 0, per Sec. 4.2.4.1 */ - if (ss->ssl3.hs.rtRetries == 0) { - ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS; - } - - rv = ssl3_HandleHandshakeMessage(ss, buf.buf, ss->ssl3.hs.msg_len, + rv = dtls_HandleHandshakeMessage(ss, buf.buf, buf.len == fragment_length); if (rv == SECFailure) { - /* Do not attempt to process rest of messages in this record */ - break; + break; /* Discard the remainder of the record. */ } } else { if (message_seq < ss->ssl3.hs.recvMessageSeq) { @@ -446,24 +453,11 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) /* If we have all the bytes, then we are good to go */ if (ss->ssl3.hs.recvdHighWater == ss->ssl3.hs.msg_len) { - ss->ssl3.hs.recvdHighWater = -1; + rv = dtls_HandleHandshakeMessage(ss, ss->ssl3.hs.msg_body.buf, + buf.len == fragment_length); - rv = ssl3_HandleHandshakeMessage( - ss, - ss->ssl3.hs.msg_body.buf, ss->ssl3.hs.msg_len, - buf.len == fragment_length); - if (rv == SECFailure) - break; /* Skip rest of record */ - - /* At this point we are advancing our state machine, so - * we can free our last flight of messages */ - dtls_FreeHandshakeMessages(&ss->ssl3.hs.lastMessageFlight); - dtls_CancelTimer(ss); - - /* If there have been no retries this time, reset the - * timer value to the default per Section 4.2.4.1 */ - if (ss->ssl3.hs.rtRetries == 0) { - ss->ssl3.hs.rtTimeoutMs = DTLS_RETRANSMIT_INITIAL_MS; + if (rv == SECFailure) { + break; /* Discard the rest of the record. */ } } } @@ -488,7 +482,7 @@ dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf) */ SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type, - const SSL3Opaque *pIn, PRInt32 nIn) + const PRUint8 *pIn, PRInt32 nIn) { SECStatus rv = SECSuccess; DTLSQueuedMessage *msg = NULL; @@ -947,7 +941,7 @@ dtls_SetMTU(sslSocket *ss, PRUint16 advertised) * Caller must hold Handshake and RecvBuf locks. */ SECStatus -dtls_HandleHelloVerifyRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +dtls_HandleHelloVerifyRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) { int errCode = SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST; SECStatus rv; diff --git a/security/nss/lib/ssl/manifest.mn b/security/nss/lib/ssl/manifest.mn index e7564edb2..fbb88baff 100644 --- a/security/nss/lib/ssl/manifest.mn +++ b/security/nss/lib/ssl/manifest.mn @@ -25,6 +25,7 @@ CSRCS = \ sslauth.c \ sslcon.c \ ssldef.c \ + ssl3encode.c \ sslenum.c \ sslerr.c \ sslerrstrs.c \ @@ -41,6 +42,7 @@ CSRCS = \ sslver.c \ authcert.c \ cmpcert.c \ + selfencrypt.c \ sslinfo.c \ ssl3ecc.c \ tls13con.c \ diff --git a/security/nss/lib/ssl/selfencrypt.c b/security/nss/lib/ssl/selfencrypt.c new file mode 100644 index 000000000..6d6e25cfc --- /dev/null +++ b/security/nss/lib/ssl/selfencrypt.c @@ -0,0 +1,314 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nss.h" +#include "blapit.h" +#include "pk11func.h" +#include "ssl.h" +#include "sslt.h" +#include "ssl3encode.h" +#include "sslimpl.h" +#include "selfencrypt.h" + +static SECStatus +ssl_MacBuffer(PK11SymKey *key, CK_MECHANISM_TYPE mech, + const unsigned char *in, unsigned int len, + unsigned char *mac, unsigned int *macLen, unsigned int maxMacLen) +{ + PK11Context *ctx; + SECItem macParam = { 0, NULL, 0 }; + unsigned int computedLen; + SECStatus rv; + + ctx = PK11_CreateContextBySymKey(mech, CKA_SIGN, key, &macParam); + if (!ctx) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + rv = PK11_DigestBegin(ctx); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto loser; + } + + rv = PK11_DigestOp(ctx, in, len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto loser; + } + + rv = PK11_DigestFinal(ctx, mac, &computedLen, maxMacLen); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto loser; + } + + *macLen = maxMacLen; + PK11_DestroyContext(ctx, PR_TRUE); + return SECSuccess; + +loser: + PK11_DestroyContext(ctx, PR_TRUE); + return SECFailure; +} + +#ifdef UNSAFE_FUZZER_MODE +SECStatus +ssl_SelfEncryptProtectInt( + PK11SymKey *encKey, PK11SymKey *macKey, + const unsigned char *keyName, + const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) +{ + if (inLen > maxOutLen) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + PORT_Memcpy(out, in, inLen); + *outLen = inLen; + + return 0; +} + +SECStatus +ssl_SelfEncryptUnprotectInt( + PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName, + const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) +{ + if (inLen > maxOutLen) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + PORT_Memcpy(out, in, inLen); + *outLen = inLen; + + return 0; +} + +#else +/* + * Structure is. + * + * struct { + * opaque keyName[16]; + * opaque iv[16]; + * opaque ciphertext<16..2^16-1>; + * opaque mac[32]; + * } SelfEncrypted; + * + * We are using AES-CBC + HMAC-SHA256 in Encrypt-then-MAC mode for + * two reasons: + * + * 1. It's what we already used for tickets. + * 2. We don't have to worry about nonce collisions as much + * (the chance is lower because we have a random 128-bit nonce + * and they are less serious than with AES-GCM). + */ +SECStatus +ssl_SelfEncryptProtectInt( + PK11SymKey *encKey, PK11SymKey *macKey, + const unsigned char *keyName, + const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) +{ + unsigned int len; + unsigned char iv[AES_BLOCK_SIZE]; + SECItem ivItem = { siBuffer, iv, sizeof(iv) }; + unsigned char mac[SHA256_LENGTH]; /* SHA-256 */ + unsigned int macLen; + SECItem outItem = { siBuffer, out, maxOutLen }; + SECItem lengthBytesItem; + SECStatus rv; + + /* Generate a random IV */ + rv = PK11_GenerateRandom(iv, sizeof(iv)); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + /* Add header. */ + rv = ssl3_AppendToItem(&outItem, keyName, SELF_ENCRYPT_KEY_NAME_LEN); + if (rv != SECSuccess) { + return SECFailure; + } + rv = ssl3_AppendToItem(&outItem, iv, sizeof(iv)); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Skip forward by two so we can encode the ciphertext in place. */ + lengthBytesItem = outItem; + rv = ssl3_AppendNumberToItem(&outItem, 0, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = PK11_Encrypt(encKey, CKM_AES_CBC_PAD, &ivItem, + outItem.data, &len, outItem.len, in, inLen); + if (rv != SECSuccess) { + return SECFailure; + } + + outItem.data += len; + outItem.len -= len; + + /* Now encode the ciphertext length. */ + rv = ssl3_AppendNumberToItem(&lengthBytesItem, len, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + /* MAC the entire output buffer and append the MAC to the end. */ + rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, + out, outItem.data - out, + mac, &macLen, sizeof(mac)); + if (rv != SECSuccess) { + return SECFailure; + } + PORT_Assert(macLen == sizeof(mac)); + + rv = ssl3_AppendToItem(&outItem, mac, macLen); + if (rv != SECSuccess) { + return SECFailure; + } + + *outLen = outItem.data - out; + return SECSuccess; +} + +SECStatus +ssl_SelfEncryptUnprotectInt( + PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName, + const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) +{ + unsigned char *encodedKeyName; + unsigned char *iv; + SECItem ivItem = { siBuffer, NULL, 0 }; + SECItem inItem = { siBuffer, (unsigned char *)in, inLen }; + unsigned char *cipherText; + PRUint32 cipherTextLen; + unsigned char *encodedMac; + unsigned char computedMac[SHA256_LENGTH]; + unsigned int computedMacLen; + unsigned int bytesToMac; + SECStatus rv; + + rv = ssl3_ConsumeFromItem(&inItem, &encodedKeyName, + SELF_ENCRYPT_KEY_NAME_LEN); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = ssl3_ConsumeFromItem(&inItem, &iv, AES_BLOCK_SIZE); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = ssl3_ConsumeNumberFromItem(&inItem, &cipherTextLen, 2); + if (rv != SECSuccess) { + return SECFailure; + } + + rv = ssl3_ConsumeFromItem(&inItem, &cipherText, cipherTextLen); + if (rv != SECSuccess) { + return SECFailure; + } + bytesToMac = inItem.data - in; + + rv = ssl3_ConsumeFromItem(&inItem, &encodedMac, SHA256_LENGTH); + if (rv != SECSuccess) { + return SECFailure; + } + + /* Make sure we're at the end of the block. */ + if (inItem.len) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + + /* Now that everything is decoded, we can make progress. */ + /* 1. Check that we have the right key. */ + if (PORT_Memcmp(keyName, encodedKeyName, SELF_ENCRYPT_KEY_NAME_LEN)) { + PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT); + return SECFailure; + } + + /* 2. Check the MAC */ + rv = ssl_MacBuffer(macKey, CKM_SHA256_HMAC, in, bytesToMac, + computedMac, &computedMacLen, sizeof(computedMac)); + if (rv != SECSuccess) { + return SECFailure; + } + PORT_Assert(computedMacLen == SHA256_LENGTH); + if (NSS_SecureMemcmp(computedMac, encodedMac, computedMacLen) != 0) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + + /* 3. OK, it verifies, now decrypt. */ + ivItem.data = iv; + ivItem.len = AES_BLOCK_SIZE; + rv = PK11_Decrypt(encKey, CKM_AES_CBC_PAD, &ivItem, + out, outLen, maxOutLen, cipherText, cipherTextLen); + if (rv != SECSuccess) { + return SECFailure; + } + + return SECSuccess; +} +#endif + +SECStatus +ssl_SelfEncryptProtect( + sslSocket *ss, const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) +{ + PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN]; + PK11SymKey *encKey; + PK11SymKey *macKey; + SECStatus rv; + + /* Get session ticket keys. */ + rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey); + if (rv != SECSuccess) { + SSL_DBG(("%d: SSL[%d]: Unable to get/generate self-encrypt keys.", + SSL_GETPID(), ss->fd)); + return SECFailure; + } + + return ssl_SelfEncryptProtectInt(encKey, macKey, keyName, + in, inLen, out, outLen, maxOutLen); +} + +SECStatus +ssl_SelfEncryptUnprotect( + sslSocket *ss, const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen) +{ + PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN]; + PK11SymKey *encKey; + PK11SymKey *macKey; + SECStatus rv; + + /* Get session ticket keys. */ + rv = ssl_GetSelfEncryptKeys(ss, keyName, &encKey, &macKey); + if (rv != SECSuccess) { + SSL_DBG(("%d: SSL[%d]: Unable to get/generate self-encrypt keys.", + SSL_GETPID(), ss->fd)); + return SECFailure; + } + + return ssl_SelfEncryptUnprotectInt(encKey, macKey, keyName, + in, inLen, out, outLen, maxOutLen); +} diff --git a/security/nss/lib/ssl/selfencrypt.h b/security/nss/lib/ssl/selfencrypt.h new file mode 100644 index 000000000..5bc8e4348 --- /dev/null +++ b/security/nss/lib/ssl/selfencrypt.h @@ -0,0 +1,31 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __selfencrypt_h_ +#define __selfencrypt_h_ + +#include "secmodt.h" + +SECStatus ssl_SelfEncryptProtect( + sslSocket *ss, const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen); +SECStatus ssl_SelfEncryptUnprotect( + sslSocket *ss, const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen); + +/* Exported for use in unit tests.*/ +SECStatus ssl_SelfEncryptProtectInt( + PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName, + const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen); +SECStatus ssl_SelfEncryptUnprotectInt( + PK11SymKey *encKey, PK11SymKey *macKey, const unsigned char *keyName, + const PRUint8 *in, unsigned int inLen, + PRUint8 *out, unsigned int *outLen, unsigned int maxOutLen); + +#endif diff --git a/security/nss/lib/ssl/ssl.def b/security/nss/lib/ssl/ssl.def index 6aa8b6437..94d304223 100644 --- a/security/nss/lib/ssl/ssl.def +++ b/security/nss/lib/ssl/ssl.def @@ -221,3 +221,16 @@ SSL_SignatureSchemePrefGet; ;+ local: ;+*; ;+}; +;+NSS_3.30 { # NSS 3.30 release +;+ global: +SSL_SetSessionTicketKeyPair; +;+ local: +;+*; +;+}; +;+NSS_3.30.0.1 { # Additional symbols for NSS 3.30 release +;+ global: +SSL_AlertReceivedCallback; +SSL_AlertSentCallback; +;+ local: +;+*; +;+}; diff --git a/security/nss/lib/ssl/ssl.gyp b/security/nss/lib/ssl/ssl.gyp index 0306ab667..03b2d6014 100644 --- a/security/nss/lib/ssl/ssl.gyp +++ b/security/nss/lib/ssl/ssl.gyp @@ -14,8 +14,10 @@ 'cmpcert.c', 'dtlscon.c', 'prelib.c', + 'selfencrypt.c', 'ssl3con.c', 'ssl3ecc.c', + 'ssl3encode.c', 'ssl3ext.c', 'ssl3exthandle.c', 'ssl3gthr.c', @@ -63,7 +65,7 @@ 'NSS_SSL_ENABLE_ZLIB', ], }], - [ 'fuzz==1', { + [ 'fuzz_tls==1', { 'defines': [ 'UNSAFE_FUZZER_MODE', ], @@ -71,7 +73,6 @@ ], 'dependencies': [ '<(DEPTH)/exports.gyp:nss_exports', - '<(DEPTH)/lib/freebl/freebl.gyp:freebl', ], }, { @@ -81,6 +82,7 @@ 'ssl', '<(DEPTH)/lib/nss/nss.gyp:nss3', '<(DEPTH)/lib/util/util.gyp:nssutil3', + '<(DEPTH)/lib/freebl/freebl.gyp:freebl', ], 'variables': { 'mapfile': 'ssl.def' diff --git a/security/nss/lib/ssl/ssl.h b/security/nss/lib/ssl/ssl.h index 9394adcca..7e538ac1f 100644 --- a/security/nss/lib/ssl/ssl.h +++ b/security/nss/lib/ssl/ssl.h @@ -228,7 +228,7 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd); * on the server to read that data. Calls to * SSL_GetPreliminaryChannelInfo() and SSL_GetNextProto() * can be made used during this period to learn about the channel - * parameters [TODO(ekr@rtfm.com): This hasn't landed yet]. + * parameters. * * The transition between the 0-RTT and 1-RTT modes is marked by the * handshake callback. @@ -394,7 +394,7 @@ SSL_IMPORT SECStatus SSL_SignaturePrefGet( ** can be set or retrieved using SSL_SignatureSchemePrefSet or ** SSL_SignatureSchemePrefGet. */ -SSL_IMPORT unsigned int SSL_SignatureMaxCount(); +SSL_IMPORT unsigned int SSL_SignatureMaxCount(void); /* ** Define custom priorities for EC and FF groups used in DH key exchange and EC @@ -820,6 +820,25 @@ SSL_IMPORT PRFileDesc *SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd); SSL_IMPORT SECStatus SSL_SetPKCS11PinArg(PRFileDesc *fd, void *a); /* +** These are callbacks for dealing with SSL alerts. + */ + +typedef PRUint8 SSLAlertLevel; +typedef PRUint8 SSLAlertDescription; + +typedef struct { + SSLAlertLevel level; + SSLAlertDescription description; +} SSLAlert; + +typedef void(PR_CALLBACK *SSLAlertCallback)(const PRFileDesc *fd, void *arg, + const SSLAlert *alert); + +SSL_IMPORT SECStatus SSL_AlertReceivedCallback(PRFileDesc *fd, SSLAlertCallback cb, + void *arg); +SSL_IMPORT SECStatus SSL_AlertSentCallback(PRFileDesc *fd, SSLAlertCallback cb, + void *arg); +/* ** This is a callback for dealing with server certs that are not authenticated ** by the client. The client app can decide that it actually likes the ** cert by some external means and restart the connection. @@ -915,6 +934,22 @@ SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, SECKEYPrivateKey *key, SSLKEAType kea); /* +** SSL_SetSessionTicketKeyPair configures an asymmetric key pair for use in +** wrapping session ticket keys, used by the server. This function currently +** only accepts an RSA public/private key pair. +** +** Prior to the existence of this function, NSS used an RSA private key +** associated with a configured certificate to perform session ticket +** encryption. If this function isn't used, the keys provided with a configured +** RSA certificate are used for wrapping session ticket keys. +** +** NOTE: This key is used for all self-encryption but is named for +** session tickets for historical reasons. +*/ +SSL_IMPORT SECStatus +SSL_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey, SECKEYPrivateKey *privKey); + +/* ** Configure a secure server's session-id cache. Define the maximum number ** of entries in the cache, the longevity of the entires, and the directory ** where the cache files will be placed. These values can be zero, and diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 186ce23f3..5cbe2bd09 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -38,13 +38,6 @@ #include "zlib.h" #endif -#ifndef PK11_SETATTRS -#define PK11_SETATTRS(x, id, v, l) \ - (x)->type = (id); \ - (x)->pValue = (v); \ - (x)->ulValueLen = (l); -#endif - static PK11SymKey *ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, PK11SlotInfo *serverKeySlot); static SECStatus ssl3_DeriveMasterSecret(sslSocket *ss, PK11SymKey *pms); @@ -64,7 +57,7 @@ static SECStatus ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, int *retErrCode); static SECStatus ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, - SSL3Opaque *b, + PRUint8 *b, PRUint32 length, SSL3Hashes *hashesPtr); static SECStatus ssl3_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); @@ -273,10 +266,6 @@ static const /*SSL3ClientCertificateType */ PRUint8 certificate_types[] = { ct_DSS_sign, }; -/* This global item is used only in servers. It is is initialized by -** SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest(). -*/ -CERTDistNames *ssl3_server_ca_list = NULL; static SSL3Statistics ssl3stats; /* Record protection algorithms, indexed by SSL3BulkCipher. @@ -863,12 +852,10 @@ ssl_HasCert(const sslSocket *ss, SSLAuthType authType) cursor != &ss->serverCerts; cursor = PR_NEXT_LINK(cursor)) { sslServerCert *cert = (sslServerCert *)cursor; - if (cert->certType.authType != authType) { - continue; - } if (!cert->serverKeyPair || !cert->serverKeyPair->privKey || - !cert->serverCertChain) { + !cert->serverCertChain || + !SSL_CERT_IS(cert, authType)) { continue; } /* When called from ssl3_config_match_init(), all the EC curves will be @@ -879,7 +866,7 @@ ssl_HasCert(const sslSocket *ss, SSLAuthType authType) if ((authType == ssl_auth_ecdsa || authType == ssl_auth_ecdh_ecdsa || authType == ssl_auth_ecdh_rsa) && - !ssl_NamedGroupEnabled(ss, cert->certType.namedCurve)) { + !ssl_NamedGroupEnabled(ss, cert->namedCurve)) { continue; } return PR_TRUE; @@ -1044,8 +1031,9 @@ Null_Cipher(void *ctx, unsigned char *output, int *outputLen, int maxOutputLen, return SECFailure; } *outputLen = inputLen; - if (input != output) + if (inputLen > 0 && input != output) { PORT_Memcpy(output, input, inputLen); + } return SECSuccess; } @@ -1084,14 +1072,15 @@ ssl3_NegotiateVersion(sslSocket *ss, SSL3ProtocolVersion peerVersion, /* Used by the client when the server produces a version number. * This reads, validates, and normalizes the value. */ SECStatus -ssl_ClientReadVersion(sslSocket *ss, SSL3Opaque **b, unsigned int *len, +ssl_ClientReadVersion(sslSocket *ss, PRUint8 **b, unsigned int *len, SSL3ProtocolVersion *version) { SSL3ProtocolVersion v; - PRInt32 temp; + PRUint32 temp; + SECStatus rv; - temp = ssl3_ConsumeHandshakeNumber(ss, 2, b, len); - if (temp < 0) { + rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 2, b, len); + if (rv != SECSuccess) { return SECFailure; /* alert has been sent */ } @@ -1624,10 +1613,6 @@ ssl3_SetupPendingCipherSpec(sslSocket *ss) pwSpec->compressContext = NULL; pwSpec->decompressContext = NULL; - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { - PORT_Assert(ss->ssl3.hs.kea_def->ephemeral); - PORT_Assert(pwSpec->cipher_def->type == type_aead); - } ssl_ReleaseSpecWriteLock(ss); /*******************************/ return SECSuccess; } @@ -1777,29 +1762,6 @@ ssl3_InitCompressionContext(ssl3CipherSpec *pwSpec) return SECSuccess; } -/* This function should probably be moved to pk11wrap and be named - * PK11_ParamFromIVAndEffectiveKeyBits - */ -static SECItem * -ssl3_ParamFromIV(CK_MECHANISM_TYPE mtype, SECItem *iv, CK_ULONG ulEffectiveBits) -{ - SECItem *param = PK11_ParamFromIV(mtype, iv); - if (param && param->data && param->len >= sizeof(CK_RC2_PARAMS)) { - switch (mtype) { - case CKM_RC2_KEY_GEN: - case CKM_RC2_ECB: - case CKM_RC2_CBC: - case CKM_RC2_MAC: - case CKM_RC2_MAC_GENERAL: - case CKM_RC2_CBC_PAD: - *(CK_RC2_PARAMS *)param->data = ulEffectiveBits; - default: - break; - } - } - return param; -} - /* ssl3_BuildRecordPseudoHeader writes the SSL/TLS pseudo-header (the data * which is included in the MAC or AEAD additional data) to |out| and returns * its length. See https://tools.ietf.org/html/rfc5246#section-6.2.3.3 for the @@ -1981,7 +1943,6 @@ ssl3_InitPendingContexts(sslSocket *ss) CK_MECHANISM_TYPE mechanism; CK_MECHANISM_TYPE mac_mech; CK_ULONG macLength; - CK_ULONG effKeyBits; SECItem iv; SECItem mac_param; SSLCipherAlgorithm calg; @@ -2051,14 +2012,13 @@ ssl3_InitPendingContexts(sslSocket *ss) return SECSuccess; } mechanism = ssl3_Alg2Mech(calg); - effKeyBits = cipher_def->key_size * BPB; /* * build the server context */ iv.data = pwSpec->server.write_iv; iv.len = cipher_def->iv_size; - param = ssl3_ParamFromIV(mechanism, &iv, effKeyBits); + param = PK11_ParamFromIV(mechanism, &iv); if (param == NULL) { ssl_MapLowLevelError(SSL_ERROR_IV_PARAM_FAILURE); goto fail; @@ -2082,7 +2042,7 @@ ssl3_InitPendingContexts(sslSocket *ss) iv.data = pwSpec->client.write_iv; iv.len = cipher_def->iv_size; - param = ssl3_ParamFromIV(mechanism, &iv, effKeyBits); + param = PK11_ParamFromIV(mechanism, &iv); if (param == NULL) { ssl_MapLowLevelError(SSL_ERROR_IV_PARAM_FAILURE); goto fail; @@ -2256,7 +2216,7 @@ ssl3_ComputeRecordMAC( PRBool useServerMacKey, const unsigned char *header, unsigned int headerLen, - const SSL3Opaque *input, + const PRUint8 *input, int inputLength, unsigned char *outbuf, unsigned int *outLength) @@ -2303,7 +2263,7 @@ ssl3_ComputeRecordMACConstantTime( PRBool useServerMacKey, const unsigned char *header, unsigned int headerLen, - const SSL3Opaque *input, + const PRUint8 *input, int inputLen, int originalLen, unsigned char *outbuf, @@ -2408,7 +2368,7 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, PRBool isDTLS, PRBool capRecordVersion, SSL3ContentType type, - const SSL3Opaque *pIn, + const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf) { @@ -2577,7 +2537,7 @@ ssl3_CompressMACEncryptRecord(ssl3CipherSpec *cwSpec, SECStatus ssl_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, PRBool capRecordVersion, SSL3ContentType type, - const SSL3Opaque *pIn, PRUint32 contentLen, sslBuffer *wrBuf) + const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf) { const ssl3BulkCipherDef *cipher_def = cwSpec->cipher_def; PRUint16 headerLen; @@ -2694,14 +2654,15 @@ PRInt32 ssl3_SendRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, /* non-NULL for DTLS retransmits */ SSL3ContentType type, - const SSL3Opaque *pIn, /* input buffer */ - PRInt32 nIn, /* bytes of input */ + const PRUint8 *pIn, /* input buffer */ + PRInt32 nIn, /* bytes of input */ PRInt32 flags) { sslBuffer *wrBuf = &ss->sec.writeBuf; SECStatus rv; PRInt32 totalSent = 0; PRBool capRecordVersion; + ssl3CipherSpec *spec; SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d", SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type), @@ -2733,10 +2694,7 @@ ssl3_SendRecord(sslSocket *ss, ** trying to send an alert. */ PR_ASSERT(type == content_alert); - rv = ssl3_InitState(ss); - if (rv != SECSuccess) { - return SECFailure; /* ssl3_InitState has set the error code. */ - } + ssl3_InitState(ss); } /* check for Token Presence */ @@ -2806,11 +2764,12 @@ ssl3_SendRecord(sslSocket *ss, PORT_Assert(IS_DTLS(ss) && (type == content_handshake || type == content_change_cipher_spec)); + spec = cwSpec; } else { - cwSpec = ss->ssl3.cwSpec; + spec = ss->ssl3.cwSpec; } - rv = ssl_ProtectRecord(ss, cwSpec, !IS_DTLS(ss) && capRecordVersion, + rv = ssl_ProtectRecord(ss, spec, !IS_DTLS(ss) && capRecordVersion, type, pIn, contentLen, wrBuf); if (rv == SECSuccess) { PRINT_BUF(50, (ss, "send (encrypted) record data:", @@ -2941,6 +2900,7 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, ssl_GetXmitBufLock(ss); } toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH); + /* * Note that the 0 epoch is OK because flags will never require * its use, as guaranteed by the PORT_Assert above. @@ -3077,7 +3037,9 @@ ssl3_HandleNoCertificate(sslSocket *ss) (ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE))) { PRFileDesc *lower; - ss->sec.uncache(ss->sec.ci.sid); + if (!ss->opt.noCache) { + ss->sec.uncache(ss->sec.ci.sid); + } SSL3_SendAlert(ss, alert_fatal, bad_certificate); lower = ss->fd->lower; @@ -3124,6 +3086,10 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc) { PRUint8 bytes[2]; SECStatus rv; + PRBool needHsLock = !ssl_HaveSSL3HandshakeLock(ss); + + /* Check that if I need the HS lock I also need the Xmit lock */ + PORT_Assert(!needHsLock || !ssl_HaveXmitBufLock(ss)); SSL_TRC(3, ("%d: SSL3[%d]: send alert record, level=%d desc=%d", SSL_GETPID(), ss->fd, level, desc)); @@ -3131,7 +3097,9 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc) bytes[0] = level; bytes[1] = desc; - ssl_GetSSL3HandshakeLock(ss); + if (needHsLock) { + ssl_GetSSL3HandshakeLock(ss); + } if (level == alert_fatal) { if (!ss->opt.noCache && ss->sec.ci.sid) { ss->sec.uncache(ss->sec.ci.sid); @@ -3149,7 +3117,13 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc) ss->ssl3.fatalAlertSent = PR_TRUE; } ssl_ReleaseXmitBufLock(ss); - ssl_ReleaseSSL3HandshakeLock(ss); + if (needHsLock) { + ssl_ReleaseSSL3HandshakeLock(ss); + } + if (rv == SECSuccess && ss->alertSentCallback) { + SSLAlert alert = { level, desc }; + ss->alertSentCallback(ss->fd, ss->alertSentCallbackArg, &alert); + } return rv; /* error set by ssl3_FlushHandshake or ssl3_SendRecord */ } @@ -3262,6 +3236,11 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) SSL_TRC(5, ("%d: SSL3[%d] received alert, level = %d, description = %d", SSL_GETPID(), ss->fd, level, desc)); + if (ss->alertReceivedCallback) { + SSLAlert alert = { level, desc }; + ss->alertReceivedCallback(ss->fd, ss->alertReceivedCallbackArg, &alert); + } + switch (desc) { case close_notify: ss->recvdCloseNotify = 1; @@ -4088,11 +4067,9 @@ ssl3_InitHandshakeHashes(sslSocket *ss) return SECSuccess; } -SECStatus +void ssl3_RestartHandshakeHashes(sslSocket *ss) { - SECStatus rv = SECSuccess; - SSL_TRC(30, ("%d: SSL3[%d]: reset handshake hashes", SSL_GETPID(), ss->fd)); ss->ssl3.hs.hashType = handshake_hash_unknown; @@ -4105,7 +4082,6 @@ ssl3_RestartHandshakeHashes(sslSocket *ss) PK11_DestroyContext(ss->ssl3.hs.sha, PR_TRUE); ss->ssl3.hs.sha = NULL; } - return rv; } /* @@ -4243,7 +4219,7 @@ ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, PRInt32 lenSize) SECStatus ssl3_AppendHandshakeVariable( - sslSocket *ss, const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize) + sslSocket *ss, const PRUint8 *src, PRInt32 bytes, PRInt32 lenSize) { SECStatus rv; @@ -4330,7 +4306,7 @@ ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length) * override the generic error code by setting another. */ SECStatus -ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, SSL3Opaque **b, +ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRUint32 bytes, PRUint8 **b, PRUint32 *length) { PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); @@ -4348,37 +4324,33 @@ ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, SSL3Opaque **b, /* Read up the next "bytes" number of bytes from the (decrypted) input * stream "b" (which is *length bytes long), and interpret them as an - * integer in network byte order. Returns the received value. + * integer in network byte order. Sets *num to the received value. * Reduces *length by bytes. Advances *b by bytes. * - * Returns SECFailure (-1) on failure. - * This value is indistinguishable from the equivalent received value. - * Only positive numbers are to be received this way. - * Thus, the largest value that may be sent this way is 0x7fffffff. * On error, an alert has been sent, and a generic error code has been set. */ -PRInt32 -ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, SSL3Opaque **b, - PRUint32 *length) +SECStatus +ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRUint32 *num, PRUint32 bytes, + PRUint8 **b, PRUint32 *length) { PRUint8 *buf = *b; int i; - PRInt32 num = 0; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - PORT_Assert(bytes <= sizeof num); - if ((PRUint32)bytes > *length) { + *num = 0; + if (bytes > *length || bytes > sizeof(*num)) { return ssl3_DecodeError(ss); } PRINT_BUF(60, (ss, "consume bytes:", *b, bytes)); - for (i = 0; i < bytes; i++) - num = (num << 8) + buf[i]; + for (i = 0; i < bytes; i++) { + *num = (*num << 8) + buf[i]; + } *b += bytes; *length -= bytes; - return num; + return SECSuccess; } /* Read in two values from the incoming decrypted byte stream "b", which is @@ -4396,21 +4368,22 @@ ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, SSL3Opaque **b, * point to the values in the buffer **b. */ SECStatus -ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes, - SSL3Opaque **b, PRUint32 *length) +ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRUint32 bytes, + PRUint8 **b, PRUint32 *length) { - PRInt32 count; + PRUint32 count; + SECStatus rv; PORT_Assert(bytes <= 3); i->len = 0; i->data = NULL; i->type = siBuffer; - count = ssl3_ConsumeHandshakeNumber(ss, bytes, b, length); - if (count < 0) { /* Can't test for SECSuccess here. */ + rv = ssl3_ConsumeHandshakeNumber(ss, &count, bytes, b, length); + if (rv != SECSuccess) { return SECFailure; } if (count > 0) { - if ((PRUint32)count > *length) { + if (count > *length) { return ssl3_DecodeError(ss); } i->data = *b; @@ -4421,19 +4394,6 @@ ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes, return SECSuccess; } -/* Helper function to encode an unsigned integer into a buffer. */ -PRUint8 * -ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to) -{ - PRUint64 encoded; - - PORT_Assert(bytes > 0 && bytes <= sizeof(encoded)); - - encoded = PR_htonll(value); - memcpy(to, ((unsigned char *)(&encoded)) + (sizeof(encoded) - bytes), bytes); - return to + bytes; -} - /* ssl3_TLSHashAlgorithmToOID converts a TLS hash identifier into an OID value. * If the hash is not recognised, SEC_OID_UNKNOWN is returned. * @@ -4678,13 +4638,14 @@ ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme) * * See https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 */ SECStatus -ssl_ConsumeSignatureScheme(sslSocket *ss, SSL3Opaque **b, +ssl_ConsumeSignatureScheme(sslSocket *ss, PRUint8 **b, PRUint32 *length, SSLSignatureScheme *out) { - PRInt32 tmp; + PRUint32 tmp; + SECStatus rv; - tmp = ssl3_ConsumeHandshakeNumber(ss, 2, b, length); - if (tmp < 0) { + rv = ssl3_ConsumeHandshakeNumber(ss, &tmp, 2, b, length); + if (rv != SECSuccess) { return SECFailure; /* Error code set already. */ } if (!ssl_IsSupportedSignatureScheme((SSLSignatureScheme)tmp)) { @@ -4743,8 +4704,8 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss, SECStatus rv = SECSuccess; PRBool isTLS = (PRBool)(spec->version > SSL_LIBRARY_VERSION_3_0); unsigned int outLength; - SSL3Opaque md5_inner[MAX_MAC_LENGTH]; - SSL3Opaque sha_inner[MAX_MAC_LENGTH]; + PRUint8 md5_inner[MAX_MAC_LENGTH]; + PRUint8 sha_inner[MAX_MAC_LENGTH]; PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); if (ss->ssl3.hs.hashType == handshake_hash_unknown) { @@ -4990,7 +4951,6 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) PRBool isTLS = PR_FALSE; PRBool requestingResume = PR_FALSE, fallbackSCSV = PR_FALSE; PRInt32 total_exten_len = 0; - unsigned paddingExtensionLen; unsigned numCompressionMethods; PRUint16 version; PRInt32 flags; @@ -5013,15 +4973,8 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) if (ss->ssl3.hs.helloRetry) { PORT_Assert(type == client_hello_retry); } else { - rv = ssl3_InitState(ss); - if (rv != SECSuccess) { - return rv; /* ssl3_InitState has set the error code. */ - } - - rv = ssl3_RestartHandshakeHashes(ss); - if (rv != SECSuccess) { - return rv; - } + ssl3_InitState(ss); + ssl3_RestartHandshakeHashes(ss); } /* These must be reset every handshake. */ @@ -5293,19 +5246,12 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) length += 1 + ss->ssl3.hs.cookie.len; } - /* A padding extension may be included to ensure that the record containing - * the ClientHello doesn't have a length between 256 and 511 bytes - * (inclusive). Initial, ClientHello records with such lengths trigger bugs - * in F5 devices. - * - * This is not done for DTLS, for renegotiation, or when there are no - * extensions. */ - if (!IS_DTLS(ss) && isTLS && !ss->firstHsDone && total_exten_len) { - paddingExtensionLen = ssl3_CalculatePaddingExtensionLength(length); - total_exten_len += paddingExtensionLen; - length += paddingExtensionLen; - } else { - paddingExtensionLen = 0; + if (total_exten_len > 0) { + ssl3_CalculatePaddingExtLen(ss, length); + if (ss->xtnData.paddingLen) { + total_exten_len += 4 + ss->xtnData.paddingLen; + length += 4 + ss->xtnData.paddingLen; + } } rv = ssl3_AppendHandshakeHeader(ss, client_hello, length); @@ -5476,15 +5422,6 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type) return rv; /* err set by AppendHandshake. */ } - extLen = ssl3_AppendPaddingExtension(ss, paddingExtensionLen, maxBytes); - if (extLen < 0) { - if (sid->u.ssl3.lock) { - PR_RWLock_Unlock(sid->u.ssl3.lock); - } - return SECFailure; - } - maxBytes -= extLen; - extLen = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, maxBytes, NULL); if (extLen < 0) { if (sid->u.ssl3.lock) { @@ -5579,8 +5516,6 @@ ssl3_HandleHelloRequest(sslSocket *ss) return rv; } -#define UNKNOWN_WRAP_MECHANISM 0x7fffffff - static const CK_MECHANISM_TYPE wrapMechanismList[SSL_NUM_WRAP_MECHS] = { CKM_DES3_ECB, CKM_CAST5_ECB, @@ -5596,27 +5531,58 @@ static const CK_MECHANISM_TYPE wrapMechanismList[SSL_NUM_WRAP_MECHS] = { CKM_SKIPJACK_CBC64, CKM_AES_ECB, CKM_CAMELLIA_ECB, - CKM_SEED_ECB, - UNKNOWN_WRAP_MECHANISM + CKM_SEED_ECB }; -static int -ssl_FindIndexByWrapMechanism(CK_MECHANISM_TYPE mech) +static SECStatus +ssl_FindIndexByWrapMechanism(CK_MECHANISM_TYPE mech, unsigned int *wrapMechIndex) { - const CK_MECHANISM_TYPE *pMech = wrapMechanismList; + unsigned int i; + for (i = 0; i < SSL_NUM_WRAP_MECHS; ++i) { + if (wrapMechanismList[i] == mech) { + *wrapMechIndex = i; + return SECSuccess; + } + } + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; +} - while (mech != *pMech && *pMech != UNKNOWN_WRAP_MECHANISM) { - ++pMech; +/* Each process sharing the server session ID cache has its own array of SymKey + * pointers for the symmetric wrapping keys that are used to wrap the master + * secrets. There is one key for each authentication type. These Symkeys + * correspond to the wrapped SymKeys kept in the server session cache. + */ +const SSLAuthType ssl_wrap_key_auth_type[SSL_NUM_WRAP_KEYS] = { + ssl_auth_rsa_decrypt, + ssl_auth_rsa_sign, + ssl_auth_rsa_pss, + ssl_auth_ecdsa, + ssl_auth_ecdh_rsa, + ssl_auth_ecdh_ecdsa +}; + +static SECStatus +ssl_FindIndexByWrapKey(const sslServerCert *serverCert, unsigned int *wrapKeyIndex) +{ + unsigned int i; + for (i = 0; i < SSL_NUM_WRAP_KEYS; ++i) { + if (SSL_CERT_IS(serverCert, ssl_wrap_key_auth_type[i])) { + *wrapKeyIndex = i; + return SECSuccess; + } } - return (*pMech == UNKNOWN_WRAP_MECHANISM) ? -1 - : (pMech - wrapMechanismList); + /* Can't assert here because we still get people using DSA certificates. */ + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } static PK11SymKey * ssl_UnwrapSymWrappingKey( SSLWrappedSymWrappingKey *pWswk, SECKEYPrivateKey *svrPrivKey, - SSLAuthType authType, + unsigned int wrapKeyIndex, CK_MECHANISM_TYPE masterWrapMech, void *pwArg) { @@ -5628,9 +5594,9 @@ ssl_UnwrapSymWrappingKey( /* found the wrapping key on disk. */ PORT_Assert(pWswk->symWrapMechanism == masterWrapMech); - PORT_Assert(pWswk->authType == authType); + PORT_Assert(pWswk->wrapKeyIndex == wrapKeyIndex); if (pWswk->symWrapMechanism != masterWrapMech || - pWswk->authType != authType) { + pWswk->wrapKeyIndex != wrapKeyIndex) { goto loser; } wrappedKey.type = siBuffer; @@ -5638,7 +5604,7 @@ ssl_UnwrapSymWrappingKey( wrappedKey.len = pWswk->wrappedSymKeyLen; PORT_Assert(wrappedKey.len <= sizeof pWswk->wrappedSymmetricWrappingkey); - switch (authType) { + switch (ssl_wrap_key_auth_type[wrapKeyIndex]) { case ssl_auth_rsa_decrypt: case ssl_auth_rsa_sign: /* bad: see Bug 1248320 */ @@ -5711,14 +5677,8 @@ loser: return unwrappedWrappingKey; } -/* Each process sharing the server session ID cache has its own array of SymKey - * pointers for the symmetric wrapping keys that are used to wrap the master - * secrets. There is one key for each authentication type. These Symkeys - * correspond to the wrapped SymKeys kept in the server session cache. - */ - typedef struct { - PK11SymKey *symWrapKey[ssl_auth_size]; + PK11SymKey *symWrapKey[SSL_NUM_WRAP_KEYS]; } ssl3SymWrapKey; static PZLock *symWrapKeysLock = NULL; @@ -5746,7 +5706,7 @@ SSL3_ShutdownServerCache(void) PZ_Lock(symWrapKeysLock); /* get rid of all symWrapKeys */ for (i = 0; i < SSL_NUM_WRAP_MECHS; ++i) { - for (j = 0; j < ssl_auth_size; ++j) { + for (j = 0; j < SSL_NUM_WRAP_KEYS; ++j) { PK11SymKey **pSymWrapKey; pSymWrapKey = &symWrapKeys[i].symWrapKey[j]; if (*pSymWrapKey) { @@ -5780,7 +5740,6 @@ ssl_InitSymWrapKeysLock(void) PK11SymKey * ssl3_GetWrappingKey(sslSocket *ss, PK11SlotInfo *masterSecretSlot, - const sslServerCert *serverCert, CK_MECHANISM_TYPE masterWrapMech, void *pwArg) { @@ -5791,7 +5750,8 @@ ssl3_GetWrappingKey(sslSocket *ss, PK11SymKey **pSymWrapKey; CK_MECHANISM_TYPE asymWrapMechanism = CKM_INVALID_MECHANISM; int length; - int symWrapMechIndex; + unsigned int wrapMechIndex; + unsigned int wrapKeyIndex; SECStatus rv; SECItem wrappedKey; SSLWrappedSymWrappingKey wswk; @@ -5799,6 +5759,7 @@ ssl3_GetWrappingKey(sslSocket *ss, SECKEYPublicKey *pubWrapKey = NULL; SECKEYPrivateKey *privWrapKey = NULL; ECCWrappedKeyInfo *ecWrapped; + const sslServerCert *serverCert = ss->sec.serverCert; PORT_Assert(serverCert); PORT_Assert(serverCert->serverKeyPair); @@ -5810,15 +5771,18 @@ ssl3_GetWrappingKey(sslSocket *ss, PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return NULL; /* hmm */ } - authType = serverCert->certType.authType; - svrPrivKey = serverCert->serverKeyPair->privKey; - symWrapMechIndex = ssl_FindIndexByWrapMechanism(masterWrapMech); - PORT_Assert(symWrapMechIndex >= 0); - if (symWrapMechIndex < 0) + rv = ssl_FindIndexByWrapKey(serverCert, &wrapKeyIndex); + if (rv != SECSuccess) + return NULL; /* unusable wrapping key. */ + + rv = ssl_FindIndexByWrapMechanism(masterWrapMech, &wrapMechIndex); + if (rv != SECSuccess) return NULL; /* invalid masterWrapMech. */ - pSymWrapKey = &symWrapKeys[symWrapMechIndex].symWrapKey[authType]; + authType = ssl_wrap_key_auth_type[wrapKeyIndex]; + svrPrivKey = serverCert->serverKeyPair->privKey; + pSymWrapKey = &symWrapKeys[wrapMechIndex].symWrapKey[wrapKeyIndex]; ssl_InitSessionCacheLocks(PR_TRUE); @@ -5837,10 +5801,11 @@ ssl3_GetWrappingKey(sslSocket *ss, /* Try to get wrapped SymWrapping key out of the (disk) cache. */ /* Following call fills in wswk on success. */ - if (ssl_GetWrappingKey(symWrapMechIndex, authType, &wswk)) { + rv = ssl_GetWrappingKey(wrapMechIndex, wrapKeyIndex, &wswk); + if (rv == SECSuccess) { /* found the wrapped sym wrapping key on disk. */ unwrappedWrappingKey = - ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, authType, + ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, wrapKeyIndex, masterWrapMech, pwArg); if (unwrappedWrappingKey) { goto install; @@ -5989,9 +5954,9 @@ ssl3_GetWrappingKey(sslSocket *ss, PORT_Assert(asymWrapMechanism != CKM_INVALID_MECHANISM); wswk.symWrapMechanism = masterWrapMech; - wswk.symWrapMechIndex = symWrapMechIndex; wswk.asymWrapMechanism = asymWrapMechanism; - wswk.authType = authType; + wswk.wrapMechIndex = wrapMechIndex; + wswk.wrapKeyIndex = wrapKeyIndex; wswk.wrappedSymKeyLen = wrappedKey.len; /* put it on disk. */ @@ -5999,7 +5964,8 @@ ssl3_GetWrappingKey(sslSocket *ss, * then abandon the value we just computed and * use the one we got from the disk. */ - if (ssl_SetWrappingKey(&wswk)) { + rv = ssl_SetWrappingKey(&wswk); + if (rv == SECSuccess) { /* somebody beat us to it. The original contents of our wswk * has been replaced with the content on disk. Now, discard * the key we just created and unwrap this new one. @@ -6007,7 +5973,7 @@ ssl3_GetWrappingKey(sslSocket *ss, PK11_FreeSymKey(unwrappedWrappingKey); unwrappedWrappingKey = - ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, authType, + ssl_UnwrapSymWrappingKey(&wswk, svrPrivKey, wrapKeyIndex, masterWrapMech, pwArg); } @@ -6411,6 +6377,33 @@ ssl_PickSignatureScheme(sslSocket *ss, return SECFailure; } +static SECStatus +ssl_PickFallbackSignatureScheme(sslSocket *ss, SECKEYPublicKey *pubKey) +{ + PRBool isTLS12 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_2; + + switch (SECKEY_GetPublicKeyType(pubKey)) { + case rsaKey: + if (isTLS12) { + ss->ssl3.hs.signatureScheme = ssl_sig_rsa_pkcs1_sha1; + } else { + ss->ssl3.hs.signatureScheme = ssl_sig_rsa_pkcs1_sha1md5; + } + break; + case ecKey: + ss->ssl3.hs.signatureScheme = ssl_sig_ecdsa_sha1; + break; + case dsaKey: + ss->ssl3.hs.signatureScheme = ssl_sig_dsa_sha1; + break; + default: + PORT_Assert(0); + PORT_SetError(SEC_ERROR_INVALID_KEY); + return SECFailure; + } + return SECSuccess; +} + /* ssl3_PickServerSignatureScheme selects a signature scheme for signing the * handshake. Most of this is determined by the key pair we are using. * Prior to TLS 1.2, the MD5/SHA1 combination is always used. With TLS 1.2, a @@ -6424,26 +6417,7 @@ ssl3_PickServerSignatureScheme(sslSocket *ss) if (!isTLS12 || !ssl3_ExtensionNegotiated(ss, ssl_signature_algorithms_xtn)) { /* If the client didn't provide any signature_algorithms extension then * we can assume that they support SHA-1: RFC5246, Section 7.4.1.4.1. */ - switch (SECKEY_GetPublicKeyType(keyPair->pubKey)) { - case rsaKey: - if (isTLS12) { - ss->ssl3.hs.signatureScheme = ssl_sig_rsa_pkcs1_sha1; - } else { - ss->ssl3.hs.signatureScheme = ssl_sig_rsa_pkcs1_sha1md5; - } - break; - case ecKey: - ss->ssl3.hs.signatureScheme = ssl_sig_ecdsa_sha1; - break; - case dsaKey: - ss->ssl3.hs.signatureScheme = ssl_sig_dsa_sha1; - break; - default: - PORT_Assert(0); - PORT_SetError(SEC_ERROR_INVALID_KEY); - return SECFailure; - } - return SECSuccess; + return ssl_PickFallbackSignatureScheme(ss, keyPair->pubKey); } /* Sets error code, if needed. */ @@ -6461,9 +6435,21 @@ ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes, SECKEYPublicKey *pubKey; SECStatus rv; + PRBool isTLS13 = (PRBool)ss->version >= SSL_LIBRARY_VERSION_TLS_1_3; pubKey = CERT_ExtractPublicKey(ss->ssl3.clientCertificate); PORT_Assert(pubKey); - if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3 && + + if (!isTLS13 && numSchemes == 0) { + /* If the server didn't provide any signature algorithms + * then let's assume they support SHA-1. */ + rv = ssl_PickFallbackSignatureScheme(ss, pubKey); + SECKEY_DestroyPublicKey(pubKey); + return rv; + } + + PORT_Assert(schemes && numSchemes > 0); + + if (!isTLS13 && (SECKEY_GetPublicKeyType(pubKey) == rsaKey || SECKEY_GetPublicKeyType(pubKey) == dsaKey) && SECKEY_PublicKeyStrengthInBits(pubKey) <= 1024) { @@ -6604,9 +6590,9 @@ ssl3_SetCipherSuite(sslSocket *ss, ssl3CipherSuite chosenSuite, * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length) { - PRInt32 temp; /* allow for consume number failure */ + PRUint32 temp; PRBool suite_found = PR_FALSE; int i; int errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO; @@ -6649,11 +6635,21 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto loser; /* alert has been sent */ } - /* We got a HelloRetryRequest, but the server didn't pick 1.3. Scream. */ - if (ss->ssl3.hs.helloRetry && ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - desc = illegal_parameter; - errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO; - goto alert_loser; + /* The server didn't pick 1.3 although we either received a + * HelloRetryRequest, or we prepared to send early app data. */ + if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { + if (ss->ssl3.hs.helloRetry) { + /* SSL3_SendAlert() will uncache the SID. */ + desc = illegal_parameter; + errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO; + goto alert_loser; + } + if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) { + /* SSL3_SendAlert() will uncache the SID. */ + desc = illegal_parameter; + errCode = SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA; + goto alert_loser; + } } /* Check that the server negotiated the same version as it did @@ -6721,8 +6717,8 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } /* find selected cipher suite in our list. */ - temp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (temp < 0) { + rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 2, &b, &length); + if (rv != SECSuccess) { goto loser; /* alert has been sent */ } i = ssl3_config_match_init(ss); @@ -6767,8 +6763,8 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { /* find selected compression method in our list. */ - temp = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length); - if (temp < 0) { + rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 1, &b, &length); + if (rv != SECSuccess) { goto loser; /* alert has been sent */ } suite_found = PR_FALSE; @@ -7010,6 +7006,19 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes, else SSL_AtomicIncrementLong(&ssl3stats.hsh_sid_cache_misses); + /* We tried to resume a 1.3 session but the server negotiated 1.2. */ + if (ss->statelessResume) { + PORT_Assert(sid->version == SSL_LIBRARY_VERSION_TLS_1_3); + PORT_Assert(ss->ssl3.hs.currentSecret); + + /* Reset resumption state, only used by 1.3 code. */ + ss->statelessResume = PR_FALSE; + + /* Clear TLS 1.3 early data traffic key. */ + PK11_FreeSymKey(ss->ssl3.hs.currentSecret); + ss->ssl3.hs.currentSecret = NULL; + } + /* throw the old one away */ sid->u.ssl3.keys.resumable = PR_FALSE; ss->sec.uncache(sid); @@ -7062,7 +7071,7 @@ loser: } static SECStatus -ssl_HandleDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +ssl_HandleDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; int errCode = SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH; @@ -7222,7 +7231,7 @@ loser: * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +ssl3_HandleServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; @@ -7273,19 +7282,20 @@ typedef struct dnameNode { * tls13_HandleCertificateRequest */ SECStatus -ssl3_ParseCertificateRequestCAs(sslSocket *ss, SSL3Opaque **b, PRUint32 *length, +ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, PRUint32 *length, PLArenaPool *arena, CERTDistNames *ca_list) { - PRInt32 remaining; + PRUint32 remaining; int nnames = 0; dnameNode *node; + SECStatus rv; int i; - remaining = ssl3_ConsumeHandshakeNumber(ss, 2, b, length); - if (remaining < 0) + rv = ssl3_ConsumeHandshakeNumber(ss, &remaining, 2, b, length); + if (rv != SECSuccess) return SECFailure; /* malformed, alert has been sent */ - if ((PRUint32)remaining > *length) + if (remaining > *length) goto alert_loser; ca_list->head = node = PORT_ArenaZNew(arena, dnameNode); @@ -7293,19 +7303,19 @@ ssl3_ParseCertificateRequestCAs(sslSocket *ss, SSL3Opaque **b, PRUint32 *length, goto no_mem; while (remaining > 0) { - PRInt32 len; + PRUint32 len; if (remaining < 2) goto alert_loser; /* malformed */ - node->name.len = len = ssl3_ConsumeHandshakeNumber(ss, 2, b, length); - if (len <= 0) + rv = ssl3_ConsumeHandshakeNumber(ss, &len, 2, b, length); + if (rv != SECSuccess) return SECFailure; /* malformed, alert has been sent */ - - remaining -= 2; - if (remaining < len) + if (len == 0 || remaining < len + 2) goto alert_loser; /* malformed */ + remaining -= 2; + node->name.len = len; node->name.data = *b; *b += len; *length -= len; @@ -7353,7 +7363,7 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena, { SECStatus rv; SECItem buf; - SSLSignatureScheme *schemes; + SSLSignatureScheme *schemes = NULL; unsigned int numSchemes = 0; unsigned int max; @@ -7361,12 +7371,17 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena, if (rv != SECSuccess) { return SECFailure; } - /* An empty or odd-length value is invalid. */ - if (buf.len == 0 || (buf.len & 1) != 0) { + /* An odd-length value is invalid. */ + if ((buf.len & 1) != 0) { ssl3_ExtSendAlert(ss, alert_fatal, decode_error); return SECFailure; } + /* Let the caller decide whether to alert here. */ + if (buf.len == 0) { + goto done; + } + /* Limit the number of schemes we read. */ max = PR_MIN(buf.len / 2, MAX_SIGNATURE_SCHEMES); @@ -7381,9 +7396,9 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena, } for (; max; --max) { - PRInt32 tmp; - tmp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buf.data, &buf.len); - if (tmp < 0) { + PRUint32 tmp; + rv = ssl3_ExtConsumeHandshakeNumber(ss, &tmp, 2, &buf.data, &buf.len); + if (rv != SECSuccess) { PORT_Assert(0); PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); return SECFailure; @@ -7400,6 +7415,7 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena, schemes = NULL; } +done: *schemesOut = schemes; *numSchemesOut = numSchemes; return SECSuccess; @@ -7410,7 +7426,7 @@ ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *arena, * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +ssl3_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) { PLArenaPool *arena = NULL; PRBool isTLS = PR_FALSE; @@ -8227,19 +8243,17 @@ ssl3_SelectServerCert(sslSocket *ss) cursor != &ss->serverCerts; cursor = PR_NEXT_LINK(cursor)) { sslServerCert *cert = (sslServerCert *)cursor; - if (cert->certType.authType != kea_def->authKeyType) { + if (!SSL_CERT_IS(cert, kea_def->authKeyType)) { continue; } - if ((cert->certType.authType == ssl_auth_ecdsa || - cert->certType.authType == ssl_auth_ecdh_rsa || - cert->certType.authType == ssl_auth_ecdh_ecdsa) && - !ssl_NamedGroupEnabled(ss, cert->certType.namedCurve)) { + if (SSL_CERT_IS_EC(cert) && + !ssl_NamedGroupEnabled(ss, cert->namedCurve)) { continue; } /* Found one. */ ss->sec.serverCert = cert; - ss->sec.authType = cert->certType.authType; + ss->sec.authType = kea_def->authKeyType; ss->sec.authKeyBits = cert->serverKeyBits; /* Don't pick a signature scheme if we aren't going to use it. */ @@ -8258,10 +8272,10 @@ ssl3_SelectServerCert(sslSocket *ss) * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length) { sslSessionID *sid = NULL; - PRInt32 tmp; + PRUint32 tmp; unsigned int i; SECStatus rv; int errCode = SSL_ERROR_RX_MALFORMED_CLIENT_HELLO; @@ -8321,8 +8335,8 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) dtls_RehandshakeCleanup(ss); } - tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (tmp < 0) + rv = ssl3_ConsumeHandshakeNumber(ss, &tmp, 2, &b, &length); + if (rv != SECSuccess) goto loser; /* malformed, alert already sent */ /* Translate the version. */ @@ -8375,9 +8389,9 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (length) { /* Get length of hello extensions */ - PRInt32 extension_length; - extension_length = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (extension_length < 0) { + PRUint32 extension_length; + rv = ssl3_ConsumeHandshakeNumber(ss, &extension_length, 2, &b, &length); + if (rv != SECSuccess) { goto loser; /* alert already sent */ } if (extension_length != length) { @@ -8479,7 +8493,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) /* If the ClientHello version is less than our maximum version, check for a * TLS_FALLBACK_SCSV and reject the connection if found. */ - if (ss->vrange.max > ss->clientHelloVersion) { + if (ss->vrange.max > ss->version) { for (i = 0; i + 1 < suites.len; i += 2) { PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1]; if (suite_i != TLS_FALLBACK_SCSV) @@ -8505,7 +8519,7 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) for (i = 0; i + 1 < suites.len; i += 2) { PRUint16 suite_i = (suites.data[i] << 8) | suites.data[i + 1]; if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) { - SSL3Opaque *b2 = (SSL3Opaque *)emptyRIext; + PRUint8 *b2 = (PRUint8 *)emptyRIext; PRUint32 L2 = sizeof emptyRIext; (void)ssl3_HandleExtensions(ss, &b2, &L2, client_hello); break; @@ -8763,7 +8777,6 @@ compression_found: do { ssl3CipherSpec *pwSpec; SECItem wrappedMS; /* wrapped key */ - const sslServerCert *serverCert; if (sid->version != ss->version || sid->u.ssl3.cipherSuite != ss->ssl3.hs.cipher_suite || @@ -8771,8 +8784,13 @@ compression_found: break; /* not an error */ } - serverCert = ssl_FindServerCert(ss, &sid->certType); - if (!serverCert || !serverCert->serverCert) { + /* server sids don't remember the server cert we previously sent, + ** but they do remember the slot we originally used, so we + ** can locate it again, provided that the current ssl socket + ** has had its server certs configured the same as the previous one. + */ + ss->sec.serverCert = ssl_FindServerCert(ss, sid->authType, sid->namedCurve); + if (!ss->sec.serverCert || !ss->sec.serverCert->serverCert) { /* A compatible certificate must not have been configured. It * might not be the same certificate, but we only find that out * when the ticket fails to decrypt. */ @@ -8820,7 +8838,7 @@ compression_found: PK11SymKey *wrapKey; /* wrapping key */ CK_FLAGS keyFlags = 0; - wrapKey = ssl3_GetWrappingKey(ss, NULL, serverCert, + wrapKey = ssl3_GetWrappingKey(ss, NULL, sid->u.ssl3.masterWrapMech, ss->pkcs11PinArg); if (!wrapKey) { @@ -8879,13 +8897,8 @@ compression_found: ss->sec.keaType = sid->keaType; ss->sec.keaKeyBits = sid->keaKeyBits; - /* server sids don't remember the server cert we previously sent, - ** but they do remember the slot we originally used, so we - ** can locate it again, provided that the current ssl socket - ** has had its server certs configured the same as the previous one. - */ - ss->sec.serverCert = serverCert; - ss->sec.localCert = CERT_DupCertificate(serverCert->serverCert); + ss->sec.localCert = + CERT_DupCertificate(ss->sec.serverCert->serverCert); /* Copy cached name in to pending spec */ if (sid != NULL && @@ -9077,16 +9090,8 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length, goto loser; } - rv = ssl3_InitState(ss); - if (rv != SECSuccess) { - ssl_ReleaseSSL3HandshakeLock(ss); - return rv; /* ssl3_InitState has set the error code. */ - } - rv = ssl3_RestartHandshakeHashes(ss); - if (rv != SECSuccess) { - ssl_ReleaseSSL3HandshakeLock(ss); - return rv; - } + ssl3_InitState(ss); + ssl3_RestartHandshakeHashes(ss); if (ss->ssl3.hs.ws != wait_client_hello) { desc = unexpected_message; @@ -9202,7 +9207,7 @@ suite_found: for (i = 0; i + 2 < suite_length; i += 3) { PRUint32 suite_i = (suites[i] << 16) | (suites[i + 1] << 8) | suites[i + 2]; if (suite_i == TLS_EMPTY_RENEGOTIATION_INFO_SCSV) { - SSL3Opaque *b2 = (SSL3Opaque *)emptyRIext; + PRUint8 *b2 = (PRUint8 *)emptyRIext; PRUint32 L2 = sizeof emptyRIext; (void)ssl3_HandleExtensions(ss, &b2, &L2, client_hello); break; @@ -9603,34 +9608,6 @@ ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf, unsigned maxLen, PRUint32 return SECSuccess; } -void -ssl3_GetCertificateRequestCAs(sslSocket *ss, int *calen, SECItem **names, - int *nnames) -{ - SECItem *name; - CERTDistNames *ca_list; - int i; - - *calen = 0; - *names = NULL; - *nnames = 0; - - /* ssl3.ca_list is initialized to NULL, and never changed. */ - ca_list = ss->ssl3.ca_list; - if (!ca_list) { - ca_list = ssl3_server_ca_list; - } - - if (ca_list != NULL) { - *names = ca_list->names; - *nnames = ca_list->nnames; - } - - for (i = 0, name = *names; i < *nnames; i++, name++) { - *calen += 2 + name->len; - } -} - static SECStatus ssl3_SendCertificateRequest(sslSocket *ss) { @@ -9639,8 +9616,8 @@ ssl3_SendCertificateRequest(sslSocket *ss) SECStatus rv; int length; SECItem *names; - int calen; - int nnames; + unsigned int calen; + unsigned int nnames; SECItem *name; int i; int certTypesLength; @@ -9655,7 +9632,10 @@ ssl3_SendCertificateRequest(sslSocket *ss) isTLS12 = (PRBool)(ss->ssl3.pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2); - ssl3_GetCertificateRequestCAs(ss, &calen, &names, &nnames); + rv = ssl_GetCertificateRequestCAs(ss, &calen, &names, &nnames); + if (rv != SECSuccess) { + return rv; + } certTypes = certificate_types; certTypesLength = sizeof certificate_types; @@ -9723,7 +9703,7 @@ ssl3_SendServerHelloDone(sslSocket *ss) * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, +ssl3_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, SSL3Hashes *hashes) { SECItem signed_hash = { siBuffer, NULL, 0 }; @@ -9741,17 +9721,15 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); - /* TLS 1.3 is handled by tls13_HandleCertificateVerify */ - PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2); - - isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); - if (ss->ssl3.hs.ws != wait_cert_verify) { desc = unexpected_message; errCode = SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY; goto alert_loser; } + /* TLS 1.3 is handled by tls13_HandleCertificateVerify */ + PORT_Assert(ss->ssl3.prSpec->version <= SSL_LIBRARY_VERSION_TLS_1_2); + if (!hashes) { PORT_Assert(0); desc = internal_error; @@ -9798,6 +9776,8 @@ ssl3_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, goto loser; /* malformed. */ } + isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); + /* XXX verify that the key & kea match */ rv = ssl3_VerifySignedHashes(ss, sigScheme, hashesForVerify, &signed_hash); if (rv != SECSuccess) { @@ -9910,7 +9890,7 @@ ssl3_GenerateRSAPMS(sslSocket *ss, ssl3CipherSpec *spec, */ static SECStatus ssl3_HandleRSAClientKeyExchange(sslSocket *ss, - SSL3Opaque *b, + PRUint8 *b, PRUint32 length, sslKeyPair *serverKeyPair) { @@ -9928,9 +9908,9 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss, enc_pms.len = length; if (ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0) { /* isTLS */ - PRInt32 kLen; - kLen = ssl3_ConsumeHandshakeNumber(ss, 2, &enc_pms.data, &enc_pms.len); - if (kLen < 0) { + PRUint32 kLen; + rv = ssl3_ConsumeHandshakeNumber(ss, &kLen, 2, &enc_pms.data, &enc_pms.len); + if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); return SECFailure; } @@ -10037,7 +10017,7 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss, static SECStatus ssl3_HandleDHClientKeyExchange(sslSocket *ss, - SSL3Opaque *b, + PRUint8 *b, PRUint32 length, sslKeyPair *serverKeyPair) { @@ -10095,7 +10075,7 @@ ssl3_HandleDHClientKeyExchange(sslSocket *ss, * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +ssl3_HandleClientKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length) { sslKeyPair *serverKeyPair = NULL; SECStatus rv; @@ -10227,7 +10207,7 @@ ssl3_SendNewSessionTicket(sslSocket *ss) goto loser; /* This is a fixed value. */ - rv = ssl3_AppendHandshakeNumber(ss, TLS_EX_SESS_TICKET_LIFETIME_HINT, 4); + rv = ssl3_AppendHandshakeNumber(ss, ssl_ticket_lifetime, 4); if (rv != SECSuccess) goto loser; @@ -10246,10 +10226,11 @@ loser: } static SECStatus -ssl3_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +ssl3_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; SECItem ticketData; + PRUint32 temp; SSL_TRC(3, ("%d: SSL3[%d]: handle session_ticket handshake", SSL_GETPID(), ss->fd)); @@ -10270,14 +10251,19 @@ ssl3_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length) * until it has verified the server's Finished message." See the comment in * ssl3_FinishHandshake for more details. */ - ss->ssl3.hs.newSessionTicket.received_timestamp = ssl_Time(); + ss->ssl3.hs.newSessionTicket.received_timestamp = PR_Now(); if (length < 4) { (void)SSL3_SendAlert(ss, alert_fatal, decode_error); PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET); return SECFailure; } - ss->ssl3.hs.newSessionTicket.ticket_lifetime_hint = - (PRUint32)ssl3_ConsumeHandshakeNumber(ss, 4, &b, &length); + + rv = ssl3_ConsumeHandshakeNumber(ss, &temp, 4, &b, &length); + if (rv != SECSuccess) { + PORT_SetError(SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET); + return SECFailure; + } + ss->ssl3.hs.newSessionTicket.ticket_lifetime_hint = temp; rv = ssl3_ConsumeHandshakeVariable(ss, &ticketData, 2, &b, &length); if (rv != SECSuccess || length != 0) { @@ -10551,7 +10537,7 @@ ssl3_CleanupPeerCerts(sslSocket *ss) * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +ssl3_HandleCertificateStatus(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; @@ -10570,23 +10556,22 @@ ssl3_HandleCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } SECStatus -ssl_ReadCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +ssl_ReadCertificateStatus(sslSocket *ss, PRUint8 *b, PRUint32 length) { - PRInt32 status, len; + PRUint32 status, len; + SECStatus rv; PORT_Assert(!ss->sec.isServer); /* Consume the CertificateStatusType enum */ - status = ssl3_ConsumeHandshakeNumber(ss, 1, &b, &length); - if (status != 1 /* ocsp */) { - ssl3_DecodeError(ss); /* sets error code */ - return SECFailure; + rv = ssl3_ConsumeHandshakeNumber(ss, &status, 1, &b, &length); + if (rv != SECSuccess || status != 1 /* ocsp */) { + return ssl3_DecodeError(ss); } - len = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length); - if (len != length) { - ssl3_DecodeError(ss); /* sets error code */ - return SECFailure; + rv = ssl3_ConsumeHandshakeNumber(ss, &len, 3, &b, &length); + if (rv != SECSuccess || len != length) { + return ssl3_DecodeError(ss); } #define MAX_CERTSTATUS_LEN 0x1ffff /* 128k - 1 */ @@ -10619,7 +10604,7 @@ ssl_ReadCertificateStatus(sslSocket *ss, SSL3Opaque *b, PRUint32 length) * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +ssl3_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length) { SSL_TRC(3, ("%d: SSL3[%d]: handle certificate handshake", SSL_GETPID(), ss->fd)); @@ -10639,12 +10624,12 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) /* Called from ssl3_HandleCertificate */ SECStatus -ssl3_CompleteHandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +ssl3_CompleteHandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length) { ssl3CertNode *c; ssl3CertNode *lastCert = NULL; - PRInt32 remaining = 0; - PRInt32 size; + PRUint32 remaining = 0; + PRUint32 size; SECStatus rv; PRBool isServer = ss->sec.isServer; PRBool isTLS; @@ -10660,10 +10645,10 @@ ssl3_CompleteHandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ** normal no_certificates message to maximize interoperability. */ if (length) { - remaining = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length); - if (remaining < 0) + rv = ssl3_ConsumeHandshakeNumber(ss, &remaining, 3, &b, &length); + if (rv != SECSuccess) goto loser; /* fatal alert already sent by ConsumeHandshake. */ - if ((PRUint32)remaining > length) + if (remaining > length) goto decode_loser; } @@ -10694,15 +10679,14 @@ ssl3_CompleteHandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } /* First get the peer cert. */ - remaining -= 3; - if (remaining < 0) + if (remaining < 3) goto decode_loser; - size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length); - if (size <= 0) + remaining -= 3; + rv = ssl3_ConsumeHandshakeNumber(ss, &size, 3, &b, &length); + if (rv != SECSuccess) goto loser; /* fatal alert already sent by ConsumeHandshake. */ - - if (remaining < size) + if (size == 0 || remaining < size) goto decode_loser; certItem.data = b; @@ -10722,15 +10706,14 @@ ssl3_CompleteHandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) /* Now get all of the CA certs. */ while (remaining > 0) { - remaining -= 3; - if (remaining < 0) + if (remaining < 3) goto decode_loser; - size = ssl3_ConsumeHandshakeNumber(ss, 3, &b, &length); - if (size <= 0) + remaining -= 3; + rv = ssl3_ConsumeHandshakeNumber(ss, &size, 3, &b, &length); + if (rv != SECSuccess) goto loser; /* fatal alert already sent by ConsumeHandshake. */ - - if (remaining < size) + if (size == 0 || remaining < size) goto decode_loser; certItem.data = b; @@ -10759,9 +10742,6 @@ ssl3_CompleteHandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) lastCert = c; } - if (remaining != 0) - goto decode_loser; - SECKEY_UpdateCertPQG(ss->sec.peerCert); if (!isServer && @@ -11049,13 +11029,10 @@ ssl3_ComputeTLSFinished(sslSocket *ss, ssl3CipherSpec *spec, PK11Context *prf_context; unsigned int retLen; + PORT_Assert(spec->master_secret); if (!spec->master_secret) { - const char *label = isServer ? "server finished" : "client finished"; - unsigned int len = 15; - HASH_HashType hashType = ssl3_GetTls12HashType(ss); - return ssl3_TLSPRFWithMasterSecret(spec, label, len, hashes->u.raw, - hashes->len, tlsFinished->verify_data, - sizeof tlsFinished->verify_data, hashType); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } if (spec->version < SSL_LIBRARY_VERSION_TLS_1_2) { @@ -11088,9 +11065,10 @@ ssl3_ComputeTLSFinished(sslSocket *ss, ssl3CipherSpec *spec, * ss->ssl3.crSpec). */ SECStatus -ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec, const char *label, - unsigned int labelLen, const unsigned char *val, unsigned int valLen, - unsigned char *out, unsigned int outLen, HASH_HashType tls12HashType) +ssl3_TLSPRFWithMasterSecret(sslSocket *ss, ssl3CipherSpec *spec, + const char *label, unsigned int labelLen, + const unsigned char *val, unsigned int valLen, + unsigned char *out, unsigned int outLen) { SECStatus rv = SECSuccess; @@ -11101,6 +11079,12 @@ ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec, const char *label, unsigned int retLen; if (spec->version >= SSL_LIBRARY_VERSION_TLS_1_2) { + /* Bug 1312976 non-SHA256 exporters are broken. */ + if (ssl3_GetPrfHashMechanism(ss) != CKM_SHA256) { + PORT_Assert(0); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } mech = CKM_NSS_TLS_PRF_GENERAL_SHA256; } prf_context = PK11_CreateContextBySymKey(mech, CKA_SIGN, @@ -11143,9 +11127,7 @@ ssl3_SendNextProto(sslSocket *ss) padding_len = 32 - ((ss->xtnData.nextProto.len + 2) % 32); - rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->xtnData.nextProto.len + - 2 + - padding_len); + rv = ssl3_AppendHandshakeHeader(ss, next_proto, ss->xtnData.nextProto.len + 2 + padding_len); if (rv != SECSuccess) { return rv; /* error code set by AppendHandshakeHeader */ } @@ -11298,7 +11280,7 @@ fail: */ SECStatus ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, - ssl3CipherSpec *spec, SSLAuthType authType) + ssl3CipherSpec *spec) { PK11SymKey *wrappingKey = NULL; PK11SlotInfo *symKeySlot; @@ -11352,8 +11334,7 @@ ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, mechanism = PK11_GetBestWrapMechanism(symKeySlot); if (mechanism != CKM_INVALID_MECHANISM) { wrappingKey = - ssl3_GetWrappingKey(ss, symKeySlot, ss->sec.serverCert, - mechanism, pwArg); + ssl3_GetWrappingKey(ss, symKeySlot, mechanism, pwArg); if (wrappingKey) { mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */ } @@ -11382,7 +11363,7 @@ ssl3_CacheWrappedMasterSecret(sslSocket *ss, sslSessionID *sid, * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, +ssl3_HandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, const SSL3Hashes *hashes) { sslSessionID *sid = ss->sec.ci.sid; @@ -11560,9 +11541,7 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid) sid->expirationTime = sid->creationTime + ssl3_sid_timeout; sid->localCert = CERT_DupCertificate(ss->sec.localCert); if (ss->sec.isServer) { - memcpy(&sid->certType, &ss->sec.serverCert->certType, sizeof(sid->certType)); - } else { - sid->certType.authType = ssl_auth_null; + sid->namedCurve = ss->sec.serverCert->namedCurve; } if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT && @@ -11586,8 +11565,7 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid) rv = SECSuccess; } else { rv = ssl3_CacheWrappedMasterSecret(ss, ss->sec.ci.sid, - ss->ssl3.crSpec, - ss->ssl3.hs.kea_def->authKeyType); + ss->ssl3.crSpec); sid->u.ssl3.keys.msIsWrapped = PR_TRUE; } ssl_ReleaseSpecReadLock(ss); /*************************************/ @@ -11646,7 +11624,7 @@ ssl3_FinishHandshake(sslSocket *ss) * Caller must hold Handshake and RecvBuf locks. */ SECStatus -ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length, +ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, PRBool endOfRecord) { SECStatus rv = SECSuccess; @@ -11732,10 +11710,7 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length, /* Start new handshake hashes when we start a new handshake. Unless this is * TLS 1.3 and we sent a HelloRetryRequest. */ if (ss->ssl3.hs.msg_type == client_hello && !ss->ssl3.hs.helloRetry) { - rv = ssl3_RestartHandshakeHashes(ss); - if (rv != SECSuccess) { - return rv; - } + ssl3_RestartHandshakeHashes(ss); } /* We should not include hello_request and hello_verify_request messages * in the handshake hashes */ @@ -11835,7 +11810,7 @@ ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, PRUint32 length, } static SECStatus -ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, SSL3Opaque *b, +ssl3_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, SSL3Hashes *hashesPtr) { SECStatus rv; @@ -12203,7 +12178,7 @@ ssl_RemoveTLSCBCPadding(sslBuffer *plaintext, unsigned int macSize) static void ssl_CBCExtractMAC(sslBuffer *plaintext, unsigned int originalLength, - SSL3Opaque *out, + PRUint8 *out, unsigned int macSize) { unsigned char rotatedMac[MAX_MAC_LENGTH]; @@ -12314,9 +12289,9 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, unsigned int originalLen = 0; unsigned char header[13]; unsigned int headerLen; - SSL3Opaque hash[MAX_MAC_LENGTH]; - SSL3Opaque givenHashBuf[MAX_MAC_LENGTH]; - SSL3Opaque *givenHash; + PRUint8 hash[MAX_MAC_LENGTH]; + PRUint8 givenHashBuf[MAX_MAC_LENGTH]; + PRUint8 *givenHash; unsigned int hashBytes = MAX_MAC_LENGTH + 1; SECStatus rv; @@ -12347,7 +12322,7 @@ ssl3_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext, * component." Instead, we decrypt the first cipher block and then * discard it before decrypting the rest. */ - SSL3Opaque iv[MAX_IV_LENGTH]; + PRUint8 iv[MAX_IV_LENGTH]; int decoded; ivLen = cipher_def->iv_size; @@ -12521,17 +12496,14 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) ssl3CipherSpec *crSpec; SSL3ContentType rType; sslBuffer *plaintext; - sslBuffer temp_buf; + sslBuffer temp_buf = { NULL, 0, 0 }; SSL3AlertDescription alert = internal_error; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); if (!ss->ssl3.initialized) { ssl_GetSSL3HandshakeLock(ss); - rv = ssl3_InitState(ss); + ssl3_InitState(ss); ssl_ReleaseSSL3HandshakeLock(ss); - if (rv != SECSuccess) { - return rv; /* ssl3_InitState has set the error code. */ - } } /* check for Token Presence */ @@ -12578,25 +12550,11 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) /* If we will be decompressing the buffer we need to decrypt somewhere * other than into databuf */ if (crSpec->decompressor) { - temp_buf.buf = NULL; - temp_buf.space = 0; plaintext = &temp_buf; } else { plaintext = databuf; } - plaintext->len = 0; /* filled in by Unprotect call below. */ - if (plaintext->space < MAX_FRAGMENT_LENGTH) { - rv = sslBuffer_Grow(plaintext, MAX_FRAGMENT_LENGTH + 2048); - if (rv != SECSuccess) { - ssl_ReleaseSpecReadLock(ss); /*************************/ - SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes", - SSL_GETPID(), ss->fd, MAX_FRAGMENT_LENGTH + 2048)); - /* sslBuffer_Grow has set a memory error code. */ - /* Perhaps we should send an alert. (but we have no memory!) */ - return SECFailure; - } - } /* We're waiting for another ClientHello, which will appear unencrypted. * Use the content type to tell whether this is should be discarded. @@ -12611,6 +12569,18 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) return SECSuccess; } + if (plaintext->space < MAX_FRAGMENT_LENGTH) { + rv = sslBuffer_Grow(plaintext, MAX_FRAGMENT_LENGTH + 2048); + if (rv != SECSuccess) { + ssl_ReleaseSpecReadLock(ss); /*************************/ + SSL_DBG(("%d: SSL3[%d]: HandleRecord, tried to get %d bytes", + SSL_GETPID(), ss->fd, MAX_FRAGMENT_LENGTH + 2048)); + /* sslBuffer_Grow has set a memory error code. */ + /* Perhaps we should send an alert. (but we have no memory!) */ + return SECFailure; + } + } + #ifdef UNSAFE_FUZZER_MODE rv = Null_Cipher(NULL, plaintext->buf, (int *)&plaintext->len, plaintext->space, cText->buf->buf, cText->buf->len); @@ -12632,6 +12602,9 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) SSL_DBG(("%d: SSL3[%d]: decryption failed", SSL_GETPID(), ss->fd)); + /* Clear the temp buffer used for decompression upon failure. */ + sslBuffer_Clear(&temp_buf); + if (IS_DTLS(ss) || (ss->sec.isServer && ss->ssl3.hs.zeroRttIgnore == ssl_0rtt_ignore_trial)) { @@ -12676,7 +12649,7 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) SSL3_COMPRESSION_MAX_EXPANSION)); /* sslBuffer_Grow has set a memory error code. */ /* Perhaps we should send an alert. (but we have no memory!) */ - PORT_Free(plaintext->buf); + sslBuffer_Clear(&temp_buf); return SECFailure; } } @@ -12714,12 +12687,12 @@ ssl3_HandleRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *databuf) } } - PORT_Free(plaintext->buf); + sslBuffer_Clear(&temp_buf); PORT_SetError(err); return SECFailure; } - PORT_Free(plaintext->buf); + sslBuffer_Clear(&temp_buf); } /* @@ -12849,16 +12822,14 @@ ssl3_InitCipherSpec(ssl3CipherSpec *spec) ** ssl3_HandleRecord() ** ** This function should perhaps acquire and release the SpecWriteLock. -** -** */ -SECStatus +void ssl3_InitState(sslSocket *ss) { PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); if (ss->ssl3.initialized) - return SECSuccess; /* Function should be idempotent */ + return; /* Function should be idempotent */ ss->ssl3.policy = SSL_ALLOWED; @@ -12913,7 +12884,6 @@ ssl3_InitState(sslSocket *ss) ssl_FilterSupportedGroups(ss); ss->ssl3.initialized = PR_TRUE; - return SECSuccess; } /* record the export policy for this cipher suite */ @@ -13136,7 +13106,7 @@ SSL_SignaturePrefGet(PRFileDesc *fd, SSLSignatureAndHashAlg *algorithms, } unsigned int -SSL_SignatureMaxCount() +SSL_SignatureMaxCount(void) { return MAX_SIGNATURE_SCHEMES; } diff --git a/security/nss/lib/ssl/ssl3ecc.c b/security/nss/lib/ssl/ssl3ecc.c index 9f2f4d621..b440b4b02 100644 --- a/security/nss/lib/ssl/ssl3ecc.c +++ b/security/nss/lib/ssl/ssl3ecc.c @@ -31,13 +31,6 @@ #include <stdio.h> -#ifndef PK11_SETATTRS -#define PK11_SETATTRS(x, id, v, l) \ - (x)->type = (id); \ - (x)->pValue = (v); \ - (x)->ulValueLen = (l); -#endif - SECStatus ssl_NamedGroup2ECParams(PLArenaPool *arena, const sslNamedGroupDef *ecGroup, SECKEYECParams *params) @@ -257,16 +250,6 @@ loser: return SECFailure; } -/* This function returns the size of the key_exchange field in - * the KeyShareEntry structure, i.e.: - * opaque point <1..2^8-1>; */ -unsigned int -tls13_SizeOfECDHEKeyShareKEX(const SECKEYPublicKey *pubKey) -{ - PORT_Assert(pubKey->keyType == ecKey); - return pubKey->u.ec.publicValue.len; -} - /* This function encodes the key_exchange field in * the KeyShareEntry structure. */ SECStatus @@ -284,7 +267,7 @@ tls13_EncodeECDHEKeyShareKEX(const sslSocket *ss, const SECKEYPublicKey *pubKey) ** Called from ssl3_HandleClientKeyExchange() */ SECStatus -ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, +ssl3_HandleECDHClientKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length, sslKeyPair *serverKeyPair) { @@ -358,7 +341,7 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, */ SECStatus ssl_ImportECDHKeyShare(sslSocket *ss, SECKEYPublicKey *peerKey, - SSL3Opaque *b, PRUint32 length, + PRUint8 *b, PRUint32 length, const sslNamedGroupDef *ecGroup) { SECStatus rv; @@ -436,23 +419,19 @@ ssl_GetECGroupForServerSocket(sslSocket *ss) return NULL; } - if (cert->certType.authType == ssl_auth_rsa_sign) { + if (SSL_CERT_IS(cert, ssl_auth_rsa_sign) || + SSL_CERT_IS(cert, ssl_auth_rsa_pss)) { certKeySize = SECKEY_PublicKeyStrengthInBits(cert->serverKeyPair->pubKey); - certKeySize = - SSL_RSASTRENGTH_TO_ECSTRENGTH(certKeySize); - } else if (cert->certType.authType == ssl_auth_ecdsa || - cert->certType.authType == ssl_auth_ecdh_rsa || - cert->certType.authType == ssl_auth_ecdh_ecdsa) { - const sslNamedGroupDef *groupDef = cert->certType.namedCurve; - + certKeySize = SSL_RSASTRENGTH_TO_ECSTRENGTH(certKeySize); + } else if (SSL_CERT_IS_EC(cert)) { /* We won't select a certificate unless the named curve has been * negotiated (or supported_curves was absent), double check that. */ - PORT_Assert(groupDef->keaType == ssl_kea_ecdh); - PORT_Assert(ssl_NamedGroupEnabled(ss, groupDef)); - if (!ssl_NamedGroupEnabled(ss, groupDef)) { + PORT_Assert(cert->namedCurve->keaType == ssl_kea_ecdh); + PORT_Assert(ssl_NamedGroupEnabled(ss, cert->namedCurve)); + if (!ssl_NamedGroupEnabled(ss, cert->namedCurve)) { return NULL; } - certKeySize = groupDef->bits; + certKeySize = cert->namedCurve->bits; } else { PORT_Assert(0); return NULL; @@ -519,7 +498,7 @@ ssl_CreateECDHEphemeralKeyPair(const sslSocket *ss, } SECStatus -ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +ssl3_HandleECDHServerKeyExchange(sslSocket *ss, PRUint8 *b, PRUint32 length) { PLArenaPool *arena = NULL; SECKEYPublicKey *peerKey = NULL; diff --git a/security/nss/lib/ssl/ssl3encode.c b/security/nss/lib/ssl/ssl3encode.c new file mode 100644 index 000000000..960208a0f --- /dev/null +++ b/security/nss/lib/ssl/ssl3encode.c @@ -0,0 +1,85 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "prnetdb.h" +#include "seccomon.h" +#include "secerr.h" +#include "ssl3encode.h" + +SECStatus +ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes) +{ + if (bytes > item->len) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + PORT_Memcpy(item->data, buf, bytes); + item->data += bytes; + item->len -= bytes; + return SECSuccess; +} + +SECStatus +ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 lenSize) +{ + SECStatus rv; + PRUint8 b[4]; + + ssl_EncodeUintX(num, lenSize, b); + rv = ssl3_AppendToItem(item, &b[0], lenSize); + return rv; +} + +SECStatus +ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes) +{ + if (bytes > item->len) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + + *buf = item->data; + item->data += bytes; + item->len -= bytes; + return SECSuccess; +} + +SECStatus +ssl3_ConsumeNumberFromItem(SECItem *item, PRUint32 *num, PRUint32 bytes) +{ + int i; + + if (bytes > item->len || bytes > sizeof(*num)) { + PORT_SetError(SEC_ERROR_BAD_DATA); + return SECFailure; + } + + *num = 0; + for (i = 0; i < bytes; i++) { + *num = (*num << 8) + item->data[i]; + } + + item->data += bytes; + item->len -= bytes; + + return SECSuccess; +} + +/* Helper function to encode an unsigned integer into a buffer. */ +PRUint8 * +ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to) +{ + PRUint64 encoded; + + PORT_Assert(bytes > 0 && bytes <= sizeof(encoded)); + + encoded = PR_htonll(value); + memcpy(to, ((unsigned char *)(&encoded)) + (sizeof(encoded) - bytes), bytes); + return to + bytes; +} diff --git a/security/nss/lib/ssl/ssl3encode.h b/security/nss/lib/ssl/ssl3encode.h new file mode 100644 index 000000000..3b88f7e7b --- /dev/null +++ b/security/nss/lib/ssl/ssl3encode.h @@ -0,0 +1,26 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is PRIVATE to SSL. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef __ssl3encode_h_ +#define __ssl3encode_h_ + +#include "seccomon.h" + +/* All of these functions modify the underlying SECItem, and so should + * be performed on a shallow copy.*/ +SECStatus ssl3_AppendToItem(SECItem *item, + const unsigned char *buf, PRUint32 bytes); +SECStatus ssl3_AppendNumberToItem(SECItem *item, + PRUint32 num, PRInt32 lenSize); +SECStatus ssl3_ConsumeFromItem(SECItem *item, + unsigned char **buf, PRUint32 bytes); +SECStatus ssl3_ConsumeNumberFromItem(SECItem *item, + PRUint32 *num, PRUint32 bytes); +PRUint8 *ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to); + +#endif diff --git a/security/nss/lib/ssl/ssl3ext.c b/security/nss/lib/ssl/ssl3ext.c index 0da41be12..271084cf7 100644 --- a/security/nss/lib/ssl/ssl3ext.c +++ b/security/nss/lib/ssl/ssl3ext.c @@ -87,6 +87,10 @@ static const ssl3ExtensionHandler serverCertificateHandlers[] = { { -1, NULL } }; +static const ssl3ExtensionHandler certificateRequestHandlers[] = { + { -1, NULL } +}; + /* Tables of functions to format TLS hello extensions, one function per * extension. * These static tables are for the formatting of client hello extensions. @@ -122,6 +126,7 @@ static const ssl3HelloExtensionSender clientHelloSendersTLS[SSL_MAX_EXTENSIONS] { ssl_tls13_cookie_xtn, &tls13_ClientSendHrrCookieXtn }, { ssl_tls13_psk_key_exchange_modes_xtn, &tls13_ClientSendPskKeyExchangeModesXtn }, + { ssl_padding_xtn, &ssl3_ClientSendPaddingExtension }, /* The pre_shared_key extension MUST be last. */ { ssl_tls13_pre_shared_key_xtn, &tls13_ClientSendPreSharedKeyXtn }, /* any extra entries will appear as { 0, NULL } */ @@ -167,22 +172,22 @@ ssl3_ClientExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type) * buffer so they can only be used during ClientHello processing. */ SECStatus -ssl3_ParseExtensions(sslSocket *ss, SSL3Opaque **b, PRUint32 *length) +ssl3_ParseExtensions(sslSocket *ss, PRUint8 **b, PRUint32 *length) { /* Clean out the extensions list. */ ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions); while (*length) { SECStatus rv; - PRInt32 extension_type; + PRUint32 extension_type; SECItem extension_data = { siBuffer, NULL, 0 }; TLSExtension *extension; PRCList *cursor; /* Get the extension's type field */ - extension_type = ssl3_ConsumeHandshakeNumber(ss, 2, b, length); - if (extension_type < 0) { /* failure to decode extension_type */ - return SECFailure; /* alert already sent */ + rv = ssl3_ConsumeHandshakeNumber(ss, &extension_type, 2, b, length); + if (rv != SECSuccess) { + return SECFailure; /* alert already sent */ } SSL_TRC(10, ("%d: SSL3[%d]: parsing extension %d", @@ -249,7 +254,10 @@ ssl3_HandleParsedExtensions(sslSocket *ss, SSL3HandshakeType handshakeMessage) { const ssl3ExtensionHandler *handlers; - PRBool isTLS13 = ss->version >= SSL_LIBRARY_VERSION_TLS_1_3; + /* HelloRetryRequest doesn't set ss->version. It might be safe to + * do so, but we weren't entirely sure. TODO(ekr@rtfm.com). */ + PRBool isTLS13 = (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) || + (handshakeMessage == hello_retry_request); PRCList *cursor; switch (handshakeMessage) { @@ -277,6 +285,10 @@ ssl3_HandleParsedExtensions(sslSocket *ss, PORT_Assert(!ss->sec.isServer); handlers = serverCertificateHandlers; break; + case certificate_request: + PORT_Assert(!ss->sec.isServer); + handlers = certificateRequestHandlers; + break; default: PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); PORT_Assert(0); @@ -348,7 +360,7 @@ ssl3_HandleParsedExtensions(sslSocket *ss, * ssl3_HandleParsedExtensions. */ SECStatus ssl3_HandleExtensions(sslSocket *ss, - SSL3Opaque **b, PRUint32 *length, + PRUint8 **b, PRUint32 *length, SSL3HandshakeType handshakeMessage) { SECStatus rv; @@ -488,7 +500,7 @@ ssl3_ExtAppendHandshakeNumber(const sslSocket *ss, PRInt32 num, SECStatus ssl3_ExtAppendHandshakeVariable(const sslSocket *ss, - const SSL3Opaque *src, PRInt32 bytes, + const PRUint8 *src, PRInt32 bytes, PRInt32 lenSize) { return ssl3_AppendHandshakeVariable((sslSocket *)ss, src, bytes, lenSize); @@ -508,22 +520,22 @@ ssl3_ExtDecodeError(const sslSocket *ss) } SECStatus -ssl3_ExtConsumeHandshake(const sslSocket *ss, void *v, PRInt32 bytes, - SSL3Opaque **b, PRUint32 *length) +ssl3_ExtConsumeHandshake(const sslSocket *ss, void *v, PRUint32 bytes, + PRUint8 **b, PRUint32 *length) { return ssl3_ConsumeHandshake((sslSocket *)ss, v, bytes, b, length); } -PRInt32 -ssl3_ExtConsumeHandshakeNumber(const sslSocket *ss, PRInt32 bytes, - SSL3Opaque **b, PRUint32 *length) +SECStatus +ssl3_ExtConsumeHandshakeNumber(const sslSocket *ss, PRUint32 *num, + PRUint32 bytes, PRUint8 **b, PRUint32 *length) { - return ssl3_ConsumeHandshakeNumber((sslSocket *)ss, bytes, b, length); + return ssl3_ConsumeHandshakeNumber((sslSocket *)ss, num, bytes, b, length); } SECStatus ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i, - PRInt32 bytes, SSL3Opaque **b, + PRUint32 bytes, PRUint8 **b, PRUint32 *length) { return ssl3_ConsumeHandshakeVariable((sslSocket *)ss, i, bytes, b, length); diff --git a/security/nss/lib/ssl/ssl3ext.h b/security/nss/lib/ssl/ssl3ext.h index f93ad65bd..90407375a 100644 --- a/security/nss/lib/ssl/ssl3ext.h +++ b/security/nss/lib/ssl/ssl3ext.h @@ -54,6 +54,9 @@ struct TLSExtensionDataStr { PRUint16 advertised[SSL_MAX_EXTENSIONS]; PRUint16 negotiated[SSL_MAX_EXTENSIONS]; + /* Amount of padding we need to add. */ + PRUint16 paddingLen; + /* SessionTicket Extension related data. */ PRBool ticketTimestampVerified; PRBool emptySessionTicket; @@ -108,10 +111,10 @@ typedef struct TLSExtensionStr { } TLSExtension; SECStatus ssl3_HandleExtensions(sslSocket *ss, - SSL3Opaque **b, PRUint32 *length, + PRUint8 **b, PRUint32 *length, SSL3HandshakeType handshakeMessage); SECStatus ssl3_ParseExtensions(sslSocket *ss, - SSL3Opaque **b, PRUint32 *length); + PRUint8 **b, PRUint32 *length); SECStatus ssl3_HandleParsedExtensions(sslSocket *ss, SSL3HandshakeType handshakeMessage); TLSExtension *ssl3_FindExtension(sslSocket *ss, @@ -130,9 +133,8 @@ SECStatus ssl3_RegisterExtensionSender(const sslSocket *ss, PRInt32 ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, const ssl3HelloExtensionSender *sender); -unsigned int ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength); -PRInt32 ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen, - PRUint32 maxBytes); +void ssl3_CalculatePaddingExtLen(sslSocket *ss, + unsigned int clientHelloLength); /* Thunks to let us operate on const sslSocket* objects. */ SECStatus ssl3_ExtAppendHandshake(const sslSocket *ss, const void *void_src, @@ -140,17 +142,18 @@ SECStatus ssl3_ExtAppendHandshake(const sslSocket *ss, const void *void_src, SECStatus ssl3_ExtAppendHandshakeNumber(const sslSocket *ss, PRInt32 num, PRInt32 lenSize); SECStatus ssl3_ExtAppendHandshakeVariable(const sslSocket *ss, - const SSL3Opaque *src, PRInt32 bytes, + const PRUint8 *src, PRInt32 bytes, PRInt32 lenSize); void ssl3_ExtSendAlert(const sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc); void ssl3_ExtDecodeError(const sslSocket *ss); -SECStatus ssl3_ExtConsumeHandshake(const sslSocket *ss, void *v, PRInt32 bytes, - SSL3Opaque **b, PRUint32 *length); -PRInt32 ssl3_ExtConsumeHandshakeNumber(const sslSocket *ss, PRInt32 bytes, - SSL3Opaque **b, PRUint32 *length); +SECStatus ssl3_ExtConsumeHandshake(const sslSocket *ss, void *v, PRUint32 bytes, + PRUint8 **b, PRUint32 *length); +SECStatus ssl3_ExtConsumeHandshakeNumber(const sslSocket *ss, PRUint32 *num, + PRUint32 bytes, PRUint8 **b, + PRUint32 *length); SECStatus ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i, - PRInt32 bytes, SSL3Opaque **b, + PRUint32 bytes, PRUint8 **b, PRUint32 *length); #endif diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c index 2a80e2690..370bd8b3e 100644 --- a/security/nss/lib/ssl/ssl3exthandle.c +++ b/security/nss/lib/ssl/ssl3exthandle.c @@ -12,147 +12,12 @@ #include "pk11pub.h" #include "blapit.h" #include "prinit.h" +#include "selfencrypt.h" +#include "ssl3encode.h" #include "ssl3ext.h" #include "ssl3exthandle.h" #include "tls13exthandle.h" /* For tls13_ServerSendStatusRequestXtn. */ -static unsigned char key_name[SESS_TICKET_KEY_NAME_LEN]; -static PK11SymKey *session_ticket_enc_key = NULL; -static PK11SymKey *session_ticket_mac_key = NULL; - -static PRCallOnceType generate_session_keys_once; - -static SECStatus ssl3_ParseEncryptedSessionTicket(sslSocket *ss, - SECItem *data, EncryptedSessionTicket *enc_session_ticket); -static SECStatus ssl3_AppendToItem(SECItem *item, const unsigned char *buf, - PRUint32 bytes); -static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes); -static SECStatus ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, - PRInt32 lenSize); -static SECStatus ssl3_GetSessionTicketKeys(sslSocket *ss, - PK11SymKey **aes_key, PK11SymKey **mac_key); -static SECStatus ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes); - -/* - * Write bytes. Using this function means the SECItem structure - * cannot be freed. The caller is expected to call this function - * on a shallow copy of the structure. - */ -static SECStatus -ssl3_AppendToItem(SECItem *item, const unsigned char *buf, PRUint32 bytes) -{ - if (bytes > item->len) - return SECFailure; - - PORT_Memcpy(item->data, buf, bytes); - item->data += bytes; - item->len -= bytes; - return SECSuccess; -} - -/* - * Write a number in network byte order. Using this function means the - * SECItem structure cannot be freed. The caller is expected to call - * this function on a shallow copy of the structure. - */ -static SECStatus -ssl3_AppendNumberToItem(SECItem *item, PRUint32 num, PRInt32 lenSize) -{ - SECStatus rv; - PRUint8 b[4]; - PRUint8 *p = b; - - switch (lenSize) { - case 4: - *p++ = (PRUint8)(num >> 24); - case 3: - *p++ = (PRUint8)(num >> 16); - case 2: - *p++ = (PRUint8)(num >> 8); - case 1: - *p = (PRUint8)num; - } - rv = ssl3_AppendToItem(item, &b[0], lenSize); - return rv; -} - -SECStatus -ssl3_SessionTicketShutdown(void *appData, void *nssData) -{ - if (session_ticket_enc_key) { - PK11_FreeSymKey(session_ticket_enc_key); - session_ticket_enc_key = NULL; - } - if (session_ticket_mac_key) { - PK11_FreeSymKey(session_ticket_mac_key); - session_ticket_mac_key = NULL; - } - PORT_Memset(&generate_session_keys_once, 0, - sizeof(generate_session_keys_once)); - return SECSuccess; -} - -static PRStatus -ssl3_GenerateSessionTicketKeys(void *data) -{ - SECStatus rv; - sslSocket *ss = (sslSocket *)data; - sslServerCertType certType = { ssl_auth_rsa_decrypt, NULL }; - const sslServerCert *sc; - SECKEYPrivateKey *svrPrivKey; - SECKEYPublicKey *svrPubKey; - - sc = ssl_FindServerCert(ss, &certType); - if (!sc || !sc->serverKeyPair) { - SSL_DBG(("%d: SSL[%d]: No ssl_auth_rsa_decrypt cert and key pair", - SSL_GETPID(), ss->fd)); - goto loser; - } - svrPrivKey = sc->serverKeyPair->privKey; - svrPubKey = sc->serverKeyPair->pubKey; - if (svrPrivKey == NULL || svrPubKey == NULL) { - SSL_DBG(("%d: SSL[%d]: Pub or priv key(s) is NULL.", - SSL_GETPID(), ss->fd)); - goto loser; - } - - /* Get a copy of the session keys from shared memory. */ - PORT_Memcpy(key_name, SESS_TICKET_KEY_NAME_PREFIX, - sizeof(SESS_TICKET_KEY_NAME_PREFIX)); - if (!ssl_GetSessionTicketKeys(svrPrivKey, svrPubKey, ss->pkcs11PinArg, - &key_name[SESS_TICKET_KEY_NAME_PREFIX_LEN], - &session_ticket_enc_key, &session_ticket_mac_key)) - return PR_FAILURE; - - rv = NSS_RegisterShutdown(ssl3_SessionTicketShutdown, NULL); - if (rv != SECSuccess) - goto loser; - - return PR_SUCCESS; - -loser: - ssl3_SessionTicketShutdown(NULL, NULL); - return PR_FAILURE; -} - -static SECStatus -ssl3_GetSessionTicketKeys(sslSocket *ss, PK11SymKey **aes_key, - PK11SymKey **mac_key) -{ - if (PR_CallOnceWithArg(&generate_session_keys_once, - ssl3_GenerateSessionTicketKeys, ss) != - PR_SUCCESS) - return SECFailure; - - if (session_ticket_enc_key == NULL || - session_ticket_mac_key == NULL) - return SECFailure; - - *aes_key = session_ticket_enc_key; - *mac_key = session_ticket_mac_key; - return SECSuccess; -} - /* Format an SNI extension, using the name from the socket's URL, * unless that name is a dotted decimal string. * Used by client and server. @@ -223,7 +88,8 @@ SECStatus ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECItem *names = NULL; - PRInt32 listLenBytes = 0; + PRUint32 listLenBytes = 0; + SECStatus rv; if (!ss->sec.isServer) { return SECSuccess; /* ignore extension */ @@ -236,8 +102,8 @@ ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint1 } /* length of server_name_list */ - listLenBytes = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - if (listLenBytes < 0) { + rv = ssl3_ExtConsumeHandshakeNumber(ss, &listLenBytes, 2, &data->data, &data->len); + if (rv != SECSuccess) { goto loser; /* alert already sent */ } if (listLenBytes == 0 || listLenBytes != data->len) { @@ -247,12 +113,11 @@ ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint1 /* Read ServerNameList. */ while (data->len > 0) { SECItem tmp; - SECStatus rv; - PRInt32 type; + PRUint32 type; /* Read Name Type. */ - type = ssl3_ExtConsumeHandshakeNumber(ss, 1, &data->data, &data->len); - if (type < 0) { /* i.e., SECFailure cast to PRint32 */ + rv = ssl3_ExtConsumeHandshakeNumber(ss, &type, 1, &data->data, &data->len); + if (rv != SECSuccess) { /* alert sent in ConsumeHandshakeNumber */ goto loser; } @@ -372,11 +237,7 @@ ssl3_SendSessionTicketXtn( if (session_ticket->ticket.data) { if (xtnData->ticketTimestampVerified) { extension_length += session_ticket->ticket.len; - } else if (!append && - (session_ticket->ticket_lifetime_hint == 0 || - (session_ticket->ticket_lifetime_hint + - session_ticket->received_timestamp > - ssl_Time()))) { + } else if (!append && ssl_TicketTimeValid(session_ticket)) { extension_length += session_ticket->ticket.len; xtnData->ticketTimestampVerified = PR_TRUE; } @@ -417,30 +278,25 @@ loser: return -1; } -static SECStatus -ssl3_ParseEncryptedSessionTicket(sslSocket *ss, SECItem *data, - EncryptedSessionTicket *enc_session_ticket) +PRBool +ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag) { - if (ssl3_ConsumeFromItem(data, &enc_session_ticket->key_name, - SESS_TICKET_KEY_NAME_LEN) != - SECSuccess) - return SECFailure; - if (ssl3_ConsumeFromItem(data, &enc_session_ticket->iv, - AES_BLOCK_SIZE) != - SECSuccess) - return SECFailure; - if (ssl3_ConsumeHandshakeVariable(ss, &enc_session_ticket->encrypted_state, - 2, &data->data, &data->len) != - SECSuccess) - return SECFailure; - if (ssl3_ConsumeFromItem(data, &enc_session_ticket->mac, - TLS_EX_SESS_TICKET_MAC_LENGTH) != - SECSuccess) - return SECFailure; - if (data->len != 0) /* Make sure that we have consumed all bytes. */ - return SECFailure; + const unsigned char *data = ss->opt.nextProtoNego.data; + unsigned int length = ss->opt.nextProtoNego.len; + unsigned int offset = 0; - return SECSuccess; + if (!tag->len) + return PR_TRUE; + + while (offset < length) { + unsigned int taglen = (unsigned int)data[offset]; + if ((taglen == tag->len) && + !PORT_Memcmp(data + offset + 1, tag->data, tag->len)) + return PR_TRUE; + offset += 1 + taglen; + } + + return PR_FALSE; } /* handle an incoming Next Protocol Negotiation extension. */ @@ -542,7 +398,7 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData, SECStatus ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - int count; + PRUint32 count; SECStatus rv; /* We expressly don't want to allow ALPN on renegotiation, @@ -556,8 +412,8 @@ ssl3_ServerHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRU /* Unlike NPN, ALPN has extra redundant length information so that * the extension is the same in both ClientHello and ServerHello. */ - count = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - if (count != data->len) { + rv = ssl3_ExtConsumeHandshakeNumber(ss, &count, 2, &data->data, &data->len); + if (rv != SECSuccess || count != data->len) { ssl3_ExtDecodeError(ss); return SECFailure; } @@ -621,7 +477,7 @@ SECStatus ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; - PRInt32 list_len; + PRUint32 list_len; SECItem protocol_name; if (ssl3_ExtensionNegotiated(ss, ssl_next_proto_nego_xtn)) { @@ -639,9 +495,10 @@ ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRU return SECFailure; } - list_len = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len); + rv = ssl3_ExtConsumeHandshakeNumber(ss, &list_len, 2, &data->data, + &data->len); /* The list has to be the entire extension. */ - if (list_len != data->len) { + if (rv != SECSuccess || list_len != data->len) { ssl3_ExtSendAlert(ss, alert_fatal, decode_error); PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); return SECFailure; @@ -656,6 +513,12 @@ ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRU return SECFailure; } + if (!ssl_AlpnTagAllowed(ss, &protocol_name)) { + ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter); + PORT_SetError(SSL_ERROR_NEXT_PROTOCOL_DATA_INVALID); + return SECFailure; + } + SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE); xtnData->nextProtoState = SSL_NEXT_PROTO_SELECTED; xtnData->negotiated[xtnData->numNegotiated++] = ex_type; @@ -938,6 +801,9 @@ ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECSuccess; } +PRUint32 ssl_ticket_lifetime = 2 * 24 * 60 * 60; /* 2 days in seconds */ +#define TLS_EX_SESS_TICKET_VERSION (0x0105) + /* * Called from ssl3_SendNewSessionTicket, tls13_SendNewSessionTicket */ @@ -946,40 +812,21 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket, SECItem *ticket_data) { - PRUint32 i; SECStatus rv; SECItem plaintext; SECItem plaintext_item = { 0, NULL, 0 }; - SECItem ciphertext = { 0, NULL, 0 }; - PRUint32 ciphertext_length; + PRUint32 plaintext_length; SECItem ticket_buf = { 0, NULL, 0 }; - SECItem ticket_tmp = { 0, NULL, 0 }; - SECItem macParam = { 0, NULL, 0 }; PRBool ms_is_wrapped; unsigned char wrapped_ms[SSL3_MASTER_SECRET_LENGTH]; SECItem ms_item = { 0, NULL, 0 }; - PRUint32 padding_length; - PRUint32 ticket_length; PRUint32 cert_length = 0; - PRUint8 length_buf[4]; PRUint32 now; - PK11SymKey *aes_key = NULL; - PK11SymKey *mac_key = NULL; - CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC; - PK11Context *aes_ctx; - CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC; - PK11Context *hmac_ctx = NULL; - unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH]; - unsigned int computed_mac_length; - unsigned char iv[AES_BLOCK_SIZE]; - SECItem ivItem; SECItem *srvName = NULL; - PRUint32 srvNameLen = 0; CK_MECHANISM_TYPE msWrapMech = 0; /* dummy default value, * must be >= 0 */ ssl3CipherSpec *spec; - const sslServerCertType *certType; - SECItem alpnSelection = { siBuffer, NULL, 0 }; + SECItem *alpnSelection = NULL; SSL_TRC(3, ("%d: SSL3[%d]: send session_ticket handshake", SSL_GETPID(), ss->fd)); @@ -988,20 +835,9 @@ ssl3_EncodeSessionTicket(sslSocket *ss, PORT_Assert(ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { - cert_length = 3 + ss->sec.ci.sid->peerCert->derCert.len; + cert_length = 2 + ss->sec.ci.sid->peerCert->derCert.len; } - /* Get IV and encryption keys */ - ivItem.data = iv; - ivItem.len = sizeof(iv); - rv = PK11_GenerateRandom(iv, sizeof(iv)); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_GetSessionTicketKeys(ss, &aes_key, &mac_key); - if (rv != SECSuccess) - goto loser; - if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) { spec = ss->ssl3.cwSpec; } else { @@ -1017,8 +853,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, sslSessionID sid; PORT_Memset(&sid, 0, sizeof(sslSessionID)); - rv = ssl3_CacheWrappedMasterSecret(ss, &sid, spec, - ss->ssl3.hs.kea_def->authKeyType); + rv = ssl3_CacheWrappedMasterSecret(ss, &sid, spec); if (rv == SECSuccess) { if (sid.u.ssl3.keys.wrapped_master_secret_len > sizeof(wrapped_ms)) goto loser; @@ -1035,17 +870,14 @@ ssl3_EncodeSessionTicket(sslSocket *ss, } /* Prep to send negotiated name */ srvName = &ss->sec.ci.sid->u.ssl3.srvName; - if (srvName->data && srvName->len) { - srvNameLen = 2 + srvName->len; /* len bytes + name len */ - } - if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT && - ss->xtnData.nextProto.data) { - alpnSelection = ss->xtnData.nextProto; - } + PORT_Assert(ss->xtnData.nextProtoState == SSL_NEXT_PROTO_SELECTED || + ss->xtnData.nextProtoState == SSL_NEXT_PROTO_NEGOTIATED || + ss->xtnData.nextProto.len == 0); + alpnSelection = &ss->xtnData.nextProto; - ciphertext_length = - sizeof(PRUint16) /* ticket_version */ + plaintext_length = + sizeof(PRUint16) /* ticket version */ + sizeof(SSL3ProtocolVersion) /* ssl_version */ + sizeof(ssl3CipherSuite) /* ciphersuite */ + 1 /* compression */ @@ -1057,23 +889,19 @@ ssl3_EncodeSessionTicket(sslSocket *ss, + ms_item.len /* master_secret */ + 1 /* client_auth_type */ + cert_length /* cert */ - + 1 /* server name type */ - + srvNameLen /* name len + length field */ + + 2 + srvName->len /* name len + length field */ + 1 /* extendedMasterSecretUsed */ + sizeof(ticket->ticket_lifetime_hint) /* ticket lifetime hint */ + sizeof(ticket->flags) /* ticket flags */ - + 1 + alpnSelection.len; /* npn value + length field. */ - padding_length = AES_BLOCK_SIZE - - (ciphertext_length % - AES_BLOCK_SIZE); - ciphertext_length += padding_length; + + 1 + alpnSelection->len /* alpn value + length field */ + + 4; /* maxEarlyData */ - if (SECITEM_AllocItem(NULL, &plaintext_item, ciphertext_length) == NULL) + if (SECITEM_AllocItem(NULL, &plaintext_item, plaintext_length) == NULL) goto loser; plaintext = plaintext_item; - /* ticket_version */ + /* ticket version */ rv = ssl3_AppendNumberToItem(&plaintext, TLS_EX_SESS_TICKET_VERSION, sizeof(PRUint16)); if (rv != SECSuccess) @@ -1111,22 +939,15 @@ ssl3_EncodeSessionTicket(sslSocket *ss, goto loser; /* certificate type */ - certType = &ss->sec.serverCert->certType; - PORT_Assert(certType->authType == ss->sec.authType); - switch (ss->sec.authType) { - case ssl_auth_ecdsa: - case ssl_auth_ecdh_rsa: - case ssl_auth_ecdh_ecdsa: - PORT_Assert(certType->namedCurve); - PORT_Assert(certType->namedCurve->keaType == ssl_kea_ecdh); - /* EC curves only use the second of the two bytes. */ - PORT_Assert(certType->namedCurve->name < 256); - rv = ssl3_AppendNumberToItem(&plaintext, - certType->namedCurve->name, 1); - break; - default: - rv = ssl3_AppendNumberToItem(&plaintext, 0, 1); - break; + PORT_Assert(SSL_CERT_IS(ss->sec.serverCert, ss->sec.authType)); + if (SSL_CERT_IS_EC(ss->sec.serverCert)) { + const sslServerCert *cert = ss->sec.serverCert; + PORT_Assert(cert->namedCurve); + /* EC curves only use the second of the two bytes. */ + PORT_Assert(cert->namedCurve->name < 256); + rv = ssl3_AppendNumberToItem(&plaintext, cert->namedCurve->name, 1); + } else { + rv = ssl3_AppendNumberToItem(&plaintext, 0, 1); } if (rv != SECSuccess) goto loser; @@ -1145,13 +966,13 @@ ssl3_EncodeSessionTicket(sslSocket *ss, if (rv != SECSuccess) goto loser; - /* client_identity */ + /* client identity */ if (ss->opt.requestCertificate && ss->sec.ci.sid->peerCert) { rv = ssl3_AppendNumberToItem(&plaintext, CLIENT_AUTH_CERTIFICATE, 1); if (rv != SECSuccess) goto loser; rv = ssl3_AppendNumberToItem(&plaintext, - ss->sec.ci.sid->peerCert->derCert.len, 3); + ss->sec.ci.sid->peerCert->derCert.len, 2); if (rv != SECSuccess) goto loser; rv = ssl3_AppendToItem(&plaintext, @@ -1172,23 +993,14 @@ ssl3_EncodeSessionTicket(sslSocket *ss, if (rv != SECSuccess) goto loser; - if (srvNameLen) { - /* Name Type (sni_host_name) */ - rv = ssl3_AppendNumberToItem(&plaintext, srvName->type, 1); - if (rv != SECSuccess) - goto loser; - /* HostName (length and value) */ - rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2); - if (rv != SECSuccess) - goto loser; + /* HostName (length and value) */ + rv = ssl3_AppendNumberToItem(&plaintext, srvName->len, 2); + if (rv != SECSuccess) + goto loser; + if (srvName->len) { rv = ssl3_AppendToItem(&plaintext, srvName->data, srvName->len); if (rv != SECSuccess) goto loser; - } else { - /* No Name */ - rv = ssl3_AppendNumberToItem(&plaintext, (char)TLS_STE_NO_SERVER_NAME, 1); - if (rv != SECSuccess) - goto loser; } /* extendedMasterSecretUsed */ @@ -1203,123 +1015,52 @@ ssl3_EncodeSessionTicket(sslSocket *ss, if (rv != SECSuccess) goto loser; - /* NPN value. */ - PORT_Assert(alpnSelection.len < 256); - rv = ssl3_AppendNumberToItem(&plaintext, alpnSelection.len, 1); + /* ALPN value. */ + PORT_Assert(alpnSelection->len < 256); + rv = ssl3_AppendNumberToItem(&plaintext, alpnSelection->len, 1); if (rv != SECSuccess) goto loser; - if (alpnSelection.len) { - rv = ssl3_AppendToItem(&plaintext, alpnSelection.data, alpnSelection.len); + if (alpnSelection->len) { + rv = ssl3_AppendToItem(&plaintext, alpnSelection->data, + alpnSelection->len); if (rv != SECSuccess) goto loser; } - PORT_Assert(plaintext.len == padding_length); - for (i = 0; i < padding_length; i++) - plaintext.data[i] = (unsigned char)padding_length; - - if (SECITEM_AllocItem(NULL, &ciphertext, ciphertext_length) == NULL) { - rv = SECFailure; - goto loser; - } - - /* Generate encrypted portion of ticket. */ - PORT_Assert(aes_key); - aes_ctx = PK11_CreateContextBySymKey(cipherMech, CKA_ENCRYPT, aes_key, &ivItem); - if (!aes_ctx) - goto loser; - - rv = PK11_CipherOp(aes_ctx, ciphertext.data, - (int *)&ciphertext.len, ciphertext.len, - plaintext_item.data, plaintext_item.len); - PK11_Finalize(aes_ctx); - PK11_DestroyContext(aes_ctx, PR_TRUE); - if (rv != SECSuccess) - goto loser; - - /* Convert ciphertext length to network order. */ - length_buf[0] = (ciphertext.len >> 8) & 0xff; - length_buf[1] = (ciphertext.len) & 0xff; - - /* Compute MAC. */ - PORT_Assert(mac_key); - hmac_ctx = PK11_CreateContextBySymKey(macMech, CKA_SIGN, mac_key, &macParam); - if (!hmac_ctx) - goto loser; - - rv = PK11_DigestBegin(hmac_ctx); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestOp(hmac_ctx, key_name, SESS_TICKET_KEY_NAME_LEN); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestOp(hmac_ctx, iv, sizeof(iv)); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestOp(hmac_ctx, (unsigned char *)length_buf, 2); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestOp(hmac_ctx, ciphertext.data, ciphertext.len); - if (rv != SECSuccess) - goto loser; - rv = PK11_DigestFinal(hmac_ctx, computed_mac, - &computed_mac_length, sizeof(computed_mac)); + rv = ssl3_AppendNumberToItem(&plaintext, ssl_max_early_data_size, 4); if (rv != SECSuccess) goto loser; - ticket_length = - +SESS_TICKET_KEY_NAME_LEN /* key_name */ - + AES_BLOCK_SIZE /* iv */ - + 2 /* length field for NewSessionTicket.ticket.encrypted_state */ - + ciphertext_length /* encrypted_state */ - + TLS_EX_SESS_TICKET_MAC_LENGTH; /* mac */ + /* Check that we are totally full. */ + PORT_Assert(plaintext.len == 0); - if (SECITEM_AllocItem(NULL, &ticket_buf, ticket_length) == NULL) { - rv = SECFailure; + /* 128 just gives us enough room for overhead. */ + if (SECITEM_AllocItem(NULL, &ticket_buf, plaintext_length + 128) == NULL) { goto loser; } - ticket_tmp = ticket_buf; /* Shallow copy because AppendToItem is - * destructive. */ - rv = ssl3_AppendToItem(&ticket_tmp, key_name, SESS_TICKET_KEY_NAME_LEN); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendToItem(&ticket_tmp, iv, sizeof(iv)); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendNumberToItem(&ticket_tmp, ciphertext.len, 2); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendToItem(&ticket_tmp, ciphertext.data, ciphertext.len); - if (rv != SECSuccess) - goto loser; - - rv = ssl3_AppendToItem(&ticket_tmp, computed_mac, computed_mac_length); - if (rv != SECSuccess) + /* Finally, encrypt the ticket. */ + rv = ssl_SelfEncryptProtect(ss, plaintext_item.data, plaintext_item.len, + ticket_buf.data, &ticket_buf.len, ticket_buf.len); + if (rv != SECSuccess) { goto loser; + } /* Give ownership of memory to caller. */ *ticket_data = ticket_buf; - ticket_buf.data = NULL; + + SECITEM_FreeItem(&plaintext_item, PR_FALSE); + return SECSuccess; loser: - if (hmac_ctx) { - PK11_DestroyContext(hmac_ctx, PR_TRUE); - } if (plaintext_item.data) { SECITEM_FreeItem(&plaintext_item, PR_FALSE); } - if (ciphertext.data) { - SECITEM_FreeItem(&ciphertext, PR_FALSE); - } if (ticket_buf.data) { SECITEM_FreeItem(&ticket_buf, PR_FALSE); } - return rv; + return SECFailure; } /* When a client receives a SessionTicket extension a NewSessionTicket @@ -1338,434 +1079,375 @@ ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData return SECSuccess; } -/* Generic ticket processing code, common to TLS 1.0-1.2 and - * TLS 1.3. */ -SECStatus -ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) +static SECStatus +ssl_ParseSessionTicket(sslSocket *ss, const SECItem *decryptedTicket, + SessionTicket *parsedTicket) { + PRUint32 temp; SECStatus rv; - SECItem *decrypted_state = NULL; - SessionTicket *parsed_session_ticket = NULL; - sslSessionID *sid = NULL; - SSL3Statistics *ssl3stats; - PRUint32 i; - SECItem extension_data; - EncryptedSessionTicket enc_session_ticket; - unsigned char computed_mac[TLS_EX_SESS_TICKET_MAC_LENGTH]; - unsigned int computed_mac_length; - PK11SymKey *aes_key = NULL; - PK11SymKey *mac_key = NULL; - PK11Context *hmac_ctx; - CK_MECHANISM_TYPE macMech = CKM_SHA256_HMAC; - PK11Context *aes_ctx; - CK_MECHANISM_TYPE cipherMech = CKM_AES_CBC; - unsigned char *padding; - PRUint32 padding_length; - unsigned char *buffer; - unsigned int buffer_len; - PRInt32 temp; - SECItem cert_item; - PRInt8 nameType = TLS_STE_NO_SERVER_NAME; - SECItem macParam = { siBuffer, NULL, 0 }; - SECItem alpn_item; - SECItem ivItem; - - /* Turn off stateless session resumption if the client sends a - * SessionTicket extension, even if the extension turns out to be - * malformed (ss->sec.ci.sid is non-NULL when doing session - * renegotiation.) - */ - if (ss->sec.ci.sid != NULL) { - ss->sec.uncache(ss->sec.ci.sid); - ssl_FreeSID(ss->sec.ci.sid); - ss->sec.ci.sid = NULL; - } - extension_data.data = data->data; /* Keep a copy for future use. */ - extension_data.len = data->len; + PRUint8 *buffer = decryptedTicket->data; + unsigned int len = decryptedTicket->len; + + PORT_Memset(parsedTicket, 0, sizeof(*parsedTicket)); + parsedTicket->valid = PR_FALSE; - if (ssl3_ParseEncryptedSessionTicket(ss, data, &enc_session_ticket) != - SECSuccess) { - return SECSuccess; /* Pretend it isn't there */ + /* If the decrypted ticket is empty, then report success, but leave the + * ticket marked as invalid. */ + if (decryptedTicket->len == 0) { + return SECSuccess; } - /* Get session ticket keys. */ - rv = ssl3_GetSessionTicketKeys(ss, &aes_key, &mac_key); + /* Read ticket version. */ + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &len); if (rv != SECSuccess) { - SSL_DBG(("%d: SSL[%d]: Unable to get/generate session ticket keys.", - SSL_GETPID(), ss->fd)); - goto loser; + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } - /* If the ticket sent by the client was generated under a key different - * from the one we have, bypass ticket processing. - */ - if (PORT_Memcmp(enc_session_ticket.key_name, key_name, - SESS_TICKET_KEY_NAME_LEN) != 0) { - SSL_DBG(("%d: SSL[%d]: Session ticket key_name sent mismatch.", - SSL_GETPID(), ss->fd)); - goto no_ticket; + /* Skip the ticket if the version is wrong. This won't result in a + * handshake failure, just a failure to resume. */ + if (temp != TLS_EX_SESS_TICKET_VERSION) { + return SECSuccess; } - /* Verify the MAC on the ticket. MAC verification may also - * fail if the MAC key has been recently refreshed. - */ - PORT_Assert(mac_key); - hmac_ctx = PK11_CreateContextBySymKey(macMech, CKA_SIGN, mac_key, &macParam); - if (!hmac_ctx) { - SSL_DBG(("%d: SSL[%d]: Unable to create HMAC context: %d.", - SSL_GETPID(), ss->fd, PORT_GetError())); - goto no_ticket; - } else { - SSL_DBG(("%d: SSL[%d]: Successfully created HMAC context.", - SSL_GETPID(), ss->fd)); - } - rv = PK11_DigestBegin(hmac_ctx); + /* Read SSLVersion. */ + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &len); if (rv != SECSuccess) { - PK11_DestroyContext(hmac_ctx, PR_TRUE); - goto no_ticket; + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } - rv = PK11_DigestOp(hmac_ctx, extension_data.data, - extension_data.len - - TLS_EX_SESS_TICKET_MAC_LENGTH); - if (rv != SECSuccess) { - PK11_DestroyContext(hmac_ctx, PR_TRUE); - goto no_ticket; + parsedTicket->ssl_version = (SSL3ProtocolVersion)temp; + if (!ssl3_VersionIsSupported(ss->protocolVariant, + parsedTicket->ssl_version)) { + /* This socket doesn't support the version from the ticket. */ + return SECSuccess; } - rv = PK11_DigestFinal(hmac_ctx, computed_mac, - &computed_mac_length, sizeof(computed_mac)); - PK11_DestroyContext(hmac_ctx, PR_TRUE); - if (rv != SECSuccess) - goto no_ticket; - if (NSS_SecureMemcmp(computed_mac, enc_session_ticket.mac, - computed_mac_length) != - 0) { - SSL_DBG(("%d: SSL[%d]: Session ticket MAC mismatch.", - SSL_GETPID(), ss->fd)); - goto no_ticket; + /* Read cipher_suite. */ + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } + parsedTicket->cipher_suite = (ssl3CipherSuite)temp; - /* We ignore key_name for now. - * This is ok as MAC verification succeeded. - */ - - /* Decrypt the ticket. */ - - /* Plaintext is shorter than the ciphertext due to padding. */ - decrypted_state = SECITEM_AllocItem(NULL, NULL, - enc_session_ticket.encrypted_state.len); - - PORT_Assert(aes_key); - ivItem.data = enc_session_ticket.iv; - ivItem.len = AES_BLOCK_SIZE; - aes_ctx = PK11_CreateContextBySymKey(cipherMech, CKA_DECRYPT, - aes_key, &ivItem); - if (!aes_ctx) { - SSL_DBG(("%d: SSL[%d]: Unable to create AES context.", - SSL_GETPID(), ss->fd)); - goto no_ticket; + /* Read compression_method. */ + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } + parsedTicket->compression_method = (SSLCompressionMethod)temp; - rv = PK11_CipherOp(aes_ctx, decrypted_state->data, - (int *)&decrypted_state->len, decrypted_state->len, - enc_session_ticket.encrypted_state.data, - enc_session_ticket.encrypted_state.len); - PK11_Finalize(aes_ctx); - PK11_DestroyContext(aes_ctx, PR_TRUE); - if (rv != SECSuccess) - goto no_ticket; - - /* Check padding. */ - padding_length = - (PRUint32)decrypted_state->data[decrypted_state->len - 1]; - if (padding_length == 0 || padding_length > AES_BLOCK_SIZE) - goto no_ticket; - - padding = &decrypted_state->data[decrypted_state->len - padding_length]; - for (i = 0; i < padding_length; i++, padding++) { - if (padding_length != (PRUint32)*padding) - goto no_ticket; + /* Read cipher spec parameters. */ + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } - - /* Deserialize session state. */ - buffer = decrypted_state->data; - buffer_len = decrypted_state->len; - - parsed_session_ticket = PORT_ZAlloc(sizeof(SessionTicket)); - if (parsed_session_ticket == NULL) { - rv = SECFailure; - goto loser; + parsedTicket->authType = (SSLAuthType)temp; + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } + parsedTicket->authKeyBits = temp; + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->keaType = (SSLKEAType)temp; + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->keaKeyBits = temp; - /* Read ticket_version and reject if the version is wrong */ - temp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); - if (temp != TLS_EX_SESS_TICKET_VERSION) - goto no_ticket; - - parsed_session_ticket->ticket_version = (SSL3ProtocolVersion)temp; - - /* Read SSLVersion. */ - temp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->ssl_version = (SSL3ProtocolVersion)temp; + /* Read the optional named curve. */ + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + if (parsedTicket->authType == ssl_auth_ecdsa || + parsedTicket->authType == ssl_auth_ecdh_rsa || + parsedTicket->authType == ssl_auth_ecdh_ecdsa) { + const sslNamedGroupDef *group = + ssl_LookupNamedGroup((SSLNamedGroup)temp); + if (!group || group->keaType != ssl_kea_ecdh) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->namedCurve = group; + } - /* Read cipher_suite. */ - temp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->cipher_suite = (ssl3CipherSuite)temp; + /* Read the master secret (and how it is wrapped). */ + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + PORT_Assert(temp == PR_TRUE || temp == PR_FALSE); + parsedTicket->ms_is_wrapped = (PRBool)temp; - /* Read compression_method. */ - temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->compression_method = (SSLCompressionMethod)temp; + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->msWrapMech = (CK_MECHANISM_TYPE)temp; - /* Read cipher spec parameters. */ - temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->authType = (SSLAuthType)temp; - temp = ssl3_ExtConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->authKeyBits = (PRUint32)temp; - temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->keaType = (SSLKEAType)temp; - temp = ssl3_ExtConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->keaKeyBits = (PRUint32)temp; - - /* Read certificate slot */ - parsed_session_ticket->certType.authType = parsed_session_ticket->authType; - temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - switch (parsed_session_ticket->authType) { - case ssl_auth_ecdsa: - case ssl_auth_ecdh_rsa: - case ssl_auth_ecdh_ecdsa: { - const sslNamedGroupDef *group = - ssl_LookupNamedGroup((SSLNamedGroup)temp); - if (!group || group->keaType != ssl_kea_ecdh) { - goto no_ticket; - } - parsed_session_ticket->certType.namedCurve = group; - } break; - default: - break; + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 2, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } + if (temp == 0 || temp > sizeof(parsedTicket->master_secret)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->ms_length = (PRUint16)temp; - /* Read wrapped master_secret. */ - temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->ms_is_wrapped = (PRBool)temp; - - temp = ssl3_ExtConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->msWrapMech = (CK_MECHANISM_TYPE)temp; - - temp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->ms_length = (PRUint16)temp; - if (parsed_session_ticket->ms_length == 0 || /* sanity check MS. */ - parsed_session_ticket->ms_length > - sizeof(parsed_session_ticket->master_secret)) - goto no_ticket; - - /* Allow for the wrapped master secret to be longer. */ - if (buffer_len < parsed_session_ticket->ms_length) - goto no_ticket; - PORT_Memcpy(parsed_session_ticket->master_secret, buffer, - parsed_session_ticket->ms_length); - buffer += parsed_session_ticket->ms_length; - buffer_len -= parsed_session_ticket->ms_length; - - /* Read client_identity */ - temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->client_identity.client_auth_type = - (ClientAuthenticationType)temp; - switch (parsed_session_ticket->client_identity.client_auth_type) { + /* Read the master secret. */ + rv = ssl3_ExtConsumeHandshake(ss, parsedTicket->master_secret, + parsedTicket->ms_length, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + /* Read client identity */ + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->client_auth_type = (ClientAuthenticationType)temp; + switch (parsedTicket->client_auth_type) { case CLIENT_AUTH_ANONYMOUS: break; case CLIENT_AUTH_CERTIFICATE: - rv = ssl3_ExtConsumeHandshakeVariable(ss, &cert_item, 3, - &buffer, &buffer_len); - if (rv != SECSuccess) - goto no_ticket; - rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->peer_cert, - &cert_item); - if (rv != SECSuccess) - goto no_ticket; + rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->peer_cert, 2, + &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } break; default: - goto no_ticket; + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } /* Read timestamp. */ - temp = ssl3_ExtConsumeHandshakeNumber(ss, 4, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; - parsed_session_ticket->timestamp = (PRUint32)temp; + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->timestamp = temp; /* Read server name */ - nameType = - ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (nameType != TLS_STE_NO_SERVER_NAME) { - SECItem name_item; - rv = ssl3_ExtConsumeHandshakeVariable(ss, &name_item, 2, &buffer, - &buffer_len); - if (rv != SECSuccess) - goto no_ticket; - rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->srvName, - &name_item); - if (rv != SECSuccess) - goto no_ticket; - parsed_session_ticket->srvName.type = nameType; + rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->srvName, 2, + &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } /* Read extendedMasterSecretUsed */ - temp = ssl3_ExtConsumeHandshakeNumber(ss, 1, &buffer, &buffer_len); - if (temp < 0) - goto no_ticket; + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 1, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } PORT_Assert(temp == PR_TRUE || temp == PR_FALSE); - parsed_session_ticket->extendedMasterSecretUsed = (PRBool)temp; + parsedTicket->extendedMasterSecretUsed = (PRBool)temp; - rv = ssl3_ExtConsumeHandshake(ss, &parsed_session_ticket->flags, 4, - &buffer, &buffer_len); - if (rv != SECSuccess) - goto no_ticket; - parsed_session_ticket->flags = PR_ntohl(parsed_session_ticket->flags); + rv = ssl3_ExtConsumeHandshake(ss, &temp, 4, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + parsedTicket->flags = PR_ntohl(temp); - rv = ssl3_ExtConsumeHandshakeVariable(ss, &alpn_item, 1, &buffer, &buffer_len); - if (rv != SECSuccess) - goto no_ticket; - if (alpn_item.len != 0) { - rv = SECITEM_CopyItem(NULL, &parsed_session_ticket->alpnSelection, - &alpn_item); - if (rv != SECSuccess) - goto no_ticket; - if (alpn_item.len >= 256) - goto no_ticket; + rv = ssl3_ExtConsumeHandshakeVariable(ss, &parsedTicket->alpnSelection, 1, + &buffer, &len); + PORT_Assert(parsedTicket->alpnSelection.len < 256); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + rv = ssl3_ExtConsumeHandshakeNumber(ss, &temp, 4, &buffer, &len); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; } + parsedTicket->maxEarlyData = temp; +#ifndef UNSAFE_FUZZER_MODE /* Done parsing. Check that all bytes have been consumed. */ - if (buffer_len != padding_length) - goto no_ticket; + if (len != 0) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } +#endif - /* Use the ticket if it has not expired, otherwise free the allocated - * memory since the ticket is of no use. - */ - if (parsed_session_ticket->timestamp != 0 && - parsed_session_ticket->timestamp + - TLS_EX_SESS_TICKET_LIFETIME_HINT > - ssl_Time()) { - - sid = ssl3_NewSessionID(ss, PR_TRUE); - if (sid == NULL) { - rv = SECFailure; + parsedTicket->valid = PR_TRUE; + return SECSuccess; +} + +static SECStatus +ssl_CreateSIDFromTicket(sslSocket *ss, const SECItem *rawTicket, + SessionTicket *parsedTicket, sslSessionID **out) +{ + sslSessionID *sid; + SECStatus rv; + + sid = ssl3_NewSessionID(ss, PR_TRUE); + if (sid == NULL) { + return SECFailure; + } + + /* Copy over parameters. */ + sid->version = parsedTicket->ssl_version; + sid->u.ssl3.cipherSuite = parsedTicket->cipher_suite; + sid->u.ssl3.compression = parsedTicket->compression_method; + sid->authType = parsedTicket->authType; + sid->authKeyBits = parsedTicket->authKeyBits; + sid->keaType = parsedTicket->keaType; + sid->keaKeyBits = parsedTicket->keaKeyBits; + sid->namedCurve = parsedTicket->namedCurve; + + rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.locked.sessionTicket.ticket, + rawTicket); + if (rv != SECSuccess) { + goto loser; + } + sid->u.ssl3.locked.sessionTicket.flags = parsedTicket->flags; + sid->u.ssl3.locked.sessionTicket.max_early_data_size = + parsedTicket->maxEarlyData; + + if (parsedTicket->ms_length > + sizeof(sid->u.ssl3.keys.wrapped_master_secret)) { + goto loser; + } + PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret, + parsedTicket->master_secret, parsedTicket->ms_length); + sid->u.ssl3.keys.wrapped_master_secret_len = parsedTicket->ms_length; + sid->u.ssl3.masterWrapMech = parsedTicket->msWrapMech; + sid->u.ssl3.keys.msIsWrapped = parsedTicket->ms_is_wrapped; + sid->u.ssl3.masterValid = PR_TRUE; + sid->u.ssl3.keys.resumable = PR_TRUE; + sid->u.ssl3.keys.extendedMasterSecretUsed = parsedTicket->extendedMasterSecretUsed; + + /* Copy over client cert from session ticket if there is one. */ + if (parsedTicket->peer_cert.data != NULL) { + PORT_Assert(!sid->peerCert); + sid->peerCert = CERT_NewTempCertificate(ss->dbHandle, + &parsedTicket->peer_cert, + NULL, PR_FALSE, PR_TRUE); + if (!sid->peerCert) { goto loser; } + } - /* Copy over parameters. */ - sid->version = parsed_session_ticket->ssl_version; - sid->u.ssl3.cipherSuite = parsed_session_ticket->cipher_suite; - sid->u.ssl3.compression = parsed_session_ticket->compression_method; - sid->authType = parsed_session_ticket->authType; - sid->authKeyBits = parsed_session_ticket->authKeyBits; - sid->keaType = parsed_session_ticket->keaType; - sid->keaKeyBits = parsed_session_ticket->keaKeyBits; - memcpy(&sid->certType, &parsed_session_ticket->certType, - sizeof(sslServerCertType)); - - if (SECITEM_CopyItem(NULL, &sid->u.ssl3.locked.sessionTicket.ticket, - &extension_data) != SECSuccess) - goto no_ticket; - sid->u.ssl3.locked.sessionTicket.flags = parsed_session_ticket->flags; - - if (parsed_session_ticket->ms_length > - sizeof(sid->u.ssl3.keys.wrapped_master_secret)) - goto no_ticket; - PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret, - parsed_session_ticket->master_secret, - parsed_session_ticket->ms_length); - sid->u.ssl3.keys.wrapped_master_secret_len = - parsed_session_ticket->ms_length; - sid->u.ssl3.masterWrapMech = parsed_session_ticket->msWrapMech; - sid->u.ssl3.keys.msIsWrapped = - parsed_session_ticket->ms_is_wrapped; - sid->u.ssl3.masterValid = PR_TRUE; - sid->u.ssl3.keys.resumable = PR_TRUE; - sid->u.ssl3.keys.extendedMasterSecretUsed = parsed_session_ticket->extendedMasterSecretUsed; - - /* Copy over client cert from session ticket if there is one. */ - if (parsed_session_ticket->peer_cert.data != NULL) { - if (sid->peerCert != NULL) - CERT_DestroyCertificate(sid->peerCert); - sid->peerCert = CERT_NewTempCertificate(ss->dbHandle, - &parsed_session_ticket->peer_cert, NULL, PR_FALSE, PR_TRUE); - if (sid->peerCert == NULL) { - rv = SECFailure; - goto loser; - } + /* Transfer ownership of the remaining items. */ + if (parsedTicket->srvName.data != NULL) { + SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE); + rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.srvName, + &parsedTicket->srvName); + if (rv != SECSuccess) { + goto loser; } - if (parsed_session_ticket->srvName.data != NULL) { - if (sid->u.ssl3.srvName.data) { - SECITEM_FreeItem(&sid->u.ssl3.srvName, PR_FALSE); - } - sid->u.ssl3.srvName = parsed_session_ticket->srvName; + } + if (parsedTicket->alpnSelection.data != NULL) { + rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.alpnSelection, + &parsedTicket->alpnSelection); + if (rv != SECSuccess) { + goto loser; } - if (parsed_session_ticket->alpnSelection.data != NULL) { - sid->u.ssl3.alpnSelection = parsed_session_ticket->alpnSelection; - /* So we don't free below. */ - parsed_session_ticket->alpnSelection.data = NULL; + } + + *out = sid; + return SECSuccess; + +loser: + ssl_FreeSID(sid); + return SECFailure; +} + +/* Generic ticket processing code, common to all TLS versions. */ +SECStatus +ssl3_ProcessSessionTicketCommon(sslSocket *ss, SECItem *data) +{ + SECItem decryptedTicket = { siBuffer, NULL, 0 }; + SessionTicket parsedTicket; + SECStatus rv; + + if (ss->sec.ci.sid != NULL) { + ss->sec.uncache(ss->sec.ci.sid); + ssl_FreeSID(ss->sec.ci.sid); + ss->sec.ci.sid = NULL; + } + + if (!SECITEM_AllocItem(NULL, &decryptedTicket, data->len)) { + return SECFailure; + } + + /* Decrypt the ticket. */ + rv = ssl_SelfEncryptUnprotect(ss, data->data, data->len, + decryptedTicket.data, + &decryptedTicket.len, + decryptedTicket.len); + if (rv != SECSuccess) { + SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE); + + /* Fail with no ticket if we're not a recipient. Otherwise + * it's a hard failure. */ + if (PORT_GetError() != SEC_ERROR_NOT_A_RECIPIENT) { + SSL3_SendAlert(ss, alert_fatal, illegal_parameter); + return SECFailure; } - ss->statelessResume = PR_TRUE; - ss->sec.ci.sid = sid; + + /* We didn't have the right key, so pretend we don't have a + * ticket. */ } - if (0) { - no_ticket: + rv = ssl_ParseSessionTicket(ss, &decryptedTicket, &parsedTicket); + if (rv != SECSuccess) { + SSL3Statistics *ssl3stats; + SSL_DBG(("%d: SSL[%d]: Session ticket parsing failed.", SSL_GETPID(), ss->fd)); ssl3stats = SSL_GetStatistics(); SSL_AtomicIncrementLong(&ssl3stats->hch_sid_ticket_parse_failures); + goto loser; /* code already set */ } - rv = SECSuccess; -loser: - /* ss->sec.ci.sid == sid if it did NOT come here via goto statement - * in that case do not free sid - */ - if (sid && (ss->sec.ci.sid != sid)) { - ssl_FreeSID(sid); - sid = NULL; - } - if (decrypted_state != NULL) { - SECITEM_FreeItem(decrypted_state, PR_TRUE); - decrypted_state = NULL; - } + /* Use the ticket if it is valid and unexpired. */ + if (parsedTicket.valid && + parsedTicket.timestamp + ssl_ticket_lifetime > ssl_Time()) { + sslSessionID *sid; - if (parsed_session_ticket != NULL) { - if (parsed_session_ticket->peer_cert.data) { - SECITEM_FreeItem(&parsed_session_ticket->peer_cert, PR_FALSE); - } - if (parsed_session_ticket->alpnSelection.data) { - SECITEM_FreeItem(&parsed_session_ticket->alpnSelection, PR_FALSE); + rv = ssl_CreateSIDFromTicket(ss, data, &parsedTicket, &sid); + if (rv != SECSuccess) { + goto loser; /* code already set */ } - PORT_ZFree(parsed_session_ticket, sizeof(SessionTicket)); + ss->statelessResume = PR_TRUE; + ss->sec.ci.sid = sid; } - return rv; + SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE); + PORT_Memset(&parsedTicket, 0, sizeof(parsedTicket)); + return SECSuccess; + +loser: + SECITEM_ZfreeItem(&decryptedTicket, PR_FALSE); + PORT_Memset(&parsedTicket, 0, sizeof(parsedTicket)); + return SECFailure; } SECStatus @@ -1798,23 +1480,6 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData return ssl3_ProcessSessionTicketCommon(CONST_CAST(sslSocket, ss), data); } -/* - * Read bytes. Using this function means the SECItem structure - * cannot be freed. The caller is expected to call this function - * on a shallow copy of the structure. - */ -static SECStatus -ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, PRUint32 bytes) -{ - if (bytes > item->len) - return SECFailure; - - *buf = item->data; - item->data += bytes; - item->len -= bytes; - return SECSuccess; -} - /* Extension format: * Extension number: 2 bytes * Extension length: 2 bytes @@ -2145,7 +1810,8 @@ ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUi &xtnData->clientSigSchemes, &xtnData->numClientSigScheme, &data->data, &data->len); - if (rv != SECSuccess) { + if (rv != SECSuccess || xtnData->numClientSigScheme == 0) { + ssl3_ExtSendAlert(ss, alert_fatal, decode_error); PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); return SECFailure; } @@ -2216,55 +1882,73 @@ ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool /* Takes the size of the ClientHello, less the record header, and determines how * much padding is required. */ -unsigned int -ssl3_CalculatePaddingExtensionLength(unsigned int clientHelloLength) +void +ssl3_CalculatePaddingExtLen(sslSocket *ss, + unsigned int clientHelloLength) { unsigned int recordLength = 1 /* handshake message type */ + 3 /* handshake message length */ + clientHelloLength; - unsigned int extensionLength; + unsigned int extensionLen; + + /* Don't pad for DTLS, for SSLv3, or for renegotiation. */ + if (IS_DTLS(ss) || + ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_0 || + ss->firstHsDone) { + return; + } + /* A padding extension may be included to ensure that the record containing + * the ClientHello doesn't have a length between 256 and 511 bytes + * (inclusive). Initial ClientHello records with such lengths trigger bugs + * in F5 devices. */ if (recordLength < 256 || recordLength >= 512) { - return 0; + return; } - extensionLength = 512 - recordLength; + extensionLen = 512 - recordLength; /* Extensions take at least four bytes to encode. Always include at least - * one byte of data if including the extension. Some servers (e.g. - * WebSphere Application Server 7.0 and Tomcat) will time out or terminate - * the connection if the last extension in the client hello is empty. */ - if (extensionLength < 4 + 1) { - extensionLength = 4 + 1; + * one byte of data if we are padding. Some servers will time out or + * terminate the connection if the last ClientHello extension is empty. */ + if (extensionLen < 4 + 1) { + extensionLen = 4 + 1; } - return extensionLength; + ss->xtnData.paddingLen = extensionLen - 4; } -/* ssl3_AppendPaddingExtension possibly adds an extension which ensures that a +/* ssl3_SendPaddingExtension possibly adds an extension which ensures that a * ClientHello record is either < 256 bytes or is >= 512 bytes. This ensures * that we don't trigger bugs in F5 products. */ PRInt32 -ssl3_AppendPaddingExtension(sslSocket *ss, unsigned int extensionLen, - PRUint32 maxBytes) +ssl3_ClientSendPaddingExtension(const sslSocket *ss, TLSExtensionData *xtnData, + PRBool append, PRUint32 maxBytes) { - unsigned int paddingLen = extensionLen - 4; - static unsigned char padding[252]; + static unsigned char padding[252] = { 0 }; + unsigned int extensionLen; + SECStatus rv; - if (extensionLen == 0) { + /* On the length-calculation pass, report zero total length. The record + * will be larger on the second pass if needed. */ + if (!append || !xtnData->paddingLen) { return 0; } + extensionLen = xtnData->paddingLen + 4; if (extensionLen > maxBytes || - !paddingLen || - paddingLen > sizeof(padding)) { + xtnData->paddingLen > sizeof(padding)) { PORT_Assert(0); return -1; } - if (SECSuccess != ssl3_ExtAppendHandshakeNumber(ss, ssl_padding_xtn, 2)) + rv = ssl3_ExtAppendHandshakeNumber(ss, ssl_padding_xtn, 2); + if (rv != SECSuccess) { return -1; - if (SECSuccess != ssl3_ExtAppendHandshakeVariable(ss, padding, paddingLen, 2)) + } + rv = ssl3_ExtAppendHandshakeVariable(ss, padding, xtnData->paddingLen, 2); + if (rv != SECSuccess) { return -1; + } return extensionLen; } @@ -2321,6 +2005,7 @@ ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnDat if (data->len != 0) { SSL_TRC(30, ("%d: SSL3[%d]: Bogus extended master secret extension", SSL_GETPID(), ss->fd)); + ssl3_ExtSendAlert(ss, alert_fatal, decode_error); return SECFailure; } @@ -2445,6 +2130,12 @@ ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss, PRUint16 ex_type, SECItem *data) { + if (data->len != 0) { + ssl3_ExtSendAlert(ss, alert_fatal, decode_error); + PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); + return SECFailure; + } + xtnData->negotiated[xtnData->numNegotiated++] = ex_type; PORT_Assert(ss->sec.isServer); return ssl3_RegisterExtensionSender( @@ -2484,7 +2175,8 @@ ssl3_HandleSupportedPointFormatsXtn(const sslSocket *ss, TLSExtensionData *xtnDa static SECStatus ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data) { - PRInt32 list_len; + SECStatus rv; + PRUint32 list_len; unsigned int i; const sslNamedGroupDef *enabled[SSL_NAMED_GROUP_COUNT] = { 0 }; PORT_Assert(SSL_NAMED_GROUP_COUNT == PR_ARRAY_SIZE(enabled)); @@ -2495,8 +2187,8 @@ ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data) } /* get the length of elliptic_curve_list */ - list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) { + rv = ssl3_ConsumeHandshakeNumber(ss, &list_len, 2, &data->data, &data->len); + if (rv != SECSuccess || data->len != list_len || (data->len % 2) != 0) { (void)ssl3_DecodeError(ss); return SECFailure; } @@ -2510,9 +2202,10 @@ ssl_UpdateSupportedGroups(sslSocket *ss, SECItem *data) /* Read groups from data and enable if in |enabled| */ while (data->len) { const sslNamedGroupDef *group; - PRInt32 curve_name = - ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - if (curve_name < 0) { + PRUint32 curve_name; + rv = ssl3_ConsumeHandshakeNumber(ss, &curve_name, 2, &data->data, + &data->len); + if (rv != SECSuccess) { return SECFailure; /* fatal alert already sent */ } group = ssl_LookupNamedGroup(curve_name); diff --git a/security/nss/lib/ssl/ssl3exthandle.h b/security/nss/lib/ssl/ssl3exthandle.h index 65223d6fd..5fdbe9053 100644 --- a/security/nss/lib/ssl/ssl3exthandle.h +++ b/security/nss/lib/ssl/ssl3exthandle.h @@ -49,6 +49,9 @@ PRInt32 ssl3_ClientSendSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData SECStatus ssl3_ServerHandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data); +PRInt32 ssl3_ClientSendPaddingExtension(const sslSocket *ss, TLSExtensionData *xtnData, + PRBool append, PRUint32 maxBytes); + PRInt32 ssl3_ClientSendSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRBool append, PRUint32 maxBytes); diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c index 2bcc1d0aa..cf6f4cb33 100644 --- a/security/nss/lib/ssl/ssl3gthr.c +++ b/security/nss/lib/ssl/ssl3gthr.c @@ -32,6 +32,7 @@ ssl3_InitGather(sslGather *gs) gs->readOffset = 0; gs->dtlsPacketOffset = 0; gs->dtlsPacket.len = 0; + gs->rejectV2Records = PR_FALSE; status = sslBuffer_Grow(&gs->buf, 4096); return status; } @@ -147,8 +148,11 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs) switch (gs->state) { case GS_HEADER: /* Check for SSLv2 handshakes. Always assume SSLv3 on clients, - * support SSLv2 handshakes only when ssl2gs != NULL. */ - if (!ssl2gs || ssl3_isLikelyV3Hello(gs->hdr)) { + * support SSLv2 handshakes only when ssl2gs != NULL. + * Always assume v3 after we received the first record. */ + if (!ssl2gs || + ss->gs.rejectV2Records || + ssl3_isLikelyV3Hello(gs->hdr)) { /* Should have a non-SSLv2 record header in gs->hdr. Extract * the length of the following encrypted data, and then * read in the rest of the record into gs->inbuf. */ @@ -183,7 +187,7 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs) /* This is the max length for an encrypted SSLv3+ fragment. */ if (!v2HdrLength && gs->remainder > (MAX_FRAGMENT_LENGTH + 2048)) { - SSL3_SendAlert(ss, alert_fatal, unexpected_message); + SSL3_SendAlert(ss, alert_fatal, record_overflow); gs->state = GS_INIT; PORT_SetError(SSL_ERROR_RX_RECORD_TOO_LONG); return SECFailure; @@ -205,13 +209,28 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs) * many into the gs->hdr[] buffer. Copy them over into inbuf so * that we can properly process the hello record later. */ if (v2HdrLength) { + /* Reject v2 records that don't even carry enough data to + * resemble a valid ClientHello header. */ + if (gs->remainder < SSL_HL_CLIENT_HELLO_HBYTES) { + SSL3_SendAlert(ss, alert_fatal, illegal_parameter); + PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO); + return SECFailure; + } + + PORT_Assert(lbp); gs->inbuf.len = 5 - v2HdrLength; PORT_Memcpy(lbp, gs->hdr + v2HdrLength, gs->inbuf.len); gs->remainder -= gs->inbuf.len; lbp += gs->inbuf.len; } - break; /* End this case. Continue around the loop. */ + if (gs->remainder > 0) { + break; /* End this case. Continue around the loop. */ + } + + /* FALL THROUGH if (gs->remainder == 0) as we just received + * an empty record and there's really no point in calling + * ssl_DefRecv() with buf=NULL and len=0. */ case GS_DATA: /* @@ -219,6 +238,10 @@ ssl3_GatherData(sslSocket *ss, sslGather *gs, int flags, ssl2Gather *ssl2gs) */ SSL_TRC(10, ("%d: SSL[%d]: got record of %d bytes", SSL_GETPID(), ss->fd, gs->inbuf.len)); + + /* reject any v2 records from now on */ + ss->gs.rejectV2Records = PR_TRUE; + gs->state = GS_INIT; return 1; } diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h index 35c7e547d..ac31cf263 100644 --- a/security/nss/lib/ssl/ssl3prot.h +++ b/security/nss/lib/ssl/ssl3prot.h @@ -10,8 +10,6 @@ #ifndef __ssl3proto_h_ #define __ssl3proto_h_ -typedef PRUint8 SSL3Opaque; - typedef PRUint16 SSL3ProtocolVersion; /* version numbers are defined in sslproto.h */ @@ -62,12 +60,12 @@ typedef struct { typedef struct { SECItem content; - SSL3Opaque MAC[MAX_MAC_LENGTH]; + PRUint8 MAC[MAX_MAC_LENGTH]; } SSL3GenericStreamCipher; typedef struct { SECItem content; - SSL3Opaque MAC[MAX_MAC_LENGTH]; + PRUint8 MAC[MAX_MAC_LENGTH]; PRUint8 padding[MAX_PADDING_LENGTH]; PRUint8 padding_length; } SSL3GenericBlockCipher; @@ -153,11 +151,11 @@ typedef struct { } SSL3HelloRequest; typedef struct { - SSL3Opaque rand[SSL3_RANDOM_LENGTH]; + PRUint8 rand[SSL3_RANDOM_LENGTH]; } SSL3Random; typedef struct { - SSL3Opaque id[32]; + PRUint8 id[32]; PRUint8 length; } SSL3SessionID; @@ -243,7 +241,7 @@ typedef struct { typedef struct { union { - SSL3Opaque anonymous; + PRUint8 anonymous; SSL3Hashes certified; } u; } SSL3ServerKeyExchange; @@ -262,11 +260,11 @@ typedef enum { } SSL3ClientCertificateType; typedef struct { - SSL3Opaque client_version[2]; - SSL3Opaque random[46]; + PRUint8 client_version[2]; + PRUint8 random[46]; } SSL3RSAPreMasterSecret; -typedef SSL3Opaque SSL3MasterSecret[48]; +typedef PRUint8 SSL3MasterSecret[48]; typedef enum { sender_client = 0x434c4e54, @@ -276,7 +274,7 @@ typedef enum { typedef SSL3HashesIndividually SSL3Finished; typedef struct { - SSL3Opaque verify_data[12]; + PRUint8 verify_data[12]; } TLSFinished; /* @@ -287,7 +285,7 @@ typedef struct { /* NewSessionTicket handshake message. */ typedef struct { - PRUint32 received_timestamp; + PRTime received_timestamp; PRUint32 ticket_lifetime_hint; PRUint32 flags; PRUint32 ticket_age_add; @@ -305,27 +303,9 @@ typedef enum { CLIENT_AUTH_CERTIFICATE = 1 } ClientAuthenticationType; -typedef struct { - ClientAuthenticationType client_auth_type; - union { - SSL3Opaque *certificate_list; - } identity; -} ClientIdentity; - -#define SESS_TICKET_KEY_NAME_LEN 16 -#define SESS_TICKET_KEY_NAME_PREFIX "NSS!" -#define SESS_TICKET_KEY_NAME_PREFIX_LEN 4 -#define SESS_TICKET_KEY_VAR_NAME_LEN 12 - -typedef struct { - unsigned char *key_name; - unsigned char *iv; - SECItem encrypted_state; - unsigned char *mac; -} EncryptedSessionTicket; - -#define TLS_EX_SESS_TICKET_MAC_LENGTH 32 - -#define TLS_STE_NO_SERVER_NAME -1 +#define SELF_ENCRYPT_KEY_NAME_LEN 16 +#define SELF_ENCRYPT_KEY_NAME_PREFIX "NSS!" +#define SELF_ENCRYPT_KEY_NAME_PREFIX_LEN 4 +#define SELF_ENCRYPT_KEY_VAR_NAME_LEN 12 #endif /* __ssl3proto_h_ */ diff --git a/security/nss/lib/ssl/sslcert.c b/security/nss/lib/ssl/sslcert.c index ea524552d..cc1d3c683 100644 --- a/security/nss/lib/ssl/sslcert.c +++ b/security/nss/lib/ssl/sslcert.c @@ -13,42 +13,91 @@ #include "nss.h" /* for NSS_RegisterShutdown */ #include "prinit.h" /* for PR_CallOnceWithArg */ -static const PRCallOnceType pristineCallOnce; -static PRCallOnceType setupServerCAListOnce; +/* This global item is used only in servers. It is is initialized by + * SSL_ConfigSecureServer(), and is used in ssl3_SendCertificateRequest(). + */ +static struct { + PRCallOnceType setup; + CERTDistNames *names; +} ssl_server_ca_list; static SECStatus -serverCAListShutdown(void *appData, void *nssData) +ssl_ServerCAListShutdown(void *appData, void *nssData) { - PORT_Assert(ssl3_server_ca_list); - if (ssl3_server_ca_list) { - CERT_FreeDistNames(ssl3_server_ca_list); - ssl3_server_ca_list = NULL; + PORT_Assert(ssl_server_ca_list.names); + if (ssl_server_ca_list.names) { + CERT_FreeDistNames(ssl_server_ca_list.names); } - setupServerCAListOnce = pristineCallOnce; + PORT_Memset(&ssl_server_ca_list, 0, sizeof(ssl_server_ca_list)); return SECSuccess; } static PRStatus -serverCAListSetup(void *arg) +ssl_SetupCAListOnce(void *arg) { CERTCertDBHandle *dbHandle = (CERTCertDBHandle *)arg; - SECStatus rv = NSS_RegisterShutdown(serverCAListShutdown, NULL); + SECStatus rv = NSS_RegisterShutdown(ssl_ServerCAListShutdown, NULL); PORT_Assert(SECSuccess == rv); if (SECSuccess == rv) { - ssl3_server_ca_list = CERT_GetSSLCACerts(dbHandle); + ssl_server_ca_list.names = CERT_GetSSLCACerts(dbHandle); return PR_SUCCESS; } return PR_FAILURE; } +SECStatus +ssl_SetupCAList(sslSocket *ss) +{ + if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_server_ca_list.setup, + &ssl_SetupCAListOnce, + (void *)(ss->dbHandle))) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return SECSuccess; +} + +SECStatus +ssl_GetCertificateRequestCAs(sslSocket *ss, unsigned int *calen, + SECItem **names, unsigned int *nnames) +{ + SECItem *name; + CERTDistNames *ca_list; + unsigned int i; + + *calen = 0; + *names = NULL; + *nnames = 0; + + /* ssl3.ca_list is initialized to NULL, and never changed. */ + ca_list = ss->ssl3.ca_list; + if (!ca_list) { + if (ssl_SetupCAList(ss) != SECSuccess) { + return SECFailure; + } + ca_list = ssl_server_ca_list.names; + } + + if (ca_list != NULL) { + *names = ca_list->names; + *nnames = ca_list->nnames; + } + + for (i = 0, name = *names; i < *nnames; i++, name++) { + *calen += 2 + name->len; + } + return SECSuccess; +} + sslServerCert * -ssl_NewServerCert(const sslServerCertType *certType) +ssl_NewServerCert() { sslServerCert *sc = PORT_ZNew(sslServerCert); if (!sc) { return NULL; } - memcpy(&sc->certType, certType, sizeof(sc->certType)); + sc->authTypes = 0; + sc->namedCurve = NULL; sc->serverCert = NULL; sc->serverCertChain = NULL; sc->certStatusArray = NULL; @@ -61,11 +110,14 @@ ssl_CopyServerCert(const sslServerCert *oc) { sslServerCert *sc; - sc = ssl_NewServerCert(&oc->certType); + sc = ssl_NewServerCert(); if (!sc) { return NULL; } + sc->authTypes = oc->authTypes; + sc->namedCurve = oc->namedCurve; + if (oc->serverCert && oc->serverCertChain) { sc->serverCert = CERT_DupCertificate(oc->serverCert); if (!sc->serverCert) @@ -129,9 +181,9 @@ ssl_FreeServerCert(sslServerCert *sc) PORT_ZFree(sc, sizeof(*sc)); } -sslServerCert * -ssl_FindServerCert(const sslSocket *ss, - const sslServerCertType *certType) +const sslServerCert * +ssl_FindServerCert(const sslSocket *ss, SSLAuthType authType, + const sslNamedGroupDef *namedCurve) { PRCList *cursor; @@ -139,68 +191,21 @@ ssl_FindServerCert(const sslSocket *ss, cursor != &ss->serverCerts; cursor = PR_NEXT_LINK(cursor)) { sslServerCert *cert = (sslServerCert *)cursor; - if (cert->certType.authType != certType->authType) { + if (!SSL_CERT_IS(cert, authType)) { continue; } - switch (cert->certType.authType) { - case ssl_auth_ecdsa: - case ssl_auth_ecdh_rsa: - case ssl_auth_ecdh_ecdsa: - /* Note: For deprecated APIs, we need to be able to find and - match a slot with any named curve. */ - if (certType->namedCurve && - cert->certType.namedCurve != certType->namedCurve) { - continue; - } - break; - default: - break; + if (SSL_CERT_IS_EC(cert)) { + /* Note: For deprecated APIs, we need to be able to find and + match a slot with any named curve. */ + if (namedCurve && cert->namedCurve != namedCurve) { + continue; + } } return cert; } return NULL; } -sslServerCert * -ssl_FindServerCertByAuthType(const sslSocket *ss, SSLAuthType authType) -{ - sslServerCertType certType; - certType.authType = authType; - /* Setting the named curve to NULL ensures that all EC certificates - * are matched when searching for this slot. */ - certType.namedCurve = NULL; - return ssl_FindServerCert(ss, &certType); -} - -SECStatus -ssl_OneTimeCertSetup(sslSocket *ss, const sslServerCert *sc) -{ - if (PR_SUCCESS != PR_CallOnceWithArg(&setupServerCAListOnce, - &serverCAListSetup, - (void *)(ss->dbHandle))) { - return SECFailure; - } - return SECSuccess; -} - -/* Determine which slot a certificate fits into. SSLAuthType is known, but - * extra information needs to be worked out from the cert and key. */ -static void -ssl_PopulateCertType(sslServerCertType *certType, SSLAuthType authType, - CERTCertificate *cert, sslKeyPair *keyPair) -{ - certType->authType = authType; - switch (authType) { - case ssl_auth_ecdsa: - case ssl_auth_ecdh_rsa: - case ssl_auth_ecdh_ecdsa: - certType->namedCurve = ssl_ECPubKey2NamedGroup(keyPair->pubKey); - break; - default: - break; - } -} - static SECStatus ssl_PopulateServerCert(sslServerCert *sc, CERTCertificate *cert, const CERTCertificateList *certChain) @@ -232,21 +237,43 @@ ssl_PopulateServerCert(sslServerCert *sc, CERTCertificate *cert, static SECStatus ssl_PopulateKeyPair(sslServerCert *sc, sslKeyPair *keyPair) { - /* Copy over the key pair. */ if (sc->serverKeyPair) { ssl_FreeKeyPair(sc->serverKeyPair); + sc->serverKeyPair = NULL; } if (keyPair) { + KeyType keyType = SECKEY_GetPublicKeyType(keyPair->pubKey); + PORT_Assert(keyType == SECKEY_GetPrivateKeyType(keyPair->privKey)); + + if (keyType == ecKey) { + sc->namedCurve = ssl_ECPubKey2NamedGroup(keyPair->pubKey); + if (!sc->namedCurve) { + /* Unsupported curve. */ + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + } + /* Get the size of the cert's public key, and remember it. */ sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(keyPair->pubKey); if (sc->serverKeyBits == 0) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } SECKEY_CacheStaticFlags(keyPair->privKey); sc->serverKeyPair = ssl_GetKeyPairRef(keyPair); + + if (SSL_CERT_IS(sc, ssl_auth_rsa_decrypt)) { + /* This will update the global session ticket key pair with this + * key, if a value hasn't been set already. */ + if (ssl_MaybeSetSelfEncryptKeyPair(keyPair) != SECSuccess) { + return SECFailure; + } + } } else { sc->serverKeyPair = NULL; + sc->namedCurve = NULL; } return SECSuccess; } @@ -281,12 +308,39 @@ ssl_PopulateSignedCertTimestamps(sslServerCert *sc, return SECSuccess; } +/* Find any existing certificates that overlap with the new certificate and + * either remove any supported authentication types that overlap with the new + * certificate or - if they have no types left - remove them entirely. */ +static void +ssl_ClearMatchingCerts(sslSocket *ss, sslAuthTypeMask authTypes, + const sslNamedGroupDef *namedCurve) +{ + PRCList *cursor = PR_NEXT_LINK(&ss->serverCerts); + + while (cursor != &ss->serverCerts) { + sslServerCert *sc = (sslServerCert *)cursor; + cursor = PR_NEXT_LINK(cursor); + if ((sc->authTypes & authTypes) == 0) { + continue; + } + /* namedCurve will be NULL only for legacy functions. */ + if (namedCurve != NULL && sc->namedCurve != namedCurve) { + continue; + } + + sc->authTypes &= ~authTypes; + if (sc->authTypes == 0) { + PR_REMOVE_LINK(&sc->link); + ssl_FreeServerCert(sc); + } + } +} + static SECStatus -ssl_ConfigCert(sslSocket *ss, CERTCertificate *cert, - sslKeyPair *keyPair, const SSLExtraServerCertData *data) +ssl_ConfigCert(sslSocket *ss, sslAuthTypeMask authTypes, + CERTCertificate *cert, sslKeyPair *keyPair, + const SSLExtraServerCertData *data) { - sslServerCert *oldsc; - sslServerCertType certType; SECStatus rv; sslServerCert *sc = NULL; int error_code = SEC_ERROR_NO_MEMORY; @@ -294,34 +348,26 @@ ssl_ConfigCert(sslSocket *ss, CERTCertificate *cert, PORT_Assert(cert); PORT_Assert(keyPair); PORT_Assert(data); - PORT_Assert(data->authType != ssl_auth_null); + PORT_Assert(authTypes); - if (!cert || !keyPair || !data || data->authType == ssl_auth_null) { + if (!cert || !keyPair || !data || !authTypes) { error_code = SEC_ERROR_INVALID_ARGS; goto loser; } - ssl_PopulateCertType(&certType, data->authType, cert, keyPair); - - /* Delete any existing certificate that matches this one, since we can only - * use one certificate of a given type. */ - oldsc = ssl_FindServerCert(ss, &certType); - if (oldsc) { - PR_REMOVE_LINK(&oldsc->link); - ssl_FreeServerCert(oldsc); - } - sc = ssl_NewServerCert(&certType); + sc = ssl_NewServerCert(); if (!sc) { goto loser; } + sc->authTypes = authTypes; rv = ssl_PopulateServerCert(sc, cert, data->certChain); if (rv != SECSuccess) { goto loser; } rv = ssl_PopulateKeyPair(sc, keyPair); if (rv != SECSuccess) { - error_code = SEC_ERROR_INVALID_ARGS; + error_code = PORT_GetError(); goto loser; } rv = ssl_PopulateOCSPResponses(sc, data->stapledOCSPResponses); @@ -332,23 +378,12 @@ ssl_ConfigCert(sslSocket *ss, CERTCertificate *cert, if (rv != SECSuccess) { goto loser; } + ssl_ClearMatchingCerts(ss, sc->authTypes, sc->namedCurve); PR_APPEND_LINK(&sc->link, &ss->serverCerts); - - /* This one-time setup depends on having the certificate in place. */ - rv = ssl_OneTimeCertSetup(ss, sc); - if (rv != SECSuccess) { - PR_REMOVE_LINK(&sc->link); - error_code = PORT_GetError(); - goto loser; - } return SECSuccess; loser: - if (sc) { - ssl_FreeServerCert(sc); - } - /* This is the only way any of the calls above can fail, except the one time - * setup, which doesn't land here. */ + ssl_FreeServerCert(sc); PORT_SetError(error_code); return SECFailure; } @@ -382,114 +417,55 @@ ssl_GetEcdhAuthType(CERTCertificate *cert) } } -/* This function examines the key usages of the given RSA-PKCS1 certificate - * and configures one or multiple server certificates based on that data. - * - * If the data argument contains an authType value other than ssl_auth_null, - * then only that slot will be used. If that choice is invalid, - * then this will fail. */ -static SECStatus -ssl_ConfigRsaPkcs1CertByUsage(sslSocket *ss, CERTCertificate *cert, - sslKeyPair *keyPair, - SSLExtraServerCertData *data) -{ - SECStatus rv = SECFailure; - - PRBool ku_sig = (PRBool)(cert->keyUsage & KU_DIGITAL_SIGNATURE); - PRBool ku_enc = (PRBool)(cert->keyUsage & KU_KEY_ENCIPHERMENT); - - if ((data->authType == ssl_auth_rsa_sign && ku_sig) || - (data->authType == ssl_auth_rsa_pss && ku_sig) || - (data->authType == ssl_auth_rsa_decrypt && ku_enc)) { - return ssl_ConfigCert(ss, cert, keyPair, data); - } - - if (data->authType != ssl_auth_null || !(ku_sig || ku_enc)) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - if (ku_sig) { - data->authType = ssl_auth_rsa_sign; - rv = ssl_ConfigCert(ss, cert, keyPair, data); - if (rv != SECSuccess) { - return rv; - } - - /* This certificate is RSA, assume that it's also PSS. */ - data->authType = ssl_auth_rsa_pss; - rv = ssl_ConfigCert(ss, cert, keyPair, data); - if (rv != SECSuccess) { - return rv; - } - } - - if (ku_enc) { - /* If ku_sig=true we configure signature and encryption slots with the - * same cert. This is bad form, but there are enough dual-usage RSA - * certs that we can't really break by limiting this to one type. */ - data->authType = ssl_auth_rsa_decrypt; - rv = ssl_ConfigCert(ss, cert, keyPair, data); - if (rv != SECSuccess) { - return rv; - } - } - - return rv; -} - /* This function examines the type of certificate and its key usage and - * configures a certificate based on that information. For some certificates - * this can mean that multiple server certificates are configured. + * chooses which authTypes apply. For some certificates + * this can mean that multiple authTypes. * - * If the data argument contains an authType value other than ssl_auth_null, - * then only that slot will be used. If that choice is invalid, - * then this will fail. */ -static SECStatus -ssl_ConfigCertByUsage(sslSocket *ss, CERTCertificate *cert, - sslKeyPair *keyPair, const SSLExtraServerCertData *data) + * If the targetAuthType is not ssl_auth_null, then only that type will be used. + * If that choice is invalid, then this function will fail. */ +static sslAuthTypeMask +ssl_GetCertificateAuthTypes(CERTCertificate *cert, SSLAuthType targetAuthType) { - SECStatus rv = SECFailure; - SSLExtraServerCertData arg; + sslAuthTypeMask authTypes = 0; SECOidTag tag; - PORT_Assert(data); - /* Take a (shallow) copy so that we can play with it */ - memcpy(&arg, data, sizeof(arg)); - tag = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm); switch (tag) { case SEC_OID_X500_RSA_ENCRYPTION: case SEC_OID_PKCS1_RSA_ENCRYPTION: - return ssl_ConfigRsaPkcs1CertByUsage(ss, cert, keyPair, &arg); + if (cert->keyUsage & KU_DIGITAL_SIGNATURE) { + authTypes |= 1 << ssl_auth_rsa_sign; + /* This certificate is RSA, assume that it's also PSS. */ + authTypes |= 1 << ssl_auth_rsa_pss; + } + + if (cert->keyUsage & KU_KEY_ENCIPHERMENT) { + /* If ku_sig=true we configure signature and encryption slots with the + * same cert. This is bad form, but there are enough dual-usage RSA + * certs that we can't really break by limiting this to one type. */ + authTypes |= 1 << ssl_auth_rsa_decrypt; + } + break; case SEC_OID_PKCS1_RSA_PSS_SIGNATURE: if (cert->keyUsage & KU_DIGITAL_SIGNATURE) { - arg.authType = ssl_auth_rsa_pss; + authTypes |= 1 << ssl_auth_rsa_pss; } break; case SEC_OID_ANSIX9_DSA_SIGNATURE: if (cert->keyUsage & KU_DIGITAL_SIGNATURE) { - arg.authType = ssl_auth_dsa; + authTypes |= 1 << ssl_auth_dsa; } break; case SEC_OID_ANSIX962_EC_PUBLIC_KEY: + if (cert->keyUsage & KU_DIGITAL_SIGNATURE) { + authTypes |= 1 << ssl_auth_ecdsa; + } + /* Again, bad form to have dual usage and we don't prevent it. */ if (cert->keyUsage & KU_KEY_ENCIPHERMENT) { - if ((cert->keyUsage & KU_DIGITAL_SIGNATURE) && - arg.authType == ssl_auth_null) { - /* See above regarding bad practice. */ - arg.authType = ssl_auth_ecdsa; - rv = ssl_ConfigCert(ss, cert, keyPair, &arg); - if (rv != SECSuccess) { - return rv; - } - } - - arg.authType = ssl_GetEcdhAuthType(cert); - } else if (cert->keyUsage & KU_DIGITAL_SIGNATURE) { - arg.authType = ssl_auth_ecdsa; + authTypes |= 1 << ssl_GetEcdhAuthType(cert); } break; @@ -498,27 +474,33 @@ ssl_ConfigCertByUsage(sslSocket *ss, CERTCertificate *cert, } /* Check that we successfully picked an authType */ - if (arg.authType == ssl_auth_null) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - /* |data->authType| has to either agree or be ssl_auth_null. */ - if (data && data->authType != ssl_auth_null && - data->authType != arg.authType) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; + if (targetAuthType != ssl_auth_null) { + authTypes &= 1 << targetAuthType; } - return ssl_ConfigCert(ss, cert, keyPair, &arg); + return authTypes; } /* This function adopts pubKey and destroys it if things go wrong. */ static sslKeyPair * -ssl_MakeKeyPairForCert(SECKEYPrivateKey *key, SECKEYPublicKey *pubKey) +ssl_MakeKeyPairForCert(SECKEYPrivateKey *key, CERTCertificate *cert) { sslKeyPair *keyPair = NULL; + SECKEYPublicKey *pubKey = NULL; SECKEYPrivateKey *privKeyCopy = NULL; PK11SlotInfo *bestSlot; + pubKey = CERT_ExtractPublicKey(cert); + if (!pubKey) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; + } + + if (SECKEY_GetPublicKeyType(pubKey) != SECKEY_GetPrivateKeyType(key)) { + SECKEY_DestroyPublicKey(pubKey); + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return NULL; + } + if (key->pkcs11Slot) { bestSlot = PK11_ReferenceSlot(key->pkcs11Slot); if (bestSlot) { @@ -545,20 +527,18 @@ ssl_MakeKeyPairForCert(SECKEYPrivateKey *key, SECKEYPublicKey *pubKey) if (privKeyCopy) { SECKEY_DestroyPrivateKey(privKeyCopy); } - /* We adopted the public key, so we're responsible. */ - if (pubKey) { - SECKEY_DestroyPublicKey(pubKey); - } + SECKEY_DestroyPublicKey(pubKey); + PORT_SetError(SEC_ERROR_NO_MEMORY); } return keyPair; } /* Configure a certificate and private key. * - * This function examines the certificate and key to determine which slot (or - * slots) to place the information in. As long as certificates are different - * (based on having different values of sslServerCertType), then this function - * can be called multiple times and the certificates will all be remembered. + * This function examines the certificate and key to determine the type (or + * types) of authentication the certificate supports. As long as certificates + * are different (different authTypes and maybe keys in different ec groups), + * then this function can be called multiple times. */ SECStatus SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert, @@ -566,12 +546,12 @@ SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert, const SSLExtraServerCertData *data, unsigned int data_len) { sslSocket *ss; - SECKEYPublicKey *pubKey; sslKeyPair *keyPair; SECStatus rv; SSLExtraServerCertData dataCopy = { ssl_auth_null, NULL, NULL, NULL }; + sslAuthTypeMask authTypes; ss = ssl_FindSocket(fd); if (!ss) { @@ -591,21 +571,23 @@ SSL_ConfigServerCert(PRFileDesc *fd, CERTCertificate *cert, PORT_Memcpy(&dataCopy, data, data_len); } - pubKey = CERT_ExtractPublicKey(cert); - if (!pubKey) { + authTypes = ssl_GetCertificateAuthTypes(cert, dataCopy.authType); + if (!authTypes) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - keyPair = ssl_MakeKeyPairForCert(key, pubKey); + keyPair = ssl_MakeKeyPairForCert(key, cert); if (!keyPair) { - /* pubKey is adopted by ssl_MakeKeyPairForCert() */ - PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } - rv = ssl_ConfigCertByUsage(ss, cert, keyPair, &dataCopy); + rv = ssl_ConfigCert(ss, authTypes, cert, keyPair, &dataCopy); ssl_FreeKeyPair(keyPair); - return rv; + if (rv != SECSuccess) { + return SECFailure; + } + return SECSuccess; } /*******************************************************************/ @@ -630,164 +612,148 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, * ssl_ConfigCertByUsage(), only checking against the type of key and ignoring * things like usage. */ static PRBool -ssl_CertSuitableForAuthType(CERTCertificate *cert, SSLAuthType authType) +ssl_CertSuitableForAuthType(CERTCertificate *cert, sslAuthTypeMask authTypes) { SECOidTag tag = SECOID_GetAlgorithmTag(&cert->subjectPublicKeyInfo.algorithm); - switch (authType) { - case ssl_auth_rsa_decrypt: - case ssl_auth_rsa_sign: - return tag == SEC_OID_X500_RSA_ENCRYPTION || - tag == SEC_OID_PKCS1_RSA_ENCRYPTION; - case ssl_auth_dsa: - return tag == SEC_OID_ANSIX9_DSA_SIGNATURE; - case ssl_auth_ecdsa: - case ssl_auth_ecdh_rsa: - case ssl_auth_ecdh_ecdsa: - return tag == SEC_OID_ANSIX962_EC_PUBLIC_KEY; - case ssl_auth_null: - case ssl_auth_kea: - case ssl_auth_rsa_pss: /* not supported with deprecated APIs */ - return PR_FALSE; + sslAuthTypeMask mask = 0; + switch (tag) { + case SEC_OID_X500_RSA_ENCRYPTION: + case SEC_OID_PKCS1_RSA_ENCRYPTION: + mask |= 1 << ssl_auth_rsa_decrypt; + mask |= 1 << ssl_auth_rsa_sign; + break; + case SEC_OID_ANSIX9_DSA_SIGNATURE: + mask |= 1 << ssl_auth_dsa; + break; + case SEC_OID_ANSIX962_EC_PUBLIC_KEY: + mask |= 1 << ssl_auth_ecdsa; + mask |= 1 << ssl_auth_ecdh_rsa; + mask |= 1 << ssl_auth_ecdh_ecdsa; + break; default: - PORT_Assert(0); - return PR_FALSE; + break; + } + PORT_Assert(authTypes); + /* Simply test that no inappropriate auth types are set. */ + return (authTypes & ~mask) == 0; +} + +/* Lookup a cert for the legacy configuration functions. An exact match on + * authTypes and ignoring namedCurve will ensure that values configured using + * legacy functions are overwritten by other legacy functions. */ +static sslServerCert * +ssl_FindCertWithMask(sslSocket *ss, sslAuthTypeMask authTypes) +{ + PRCList *cursor; + + for (cursor = PR_NEXT_LINK(&ss->serverCerts); + cursor != &ss->serverCerts; + cursor = PR_NEXT_LINK(cursor)) { + sslServerCert *cert = (sslServerCert *)cursor; + if (cert->authTypes == authTypes) { + return cert; + } } + return NULL; } -/* This finds an existing server cert slot and unlinks it, or it makes a new +/* This finds an existing server cert in a matching slot that can be reused. + * Failing that, it removes any other certs that might conflict and makes a new * server cert slot of the right type. */ static sslServerCert * -ssl_FindOrMakeCertType(sslSocket *ss, SSLAuthType authType) +ssl_FindOrMakeCert(sslSocket *ss, sslAuthTypeMask authTypes) { sslServerCert *sc; - sslServerCertType certType; - certType.authType = authType; - /* Setting the named curve to NULL ensures that all EC certificates - * are matched when searching for this slot. */ - certType.namedCurve = NULL; - sc = ssl_FindServerCert(ss, &certType); + /* Reuse a perfect match. Note that there is a problem here with use of + * multiple EC certificates that have keys on different curves: these + * deprecated functions will match the first found and overwrite that + * certificate, potentially leaving the other values with a duplicate curve. + * Configuring multiple EC certificates are only possible with the new + * functions, so this is not something that is worth fixing. */ + sc = ssl_FindCertWithMask(ss, authTypes); if (sc) { PR_REMOVE_LINK(&sc->link); return sc; } - return ssl_NewServerCert(&certType); + /* Ignore the namedCurve parameter. Like above, this means that legacy + * functions will clobber values set with the new functions blindly. */ + ssl_ClearMatchingCerts(ss, authTypes, NULL); + + sc = ssl_NewServerCert(); + if (sc) { + sc->authTypes = authTypes; + } + return sc; } -static void -ssl_RemoveCertAndKeyByAuthType(sslSocket *ss, SSLAuthType authType) +static sslAuthTypeMask +ssl_KeaTypeToAuthTypeMask(SSLKEAType keaType) { - sslServerCert *sc; + switch (keaType) { + case ssl_kea_rsa: + return (1 << ssl_auth_rsa_decrypt) | + (1 << ssl_auth_rsa_sign); - sc = ssl_FindServerCertByAuthType(ss, authType); - if (sc) { - (void)ssl_PopulateServerCert(sc, NULL, NULL); - (void)ssl_PopulateKeyPair(sc, NULL); - /* Leave the entry linked here because the old API expects that. There - * might be OCSP stapling values or signed certificate timestamps still - * present that will subsequently be used. */ - /* For ECC certificates, also leave the namedCurve parameter on the slot - * unchanged; the value will be updated when a key is added. */ + case ssl_kea_dh: + return 1 << ssl_auth_dsa; + + case ssl_kea_ecdh: + return (1 << ssl_auth_ecdsa) | + (1 << ssl_auth_ecdh_rsa) | + (1 << ssl_auth_ecdh_ecdsa); + + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); } + return 0; } static SECStatus -ssl_AddCertAndKeyByAuthType(sslSocket *ss, SSLAuthType authType, - CERTCertificate *cert, - const CERTCertificateList *certChainOpt, - sslKeyPair *keyPair) +ssl_AddCertChain(sslSocket *ss, CERTCertificate *cert, + const CERTCertificateList *certChainOpt, + SECKEYPrivateKey *key, sslAuthTypeMask authTypes) { sslServerCert *sc; + sslKeyPair *keyPair; SECStatus rv; + PRErrorCode err = SEC_ERROR_NO_MEMORY; - if (!ssl_CertSuitableForAuthType(cert, authType)) { + if (!ssl_CertSuitableForAuthType(cert, authTypes)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - sc = ssl_FindOrMakeCertType(ss, authType); + sc = ssl_FindOrMakeCert(ss, authTypes); if (!sc) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - rv = ssl_PopulateKeyPair(sc, keyPair); - if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); goto loser; } - /* Now that we have a key pair, update the details of the slot. Many of the - * legacy functions create a slot with a namedCurve of NULL, which - * makes the slot unusable; this corrects that. */ - ssl_PopulateCertType(&sc->certType, authType, cert, keyPair); + rv = ssl_PopulateServerCert(sc, cert, certChainOpt); if (rv != SECSuccess) { - PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } - PR_APPEND_LINK(&sc->link, &ss->serverCerts); - return ssl_OneTimeCertSetup(ss, sc); -loser: - ssl_FreeServerCert(sc); - return SECFailure; -} - -static SECStatus -ssl_AddCertsByKEA(sslSocket *ss, CERTCertificate *cert, - const CERTCertificateList *certChainOpt, - SECKEYPrivateKey *key, SSLKEAType certType) -{ - SECKEYPublicKey *pubKey; - sslKeyPair *keyPair; - SECStatus rv; - pubKey = CERT_ExtractPublicKey(cert); - if (!pubKey) { - return SECFailure; - } - - keyPair = ssl_MakeKeyPairForCert(key, pubKey); + keyPair = ssl_MakeKeyPairForCert(key, cert); if (!keyPair) { - /* Note: pubKey is adopted or freed by ssl_MakeKeyPairForCert() - * depending on whether it succeeds or not. */ - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; + /* Error code is set by ssl_MakeKeyPairForCert */ + goto loser; } - - switch (certType) { - case ssl_kea_rsa: - rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_rsa_decrypt, - cert, certChainOpt, keyPair); - if (rv != SECSuccess) { - return SECFailure; - } - rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_rsa_sign, - cert, certChainOpt, keyPair); - break; - - case ssl_kea_dh: - rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_dsa, - cert, certChainOpt, keyPair); - break; - - case ssl_kea_ecdh: - rv = ssl_AddCertAndKeyByAuthType(ss, ssl_auth_ecdsa, - cert, certChainOpt, keyPair); - if (rv != SECSuccess) { - return SECFailure; - } - rv = ssl_AddCertAndKeyByAuthType(ss, ssl_GetEcdhAuthType(cert), - cert, certChainOpt, keyPair); - break; - - default: - PORT_SetError(SEC_ERROR_INVALID_ARGS); - rv = SECFailure; - break; + rv = ssl_PopulateKeyPair(sc, keyPair); + ssl_FreeKeyPair(keyPair); + if (rv != SECSuccess) { + err = PORT_GetError(); + goto loser; } - ssl_FreeKeyPair(keyPair); - return rv; + PR_APPEND_LINK(&sc->link, &ss->serverCerts); + return SECSuccess; + +loser: + ssl_FreeServerCert(sc); + PORT_SetError(err); + return SECFailure; } /* Public deprecated function */ @@ -797,6 +763,7 @@ SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, SECKEYPrivateKey *key, SSLKEAType certType) { sslSocket *ss; + sslAuthTypeMask authTypes; ss = ssl_FindSocket(fd); if (!ss) { @@ -808,52 +775,25 @@ SSL_ConfigSecureServerWithCertChain(PRFileDesc *fd, CERTCertificate *cert, return SECFailure; } + authTypes = ssl_KeaTypeToAuthTypeMask(certType); + if (!authTypes) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + if (!cert) { - switch (certType) { - case ssl_kea_rsa: - ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_rsa_decrypt); - ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_rsa_sign); - break; - - case ssl_kea_dh: - ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_dsa); - break; - - case ssl_kea_ecdh: - ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdsa); - ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdh_rsa); - ssl_RemoveCertAndKeyByAuthType(ss, ssl_auth_ecdh_ecdsa); - break; - - default: - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; + sslServerCert *sc = ssl_FindCertWithMask(ss, authTypes); + if (sc) { + (void)ssl_PopulateServerCert(sc, NULL, NULL); + (void)ssl_PopulateKeyPair(sc, NULL); + /* Leave the entry linked here because the old API expects that. + * There might be OCSP stapling values or signed certificate + * timestamps still present that will subsequently be used. */ } return SECSuccess; } - return ssl_AddCertsByKEA(ss, cert, certChainOpt, key, certType); -} - -static SECStatus -ssl_SetOCSPResponsesInSlot(sslSocket *ss, SSLAuthType authType, - const SECItemArray *responses) -{ - sslServerCert *sc; - SECStatus rv; - - sc = ssl_FindOrMakeCertType(ss, authType); - if (!sc) { - PORT_SetError(SEC_ERROR_NO_MEMORY); - return SECFailure; - } - rv = ssl_PopulateOCSPResponses(sc, responses); - if (rv == SECSuccess) { - PR_APPEND_LINK(&sc->link, &ss->serverCerts); - } else { - ssl_FreeServerCert(sc); - } - return rv; + return ssl_AddCertChain(ss, cert, certChainOpt, key, authTypes); } /* Public deprecated function */ @@ -862,6 +802,8 @@ SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses, SSLKEAType certType) { sslSocket *ss; + sslServerCert *sc; + sslAuthTypeMask authTypes; SECStatus rv; ss = ssl_FindSocket(fd); @@ -871,49 +813,28 @@ SSL_SetStapledOCSPResponses(PRFileDesc *fd, const SECItemArray *responses, return SECFailure; } - switch (certType) { - case ssl_kea_rsa: - rv = ssl_SetOCSPResponsesInSlot(ss, ssl_auth_rsa_decrypt, responses); - if (rv != SECSuccess) { - return SECFailure; - } - return ssl_SetOCSPResponsesInSlot(ss, ssl_auth_rsa_sign, responses); - - case ssl_kea_dh: - return ssl_SetOCSPResponsesInSlot(ss, ssl_auth_dsa, responses); - - case ssl_kea_ecdh: - rv = ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdsa, responses); - if (rv != SECSuccess) { - return SECFailure; - } - rv = ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdh_rsa, responses); - if (rv != SECSuccess) { - return SECFailure; - } - return ssl_SetOCSPResponsesInSlot(ss, ssl_auth_ecdh_ecdsa, responses); - - default: - SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetStapledOCSPResponses", - SSL_GETPID(), fd)); - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; + authTypes = ssl_KeaTypeToAuthTypeMask(certType); + if (!authTypes) { + SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetStapledOCSPResponses", + SSL_GETPID(), fd)); + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; } -} -static SECStatus -ssl_SetSignedTimestampsInSlot(sslSocket *ss, SSLAuthType authType, - const SECItem *scts) -{ - sslServerCert *sc; - SECStatus rv; + if (!responses) { + sc = ssl_FindCertWithMask(ss, authTypes); + if (sc) { + (void)ssl_PopulateOCSPResponses(sc, NULL); + } + return SECSuccess; + } - sc = ssl_FindOrMakeCertType(ss, authType); + sc = ssl_FindOrMakeCert(ss, authTypes); if (!sc) { - PORT_SetError(SEC_ERROR_NO_MEMORY); return SECFailure; } - rv = ssl_PopulateSignedCertTimestamps(sc, scts); + + rv = ssl_PopulateOCSPResponses(sc, responses); if (rv == SECSuccess) { PR_APPEND_LINK(&sc->link, &ss->serverCerts); } else { @@ -928,6 +849,8 @@ SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts, SSLKEAType certType) { sslSocket *ss; + sslServerCert *sc; + sslAuthTypeMask authTypes; SECStatus rv; ss = ssl_FindSocket(fd); @@ -937,34 +860,34 @@ SSL_SetSignedCertTimestamps(PRFileDesc *fd, const SECItem *scts, return SECFailure; } - switch (certType) { - case ssl_kea_rsa: - rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_rsa_decrypt, scts); - if (rv != SECSuccess) { - return SECFailure; - } - return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_rsa_sign, scts); + authTypes = ssl_KeaTypeToAuthTypeMask(certType); + if (!authTypes) { + SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetSignedCertTimestamps", + SSL_GETPID(), fd)); + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } - case ssl_kea_dh: - return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_dsa, scts); + if (!scts) { + sc = ssl_FindCertWithMask(ss, authTypes); + if (sc) { + (void)ssl_PopulateSignedCertTimestamps(sc, NULL); + } + return SECSuccess; + } - case ssl_kea_ecdh: - rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdsa, scts); - if (rv != SECSuccess) { - return SECFailure; - } - rv = ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh_rsa, scts); - if (rv != SECSuccess) { - return SECFailure; - } - return ssl_SetSignedTimestampsInSlot(ss, ssl_auth_ecdh_ecdsa, scts); + sc = ssl_FindOrMakeCert(ss, authTypes); + if (!sc) { + return SECFailure; + } - default: - SSL_DBG(("%d: SSL[%d]: invalid cert type in SSL_SetSignedCertTimestamps", - SSL_GETPID(), fd)); - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; + rv = ssl_PopulateSignedCertTimestamps(sc, scts); + if (rv == SECSuccess) { + PR_APPEND_LINK(&sc->link, &ss->serverCerts); + } else { + ssl_FreeServerCert(sc); } + return rv; } /* Public deprecated function. */ diff --git a/security/nss/lib/ssl/sslcert.h b/security/nss/lib/ssl/sslcert.h index 052c7d6db..fb31d1389 100644 --- a/security/nss/lib/ssl/sslcert.h +++ b/security/nss/lib/ssl/sslcert.h @@ -13,26 +13,21 @@ #include "secitem.h" #include "keyhi.h" -/* The following struct identifies a single slot into which a certificate can be -** loaded. The authType field determines the basic slot, then additional -** parameters further narrow the slot. -** -** An EC key (ssl_auth_ecdsa or ssl_auth_ecdh_*) is assigned to a slot based on -** the named curve of the key. -*/ -typedef struct sslServerCertTypeStr { - SSLAuthType authType; +/* This type is a bitvector that is indexed by SSLAuthType values. Note that + * the bit for ssl_auth_null(0) - the least significant bit - isn't used. */ +typedef PRUint16 sslAuthTypeMask; +PR_STATIC_ASSERT(sizeof(sslAuthTypeMask) * 8 >= ssl_auth_size); + +typedef struct sslServerCertStr { + PRCList link; /* The linked list link */ + + /* The auth types that this certificate provides. */ + sslAuthTypeMask authTypes; /* For ssl_auth_ecdsa and ssl_auth_ecdh_*. This is only the named curve * of the end-entity certificate key. The keys in other certificates in * the chain aren't directly relevant to the operation of TLS (though it * might make certificate validation difficult, libssl doesn't care). */ const sslNamedGroupDef *namedCurve; -} sslServerCertType; - -typedef struct sslServerCertStr { - PRCList link; /* The linked list link */ - - sslServerCertType certType; /* The certificate slot this occupies */ /* Configuration state for server sockets */ CERTCertificate *serverCert; @@ -48,12 +43,18 @@ typedef struct sslServerCertStr { SECItem signedCertTimestamps; } sslServerCert; -extern sslServerCert *ssl_NewServerCert(const sslServerCertType *slot); +#define SSL_CERT_IS(c, t) ((c)->authTypes & (1 << (t))) +#define SSL_CERT_IS_ONLY(c, t) ((c)->authTypes == (1 << (t))) +#define SSL_CERT_IS_EC(c) \ + ((c)->authTypes & ((1 << ssl_auth_ecdsa) | \ + (1 << ssl_auth_ecdh_rsa) | \ + (1 << ssl_auth_ecdh_ecdsa))) + +extern sslServerCert *ssl_NewServerCert(); extern sslServerCert *ssl_CopyServerCert(const sslServerCert *oc); -extern sslServerCert *ssl_FindServerCert(const sslSocket *ss, - const sslServerCertType *slot); -extern sslServerCert *ssl_FindServerCertByAuthType(const sslSocket *ss, - SSLAuthType authType); +extern const sslServerCert *ssl_FindServerCert( + const sslSocket *ss, SSLAuthType authType, + const sslNamedGroupDef *namedCurve); extern void ssl_FreeServerCert(sslServerCert *sc); #endif /* __sslcert_h_ */ diff --git a/security/nss/lib/ssl/ssldef.c b/security/nss/lib/ssl/ssldef.c index 77a744cc7..be5bcb269 100644 --- a/security/nss/lib/ssl/ssldef.c +++ b/security/nss/lib/ssl/ssldef.c @@ -66,6 +66,8 @@ ssl_DefRecv(sslSocket *ss, unsigned char *buf, int len, int flags) PRFileDesc *lower = ss->fd->lower; int rv; + PORT_Assert(buf && len > 0); + rv = lower->methods->recv(lower, (void *)buf, len, flags, ss->rTimeout); if (rv < 0) { DEFINE_ERROR diff --git a/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h index 751c33541..865077cda 100644 --- a/security/nss/lib/ssl/sslerr.h +++ b/security/nss/lib/ssl/sslerr.h @@ -244,6 +244,8 @@ typedef enum { SSL_ERROR_MISSING_SIGNATURE_ALGORITHMS_EXTENSION = (SSL_ERROR_BASE + 157), SSL_ERROR_MALFORMED_PSK_KEY_EXCHANGE_MODES = (SSL_ERROR_BASE + 158), SSL_ERROR_MISSING_PSK_KEY_EXCHANGE_MODES = (SSL_ERROR_BASE + 159), + SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA = (SSL_ERROR_BASE + 160), + SSL_ERROR_TOO_MUCH_EARLY_DATA = (SSL_ERROR_BASE + 161), SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ } SSLErrorCodes; #endif /* NO_SECURITY_ERROR_ENUM */ diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index 09c37832a..64694b0df 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -34,7 +34,7 @@ #include "sslt.h" /* for some formerly private types, now public */ typedef struct sslSocketStr sslSocket; - +typedef struct ssl3CipherSpecStr ssl3CipherSpec; #include "ssl3ext.h" /* to make some of these old enums public without namespace pollution, @@ -125,7 +125,8 @@ typedef enum { SSLAppOpRead = 0, #define SSL3_MASTER_SECRET_LENGTH 48 /* number of wrap mechanisms potentially used to wrap master secrets. */ -#define SSL_NUM_WRAP_MECHS 16 +#define SSL_NUM_WRAP_MECHS 15 +#define SSL_NUM_WRAP_KEYS 6 /* This makes the cert cache entry exactly 4k. */ #define SSL_MAX_CACHED_CERT_LEN 4060 @@ -200,6 +201,9 @@ typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr, unsigned char *sid, unsigned int sidLen, CERTCertDBHandle *dbHandle); +typedef void (*sslCipherSpecChangedFunc)(void *arg, + PRBool sending, + ssl3CipherSpec *newSpec); /* Socket ops */ struct sslSocketOpsStr { @@ -367,6 +371,10 @@ struct sslGatherStr { /* the start of the buffered DTLS record in dtlsPacket */ unsigned int dtlsPacketOffset; + + /* tracks whether we've seen a v3-type record before and must reject + * any further v2-type records. */ + PRBool rejectV2Records; }; /* sslGather.state */ @@ -408,7 +416,7 @@ typedef PRUint16 DTLSEpoch; typedef void (*DTLSTimerCb)(sslSocket *); typedef struct { - SSL3Opaque wrapped_master_secret[48]; + PRUint8 wrapped_master_secret[48]; PRUint16 wrapped_master_secret_len; PRUint8 msIsWrapped; PRUint8 resumable; @@ -422,7 +430,7 @@ typedef struct { SECItem write_key_item; SECItem write_iv_item; SECItem write_mac_key_item; - SSL3Opaque write_iv[MAX_IV_LENGTH]; + PRUint8 write_iv[MAX_IV_LENGTH]; } ssl3KeyMaterial; typedef SECStatus (*SSLCipher)(void *context, @@ -469,7 +477,7 @@ typedef struct DTLSRecvdRecordsStr { ** Access to the pointers to these specs, and all the specs' contents ** (direct and indirect) is protected by the reader/writer lock ss->specLock. */ -typedef struct { +struct ssl3CipherSpecStr { PRCList link; const ssl3BulkCipherDef *cipher_def; const ssl3MACDef *mac_def; @@ -496,10 +504,13 @@ typedef struct { SECItem msItem; DTLSEpoch epoch; DTLSRecvdRecords recvdRecords; + /* The number of 0-RTT bytes that can be sent or received in TLS 1.3. This + * will be zero for everything but 0-RTT. */ + PRUint32 earlyDataRemaining; PRUint8 refCt; const char *phase; -} ssl3CipherSpec; +}; typedef enum { never_cached, in_client_cache, @@ -523,10 +534,10 @@ struct sslSessionIDStr { */ CERTCertificate *peerCert; - SECItemArray peerCertStatus; /* client only */ - const char *peerID; /* client only */ - const char *urlSvrName; /* client only */ - sslServerCertType certType; + SECItemArray peerCertStatus; /* client only */ + const char *peerID; /* client only */ + const char *urlSvrName; /* client only */ + const sslNamedGroupDef *namedCurve; /* (server) for certificate lookup */ CERTCertificate *localCert; PRIPv6Addr addr; @@ -546,7 +557,7 @@ struct sslSessionIDStr { struct { /* values that are copied into the server's on-disk SID cache. */ PRUint8 sessionIDLength; - SSL3Opaque sessionID[SSL3_SESSIONID_BYTES]; + PRUint8 sessionID[SSL3_SESSIONID_BYTES]; ssl3CipherSuite cipherSuite; SSLCompressionMethod compression; @@ -804,7 +815,7 @@ typedef struct SSL3HandshakeStateStr { union { TLSFinished tFinished[2]; /* client, then server */ SSL3Finished sFinished[2]; - SSL3Opaque data[72]; + PRUint8 data[72]; } finishedMsgs; PRBool authCertificatePending; @@ -862,7 +873,6 @@ typedef struct SSL3HandshakeStateStr { TLS13CertificateRequest *certificateRequest; PRCList cipherSpecs; /* The cipher specs in the sequence they * will be applied. */ - ssl3CipherSpec *nullSpec; /* In case 0-RTT is rejected. */ sslZeroRttState zeroRttState; /* Are we doing a 0-RTT handshake? */ sslZeroRttIgnore zeroRttIgnore; /* Are we ignoring 0-RTT? */ ssl3CipherSuite zeroRttSuite; /* The cipher suite we used for 0-RTT. */ @@ -894,6 +904,11 @@ struct ssl3StateStr { ssl3CipherSpec *cwSpec; /* current write spec. */ ssl3CipherSpec *pwSpec; /* pending write spec. */ + /* Internal callback for when we do a cipher suite change. Used for + * debugging in TLS 1.3. This can only be set by non-public functions. */ + sslCipherSpecChangedFunc changedCipherSpecFunc; + void *changedCipherSpecArg; + CERTCertificate *clientCertificate; /* used by client */ SECKEYPrivateKey *clientPrivateKey; /* used by client */ CERTCertificateList *clientCertChain; /* used by client */ @@ -965,19 +980,19 @@ struct ssl3DHParamsStr { }; typedef struct SSLWrappedSymWrappingKeyStr { - SSL3Opaque wrappedSymmetricWrappingkey[512]; + PRUint8 wrappedSymmetricWrappingkey[512]; CK_MECHANISM_TYPE symWrapMechanism; /* unwrapped symmetric wrapping key uses this mechanism */ CK_MECHANISM_TYPE asymWrapMechanism; /* mechanism used to wrap the SymmetricWrappingKey using * server's public and/or private keys. */ - SSLAuthType authType; /* type of keys used to wrap SymWrapKey*/ - PRInt32 symWrapMechIndex; + PRInt16 wrapMechIndex; + PRUint16 wrapKeyIndex; PRUint16 wrappedSymKeyLen; } SSLWrappedSymWrappingKey; typedef struct SessionTicketStr { - PRUint16 ticket_version; + PRBool valid; SSL3ProtocolVersion ssl_version; ssl3CipherSuite cipher_suite; SSLCompressionMethod compression_method; @@ -985,21 +1000,23 @@ typedef struct SessionTicketStr { PRUint32 authKeyBits; SSLKEAType keaType; PRUint32 keaKeyBits; - sslServerCertType certType; + const sslNamedGroupDef *namedCurve; /* For certificate lookup. */ + /* * msWrapMech contains a meaningful value only if ms_is_wrapped is true. */ PRUint8 ms_is_wrapped; CK_MECHANISM_TYPE msWrapMech; PRUint16 ms_length; - SSL3Opaque master_secret[48]; + PRUint8 master_secret[48]; PRBool extendedMasterSecretUsed; - ClientIdentity client_identity; + ClientAuthenticationType client_auth_type; SECItem peer_cert; PRUint32 timestamp; PRUint32 flags; SECItem srvName; /* negotiated server name */ SECItem alpnSelection; + PRUint32 maxEarlyData; } SessionTicket; /* @@ -1121,6 +1138,10 @@ struct sslSocketStr { void *getClientAuthDataArg; SSLSNISocketConfig sniSocketConfig; void *sniSocketConfigArg; + SSLAlertCallback alertReceivedCallback; + void *alertReceivedCallbackArg; + SSLAlertCallback alertSentCallback; + void *alertSentCallbackArg; SSLBadCertHandler handleBadCert; void *badCertArg; SSLHandshakeCallback handshakeCallback; @@ -1208,17 +1229,21 @@ struct sslSocketStr { SSLProtocolVariant protocolVariant; }; -/* All the global data items declared here should be protected using the -** ssl_global_data_lock, which is a reader/writer lock. -*/ -extern NSSRWLock *ssl_global_data_lock; +struct sslSelfEncryptKeysStr { + PRCallOnceType setup; + PRUint8 keyName[SELF_ENCRYPT_KEY_NAME_LEN]; + PK11SymKey *encKey; + PK11SymKey *macKey; +}; +typedef struct sslSelfEncryptKeysStr sslSelfEncryptKeys; + extern char ssl_debug; extern char ssl_trace; extern FILE *ssl_trace_iob; extern FILE *ssl_keylog_iob; -extern CERTDistNames *ssl3_server_ca_list; -extern PRUint32 ssl_sid_timeout; extern PRUint32 ssl3_sid_timeout; +extern PRUint32 ssl_ticket_lifetime; +extern PRUint32 ssl_max_early_data_size; extern const char *const ssl3_cipherName[]; @@ -1338,8 +1363,8 @@ extern SECStatus ssl_CipherPrefSetDefault(PRInt32 which, PRBool enabled); extern SECStatus ssl3_ConstrainRangeByPolicy(void); -extern SECStatus ssl3_InitState(sslSocket *ss); -extern SECStatus ssl3_RestartHandshakeHashes(sslSocket *ss); +extern void ssl3_InitState(sslSocket *ss); +extern void ssl3_RestartHandshakeHashes(sslSocket *ss); extern SECStatus ssl3_UpdateHandshakeHashes(sslSocket *ss, const unsigned char *b, unsigned int l); @@ -1352,7 +1377,7 @@ extern PRBool ssl3_WaitingForServerSecondRound(sslSocket *ss); extern PRInt32 ssl3_SendRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type, - const SSL3Opaque *pIn, PRInt32 nIn, + const PRUint8 *pIn, PRInt32 nIn, PRInt32 flags); #ifdef NSS_SSL_ENABLE_ZLIB @@ -1479,6 +1504,14 @@ extern PRInt32 ssl3_SendRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, */ #define SSL_LIBRARY_VERSION_NONE 0 +/* SSL_LIBRARY_VERSION_MIN_SUPPORTED is the minimum version that this version + * of libssl supports. Applications should use SSL_VersionRangeGetSupported at + * runtime to determine which versions are supported by the version of libssl + * in use. + */ +#define SSL_LIBRARY_VERSION_MIN_SUPPORTED_DATAGRAM SSL_LIBRARY_VERSION_TLS_1_1 +#define SSL_LIBRARY_VERSION_MIN_SUPPORTED_STREAM SSL_LIBRARY_VERSION_3_0 + /* SSL_LIBRARY_VERSION_MAX_SUPPORTED is the maximum version that this version * of libssl supports. Applications should use SSL_VersionRangeGetSupported at * runtime to determine which versions are supported by the version of libssl @@ -1600,13 +1633,13 @@ extern SECStatus ssl3_GetPolicy(ssl3CipherSuite which, PRInt32 *policy); extern void ssl3_InitSocketPolicy(sslSocket *ss); extern SECStatus ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache); -extern SECStatus ssl3_HandleHandshakeMessage(sslSocket *ss, SSL3Opaque *b, +extern SECStatus ssl3_HandleHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, PRBool endOfRecord); extern void ssl3_DestroySSL3Info(sslSocket *ss); -extern SECStatus ssl_ClientReadVersion(sslSocket *ss, SSL3Opaque **b, +extern SECStatus ssl_ClientReadVersion(sslSocket *ss, PRUint8 **b, PRUint32 *length, SSL3ProtocolVersion *version); extern SECStatus ssl3_NegotiateVersion(sslSocket *ss, @@ -1619,15 +1652,14 @@ extern SECStatus ssl_GetPeerInfo(sslSocket *ss); extern SECStatus ssl3_SendECDHClientKeyExchange(sslSocket *ss, SECKEYPublicKey *svrPubKey); extern SECStatus ssl3_HandleECDHServerKeyExchange(sslSocket *ss, - SSL3Opaque *b, PRUint32 length); + PRUint8 *b, PRUint32 length); extern SECStatus ssl3_HandleECDHClientKeyExchange(sslSocket *ss, - SSL3Opaque *b, PRUint32 length, + PRUint8 *b, PRUint32 length, sslKeyPair *serverKeys); extern SECStatus ssl3_SendECDHServerKeyExchange(sslSocket *ss); extern SECStatus ssl_ImportECDHKeyShare( sslSocket *ss, SECKEYPublicKey *peerKey, - SSL3Opaque *b, PRUint32 length, const sslNamedGroupDef *curve); -unsigned int tls13_SizeOfECDHEKeyShareKEX(const SECKEYPublicKey *pubKey); + PRUint8 *b, PRUint32 length, const sslNamedGroupDef *curve); SECStatus tls13_EncodeECDHEKeyShareKEX(const sslSocket *ss, const SECKEYPublicKey *pubKey); @@ -1644,15 +1676,16 @@ extern SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss, extern SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, PRInt32 lenSize); extern SECStatus ssl3_AppendHandshakeVariable(sslSocket *ss, - const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize); + const PRUint8 *src, PRInt32 bytes, PRInt32 lenSize); extern SECStatus ssl3_AppendSignatureAndHashAlgorithm( sslSocket *ss, const SSLSignatureAndHashAlg *sigAndHash); -extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, - SSL3Opaque **b, PRUint32 *length); -extern PRInt32 ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, - SSL3Opaque **b, PRUint32 *length); +extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRUint32 bytes, + PRUint8 **b, PRUint32 *length); +extern SECStatus ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRUint32 *num, + PRUint32 bytes, PRUint8 **b, + PRUint32 *length); extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, - PRInt32 bytes, SSL3Opaque **b, + PRUint32 bytes, PRUint8 **b, PRUint32 *length); extern PRUint8 *ssl_EncodeUintX(PRUint64 value, unsigned int bytes, PRUint8 *to); @@ -1665,14 +1698,13 @@ extern SECStatus ssl_ParseSignatureSchemes(const sslSocket *ss, PLArenaPool *are unsigned char **b, unsigned int *len); extern SECStatus ssl_ConsumeSignatureScheme( - sslSocket *ss, SSL3Opaque **b, PRUint32 *length, SSLSignatureScheme *out); + sslSocket *ss, PRUint8 **b, PRUint32 *length, SSLSignatureScheme *out); extern SECStatus ssl3_SignHashes(sslSocket *ss, SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf); extern SECStatus ssl3_VerifySignedHashes(sslSocket *ss, SSLSignatureScheme scheme, SSL3Hashes *hash, SECItem *buf); extern SECStatus ssl3_CacheWrappedMasterSecret( - sslSocket *ss, sslSessionID *sid, - ssl3CipherSpec *spec, SSLAuthType authType); + sslSocket *ss, sslSessionID *sid, ssl3CipherSpec *spec); extern void ssl3_FreeSniNameArray(TLSExtensionData *xtnData); /* Hello Extension related routines. */ @@ -1681,15 +1713,11 @@ extern void ssl3_SetSIDSessionTicket(sslSessionID *sid, SECStatus ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket_input, SECItem *ticket_data); -extern PRBool ssl_GetSessionTicketKeys(SECKEYPrivateKey *svrPrivKey, - SECKEYPublicKey *svrPubKey, void *pwArg, - unsigned char *keyName, PK11SymKey **aesKey, - PK11SymKey **macKey); -extern SECStatus ssl3_SessionTicketShutdown(void *appData, void *nssData); -/* Tell clients to consider tickets valid for this long. */ -#define TLS_EX_SESS_TICKET_LIFETIME_HINT (2 * 24 * 60 * 60) /* 2 days */ -#define TLS_EX_SESS_TICKET_VERSION (0x0103) +SECStatus ssl_MaybeSetSelfEncryptKeyPair(const sslKeyPair *keyPair); +SECStatus ssl_GetSelfEncryptKeys(sslSocket *ss, unsigned char *keyName, + PK11SymKey **encKey, PK11SymKey **macKey); +void ssl_ResetSelfEncryptKeys(); extern SECStatus ssl3_ValidateNextProtoNego(const unsigned char *data, unsigned int length); @@ -1703,8 +1731,8 @@ extern void ssl_FreePRSocket(PRFileDesc *fd); extern int ssl3_config_match_init(sslSocket *); /* calls for accessing wrapping keys across processes. */ -extern PRBool -ssl_GetWrappingKey(PRInt32 symWrapMechIndex, SSLAuthType authType, +extern SECStatus +ssl_GetWrappingKey(unsigned int symWrapMechIndex, unsigned int wrapKeyIndex, SSLWrappedSymWrappingKey *wswk); /* The caller passes in the new value it wants @@ -1716,7 +1744,7 @@ ssl_GetWrappingKey(PRInt32 symWrapMechIndex, SSLAuthType authType, * This is all done while holding the locks/semaphores necessary to make * the operation atomic. */ -extern PRBool +extern SECStatus ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk); /* get rid of the symmetric wrapping key references. */ @@ -1736,10 +1764,10 @@ extern void dtls_FreeHandshakeMessages(PRCList *lst); extern SECStatus dtls_HandleHandshake(sslSocket *ss, sslBuffer *origBuf); extern SECStatus dtls_HandleHelloVerifyRequest(sslSocket *ss, - SSL3Opaque *b, PRUint32 length); + PRUint8 *b, PRUint32 length); extern SECStatus dtls_StageHandshakeMessage(sslSocket *ss); extern SECStatus dtls_QueueMessage(sslSocket *ss, SSL3ContentType type, - const SSL3Opaque *pIn, PRInt32 nIn); + const PRUint8 *pIn, PRInt32 nIn); extern SECStatus dtls_FlushHandshakeMessages(sslSocket *ss, PRInt32 flags); SECStatus ssl3_DisableNonDTLSSuites(sslSocket *ss); extern SECStatus dtls_StartHolddownTimer(sslSocket *ss); @@ -1770,20 +1798,20 @@ SECStatus ssl3_ServerCallSNICallback(sslSocket *ss); SECStatus ssl3_SetupPendingCipherSpec(sslSocket *ss); SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags); SECStatus ssl3_CompleteHandleCertificate(sslSocket *ss, - SSL3Opaque *b, PRUint32 length); + PRUint8 *b, PRUint32 length); void ssl3_SendAlertForCertError(sslSocket *ss, PRErrorCode errCode); SECStatus ssl3_HandleNoCertificate(sslSocket *ss); SECStatus ssl3_SendEmptyCertificate(sslSocket *ss); void ssl3_CleanupPeerCerts(sslSocket *ss); SECStatus ssl3_SendCertificateStatus(sslSocket *ss); SECStatus ssl3_AuthCertificate(sslSocket *ss); -SECStatus ssl_ReadCertificateStatus(sslSocket *ss, SSL3Opaque *b, +SECStatus ssl_ReadCertificateStatus(sslSocket *ss, PRUint8 *b, PRUint32 length); SECStatus ssl3_EncodeSigAlgs(const sslSocket *ss, PRUint8 *buf, unsigned maxLen, PRUint32 *len); -void ssl3_GetCertificateRequestCAs(sslSocket *ss, int *calenp, SECItem **namesp, - int *nnamesp); -SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, SSL3Opaque **b, +SECStatus ssl_GetCertificateRequestCAs(sslSocket *ss, unsigned int *calenp, + SECItem **namesp, unsigned int *nnamesp); +SECStatus ssl3_ParseCertificateRequestCAs(sslSocket *ss, PRUint8 **b, PRUint32 *length, PLArenaPool *arena, CERTDistNames *ca_list); SECStatus ssl3_CompleteHandleCertificateRequest( @@ -1802,7 +1830,6 @@ SECStatus ssl_CreateStaticECDHEKey(sslSocket *ss, SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags); PK11SymKey *ssl3_GetWrappingKey(sslSocket *ss, PK11SlotInfo *masterSecretSlot, - const sslServerCert *serverCert, CK_MECHANISM_TYPE masterWrapMech, void *pwArg); SECStatus ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid); @@ -1835,6 +1862,7 @@ extern void ssl3_CheckCipherSuiteOrderConsistency(); extern int ssl_MapLowLevelError(int hiLevelError); extern PRUint32 ssl_Time(void); +extern PRBool ssl_TicketTimeValid(const NewSessionTicket *ticket); extern void SSL_AtomicIncrementLong(long *x); @@ -1844,11 +1872,12 @@ extern HASH_HashType ssl3_GetTls12HashType(sslSocket *ss); extern SECStatus -ssl3_TLSPRFWithMasterSecret(ssl3CipherSpec *spec, +ssl3_TLSPRFWithMasterSecret(sslSocket *ss, ssl3CipherSpec *spec, const char *label, unsigned int labelLen, const unsigned char *val, unsigned int valLen, - unsigned char *out, unsigned int outLen, - HASH_HashType tls12HashType); + unsigned char *out, unsigned int outLen); + +PRBool ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag); #ifdef TRACE #define SSL_TRACE(msg) ssl_Trace msg diff --git a/security/nss/lib/ssl/sslinfo.c b/security/nss/lib/ssl/sslinfo.c index 665109d65..88162d814 100644 --- a/security/nss/lib/ssl/sslinfo.c +++ b/security/nss/lib/ssl/sslinfo.c @@ -140,6 +140,20 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd, inf.valuesSet = ss->ssl3.hs.preliminaryInfo; inf.protocolVersion = ss->version; inf.cipherSuite = ss->ssl3.hs.cipher_suite; + inf.canSendEarlyData = !ss->sec.isServer && + (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent || + ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted); + /* We shouldn't be able to send early data if the handshake is done. */ + PORT_Assert(!ss->firstHsDone || !inf.canSendEarlyData); + + if (ss->sec.ci.sid && + (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent || + ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted)) { + inf.maxEarlyDataSize = + ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size; + } else { + inf.maxEarlyDataSize = 0; + } memcpy(info, &inf, inf.length); return SECSuccess; @@ -219,6 +233,9 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd, #define F_NFIPS_NSTD 0, 0, 1, 0 /* i.e., trash */ #define F_EXPORT 0, 1, 0, 0 /* i.e., trash */ +// RFC 5705 +#define MAX_CONTEXT_LEN PR_UINT16_MAX - 1 + static const SSLCipherSuiteInfo suiteInfo[] = { /* <------ Cipher suite --------------------> <auth> <KEA> <bulk cipher> <MAC> <FIPS> */ { 0, CS_(TLS_AES_128_GCM_SHA256), S_ANY, K_ANY, C_AESGCM, B_128, M_AEAD_128, F_FIPS_STD, A_ANY }, @@ -425,6 +442,11 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd, out, outLen); } + if (hasContext && contextLen > MAX_CONTEXT_LEN) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + /* construct PRF arguments */ valLen = SSL3_RANDOM_LENGTH * 2; if (hasContext) { @@ -455,9 +477,8 @@ SSL_ExportKeyingMaterial(PRFileDesc *fd, PORT_SetError(SSL_ERROR_HANDSHAKE_NOT_COMPLETED); rv = SECFailure; } else { - HASH_HashType ht = ssl3_GetTls12HashType(ss); - rv = ssl3_TLSPRFWithMasterSecret(ss->ssl3.cwSpec, label, labelLen, val, - valLen, out, outLen, ht); + rv = ssl3_TLSPRFWithMasterSecret(ss, ss->ssl3.cwSpec, label, labelLen, + val, valLen, out, outLen); } ssl_ReleaseSpecReadLock(ss); diff --git a/security/nss/lib/ssl/sslmutex.c b/security/nss/lib/ssl/sslmutex.c index 560a9e823..10b6cf55f 100644 --- a/security/nss/lib/ssl/sslmutex.c +++ b/security/nss/lib/ssl/sslmutex.c @@ -60,7 +60,8 @@ single_process_sslMutex_Lock(sslMutex* pMutex) return SECSuccess; } -#if defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD) +#if defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || \ + (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD) || defined(__GLIBC__) #include <unistd.h> #include <fcntl.h> diff --git a/security/nss/lib/ssl/sslmutex.h b/security/nss/lib/ssl/sslmutex.h index 7611148ad..3f63ed80d 100644 --- a/security/nss/lib/ssl/sslmutex.h +++ b/security/nss/lib/ssl/sslmutex.h @@ -49,7 +49,8 @@ typedef struct { typedef int sslPID; -#elif defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD) +#elif defined(LINUX) || defined(AIX) || defined(BEOS) || defined(BSDI) || \ + (defined(NETBSD) && __NetBSD_Version__ < 500000000) || defined(OPENBSD) || defined(__GLIBC__) #include <sys/types.h> #include "prtypes.h" diff --git a/security/nss/lib/ssl/sslnonce.c b/security/nss/lib/ssl/sslnonce.c index 91cc87040..7ad1c6bc7 100644 --- a/security/nss/lib/ssl/sslnonce.c +++ b/security/nss/lib/ssl/sslnonce.c @@ -1,3 +1,4 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file implements the CLIENT Session ID cache. * @@ -18,7 +19,6 @@ #include <time.h> #endif -PRUint32 ssl_sid_timeout = 100; PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */ static sslSessionID *cache = NULL; @@ -460,6 +460,20 @@ ssl_Time(void) return myTime; } +PRBool +ssl_TicketTimeValid(const NewSessionTicket *ticket) +{ + PRTime endTime; + + if (ticket->ticket_lifetime_hint == 0) { + return PR_TRUE; + } + + endTime = ticket->received_timestamp + + (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC); + return endTime > PR_Now(); +} + void ssl3_SetSIDSessionTicket(sslSessionID *sid, /*in/out*/ NewSessionTicket *newSessionTicket) diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c index eecf44396..8bec3d327 100644 --- a/security/nss/lib/ssl/sslsecur.c +++ b/security/nss/lib/ssl/sslsecur.c @@ -478,7 +478,7 @@ sslBuffer_Append(sslBuffer *b, const void *data, unsigned int len) void sslBuffer_Clear(sslBuffer *b) { - if (b->len > 0) { + if (b->buf) { PORT_Free(b->buf); b->buf = NULL; b->len = 0; @@ -884,6 +884,7 @@ int ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) { int rv = 0; + PRBool zeroRtt = PR_FALSE; SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes", SSL_GETPID(), ss->fd, len)); @@ -923,19 +924,20 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) * Case 2: TLS 1.3 0-RTT */ if (!ss->firstHsDone) { - PRBool falseStart = PR_FALSE; + PRBool allowEarlySend = PR_FALSE; + ssl_Get1stHandshakeLock(ss); if (ss->opt.enableFalseStart || (ss->opt.enable0RttData && !ss->sec.isServer)) { ssl_GetSSL3HandshakeLock(ss); /* The client can sometimes send before the handshake is fully * complete. In TLS 1.2: false start; in TLS 1.3: 0-RTT. */ - falseStart = ss->ssl3.hs.canFalseStart || - ss->ssl3.hs.zeroRttState == ssl_0rtt_sent || - ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted; + zeroRtt = ss->ssl3.hs.zeroRttState == ssl_0rtt_sent || + ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted; + allowEarlySend = ss->ssl3.hs.canFalseStart || zeroRtt; ssl_ReleaseSSL3HandshakeLock(ss); } - if (!falseStart && ss->handshake) { + if (!allowEarlySend && ss->handshake) { rv = ssl_Do1stHandshake(ss); } ssl_Release1stHandshakeLock(ss); @@ -945,6 +947,20 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) goto done; } + if (zeroRtt) { + /* There's a limit to the number of early data octets we can send. + * + * Note that taking this lock doesn't prevent the cipher specs from + * being changed out between here and when records are ultimately + * encrypted. The only effect of that is to occasionally do an + * unnecessary short write when data is identified as 0-RTT here but + * 1-RTT later. + */ + ssl_GetSpecReadLock(ss); + len = tls13_LimitEarlyData(ss, content_application_data, len); + ssl_ReleaseSpecReadLock(ss); + } + /* Check for zero length writes after we do housekeeping so we make forward * progress. */ @@ -959,19 +975,6 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) goto done; } - if (!ss->firstHsDone) { -#ifdef DEBUG - ssl_GetSSL3HandshakeLock(ss); - PORT_Assert(!ss->sec.isServer && - (ss->ssl3.hs.canFalseStart || - ss->ssl3.hs.zeroRttState == ssl_0rtt_sent || - ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted)); - ssl_ReleaseSSL3HandshakeLock(ss); -#endif - SSL_TRC(3, ("%d: SSL[%d]: SecureSend: sending data due to false start", - SSL_GETPID(), ss->fd)); - } - ssl_GetXmitBufLock(ss); rv = ssl3_SendApplicationData(ss, buf, len, flags); ssl_ReleaseXmitBufLock(ss); @@ -994,6 +997,42 @@ ssl_SecureWrite(sslSocket *ss, const unsigned char *buf, int len) } SECStatus +SSL_AlertReceivedCallback(PRFileDesc *fd, SSLAlertCallback cb, void *arg) +{ + sslSocket *ss; + + ss = ssl_FindSocket(fd); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: unable to find socket in SSL_AlertReceivedCallback", + SSL_GETPID(), fd)); + return SECFailure; + } + + ss->alertReceivedCallback = cb; + ss->alertReceivedCallbackArg = arg; + + return SECSuccess; +} + +SECStatus +SSL_AlertSentCallback(PRFileDesc *fd, SSLAlertCallback cb, void *arg) +{ + sslSocket *ss; + + ss = ssl_FindSocket(fd); + if (!ss) { + SSL_DBG(("%d: SSL[%d]: unable to find socket in SSL_AlertSentCallback", + SSL_GETPID(), fd)); + return SECFailure; + } + + ss->alertSentCallback = cb; + ss->alertSentCallbackArg = arg; + + return SECSuccess; +} + +SECStatus SSL_BadCertHook(PRFileDesc *fd, SSLBadCertHandler f, void *arg) { sslSocket *ss; diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c index 4a4005c2d..3ef11f7a7 100644 --- a/security/nss/lib/ssl/sslsnce.c +++ b/security/nss/lib/ssl/sslsnce.c @@ -1,3 +1,4 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* This file implements the SERVER Session ID cache. * NOTE: The contents of this file are NOT used by the client. * @@ -33,8 +34,8 @@ * sidCacheSet sidCacheSets[ numSIDCacheSets ]; * sidCacheEntry sidCacheData[ numSIDCacheEntries]; * certCacheEntry certCacheData[numCertCacheEntries]; - * SSLWrappedSymWrappingKey keyCacheData[ssl_auth_size][SSL_NUM_WRAP_MECHS]; - * PRUint8 keyNameSuffix[SESS_TICKET_KEY_VAR_NAME_LEN] + * SSLWrappedSymWrappingKey keyCacheData[SSL_NUM_WRAP_KEYS][SSL_NUM_WRAP_MECHS]; + * PRUint8 keyNameSuffix[SELF_ENCRYPT_KEY_VAR_NAME_LEN] * encKeyCacheEntry ticketEncKey; // Wrapped * encKeyCacheEntry ticketMacKey; // Wrapped * PRBool ticketKeysValid; @@ -54,8 +55,9 @@ #include "base64.h" #include "keyhi.h" #include "blapit.h" +#include "nss.h" /* for NSS_RegisterShutdown */ #include "sechash.h" - +#include "selfencrypt.h" #include <stdio.h> #if defined(XP_UNIX) || defined(XP_BEOS) @@ -109,7 +111,7 @@ struct sidCacheEntryStr { /* 4 */ PRInt32 certIndex; /* 4 */ PRInt32 srvNameIndex; /* 32 */ PRUint8 srvNameHash[SHA256_LENGTH]; /* SHA256 name hash */ - /* 2 */ PRUint16 certTypeArgs; + /* 2 */ PRUint16 namedCurve; /*104 */} ssl3; /* force sizeof(sidCacheEntry) to be a multiple of cache line size */ @@ -440,17 +442,12 @@ ConvertFromSID(sidCacheEntry *to, sslSessionID *from) to->u.ssl3.srvNameIndex = -1; PORT_Memcpy(to->sessionID, from->u.ssl3.sessionID, to->sessionIDLength); - to->u.ssl3.certTypeArgs = 0U; - switch (from->authType) { - case ssl_auth_ecdsa: - case ssl_auth_ecdh_rsa: - case ssl_auth_ecdh_ecdsa: - PORT_Assert(from->certType.namedCurve); - to->u.ssl3.certTypeArgs = - (PRUint16)from->certType.namedCurve->name; - break; - default: - break; + to->u.ssl3.namedCurve = 0U; + if (from->authType == ssl_auth_ecdsa || + from->authType == ssl_auth_ecdh_rsa || + from->authType == ssl_auth_ecdh_ecdsa) { + PORT_Assert(from->namedCurve); + to->u.ssl3.namedCurve = (PRUint16)from->namedCurve->name; } SSL_TRC(8, ("%d: SSL3: ConvertSID: time=%d addr=0x%08x%08x%08x%08x " @@ -526,16 +523,11 @@ ConvertToSID(sidCacheEntry *from, if (to->peerCert == NULL) goto loser; } - to->certType.authType = from->authType; - switch (from->authType) { - case ssl_auth_ecdsa: - case ssl_auth_ecdh_rsa: - case ssl_auth_ecdh_ecdsa: - to->certType.namedCurve = - ssl_LookupNamedGroup((SSLNamedGroup)from->u.ssl3.certTypeArgs); - break; - default: - break; + if (from->authType == ssl_auth_ecdsa || + from->authType == ssl_auth_ecdh_rsa || + from->authType == ssl_auth_ecdh_ecdsa) { + to->namedCurve = + ssl_LookupNamedGroup((SSLNamedGroup)from->u.ssl3.namedCurve); } to->version = from->version; @@ -983,7 +975,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries, cache->certCacheSize = (char *)cache->keyCacheData - (char *)cache->certCacheData; - cache->numKeyCacheEntries = ssl_auth_size * SSL_NUM_WRAP_MECHS; + cache->numKeyCacheEntries = SSL_NUM_WRAP_KEYS * SSL_NUM_WRAP_MECHS; ptr = (ptrdiff_t)(cache->keyCacheData + cache->numKeyCacheEntries); ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); @@ -991,7 +983,7 @@ InitCache(cacheDesc *cache, int maxCacheEntries, int maxCertCacheEntries, cache->ticketKeyNameSuffix = (PRUint8 *)ptr; ptr = (ptrdiff_t)(cache->ticketKeyNameSuffix + - SESS_TICKET_KEY_VAR_NAME_LEN); + SELF_ENCRYPT_KEY_VAR_NAME_LEN); ptr = SID_ROUNDUP(ptr, SID_ALIGNMENT); cache->ticketEncKey = (encKeyCacheEntry *)ptr; @@ -1608,36 +1600,260 @@ StopLockPoller(cacheDesc *cache) * Code dealing with shared wrapped symmetric wrapping keys below * ************************************************************************/ -/* If now is zero, it implies that the lock is not held, and must be -** aquired here. -*/ +/* The asymmetric key we use for wrapping the self-encryption keys. This is a + * global structure that can be initialized without a socket. Access is + * synchronized on the reader-writer lock. This is setup either by calling + * SSL_SetSessionTicketKeyPair() or by configuring a certificate of the + * ssl_auth_rsa_decrypt type. */ +static struct { + PRCallOnceType setup; + PRRWLock *lock; + SECKEYPublicKey *pubKey; + SECKEYPrivateKey *privKey; + PRBool configured; +} ssl_self_encrypt_key_pair; + +/* The symmetric self-encryption keys. This requires a socket to construct + * and requires that the global structure be initialized before use. + */ +static sslSelfEncryptKeys ssl_self_encrypt_keys; + +/* Externalize the self encrypt keys. Purely used for testing. */ +sslSelfEncryptKeys * +ssl_GetSelfEncryptKeysInt() +{ + return &ssl_self_encrypt_keys; +} + +static void +ssl_CleanupSelfEncryptKeyPair() +{ + if (ssl_self_encrypt_key_pair.pubKey) { + PORT_Assert(ssl_self_encrypt_key_pair.privKey); + SECKEY_DestroyPublicKey(ssl_self_encrypt_key_pair.pubKey); + SECKEY_DestroyPrivateKey(ssl_self_encrypt_key_pair.privKey); + } +} + +void +ssl_ResetSelfEncryptKeys() +{ + if (ssl_self_encrypt_keys.encKey) { + PORT_Assert(ssl_self_encrypt_keys.macKey); + PK11_FreeSymKey(ssl_self_encrypt_keys.encKey); + PK11_FreeSymKey(ssl_self_encrypt_keys.macKey); + } + PORT_Memset(&ssl_self_encrypt_keys, 0, + sizeof(ssl_self_encrypt_keys)); +} + +static SECStatus +ssl_SelfEncryptShutdown(void *appData, void *nssData) +{ + ssl_CleanupSelfEncryptKeyPair(); + PR_DestroyRWLock(ssl_self_encrypt_key_pair.lock); + PORT_Memset(&ssl_self_encrypt_key_pair, 0, + sizeof(ssl_self_encrypt_key_pair)); + + ssl_ResetSelfEncryptKeys(); + return SECSuccess; +} + +static PRStatus +ssl_SelfEncryptSetup(void) +{ + SECStatus rv = NSS_RegisterShutdown(ssl_SelfEncryptShutdown, NULL); + if (rv != SECSuccess) { + return PR_FAILURE; + } + ssl_self_encrypt_key_pair.lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, NULL); + if (!ssl_self_encrypt_key_pair.lock) { + return PR_FAILURE; + } + return PR_SUCCESS; +} + +/* Configure a self encryption key pair. |explicitConfig| is set to true for + * calls to SSL_SetSessionTicketKeyPair(), false for implicit configuration. + * This assumes that the setup has been run. */ +static SECStatus +ssl_SetSelfEncryptKeyPair(SECKEYPublicKey *pubKey, + SECKEYPrivateKey *privKey, + PRBool explicitConfig) +{ + SECKEYPublicKey *pubKeyCopy; + SECKEYPrivateKey *privKeyCopy; + + PORT_Assert(ssl_self_encrypt_key_pair.lock); + + pubKeyCopy = SECKEY_CopyPublicKey(pubKey); + if (!pubKeyCopy) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + + privKeyCopy = SECKEY_CopyPrivateKey(privKey); + if (!privKeyCopy) { + SECKEY_DestroyPublicKey(pubKeyCopy); + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + + PR_RWLock_Wlock(ssl_self_encrypt_key_pair.lock); + ssl_CleanupSelfEncryptKeyPair(); + ssl_self_encrypt_key_pair.pubKey = pubKeyCopy; + ssl_self_encrypt_key_pair.privKey = privKeyCopy; + ssl_self_encrypt_key_pair.configured = explicitConfig; + PR_RWLock_Unlock(ssl_self_encrypt_key_pair.lock); + return SECSuccess; +} + +/* This is really the self-encryption keys but it has the + * wrong name for historical API stability reasons. */ +SECStatus +SSL_SetSessionTicketKeyPair(SECKEYPublicKey *pubKey, + SECKEYPrivateKey *privKey) +{ + if (SECKEY_GetPublicKeyType(pubKey) != rsaKey || + SECKEY_GetPrivateKeyType(privKey) != rsaKey) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + if (PR_SUCCESS != PR_CallOnce(&ssl_self_encrypt_key_pair.setup, + &ssl_SelfEncryptSetup)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + return ssl_SetSelfEncryptKeyPair(pubKey, privKey, PR_TRUE); +} + +/* When configuring a server cert, we should save the RSA key in case it is + * needed for self-encryption. This saves the latest copy, unless there has + * been an explicit call to SSL_SetSessionTicketKeyPair(). */ +SECStatus +ssl_MaybeSetSelfEncryptKeyPair(const sslKeyPair *keyPair) +{ + PRBool configured; + + if (PR_SUCCESS != PR_CallOnce(&ssl_self_encrypt_key_pair.setup, + &ssl_SelfEncryptSetup)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + PR_RWLock_Rlock(ssl_self_encrypt_key_pair.lock); + configured = ssl_self_encrypt_key_pair.configured; + PR_RWLock_Unlock(ssl_self_encrypt_key_pair.lock); + if (configured) { + return SECSuccess; + } + return ssl_SetSelfEncryptKeyPair(keyPair->pubKey, + keyPair->privKey, PR_FALSE); +} + +static SECStatus +ssl_GetSelfEncryptKeyPair(SECKEYPublicKey **pubKey, + SECKEYPrivateKey **privKey) +{ + if (PR_SUCCESS != PR_CallOnce(&ssl_self_encrypt_key_pair.setup, + &ssl_SelfEncryptSetup)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + PR_RWLock_Rlock(ssl_self_encrypt_key_pair.lock); + *pubKey = ssl_self_encrypt_key_pair.pubKey; + *privKey = ssl_self_encrypt_key_pair.privKey; + PR_RWLock_Unlock(ssl_self_encrypt_key_pair.lock); + if (!*pubKey) { + PORT_Assert(!*privKey); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + PORT_Assert(*privKey); + return SECSuccess; +} + static PRBool -getSvrWrappingKey(PRInt32 symWrapMechIndex, - SSLAuthType authType, +ssl_GenerateSelfEncryptKeys(void *pwArg, PRUint8 *keyName, + PK11SymKey **aesKey, PK11SymKey **macKey); + +static PRStatus +ssl_GenerateSelfEncryptKeysOnce(void *arg) +{ + SECStatus rv; + + /* Get a copy of the session keys from shared memory. */ + PORT_Memcpy(ssl_self_encrypt_keys.keyName, + SELF_ENCRYPT_KEY_NAME_PREFIX, + sizeof(SELF_ENCRYPT_KEY_NAME_PREFIX)); + /* This function calls ssl_GetSelfEncryptKeyPair(), which initializes the + * key pair stuff. That allows this to use the same shutdown function. */ + rv = ssl_GenerateSelfEncryptKeys(arg, ssl_self_encrypt_keys.keyName, + &ssl_self_encrypt_keys.encKey, + &ssl_self_encrypt_keys.macKey); + if (rv != SECSuccess) { + return PR_FAILURE; + } + + return PR_SUCCESS; +} + +SECStatus +ssl_GetSelfEncryptKeys(sslSocket *ss, PRUint8 *keyName, + PK11SymKey **encKey, PK11SymKey **macKey) +{ + if (PR_SUCCESS != PR_CallOnceWithArg(&ssl_self_encrypt_keys.setup, + &ssl_GenerateSelfEncryptKeysOnce, + ss->pkcs11PinArg)) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + if (!ssl_self_encrypt_keys.encKey || !ssl_self_encrypt_keys.macKey) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + PORT_Memcpy(keyName, ssl_self_encrypt_keys.keyName, + sizeof(ssl_self_encrypt_keys.keyName)); + *encKey = ssl_self_encrypt_keys.encKey; + *macKey = ssl_self_encrypt_keys.macKey; + return SECSuccess; +} + +/* If lockTime is zero, it implies that the lock is not held, and must be + * aquired here. + */ +static SECStatus +getSvrWrappingKey(unsigned int symWrapMechIndex, + unsigned int wrapKeyIndex, SSLWrappedSymWrappingKey *wswk, cacheDesc *cache, PRUint32 lockTime) { - PRUint32 ndx = (authType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; + PRUint32 ndx = (wrapKeyIndex * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; SSLWrappedSymWrappingKey *pwswk = cache->keyCacheData + ndx; PRUint32 now = 0; - PRBool rv = PR_FALSE; + PRBool rv = SECFailure; if (!cache->cacheMem) { /* cache is uninitialized */ PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED); - return rv; + return SECFailure; } if (!lockTime) { - lockTime = now = LockSidCacheLock(cache->keyCacheLock, now); - if (!lockTime) { - return rv; + now = LockSidCacheLock(cache->keyCacheLock, 0); + if (!now) { + return SECFailure; } } - if (pwswk->authType == authType && - pwswk->symWrapMechIndex == symWrapMechIndex && + if (pwswk->wrapKeyIndex == wrapKeyIndex && + pwswk->wrapMechIndex == symWrapMechIndex && pwswk->wrappedSymKeyLen != 0) { *wswk = *pwswk; - rv = PR_TRUE; + rv = SECSuccess; } if (now) { UnlockSidCacheLock(cache->keyCacheLock); @@ -1645,30 +1861,27 @@ getSvrWrappingKey(PRInt32 symWrapMechIndex, return rv; } -PRBool -ssl_GetWrappingKey(PRInt32 symWrapMechIndex, - SSLAuthType authType, +SECStatus +ssl_GetWrappingKey(unsigned int wrapMechIndex, + unsigned int wrapKeyIndex, SSLWrappedSymWrappingKey *wswk) { - PRBool rv; - - PORT_Assert((unsigned)authType < ssl_auth_size); - PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); - if ((unsigned)authType < ssl_auth_size && - (unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS) { - rv = getSvrWrappingKey(symWrapMechIndex, authType, wswk, - &globalCache, 0); - } else { - rv = PR_FALSE; + PORT_Assert(wrapMechIndex < SSL_NUM_WRAP_MECHS); + PORT_Assert(wrapKeyIndex < SSL_NUM_WRAP_KEYS); + if (wrapMechIndex >= SSL_NUM_WRAP_MECHS || + wrapKeyIndex >= SSL_NUM_WRAP_KEYS) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; } - return rv; + return getSvrWrappingKey(wrapMechIndex, wrapKeyIndex, wswk, + &globalCache, 0); } /* Wrap and cache a session ticket key. */ -static PRBool -WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey, - const char *keyName, encKeyCacheEntry *cacheEntry) +static SECStatus +WrapSelfEncryptKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey, + const char *keyName, encKeyCacheEntry *cacheEntry) { SECItem wrappedKey = { siBuffer, NULL, 0 }; @@ -1680,24 +1893,24 @@ WrapTicketKey(SECKEYPublicKey *svrPubKey, PK11SymKey *symKey, if (PK11_PubWrapSymKey(CKM_RSA_PKCS, svrPubKey, symKey, &wrappedKey) != SECSuccess) { - SSL_DBG(("%d: SSL[%s]: Unable to wrap session ticket %s.", + SSL_DBG(("%d: SSL[%s]: Unable to wrap self encrypt key %s.", SSL_GETPID(), "unknown", keyName)); - return PR_FALSE; + return SECFailure; } cacheEntry->length = wrappedKey.len; - return PR_TRUE; + return SECSuccess; } -static PRBool -GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey, - PK11SymKey **macKey) +static SECStatus +GenerateSelfEncryptKeys(void *pwArg, PRUint8 *keyName, PK11SymKey **aesKey, + PK11SymKey **macKey) { PK11SlotInfo *slot; CK_MECHANISM_TYPE mechanismArray[2]; PK11SymKey *aesKeyTmp = NULL; PK11SymKey *macKeyTmp = NULL; cacheDesc *cache = &globalCache; - PRUint8 ticketKeyNameSuffixLocal[SESS_TICKET_KEY_VAR_NAME_LEN]; + PRUint8 ticketKeyNameSuffixLocal[SELF_ENCRYPT_KEY_VAR_NAME_LEN]; PRUint8 *ticketKeyNameSuffix; if (!cache->cacheMem) { @@ -1708,11 +1921,11 @@ GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey, } if (PK11_GenerateRandom(ticketKeyNameSuffix, - SESS_TICKET_KEY_VAR_NAME_LEN) != + SELF_ENCRYPT_KEY_VAR_NAME_LEN) != SECSuccess) { SSL_DBG(("%d: SSL[%s]: Unable to generate random key name bytes.", SSL_GETPID(), "unknown")); - goto loser; + return SECFailure; } mechanismArray[0] = CKM_AES_CBC; @@ -1732,54 +1945,58 @@ GenerateTicketKeys(void *pwArg, unsigned char *keyName, PK11SymKey **aesKey, SSL_GETPID(), "unknown")); goto loser; } - PORT_Memcpy(keyName, ticketKeyNameSuffix, SESS_TICKET_KEY_VAR_NAME_LEN); + PORT_Memcpy(keyName, ticketKeyNameSuffix, SELF_ENCRYPT_KEY_VAR_NAME_LEN); *aesKey = aesKeyTmp; *macKey = macKeyTmp; - return PR_TRUE; + return SECSuccess; loser: if (aesKeyTmp) PK11_FreeSymKey(aesKeyTmp); if (macKeyTmp) PK11_FreeSymKey(macKeyTmp); - return PR_FALSE; + return SECFailure; } -static PRBool -GenerateAndWrapTicketKeys(SECKEYPublicKey *svrPubKey, void *pwArg, - unsigned char *keyName, PK11SymKey **aesKey, - PK11SymKey **macKey) +static SECStatus +GenerateAndWrapSelfEncryptKeys(SECKEYPublicKey *svrPubKey, void *pwArg, + PRUint8 *keyName, PK11SymKey **aesKey, + PK11SymKey **macKey) { PK11SymKey *aesKeyTmp = NULL; PK11SymKey *macKeyTmp = NULL; cacheDesc *cache = &globalCache; + SECStatus rv; - if (!GenerateTicketKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp)) { - goto loser; + rv = GenerateSelfEncryptKeys(pwArg, keyName, &aesKeyTmp, &macKeyTmp); + if (rv != SECSuccess) { + return SECFailure; } if (cache->cacheMem) { /* Export the keys to the shared cache in wrapped form. */ - if (!WrapTicketKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey)) + rv = WrapSelfEncryptKey(svrPubKey, aesKeyTmp, "enc key", cache->ticketEncKey); + if (rv != SECSuccess) { goto loser; - if (!WrapTicketKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey)) + } + rv = WrapSelfEncryptKey(svrPubKey, macKeyTmp, "mac key", cache->ticketMacKey); + if (rv != SECSuccess) { goto loser; + } } *aesKey = aesKeyTmp; *macKey = macKeyTmp; - return PR_TRUE; + return SECSuccess; loser: - if (aesKeyTmp) - PK11_FreeSymKey(aesKeyTmp); - if (macKeyTmp) - PK11_FreeSymKey(macKeyTmp); - return PR_FALSE; + PK11_FreeSymKey(aesKeyTmp); + PK11_FreeSymKey(macKeyTmp); + return SECFailure; } -static PRBool -UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName, - PK11SymKey **aesKey, PK11SymKey **macKey) +static SECStatus +UnwrapCachedSelfEncryptKeys(SECKEYPrivateKey *svrPrivKey, PRUint8 *keyName, + PK11SymKey **aesKey, PK11SymKey **macKey) { SECItem wrappedKey = { siBuffer, NULL, 0 }; PK11SymKey *aesKeyTmp = NULL; @@ -1807,55 +2024,51 @@ UnwrapCachedTicketKeys(SECKEYPrivateKey *svrPrivKey, unsigned char *keyName, SSL_GETPID(), "unknown")); PORT_Memcpy(keyName, cache->ticketKeyNameSuffix, - SESS_TICKET_KEY_VAR_NAME_LEN); + SELF_ENCRYPT_KEY_VAR_NAME_LEN); *aesKey = aesKeyTmp; *macKey = macKeyTmp; - return PR_TRUE; + return SECSuccess; loser: if (aesKeyTmp) PK11_FreeSymKey(aesKeyTmp); if (macKeyTmp) PK11_FreeSymKey(macKeyTmp); - return PR_FALSE; + return SECFailure; } -PRBool -ssl_GetSessionTicketKeys(SECKEYPrivateKey *svrPrivKey, - SECKEYPublicKey *svrPubKey, void *pwArg, - unsigned char *keyName, PK11SymKey **aesKey, - PK11SymKey **macKey) +static SECStatus +ssl_GenerateSelfEncryptKeys(void *pwArg, PRUint8 *keyName, + PK11SymKey **encKey, PK11SymKey **macKey) { - PRUint32 now = 0; - PRBool rv = PR_FALSE; - PRBool keysGenerated = PR_FALSE; + SECKEYPrivateKey *svrPrivKey; + SECKEYPublicKey *svrPubKey; + PRUint32 now; + SECStatus rv; cacheDesc *cache = &globalCache; - if (!cache->cacheMem) { - /* cache is uninitialized. Generate keys and return them - * without caching. */ - return GenerateTicketKeys(pwArg, keyName, aesKey, macKey); + rv = ssl_GetSelfEncryptKeyPair(&svrPubKey, &svrPrivKey); + if (rv != SECSuccess || !cache->cacheMem) { + /* No key pair for wrapping, or the cache is uninitialized. Generate + * keys and return them without caching. */ + return GenerateSelfEncryptKeys(pwArg, keyName, encKey, macKey); } - now = LockSidCacheLock(cache->keyCacheLock, now); + now = LockSidCacheLock(cache->keyCacheLock, 0); if (!now) - return rv; + return SECFailure; - if (!*(cache->ticketKeysValid)) { + if (*(cache->ticketKeysValid)) { + rv = UnwrapCachedSelfEncryptKeys(svrPrivKey, keyName, encKey, macKey); + } else { /* Keys do not exist, create them. */ - if (!GenerateAndWrapTicketKeys(svrPubKey, pwArg, keyName, - aesKey, macKey)) - goto loser; - keysGenerated = PR_TRUE; - *(cache->ticketKeysValid) = 1; + rv = GenerateAndWrapSelfEncryptKeys(svrPubKey, pwArg, keyName, + encKey, macKey); + if (rv == SECSuccess) { + *(cache->ticketKeysValid) = 1; + } } - - rv = PR_TRUE; - -loser: UnlockSidCacheLock(cache->keyCacheLock); - if (rv && !keysGenerated) - rv = UnwrapCachedTicketKeys(svrPrivKey, keyName, aesKey, macKey); return rv; } @@ -1868,47 +2081,45 @@ loser: * This is all done while holding the locks/mutexes necessary to make * the operation atomic. */ -PRBool +SECStatus ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) { cacheDesc *cache = &globalCache; - PRBool rv = PR_FALSE; - SSLAuthType authType = wswk->authType; - /* type of keys used to wrap SymWrapKey*/ - PRInt32 symWrapMechIndex = wswk->symWrapMechIndex; + PRBool rv = SECFailure; PRUint32 ndx; - PRUint32 now = 0; + PRUint32 now; SSLWrappedSymWrappingKey myWswk; if (!cache->cacheMem) { /* cache is uninitialized */ PORT_SetError(SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED); - return 0; + return SECFailure; } - PORT_Assert((unsigned)authType < ssl_auth_size); - if ((unsigned)authType >= ssl_auth_size) - return 0; - - PORT_Assert((unsigned)symWrapMechIndex < SSL_NUM_WRAP_MECHS); - if ((unsigned)symWrapMechIndex >= SSL_NUM_WRAP_MECHS) - return 0; + PORT_Assert(wswk->wrapMechIndex < SSL_NUM_WRAP_MECHS); + PORT_Assert(wswk->wrapKeyIndex < SSL_NUM_WRAP_KEYS); + if (wswk->wrapMechIndex >= SSL_NUM_WRAP_MECHS || + wswk->wrapKeyIndex >= SSL_NUM_WRAP_KEYS) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } - ndx = (authType * SSL_NUM_WRAP_MECHS) + symWrapMechIndex; + ndx = (wswk->wrapKeyIndex * SSL_NUM_WRAP_MECHS) + wswk->wrapMechIndex; PORT_Memset(&myWswk, 0, sizeof myWswk); /* eliminate UMRs. */ - now = LockSidCacheLock(cache->keyCacheLock, now); - if (now) { - rv = getSvrWrappingKey(wswk->symWrapMechIndex, wswk->authType, - &myWswk, cache, now); - if (rv) { - /* we found it on disk, copy it out to the caller. */ - PORT_Memcpy(wswk, &myWswk, sizeof *wswk); - } else { - /* Wasn't on disk, and we're still holding the lock, so write it. */ - cache->keyCacheData[ndx] = *wswk; - } - UnlockSidCacheLock(cache->keyCacheLock); + now = LockSidCacheLock(cache->keyCacheLock, 0); + if (!now) { + return SECFailure; + } + rv = getSvrWrappingKey(wswk->wrapMechIndex, wswk->wrapKeyIndex, + &myWswk, cache, now); + if (rv == SECSuccess) { + /* we found it on disk, copy it out to the caller. */ + PORT_Memcpy(wswk, &myWswk, sizeof *wswk); + } else { + /* Wasn't on disk, and we're still holding the lock, so write it. */ + cache->keyCacheData[ndx] = *wswk; } + UnlockSidCacheLock(cache->keyCacheLock); return rv; } @@ -1946,14 +2157,13 @@ SSL_InheritMPServerSIDCache(const char *envString) return SECFailure; } -PRBool -ssl_GetWrappingKey(PRInt32 symWrapMechIndex, - SSLAuthType authType, +SECStatus +ssl_GetWrappingKey(unsigned int wrapMechIndex, + unsigned int wrapKeyIndex, SSLWrappedSymWrappingKey *wswk) { - PRBool rv = PR_FALSE; PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_GetWrappingKey)"); - return rv; + return SECFailure; } /* This is a kind of test-and-set. The caller passes in the new value it wants @@ -1965,12 +2175,11 @@ ssl_GetWrappingKey(PRInt32 symWrapMechIndex, * This is all done while holding the locks/mutexes necessary to make * the operation atomic. */ -PRBool +SECStatus ssl_SetWrappingKey(SSLWrappedSymWrappingKey *wswk) { - PRBool rv = PR_FALSE; PR_ASSERT(!"SSL servers are not supported on this platform. (ssl_SetWrappingKey)"); - return rv; + return SECFailure; } PRUint32 diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c index f089c75e0..99828c85b 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -330,6 +330,10 @@ ssl_DupSocket(sslSocket *os) ss->getClientAuthDataArg = os->getClientAuthDataArg; ss->sniSocketConfig = os->sniSocketConfig; ss->sniSocketConfigArg = os->sniSocketConfigArg; + ss->alertReceivedCallback = os->alertReceivedCallback; + ss->alertReceivedCallbackArg = os->alertReceivedCallbackArg; + ss->alertSentCallback = os->alertSentCallback; + ss->alertSentCallbackArg = os->alertSentCallbackArg; ss->handleBadCert = os->handleBadCert; ss->badCertArg = os->badCertArg; ss->handshakeCallback = os->handshakeCallback; @@ -2148,6 +2152,14 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) ss->sniSocketConfig = sm->sniSocketConfig; if (sm->sniSocketConfigArg) ss->sniSocketConfigArg = sm->sniSocketConfigArg; + if (sm->alertReceivedCallback) { + ss->alertReceivedCallback = sm->alertReceivedCallback; + ss->alertReceivedCallbackArg = sm->alertReceivedCallbackArg; + } + if (sm->alertSentCallback) { + ss->alertSentCallback = sm->alertSentCallback; + ss->alertSentCallbackArg = sm->alertSentCallbackArg; + } if (sm->handleBadCert) ss->handleBadCert = sm->handleBadCert; if (sm->badCertArg) @@ -2161,61 +2173,82 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd) return fd; } -/* - * Get the user supplied range - */ -static SECStatus -ssl3_GetRangePolicy(SSLProtocolVariant protocolVariant, SSLVersionRange *prange) +SECStatus +ssl3_GetEffectiveVersionPolicy(SSLProtocolVariant variant, + SSLVersionRange *effectivePolicy) { SECStatus rv; - PRUint32 policy; - PRInt32 option; + PRUint32 policyFlag; + PRInt32 minPolicy, maxPolicy; - /* only use policy constraints if we've set the apply ssl policy bit */ - rv = NSS_GetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, &policy); - if ((rv != SECSuccess) || !(policy & NSS_USE_POLICY_IN_SSL)) { - return SECFailure; + if (variant == ssl_variant_stream) { + effectivePolicy->min = SSL_LIBRARY_VERSION_MIN_SUPPORTED_STREAM; + effectivePolicy->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED; + } else { + effectivePolicy->min = SSL_LIBRARY_VERSION_MIN_SUPPORTED_DATAGRAM; + effectivePolicy->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED; } - rv = NSS_OptionGet(VERSIONS_POLICY_MIN(protocolVariant), &option); + + rv = NSS_GetAlgorithmPolicy(SEC_OID_APPLY_SSL_POLICY, &policyFlag); + if ((rv != SECSuccess) || !(policyFlag & NSS_USE_POLICY_IN_SSL)) { + /* Policy is not active, report library extents. */ + return SECSuccess; + } + + rv = NSS_OptionGet(VERSIONS_POLICY_MIN(variant), &minPolicy); if (rv != SECSuccess) { - return rv; + return SECFailure; } - prange->min = (PRUint16)option; - rv = NSS_OptionGet(VERSIONS_POLICY_MAX(protocolVariant), &option); + rv = NSS_OptionGet(VERSIONS_POLICY_MAX(variant), &maxPolicy); if (rv != SECSuccess) { - return rv; + return SECFailure; } - prange->max = (PRUint16)option; - if (prange->max < prange->min) { - return SECFailure; /* don't accept an invalid policy */ + + if (minPolicy > effectivePolicy->max || + maxPolicy < effectivePolicy->min || + minPolicy > maxPolicy) { + return SECFailure; } + effectivePolicy->min = PR_MAX(effectivePolicy->min, minPolicy); + effectivePolicy->max = PR_MIN(effectivePolicy->max, maxPolicy); return SECSuccess; } -/* - * Constrain a single protocol variant's range based on the user policy +/* + * Assumes that rangeParam values are within the supported boundaries, + * but should contain all potentially allowed versions, even if they contain + * conflicting versions. + * Will return the overlap, or a NONE range if system policy is invalid. */ static SECStatus -ssl3_ConstrainVariantRangeByPolicy(SSLProtocolVariant protocolVariant) +ssl3_CreateOverlapWithPolicy(SSLProtocolVariant protocolVariant, + SSLVersionRange *input, + SSLVersionRange *overlap) { - SSLVersionRange vrange; - SSLVersionRange pvrange; SECStatus rv; + SSLVersionRange effectivePolicyBoundary; + SSLVersionRange vrange; - vrange = *VERSIONS_DEFAULTS(protocolVariant); - rv = ssl3_GetRangePolicy(protocolVariant, &pvrange); - if (rv != SECSuccess) { - return SECSuccess; /* we don't have any policy */ + PORT_Assert(input != NULL); + + rv = ssl3_GetEffectiveVersionPolicy(protocolVariant, + &effectivePolicyBoundary); + if (rv == SECFailure) { + /* SECFailure means internal failure or invalid configuration. */ + overlap->min = overlap->max = SSL_LIBRARY_VERSION_NONE; + return SECFailure; } - vrange.min = PR_MAX(vrange.min, pvrange.min); - vrange.max = PR_MIN(vrange.max, pvrange.max); - if (vrange.max >= vrange.min) { - *VERSIONS_DEFAULTS(protocolVariant) = vrange; - } else { + + vrange.min = PR_MAX(input->min, effectivePolicyBoundary.min); + vrange.max = PR_MIN(input->max, effectivePolicyBoundary.max); + + if (vrange.max < vrange.min) { /* there was no overlap, turn off range altogether */ - pvrange.min = pvrange.max = SSL_LIBRARY_VERSION_NONE; - *VERSIONS_DEFAULTS(protocolVariant) = pvrange; + overlap->min = overlap->max = SSL_LIBRARY_VERSION_NONE; + return SECFailure; } + + *overlap = vrange; return SECSuccess; } @@ -2223,16 +2256,17 @@ static PRBool ssl_VersionIsSupportedByPolicy(SSLProtocolVariant protocolVariant, SSL3ProtocolVersion version) { - SSLVersionRange pvrange; SECStatus rv; + SSLVersionRange effectivePolicyBoundary; - rv = ssl3_GetRangePolicy(protocolVariant, &pvrange); - if (rv == SECSuccess) { - if ((version > pvrange.max) || (version < pvrange.min)) { - return PR_FALSE; /* disallowed by policy */ - } + rv = ssl3_GetEffectiveVersionPolicy(protocolVariant, + &effectivePolicyBoundary); + if (rv == SECFailure) { + /* SECFailure means internal failure or invalid configuration. */ + return PR_FALSE; } - return PR_TRUE; + return version >= effectivePolicyBoundary.min && + version <= effectivePolicyBoundary.max; } /* @@ -2242,52 +2276,44 @@ ssl_VersionIsSupportedByPolicy(SSLProtocolVariant protocolVariant, SECStatus ssl3_ConstrainRangeByPolicy(void) { - SECStatus rv; - rv = ssl3_ConstrainVariantRangeByPolicy(ssl_variant_stream); - if (rv != SECSuccess) { - return rv; - } - rv = ssl3_ConstrainVariantRangeByPolicy(ssl_variant_datagram); - if (rv != SECSuccess) { - return rv; - } + /* We ignore failures in ssl3_CreateOverlapWithPolicy. Although an empty + * overlap disables all connectivity, it's an allowed state. + */ + ssl3_CreateOverlapWithPolicy(ssl_variant_stream, + VERSIONS_DEFAULTS(ssl_variant_stream), + VERSIONS_DEFAULTS(ssl_variant_stream)); + ssl3_CreateOverlapWithPolicy(ssl_variant_datagram, + VERSIONS_DEFAULTS(ssl_variant_datagram), + VERSIONS_DEFAULTS(ssl_variant_datagram)); return SECSuccess; } PRBool -ssl3_VersionIsSupported(SSLProtocolVariant protocolVariant, - SSL3ProtocolVersion version) +ssl3_VersionIsSupportedByCode(SSLProtocolVariant protocolVariant, + SSL3ProtocolVersion version) { - if (!ssl_VersionIsSupportedByPolicy(protocolVariant, version)) { - return PR_FALSE; - } switch (protocolVariant) { case ssl_variant_stream: - return (version >= SSL_LIBRARY_VERSION_3_0 && + return (version >= SSL_LIBRARY_VERSION_MIN_SUPPORTED_STREAM && version <= SSL_LIBRARY_VERSION_MAX_SUPPORTED); case ssl_variant_datagram: - return (version >= SSL_LIBRARY_VERSION_TLS_1_1 && + return (version >= SSL_LIBRARY_VERSION_MIN_SUPPORTED_DATAGRAM && version <= SSL_LIBRARY_VERSION_MAX_SUPPORTED); - default: - /* Can't get here */ - PORT_Assert(PR_FALSE); - return PR_FALSE; } + + /* Can't get here */ + PORT_Assert(PR_FALSE); + return PR_FALSE; } -/* Returns PR_TRUE if the given version range is valid and -** fully supported; otherwise, returns PR_FALSE. -*/ -static PRBool -ssl3_VersionRangeIsValid(SSLProtocolVariant protocolVariant, - const SSLVersionRange *vrange) +PRBool +ssl3_VersionIsSupported(SSLProtocolVariant protocolVariant, + SSL3ProtocolVersion version) { - return vrange && - vrange->min <= vrange->max && - ssl3_VersionIsSupported(protocolVariant, vrange->min) && - ssl3_VersionIsSupported(protocolVariant, vrange->max) && - (vrange->min > SSL_LIBRARY_VERSION_3_0 || - vrange->max < SSL_LIBRARY_VERSION_TLS_1_3); + if (!ssl_VersionIsSupportedByPolicy(protocolVariant, version)) { + return PR_FALSE; + } + return ssl3_VersionIsSupportedByCode(protocolVariant, version); } const SECItem * @@ -2313,6 +2339,8 @@ SECStatus SSL_VersionRangeGetSupported(SSLProtocolVariant protocolVariant, SSLVersionRange *vrange) { + SECStatus rv; + if (!vrange) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; @@ -2320,15 +2348,15 @@ SSL_VersionRangeGetSupported(SSLProtocolVariant protocolVariant, switch (protocolVariant) { case ssl_variant_stream: - vrange->min = SSL_LIBRARY_VERSION_3_0; + vrange->min = SSL_LIBRARY_VERSION_MIN_SUPPORTED_STREAM; vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED; - // We don't allow SSLv3 and TLSv1.3 together. - if (vrange->max == SSL_LIBRARY_VERSION_TLS_1_3) { - vrange->min = SSL_LIBRARY_VERSION_TLS_1_0; - } + /* We don't allow SSLv3 and TLSv1.3 together. + * However, don't check yet, apply the policy first. + * Because if the effective supported range doesn't use TLS 1.3, + * then we don't need to increase the minimum. */ break; case ssl_variant_datagram: - vrange->min = SSL_LIBRARY_VERSION_TLS_1_1; + vrange->min = SSL_LIBRARY_VERSION_MIN_SUPPORTED_DATAGRAM; vrange->max = SSL_LIBRARY_VERSION_MAX_SUPPORTED; break; default: @@ -2336,6 +2364,17 @@ SSL_VersionRangeGetSupported(SSLProtocolVariant protocolVariant, return SECFailure; } + rv = ssl3_CreateOverlapWithPolicy(protocolVariant, vrange, vrange); + if (rv != SECSuccess) { + /* Library default and policy don't overlap. */ + return rv; + } + + /* We don't allow SSLv3 and TLSv1.3 together */ + if (vrange->max >= SSL_LIBRARY_VERSION_TLS_1_3) { + vrange->min = PR_MAX(vrange->min, SSL_LIBRARY_VERSION_TLS_1_0); + } + return SECSuccess; } @@ -2351,6 +2390,43 @@ SSL_VersionRangeGetDefault(SSLProtocolVariant protocolVariant, } *vrange = *VERSIONS_DEFAULTS(protocolVariant); + return ssl3_CreateOverlapWithPolicy(protocolVariant, vrange, vrange); +} + +static PRBool +ssl3_HasConflictingSSLVersions(const SSLVersionRange *vrange) +{ + return (vrange->min <= SSL_LIBRARY_VERSION_3_0 && + vrange->max >= SSL_LIBRARY_VERSION_TLS_1_3); +} + +static SECStatus +ssl3_CheckRangeValidAndConstrainByPolicy(SSLProtocolVariant protocolVariant, + SSLVersionRange *vrange) +{ + SECStatus rv; + + if (vrange->min > vrange->max || + !ssl3_VersionIsSupportedByCode(protocolVariant, vrange->min) || + !ssl3_VersionIsSupportedByCode(protocolVariant, vrange->max) || + ssl3_HasConflictingSSLVersions(vrange)) { + PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE); + return SECFailure; + } + + /* Try to adjust the received range using our policy. + * If there's overlap, we'll use the (possibly reduced) range. + * If there isn't overlap, it's failure. */ + + rv = ssl3_CreateOverlapWithPolicy(protocolVariant, vrange, vrange); + if (rv != SECSuccess) { + return rv; + } + + /* We don't allow SSLv3 and TLSv1.3 together */ + if (vrange->max >= SSL_LIBRARY_VERSION_TLS_1_3) { + vrange->min = PR_MAX(vrange->min, SSL_LIBRARY_VERSION_TLS_1_0); + } return SECSuccess; } @@ -2359,13 +2435,21 @@ SECStatus SSL_VersionRangeSetDefault(SSLProtocolVariant protocolVariant, const SSLVersionRange *vrange) { - if (!ssl3_VersionRangeIsValid(protocolVariant, vrange)) { - PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE); + SSLVersionRange constrainedRange; + SECStatus rv; + + if (!vrange) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } - *VERSIONS_DEFAULTS(protocolVariant) = *vrange; + constrainedRange = *vrange; + rv = ssl3_CheckRangeValidAndConstrainByPolicy(protocolVariant, + &constrainedRange); + if (rv != SECSuccess) + return rv; + *VERSIONS_DEFAULTS(protocolVariant) = constrainedRange; return SECSuccess; } @@ -2393,24 +2477,33 @@ SSL_VersionRangeGet(PRFileDesc *fd, SSLVersionRange *vrange) ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); - return SECSuccess; + return ssl3_CreateOverlapWithPolicy(ss->protocolVariant, vrange, vrange); } SECStatus SSL_VersionRangeSet(PRFileDesc *fd, const SSLVersionRange *vrange) { - sslSocket *ss = ssl_FindSocket(fd); + SSLVersionRange constrainedRange; + sslSocket *ss; + SECStatus rv; + + if (!vrange) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + ss = ssl_FindSocket(fd); if (!ss) { SSL_DBG(("%d: SSL[%d]: bad socket in SSL_VersionRangeSet", SSL_GETPID(), fd)); return SECFailure; } - if (!ssl3_VersionRangeIsValid(ss->protocolVariant, vrange)) { - PORT_SetError(SSL_ERROR_INVALID_VERSION_RANGE); - return SECFailure; - } + constrainedRange = *vrange; + rv = ssl3_CheckRangeValidAndConstrainByPolicy(ss->protocolVariant, + &constrainedRange); + if (rv != SECSuccess) + return rv; ssl_Get1stHandshakeLock(ss); ssl_GetSSL3HandshakeLock(ss); @@ -2423,7 +2516,7 @@ SSL_VersionRangeSet(PRFileDesc *fd, const SSLVersionRange *vrange) return SECFailure; } - ss->vrange = *vrange; + ss->vrange = constrainedRange; ssl_ReleaseSSL3HandshakeLock(ss); ssl_Release1stHandshakeLock(ss); @@ -3672,7 +3765,10 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) ss->opt.noLocks = !makeLocks; ss->vrange = *VERSIONS_DEFAULTS(protocolVariant); ss->protocolVariant = protocolVariant; - + /* Ignore overlap failures, because returning NULL would trigger assertion + * failures elsewhere. We don't want this scenario to be fatal, it's just + * a state where no SSL connectivity is possible. */ + ssl3_CreateOverlapWithPolicy(ss->protocolVariant, &ss->vrange, &ss->vrange); ss->peerID = NULL; ss->rTimeout = PR_INTERVAL_NO_TIMEOUT; ss->wTimeout = PR_INTERVAL_NO_TIMEOUT; @@ -3690,6 +3786,10 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant) ss->sniSocketConfig = NULL; ss->sniSocketConfigArg = NULL; ss->getClientAuthData = NULL; + ss->alertReceivedCallback = NULL; + ss->alertReceivedCallbackArg = NULL; + ss->alertSentCallback = NULL; + ss->alertSentCallbackArg = NULL; ss->handleBadCert = NULL; ss->badCertArg = NULL; ss->pkcs11PinArg = NULL; diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h index 506b78d64..bd9a2ae88 100644 --- a/security/nss/lib/ssl/sslt.h +++ b/security/nss/lib/ssl/sslt.h @@ -298,6 +298,21 @@ typedef struct SSLPreliminaryChannelInfoStr { /* Cipher suite: test (valuesSet & ssl_preinfo_cipher_suite) */ PRUint16 cipherSuite; + /* The following fields were added in NSS 3.29. */ + /* |canSendEarlyData| is true when a 0-RTT is enabled. This can only be + * true after sending the ClientHello and before the handshake completes. + */ + PRBool canSendEarlyData; + + /* The following fields were added in NSS 3.31. */ + /* The number of early data octets that a client is permitted to send on + * this connection. The value will be zero if the connection was not + * resumed or early data is not permitted. For a client, this value only + * has meaning if |canSendEarlyData| is true. For a server, this indicates + * the value that was advertised in the session ticket that was used to + * resume this session. */ + PRUint32 maxEarlyDataSize; + /* When adding new fields to this structure, please document the * NSS version in which they were added. */ } SSLPreliminaryChannelInfo; @@ -395,11 +410,10 @@ typedef enum { /* This is the old name for the supported_groups extensions. */ #define ssl_elliptic_curves_xtn ssl_supported_groups_xtn -/* SSL_MAX_EXTENSIONS doesn't include ssl_padding_xtn. It includes the maximum - * number of extensions that are supported for any single message type. That - * is, a ClientHello; ServerHello and TLS 1.3 NewSessionTicket and - * HelloRetryRequest extensions are smaller. */ -#define SSL_MAX_EXTENSIONS 19 +/* SSL_MAX_EXTENSIONS includes the maximum number of extensions that are + * supported for any single message type. That is, a ClientHello; ServerHello + * and TLS 1.3 NewSessionTicket and HelloRetryRequest extensions have fewer. */ +#define SSL_MAX_EXTENSIONS 20 /* Deprecated */ typedef enum { diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c index c6a584748..560493848 100644 --- a/security/nss/lib/ssl/tls13con.c +++ b/security/nss/lib/ssl/tls13con.c @@ -22,9 +22,10 @@ #include "tls13exthandle.h" typedef enum { - TrafficKeyEarlyApplicationData, - TrafficKeyHandshake, - TrafficKeyApplicationData + TrafficKeyClearText = 0, + TrafficKeyEarlyApplicationData = 1, + TrafficKeyHandshake = 2, + TrafficKeyApplicationData = 3 } TrafficKeyType; typedef enum { @@ -56,17 +57,17 @@ static SECStatus tls13_SendHelloRetryRequest(sslSocket *ss, const sslNamedGroupDef *selectedGroup); static SECStatus tls13_HandleServerKeyShare(sslSocket *ss); -static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b, +static SECStatus tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length); static SECStatus tls13_SendCertificate(sslSocket *ss); static SECStatus tls13_HandleCertificate( - sslSocket *ss, SSL3Opaque *b, PRUint32 length); -static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, + sslSocket *ss, PRUint8 *b, PRUint32 length); +static SECStatus tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length); static SECStatus tls13_SendCertificateVerify(sslSocket *ss, SECKEYPrivateKey *privKey); static SECStatus tls13_HandleCertificateVerify( - sslSocket *ss, SSL3Opaque *b, PRUint32 length, + sslSocket *ss, PRUint8 *b, PRUint32 length, SSL3Hashes *hashes); static SECStatus tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid); @@ -76,7 +77,6 @@ tls13_DeriveSecret(sslSocket *ss, PK11SymKey *key, const char *suffix, const SSL3Hashes *hashes, PK11SymKey **dest); -static void tls13_SetNullCipherSpec(sslSocket *ss, ssl3CipherSpec **specp); static SECStatus tls13_SendEndOfEarlyData(sslSocket *ss); static SECStatus tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey); static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, @@ -84,15 +84,15 @@ static SECStatus tls13_ComputePskBinderHash(sslSocket *ss, SSL3Hashes *hashes); static SECStatus tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message, PK11SymKey *secret, - SSL3Opaque *b, PRUint32 length, + PRUint8 *b, PRUint32 length, const SSL3Hashes *hashes); static SECStatus tls13_ClientHandleFinished(sslSocket *ss, - SSL3Opaque *b, PRUint32 length, + PRUint8 *b, PRUint32 length, const SSL3Hashes *hashes); static SECStatus tls13_ServerHandleFinished(sslSocket *ss, - SSL3Opaque *b, PRUint32 length, + PRUint8 *b, PRUint32 length, const SSL3Hashes *hashes); -static SECStatus tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, +static SECStatus tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length); static SECStatus tls13_ComputeHandshakeHashes(sslSocket *ss, SSL3Hashes *hashes); @@ -132,7 +132,7 @@ const SSL3ProtocolVersion kDtlsRecordVersion = SSL_LIBRARY_VERSION_TLS_1_1; PR_STATIC_ASSERT(SSL_LIBRARY_VERSION_MAX_SUPPORTED <= SSL_LIBRARY_VERSION_TLS_1_3); -/* Use this instead of FATAL_ERROR when an alert isn't possible. */ +/* Use this instead of FATAL_ERROR when no alert shall be sent. */ #define LOG_ERROR(ss, prError) \ do { \ SSL_TRC(3, ("%d: TLS13[%d]: fatal error %d in %s (%s:%d)", \ @@ -163,15 +163,21 @@ static char * tls13_HandshakeState(SSL3WaitState st) { switch (st) { + STATE_CASE(idle_handshake); STATE_CASE(wait_client_hello); STATE_CASE(wait_client_cert); + STATE_CASE(wait_client_key); STATE_CASE(wait_cert_verify); + STATE_CASE(wait_change_cipher); STATE_CASE(wait_finished); STATE_CASE(wait_server_hello); + STATE_CASE(wait_certificate_status); STATE_CASE(wait_server_cert); + STATE_CASE(wait_server_key); STATE_CASE(wait_cert_request); + STATE_CASE(wait_hello_done); + STATE_CASE(wait_new_session_ticket); STATE_CASE(wait_encrypted_extensions); - STATE_CASE(idle_handshake); default: break; } @@ -426,10 +432,7 @@ tls13_SetupClientHello(sslSocket *ss) session_ticket = &sid->u.ssl3.locked.sessionTicket; PORT_Assert(session_ticket && session_ticket->ticket.data); - if (session_ticket->ticket_lifetime_hint == 0 || - (session_ticket->ticket_lifetime_hint + - session_ticket->received_timestamp > - ssl_Time())) { + if (ssl_TicketTimeValid(session_ticket)) { ss->statelessResume = PR_TRUE; } @@ -465,7 +468,7 @@ tls13_SetupClientHello(sslSocket *ss) static SECStatus tls13_ImportDHEKeyShare(sslSocket *ss, SECKEYPublicKey *peerKey, - SSL3Opaque *b, PRUint32 length, + PRUint8 *b, PRUint32 length, SECKEYPublicKey *pubKey) { SECStatus rv; @@ -556,7 +559,7 @@ loser: } SECStatus -tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, SSL3Opaque *b, +tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, SSL3Hashes *hashesPtr) { if (ss->sec.isServer && ss->ssl3.hs.zeroRttIgnore != ssl_0rtt_ignore_none) { @@ -625,13 +628,9 @@ tls13_RecoverWrappedSharedSecret(sslSocket *ss, sslSessionID *sid) hashType = tls13_GetHashForCipherSuite(sid->u.ssl3.cipherSuite); /* If we are the server, we compute the wrapping key, but if we - * are the client, it's coordinates are stored with the ticket. */ + * are the client, its coordinates are stored with the ticket. */ if (ss->sec.isServer) { - const sslServerCert *serverCert; - - serverCert = ssl_FindServerCert(ss, &sid->certType); - PORT_Assert(serverCert); - wrapKey = ssl3_GetWrappingKey(ss, NULL, serverCert, + wrapKey = ssl3_GetWrappingKey(ss, NULL, sid->u.ssl3.masterWrapMech, ss->pkcs11PinArg); } else { @@ -934,7 +933,7 @@ tls13_CanResume(sslSocket *ss, const sslSessionID *sid) * do remember the type of certificate we originally used, so we can locate * it again, provided that the current ssl socket has had its server certs * configured the same as the previous one. */ - sc = ssl_FindServerCert(ss, &sid->certType); + sc = ssl_FindServerCert(ss, sid->authType, sid->namedCurve); if (!sc || !sc->serverCert) { return PR_FALSE; } @@ -943,27 +942,6 @@ tls13_CanResume(sslSocket *ss, const sslSessionID *sid) } static PRBool -tls13_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag) -{ - const unsigned char *data = ss->opt.nextProtoNego.data; - unsigned int length = ss->opt.nextProtoNego.len; - unsigned int offset = 0; - - if (!tag->len) - return PR_TRUE; - - while (offset < length) { - unsigned int taglen = (unsigned int)data[offset]; - if ((taglen == tag->len) && - !PORT_Memcmp(data + offset + 1, tag->data, tag->len)) - return PR_TRUE; - offset += 1 + taglen; - } - - return PR_FALSE; -} - -static PRBool tls13_CanNegotiateZeroRtt(sslSocket *ss, const sslSessionID *sid) { PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_sent); @@ -1158,6 +1136,30 @@ tls13_NegotiateKeyExchange(sslSocket *ss, TLS13KeyShareEntry **clientShare) return SECSuccess; } +SSLAuthType +ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme) +{ + switch (scheme) { + case ssl_sig_rsa_pkcs1_sha1: + case ssl_sig_rsa_pkcs1_sha256: + case ssl_sig_rsa_pkcs1_sha384: + case ssl_sig_rsa_pkcs1_sha512: + /* We report PSS signatures as being just RSA signatures. */ + case ssl_sig_rsa_pss_sha256: + case ssl_sig_rsa_pss_sha384: + case ssl_sig_rsa_pss_sha512: + return ssl_auth_rsa_sign; + case ssl_sig_ecdsa_secp256r1_sha256: + case ssl_sig_ecdsa_secp384r1_sha384: + case ssl_sig_ecdsa_secp521r1_sha512: + case ssl_sig_ecdsa_sha1: + return ssl_auth_ecdsa; + default: + PORT_Assert(0); + } + return ssl_auth_null; +} + SECStatus tls13_SelectServerCert(sslSocket *ss) { @@ -1181,8 +1183,7 @@ tls13_SelectServerCert(sslSocket *ss) cursor = PR_NEXT_LINK(cursor)) { sslServerCert *cert = (sslServerCert *)cursor; - if (cert->certType.authType == ssl_auth_rsa_pss || - cert->certType.authType == ssl_auth_rsa_decrypt) { + if (SSL_CERT_IS_ONLY(cert, ssl_auth_rsa_decrypt)) { continue; } @@ -1195,8 +1196,8 @@ tls13_SelectServerCert(sslSocket *ss) if (rv == SECSuccess) { /* Found one. */ ss->sec.serverCert = cert; - ss->sec.authType = cert->certType.authType; - ss->ssl3.hs.kea_def_mutable.authKeyType = cert->certType.authType; + ss->sec.authType = ss->ssl3.hs.kea_def_mutable.authKeyType = + ssl_SignatureSchemeToAuthType(ss->ssl3.hs.signatureScheme); ss->sec.authKeyBits = cert->serverKeyBits; return SECSuccess; } @@ -1227,8 +1228,6 @@ tls13_NegotiateAuthentication(sslSocket *ss) if (rv != SECSuccess) { return SECFailure; } - ss->ssl3.hs.kea_def_mutable.authKeyType = - ss->sec.serverCert->certType.authType; return SECSuccess; } @@ -1248,16 +1247,6 @@ tls13_HandleClientHelloPart2(sslSocket *ss, if (ssl3_ExtensionNegotiated(ss, ssl_tls13_early_data_xtn)) { ss->ssl3.hs.zeroRttState = ssl_0rtt_sent; - - if (IS_DTLS(ss)) { - /* Save the null spec, which we should be currently reading. We will - * use this when 0-RTT sending is over. */ - ssl_GetSpecReadLock(ss); - ss->ssl3.hs.nullSpec = ss->ssl3.crSpec; - tls13_CipherSpecAddRef(ss->ssl3.hs.nullSpec); - PORT_Assert(ss->ssl3.hs.nullSpec->cipher_def->cipher == cipher_null); - ssl_ReleaseSpecReadLock(ss); - } } #ifndef PARANOID @@ -1340,6 +1329,10 @@ tls13_HandleClientHelloPart2(sslSocket *ss, goto loser; } + ss->sec.serverCert = ssl_FindServerCert(ss, sid->authType, + sid->namedCurve); + PORT_Assert(ss->sec.serverCert); + rv = tls13_RecoverWrappedSharedSecret(ss, sid); if (rv != SECSuccess) { SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok); @@ -1348,12 +1341,11 @@ tls13_HandleClientHelloPart2(sslSocket *ss, } tls13_RestoreCipherInfo(ss, sid); - ss->sec.serverCert = ssl_FindServerCert(ss, &sid->certType); - PORT_Assert(ss->sec.serverCert); ss->sec.localCert = CERT_DupCertificate(ss->sec.serverCert->serverCert); if (sid->peerCert != NULL) { ss->sec.peerCert = CERT_DupCertificate(sid->peerCert); } + ssl3_RegisterExtensionSender( ss, &ss->xtnData, ssl_tls13_pre_shared_key_xtn, tls13_ServerSendPreSharedKeyXtn); @@ -1614,9 +1606,9 @@ static SECStatus tls13_SendCertificateRequest(sslSocket *ss) { SECStatus rv; - int calen; + unsigned int calen; SECItem *names; - int nnames; + unsigned int nnames; SECItem *name; int i; PRUint8 sigSchemes[MAX_SIGNATURE_SCHEMES * 2]; @@ -1632,7 +1624,10 @@ tls13_SendCertificateRequest(sslSocket *ss) return rv; } - ssl3_GetCertificateRequestCAs(ss, &calen, &names, &nnames); + rv = ssl_GetCertificateRequestCAs(ss, &calen, &names, &nnames); + if (rv != SECSuccess) { + return rv; + } length = 1 + 0 /* length byte for empty request context */ + 2 + sigSchemesLength + 2 + calen + 2; @@ -1667,10 +1662,10 @@ tls13_SendCertificateRequest(sslSocket *ss) } SECStatus -tls13_HandleHelloRetryRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +tls13_HandleHelloRetryRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; - PRInt32 tmp; + PRUint32 tmp; SSL3ProtocolVersion version; SSL_TRC(3, ("%d: TLS13[%d]: handle hello retry request", @@ -1700,9 +1695,13 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } if (ss->ssl3.hs.zeroRttState == ssl_0rtt_sent) { - /* Oh well, back to the start. */ - tls13_SetNullCipherSpec(ss, &ss->ssl3.cwSpec); ss->ssl3.hs.zeroRttState = ssl_0rtt_ignored; + /* Restore the null cipher spec for writing. */ + ssl_GetSpecWriteLock(ss); + tls13_CipherSpecRelease(ss->ssl3.cwSpec); + ss->ssl3.cwSpec = ss->ssl3.crSpec; + PORT_Assert(ss->ssl3.cwSpec->cipher_def->cipher == cipher_null); + ssl_ReleaseSpecWriteLock(ss); } else { PORT_Assert(ss->ssl3.hs.zeroRttState == ssl_0rtt_none); } @@ -1719,8 +1718,8 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } /* Extensions. */ - tmp = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (tmp < 0) { + rv = ssl3_ConsumeHandshakeNumber(ss, &tmp, 2, &b, &length); + if (rv != SECSuccess) { return SECFailure; /* error code already set */ } /* Extensions must be non-empty and use the remainder of the message. @@ -1752,13 +1751,13 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } static SECStatus -tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +tls13_HandleCertificateRequest(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; TLS13CertificateRequest *certRequest = NULL; SECItem context = { siBuffer, NULL, 0 }; PLArenaPool *arena; - PRInt32 extensionsLength; + SECItem extensionsData = { siBuffer, NULL, 0 }; SSL_TRC(3, ("%d: TLS13[%d]: handle certificate_request sequence", SSL_GETPID(), ss->fd)); @@ -1805,7 +1804,7 @@ tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) &certRequest->signatureSchemes, &certRequest->signatureSchemeCount, &b, &length); - if (rv != SECSuccess) { + if (rv != SECSuccess || certRequest->signatureSchemeCount == 0) { FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, decode_error); goto loser; @@ -1816,14 +1815,16 @@ tls13_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) if (rv != SECSuccess) goto loser; /* alert already sent */ - /* Verify that the extensions length is correct. */ - extensionsLength = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (extensionsLength < 0) { - goto loser; /* alert already sent */ + /* Verify that the extensions are sane. */ + rv = ssl3_ConsumeHandshakeVariable(ss, &extensionsData, 2, &b, &length); + if (rv != SECSuccess) { + goto loser; } - if (extensionsLength != length) { - FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERT_REQUEST, - illegal_parameter); + + /* Process all the extensions (note: currently a no-op). */ + rv = ssl3_HandleExtensions(ss, &extensionsData.data, &extensionsData.len, + certificate_request); + if (rv != SECSuccess) { goto loser; } @@ -2327,7 +2328,7 @@ tls13_HandleCertificateEntry(sslSocket *ss, SECItem *data, PRBool first, * Caller must hold Handshake and RecvBuf locks. */ static SECStatus -tls13_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +tls13_HandleCertificate(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; SECItem context = { siBuffer, NULL, 0 }; @@ -2758,7 +2759,7 @@ tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type, if ((*specp)->epoch == PR_UINT16_MAX) { return SECFailure; } - spec->epoch = (*specp)->epoch + 1; + spec->epoch = (PRUint16)type; if (!IS_DTLS(ss)) { spec->read_seq_num = spec->write_seq_num = 0; @@ -2770,6 +2771,11 @@ tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type, dtls_InitRecvdRecords(&spec->recvdRecords); } + if (type == TrafficKeyEarlyApplicationData) { + spec->earlyDataRemaining = + ss->sec.ci.sid->u.ssl3.locked.sessionTicket.max_early_data_size; + } + /* Now that we've set almost everything up, finally cut over. */ ssl_GetSpecWriteLock(ss); tls13_CipherSpecRelease(*specp); /* May delete old cipher. */ @@ -2781,6 +2787,10 @@ tls13_SetCipherSpec(sslSocket *ss, TrafficKeyType type, spec->phase, spec->epoch, direction == CipherSpecRead ? "read" : "write")); + if (ss->ssl3.changedCipherSpecFunc) { + ss->ssl3.changedCipherSpecFunc(ss->ssl3.changedCipherSpecArg, + direction == CipherSpecWrite, spec); + } return SECSuccess; } @@ -2929,6 +2939,7 @@ tls13_WriteNonce(ssl3KeyMaterial *keys, for (i = 0; i < 8; ++i) { nonce[4 + i] ^= seqNumBuf[i]; } + PRINT_BUF(50, (NULL, "Nonce", nonce, nonceLen)); } /* Implement the SSLAEADCipher interface defined in sslimpl.h. @@ -3015,10 +3026,10 @@ tls13_ChaCha20Poly1305(ssl3KeyMaterial *keys, PRBool doDecrypt, } static SECStatus -tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +tls13_HandleEncryptedExtensions(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; - PRInt32 innerLength; + PRUint32 innerLength; SECItem oldNpn = { siBuffer, NULL, 0 }; PORT_Assert(ss->opt.noLocks || ssl_HaveRecvBufLock(ss)); @@ -3033,8 +3044,8 @@ tls13_HandleEncryptedExtensions(sslSocket *ss, SSL3Opaque *b, PRUint32 length) return SECFailure; } - innerLength = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); - if (innerLength < 0) { + rv = ssl3_ConsumeHandshakeNumber(ss, &innerLength, 2, &b, &length); + if (rv != SECSuccess) { return SECFailure; /* Alert already sent. */ } if (innerLength != length) { @@ -3227,7 +3238,7 @@ done: * Caller must hold Handshake and RecvBuf locks. */ SECStatus -tls13_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, +tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length, SSL3Hashes *hashes) { SECItem signed_hash = { siBuffer, NULL, 0 }; @@ -3286,16 +3297,7 @@ tls13_HandleCertificateVerify(sslSocket *ss, SSL3Opaque *b, PRUint32 length, /* Set the auth type. */ if (!ss->sec.isServer) { - switch (ssl_SignatureSchemeToKeyType(sigScheme)) { - case rsaKey: - ss->sec.authType = ssl_auth_rsa_sign; - break; - case ecKey: - ss->sec.authType = ssl_auth_ecdsa; - break; - default: - PORT_Assert(PR_FALSE); - } + ss->sec.authType = ssl_SignatureSchemeToAuthType(sigScheme); } /* Request a client certificate now if one was requested. */ @@ -3477,7 +3479,7 @@ tls13_SendFinished(sslSocket *ss, PK11SymKey *baseKey) static SECStatus tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message, PK11SymKey *secret, - SSL3Opaque *b, PRUint32 length, + PRUint8 *b, PRUint32 length, const SSL3Hashes *hashes) { SECStatus rv; @@ -3515,7 +3517,7 @@ tls13_VerifyFinished(sslSocket *ss, SSL3HandshakeType message, } static SECStatus -tls13_ClientHandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, +tls13_ClientHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, const SSL3Hashes *hashes) { SECStatus rv; @@ -3542,7 +3544,7 @@ tls13_ClientHandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, } static SECStatus -tls13_ServerHandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, +tls13_ServerHandleFinished(sslSocket *ss, PRUint8 *b, PRUint32 length, const SSL3Hashes *hashes) { SECStatus rv; @@ -3715,17 +3717,10 @@ tls13_SendClientSecondRound(sslSocket *ss) return SECWouldBlock; } - if (ss->ssl3.hs.zeroRttState != ssl_0rtt_none) { - if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) { - rv = tls13_SendEndOfEarlyData(ss); - if (rv != SECSuccess) { - return SECFailure; /* Error code already set. */ - } - } - if (IS_DTLS(ss) && !ss->ssl3.hs.helloRetry) { - /* Reset the counters so that the next epoch isn't set - * incorrectly. */ - tls13_SetNullCipherSpec(ss, &ss->ssl3.cwSpec); + if (ss->ssl3.hs.zeroRttState == ssl_0rtt_accepted) { + rv = tls13_SendEndOfEarlyData(ss); + if (rv != SECSuccess) { + return SECFailure; /* Error code already set. */ } } @@ -3787,7 +3782,7 @@ tls13_SendClientSecondRound(sslSocket *ss) * } NewSessionTicket; */ -#define MAX_EARLY_DATA_SIZE (2 << 16) /* Arbitrary limit. */ +PRUint32 ssl_max_early_data_size = (2 << 16); /* Arbitrary limit. */ SECStatus tls13_SendNewSessionTicket(sslSocket *ss) @@ -3802,7 +3797,7 @@ tls13_SendNewSessionTicket(sslSocket *ss) ticket.flags |= ticket_allow_early_data; max_early_data_size_len = 8; /* type + len + value. */ } - ticket.ticket_lifetime_hint = TLS_EX_SESS_TICKET_LIFETIME_HINT; + ticket.ticket_lifetime_hint = ssl_ticket_lifetime; rv = ssl3_EncodeSessionTicket(ss, &ticket, &ticket_data); if (rv != SECSuccess) @@ -3821,7 +3816,7 @@ tls13_SendNewSessionTicket(sslSocket *ss) goto loser; /* This is a fixed value. */ - rv = ssl3_AppendHandshakeNumber(ss, TLS_EX_SESS_TICKET_LIFETIME_HINT, 4); + rv = ssl3_AppendHandshakeNumber(ss, ssl_ticket_lifetime, 4); if (rv != SECSuccess) goto loser; @@ -3857,7 +3852,7 @@ tls13_SendNewSessionTicket(sslSocket *ss) if (rv != SECSuccess) goto loser; - rv = ssl3_AppendHandshakeNumber(ss, MAX_EARLY_DATA_SIZE, 4); + rv = ssl3_AppendHandshakeNumber(ss, ssl_max_early_data_size, 4); if (rv != SECSuccess) goto loser; } @@ -3873,10 +3868,9 @@ loser: } static SECStatus -tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length) +tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length) { SECStatus rv; - PRInt32 tmp; PRUint32 utmp; NewSessionTicket ticket = { 0 }; SECItem data; @@ -3896,14 +3890,14 @@ tls13_HandleNewSessionTicket(sslSocket *ss, SSL3Opaque *b, PRUint32 length) return SECFailure; } - ticket.received_timestamp = ssl_Time(); - tmp = ssl3_ConsumeHandshakeNumber(ss, 4, &b, &length); - if (tmp < 0) { + ticket.received_timestamp = PR_Now(); + rv = ssl3_ConsumeHandshakeNumber(ss, &ticket.ticket_lifetime_hint, 4, &b, + &length); + if (rv != SECSuccess) { FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_NEW_SESSION_TICKET, decode_error); return SECFailure; } - ticket.ticket_lifetime_hint = (PRUint32)tmp; ticket.ticket.type = siBuffer; rv = ssl3_ConsumeHandshake(ss, &utmp, sizeof(utmp), @@ -4042,7 +4036,8 @@ tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message) (message == hello_retry_request) || (message == encrypted_extensions) || (message == new_session_ticket) || - (message == certificate)); + (message == certificate) || + (message == certificate_request)); for (i = 0; i < PR_ARRAY_SIZE(KnownExtensions); i++) { if (KnownExtensions[i].ex_value == extension) @@ -4102,11 +4097,33 @@ tls13_FormatAdditionalData(PRUint8 *aad, unsigned int length, PORT_Assert((ptr - aad) == length); } +PRInt32 +tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend) +{ + PRInt32 reduced; + + PORT_Assert(type == content_application_data); + PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3); + PORT_Assert(!ss->firstHsDone); + if (ss->ssl3.cwSpec->epoch != TrafficKeyEarlyApplicationData) { + return toSend; + } + + if (IS_DTLS(ss) && toSend > ss->ssl3.cwSpec->earlyDataRemaining) { + /* Don't split application data records in DTLS. */ + return 0; + } + + reduced = PR_MIN(toSend, ss->ssl3.cwSpec->earlyDataRemaining); + ss->ssl3.cwSpec->earlyDataRemaining -= reduced; + return reduced; +} + SECStatus tls13_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type, - const SSL3Opaque *pIn, + const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf) { @@ -4253,6 +4270,17 @@ tls13_UnprotectRecord(sslSocket *ss, SSL3Ciphertext *cText, sslBuffer *plaintext cText->type = plaintext->buf[plaintext->len - 1]; --plaintext->len; + /* Check that we haven't received too much 0-RTT data. */ + if (crSpec->epoch == TrafficKeyEarlyApplicationData && + cText->type == content_application_data) { + if (plaintext->len > crSpec->earlyDataRemaining) { + *alert = unexpected_message; + PORT_SetError(SSL_ERROR_TOO_MUCH_EARLY_DATA); + return SECFailure; + } + crSpec->earlyDataRemaining -= plaintext->len; + } + SSL_TRC(10, ("%d: TLS13[%d]: %s received record of length=%d type=%d", SSL_GETPID(), ss->fd, SSL_ROLE(ss), @@ -4288,7 +4316,7 @@ tls13_ClientAllow0Rtt(const sslSocket *ss, const sslSessionID *sid) return PR_FALSE; if ((sid->u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) == 0) return PR_FALSE; - return tls13_AlpnTagAllowed(ss, &sid->u.ssl3.alpnSelection); + return ssl_AlpnTagAllowed(ss, &sid->u.ssl3.alpnSelection); } SECStatus @@ -4317,15 +4345,8 @@ tls13_MaybeDo0RTTHandshake(sslSocket *ss) return rv; } - /* Null spec... */ - ssl_GetSpecReadLock(ss); - ss->ssl3.hs.nullSpec = ss->ssl3.cwSpec; - tls13_CipherSpecAddRef(ss->ssl3.hs.nullSpec); - ssl_ReleaseSpecReadLock(ss); - /* Cipher suite already set in tls13_SetupClientHello. */ - ss->ssl3.hs.preliminaryInfo = 0; /* TODO(ekr@rtfm.com) Fill this in. - * bug 1281255. */ + ss->ssl3.hs.preliminaryInfo = 0; rv = tls13_DeriveSecret(ss, ss->ssl3.hs.currentSecret, kHkdfLabelClient, @@ -4366,21 +4387,6 @@ tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len) return len; } -/* 0-RTT data will be followed by a different cipher spec; this resets the - * current spec to the null spec so that the following state can be set as - * though 0-RTT didn't happen. TODO: work out if this is the best plan. */ -static void -tls13_SetNullCipherSpec(sslSocket *ss, ssl3CipherSpec **specp) -{ - PORT_Assert(ss->ssl3.hs.nullSpec); - - ssl_GetSpecWriteLock(ss); - tls13_CipherSpecRelease(*specp); - *specp = ss->ssl3.hs.nullSpec; - ssl_ReleaseSpecWriteLock(ss); - ss->ssl3.hs.nullSpec = NULL; -} - static SECStatus tls13_SendEndOfEarlyData(sslSocket *ss) { @@ -4413,11 +4419,6 @@ tls13_HandleEndOfEarlyData(sslSocket *ss) PORT_Assert(TLS13_IN_HS_STATE(ss, ss->opt.requestCertificate ? wait_client_cert : wait_finished)); - if (IS_DTLS(ss)) { - /* Reset the cipher spec so that the epoch counter is properly reset. */ - tls13_SetNullCipherSpec(ss, &ss->ssl3.crSpec); - } - rv = tls13_SetCipherSpec(ss, TrafficKeyHandshake, CipherSpecRead, PR_FALSE); if (rv != SECSuccess) { diff --git a/security/nss/lib/ssl/tls13con.h b/security/nss/lib/ssl/tls13con.h index c39c62a69..92eb545b0 100644 --- a/security/nss/lib/ssl/tls13con.h +++ b/security/nss/lib/ssl/tls13con.h @@ -45,6 +45,7 @@ void tls13_FatalError(sslSocket *ss, PRErrorCode prError, SSL3AlertDescription desc); SECStatus tls13_SetupClientHello(sslSocket *ss); SECStatus tls13_MaybeDo0RTTHandshake(sslSocket *ss); +PRInt32 tls13_LimitEarlyData(sslSocket *ss, SSL3ContentType type, PRInt32 toSend); PRBool tls13_AllowPskCipher(const sslSocket *ss, const ssl3CipherSuiteDef *cipher_def); PRBool tls13_PskSuiteEnabled(sslSocket *ss); @@ -56,10 +57,10 @@ SECStatus tls13_HandleClientHelloPart2(sslSocket *ss, const SECItem *suites, sslSessionID *sid); SECStatus tls13_HandleServerHelloPart2(sslSocket *ss); -SECStatus tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, SSL3Opaque *b, +SECStatus tls13_HandlePostHelloHandshakeMessage(sslSocket *ss, PRUint8 *b, PRUint32 length, SSL3Hashes *hashesPtr); -SECStatus tls13_HandleHelloRetryRequest(sslSocket *ss, SSL3Opaque *b, +SECStatus tls13_HandleHelloRetryRequest(sslSocket *ss, PRUint8 *b, PRUint32 length); void tls13_DestroyKeyShareEntry(TLS13KeyShareEntry *entry); void tls13_DestroyKeyShares(PRCList *list); @@ -72,7 +73,7 @@ PRBool tls13_ExtensionAllowed(PRUint16 extension, SSL3HandshakeType message); SECStatus tls13_ProtectRecord(sslSocket *ss, ssl3CipherSpec *cwSpec, SSL3ContentType type, - const SSL3Opaque *pIn, + const PRUint8 *pIn, PRUint32 contentLen, sslBuffer *wrBuf); PRInt32 tls13_Read0RttData(sslSocket *ss, void *buf, PRInt32 len); diff --git a/security/nss/lib/ssl/tls13exthandle.c b/security/nss/lib/ssl/tls13exthandle.c index be93b97db..c2ce390ff 100644 --- a/security/nss/lib/ssl/tls13exthandle.c +++ b/security/nss/lib/ssl/tls13exthandle.c @@ -208,13 +208,13 @@ static SECStatus tls13_HandleKeyShareEntry(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data) { SECStatus rv; - PRInt32 group; + PRUint32 group; const sslNamedGroupDef *groupDef; TLS13KeyShareEntry *ks = NULL; SECItem share = { siBuffer, NULL, 0 }; - group = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - if (group < 0) { + rv = ssl3_ExtConsumeHandshakeNumber(ss, &group, 2, &data->data, &data->len); + if (rv != SECSuccess) { PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE); goto loser; } @@ -256,11 +256,10 @@ tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PR PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares)); PORT_Assert(!ss->sec.isServer); + + /* The server must not send this extension when negotiating < TLS 1.3. */ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - /* This can't happen because the extension processing - * code filters out TLS 1.3 extensions when not in - * TLS 1.3 mode. */ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION); return SECFailure; } @@ -285,7 +284,7 @@ SECStatus tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; - PRInt32 tmp; + PRUint32 tmp; const sslNamedGroupDef *group; PORT_Assert(!ss->sec.isServer); @@ -294,8 +293,8 @@ tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData, SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension in HRR", SSL_GETPID(), ss->fd)); - tmp = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - if (tmp < 0) { + rv = ssl3_ExtConsumeHandshakeNumber(ss, &tmp, 2, &data->data, &data->len); + if (rv != SECSuccess) { return SECFailure; /* error code already set */ } if (data->len) { @@ -335,7 +334,7 @@ SECStatus tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { SECStatus rv; - PRInt32 length; + PRUint32 length; PORT_Assert(ss->sec.isServer); PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares)); @@ -349,9 +348,9 @@ tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData, PR /* Redundant length because of TLS encoding (this vector consumes * the entire extension.) */ - length = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, - &data->len); - if (length < 0) + rv = ssl3_ExtConsumeHandshakeNumber(ss, &length, 2, &data->data, + &data->len); + if (rv != SECSuccess) goto loser; if (length != data->len) { /* Check for consistency */ @@ -487,7 +486,7 @@ tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, if (append) { SECStatus rv; - PRUint32 age; + PRTime age; unsigned int prefixLength; PRUint8 binder[TLS13_MAX_FINISHED_SIZE]; unsigned int binderLen; @@ -508,7 +507,8 @@ tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, goto loser; /* Obfuscated age. */ - age = ssl_Time() - session_ticket->received_timestamp; + age = PR_Now() - session_ticket->received_timestamp; + age /= PR_USEC_PER_MSEC; age += session_ticket->ticket_age_add; rv = ssl3_ExtAppendHandshakeNumber(ss, age, 4); if (rv != SECSuccess) @@ -684,18 +684,20 @@ SECStatus tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - PRInt32 index; + PRUint32 index; + SECStatus rv; SSL_TRC(3, ("%d: SSL3[%d]: handle pre_shared_key extension", SSL_GETPID(), ss->fd)); - /* If we are doing < TLS 1.3, then ignore this. */ + /* The server must not send this extension when negotiating < TLS 1.3. */ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { - return SECSuccess; + PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION); + return SECFailure; } - index = ssl3_ExtConsumeHandshakeNumber(ss, 2, &data->data, &data->len); - if (index < 0) + rv = ssl3_ExtConsumeHandshakeNumber(ss, &index, 2, &data->data, &data->len); + if (rv != SECSuccess) return SECFailure; /* This should be the end of the extension. */ @@ -746,10 +748,10 @@ tls13_ClientSendEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, rv = ssl3_ExtAppendHandshakeNumber(ss, 0, 2); if (rv != SECSuccess) return -1; - } - xtnData->advertised[xtnData->numAdvertised++] = - ssl_tls13_early_data_xtn; + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_early_data_xtn; + } return extension_length; } @@ -766,6 +768,12 @@ tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, P return SECSuccess; } + if (ss->ssl3.hs.helloRetry) { + ssl3_ExtSendAlert(ss, alert_fatal, unsupported_extension); + PORT_SetError(SSL_ERROR_RX_UNEXPECTED_EXTENSION); + return SECFailure; + } + if (data->len) { PORT_SetError(SSL_ERROR_MALFORMED_EARLY_DATA); return SECFailure; @@ -814,7 +822,7 @@ tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData, P SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension", SSL_GETPID(), ss->fd)); - /* If we are doing < TLS 1.3, then ignore this. */ + /* The server must not send this extension when negotiating < TLS 1.3. */ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION); return SECFailure; @@ -841,7 +849,7 @@ tls13_ClientHandleTicketEarlyDataInfoXtn(const sslSocket *ss, TLSExtensionData * SSL_TRC(3, ("%d: TLS13[%d]: handle early_data_info extension", SSL_GETPID(), ss->fd)); - /* If we are doing < TLS 1.3, then ignore this. */ + /* The server must not send this extension when negotiating < TLS 1.3. */ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { PORT_SetError(SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION); return SECFailure; @@ -912,6 +920,9 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD if (rv != SECSuccess) return -1; } + + xtnData->advertised[xtnData->numAdvertised++] = + ssl_tls13_supported_versions_xtn; } return extensions_len; @@ -1091,6 +1102,13 @@ tls13_SendShortHeaderXtn(const sslSocket *ss, return 0; } + /* Don't send this if TLS 1.3 isn't at least possible. */ + if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) { + /* This should only happen on the client. */ + PORT_Assert(!ss->sec.isServer); + return 0; + } + SSL_TRC(3, ("%d: TLS13[%d]: send short_header extension", SSL_GETPID(), ss->fd)); @@ -1122,10 +1140,10 @@ tls13_HandleShortHeaderXtn( const sslSocket *ss, TLSExtensionData *xtnData, PRUint16 ex_type, SECItem *data) { - SSL_TRC(3, ("%d: TLS13[%d]: handle early_data extension", + SSL_TRC(3, ("%d: TLS13[%d]: handle short_header extension", SSL_GETPID(), ss->fd)); - /* If we are doing < TLS 1.3, then ignore this. */ + /* The client might have asked for this, but we didn't negotiate TLS 1.3. */ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) { return SECSuccess; } |