diff options
author | Leander Schwarz <lschwarz@mozilla.com> | 2023-02-15 10:45:12 +0000 |
---|---|---|
committer | Leander Schwarz <lschwarz@mozilla.com> | 2023-02-15 10:45:12 +0000 |
commit | 4e99dc43b543fad63c6565e2a9ddb9f42d6638ff (patch) | |
tree | 00be1e0e4618849f7cd241f741b4ca1f20cc284b /lib | |
parent | 4c1e6ff0d8911b11b607eabcafb9f2b52888481c (diff) | |
download | nss-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.h | 7 | ||||
-rw-r--r-- | lib/ssl/ssl3con.c | 13 | ||||
-rw-r--r-- | lib/ssl/ssl3ext.c | 59 | ||||
-rw-r--r-- | lib/ssl/ssl3ext.h | 2 | ||||
-rw-r--r-- | lib/ssl/sslimpl.h | 4 | ||||
-rw-r--r-- | lib/ssl/sslsecur.c | 2 | ||||
-rw-r--r-- | lib/ssl/sslsock.c | 5 |
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; |