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. 4 5 #include "net/cert/sha256_legacy_support_win.h" 6 7 #include <windows.h> 8 #include <wincrypt.h> 9 10 #include <cert.h> 11 #include <keyhi.h> 12 #include <secoid.h> 13 14 #include "base/lazy_instance.h" 15 #include "base/logging.h" 16 #include "base/strings/string_piece.h" 17 #include "base/win/windows_version.h" 18 #include "crypto/scoped_nss_types.h" 19 20 namespace net { 21 22 namespace sha256_interception { 23 24 namespace { 25 26 bool IsSupportedSubjectType(DWORD subject_type) { 27 switch (subject_type) { 28 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB: 29 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT: 30 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL: 31 return true; 32 } 33 return false; 34 } 35 36 bool IsSupportedIssuerType(DWORD issuer_type) { 37 switch (issuer_type) { 38 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY: 39 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT: 40 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: 41 return true; 42 } 43 return false; 44 } 45 46 base::StringPiece GetSubjectSignature(DWORD subject_type, 47 void* subject_data) { 48 switch (subject_type) { 49 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_BLOB: { 50 CRYPT_DATA_BLOB* data_blob = 51 reinterpret_cast<CRYPT_DATA_BLOB*>(subject_data); 52 return base::StringPiece(reinterpret_cast<char*>(data_blob->pbData), 53 data_blob->cbData); 54 } 55 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT: { 56 PCCERT_CONTEXT subject_cert = 57 reinterpret_cast<PCCERT_CONTEXT>(subject_data); 58 return base::StringPiece( 59 reinterpret_cast<char*>(subject_cert->pbCertEncoded), 60 subject_cert->cbCertEncoded); 61 } 62 case CRYPT_VERIFY_CERT_SIGN_SUBJECT_CRL: { 63 PCCRL_CONTEXT subject_crl = 64 reinterpret_cast<PCCRL_CONTEXT>(subject_data); 65 return base::StringPiece( 66 reinterpret_cast<char*>(subject_crl->pbCrlEncoded), 67 subject_crl->cbCrlEncoded); 68 } 69 } 70 return base::StringPiece(); 71 } 72 73 PCERT_PUBLIC_KEY_INFO GetIssuerPublicKey(DWORD issuer_type, 74 void* issuer_data) { 75 switch (issuer_type) { 76 case CRYPT_VERIFY_CERT_SIGN_ISSUER_PUBKEY: 77 return reinterpret_cast<PCERT_PUBLIC_KEY_INFO>(issuer_data); 78 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT: { 79 PCCERT_CONTEXT cert = reinterpret_cast<PCCERT_CONTEXT>(issuer_data); 80 return &cert->pCertInfo->SubjectPublicKeyInfo; 81 } 82 case CRYPT_VERIFY_CERT_SIGN_ISSUER_CHAIN: { 83 PCCERT_CHAIN_CONTEXT chain = 84 reinterpret_cast<PCCERT_CHAIN_CONTEXT>(issuer_data); 85 PCCERT_CONTEXT cert = chain->rgpChain[0]->rgpElement[0]->pCertContext; 86 return &cert->pCertInfo->SubjectPublicKeyInfo; 87 } 88 } 89 return NULL; 90 } 91 92 } // namespace 93 94 BOOL CryptVerifyCertificateSignatureExHook( 95 CryptVerifyCertificateSignatureExFunc original_func, 96 HCRYPTPROV_LEGACY provider, 97 DWORD encoding_type, 98 DWORD subject_type, 99 void* subject_data, 100 DWORD issuer_type, 101 void* issuer_data, 102 DWORD flags, 103 void* extra) { 104 CHECK(original_func); 105 106 // Only intercept if the arguments are supported. 107 if (provider != NULL || (encoding_type != X509_ASN_ENCODING) || 108 !IsSupportedSubjectType(subject_type) || subject_data == NULL || 109 !IsSupportedIssuerType(issuer_type) || issuer_data == NULL) { 110 return original_func(provider, encoding_type, subject_type, subject_data, 111 issuer_type, issuer_data, flags, extra); 112 } 113 114 base::StringPiece subject_signature = 115 GetSubjectSignature(subject_type, subject_data); 116 bool should_intercept = false; 117 118 crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); 119 CERTSignedData signed_data; 120 memset(&signed_data, 0, sizeof(signed_data)); 121 122 // Attempt to decode the subject using the generic "Signed Data" template, 123 // which all of the supported subject types match. If the signature 124 // algorithm is RSA with one of the SHA-2 algorithms supported by NSS 125 // (excluding SHA-224, which is pointless), then defer to the NSS 126 // implementation. Otherwise, fall back and let the OS handle it (e.g. 127 // in case there are any algorithm policies in effect). 128 if (!subject_signature.empty()) { 129 SECItem subject_sig_item; 130 subject_sig_item.data = const_cast<unsigned char*>( 131 reinterpret_cast<const unsigned char*>(subject_signature.data())); 132 subject_sig_item.len = subject_signature.size(); 133 SECStatus rv = SEC_QuickDERDecodeItem( 134 arena.get(), &signed_data, SEC_ASN1_GET(CERT_SignedDataTemplate), 135 &subject_sig_item); 136 if (rv == SECSuccess) { 137 SECOidTag signature_alg = 138 SECOID_GetAlgorithmTag(&signed_data.signatureAlgorithm); 139 if (signature_alg == SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION || 140 signature_alg == SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION || 141 signature_alg == SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION) { 142 should_intercept = true; 143 } 144 } 145 } 146 147 if (!should_intercept) { 148 return original_func(provider, encoding_type, subject_type, subject_data, 149 issuer_type, issuer_data, flags, extra); 150 } 151 152 // Rather than attempting to synthesize a CERTSubjectPublicKeyInfo by hand, 153 // just force the OS to do an ASN.1 encoding and then decode it back into 154 // NSS. This is silly for performance, but safest for consistency. 155 PCERT_PUBLIC_KEY_INFO issuer_public_key = 156 GetIssuerPublicKey(issuer_type, issuer_data); 157 if (!issuer_public_key) { 158 SetLastError(static_cast<DWORD>(NTE_BAD_ALGID)); 159 return FALSE; 160 } 161 162 unsigned char* issuer_spki_data = NULL; 163 DWORD issuer_spki_len = 0; 164 if (!CryptEncodeObjectEx(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, 165 issuer_public_key, CRYPT_ENCODE_ALLOC_FLAG, NULL, 166 &issuer_spki_data, &issuer_spki_len)) { 167 return FALSE; 168 } 169 170 SECItem nss_issuer_spki; 171 nss_issuer_spki.data = issuer_spki_data; 172 nss_issuer_spki.len = issuer_spki_len; 173 CERTSubjectPublicKeyInfo* spki = 174 SECKEY_DecodeDERSubjectPublicKeyInfo(&nss_issuer_spki); 175 ::LocalFree(issuer_spki_data); 176 if (!spki) { 177 SetLastError(static_cast<DWORD>(NTE_BAD_ALGID)); 178 return FALSE; 179 } 180 181 // Attempt to actually verify the signed data. If it fails, synthesize the 182 // failure as a generic "bad signature" and let CryptoAPI handle the rest. 183 SECStatus rv = CERT_VerifySignedDataWithPublicKeyInfo( 184 &signed_data, spki, NULL); 185 SECKEY_DestroySubjectPublicKeyInfo(spki); 186 if (rv != SECSuccess) { 187 SetLastError(static_cast<DWORD>(NTE_BAD_SIGNATURE)); 188 return FALSE; 189 } 190 return TRUE; 191 } 192 193 } // namespace sha256_interception 194 195 } // namespace net