[NSS] ported mozilla upstream changes:

- Bug 1552254 internal_error alert on Certificate Request with sha1+ecdsa in TLS 1.3 (be6a9782)
- Bug 1753535 - Remove obsolete stateEnd check in SEC_ASN1DecoderUpdate. r=rrelyea (800111fa)
- Bug 1756271 - Remove token member from NSSSlot struct. r=rrelyea (55052f78)
- Bug 1396616 - Update nssUTF8_Length to RFC 3629 and fix buffer overrun. r=nss-reviewers,jschanck (2f2c8564)
- Bug 1755264 - TLS 1.3 Illegal legacy_version handling/alerts. r=djackson (7d931c59)
- Bug 1751305 - Remove expired explicitly distrusted certificates from certdata.txt. r=KathleenWilson (b722e523)
- Bug 1751298 - Add Telia Root CA v2 root certificate. r=KathleenWilson (1fcbbd7e)
- Bug 1754890 - Add two D-TRUST 2020 root certificates. r=KathleenWilson (f63fb86d)
This commit is contained in:
roytam1 2022-03-25 23:38:11 +08:00
commit 3336114a36
37 changed files with 1556 additions and 671 deletions

View file

@ -0,0 +1,8 @@
4 Added functions:
'function SECStatus CERT_FilterCertListByCertList(CERTCertList*, const CERTCertList*)' {CERT_FilterCertListByCertList@@NSS_3.77}
'function SECStatus CERT_FilterCertListByNickname(CERTCertList*, char*, void*)' {CERT_FilterCertListByNickname@@NSS_3.77}
'function PRBool CERT_IsInList(const CERTCertificate*, const CERTCertList*)' {CERT_IsInList@@NSS_3.77}
'function CK_OBJECT_HANDLE PK11_FindObjectForCert(CERTCertificate*, void*, PK11SlotInfo**)' {PK11_FindObjectForCert@@NSS_3.77}

View file

@ -11,3 +11,7 @@
'PRUint32 SSLPreliminaryChannelInfoStr::authKeyBits', at offset 224 (in bits) at sslt.h:419:1
'SSLSignatureScheme SSLPreliminaryChannelInfoStr::signatureScheme', at offset 256 (in bits) at sslt.h:420:1
2 Added functions:
'function PRBool SSL_CertIsUsable(PRFileDesc*, CERTCertificate*)' {SSL_CertIsUsable@@NSS_3.77}
'function SECStatus SSL_FilterClientCertListBySocket(PRFileDesc*, CERTCertList*)' {SSL_FilterClientCertListBySocket@@NSS_3.77}

View file

@ -0,0 +1,43 @@
#! gmake
#
# 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/.
#######################################################################
# (1) Include initial platform-independent assignments (MANDATORY). #
#######################################################################
include manifest.mn
#######################################################################
# (2) Include "global" configuration information. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/config.mk
#######################################################################
# (3) Include "component" configuration information. (OPTIONAL) #
#######################################################################
#######################################################################
# (4) Include "local" platform-dependent assignments (OPTIONAL). #
#######################################################################
include ../common/gtest.mk
#######################################################################
# (5) Execute "global" rules. (OPTIONAL) #
#######################################################################
include $(CORE_DEPTH)/coreconf/rules.mk
#######################################################################
# (6) Execute "component" rules. (OPTIONAL) #
#######################################################################
#######################################################################
# (7) Execute "local" rules. (OPTIONAL). #
#######################################################################

View file

@ -0,0 +1,31 @@
# 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/.
{
'includes': [
'../../coreconf/config.gypi',
'../common/gtest.gypi',
],
'targets': [
{
'target_name': 'base_gtest',
'type': 'executable',
'sources': [
'utf8_unittest.cc',
'<(DEPTH)/gtests/common/gtests.cc'
],
'dependencies': [
'<(DEPTH)/exports.gyp:nss_exports',
'<(DEPTH)/gtests/google_test/google_test.gyp:gtest',
'<(DEPTH)/lib/util/util.gyp:nssutil3',
'<(DEPTH)/lib/ssl/ssl.gyp:ssl3',
'<(DEPTH)/lib/nss/nss.gyp:nss3',
'<(DEPTH)/lib/smime/smime.gyp:smime3',
'<(DEPTH)/lib/base/base.gyp:nssb',
]
}
],
'variables': {
'module': 'nss'
}
}

View file

@ -0,0 +1,23 @@
#
# 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/.
CORE_DEPTH = ../..
DEPTH = ../..
MODULE = nss
CPPSRCS = \
utf8_unittest.cc \
$(NULL)
INCLUDES += -I$(CORE_DEPTH)/gtests/google_test/gtest/include \
-I$(CORE_DEPTH)/gtests/common \
-I$(CORE_DEPTH)/cpputil
REQUIRES = nspr nss libdbm gtest
PROGRAM = base_gtest
EXTRA_LIBS = $(DIST)/lib/$(LIB_PREFIX)gtest.$(LIB_SUFFIX) $(EXTRA_OBJS) \
$(DIST)/lib/$(LIB_PREFIX)nssb.$(LIB_SUFFIX) \
$(DIST)/lib/$(LIB_PREFIX)gtestutil.$(LIB_SUFFIX)

View file

