summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/ssl/tls13exthandle.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/ssl/tls13exthandle.c')
-rw-r--r--security/nss/lib/ssl/tls13exthandle.c375
1 files changed, 344 insertions, 31 deletions
diff --git a/security/nss/lib/ssl/tls13exthandle.c b/security/nss/lib/ssl/tls13exthandle.c
index 1ab8a8e59..8ed18f69c 100644
--- a/security/nss/lib/ssl/tls13exthandle.c
+++ b/security/nss/lib/ssl/tls13exthandle.c
@@ -12,6 +12,7 @@
#include "pk11pub.h"
#include "ssl3ext.h"
#include "ssl3exthandle.h"
+#include "tls13esni.h"
#include "tls13exthandle.h"
SECStatus
@@ -71,7 +72,7 @@ tls13_ServerSendStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData,
*
* opaque point <1..2^8-1>;
*/
-static PRUint32
+PRUint32
tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey)
{
/* Size = NamedGroup(2) + length(2) + opaque<?> share */
@@ -86,14 +87,14 @@ tls13_SizeOfKeyShareEntry(const SECKEYPublicKey *pubKey)
return 0;
}
-static SECStatus
-tls13_EncodeKeyShareEntry(sslBuffer *buf, const sslEphemeralKeyPair *keyPair)
+SECStatus
+tls13_EncodeKeyShareEntry(sslBuffer *buf, SSLNamedGroup group,
+ SECKEYPublicKey *pubKey)
{
SECStatus rv;
- SECKEYPublicKey *pubKey = keyPair->keys->pubKey;
unsigned int size = tls13_SizeOfKeyShareEntry(pubKey);
- rv = sslBuffer_AppendNumber(buf, keyPair->group->name, 2);
+ rv = sslBuffer_AppendNumber(buf, group, 2);
if (rv != SECSuccess)
return rv;
rv = sslBuffer_AppendNumber(buf, size - 4, 2);
@@ -123,6 +124,7 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
{
SECStatus rv;
PRCList *cursor;
+ unsigned int extStart;
unsigned int lengthOffset;
if (ss->vrange.max < SSL_LIBRARY_VERSION_TLS_1_3) {
@@ -134,6 +136,8 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SSL_TRC(3, ("%d: TLS13[%d]: send client key share xtn",
SSL_GETPID(), ss->fd));
+ extStart = SSL_BUFFER_LEN(buf);
+
/* Save the offset to the length. */
rv = sslBuffer_Skip(buf, 2, &lengthOffset);
if (rv != SECSuccess) {
@@ -144,7 +148,9 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
cursor != &ss->ephemeralKeyPairs;
cursor = PR_NEXT_LINK(cursor)) {
sslEphemeralKeyPair *keyPair = (sslEphemeralKeyPair *)cursor;
- rv = tls13_EncodeKeyShareEntry(buf, keyPair);
+ rv = tls13_EncodeKeyShareEntry(buf,
+ keyPair->group->name,
+ keyPair->keys->pubKey);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -154,50 +160,62 @@ tls13_ClientSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECFailure;
}
+ rv = SECITEM_MakeItem(NULL, &xtnData->keyShareExtension,
+ SSL_BUFFER_BASE(buf) + extStart,
+ SSL_BUFFER_LEN(buf) - extStart);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
*added = PR_TRUE;
return SECSuccess;
}
-static SECStatus
-tls13_HandleKeyShareEntry(const sslSocket *ss, TLSExtensionData *xtnData, SECItem *data)
+SECStatus
+tls13_DecodeKeyShareEntry(sslReader *rdr, TLS13KeyShareEntry **ksp)
{
SECStatus rv;
- PRUint32 group;
+ PRUint64 group;
const sslNamedGroupDef *groupDef;
TLS13KeyShareEntry *ks = NULL;
- SECItem share = { siBuffer, NULL, 0 };
+ sslReadBuffer share;
- rv = ssl3_ExtConsumeHandshakeNumber(ss, &group, 2, &data->data, &data->len);
+ rv = sslRead_ReadNumber(rdr, 2, &group);
if (rv != SECSuccess) {
- PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
goto loser;
}
groupDef = ssl_LookupNamedGroup(group);
- rv = ssl3_ExtConsumeHandshakeVariable(ss, &share, 2, &data->data,
- &data->len);
+ rv = sslRead_ReadVariable(rdr, 2, &share);
if (rv != SECSuccess) {
goto loser;
}
+
+ /* This has to happen here because we want to consume
+ * the entire entry even if the group is unknown
+ * or disabled. */
/* If the group is disabled, continue. */
if (!groupDef) {
return SECSuccess;
}
ks = PORT_ZNew(TLS13KeyShareEntry);
- if (!ks)
+ if (!ks) {
goto loser;
+ }
ks->group = groupDef;
- rv = SECITEM_CopyItem(NULL, &ks->key_exchange, &share);
- if (rv != SECSuccess)
+ rv = SECITEM_MakeItem(NULL, &ks->key_exchange,
+ share.buf, share.len);
+ if (rv != SECSuccess) {
goto loser;
+ }
- PR_APPEND_LINK(&ks->link, &xtnData->remoteKeyShares);
+ *ksp = ks;
return SECSuccess;
loser:
- if (ks)
- tls13_DestroyKeyShareEntry(ks);
+ tls13_DestroyKeyShareEntry(ks);
+
return SECFailure;
}
/* Handle an incoming KeyShare extension at the client and copy to
@@ -209,6 +227,7 @@ tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
{
SECStatus rv;
PORT_Assert(PR_CLIST_IS_EMPTY(&xtnData->remoteKeyShares));
+ TLS13KeyShareEntry *ks = NULL;
PORT_Assert(!ss->sec.isServer);
@@ -221,16 +240,20 @@ tls13_ClientHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SSL_TRC(3, ("%d: SSL3[%d]: handle key_share extension",
SSL_GETPID(), ss->fd));
- rv = tls13_HandleKeyShareEntry(ss, xtnData, data);
- if (rv != SECSuccess) {
+ sslReader rdr = SSL_READER(data->data, data->len);
+ rv = tls13_DecodeKeyShareEntry(&rdr, &ks);
+ if ((rv != SECSuccess) || !ks) {
+ ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
return SECFailure;
}
- if (data->len) {
+ if (SSL_READER_REMAINING(&rdr)) {
+ tls13_DestroyKeyShareEntry(ks);
PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
return SECFailure;
}
+ PR_APPEND_LINK(&ks->link, &xtnData->remoteKeyShares);
return SECSuccess;
}
@@ -273,7 +296,7 @@ tls13_ClientHandleKeyShareXtnHrr(const sslSocket *ss, TLSExtensionData *xtnData,
ssl_FreeEphemeralKeyPairs(CONST_CAST(sslSocket, ss));
/* And replace with our new share. */
- rv = tls13_CreateKeyShare(CONST_CAST(sslSocket, ss), group);
+ rv = tls13_AddKeyShare(CONST_CAST(sslSocket, ss), group);
if (rv != SECSuccess) {
ssl3_ExtSendAlert(ss, alert_fatal, internal_error);
PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
@@ -315,12 +338,24 @@ tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
goto loser;
}
- while (data->len) {
- rv = tls13_HandleKeyShareEntry(ss, xtnData, data);
- if (rv != SECSuccess)
+ sslReader rdr = SSL_READER(data->data, data->len);
+ while (SSL_READER_REMAINING(&rdr)) {
+ TLS13KeyShareEntry *ks = NULL;
+ rv = tls13_DecodeKeyShareEntry(&rdr, &ks);
+ if (rv != SECSuccess) {
+ PORT_SetError(SSL_ERROR_RX_MALFORMED_KEY_SHARE);
goto loser;
+ }
+ if (ks) {
+ /* |ks| == NULL if this is an unknown group. */
+ PR_APPEND_LINK(&ks->link, &xtnData->remoteKeyShares);
+ }
}
+ /* Keep track of negotiated extensions. */
+ xtnData->negotiated[xtnData->numNegotiated++] =
+ ssl_tls13_key_share_xtn;
+
return SECSuccess;
loser:
@@ -342,7 +377,8 @@ tls13_ServerSendKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
keyPair = (sslEphemeralKeyPair *)PR_NEXT_LINK(&ss->ephemeralKeyPairs);
- rv = tls13_EncodeKeyShareEntry(buf, keyPair);
+ rv = tls13_EncodeKeyShareEntry(buf, keyPair->group->name,
+ keyPair->keys->pubKey);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -396,6 +432,7 @@ tls13_ClientSendPreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData,
xtnData->lastXtnOffset = buf->len - 4;
PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3);
+ PORT_Assert(ss->sec.ci.sid->version >= SSL_LIBRARY_VERSION_TLS_1_3);
/* Send a single ticket identity. */
session_ticket = &ss->sec.ci.sid->u.ssl3.locked.sessionTicket;
@@ -751,7 +788,9 @@ tls13_ClientSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD
}
for (version = ss->vrange.max; version >= ss->vrange.min; --version) {
- rv = sslBuffer_AppendNumber(buf, tls13_EncodeDraftVersion(version), 2);
+ PRUint16 wire = tls13_EncodeDraftVersion(version,
+ ss->protocolVariant);
+ rv = sslBuffer_AppendNumber(buf, wire, 2);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -779,8 +818,9 @@ tls13_ServerSendSupportedVersionsXtn(const sslSocket *ss, TLSExtensionData *xtnD
SSL_TRC(3, ("%d: TLS13[%d]: server send supported_versions extension",
SSL_GETPID(), ss->fd));
- rv = sslBuffer_AppendNumber(
- buf, tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3), 2);
+ PRUint16 ver = tls13_EncodeDraftVersion(SSL_LIBRARY_VERSION_TLS_1_3,
+ ss->protocolVariant);
+ rv = sslBuffer_AppendNumber(buf, ver, 2);
if (rv != SECSuccess) {
return SECFailure;
}
@@ -1056,3 +1096,276 @@ tls13_ServerSendHrrCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData,
*added = PR_TRUE;
return SECSuccess;
}
+
+SECStatus
+tls13_ClientSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added)
+{
+ SECStatus rv;
+ PRUint8 sniBuf[1024];
+ PRUint8 hash[64];
+ sslBuffer sni = SSL_BUFFER(sniBuf);
+ const ssl3CipherSuiteDef *suiteDef;
+ ssl3KeyMaterial keyMat;
+ SSLAEADCipher aead;
+ PRUint8 outBuf[1024];
+ int outLen;
+ unsigned int sniStart;
+ unsigned int sniLen;
+ sslBuffer aadInput = SSL_BUFFER_EMPTY;
+ unsigned int keyShareBufStart;
+ unsigned int keyShareBufLen;
+
+ PORT_Memset(&keyMat, 0, sizeof(keyMat));
+
+ if (!ss->xtnData.esniPrivateKey) {
+ return SECSuccess;
+ }
+
+ /* nonce */
+ rv = PK11_GenerateRandom(
+ (unsigned char *)xtnData->esniNonce, sizeof(xtnData->esniNonce));
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ rv = sslBuffer_Append(&sni, xtnData->esniNonce, sizeof(xtnData->esniNonce));
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* sni */
+ sniStart = SSL_BUFFER_LEN(&sni);
+ rv = ssl3_ClientFormatServerNameXtn(ss, ss->url, xtnData, &sni);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ sniLen = SSL_BUFFER_LEN(&sni) - sniStart;
+ /* Padding. */
+ if (ss->esniKeys->paddedLength > sniLen) {
+ unsigned int paddingRequired = ss->esniKeys->paddedLength - sniLen;
+ while (paddingRequired--) {
+ rv = sslBuffer_AppendNumber(&sni, 0, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+ }
+
+ suiteDef = ssl_LookupCipherSuiteDef(xtnData->esniSuite);
+ PORT_Assert(suiteDef);
+ if (!suiteDef) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ aead = tls13_GetAead(ssl_GetBulkCipherDef(suiteDef));
+ if (!aead) {
+ return SECFailure;
+ }
+
+ /* Format the first part of the extension so we have the
+ * encoded KeyShareEntry. */
+ rv = sslBuffer_AppendNumber(buf, xtnData->esniSuite, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ keyShareBufStart = SSL_BUFFER_LEN(buf);
+ rv = tls13_EncodeKeyShareEntry(buf,
+ xtnData->esniPrivateKey->group->name,
+ xtnData->esniPrivateKey->keys->pubKey);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ keyShareBufLen = SSL_BUFFER_LEN(buf) - keyShareBufStart;
+
+ if (tls13_GetHashSizeForHash(suiteDef->prf_hash) > sizeof(hash)) {
+ PORT_Assert(PR_FALSE);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ rv = PK11_HashBuf(ssl3_HashTypeToOID(suiteDef->prf_hash),
+ hash,
+ ss->esniKeys->data.data,
+ ss->esniKeys->data.len);
+ if (rv != SECSuccess) {
+ PORT_Assert(PR_FALSE);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendVariable(buf, hash,
+ tls13_GetHashSizeForHash(suiteDef->prf_hash), 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* Compute the ESNI keys. */
+ rv = tls13_ComputeESNIKeys(ss, xtnData->peerEsniShare,
+ xtnData->esniPrivateKey->keys,
+ suiteDef,
+ hash,
+ SSL_BUFFER_BASE(buf) + keyShareBufStart,
+ keyShareBufLen,
+ CONST_CAST(PRUint8, ss->ssl3.hs.client_random),
+ &keyMat);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = tls13_FormatEsniAADInput(&aadInput,
+ xtnData->keyShareExtension.data,
+ xtnData->keyShareExtension.len);
+ if (rv != SECSuccess) {
+ ssl_DestroyKeyMaterial(&keyMat);
+ return SECFailure;
+ }
+ /* Now encrypt. */
+ rv = aead(&keyMat, PR_FALSE /* Encrypt */,
+ outBuf, &outLen, sizeof(outBuf),
+ SSL_BUFFER_BASE(&sni),
+ SSL_BUFFER_LEN(&sni),
+ SSL_BUFFER_BASE(&aadInput),
+ SSL_BUFFER_LEN(&aadInput));
+ ssl_DestroyKeyMaterial(&keyMat);
+ sslBuffer_Clear(&aadInput);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ /* Encode the rest. */
+ rv = sslBuffer_AppendVariable(buf, outBuf, outLen, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ *added = PR_TRUE;
+ return SECSuccess;
+}
+
+static SECStatus
+tls13_ServerSendEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+ sslBuffer *buf, PRBool *added)
+{
+ SECStatus rv;
+
+ rv = sslBuffer_Append(buf, xtnData->esniNonce, sizeof(xtnData->esniNonce));
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ *added = PR_TRUE;
+ return SECSuccess;
+}
+
+SECStatus
+tls13_ServerHandleEsniXtn(const sslSocket *ss, TLSExtensionData *xtnData,
+ SECItem *data)
+{
+ sslReadBuffer buf;
+ PRUint8 *plainText = NULL;
+ int ptLen;
+ SECStatus rv;
+
+ /* If we are doing < TLS 1.3, then ignore this. */
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ return SECSuccess;
+ }
+
+ if (!ss->esniKeys) {
+ /* Apparently we used to be configured for ESNI, but
+ * no longer. This violates the spec, or the client is
+ * broken. */
+ return SECFailure;
+ }
+
+ plainText = PORT_ZAlloc(data->len);
+ if (!plainText) {
+ return SECFailure;
+ }
+ rv = tls13_ServerDecryptEsniXtn(ss, data->data, data->len,
+ plainText, &ptLen, data->len);
+ if (rv) {
+ goto loser;
+ }
+
+ /* Read out the interior extension. */
+ sslReader sniRdr = SSL_READER(plainText, ptLen);
+
+ rv = sslRead_Read(&sniRdr, sizeof(xtnData->esniNonce), &buf);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ PORT_Memcpy(xtnData->esniNonce, buf.buf, sizeof(xtnData->esniNonce));
+
+ /* We need to capture the whole block with the length. */
+ SECItem sniItem = { siBuffer, (unsigned char *)SSL_READER_CURRENT(&sniRdr), 0 };
+ rv = sslRead_ReadVariable(&sniRdr, 2, &buf);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ sniItem.len = buf.len + 2;
+
+ /* Check the padding. Note we don't need to do this in constant time
+ * because it's inside the AEAD boundary. */
+ /* TODO(ekr@rtfm.com): check that the padding is the right length. */
+ PRUint64 tmp;
+ while (SSL_READER_REMAINING(&sniRdr)) {
+ rv = sslRead_ReadNumber(&sniRdr, 1, &tmp);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ if (tmp != 0) {
+ goto loser;
+ }
+ }
+
+ rv = ssl3_HandleServerNameXtn(ss, xtnData, &sniItem);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ rv = ssl3_RegisterExtensionSender(ss, xtnData,
+ ssl_tls13_encrypted_sni_xtn,
+ tls13_ServerSendEsniXtn);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ /* Keep track of negotiated extensions. */
+ xtnData->negotiated[xtnData->numNegotiated++] =
+ ssl_tls13_encrypted_sni_xtn;
+
+ PORT_ZFree(plainText, data->len);
+ return SECSuccess;
+loser:
+ PORT_ZFree(plainText, data->len);
+ return SECFailure;
+}
+
+/* Function to check the extension. We don't install a handler here
+ * because we need to check for the presence of the extension as
+ * well and it's easier to do it in one place. */
+SECStatus
+tls13_ClientCheckEsniXtn(sslSocket *ss)
+{
+ TLSExtension *esniExtension =
+ ssl3_FindExtension(ss, ssl_tls13_encrypted_sni_xtn);
+ if (!esniExtension) {
+ FATAL_ERROR(ss, SSL_ERROR_MISSING_ESNI_EXTENSION, missing_extension);
+ return SECFailure;
+ }
+
+ if (esniExtension->data.len != sizeof(ss->xtnData.esniNonce)) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, illegal_parameter);
+ return SECFailure;
+ }
+
+ if (0 != NSS_SecureMemcmp(esniExtension->data.data,
+ ss->xtnData.esniNonce,
+ sizeof(ss->xtnData.esniNonce))) {
+ FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_ESNI_EXTENSION, illegal_parameter);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}