1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
9 #include "base/logging.h"
10 #include "crypto/scoped_nss_types.h"
11 #include "net/cert/sha256_legacy_support_win.h"
15 namespace sha256_interception
{
17 BOOL
CryptVerifyCertificateSignatureExHook(
18 CryptVerifyCertificateSignatureExFunc original_func
,
19 HCRYPTPROV_LEGACY provider
,
29 // Only intercept if the arguments are supported.
30 if (provider
!= NULL
|| (encoding_type
!= X509_ASN_ENCODING
) ||
31 !IsSupportedSubjectType(subject_type
) || subject_data
== NULL
||
32 !IsSupportedIssuerType(issuer_type
) || issuer_data
== NULL
) {
33 return original_func(provider
, encoding_type
, subject_type
, subject_data
,
34 issuer_type
, issuer_data
, flags
, extra
);
37 base::StringPiece subject_signature
=
38 GetSubjectSignature(subject_type
, subject_data
);
39 bool should_intercept
= false;
41 crypto::ScopedPLArenaPool
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE
));
42 CERTSignedData signed_data
;
43 memset(&signed_data
, 0, sizeof(signed_data
));
45 // Attempt to decode the subject using the generic "Signed Data" template,
46 // which all of the supported subject types match. If the signature
47 // algorithm is RSA with one of the SHA-2 algorithms supported by NSS
48 // (excluding SHA-224, which is pointless), then defer to the NSS
49 // implementation. Otherwise, fall back and let the OS handle it (e.g.
50 // in case there are any algorithm policies in effect).
51 if (!subject_signature
.empty()) {
52 SECItem subject_sig_item
;
53 subject_sig_item
.data
= const_cast<unsigned char*>(
54 reinterpret_cast<const unsigned char*>(subject_signature
.data()));
55 subject_sig_item
.len
= subject_signature
.size();
56 SECStatus rv
= SEC_QuickDERDecodeItem(
57 arena
.get(), &signed_data
, SEC_ASN1_GET(CERT_SignedDataTemplate
),
59 if (rv
== SECSuccess
) {
60 SECOidTag signature_alg
=
61 SECOID_GetAlgorithmTag(&signed_data
.signatureAlgorithm
);
62 if (signature_alg
== SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION
||
63 signature_alg
== SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION
||
64 signature_alg
== SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION
) {
65 should_intercept
= true;
70 if (!should_intercept
) {
71 return original_func(provider
, encoding_type
, subject_type
, subject_data
,
72 issuer_type
, issuer_data
, flags
, extra
);
75 // Rather than attempting to synthesize a CERTSubjectPublicKeyInfo by hand,
76 // just force the OS to do an ASN.1 encoding and then decode it back into
77 // NSS. This is silly for performance, but safest for consistency.
78 PCERT_PUBLIC_KEY_INFO issuer_public_key
=
79 GetIssuerPublicKey(issuer_type
, issuer_data
);
80 if (!issuer_public_key
) {
81 SetLastError(static_cast<DWORD
>(NTE_BAD_ALGID
));
85 unsigned char* issuer_spki_data
= NULL
;
86 DWORD issuer_spki_len
= 0;
87 if (!CryptEncodeObjectEx(X509_ASN_ENCODING
, X509_PUBLIC_KEY_INFO
,
88 issuer_public_key
, CRYPT_ENCODE_ALLOC_FLAG
, NULL
,
89 &issuer_spki_data
, &issuer_spki_len
)) {
93 SECItem nss_issuer_spki
;
94 nss_issuer_spki
.data
= issuer_spki_data
;
95 nss_issuer_spki
.len
= issuer_spki_len
;
96 CERTSubjectPublicKeyInfo
* spki
=
97 SECKEY_DecodeDERSubjectPublicKeyInfo(&nss_issuer_spki
);
98 ::LocalFree(issuer_spki_data
);
100 SetLastError(static_cast<DWORD
>(NTE_BAD_ALGID
));
104 // Attempt to actually verify the signed data. If it fails, synthesize the
105 // failure as a generic "bad signature" and let CryptoAPI handle the rest.
106 SECStatus rv
= CERT_VerifySignedDataWithPublicKeyInfo(
107 &signed_data
, spki
, NULL
);
108 SECKEY_DestroySubjectPublicKeyInfo(spki
);
109 if (rv
!= SECSuccess
) {
110 SetLastError(static_cast<DWORD
>(NTE_BAD_SIGNATURE
));
116 } // namespace sha256_interception