• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
3 // found in the LICENSE file.
4 
5 #include "crypto/signature_verifier.h"
6 
7 #include "base/logging.h"
8 
9 #pragma comment(lib, "crypt32.lib")
10 
11 namespace {
12 
13 // Wrappers of malloc and free for CRYPT_DECODE_PARA, which requires the
14 // WINAPI calling convention.
MyCryptAlloc(size_t size)15 void* WINAPI MyCryptAlloc(size_t size) {
16   return malloc(size);
17 }
18 
MyCryptFree(void * p)19 void WINAPI MyCryptFree(void* p) {
20   free(p);
21 }
22 
23 }  // namespace
24 
25 namespace crypto {
26 
SignatureVerifier()27 SignatureVerifier::SignatureVerifier() : hash_object_(0), public_key_(0) {
28   if (!CryptAcquireContext(provider_.receive(), NULL, NULL,
29                            PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
30     provider_.reset();
31 }
32 
~SignatureVerifier()33 SignatureVerifier::~SignatureVerifier() {
34 }
35 
VerifyInit(const uint8 * signature_algorithm,int signature_algorithm_len,const uint8 * signature,int signature_len,const uint8 * public_key_info,int public_key_info_len)36 bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
37                                    int signature_algorithm_len,
38                                    const uint8* signature,
39                                    int signature_len,
40                                    const uint8* public_key_info,
41                                    int public_key_info_len) {
42   signature_.reserve(signature_len);
43   // CryptoAPI uses big integers in the little-endian byte order, so we need
44   // to first swap the order of signature bytes.
45   for (int i = signature_len - 1; i >= 0; --i)
46     signature_.push_back(signature[i]);
47 
48   CRYPT_DECODE_PARA decode_para;
49   decode_para.cbSize = sizeof(decode_para);
50   decode_para.pfnAlloc = MyCryptAlloc;
51   decode_para.pfnFree = MyCryptFree;
52   CERT_PUBLIC_KEY_INFO* cert_public_key_info = NULL;
53   DWORD struct_len = 0;
54   BOOL ok;
55   ok = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
56                            X509_PUBLIC_KEY_INFO,
57                            public_key_info,
58                            public_key_info_len,
59                            CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
60                            &decode_para,
61                            &cert_public_key_info,
62                            &struct_len);
63   if (!ok)
64     return false;
65 
66   ok = CryptImportPublicKeyInfo(provider_,
67                                 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
68                                 cert_public_key_info, public_key_.receive());
69   free(cert_public_key_info);
70   if (!ok)
71     return false;
72 
73   CRYPT_ALGORITHM_IDENTIFIER* signature_algorithm_id;
74   struct_len = 0;
75   ok = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
76                            X509_ALGORITHM_IDENTIFIER,
77                            signature_algorithm,
78                            signature_algorithm_len,
79                            CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
80                            &decode_para,
81                            &signature_algorithm_id,
82                            &struct_len);
83   DCHECK(ok || GetLastError() == ERROR_FILE_NOT_FOUND);
84   ALG_ID hash_alg_id;
85   if (ok) {
86     hash_alg_id = CALG_MD4;  // Initialize to a weak hash algorithm that we
87                              // don't support.
88     if (!strcmp(signature_algorithm_id->pszObjId, szOID_RSA_SHA1RSA))
89       hash_alg_id = CALG_SHA1;
90     else if (!strcmp(signature_algorithm_id->pszObjId, szOID_RSA_MD5RSA))
91       hash_alg_id = CALG_MD5;
92     free(signature_algorithm_id);
93     DCHECK(hash_alg_id != CALG_MD4);
94     if (hash_alg_id == CALG_MD4)
95       return false;  // Unsupported hash algorithm.
96   } else if (GetLastError() == ERROR_FILE_NOT_FOUND) {
97     // TODO(wtc): X509_ALGORITHM_IDENTIFIER isn't supported on XP SP2.  We
98     // may be able to encapsulate signature_algorithm in a dummy SignedContent
99     // and decode it with X509_CERT into a CERT_SIGNED_CONTENT_INFO.  For now,
100     // just hardcode the hash algorithm to be SHA-1.
101     hash_alg_id = CALG_SHA1;
102   } else {
103     return false;
104   }
105 
106   ok = CryptCreateHash(provider_, hash_alg_id, 0, 0, hash_object_.receive());
107   if (!ok)
108     return false;
109   return true;
110 }
111 
VerifyUpdate(const uint8 * data_part,int data_part_len)112 void SignatureVerifier::VerifyUpdate(const uint8* data_part,
113                                      int data_part_len) {
114   BOOL ok = CryptHashData(hash_object_, data_part, data_part_len, 0);
115   DCHECK(ok) << "CryptHashData failed: " << GetLastError();
116 }
117 
VerifyFinal()118 bool SignatureVerifier::VerifyFinal() {
119   BOOL ok = CryptVerifySignature(hash_object_, &signature_[0],
120                                  signature_.size(), public_key_, NULL, 0);
121   Reset();
122   if (!ok)
123     return false;
124   return true;
125 }
126 
Reset()127 void SignatureVerifier::Reset() {
128   hash_object_.reset();
129   public_key_.reset();
130   signature_.clear();
131 }
132 
133 }  // namespace crypto
134 
135