summaryrefslogtreecommitdiffstats
path: root/chrome/browser/safe_browsing/signature_util_win.cc
blob: a96341d19f952c392dc41fc1c663f7b15c32495f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/safe_browsing/signature_util.h"

#include <windows.h>
#include <wincrypt.h>

#include "base/file_path.h"
#include "base/logging.h"
#include "base/scoped_ptr.h"
#include "crypto/scoped_capi_types.h"
#include "chrome/common/safe_browsing/csd.pb.h"

namespace safe_browsing {
namespace {
using crypto::ScopedCAPIHandle;
using crypto::CAPIDestroyer;
using crypto::CAPIDestroyerWithFlags;

// Free functor for scoped_ptr_malloc.
class FreeConstCertContext {
 public:
  void operator()(const CERT_CONTEXT* cert_context) const {
    CertFreeCertificateContext(cert_context);
  }
};

// Tries to extract the signing certificate from |file_path|.  On success,
// the |certificate_contents| field of |signature_info| is populated with the
// DER-encoded X.509 certificate.
void GetCertificateContents(
    const FilePath& file_path,
    ClientDownloadRequest_SignatureInfo* signature_info) {
  // Largely based on http://support.microsoft.com/kb/323809
  // Get message handle and store handle from the signed file.
  typedef CAPIDestroyer<HCRYPTMSG, CryptMsgClose> CryptMsgDestroyer;
  ScopedCAPIHandle<HCRYPTMSG, CryptMsgDestroyer> crypt_msg;
  typedef CAPIDestroyerWithFlags<
      HCERTSTORE, CertCloseStore, 0> CertStoreDestroyer;
  ScopedCAPIHandle<HCERTSTORE, CertStoreDestroyer> cert_store;

  VLOG(2) << "Looking for signature in: " << file_path.value();
  if (!CryptQueryObject(CERT_QUERY_OBJECT_FILE,
                        file_path.value().c_str(),
                        CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED,
                        CERT_QUERY_FORMAT_FLAG_BINARY,
                        0,      // flags
                        NULL,   // encoding
                        NULL,   // content type
                        NULL,   // format type
                        cert_store.receive(),
                        crypt_msg.receive(),
                        NULL)) {  // context
    VLOG(2) << "No signature found.";
    return;
  }

  // Get the signer information size.
  DWORD signer_info_size;
  if (!CryptMsgGetParam(crypt_msg.get(),
                        CMSG_SIGNER_INFO_PARAM,
                        0,  // index
                        NULL,  // no buffer when checking the size
                        &signer_info_size)) {
    VLOG(2) << "Failed to get signer info size";
    return;
  }

  // Get the signer information.
  scoped_array<BYTE> signer_info_buffer(new BYTE[signer_info_size]);
  CMSG_SIGNER_INFO* signer_info =
      reinterpret_cast<CMSG_SIGNER_INFO*>(signer_info_buffer.get());
  if (!CryptMsgGetParam(crypt_msg.get(),
                        CMSG_SIGNER_INFO_PARAM,
                        0,  // index
                        signer_info,
                        &signer_info_size)) {
    VLOG(2) << "Failed to get signer info";
    return;
  }

  // Search for the signer certificate in the temporary certificate store.
  CERT_INFO cert_info;
  cert_info.Issuer = signer_info->Issuer;
  cert_info.SerialNumber = signer_info->SerialNumber;

  scoped_ptr_malloc<const CERT_CONTEXT, FreeConstCertContext> cert_context(
      CertFindCertificateInStore(
          cert_store.get(),
          X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
          0, // flags
          CERT_FIND_SUBJECT_CERT,
          &cert_info,
          NULL));  // no previous context
  if (!cert_context.get()) {
    VLOG(2) << "Failed to get CERT_CONTEXT";
    return;
  }

  signature_info->set_certificate_contents(cert_context->pbCertEncoded,
                                           cert_context->cbCertEncoded);
  VLOG(2) << "Successfully extracted cert";
}
}  // namespace

SignatureUtil::SignatureUtil() {}

SignatureUtil::~SignatureUtil() {}

void SignatureUtil::CheckSignature(
    const FilePath& file_path,
    ClientDownloadRequest_SignatureInfo* signature_info) {
  GetCertificateContents(file_path, signature_info);
  // TODO(bryner): Populate is_trusted.
}

}  // namespace safe_browsing