icecat: add release icecat-140.10.1-1gnu1 for ecne

This commit is contained in:
Ark74 2026-05-04 16:58:41 -06:00
parent a5f93cb214
commit ff85d7c623
1256 changed files with 63469 additions and 24141 deletions

View file

@ -14,7 +14,7 @@
#include <stddef.h>
static const PRTime kCTExpirationTime = INT64_C(1779695596000000);
static const PRTime kCTExpirationTime = INT64_C(1782114585000000);
namespace mozilla::ct {

View file

@ -1,42 +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 "PSMRunnable.h"
namespace mozilla {
namespace psm {
SyncRunnableBase::SyncRunnableBase()
: Runnable("psm::SyncRunnableBase"), monitor("SyncRunnableBase::monitor") {}
nsresult SyncRunnableBase::DispatchToMainThreadAndWait() {
nsresult rv;
if (NS_IsMainThread()) {
RunOnTargetThread();
rv = NS_OK;
} else {
mozilla::MonitorAutoLock lock(monitor);
rv = NS_DispatchToMainThread(this);
if (NS_SUCCEEDED(rv)) {
lock.Wait();
}
}
return rv;
}
NS_IMETHODIMP
SyncRunnableBase::Run() {
RunOnTargetThread();
mozilla::MonitorAutoLock(monitor).Notify();
return NS_OK;
}
nsresult NotifyObserverRunnable::Run() {
mObserver->Observe(nullptr, mTopic, nullptr);
return NS_OK;
}
} // namespace psm
} // namespace mozilla

View file

@ -1,49 +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/. */
#ifndef PSMRunnable_h
#define PSMRunnable_h
#include "mozilla/Monitor.h"
#include "nsThreadUtils.h"
#include "nsIObserver.h"
#include "nsProxyRelease.h"
namespace mozilla {
namespace psm {
// Wait for the event to run on the target thread without spinning the event
// loop on the calling thread. (Dispatching events to a thread using
// NS_DispatchAndSpinEventLoopUntilComplete would cause the event loop on the
// calling thread to spin.)
class SyncRunnableBase : public Runnable {
public:
NS_DECL_NSIRUNNABLE
nsresult DispatchToMainThreadAndWait();
protected:
SyncRunnableBase();
virtual void RunOnTargetThread() = 0;
private:
mozilla::Monitor monitor MOZ_UNANNOTATED;
};
class NotifyObserverRunnable : public Runnable {
public:
NotifyObserverRunnable(nsIObserver* observer, const char* topicStringLiteral)
: Runnable("psm::NotifyObserverRunnable"),
mObserver(new nsMainThreadPtrHolder<nsIObserver>(
"psm::NotifyObserverRunnable::mObserver", observer)),
mTopic(topicStringLiteral) {}
NS_DECL_NSIRUNNABLE
private:
nsMainThreadPtrHandle<nsIObserver> mObserver;
const char* const mTopic;
};
} // namespace psm
} // namespace mozilla
#endif

View file

@ -99,7 +99,6 @@
#include "ExtendedValidation.h"
#include "NSSCertDBTrustDomain.h"
#include "NSSSocketControl.h"
#include "PSMRunnable.h"
#include "RootCertificateTelemetryUtils.h"
#include "ScopedNSSTypes.h"
#include "SharedCertVerifier.h"

View file

@ -726,4 +726,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1782114773318000);
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1784533762555000);

View file