@ -0,0 +1,150 @@
/* -*- 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 "gtest/gtest.h"
#include "nss.h"
#include "base.h"
#include "secerr.h"
namespace nss_test {
class Utf8Test : public ::testing::Test {};
// Tests nssUTF8_Length rejects overlong forms, surrogates, etc.
TEST_F(Utf8Test, Utf8Length) {
PRStatus status;
EXPECT_EQ(0u, nssUTF8_Length("", &status));
EXPECT_EQ(PR_SUCCESS, status);
// U+0000..U+007F
EXPECT_EQ(1u, nssUTF8_Length("\x01", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(1u, nssUTF8_Length("\x7F", &status));
EXPECT_EQ(PR_SUCCESS, status);
// lone trailing byte
EXPECT_EQ(0u, nssUTF8_Length("\x80", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
EXPECT_EQ(0u, nssUTF8_Length("\xBF", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
// overlong U+0000..U+007F
EXPECT_EQ(0u, nssUTF8_Length("\xC0\x80", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
EXPECT_EQ(0u, nssUTF8_Length("\xC1\xBF", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
// U+0080..U+07FF
EXPECT_EQ(2u, nssUTF8_Length("\xC2\x80", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(2u, nssUTF8_Length("\xDF\xBF", &status));
EXPECT_EQ(PR_SUCCESS, status);
// overlong U+0000..U+07FF
EXPECT_EQ(0u, nssUTF8_Length("\xE0\x80\x80", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
EXPECT_EQ(0u, nssUTF8_Length("\xE0\x9F\xBF", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
// U+0800..U+D7FF
EXPECT_EQ(3u, nssUTF8_Length("\xE0\xA0\x80", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(3u, nssUTF8_Length("\xE0\xBF\xBF", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(3u, nssUTF8_Length("\xE1\x80\x80", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(3u, nssUTF8_Length("\xEC\xBF\xBF", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(3u, nssUTF8_Length("\xED\x80\x80", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(3u, nssUTF8_Length("\xED\x9F\xBF", &status));
EXPECT_EQ(PR_SUCCESS, status);
// lone surrogate
EXPECT_EQ(0u, nssUTF8_Length("\xED\xA0\x80", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
EXPECT_EQ(0u, nssUTF8_Length("\xED\xBF\xBF", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
// U+E000..U+FFFF
EXPECT_EQ(3u, nssUTF8_Length("\xEE\x80\x80", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(3u, nssUTF8_Length("\xEF\xBF\xBF", &status));
EXPECT_EQ(PR_SUCCESS, status);
// overlong U+0000..U+FFFF
EXPECT_EQ(0u, nssUTF8_Length("\xF0\x80\x80\x80", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
EXPECT_EQ(0u, nssUTF8_Length("\xF0\x8F\xBF\xBF", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
// U+10000..U+10FFFF
EXPECT_EQ(4u, nssUTF8_Length("\xF0\x90\x80\x80", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(4u, nssUTF8_Length("\xF0\xBF\xBF\xBF", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(4u, nssUTF8_Length("\xF1\x80\x80\x80", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(4u, nssUTF8_Length("\xF3\xBF\xBF\xBF", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(4u, nssUTF8_Length("\xF4\x80\x80\x80", &status));
EXPECT_EQ(PR_SUCCESS, status);
EXPECT_EQ(4u, nssUTF8_Length("\xF4\x8F\xBF\xBF", &status));
EXPECT_EQ(PR_SUCCESS, status);
// out of Unicode range
EXPECT_EQ(0u, nssUTF8_Length("\xF4\x90\x80\x80", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
EXPECT_EQ(0u, nssUTF8_Length("\xF4\xBF\xBF\xBF", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
EXPECT_EQ(0u, nssUTF8_Length("\xF5\x80\x80\x80", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
EXPECT_EQ(0u, nssUTF8_Length("\xF7\xBF\xBF\xBF", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
// former 5-byte sequence
EXPECT_EQ(0u, nssUTF8_Length("\xF8\x80\x80\x80\x80", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
EXPECT_EQ(0u, nssUTF8_Length("\xFB\xBF\xBF\xBF\xBF", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
// former 6-byte sequence
EXPECT_EQ(0u, nssUTF8_Length("\xFC\x80\x80\x80\x80\x80", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
EXPECT_EQ(0u, nssUTF8_Length("\xFD\xBF\xBF\xBF\xBF\xBF", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
// invalid lead byte
EXPECT_EQ(0u, nssUTF8_Length("\xFE", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
EXPECT_EQ(0u, nssUTF8_Length("\xFF", &status));
EXPECT_EQ(PR_FAILURE, status);
EXPECT_EQ(NSS_ERROR_INVALID_STRING, NSS_GetError());
nss_DestroyErrorStack();
}
}

View file

@ -19,6 +19,7 @@ endif
ifneq ($(NSS_BUILD_SOFTOKEN_ONLY),1)
ifneq ($(NSS_BUILD_UTIL_ONLY),1)
NSS_SRCDIRS = \
base_gtest \
certdb_gtest \
certhigh_gtest \
cryptohi_gtest \

View file

@ -268,6 +268,126 @@ static SECStatus GetClientAuthDataHook(void* self, PRFileDesc* fd,
return SECSuccess;
}
typedef struct AutoClientTestStr {
SECStatus result;
const std::string cert;
} AutoClientTest;
typedef struct AutoClientResultsStr {
AutoClientTest isRsa2048;
AutoClientTest isClient;
AutoClientTest isNull;
bool hookCalled;
} AutoClientResults;
void VerifyClientCertMatch(CERTCertificate* clientCert,
const std::string expectedName) {
const char* name = clientCert->nickname;
std::cout << "Match name=\"" << name << "\" expected=\"" << expectedName
<< "\"" << std::endl;
EXPECT_TRUE(PORT_Strcmp(name, expectedName.c_str()) == 0)
<< " Certmismatch: \"" << name << "\" != \"" << expectedName << "\"";
}
static SECStatus GetAutoClientAuthDataHook(void* expectResults, PRFileDesc* fd,
CERTDistNames* caNames,
CERTCertificate** clientCert,
SECKEYPrivateKey** clientKey) {
AutoClientResults& results = *(AutoClientResults*)expectResults;
SECStatus rv;
results.hookCalled = true;
*clientCert = NULL;
*clientKey = NULL;
rv = NSS_GetClientAuthData((void*)TlsAgent::kRsa2048.c_str(), fd, caNames,
clientCert, clientKey);
if (rv == SECSuccess) {
VerifyClientCertMatch(*clientCert, results.isRsa2048.cert);
CERT_DestroyCertificate(*clientCert);
SECKEY_DestroyPrivateKey(*clientKey);
*clientCert = NULL;
*clientKey = NULL;
}
EXPECT_EQ(results.isRsa2048.result, rv);
rv = NSS_GetClientAuthData((void*)TlsAgent::kClient.c_str(), fd, caNames,
clientCert, clientKey);
if (rv == SECSuccess) {
VerifyClientCertMatch(*clientCert, results.isClient.cert);
CERT_DestroyCertificate(*clientCert);
SECKEY_DestroyPrivateKey(*clientKey);
*clientCert = NULL;
*clientKey = NULL;
}
EXPECT_EQ(results.isClient.result, rv);
EXPECT_EQ(*clientCert, nullptr);
EXPECT_EQ(*clientKey, nullptr);
rv = NSS_GetClientAuthData(NULL, fd, caNames, clientCert, clientKey);
if (rv == SECSuccess) {
VerifyClientCertMatch(*clientCert, results.isNull.cert);
// return this result
}
EXPECT_EQ(results.isNull.result, rv);
return rv;
}
// while I would have liked to use a new INSTANTIATE macro the
// generates the following three tests, figuring out how to make that
// work on top of the existing TlsConnect* plumbing hurts my head.
TEST_P(TlsConnectTls12, AutoClientSelectRsaPss) {
AutoClientResults rsa = {{SECSuccess, TlsAgent::kRsa2048},
{SECSuccess, TlsAgent::kClient},
{SECSuccess, TlsAgent::kDelegatorRsaPss2048},
false};
static const SSLSignatureScheme kSchemes[] = {ssl_sig_rsa_pss_pss_sha256,
ssl_sig_rsa_pkcs1_sha256,
ssl_sig_rsa_pkcs1_sha1};
Reset("rsa_pss_noparam");
client_->SetupClientAuth();
server_->RequestClientAuth(true);
EXPECT_EQ(SECSuccess,
SSL_GetClientAuthDataHook(client_->ssl_fd(),
GetAutoClientAuthDataHook, (void*)&rsa));
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
Connect();
EXPECT_TRUE(rsa.hookCalled);
}
TEST_P(TlsConnectTls12, AutoClientSelectEcc) {
AutoClientResults ecc = {{SECFailure, TlsAgent::kClient},
{SECFailure, TlsAgent::kClient},
{SECSuccess, TlsAgent::kDelegatorEcdsa256},
false};
static const SSLSignatureScheme kSchemes[] = {ssl_sig_ecdsa_secp256r1_sha256};
client_->SetupClientAuth();
server_->RequestClientAuth(true);
EXPECT_EQ(SECSuccess,
SSL_GetClientAuthDataHook(client_->ssl_fd(),
GetAutoClientAuthDataHook, (void*)&ecc));
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
Connect();
EXPECT_TRUE(ecc.hookCalled);
}
TEST_P(TlsConnectTls12, AutoClientSelectDsa) {
AutoClientResults dsa = {{SECFailure, TlsAgent::kClient},
{SECFailure, TlsAgent::kClient},
{SECSuccess, TlsAgent::kServerDsa},
false};
static const SSLSignatureScheme kSchemes[] = {ssl_sig_dsa_sha256};
client_->SetupClientAuth();
server_->RequestClientAuth(true);
EXPECT_EQ(SECSuccess,
SSL_GetClientAuthDataHook(client_->ssl_fd(),
GetAutoClientAuthDataHook, (void*)&dsa));
server_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
client_->SetSignatureSchemes(kSchemes, PR_ARRAY_SIZE(kSchemes));
Connect();
EXPECT_TRUE(dsa.hookCalled);
}
TEST_F(TlsConnectStreamTls13, PostHandshakeAuthMultiple) {
client_->SetupClientAuth();
EXPECT_EQ(SECSuccess, SSL_OptionSet(client_->ssl_fd(),

View file

@ -327,13 +327,24 @@ TEST_F(TlsConnectStreamTls13, Tls14ClientHelloWithSupportedVersions) {
ASSERT_LT(static_cast<uint32_t>(SSL_LIBRARY_VERSION_TLS_1_2), version);
}
// Offer 1.3 but with ClientHello.legacy_version == SSL 3.0. This
// Offer 1.3 but with Server/ClientHello.legacy_version == SSL 3.0. This
// causes a protocol version alert. See RFC 8446 Appendix D.5.
TEST_F(TlsConnectStreamTls13, Ssl30ClientHelloWithSupportedVersions) {
MakeTlsFilter<TlsClientHelloVersionSetter>(client_, SSL_LIBRARY_VERSION_3_0);
ConnectExpectAlert(server_, kTlsAlertProtocolVersion);
}
TEST_F(TlsConnectStreamTls13, Ssl30ServerHelloWithSupportedVersions) {
MakeTlsFilter<TlsServerHelloVersionSetter>(server_, SSL_LIBRARY_VERSION_3_0);
StartConnect();
client_->ExpectSendAlert(kTlsAlertProtocolVersion);
/* Since the handshake is not finished the client will send an unencrypted
* alert. The server is expected to close the connection with a unexpected
* message alert. */
server_->ExpectSendAlert(kTlsAlertUnexpectedMessage);
Handshake();
}
INSTANTIATE_TEST_CASE_P(
TlsDowngradeSentinelTest, TlsDowngradeTest,
::testing::Combine(TlsConnectTestBase::kTlsVariantsStream,

View file

@ -1060,6 +1060,14 @@ PacketFilter::Action TlsClientHelloVersionSetter::FilterHandshake(
return CHANGE;
}
PacketFilter::Action TlsServerHelloVersionSetter::FilterHandshake(
const HandshakeHeader& header, const DataBuffer& input,
DataBuffer* output) {
*output = input;
output->Write(0, version_, 2);
return CHANGE;
}
PacketFilter::Action SelectedCipherSuiteReplacer::FilterHandshake(
const HandshakeHeader& header, const DataBuffer& input,
DataBuffer* output) {

View file

@ -669,6 +669,21 @@ class TlsClientHelloVersionSetter : public TlsHandshakeFilter {
uint16_t version_;
};
// Set the version number in the ServerHello.
class TlsServerHelloVersionSetter : public TlsHandshakeFilter {
public:
TlsServerHelloVersionSetter(const std::shared_ptr<TlsAgent>& a,
uint16_t version)
: TlsHandshakeFilter(a, {kTlsHandshakeServerHello}), version_(version) {}
virtual PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
const DataBuffer& input,
DataBuffer* output);
private:
uint16_t version_;
};
// Damages the last byte of a handshake message.
class TlsLastByteDamager : public TlsHandshakeFilter {
public:

View file

@ -307,31 +307,54 @@ nssUTF8_Length(const NSSUTF8 *s, PRStatus *statusOpt)
#endif /* NSSDEBUG */
/*
* From RFC 2044:
* From RFC 3629:
*
* UCS-4 range (hex.) UTF-8 octet sequence (binary)
* 0000 0000-0000 007F 0xxxxxxx
* 0000 0080-0000 07FF 110xxxxx 10xxxxxx
* 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
* 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
* 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
* 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx
* UTF8-octets = *( UTF8-char )
* UTF8-char = UTF8-1 / UTF8-2 / UTF8-3 / UTF8-4
* UTF8-1 = %x00-7F
* UTF8-2 = %xC2-DF UTF8-tail
* UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /
* %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )
* UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /
* %xF4 %x80-8F 2( UTF8-tail )
* UTF8-tail = %x80-BF
*/
while (0 != *c) {
PRUint32 incr;
if ((*c & 0x80) == 0) {
if (*c < 0x80) {
incr = 1;
} else if ((*c & 0xE0) == 0xC0) {
} else if (*c < 0xC2) {
nss_SetError(NSS_ERROR_INVALID_STRING);
goto loser;
} else if (*c < 0xE0) {
incr = 2;
} else if ((*c & 0xF0) == 0xE0) {
} else if (*c == 0xE0) {
if (c[1] < 0xA0) {
nss_SetError(NSS_ERROR_INVALID_STRING);
goto loser;
}
incr = 3;
} else if ((*c & 0xF8) == 0xF0) {
} else if (*c < 0xF0) {
if (*c == 0xED && c[1] > 0x9F) {
nss_SetError(NSS_ERROR_INVALID_STRING);
goto loser;
}
incr = 3;
} else if (*c == 0xF0) {
if (c[1] < 0x90) {
nss_SetError(NSS_ERROR_INVALID_STRING);
goto loser;
}
incr = 4;
} else if (*c < 0xF4) {
incr = 4;
} else if (*c == 0xF4) {
if (c[1] > 0x8F) {
nss_SetError(NSS_ERROR_INVALID_STRING);
goto loser;
}
incr = 4;
} else if ((*c & 0xFC) == 0xF8) {
incr = 5;
} else if ((*c & 0xFE) == 0xFC) {
incr = 6;
} else {
nss_SetError(NSS_ERROR_INVALID_STRING);
goto loser;
@ -345,17 +368,17 @@ nssUTF8_Length(const NSSUTF8 *s, PRStatus *statusOpt)
nss_SetError(NSS_ERROR_VALUE_TOO_LARGE);
goto loser;
}
#endif /* PEDANTIC */
{
PRUint8 *d;
const PRUint8 *d;
for (d = &c[1]; d < &c[incr]; d++) {
if ((*d & 0xC0) != 0xF0) {
if ((*d & 0xC0) != 0x80) {
nss_SetError(NSS_ERROR_INVALID_STRING);
goto loser;
}
}
}
#endif /* PEDANTIC */
c += incr;
}

View file

@ -1314,6 +1314,21 @@ SECStatus CERT_FilterCertListByCANames(CERTCertList *certList, int nCANames,
*/
SECStatus CERT_FilterCertListForUserCerts(CERTCertList *certList);
/*
* Filter a list of certificates, removing those certs that don't match the
* nickname.
*/
SECStatus CERT_FilterCertListByNickname(CERTCertList *certList, char *nickname,
void *pwarg);
/* return true if cert is in cert list */
PRBool CERT_IsInList(const CERTCertificate *cert, const CERTCertList *certList);
/* returned certList is the intersection of the certs on certList and the
* certs on filterList */
SECStatus CERT_FilterCertListByCertList(CERTCertList *certList,
const CERTCertList *filterList);
/*
* Collect the nicknames from all certs in a CertList. If the cert is not
* valid, append a string to that nickname.

View file

@ -2552,6 +2552,10 @@ CERT_DestroyCertList(CERTCertList *certs)
{
PRCList *node;
if (!certs) {
return;
}
while (!PR_CLIST_IS_EMPTY(&certs->list)) {
node = PR_LIST_HEAD(&certs->list);
CERT_DestroyCertificate(((CERTCertListNode *)node)->cert);
@ -2866,6 +2870,86 @@ CERT_FilterCertListForUserCerts(CERTCertList *certList)
return (SECSuccess);
}
/* return true if cert is in the list */
PRBool
CERT_IsInList(const CERTCertificate *cert, const CERTCertList *certList)
{
CERTCertListNode *node;
for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);
node = CERT_LIST_NEXT(node)) {
if (node->cert == cert) {
return PR_TRUE;
}
}
return PR_FALSE;
}
/* returned certList is the intersection of the certs on certList and the
* certs on filterList */
SECStatus
CERT_FilterCertListByCertList(CERTCertList *certList,
const CERTCertList *filterList)
{
CERTCertListNode *node, *freenode;
CERTCertificate *cert;
if (!certList) {
return SECFailure;
}
if (!filterList || CERT_LIST_EMPTY(certList)) {
/* if the filterList is empty, just clear out certList and return */
for (node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList);) {
freenode = node;
node = CERT_LIST_NEXT(node);
CERT_RemoveCertListNode(freenode);
}
return SECSuccess;
}
node = CERT_LIST_HEAD(certList);
while (!CERT_LIST_END(node, certList)) {
cert = node->cert;
if (!CERT_IsInList(cert, filterList)) {
// no matching cert on filter list, remove it from certlist */
freenode = node;
node = CERT_LIST_NEXT(node);
CERT_RemoveCertListNode(freenode);
} else {
/* matching cert, keep it around */
node = CERT_LIST_NEXT(node);
}
}
return (SECSuccess);
}
SECStatus
CERT_FilterCertListByNickname(CERTCertList *certList, char *nickname,
void *pwarg)
{
CERTCertList *nameList;
SECStatus rv;
if (!certList) {
return SECFailure;
}
/* we could try to match the nickname to the individual cert,
* but nickname parsing is quite complicated, so it's best just
* to use the existing code and get a list of certs that match the
* nickname. We can then compare that list with our input cert list
* and return only those certs that are on both. */
nameList = PK11_FindCertsFromNickname(nickname, pwarg);
/* namelist could be NULL, this will force certList to become empty */
rv = CERT_FilterCertListByCertList(certList, nameList);
/* CERT_DestroyCertList can now accept a NULL pointer */
CERT_DestroyCertList(nameList);
return rv;
}
static PZLock *certRefCountLock = NULL;
/*

File diff suppressed because it is too large Load diff

View file

@ -146,7 +146,6 @@ nssModule_GetCertOrder(
* nssSlot_Destroy
* nssSlot_AddRef
* nssSlot_GetName
* nssSlot_GetTokenName
* nssSlot_IsTokenPresent
* nssSlot_IsPermanent
* nssSlot_IsFriendly
@ -176,10 +175,6 @@ NSS_EXTERN NSSUTF8 *
nssSlot_GetName(
NSSSlot *slot);
NSS_EXTERN NSSUTF8 *
nssSlot_GetTokenName(
NSSSlot *slot);
NSS_EXTERN NSSModule *
nssSlot_GetModule(
NSSSlot *slot);

View file

@ -12,7 +12,9 @@
#include "ckhelper.h"
#endif /* CKHELPER_H */
#include "pk11pub.h"
#include "pkim.h"
#include "dev3hack.h"
#include "pk11func.h"
/* measured in seconds */
#define NSSSLOT_TOKEN_DELAY_TIME 1
@ -79,13 +81,6 @@ nssSlot_GetName(
return slot->base.name;
}
NSS_IMPLEMENT NSSUTF8 *
nssSlot_GetTokenName(
NSSSlot *slot)
{
return nssToken_GetName(slot->token);
}
NSS_IMPLEMENT void
nssSlot_ResetDelay(
NSSSlot *slot)
@ -123,11 +118,13 @@ nssSlot_IsTokenPresent(
{
CK_RV ckrv;
PRStatus nssrv;
NSSToken *nssToken = NULL;
/* XXX */
nssSession *session;
CK_SLOT_INFO slotInfo;
void *epv;
PRBool isPresent = PR_FALSE;
PRBool doUpdateCachedCerts = PR_FALSE;
/* permanent slots are always present unless they're disabled */
if (nssSlot_IsPermanent(slot)) {
@ -169,23 +166,24 @@ nssSlot_IsTokenPresent(
PZ_Unlock(slot->isPresentLock);
nssToken = PK11Slot_GetNSSToken(slot->pk11slot);
if (!nssToken) {
isPresent = PR_FALSE;
goto done;
}
nssSlot_EnterMonitor(slot);
ckrv = CKAPI(epv)->C_GetSlotInfo(slot->slotID, &slotInfo);
nssSlot_ExitMonitor(slot);
if (ckrv != CKR_OK) {
slot->token->base.name[0] = 0; /* XXX */
nssToken->base.name[0] = 0; /* XXX */
isPresent = PR_FALSE;
goto done;
}
slot->ckFlags = slotInfo.flags;
/* check for the presence of the token */
if ((slot->ckFlags & CKF_TOKEN_PRESENT) == 0) {
if (!slot->token) {
/* token was never present */
isPresent = PR_FALSE;
goto done;
}
session = nssToken_GetDefaultSession(slot->token);
session = nssToken_GetDefaultSession(nssToken);
if (session) {
nssSession_EnterMonitor(session);
/* token is not present */
@ -197,21 +195,21 @@ nssSlot_IsTokenPresent(
}
nssSession_ExitMonitor(session);
}
if (slot->token->base.name[0] != 0) {
if (nssToken->base.name[0] != 0) {
/* notify the high-level cache that the token is removed */
slot->token->base.name[0] = 0; /* XXX */
nssToken_NotifyCertsNotVisible(slot->token);
nssToken->base.name[0] = 0; /* XXX */
nssToken_NotifyCertsNotVisible(nssToken);
}
slot->token->base.name[0] = 0; /* XXX */
nssToken->base.name[0] = 0; /* XXX */
/* clear the token cache */
nssToken_Remove(slot->token);
nssToken_Remove(nssToken);
isPresent = PR_FALSE;
goto done;
}
/* token is present, use the session info to determine if the card
* has been removed and reinserted.
*/
session = nssToken_GetDefaultSession(slot->token);
session = nssToken_GetDefaultSession(nssToken);
if (session) {
PRBool tokenRemoved;
nssSession_EnterMonitor(session);
@ -237,17 +235,31 @@ nssSlot_IsTokenPresent(
* a token it doesn't recognize. invalidate all the old
* information we had on this token, if we can't refresh, clear
* the present flag */
nssToken_NotifyCertsNotVisible(slot->token);
nssToken_Remove(slot->token);
/* token has been removed, need to refresh with new session */
nssrv = nssSlot_Refresh(slot);
isPresent = PR_TRUE;
nssToken_NotifyCertsNotVisible(nssToken);
nssToken_Remove(nssToken);
if (nssToken->base.name[0] == 0) {
doUpdateCachedCerts = PR_TRUE;
}
if (PK11_InitToken(slot->pk11slot, PR_FALSE) != SECSuccess) {
isPresent = PR_FALSE;
goto done;
}
if (doUpdateCachedCerts) {
nssTrustDomain_UpdateCachedTokenCerts(nssToken->trustDomain,
nssToken);
}
nssrv = nssToken_Refresh(nssToken);
if (nssrv != PR_SUCCESS) {
slot->token->base.name[0] = 0; /* XXX */
nssToken->base.name[0] = 0; /* XXX */
slot->ckFlags &= ~CKF_TOKEN_PRESENT;
isPresent = PR_FALSE;
goto done;
}
isPresent = PR_TRUE;
done:
if (nssToken) {
(void)nssToken_Destroy(nssToken);
}
/* Once we've set up the condition variable,
* Before returning, it's necessary to:
* 1) Set the lastTokenPingTime so that any other threads waiting on this
@ -283,12 +295,7 @@ nssSlot_GetToken(
NSSToken *rvToken = NULL;
if (nssSlot_IsTokenPresent(slot)) {
/* Even if a token should be present, check `slot->token` too as it
* might be gone already. This would happen mostly on shutdown. */
nssSlot_EnterMonitor(slot);
if (slot->token)
rvToken = nssToken_AddRef(slot->token);
nssSlot_ExitMonitor(slot);
rvToken = PK11Slot_GetNSSToken(slot->pk11slot);
}
return rvToken;

View file

@ -81,7 +81,6 @@ typedef enum {
struct NSSSlotStr {
struct nssDeviceBaseStr base;
NSSModule *module; /* Parent */
NSSToken *token; /* Peer */
CK_SLOT_ID slotID;
CK_FLAGS ckFlags; /* from CK_SLOT_INFO.flags */
struct nssSlotAuthInfoStr authInfo;

View file

@ -32,13 +32,6 @@ nssToken_Destroy(
PK11_FreeSlot(tok->pk11slot);
PZ_DestroyLock(tok->base.lock);
nssTokenObjectCache_Destroy(tok->cache);
/* We're going away, let the nssSlot know in case it's held
* alive by someone else. Usually we should hold the last ref. */
nssSlot_EnterMonitor(tok->slot);
tok->slot->token = NULL;
nssSlot_ExitMonitor(tok->slot);
(void)nssSlot_Destroy(tok->slot);
return nssArena_Destroy(tok->base.arena);
}

View file

@ -1163,3 +1163,12 @@ PK11_GetCertsMatchingPrivateKey;
;+ local:
;+ *;
;+};
;+NSS_3.77 { # NSS 3.77 release
;+ global:
CERT_FilterCertListByCertList;
CERT_FilterCertListByNickname;
CERT_IsInList;
PK11_FindObjectForCert;
;+ local:
;+ *;
;+};

View file

@ -179,7 +179,6 @@ nssToken_CreateFromPK11SlotInfo(NSSTrustDomain *td, PK11SlotInfo *nss3slot)
if (!rvToken->slot) {
goto loser;
}
rvToken->slot->token = rvToken;
if (rvToken->defaultSession)
rvToken->defaultSession->slot = rvToken->slot;
return rvToken;
@ -227,24 +226,6 @@ nssToken_Refresh(NSSToken *token)
return token->defaultSession ? PR_SUCCESS : PR_FAILURE;
}
NSS_IMPLEMENT PRStatus
nssSlot_Refresh(NSSSlot *slot)
{
PK11SlotInfo *nss3slot = slot->pk11slot;
PRBool doit = PR_FALSE;
if (slot->token && slot->token->base.name[0] == 0) {
doit = PR_TRUE;
}
if (PK11_InitToken(nss3slot, PR_FALSE) != SECSuccess) {
return PR_FAILURE;
}
if (doit) {
nssTrustDomain_UpdateCachedTokenCerts(slot->token->trustDomain,
slot->token);
}
return nssToken_Refresh(slot->token);
}
NSS_IMPLEMENT PRStatus
nssToken_GetTrustOrder(NSSToken *tok)
{

View file

@ -1722,7 +1722,10 @@ PK11_WriteRawAttribute(PK11ObjectType objType, void *objSpec,
slot = ((PK11SymKey *)objSpec)->slot;
handle = ((PK11SymKey *)objSpec)->objectID;
break;
case PK11_TypeCert: /* don't handle cert case for now */
case PK11_TypeCert:
handle = PK11_FindObjectForCert((CERTCertificate *)objSpec, NULL,
&slot);
break;
default:
break;
}

View file

@ -680,6 +680,8 @@ CERTCertificate *PK11_FindBestKEAMatch(CERTCertificate *serverCert, void *wincx)
PRBool PK11_FortezzaHasKEA(CERTCertificate *cert);
CK_OBJECT_HANDLE PK11_FindCertInSlot(PK11SlotInfo *slot, CERTCertificate *cert,
void *wincx);
CK_OBJECT_HANDLE PK11_FindObjectForCert(CERTCertificate *cert,
void *wincx, PK11SlotInfo **pSlot);
SECStatus PK11_TraverseCertsForNicknameInSlot(SECItem *nickname,
PK11SlotInfo *slot, SECStatus (*callback)(CERTCertificate *, void *),
void *arg);

View file

@ -19,6 +19,149 @@
#include "pk11func.h" /* for PK11_ function calls */
#include "sslimpl.h"
/* convert a CERTDistNameStr to an array ascii strings.
* we ignore caNames which we can't convert, so n could be less than nnames
* n is always set, even on failure.
* This function allows us to use the existing CERT_FilterCertListByCANames. */
static char **
ssl_DistNamesToStrings(struct CERTDistNamesStr *caNames, int *n)
{
char **names;
int i;
SECStatus rv;
PLArenaPool *arena;
*n = 0;
names = PORT_ZNewArray(char *, caNames->nnames);
if (names == NULL) {
return NULL;
}
arena = PORT_NewArena(2048);
if (arena == NULL) {
PORT_Free(names);
return NULL;
}
for (i = 0; i < caNames->nnames; ++i) {
CERTName dn;
rv = SEC_QuickDERDecodeItem(arena, &dn, SEC_ASN1_GET(CERT_NameTemplate),
caNames->names + i);
if (rv != SECSuccess) {
continue;
}
names[*n] = CERT_NameToAscii(&dn);
if (names[*n])
(*n)++;
}
PORT_FreeArena(arena, PR_FALSE);
return names;
}
/* free the dist names we allocated in the above function. n must be the
* returned n from that function. */
static void
ssl_FreeDistNamesStrings(char **strings, int n)
{
int i;
for (i = 0; i < n; i++) {
PORT_Free(strings[i]);
}
PORT_Free(strings);
}
PRBool
ssl_CertIsUsable(sslSocket *ss, CERTCertificate *cert)
{
SECStatus rv;
SSLSignatureScheme scheme;
if ((ss == NULL) || (cert == NULL)) {
return PR_FALSE;
}
/* There are two ways of handling the old style handshake:
* 1) check the actual record we are using and return true,
* if (!ss->ssl3.hs.hashType == handshake_hash_record &&
* ss->ssl3.hs.hashType == handshake_hash_single) {
* return PR_TRUE;
* 2) assume if ss->peerSignatureSchemesCount == 0 we are using the
* old handshake.
* There is one case where using 2 will be wrong: we somehow call this
* function outside the case where of out GetClientAuthData context.
* In that case we don't know that the 'real' peerScheme list is, so the
* best we can do is either always assume good or always assume bad.
* I think the best results is to always assume good, so we use
* option 2 here to handle that case as well.*/
if (ss->peerSignatureSchemeCount == 0) {
return PR_TRUE;
}
if (ss->peerSignatureSchemes == NULL) {
return PR_FALSE; /* should this really be an assert? */
}
rv = ssl_PickClientSignatureScheme(ss, cert, NULL,
ss->peerSignatureSchemes,
ss->peerSignatureSchemeCount,
&scheme);
if (rv != SECSuccess) {
return PR_FALSE;
}
return PR_TRUE;
}
SECStatus
ssl_FilterClientCertListBySSLSocket(sslSocket *ss, CERTCertList *certList)
{
CERTCertListNode *node;
CERTCertificate *cert;
if (!certList) {
return SECFailure;
}
node = CERT_LIST_HEAD(certList);
while (!CERT_LIST_END(node, certList)) {
cert = node->cert;
if (PR_TRUE != ssl_CertIsUsable(ss, cert)) {
/* cert doesn't match the socket criteria, remove it */
CERTCertListNode *freenode = node;
node = CERT_LIST_NEXT(node);
CERT_RemoveCertListNode(freenode);
} else {
/* this cert is good, go to the next cert */
node = CERT_LIST_NEXT(node);
}
}
return (SECSuccess);
}
/* This function can be called by the application's custom GetClientAuthHook
* to filter out any certs in the cert list that doesn't match the negotiated
* requirements of the current SSL connection.
*/
SECStatus
SSL_FilterClientCertListBySocket(PRFileDesc *fd, CERTCertList *certList)
{
sslSocket *ss = ssl_FindSocket(fd);
if (ss == NULL) {
return SECFailure;
}
return ssl_FilterClientCertListBySSLSocket(ss, certList);
}
/* This function can be called by the application's custom GetClientAuthHook
* to determine if a single certificate matches the negotiated requirements of
* the current SSL connection.
*/
PRBool
SSL_CertIsUsable(PRFileDesc *fd, CERTCertificate *cert)
{
sslSocket *ss = ssl_FindSocket(fd);
if (ss == NULL) {
return PR_FALSE;
}
return ssl_CertIsUsable(ss, cert);
}
/*
* This callback used by SSL to pull client certificate upon
* server request
@ -31,6 +174,7 @@ NSS_GetClientAuthData(void *arg,
struct SECKEYPrivateKeyStr **pRetKey)
{
CERTCertificate *cert = NULL;
CERTCertList *certList = NULL;
SECKEYPrivateKey *privkey = NULL;
char *chosenNickName = (char *)arg; /* CONST */
SECStatus rv = SECFailure;
@ -39,56 +183,68 @@ NSS_GetClientAuthData(void *arg,
if (!ss) {
return SECFailure;
}
void *proto_win = SSL_RevealPinArg(fd);
PRTime now = ssl_Time(ss);
void *pw_arg = SSL_RevealPinArg(fd);
if (chosenNickName) {
cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
chosenNickName, certUsageSSLClient,
PR_FALSE, proto_win);
if (cert) {
privkey = PK11_FindKeyByAnyCert(cert, proto_win);
if (privkey) {
rv = SECSuccess;
} else {
CERT_DestroyCertificate(cert);
/* first, handle any token authentication that may be needed */
if (chosenNickName && pw_arg) {
certList = PK11_FindCertsFromNickname(chosenNickName, pw_arg);
if (certList) {
CERT_FilterCertListForUserCerts(certList);
rv = CERT_FilterCertListByUsage(certList, certUsageSSLClient,
PR_FALSE);
if ((rv != SECSuccess) || CERT_LIST_EMPTY(certList)) {
CERT_DestroyCertList(certList);
certList = NULL;
}
}
} else { /* no name given, automatically find the right cert. */
CERTCertNicknames *names;
int i;
}
names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(),
SEC_CERT_NICKNAMES_USER, proto_win);
if (names != NULL) {
for (i = 0; i < names->numnicknames; i++) {
cert = CERT_FindUserCertByUsage(CERT_GetDefaultCertDB(),
names->nicknames[i], certUsageSSLClient,
PR_FALSE, proto_win);
if (!cert)
continue;
/* Only check unexpired certs */
if (CERT_CheckCertValidTimes(cert, now, PR_TRUE) !=
secCertTimeValid) {
CERT_DestroyCertificate(cert);
continue;
}
rv = NSS_CmpCertChainWCANames(cert, caNames);
if (rv == SECSuccess) {
privkey =
PK11_FindKeyByAnyCert(cert, proto_win);
if (privkey)
break;
}
rv = SECFailure;
CERT_DestroyCertificate(cert);
}
CERT_FreeNicknames(names);
/* otherwise look through the cache based on usage
* if chosenNickname is set, we ignore the expiration date */
if (certList == NULL) {
certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(),
certUsageSSLClient,
PR_FALSE, chosenNickName == NULL,
pw_arg);
/* filter only the certs that meet the nickname requirements */
if (chosenNickName) {
rv = CERT_FilterCertListByNickname(certList, chosenNickName,
pw_arg);
} else {
int nnames = 0;
char **names = ssl_DistNamesToStrings(caNames, &nnames);
rv = CERT_FilterCertListByCANames(certList, nnames, names,
certUsageSSLClient);
ssl_FreeDistNamesStrings(names, nnames);
}
if ((rv != SECSuccess) || CERT_LIST_EMPTY(certList)) {
CERT_DestroyCertList(certList);
certList = NULL;
}
}
if (rv == SECSuccess) {
*pRetCert = cert;
*pRetKey = privkey;
if (certList == NULL) {
/* no user certs meeting the nickname/usage requirements found */
return SECFailure;
}
return rv;
/* now remove any certs that can't meet the connection requirements */
rv = ssl_FilterClientCertListBySSLSocket(ss, certList);
if ((rv != SECSuccess) || CERT_LIST_EMPTY(certList)) {
// no certs left.
CERT_DestroyCertList(certList);
return SECFailure;
}
/* now return the top cert in the list. We've strived to make the
* list ordered by the most likely usable cert, so it should be the best
* match. */
cert = CERT_DupCertificate(CERT_LIST_HEAD(certList)->cert);
CERT_DestroyCertList(certList);
privkey = PK11_FindKeyByAnyCert(cert, pw_arg);
if (privkey == NULL) {
CERT_DestroyCertificate(cert);
return SECFailure;
}
*pRetCert = cert;
*pRetKey = privkey;
return SECSuccess;
}

View file

@ -240,3 +240,10 @@ SSL_GetExperimentalAPI;
;+ local:
;+*;
;+};
;+NSS_3.77 { # NSS 3.77 release
;+ global:
SSL_CertIsUsable;
SSL_FilterClientCertListBySocket;
;+ local:
;+*;
;+};

View file

@ -1232,6 +1232,20 @@ NSS_GetClientAuthData(void *arg,
struct CERTCertificateStr **pRetCert,
struct SECKEYPrivateKeyStr **pRetKey);
/* This function can be called by the appliation's custom GetClientAuthHook
* to filter out any certs in the cert list that doesn't match the negotiated
* requirements of the current SSL connection.
*/
SSL_IMPORT SECStatus
SSL_FilterClientCertListBySocket(PRFileDesc *socket, CERTCertList *certlist);
/* This function can be called by the application's custom GetClientAuthHook
* to determine if a single certificate matches the negotiated requirements of
* the current SSL connection.
*/
SSL_IMPORT PRBool
SSL_CertIsUsable(PRFileDesc *socket, CERTCertificate *cert);
/*
** Configure DTLS-SRTP (RFC 5764) cipher suite preferences.
** Input is a list of ciphers in descending preference order and a length

View file

@ -6334,11 +6334,19 @@ ssl_CanUseSignatureScheme(SSLSignatureScheme scheme,
}
SECStatus
ssl_PrivateKeySupportsRsaPss(SECKEYPrivateKey *privKey,
PRBool *supportsRsaPss)
ssl_PrivateKeySupportsRsaPss(SECKEYPrivateKey *privKey, CERTCertificate *cert,
void *pwarg, PRBool *supportsRsaPss)
{
PK11SlotInfo *slot;
slot = PK11_GetSlotFromPrivateKey(privKey);
PK11SlotInfo *slot = NULL;
if (privKey) {
slot = PK11_GetSlotFromPrivateKey(privKey);
} else {
CK_OBJECT_HANDLE certID = PK11_FindObjectForCert(cert, pwarg, &slot);
if (certID == CK_INVALID_HANDLE) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
}
if (!slot) {
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
@ -6355,7 +6363,8 @@ ssl_PickSignatureScheme(sslSocket *ss,
SECKEYPrivateKey *privKey,
const SSLSignatureScheme *peerSchemes,
unsigned int peerSchemeCount,
PRBool requireSha1)
PRBool requireSha1,
SSLSignatureScheme *schemePtr)
{
unsigned int i;
PRBool doesRsaPss;
@ -6366,13 +6375,13 @@ ssl_PickSignatureScheme(sslSocket *ss,
/* We can't require SHA-1 in TLS 1.3. */
PORT_Assert(!(requireSha1 && isTLS13));
if (!pubKey || !privKey) {
if (!pubKey || !cert) {
PORT_Assert(0);
PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
return SECFailure;
}
rv = ssl_PrivateKeySupportsRsaPss(privKey, &doesRsaPss);
rv = ssl_PrivateKeySupportsRsaPss(privKey, cert, ss->pkcs11PinArg,
&doesRsaPss);
if (rv != SECSuccess) {
return SECFailure;
}
@ -6390,7 +6399,7 @@ ssl_PickSignatureScheme(sslSocket *ss,
PORT_SetError(SSL_ERROR_UNSUPPORTED_SIGNATURE_ALGORITHM);
return SECFailure;
}
ss->ssl3.hs.signatureScheme = scheme;
*schemePtr = scheme;
return SECSuccess;
}
@ -6404,7 +6413,7 @@ ssl_PickSignatureScheme(sslSocket *ss,
if (ssl_SignatureSchemeValid(scheme, spkiOid, isTLS13) &&
ssl_CanUseSignatureScheme(scheme, peerSchemes, peerSchemeCount,
requireSha1, doesRsaPss)) {
ss->ssl3.hs.signatureScheme = scheme;
*schemePtr = scheme;
return SECSuccess;
}
}
@ -6462,17 +6471,20 @@ ssl3_PickServerSignatureScheme(sslSocket *ss)
cert->serverKeyPair->privKey,
ss->xtnData.sigSchemes,
ss->xtnData.numSigSchemes,
PR_FALSE /* requireSha1 */);
PR_FALSE /* requireSha1 */,
&ss->ssl3.hs.signatureScheme);
}
static SECStatus
ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes,
unsigned int numSchemes)
SECStatus
ssl_PickClientSignatureScheme(sslSocket *ss, CERTCertificate *clientCertificate,
SECKEYPrivateKey *privKey,
const SSLSignatureScheme *schemes,
unsigned int numSchemes,
SSLSignatureScheme *schemePtr)
{
SECKEYPrivateKey *privKey = ss->ssl3.clientPrivateKey;
SECStatus rv;
PRBool isTLS13 = (PRBool)ss->version >= SSL_LIBRARY_VERSION_TLS_1_3;
SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(ss->ssl3.clientCertificate);
SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(clientCertificate);
PORT_Assert(pubKey);
@ -6492,9 +6504,9 @@ ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes,
* older, DSA key size is at most 1024 bits and the hash function must
* be SHA-1.
*/
rv = ssl_PickSignatureScheme(ss, ss->ssl3.clientCertificate,
rv = ssl_PickSignatureScheme(ss, clientCertificate,
pubKey, privKey, schemes, numSchemes,
PR_TRUE /* requireSha1 */);
PR_TRUE /* requireSha1 */, schemePtr);
if (rv == SECSuccess) {
SECKEY_DestroyPublicKey(pubKey);
return SECSuccess;
@ -6502,9 +6514,9 @@ ssl_PickClientSignatureScheme(sslSocket *ss, const SSLSignatureScheme *schemes,
/* If this fails, that's because the peer doesn't advertise SHA-1,
* so fall back to the full negotiation. */
}
rv = ssl_PickSignatureScheme(ss, ss->ssl3.clientCertificate,
rv = ssl_PickSignatureScheme(ss, clientCertificate,
pubKey, privKey, schemes, numSchemes,
PR_FALSE /* requireSha1 */);
PR_FALSE /* requireSha1 */, schemePtr);
SECKEY_DestroyPublicKey(pubKey);
return rv;
}
@ -7690,11 +7702,23 @@ ssl3_CompleteHandleCertificateRequest(sslSocket *ss,
PORT_Assert(ss->ssl3.clientPrivateKey == NULL);
PORT_Assert(ss->ssl3.clientCertificate == NULL);
PORT_Assert(ss->ssl3.clientCertChain == NULL);
/*
* Peer signatures are only available while in the context of
* of a getClientAuthData callback. It is required for proper
* functioning of SSL_CertIsUsable and SSL_FilterClientCertListBySocket
* Calling these functions outside the context of a getClientAuthData
* callback will result in no filtering.*/
ss->peerSignatureSchemes = signatureSchemes;
ss->peerSignatureSchemeCount = signatureSchemeCount;
/* XXX Should pass cert_types and algorithms in this call!! */
rv = (SECStatus)(*ss->getClientAuthData)(ss->getClientAuthDataArg,
ss->fd, ca_list,
&ss->ssl3.clientCertificate,
&ss->ssl3.clientPrivateKey);
/* memory for the signature schemes will go away after the request,
* so don't leave dangling pointers around */
ss->peerSignatureSchemes = NULL;
ss->peerSignatureSchemeCount = 0;
} else {
rv = SECFailure; /* force it to send a no_certificate alert */
}
@ -7734,8 +7758,12 @@ ssl3_CompleteHandleCertificateRequest(sslSocket *ss,
}
if (ss->ssl3.hs.hashType == handshake_hash_record ||
ss->ssl3.hs.hashType == handshake_hash_single) {
rv = ssl_PickClientSignatureScheme(ss, signatureSchemes,
signatureSchemeCount);
rv = ssl_PickClientSignatureScheme(ss,
ss->ssl3.clientCertificate,
ss->ssl3.clientPrivateKey,
signatureSchemes,
signatureSchemeCount,
&ss->ssl3.hs.signatureScheme);
}
break; /* not an error */

View file

@ -1100,6 +1100,10 @@ struct sslSocketStr {
/* Anti-replay for TLS 1.3 0-RTT. */
SSLAntiReplayContext *antiReplay;
/* peer data passed in during getClientAuthData */
const SSLSignatureScheme *peerSignatureSchemes;
unsigned int peerSignatureSchemeCount;
};
struct sslSelfEncryptKeysStr {
@ -1723,6 +1727,8 @@ PRBool ssl3_CipherSuiteAllowedForVersionRange(ssl3CipherSuite cipherSuite,
SECStatus ssl3_SelectServerCert(sslSocket *ss);
SECStatus ssl_PrivateKeySupportsRsaPss(SECKEYPrivateKey *privKey,
CERTCertificate *cert,
void *pwArg,
PRBool *supportsRsaPss);
SECStatus ssl_PickSignatureScheme(sslSocket *ss,
CERTCertificate *cert,
@ -1730,7 +1736,14 @@ SECStatus ssl_PickSignatureScheme(sslSocket *ss,
SECKEYPrivateKey *privKey,
const SSLSignatureScheme *peerSchemes,
unsigned int peerSchemeCount,
PRBool requireSha1);
PRBool requireSha1,
SSLSignatureScheme *schemPtr);
SECStatus ssl_PickClientSignatureScheme(sslSocket *ss,
CERTCertificate *clientCertificate,
SECKEYPrivateKey *privKey,
const SSLSignatureScheme *schemes,
unsigned int numSchemes,
SSLSignatureScheme *schemePtr);
SECOidTag ssl3_HashTypeToOID(SSLHashType hashType);
SSLHashType ssl_SignatureSchemeToHashType(SSLSignatureScheme scheme);
SSLAuthType ssl_SignatureSchemeToAuthType(SSLSignatureScheme scheme);

View file

@ -381,6 +381,10 @@ ssl_DupSocket(sslSocket *os)
goto loser;
}
}
/* The original socket 'owns' the copy of these, so
* just set the target copies to zero */
ss->peerSignatureSchemes = NULL;
ss->peerSignatureSchemeCount = 0;
/* Create security data */
rv = ssl_CopySecurityInfo(ss, os);
@ -468,6 +472,11 @@ ssl_DestroySocketContents(sslSocket *ss)
ssl_ClearPRCList(&ss->ssl3.hs.dtlsSentHandshake, NULL);
ssl_ClearPRCList(&ss->ssl3.hs.dtlsRcvdHandshake, NULL);
/* data in peer Signature schemes comes from the buffer system,
* so there is nothing to free here. Make sure that's the case */
PORT_Assert(ss->peerSignatureSchemes == NULL);
PORT_Assert(ss->peerSignatureSchemeCount == 0);
tls13_DestroyESNIKeys(ss->esniKeys);
tls13_ReleaseAntiReplayContext(ss->antiReplay);
}
@ -2482,6 +2491,8 @@ SSL_ReconfigFD(PRFileDesc *model, PRFileDesc *fd)
ss->handshakeCallbackData = sm->handshakeCallbackData;
if (sm->pkcs11PinArg)
ss->pkcs11PinArg = sm->pkcs11PinArg;
ss->peerSignatureSchemes = NULL;
ss->peerSignatureSchemeCount = 0;
return fd;
}
@ -4149,6 +4160,8 @@ ssl_NewSocket(PRBool makeLocks, SSLProtocolVariant protocolVariant)
ss->esniKeys = NULL;
ss->antiReplay = NULL;
ss->peerSignatureSchemes = NULL;
ss->peerSignatureSchemeCount = 0;
if (makeLocks) {
rv = ssl_MakeLocks(ss);

View file

@ -1585,7 +1585,8 @@ tls13_SelectServerCert(sslSocket *ss)
cert->serverKeyPair->privKey,
ss->xtnData.sigSchemes,
ss->xtnData.numSigSchemes,
PR_FALSE);
PR_FALSE,
&ss->ssl3.hs.signatureScheme);
if (rv == SECSuccess) {
/* Found one. */
ss->sec.serverCert = cert;
@ -5808,6 +5809,17 @@ tls13_ClientReadSupportedVersion(sslSocket *ss)
return SECFailure;
}
/* Any endpoint receiving a Hello message with...ServerHello.legacy_version
* set to 0x0300 (SSL3) MUST abort the handshake with a "protocol_version"
* alert. [RFC8446, Section D.5]
*
* The ServerHello.legacy_version is read into the ss->version field by
* ssl_ClientReadVersion(). */
if (ss->version == SSL_LIBRARY_VERSION_3_0) {
FATAL_ERROR(ss, SSL_ERROR_RX_MALFORMED_SERVER_HELLO, protocol_version);
return SECFailure;
}
ss->version = SSL_LIBRARY_VERSION_TLS_1_3;
return SECSuccess;
}

View file

@ -221,7 +221,7 @@ tls13_MaybeSetDelegatedCredential(sslSocket *ss)
}
priv = ss->sec.serverCert->delegCredKeyPair->privKey;
rv = ssl_PrivateKeySupportsRsaPss(priv, &doesRsaPss);
rv = ssl_PrivateKeySupportsRsaPss(priv, NULL, NULL, &doesRsaPss);
if (rv != SECSuccess) {
return SECFailure;
}

View file

@ -2743,7 +2743,6 @@ SEC_ASN1DecoderUpdate(SEC_ASN1DecoderContext *cx,
sec_asn1d_state *state = NULL;
unsigned long consumed;
SEC_ASN1EncodingPart what;
sec_asn1d_state *stateEnd = cx->current;
if (cx->status == needBytes)
cx->status = keepGoing;
@ -2932,7 +2931,7 @@ SEC_ASN1DecoderUpdate(SEC_ASN1DecoderContext *cx,
}
if (cx->status == decodeError) {
while (state != NULL && stateEnd->parent != state) {
while (state != NULL) {
sec_asn1d_free_child(state, PR_TRUE);
state = state->parent;
}

View file

@ -444,7 +444,8 @@ class covAction(argparse.Action):
def runSslGtests(self, outdir):
env = {
"GTESTFILTER": "*", # Prevent parallel test runs.
"ASAN_OPTIONS": "coverage=1:coverage_dir=" + outdir
"ASAN_OPTIONS": "coverage=1:coverage_dir=" + outdir,
"NSS_DISABLE_UNLOAD": "1"
}
run_tests("ssl_gtests", env=env, silent=True)

View file

@ -204,6 +204,7 @@
'cmd/vfychain/vfychain.gyp:vfychain',
'cmd/vfyserv/vfyserv.gyp:vfyserv',
'cmd/mpitests/mpitests.gyp:mpi_tests',
'gtests/base_gtest/base_gtest.gyp:base_gtest',
'gtests/certhigh_gtest/certhigh_gtest.gyp:certhigh_gtest',
'gtests/cryptohi_gtest/cryptohi_gtest.gyp:cryptohi_gtest',
'gtests/der_gtest/der_gtest.gyp:der_gtest',

View file

@ -98,7 +98,7 @@ gtest_cleanup()
}
################## main #################################################
GTESTS="${GTESTS:-prng_gtest certhigh_gtest certdb_gtest der_gtest pk11_gtest util_gtest freebl_gtest softoken_gtest sysinit_gtest blake2b_gtest smime_gtest mozpkix_gtest}"
GTESTS="${GTESTS:-base_gtest prng_gtest certhigh_gtest certdb_gtest der_gtest pk11_gtest util_gtest freebl_gtest softoken_gtest sysinit_gtest blake2b_gtest smime_gtest mozpkix_gtest}"
SOURCE_DIR="$PWD"/../..
gtest_init "$0"
gtest_start

View file

@ -723,7 +723,10 @@ ssl_crl_ssl()
fi
servarg=`echo $sparam | awk '{r=split($0,a,"-r") - 1;print r;}'`
pwd=`echo $cparam | grep nss`
# did we select TestUser?
user=`echo $cparam | grep TestUser`
# did we explicitly select a cert?
auto=`echo $cparam | grep '\\-n'`
_cparam=$cparam
case $servarg in
1) if [ -z "$pwd" -o -z "$user" ]; then
@ -732,14 +735,24 @@ ssl_crl_ssl()
rev_modvalue=254
fi
;;
2) rev_modvalue=254 ;;
2) if [ -z "$auto" ]; then
rev_modvalue=0
else
rev_modvalue=254
fi
;;
3) if [ -z "$pwd" -o -z "$user" ]; then
rev_modvalue=0
else
rev_modvalue=1
fi
;;
4) rev_modvalue=1 ;;
4) if [ -z "$auto" ]; then
rev_modvalue=0
else
rev_modvalue=1
fi
;;
esac
TEMP_NUM=0
while [ $TEMP_NUM -lt $CRL_GROUP_RANGE ]
@ -747,8 +760,8 @@ ssl_crl_ssl()
CURR_SER_NUM=`expr ${CRL_GROUP_BEGIN} + ${TEMP_NUM}`
TEMP_NUM=`expr $TEMP_NUM + 1`
USER_NICKNAME="TestUser${CURR_SER_NUM}"
cparam=`echo $_cparam | sed -e 's;_; ;g' -e "s/TestUser/$USER_NICKNAME/g" `
start_selfserv `echo "$sparam" | sed -e 's,_, ,g'`
cparam=`echo $_cparam | sed -e 's;\([^\\]\)_;\1 ;g' -e 's;\\\\_;_;g' -e "s/TestUser/$USER_NICKNAME/g" `
start_selfserv `echo "$sparam" | sed -e 's;\([^\\]\)_;\1 ;g' -e 's;\\\\_;_;g'`
echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${R_CLIENTDIR} $verbose \\"
echo " ${cparam} < ${REQUEST_FILE}"
@ -1130,7 +1143,7 @@ ssl_crl_cache()
CURR_SER_NUM=`expr ${CRL_GRP_1_BEGIN} + ${TEMP_NUM}`
TEMP_NUM=`expr $TEMP_NUM + 1`
USER_NICKNAME="TestUser${CURR_SER_NUM}"
cparam=`echo $_cparam | sed -e 's;_; ;g' -e "s/TestUser/$USER_NICKNAME/g" `
cparam=`echo $_cparam | sed -e 's;\([^\]\)_;\1 ;g' -e 's;\\_;_;g' -e "s/TestUser/$USER_NICKNAME/g" `
echo "Server Args: $SERV_ARG"
echo "tstclnt -4 -p ${PORT} -h ${HOSTADDR} -f -d ${R_CLIENTDIR} $verbose \\"

