summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorLeander Schwarz <lschwarz@mozilla.com>2023-02-15 10:45:12 +0000
committerLeander Schwarz <lschwarz@mozilla.com>2023-02-15 10:45:12 +0000
commit4e99dc43b543fad63c6565e2a9ddb9f42d6638ff (patch)
tree00be1e0e4618849f7cd241f741b4ca1f20cc284b /lib
parent4c1e6ff0d8911b11b607eabcafb9f2b52888481c (diff)
downloadnss-hg-4e99dc43b543fad63c6565e2a9ddb9f42d6638ff.tar.gz
Bug 1789436 - CH extension permutation. r=djackson
Depends on D161806 Differential Revision: https://phabricator.services.mozilla.com/D163078
Diffstat (limited to 'lib')
-rw-r--r--lib/ssl/ssl.h7
-rw-r--r--lib/ssl/ssl3con.c13
-rw-r--r--lib/ssl/ssl3ext.c59
-rw-r--r--lib/ssl/ssl3ext.h2
-rw-r--r--lib/ssl/sslimpl.h4
-rw-r--r--lib/ssl/sslsecur.c2
-rw-r--r--lib/ssl/sslsock.c5
7 files changed, 91 insertions, 1 deletions
diff --git a/lib/ssl/ssl.h b/lib/ssl/ssl.h
index d2e92b170..fc817a781 100644
--- a/lib/ssl/ssl.h
+++ b/lib/ssl/ssl.h
@@ -373,6 +373,13 @@ SSL_IMPORT PRFileDesc *DTLS_ImportFD(PRFileDesc *model, PRFileDesc *fd);
*/
#define SSL_ENABLE_GREASE 42
+/* Enables TLS ClientHello Extension Permutation.
+ *
+ * On a TLS ClientHello all extensions but the Psk extension
+ * (which MUST be last) will be sent in randomly shuffeld order.
+ */
+#define SSL_ENABLE_CH_EXTENSION_PERMUTATION 43
+
#ifdef SSL_DEPRECATED_FUNCTION
/* Old deprecated function names */
SSL_IMPORT SECStatus SSL_Enable(PRFileDesc *fd, int option, PRIntn on);
diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
index 982d8587b..867c13ee7 100644
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -5532,6 +5532,16 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
}
}
+ /* Setup TLS ClientHello Extension Permutation? */
+ if (type == client_hello_initial &&
+ ss->vrange.max > SSL_LIBRARY_VERSION_3_0 &&
+ ss->opt.enableChXtnPermutation) {
+ rv = tls_ClientHelloExtensionPermutationSetup(ss);
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+ }
+
if (isTLS || (ss->firstHsDone && ss->peerRequestedProtection)) {
rv = ssl_ConstructExtensions(ss, &extensionBuf, ssl_hs_client_hello);
if (rv != SECSuccess) {
@@ -14134,6 +14144,9 @@ ssl3_DestroySSL3Info(sslSocket *ss)
/* TLS 1.3 GREASE (client) state. */
tls13_ClientGreaseDestroy(ss);
+
+ /* TLS ClientHello Extension Permutation state. */
+ tls_ClientHelloExtensionPermutationDestroy(ss);
}
/* check if the current cipher spec is FIPS. We only need to
diff --git a/lib/ssl/ssl3ext.c b/lib/ssl/ssl3ext.c
index 04731115f..c4f9c92d4 100644
--- a/lib/ssl/ssl3ext.c
+++ b/lib/ssl/ssl3ext.c
@@ -760,7 +760,12 @@ ssl_ConstructExtensions(sslSocket *ss, sslBuffer *buf, SSLHandshakeType message)
switch (message) {
case ssl_hs_client_hello:
if (ss->vrange.max > SSL_LIBRARY_VERSION_3_0) {
- sender = clientHelloSendersTLS;
+ /* Use TLS ClientHello Extension Permutation? */
+ if (ss->opt.enableChXtnPermutation) {
+ sender = ss->ssl3.hs.chExtensionPermutation;
+ } else {
+ sender = clientHelloSendersTLS;
+ }
} else {
sender = clientHelloSendersSSL3;
}
@@ -1119,3 +1124,55 @@ ssl3_ExtConsumeHandshakeVariable(const sslSocket *ss, SECItem *i,
{
return ssl3_ConsumeHandshakeVariable((sslSocket *)ss, i, bytes, b, length);
}
+
+SECStatus
+tls_ClientHelloExtensionPermutationSetup(sslSocket *ss)
+{
+ const size_t buildersLen = PR_ARRAY_SIZE(clientHelloSendersTLS);
+ const size_t buildersSize = (sizeof(sslExtensionBuilder) * buildersLen);
+ /* Psk Extension and then NULL entry MUST be last. */
+ const size_t permutationLen = buildersLen - 2;
+
+ sslExtensionBuilder *builders = PORT_Alloc(buildersSize);
+ if (!builders) {
+ return SECFailure;
+ }
+
+ /* Get a working copy of default builders. */
+ PORT_Memcpy(builders, clientHelloSendersTLS, buildersSize);
+
+ /* Get permutation randoms. */
+ uint8_t random[permutationLen];
+ if (PK11_GenerateRandom(random, permutationLen) != SECSuccess) {
+ PORT_Free(builders);
+ return SECFailure;
+ }
+
+ /* Fisher-Yates Shuffle */
+ for (size_t i = permutationLen - 1; i > 0; i--) {
+ size_t idx = random[i - 1] % (i + 1);
+ sslExtensionBuilder tmp = builders[i];
+ builders[i] = builders[idx];
+ builders[idx] = tmp;
+ }
+
+ /* Make sure that Psk extension is penultimate (before NULL entry). */
+ PR_ASSERT(builders[buildersLen - 2].ex_type == ssl_tls13_pre_shared_key_xtn);
+
+ if (ss->ssl3.hs.chExtensionPermutation) {
+ PORT_Free(builders);
+ return SECFailure;
+ }
+ ss->ssl3.hs.chExtensionPermutation = builders;
+
+ return SECSuccess;
+}
+
+void
+tls_ClientHelloExtensionPermutationDestroy(sslSocket *ss)
+{
+ if (ss->ssl3.hs.chExtensionPermutation) {
+ PORT_Free(ss->ssl3.hs.chExtensionPermutation);
+ ss->ssl3.hs.chExtensionPermutation = NULL;
+ }
+}
diff --git a/lib/ssl/ssl3ext.h b/lib/ssl/ssl3ext.h
index 73daffb08..d582e2b2c 100644
--- a/lib/ssl/ssl3ext.h
+++ b/lib/ssl/ssl3ext.h
@@ -206,5 +206,7 @@ SECStatus SSLExp_InstallExtensionHooks(
sslCustomExtensionHooks *ssl_FindCustomExtensionHooks(sslSocket *ss, PRUint16 extension);
SECStatus ssl_CallCustomExtensionSenders(sslSocket *ss, sslBuffer *buf,
SSLHandshakeType message);
+SECStatus tls_ClientHelloExtensionPermutationSetup(sslSocket *ss);
+void tls_ClientHelloExtensionPermutationDestroy(sslSocket *ss);
#endif
diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
index 64c657788..4486d0df5 100644
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -291,6 +291,7 @@ typedef struct sslOptionsStr {
unsigned int enableTls13BackendEch : 1;
unsigned int callExtensionWriterOnEchInner : 1;
unsigned int enableGrease : 1;
+ unsigned int enableChXtnPermutation : 1;
} sslOptions;
typedef enum { sslHandshakingUndetermined = 0,
@@ -784,6 +785,9 @@ typedef struct SSL3HandshakeStateStr {
/* TLS 1.3 GREASE state. */
tls13ClientGrease *grease;
+
+ /* ClientHello Extension Permutation state. */
+ sslExtensionBuilder *chExtensionPermutation;
} SSL3HandshakeState;
#define SSL_ASSERT_HASHES_EMPTY(ss) \
diff --git a/lib/ssl/sslsecur.c b/lib/ssl/sslsecur.c
index 37affd36a..4a0563703 100644
--- a/lib/ssl/sslsecur.c
+++ b/lib/ssl/sslsecur.c
@@ -219,6 +219,8 @@ SSL_ResetHandshake(PRFileDesc *s, PRBool asServer)
tls13_ClientGreaseDestroy(ss);
+ tls_ClientHelloExtensionPermutationDestroy(ss);
+
if (!ss->TCPconnected)
ss->TCPconnected = (PR_SUCCESS == ssl_DefGetpeername(ss, &addr));
diff --git a/lib/ssl/sslsock.c b/lib/ssl/sslsock.c
index 3d1603d92..9a778218a 100644
--- a/lib/ssl/sslsock.c
+++ b/lib/ssl/sslsock.c
@@ -97,6 +97,7 @@ static sslOptions ssl_defaults = {
.enableTls13BackendEch = PR_FALSE,
.callExtensionWriterOnEchInner = PR_FALSE,
.enableGrease = PR_FALSE,
+ .enableChXtnPermutation = PR_FALSE
};
/*
@@ -896,6 +897,10 @@ SSL_OptionSet(PRFileDesc *fd, PRInt32 which, PRIntn val)
ss->opt.enableGrease = val;
break;
+ case SSL_ENABLE_CH_EXTENSION_PERMUTATION:
+ ss->opt.enableChXtnPermutation = val;
+ break;
+
default:
PORT_SetError(SEC_ERROR_INVALID_ARGS);
rv = SECFailure;