Upstream version 10.38.220.0
[platform/framework/web/crosswalk.git] / src / net / cert / sha256_legacy_support_win.cc
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