Version in base suite: 3.110-1+deb13u1 Base version: nss_3.110-1+deb13u1 Target version: nss_3.110-1+deb13u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/n/nss/nss_3.110-1+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/n/nss/nss_3.110-1+deb13u2.dsc changelog | 8 patches/CVE-2026-6766.patch | 22 ++ patches/CVE-2026-6767.patch | 239 +++++++++++++++++++++++++++++ patches/CVE-2026-6772.patch | 359 ++++++++++++++++++++++++++++++++++++++++++++ patches/series | 3 5 files changed, 631 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp1dxo1mnz/nss_3.110-1+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp1dxo1mnz/nss_3.110-1+deb13u2.dsc: no acceptable signature found diff -Nru nss-3.110/debian/changelog nss-3.110/debian/changelog --- nss-3.110/debian/changelog 2026-02-25 19:47:21.000000000 +0000 +++ nss-3.110/debian/changelog 2026-05-17 16:37:16.000000000 +0000 @@ -1,3 +1,11 @@ +nss (2:3.110-1+deb13u2) trixie-security; urgency=medium + + * CVE-2026-6766 + * CVE-2026-6767 + * CVE-2026-6772 + + -- Moritz Mühlenhoff Sun, 17 May 2026 18:37:16 +0200 + nss (2:3.110-1+deb13u1) trixie-security; urgency=medium * CVE-2026-2781 diff -Nru nss-3.110/debian/patches/CVE-2026-6766.patch nss-3.110/debian/patches/CVE-2026-6766.patch --- nss-3.110/debian/patches/CVE-2026-6766.patch 1970-01-01 00:00:00.000000000 +0000 +++ nss-3.110/debian/patches/CVE-2026-6766.patch 2026-05-17 16:35:48.000000000 +0000 @@ -0,0 +1,22 @@ +# HG changeset patch +# User John Schanck +# Date 1773760657 0 +# Node ID 42da9a7f8a035849ba92e89dd095d4219a3e1d3d +# Parent 2d03bf59ca4feacb31a30923f730f549f25332e8 +Bug 2023207 - Fix integer underflow in tls13_AEAD when ciphertext is shorter than tag. r=#nss-reviewers + +Differential Revision: https://phabricator.services.mozilla.com/D287662 + +--- nss-3.110.orig/nss/lib/ssl/tls13con.c ++++ nss-3.110/nss/lib/ssl/tls13con.c +@@ -4988,6 +4988,10 @@ tls13_AEAD(PK11Context *context, PRBool + 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 */ diff -Nru nss-3.110/debian/patches/CVE-2026-6767.patch nss-3.110/debian/patches/CVE-2026-6767.patch --- nss-3.110/debian/patches/CVE-2026-6767.patch 1970-01-01 00:00:00.000000000 +0000 +++ nss-3.110/debian/patches/CVE-2026-6767.patch 2026-05-17 16:36:31.000000000 +0000 @@ -0,0 +1,239 @@ + +# HG changeset patch +# User Dana Keeler +# Date 1773854548 0 +# Node ID 4e693e8b5c0db30ee8e0043edabcf9787a747aa8 +# Parent 42da9a7f8a035849ba92e89dd095d4219a3e1d3d +Bug 2023209 - ensure permittedSubtrees don't match wildcards that could be outside the permitted tree r?jschanck + +Differential Revision: https://phabricator.services.mozilla.com/D287712 + +--- nss-3.110.orig/nss/gtests/mozpkix_gtest/pkixnames_tests.cpp ++++ nss-3.110/nss/gtests/mozpkix_gtest/pkixnames_tests.cpp +@@ -2132,6 +2132,45 @@ static const NameConstraintParams NAME_C + 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) + +--- nss-3.110.orig/nss/lib/mozpkix/lib/pkixnames.cpp ++++ nss-3.110/nss/lib/mozpkix/lib/pkixnames.cpp +@@ -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 + 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(In + 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(GeneralN + rv = MatchPresentedDNSIDWithReferenceDNSID( + presentedID, AllowWildcards::Yes, + AllowDotlessSubdomainMatches::Yes, IDRole::ReferenceID, +- referenceID, foundMatch); ++ nullptr, referenceID, foundMatch); + break; + + case GeneralNameType::iPAddress: +@@ -741,7 +753,7 @@ MatchPresentedIDWithReferenceID(GeneralN + + 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(GeneralN + 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 @@ CheckPresentedIDConformsToNameConstraint + rv = MatchPresentedDNSIDWithReferenceDNSID( + presentedID, AllowWildcards::Yes, + AllowDotlessSubdomainMatches::Yes, IDRole::NameConstraint, +- base, matches); ++ &subtreesType, base, matches); + if (rv != Success) { + return rv; + } +@@ -911,7 +919,7 @@ CheckPresentedIDConformsToNameConstraint + + 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 @@ MatchPresentedRFC822NameWithReferenceRFC + return MatchPresentedDNSIDWithReferenceDNSID( + presentedDNSID, AllowWildcards::No, + AllowDotlessSubdomainMatches::No, IDRole::NameConstraint, ++ subtreesType, + referenceRFC822Name, matches); + } + } diff -Nru nss-3.110/debian/patches/CVE-2026-6772.patch nss-3.110/debian/patches/CVE-2026-6772.patch --- nss-3.110/debian/patches/CVE-2026-6772.patch 1970-01-01 00:00:00.000000000 +0000 +++ nss-3.110/debian/patches/CVE-2026-6772.patch 2026-05-17 16:37:10.000000000 +0000 @@ -0,0 +1,359 @@ + +# HG changeset patch +# User Dennis Jackson +# Date 1776100981 0 +# Node ID 961f1a40f5e7d182723a216e236e1e638eaddb40 +# Parent 5c15dd1fb0151b7ca62b0d6e95a9942778dcabe2 +Bug 2026089 - Clarify extension negotiation mechanism for TLS Handshakes r=#nss-reviewers + +Differential Revision: https://phabricator.services.mozilla.com/D289764 + +--- nss-3.110.orig/nss/gtests/ssl_gtest/ssl_certificate_compression_unittest.cc ++++ nss-3.110/nss/gtests/ssl_gtest/ssl_certificate_compression_unittest.cc +@@ -500,8 +500,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); +@@ -1391,8 +1389,6 @@ TEST_F(TlsConnectStreamTls13, Certificat + server_->ReadBytes(50); + + EXPECT_EQ(1U, called); +- EXPECT_TRUE(SSLInt_ExtensionNegotiated(client_->ssl_fd(), +- ssl_certificate_compression_xtn)); + + SendReceive(60); + client_->CheckClientAuthCompleted(); +@@ -1469,8 +1465,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(); +--- nss-3.110.orig/nss/lib/ssl/ssl3ext.c ++++ nss-3.110/nss/lib/ssl/ssl3ext.c +@@ -336,6 +336,26 @@ ssl3_ExtensionAdvertised(const sslSocket + 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) + { +--- nss-3.110.orig/nss/lib/ssl/ssl3ext.h ++++ nss-3.110/nss/lib/ssl/ssl3ext.h +@@ -175,6 +175,9 @@ void ssl3_ResetExtensionData(TLSExtensio + + 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, +--- nss-3.110.orig/nss/lib/ssl/ssl3exthandle.c ++++ nss-3.110/nss/lib/ssl/ssl3exthandle.c +@@ -165,7 +165,7 @@ ssl3_HandleServerNameXtn(const sslSocket + 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 * + } + + 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 sslSo + + 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 + 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 + } + + /* 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 + } + + /* 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 + } + + /* 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 ss + /* 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 sslSoc + } + + /* 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 sslSoc + + /* 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 *s + 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 + 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( + } + *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( + 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 sslSo + } + + /* 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 sslSo + /* 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; + } + +--- nss-3.110.orig/nss/lib/ssl/tls13ech.c ++++ nss-3.110/nss/lib/ssl/tls13ech.c +@@ -2437,7 +2437,7 @@ tls13_MaybeHandleEchSignal(sslSocket *ss + 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). */ +--- nss-3.110.orig/nss/lib/ssl/tls13exthandle.c ++++ nss-3.110/nss/lib/ssl/tls13exthandle.c +@@ -446,8 +446,7 @@ tls13_ServerHandleKeyShareXtn(const sslS + } + + /* 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 + 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 + } + + /* 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 ssl + 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 ssl + } + + /* 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; + } +@@ -1101,7 +1100,7 @@ tls13_ServerHandleCookieXtn(const sslSoc + } + + /* 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 +1137,7 @@ tls13_ServerHandlePostHandshakeAuthXtn(c + * 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 +1208,7 @@ tls13_ServerHandlePskModesXtn(const sslS + } + + /* 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 +1552,7 @@ tls13_ClientHandleDelegatedCredentialsXt + } + + 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 +1616,7 @@ tls13_ServerHandleDelegatedCredentialsXt + + /* 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 +1705,7 @@ tls13_ServerHandleInnerEchXtn(const sslS + } + + 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 +1991,9 @@ ssl3_HandleCertificateCompressionXtn(con + 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; + } diff -Nru nss-3.110/debian/patches/series nss-3.110/debian/patches/series --- nss-3.110/debian/patches/series 2026-02-25 19:47:00.000000000 +0000 +++ nss-3.110/debian/patches/series 2026-05-17 16:36:57.000000000 +0000 @@ -1,3 +1,6 @@ 38_hurd.patch 80_security_tools.patch CVE-2026-2781.patch +CVE-2026-6766.patch +CVE-2026-6767.patch +CVE-2026-6772.patch