| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/safe_browsing/signature_util.h" | 5 #include "chrome/browser/safe_browsing/signature_util.h" |
| 6 | 6 |
| 7 #include <windows.h> | 7 #include <windows.h> |
| 8 #include <wincrypt.h> | 8 #include <wincrypt.h> |
| 9 |
| 9 #include "base/file_path.h" | 10 #include "base/file_path.h" |
| 11 #include "base/logging.h" |
| 12 #include "base/scoped_ptr.h" |
| 13 #include "crypto/scoped_capi_types.h" |
| 14 #include "chrome/common/safe_browsing/csd.pb.h" |
| 10 | 15 |
| 11 namespace safe_browsing { | 16 namespace safe_browsing { |
| 12 namespace signature_util { | 17 namespace { |
| 18 using crypto::ScopedCAPIHandle; |
| 19 using crypto::CAPIDestroyer; |
| 20 using crypto::CAPIDestroyerWithFlags; |
| 13 | 21 |
| 14 bool IsSigned(const FilePath& file_path) { | 22 // Free functor for scoped_ptr_malloc. |
| 23 class FreeConstCertContext { |
| 24 public: |
| 25 void operator()(const CERT_CONTEXT* cert_context) const { |
| 26 CertFreeCertificateContext(cert_context); |
| 27 } |
| 28 }; |
| 29 |
| 30 // Tries to extract the signing certificate from |file_path|. On success, |
| 31 // the |certificate_contents| field of |signature_info| is populated with the |
| 32 // DER-encoded X.509 certificate. |
| 33 void GetCertificateContents( |
| 34 const FilePath& file_path, |
| 35 ClientDownloadRequest_SignatureInfo* signature_info) { |
| 36 // Largely based on http://support.microsoft.com/kb/323809 |
| 15 // Get message handle and store handle from the signed file. | 37 // Get message handle and store handle from the signed file. |
| 16 BOOL result = CryptQueryObject(CERT_QUERY_OBJECT_FILE, | 38 typedef CAPIDestroyer<HCRYPTMSG, CryptMsgClose> CryptMsgDestroyer; |
| 17 file_path.value().c_str(), | 39 ScopedCAPIHandle<HCRYPTMSG, CryptMsgDestroyer> crypt_msg; |
| 18 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, | 40 typedef CAPIDestroyerWithFlags< |
| 19 CERT_QUERY_FORMAT_FLAG_BINARY, | 41 HCERTSTORE, CertCloseStore, 0> CertStoreDestroyer; |
| 20 0, // flags | 42 ScopedCAPIHandle<HCERTSTORE, CertStoreDestroyer> cert_store; |
| 21 NULL, // encoding | 43 |
| 22 NULL, // content type | 44 VLOG(2) << "Looking for signature in: " << file_path.value(); |
| 23 NULL, // format type | 45 if (!CryptQueryObject(CERT_QUERY_OBJECT_FILE, |
| 24 NULL, // HCERTSTORE | 46 file_path.value().c_str(), |
| 25 NULL, // HCRYPTMSG | 47 CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, |
| 26 NULL); // context | 48 CERT_QUERY_FORMAT_FLAG_BINARY, |
| 27 return result == TRUE; | 49 0, // flags |
| 50 NULL, // encoding |
| 51 NULL, // content type |
| 52 NULL, // format type |
| 53 cert_store.receive(), |
| 54 crypt_msg.receive(), |
| 55 NULL)) { // context |
| 56 VLOG(2) << "No signature found."; |
| 57 return; |
| 58 } |
| 59 |
| 60 // Get the signer information size. |
| 61 DWORD signer_info_size; |
| 62 if (!CryptMsgGetParam(crypt_msg.get(), |
| 63 CMSG_SIGNER_INFO_PARAM, |
| 64 0, // index |
| 65 NULL, // no buffer when checking the size |
| 66 &signer_info_size)) { |
| 67 VLOG(2) << "Failed to get signer info size"; |
| 68 return; |
| 69 } |
| 70 |
| 71 // Get the signer information. |
| 72 scoped_array<BYTE> signer_info_buffer(new BYTE[signer_info_size]); |
| 73 CMSG_SIGNER_INFO* signer_info = |
| 74 reinterpret_cast<CMSG_SIGNER_INFO*>(signer_info_buffer.get()); |
| 75 if (!CryptMsgGetParam(crypt_msg.get(), |
| 76 CMSG_SIGNER_INFO_PARAM, |
| 77 0, // index |
| 78 signer_info, |
| 79 &signer_info_size)) { |
| 80 VLOG(2) << "Failed to get signer info"; |
| 81 return; |
| 82 } |
| 83 |
| 84 // Search for the signer certificate in the temporary certificate store. |
| 85 CERT_INFO cert_info; |
| 86 cert_info.Issuer = signer_info->Issuer; |
| 87 cert_info.SerialNumber = signer_info->SerialNumber; |
| 88 |
| 89 scoped_ptr_malloc<const CERT_CONTEXT, FreeConstCertContext> cert_context( |
| 90 CertFindCertificateInStore( |
| 91 cert_store.get(), |
| 92 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, |
| 93 0, // flags |
| 94 CERT_FIND_SUBJECT_CERT, |
| 95 &cert_info, |
| 96 NULL)); // no previous context |
| 97 if (!cert_context.get()) { |
| 98 VLOG(2) << "Failed to get CERT_CONTEXT"; |
| 99 return; |
| 100 } |
| 101 |
| 102 signature_info->set_certificate_contents(cert_context->pbCertEncoded, |
| 103 cert_context->cbCertEncoded); |
| 104 VLOG(2) << "Successfully extracted cert"; |
| 105 } |
| 106 } // namespace |
| 107 |
| 108 SignatureUtil::SignatureUtil() {} |
| 109 |
| 110 SignatureUtil::~SignatureUtil() {} |
| 111 |
| 112 void SignatureUtil::CheckSignature( |
| 113 const FilePath& file_path, |
| 114 ClientDownloadRequest_SignatureInfo* signature_info) { |
| 115 GetCertificateContents(file_path, signature_info); |
| 116 // TODO(bryner): Populate is_trusted. |
| 28 } | 117 } |
| 29 | 118 |
| 30 } // namespace signature_util | |
| 31 } // namespace safe_browsing | 119 } // namespace safe_browsing |
| OLD | NEW |