Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / net / cert / x509_certificate_win.cc
1 // Copyright (c) 2012 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/x509_certificate.h"
6
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/pickle.h"
10 #include "base/sha1.h"
11 #include "base/strings/string_util.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "crypto/capi_util.h"
14 #include "crypto/scoped_capi_types.h"
15 #include "crypto/sha2.h"
16 #include "net/base/net_errors.h"
17
18 // Implement CalculateChainFingerprint() with our native crypto library.
19 #if defined(USE_OPENSSL)
20 #include <openssl/sha.h>
21 #else
22 #include <blapi.h>
23 #endif
24
25 #pragma comment(lib, "crypt32.lib")
26
27 using base::Time;
28
29 namespace net {
30
31 namespace {
32
33 typedef crypto::ScopedCAPIHandle<
34     HCERTSTORE,
35     crypto::CAPIDestroyerWithFlags<HCERTSTORE,
36                                    CertCloseStore, 0> > ScopedHCERTSTORE;
37
38 void ExplodedTimeToSystemTime(const base::Time::Exploded& exploded,
39                               SYSTEMTIME* system_time) {
40   system_time->wYear = exploded.year;
41   system_time->wMonth = exploded.month;
42   system_time->wDayOfWeek = exploded.day_of_week;
43   system_time->wDay = exploded.day_of_month;
44   system_time->wHour = exploded.hour;
45   system_time->wMinute = exploded.minute;
46   system_time->wSecond = exploded.second;
47   system_time->wMilliseconds = exploded.millisecond;
48 }
49
50 //-----------------------------------------------------------------------------
51
52 // Decodes the cert's subjectAltName extension into a CERT_ALT_NAME_INFO
53 // structure and stores it in *output.
54 void GetCertSubjectAltName(
55     PCCERT_CONTEXT cert,
56     scoped_ptr<CERT_ALT_NAME_INFO, base::FreeDeleter>* output) {
57   PCERT_EXTENSION extension = CertFindExtension(szOID_SUBJECT_ALT_NAME2,
58                                                 cert->pCertInfo->cExtension,
59                                                 cert->pCertInfo->rgExtension);
60   if (!extension)
61     return;
62
63   CRYPT_DECODE_PARA decode_para;
64   decode_para.cbSize = sizeof(decode_para);
65   decode_para.pfnAlloc = crypto::CryptAlloc;
66   decode_para.pfnFree = crypto::CryptFree;
67   CERT_ALT_NAME_INFO* alt_name_info = NULL;
68   DWORD alt_name_info_size = 0;
69   BOOL rv;
70   rv = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
71                            szOID_SUBJECT_ALT_NAME2,
72                            extension->Value.pbData,
73                            extension->Value.cbData,
74                            CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
75                            &decode_para,
76                            &alt_name_info,
77                            &alt_name_info_size);
78   if (rv)
79     output->reset(alt_name_info);
80 }
81
82 void AddCertsFromStore(HCERTSTORE store,
83                        X509Certificate::OSCertHandles* results) {
84   PCCERT_CONTEXT cert = NULL;
85
86   while ((cert = CertEnumCertificatesInStore(store, cert)) != NULL) {
87     PCCERT_CONTEXT to_add = NULL;
88     if (CertAddCertificateContextToStore(
89         NULL,  // The cert won't be persisted in any cert store. This breaks
90                // any association the context currently has to |store|, which
91                // allows us, the caller, to safely close |store| without
92                // releasing the cert handles.
93         cert,
94         CERT_STORE_ADD_USE_EXISTING,
95         &to_add) && to_add != NULL) {
96       // When processing stores generated from PKCS#7/PKCS#12 files, it
97       // appears that the order returned is the inverse of the order that it
98       // appeared in the file.
99       // TODO(rsleevi): Ensure this order is consistent across all Win
100       // versions
101       results->insert(results->begin(), to_add);
102     }
103   }
104 }
105
106 X509Certificate::OSCertHandles ParsePKCS7(const char* data, size_t length) {
107   X509Certificate::OSCertHandles results;
108   CERT_BLOB data_blob;
109   data_blob.cbData = length;
110   data_blob.pbData = reinterpret_cast<BYTE*>(const_cast<char*>(data));
111
112   HCERTSTORE out_store = NULL;
113
114   DWORD expected_types = CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED |
115                          CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED |
116                          CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED;
117
118   if (!CryptQueryObject(CERT_QUERY_OBJECT_BLOB, &data_blob, expected_types,
119                         CERT_QUERY_FORMAT_FLAG_BINARY, 0, NULL, NULL, NULL,
120                         &out_store, NULL, NULL) || out_store == NULL) {
121     return results;
122   }
123
124   AddCertsFromStore(out_store, &results);
125   CertCloseStore(out_store, CERT_CLOSE_STORE_CHECK_FLAG);
126
127   return results;
128 }
129
130 // Given a CERT_NAME_BLOB, returns true if it appears in a given list,
131 // formatted as a vector of strings holding DER-encoded X.509
132 // DistinguishedName entries.
133 bool IsCertNameBlobInIssuerList(
134     CERT_NAME_BLOB* name_blob,
135     const std::vector<std::string>& issuer_names) {
136   for (std::vector<std::string>::const_iterator it = issuer_names.begin();
137        it != issuer_names.end(); ++it) {
138     CERT_NAME_BLOB issuer_blob;
139     issuer_blob.pbData =
140         reinterpret_cast<BYTE*>(const_cast<char*>(it->data()));
141     issuer_blob.cbData = static_cast<DWORD>(it->length());
142
143     BOOL rb = CertCompareCertificateName(
144         X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, &issuer_blob, name_blob);
145     if (rb)
146       return true;
147   }
148   return false;
149 }
150
151 }  // namespace
152
153 void X509Certificate::Initialize() {
154   DCHECK(cert_handle_);
155   subject_.ParseDistinguishedName(cert_handle_->pCertInfo->Subject.pbData,
156                                   cert_handle_->pCertInfo->Subject.cbData);
157   issuer_.ParseDistinguishedName(cert_handle_->pCertInfo->Issuer.pbData,
158                                  cert_handle_->pCertInfo->Issuer.cbData);
159
160   valid_start_ = Time::FromFileTime(cert_handle_->pCertInfo->NotBefore);
161   valid_expiry_ = Time::FromFileTime(cert_handle_->pCertInfo->NotAfter);
162
163   fingerprint_ = CalculateFingerprint(cert_handle_);
164   ca_fingerprint_ = CalculateCAFingerprint(intermediate_ca_certs_);
165
166   const CRYPT_INTEGER_BLOB* serial = &cert_handle_->pCertInfo->SerialNumber;
167   scoped_ptr<uint8[]> serial_bytes(new uint8[serial->cbData]);
168   for (unsigned i = 0; i < serial->cbData; i++)
169     serial_bytes[i] = serial->pbData[serial->cbData - i - 1];
170   serial_number_ = std::string(
171       reinterpret_cast<char*>(serial_bytes.get()), serial->cbData);
172 }
173
174 void X509Certificate::GetSubjectAltName(
175     std::vector<std::string>* dns_names,
176     std::vector<std::string>* ip_addrs) const {
177   if (dns_names)
178     dns_names->clear();
179   if (ip_addrs)
180     ip_addrs->clear();
181
182   if (!cert_handle_)
183     return;
184
185   scoped_ptr<CERT_ALT_NAME_INFO, base::FreeDeleter> alt_name_info;
186   GetCertSubjectAltName(cert_handle_, &alt_name_info);
187   CERT_ALT_NAME_INFO* alt_name = alt_name_info.get();
188   if (alt_name) {
189     int num_entries = alt_name->cAltEntry;
190     for (int i = 0; i < num_entries; i++) {
191       // dNSName is an ASN.1 IA5String representing a string of ASCII
192       // characters, so we can use UTF16ToASCII here.
193       const CERT_ALT_NAME_ENTRY& entry = alt_name->rgAltEntry[i];
194
195       if (dns_names && entry.dwAltNameChoice == CERT_ALT_NAME_DNS_NAME) {
196         dns_names->push_back(base::UTF16ToASCII(entry.pwszDNSName));
197       } else if (ip_addrs &&
198                  entry.dwAltNameChoice == CERT_ALT_NAME_IP_ADDRESS) {
199         ip_addrs->push_back(std::string(
200             reinterpret_cast<const char*>(entry.IPAddress.pbData),
201             entry.IPAddress.cbData));
202       }
203     }
204   }
205 }
206
207 PCCERT_CONTEXT X509Certificate::CreateOSCertChainForCert() const {
208   // Create an in-memory certificate store to hold this certificate and
209   // any intermediate certificates in |intermediate_ca_certs_|. The store
210   // will be referenced in the returned PCCERT_CONTEXT, and will not be freed
211   // until the PCCERT_CONTEXT is freed.
212   ScopedHCERTSTORE store(CertOpenStore(
213       CERT_STORE_PROV_MEMORY, 0, NULL,
214       CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, NULL));
215   if (!store.get())
216     return NULL;
217
218   // NOTE: This preserves all of the properties of |os_cert_handle()| except
219   // for CERT_KEY_PROV_HANDLE_PROP_ID and CERT_KEY_CONTEXT_PROP_ID - the two
220   // properties that hold access to already-opened private keys. If a handle
221   // has already been unlocked (eg: PIN prompt), then the first time that the
222   // identity is used for client auth, it may prompt the user again.
223   PCCERT_CONTEXT primary_cert;
224   BOOL ok = CertAddCertificateContextToStore(store.get(), os_cert_handle(),
225                                              CERT_STORE_ADD_ALWAYS,
226                                              &primary_cert);
227   if (!ok || !primary_cert)
228     return NULL;
229
230   for (size_t i = 0; i < intermediate_ca_certs_.size(); ++i) {
231     CertAddCertificateContextToStore(store.get(), intermediate_ca_certs_[i],
232                                      CERT_STORE_ADD_ALWAYS, NULL);
233   }
234
235   // Note: |store| is explicitly not released, as the call to CertCloseStore()
236   // when |store| goes out of scope will not actually free the store. Instead,
237   // the store will be freed when |primary_cert| is freed.
238   return primary_cert;
239 }
240
241 // static
242 bool X509Certificate::GetDEREncoded(X509Certificate::OSCertHandle cert_handle,
243                                     std::string* encoded) {
244   if (!cert_handle || !cert_handle->pbCertEncoded ||
245       !cert_handle->cbCertEncoded) {
246     return false;
247   }
248   encoded->assign(reinterpret_cast<char*>(cert_handle->pbCertEncoded),
249                   cert_handle->cbCertEncoded);
250   return true;
251 }
252
253 // static
254 bool X509Certificate::IsSameOSCert(X509Certificate::OSCertHandle a,
255                                    X509Certificate::OSCertHandle b) {
256   DCHECK(a && b);
257   if (a == b)
258     return true;
259   return a->cbCertEncoded == b->cbCertEncoded &&
260       memcmp(a->pbCertEncoded, b->pbCertEncoded, a->cbCertEncoded) == 0;
261 }
262
263 // static
264 X509Certificate::OSCertHandle X509Certificate::CreateOSCertHandleFromBytes(
265     const char* data, int length) {
266   OSCertHandle cert_handle = NULL;
267   if (!CertAddEncodedCertificateToStore(
268       NULL, X509_ASN_ENCODING, reinterpret_cast<const BYTE*>(data),
269       length, CERT_STORE_ADD_USE_EXISTING, &cert_handle))
270     return NULL;
271
272   return cert_handle;
273 }
274
275 X509Certificate::OSCertHandles X509Certificate::CreateOSCertHandlesFromBytes(
276     const char* data, int length, Format format) {
277   OSCertHandles results;
278   switch (format) {
279     case FORMAT_SINGLE_CERTIFICATE: {
280       OSCertHandle handle = CreateOSCertHandleFromBytes(data, length);
281       if (handle != NULL)
282         results.push_back(handle);
283       break;
284     }
285     case FORMAT_PKCS7:
286       results = ParsePKCS7(data, length);
287       break;
288     default:
289       NOTREACHED() << "Certificate format " << format << " unimplemented";
290       break;
291   }
292
293   return results;
294 }
295
296 // static
297 X509Certificate::OSCertHandle X509Certificate::DupOSCertHandle(
298     OSCertHandle cert_handle) {
299   return CertDuplicateCertificateContext(cert_handle);
300 }
301
302 // static
303 void X509Certificate::FreeOSCertHandle(OSCertHandle cert_handle) {
304   CertFreeCertificateContext(cert_handle);
305 }
306
307 // static
308 SHA1HashValue X509Certificate::CalculateFingerprint(
309     OSCertHandle cert) {
310   DCHECK(NULL != cert->pbCertEncoded);
311   DCHECK_NE(static_cast<DWORD>(0), cert->cbCertEncoded);
312
313   BOOL rv;
314   SHA1HashValue sha1;
315   DWORD sha1_size = sizeof(sha1.data);
316   rv = CryptHashCertificate(NULL, CALG_SHA1, 0, cert->pbCertEncoded,
317                             cert->cbCertEncoded, sha1.data, &sha1_size);
318   DCHECK(rv && sha1_size == sizeof(sha1.data));
319   if (!rv)
320     memset(sha1.data, 0, sizeof(sha1.data));
321   return sha1;
322 }
323
324 // static
325 SHA256HashValue X509Certificate::CalculateFingerprint256(OSCertHandle cert) {
326   DCHECK(NULL != cert->pbCertEncoded);
327   DCHECK_NE(0u, cert->cbCertEncoded);
328
329   SHA256HashValue sha256;
330   size_t sha256_size = sizeof(sha256.data);
331
332   // Use crypto::SHA256HashString for two reasons:
333   // * < Windows Vista does not have universal SHA-256 support.
334   // * More efficient on Windows > Vista (less overhead since non-default CSP
335   // is not needed).
336   base::StringPiece der_cert(reinterpret_cast<const char*>(cert->pbCertEncoded),
337                              cert->cbCertEncoded);
338   crypto::SHA256HashString(der_cert, sha256.data, sha256_size);
339   return sha256;
340 }
341
342 SHA1HashValue X509Certificate::CalculateCAFingerprint(
343     const OSCertHandles& intermediates) {
344   SHA1HashValue sha1;
345   memset(sha1.data, 0, sizeof(sha1.data));
346
347 #if defined(USE_OPENSSL)
348   SHA_CTX ctx;
349   if (!SHA1_Init(&ctx))
350     return sha1;
351   for (size_t i = 0; i < intermediates.size(); ++i) {
352     PCCERT_CONTEXT ca_cert = intermediates[i];
353     if (!SHA1_Update(&ctx, ca_cert->pbCertEncoded, ca_cert->cbCertEncoded))
354       return sha1;
355   }
356   SHA1_Final(sha1.data, &ctx);
357 #else  // !USE_OPENSSL
358   SHA1Context* sha1_ctx = SHA1_NewContext();
359   if (!sha1_ctx)
360     return sha1;
361   SHA1_Begin(sha1_ctx);
362   for (size_t i = 0; i < intermediates.size(); ++i) {
363     PCCERT_CONTEXT ca_cert = intermediates[i];
364     SHA1_Update(sha1_ctx, ca_cert->pbCertEncoded, ca_cert->cbCertEncoded);
365   }
366   unsigned int result_len;
367   SHA1_End(sha1_ctx, sha1.data, &result_len, SHA1_LENGTH);
368   SHA1_DestroyContext(sha1_ctx, PR_TRUE);
369 #endif  // USE_OPENSSL
370
371   return sha1;
372 }
373
374 // static
375 X509Certificate::OSCertHandle
376 X509Certificate::ReadOSCertHandleFromPickle(PickleIterator* pickle_iter) {
377   const char* data;
378   int length;
379   if (!pickle_iter->ReadData(&data, &length))
380     return NULL;
381
382   // Legacy serialized certificates were serialized with extended attributes,
383   // rather than as DER only. As a result, these serialized certificates are
384   // not portable across platforms and may have side-effects on Windows due
385   // to extended attributes being serialized/deserialized -
386   // http://crbug.com/118706. To avoid deserializing these attributes, write
387   // the deserialized cert into a temporary cert store and then create a new
388   // cert from the DER - that is, without attributes.
389   ScopedHCERTSTORE store(
390       CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL));
391   if (!store.get())
392     return NULL;
393
394   OSCertHandle cert_handle = NULL;
395   if (!CertAddSerializedElementToStore(
396           store.get(), reinterpret_cast<const BYTE*>(data), length,
397           CERT_STORE_ADD_NEW, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG,
398           NULL, reinterpret_cast<const void **>(&cert_handle))) {
399     return NULL;
400   }
401
402   std::string encoded;
403   bool ok = GetDEREncoded(cert_handle, &encoded);
404   FreeOSCertHandle(cert_handle);
405   cert_handle = NULL;
406
407   if (ok)
408     cert_handle = CreateOSCertHandleFromBytes(encoded.data(), encoded.size());
409   return cert_handle;
410 }
411
412 // static
413 bool X509Certificate::WriteOSCertHandleToPickle(OSCertHandle cert_handle,
414                                                 Pickle* pickle) {
415   return pickle->WriteData(
416       reinterpret_cast<char*>(cert_handle->pbCertEncoded),
417       cert_handle->cbCertEncoded);
418 }
419
420 // static
421 void X509Certificate::GetPublicKeyInfo(OSCertHandle cert_handle,
422                                        size_t* size_bits,
423                                        PublicKeyType* type) {
424   *type = kPublicKeyTypeUnknown;
425   *size_bits = 0;
426
427   PCCRYPT_OID_INFO oid_info = CryptFindOIDInfo(
428       CRYPT_OID_INFO_OID_KEY,
429       cert_handle->pCertInfo->SubjectPublicKeyInfo.Algorithm.pszObjId,
430       CRYPT_PUBKEY_ALG_OID_GROUP_ID);
431   if (!oid_info)
432     return;
433
434   CHECK_EQ(oid_info->dwGroupId,
435            static_cast<DWORD>(CRYPT_PUBKEY_ALG_OID_GROUP_ID));
436
437   *size_bits = CertGetPublicKeyLength(
438       X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
439       &cert_handle->pCertInfo->SubjectPublicKeyInfo);
440
441   if (IS_SPECIAL_OID_INFO_ALGID(oid_info->Algid)) {
442     // For an EC public key, oid_info->Algid is CALG_OID_INFO_PARAMETERS
443     // (0xFFFFFFFE). Need to handle it as a special case.
444     if (strcmp(oid_info->pszOID, szOID_ECC_PUBLIC_KEY) == 0) {
445       *type = kPublicKeyTypeECDSA;
446     } else {
447       NOTREACHED();
448     }
449     return;
450   }
451   switch (oid_info->Algid) {
452     case CALG_RSA_SIGN:
453     case CALG_RSA_KEYX:
454       *type = kPublicKeyTypeRSA;
455       break;
456     case CALG_DSS_SIGN:
457       *type = kPublicKeyTypeDSA;
458       break;
459     case CALG_ECDSA:
460       *type = kPublicKeyTypeECDSA;
461       break;
462     case CALG_ECDH:
463       *type = kPublicKeyTypeECDH;
464       break;
465   }
466 }
467
468 bool X509Certificate::IsIssuedByEncoded(
469     const std::vector<std::string>& valid_issuers) {
470
471   // If the certificate's issuer in the list?
472   if (IsCertNameBlobInIssuerList(&cert_handle_->pCertInfo->Issuer,
473                                  valid_issuers)) {
474     return true;
475   }
476   // Otherwise, is any of the intermediate CA subjects in the list?
477   for (OSCertHandles::iterator it = intermediate_ca_certs_.begin();
478        it != intermediate_ca_certs_.end(); ++it) {
479     if (IsCertNameBlobInIssuerList(&(*it)->pCertInfo->Issuer,
480                                    valid_issuers)) {
481       return true;
482     }
483   }
484
485   return false;
486 }
487
488 // static
489 bool X509Certificate::IsSelfSigned(OSCertHandle cert_handle) {
490   return !!CryptVerifyCertificateSignatureEx(
491       NULL,
492       X509_ASN_ENCODING,
493       CRYPT_VERIFY_CERT_SIGN_SUBJECT_CERT,
494       reinterpret_cast<void*>(const_cast<PCERT_CONTEXT>(cert_handle)),
495       CRYPT_VERIFY_CERT_SIGN_ISSUER_CERT,
496       reinterpret_cast<void*>(const_cast<PCERT_CONTEXT>(cert_handle)),
497       0,
498       NULL);
499 }
500
501 }  // namespace net