From f83f62e1bff0c2aedc32e67fe369ba923c5b104a Mon Sep 17 00:00:00 2001 From: JustOff Date: Sat, 9 Jun 2018 15:11:22 +0300 Subject: Update NSS to 3.36.4-RTM --- security/nss/lib/certdb/stanpcertdb.c | 15 +- security/nss/lib/dev/devslot.c | 105 ++- security/nss/lib/dev/devt.h | 14 +- security/nss/lib/dev/devutil.c | 2 +- security/nss/lib/freebl/Makefile | 16 +- security/nss/lib/freebl/blapii.h | 6 + security/nss/lib/freebl/blinit.c | 162 +++++ security/nss/lib/freebl/chacha20.c | 19 - security/nss/lib/freebl/chacha20.h | 26 - security/nss/lib/freebl/chacha20_vec.c | 327 --------- security/nss/lib/freebl/chacha20poly1305.c | 51 +- security/nss/lib/freebl/config.mk | 2 +- security/nss/lib/freebl/det_rng.c | 4 +- security/nss/lib/freebl/drbg.c | 15 +- security/nss/lib/freebl/ecl/uint128.c | 90 --- security/nss/lib/freebl/ecl/uint128.h | 35 - security/nss/lib/freebl/freebl.gyp | 45 +- security/nss/lib/freebl/freebl_base.gypi | 13 +- security/nss/lib/freebl/lowhash_vector.c | 75 +- security/nss/lib/freebl/stubs.c | 8 +- .../nss/lib/freebl/verified/Hacl_Chacha20_Vec128.c | 390 +++++++++++ .../nss/lib/freebl/verified/Hacl_Chacha20_Vec128.h | 61 ++ security/nss/lib/freebl/verified/kremlib_base.h | 1 + security/nss/lib/freebl/verified/vec128.h | 345 ++++++++++ security/nss/lib/nss/nss.h | 6 +- security/nss/lib/pk11wrap/dev3hack.c | 4 + security/nss/lib/pk11wrap/pk11auth.c | 2 +- security/nss/lib/pk11wrap/secmodi.h | 1 + security/nss/lib/pkcs12/p12d.c | 1 + security/nss/lib/pkcs7/p7create.c | 2 +- security/nss/lib/pkcs7/p7decode.c | 6 + security/nss/lib/pki/pkibase.c | 2 + security/nss/lib/softoken/softkver.h | 6 +- security/nss/lib/ssl/SSLerrs.h | 3 + security/nss/lib/ssl/selfencrypt.c | 44 +- security/nss/lib/ssl/ssl3con.c | 180 +++-- security/nss/lib/ssl/ssl3encode.c | 85 --- security/nss/lib/ssl/ssl3encode.h | 26 - security/nss/lib/ssl/ssl3ext.c | 2 + security/nss/lib/ssl/ssl3exthandle.c | 14 +- security/nss/lib/ssl/ssl3gthr.c | 7 + security/nss/lib/ssl/sslcon.c | 17 +- security/nss/lib/ssl/sslencode.c | 64 +- security/nss/lib/ssl/sslencode.h | 30 +- security/nss/lib/ssl/sslerr.h | 2 + security/nss/lib/ssl/sslexp.h | 107 ++- security/nss/lib/ssl/sslimpl.h | 63 +- security/nss/lib/ssl/sslinit.c | 1 + security/nss/lib/ssl/sslnonce.c | 756 ++++++++++++++++++++- security/nss/lib/ssl/sslsecur.c | 5 +- security/nss/lib/ssl/sslsnce.c | 20 +- security/nss/lib/ssl/sslsock.c | 231 ++++++- security/nss/lib/ssl/sslt.h | 24 +- security/nss/lib/ssl/tls13con.c | 30 +- security/nss/lib/ssl/tls13hashstate.c | 34 +- security/nss/lib/util/nssutil.h | 6 +- security/nss/lib/util/secasn1d.c | 15 +- 57 files changed, 2625 insertions(+), 998 deletions(-) delete mode 100644 security/nss/lib/freebl/chacha20.c delete mode 100644 security/nss/lib/freebl/chacha20.h delete mode 100644 security/nss/lib/freebl/chacha20_vec.c delete mode 100644 security/nss/lib/freebl/ecl/uint128.c delete mode 100644 security/nss/lib/freebl/ecl/uint128.h create mode 100644 security/nss/lib/freebl/verified/Hacl_Chacha20_Vec128.c create mode 100644 security/nss/lib/freebl/verified/Hacl_Chacha20_Vec128.h create mode 100644 security/nss/lib/freebl/verified/vec128.h delete mode 100644 security/nss/lib/ssl/ssl3encode.c delete mode 100644 security/nss/lib/ssl/ssl3encode.h (limited to 'security/nss/lib') 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() || defined(__linux__)) && \ + defined(__GNUC__) && __GNUC__ >= 2 && defined(__ELF__) +#include +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 +// 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 -#include - -#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 -#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 - -#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 -#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 -#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 -#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 - -#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' @@ -22,6 +22,38 @@ '-mssse3' ] }, + { + # 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', @@ -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 #include #include +#include #include /* 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 +#include #include #include #include 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 +#include + +#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 + +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 * ".[.[.]][ ][ ]" */ -#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 * ".[.[.]][ ][ ]" */ -#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 #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 * ".[.[.]][ ]" */ -#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 { -- cgit v1.2.3