View file

@ -43,17 +43,18 @@
noECC 0 -r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_none_-w_nss TLS 1.3 Request don't require client auth on post hs (client does not provide auth)
noECC 1 -r_-r_-r_-r_-E -V_tls1.3:tls1.3_-E_-n_none_-w_nss TLS 1.3 Require client auth on post hs (client does not provide auth)
noECC 0 -r_-r_-r_-E_-u -V_tls1.3:tls1.3_-E_-n_TestUser_-w_nss TLS 1.3 Request don't require client auth on post hs with session ticket (client auth)
noECC 0 -r_-r_-J_rsa\\_pkcs1\\_sha256 -V_tls1.2:_-w_nss TLS 1.2 Require client auth auto select(RSA) (client auth)
#
# Use EC cert for client authentication
#
ECC 0 -r -V_ssl3:tls1.2_-w_bogus_-n_TestUser-ec TLS Request don't require client auth (EC) (bad password)
ECC 0 -r -V_ssl3:tls1.2_-w_nss_-n_TestUser-ec TLS Request don't require client auth (EC) (client auth)
ECC 254 -r_-r -V_ssl3:tls1.2_-w_bogus_-n_TestUser-ec TLS Require client auth (EC) (bad password)
ECC 0 -r_-r -V_ssl3:tls1.2_-w_nss_-n_TestUser-ec_ TLS Require client auth (EC) (client auth)
ECC 0 -r -V_ssl3:ssl3_-n_TestUser-ec_-w_bogus SSL3 Request don't require client auth (EC) (bad password)
ECC 0 -r -V_ssl3:ssl3_-n_TestUser-ec_-w_nss SSL3 Request don't require client auth (EC) (client auth)
ECC 254 -r_-r -V_ssl3:ssl3_-n_TestUser-ec_-w_bogus SSL3 Require client auth (EC) (bad password)
ECC 0 -r_-r -V_ssl3:ssl3_-n_TestUser-ec_-w_nss SSL3 Require client auth (EC) (client auth)
ECC 0 -r -V_ssl3:tls1.2_-w_bogus_-n_TestUser-ec TLS Request don't require client auth (EC) (bad password)
ECC 0 -r -V_ssl3:tls1.2_-w_nss_-n_TestUser-ec TLS Request don't require client auth (EC) (client auth)
ECC 254 -r_-r -V_ssl3:tls1.2_-w_bogus_-n_TestUser-ec TLS Require client auth (EC) (bad password)
ECC 0 -r_-r -V_ssl3:tls1.2_-w_nss_-n_TestUser-ec_ TLS Require client auth (EC) (client auth)
ECC 0 -r -V_ssl3:ssl3_-n_TestUser-ec_-w_bogus SSL3 Request don't require client auth (EC) (bad password)
ECC 0 -r -V_ssl3:ssl3_-n_TestUser-ec_-w_nss SSL3 Request don't require client auth (EC) (client auth)
ECC 254 -r_-r -V_ssl3:ssl3_-n_TestUser-ec_-w_bogus SSL3 Require client auth (EC) (bad password)
ECC 0 -r_-r -V_ssl3:ssl3_-n_TestUser-ec_-w_nss SSL3 Require client auth (EC) (client auth)
ECC 0 -r_-r_-r -V_ssl3:tls1.2_-w_bogus_-n_TestUser-ec TLS Request don't require client auth on 2nd hs (EC) (bad password)
ECC 0 -r_-r_-r -V_ssl3:tls1.2_-w_nss_-n_TestUser-ec TLS Request don't require client auth on 2nd hs (EC) (client auth)
ECC 1 -r_-r_-r_-r -V_ssl3:tls1.2_-w_bogus_-n_TestUser-ec TLS Require client auth on 2nd hs (EC) (bad password)
@ -62,10 +63,12 @@
ECC 0 -r_-r_-r -V_ssl3:tls1.0_-w_nss_-n_TestUser-ec TLS 1.0 Request don't require client auth on 2nd hs (EC) (client auth)
ECC 1 -r_-r_-r_-r -V_ssl3:tls1.0_-w_bogus_-n_TestUser-ec TLS 1.0 Require client auth on 2nd hs (EC) (bad password)
ECC 0 -r_-r_-r_-r -V_ssl3:tls1.0_-w_nss_-n_TestUser-ec_ TLS 1.0 Require client auth on 2nd hs (EC) (client auth)
ECC 0 -r_-r_-r -V_ssl3:ssl3_-n_TestUser-ec_-w_bogus SSL3 Request don't require client auth on 2nd hs (EC) (bad password)
ECC 0 -r_-r_-r -V_ssl3:ssl3_-n_TestUser-ec_-w_nss SSL3 Request don't require client auth on 2nd hs (EC) (client auth)
ECC 1 -r_-r_-r_-r -V_ssl3:ssl3_-n_TestUser-ec_-w_bogus SSL3 Require client auth on 2nd hs (EC) (bad password)
ECC 0 -r_-r_-r_-r -V_ssl3:ssl3_-n_TestUser-ec_-w_nss SSL3 Require client auth on 2nd hs (EC) (client auth)
ECC 0 -r_-r_-r -V_ssl3:ssl3_-n_TestUser-ec_-w_bogus SSL3 Request don't require client auth on 2nd hs (EC) (bad password)
ECC 0 -r_-r_-r -V_ssl3:ssl3_-n_TestUser-ec_-w_nss SSL3 Request don't require client auth on 2nd hs (EC) (client auth)
ECC 1 -r_-r_-r_-r -V_ssl3:ssl3_-n_TestUser-ec_-w_bogus SSL3 Require client auth on 2nd hs (EC) (bad password)
ECC 0 -r_-r_-r_-r -V_ssl3:ssl3_-n_TestUser-ec_-w_nss SSL3 Require client auth on 2nd hs (EC) (client auth)
ECC 0 -r_-r_-J_ecdsa\\_secp256r1\\_sha256 -V_tls1.2:_-w_nss TLS 1.2 Require client auth auto select(EC) (client auth)
ECC 0 -r_-r_-J_ecdsa\\_secp256r1\\_sha256,ecdsa\\_secp384r1\\_sha384 -V_tls1.3:_-w_nss TLS 1.3 Require client auth auto select (EC) (client auth)
#
# SNI Tests
#