diff options
Diffstat (limited to 'security/nss/lib/ssl/tls13replay.c')
-rw-r--r-- | security/nss/lib/ssl/tls13replay.c | 276 |
1 files changed, 0 insertions, 276 deletions
diff --git a/security/nss/lib/ssl/tls13replay.c b/security/nss/lib/ssl/tls13replay.c deleted file mode 100644 index b090f9bca..000000000 --- a/security/nss/lib/ssl/tls13replay.c +++ /dev/null @@ -1,276 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * Anti-replay measures for TLS 1.3. - * - * 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" /* for NSS_RegisterShutdown */ -#include "nssilock.h" /* for PZMonitor */ -#include "pk11pub.h" -#include "prinit.h" /* for PR_CallOnce */ -#include "prmon.h" -#include "prtime.h" -#include "secerr.h" -#include "ssl.h" -#include "sslbloom.h" -#include "sslimpl.h" -#include "tls13hkdf.h" - -static struct { - /* Used to ensure that we only initialize the cleanup function once. */ - PRCallOnceType init; - /* Used to serialize access to the filters. */ - PZMonitor *lock; - /* The filters, use of which alternates. */ - sslBloomFilter filters[2]; - /* Which of the two filters is active (0 or 1). */ - PRUint8 current; - /* The time that we will next update. */ - PRTime nextUpdate; - /* The width of the window; i.e., the period of updates. */ - PRTime window; - /* This key ensures that the bloom filter index is unpredictable. */ - PK11SymKey *key; -} ssl_anti_replay; - -/* Clear the current state and free any resources we allocated. The signature - * here is odd to allow this to be called during shutdown. */ -static SECStatus -tls13_AntiReplayReset(void *appData, void *nssData) -{ - if (ssl_anti_replay.key) { - PK11_FreeSymKey(ssl_anti_replay.key); - ssl_anti_replay.key = NULL; - } - if (ssl_anti_replay.lock) { - PZ_DestroyMonitor(ssl_anti_replay.lock); - ssl_anti_replay.lock = NULL; - } - sslBloom_Destroy(&ssl_anti_replay.filters[0]); - sslBloom_Destroy(&ssl_anti_replay.filters[1]); - return SECSuccess; -} - -static PRStatus -tls13_AntiReplayInit(void) -{ - SECStatus rv = NSS_RegisterShutdown(tls13_AntiReplayReset, NULL); - if (rv != SECSuccess) { - return PR_FAILURE; - } - return PR_SUCCESS; -} - -static SECStatus -tls13_AntiReplayKeyGen() -{ - PRUint8 buf[32]; - SECItem keyItem = { siBuffer, buf, sizeof(buf) }; - PK11SlotInfo *slot; - SECStatus rv; - - slot = PK11_GetInternalSlot(); - if (!slot) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - rv = PK11_GenerateRandomOnSlot(slot, buf, sizeof(buf)); - if (rv != SECSuccess) { - goto loser; - } - - ssl_anti_replay.key = PK11_ImportSymKey(slot, CKM_NSS_HKDF_SHA256, - PK11_OriginUnwrap, CKA_DERIVE, - &keyItem, NULL); - if (!ssl_anti_replay.key) { - goto loser; - } - - PK11_FreeSlot(slot); - return SECSuccess; - -loser: - PK11_FreeSlot(slot); - return SECFailure; -} - -/* Set a limit on the combination of number of hashes and bits in each hash. */ -#define SSL_MAX_BLOOM_FILTER_SIZE 64 - -/* - * The structures created by this function can be called concurrently on - * multiple threads if the server is multi-threaded. A monitor is used to - * ensure that only one thread can access the structures that change over time, - * but no such guarantee is provided for configuration data. - * - * Functions that read from static configuration data depend on there being a - * memory barrier between the setup and use of this function. - */ -SECStatus -SSLExp_SetupAntiReplay(PRTime window, unsigned int k, unsigned int bits) -{ - SECStatus rv; - - if (k == 0 || bits == 0) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - if ((k * (bits + 7) / 8) > SSL_MAX_BLOOM_FILTER_SIZE) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - - if (PR_SUCCESS != PR_CallOnce(&ssl_anti_replay.init, - tls13_AntiReplayInit)) { - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } - - (void)tls13_AntiReplayReset(NULL, NULL); - - ssl_anti_replay.lock = PZ_NewMonitor(nssILockSSL); - if (!ssl_anti_replay.lock) { - goto loser; /* Code already set. */ - } - - rv = tls13_AntiReplayKeyGen(); - if (rv != SECSuccess) { - goto loser; /* Code already set. */ - } - - rv = sslBloom_Init(&ssl_anti_replay.filters[0], k, bits); - if (rv != SECSuccess) { - goto loser; /* Code already set. */ - } - rv = sslBloom_Init(&ssl_anti_replay.filters[1], k, bits); - if (rv != SECSuccess) { - goto loser; /* Code already set. */ - } - /* When starting out, ensure that 0-RTT is not accepted until the window is - * updated. A ClientHello might have been accepted prior to a restart. */ - sslBloom_Fill(&ssl_anti_replay.filters[1]); - - ssl_anti_replay.current = 0; - ssl_anti_replay.nextUpdate = ssl_TimeUsec() + window; - ssl_anti_replay.window = window; - return SECSuccess; - -loser: - (void)tls13_AntiReplayReset(NULL, NULL); - return SECFailure; -} - -/* This is exposed to tests. Though it could, this doesn't take the lock on the - * basis that those tests use thread confinement. */ -void -tls13_AntiReplayRollover(PRTime now) -{ - ssl_anti_replay.current ^= 1; - ssl_anti_replay.nextUpdate = now + ssl_anti_replay.window; - sslBloom_Zero(ssl_anti_replay.filters + ssl_anti_replay.current); -} - -static void -tls13_AntiReplayUpdate() -{ - PRTime now; - - PR_ASSERT_CURRENT_THREAD_IN_MONITOR(ssl_anti_replay.lock); - - now = ssl_TimeUsec(); - if (now < ssl_anti_replay.nextUpdate) { - return; - } - - tls13_AntiReplayRollover(now); -} - -PRBool -tls13_InWindow(const sslSocket *ss, const sslSessionID *sid) -{ - PRInt32 timeDelta; - - /* Calculate the difference between the client's view of the age of the - * ticket (in |ss->xtnData.ticketAge|) and the server's view, which we now - * calculate. The result should be close to zero. timeDelta is signed to - * make the comparisons below easier. */ - timeDelta = ss->xtnData.ticketAge - - ((ssl_TimeUsec() - sid->creationTime) / PR_USEC_PER_MSEC); - - /* Only allow the time delta to be at most half of our window. This is - * symmetrical, though it doesn't need to be; this assumes that clock errors - * on server and client will tend to cancel each other out. - * - * There are two anti-replay filters that roll over each window. In the - * worst case, immediately after a rollover of the filters, we only have a - * single window worth of recorded 0-RTT attempts. Thus, the period in - * which we can accept 0-RTT is at most one window wide. This uses PR_ABS() - * and half the window so that the first attempt can be up to half a window - * early and then replays will be caught until the attempts are half a - * window late. - * - * For example, a 0-RTT attempt arrives early, but near the end of window 1. - * The attempt is then recorded in window 1. Rollover to window 2 could - * occur immediately afterwards. Window 1 is still checked for new 0-RTT - * attempts for the remainder of window 2. Therefore, attempts to replay - * are detected because the value is recorded in window 1. When rollover - * occurs again, window 1 is erased and window 3 instated. If we allowed an - * attempt to be late by more than half a window, then this check would not - * prevent the same 0-RTT attempt from being accepted during window 1 and - * later window 3. - */ - return PR_ABS(timeDelta) < (ssl_anti_replay.window / 2); -} - -/* Checks for a duplicate in the two filters we have. Performs maintenance on - * the filters as a side-effect. This only detects a probable replay, it's - * possible that this will return true when the 0-RTT attempt is not genuinely a - * replay. In that case, we reject 0-RTT unnecessarily, but that's OK because - * no client expects 0-RTT to work every time. */ -PRBool -tls13_IsReplay(const sslSocket *ss, const sslSessionID *sid) -{ - PRBool replay; - unsigned int size; - PRUint8 index; - SECStatus rv; - static const char *label = "tls13 anti-replay"; - PRUint8 buf[SSL_MAX_BLOOM_FILTER_SIZE]; - - /* If SSL_SetupAntiReplay hasn't been called, then treat all attempts at - * 0-RTT as a replay. */ - if (!ssl_anti_replay.init.initialized) { - return PR_TRUE; - } - - if (!tls13_InWindow(ss, sid)) { - return PR_TRUE; - } - - size = ssl_anti_replay.filters[0].k * - (ssl_anti_replay.filters[0].bits + 7) / 8; - PORT_Assert(size <= SSL_MAX_BLOOM_FILTER_SIZE); - rv = tls13_HkdfExpandLabelRaw(ssl_anti_replay.key, ssl_hash_sha256, - ss->xtnData.pskBinder.data, - ss->xtnData.pskBinder.len, - label, strlen(label), - buf, size); - if (rv != SECSuccess) { - return PR_TRUE; - } - - PZ_EnterMonitor(ssl_anti_replay.lock); - tls13_AntiReplayUpdate(); - - index = ssl_anti_replay.current; - replay = sslBloom_Add(&ssl_anti_replay.filters[index], buf); - if (!replay) { - replay = sslBloom_Check(&ssl_anti_replay.filters[index ^ 1], - buf); - } - - PZ_ExitMonitor(ssl_anti_replay.lock); - return replay; -} |