summaryrefslogtreecommitdiffstats
path: root/security/nss/lib
diff options
context:
space:
mode:
authorMoonchild <mcwerewolf@gmail.com>2018-06-12 00:58:35 +0200
committerGitHub <noreply@github.com>2018-06-12 00:58:35 +0200
commitb0f5f9bc6bb3c8b5ab7b5120dbf7ec48f8445387 (patch)
tree40d946c5ff23b3c0c09558f478cc68e87cc71448 /security/nss/lib
parentb1d82a62259c6888ea6f3f71f3e0973ea4b4e85e (diff)
parent505a561549b5226fd3c7905eaa61fe787dfad243 (diff)
downloadUXP-b0f5f9bc6bb3c8b5ab7b5120dbf7ec48f8445387.tar
UXP-b0f5f9bc6bb3c8b5ab7b5120dbf7ec48f8445387.tar.gz
UXP-b0f5f9bc6bb3c8b5ab7b5120dbf7ec48f8445387.tar.lz
UXP-b0f5f9bc6bb3c8b5ab7b5120dbf7ec48f8445387.tar.xz
UXP-b0f5f9bc6bb3c8b5ab7b5120dbf7ec48f8445387.zip
Merge pull request #477 from JustOff/PR_nss-3.36
Update NSS/NSPR to 3.36.4/4.19
Diffstat (limited to 'security/nss/lib')
-rw-r--r--security/nss/lib/certdb/stanpcertdb.c15
-rw-r--r--security/nss/lib/dev/devslot.c105
-rw-r--r--security/nss/lib/dev/devt.h14
-rw-r--r--security/nss/lib/dev/devutil.c2
-rw-r--r--security/nss/lib/freebl/Makefile16
-rw-r--r--security/nss/lib/freebl/blapii.h6
-rw-r--r--security/nss/lib/freebl/blinit.c162
-rw-r--r--security/nss/lib/freebl/chacha20.c19
-rw-r--r--security/nss/lib/freebl/chacha20.h26
-rw-r--r--security/nss/lib/freebl/chacha20_vec.c327
-rw-r--r--security/nss/lib/freebl/chacha20poly1305.c51
-rw-r--r--security/nss/lib/freebl/config.mk2
-rw-r--r--security/nss/lib/freebl/det_rng.c4
-rw-r--r--security/nss/lib/freebl/drbg.c15
-rw-r--r--security/nss/lib/freebl/ecl/uint128.c90
-rw-r--r--security/nss/lib/freebl/ecl/uint128.h35
-rw-r--r--security/nss/lib/freebl/freebl.gyp45
-rw-r--r--security/nss/lib/freebl/freebl_base.gypi13
-rw-r--r--security/nss/lib/freebl/lowhash_vector.c75
-rw-r--r--security/nss/lib/freebl/stubs.c8
-rw-r--r--security/nss/lib/freebl/verified/Hacl_Chacha20_Vec128.c390
-rw-r--r--security/nss/lib/freebl/verified/Hacl_Chacha20_Vec128.h61
-rw-r--r--security/nss/lib/freebl/verified/kremlib_base.h1
-rw-r--r--security/nss/lib/freebl/verified/vec128.h345
-rw-r--r--security/nss/lib/nss/nss.h6
-rw-r--r--security/nss/lib/pk11wrap/dev3hack.c4
-rw-r--r--security/nss/lib/pk11wrap/pk11auth.c2
-rw-r--r--security/nss/lib/pk11wrap/secmodi.h1
-rw-r--r--security/nss/lib/pkcs12/p12d.c1
-rw-r--r--security/nss/lib/pkcs7/p7create.c2
-rw-r--r--security/nss/lib/pkcs7/p7decode.c6
-rw-r--r--security/nss/lib/pki/pkibase.c2
-rw-r--r--security/nss/lib/softoken/softkver.h6
-rw-r--r--security/nss/lib/ssl/SSLerrs.h3
-rw-r--r--security/nss/lib/ssl/selfencrypt.c44
-rw-r--r--security/nss/lib/ssl/ssl3con.c180
-rw-r--r--security/nss/lib/ssl/ssl3encode.c85
-rw-r--r--security/nss/lib/ssl/ssl3encode.h26
-rw-r--r--security/nss/lib/ssl/ssl3ext.c2
-rw-r--r--security/nss/lib/ssl/ssl3exthandle.c14
-rw-r--r--security/nss/lib/ssl/ssl3gthr.c7
-rw-r--r--security/nss/lib/ssl/sslcon.c17
-rw-r--r--security/nss/lib/ssl/sslencode.c64
-rw-r--r--security/nss/lib/ssl/sslencode.h30
-rw-r--r--security/nss/lib/ssl/sslerr.h2
-rw-r--r--security/nss/lib/ssl/sslexp.h107
-rw-r--r--security/nss/lib/ssl/sslimpl.h63
-rw-r--r--security/nss/lib/ssl/sslinit.c1
-rw-r--r--security/nss/lib/ssl/sslnonce.c756
-rw-r--r--security/nss/lib/ssl/sslsecur.c5
-rw-r--r--security/nss/lib/ssl/sslsnce.c20
-rw-r--r--security/nss/lib/ssl/sslsock.c231
-rw-r--r--security/nss/lib/ssl/sslt.h24
-rw-r--r--security/nss/lib/ssl/tls13con.c30
-rw-r--r--security/nss/lib/ssl/tls13hashstate.c34
-rw-r--r--security/nss/lib/util/nssutil.h6
-rw-r--r--security/nss/lib/util/secasn1d.c15
57 files changed, 2625 insertions, 998 deletions
diff --git a/security/nss/lib/certdb/stanpcertdb.c b/security/nss/lib/certdb/stanpcertdb.c
index beaa66040..d5d19c39d 100644
--- a/security/nss/lib/certdb/stanpcertdb.c
+++ b/security/nss/lib/certdb/stanpcertdb.c
@@ -30,6 +30,7 @@
#include "pkistore.h"
#include "dev3hack.h"
#include "dev.h"
+#include "secmodi.h"
PRBool
SEC_CertNicknameConflict(const char *nickname, const SECItem *derSubject,
@@ -280,6 +281,18 @@ __CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname,
nssCertificateStore_RemoveCertLOCKED(context->certStore, c);
nssCertificateStore_Unlock(context->certStore, &lockTrace, &unlockTrace);
c->object.cryptoContext = NULL;
+
+ /* if the id has not been set explicitly yet, create one from the public
+ * key. */
+ if (c->id.data == NULL) {
+ SECItem *keyID = pk11_mkcertKeyID(cert);
+ if (keyID) {
+ nssItem_Create(c->object.arena, &c->id, keyID->len, keyID->data);
+ SECITEM_FreeItem(keyID, PR_TRUE);
+ }
+ /* if any of these failed, continue with our null c->id */
+ }
+
/* Import the perm instance onto the internal token */
slot = PK11_GetInternalKeySlot();
internal = PK11Slot_GetNSSToken(slot);
@@ -343,7 +356,7 @@ CERT_NewTempCertificate(CERTCertDBHandle *handle, SECItem *derCert,
/* First, see if it is already a temp cert */
c = NSSCryptoContext_FindCertificateByEncodedCertificate(gCC,
&encoding);
- if (!c) {
+ if (!c && handle) {
/* Then, see if it is already a perm cert */
c = NSSTrustDomain_FindCertificateByEncodedCertificate(handle,
&encoding);
diff --git a/security/nss/lib/dev/devslot.c b/security/nss/lib/dev/devslot.c
index 9f0bd8226..ebd6e6aa5 100644
--- a/security/nss/lib/dev/devslot.c
+++ b/security/nss/lib/dev/devslot.c
@@ -33,6 +33,8 @@ nssSlot_Destroy(
if (PR_ATOMIC_DECREMENT(&slot->base.refCount) == 0) {
PK11_FreeSlot(slot->pk11slot);
PZ_DestroyLock(slot->base.lock);
+ PZ_DestroyCondVar(slot->isPresentCondition);
+ PZ_DestroyLock(slot->isPresentLock);
return nssArena_Destroy(slot->base.arena);
}
}
@@ -88,20 +90,28 @@ NSS_IMPLEMENT void
nssSlot_ResetDelay(
NSSSlot *slot)
{
- slot->lastTokenPing = 0;
+ PZ_Lock(slot->isPresentLock);
+ slot->lastTokenPingState = nssSlotLastPingState_Reset;
+ PZ_Unlock(slot->isPresentLock);
}
static PRBool
-within_token_delay_period(const NSSSlot *slot)
+token_status_checked(const NSSSlot *slot)
{
- PRIntervalTime time, lastTime;
+ PRIntervalTime time;
+ int lastPingState = slot->lastTokenPingState;
+ /* When called from the same thread, that means
+ * nssSlot_IsTokenPresent() is called recursively through
+ * nssSlot_Refresh(). Return immediately in that case. */
+ if (slot->isPresentThread == PR_GetCurrentThread()) {
+ return PR_TRUE;
+ }
/* Set the delay time for checking the token presence */
if (s_token_delay_time == 0) {
s_token_delay_time = PR_SecondsToInterval(NSSSLOT_TOKEN_DELAY_TIME);
}
time = PR_IntervalNow();
- lastTime = slot->lastTokenPing;
- if ((lastTime) && ((time - lastTime) < s_token_delay_time)) {
+ if ((lastPingState == nssSlotLastPingState_Valid) && ((time - slot->lastTokenPingTime) < s_token_delay_time)) {
return PR_TRUE;
}
return PR_FALSE;
@@ -117,35 +127,63 @@ nssSlot_IsTokenPresent(
nssSession *session;
CK_SLOT_INFO slotInfo;
void *epv;
+ PRBool isPresent = PR_FALSE;
+
/* permanent slots are always present unless they're disabled */
if (nssSlot_IsPermanent(slot)) {
return !PK11_IsDisabled(slot->pk11slot);
}
+
/* avoid repeated calls to check token status within set interval */
- if (within_token_delay_period(slot)) {
- return ((slot->ckFlags & CKF_TOKEN_PRESENT) != 0);
+ PZ_Lock(slot->isPresentLock);
+ if (token_status_checked(slot)) {
+ CK_FLAGS ckFlags = slot->ckFlags;
+ PZ_Unlock(slot->isPresentLock);
+ return ((ckFlags & CKF_TOKEN_PRESENT) != 0);
}
+ PZ_Unlock(slot->isPresentLock);
- /* First obtain the slot info */
+ /* First obtain the slot epv before we set up the condition
+ * variable, so we can just return if we couldn't get it. */
epv = slot->epv;
if (!epv) {
return PR_FALSE;
}
+
+ /* set up condition so only one thread is active in this part of the code at a time */
+ PZ_Lock(slot->isPresentLock);
+ while (slot->isPresentThread) {
+ PR_WaitCondVar(slot->isPresentCondition, PR_INTERVAL_NO_TIMEOUT);
+ }
+ /* if we were one of multiple threads here, the first thread will have
+ * given us the answer, no need to make more queries of the token. */
+ if (token_status_checked(slot)) {
+ CK_FLAGS ckFlags = slot->ckFlags;
+ PZ_Unlock(slot->isPresentLock);
+ return ((ckFlags & CKF_TOKEN_PRESENT) != 0);
+ }
+ /* this is the winning thread, block all others until we've determined
+ * if the token is present and that it needs initialization. */
+ slot->lastTokenPingState = nssSlotLastPingState_Update;
+ slot->isPresentThread = PR_GetCurrentThread();
+
+ PZ_Unlock(slot->isPresentLock);
+
nssSlot_EnterMonitor(slot);
ckrv = CKAPI(epv)->C_GetSlotInfo(slot->slotID, &slotInfo);
nssSlot_ExitMonitor(slot);
if (ckrv != CKR_OK) {
slot->token->base.name[0] = 0; /* XXX */
- slot->lastTokenPing = PR_IntervalNow();
- return PR_FALSE;
+ isPresent = PR_FALSE;
+ goto done;
}
slot->ckFlags = slotInfo.flags;
/* check for the presence of the token */
if ((slot->ckFlags & CKF_TOKEN_PRESENT) == 0) {
if (!slot->token) {
/* token was never present */
- slot->lastTokenPing = PR_IntervalNow();
- return PR_FALSE;
+ isPresent = PR_FALSE;
+ goto done;
}
session = nssToken_GetDefaultSession(slot->token);
if (session) {
@@ -167,15 +205,15 @@ nssSlot_IsTokenPresent(
slot->token->base.name[0] = 0; /* XXX */
/* clear the token cache */
nssToken_Remove(slot->token);
- slot->lastTokenPing = PR_IntervalNow();
- return PR_FALSE;
+ isPresent = PR_FALSE;
+ goto done;
}
/* token is present, use the session info to determine if the card
* has been removed and reinserted.
*/
session = nssToken_GetDefaultSession(slot->token);
if (session) {
- PRBool isPresent = PR_FALSE;
+ PRBool tokenRemoved;
nssSession_EnterMonitor(session);
if (session->handle != CK_INVALID_SESSION) {
CK_SESSION_INFO sessionInfo;
@@ -187,12 +225,12 @@ nssSlot_IsTokenPresent(
session->handle = CK_INVALID_SESSION;
}
}
- isPresent = session->handle != CK_INVALID_SESSION;
+ tokenRemoved = (session->handle == CK_INVALID_SESSION);
nssSession_ExitMonitor(session);
/* token not removed, finished */
- if (isPresent) {
- slot->lastTokenPing = PR_IntervalNow();
- return PR_TRUE;
+ if (!tokenRemoved) {
+ isPresent = PR_TRUE;
+ goto done;
}
}
/* the token has been removed, and reinserted, or the slot contains
@@ -203,15 +241,32 @@ nssSlot_IsTokenPresent(
nssToken_Remove(slot->token);
/* token has been removed, need to refresh with new session */
nssrv = nssSlot_Refresh(slot);
+ isPresent = PR_TRUE;
if (nssrv != PR_SUCCESS) {
slot->token->base.name[0] = 0; /* XXX */
slot->ckFlags &= ~CKF_TOKEN_PRESENT;
- /* TODO: insert a barrier here to avoid reordering of the assingments */
- slot->lastTokenPing = PR_IntervalNow();
- return PR_FALSE;
+ isPresent = PR_FALSE;
+ }
+done:
+ /* Once we've set up the condition variable,
+ * Before returning, it's necessary to:
+ * 1) Set the lastTokenPingTime so that any other threads waiting on this
+ * initialization and any future calls within the initialization window
+ * return the just-computed status.
+ * 2) Indicate we're complete, waking up all other threads that may still
+ * be waiting on initialization can progress.
+ */
+ PZ_Lock(slot->isPresentLock);
+ /* don't update the time if we were reset while we were
+ * getting the token state */
+ if (slot->lastTokenPingState == nssSlotLastPingState_Update) {
+ slot->lastTokenPingTime = PR_IntervalNow();
+ slot->lastTokenPingState = nssSlotLastPingState_Valid;
}
- slot->lastTokenPing = PR_IntervalNow();
- return PR_TRUE;
+ slot->isPresentThread = NULL;
+ PR_NotifyAllCondVar(slot->isPresentCondition);
+ PZ_Unlock(slot->isPresentLock);
+ return isPresent;
}
NSS_IMPLEMENT void *
@@ -229,7 +284,7 @@ nssSlot_GetToken(
if (nssSlot_IsTokenPresent(slot)) {
/* Even if a token should be present, check `slot->token` too as it
- * might be gone already. This would happen mostly on shutdown. */
+ * might be gone already. This would happen mostly on shutdown. */
nssSlot_EnterMonitor(slot);
if (slot->token)
rvToken = nssToken_AddRef(slot->token);
diff --git a/security/nss/lib/dev/devt.h b/security/nss/lib/dev/devt.h
index db93deb12..0f6d9e49a 100644
--- a/security/nss/lib/dev/devt.h
+++ b/security/nss/lib/dev/devt.h
@@ -70,6 +70,14 @@ struct nssSlotAuthInfoStr {
PRIntervalTime askPasswordTimeout;
};
+/* values for lastTokenPingState */
+typedef enum {
+ nssSlotLastPingState_Reset = 0, /* the state has just been reset, discard
+ * our cache */
+ nssSlotLastPingState_Update = 1, /* we are updating the lastTokenPingTime */
+ nssSlotLastPingState_Valid = 2, /* lastTokenPingTime is valid */
+} nssSlotLastPingState;
+
struct NSSSlotStr {
struct nssDeviceBaseStr base;
NSSModule *module; /* Parent */
@@ -77,10 +85,14 @@ struct NSSSlotStr {
CK_SLOT_ID slotID;
CK_FLAGS ckFlags; /* from CK_SLOT_INFO.flags */
struct nssSlotAuthInfoStr authInfo;
- PRIntervalTime lastTokenPing;
+ PRIntervalTime lastTokenPingTime;
+ nssSlotLastPingState lastTokenPingState;
PZLock *lock;
void *epv;
PK11SlotInfo *pk11slot;
+ PZLock *isPresentLock;
+ PRCondVar *isPresentCondition;
+ PRThread *isPresentThread;
};
struct nssSessionStr {
diff --git a/security/nss/lib/dev/devutil.c b/security/nss/lib/dev/devutil.c
index 42ce03c97..74c32f088 100644
--- a/security/nss/lib/dev/devutil.c
+++ b/security/nss/lib/dev/devutil.c
@@ -32,7 +32,7 @@ nssCryptokiObject_Create(
/* a failure here indicates a device error */
return (nssCryptokiObject *)NULL;
}
- if (cert_template[0].ulValueLen == 0) {
+ if (cert_template[0].ulValueLen == 0 || !cert_template[0].pValue) {
nss_ZFreeIf(cert_template[1].pValue);
return (nssCryptokiObject *)NULL;
}
diff --git a/security/nss/lib/freebl/Makefile b/security/nss/lib/freebl/Makefile
index 0b3daa275..a4b1a86ae 100644
--- a/security/nss/lib/freebl/Makefile
+++ b/security/nss/lib/freebl/Makefile
@@ -519,18 +519,16 @@ ifndef NSS_DISABLE_CHACHAPOLY
else
EXTRA_SRCS += poly1305.c
endif
-
- ifneq (1,$(CC_IS_GCC))
- EXTRA_SRCS += chacha20.c
- VERIFIED_SRCS += Hacl_Chacha20.c
+ else
+ ifeq ($(CPU_ARCH),aarch64)
+ EXTRA_SRCS += Hacl_Poly1305_64.c
else
- EXTRA_SRCS += chacha20_vec.c
+ EXTRA_SRCS += poly1305.c
endif
- else
- EXTRA_SRCS += poly1305.c
- EXTRA_SRCS += chacha20.c
- VERIFIED_SRCS += Hacl_Chacha20.c
endif # x86_64
+
+ VERIFIED_SRCS += Hacl_Chacha20.c
+ VERIFIED_SRCS += Hacl_Chacha20_Vec128.c
endif # NSS_DISABLE_CHACHAPOLY
ifeq (,$(filter-out i386 x386 x86 x86_64 aarch64,$(CPU_ARCH)))
diff --git a/security/nss/lib/freebl/blapii.h b/security/nss/lib/freebl/blapii.h
index bcf62e9f3..743a1168b 100644
--- a/security/nss/lib/freebl/blapii.h
+++ b/security/nss/lib/freebl/blapii.h
@@ -80,5 +80,11 @@ SECStatus generate_prime(mp_int *prime, int primeLen);
PRBool aesni_support();
PRBool clmul_support();
PRBool avx_support();
+PRBool ssse3_support();
+PRBool arm_neon_support();
+PRBool arm_aes_support();
+PRBool arm_pmull_support();
+PRBool arm_sha1_support();
+PRBool arm_sha2_support();
#endif /* _BLAPII_H_ */
diff --git a/security/nss/lib/freebl/blinit.c b/security/nss/lib/freebl/blinit.c
index d7f2ec53a..f369e62e7 100644
--- a/security/nss/lib/freebl/blinit.c
+++ b/security/nss/lib/freebl/blinit.c
@@ -23,6 +23,12 @@ static PRCallOnceType coFreeblInit;
static PRBool aesni_support_ = PR_FALSE;
static PRBool clmul_support_ = PR_FALSE;
static PRBool avx_support_ = PR_FALSE;
+static PRBool ssse3_support_ = PR_FALSE;
+static PRBool arm_neon_support_ = PR_FALSE;
+static PRBool arm_aes_support_ = PR_FALSE;
+static PRBool arm_sha1_support_ = PR_FALSE;
+static PRBool arm_sha2_support_ = PR_FALSE;
+static PRBool arm_pmull_support_ = PR_FALSE;
#ifdef NSS_X86_OR_X64
/*
@@ -62,6 +68,7 @@ check_xcr0_ymm()
#define ECX_XSAVE (1 << 26)
#define ECX_OSXSAVE (1 << 27)
#define ECX_AVX (1 << 28)
+#define ECX_SSSE3 (1 << 9)
#define AVX_BITS (ECX_XSAVE | ECX_OSXSAVE | ECX_AVX)
void
@@ -71,6 +78,7 @@ CheckX86CPUSupport()
char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES");
char *disable_pclmul = PR_GetEnvSecure("NSS_DISABLE_PCLMUL");
char *disable_avx = PR_GetEnvSecure("NSS_DISABLE_AVX");
+ char *disable_ssse3 = PR_GetEnvSecure("NSS_DISABLE_SSSE3");
freebl_cpuid(1, &eax, &ebx, &ecx, &edx);
aesni_support_ = (PRBool)((ecx & ECX_AESNI) != 0 && disable_hw_aes == NULL);
clmul_support_ = (PRBool)((ecx & ECX_CLMUL) != 0 && disable_pclmul == NULL);
@@ -78,9 +86,131 @@ CheckX86CPUSupport()
* as well as XMM and YMM state. */
avx_support_ = (PRBool)((ecx & AVX_BITS) == AVX_BITS) && check_xcr0_ymm() &&
disable_avx == NULL;
+ ssse3_support_ = (PRBool)((ecx & ECX_SSSE3) != 0 &&
+ disable_ssse3 == NULL);
}
#endif /* NSS_X86_OR_X64 */
+/* clang-format off */
+#if (defined(__aarch64__) || defined(__arm__)) && !defined(__ANDROID__)
+#ifndef __has_include
+#define __has_include(x) 0
+#endif
+#if (__has_include(<sys/auxv.h>) || defined(__linux__)) && \
+ defined(__GNUC__) && __GNUC__ >= 2 && defined(__ELF__)
+#include <sys/auxv.h>
+extern unsigned long getauxval(unsigned long type) __attribute__((weak));
+#else
+static unsigned long (*getauxval)(unsigned long) = NULL;
+#define AT_HWCAP2 0
+#define AT_HWCAP 0
+#endif /* defined(__GNUC__) && __GNUC__ >= 2 && defined(__ELF__)*/
+#endif /* (defined(__aarch64__) || defined(__arm__)) && !defined(__ANDROID__) */
+/* clang-format on */
+
+#if defined(__aarch64__) && !defined(__ANDROID__)
+// Defines from hwcap.h in Linux kernel - ARM64
+#ifndef HWCAP_AES
+#define HWCAP_AES (1 << 3)
+#endif
+#ifndef HWCAP_PMULL
+#define HWCAP_PMULL (1 << 4)
+#endif
+#ifndef HWCAP_SHA1
+#define HWCAP_SHA1 (1 << 5)
+#endif
+#ifndef HWCAP_SHA2
+#define HWCAP_SHA2 (1 << 6)
+#endif
+
+void
+CheckARMSupport()
+{
+ char *disable_arm_neon = PR_GetEnvSecure("NSS_DISABLE_ARM_NEON");
+ char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES");
+ if (getauxval) {
+ long hwcaps = getauxval(AT_HWCAP);
+ arm_aes_support_ = hwcaps & HWCAP_AES && disable_hw_aes == NULL;
+ arm_pmull_support_ = hwcaps & HWCAP_PMULL;
+ arm_sha1_support_ = hwcaps & HWCAP_SHA1;
+ arm_sha2_support_ = hwcaps & HWCAP_SHA2;
+ }
+ /* aarch64 must support NEON. */
+ arm_neon_support_ = disable_arm_neon == NULL;
+}
+#endif /* defined(__aarch64__) && !defined(__ANDROID__) */
+
+#if defined(__arm__) && !defined(__ANDROID__)
+// Defines from hwcap.h in Linux kernel - ARM
+/*
+ * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP
+ */
+#ifndef HWCAP_NEON
+#define HWCAP_NEON (1 << 12)
+#endif
+
+/*
+ * HWCAP2 flags - for elf_hwcap2 (in kernel) and AT_HWCAP2
+ */
+#ifndef HWCAP2_AES
+#define HWCAP2_AES (1 << 0)
+#endif
+#ifndef HWCAP2_PMULL
+#define HWCAP2_PMULL (1 << 1)
+#endif
+#ifndef HWCAP2_SHA1
+#define HWCAP2_SHA1 (1 << 2)
+#endif
+#ifndef HWCAP2_SHA2
+#define HWCAP2_SHA2 (1 << 3)
+#endif
+
+void
+CheckARMSupport()
+{
+ char *disable_arm_neon = PR_GetEnvSecure("NSS_DISABLE_ARM_NEON");
+ char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES");
+ if (getauxval) {
+ long hwcaps = getauxval(AT_HWCAP2);
+ arm_aes_support_ = hwcaps & HWCAP2_AES && disable_hw_aes == NULL;
+ arm_pmull_support_ = hwcaps & HWCAP2_PMULL;
+ arm_sha1_support_ = hwcaps & HWCAP2_SHA1;
+ arm_sha2_support_ = hwcaps & HWCAP2_SHA2;
+ arm_neon_support_ = hwcaps & HWCAP_NEON && disable_arm_neon == NULL;
+ }
+}
+#endif /* defined(__arm__) && !defined(__ANDROID__) */
+
+// Enable when Firefox can use it.
+// #if defined(__ANDROID__) && (defined(__arm__) || defined(__aarch64__))
+// #include <cpu-features.h>
+// void
+// CheckARMSupport()
+// {
+// char *disable_arm_neon = PR_GetEnvSecure("NSS_DISABLE_ARM_NEON");
+// char *disable_hw_aes = PR_GetEnvSecure("NSS_DISABLE_HW_AES");
+// AndroidCpuFamily family = android_getCpuFamily();
+// uint64_t features = android_getCpuFeatures();
+// if (family == ANDROID_CPU_FAMILY_ARM64) {
+// arm_aes_support_ = features & ANDROID_CPU_ARM64_FEATURE_AES &&
+// disable_hw_aes == NULL;
+// arm_pmull_support_ = features & ANDROID_CPU_ARM64_FEATURE_PMULL;
+// arm_sha1_support_ = features & ANDROID_CPU_ARM64_FEATURE_SHA1;
+// arm_sha2_support_ = features & ANDROID_CPU_ARM64_FEATURE_SHA2;
+// arm_neon_support_ = disable_arm_neon == NULL;
+// }
+// if (family == ANDROID_CPU_FAMILY_ARM) {
+// arm_aes_support_ = features & ANDROID_CPU_ARM_FEATURE_AES &&
+// disable_hw_aes == NULL;
+// arm_pmull_support_ = features & ANDROID_CPU_ARM_FEATURE_PMULL;
+// arm_sha1_support_ = features & ANDROID_CPU_ARM_FEATURE_SHA1;
+// arm_sha2_support_ = features & ANDROID_CPU_ARM_FEATURE_SHA2;
+// arm_neon_support_ = hwcaps & ANDROID_CPU_ARM_FEATURE_NEON &&
+// disable_arm_neon == NULL;
+// }
+// }
+// #endif /* defined(__ANDROID__) && (defined(__arm__) || defined(__aarch64__)) */
+
PRBool
aesni_support()
{
@@ -96,12 +226,44 @@ avx_support()
{
return avx_support_;
}
+PRBool
+ssse3_support()
+{
+ return ssse3_support_;
+}
+PRBool
+arm_neon_support()
+{
+ return arm_neon_support_;
+}
+PRBool
+arm_aes_support()
+{
+ return arm_aes_support_;
+}
+PRBool
+arm_pmull_support()
+{
+ return arm_pmull_support_;
+}
+PRBool
+arm_sha1_support()
+{
+ return arm_sha1_support_;
+}
+PRBool
+arm_sha2_support()
+{
+ return arm_sha2_support_;
+}
static PRStatus
FreeblInit(void)
{
#ifdef NSS_X86_OR_X64
CheckX86CPUSupport();
+#elif (defined(__aarch64__) || defined(__arm__)) && !defined(__ANDROID__)
+ CheckARMSupport();
#endif
return PR_SUCCESS;
}
diff --git a/security/nss/lib/freebl/chacha20.c b/security/nss/lib/freebl/chacha20.c
deleted file mode 100644
index 15ed67b5b..000000000
--- a/security/nss/lib/freebl/chacha20.c
+++ /dev/null
@@ -1,19 +0,0 @@
-/* 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/. */
-
-/* Adopted from the public domain code in NaCl by djb. */
-
-#include <string.h>
-#include <stdio.h>
-
-#include "chacha20.h"
-#include "verified/Hacl_Chacha20.h"
-
-void
-ChaCha20XOR(unsigned char *out, const unsigned char *in, unsigned int inLen,
- const unsigned char key[32], const unsigned char nonce[12],
- uint32_t counter)
-{
- Hacl_Chacha20_chacha20(out, (uint8_t *)in, inLen, (uint8_t *)key, (uint8_t *)nonce, counter);
-}
diff --git a/security/nss/lib/freebl/chacha20.h b/security/nss/lib/freebl/chacha20.h
deleted file mode 100644
index 7e396fa8c..000000000
--- a/security/nss/lib/freebl/chacha20.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * chacha20.h - header file for ChaCha20 implementation.
- *
- * 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 FREEBL_CHACHA20_H_
-#define FREEBL_CHACHA20_H_
-
-#if defined(_MSC_VER) && _MSC_VER < 1600
-#include "prtypes.h"
-typedef PRUint32 uint32_t;
-typedef PRUint64 uint64_t;
-#else
-#include <stdint.h>
-#endif
-
-/* ChaCha20XOR encrypts |inLen| bytes from |in| with the given key and
- * nonce and writes the result to |out|, which may be equal to |in|. The
- * initial block counter is specified by |counter|. */
-extern void ChaCha20XOR(unsigned char *out, const unsigned char *in,
- unsigned int inLen, const unsigned char key[32],
- const unsigned char nonce[12], uint32_t counter);
-
-#endif /* FREEBL_CHACHA20_H_ */
diff --git a/security/nss/lib/freebl/chacha20_vec.c b/security/nss/lib/freebl/chacha20_vec.c
deleted file mode 100644
index 12f94d897..000000000
--- a/security/nss/lib/freebl/chacha20_vec.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/* 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/. */
-
-/* This implementation is by Ted Krovetz and was submitted to SUPERCOP and
- * marked as public domain. It was been altered to allow for non-aligned inputs
- * and to allow the block counter to be passed in specifically. */
-
-#include <string.h>
-
-#include "chacha20.h"
-#include "blapii.h"
-
-#ifndef CHACHA_RNDS
-#define CHACHA_RNDS 20 /* 8 (high speed), 20 (conservative), 12 (middle) */
-#endif
-
-/* Architecture-neutral way to specify 16-byte vector of ints */
-typedef unsigned vec __attribute__((vector_size(16)));
-
-/* This implementation is designed for Neon, SSE and AltiVec machines. The
- * following specify how to do certain vector operations efficiently on
- * each architecture, using intrinsics.
- * This implementation supports parallel processing of multiple blocks,
- * including potentially using general-purpose registers.
- */
-#if __ARM_NEON__
-#include <arm_neon.h>
-#define GPR_TOO 1
-#define VBPI 2
-#define ONE (vec) vsetq_lane_u32(1, vdupq_n_u32(0), 0)
-#define LOAD(m) (vec)(*((vec *)(m)))
-#define STORE(m, r) (*((vec *)(m))) = (r)
-#define ROTV1(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 1)
-#define ROTV2(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 2)
-#define ROTV3(x) (vec) vextq_u32((uint32x4_t)x, (uint32x4_t)x, 3)
-#define ROTW16(x) (vec) vrev32q_u16((uint16x8_t)x)
-#if __clang__
-#define ROTW7(x) (x << ((vec){ 7, 7, 7, 7 })) ^ (x >> ((vec){ 25, 25, 25, 25 }))
-#define ROTW8(x) (x << ((vec){ 8, 8, 8, 8 })) ^ (x >> ((vec){ 24, 24, 24, 24 }))
-#define ROTW12(x) (x << ((vec){ 12, 12, 12, 12 })) ^ (x >> ((vec){ 20, 20, 20, 20 }))
-#else
-#define ROTW7(x) (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 7), (uint32x4_t)x, 25)
-#define ROTW8(x) (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 8), (uint32x4_t)x, 24)
-#define ROTW12(x) (vec) vsriq_n_u32(vshlq_n_u32((uint32x4_t)x, 12), (uint32x4_t)x, 20)
-#endif
-#elif __SSE2__
-#include <emmintrin.h>
-#define GPR_TOO 0
-#if __clang__
-#define VBPI 4
-#else
-#define VBPI 3
-#endif
-#define ONE (vec) _mm_set_epi32(0, 0, 0, 1)
-#define LOAD(m) (vec) _mm_loadu_si128((__m128i *)(m))
-#define STORE(m, r) _mm_storeu_si128((__m128i *)(m), (__m128i)(r))
-#define ROTV1(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(0, 3, 2, 1))
-#define ROTV2(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(1, 0, 3, 2))
-#define ROTV3(x) (vec) _mm_shuffle_epi32((__m128i)x, _MM_SHUFFLE(2, 1, 0, 3))
-#define ROTW7(x) (vec)(_mm_slli_epi32((__m128i)x, 7) ^ _mm_srli_epi32((__m128i)x, 25))
-#define ROTW12(x) (vec)(_mm_slli_epi32((__m128i)x, 12) ^ _mm_srli_epi32((__m128i)x, 20))
-#if __SSSE3__
-#include <tmmintrin.h>
-#define ROTW8(x) (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3))
-#define ROTW16(x) (vec) _mm_shuffle_epi8((__m128i)x, _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2))
-#else
-#define ROTW8(x) (vec)(_mm_slli_epi32((__m128i)x, 8) ^ _mm_srli_epi32((__m128i)x, 24))
-#define ROTW16(x) (vec)(_mm_slli_epi32((__m128i)x, 16) ^ _mm_srli_epi32((__m128i)x, 16))
-#endif
-#else
-#error-- Implementation supports only machines with neon or SSE2
-#endif
-
-#ifndef REVV_BE
-#define REVV_BE(x) (x)
-#endif
-
-#ifndef REVW_BE
-#define REVW_BE(x) (x)
-#endif
-
-#define BPI (VBPI + GPR_TOO) /* Blocks computed per loop iteration */
-
-#define DQROUND_VECTORS(a, b, c, d) \
- a += b; \
- d ^= a; \
- d = ROTW16(d); \
- c += d; \
- b ^= c; \
- b = ROTW12(b); \
- a += b; \
- d ^= a; \
- d = ROTW8(d); \
- c += d; \
- b ^= c; \
- b = ROTW7(b); \
- b = ROTV1(b); \
- c = ROTV2(c); \
- d = ROTV3(d); \
- a += b; \
- d ^= a; \
- d = ROTW16(d); \
- c += d; \
- b ^= c; \
- b = ROTW12(b); \
- a += b; \
- d ^= a; \
- d = ROTW8(d); \
- c += d; \
- b ^= c; \
- b = ROTW7(b); \
- b = ROTV3(b); \
- c = ROTV2(c); \
- d = ROTV1(d);
-
-#define QROUND_WORDS(a, b, c, d) \
- a = a + b; \
- d ^= a; \
- d = d << 16 | d >> 16; \
- c = c + d; \
- b ^= c; \
- b = b << 12 | b >> 20; \
- a = a + b; \
- d ^= a; \
- d = d << 8 | d >> 24; \
- c = c + d; \
- b ^= c; \
- b = b << 7 | b >> 25;
-
-#define WRITE_XOR(in, op, d, v0, v1, v2, v3) \
- STORE(op + d + 0, LOAD(in + d + 0) ^ REVV_BE(v0)); \
- STORE(op + d + 4, LOAD(in + d + 4) ^ REVV_BE(v1)); \
- STORE(op + d + 8, LOAD(in + d + 8) ^ REVV_BE(v2)); \
- STORE(op + d + 12, LOAD(in + d + 12) ^ REVV_BE(v3));
-
-void NO_SANITIZE_ALIGNMENT
-ChaCha20XOR(unsigned char *out, const unsigned char *in, unsigned int inlen,
- const unsigned char key[32], const unsigned char nonce[12],
- uint32_t counter)
-{
- unsigned iters, i, *op = (unsigned *)out, *ip = (unsigned *)in, *kp;
-#if defined(__ARM_NEON__)
- unsigned *np;
-#endif
- vec s0, s1, s2, s3;
-#if !defined(__ARM_NEON__) && !defined(__SSE2__)
- __attribute__((aligned(16))) unsigned key[8], nonce[4];
-#endif
- __attribute__((aligned(16))) unsigned chacha_const[] =
- { 0x61707865, 0x3320646E, 0x79622D32, 0x6B206574 };
-#if defined(__ARM_NEON__) || defined(__SSE2__)
- kp = (unsigned *)key;
-#else
- ((vec *)key)[0] = REVV_BE(((vec *)key)[0]);
- ((vec *)key)[1] = REVV_BE(((vec *)key)[1]);
- ((unsigned *)nonce)[0] = REVW_BE(((unsigned *)nonce)[0]);
- ((unsigned *)nonce)[1] = REVW_BE(((unsigned *)nonce)[1]);
- ((unsigned *)nonce)[2] = REVW_BE(((unsigned *)nonce)[2]);
- ((unsigned *)nonce)[3] = REVW_BE(((unsigned *)nonce)[3]);
- kp = (unsigned *)key;
- np = (unsigned *)nonce;
-#endif
-#if defined(__ARM_NEON__)
- np = (unsigned *)nonce;
-#endif
- s0 = LOAD(chacha_const);
- s1 = LOAD(&((vec *)kp)[0]);
- s2 = LOAD(&((vec *)kp)[1]);
- s3 = (vec){
- counter,
- ((uint32_t *)nonce)[0],
- ((uint32_t *)nonce)[1],
- ((uint32_t *)nonce)[2]
- };
-
- for (iters = 0; iters < inlen / (BPI * 64); iters++) {
-#if GPR_TOO
- register unsigned x0, x1, x2, x3, x4, x5, x6, x7, x8,
- x9, x10, x11, x12, x13, x14, x15;
-#endif
-#if VBPI > 2
- vec v8, v9, v10, v11;
-#endif
-#if VBPI > 3
- vec v12, v13, v14, v15;
-#endif
-
- vec v0, v1, v2, v3, v4, v5, v6, v7;
- v4 = v0 = s0;
- v5 = v1 = s1;
- v6 = v2 = s2;
- v3 = s3;
- v7 = v3 + ONE;
-#if VBPI > 2
- v8 = v4;
- v9 = v5;
- v10 = v6;
- v11 = v7 + ONE;
-#endif
-#if VBPI > 3
- v12 = v8;
- v13 = v9;
- v14 = v10;
- v15 = v11 + ONE;
-#endif
-#if GPR_TOO
- x0 = chacha_const[0];
- x1 = chacha_const[1];
- x2 = chacha_const[2];
- x3 = chacha_const[3];
- x4 = kp[0];
- x5 = kp[1];
- x6 = kp[2];
- x7 = kp[3];
- x8 = kp[4];
- x9 = kp[5];
- x10 = kp[6];
- x11 = kp[7];
- x12 = counter + BPI * iters + (BPI - 1);
- x13 = np[0];
- x14 = np[1];
- x15 = np[2];
-#endif
- for (i = CHACHA_RNDS / 2; i; i--) {
- DQROUND_VECTORS(v0, v1, v2, v3)
- DQROUND_VECTORS(v4, v5, v6, v7)
-#if VBPI > 2
- DQROUND_VECTORS(v8, v9, v10, v11)
-#endif
-#if VBPI > 3
- DQROUND_VECTORS(v12, v13, v14, v15)
-#endif
-#if GPR_TOO
- QROUND_WORDS(x0, x4, x8, x12)
- QROUND_WORDS(x1, x5, x9, x13)
- QROUND_WORDS(x2, x6, x10, x14)
- QROUND_WORDS(x3, x7, x11, x15)
- QROUND_WORDS(x0, x5, x10, x15)
- QROUND_WORDS(x1, x6, x11, x12)
- QROUND_WORDS(x2, x7, x8, x13)
- QROUND_WORDS(x3, x4, x9, x14)
-#endif
- }
-
- WRITE_XOR(ip, op, 0, v0 + s0, v1 + s1, v2 + s2, v3 + s3)
- s3 += ONE;
- WRITE_XOR(ip, op, 16, v4 + s0, v5 + s1, v6 + s2, v7 + s3)
- s3 += ONE;
-#if VBPI > 2
- WRITE_XOR(ip, op, 32, v8 + s0, v9 + s1, v10 + s2, v11 + s3)
- s3 += ONE;
-#endif
-#if VBPI > 3
- WRITE_XOR(ip, op, 48, v12 + s0, v13 + s1, v14 + s2, v15 + s3)
- s3 += ONE;
-#endif
- ip += VBPI * 16;
- op += VBPI * 16;
-#if GPR_TOO
- op[0] = REVW_BE(REVW_BE(ip[0]) ^ (x0 + chacha_const[0]));
- op[1] = REVW_BE(REVW_BE(ip[1]) ^ (x1 + chacha_const[1]));
- op[2] = REVW_BE(REVW_BE(ip[2]) ^ (x2 + chacha_const[2]));
- op[3] = REVW_BE(REVW_BE(ip[3]) ^ (x3 + chacha_const[3]));
- op[4] = REVW_BE(REVW_BE(ip[4]) ^ (x4 + kp[0]));
- op[5] = REVW_BE(REVW_BE(ip[5]) ^ (x5 + kp[1]));
- op[6] = REVW_BE(REVW_BE(ip[6]) ^ (x6 + kp[2]));
- op[7] = REVW_BE(REVW_BE(ip[7]) ^ (x7 + kp[3]));
- op[8] = REVW_BE(REVW_BE(ip[8]) ^ (x8 + kp[4]));
- op[9] = REVW_BE(REVW_BE(ip[9]) ^ (x9 + kp[5]));
- op[10] = REVW_BE(REVW_BE(ip[10]) ^ (x10 + kp[6]));
- op[11] = REVW_BE(REVW_BE(ip[11]) ^ (x11 + kp[7]));
- op[12] = REVW_BE(REVW_BE(ip[12]) ^ (x12 + counter + BPI * iters + (BPI - 1)));
- op[13] = REVW_BE(REVW_BE(ip[13]) ^ (x13 + np[0]));
- op[14] = REVW_BE(REVW_BE(ip[14]) ^ (x14 + np[1]));
- op[15] = REVW_BE(REVW_BE(ip[15]) ^ (x15 + np[2]));
- s3 += ONE;
- ip += 16;
- op += 16;
-#endif
- }
-
- for (iters = inlen % (BPI * 64) / 64; iters != 0; iters--) {
- vec v0 = s0, v1 = s1, v2 = s2, v3 = s3;
- for (i = CHACHA_RNDS / 2; i; i--) {
- DQROUND_VECTORS(v0, v1, v2, v3);
- }
- WRITE_XOR(ip, op, 0, v0 + s0, v1 + s1, v2 + s2, v3 + s3)
- s3 += ONE;
- ip += 16;
- op += 16;
- }
-
- inlen = inlen % 64;
- if (inlen) {
- __attribute__((aligned(16))) vec buf[4];
- vec v0, v1, v2, v3;
- v0 = s0;
- v1 = s1;
- v2 = s2;
- v3 = s3;
- for (i = CHACHA_RNDS / 2; i; i--) {
- DQROUND_VECTORS(v0, v1, v2, v3);
- }
-
- if (inlen >= 16) {
- STORE(op + 0, LOAD(ip + 0) ^ REVV_BE(v0 + s0));
- if (inlen >= 32) {
- STORE(op + 4, LOAD(ip + 4) ^ REVV_BE(v1 + s1));
- if (inlen >= 48) {
- STORE(op + 8, LOAD(ip + 8) ^ REVV_BE(v2 + s2));
- buf[3] = REVV_BE(v3 + s3);
- } else {
- buf[2] = REVV_BE(v2 + s2);
- }
- } else {
- buf[1] = REVV_BE(v1 + s1);
- }
- } else {
- buf[0] = REVV_BE(v0 + s0);
- }
-
- for (i = inlen & ~15; i < inlen; i++) {
- ((char *)op)[i] = ((char *)ip)[i] ^ ((char *)buf)[i];
- }
- }
-}
diff --git a/security/nss/lib/freebl/chacha20poly1305.c b/security/nss/lib/freebl/chacha20poly1305.c
index 991fa0ca3..859d05316 100644
--- a/security/nss/lib/freebl/chacha20poly1305.c
+++ b/security/nss/lib/freebl/chacha20poly1305.c
@@ -12,25 +12,28 @@
#include "seccomon.h"
#include "secerr.h"
#include "blapit.h"
+#include "blapii.h"
#ifndef NSS_DISABLE_CHACHAPOLY
-#if defined(HAVE_INT128_SUPPORT) && (defined(NSS_X86_OR_X64) || defined(__aarch64__))
-#include "verified/Hacl_Poly1305_64.h"
-#else
-#include "poly1305.h"
-#endif
-#include "chacha20.h"
#include "chacha20poly1305.h"
-#endif
+// Forward declaration from "Hacl_Chacha20_Vec128.h".
+extern void Hacl_Chacha20_Vec128_chacha20(uint8_t *output, uint8_t *plain,
+ uint32_t len, uint8_t *k, uint8_t *n1,
+ uint32_t ctr);
+// Forward declaration from "Hacl_Chacha20.h".
+extern void Hacl_Chacha20_chacha20(uint8_t *output, uint8_t *plain, uint32_t len,
+ uint8_t *k, uint8_t *n1, uint32_t ctr);
/* Poly1305Do writes the Poly1305 authenticator of the given additional data
* and ciphertext to |out|. */
-#ifndef NSS_DISABLE_CHACHAPOLY
-
#if defined(HAVE_INT128_SUPPORT) && (defined(NSS_X86_OR_X64) || defined(__aarch64__))
+/* Use HACL* Poly1305 on 64-bit Intel and ARM */
+#include "verified/Hacl_Poly1305_64.h"
static void
-Poly1305PadUpdate(Hacl_Impl_Poly1305_64_State_poly1305_state state, unsigned char *block, const unsigned char *p, const unsigned int pLen)
+Poly1305PadUpdate(Hacl_Impl_Poly1305_64_State_poly1305_state state,
+ unsigned char *block, const unsigned char *p,
+ const unsigned int pLen)
{
unsigned int pRemLen = pLen % 16;
Hacl_Poly1305_64_update(state, (uint8_t *)p, (pLen / 16));
@@ -46,7 +49,8 @@ Poly1305Do(unsigned char *out, const unsigned char *ad, unsigned int adLen,
const unsigned char key[32])
{
uint64_t tmp1[6U] = { 0U };
- Hacl_Impl_Poly1305_64_State_poly1305_state state = Hacl_Poly1305_64_mk_state(tmp1, tmp1 + 3);
+ Hacl_Impl_Poly1305_64_State_poly1305_state state =
+ Hacl_Poly1305_64_mk_state(tmp1, tmp1 + 3);
unsigned char block[16] = { 0 };
Hacl_Poly1305_64_init(state, (uint8_t *)key);
@@ -68,6 +72,8 @@ Poly1305Do(unsigned char *out, const unsigned char *ad, unsigned int adLen,
Hacl_Poly1305_64_finish(state, out, (uint8_t *)(key + 16));
}
#else
+/* All other platforms get the 32-bit poly1305 reference implementation. */
+#include "poly1305.h"
static void
Poly1305Do(unsigned char *out, const unsigned char *ad, unsigned int adLen,
@@ -165,6 +171,17 @@ ChaCha20Poly1305_DestroyContext(ChaCha20Poly1305Context *ctx, PRBool freeit)
#endif
}
+void
+ChaCha20Xor(uint8_t *output, uint8_t *block, uint32_t len, uint8_t *k,
+ uint8_t *nonce, uint32_t ctr)
+{
+ if (ssse3_support() || arm_neon_support()) {
+ Hacl_Chacha20_Vec128_chacha20(output, block, len, k, nonce, ctr);
+ } else {
+ Hacl_Chacha20_chacha20(output, block, len, k, nonce, ctr);
+ }
+}
+
SECStatus
ChaCha20Poly1305_Seal(const ChaCha20Poly1305Context *ctx, unsigned char *output,
unsigned int *outputLen, unsigned int maxOutputLen,
@@ -191,8 +208,10 @@ ChaCha20Poly1305_Seal(const ChaCha20Poly1305Context *ctx, unsigned char *output,
PORT_Memset(block, 0, sizeof(block));
// Generate a block of keystream. The first 32 bytes will be the poly1305
// key. The remainder of the block is discarded.
- ChaCha20XOR(block, block, sizeof(block), ctx->key, nonce, 0);
- ChaCha20XOR(output, input, inputLen, ctx->key, nonce, 1);
+ ChaCha20Xor(block, (uint8_t *)block, sizeof(block), (uint8_t *)ctx->key,
+ (uint8_t *)nonce, 0);
+ ChaCha20Xor(output, (uint8_t *)input, inputLen, (uint8_t *)ctx->key,
+ (uint8_t *)nonce, 1);
Poly1305Do(tag, ad, adLen, output, inputLen, block);
PORT_Memcpy(output + inputLen, tag, ctx->tagLen);
@@ -233,14 +252,16 @@ ChaCha20Poly1305_Open(const ChaCha20Poly1305Context *ctx, unsigned char *output,
PORT_Memset(block, 0, sizeof(block));
// Generate a block of keystream. The first 32 bytes will be the poly1305
// key. The remainder of the block is discarded.
- ChaCha20XOR(block, block, sizeof(block), ctx->key, nonce, 0);
+ ChaCha20Xor(block, (uint8_t *)block, sizeof(block), (uint8_t *)ctx->key,
+ (uint8_t *)nonce, 0);
Poly1305Do(tag, ad, adLen, input, ciphertextLen, block);
if (NSS_SecureMemcmp(tag, &input[ciphertextLen], ctx->tagLen) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
- ChaCha20XOR(output, input, ciphertextLen, ctx->key, nonce, 1);
+ ChaCha20Xor(output, (uint8_t *)input, ciphertextLen, (uint8_t *)ctx->key,
+ (uint8_t *)nonce, 1);
return SECSuccess;
#endif
diff --git a/security/nss/lib/freebl/config.mk b/security/nss/lib/freebl/config.mk
index f15077096..7ac50db65 100644
--- a/security/nss/lib/freebl/config.mk
+++ b/security/nss/lib/freebl/config.mk
@@ -90,7 +90,7 @@ EXTRA_SHARED_LIBS += \
endif
endif
-ifeq ($(OS_ARCH), Linux)
+ifeq (,$(filter-out DragonFly FreeBSD Linux NetBSD OpenBSD, $(OS_TARGET)))
CFLAGS += -std=gnu99
endif
diff --git a/security/nss/lib/freebl/det_rng.c b/security/nss/lib/freebl/det_rng.c
index 53d48bc7c..56be2d356 100644
--- a/security/nss/lib/freebl/det_rng.c
+++ b/security/nss/lib/freebl/det_rng.c
@@ -4,7 +4,7 @@
#include "blapi.h"
#include "blapit.h"
-#include "chacha20.h"
+#include "Hacl_Chacha20.h"
#include "nssilock.h"
#include "seccomon.h"
#include "secerr.h"
@@ -99,7 +99,7 @@ RNG_GenerateGlobalRandomBytes(void *dest, size_t len)
memset(dest, 0, len);
memcpy(dest, globalBytes, PR_MIN(len, GLOBAL_BYTES_SIZE));
- ChaCha20XOR(dest, dest, len, key, nonce, 0);
+ Hacl_Chacha20_chacha20(dest, (uint8_t *)dest, len, (uint8_t *)key, nonce, 0);
ChaCha20Poly1305_DestroyContext(cx, PR_TRUE);
PZ_Unlock(rng_lock);
diff --git a/security/nss/lib/freebl/drbg.c b/security/nss/lib/freebl/drbg.c
index 224bbe87d..70ae2618e 100644
--- a/security/nss/lib/freebl/drbg.c
+++ b/security/nss/lib/freebl/drbg.c
@@ -74,8 +74,7 @@ struct RNGContextStr {
#define V_type V_Data[0]
#define V(rng) (((rng)->V_Data) + 1)
#define VSize(rng) ((sizeof(rng)->V_Data) - 1)
- PRUint8 C[PRNG_SEEDLEN]; /* internal state variables */
- PRUint8 lastOutput[SHA256_LENGTH]; /* for continuous rng checking */
+ PRUint8 C[PRNG_SEEDLEN]; /* internal state variables */
/* If we get calls for the PRNG to return less than the length of our
* hash, we extend the request for a full hash (since we'll be doing
* the full hash anyway). Future requests for random numbers are fulfilled
@@ -286,7 +285,6 @@ prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes,
{
PRUint8 data[VSize(rng)];
PRUint8 thisHash[SHA256_LENGTH];
- PRUint8 *lastHash = rng->lastOutput;
PORT_Memcpy(data, V(rng), VSize(rng));
while (no_of_returned_bytes) {
@@ -297,15 +295,10 @@ prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes,
SHA256_Begin(&ctx);
SHA256_Update(&ctx, data, sizeof data);
SHA256_End(&ctx, thisHash, &len, SHA256_LENGTH);
- if (PORT_Memcmp(lastHash, thisHash, len) == 0) {
- rng->isValid = PR_FALSE;
- break;
- }
if (no_of_returned_bytes < SHA256_LENGTH) {
len = no_of_returned_bytes;
}
PORT_Memcpy(returned_bytes, thisHash, len);
- lastHash = returned_bytes;
returned_bytes += len;
no_of_returned_bytes -= len;
/* The carry parameter is a bool (increment or not).
@@ -313,7 +306,6 @@ prng_Hashgen(RNGContext *rng, PRUint8 *returned_bytes,
carry = no_of_returned_bytes;
PRNG_ADD_CARRY_ONLY(data, (sizeof data) - 1, carry);
}
- PORT_Memcpy(rng->lastOutput, thisHash, SHA256_LENGTH);
PORT_Memset(data, 0, sizeof data);
PORT_Memset(thisHash, 0, sizeof thisHash);
}
@@ -361,11 +353,6 @@ prng_generateNewBytes(RNGContext *rng,
if (no_of_returned_bytes == SHA256_LENGTH) {
/* short_cut to hashbuf and a couple of copies and clears */
SHA256_HashBuf(returned_bytes, V(rng), VSize(rng));
- /* continuous rng check */
- if (memcmp(rng->lastOutput, returned_bytes, SHA256_LENGTH) == 0) {
- rng->isValid = PR_FALSE;
- }
- PORT_Memcpy(rng->lastOutput, returned_bytes, sizeof rng->lastOutput);
} else {
prng_Hashgen(rng, returned_bytes, no_of_returned_bytes);
}
diff --git a/security/nss/lib/freebl/ecl/uint128.c b/security/nss/lib/freebl/ecl/uint128.c
deleted file mode 100644
index 5465875ad..000000000
--- a/security/nss/lib/freebl/ecl/uint128.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* 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 "uint128.h"
-
-/* helper functions */
-uint64_t
-mask51(uint128_t x)
-{
- return x.lo & MASK51;
-}
-
-uint64_t
-mask_lower(uint128_t x)
-{
- return x.lo;
-}
-
-uint128_t
-mask51full(uint128_t x)
-{
- uint128_t ret = { x.lo & MASK51, 0 };
- return ret;
-}
-
-uint128_t
-init128x(uint64_t x)
-{
- uint128_t ret = { x, 0 };
- return ret;
-}
-
-#define CONSTANT_TIME_CARRY(a, b) \
- ((a ^ ((a ^ b) | ((a - b) ^ b))) >> (sizeof(a) * 8 - 1))
-
-/* arithmetic */
-
-uint128_t
-add128(uint128_t a, uint128_t b)
-{
- uint128_t ret;
- ret.lo = a.lo + b.lo;
- ret.hi = a.hi + b.hi + CONSTANT_TIME_CARRY(ret.lo, b.lo);
- return ret;
-}
-
-/* out = 19 * a */
-uint128_t
-mul12819(uint128_t a)
-{
- uint128_t ret = lshift128(a, 4);
- ret = add128(ret, a);
- ret = add128(ret, a);
- ret = add128(ret, a);
- return ret;
-}
-
-uint128_t
-mul6464(uint64_t a, uint64_t b)
-{
- uint128_t ret;
- uint64_t t0 = ((uint64_t)(uint32_t)a) * ((uint64_t)(uint32_t)b);
- uint64_t t1 = (a >> 32) * ((uint64_t)(uint32_t)b) + (t0 >> 32);
- uint64_t t2 = (b >> 32) * ((uint64_t)(uint32_t)a) + ((uint32_t)t1);
- ret.lo = (((uint64_t)((uint32_t)t2)) << 32) + ((uint32_t)t0);
- ret.hi = (a >> 32) * (b >> 32);
- ret.hi += (t2 >> 32) + (t1 >> 32);
- return ret;
-}
-
-/* only defined for n < 64 */
-uint128_t
-rshift128(uint128_t x, uint8_t n)
-{
- uint128_t ret;
- ret.lo = (x.lo >> n) + (x.hi << (64 - n));
- ret.hi = x.hi >> n;
- return ret;
-}
-
-/* only defined for n < 64 */
-uint128_t
-lshift128(uint128_t x, uint8_t n)
-{
- uint128_t ret;
- ret.hi = (x.hi << n) + (x.lo >> (64 - n));
- ret.lo = x.lo << n;
- return ret;
-}
diff --git a/security/nss/lib/freebl/ecl/uint128.h b/security/nss/lib/freebl/ecl/uint128.h
deleted file mode 100644
index a3a71e6e7..000000000
--- a/security/nss/lib/freebl/ecl/uint128.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* 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 <stdint.h>
-
-#define MASK51 0x7ffffffffffffULL
-
-#ifdef HAVE_INT128_SUPPORT
-typedef unsigned __int128 uint128_t;
-#define add128(a, b) (a) + (b)
-#define mul6464(a, b) (uint128_t)(a) * (uint128_t)(b)
-#define mul12819(a) (uint128_t)(a) * 19
-#define rshift128(x, n) (x) >> (n)
-#define lshift128(x, n) (x) << (n)
-#define mask51(x) (x) & 0x7ffffffffffff
-#define mask_lower(x) (uint64_t)(x)
-#define mask51full(x) (x) & 0x7ffffffffffff
-#define init128x(x) (x)
-#else /* uint128_t for Windows and 32 bit intel systems */
-struct uint128_t_str {
- uint64_t lo;
- uint64_t hi;
-};
-typedef struct uint128_t_str uint128_t;
-uint128_t add128(uint128_t a, uint128_t b);
-uint128_t mul6464(uint64_t a, uint64_t b);
-uint128_t mul12819(uint128_t a);
-uint128_t rshift128(uint128_t x, uint8_t n);
-uint128_t lshift128(uint128_t x, uint8_t n);
-uint64_t mask51(uint128_t x);
-uint64_t mask_lower(uint128_t x);
-uint128_t mask51full(uint128_t x);
-uint128_t init128x(uint64_t x);
-#endif
diff --git a/security/nss/lib/freebl/freebl.gyp b/security/nss/lib/freebl/freebl.gyp
index 8b6a546e7..fae56f709 100644
--- a/security/nss/lib/freebl/freebl.gyp
+++ b/security/nss/lib/freebl/freebl.gyp
@@ -10,7 +10,7 @@
'target_name': 'intel-gcm-wrap_c_lib',
'type': 'static_library',
'sources': [
- 'intel-gcm-wrap.c'
+ 'intel-gcm-wrap.c',
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports'
@@ -23,6 +23,38 @@
]
},
{
+ # TODO: make this so that all hardware accelerated code is in here.
+ 'target_name': 'hw-acc-crypto',
+ 'type': 'static_library',
+ 'sources': [
+ 'verified/Hacl_Chacha20_Vec128.c',
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ],
+ 'conditions': [
+ [ 'target_arch=="ia32" or target_arch=="x64"', {
+ 'cflags': [
+ '-mssse3'
+ ],
+ 'cflags_mozilla': [
+ '-mssse3'
+ ],
+ # GCC doesn't define this.
+ 'defines': [
+ '__SSSE3__',
+ ],
+ }],
+ [ 'OS=="android"', {
+ # On Android we can't use any of the hardware acceleration :(
+ 'defines!': [
+ '__ARM_NEON__',
+ '__ARM_NEON',
+ ],
+ }],
+ ],
+ },
+ {
'target_name': 'gcm-aes-x86_c_lib',
'type': 'static_library',
'sources': [
@@ -74,11 +106,12 @@
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
+ 'hw-acc-crypto',
],
'conditions': [
[ 'target_arch=="ia32" or target_arch=="x64"', {
'dependencies': [
- 'gcm-aes-x86_c_lib'
+ 'gcm-aes-x86_c_lib',
],
}],
[ 'OS=="linux"', {
@@ -110,11 +143,12 @@
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
+ 'hw-acc-crypto',
],
'conditions': [
[ 'target_arch=="ia32" or target_arch=="x64"', {
'dependencies': [
- 'gcm-aes-x86_c_lib'
+ 'gcm-aes-x86_c_lib',
]
}],
[ 'OS!="linux" and OS!="android"', {
@@ -275,6 +309,11 @@
'-std=gnu99',
],
}],
+ [ 'OS=="dragonfly" or OS=="freebsd" or OS=="netbsd" or OS=="openbsd"', {
+ 'cflags': [
+ '-std=gnu99',
+ ],
+ }],
[ 'OS=="linux" or OS=="android"', {
'conditions': [
[ 'target_arch=="x64"', {
diff --git a/security/nss/lib/freebl/freebl_base.gypi b/security/nss/lib/freebl/freebl_base.gypi
index 44e28963b..ebd1018d8 100644
--- a/security/nss/lib/freebl/freebl_base.gypi
+++ b/security/nss/lib/freebl/freebl_base.gypi
@@ -144,12 +144,17 @@
],
}],
[ 'disable_chachapoly==0', {
+ # The ChaCha20 code is linked in through the static ssse3-crypto lib on
+ # all platforms that support SSSE3. There are runtime checks in place to
+ # choose the correct ChaCha implementation at runtime.
+ 'sources': [
+ 'verified/Hacl_Chacha20.c',
+ ],
'conditions': [
[ 'OS!="win"', {
'conditions': [
[ 'target_arch=="x64"', {
'sources': [
- 'chacha20_vec.c',
'verified/Hacl_Poly1305_64.c',
],
}, {
@@ -157,15 +162,11 @@
'conditions': [
[ 'target_arch=="arm64" or target_arch=="aarch64"', {
'sources': [
- 'chacha20.c',
- 'verified/Hacl_Chacha20.c',
'verified/Hacl_Poly1305_64.c',
],
}, {
# !Windows & !x64 & !arm64 & !aarch64
'sources': [
- 'chacha20.c',
- 'verified/Hacl_Chacha20.c',
'poly1305.c',
],
}],
@@ -175,8 +176,6 @@
}, {
# Windows
'sources': [
- 'chacha20.c',
- 'verified/Hacl_Chacha20.c',
'poly1305.c',
],
}],
diff --git a/security/nss/lib/freebl/lowhash_vector.c b/security/nss/lib/freebl/lowhash_vector.c
index 7690c98da..be53bbdc6 100644
--- a/security/nss/lib/freebl/lowhash_vector.c
+++ b/security/nss/lib/freebl/lowhash_vector.c
@@ -102,13 +102,13 @@ freebl_LoadDSO(void)
static PRCallOnceType loadFreeBLOnce;
-static PRStatus
+static void
freebl_RunLoaderOnce(void)
{
/* Don't have NSPR, so can use the real PR_CallOnce, implement a stripped
* down version. */
if (loadFreeBLOnce.initialized) {
- return loadFreeBLOnce.status;
+ return;
}
if (__sync_lock_test_and_set(&loadFreeBLOnce.inProgress, 1) == 0) {
loadFreeBLOnce.status = freebl_LoadDSO();
@@ -122,17 +122,21 @@ freebl_RunLoaderOnce(void)
sleep(1); /* don't have condition variables, just give up the CPU */
}
}
+}
- return loadFreeBLOnce.status;
+static const NSSLOWVector *
+freebl_InitVector(void)
+{
+ if (!vector) {
+ freebl_RunLoaderOnce();
+ }
+ return vector;
}
const FREEBLVector *
FREEBL_GetVector(void)
{
- if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) {
- return NULL;
- }
- if (vector) {
+ if (freebl_InitVector()) {
return (vector->p_FREEBL_GetVector)();
}
return NULL;
@@ -141,25 +145,26 @@ FREEBL_GetVector(void)
NSSLOWInitContext *
NSSLOW_Init(void)
{
- if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
- return NULL;
- return (vector->p_NSSLOW_Init)();
+ if (freebl_InitVector()) {
+ return (vector->p_NSSLOW_Init)();
+ }
+ return NULL;
}
void
NSSLOW_Shutdown(NSSLOWInitContext *context)
{
- if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
- return;
- (vector->p_NSSLOW_Shutdown)(context);
+ if (freebl_InitVector()) {
+ (vector->p_NSSLOW_Shutdown)(context);
+ }
}
void
NSSLOW_Reset(NSSLOWInitContext *context)
{
- if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
- return;
- (vector->p_NSSLOW_Reset)(context);
+ if (freebl_InitVector()) {
+ (vector->p_NSSLOW_Reset)(context);
+ }
}
NSSLOWHASHContext *
@@ -167,17 +172,18 @@ NSSLOWHASH_NewContext(
NSSLOWInitContext *initContext,
HASH_HashType hashType)
{
- if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
- return NULL;
- return (vector->p_NSSLOWHASH_NewContext)(initContext, hashType);
+ if (freebl_InitVector()) {
+ return (vector->p_NSSLOWHASH_NewContext)(initContext, hashType);
+ }
+ return NULL;
}
void
NSSLOWHASH_Begin(NSSLOWHASHContext *context)
{
- if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
- return;
- (vector->p_NSSLOWHASH_Begin)(context);
+ if (freebl_InitVector()) {
+ (vector->p_NSSLOWHASH_Begin)(context);
+ }
}
void
@@ -185,9 +191,9 @@ NSSLOWHASH_Update(NSSLOWHASHContext *context,
const unsigned char *buf,
unsigned int len)
{
- if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
- return;
- (vector->p_NSSLOWHASH_Update)(context, buf, len);
+ if (freebl_InitVector()) {
+ (vector->p_NSSLOWHASH_Update)(context, buf, len);
+ }
}
void
@@ -195,23 +201,24 @@ NSSLOWHASH_End(NSSLOWHASHContext *context,
unsigned char *buf,
unsigned int *ret, unsigned int len)
{
- if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
- return;
- (vector->p_NSSLOWHASH_End)(context, buf, ret, len);
+ if (freebl_InitVector()) {
+ (vector->p_NSSLOWHASH_End)(context, buf, ret, len);
+ }
}
void
NSSLOWHASH_Destroy(NSSLOWHASHContext *context)
{
- if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
- return;
- (vector->p_NSSLOWHASH_Destroy)(context);
+ if (freebl_InitVector()) {
+ (vector->p_NSSLOWHASH_Destroy)(context);
+ }
}
unsigned int
NSSLOWHASH_Length(NSSLOWHASHContext *context)
{
- if (!vector && PR_SUCCESS != freebl_RunLoaderOnce())
- return -1;
- return (vector->p_NSSLOWHASH_Length)(context);
+ if (freebl_InitVector()) {
+ return (vector->p_NSSLOWHASH_Length)(context);
+ }
+ return -1;
}
diff --git a/security/nss/lib/freebl/stubs.c b/security/nss/lib/freebl/stubs.c
index 4d41ef975..c42f694d7 100644
--- a/security/nss/lib/freebl/stubs.c
+++ b/security/nss/lib/freebl/stubs.c
@@ -36,6 +36,7 @@
#include <secport.h>
#include <secitem.h>
#include <blapi.h>
+#include <assert.h>
#include <private/pprio.h>
/* Android API < 21 doesn't define RTLD_NOLOAD */
@@ -252,7 +253,12 @@ PORT_ZAllocAligned_stub(size_t bytes, size_t alignment, void **mem)
}
memset(*mem, 0, len);
- return (void *)(((uintptr_t)*mem + x) & ~(uintptr_t)x);
+
+ /* We're pretty sure this is non-zero, but let's assure scan-build too. */
+ void *ret = (void *)(((uintptr_t)*mem + x) & ~(uintptr_t)x);
+ assert(ret);
+
+ return ret;
}
extern void *
diff --git a/security/nss/lib/freebl/verified/Hacl_Chacha20_Vec128.c b/security/nss/lib/freebl/verified/Hacl_Chacha20_Vec128.c
new file mode 100644
index 000000000..4eba49f47
--- /dev/null
+++ b/security/nss/lib/freebl/verified/Hacl_Chacha20_Vec128.c
@@ -0,0 +1,390 @@
+/* Copyright 2016-2017 INRIA and Microsoft Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Hacl_Chacha20_Vec128.h"
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_State_state_incr(vec *k)
+{
+ vec k3 = k[3U];
+ k[3U] = vec_increment(k3);
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_State_state_to_key_block(uint8_t *stream_block, vec *k)
+{
+ vec k0 = k[0U];
+ vec k1 = k[1U];
+ vec k2 = k[2U];
+ vec k3 = k[3U];
+ uint8_t *a = stream_block;
+ uint8_t *b = stream_block + (uint32_t)16U;
+ uint8_t *c = stream_block + (uint32_t)32U;
+ uint8_t *d = stream_block + (uint32_t)48U;
+ vec_store_le(a, k0);
+ vec_store_le(b, k1);
+ vec_store_le(c, k2);
+ vec_store_le(d, k3);
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_State_state_setup(vec *st, uint8_t *k, uint8_t *n1, uint32_t c)
+{
+ st[0U] =
+ vec_load_32x4((uint32_t)0x61707865U,
+ (uint32_t)0x3320646eU,
+ (uint32_t)0x79622d32U,
+ (uint32_t)0x6b206574U);
+ vec k0 = vec_load128_le(k);
+ vec k1 = vec_load128_le(k + (uint32_t)16U);
+ st[1U] = k0;
+ st[2U] = k1;
+ uint32_t n0 = load32_le(n1);
+ uint8_t *x00 = n1 + (uint32_t)4U;
+ uint32_t n10 = load32_le(x00);
+ uint8_t *x0 = n1 + (uint32_t)8U;
+ uint32_t n2 = load32_le(x0);
+ vec v1 = vec_load_32x4(c, n0, n10, n2);
+ st[3U] = v1;
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_round(vec *st)
+{
+ vec sa = st[0U];
+ vec sb0 = st[1U];
+ vec sd0 = st[3U];
+ vec sa10 = vec_add(sa, sb0);
+ vec sd10 = vec_rotate_left(vec_xor(sd0, sa10), (uint32_t)16U);
+ st[0U] = sa10;
+ st[3U] = sd10;
+ vec sa0 = st[2U];
+ vec sb1 = st[3U];
+ vec sd2 = st[1U];
+ vec sa11 = vec_add(sa0, sb1);
+ vec sd11 = vec_rotate_left(vec_xor(sd2, sa11), (uint32_t)12U);
+ st[2U] = sa11;
+ st[1U] = sd11;
+ vec sa2 = st[0U];
+ vec sb2 = st[1U];
+ vec sd3 = st[3U];
+ vec sa12 = vec_add(sa2, sb2);
+ vec sd12 = vec_rotate_left(vec_xor(sd3, sa12), (uint32_t)8U);
+ st[0U] = sa12;
+ st[3U] = sd12;
+ vec sa3 = st[2U];
+ vec sb = st[3U];
+ vec sd = st[1U];
+ vec sa1 = vec_add(sa3, sb);
+ vec sd1 = vec_rotate_left(vec_xor(sd, sa1), (uint32_t)7U);
+ st[2U] = sa1;
+ st[1U] = sd1;
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_double_round(vec *st)
+{
+ Hacl_Impl_Chacha20_Vec128_round(st);
+ vec r1 = st[1U];
+ vec r20 = st[2U];
+ vec r30 = st[3U];
+ st[1U] = vec_shuffle_right(r1, (uint32_t)1U);
+ st[2U] = vec_shuffle_right(r20, (uint32_t)2U);
+ st[3U] = vec_shuffle_right(r30, (uint32_t)3U);
+ Hacl_Impl_Chacha20_Vec128_round(st);
+ vec r10 = st[1U];
+ vec r2 = st[2U];
+ vec r3 = st[3U];
+ st[1U] = vec_shuffle_right(r10, (uint32_t)3U);
+ st[2U] = vec_shuffle_right(r2, (uint32_t)2U);
+ st[3U] = vec_shuffle_right(r3, (uint32_t)1U);
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_double_round3(vec *st, vec *st_, vec *st__)
+{
+ Hacl_Impl_Chacha20_Vec128_double_round(st);
+ Hacl_Impl_Chacha20_Vec128_double_round(st_);
+ Hacl_Impl_Chacha20_Vec128_double_round(st__);
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_sum_states(vec *st_, vec *st)
+{
+ vec s0 = st[0U];
+ vec s1 = st[1U];
+ vec s2 = st[2U];
+ vec s3 = st[3U];
+ vec s0_ = st_[0U];
+ vec s1_ = st_[1U];
+ vec s2_ = st_[2U];
+ vec s3_ = st_[3U];
+ st_[0U] = vec_add(s0_, s0);
+ st_[1U] = vec_add(s1_, s1);
+ st_[2U] = vec_add(s2_, s2);
+ st_[3U] = vec_add(s3_, s3);
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_copy_state(vec *st_, vec *st)
+{
+ vec st0 = st[0U];
+ vec st1 = st[1U];
+ vec st2 = st[2U];
+ vec st3 = st[3U];
+ st_[0U] = st0;
+ st_[1U] = st1;
+ st_[2U] = st2;
+ st_[3U] = st3;
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_chacha20_core(vec *k, vec *st)
+{
+ Hacl_Impl_Chacha20_Vec128_copy_state(k, st);
+ for (uint32_t i = (uint32_t)0U; i < (uint32_t)10U; i = i + (uint32_t)1U)
+ Hacl_Impl_Chacha20_Vec128_double_round(k);
+ Hacl_Impl_Chacha20_Vec128_sum_states(k, st);
+}
+
+static void
+Hacl_Impl_Chacha20_Vec128_state_incr(vec *st)
+{
+ Hacl_Impl_Chacha20_Vec128_State_state_incr(st);
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_chacha20_incr3(vec *k0, vec *k1, vec *k2, vec *st)
+{
+ Hacl_Impl_Chacha20_Vec128_copy_state(k0, st);
+ Hacl_Impl_Chacha20_Vec128_copy_state(k1, st);
+ Hacl_Impl_Chacha20_Vec128_state_incr(k1);
+ Hacl_Impl_Chacha20_Vec128_copy_state(k2, k1);
+ Hacl_Impl_Chacha20_Vec128_state_incr(k2);
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_chacha20_sum3(vec *k0, vec *k1, vec *k2, vec *st)
+{
+ Hacl_Impl_Chacha20_Vec128_sum_states(k0, st);
+ Hacl_Impl_Chacha20_Vec128_state_incr(st);
+ Hacl_Impl_Chacha20_Vec128_sum_states(k1, st);
+ Hacl_Impl_Chacha20_Vec128_state_incr(st);
+ Hacl_Impl_Chacha20_Vec128_sum_states(k2, st);
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_chacha20_core3(vec *k0, vec *k1, vec *k2, vec *st)
+{
+ Hacl_Impl_Chacha20_Vec128_chacha20_incr3(k0, k1, k2, st);
+ for (uint32_t i = (uint32_t)0U; i < (uint32_t)10U; i = i + (uint32_t)1U)
+ Hacl_Impl_Chacha20_Vec128_double_round3(k0, k1, k2);
+ Hacl_Impl_Chacha20_Vec128_chacha20_sum3(k0, k1, k2, st);
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_chacha20_block(uint8_t *stream_block, vec *st)
+{
+ KRML_CHECK_SIZE(vec_zero(), (uint32_t)4U);
+ vec k[4U];
+ for (uint32_t _i = 0U; _i < (uint32_t)4U; ++_i)
+ k[_i] = vec_zero();
+ Hacl_Impl_Chacha20_Vec128_chacha20_core(k, st);
+ Hacl_Impl_Chacha20_Vec128_State_state_to_key_block(stream_block, k);
+}
+
+inline static void
+Hacl_Impl_Chacha20_Vec128_init(vec *st, uint8_t *k, uint8_t *n1, uint32_t ctr)
+{
+ Hacl_Impl_Chacha20_Vec128_State_state_setup(st, k, n1, ctr);
+}
+
+static void
+Hacl_Impl_Chacha20_Vec128_update_last(uint8_t *output, uint8_t *plain, uint32_t len, vec *st)
+{
+ uint8_t block[64U] = { 0U };
+ Hacl_Impl_Chacha20_Vec128_chacha20_block(block, st);
+ uint8_t *mask = block;
+ for (uint32_t i = (uint32_t)0U; i < len; i = i + (uint32_t)1U) {
+ uint8_t xi = plain[i];
+ uint8_t yi = mask[i];
+ output[i] = xi ^ yi;
+ }
+}
+
+static void
+Hacl_Impl_Chacha20_Vec128_xor_block(uint8_t *output, uint8_t *plain, vec *st)
+{
+ vec p0 = vec_load_le(plain);
+ vec p1 = vec_load_le(plain + (uint32_t)16U);
+ vec p2 = vec_load_le(plain + (uint32_t)32U);
+ vec p3 = vec_load_le(plain + (uint32_t)48U);
+ vec k0 = st[0U];
+ vec k1 = st[1U];
+ vec k2 = st[2U];
+ vec k3 = st[3U];
+ vec o00 = vec_xor(p0, k0);
+ vec o10 = vec_xor(p1, k1);
+ vec o20 = vec_xor(p2, k2);
+ vec o30 = vec_xor(p3, k3);
+ uint8_t *o0 = output;
+ uint8_t *o1 = output + (uint32_t)16U;
+ uint8_t *o2 = output + (uint32_t)32U;
+ uint8_t *o3 = output + (uint32_t)48U;
+ vec_store_le(o0, o00);
+ vec_store_le(o1, o10);
+ vec_store_le(o2, o20);
+ vec_store_le(o3, o30);
+}
+
+static void
+Hacl_Impl_Chacha20_Vec128_update(uint8_t *output, uint8_t *plain, vec *st)
+{
+ KRML_CHECK_SIZE(vec_zero(), (uint32_t)4U);
+ vec k[4U];
+ for (uint32_t _i = 0U; _i < (uint32_t)4U; ++_i)
+ k[_i] = vec_zero();
+ Hacl_Impl_Chacha20_Vec128_chacha20_core(k, st);
+ Hacl_Impl_Chacha20_Vec128_xor_block(output, plain, k);
+}
+
+static void
+Hacl_Impl_Chacha20_Vec128_update3(uint8_t *output, uint8_t *plain, vec *st)
+{
+ KRML_CHECK_SIZE(vec_zero(), (uint32_t)4U);
+ vec k0[4U];
+ for (uint32_t _i = 0U; _i < (uint32_t)4U; ++_i)
+ k0[_i] = vec_zero();
+ KRML_CHECK_SIZE(vec_zero(), (uint32_t)4U);
+ vec k1[4U];
+ for (uint32_t _i = 0U; _i < (uint32_t)4U; ++_i)
+ k1[_i] = vec_zero();
+ KRML_CHECK_SIZE(vec_zero(), (uint32_t)4U);
+ vec k2[4U];
+ for (uint32_t _i = 0U; _i < (uint32_t)4U; ++_i)
+ k2[_i] = vec_zero();
+ Hacl_Impl_Chacha20_Vec128_chacha20_core3(k0, k1, k2, st);
+ uint8_t *p0 = plain;
+ uint8_t *p1 = plain + (uint32_t)64U;
+ uint8_t *p2 = plain + (uint32_t)128U;
+ uint8_t *o0 = output;
+ uint8_t *o1 = output + (uint32_t)64U;
+ uint8_t *o2 = output + (uint32_t)128U;
+ Hacl_Impl_Chacha20_Vec128_xor_block(o0, p0, k0);
+ Hacl_Impl_Chacha20_Vec128_xor_block(o1, p1, k1);
+ Hacl_Impl_Chacha20_Vec128_xor_block(o2, p2, k2);
+}
+
+static void
+Hacl_Impl_Chacha20_Vec128_update3_(
+ uint8_t *output,
+ uint8_t *plain,
+ uint32_t len,
+ vec *st,
+ uint32_t i)
+{
+ uint8_t *out_block = output + (uint32_t)192U * i;
+ uint8_t *plain_block = plain + (uint32_t)192U * i;
+ Hacl_Impl_Chacha20_Vec128_update3(out_block, plain_block, st);
+ Hacl_Impl_Chacha20_Vec128_state_incr(st);
+}
+
+static void
+Hacl_Impl_Chacha20_Vec128_chacha20_counter_mode_blocks3(
+ uint8_t *output,
+ uint8_t *plain,
+ uint32_t len,
+ vec *st)
+{
+ for (uint32_t i = (uint32_t)0U; i < len; i = i + (uint32_t)1U)
+ Hacl_Impl_Chacha20_Vec128_update3_(output, plain, len, st, i);
+}
+
+static void
+Hacl_Impl_Chacha20_Vec128_chacha20_counter_mode_blocks(
+ uint8_t *output,
+ uint8_t *plain,
+ uint32_t len,
+ vec *st)
+{
+ uint32_t len3 = len / (uint32_t)3U;
+ uint32_t rest3 = len % (uint32_t)3U;
+ uint8_t *plain_ = plain;
+ uint8_t *blocks1 = plain + (uint32_t)192U * len3;
+ uint8_t *output_ = output;
+ uint8_t *outs = output + (uint32_t)192U * len3;
+ Hacl_Impl_Chacha20_Vec128_chacha20_counter_mode_blocks3(output_, plain_, len3, st);
+ if (rest3 == (uint32_t)2U) {
+ uint8_t *block0 = blocks1;
+ uint8_t *block1 = blocks1 + (uint32_t)64U;
+ uint8_t *out0 = outs;
+ uint8_t *out1 = outs + (uint32_t)64U;
+ Hacl_Impl_Chacha20_Vec128_update(out0, block0, st);
+ Hacl_Impl_Chacha20_Vec128_state_incr(st);
+ Hacl_Impl_Chacha20_Vec128_update(out1, block1, st);
+ Hacl_Impl_Chacha20_Vec128_state_incr(st);
+ } else if (rest3 == (uint32_t)1U) {
+ Hacl_Impl_Chacha20_Vec128_update(outs, blocks1, st);
+ Hacl_Impl_Chacha20_Vec128_state_incr(st);
+ }
+}
+
+static void
+Hacl_Impl_Chacha20_Vec128_chacha20_counter_mode(
+ uint8_t *output,
+ uint8_t *plain,
+ uint32_t len,
+ vec *st)
+{
+ uint32_t blocks_len = len >> (uint32_t)6U;
+ uint32_t part_len = len & (uint32_t)0x3fU;
+ uint8_t *output_ = output;
+ uint8_t *plain_ = plain;
+ uint8_t *output__ = output + (uint32_t)64U * blocks_len;
+ uint8_t *plain__ = plain + (uint32_t)64U * blocks_len;
+ Hacl_Impl_Chacha20_Vec128_chacha20_counter_mode_blocks(output_, plain_, blocks_len, st);
+ if (part_len > (uint32_t)0U)
+ Hacl_Impl_Chacha20_Vec128_update_last(output__, plain__, part_len, st);
+}
+
+static void
+Hacl_Impl_Chacha20_Vec128_chacha20(
+ uint8_t *output,
+ uint8_t *plain,
+ uint32_t len,
+ uint8_t *k,
+ uint8_t *n1,
+ uint32_t ctr)
+{
+ KRML_CHECK_SIZE(vec_zero(), (uint32_t)4U);
+ vec buf[4U];
+ for (uint32_t _i = 0U; _i < (uint32_t)4U; ++_i)
+ buf[_i] = vec_zero();
+ vec *st = buf;
+ Hacl_Impl_Chacha20_Vec128_init(st, k, n1, ctr);
+ Hacl_Impl_Chacha20_Vec128_chacha20_counter_mode(output, plain, len, st);
+}
+
+void
+Hacl_Chacha20_Vec128_chacha20(
+ uint8_t *output,
+ uint8_t *plain,
+ uint32_t len,
+ uint8_t *k,
+ uint8_t *n1,
+ uint32_t ctr)
+{
+ Hacl_Impl_Chacha20_Vec128_chacha20(output, plain, len, k, n1, ctr);
+}
diff --git a/security/nss/lib/freebl/verified/Hacl_Chacha20_Vec128.h b/security/nss/lib/freebl/verified/Hacl_Chacha20_Vec128.h
new file mode 100644
index 000000000..57942093d
--- /dev/null
+++ b/security/nss/lib/freebl/verified/Hacl_Chacha20_Vec128.h
@@ -0,0 +1,61 @@
+/* Copyright 2016-2017 INRIA and Microsoft Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "kremlib.h"
+#ifndef __Hacl_Chacha20_Vec128_H
+#define __Hacl_Chacha20_Vec128_H
+
+#include "vec128.h"
+
+typedef uint32_t Hacl_Impl_Xor_Lemmas_u32;
+
+typedef uint8_t Hacl_Impl_Xor_Lemmas_u8;
+
+typedef uint32_t Hacl_Impl_Chacha20_Vec128_State_u32;
+
+typedef uint32_t Hacl_Impl_Chacha20_Vec128_State_h32;
+
+typedef uint8_t *Hacl_Impl_Chacha20_Vec128_State_uint8_p;
+
+typedef vec *Hacl_Impl_Chacha20_Vec128_State_state;
+
+typedef uint32_t Hacl_Impl_Chacha20_Vec128_u32;
+
+typedef uint32_t Hacl_Impl_Chacha20_Vec128_h32;
+
+typedef uint8_t *Hacl_Impl_Chacha20_Vec128_uint8_p;
+
+typedef uint32_t Hacl_Impl_Chacha20_Vec128_idx;
+
+typedef struct
+{
+ void *k;
+ void *n;
+ uint32_t ctr;
+} Hacl_Impl_Chacha20_Vec128_log_t_;
+
+typedef void *Hacl_Impl_Chacha20_Vec128_log_t;
+
+typedef uint8_t *Hacl_Chacha20_Vec128_uint8_p;
+
+void
+Hacl_Chacha20_Vec128_chacha20(
+ uint8_t *output,
+ uint8_t *plain,
+ uint32_t len,
+ uint8_t *k,
+ uint8_t *n1,
+ uint32_t ctr);
+#endif
diff --git a/security/nss/lib/freebl/verified/kremlib_base.h b/security/nss/lib/freebl/verified/kremlib_base.h
index 61bac11d4..14170625d 100644
--- a/security/nss/lib/freebl/verified/kremlib_base.h
+++ b/security/nss/lib/freebl/verified/kremlib_base.h
@@ -17,6 +17,7 @@
#define __KREMLIB_BASE_H
#include <inttypes.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/security/nss/lib/freebl/verified/vec128.h b/security/nss/lib/freebl/verified/vec128.h
new file mode 100644
index 000000000..986e9db82
--- /dev/null
+++ b/security/nss/lib/freebl/verified/vec128.h
@@ -0,0 +1,345 @@
+/* Copyright 2016-2017 INRIA and Microsoft Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __Vec_H
+#define __Vec_H
+
+#ifdef __MSVC__
+#define forceinline __forceinline inline
+#elif (defined(__GNUC__) || defined(__clang__))
+#define forceinline __attribute__((always_inline)) inline
+#else
+#define forceinline inline
+#endif
+
+#if defined(__SSSE3__) || defined(__AVX2__) || defined(__AVX__)
+
+#include <emmintrin.h>
+#include <tmmintrin.h>
+
+#define VEC128
+#define vec_size 4
+
+typedef __m128i vec;
+
+static forceinline vec
+vec_rotate_left_8(vec v)
+{
+ __m128i x = _mm_set_epi8(14, 13, 12, 15, 10, 9, 8, 11, 6, 5, 4, 7, 2, 1, 0, 3);
+ return _mm_shuffle_epi8(v, x);
+}
+
+static forceinline vec
+vec_rotate_left_16(vec v)
+{
+ __m128i x = _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2);
+ return _mm_shuffle_epi8(v, x);
+}
+
+static forceinline vec
+vec_rotate_left(vec v, unsigned int n)
+{
+ if (n == 8)
+ return vec_rotate_left_8(v);
+ if (n == 16)
+ return vec_rotate_left_16(v);
+ return _mm_xor_si128(_mm_slli_epi32(v, n),
+ _mm_srli_epi32(v, 32 - n));
+}
+
+static forceinline vec
+vec_rotate_right(vec v, unsigned int n)
+{
+ return (vec_rotate_left(v, 32 - n));
+}
+
+#define vec_shuffle_right(x, n) \
+ _mm_shuffle_epi32(x, _MM_SHUFFLE((3 + (n)) % 4, (2 + (n)) % 4, (1 + (n)) % 4, (n) % 4))
+
+#define vec_shuffle_left(x, n) vec_shuffle_right((x), 4 - (n))
+
+static forceinline vec
+vec_load_32x4(uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4)
+{
+ return _mm_set_epi32(x4, x3, x2, x1);
+}
+
+static forceinline vec
+vec_load_32x8(uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8)
+{
+ return _mm_set_epi32(x4, x3, x2, x1);
+}
+
+static forceinline vec
+vec_load_le(const unsigned char* in)
+{
+ return _mm_loadu_si128((__m128i*)(in));
+}
+
+static forceinline vec
+vec_load128_le(const unsigned char* in)
+{
+ return vec_load_le(in);
+}
+
+static forceinline void
+vec_store_le(unsigned char* out, vec v)
+{
+ _mm_storeu_si128((__m128i*)(out), v);
+}
+
+static forceinline vec
+vec_add(vec v1, vec v2)
+{
+ return _mm_add_epi32(v1, v2);
+}
+
+static forceinline vec
+vec_add_u32(vec v1, uint32_t x)
+{
+ vec v2 = vec_load_32x4(x, 0, 0, 0);
+ return _mm_add_epi32(v1, v2);
+}
+
+static forceinline vec
+vec_increment(vec v1)
+{
+ vec one = vec_load_32x4(1, 0, 0, 0);
+ return _mm_add_epi32(v1, one);
+}
+
+static forceinline vec
+vec_xor(vec v1, vec v2)
+{
+ return _mm_xor_si128(v1, v2);
+}
+
+#define vec_zero() _mm_set_epi32(0, 0, 0, 0)
+
+#elif defined(__ARM_NEON__) || defined(__ARM_NEON)
+#include <arm_neon.h>
+
+typedef uint32x4_t vec;
+
+static forceinline vec
+vec_xor(vec v1, vec v2)
+{
+ return veorq_u32(v1, v2);
+}
+
+#define vec_rotate_left(x, n) \
+ vsriq_n_u32(vshlq_n_u32((x), (n)), (x), 32 - (n))
+
+#define vec_rotate_right(a, b) \
+ vec_rotate_left((b), 32 - (b))
+
+#define vec_shuffle_right(x, n) \
+ vextq_u32((x), (x), (n))
+
+#define vec_shuffle_left(a, b) \
+ vec_shuffle_right((a), 4 - (b))
+
+static forceinline vec
+vec_load_32x4(uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4)
+{
+ uint32_t a[4] = { x1, x2, x3, x4 };
+ return vld1q_u32(a);
+}
+
+static forceinline vec
+vec_load_32(uint32_t x1)
+{
+ uint32_t a[4] = { x1, x1, x1, x1 };
+ return vld1q_u32(a);
+}
+
+static forceinline vec
+vec_load_32x8(uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8)
+{
+ return vec_load_32x4(x1, x2, x3, x4);
+}
+
+static forceinline vec
+vec_load_le(const unsigned char* in)
+{
+ return vld1q_u32((uint32_t*)in);
+}
+
+static forceinline vec
+vec_load128_le(const unsigned char* in)
+{
+ return vec_load_le(in);
+}
+
+static forceinline void
+vec_store_le(unsigned char* out, vec v)
+{
+ vst1q_u32((uint32_t*)out, v);
+}
+
+static forceinline vec
+vec_add(vec v1, vec v2)
+{
+ return vaddq_u32(v1, v2);
+}
+
+static forceinline vec
+vec_add_u32(vec v1, uint32_t x)
+{
+ vec v2 = vec_load_32x4(x, 0, 0, 0);
+ return vec_add(v1, v2);
+}
+
+static forceinline vec
+vec_increment(vec v1)
+{
+ vec one = vec_load_32x4(1, 0, 0, 0);
+ return vec_add(v1, one);
+}
+
+#define vec_zero() vec_load_32x4(0, 0, 0, 0)
+
+#else
+
+#define VEC128
+#define vec_size 4
+
+typedef struct {
+ uint32_t v[4];
+} vec;
+
+static forceinline vec
+vec_xor(vec v1, vec v2)
+{
+ vec r;
+ r.v[0] = v1.v[0] ^ v2.v[0];
+ r.v[1] = v1.v[1] ^ v2.v[1];
+ r.v[2] = v1.v[2] ^ v2.v[2];
+ r.v[3] = v1.v[3] ^ v2.v[3];
+ return r;
+}
+
+static forceinline vec
+vec_rotate_left(vec v, unsigned int n)
+{
+ vec r;
+ r.v[0] = (v.v[0] << n) ^ (v.v[0] >> (32 - n));
+ r.v[1] = (v.v[1] << n) ^ (v.v[1] >> (32 - n));
+ r.v[2] = (v.v[2] << n) ^ (v.v[2] >> (32 - n));
+ r.v[3] = (v.v[3] << n) ^ (v.v[3] >> (32 - n));
+ return r;
+}
+
+static forceinline vec
+vec_rotate_right(vec v, unsigned int n)
+{
+ return (vec_rotate_left(v, 32 - n));
+}
+
+static forceinline vec
+vec_shuffle_right(vec v, unsigned int n)
+{
+ vec r;
+ r.v[0] = v.v[n % 4];
+ r.v[1] = v.v[(n + 1) % 4];
+ r.v[2] = v.v[(n + 2) % 4];
+ r.v[3] = v.v[(n + 3) % 4];
+ return r;
+}
+
+static forceinline vec
+vec_shuffle_left(vec x, unsigned int n)
+{
+ return vec_shuffle_right(x, 4 - n);
+}
+
+static forceinline vec
+vec_load_32x4(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3)
+{
+ vec v;
+ v.v[0] = x0;
+ v.v[1] = x1;
+ v.v[2] = x2;
+ v.v[3] = x3;
+ return v;
+}
+
+static forceinline vec
+vec_load_32(uint32_t x0)
+{
+ vec v;
+ v.v[0] = x0;
+ v.v[1] = x0;
+ v.v[2] = x0;
+ v.v[3] = x0;
+ return v;
+}
+
+static forceinline vec
+vec_load_le(const uint8_t* in)
+{
+ vec r;
+ r.v[0] = load32_le((uint8_t*)in);
+ r.v[1] = load32_le((uint8_t*)in + 4);
+ r.v[2] = load32_le((uint8_t*)in + 8);
+ r.v[3] = load32_le((uint8_t*)in + 12);
+ return r;
+}
+
+static forceinline void
+vec_store_le(unsigned char* out, vec r)
+{
+ store32_le(out, r.v[0]);
+ store32_le(out + 4, r.v[1]);
+ store32_le(out + 8, r.v[2]);
+ store32_le(out + 12, r.v[3]);
+}
+
+static forceinline vec
+vec_load128_le(const unsigned char* in)
+{
+ return vec_load_le(in);
+}
+
+static forceinline vec
+vec_add(vec v1, vec v2)
+{
+ vec r;
+ r.v[0] = v1.v[0] + v2.v[0];
+ r.v[1] = v1.v[1] + v2.v[1];
+ r.v[2] = v1.v[2] + v2.v[2];
+ r.v[3] = v1.v[3] + v2.v[3];
+ return r;
+}
+
+static forceinline vec
+vec_add_u32(vec v1, uint32_t x)
+{
+ vec v2 = vec_load_32x4(x, 0, 0, 0);
+ return vec_add(v1, v2);
+}
+
+static forceinline vec
+vec_increment(vec v1)
+{
+ vec one = vec_load_32x4(1, 0, 0, 0);
+ return vec_add(v1, one);
+}
+
+#define vec_zero() vec_load_32x4(0, 0, 0, 0)
+
+#endif
+
+#endif
diff --git a/security/nss/lib/nss/nss.h b/security/nss/lib/nss/nss.h
index 62cf36730..d62f4957b 100644
--- a/security/nss/lib/nss/nss.h
+++ b/security/nss/lib/nss/nss.h
@@ -22,10 +22,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
-#define NSS_VERSION "3.35" _NSS_CUSTOMIZED
+#define NSS_VERSION "3.36.4" _NSS_CUSTOMIZED
#define NSS_VMAJOR 3
-#define NSS_VMINOR 35
-#define NSS_VPATCH 0
+#define NSS_VMINOR 36
+#define NSS_VPATCH 4
#define NSS_VBUILD 0
#define NSS_BETA PR_FALSE
diff --git a/security/nss/lib/pk11wrap/dev3hack.c b/security/nss/lib/pk11wrap/dev3hack.c
index 39afd6743..3fb0cb0aa 100644
--- a/security/nss/lib/pk11wrap/dev3hack.c
+++ b/security/nss/lib/pk11wrap/dev3hack.c
@@ -120,6 +120,10 @@ nssSlot_CreateFromPK11SlotInfo(NSSTrustDomain *td, PK11SlotInfo *nss3slot)
/* Grab the slot name from the PKCS#11 fixed-length buffer */
rvSlot->base.name = nssUTF8_Duplicate(nss3slot->slot_name, td->arena);
rvSlot->lock = (nss3slot->isThreadSafe) ? NULL : nss3slot->sessionLock;
+ rvSlot->isPresentLock = PZ_NewLock(nssiLockOther);
+ rvSlot->isPresentCondition = PR_NewCondVar(rvSlot->isPresentLock);
+ rvSlot->isPresentThread = NULL;
+ rvSlot->lastTokenPingState = nssSlotLastPingState_Reset;
return rvSlot;
}
diff --git a/security/nss/lib/pk11wrap/pk11auth.c b/security/nss/lib/pk11wrap/pk11auth.c
index 625fa2dc6..6a3ba40d9 100644
--- a/security/nss/lib/pk11wrap/pk11auth.c
+++ b/security/nss/lib/pk11wrap/pk11auth.c
@@ -636,7 +636,7 @@ PK11_DoPassword(PK11SlotInfo *slot, CK_SESSION_HANDLE session,
break;
}
if (rv == SECSuccess) {
- if (!PK11_IsFriendly(slot)) {
+ if (!contextSpecific && !PK11_IsFriendly(slot)) {
nssTrustDomain_UpdateCachedTokenCerts(slot->nssToken->trustDomain,
slot->nssToken);
}
diff --git a/security/nss/lib/pk11wrap/secmodi.h b/security/nss/lib/pk11wrap/secmodi.h
index 1225661ad..84f5f2a30 100644
--- a/security/nss/lib/pk11wrap/secmodi.h
+++ b/security/nss/lib/pk11wrap/secmodi.h
@@ -164,6 +164,7 @@ CERTCertificate *PK11_MakeCertFromHandle(PK11SlotInfo *slot,
SECItem *pk11_GenerateNewParamWithKeyLen(CK_MECHANISM_TYPE type, int keyLen);
SECItem *pk11_ParamFromIVWithLen(CK_MECHANISM_TYPE type,
SECItem *iv, int keyLen);
+SECItem *pk11_mkcertKeyID(CERTCertificate *cert);
SEC_END_PROTOS
diff --git a/security/nss/lib/pkcs12/p12d.c b/security/nss/lib/pkcs12/p12d.c
index dfe7015df..34362db2d 100644
--- a/security/nss/lib/pkcs12/p12d.c
+++ b/security/nss/lib/pkcs12/p12d.c
@@ -813,6 +813,7 @@ sec_pkcs12_decoder_asafes_notify(void *arg, PRBool before, void *dest,
unsigned int cnt = p12dcx->safeContentsCnt - 1;
safeContentsCtx = p12dcx->safeContentsList[cnt];
if (safeContentsCtx->safeContentsA1Dcx) {
+ SEC_ASN1DecoderClearFilterProc(p12dcx->aSafeA1Dcx);
SEC_ASN1DecoderFinish(safeContentsCtx->safeContentsA1Dcx);
safeContentsCtx->safeContentsA1Dcx = NULL;
}
diff --git a/security/nss/lib/pkcs7/p7create.c b/security/nss/lib/pkcs7/p7create.c
index a79d5aa26..f19330386 100644
--- a/security/nss/lib/pkcs7/p7create.c
+++ b/security/nss/lib/pkcs7/p7create.c
@@ -22,7 +22,7 @@ const int NSS_PBE_DEFAULT_ITERATION_COUNT = /* used in p12e.c too */
#ifdef DEBUG
10000
#else
- 1000000
+ 600000
#endif
;
diff --git a/security/nss/lib/pkcs7/p7decode.c b/security/nss/lib/pkcs7/p7decode.c
index 658c61e44..4f17b8e84 100644
--- a/security/nss/lib/pkcs7/p7decode.c
+++ b/security/nss/lib/pkcs7/p7decode.c
@@ -560,6 +560,7 @@ sec_pkcs7_decoder_start_decrypt(SEC_PKCS7DecoderContext *p7dcx, int depth,
return SECSuccess;
no_decryption:
+ PK11_FreeSymKey(bulkkey);
/*
* For some reason (error set already, if appropriate), we cannot
* decrypt the content. I am not sure what exactly is the right
@@ -1031,6 +1032,11 @@ SECStatus
SEC_PKCS7DecoderUpdate(SEC_PKCS7DecoderContext *p7dcx,
const char *buf, unsigned long len)
{
+ if (!p7dcx) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
if (p7dcx->cinfo != NULL && p7dcx->dcx != NULL) {
PORT_Assert(p7dcx->error == 0);
if (p7dcx->error == 0) {
diff --git a/security/nss/lib/pki/pkibase.c b/security/nss/lib/pki/pkibase.c
index 4082a37bd..f58a262cf 100644
--- a/security/nss/lib/pki/pkibase.c
+++ b/security/nss/lib/pki/pkibase.c
@@ -923,9 +923,11 @@ nssPKIObjectCollection_AddInstanceAsObject(
return PR_FAILURE;
}
if (!node->haveObject) {
+ nssPKIObject *original = node->object;
node->object = (*collection->createObject)(node->object);
if (!node->object) {
/*remove bogus object from list*/
+ nssPKIObject_Destroy(original);
nssPKIObjectCollection_RemoveNode(collection, node);
return PR_FAILURE;
}
diff --git a/security/nss/lib/softoken/softkver.h b/security/nss/lib/softoken/softkver.h
index 9fd99a8e0..f760ba21d 100644
--- a/security/nss/lib/softoken/softkver.h
+++ b/security/nss/lib/softoken/softkver.h
@@ -17,10 +17,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
-#define SOFTOKEN_VERSION "3.35" SOFTOKEN_ECC_STRING
+#define SOFTOKEN_VERSION "3.36.4" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VMAJOR 3
-#define SOFTOKEN_VMINOR 35
-#define SOFTOKEN_VPATCH 0
+#define SOFTOKEN_VMINOR 36
+#define SOFTOKEN_VPATCH 4
#define SOFTOKEN_VBUILD 0
#define SOFTOKEN_BETA PR_FALSE
diff --git a/security/nss/lib/ssl/SSLerrs.h b/security/nss/lib/ssl/SSLerrs.h
index c95fe661a..d3f087544 100644
--- a/security/nss/lib/ssl/SSLerrs.h
+++ b/security/nss/lib/ssl/SSLerrs.h
@@ -540,3 +540,6 @@ ER3(SSL_ERROR_RX_MALFORMED_KEY_UPDATE, (SSL_ERROR_BASE + 170),
ER3(SSL_ERROR_TOO_MANY_KEY_UPDATES, (SSL_ERROR_BASE + 171),
"SSL attempted too many key updates.")
+
+ER3(SSL_ERROR_HANDSHAKE_FAILED, (SSL_ERROR_BASE + 172),
+ "SSL handshake has already failed. No more operations possible.")
diff --git a/security/nss/lib/ssl/selfencrypt.c b/security/nss/lib/ssl/selfencrypt.c
index 97217b4a6..1c70f7635 100644
--- a/security/nss/lib/ssl/selfencrypt.c
+++ b/security/nss/lib/ssl/selfencrypt.c
@@ -192,75 +192,71 @@ ssl_SelfEncryptUnprotectInt(
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;
+ sslReader reader = SSL_READER(in, inLen);
- rv = ssl3_ConsumeFromItem(&inItem, &encodedKeyName,
- SELF_ENCRYPT_KEY_NAME_LEN);
+ sslReadBuffer encodedKeyNameBuffer = { 0 };
+ SECStatus rv = sslRead_Read(&reader, SELF_ENCRYPT_KEY_NAME_LEN,
+ &encodedKeyNameBuffer);
if (rv != SECSuccess) {
return SECFailure;
}
- rv = ssl3_ConsumeFromItem(&inItem, &iv, AES_BLOCK_SIZE);
+ sslReadBuffer ivBuffer = { 0 };
+ rv = sslRead_Read(&reader, AES_BLOCK_SIZE, &ivBuffer);
if (rv != SECSuccess) {
return SECFailure;
}
- rv = ssl3_ConsumeNumberFromItem(&inItem, &cipherTextLen, 2);
+ PRUint64 cipherTextLen = 0;
+ rv = sslRead_ReadNumber(&reader, 2, &cipherTextLen);
if (rv != SECSuccess) {
return SECFailure;
}
- rv = ssl3_ConsumeFromItem(&inItem, &cipherText, cipherTextLen);
+ sslReadBuffer cipherTextBuffer = { 0 };
+ rv = sslRead_Read(&reader, (unsigned int)cipherTextLen, &cipherTextBuffer);
if (rv != SECSuccess) {
return SECFailure;
}
- bytesToMac = inItem.data - in;
+ unsigned int bytesToMac = reader.offset;
- rv = ssl3_ConsumeFromItem(&inItem, &encodedMac, SHA256_LENGTH);
+ sslReadBuffer encodedMacBuffer = { 0 };
+ rv = sslRead_Read(&reader, SHA256_LENGTH, &encodedMacBuffer);
if (rv != SECSuccess) {
return SECFailure;
}
/* Make sure we're at the end of the block. */
- if (inItem.len) {
+ if (reader.offset != reader.buf.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)) {
+ if (PORT_Memcmp(keyName, encodedKeyNameBuffer.buf, SELF_ENCRYPT_KEY_NAME_LEN)) {
PORT_SetError(SEC_ERROR_NOT_A_RECIPIENT);
return SECFailure;
}
/* 2. Check the MAC */
+ unsigned char computedMac[SHA256_LENGTH];
+ unsigned int computedMacLen = 0;
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) {
+ if (NSS_SecureMemcmp(computedMac, encodedMacBuffer.buf, computedMacLen) != 0) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
/* 3. OK, it verifies, now decrypt. */
- ivItem.data = iv;
- ivItem.len = AES_BLOCK_SIZE;
+ SECItem ivItem = { siBuffer, (unsigned char *)ivBuffer.buf, AES_BLOCK_SIZE };
rv = PK11_Decrypt(encKey, CKM_AES_CBC_PAD, &ivItem,
- out, outLen, maxOutLen, cipherText, cipherTextLen);
+ out, outLen, maxOutLen, cipherTextBuffer.buf, cipherTextLen);
if (rv != SECSuccess) {
return SECFailure;
}
diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c
index 61878ae99..2593bbacc 100644
--- a/security/nss/lib/ssl/ssl3con.c
+++ b/security/nss/lib/ssl/ssl3con.c
@@ -183,9 +183,9 @@ static const SSLSignatureScheme defaultSignatureSchemes[] = {
ssl_sig_ecdsa_secp384r1_sha384,
ssl_sig_ecdsa_secp521r1_sha512,
ssl_sig_ecdsa_sha1,
- ssl_sig_rsa_pss_sha256,
- ssl_sig_rsa_pss_sha384,
- ssl_sig_rsa_pss_sha512,
+ ssl_sig_rsa_pss_rsae_sha256,
+ ssl_sig_rsa_pss_rsae_sha384,
+ ssl_sig_rsa_pss_rsae_sha512,
ssl_sig_rsa_pkcs1_sha256,
ssl_sig_rsa_pkcs1_sha384,
ssl_sig_rsa_pkcs1_sha512,
@@ -852,7 +852,7 @@ ssl3_config_match_init(sslSocket *ss)
* enabled, has a certificate (as needed), has a viable key agreement method, is
* usable with the negotiated TLS version, and is otherwise usable. */
static PRBool
-config_match(const ssl3CipherSuiteCfg *suite, int policy,
+config_match(const ssl3CipherSuiteCfg *suite, PRUint8 policy,
const SSLVersionRange *vrange, const sslSocket *ss)
{
const ssl3CipherSuiteDef *cipher_def;
@@ -888,7 +888,7 @@ config_match(const ssl3CipherSuiteCfg *suite, int policy,
/* Return the number of cipher suites that are usable. */
/* called from ssl3_SendClientHello */
static unsigned int
-count_cipher_suites(sslSocket *ss, int policy)
+count_cipher_suites(sslSocket *ss, PRUint8 policy)
{
unsigned int i, count = 0;
@@ -2336,6 +2336,11 @@ ssl3_SendRecord(sslSocket *ss,
if (ss->ssl3.fatalAlertSent) {
SSL_TRC(3, ("%d: SSL3[%d] Suppress write, fatal alert already sent",
SSL_GETPID(), ss->fd));
+ if (type != content_alert) {
+ /* If we are sending an alert, then we already have an
+ * error, so don't overwrite. */
+ PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED);
+ }
return SECFailure;
}
@@ -2647,9 +2652,7 @@ ssl3_HandleNoCertificate(sslSocket *ss)
(ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE))) {
PRFileDesc *lower;
- if (!ss->opt.noCache) {
- ss->sec.uncache(ss->sec.ci.sid);
- }
+ ssl_UncacheSessionID(ss);
SSL3_SendAlert(ss, alert_fatal, bad_certificate);
lower = ss->fd->lower;
@@ -2711,8 +2714,8 @@ SSL3_SendAlert(sslSocket *ss, SSL3AlertLevel level, SSL3AlertDescription desc)
ssl_GetSSL3HandshakeLock(ss);
}
if (level == alert_fatal) {
- if (!ss->opt.noCache && ss->sec.ci.sid) {
- ss->sec.uncache(ss->sec.ci.sid);
+ if (ss->sec.ci.sid) {
+ ssl_UncacheSessionID(ss);
}
}
@@ -2976,9 +2979,7 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf)
}
}
if (level == alert_fatal) {
- if (!ss->opt.noCache) {
- ss->sec.uncache(ss->sec.ci.sid);
- }
+ ssl_UncacheSessionID(ss);
if ((ss->ssl3.hs.ws == wait_server_hello) &&
(desc == handshake_failure)) {
/* XXX This is a hack. We're assuming that any handshake failure
@@ -3962,17 +3963,20 @@ ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme)
return ssl_hash_sha1;
case ssl_sig_rsa_pkcs1_sha256:
case ssl_sig_ecdsa_secp256r1_sha256:
- case ssl_sig_rsa_pss_sha256:
+ case ssl_sig_rsa_pss_rsae_sha256:
+ case ssl_sig_rsa_pss_pss_sha256:
case ssl_sig_dsa_sha256:
return ssl_hash_sha256;
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_ecdsa_secp384r1_sha384:
- case ssl_sig_rsa_pss_sha384:
+ case ssl_sig_rsa_pss_rsae_sha384:
+ case ssl_sig_rsa_pss_pss_sha384:
case ssl_sig_dsa_sha384:
return ssl_hash_sha384;
case ssl_sig_rsa_pkcs1_sha512:
case ssl_sig_ecdsa_secp521r1_sha512:
- case ssl_sig_rsa_pss_sha512:
+ case ssl_sig_rsa_pss_rsae_sha512:
+ case ssl_sig_rsa_pss_pss_sha512:
case ssl_sig_dsa_sha512:
return ssl_hash_sha512;
case ssl_sig_rsa_pkcs1_sha1md5:
@@ -3994,9 +3998,12 @@ ssl_SignatureSchemeToKeyType(SSLSignatureScheme scheme)
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_rsa_pkcs1_sha512:
case ssl_sig_rsa_pkcs1_sha1:
- case ssl_sig_rsa_pss_sha256:
- case ssl_sig_rsa_pss_sha384:
- case ssl_sig_rsa_pss_sha512:
+ case ssl_sig_rsa_pss_rsae_sha256:
+ case ssl_sig_rsa_pss_rsae_sha384:
+ case ssl_sig_rsa_pss_rsae_sha512:
+ case ssl_sig_rsa_pss_pss_sha256:
+ case ssl_sig_rsa_pss_pss_sha384:
+ case ssl_sig_rsa_pss_pss_sha512:
case ssl_sig_rsa_pkcs1_sha1md5:
return rsaKey;
case ssl_sig_ecdsa_secp256r1_sha256:
@@ -4131,9 +4138,9 @@ ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme)
case ssl_sig_rsa_pkcs1_sha256:
case ssl_sig_rsa_pkcs1_sha384:
case ssl_sig_rsa_pkcs1_sha512:
- case ssl_sig_rsa_pss_sha256:
- case ssl_sig_rsa_pss_sha384:
- case ssl_sig_rsa_pss_sha512:
+ case ssl_sig_rsa_pss_rsae_sha256:
+ case ssl_sig_rsa_pss_rsae_sha384:
+ case ssl_sig_rsa_pss_rsae_sha512:
case ssl_sig_ecdsa_secp256r1_sha256:
case ssl_sig_ecdsa_secp384r1_sha384:
case ssl_sig_ecdsa_secp521r1_sha512:
@@ -4145,6 +4152,9 @@ ssl_IsSupportedSignatureScheme(SSLSignatureScheme scheme)
return PR_TRUE;
case ssl_sig_rsa_pkcs1_sha1md5:
+ case ssl_sig_rsa_pss_pss_sha256:
+ case ssl_sig_rsa_pss_pss_sha384:
+ case ssl_sig_rsa_pss_pss_sha512:
case ssl_sig_none:
case ssl_sig_ed25519:
case ssl_sig_ed448:
@@ -4157,9 +4167,9 @@ PRBool
ssl_IsRsaPssSignatureScheme(SSLSignatureScheme scheme)
{
switch (scheme) {
- case ssl_sig_rsa_pss_sha256:
- case ssl_sig_rsa_pss_sha384:
- case ssl_sig_rsa_pss_sha512:
+ case ssl_sig_rsa_pss_rsae_sha256:
+ case ssl_sig_rsa_pss_rsae_sha384:
+ case ssl_sig_rsa_pss_rsae_sha512:
return PR_TRUE;
default:
@@ -4262,6 +4272,7 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss,
sizeof(stackBuf), &stateLen);
if (stateBuf == NULL) {
ssl_MapLowLevelError(SSL_ERROR_DIGEST_FAILURE);
+ rv = SECFailure;
goto tls12_loser;
}
rv |= PK11_DigestFinal(h, hashes->u.raw, &hashes->len,
@@ -4273,7 +4284,6 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss,
}
hashes->hashAlg = ssl3_GetSuitePrfHash(ss);
- rv = SECSuccess;
tls12_loser:
if (stateBuf) {
@@ -4305,6 +4315,7 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss,
sizeof md5StackBuf, &md5StateLen);
if (md5StateBuf == NULL) {
ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE);
+ rv = SECFailure;
goto loser;
}
md5 = ss->ssl3.hs.md5;
@@ -4313,6 +4324,7 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss,
sizeof shaStackBuf, &shaStateLen);
if (shaStateBuf == NULL) {
ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE);
+ rv = SECFailure;
goto loser;
}
sha = ss->ssl3.hs.sha;
@@ -4408,7 +4420,6 @@ ssl3_ComputeHandshakeHashes(sslSocket *ss,
PRINT_BUF(60, (NULL, "SHA outer: result", hashes->u.s.sha, SHA1_LENGTH));
hashes->len = MD5_LENGTH + SHA1_LENGTH;
- rv = SECSuccess;
loser:
if (md5StateBuf) {
@@ -4589,13 +4600,24 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
}
}
- /* We ignore ss->sec.ci.sid here, and use ssl_Lookup because Lookup
- * handles expired entries and other details.
- * XXX If we've been called from ssl_BeginClientHandshake, then
- * this lookup is duplicative and wasteful.
- */
- sid = (ss->opt.noCache) ? NULL
- : ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, ss->url);
+ /* Check if we have a ss->sec.ci.sid.
+ * Check that it's not expired.
+ * If we have an sid and it comes from an external cache, we use it. */
+ if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) {
+ PORT_Assert(!ss->sec.isServer);
+ sid = ss->sec.ci.sid;
+ SSL_TRC(3, ("%d: SSL3[%d]: using external resumption token in ClientHello",
+ SSL_GETPID(), ss->fd));
+ } else if (!ss->opt.noCache) {
+ /* We ignore ss->sec.ci.sid here, and use ssl_Lookup because Lookup
+ * handles expired entries and other details.
+ * XXX If we've been called from ssl_BeginClientHandshake, then
+ * this lookup is duplicative and wasteful.
+ */
+ sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID, ss->url);
+ } else {
+ sid = NULL;
+ }
/* We can't resume based on a different token. If the sid exists,
* make sure the token that holds the master secret still exists ...
@@ -4686,7 +4708,7 @@ ssl3_SendClientHello(sslSocket *ss, sslClientHelloType type)
if (!sidOK) {
SSL_AtomicIncrementLong(&ssl3stats.sch_sid_cache_not_ok);
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@@ -5017,7 +5039,7 @@ ssl3_HandleHelloRequest(sslSocket *ss)
}
if (sid) {
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
ss->sec.ci.sid = NULL;
}
@@ -6130,6 +6152,48 @@ ssl_ClientSetCipherSuite(sslSocket *ss, SSL3ProtocolVersion version,
return ssl3_SetupCipherSuite(ss, initHashes);
}
+/* Check that session ID we received from the server, if any, matches our
+ * expectations, depending on whether we're in compat mode and whether we
+ * negotiated TLS 1.3+ or TLS 1.2-.
+ */
+static PRBool
+ssl_CheckServerSessionIdCorrectness(sslSocket *ss, SECItem *sidBytes)
+{
+ sslSessionID *sid = ss->sec.ci.sid;
+ PRBool sidMatch = PR_FALSE;
+ PRBool sentFakeSid = PR_FALSE;
+ PRBool sentRealSid = sid && sid->version < SSL_LIBRARY_VERSION_TLS_1_3;
+
+ /* If attempting to resume a TLS 1.2 connection, the session ID won't be a
+ * fake. Check for the real value. */
+ if (sentRealSid) {
+ sidMatch = (sidBytes->len == sid->u.ssl3.sessionIDLength) &&
+ PORT_Memcmp(sid->u.ssl3.sessionID, sidBytes->data, sidBytes->len) == 0;
+ } else {
+ /* Otherwise, the session ID was a fake if TLS 1.3 compat mode is
+ * enabled. If so, check for the fake value. */
+ sentFakeSid = ss->opt.enableTls13CompatMode && !IS_DTLS(ss);
+ if (sentFakeSid && sidBytes->len == SSL3_SESSIONID_BYTES) {
+ PRUint8 buf[SSL3_SESSIONID_BYTES];
+ ssl_MakeFakeSid(ss, buf);
+ sidMatch = PORT_Memcmp(buf, sidBytes->data, sidBytes->len) == 0;
+ }
+ }
+
+ /* TLS 1.2: Session ID shouldn't match if we sent a fake. */
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ return !sentFakeSid || !sidMatch;
+ }
+
+ /* TLS 1.3: We sent a session ID. The server's should match. */
+ if (sentRealSid || sentFakeSid) {
+ return sidMatch;
+ }
+
+ /* TLS 1.3: The server shouldn't send a session ID. */
+ return sidBytes->len == 0;
+}
+
/* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete
* ssl3 ServerHello message.
* Caller must hold Handshake and RecvBuf locks.
@@ -6337,22 +6401,10 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
/* Check that the session ID is as expected. */
- if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
- PRUint8 buf[SSL3_SESSIONID_BYTES];
- unsigned int expectedSidLen;
- if (ss->opt.enableTls13CompatMode && !IS_DTLS(ss)) {
- expectedSidLen = SSL3_SESSIONID_BYTES;
- ssl_MakeFakeSid(ss, buf);
- } else {
- expectedSidLen = 0;
- }
- if (sidBytes.len != expectedSidLen ||
- (expectedSidLen > 0 &&
- PORT_Memcmp(buf, sidBytes.data, expectedSidLen) != 0)) {
- desc = illegal_parameter;
- errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
- goto alert_loser;
- }
+ if (!ssl_CheckServerSessionIdCorrectness(ss, &sidBytes)) {
+ desc = illegal_parameter;
+ errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
+ goto alert_loser;
}
/* Only initialize hashes if this isn't a Hello Retry. */
@@ -6592,7 +6644,7 @@ ssl3_HandleServerHelloPart2(sslSocket *ss, const SECItem *sidBytes,
/* throw the old one away */
sid->u.ssl3.keys.resumable = PR_FALSE;
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
/* get a new sid */
@@ -7502,8 +7554,6 @@ ssl3_NewSessionID(sslSocket *ss, PRBool is_server)
sid->u.ssl3.keys.resumable = PR_TRUE;
sid->u.ssl3.policy = SSL_ALLOWED;
- sid->u.ssl3.clientWriteKey = NULL;
- sid->u.ssl3.serverWriteKey = NULL;
sid->u.ssl3.keys.extendedMasterSecretUsed = PR_FALSE;
if (is_server) {
@@ -8102,6 +8152,9 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
rv = ssl3_HandleParsedExtensions(ss, ssl_hs_client_hello);
ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
if (rv != SECSuccess) {
+ if (PORT_GetError() == SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM) {
+ errCode = SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM;
+ }
goto loser; /* malformed */
}
@@ -8229,7 +8282,7 @@ ssl3_HandleClientHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
!ss->firstHsDone))) {
SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_not_ok);
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@@ -8435,7 +8488,7 @@ cipher_found:
}
if (ss->sec.ci.sid) {
- ss->sec.uncache(ss->sec.ci.sid);
+ ssl_UncacheSessionID(ss);
PORT_Assert(ss->sec.ci.sid != sid); /* should be impossible, but ... */
if (ss->sec.ci.sid != sid) {
ssl_FreeSID(ss->sec.ci.sid);
@@ -8531,7 +8584,7 @@ cipher_found:
if (sid) { /* we had a sid, but it's no longer valid, free it */
ss->statelessResume = PR_FALSE;
SSL_AtomicIncrementLong(&ssl3stats.hch_sid_cache_not_ok);
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@@ -8597,7 +8650,7 @@ alert_loser:
/* FALLTHRU */
loser:
if (sid && sid != ss->sec.ci.sid) {
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
}
@@ -11137,6 +11190,7 @@ ssl3_FillInCachedSID(sslSocket *ss, sslSessionID *sid, PK11SymKey *secret)
if (ss->xtnData.nextProtoState != SSL_NEXT_PROTO_NO_SUPPORT &&
ss->xtnData.nextProto.data) {
+ SECITEM_FreeItem(&sid->u.ssl3.alpnSelection, PR_FALSE);
if (SECITEM_CopyItem(
NULL, &sid->u.ssl3.alpnSelection, &ss->xtnData.nextProto) != SECSuccess) {
return SECFailure; /* error already set. */
@@ -11166,7 +11220,7 @@ ssl3_FinishHandshake(sslSocket *ss)
* the handshake is finished (we have verified the server's Finished
* AND the server's certificate) before we update the ticket in the sid.
*
- * This must be done before we call ss->sec.cache(ss->sec.ci.sid)
+ * This must be done before we call ssl_CacheSessionID(ss)
* because CacheSID requires the session ticket to already be set, and also
* because of the lazy lock creation scheme used by CacheSID and
* ssl3_SetSIDSessionTicket.
@@ -11181,7 +11235,7 @@ ssl3_FinishHandshake(sslSocket *ss)
if (ss->ssl3.hs.cacheSID) {
PORT_Assert(ss->sec.ci.sid->cached == never_cached);
- ss->sec.cache(ss->sec.ci.sid);
+ ssl_CacheSessionID(ss);
ss->ssl3.hs.cacheSID = PR_FALSE;
}
@@ -12645,8 +12699,8 @@ ssl3_RedoHandshake(sslSocket *ss, PRBool flushCache)
}
if (sid && flushCache) {
- ss->sec.uncache(sid); /* remove it from whichever cache it's in. */
- ssl_FreeSID(sid); /* dec ref count and free if zero. */
+ ssl_UncacheSessionID(ss); /* remove it from whichever cache it's in. */
+ ssl_FreeSID(sid); /* dec ref count and free if zero. */
ss->sec.ci.sid = NULL;
}
diff --git a/security/nss/lib/ssl/ssl3encode.c b/security/nss/lib/ssl/ssl3encode.c
deleted file mode 100644
index 960208a0f..000000000
--- a/security/nss/lib/ssl/ssl3encode.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/* -*- 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
deleted file mode 100644
index 3b88f7e7b..000000000
--- a/security/nss/lib/ssl/ssl3encode.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- 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 ade280903..5a5077998 100644
--- a/security/nss/lib/ssl/ssl3ext.c
+++ b/security/nss/lib/ssl/ssl3ext.c
@@ -519,6 +519,8 @@ ssl3_HandleParsedExtensions(sslSocket *ss, SSLHandshakeType message)
}
/* Fall through. */
case tls13_extension_disallowed:
+ SSL_TRC(3, ("%d: TLS13: unexpected extension %d in message %d",
+ SSL_GETPID(), extension, message));
tls13_FatalError(ss, SSL_ERROR_EXTENSION_DISALLOWED_FOR_VERSION,
unsupported_extension);
return SECFailure;
diff --git a/security/nss/lib/ssl/ssl3exthandle.c b/security/nss/lib/ssl/ssl3exthandle.c
index c0fbda7ab..e6388945e 100644
--- a/security/nss/lib/ssl/ssl3exthandle.c
+++ b/security/nss/lib/ssl/ssl3exthandle.c
@@ -182,7 +182,7 @@ ssl3_ClientSendSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData,
/* Never send an extension with a ticket for TLS 1.3, but
* OK to send the empty one in case the server does 1.2. */
- if (sid->cached == in_client_cache &&
+ if ((sid->cached == in_client_cache || sid->cached == in_external_cache) &&
sid->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
return SECSuccess;
}
@@ -821,7 +821,7 @@ ssl3_EncodeSessionTicket(sslSocket *ss, const NewSessionTicket *ticket,
if (rv != SECSuccess)
goto loser;
- rv = sslBuffer_AppendNumber(&plaintext, ssl_max_early_data_size, 4);
+ rv = sslBuffer_AppendNumber(&plaintext, ss->opt.maxEarlyDataSize, 4);
if (rv != SECSuccess)
goto loser;
@@ -1219,6 +1219,7 @@ ssl_CreateSIDFromTicket(sslSocket *ss, const SECItem *rawTicket,
}
}
if (parsedTicket->alpnSelection.data != NULL) {
+ SECITEM_FreeItem(&sid->u.ssl3.alpnSelection, PR_FALSE);
rv = SECITEM_CopyItem(NULL, &sid->u.ssl3.alpnSelection,
&parsedTicket->alpnSelection);
if (rv != SECSuccess) {
@@ -1245,7 +1246,7 @@ ssl3_ProcessSessionTicketCommon(sslSocket *ss, const SECItem *ticket,
SECStatus rv;
if (ss->sec.ci.sid != NULL) {
- ss->sec.uncache(ss->sec.ci.sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = NULL;
}
@@ -1652,11 +1653,16 @@ ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
&xtnData->sigSchemes,
&xtnData->numSigSchemes,
&data->data, &data->len);
- if (rv != SECSuccess || xtnData->numSigSchemes == 0) {
+ if (rv != SECSuccess) {
ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
PORT_SetError(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO);
return SECFailure;
}
+ if (xtnData->numSigSchemes == 0) {
+ ssl3_ExtSendAlert(ss, alert_fatal, handshake_failure);
+ PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
+ return SECFailure;
+ }
/* Check for trailing data. */
if (data->len != 0) {
ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
diff --git a/security/nss/lib/ssl/ssl3gthr.c b/security/nss/lib/ssl/ssl3gthr.c
index 20404f4da..8b323bb05 100644
--- a/security/nss/lib/ssl/ssl3gthr.c
+++ b/security/nss/lib/ssl/ssl3gthr.c
@@ -386,6 +386,13 @@ ssl3_GatherCompleteHandshake(sslSocket *ss, int flags)
SSL3Ciphertext cText;
PRBool keepGoing = PR_TRUE;
+ if (ss->ssl3.fatalAlertSent) {
+ SSL_TRC(3, ("%d: SSL3[%d] Cannot gather data; fatal alert already sent",
+ SSL_GETPID(), ss->fd));
+ PORT_SetError(SSL_ERROR_HANDSHAKE_FAILED);
+ return SECFailure;
+ }
+
SSL_TRC(30, ("%d: SSL3[%d]: ssl3_GatherCompleteHandshake",
SSL_GETPID(), ss->fd));
diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c
index 448170640..bc63e1537 100644
--- a/security/nss/lib/ssl/sslcon.c
+++ b/security/nss/lib/ssl/sslcon.c
@@ -119,13 +119,12 @@ ssl_CheckConfigSanity(sslSocket *ss)
SECStatus
ssl_BeginClientHandshake(sslSocket *ss)
{
- sslSessionID *sid;
+ sslSessionID *sid = NULL;
SECStatus rv;
PORT_Assert(ss->opt.noLocks || ssl_Have1stHandshakeLock(ss));
ss->sec.isServer = PR_FALSE;
- ssl_ChooseSessionIDProcs(&ss->sec);
rv = ssl_CheckConfigSanity(ss);
if (rv != SECSuccess)
@@ -156,19 +155,22 @@ ssl_BeginClientHandshake(sslSocket *ss)
SSL_TRC(3, ("%d: SSL[%d]: sending client-hello", SSL_GETPID(), ss->fd));
- /* Try to find server in our session-id cache */
- if (ss->opt.noCache) {
- sid = NULL;
- } else {
+ /* If there's an sid set from an external cache, use it. */
+ if (ss->sec.ci.sid && ss->sec.ci.sid->cached == in_external_cache) {
+ sid = ss->sec.ci.sid;
+ SSL_TRC(3, ("%d: SSL[%d]: using external token", SSL_GETPID(), ss->fd));
+ } else if (!ss->opt.noCache) {
+ /* Try to find server in our session-id cache */
sid = ssl_LookupSID(&ss->sec.ci.peer, ss->sec.ci.port, ss->peerID,
ss->url);
}
+
if (sid) {
if (sid->version >= ss->vrange.min && sid->version <= ss->vrange.max) {
PORT_Assert(!ss->sec.localCert);
ss->sec.localCert = CERT_DupCertificate(sid->localCert);
} else {
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@@ -218,7 +220,6 @@ ssl_BeginServerHandshake(sslSocket *ss)
ss->sec.isServer = PR_TRUE;
ss->ssl3.hs.ws = wait_client_hello;
- ssl_ChooseSessionIDProcs(&ss->sec);
rv = ssl_CheckConfigSanity(ss);
if (rv != SECSuccess)
diff --git a/security/nss/lib/ssl/sslencode.c b/security/nss/lib/ssl/sslencode.c
index 2f127fe8f..e50880451 100644
--- a/security/nss/lib/ssl/sslencode.c
+++ b/security/nss/lib/ssl/sslencode.c
@@ -29,6 +29,7 @@ ssl_EncodeUintX(PRUint8 *to, PRUint64 value, unsigned int bytes)
SECStatus
sslBuffer_Grow(sslBuffer *b, unsigned int newLen)
{
+ PORT_Assert(b);
if (b->fixed) {
PORT_Assert(newLen <= b->space);
if (newLen > b->space) {
@@ -84,6 +85,7 @@ sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data, unsigned int len,
unsigned int size)
{
PORT_Assert(size <= 4 && size > 0);
+ PORT_Assert(b);
if (len >= (1ULL << (8 * size))) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@@ -95,7 +97,11 @@ sslBuffer_AppendVariable(sslBuffer *b, const PRUint8 *data, unsigned int len,
ssl_EncodeUintX(SSL_BUFFER_NEXT(b), len, size);
b->len += size;
- PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len);
+ if (len != 0) {
+ PORT_Assert(data);
+ /* We sometimes pass NULL, 0 and memcpy() doesn't want NULL. */
+ PORT_Memcpy(SSL_BUFFER_NEXT(b), data, len);
+ }
b->len += len;
return SECSuccess;
}
@@ -169,37 +175,63 @@ sslBuffer_Clear(sslBuffer *b)
}
SECStatus
-ssl3_ConsumeFromItem(SECItem *item, unsigned char **buf, unsigned int size)
+sslRead_Read(sslReader *reader, unsigned int count, sslReadBuffer *out)
{
- if (size > item->len) {
+ if (!reader || !out) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (reader->buf.len < reader->offset ||
+ count > SSL_READER_REMAINING(reader)) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
- *buf = item->data;
- item->data += size;
- item->len -= size;
+ out->buf = SSL_READER_CURRENT(reader);
+ out->len = count;
+ reader->offset += count;
+
return SECSuccess;
}
SECStatus
-ssl3_ConsumeNumberFromItem(SECItem *item, PRUint32 *num, unsigned int size)
+sslRead_ReadVariable(sslReader *reader, unsigned int sizeLen, sslReadBuffer *out)
{
- int i;
-
- if (size > item->len || size > sizeof(*num)) {
+ PRUint64 variableLen = 0;
+ SECStatus rv = sslRead_ReadNumber(reader, sizeLen, &variableLen);
+ if (rv != SECSuccess) {
PORT_SetError(SEC_ERROR_BAD_DATA);
return SECFailure;
}
-
- *num = 0;
- for (i = 0; i < size; i++) {
- *num = (*num << 8) + item->data[i];
+ if (!variableLen) {
+ // It is ok to have an empty variable.
+ out->len = variableLen;
+ return SECSuccess;
}
+ return sslRead_Read(reader, variableLen, out);
+}
- item->data += size;
- item->len -= size;
+SECStatus
+sslRead_ReadNumber(sslReader *reader, unsigned int bytes, PRUint64 *num)
+{
+ if (!reader || !num) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (reader->buf.len < reader->offset ||
+ bytes > SSL_READER_REMAINING(reader) ||
+ bytes > 8) {
+ PORT_SetError(SEC_ERROR_BAD_DATA);
+ return SECFailure;
+ }
+ unsigned int i;
+ PRUint64 number = 0;
+ for (i = 0; i < bytes; i++) {
+ number = (number << 8) + reader->buf.buf[i + reader->offset];
+ }
+ reader->offset = reader->offset + bytes;
+ *num = number;
return SECSuccess;
}
diff --git a/security/nss/lib/ssl/sslencode.h b/security/nss/lib/ssl/sslencode.h
index a1b04d88f..f43e1c54b 100644
--- a/security/nss/lib/ssl/sslencode.h
+++ b/security/nss/lib/ssl/sslencode.h
@@ -47,13 +47,6 @@ SECStatus sslBuffer_InsertLength(sslBuffer *b, unsigned int at,
unsigned int size);
void sslBuffer_Clear(sslBuffer *b);
-/* All of these functions modify the underlying SECItem, and so should
- * be performed on a shallow copy.*/
-SECStatus ssl3_ConsumeFromItem(SECItem *item,
- PRUint8 **buf, unsigned int size);
-SECStatus ssl3_ConsumeNumberFromItem(SECItem *item,
- PRUint32 *num, unsigned int size);
-
SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src,
unsigned int bytes);
SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss,
@@ -66,4 +59,27 @@ SECStatus ssl3_AppendBufferToHandshake(sslSocket *ss, sslBuffer *buf);
SECStatus ssl3_AppendBufferToHandshakeVariable(sslSocket *ss, sslBuffer *buf,
unsigned int lenSize);
+typedef struct {
+ const PRUint8 *buf;
+ unsigned int len;
+} sslReadBuffer;
+typedef struct {
+ sslReadBuffer buf;
+ unsigned int offset;
+} sslReader;
+#define SSL_READER(b, l) \
+ { \
+ { b, l }, 0 \
+ }
+#define SSL_READER_CURRENT(r) \
+ ((r)->buf.buf + (r)->offset)
+#define SSL_READER_REMAINING(r) \
+ ((r)->buf.len - (r)->offset)
+SECStatus sslRead_Read(sslReader *reader, unsigned int count,
+ sslReadBuffer *out);
+SECStatus sslRead_ReadVariable(sslReader *reader, unsigned int sizeLen,
+ sslReadBuffer *out);
+SECStatus sslRead_ReadNumber(sslReader *reader, unsigned int bytes,
+ PRUint64 *val);
+
#endif /* __sslencode_h_ */
diff --git a/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h
index 90815dd79..b94d0cc62 100644
--- a/security/nss/lib/ssl/sslerr.h
+++ b/security/nss/lib/ssl/sslerr.h
@@ -260,6 +260,8 @@ typedef enum {
SSL_ERROR_RX_UNEXPECTED_KEY_UPDATE = (SSL_ERROR_BASE + 169),
SSL_ERROR_RX_MALFORMED_KEY_UPDATE = (SSL_ERROR_BASE + 170),
SSL_ERROR_TOO_MANY_KEY_UPDATES = (SSL_ERROR_BASE + 171),
+ SSL_ERROR_HANDSHAKE_FAILED = (SSL_ERROR_BASE + 172),
+ SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR = (SSL_ERROR_BASE + 173),
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/sslexp.h b/security/nss/lib/ssl/sslexp.h
index 569add861..08654f885 100644
--- a/security/nss/lib/ssl/sslexp.h
+++ b/security/nss/lib/ssl/sslexp.h
@@ -350,8 +350,111 @@ typedef SSLHelloRetryRequestAction(PR_CALLBACK *SSLHelloRetryRequestCallback)(
(PRFileDesc * _fd, PRBool _requestUpdate), \
(fd, requestUpdate))
-#define SSL_UseAltServerHelloType(fd, enable) \
- SSL_DEPRECATED_EXPERIMENTAL_API
+/*
+ * Session cache API.
+ */
+
+/*
+ * Information that can be retrieved about a resumption token.
+ * See SSL_GetResumptionTokenInfo for details about how to use this API.
+ * Note that peerCert points to a certificate in the NSS database and must be
+ * copied by the application if it should be used after NSS shutdown or after
+ * calling SSL_DestroyResumptionTokenInfo.
+ */
+typedef struct SSLResumptionTokenInfoStr {
+ PRUint16 length;
+ CERTCertificate *peerCert;
+ PRUint8 *alpnSelection;
+ PRUint32 alpnSelectionLen;
+ PRUint32 maxEarlyDataSize;
+} SSLResumptionTokenInfo;
+
+/*
+ * Allows applications to retrieve information about a resumption token.
+ * This does not require a TLS session.
+ *
+ * - The |tokenData| argument is a pointer to the resumption token as byte array
+ * of length |tokenLen|.
+ * - The |token| argument is a pointer to a SSLResumptionTokenInfo struct of
+ * of |len|. The struct gets filled by this function.
+ * See SSL_DestroyResumptionTokenInfo for information about how to manage the
+ * |token| memory.
+ */
+#define SSL_GetResumptionTokenInfo(tokenData, tokenLen, token, len) \
+ SSL_EXPERIMENTAL_API("SSL_GetResumptionTokenInfo", \
+ (const PRUint8 *_tokenData, unsigned int _tokenLen, \
+ SSLResumptionTokenInfo *_token, PRUintn _len), \
+ (tokenData, tokenLen, token, len))
+
+/*
+ * SSL_GetResumptionTokenInfo allocates memory in order to populate |tokenInfo|.
+ * Any SSLResumptionTokenInfo struct filled with SSL_GetResumptionTokenInfo
+ * has to be freed with SSL_DestroyResumptionTokenInfo.
+ */
+#define SSL_DestroyResumptionTokenInfo(tokenInfo) \
+ SSL_EXPERIMENTAL_API( \
+ "SSL_DestroyResumptionTokenInfo", \
+ (SSLResumptionTokenInfo * _tokenInfo), \
+ (tokenInfo))
+
+/*
+ * This is the function signature for function pointers used as resumption
+ * token callback. The caller has to copy the memory at |resumptionToken| with
+ * length |len| before returning.
+ *
+ * - The |fd| argument is the socket file descriptor.
+ * - The |resumptionToken| is a pointer to the resumption token as byte array
+ * of length |len|.
+ * - The |ctx| is a void pointer to the context set by the application in
+ * SSL_SetResumptionTokenCallback.
+ */
+typedef SECStatus(PR_CALLBACK *SSLResumptionTokenCallback)(
+ PRFileDesc *fd, const PRUint8 *resumptionToken, unsigned int len,
+ void *ctx);
+
+/*
+ * This allows setting a callback for external session caches to store
+ * resumption tokens.
+ *
+ * - The |fd| argument is the socket file descriptor.
+ * - The |cb| is a function pointer to an implementation of
+ * SSLResumptionTokenCallback.
+ * - The |ctx| is a pointer to some application specific context, which is
+ * returned when |cb| is called.
+ */
+#define SSL_SetResumptionTokenCallback(fd, cb, ctx) \
+ SSL_EXPERIMENTAL_API( \
+ "SSL_SetResumptionTokenCallback", \
+ (PRFileDesc * _fd, SSLResumptionTokenCallback _cb, void *_ctx), \
+ (fd, cb, ctx))
+
+/*
+ * This allows setting a resumption token for a session.
+ * The function returns SECSuccess iff the resumption token can be used,
+ * SECFailure in any other case. The caller should remove the |token| from its
+ * cache when the function returns SECFailure.
+ *
+ * - The |fd| argument is the socket file descriptor.
+ * - The |token| is a pointer to the resumption token as byte array
+ * of length |len|.
+ */
+#define SSL_SetResumptionToken(fd, token, len) \
+ SSL_EXPERIMENTAL_API( \
+ "SSL_SetResumptionToken", \
+ (PRFileDesc * _fd, const PRUint8 *_token, const unsigned int _len), \
+ (fd, token, len))
+
+/* TLS 1.3 allows a server to set a limit on the number of bytes of early data
+ * that can be received. This allows that limit to be set. This function has no
+ * effect on a client. */
+#define SSL_SetMaxEarlyDataSize(fd, size) \
+ SSL_EXPERIMENTAL_API("SSL_SetMaxEarlyDataSize", \
+ (PRFileDesc * _fd, PRUint32 _size), \
+ (fd, size))
+
+/* Deprecated experimental APIs */
+
+#define SSL_UseAltServerHelloType(fd, enable) SSL_DEPRECATED_EXPERIMENTAL_API
SEC_END_PROTOS
diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h
index dee9aa20f..10d0333d9 100644
--- a/security/nss/lib/ssl/sslimpl.h
+++ b/security/nss/lib/ssl/sslimpl.h
@@ -168,8 +168,11 @@ struct ssl3CertNodeStr {
typedef SECStatus (*sslHandshakeFunc)(sslSocket *ss);
-typedef void (*sslSessionIDCacheFunc)(sslSessionID *sid);
-typedef void (*sslSessionIDUncacheFunc)(sslSessionID *sid);
+void ssl_CacheSessionID(sslSocket *ss);
+void ssl_UncacheSessionID(sslSocket *ss);
+void ssl_ServerCacheSessionID(sslSessionID *sid);
+void ssl_ServerUncacheSessionID(sslSessionID *sid);
+
typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr,
unsigned char *sid,
unsigned int sidLen,
@@ -230,6 +233,7 @@ typedef struct sslOptionsStr {
* list of supported protocols. */
SECItem nextProtoNego;
+ PRUint32 maxEarlyDataSize;
unsigned int useSecurity : 1;
unsigned int useSocks : 1;
unsigned int requestCertificate : 1;
@@ -341,9 +345,11 @@ struct sslGatherStr {
#define GS_HEADER 1
#define GS_DATA 2
+#define WRAPPED_MASTER_SECRET_SIZE 48
+
typedef struct {
- PRUint8 wrapped_master_secret[48];
- PRUint16 wrapped_master_secret_len;
+ PRUint8 wrapped_master_secret[WRAPPED_MASTER_SECRET_SIZE];
+ PRUint8 wrapped_master_secret_len;
PRUint8 resumable;
PRUint8 extendedMasterSecretUsed;
} ssl3SidKeys; /* 52 bytes */
@@ -351,7 +357,8 @@ typedef struct {
typedef enum { never_cached,
in_client_cache,
in_server_cache,
- invalid_cache /* no longer in any cache. */
+ invalid_cache, /* no longer in any cache. */
+ in_external_cache
} Cached;
#include "sslcert.h"
@@ -398,17 +405,11 @@ struct sslSessionIDStr {
PRUint8 sessionID[SSL3_SESSIONID_BYTES];
ssl3CipherSuite cipherSuite;
- int policy;
+ PRUint8 policy;
ssl3SidKeys keys;
/* mechanism used to wrap master secret */
CK_MECHANISM_TYPE masterWrapMech;
- /* The following values are NOT restored from the server's on-disk
- * session cache, but are restored from the client's cache.
- */
- PK11SymKey *clientWriteKey;
- PK11SymKey *serverWriteKey;
-
/* The following values pertain to the slot that wrapped the
** master secret. (used only in client)
*/
@@ -740,7 +741,7 @@ struct ssl3StateStr {
CERTCertificateList *clientCertChain; /* used by client */
PRBool sendEmptyCert; /* used by client */
- int policy;
+ PRUint8 policy;
/* This says what cipher suites we can do, and should
* be either SSL_ALLOWED or SSL_RESTRICTED
*/
@@ -897,14 +898,6 @@ struct sslSecurityInfoStr {
/* The selected certificate (for servers only). */
const sslServerCert *serverCert;
- /*
- ** Procs used for SID cache (nonce) management.
- ** Different implementations exist for clients/servers
- ** The lookup proc is only used for servers. Baloney!
- */
- sslSessionIDCacheFunc cache;
- sslSessionIDUncacheFunc uncache;
-
/* These are used during a connection handshake */
sslConnectInfo ci;
};
@@ -982,6 +975,8 @@ struct sslSocketStr {
SSLHelloRetryRequestCallback hrrCallback;
void *hrrCallbackArg;
PRCList extensionHooks;
+ SSLResumptionTokenCallback resumptionTokenCallback;
+ void *resumptionTokenContext;
PRIntervalTime rTimeout; /* timeout for NSPR I/O */
PRIntervalTime wTimeout; /* timeout for NSPR I/O */
@@ -1075,13 +1070,10 @@ extern FILE *ssl_keylog_iob;
extern PZLock *ssl_keylog_lock;
extern PRUint32 ssl3_sid_timeout;
extern PRUint32 ssl_ticket_lifetime;
-extern PRUint32 ssl_max_early_data_size;
extern const char *const ssl3_cipherName[];
extern sslSessionIDLookupFunc ssl_sid_lookup;
-extern sslSessionIDCacheFunc ssl_sid_cache;
-extern sslSessionIDUncacheFunc ssl_sid_uncache;
extern const sslNamedGroupDef ssl_named_groups[];
@@ -1163,14 +1155,13 @@ extern SECStatus ssl_BeginClientHandshake(sslSocket *ss);
extern SECStatus ssl_BeginServerHandshake(sslSocket *ss);
extern int ssl_Do1stHandshake(sslSocket *ss);
-extern void ssl_ChooseSessionIDProcs(sslSecurityInfo *sec);
-
extern SECStatus ssl3_InitPendingCipherSpecs(sslSocket *ss, PK11SymKey *secret,
PRBool derive);
extern sslSessionID *ssl3_NewSessionID(sslSocket *ss, PRBool is_server);
extern sslSessionID *ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port,
const char *peerID, const char *urlSvrName);
extern void ssl_FreeSID(sslSessionID *sid);
+extern void ssl_DestroySID(sslSessionID *sid, PRBool freeIt);
extern int ssl3_SendApplicationData(sslSocket *ss, const PRUint8 *in,
int len, int flags);
@@ -1692,6 +1683,26 @@ PRBool ssl_AlpnTagAllowed(const sslSocket *ss, const SECItem *tag);
void ssl_Trace(const char *format, ...);
+void ssl_CacheExternalToken(sslSocket *ss);
+SECStatus ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedTicket,
+ PRUint32 encodedTicketLen);
+PRBool ssl_IsResumptionTokenValid(sslSocket *ss);
+
+/* Remove when stable. */
+
+SECStatus SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
+ SSLResumptionTokenCallback cb,
+ void *ctx);
+SECStatus SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
+ unsigned int len);
+
+SECStatus SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int tokenLen,
+ SSLResumptionTokenInfo *token, unsigned int version);
+
+SECStatus SSLExp_DestroyResumptionTokenInfo(SSLResumptionTokenInfo *token);
+
+#define SSLResumptionTokenVersion 2
+
SEC_END_PROTOS
#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
diff --git a/security/nss/lib/ssl/sslinit.c b/security/nss/lib/ssl/sslinit.c
index 0f38c0b57..07d57ce6e 100644
--- a/security/nss/lib/ssl/sslinit.c
+++ b/security/nss/lib/ssl/sslinit.c
@@ -15,6 +15,7 @@
static int ssl_isInited = 0;
static PRCallOnceType ssl_init = { 0 };
+PR_STATIC_ASSERT(sizeof(unsigned long) <= sizeof(PRUint64));
PRStatus
ssl_InitCallOnce(void *arg)
diff --git a/security/nss/lib/ssl/sslnonce.c b/security/nss/lib/ssl/sslnonce.c
index 228834e3d..f79c23fc7 100644
--- a/security/nss/lib/ssl/sslnonce.c
+++ b/security/nss/lib/ssl/sslnonce.c
@@ -15,6 +15,7 @@
#include "sslimpl.h"
#include "sslproto.h"
#include "nssilock.h"
+#include "sslencode.h"
#if defined(XP_UNIX) || defined(XP_WIN) || defined(_WINDOWS) || defined(XP_BEOS)
#include <time.h>
#endif
@@ -24,12 +25,13 @@ PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
static sslSessionID *cache = NULL;
static PZLock *cacheLock = NULL;
-/* sids can be in one of 4 states:
+/* sids can be in one of 5 states:
*
* never_cached, created, but not yet put into cache.
* in_client_cache, in the client cache's linked list.
* in_server_cache, entry came from the server's cache file.
* invalid_cache has been removed from the cache.
+ * in_external_cache sid comes from an external cache.
*/
#define LOCK_CACHE lock_cache()
@@ -164,8 +166,8 @@ lock_cache(void)
/* BEWARE: This function gets called for both client and server SIDs !!
* If the unreferenced sid is not in the cache, Free sid and its contents.
*/
-static void
-ssl_DestroySID(sslSessionID *sid)
+void
+ssl_DestroySID(sslSessionID *sid, PRBool freeIt)
{
SSL_TRC(8, ("SSL: destroy sid: sid=0x%x cached=%d", sid, sid->cached));
PORT_Assert(sid->references == 0);
@@ -186,11 +188,8 @@ ssl_DestroySID(sslSessionID *sid)
PR_DestroyRWLock(sid->u.ssl3.lock);
}
- if (sid->peerID != NULL)
- PORT_Free((void *)sid->peerID); /* CONST */
-
- if (sid->urlSvrName != NULL)
- PORT_Free((void *)sid->urlSvrName); /* CONST */
+ PORT_Free((void *)sid->peerID);
+ PORT_Free((void *)sid->urlSvrName);
if (sid->peerCert) {
CERT_DestroyCertificate(sid->peerCert);
@@ -205,7 +204,9 @@ ssl_DestroySID(sslSessionID *sid)
SECITEM_FreeItem(&sid->u.ssl3.alpnSelection, PR_FALSE);
- PORT_ZFree(sid, sizeof(sslSessionID));
+ if (freeIt) {
+ PORT_ZFree(sid, sizeof(sslSessionID));
+ }
}
/* BEWARE: This function gets called for both client and server SIDs !!
@@ -220,7 +221,7 @@ ssl_FreeLockedSID(sslSessionID *sid)
{
PORT_Assert(sid->references >= 1);
if (--sid->references == 0) {
- ssl_DestroySID(sid);
+ ssl_DestroySID(sid, PR_TRUE);
}
}
@@ -306,6 +307,7 @@ ssl_LookupSID(const PRIPv6Addr *addr, PRUint16 port, const char *peerID,
static void
CacheSID(sslSessionID *sid)
{
+ PORT_Assert(sid);
PORT_Assert(sid->cached == never_cached);
SSL_TRC(8, ("SSL: Cache: sid=0x%x cached=%d addr=0x%08x%08x%08x%08x port=0x%04x "
@@ -400,7 +402,7 @@ UncacheSID(sslSessionID *zap)
/* If sid "zap" is in the cache,
* removes sid from cache, and decrements reference count.
* Although this function is static, it is called externally via
- * ss->sec.uncache().
+ * ssl_UncacheSessionID.
*/
static void
LockAndUncacheSID(sslSessionID *zap)
@@ -410,16 +412,734 @@ LockAndUncacheSID(sslSessionID *zap)
UNLOCK_CACHE;
}
-/* choose client or server cache functions for this sslsocket. */
+SECStatus
+ReadVariableFromBuffer(sslReader *reader, sslReadBuffer *readerBuffer,
+ uint8_t lenBytes, SECItem *dest)
+{
+ if (sslRead_ReadVariable(reader, lenBytes, readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer->len) {
+ SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer->buf,
+ readerBuffer->len };
+ SECStatus rv = SECITEM_CopyItem(NULL, dest, &tempItem);
+ if (rv != SECSuccess) {
+ return rv;
+ }
+ }
+ return SECSuccess;
+}
+
+/* Fill sid with the values from the encoded resumption token.
+ * sid has to be allocated.
+ * We don't care about locks here as this cache entry is externally stored.
+ */
+SECStatus
+ssl_DecodeResumptionToken(sslSessionID *sid, const PRUint8 *encodedToken,
+ PRUint32 encodedTokenLen)
+{
+ PORT_Assert(encodedTokenLen);
+ PORT_Assert(encodedToken);
+ PORT_Assert(sid);
+ if (!sid || !encodedToken || !encodedTokenLen) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (encodedToken[0] != SSLResumptionTokenVersion) {
+ /* Unknown token format version. */
+ PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
+ return SECFailure;
+ }
+
+ /* These variables are used across macros. Don't use them outside. */
+ sslReader reader = SSL_READER(encodedToken, encodedTokenLen);
+ reader.offset += 1; // We read the version already. Skip the first byte.
+ sslReadBuffer readerBuffer = { 0 };
+ PRUint64 tmpInt = 0;
+
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->lastAccessTime = (PRTime)tmpInt;
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->expirationTime = (PRTime)tmpInt;
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.locked.sessionTicket.received_timestamp = (PRTime)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint = (PRUint32)tmpInt;
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.locked.sessionTicket.flags = (PRUint32)tmpInt;
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.locked.sessionTicket.ticket_age_add = (PRUint32)tmpInt;
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.locked.sessionTicket.max_early_data_size = (PRUint32)tmpInt;
+
+ if (sslRead_ReadVariable(&reader, 3, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer.len) {
+ PORT_Assert(!sid->peerCert);
+ SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
+ readerBuffer.len };
+ sid->peerCert = CERT_NewTempCertificate(NULL, /* dbHandle */
+ &tempItem,
+ NULL, PR_FALSE, PR_TRUE);
+ if (!sid->peerCert) {
+ return SECFailure;
+ }
+ }
+
+ if (sslRead_ReadVariable(&reader, 2, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer.len) {
+ SECITEM_AllocArray(NULL, &sid->peerCertStatus, 1);
+ if (!sid->peerCertStatus.items) {
+ return SECFailure;
+ }
+ SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
+ readerBuffer.len };
+ SECITEM_CopyItem(NULL, &sid->peerCertStatus.items[0], &tempItem);
+ }
+
+ if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer.len) {
+ PORT_Assert(readerBuffer.buf);
+ sid->peerID = PORT_Strdup((const char *)readerBuffer.buf);
+ }
+
+ if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer.len) {
+ if (sid->urlSvrName) {
+ PORT_Free((void *)sid->urlSvrName);
+ }
+ PORT_Assert(readerBuffer.buf);
+ sid->urlSvrName = PORT_Strdup((const char *)readerBuffer.buf);
+ }
+
+ if (sslRead_ReadVariable(&reader, 3, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer.len) {
+ PORT_Assert(!sid->localCert);
+ SECItem tempItem = { siBuffer, (unsigned char *)readerBuffer.buf,
+ readerBuffer.len };
+ sid->localCert = CERT_NewTempCertificate(NULL, /* dbHandle */
+ &tempItem,
+ NULL, PR_FALSE, PR_TRUE);
+ }
+
+ if (sslRead_ReadNumber(&reader, 8, &sid->addr.pr_s6_addr64[0]) != SECSuccess) {
+ return SECFailure;
+ }
+ if (sslRead_ReadNumber(&reader, 8, &sid->addr.pr_s6_addr64[1]) != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->port = (PRUint16)tmpInt;
+ if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->version = (PRUint16)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->creationTime = (PRTime)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->authType = (SSLAuthType)tmpInt;
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->authKeyBits = (PRUint32)tmpInt;
+ if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->keaType = (SSLKEAType)tmpInt;
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->keaKeyBits = (PRUint32)tmpInt;
+ if (sslRead_ReadNumber(&reader, 3, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->keaGroup = (SSLNamedGroup)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 3, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->sigScheme = (SSLSignatureScheme)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.sessionIDLength = (PRUint8)tmpInt;
+
+ if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (readerBuffer.len) {
+ PORT_Assert(readerBuffer.buf);
+ PORT_Memcpy(sid->u.ssl3.sessionID, readerBuffer.buf, readerBuffer.len);
+ }
+
+ if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.cipherSuite = (PRUint16)tmpInt;
+ if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.policy = (PRUint8)tmpInt;
+
+ if (sslRead_ReadVariable(&reader, 1, &readerBuffer) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ PORT_Assert(readerBuffer.len == WRAPPED_MASTER_SECRET_SIZE);
+ if (readerBuffer.len != WRAPPED_MASTER_SECRET_SIZE) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ PORT_Assert(readerBuffer.buf);
+ PORT_Memcpy(sid->u.ssl3.keys.wrapped_master_secret, readerBuffer.buf,
+ readerBuffer.len);
+
+ if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.keys.wrapped_master_secret_len = (PRUint8)tmpInt;
+ if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.keys.extendedMasterSecretUsed = (PRUint8)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.masterWrapMech = (unsigned long)tmpInt;
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.masterModuleID = (unsigned long)tmpInt;
+ if (sslRead_ReadNumber(&reader, 8, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.masterSlotID = (unsigned long)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 4, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.masterWrapIndex = (PRUint32)tmpInt;
+ if (sslRead_ReadNumber(&reader, 2, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.masterWrapSeries = (PRUint16)tmpInt;
+
+ if (sslRead_ReadNumber(&reader, 1, &tmpInt) != SECSuccess) {
+ return SECFailure;
+ }
+ sid->u.ssl3.masterValid = (char)tmpInt;
+
+ if (ReadVariableFromBuffer(&reader, &readerBuffer, 1,
+ &sid->u.ssl3.srvName) != SECSuccess) {
+ return SECFailure;
+ }
+ if (ReadVariableFromBuffer(&reader, &readerBuffer, 2,
+ &sid->u.ssl3.signedCertTimestamps) != SECSuccess) {
+ return SECFailure;
+ }
+ if (ReadVariableFromBuffer(&reader, &readerBuffer, 1,
+ &sid->u.ssl3.alpnSelection) != SECSuccess) {
+ return SECFailure;
+ }
+ if (ReadVariableFromBuffer(&reader, &readerBuffer, 2,
+ &sid->u.ssl3.locked.sessionTicket.ticket) != SECSuccess) {
+ return SECFailure;
+ }
+ if (!sid->u.ssl3.locked.sessionTicket.ticket.len) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* At this point we must have read everything. */
+ PORT_Assert(reader.offset == reader.buf.len);
+ if (reader.offset != reader.buf.len) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+PRBool
+ssl_IsResumptionTokenValid(sslSocket *ss)
+{
+ PORT_Assert(ss);
+ sslSessionID *sid = ss->sec.ci.sid;
+ PORT_Assert(sid);
+
+ // Check that the ticket didn't expire.
+ PRTime endTime = 0;
+ NewSessionTicket *ticket = &sid->u.ssl3.locked.sessionTicket;
+ if (ticket->ticket_lifetime_hint != 0) {
+ endTime = ticket->received_timestamp +
+ (PRTime)(ticket->ticket_lifetime_hint * PR_USEC_PER_SEC);
+ if (endTime < ssl_TimeUsec()) {
+ return PR_FALSE;
+ }
+ }
+
+ // Check that the session entry didn't expire.
+ if (sid->expirationTime < ssl_TimeUsec()) {
+ return PR_FALSE;
+ }
+
+ // Check that the server name (SNI) matches the one set for this session.
+ // Don't use the token if there's no server name.
+ if (sid->urlSvrName == NULL || PORT_Strcmp(ss->url, sid->urlSvrName) != 0) {
+ return PR_FALSE;
+ }
+
+ // This shouldn't be false, but let's check it anyway.
+ if (!sid->u.ssl3.keys.resumable) {
+ return PR_FALSE;
+ }
+
+ return PR_TRUE;
+}
+
+/* Encode a session ticket into a byte array that can be handed out to a cache.
+ * Needed memory in encodedToken has to be allocated according to
+ * *encodedTokenLen. */
+static SECStatus
+ssl_EncodeResumptionToken(sslSessionID *sid, sslBuffer *encodedTokenBuf)
+{
+ PORT_Assert(encodedTokenBuf);
+ PORT_Assert(sid);
+ if (!sid || !sid->u.ssl3.locked.sessionTicket.ticket.len ||
+ !encodedTokenBuf || !sid->u.ssl3.keys.resumable || !sid->urlSvrName) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* Encoding format:
+ * 0-byte: version
+ * Integers are encoded according to their length.
+ * SECItems are prepended with a 64-bit length field followed by the bytes.
+ * Optional bytes are encoded as a 0-length item if not present.
+ */
+ SECStatus rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ SSLResumptionTokenVersion, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->lastAccessTime, 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->expirationTime, 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ // session ticket
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.locked.sessionTicket.received_timestamp,
+ 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.locked.sessionTicket.ticket_lifetime_hint,
+ 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.locked.sessionTicket.flags,
+ 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.locked.sessionTicket.ticket_age_add,
+ 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.locked.sessionTicket.max_early_data_size,
+ 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendVariable(encodedTokenBuf, sid->peerCert->derCert.data,
+ sid->peerCert->derCert.len, 3);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (sid->peerCertStatus.len > 1) {
+ /* This is not implemented so it shouldn't happen.
+ * If it gets implemented, this has to change.
+ */
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+
+ if (sid->peerCertStatus.len == 1 && sid->peerCertStatus.items[0].len) {
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ sid->peerCertStatus.items[0].data,
+ sid->peerCertStatus.items[0].len, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ } else {
+ rv = sslBuffer_AppendVariable(encodedTokenBuf, NULL, 0, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+
+ PRUint64 len = sid->peerID ? strlen(sid->peerID) : 0;
+ if (len > PR_UINT8_MAX) {
+ // This string really shouldn't be that long.
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ (const unsigned char *)sid->peerID, len, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ len = sid->urlSvrName ? strlen(sid->urlSvrName) : 0;
+ if (!len) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (len > PR_UINT8_MAX) {
+ // This string really shouldn't be that long.
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ (const unsigned char *)sid->urlSvrName,
+ len, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ if (sid->localCert) {
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ sid->localCert->derCert.data,
+ sid->localCert->derCert.len, 3);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ } else {
+ rv = sslBuffer_AppendVariable(encodedTokenBuf, NULL, 0, 3);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->addr.pr_s6_addr64[0], 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->addr.pr_s6_addr64[1], 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->port, 2);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->version, 2);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->creationTime, 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->authType, 2);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->authKeyBits, 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->keaType, 2);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->keaKeyBits, 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->keaGroup, 3);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->sigScheme, 3);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.sessionIDLength, 1);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendVariable(encodedTokenBuf, sid->u.ssl3.sessionID,
+ SSL3_SESSIONID_BYTES, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.cipherSuite, 2);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.policy, 1);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ sid->u.ssl3.keys.wrapped_master_secret,
+ WRAPPED_MASTER_SECRET_SIZE, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.keys.wrapped_master_secret_len,
+ 1);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf,
+ sid->u.ssl3.keys.extendedMasterSecretUsed,
+ 1);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterWrapMech, 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterModuleID, 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterSlotID, 8);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterWrapIndex, 4);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterWrapSeries, 2);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendNumber(encodedTokenBuf, sid->u.ssl3.masterValid, 1);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendVariable(encodedTokenBuf, sid->u.ssl3.srvName.data,
+ sid->u.ssl3.srvName.len, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ sid->u.ssl3.signedCertTimestamps.data,
+ sid->u.ssl3.signedCertTimestamps.len, 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ sid->u.ssl3.alpnSelection.data,
+ sid->u.ssl3.alpnSelection.len, 1);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ PORT_Assert(sid->u.ssl3.locked.sessionTicket.ticket.len > 1);
+ rv = sslBuffer_AppendVariable(encodedTokenBuf,
+ sid->u.ssl3.locked.sessionTicket.ticket.data,
+ sid->u.ssl3.locked.sessionTicket.ticket.len,
+ 2);
+ if (rv != SECSuccess) {
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
void
-ssl_ChooseSessionIDProcs(sslSecurityInfo *sec)
+ssl_CacheExternalToken(sslSocket *ss)
{
+ PORT_Assert(ss);
+ sslSessionID *sid = ss->sec.ci.sid;
+ PORT_Assert(sid);
+ PORT_Assert(sid->cached == never_cached);
+ PORT_Assert(ss->resumptionTokenCallback);
+
+ SSL_TRC(8, ("SSL [%d]: Cache External: sid=0x%x cached=%d "
+ "addr=0x%08x%08x%08x%08x port=0x%04x time=%x cached=%d",
+ ss->fd,
+ sid, sid->cached, sid->addr.pr_s6_addr32[0],
+ sid->addr.pr_s6_addr32[1], sid->addr.pr_s6_addr32[2],
+ sid->addr.pr_s6_addr32[3], sid->port, sid->creationTime,
+ sid->cached));
+
+ /* This is only available for stateless resumption. */
+ if (sid->u.ssl3.locked.sessionTicket.ticket.data == NULL) {
+ return;
+ }
+
+ /* Don't export token if the session used client authentication. */
+ if (sid->u.ssl3.clAuthValid) {
+ return;
+ }
+
+ if (!sid->creationTime) {
+ sid->lastAccessTime = sid->creationTime = ssl_TimeUsec();
+ }
+ if (!sid->expirationTime) {
+ sid->expirationTime = sid->creationTime + ssl3_sid_timeout;
+ }
+
+ sslBuffer encodedToken = SSL_BUFFER_EMPTY;
+
+ if (ssl_EncodeResumptionToken(sid, &encodedToken) != SECSuccess) {
+ SSL_TRC(3, ("SSL [%d]: encoding resumption token failed", ss->fd));
+ return;
+ }
+ PORT_Assert(SSL_BUFFER_LEN(&encodedToken) > 0);
+ PRINT_BUF(40, (ss, "SSL: encoded resumption token",
+ SSL_BUFFER_BASE(&encodedToken),
+ SSL_BUFFER_LEN(&encodedToken)));
+ ss->resumptionTokenCallback(ss->fd, SSL_BUFFER_BASE(&encodedToken),
+ SSL_BUFFER_LEN(&encodedToken),
+ ss->resumptionTokenContext);
+
+ sslBuffer_Clear(&encodedToken);
+}
+
+void
+ssl_CacheSessionID(sslSocket *ss)
+{
+ sslSecurityInfo *sec = &ss->sec;
+ PORT_Assert(sec);
+
+ if (sec->ci.sid && !sec->ci.sid->u.ssl3.keys.resumable) {
+ return;
+ }
+
+ if (!ss->sec.isServer && ss->resumptionTokenCallback) {
+ ssl_CacheExternalToken(ss);
+ return;
+ }
+
+ PORT_Assert(!ss->resumptionTokenCallback);
if (sec->isServer) {
- sec->cache = ssl_sid_cache;
- sec->uncache = ssl_sid_uncache;
- } else {
- sec->cache = CacheSID;
- sec->uncache = LockAndUncacheSID;
+ ssl_ServerCacheSessionID(sec->ci.sid);
+ return;
+ }
+
+ CacheSID(sec->ci.sid);
+}
+
+void
+ssl_UncacheSessionID(sslSocket *ss)
+{
+ if (ss->opt.noCache) {
+ return;
+ }
+
+ sslSecurityInfo *sec = &ss->sec;
+ PORT_Assert(sec);
+
+ if (sec->ci.sid) {
+ if (sec->isServer) {
+ ssl_ServerUncacheSessionID(sec->ci.sid);
+ } else if (!ss->resumptionTokenCallback) {
+ LockAndUncacheSID(sec->ci.sid);
+ }
}
}
diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c
index 3f7060f22..f09ec067c 100644
--- a/security/nss/lib/ssl/sslsecur.c
+++ b/security/nss/lib/ssl/sslsecur.c
@@ -599,9 +599,6 @@ ssl_CopySecurityInfo(sslSocket *ss, sslSocket *os)
if (os->sec.peerCert && !ss->sec.peerCert)
goto loser;
- ss->sec.cache = os->sec.cache;
- ss->sec.uncache = os->sec.uncache;
-
return SECSuccess;
loser:
@@ -1159,7 +1156,7 @@ SSL_InvalidateSession(PRFileDesc *fd)
ssl_GetSSL3HandshakeLock(ss);
if (ss->sec.ci.sid) {
- ss->sec.uncache(ss->sec.ci.sid);
+ ssl_UncacheSessionID(ss);
rv = SECSuccess;
}
diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c
index 279f3c015..d7abb3dc3 100644
--- a/security/nss/lib/ssl/sslsnce.c
+++ b/security/nss/lib/ssl/sslsnce.c
@@ -495,12 +495,6 @@ ConvertToSID(sidCacheEntry *from,
PORT_Memcpy(to->u.ssl3.sessionID, from->sessionID, from->sessionIDLength);
- /* the portions of the SID that are only restored on the client
- * are set to invalid values on the server.
- */
- to->u.ssl3.clientWriteKey = NULL;
- to->u.ssl3.serverWriteKey = NULL;
-
to->urlSvrName = NULL;
to->u.ssl3.masterModuleID = (SECMODModuleID)-1; /* invalid value */
@@ -735,9 +729,11 @@ ServerSessionIDLookup(const PRIPv6Addr *addr,
/*
** Place a sid into the cache, if it isn't already there.
*/
-static void
-ServerSessionIDCache(sslSessionID *sid)
+void
+ssl_ServerCacheSessionID(sslSessionID *sid)
{
+ PORT_Assert(sid);
+
sidCacheEntry sce;
PRUint32 now = 0;
cacheDesc *cache = &globalCache;
@@ -800,8 +796,8 @@ ServerSessionIDCache(sslSessionID *sid)
** Although this is static, it is called from ssl via global function pointer
** ssl_sid_uncache. This invalidates the referenced cache entry.
*/
-static void
-ServerSessionIDUncache(sslSessionID *sid)
+void
+ssl_ServerUncacheSessionID(sslSessionID *sid)
{
cacheDesc *cache = &globalCache;
PRUint8 *sessionID;
@@ -1172,8 +1168,6 @@ ssl_ConfigServerSessionIDCacheInstanceWithOpt(cacheDesc *cache,
}
ssl_sid_lookup = ServerSessionIDLookup;
- ssl_sid_cache = ServerSessionIDCache;
- ssl_sid_uncache = ServerSessionIDUncache;
return SECSuccess;
}
@@ -1356,8 +1350,6 @@ SSL_InheritMPServerSIDCacheInstance(cacheDesc *cache, const char *envString)
ssl_InitSessionCacheLocks(PR_FALSE);
ssl_sid_lookup = ServerSessionIDLookup;
- ssl_sid_cache = ServerSessionIDCache;
- ssl_sid_uncache = ServerSessionIDUncache;
if (!envString) {
envString = PR_GetEnvSecure(envVarName);
diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c
index 4893cb9f9..e08d5e232 100644
--- a/security/nss/lib/ssl/sslsock.c
+++ b/security/nss/lib/ssl/sslsock.c
@@ -53,34 +53,35 @@ static const sslSocketOps ssl_secure_ops = { /* SSL. */
** default settings for socket enables
*/
static sslOptions ssl_defaults = {
- { siBuffer, NULL, 0 }, /* nextProtoNego */
- PR_TRUE, /* useSecurity */
- PR_FALSE, /* useSocks */
- PR_FALSE, /* requestCertificate */
- 2, /* requireCertificate */
- PR_FALSE, /* handshakeAsClient */
- PR_FALSE, /* handshakeAsServer */
- PR_FALSE, /* noCache */
- PR_FALSE, /* fdx */
- PR_TRUE, /* detectRollBack */
- PR_FALSE, /* noLocks */
- PR_FALSE, /* enableSessionTickets */
- PR_FALSE, /* enableDeflate */
- 2, /* enableRenegotiation (default: requires extension) */
- PR_FALSE, /* requireSafeNegotiation */
- PR_FALSE, /* enableFalseStart */
- PR_TRUE, /* cbcRandomIV */
- PR_FALSE, /* enableOCSPStapling */
- PR_FALSE, /* enableNPN */
- PR_TRUE, /* enableALPN */
- PR_TRUE, /* reuseServerECDHEKey */
- PR_FALSE, /* enableFallbackSCSV */
- PR_TRUE, /* enableServerDhe */
- PR_FALSE, /* enableExtendedMS */
- PR_FALSE, /* enableSignedCertTimestamps */
- PR_FALSE, /* requireDHENamedGroups */
- PR_FALSE, /* enable0RttData */
- PR_FALSE /* enableTls13CompatMode */
+ .nextProtoNego = { siBuffer, NULL, 0 },
+ .maxEarlyDataSize = 1 << 16,
+ .useSecurity = PR_TRUE,
+ .useSocks = PR_FALSE,
+ .requestCertificate = PR_FALSE,
+ .requireCertificate = SSL_REQUIRE_FIRST_HANDSHAKE,
+ .handshakeAsClient = PR_FALSE,
+ .handshakeAsServer = PR_FALSE,
+ .noCache = PR_FALSE,
+ .fdx = PR_FALSE,
+ .detectRollBack = PR_TRUE,
+ .noLocks = PR_FALSE,
+ .enableSessionTickets = PR_FALSE,
+ .enableDeflate = PR_FALSE,
+ .enableRenegotiation = SSL_RENEGOTIATE_REQUIRES_XTN,
+ .requireSafeNegotiation = PR_FALSE,
+ .enableFalseStart = PR_FALSE,
+ .cbcRandomIV = PR_TRUE,
+ .enableOCSPStapling = PR_FALSE,
+ .enableNPN = PR_FALSE,
+ .enableALPN = PR_TRUE,
+ .reuseServerECDHEKey = PR_TRUE,
+ .enableFallbackSCSV = PR_FALSE,
+ .enableServerDhe = PR_TRUE,
+ .enableExtendedMS = PR_FALSE,
+ .enableSignedCertTimestamps = PR_FALSE,
+ .requireDHENamedGroups = PR_FALSE,
+ .enable0RttData = PR_FALSE,
+ .enableTls13CompatMode = PR_FALSE
};
/*
@@ -104,8 +105,6 @@ static SSLVersionRange versions_defaults_datagram = {
(variant == ssl_variant_stream ? NSS_TLS_VERSION_MAX_POLICY : NSS_DTLS_VERSION_MAX_POLICY)
sslSessionIDLookupFunc ssl_sid_lookup;
-sslSessionIDCacheFunc ssl_sid_cache;
-sslSessionIDUncacheFunc ssl_sid_uncache;
static PRDescIdentity ssl_layer_id;
@@ -356,6 +355,8 @@ ssl_DupSocket(sslSocket *os)
os->namedGroupPreferences,
sizeof(ss->namedGroupPreferences));
ss->additionalShares = os->additionalShares;
+ ss->resumptionTokenCallback = os->resumptionTokenCallback;
+ ss->resumptionTokenContext = os->resumptionTokenContext;
/* Create security data */
rv = ssl_CopySecurityInfo(ss, os);
@@ -1252,6 +1253,18 @@ SSL_OptionSetDefault(PRInt32 which, PRIntn val)
return SECSuccess;
}
+SECStatus
+SSLExp_SetMaxEarlyDataSize(PRFileDesc *fd, PRUint32 size)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure; /* Error code already set. */
+ }
+
+ ss->opt.maxEarlyDataSize = size;
+ return SECSuccess;
+}
+
/* function tells us if the cipher suite is one that we no longer support. */
static PRBool
ssl_IsRemovedCipherSuite(PRInt32 suite)
@@ -3932,7 +3945,12 @@ struct {
EXP(InstallExtensionHooks),
EXP(KeyUpdate),
EXP(SendSessionTicket),
+ EXP(SetMaxEarlyDataSize),
EXP(SetupAntiReplay),
+ EXP(SetResumptionTokenCallback),
+ EXP(SetResumptionToken),
+ EXP(GetResumptionTokenInfo),
+ EXP(DestroyResumptionTokenInfo),
#endif
{ "", NULL }
};
@@ -3967,3 +3985,156 @@ ssl_ClearPRCList(PRCList *list, void (*f)(void *))
PORT_Free(cursor);
}
}
+
+/* Experimental APIs for session cache handling. */
+
+SECStatus
+SSLExp_SetResumptionTokenCallback(PRFileDesc *fd,
+ SSLResumptionTokenCallback cb,
+ void *ctx)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetResumptionTokenCallback",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+ ss->resumptionTokenCallback = cb;
+ ss->resumptionTokenContext = ctx;
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return SECSuccess;
+}
+
+SECStatus
+SSLExp_SetResumptionToken(PRFileDesc *fd, const PRUint8 *token,
+ unsigned int len)
+{
+ sslSocket *ss = ssl_FindSocket(fd);
+
+ if (!ss) {
+ SSL_DBG(("%d: SSL[%d]: bad socket in SSL_SetResumptionToken",
+ SSL_GETPID(), fd));
+ return SECFailure;
+ }
+
+ ssl_Get1stHandshakeLock(ss);
+ ssl_GetSSL3HandshakeLock(ss);
+
+ if (ss->firstHsDone || ss->ssl3.hs.ws != idle_handshake ||
+ ss->sec.isServer || len == 0 || !token) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ goto done;
+ }
+
+ // We override any previously set session.
+ if (ss->sec.ci.sid) {
+ ssl_FreeSID(ss->sec.ci.sid);
+ ss->sec.ci.sid = NULL;
+ }
+
+ PRINT_BUF(50, (ss, "incoming resumption token", token, len));
+
+ ss->sec.ci.sid = ssl3_NewSessionID(ss, PR_FALSE);
+ if (!ss->sec.ci.sid) {
+ goto done;
+ }
+
+ /* Populate NewSessionTicket values */
+ SECStatus rv = ssl_DecodeResumptionToken(ss->sec.ci.sid, token, len);
+ if (rv != SECSuccess) {
+ // If decoding fails, we assume the token is bad.
+ PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
+ ssl_FreeSID(ss->sec.ci.sid);
+ ss->sec.ci.sid = NULL;
+ goto done;
+ }
+
+ // Make sure that the token is valid.
+ if (!ssl_IsResumptionTokenValid(ss)) {
+ ssl_FreeSID(ss->sec.ci.sid);
+ ss->sec.ci.sid = NULL;
+ PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
+ goto done;
+ }
+
+ /* Use the sid->cached as marker that this is from an external cache and
+ * we don't have to look up anything in the NSS internal cache. */
+ ss->sec.ci.sid->cached = in_external_cache;
+ // This has to be 2 to not free this in sendClientHello.
+ ss->sec.ci.sid->references = 2;
+ ss->sec.ci.sid->lastAccessTime = ssl_TimeSec();
+
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+ return SECSuccess;
+
+done:
+ ssl_ReleaseSSL3HandshakeLock(ss);
+ ssl_Release1stHandshakeLock(ss);
+
+ return SECFailure;
+}
+
+SECStatus
+SSLExp_DestroyResumptionTokenInfo(SSLResumptionTokenInfo *token)
+{
+ if (!token) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (token->peerCert) {
+ CERT_DestroyCertificate(token->peerCert);
+ }
+ PORT_Free(token->alpnSelection);
+ PORT_Memset(token, 0, token->length);
+ return SECSuccess;
+}
+
+SECStatus
+SSLExp_GetResumptionTokenInfo(const PRUint8 *tokenData, unsigned int tokenLen,
+ SSLResumptionTokenInfo *tokenOut, PRUintn len)
+{
+ if (!tokenData || !tokenOut || !tokenLen ||
+ len > sizeof(SSLResumptionTokenInfo)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ sslSessionID sid = { 0 };
+ SSLResumptionTokenInfo token;
+
+ /* Populate sid values */
+ if (ssl_DecodeResumptionToken(&sid, tokenData, tokenLen) != SECSuccess) {
+ // If decoding fails, we assume the token is bad.
+ PORT_SetError(SSL_ERROR_BAD_RESUMPTION_TOKEN_ERROR);
+ return SECFailure;
+ }
+
+ token.peerCert = CERT_DupCertificate(sid.peerCert);
+
+ token.alpnSelectionLen = sid.u.ssl3.alpnSelection.len;
+ token.alpnSelection = PORT_ZAlloc(token.alpnSelectionLen);
+ if (!token.alpnSelection) {
+ return SECFailure;
+ }
+ PORT_Memcpy(token.alpnSelection, sid.u.ssl3.alpnSelection.data,
+ token.alpnSelectionLen);
+
+ if (sid.u.ssl3.locked.sessionTicket.flags & ticket_allow_early_data) {
+ token.maxEarlyDataSize =
+ sid.u.ssl3.locked.sessionTicket.max_early_data_size;
+ } else {
+ token.maxEarlyDataSize = 0;
+ }
+
+ token.length = PR_MIN(sizeof(SSLResumptionTokenInfo), len);
+ PORT_Memcpy(tokenOut, &token, token.length);
+
+ ssl_DestroySID(&sid, PR_FALSE);
+ return SECSuccess;
+}
diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h
index ce8f6e281..e2b80fb43 100644
--- a/security/nss/lib/ssl/sslt.h
+++ b/security/nss/lib/ssl/sslt.h
@@ -123,11 +123,14 @@ typedef enum {
ssl_sig_ecdsa_secp256r1_sha256 = 0x0403,
ssl_sig_ecdsa_secp384r1_sha384 = 0x0503,
ssl_sig_ecdsa_secp521r1_sha512 = 0x0603,
- ssl_sig_rsa_pss_sha256 = 0x0804,
- ssl_sig_rsa_pss_sha384 = 0x0805,
- ssl_sig_rsa_pss_sha512 = 0x0806,
+ ssl_sig_rsa_pss_rsae_sha256 = 0x0804,
+ ssl_sig_rsa_pss_rsae_sha384 = 0x0805,
+ ssl_sig_rsa_pss_rsae_sha512 = 0x0806,
ssl_sig_ed25519 = 0x0807,
ssl_sig_ed448 = 0x0808,
+ ssl_sig_rsa_pss_pss_sha256 = 0x0809,
+ ssl_sig_rsa_pss_pss_sha384 = 0x080a,
+ ssl_sig_rsa_pss_pss_sha512 = 0x080b,
ssl_sig_dsa_sha1 = 0x0202,
ssl_sig_dsa_sha256 = 0x0402,
@@ -143,20 +146,25 @@ typedef enum {
ssl_sig_rsa_pkcs1_sha1md5 = 0x10101,
} SSLSignatureScheme;
+/* Deprecated names maintained only for source compatibility. */
+#define ssl_sig_rsa_pss_sha256 ssl_sig_rsa_pss_rsae_sha256
+#define ssl_sig_rsa_pss_sha384 ssl_sig_rsa_pss_rsae_sha384
+#define ssl_sig_rsa_pss_sha512 ssl_sig_rsa_pss_rsae_sha512
+
/*
** SSLAuthType describes the type of key that is used to authenticate a
** connection. That is, the type of key in the end-entity certificate.
*/
typedef enum {
ssl_auth_null = 0,
- ssl_auth_rsa_decrypt = 1, /* static RSA */
+ ssl_auth_rsa_decrypt = 1, /* RSA key exchange. */
ssl_auth_dsa = 2,
ssl_auth_kea = 3, /* unused */
ssl_auth_ecdsa = 4,
- ssl_auth_ecdh_rsa = 5, /* ECDH cert with an RSA signature */
- ssl_auth_ecdh_ecdsa = 6, /* ECDH cert with an ECDSA signature */
- ssl_auth_rsa_sign = 7, /* RSA PKCS#1.5 signing */
- ssl_auth_rsa_pss = 8,
+ ssl_auth_ecdh_rsa = 5, /* ECDH cert with an RSA signature. */
+ ssl_auth_ecdh_ecdsa = 6, /* ECDH cert with an ECDSA signature. */
+ ssl_auth_rsa_sign = 7, /* RSA signing with an rsaEncryption key. */
+ ssl_auth_rsa_pss = 8, /* RSA signing with a PSS key. */
ssl_auth_psk = 9,
ssl_auth_tls13_any = 10,
ssl_auth_size /* number of authentication types */
diff --git a/security/nss/lib/ssl/tls13con.c b/security/nss/lib/ssl/tls13con.c
index 1fecaf3f8..c06acc83a 100644
--- a/security/nss/lib/ssl/tls13con.c
+++ b/security/nss/lib/ssl/tls13con.c
@@ -462,7 +462,7 @@ tls13_SetupClientHello(sslSocket *ss)
if (rv != SECSuccess) {
FATAL_ERROR(ss, SEC_ERROR_LIBRARY_FAILURE, internal_error);
SSL_AtomicIncrementLong(&ssl3stats->sch_sid_cache_not_ok);
- ss->sec.uncache(ss->sec.ci.sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = NULL;
return SECFailure;
@@ -1426,9 +1426,9 @@ ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme)
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:
+ case ssl_sig_rsa_pss_rsae_sha256:
+ case ssl_sig_rsa_pss_rsae_sha384:
+ case ssl_sig_rsa_pss_rsae_sha512:
return ssl_auth_rsa_sign;
case ssl_sig_ecdsa_secp256r1_sha256:
case ssl_sig_ecdsa_secp384r1_sha384:
@@ -1719,7 +1719,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
}
if (hrr) {
if (sid) { /* Free the sid. */
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
}
PORT_Assert(ss->ssl3.hs.helloRetry);
@@ -1769,8 +1769,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
} else {
if (sid) { /* we had a sid, but it's no longer valid, free it */
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
- if (ss->sec.uncache)
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
sid = NULL;
}
@@ -1830,7 +1829,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
if (sid) {
/* We had a sid, but it's no longer valid, free it. */
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_not_ok);
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
} else {
SSL_AtomicIncrementLong(&ssl3stats->hch_sid_cache_misses);
@@ -1866,7 +1865,7 @@ tls13_HandleClientHelloPart2(sslSocket *ss,
loser:
if (sid) {
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(sid);
}
return SECFailure;
@@ -2539,7 +2538,7 @@ tls13_HandleServerHelloPart2(sslSocket *ss)
}
if (sid->cached == in_client_cache) {
/* If we tried to resume and failed, let's not try again. */
- ss->sec.uncache(sid);
+ ssl_UncacheSessionID(ss);
}
}
@@ -4418,8 +4417,6 @@ tls13_SendClientSecondRound(sslSocket *ss)
* } NewSessionTicket;
*/
-PRUint32 ssl_max_early_data_size = (2 << 16); /* Arbitrary limit. */
-
static SECStatus
tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken,
unsigned int appTokenLen)
@@ -4521,7 +4518,7 @@ tls13_SendNewSessionTicket(sslSocket *ss, const PRUint8 *appToken,
if (rv != SECSuccess)
goto loser;
- rv = ssl3_AppendHandshakeNumber(ss, ssl_max_early_data_size, 4);
+ rv = ssl3_AppendHandshakeNumber(ss, ss->opt.maxEarlyDataSize, 4);
if (rv != SECSuccess)
goto loser;
}
@@ -4681,7 +4678,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
/* Destroy the old SID. */
- ss->sec.uncache(ss->sec.ci.sid);
+ ssl_UncacheSessionID(ss);
ssl_FreeSID(ss->sec.ci.sid);
ss->sec.ci.sid = sid;
}
@@ -4707,7 +4704,7 @@ tls13_HandleNewSessionTicket(sslSocket *ss, PRUint8 *b, PRUint32 length)
}
/* Cache the session. */
- ss->sec.cache(ss->sec.ci.sid);
+ ssl_CacheSessionID(ss);
}
return SECSuccess;
@@ -4772,9 +4769,6 @@ tls13_ExtensionStatus(PRUint16 extension, SSLHandshakeType message)
/* Return "disallowed" if the message mask bit isn't set. */
if (!(_M(message) & KnownExtensions[i].messages)) {
- SSL_TRC(3, ("%d: TLS13: unexpected extension %d in message %d",
- SSL_GETPID(), extension, message));
-
return tls13_extension_disallowed;
}
diff --git a/security/nss/lib/ssl/tls13hashstate.c b/security/nss/lib/ssl/tls13hashstate.c
index e3232f524..cc0ed286b 100644
--- a/security/nss/lib/ssl/tls13hashstate.c
+++ b/security/nss/lib/ssl/tls13hashstate.c
@@ -88,36 +88,37 @@ tls13_RecoverHashState(sslSocket *ss,
{
SECStatus rv;
unsigned char plaintext[1024];
- SECItem ptItem = { siBuffer, plaintext, 0 };
+ unsigned int plaintextLen = 0;
sslBuffer messageBuf = SSL_BUFFER_EMPTY;
- PRUint32 sentinel;
- PRUint32 cipherSuite;
- PRUint32 group;
+ PRUint64 sentinel;
+ PRUint64 cipherSuite;
+ PRUint64 group;
const sslNamedGroupDef *selectedGroup;
- PRUint32 appTokenLen;
- PRUint8 *appToken;
+ PRUint64 appTokenLen;
rv = ssl_SelfEncryptUnprotect(ss, cookie, cookieLen,
- ptItem.data, &ptItem.len, sizeof(plaintext));
+ plaintext, &plaintextLen, sizeof(plaintext));
if (rv != SECSuccess) {
return SECFailure;
}
+ sslReader reader = SSL_READER(plaintext, plaintextLen);
+
/* Should start with 0xff. */
- rv = ssl3_ConsumeNumberFromItem(&ptItem, &sentinel, 1);
+ rv = sslRead_ReadNumber(&reader, 1, &sentinel);
if ((rv != SECSuccess) || (sentinel != 0xff)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* The cipher suite should be the same or there are some shenanigans. */
- rv = ssl3_ConsumeNumberFromItem(&ptItem, &cipherSuite, 2);
+ rv = sslRead_ReadNumber(&reader, 2, &cipherSuite);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
/* The named group, if any. */
- rv = ssl3_ConsumeNumberFromItem(&ptItem, &group, 2);
+ rv = sslRead_ReadNumber(&reader, 2, &group);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
@@ -126,7 +127,7 @@ tls13_RecoverHashState(sslSocket *ss,
/* Application token. */
PORT_Assert(ss->xtnData.applicationToken.len == 0);
- rv = ssl3_ConsumeNumberFromItem(&ptItem, &appTokenLen, 2);
+ rv = sslRead_ReadNumber(&reader, 2, &appTokenLen);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
@@ -137,15 +138,18 @@ tls13_RecoverHashState(sslSocket *ss,
return SECFailure;
}
ss->xtnData.applicationToken.len = appTokenLen;
- rv = ssl3_ConsumeFromItem(&ptItem, &appToken, appTokenLen);
+ sslReadBuffer appTokenReader = { 0 };
+ rv = sslRead_Read(&reader, appTokenLen, &appTokenReader);
if (rv != SECSuccess) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
- PORT_Memcpy(ss->xtnData.applicationToken.data, appToken, appTokenLen);
+ PORT_Assert(appTokenReader.len == appTokenLen);
+ PORT_Memcpy(ss->xtnData.applicationToken.data, appTokenReader.buf, appTokenLen);
/* The remainder is the hash. */
- if (ptItem.len != tls13_GetHashSize(ss)) {
+ unsigned int hashLen = SSL_READER_REMAINING(&reader);
+ if (hashLen != tls13_GetHashSize(ss)) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CLIENT_HELLO, illegal_parameter);
return SECFailure;
}
@@ -153,7 +157,7 @@ tls13_RecoverHashState(sslSocket *ss,
/* Now reinject the message. */
SSL_ASSERT_HASHES_EMPTY(ss);
rv = ssl_HashHandshakeMessageInt(ss, ssl_hs_message_hash, 0,
- ptItem.data, ptItem.len);
+ SSL_READER_CURRENT(&reader), hashLen);
if (rv != SECSuccess) {
return SECFailure;
}
diff --git a/security/nss/lib/util/nssutil.h b/security/nss/lib/util/nssutil.h
index f86dfa91e..b65d4a0c9 100644
--- a/security/nss/lib/util/nssutil.h
+++ b/security/nss/lib/util/nssutil.h
@@ -19,10 +19,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
*/
-#define NSSUTIL_VERSION "3.35"
+#define NSSUTIL_VERSION "3.36.4"
#define NSSUTIL_VMAJOR 3
-#define NSSUTIL_VMINOR 35
-#define NSSUTIL_VPATCH 0
+#define NSSUTIL_VMINOR 36
+#define NSSUTIL_VPATCH 4
#define NSSUTIL_VBUILD 0
#define NSSUTIL_BETA PR_FALSE
diff --git a/security/nss/lib/util/secasn1d.c b/security/nss/lib/util/secasn1d.c
index 4c5f0ce4b..ccd97481d 100644
--- a/security/nss/lib/util/secasn1d.c
+++ b/security/nss/lib/util/secasn1d.c
@@ -175,7 +175,7 @@ static int /* bool */
}
}
} else {
- sprintf(buf, " [%d]", k);
+ sprintf(buf, " [%lu]", k);
}
buf += strlen(buf);
@@ -982,7 +982,7 @@ sec_asn1d_prepare_for_contents(sec_asn1d_state *state)
#ifdef DEBUG_ASN1D_STATES
{
- printf("Found Length %d %s\n", state->contents_length,
+ printf("Found Length %lu %s\n", state->contents_length,
state->indefinite ? "indefinite" : "");
}
#endif
@@ -2717,16 +2717,15 @@ dump_states(SEC_ASN1DecoderContext *cx)
}
i = formatKind(state->theTemplate->kind, kindBuf);
- printf("%s: tmpl %08x, kind%s",
+ printf("%s: tmpl kind %s",
(state == cx->current) ? "STATE" : "State",
- state->theTemplate,
kindBuf);
printf(" %s", (state->place >= 0 && state->place <= notInUse) ? place_names[state->place] : "(undefined)");
if (!i)
- printf(", expect 0x%02x",
+ printf(", expect 0x%02lx",
state->expect_tag_number | state->expect_tag_modifiers);
- printf("%s%s%s %d\n",
+ printf("%s%s%s %lu\n",
state->indefinite ? ", indef" : "",
state->missing ? ", miss" : "",
state->endofcontents ? ", EOC" : "",
@@ -2754,7 +2753,7 @@ SEC_ASN1DecoderUpdate(SEC_ASN1DecoderContext *cx,
what = SEC_ASN1_Contents;
consumed = 0;
#ifdef DEBUG_ASN1D_STATES
- printf("\nPLACE = %s, next byte = 0x%02x, %08x[%d]\n",
+ printf("\nPLACE = %s, next byte = 0x%02x, %p[%lu]\n",
(state->place >= 0 && state->place <= notInUse) ? place_names[state->place] : "(undefined)",
len ? (unsigned int)((unsigned char *)buf)[consumed] : 0,
buf, consumed);
@@ -2977,7 +2976,7 @@ SEC_ASN1DecoderFinish(SEC_ASN1DecoderContext *cx)
{
SECStatus rv;
- if (cx->status == needBytes) {
+ if (!cx || cx->status == needBytes) {
PORT_SetError(SEC_ERROR_BAD_DER);
rv = SECFailure;
} else {