summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--automation/abi-check/expected-report-libssl3.so.txt13
-rw-r--r--gtests/ssl_gtest/libssl_internals.c23
-rw-r--r--gtests/ssl_gtest/libssl_internals.h2
-rw-r--r--gtests/ssl_gtest/tls_agent.cc8
-rw-r--r--gtests/ssl_gtest/tls_agent.h5
-rw-r--r--gtests/ssl_gtest/tls_filter.h13
-rw-r--r--gtests/ssl_gtest/tls_subcerts_unittest.cc120
-rw-r--r--lib/ssl/ssl3con.c77
-rw-r--r--lib/ssl/sslimpl.h1
-rw-r--r--lib/ssl/sslinfo.c4
-rw-r--r--lib/ssl/sslt.h13
-rw-r--r--lib/ssl/tls13con.c13
12 files changed, 275 insertions, 17 deletions
diff --git a/automation/abi-check/expected-report-libssl3.so.txt b/automation/abi-check/expected-report-libssl3.so.txt
index e69de29bb..bf902d170 100644
--- a/automation/abi-check/expected-report-libssl3.so.txt
+++ b/automation/abi-check/expected-report-libssl3.so.txt
@@ -0,0 +1,13 @@
+
+1 function with some indirect sub-type change:
+
+ [C]'function SECStatus SSL_GetPreliminaryChannelInfo(PRFileDesc*, SSLPreliminaryChannelInfo*, PRUintn)' at sslinfo.c:113:1 has some indirect sub-type changes:
+ parameter 2 of type 'SSLPreliminaryChannelInfo*' has sub-type changes:
+ in pointed to type 'typedef SSLPreliminaryChannelInfo' at sslt.h:424:1:
+ underlying type 'struct SSLPreliminaryChannelInfoStr' at sslt.h:373:1 changed:
+ type size changed from 192 to 288 (in bits)
+ 3 data member insertions:
+ 'PRBool SSLPreliminaryChannelInfoStr::peerDelegCred', at offset 192 (in bits) at sslt.h:418:1
+ '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
+
diff --git a/gtests/ssl_gtest/libssl_internals.c b/gtests/ssl_gtest/libssl_internals.c
index d3e4a13ed..44eee9aa8 100644
--- a/gtests/ssl_gtest/libssl_internals.c
+++ b/gtests/ssl_gtest/libssl_internals.c
@@ -12,6 +12,29 @@
#include "seccomon.h"
#include "selfencrypt.h"
+SECStatus SSLInt_TweakChannelInfoForDC(PRFileDesc *fd, PRBool changeAuthKeyBits,
+ PRBool changeScheme) {
+ if (!fd) {
+ return SECFailure;
+ }
+ sslSocket *ss = ssl_FindSocket(fd);
+ if (!ss) {
+ return SECFailure;
+ }
+
+ // Just toggle so we'll always have a valid value.
+ if (changeScheme) {
+ ss->sec.signatureScheme = (ss->sec.signatureScheme == ssl_sig_ed25519)
+ ? ssl_sig_ecdsa_secp256r1_sha256
+ : ssl_sig_ed25519;
+ }
+ if (changeAuthKeyBits) {
+ ss->sec.authKeyBits = ss->sec.authKeyBits ? ss->sec.authKeyBits * 2 : 384;
+ }
+
+ return SECSuccess;
+}
+
SECStatus SSLInt_GetHandshakeRandoms(PRFileDesc *fd, SSL3Random client_random,
SSL3Random server_random) {
if (!fd) {
diff --git a/gtests/ssl_gtest/libssl_internals.h b/gtests/ssl_gtest/libssl_internals.h
index cfba19250..a908c9ab1 100644
--- a/gtests/ssl_gtest/libssl_internals.h
+++ b/gtests/ssl_gtest/libssl_internals.h
@@ -42,5 +42,7 @@ SECStatus SSLInt_AdvanceWriteSeqByAWindow(PRFileDesc *fd, PRInt32 extra);
SSLKEAType SSLInt_GetKEAType(SSLNamedGroup group);
SECStatus SSLInt_HasPendingHandshakeData(PRFileDesc *fd, PRBool *pending);
SECStatus SSLInt_SetSocketMaxEarlyDataSize(PRFileDesc *fd, uint32_t size);
+SECStatus SSLInt_TweakChannelInfoForDC(PRFileDesc *fd, PRBool changeAuthKeyBits,
+ PRBool changeScheme);
#endif // ndef libssl_internals_h_
diff --git a/gtests/ssl_gtest/tls_agent.cc b/gtests/ssl_gtest/tls_agent.cc
index bd50434c6..0c6faabd9 100644
--- a/gtests/ssl_gtest/tls_agent.cc
+++ b/gtests/ssl_gtest/tls_agent.cc
@@ -842,6 +842,13 @@ void TlsAgent::ResetPreliminaryInfo() {
expected_cipher_suite_ = 0;
}
+void TlsAgent::UpdatePreliminaryChannelInfo() {
+ SECStatus rv = SSL_GetPreliminaryChannelInfo(ssl_fd_.get(), &pre_info_,
+ sizeof(pre_info_));
+ EXPECT_EQ(SECSuccess, rv);
+ EXPECT_EQ(sizeof(pre_info_), pre_info_.length);
+}
+
void TlsAgent::ValidateCipherSpecs() {
PRInt32 cipherSpecs = SSLInt_CountCipherSpecs(ssl_fd());
// We use one ciphersuite in each direction.
@@ -904,6 +911,7 @@ void TlsAgent::Connected() {
// Preliminary values are exposed through callbacks during the handshake.
// If either expected values were set or the callbacks were called, check
// that the final values are correct.
+ UpdatePreliminaryChannelInfo();
EXPECT_EQ(expected_version_, info_.protocolVersion);
EXPECT_EQ(expected_cipher_suite_, info_.cipherSuite);
diff --git a/gtests/ssl_gtest/tls_agent.h b/gtests/ssl_gtest/tls_agent.h
index d01618baa..4b6cce8e0 100644
--- a/gtests/ssl_gtest/tls_agent.h
+++ b/gtests/ssl_gtest/tls_agent.h
@@ -134,6 +134,7 @@ class TlsAgent : public PollTarget {
void AddDelegatedCredential(const std::string& dc_name,
SSLSignatureScheme dcCertVerifyAlg,
PRUint32 dcValidFor, PRTime now);
+ void UpdatePreliminaryChannelInfo();
bool ConfigServerCert(const std::string& name, bool updateKeyBits = false,
const SSLExtraServerCertData* serverCertData = nullptr);
@@ -228,6 +229,9 @@ class TlsAgent : public PollTarget {
EXPECT_EQ(STATE_CONNECTED, state_);
return info_;
}
+
+ const SSLPreliminaryChannelInfo& pre_info() const { return pre_info_; }
+
bool is_compressed() const {
return info().compressionMethod != ssl_compression_null;
}
@@ -425,6 +429,7 @@ class TlsAgent : public PollTarget {
bool handshake_callback_called_;
bool resumption_callback_called_;
SSLChannelInfo info_;
+ SSLPreliminaryChannelInfo pre_info_;
SSLCipherSuiteInfo csinfo_;
SSLVersionRange vrange_;
PRErrorCode error_code_;
diff --git a/gtests/ssl_gtest/tls_filter.h b/gtests/ssl_gtest/tls_filter.h
index f036fbfca..ec954e732 100644
--- a/gtests/ssl_gtest/tls_filter.h
+++ b/gtests/ssl_gtest/tls_filter.h
@@ -441,6 +441,19 @@ class TlsExtensionDropper : public TlsExtensionFilter {
uint16_t extension_;
};
+class TlsHandshakeDropper : public TlsHandshakeFilter {
+ public:
+ TlsHandshakeDropper(const std::shared_ptr<TlsAgent>& a)
+ : TlsHandshakeFilter(a) {}
+
+ protected:
+ PacketFilter::Action FilterHandshake(const HandshakeHeader& header,
+ const DataBuffer& input,
+ DataBuffer* output) override {
+ return DROP;
+ }
+};
+
class TlsExtensionInjector : public TlsHandshakeFilter {
public:
TlsExtensionInjector(const std::shared_ptr<TlsAgent>& a, uint16_t ext,
diff --git a/gtests/ssl_gtest/tls_subcerts_unittest.cc b/gtests/ssl_gtest/tls_subcerts_unittest.cc
index 48e7a7b68..0882ef7ef 100644
--- a/gtests/ssl_gtest/tls_subcerts_unittest.cc
+++ b/gtests/ssl_gtest/tls_subcerts_unittest.cc
@@ -22,14 +22,63 @@ const std::string kDCId = TlsAgent::kServerEcdsa256;
const SSLSignatureScheme kDCScheme = ssl_sig_ecdsa_secp256r1_sha256;
const PRUint32 kDCValidFor = 60 * 60 * 24 * 7 /* 1 week (seconds */;
+static void CheckPreliminaryPeerDelegCred(
+ const std::shared_ptr<TlsAgent>& client, bool expected,
+ PRUint32 key_bits = 0, SSLSignatureScheme sig_scheme = ssl_sig_none) {
+ EXPECT_NE(0U, (client->pre_info().valuesSet & ssl_preinfo_peer_auth));
+ EXPECT_EQ(expected, client->pre_info().peerDelegCred);
+ if (expected) {
+ EXPECT_EQ(key_bits, client->pre_info().authKeyBits);
+ EXPECT_EQ(sig_scheme, client->pre_info().signatureScheme);
+ }
+}
+
static void CheckPeerDelegCred(const std::shared_ptr<TlsAgent>& client,
bool expected, PRUint32 key_bits = 0) {
EXPECT_EQ(expected, client->info().peerDelegCred);
+ EXPECT_EQ(expected, client->pre_info().peerDelegCred);
if (expected) {
EXPECT_EQ(key_bits, client->info().authKeyBits);
+ EXPECT_EQ(key_bits, client->pre_info().authKeyBits);
+ EXPECT_EQ(client->info().signatureScheme,
+ client->pre_info().signatureScheme);
}
}
+// AuthCertificate callbacks to simulate DC validation
+static SECStatus CheckPreliminaryDC(TlsAgent* agent, bool checksig,
+ bool isServer) {
+ agent->UpdatePreliminaryChannelInfo();
+ EXPECT_EQ(PR_TRUE, agent->pre_info().peerDelegCred);
+ EXPECT_EQ(256U, agent->pre_info().authKeyBits);
+ EXPECT_EQ(ssl_sig_ecdsa_secp256r1_sha256, agent->pre_info().signatureScheme);
+ return SECSuccess;
+}
+
+static SECStatus CheckPreliminaryNoDC(TlsAgent* agent, bool checksig,
+ bool isServer) {
+ agent->UpdatePreliminaryChannelInfo();
+ EXPECT_EQ(PR_FALSE, agent->pre_info().peerDelegCred);
+ return SECSuccess;
+}
+
+// AuthCertificate callbacks for modifying DC attributes.
+// This allows testing tls13_CertificateVerify for rejection
+// of DC attributes that have changed since AuthCertificateHook
+// may have handled them.
+static SECStatus ModifyDCAuthKeyBits(TlsAgent* agent, bool checksig,
+ bool isServer) {
+ return SSLInt_TweakChannelInfoForDC(agent->ssl_fd(),
+ PR_TRUE, // Change authKeyBits
+ PR_FALSE); // Change scheme
+}
+
+static SECStatus ModifyDCScheme(TlsAgent* agent, bool checksig, bool isServer) {
+ return SSLInt_TweakChannelInfoForDC(agent->ssl_fd(),
+ PR_FALSE, // Change authKeyBits
+ PR_TRUE); // Change scheme
+}
+
// Attempt to configure a DC when either the DC or DC private key is missing.
TEST_P(TlsConnectTls13, DCNotConfigured) {
// Load and delegate the credential.
@@ -388,6 +437,77 @@ TEST_P(TlsConnectTls13, DCConnectExpectedCertVerifyAlgNotSupported) {
CheckPeerDelegCred(client_, false);
}
+// Check that preliminary channel info properly reflects the DC.
+TEST_P(TlsConnectTls13, DCCheckPreliminaryInfo) {
+ Reset(kEcdsaDelegatorId);
+ EnsureTlsSetup();
+ client_->EnableDelegatedCredentials();
+ server_->AddDelegatedCredential(TlsAgent::kServerEcdsa256,
+ ssl_sig_ecdsa_secp256r1_sha256, kDCValidFor,
+ now());
+
+ auto filter = MakeTlsFilter<TlsHandshakeDropper>(server_);
+ filter->SetHandshakeTypes(
+ {kTlsHandshakeCertificateVerify, kTlsHandshakeFinished});
+ filter->EnableDecryption();
+ StartConnect();
+ client_->Handshake(); // Send ClientHello
+ server_->Handshake(); // Send ServerHello
+
+ client_->SetAuthCertificateCallback(CheckPreliminaryDC);
+ client_->Handshake(); // Process response
+
+ client_->UpdatePreliminaryChannelInfo();
+ CheckPreliminaryPeerDelegCred(client_, true, 256,
+ ssl_sig_ecdsa_secp256r1_sha256);
+}
+
+// Check that preliminary channel info properly reflects a lack of DC.
+TEST_P(TlsConnectTls13, DCCheckPreliminaryInfoNoDC) {
+ Reset(kEcdsaDelegatorId);
+ EnsureTlsSetup();
+ client_->EnableDelegatedCredentials();
+ auto filter = MakeTlsFilter<TlsHandshakeDropper>(server_);
+ filter->SetHandshakeTypes(
+ {kTlsHandshakeCertificateVerify, kTlsHandshakeFinished});
+ filter->EnableDecryption();
+ StartConnect();
+ client_->Handshake(); // Send ClientHello
+ server_->Handshake(); // Send ServerHello
+
+ client_->SetAuthCertificateCallback(CheckPreliminaryNoDC);
+ client_->Handshake(); // Process response
+
+ client_->UpdatePreliminaryChannelInfo();
+ CheckPreliminaryPeerDelegCred(client_, false);
+}
+
+// Tweak the scheme in between |Cert| and |CertVerify|.
+TEST_P(TlsConnectTls13, DCRejectModifiedDCScheme) {
+ Reset(kEcdsaDelegatorId);
+ client_->EnableDelegatedCredentials();
+ client_->SetAuthCertificateCallback(ModifyDCScheme);
+ server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
+ ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
+ now());
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+ server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ client_->CheckErrorCode(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH);
+}
+
+// Tweak the authKeyBits in between |Cert| and |CertVerify|.
+TEST_P(TlsConnectTls13, DCRejectModifiedDCAuthKeyBits) {
+ Reset(kEcdsaDelegatorId);
+ client_->EnableDelegatedCredentials();
+ client_->SetAuthCertificateCallback(ModifyDCAuthKeyBits);
+ server_->AddDelegatedCredential(TlsAgent::kServerEcdsa521,
+ ssl_sig_ecdsa_secp521r1_sha512, kDCValidFor,
+ now());
+ ConnectExpectAlert(client_, kTlsAlertIllegalParameter);
+ server_->CheckErrorCode(SSL_ERROR_ILLEGAL_PARAMETER_ALERT);
+ client_->CheckErrorCode(SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH);
+}
+
class DCDelegation : public ::testing::Test {};
TEST_F(DCDelegation, DCDelegations) {
diff --git a/lib/ssl/ssl3con.c b/lib/ssl/ssl3con.c
index 79fdf6b04..29a34aeb5 100644
--- a/lib/ssl/ssl3con.c
+++ b/lib/ssl/ssl3con.c
@@ -21,6 +21,7 @@
#include "sslerr.h"
#include "ssl3ext.h"
#include "ssl3exthandle.h"
+#include "tls13subcerts.h"
#include "prtime.h"
#include "prinrval.h"
#include "prerror.h"
@@ -11047,6 +11048,47 @@ ssl_SetAuthKeyBits(sslSocket *ss, const SECKEYPublicKey *pubKey)
: illegal_parameter);
return SECFailure;
}
+
+ /* PreliminaryChannelInfo.authKeyBits, scheme, and peerDelegCred are now valid. */
+ ss->ssl3.hs.preliminaryInfo |= ssl_preinfo_peer_auth;
+
+ return SECSuccess;
+}
+
+SECStatus
+ssl3_HandleServerSpki(sslSocket *ss)
+{
+ PORT_Assert(!ss->sec.isServer);
+ SECKEYPublicKey *pubKey;
+
+ if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3 &&
+ tls13_IsVerifyingWithDelegatedCredential(ss)) {
+ sslDelegatedCredential *dc = ss->xtnData.peerDelegCred;
+ pubKey = SECKEY_ExtractPublicKey(dc->spki);
+ if (!pubKey) {
+ PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ return SECFailure;
+ }
+
+ /* Because we have only a single authType (ssl_auth_tls13_any)
+ * for TLS 1.3 at this point, set the scheme so that the
+ * callback can interpret |authKeyBits| correctly.
+ */
+ ss->sec.signatureScheme = dc->expectedCertVerifyAlg;
+ } else {
+ pubKey = CERT_ExtractPublicKey(ss->sec.peerCert);
+ if (!pubKey) {
+ PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE);
+ return SECFailure;
+ }
+ }
+
+ SECStatus rv = ssl_SetAuthKeyBits(ss, pubKey);
+ SECKEY_DestroyPublicKey(pubKey);
+ if (rv != SECSuccess) {
+ return rv; /* Alert sent and code set. */
+ }
+
return SECSuccess;
}
@@ -11061,6 +11103,26 @@ ssl3_AuthCertificate(sslSocket *ss)
PORT_Assert((ss->ssl3.hs.preliminaryInfo & ssl_preinfo_all) ==
ssl_preinfo_all);
+
+ if (!ss->sec.isServer) {
+ /* Set the |spki| used to verify the handshake. When verifying with a
+ * delegated credential (DC), this corresponds to the DC public key;
+ * otherwise it correspond to the public key of the peer's end-entity
+ * certificate. */
+ rv = ssl3_HandleServerSpki(ss);
+ if (rv != SECSuccess) {
+ /* Alert sent and code set (if not SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE).
+ * In either case, we're done here. */
+ errCode = PORT_GetError();
+ goto loser;
+ }
+
+ if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
+ ss->sec.authType = ss->ssl3.hs.kea_def->authKeyType;
+ ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType;
+ }
+ }
+
/*
* Ask caller-supplied callback function to validate cert chain.
*/
@@ -11099,21 +11161,6 @@ ssl3_AuthCertificate(sslSocket *ss)
ss->sec.ci.sid->peerCert = CERT_DupCertificate(ss->sec.peerCert);
if (!ss->sec.isServer) {
- if (ss->version < SSL_LIBRARY_VERSION_TLS_1_3) {
- /* These are filled in in tls13_HandleCertificateVerify and
- * tls13_HandleServerKeyShare (keaType). */
- SECKEYPublicKey *pubKey = CERT_ExtractPublicKey(ss->sec.peerCert);
- if (pubKey) {
- rv = ssl_SetAuthKeyBits(ss, pubKey);
- SECKEY_DestroyPublicKey(pubKey);
- if (rv != SECSuccess) {
- return SECFailure; /* Alert sent and code set. */
- }
- }
- ss->sec.authType = ss->ssl3.hs.kea_def->authKeyType;
- ss->sec.keaType = ss->ssl3.hs.kea_def->exchKeyType;
- }
-
if (ss->version >= SSL_LIBRARY_VERSION_TLS_1_3) {
TLS13_SET_HS_STATE(ss, wait_cert_verify);
} else {
diff --git a/lib/ssl/sslimpl.h b/lib/ssl/sslimpl.h
index faeedad12..4a393b281 100644
--- a/lib/ssl/sslimpl.h
+++ b/lib/ssl/sslimpl.h
@@ -1678,6 +1678,7 @@ SECStatus ssl3_SendEmptyCertificate(sslSocket *ss);
void ssl3_CleanupPeerCerts(sslSocket *ss);
SECStatus ssl3_SendCertificateStatus(sslSocket *ss);
SECStatus ssl_SetAuthKeyBits(sslSocket *ss, const SECKEYPublicKey *pubKey);
+SECStatus ssl3_HandleServerSpki(sslSocket *ss);
SECStatus ssl3_AuthCertificate(sslSocket *ss);
SECStatus ssl_ReadCertificateStatus(sslSocket *ss, PRUint8 *b,
PRUint32 length);
diff --git a/lib/ssl/sslinfo.c b/lib/ssl/sslinfo.c
index 4834605c1..b069888e2 100644
--- a/lib/ssl/sslinfo.c
+++ b/lib/ssl/sslinfo.c
@@ -154,6 +154,10 @@ SSL_GetPreliminaryChannelInfo(PRFileDesc *fd,
}
inf.zeroRttCipherSuite = ss->ssl3.hs.zeroRttSuite;
+ inf.peerDelegCred = tls13_IsVerifyingWithDelegatedCredential(ss);
+ inf.authKeyBits = ss->sec.authKeyBits;
+ inf.signatureScheme = ss->sec.signatureScheme;
+
memcpy(info, &inf, inf.length);
return SECSuccess;
}
diff --git a/lib/ssl/sslt.h b/lib/ssl/sslt.h
index 437fe5ccb..47efa2e4d 100644
--- a/lib/ssl/sslt.h
+++ b/lib/ssl/sslt.h
@@ -366,6 +366,9 @@ typedef struct SSLChannelInfoStr {
#define ssl_preinfo_version (1U << 0)
#define ssl_preinfo_cipher_suite (1U << 1)
#define ssl_preinfo_0rtt_cipher_suite (1U << 2)
+/* ssl_preinfo_peer_auth covers peerDelegCred, authKeyBits, and scheme. Not
+ * included in ssl_preinfo_all as it is client-only. */
+#define ssl_preinfo_peer_auth (1U << 3)
/* ssl_preinfo_all doesn't contain ssl_preinfo_0rtt_cipher_suite because that
* field is only set if 0-RTT is sent (client) or accepted (server). */
#define ssl_preinfo_all (ssl_preinfo_version | ssl_preinfo_cipher_suite)
@@ -406,6 +409,16 @@ typedef struct SSLPreliminaryChannelInfoStr {
* after accepting 0-RTT, so this will contain the same value. */
PRUint16 zeroRttCipherSuite;
+ /* The following fields were added in NSS 3.48. */
+ /* These fields contain information about the key that will be used in
+ * the CertificateVerify message. If Delegated Credentials are being used,
+ * this is the DC-contained SPKI, else the EE-cert SPKI. These fields are
+ * valid only after the Certificate message is handled. This can be determined
+ * by checking the valuesSet field against |ssl_preinfo_peer_auth|. */
+ PRBool peerDelegCred;
+ PRUint32 authKeyBits;
+ SSLSignatureScheme signatureScheme;
+
/* When adding new fields to this structure, please document the
* NSS version in which they were added. */
} SSLPreliminaryChannelInfo;
diff --git a/lib/ssl/tls13con.c b/lib/ssl/tls13con.c
index c24684150..513f1ced7 100644
--- a/lib/ssl/tls13con.c
+++ b/lib/ssl/tls13con.c
@@ -4184,8 +4184,10 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
if (tls13_IsVerifyingWithDelegatedCredential(ss)) {
/* DelegatedCredential.cred.expected_cert_verify_algorithm is expected
* to match CertificateVerify.scheme.
+ * DelegatedCredential.cred.expected_cert_verify_algorithm must also be
+ * the same as was reported in ssl3_AuthCertificate.
*/
- if (sigScheme != dc->expectedCertVerifyAlg) {
+ if (sigScheme != dc->expectedCertVerifyAlg || sigScheme != ss->sec.signatureScheme) {
FATAL_ERROR(ss, SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH, illegal_parameter);
return SECFailure;
}
@@ -4245,13 +4247,20 @@ tls13_HandleCertificateVerify(sslSocket *ss, PRUint8 *b, PRUint32 length)
goto loser;
}
- /* Set the auth type. */
+ /* Set the auth type and verify it is what we captured in ssl3_AuthCertificate */
if (!ss->sec.isServer) {
ss->sec.authType = ssl_SignatureSchemeToAuthType(sigScheme);
+
+ uint32_t prelimAuthKeyBits = ss->sec.authKeyBits;
rv = ssl_SetAuthKeyBits(ss, pubKey);
if (rv != SECSuccess) {
goto loser; /* Alert sent and code set. */
}
+
+ if (prelimAuthKeyBits != ss->sec.authKeyBits) {
+ FATAL_ERROR(ss, SSL_ERROR_DC_CERT_VERIFY_ALG_MISMATCH, illegal_parameter);
+ goto loser;
+ }
}
/* Request a client certificate now if one was requested. */