@ -127,7 +127,6 @@ UNIFIED_SOURCES += [
"nsTLSSocketProvider.cpp",
"OSKeyStore.cpp",
"PKCS11ModuleDB.cpp",
"PSMRunnable.cpp",
"PublicKeyPinningService.cpp",
"RootCertificateTelemetryUtils.cpp",
"SecretDecoderRing.cpp",
@ -192,7 +191,11 @@ if CONFIG["OS_ARCH"] == "WINNT":
"ntdll",
]
UNIFIED_SOURCES += [
# CredentialManagerSecret.cpp includes <windows.h> without WIN32_LEAN_AND_MEAN,
# which pulls in <winsock.h> and conflicts with <winsock2.h> included by other
# files in the same unified translation unit. Compile independently to prevent
# that interference.
SOURCES += [
"CredentialManagerSecret.cpp",
]
# Version string comparison is generally wrong, but by the time it would

View file

@ -7,7 +7,6 @@
#include "nsNSSCallbacks.h"
#include "NSSSocketControl.h"
#include "PSMRunnable.h"
#include "ScopedNSSTypes.h"
#include "SharedCertVerifier.h"
#include "mozilla/ArrayUtils.h"
@ -20,6 +19,7 @@
#include "mozilla/SpinEventLoopUntil.h"
#include "mozilla/StaticPrefs_security.h"
#include "mozilla/Unused.h"
#include "mozilla/SyncRunnable.h"
#include "mozilla/glean/SecurityManagerSslMetrics.h"
#include "mozilla/intl/Localization.h"
#include "nsContentUtils.h"
@ -40,6 +40,7 @@
#include "nsNetUtil.h"
#include "nsProxyRelease.h"
#include "nsStringStream.h"
#include "nsThreadUtils.h"
#include "mozpkix/pkixtypes.h"
#include "ssl.h"
#include "sslproto.h"
@ -546,28 +547,36 @@ static char* ShowProtectedAuthPrompt(PK11SlotInfo* slot, nsIPrompt* prompt) {
}
}
class PK11PasswordPromptRunnable : public SyncRunnableBase {
class PK11PasswordPromptRunnable final : public nsIRunnable {
public:
PK11PasswordPromptRunnable(PK11SlotInfo* slot, nsIInterfaceRequestor* ir)
: mResult(nullptr), mSlot(slot), mIR(ir) {}
virtual ~PK11PasswordPromptRunnable() = default;
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIRUNNABLE
char* mResult; // out
virtual void RunOnTargetThread() override;
private:
~PK11PasswordPromptRunnable() = default;
// Accessed only on the main thread. True if any instance of
// PK11PasswordPromptRunnable is already running.
static bool mRunning;
PK11SlotInfo* mSlot;
nsIInterfaceRequestor* mIR;
};
NS_IMPL_ISUPPORTS(PK11PasswordPromptRunnable, nsIRunnable)
bool PK11PasswordPromptRunnable::mRunning = false;
void PK11PasswordPromptRunnable::RunOnTargetThread() {
NS_IMETHODIMP
PK11PasswordPromptRunnable::Run() {
MOZ_ASSERT(NS_IsMainThread());
if (!NS_IsMainThread()) {
return;
return NS_ERROR_NOT_SAME_THREAD;
}
// If we've reentered due to the nested event loop implicit in using
@ -577,7 +586,7 @@ void PK11PasswordPromptRunnable::RunOnTargetThread() {
// to fail, but this is better than littering the screen with a bunch of
// password prompts that the user will probably just cancel anyway.
if (mRunning) {
return;
return NS_OK;
}
mRunning = true;
auto setRunningToFalseOnExit = MakeScopeExit([&]() { mRunning = false; });
@ -587,7 +596,7 @@ void PK11PasswordPromptRunnable::RunOnTargetThread() {
if (!mIR) {
rv = nsNSSComponent::GetNewPrompter(getter_AddRefs(prompt));
if (NS_FAILED(rv)) {
return;
return rv;
}
} else {
prompt = do_GetInterface(mIR);
@ -595,12 +604,12 @@ void PK11PasswordPromptRunnable::RunOnTargetThread() {
}
if (!prompt) {
return;
return NS_ERROR_FAILURE;
}
if (PK11_ProtectedAuthenticationPath(mSlot)) {
mResult = ShowProtectedAuthPrompt(mSlot, prompt);
return;
return NS_OK;
}
nsAutoString promptString;
@ -613,7 +622,7 @@ void PK11PasswordPromptRunnable::RunOnTargetThread() {
promptString);
}
if (NS_FAILED(rv)) {
return;
return rv;
}
nsString password;
@ -621,10 +630,11 @@ void PK11PasswordPromptRunnable::RunOnTargetThread() {
rv = prompt->PromptPassword(nullptr, promptString.get(),
getter_Copies(password), &userClickedOK);
if (NS_FAILED(rv) || !userClickedOK) {
return;
return rv;
}
mResult = ToNewUTF8String(password);
return NS_OK;
}
char* PK11PasswordPrompt(PK11SlotInfo* slot, PRBool /*retry*/, void* arg) {
@ -633,7 +643,8 @@ char* PK11PasswordPrompt(PK11SlotInfo* slot, PRBool /*retry*/, void* arg) {
}
RefPtr<PK11PasswordPromptRunnable> runnable(new PK11PasswordPromptRunnable(
slot, static_cast<nsIInterfaceRequestor*>(arg)));
runnable->DispatchToMainThreadAndWait();
MOZ_ALWAYS_SUCCEEDS(SyncRunnable::DispatchToThread(
GetMainThreadSerialEventTarget(), runnable));
return runnable->mResult;
}

View file

@ -13,7 +13,6 @@
#include "NSSCertDBTrustDomain.h"
#include "NSSErrorsService.h"
#include "NSSSocketControl.h"
#include "PSMRunnable.h"
#include "SSLServerCertVerification.h"
#include "ScopedNSSTypes.h"
#include "TLSClientAuthCertSelection.h"

File diff suppressed because it is too large Load diff

View file

@ -26,23 +26,19 @@
{
"chromium_data" : {
"cert_file_url": "https://chromium.googlesource.com/chromium/src/+/refs/heads/main/net/http/transport_security_state_static.pins?format=TEXT",
"json_file_url": "https://chromium.googlesource.com/chromium/src/+/refs/heads/main/net/http/transport_security_state_static_pins.json?format=TEXT",
"cert_file_url": "https://raw.githubusercontent.com/chromium/chromium/refs/heads/main/net/http/transport_security_state_static.pins",
"json_file_url": "https://raw.githubusercontent.com/chromium/chromium/refs/heads/main/net/http/transport_security_state_static_pins.json",
"substitute_pinsets": {
// Use the larger google_root_pems pinset instead of google
"google": "google_root_pems"
},
"production_pinsets": [
"google_root_pems",
"facebook",
"ncsccs"
"google_root_pems"
],
"production_domains": [
// Chrome's test domains.
"pinningtest.appspot.com",
"pinning-test.badssl.com",
// SpiderOak
"spideroak.com"
"pinning-test.badssl.com"
],
"exclude_domains" : []
},
@ -85,11 +81,6 @@
{
"name": "google_root_pems",
"sha256_hashes": [
"AffirmTrust Commercial",
"AffirmTrust Networking",
"AffirmTrust Premium",
"AffirmTrust Premium ECC",
"Baltimore CyberTrust Root",
"Comodo AAA Services root",
"COMODO Certification Authority",
"COMODO ECC Certification Authority",
@ -102,10 +93,6 @@
"DigiCert Global Root G3",
"DigiCert High Assurance EV Root CA",
"DigiCert Trusted Root G4",
"Entrust Root Certification Authority",
"Entrust Root Certification Authority - EC1",
"Entrust Root Certification Authority - G2",
"Entrust.net Premium 2048 Secure Server CA",
"GlobalSign ECC Root CA - R4",
"GlobalSign ECC Root CA - R5",
"GlobalSign Root CA",

View file

@ -1,6 +1,6 @@
{
"version": "85.16",
"log_list_timestamp": "2026-03-15T13:34:00Z",
"version": "85.43",
"log_list_timestamp": "2026-04-12T13:36:12Z",
"operators": [
{
"name": "Google",

View file

@ -0,0 +1 @@
NSS_3_112_5_RTM

View file

@ -56,6 +56,15 @@ struct ScopedDelete {
void operator()(SEC_PKCS12DecoderContext* dcx) {
SEC_PKCS12DecoderFinish(dcx);
}
void operator()(SEC_PKCS7DecoderContext* dcx) {
SEC_PKCS7ContentInfo* cinfo = SEC_PKCS7DecoderFinish(dcx);
if (cinfo) {
SEC_PKCS7DestroyContentInfo(cinfo);
}
}
void operator()(SEC_PKCS7ContentInfo* cinfo) {
SEC_PKCS7DestroyContentInfo(cinfo);
}
void operator()(NSSInitContext* init) { NSS_ShutdownContext(init); }
};
@ -96,6 +105,8 @@ SCOPED(SECKEYPrivateKeyList);
SCOPED(SECKEYPublicKey);
SCOPED(SECMODModule);
SCOPED(SEC_PKCS12DecoderContext);
SCOPED(SEC_PKCS7DecoderContext);
SCOPED(SEC_PKCS7ContentInfo);
#undef SCOPED

View file

@ -0,0 +1,52 @@
.. _mozilla_projects_nss_nss_3_112_4_release_notes:
NSS 3.112.4 release notes
========================
`Introduction <#introduction>`__
--------------------------------
.. container::
Network Security Services (NSS) 3.112.4 was released on *13 April 2026**.
`Distribution Information <#distribution_information>`__
--------------------------------------------------------
.. container::
The HG tag is NSS_3_112_4_RTM. NSS 3.112.4 requires NSPR 4.36 or newer.
NSS 3.112.4 source distributions are available on ftp.mozilla.org for secure HTTPS download:
- Source tarballs:
https://ftp.mozilla.org/pub/mozilla.org/security/nss/releases/NSS_3_112_4_RTM/src/
Other releases are available :ref:`mozilla_projects_nss_releases`.
.. _changes_in_nss_3.112.4:
`Changes in NSS 3.112.4 <#changes_in_nss_3.112.4>`__
------------------------------------------------------------------
.. container::
- Bug 2030135 - improve error handling in PK11_ImportPrivateKeyInfoAndReturnKey.
- Bug 2029752 - Improving the allocation of S/MIME DecryptSymKey.
- Bug 2029462 - store email on subject cache_entry in NSS trust domain.
- Bug 2029425 - Heap use-after-free in cert_VerifyCertChainOld via dangling certsList[] entry on NameConstraints violation.
- Bug 2029323 - Improve size calculations in CMS content buffering.
- Bug 2028001 - avoid integer overflow while escaping RFC822 Names.
- Bug 2027378 - Reject excessively large ASN.1 SEQUENCE OF in quickder.
- Bug 2027365 - Deep copy profile data in CERT_FindSMimeProfile.
- Bug 2027345 - Improve input validation in DSAU signature decoding.
- Bug 2026311 - avoid integer overflow in RSA_EMSAEncodePSS.
- Bug 2019357 - RSA_EMSAEncodePSS should validate the length of mHash.
- Bug 2026156 - Add a maximum cert uncompressed len and tests.
- Bug 2026089 - Clarify extension negotiation mechanism for TLS Handshakes.
- Bug 2023209 - ensure permittedSubtrees don't match wildcards that could be outside the permitted tree.
- Bug 2023207 - Fix integer underflow in tls13_AEAD when ciphertext is shorter than tag.
- Bug 2019224 - Remove invalid PORT_Free().
- Bug 1964722 - free digest objects in SEC_PKCS7DecoderFinish if they haven't already been freed.
- Bug 1935995 - make ss->ssl3.hs.cookie an owned-copy of the cookie.

View file

@ -0,0 +1,36 @@
.. _mozilla_projects_nss_nss_3_112_5_release_notes:
NSS 3.112.5 release notes
=========================
`Introduction <#introduction>`__
--------------------------------
.. container::
Network Security Services (NSS) 3.112.5 was released on *23 April 2026*.
`Distribution Information <#distribution_information>`__
--------------------------------------------------------
.. container::
The HG tag is NSS_3_112_5_RTM. NSS 3.112.5 requires NSPR 4.38.2 or newer.
NSS 3.112.5 source distributions are available on ftp.mozilla.org for secure HTTPS download:
- Source tarballs:
https://ftp.mozilla.org/pub/mozilla.org/security/nss/releases/NSS_3_112_5_RTM/src/
Other releases are available :ref:`mozilla_projects_nss_releases`.
.. _changes_in_nss_3.112.5:
`Changes in NSS 3.112.5 <#changes_in_nss_3.112.5>`__
------------------------------------------------------------------
.. container::
- Bug 2033783 - reject DTLS 1.3 Server Hello after HVR without capping ss->vrange.max.
- Bug 2034185 - update to version 2.84 of builtins module.

View file

@ -14,6 +14,7 @@
'der_getint_unittest.cc',
'der_quickder_unittest.cc',
'p12_import_unittest.cc',
'p7_import_unittest.cc',
'secasn1decode_unittest.cc',
'<(DEPTH)/gtests/common/gtests.cc'
],

View file

@ -231,6 +231,13 @@ static const uint8_t cert_p12[] = {
0x51, 0x04, 0x08, 0xa1, 0x52, 0xdd, 0x64, 0x46, 0xe9, 0x9e, 0x3e, 0x02,
0x02, 0x08, 0x00};
unsigned char leak_p12[] = {
0x30, 0x82, 0x20, 0x20, 0x02, 0x01, 0xff, 0x30, 0x82, 0x09, 0x20, 0x06,
0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x50,
0x30, 0x3f, 0x02, 0x01, 0x20, 0x31, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60,
0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x30, 0x20, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x01};
class PK12ImportTest : public ::testing::Test {};
TEST_F(PK12ImportTest, ImportPK12With2P7) {
@ -248,4 +255,20 @@ TEST_F(PK12ImportTest, ImportPK12With2P7) {
ASSERT_EQ(SECFailure, rv);
}
TEST_F(PK12ImportTest, FailsToImportButShouldNotLeak) {
SECItem password = {siBuffer, nullptr, 0};
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
ScopedSEC_PKCS12DecoderContext dcx(
SEC_PKCS12DecoderStart(&password, slot.get(), nullptr, nullptr, nullptr,
nullptr, nullptr, nullptr));
ASSERT_TRUE(dcx);
SECStatus rv = SEC_PKCS12DecoderUpdate(
dcx.get(), const_cast<uint8_t *>(leak_p12), sizeof(leak_p12));
ASSERT_EQ(SECSuccess, rv);
rv = SEC_PKCS12DecoderVerify(dcx.get());
// This is not a valid PKCS12 file, so a failing return value is expected.
// However, the implementation shouldn't leak memory as a result.
ASSERT_EQ(SECFailure, rv);
}
} // namespace nss_test

View file

@ -0,0 +1,60 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nss.h"
#include "secpkcs7.h"
#include "gtest/gtest.h"
#include "nss_scoped_ptrs.h"
namespace nss_test {
// This is an invalid PKCS7 message. Among other things, it contains some
// unknown hash OIDs. This should fail to parse, but it should be safe to try.
static const uint8_t p7_with_unknown_hashes[] = {
0x30, 0x4d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
0x02, 0xa0, 0x40, 0x30, 0x3e, 0x02, 0x01, 0x20, 0x31, 0x27, 0x30, 0x0b,
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05, 0x30,
0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05,
0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02,
0x04, 0x30, 0x10, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x07, 0x01, 0xa0, 0x03, 0x04, 0x01, 0x00};
// This is an invalid PKCS7 message. It contains multiple hash OIDs (that's not
// what makes it invalid). When it fails to parse, the associated digest data
// structures should be freed correctly.
static const uint8_t p7_with_multiple_hashes[] = {
0x30, 0x4d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07,
0x02, 0xa0, 0x40, 0x30, 0x3e, 0x02, 0x01, 0x20, 0x31, 0x27, 0x30, 0x0b,
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x30,
0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02,
0x04, 0x30, 0x10, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x07, 0x01, 0xa0, 0x03, 0x04, 0x01, 0x00};
class P7ImportTest : public ::testing::Test {};
TEST_F(P7ImportTest, FailSafeWithUnknownHashes) {
ScopedSEC_PKCS7DecoderContext dcx(SEC_PKCS7DecoderStart(
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));
ASSERT_TRUE(dcx);
SECStatus rv = SEC_PKCS7DecoderUpdate(
dcx.get(), reinterpret_cast<const char*>(p7_with_unknown_hashes),
sizeof(p7_with_unknown_hashes));
ASSERT_EQ(SECFailure, rv);
}
TEST_F(P7ImportTest, NoLeakWithMultipleHashes) {
ScopedSEC_PKCS7DecoderContext dcx(SEC_PKCS7DecoderStart(
nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr));
ASSERT_TRUE(dcx);
SECStatus rv = SEC_PKCS7DecoderUpdate(
dcx.get(), reinterpret_cast<const char*>(p7_with_multiple_hashes),
sizeof(p7_with_multiple_hashes));
ASSERT_EQ(SECFailure, rv);
}
} // namespace nss_test

View file

@ -2132,6 +2132,45 @@ static const NameConstraintParams NAME_CONSTRAINT_PARAMS[] =
Result::ERROR_BAD_DER, Result::ERROR_BAD_DER
},
// Wildcard SANs have subtle outcomes.
{ ByteString(), DNSName("*.example.com"),
GeneralSubtree(DNSName(".example.com")),
Success,
Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), DNSName("*.example.com"),
GeneralSubtree(DNSName("example.com")),
Success,
Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
// A certificate with a wildcard SAN entry like `*.example.com` can't be
// issued by a CA with a DNSName name constraint entry like `foo.example.com`
// in either the permitted or excluded subtrees. If in the permitted subtree,
// the certificate would be valid for `bar.example.com`, which would violate
// the constraint. If in the excluded subtree, the certificate would be valid
// for `foo.example.com`, which would violate the constraint.
{ ByteString(), DNSName("*.example.com"),
GeneralSubtree(DNSName("foo.example.com")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE,
Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), DNSName("*.foo.example.com"),
GeneralSubtree(DNSName("example.com")),
Success,
Result::ERROR_CERT_NOT_IN_NAME_SPACE
},
{ ByteString(), DNSName("*.example.com"),
GeneralSubtree(DNSName("foo.example.org")),
Result::ERROR_CERT_NOT_IN_NAME_SPACE,
Success
},
// `*invalid.example.com` is an invalid presented DNSID.
{ ByteString(), DNSName("*invalid.example.com"),
GeneralSubtree(DNSName("invalid.example.com")),
Result::ERROR_BAD_DER,
Result::ERROR_BAD_DER
},
/////////////////////////////////////////////////////////////////////////////
// Basic IP Address constraints (non-CN-ID)

View file

@ -272,6 +272,25 @@ static SECStatus SimpleXorWithDifferentValueDecode(const SECItem* input,
return SECSuccess;
}
/* Decode function that does NOT check input->len != outputLen (unlike
* SimpleXorCertCompDecode). It always sets receivedOutputLen = outputLen and
* returns SECSuccess, bypassing the actualCertLen != decodedCertLen fallback
* so that only the explicit uncompressed_length bounds check blocks an
* oversized allocation. */
static int called_count = 0;
static SECStatus PermissiveXorCertCompDecode(const SECItem* input,
uint8_t* output, size_t outputLen,
size_t* receivedOutputLen) {
called_count++;
size_t copy = PR_MIN(input->len, outputLen);
PORT_Memcpy(output, input->data, copy);
for (size_t i = 0; i < copy; i++) {
output[i] ^= 0x55;
}
*receivedOutputLen = outputLen;
return SECSuccess;
}
/* These tests are checking the behaviour
* using the different compression algorithms.
*
@ -500,8 +519,6 @@ TEST_F(TlsConnectStreamTls13,
EXPECT_TRUE(SSLInt_ExtensionNegotiated(server_->ssl_fd(),
ssl_certificate_compression_xtn));
EXPECT_TRUE(SSLInt_ExtensionNegotiated(client_->ssl_fd(),
ssl_certificate_compression_xtn));
uint16_t certCompressionAlg = filterExtension->getCertCompressionAlg();
EXPECT_EQ(certCompressionAlg, serverPreferableAlg.id);
@ -964,6 +981,56 @@ static SECStatus SimpleXorCertCompEncode_returns_buffer_size_0(
* } CompressedCertificate;
*/
/* Overwrites the uncompressed_length field of a CompressedCertificate message
* with an arbitrary uint24 value, enabling precise boundary-value testing. */
class TLSCompressedCertUncompressedLenSetter : public TlsRecordFilter {
public:
TLSCompressedCertUncompressedLenSetter(const std::shared_ptr<TlsAgent>& a,
uint32_t len)
: TlsRecordFilter(a), len_(len) {
EnableDecryption();
}
protected:
PacketFilter::Action FilterRecord(const TlsRecordHeader& header,
const DataBuffer& record, size_t* offset,
DataBuffer* output) override {
uint8_t inner_content_type;
DataBuffer plaintext;
uint16_t protection_epoch = 0;
TlsRecordHeader out_header(header);
if (!Unprotect(header, record, &protection_epoch, &inner_content_type,
&plaintext, &out_header)) {
return KEEP;
}
uint64_t skip =
findPointerToHandshakeType(plaintext, ssl_hs_compressed_certificate);
if (skip >= plaintext.len() ||
plaintext.data()[skip] != ssl_hs_compressed_certificate) {
return KEEP;
}
/* uncompressed_length is a uint24 at offset 6 from the HandshakeType byte.
*/
plaintext.Write(skip + 6, len_, 3);
DataBuffer ciphertext;
bool ok = Protect(spec(protection_epoch), out_header, inner_content_type,
plaintext, &ciphertext, &out_header);
EXPECT_TRUE(ok);
if (!ok) {
return KEEP;
}
*offset = out_header.Write(output, *offset, ciphertext);
return CHANGE;
}
private:
uint32_t len_;
};
TEST_F(TlsConnectStreamTls13,
CertificateCompression_CompressionFunctionCreatesABufferOfSize0) {
ConfigureVersion(SSL_LIBRARY_VERSION_TLS_1_3);
@ -1214,6 +1281,47 @@ TEST_F(TlsConnectStreamTls13,
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CERTIFICATE);
}
/* Boundary test for the 100KB uncompressed_length cap.
* At limit (100KB): passes bounds check, Certificate parser sees trailing
* zeros and fires illegal_parameter (tls13con.c:4362) proves the bounds
* check did not trigger.
* One over (100KB+1): caught by the bounds check (tls13con.c:4220) and fires
* bad_certificate. */
TEST_F(TlsConnectStreamTls13, CertificateCompression_UncompressedLenBoundary) {
SSLCertificateCompressionAlgorithm t = {0xff01, "test function",
SimpleXorCertCompEncode,
PermissiveXorCertCompDecode};
auto run = [&](uint32_t len, uint8_t expected_alert, bool expect_decoded) {
called_count = 0;
Reset();
EnsureTlsSetup();
MakeTlsFilter<TLSCompressedCertUncompressedLenSetter>(server_, len);
EXPECT_EQ(SECSuccess,
SSLExp_SetCertificateCompressionAlgorithm(server_->ssl_fd(), t));
EXPECT_EQ(SECSuccess,
SSLExp_SetCertificateCompressionAlgorithm(client_->ssl_fd(), t));
ExpectAlert(client_, expected_alert);
StartConnect();
client_->SetServerKeyBits(server_->server_key_bits());
client_->Handshake();
server_->Handshake();
ASSERT_TRUE_WAIT((client_->state() != TlsAgent::STATE_CONNECTING), 5000);
ASSERT_EQ(TlsAgent::STATE_ERROR, client_->state());
client_->ExpectSendAlert(kTlsAlertCloseNotify);
server_->ExpectReceiveAlert(kTlsAlertCloseNotify);
client_->CheckErrorCode(SSL_ERROR_RX_MALFORMED_CERTIFICATE);
if (expect_decoded) {
EXPECT_EQ(called_count, 1);
} else {
EXPECT_EQ(0, called_count);
}
};
run(100 * 1024, kTlsAlertIllegalParameter, true);
run(100 * 1024 + 1, kTlsAlertBadCertificate, false);
}
TEST_F(TlsConnectStreamTls13,
CertificateCompression_ReceivedCertificateTooLong) {
EnsureTlsSetup();
@ -1391,8 +1499,6 @@ TEST_F(TlsConnectStreamTls13, CertificateCompression_PostAuth) {
server_->ReadBytes(50);
EXPECT_EQ(1U, called);
EXPECT_TRUE(SSLInt_ExtensionNegotiated(client_->ssl_fd(),
ssl_certificate_compression_xtn));
SendReceive(60);
client_->CheckClientAuthCompleted();
@ -1469,8 +1575,6 @@ TEST_F(TlsConnectStreamTls13,
server_->ReadBytes(50);
EXPECT_EQ(1U, called);
EXPECT_TRUE(SSLInt_ExtensionNegotiated(client_->ssl_fd(),
ssl_certificate_compression_xtn));
SendReceive(60);
client_->CheckClientAuthCompleted();

View file

@ -1400,13 +1400,13 @@ appendItemToBuf(char* dest, SECItem* src, PRUint32* pRemaining)
if (dest && src && src->data && src->len && src->data[0]) {
PRUint32 len = src->len;
PRUint32 i;
PRUint32 reqLen = len + 1;
PRUint64 reqLen = (PRUint64)len + 1;
/* are there any embedded control characters ? */
for (i = 0; i < len; i++) {
if (NEEDS_HEX_ESCAPE(src->data[i]))
reqLen += 2;
}
if (*pRemaining > reqLen) {
if (*pRemaining >= reqLen) {
for (i = 0; i < len; ++i) {
PRUint8 c = src->data[i];
if (NEEDS_HEX_ESCAPE(c)) {
@ -1422,7 +1422,7 @@ appendItemToBuf(char* dest, SECItem* src, PRUint32* pRemaining)
}
}
*dest++ = '\0';
*pRemaining -= reqLen;
*pRemaining -= (PRUint32)reqLen;
}
}
return dest;
@ -1440,7 +1440,7 @@ cert_GetCertificateEmailAddresses(CERTCertificate* cert)
char* pBuf = NULL;
PORTCheapArenaPool tmpArena;
PRUint32 maxLen = 0;
PRInt32 finalLen = 0;
PRUint32 finalLen = 0;
SECStatus rv;
SECItem subAltName;

View file

@ -1045,10 +1045,15 @@ CERT_FindSMimeProfile(CERTCertificate *cert)
nssSMIMEProfile *stanProfile;
stanProfile = nssCryptoContext_FindSMIMEProfileForCertificate(cc, c);
if (stanProfile) {
rvItem =
SECITEM_AllocItem(NULL, NULL, stanProfile->profileData->size);
if (rvItem) {
rvItem->data = stanProfile->profileData->data;
if (stanProfile->profileData) {
rvItem =
SECITEM_AllocItem(NULL, NULL,
stanProfile->profileData->size);
if (rvItem) {
PORT_Memcpy(rvItem->data,
stanProfile->profileData->data,
stanProfile->profileData->size);
}
}
nssSMIMEProfile_Destroy(stanProfile);
}

View file

@ -736,7 +736,7 @@ cert_VerifyCertChainOld(CERTCertDBHandle *handle, CERTCertificate *cert,
certsList = tmpCertsList;
}
for (i = 0; i < subjectNameListLen; i++) {
certsList[namesCount + i] = subjectCert;
certsList[namesCount + i] = CERT_DupCertificate(subjectCert);
}
namesCount += subjectNameListLen;
namesList = cert_CombineNamesLists(namesList, subjectNameList);
@ -993,6 +993,11 @@ loser:
rv = SECFailure;
done:
if (certsList != NULL) {
for (int i = 0; i < namesCount; i++) {
if (certsList[i]) {
CERT_DestroyCertificate(certsList[i]);
}
}
PORT_Free(certsList);
}
if (issuerCert) {

File diff suppressed because it is too large Load diff

View file

@ -46,8 +46,8 @@
* It's recommend to switch back to 0 after having reached version 98/99.
*/
#define NSS_BUILTINS_LIBRARY_VERSION_MAJOR 2
#define NSS_BUILTINS_LIBRARY_VERSION_MINOR 76
#define NSS_BUILTINS_LIBRARY_VERSION "2.76"
#define NSS_BUILTINS_LIBRARY_VERSION_MINOR 84
#define NSS_BUILTINS_LIBRARY_VERSION "2.84"
/* These version numbers detail the semantic changes to the ckfw engine. */
#define NSS_BUILTINS_HARDWARE_VERSION_MAJOR 1

View file

@ -72,19 +72,18 @@ DSAU_ConvertSignedToFixedUnsigned(SECItem *dest, SECItem *src)
unsigned char *pDst = dest->data;
unsigned int cntSrc = src->len;
unsigned int cntDst = dest->len;
int zCount = cntDst - cntSrc;
if (zCount > 0) {
if (cntSrc <= cntDst) {
unsigned int zCount = cntDst - cntSrc;
PORT_Memset(pDst, 0, zCount);
PORT_Memcpy(pDst + zCount, pSrc, cntSrc);
return SECSuccess;
}
if (zCount <= 0) {
/* Source is longer than destination. Check for leading zeros. */
while (zCount++ < 0) {
if (*pSrc++ != 0)
goto loser;
}
/* Source is longer than destination: extra leading bytes must be zero. */
unsigned int extra = cntSrc - cntDst;
while (extra--) {
if (*pSrc++ != 0)
goto loser;
}
PORT_Memcpy(pDst, pSrc, cntDst);
return SECSuccess;
@ -190,6 +189,12 @@ common_DecodeDerSig(const SECItem *item, unsigned int len)
if (status != SECSuccess)
goto loser;
/* A valid DER INTEGER for r or s is at most len+1 bytes (len bytes of
** magnitude plus at most one leading zero sign byte). Reject anything
** larger before attempting the conversion to avoid pathological inputs. */
if (sig.r.len > len + 1 || sig.s.len > len + 1)
goto loser;
/* Convert sig.r and sig.s from variable length signed integers to
** fixed length unsigned integers.
*/

View file

@ -88,6 +88,7 @@ RSA_EMSAEncodePSS(unsigned char *em,
unsigned int emLen,
unsigned int emBits,
const unsigned char *mHash,
unsigned int mHashLen,
HASH_HashType hashAlg,
HASH_HashType maskHashAlg,
const unsigned char *salt,

View file

@ -200,7 +200,8 @@ RSABlinding_Blind(HASH_HashType hashAlg, PRUint8* blindedMsg, size_t blindedMsgL
goto cleanup;
}
rv = RSA_EMSAEncodePSS(encoded_msg, pkS->modulus.len, bit_len_n, msgHash, hashAlg, hashAlg, salt, saltLen);
rv = RSA_EMSAEncodePSS(encoded_msg, pkS->modulus.len, bit_len_n, msgHash,
sizeof(msgHash), hashAlg, hashAlg, salt, saltLen);
/* 2. If EMSA-PSS-ENCODE raises an error, raise the error and stop. */
if (rv != SECSuccess) {

View file

@ -1239,6 +1239,7 @@ RSA_EMSAEncodePSS(unsigned char *em,
unsigned int emLen,
unsigned int emBits,
const unsigned char *mHash,
unsigned int mHashLen,
HASH_HashType hashAlg,
HASH_HashType maskHashAlg,
const unsigned char *salt,
@ -1252,14 +1253,22 @@ RSA_EMSAEncodePSS(unsigned char *em,
SECStatus rv;
hash = HASH_GetRawHashObject(hashAlg);
dbMaskLen = emLen - hash->length - 1;
PORT_Assert(hash);
if (mHashLen < hash->length) {
PORT_SetError(SEC_ERROR_INVALID_ARGS);
return SECFailure;
}
/* Step 3 */
if (emLen < hash->length + saltLen + 2) {
if ((saltLen > emLen) ||
(hash->length + 2 > emLen - saltLen)) {
PORT_SetError(SEC_ERROR_OUTPUT_LEN);
return SECFailure;
}
dbMaskLen = emLen - hash->length - 1;
/* Step 4 */
if (salt == NULL) {
rv = RNG_GenerateGlobalRandomBytes(&em[dbMaskLen - saltLen], saltLen);
@ -1336,15 +1345,17 @@ emsa_pss_verify(const unsigned char *mHash,
SECStatus rv;
hash = HASH_GetRawHashObject(hashAlg);
dbMaskLen = emLen - hash->length - 1;
/* Step 3 + 4 */
if ((emLen < (hash->length + saltLen + 2)) ||
if ((saltLen > emLen) ||
(hash->length + 2 > emLen - saltLen) ||
(em[emLen - 1] != 0xbc)) {
PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
return SECFailure;
}
dbMaskLen = emLen - hash->length - 1;
/* Step 6 */
zeroBits = 8 * emLen - emBits;
if (em[0] >> (8 - zeroBits)) {
@ -1458,7 +1469,7 @@ RSA_SignPSS(RSAPrivateKey *key,
emLen--;
em++;
}
rv = RSA_EMSAEncodePSS(em, emLen, modulusBits - 1, input, hashAlg,
rv = RSA_EMSAEncodePSS(em, emLen, modulusBits - 1, input, inputLen, hashAlg,
maskHashAlg, salt, saltLength);
if (rv != SECSuccess)
goto done;

View file

@ -172,6 +172,12 @@ enum class IDRole
NameConstraint = 2,
};
enum class NameConstraintsSubtrees : uint8_t
{
permittedSubtrees = der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0,
excludedSubtrees = der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 1
};
enum class AllowWildcards { No = 0, Yes = 1 };
// DNSName constraints implicitly allow subdomain matching when there is no
@ -184,16 +190,22 @@ enum class AllowDotlessSubdomainMatches { No = 0, Yes = 1 };
bool IsValidDNSID(Input hostname, IDRole idRole,
AllowWildcards allowWildcards);
// `subtreesType` is relevant only when `referenceDNSIDRole` is
// `IDRole::NameConstraint`.
Result MatchPresentedDNSIDWithReferenceDNSID(
Input presentedDNSID,
AllowWildcards allowWildcards,
AllowDotlessSubdomainMatches allowDotlessSubdomainMatches,
IDRole referenceDNSIDRole,
/*optional*/ const NameConstraintsSubtrees* subtreesType,
Input referenceDNSID,
/*out*/ bool& matches);
// `subtreesType` is relevant only when `referenceDNSIDRole` is
// `IDRole::NameConstraint`.
Result MatchPresentedRFC822NameWithReferenceRFC822Name(
Input presentedRFC822Name, IDRole referenceRFC822NameRole,
/*optional*/ const NameConstraintsSubtrees* subtreesType,
Input referenceRFC822Name, /*out*/ bool& matches);
} // namespace
@ -212,7 +224,7 @@ MatchPresentedDNSIDWithReferenceDNSID(Input presentedDNSID,
return MatchPresentedDNSIDWithReferenceDNSID(
presentedDNSID, AllowWildcards::Yes,
AllowDotlessSubdomainMatches::Yes, IDRole::ReferenceID,
referenceDNSID, matches);
nullptr, referenceDNSID, matches);
}
// Verify that the given end-entity cert, which is assumed to have been already
@ -731,7 +743,7 @@ MatchPresentedIDWithReferenceID(GeneralNameType presentedIDType,
rv = MatchPresentedDNSIDWithReferenceDNSID(
presentedID, AllowWildcards::Yes,
AllowDotlessSubdomainMatches::Yes, IDRole::ReferenceID,
referenceID, foundMatch);
nullptr, referenceID, foundMatch);
break;
case GeneralNameType::iPAddress:
@ -741,7 +753,7 @@ MatchPresentedIDWithReferenceID(GeneralNameType presentedIDType,
case GeneralNameType::rfc822Name:
rv = MatchPresentedRFC822NameWithReferenceRFC822Name(
presentedID, IDRole::ReferenceID, referenceID, foundMatch);
presentedID, IDRole::ReferenceID, nullptr, referenceID, foundMatch);
break;
case GeneralNameType::directoryName:
@ -767,20 +779,16 @@ MatchPresentedIDWithReferenceID(GeneralNameType presentedIDType,
return Success;
}
enum class NameConstraintsSubtrees : uint8_t
{
permittedSubtrees = der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0,
excludedSubtrees = der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 1
};
Result CheckPresentedIDConformsToNameConstraintsSubtrees(
GeneralNameType presentedIDType,
Input presentedID,
Reader& nameConstraints,
NameConstraintsSubtrees subtreesType);
Result MatchPresentedIPAddressWithConstraint(Input presentedID,
Input iPAddressConstraint,
/*out*/ bool& foundMatch);
Result MatchPresentedDirectoryNameWithConstraint(
NameConstraintsSubtrees subtreesType, Input presentedID,
Input directoryNameConstraint, /*out*/ bool& matches);
@ -886,7 +894,7 @@ CheckPresentedIDConformsToNameConstraintsSubtrees(
rv = MatchPresentedDNSIDWithReferenceDNSID(
presentedID, AllowWildcards::Yes,
AllowDotlessSubdomainMatches::Yes, IDRole::NameConstraint,
base, matches);
&subtreesType, base, matches);
if (rv != Success) {
return rv;
}
@ -911,7 +919,7 @@ CheckPresentedIDConformsToNameConstraintsSubtrees(
case GeneralNameType::rfc822Name:
rv = MatchPresentedRFC822NameWithReferenceRFC822Name(
presentedID, IDRole::NameConstraint, base, matches);
presentedID, IDRole::NameConstraint, &subtreesType, base, matches);
if (rv != Success) {
return rv;
}
@ -1094,6 +1102,7 @@ MatchPresentedDNSIDWithReferenceDNSID(
AllowWildcards allowWildcards,
AllowDotlessSubdomainMatches allowDotlessSubdomainMatches,
IDRole referenceDNSIDRole,
/*optional*/ const NameConstraintsSubtrees* subtreesType,
Input referenceDNSID,
/*out*/ bool& matches)
{
@ -1184,18 +1193,28 @@ MatchPresentedDNSIDWithReferenceDNSID(
return NotReached("Skipping '*' failed",
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
do {
// This will happen if reference is a single, relative label
if (reference.AtEnd()) {
matches = false;
return Success;
}
uint8_t referenceByte;
if (reference.Read(referenceByte) != Success) {
return NotReached("invalid reference ID",
Result::FATAL_ERROR_INVALID_ARGS);
}
} while (!reference.Peek('.'));
// For the permittedSubtrees of a name constraint, wildcard presented
// DNSIDs of the form `*.example.com` only match if the name constraint is
// of the form `.example.com` or `example.com`. To put it another way, a
// permittedSubtrees of `foo.example.com` does not match a wildcard
// presented DNSID of `*.example.com`, because in that case, the
// certificate could be valid for `bar.example.com`, which does not match
// the name constraint.
if (referenceDNSIDRole != IDRole::NameConstraint ||
(subtreesType && *subtreesType != NameConstraintsSubtrees::permittedSubtrees)) {
do {
// This will happen if reference is a single, relative label
if (reference.AtEnd()) {
matches = false;
return Success;
}
uint8_t referenceByte;
if (reference.Read(referenceByte) != Success) {
return NotReached("invalid reference ID",
Result::FATAL_ERROR_INVALID_ARGS);
}
} while (!reference.Peek('.'));
}
}
for (;;) {
@ -1552,11 +1571,13 @@ IsValidRFC822Name(Input input)
}
}
// `subtreesType` is relevant only when `referenceRFC822NameRole` is
// `IDRole::NameConstraint`.
Result
MatchPresentedRFC822NameWithReferenceRFC822Name(Input presentedRFC822Name,
IDRole referenceRFC822NameRole,
Input referenceRFC822Name,
/*out*/ bool& matches)
MatchPresentedRFC822NameWithReferenceRFC822Name(
Input presentedRFC822Name, IDRole referenceRFC822NameRole,
/*optional*/ const NameConstraintsSubtrees* subtreesType,
Input referenceRFC822Name, /*out*/ bool& matches)
{
if (!IsValidRFC822Name(presentedRFC822Name)) {
return Result::ERROR_BAD_DER;
@ -1599,6 +1620,7 @@ MatchPresentedRFC822NameWithReferenceRFC822Name(Input presentedRFC822Name,
return MatchPresentedDNSIDWithReferenceDNSID(
presentedDNSID, AllowWildcards::No,
AllowDotlessSubdomainMatches::No, IDRole::NameConstraint,
subtreesType,
referenceRFC822Name, matches);
}
}

View file

@ -22,10 +22,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define NSS_VERSION "3.112.3" _NSS_CUSTOMIZED
#define NSS_VERSION "3.112.5" _NSS_CUSTOMIZED
#define NSS_VMAJOR 3
#define NSS_VMINOR 112
#define NSS_VPATCH 3
#define NSS_VPATCH 5
#define NSS_VBUILD 0
#define NSS_BETA PR_FALSE

View file

@ -733,12 +733,15 @@ PK11_ImportPrivateKeyInfoAndReturnKey(PK11SlotInfo *slot,
rv = PK11_ImportAndReturnPrivateKey(slot, lpk, nickname, publicValue, isPerm,
isPrivate, keyUsage, privk, wincx);
loser:
if (arena != NULL) {
PORT_FreeArena(arena, PR_TRUE);
if (rv != SECSuccess) {
goto loser;
}
PORT_FreeArena(arena, PR_TRUE);
return SECSuccess;
return rv;
loser:
PORT_FreeArena(arena, PR_TRUE);
return SECFailure;
}
SECStatus

View file

@ -230,6 +230,8 @@ sec_pkcs7_decoder_start_digests(SEC_PKCS7DecoderContext *p7dcx, int depth,
{
int i, digcnt;
p7dcx->worker.digcnt = 0;
if (digestalgs == NULL)
return SECSuccess;
@ -257,7 +259,6 @@ sec_pkcs7_decoder_start_digests(SEC_PKCS7DecoderContext *p7dcx, int depth,
}
p7dcx->worker.depth = depth;
p7dcx->worker.digcnt = 0;
/*
* Create a digest context for each algorithm.
@ -277,7 +278,6 @@ sec_pkcs7_decoder_start_digests(SEC_PKCS7DecoderContext *p7dcx, int depth,
* but we cannot know that until later.
*/
if (digobj == NULL) {
p7dcx->worker.digcnt--;
continue;
}
@ -306,25 +306,19 @@ sec_pkcs7_decoder_finish_digests(SEC_PKCS7DecoderContext *p7dcx,
PLArenaPool *poolp,
SECItem ***digestsp)
{
struct sec_pkcs7_decoder_worker *worker;
const SECHashObject *digobj;
void *digcx;
SECItem **digests, *digest;
int i;
void *mark;
/*
* XXX Handling nested contents would mean that there is a chain
* of workers -- one per each level of content. The following
* would want to find the last worker in the chain.
*/
worker = &(p7dcx->worker);
struct sec_pkcs7_decoder_worker *worker = &(p7dcx->worker);
/*
* If no digests, then we have nothing to do.
*/
if (worker->digcnt == 0)
if (worker->digcnt == 0) {
return SECSuccess;
}
/*
* No matter what happens after this, we want to stop filtering.
@ -340,46 +334,46 @@ sec_pkcs7_decoder_finish_digests(SEC_PKCS7DecoderContext *p7dcx,
* was digested.
*/
if (!worker->saw_contents) {
for (i = 0; i < worker->digcnt; i++) {
digcx = worker->digcxs[i];
digobj = worker->digobjs[i];
for (int i = 0; i < worker->digcnt; i++) {
void *digcx = worker->digcxs[i];
const SECHashObject *digobj = worker->digobjs[i];
(*digobj->destroy)(digcx, PR_TRUE);
}
worker->digcnt = 0;
return SECSuccess;
}
mark = PORT_ArenaMark(poolp);
void *mark = PORT_ArenaMark(poolp);
/*
* Close out each digest context, saving digest away.
*/
digests =
(SECItem **)PORT_ArenaAlloc(poolp, (worker->digcnt + 1) * sizeof(SECItem *));
digest = (SECItem *)PORT_ArenaAlloc(poolp, worker->digcnt * sizeof(SECItem));
if (digests == NULL || digest == NULL) {
SECItem **digests =
(SECItem **)PORT_ArenaZAlloc(poolp, (worker->digcnt + 1) * sizeof(SECItem *));
if (digests == NULL) {
p7dcx->error = PORT_GetError();
PORT_ArenaRelease(poolp, mark);
return SECFailure;
}
for (i = 0; i < worker->digcnt; i++, digest++) {
digcx = worker->digcxs[i];
digobj = worker->digobjs[i];
digest->data = (unsigned char *)PORT_ArenaAlloc(poolp, digobj->length);
if (digest->data == NULL) {
for (int i = 0; i < worker->digcnt; i++) {
const SECHashObject *digobj = worker->digobjs[i];
digests[i] = SECITEM_AllocItem(poolp, NULL, digobj->length);
if (!digests[i]) {
p7dcx->error = PORT_GetError();
PORT_ArenaRelease(poolp, mark);
return SECFailure;
}
digest->len = digobj->length;
(*digobj->end)(digcx, digest->data, &(digest->len), digest->len);
(*digobj->destroy)(digcx, PR_TRUE);
digests[i] = digest;
}
digests[i] = NULL;
for (int i = 0; i < worker->digcnt; i++) {
void *digcx = worker->digcxs[i];
const SECHashObject *digobj = worker->digobjs[i];
(*digobj->end)(digcx, digests[i]->data, &(digests[i]->len), digests[i]->len);
(*digobj->destroy)(digcx, PR_TRUE);
}
worker->digcnt = 0;
*digestsp = digests;
PORT_ArenaUnmark(poolp, mark);
@ -1084,6 +1078,13 @@ SEC_PKCS7DecoderFinish(SEC_PKCS7DecoderContext *p7dcx)
if (p7dcx->worker.decryptobj) {
sec_PKCS7DestroyDecryptObject(p7dcx->worker.decryptobj);
}
for (int i = 0; i < p7dcx->worker.digcnt; i++) {
void *digcx = p7dcx->worker.digcxs[i];
const SECHashObject *digobj = p7dcx->worker.digobjs[i];
(*digobj->destroy)(digcx, PR_TRUE);
}
p7dcx->worker.digcnt = 0;
PORT_FreeArena(p7dcx->tmp_poolp, PR_FALSE);
PORT_Free(p7dcx);
return cinfo;

View file

@ -91,6 +91,7 @@ struct cache_entry_str {
PRTime lastHit;
NSSArena *arena;
NSSUTF8 *nickname;
NSSASCII7 *email;
};
typedef struct cache_entry_str cache_entry;
@ -229,6 +230,7 @@ remove_subject_entry(
NSSCertificate *cert,
nssList **subjectList,
NSSUTF8 **nickname,
NSSASCII7 **email,
NSSArena **arena)
{
PRStatus nssrv;
@ -242,6 +244,7 @@ remove_subject_entry(
nssList_Remove(ce->entry.list, cert);
*subjectList = ce->entry.list;
*nickname = ce->nickname;
*email = ce->email;
*arena = ce->arena;
nssrv = PR_SUCCESS;
#ifdef DEBUG_CACHE
@ -276,35 +279,34 @@ remove_nickname_entry(
static PRStatus
remove_email_entry(
nssTDCertificateCache *cache,
NSSCertificate *cert,
NSSASCII7 *email,
nssList *subjectList)
{
PRStatus nssrv = PR_FAILURE;
cache_entry *ce;
/* Find the subject list in the email hash */
if (cert->email) {
ce = (cache_entry *)nssHash_Lookup(cache->email, cert->email);
if (email) {
ce = (cache_entry *)nssHash_Lookup(cache->email, email);
if (ce) {
nssList *subjects = ce->entry.list;
/* Remove the subject list from the email hash */
if (subjects) {
nssList_Remove(subjects, subjectList);
#ifdef DEBUG_CACHE
log_item_dump("removed subject list", &cert->subject);
PR_LOG(s_log, PR_LOG_DEBUG, ("for email %s", cert->email));
PR_LOG(s_log, PR_LOG_DEBUG,
("removed subject list for email %s", email));
#endif
if (nssList_Count(subjects) == 0) {
/* No more subject lists for email, delete list and
* remove hash entry
*/
(void)nssList_Destroy(subjects);
nssHash_Remove(cache->email, cert->email);
nssHash_Remove(cache->email, email);
/* there are no entries left for this address, free space
* used for email entries
*/
nssArena_Destroy(ce->arena);
#ifdef DEBUG_CACHE
PR_LOG(s_log, PR_LOG_DEBUG, ("removed email %s", cert->email));
PR_LOG(s_log, PR_LOG_DEBUG, ("removed email %s", email));
#endif
}
}
@ -323,6 +325,7 @@ nssTrustDomain_RemoveCertFromCacheLOCKED(
cache_entry *ce;
NSSArena *arena;
NSSUTF8 *nickname = NULL;
NSSASCII7 *email = NULL;
#ifdef DEBUG_CACHE
log_cert_ref("attempt to remove cert", cert);
@ -339,10 +342,10 @@ nssTrustDomain_RemoveCertFromCacheLOCKED(
}
(void)remove_issuer_and_serial_entry(td->cache, cert);
(void)remove_subject_entry(td->cache, cert, &subjectList,
&nickname, &arena);
&nickname, &email, &arena);
if (nssList_Count(subjectList) == 0) {
(void)remove_nickname_entry(td->cache, nickname, subjectList);
(void)remove_email_entry(td->cache, cert, subjectList);
(void)remove_email_entry(td->cache, email, subjectList);
(void)nssList_Destroy(subjectList);
nssHash_Remove(td->cache->subject, &cert->subject);
/* there are no entries left for this subject, free the space used
@ -537,6 +540,9 @@ add_subject_entry(
if (nickname) {
ce->nickname = nssUTF8_Duplicate(nickname, arena);
}
if (cert->email) {
ce->email = nssUTF8_Duplicate(cert->email, arena);
}
nssList_SetSortFunction(list, nssCertificate_SubjectListSort);
/* Add the cert entry to this list of subjects */
nssrv = nssList_AddUnique(list, cert);
@ -710,6 +716,7 @@ add_cert_to_cache(
PRUint32 added = 0;
cache_entry *ce;
NSSCertificate *rvCert = NULL;
NSSASCII7 *email = NULL;
NSSUTF8 *certNickname = nssCertificate_GetNickname(cert, NULL);
/* Set cc->trust and cc->nssCertificate before taking td->cache->lock.
@ -817,13 +824,13 @@ loser:
}
if (added >= 2) {
(void)remove_subject_entry(td->cache, cert, &subjectList,
&certNickname, &arena);
&certNickname, &email, &arena);
}
if (added == 3 || added == 5) {
(void)remove_nickname_entry(td->cache, certNickname, subjectList);
}
if (added >= 4) {
(void)remove_email_entry(td->cache, cert, subjectList);
(void)remove_email_entry(td->cache, email, subjectList);
}
if (subjectList) {
nssHash_Remove(td->cache->subject, &cert->subject);

View file

@ -322,7 +322,6 @@ nss_cms_before_data(NSSCMSDecoderContext *p7dcx)
loser:
if (mark)
PORT_ArenaRelease(poolp, mark);
PORT_Free(childp7dcx);
p7dcx->childp7dcx = NULL;
return SECFailure;
}
@ -555,8 +554,19 @@ nss_cms_decoder_work_data(NSSCMSDecoderContext *p7dcx,
SECItem *dataItem = &decoderData->data;
offset = dataItem->len;
/* Reject if accumulated size would exceed unsigned int storage. */
if (len > (unsigned long)(PR_UINT32_MAX - dataItem->len)) {
p7dcx->error = SEC_ERROR_INPUT_LEN;
goto loser;
}
if (dataItem->len + len > decoderData->totalBufferSize) {
int needLen = (dataItem->len + len) * 2;
/* Use size_t to avoid truncating the 64-bit sum to int.
* Double to amortize repeated reallocations across chunks. */
size_t needLen = (size_t)dataItem->len + len;
/* Only double if the result still fits in unsigned int. */
if (needLen <= PR_UINT32_MAX / 2) {
needLen *= 2;
}
dest = (unsigned char *)
PORT_ArenaAlloc(p7dcx->cmsg->poolp, needLen);
if (dest == NULL) {
@ -567,7 +577,7 @@ nss_cms_decoder_work_data(NSSCMSDecoderContext *p7dcx,
if (dataItem->len) {
PORT_Memcpy(dest, dataItem->data, dataItem->len);
}
decoderData->totalBufferSize = needLen;
decoderData->totalBufferSize = (unsigned int)needLen;
dataItem->data = dest;
}

View file

@ -566,6 +566,7 @@ NSS_CMSUtil_DecryptSymKey_ECDH(SECKEYPrivateKey *privkey, SECItem *encKey,
SECStatus rv;
PORT_Memset(&keyWrapAlg, 0, sizeof(SECAlgorithmID));
PORT_Memset(&originatorpublickey, 0, sizeof(SECKEYPublicKey));
PORT_Assert(bulkalgtag != SEC_OID_UNKNOWN);
target = PK11_AlgtagToMechanism(bulkalgtag);

View file

@ -17,10 +17,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <ECC>][ <Beta>]"
*/
#define SOFTOKEN_VERSION "3.112.3" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VERSION "3.112.5" SOFTOKEN_ECC_STRING
#define SOFTOKEN_VMAJOR 3
#define SOFTOKEN_VMINOR 112
#define SOFTOKEN_VPATCH 3
#define SOFTOKEN_VPATCH 5
#define SOFTOKEN_VBUILD 0
#define SOFTOKEN_BETA PR_FALSE

View file

@ -1101,7 +1101,7 @@ dtls_HandleHelloVerifyRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
{
int errCode = SSL_ERROR_RX_MALFORMED_HELLO_VERIFY_REQUEST;
SECStatus rv;
SSL3ProtocolVersion temp;
SSL3ProtocolVersion version;
SSL3AlertDescription desc = illegal_parameter;
SSL_TRC(3, ("%d: SSL3[%d]: handle hello_verify_request handshake",
@ -1130,22 +1130,29 @@ dtls_HandleHelloVerifyRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
* Therefore we do not do anything to enforce a match, just
* read and check that this value is sane.
*/
rv = ssl_ClientReadVersion(ss, &b, &length, &temp);
rv = ssl_ClientReadVersion(ss, &b, &length, &version);
if (rv != SECSuccess) {
goto loser; /* alert has been sent */
}
/* Read the cookie.
* IMPORTANT: The value of ss->ssl3.hs.cookie is only valid while the
* HelloVerifyRequest message remains valid. */
rv = ssl3_ConsumeHandshakeVariable(ss, &ss->ssl3.hs.cookie, 1, &b, &length);
/* Read the cookie. */
SECItem cookie;
rv = ssl3_ConsumeHandshakeVariable(ss, &cookie, 1, &b, &length);
if (rv != SECSuccess) {
goto loser; /* alert has been sent */
}
if (ss->ssl3.hs.cookie.len > DTLS_COOKIE_BYTES) {
if (cookie.len > DTLS_COOKIE_BYTES) {
desc = decode_error;
goto alert_loser; /* malformed. */
}
PORT_Assert(!ss->ssl3.hs.cookie.data && !ss->ssl3.hs.cookie.len);
SECITEM_FreeItem(&ss->ssl3.hs.cookie, PR_FALSE);
rv = SECITEM_CopyItem(NULL, &ss->ssl3.hs.cookie, &cookie);
if (rv != SECSuccess) {
goto loser;
}
ss->ssl3.hs.dtlsReceivedHVR = PR_TRUE;
ssl_GetXmitBufLock(ss); /*******************************/
@ -1154,6 +1161,8 @@ dtls_HandleHelloVerifyRequest(sslSocket *ss, PRUint8 *b, PRUint32 length)
ssl_ReleaseXmitBufLock(ss); /*******************************/
SECITEM_FreeItem(&ss->ssl3.hs.cookie, PR_FALSE);
if (rv == SECSuccess)
return rv;

View file

@ -7201,6 +7201,15 @@ ssl3_HandleServerHello(sslSocket *ss, PRUint8 *b, PRUint32 length)
goto alert_loser;
}
/* A server that sent HelloVerifyRequest is DTLS 1.2 or earlier;
* reject a subsequent TLS 1.3 ServerHello as illegal. */
if (ss->ssl3.hs.dtlsReceivedHVR &&
ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
desc = illegal_parameter;
errCode = SSL_ERROR_RX_MALFORMED_SERVER_HELLO;
goto alert_loser;
}
/* There are three situations in which the server must pick
* TLS 1.3.
*
@ -13917,6 +13926,8 @@ ssl3_InitState(sslSocket *ss)
sizeof(ss->ssl3.hs.newSessionTicket));
ss->ssl3.hs.zeroRttState = ssl_0rtt_none;
ss->ssl3.hs.dtlsReceivedHVR = PR_FALSE;
return SECSuccess;
}
@ -14266,6 +14277,7 @@ ssl3_DestroySSL3Info(sslSocket *ss)
SECITEM_FreeItem(&ss->ssl3.hs.newSessionTicket.ticket, PR_FALSE);
SECITEM_FreeItem(&ss->ssl3.hs.srvVirtName, PR_FALSE);
SECITEM_FreeItem(&ss->ssl3.hs.fakeSid, PR_FALSE);
SECITEM_FreeItem(&ss->ssl3.hs.cookie, PR_FALSE);
/* Destroy the DTLS data */
if (IS_DTLS(ss)) {

View file

@ -336,6 +336,26 @@ ssl3_ExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type)
xtnData->numAdvertised, ex_type);
}
void
ssl3_RecordExtensionNegotiated(const sslSocket *ss, TLSExtensionData *xtnData,
PRUint16 ex_type)
{
/* Record that an extension was negotiated during a full TLS handshake.
* This function must NOT be used to track extensions carried in
* post-handshake messages (e.g. CertificateRequest during PHA);
* their negotiation state should instead be stored in dedicated fields on
* TLSExtensionData or sslSocket (e.g. xtnData->compressionAlg for
* certificate compression). */
PORT_Assert(!ss->firstHsDone ||
ss->opt.enableRenegotiation != SSL_RENEGOTIATE_NEVER);
PORT_Assert(!arrayContainsExtension(xtnData->negotiated,
xtnData->numNegotiated, ex_type));
PORT_Assert(xtnData->numNegotiated < SSL_MAX_EXTENSIONS);
if (xtnData->numNegotiated < SSL_MAX_EXTENSIONS) {
xtnData->negotiated[xtnData->numNegotiated++] = ex_type;
}
}
PRBool
ssl3_ExtensionAdvertisedClientHelloInner(const sslSocket *ss, PRUint16 ex_type)
{

View file

@ -175,6 +175,9 @@ void ssl3_ResetExtensionData(TLSExtensionData *xtnData, const sslSocket *ss);
PRBool ssl3_ExtensionNegotiated(const sslSocket *ss, PRUint16 ex_type);
PRBool ssl3_ExtensionAdvertised(const sslSocket *ss, PRUint16 ex_type);
void ssl3_RecordExtensionNegotiated(const sslSocket *ss,
TLSExtensionData *xtnData,
PRUint16 ex_type);
SECStatus ssl3_RegisterExtensionSender(const sslSocket *ss,
TLSExtensionData *xtnData,

View file

@ -165,7 +165,7 @@ ssl3_HandleServerNameXtn(const sslSocket *ss, TLSExtensionData *xtnData,
ssl3_FreeSniNameArray(xtnData);
xtnData->sniNameArr = names;
xtnData->sniNameArrSize = 1;
xtnData->negotiated[xtnData->numNegotiated++] = ssl_server_name_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_server_name_xtn);
}
return SECSuccess;
@ -345,7 +345,7 @@ ssl3_SelectAppProtocol(const sslSocket *ss, TLSExtensionData *xtnData,
}
xtnData->nextProtoState = SSL_NEXT_PROTO_NEGOTIATED;
xtnData->negotiated[xtnData->numNegotiated++] = extension;
ssl3_RecordExtensionNegotiated(ss, xtnData, extension);
return SECITEM_CopyItem(NULL, &xtnData->nextProto, &result);
}
@ -447,7 +447,7 @@ ssl3_ClientHandleAppProtoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
SECITEM_FreeItem(&xtnData->nextProto, PR_FALSE);
xtnData->nextProtoState = SSL_NEXT_PROTO_SELECTED;
xtnData->negotiated[xtnData->numNegotiated++] = ssl_app_layer_protocol_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_app_layer_protocol_xtn);
return SECITEM_CopyItem(NULL, &xtnData->nextProto, &protocol_name);
}
@ -528,7 +528,7 @@ ssl3_ServerHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData
PORT_Assert(ss->sec.isServer);
/* remember that we got this extension. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_cert_status_xtn);
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
sender = tls13_ServerSendStatusRequestXtn;
@ -606,7 +606,7 @@ ssl3_ClientHandleStatusRequestXtn(const sslSocket *ss, TLSExtensionData *xtnData
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_cert_status_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_cert_status_xtn);
return SECSuccess;
}
@ -859,7 +859,7 @@ ssl3_ClientHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_session_ticket_xtn);
return SECSuccess;
}
@ -1309,7 +1309,7 @@ ssl3_ServerHandleSessionTicketXtn(const sslSocket *ss, TLSExtensionData *xtnData
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_session_ticket_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_session_ticket_xtn);
/* Parse the received ticket sent in by the client. We are
* lenient about some parse errors, falling back to a fullshake
@ -1387,7 +1387,7 @@ ssl3_HandleRenegotiationInfoXtn(const sslSocket *ss, TLSExtensionData *xtnData,
/* remember that we got this extension and it was correct. */
CONST_CAST(sslSocket, ss)
->peerRequestedProtection = 1;
xtnData->negotiated[xtnData->numNegotiated++] = ssl_renegotiation_info_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_renegotiation_info_xtn);
if (ss->sec.isServer) {
/* prepare to send back the appropriate response */
rv = ssl3_RegisterExtensionSender(ss, xtnData,
@ -1522,7 +1522,7 @@ ssl3_ClientHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
/* OK, this looks fine. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_use_srtp_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_use_srtp_xtn);
xtnData->dtlsSRTPCipherSuite = cipher;
return SECSuccess;
}
@ -1593,7 +1593,7 @@ ssl3_ServerHandleUseSRTPXtn(const sslSocket *ss, TLSExtensionData *xtnData,
/* OK, we have a valid cipher and we've selected it */
xtnData->dtlsSRTPCipherSuite = cipher;
xtnData->negotiated[xtnData->numNegotiated++] = ssl_use_srtp_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_use_srtp_xtn);
return ssl3_RegisterExtensionSender(ss, xtnData,
ssl_use_srtp_xtn,
@ -1639,8 +1639,12 @@ ssl3_HandleSigAlgsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECFailure;
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_signature_algorithms_xtn;
/* Keep track of negotiated extensions. Only the server consumes this
* entry; on the client, skipping prevents numNegotiated overflow
* during repeated post-handshake CertificateRequests. */
if (ss->sec.isServer) {
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_signature_algorithms_xtn);
}
return SECSuccess;
}
@ -1711,7 +1715,7 @@ ssl3_HandleExtendedMasterSecretXtn(const sslSocket *ss, TLSExtensionData *xtnDat
SSL_GETPID(), ss->fd));
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_extended_master_secret_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_extended_master_secret_xtn);
if (ss->sec.isServer) {
return ssl3_RegisterExtensionSender(ss, xtnData,
@ -1758,7 +1762,7 @@ ssl3_ClientHandleSignedCertTimestampXtn(const sslSocket *ss, TLSExtensionData *x
}
*scts = *data;
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_signed_cert_timestamp_xtn);
return SECSuccess;
}
@ -1794,7 +1798,7 @@ ssl3_ServerHandleSignedCertTimestampXtn(const sslSocket *ss,
return SECFailure;
}
xtnData->negotiated[xtnData->numNegotiated++] = ssl_signed_cert_timestamp_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_signed_cert_timestamp_xtn);
PORT_Assert(ss->sec.isServer);
return ssl3_RegisterExtensionSender(ss, xtnData,
ssl_signed_cert_timestamp_xtn,
@ -1934,7 +1938,7 @@ ssl_HandleSupportedGroupsXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
/* Remember that we negotiated this extension. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_supported_groups_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_supported_groups_xtn);
return SECSuccess;
}
@ -1975,7 +1979,7 @@ ssl_HandleRecordSizeLimitXtn(const sslSocket *ss, TLSExtensionData *xtnData,
/* We can't enforce the maximum on a server. But we do need to ensure
* that we don't apply a limit that is too large. */
xtnData->recordSizeLimit = PR_MIN(maxLimit, limit);
xtnData->negotiated[xtnData->numNegotiated++] = ssl_record_size_limit_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_record_size_limit_xtn);
return SECSuccess;
}

View file

@ -760,6 +760,8 @@ typedef struct SSL3HandshakeStateStr {
* on server.*/
PRBool helloRetry; /* True if HelloRetryRequest has been sent
* or received. */
PRBool dtlsReceivedHVR; /* True if a DTLS HelloVerifyRequest was
* received. */
PRBool receivedCcs; /* A server received ChangeCipherSpec
* before the handshake started. */
PRBool rejectCcs; /* Excessive ChangeCipherSpecs are rejected. */

View file

@ -3031,6 +3031,7 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *savedMsg,
rv = ssl3_HandleParsedExtensions(ss, ssl_hs_hello_retry_request);
ssl3_DestroyRemoteExtensions(&ss->ssl3.hs.remoteExtensions);
if (rv != SECSuccess) {
SECITEM_FreeItem(&ss->ssl3.hs.cookie, PR_FALSE);
return SECFailure; /* Error code set below */
}
rv = tls13_MaybeHandleEchSignal(ss, savedMsg, savedLength, PR_TRUE);
@ -3064,10 +3065,12 @@ tls13_HandleHelloRetryRequest(sslSocket *ss, const PRUint8 *savedMsg,
}
ssl_ReleaseXmitBufLock(ss);
SECITEM_FreeItem(&ss->ssl3.hs.cookie, PR_FALSE);
return SECSuccess;
loser:
ssl_ReleaseXmitBufLock(ss);
SECITEM_FreeItem(&ss->ssl3.hs.cookie, PR_FALSE);
return SECFailure;
}
@ -4060,6 +4063,20 @@ tls13_HandleCertificateDecode(sslSocket *ss, PRUint8 *b, PRUint32 length)
return SECFailure;
}
/* Cap the decompressed size to prevent memory exhaustion. The wire field
* is a uint24 (max 16MB) but the CompressedCertificate path bypasses the
* 128KB cap applied to regular handshake messages. 100KB matches the limit
* enforced by OpenSSL and BoringSSL. */
#define MAX_CERT_UNCOMPRESSED_LEN (100 * 1024)
if (decodedCertLen > MAX_CERT_UNCOMPRESSED_LEN) {
SSL_TRC(50, ("%d: TLS13[%d]: %s uncompressed_length %u exceeds limit %u",
SSL_GETPID(), ss->fd, SSL_ROLE(ss),
decodedCertLen, MAX_CERT_UNCOMPRESSED_LEN));
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_CERTIFICATE, bad_certificate);
return SECFailure;
}
#undef MAX_CERT_UNCOMPRESSED_LEN
/* opaque compressed_certificate_message<1..2^24-1>; */
PRUint32 compressedCertLen = 0;
rv = ssl3_ConsumeHandshakeNumber(ss, &compressedCertLen, 3, &b, &length);
@ -4989,6 +5006,10 @@ tls13_AEAD(PK11Context *context, PRBool decrypt,
PORT_Memcpy(ivOut, ivIn, ivLen);
}
if (decrypt) {
if (inLen < tagLen) {
PORT_SetError(SEC_ERROR_INPUT_LEN);
return SECFailure;
}
inLen = inLen - tagLen;
tag = (unsigned char *)in + inLen;
/* tag is const on decrypt, but returned on encrypt */

View file

@ -2442,7 +2442,7 @@ tls13_MaybeHandleEchSignal(sslSocket *ss, const PRUint8 *sh, PRUint32 shLen, PRB
PORT_SetError(SSL_ERROR_BAD_2ND_CLIENT_HELLO);
return SECFailure;
}
ss->xtnData.negotiated[ss->xtnData.numNegotiated++] = ssl_tls13_encrypted_client_hello_xtn;
ssl3_RecordExtensionNegotiated(ss, &ss->xtnData, ssl_tls13_encrypted_client_hello_xtn);
/* Only overwrite client_random with client_inner_random if CHInner was
* succesfully used for handshake (NOT if HRR is received). */

View file

@ -446,8 +446,7 @@ tls13_ServerHandleKeyShareXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] =
ssl_tls13_key_share_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_tls13_key_share_xtn);
return SECSuccess;
@ -746,7 +745,7 @@ tls13_ServerHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData
return SECSuccess;
}
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_tls13_pre_shared_key_xtn);
return SECSuccess;
alert_loser:
@ -816,7 +815,7 @@ tls13_ClientHandlePreSharedKeyXtn(const sslSocket *ss, TLSExtensionData *xtnData
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_pre_shared_key_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_tls13_pre_shared_key_xtn);
xtnData->selectedPsk = candidate;
return SECSuccess;
@ -860,7 +859,7 @@ tls13_ServerHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
return SECFailure;
}
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_early_data_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_tls13_early_data_xtn);
return SECSuccess;
}
@ -885,7 +884,7 @@ tls13_ClientHandleEarlyDataXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_early_data_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_tls13_early_data_xtn);
return SECSuccess;
}
@ -1036,20 +1035,27 @@ tls13_ClientHandleHrrCookie(const sslSocket *ss, TLSExtensionData *xtnData,
PORT_Assert(ss->vrange.max >= SSL_LIBRARY_VERSION_TLS_1_3);
/* IMPORTANT: this is only valid while the HelloRetryRequest is still valid. */
SECItem cookie;
rv = ssl3_ExtConsumeHandshakeVariable(
ss, &CONST_CAST(sslSocket, ss)->ssl3.hs.cookie, 2,
ss, &cookie, 2,
&data->data, &data->len);
if (rv != SECSuccess) {
PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST);
return SECFailure;
}
if (!ss->ssl3.hs.cookie.len || data->len) {
if (!cookie.len || data->len) {
ssl3_ExtSendAlert(ss, alert_fatal, decode_error);
PORT_SetError(SSL_ERROR_RX_MALFORMED_HELLO_RETRY_REQUEST);
return SECFailure;
}
PORT_Assert(!ss->ssl3.hs.cookie.data && !ss->ssl3.hs.cookie.len);
SECITEM_FreeItem(&CONST_CAST(sslSocket, ss)->ssl3.hs.cookie, PR_FALSE);
rv = SECITEM_CopyItem(NULL, &CONST_CAST(sslSocket, ss)->ssl3.hs.cookie, &cookie);
if (rv != SECSuccess) {
return SECFailure;
}
return SECSuccess;
}
@ -1101,7 +1107,7 @@ tls13_ServerHandleCookieXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_cookie_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_tls13_cookie_xtn);
return SECSuccess;
}
@ -1138,7 +1144,7 @@ tls13_ServerHandlePostHandshakeAuthXtn(const sslSocket *ss,
* NST immediately following the client Finished. */
if (!IS_DTLS(ss)) {
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_post_handshake_auth_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_tls13_post_handshake_auth_xtn);
}
return SECSuccess;
@ -1209,8 +1215,7 @@ tls13_ServerHandlePskModesXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
/* Keep track of negotiated extensions. */
xtnData->negotiated[xtnData->numNegotiated++] =
ssl_tls13_psk_key_exchange_modes_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_tls13_psk_key_exchange_modes_xtn);
return SECSuccess;
}
@ -1554,8 +1559,7 @@ tls13_ClientHandleDelegatedCredentialsXtn(const sslSocket *ss,
}
xtnData->peerDelegCred = dc;
xtnData->negotiated[xtnData->numNegotiated++] =
ssl_delegated_credentials_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_delegated_credentials_xtn);
return SECSuccess;
alert_loser:
ssl3_ExtSendAlert(ss, alert_fatal, illegal_parameter);
@ -1619,8 +1623,7 @@ tls13_ServerHandleDelegatedCredentialsXtn(const sslSocket *ss,
/* Keep track of negotiated extensions. */
xtnData->peerRequestedDelegCred = PR_TRUE;
xtnData->negotiated[xtnData->numNegotiated++] =
ssl_delegated_credentials_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_delegated_credentials_xtn);
return ssl3_RegisterExtensionSender(
ss, xtnData, ssl_delegated_credentials_xtn,
@ -1709,7 +1712,7 @@ tls13_ServerHandleInnerEchXtn(const sslSocket *ss, TLSExtensionData *xtnData,
}
xtnData->ech->receivedInnerXtn = PR_TRUE;
xtnData->negotiated[xtnData->numNegotiated++] = ssl_tls13_encrypted_client_hello_xtn;
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_tls13_encrypted_client_hello_xtn);
return SECSuccess;
alert_loser:
@ -1995,7 +1998,9 @@ ssl3_HandleCertificateCompressionXtn(const sslSocket *ss,
for (int j = 0; j < ss->ssl3.supportedCertCompressionAlgorithmsCount; j++) {
if (ss->ssl3.supportedCertCompressionAlgorithms[j].id == alg) {
xtnData->compressionAlg = alg;
xtnData->negotiated[xtnData->numNegotiated++] = ssl_certificate_compression_xtn;
if (ss->sec.isServer) {
ssl3_RecordExtensionNegotiated(ss, xtnData, ssl_certificate_compression_xtn);
}
algFound = SECSuccess;
break;
}

View file

@ -19,10 +19,10 @@
* The format of the version string should be
* "<major version>.<minor version>[.<patch level>[.<build number>]][ <Beta>]"
*/
#define NSSUTIL_VERSION "3.112.3"
#define NSSUTIL_VERSION "3.112.5"
#define NSSUTIL_VMAJOR 3
#define NSSUTIL_VMINOR 112
#define NSSUTIL_VPATCH 3
#define NSSUTIL_VPATCH 5
#define NSSUTIL_VBUILD 0
#define NSSUTIL_BETA PR_FALSE

View file

@ -522,11 +522,18 @@ DecodeGroup(void* dest,
}
} while ((SECSuccess == rv) && (counter.len));
/* Limit entry data to 1 GiB. */
if (SECSuccess == rv && subTemplate->size &&
totalEntries > ((size_t)1 << 30) / subTemplate->size) {
PORT_SetError(SEC_ERROR_BAD_DER);
rv = SECFailure;
}
if (SECSuccess == rv) {
/* allocate room for pointer array and entries */
/* we want to allocate the array even if there is 0 entry */
entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*) * (totalEntries + 1) + /* the extra one is for NULL termination */
subTemplate->size * totalEntries);
(size_t)subTemplate->size * totalEntries);
if (entries) {
entries[totalEntries] = NULL; /* terminate the array */
@ -540,7 +547,7 @@ DecodeGroup(void* dest,
PRUint32 entriesIndex = 0;
for (entriesIndex = 0; entriesIndex < totalEntries; entriesIndex++) {
entries[entriesIndex] =
(char*)entriesData + (subTemplate->size * entriesIndex);
(char*)entriesData + ((size_t)subTemplate->size * entriesIndex);
}
}
}

View file

@ -9,8 +9,8 @@ origin:
description: nss
url: https://hg-edge.mozilla.org/projects/nss
release: e65740334234fa690d1a80c807fb578bb030ed2b (2026-02-13T14:13:57Z).
revision: e65740334234fa690d1a80c807fb578bb030ed2b
release: fddd54c0fb1444c710f442c872de3af8eaa9aec9 (2026-04-23T19:27:46Z).
revision: fddd54c0fb1444c710f442c872de3af8eaa9aec9
license: MPL-2.0
license-file: COPYING