OLD | NEW |
| (Empty) |
1 // Copyright 2003-2010 Google Inc. | |
2 // | |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 // you may not use this file except in compliance with the License. | |
5 // You may obtain a copy of the License at | |
6 // | |
7 // http://www.apache.org/licenses/LICENSE-2.0 | |
8 // | |
9 // Unless required by applicable law or agreed to in writing, software | |
10 // distributed under the License is distributed on an "AS IS" BASIS, | |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 // See the License for the specific language governing permissions and | |
13 // limitations under the License. | |
14 // ======================================================================== | |
15 // | |
16 // signatures.cpp | |
17 // | |
18 // Classes and functions related to crypto-hashes of buffers and digital | |
19 // signatures of buffers. | |
20 | |
21 #include "omaha/base/signatures.h" | |
22 #include <wincrypt.h> | |
23 #include <memory.h> | |
24 #pragma warning(disable : 4245) | |
25 // C4245 : conversion from 'type1' to 'type2', signed/unsigned mismatch | |
26 #include <atlenc.h> | |
27 #pragma warning(default : 4245) | |
28 #include <vector> | |
29 #include "base/scoped_ptr.h" | |
30 #include "omaha/base/const_utils.h" | |
31 #include "omaha/base/debug.h" | |
32 #include "omaha/base/error.h" | |
33 #include "omaha/base/logging.h" | |
34 #include "omaha/base/scoped_any.h" | |
35 #include "omaha/base/string.h" | |
36 #include "omaha/base/utils.h" | |
37 | |
38 namespace omaha { | |
39 | |
40 const ALG_ID kHashAlgorithm = CALG_SHA1; | |
41 const DWORD kEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; | |
42 const DWORD kProviderType = PROV_RSA_FULL; | |
43 const DWORD kCertificateNameType = CERT_NAME_SIMPLE_DISPLAY_TYPE; | |
44 const DWORD kKeyPairType = AT_SIGNATURE; | |
45 | |
46 // Maximum file size allowed for performing authentication. | |
47 const int kMaxFileSizeForAuthentication = 512 * 1024 * 1024; // 512MB | |
48 | |
49 // Buffer size used to read files from disk. | |
50 const int kFileReadBufferSize = 128 * 1024; | |
51 | |
52 namespace CryptDetails { | |
53 | |
54 // Useful scoped pointers for working with CryptoAPI objects | |
55 | |
56 void crypt_release_context(HCRYPTPROV provider) { | |
57 UTIL_LOG(L3, (L"Releasing HCRYPTPROV 0x%08lx", provider)); | |
58 BOOL b = ::CryptReleaseContext(provider, 0 /*flags*/); | |
59 ASSERT(b, (L"")); | |
60 } | |
61 | |
62 void crypt_close_store(HCERTSTORE store) { | |
63 UTIL_LOG(L3, (L"Releasing HCERTSTORE 0x%08lx", store)); | |
64 BOOL b = ::CertCloseStore(store, 0 /*flags*/); | |
65 ASSERT(b, (L"")); | |
66 ASSERT(::GetLastError() != CRYPT_E_PENDING_CLOSE, (L"")); | |
67 } | |
68 | |
69 void crypt_free_certificate(PCCERT_CONTEXT certificate) { | |
70 UTIL_LOG(L3, (L"Releasing PCCERT_CONTEXT 0x%08lx", certificate)); | |
71 BOOL b = ::CertFreeCertificateContext(certificate); | |
72 ASSERT(b, (L"")); | |
73 } | |
74 | |
75 void crypt_destroy_key(HCRYPTKEY key) { | |
76 UTIL_LOG(L3, (L"Releasing HCRYPTKEY 0x%08lx", key)); | |
77 BOOL b = ::CryptDestroyKey(key); | |
78 ASSERT(b, (L"")); | |
79 } | |
80 | |
81 void crypt_destroy_hash(HCRYPTHASH hash) { | |
82 UTIL_LOG(L3, (L"Releasing HCRYPTHASH 0x%08lx", hash)); | |
83 BOOL b = ::CryptDestroyHash(hash); | |
84 ASSERT(b, (L"")); | |
85 } | |
86 | |
87 typedef close_fun<void (*)(HCRYPTHASH), | |
88 crypt_destroy_hash> smart_destroy_hash; | |
89 typedef scoped_any<HCRYPTHASH, smart_destroy_hash, null_t> scoped_crypt_hash; | |
90 } | |
91 | |
92 // Base64 encode/decode functions are part of ATL Server | |
93 HRESULT Base64::Encode(const std::vector<byte>& buffer_in, | |
94 std::vector<byte>* encoded, | |
95 bool break_into_lines) { | |
96 ASSERT(encoded, (L"")); | |
97 | |
98 if (buffer_in.empty()) { | |
99 encoded->resize(0); | |
100 return S_OK; | |
101 } | |
102 | |
103 int32 encoded_len = | |
104 Base64EncodeGetRequiredLength( | |
105 buffer_in.size(), | |
106 break_into_lines ? ATL_BASE64_FLAG_NONE : ATL_BASE64_FLAG_NOCRLF); | |
107 ASSERT(encoded_len > 0, (L"")); | |
108 | |
109 encoded->resize(encoded_len); | |
110 int32 str_out_len = encoded_len; | |
111 | |
112 BOOL result = Base64Encode( | |
113 &buffer_in.front(), | |
114 buffer_in.size(), | |
115 reinterpret_cast<char*>(&encoded->front()), | |
116 &str_out_len, | |
117 break_into_lines ? ATL_BASE64_FLAG_NONE : ATL_BASE64_FLAG_NOCRLF); | |
118 if (!result) | |
119 return E_FAIL; | |
120 ASSERT(str_out_len <= encoded_len, (L"")); | |
121 if (str_out_len < encoded_len) | |
122 encoded->resize(str_out_len); | |
123 | |
124 return S_OK; | |
125 } | |
126 | |
127 HRESULT Base64::Encode(const std::vector<byte>& buffer_in, | |
128 CStringA* encoded, | |
129 bool break_into_lines) { | |
130 ASSERT(encoded, (L"")); | |
131 | |
132 if (buffer_in.empty()) { | |
133 return S_OK; | |
134 } | |
135 | |
136 std::vector<byte> buffer_out; | |
137 RET_IF_FAILED(Encode(buffer_in, &buffer_out, break_into_lines)); | |
138 encoded->Append(reinterpret_cast<const char*>(&buffer_out.front()), | |
139 buffer_out.size()); | |
140 | |
141 return S_OK; | |
142 } | |
143 | |
144 HRESULT Base64::Encode(const std::vector<byte>& buffer_in, | |
145 CString* encoded, | |
146 bool break_into_lines) { | |
147 ASSERT(encoded, (L"")); | |
148 | |
149 CStringA string_out; | |
150 RET_IF_FAILED(Encode(buffer_in, &string_out, break_into_lines)); | |
151 *encoded = string_out; | |
152 | |
153 return S_OK; | |
154 } | |
155 | |
156 HRESULT Base64::Decode(const std::vector<byte>& encoded, | |
157 std::vector<byte>* buffer_out) { | |
158 ASSERT(buffer_out, (L"")); | |
159 | |
160 size_t encoded_len = encoded.size(); | |
161 int32 required_len = Base64DecodeGetRequiredLength(encoded_len); | |
162 | |
163 buffer_out->resize(required_len); | |
164 | |
165 if (required_len == 0) { | |
166 return S_OK; | |
167 } | |
168 | |
169 int32 bytes_written = required_len; | |
170 BOOL result = Base64Decode(reinterpret_cast<const char*>(&encoded.front()), | |
171 encoded_len, | |
172 &buffer_out->front(), | |
173 &bytes_written); | |
174 if (!result) | |
175 return E_FAIL; | |
176 ASSERT(bytes_written <= required_len, (L"")); | |
177 if (bytes_written < required_len) { | |
178 buffer_out->resize(bytes_written); | |
179 } | |
180 | |
181 return S_OK; | |
182 } | |
183 | |
184 HRESULT Base64::Decode(const CStringA& encoded, std::vector<byte>* buffer_out) { | |
185 ASSERT(buffer_out, (L"")); | |
186 | |
187 size_t encoded_len = encoded.GetLength(); | |
188 std::vector<byte> buffer_in(encoded_len); | |
189 if (encoded_len != 0) { | |
190 ::memcpy(&buffer_in.front(), encoded.GetString(), encoded_len); | |
191 } | |
192 | |
193 return Decode(buffer_in, buffer_out); | |
194 } | |
195 | |
196 // Base64 in a CString -> binary | |
197 HRESULT Base64::Decode(const CString& encoded, std::vector<byte>* buffer_out) { | |
198 ASSERT(buffer_out, (L"")); | |
199 | |
200 CW2A encoded_a(encoded.GetString()); | |
201 | |
202 size_t encoded_len = ::strlen(encoded_a); | |
203 std::vector<byte> buffer_in(encoded_len); | |
204 if (encoded_len != 0) { | |
205 ::memcpy(&buffer_in.front(), encoded_a, encoded_len); | |
206 } | |
207 | |
208 return Decode(buffer_in, buffer_out); | |
209 } | |
210 | |
211 CryptoHash::CryptoHash() { | |
212 } | |
213 | |
214 CryptoHash::~CryptoHash() { | |
215 } | |
216 | |
217 HRESULT CryptoHash::Compute(const TCHAR* filepath, | |
218 uint64 max_len, | |
219 std::vector<byte>* hash_out) { | |
220 ASSERT1(filepath); | |
221 ASSERT1(hash_out); | |
222 | |
223 std::vector<CString> filepaths; | |
224 filepaths.push_back(filepath); | |
225 return Compute(filepaths, max_len, hash_out); | |
226 } | |
227 | |
228 HRESULT CryptoHash::Compute(const std::vector<CString>& filepaths, | |
229 uint64 max_len, | |
230 std::vector<byte>* hash_out) { | |
231 ASSERT1(filepaths.size() > 0); | |
232 ASSERT1(hash_out); | |
233 | |
234 return ComputeOrValidate(filepaths, max_len, NULL, hash_out); | |
235 } | |
236 | |
237 HRESULT CryptoHash::Compute(const std::vector<byte>& buffer_in, | |
238 std::vector<byte>* hash_out) { | |
239 ASSERT1(buffer_in.size() > 0); | |
240 ASSERT1(hash_out); | |
241 | |
242 return ComputeOrValidate(buffer_in, NULL, hash_out); | |
243 } | |
244 | |
245 HRESULT CryptoHash::Validate(const TCHAR* filepath, | |
246 uint64 max_len, | |
247 const std::vector<byte>& hash_in) { | |
248 ASSERT1(filepath); | |
249 ASSERT1(hash_in.size() == kHashSize); | |
250 | |
251 std::vector<CString> filepaths; | |
252 filepaths.push_back(filepath); | |
253 return Validate(filepaths, max_len, hash_in); | |
254 } | |
255 | |
256 HRESULT CryptoHash::Validate(const std::vector<CString>& filepaths, | |
257 uint64 max_len, | |
258 const std::vector<byte>& hash_in) { | |
259 ASSERT1(hash_in.size() == kHashSize); | |
260 | |
261 return ComputeOrValidate(filepaths, max_len, &hash_in, NULL); | |
262 } | |
263 | |
264 | |
265 HRESULT CryptoHash::Validate(const std::vector<byte>& buffer_in, | |
266 const std::vector<byte>& hash_in) { | |
267 ASSERT1(buffer_in.size() > 0); | |
268 ASSERT1(hash_in.size() == kHashSize); | |
269 | |
270 return ComputeOrValidate(buffer_in, &hash_in, NULL); | |
271 } | |
272 | |
273 HRESULT CryptoHash::ComputeOrValidate(const std::vector<CString>& filepaths, | |
274 uint64 max_len, | |
275 const std::vector<byte>* hash_in, | |
276 std::vector<byte>* hash_out) { | |
277 ASSERT1(filepaths.size() > 0); | |
278 ASSERT1(hash_in && !hash_out || !hash_in && hash_out); | |
279 UTIL_LOG(L1, (_T("[CryptoHash::ComputeOrValidate]"))); | |
280 | |
281 std::vector<byte> buf(kFileReadBufferSize); | |
282 uint64 curr_len = 0; | |
283 | |
284 CryptDetails::scoped_crypt_context scoped_csp_handle; | |
285 if (0 == ::CryptAcquireContext(address(scoped_csp_handle), | |
286 NULL, | |
287 NULL, // Use OS-default CSP. | |
288 kProviderType, | |
289 CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { | |
290 HRESULT hr = HRESULTFromLastError(); | |
291 UTIL_LOG(LE, (_T("[CryptAcquireContext failed][0x%08lX]"), hr)); | |
292 return hr; | |
293 } | |
294 | |
295 CryptDetails::scoped_crypt_hash scoped_hash_handle; | |
296 if (0 == ::CryptCreateHash(get(scoped_csp_handle), | |
297 kHashAlgorithm, | |
298 NULL, | |
299 0, | |
300 address(scoped_hash_handle))) { | |
301 HRESULT hr = HRESULTFromLastError(); | |
302 UTIL_LOG(LE, (_T("[CryptCreateHash failed][0x%08lX]"), hr)); | |
303 return hr; | |
304 } | |
305 | |
306 for (size_t i = 0; i < filepaths.size(); ++i) { | |
307 scoped_hfile file_handle(::CreateFile(filepaths[i], | |
308 FILE_READ_DATA, | |
309 FILE_SHARE_READ, | |
310 NULL, | |
311 OPEN_EXISTING, | |
312 FILE_ATTRIBUTE_NORMAL, | |
313 NULL)); | |
314 if (!file_handle) { | |
315 return HRESULTFromLastError(); | |
316 } | |
317 | |
318 if (max_len) { | |
319 LARGE_INTEGER file_size = {0}; | |
320 if (!::GetFileSizeEx(get(file_handle), &file_size)) { | |
321 return HRESULTFromLastError(); | |
322 } | |
323 curr_len += file_size.QuadPart; | |
324 if (curr_len > max_len) { | |
325 UTIL_LOG(LE, (_T("[exceed max len][curr_len=%lu][max_len=%lu]"), | |
326 curr_len, max_len)); | |
327 return E_FAIL; | |
328 } | |
329 } | |
330 | |
331 DWORD bytes_read = 0; | |
332 do { | |
333 if (!::ReadFile(get(file_handle), | |
334 &buf[0], | |
335 buf.size(), | |
336 &bytes_read, | |
337 NULL)) { | |
338 return HRESULTFromLastError(); | |
339 } | |
340 | |
341 if (bytes_read > 0) { | |
342 if (0 == ::CryptHashData(get(scoped_hash_handle), | |
343 &buf[0], | |
344 bytes_read, | |
345 0)) { | |
346 HRESULT hr = HRESULTFromLastError(); | |
347 UTIL_LOG(LE, (_T("[CryptHashData failed][0x%08lX]"), hr)); | |
348 return hr; | |
349 } | |
350 } | |
351 } while (bytes_read == buf.size()); | |
352 } | |
353 | |
354 DWORD digest_size = kHashSize; | |
355 byte digest_data[kHashSize] = {}; | |
356 if (0 == ::CryptGetHashParam(get(scoped_hash_handle), | |
357 HP_HASHVAL, | |
358 digest_data, | |
359 &digest_size, | |
360 0)) { | |
361 HRESULT hr = HRESULTFromLastError(); | |
362 UTIL_LOG(LE, (_T("[CryptGetHashParam failed][0x%08lX]"), hr)); | |
363 return hr; | |
364 } | |
365 if (digest_size != kHashSize) { | |
366 UTIL_LOG(LE, (_T("[CryptGetHashParam returned %d bytes]"), digest_size)); | |
367 return E_UNEXPECTED; | |
368 } | |
369 | |
370 if (hash_in) { | |
371 int res = ::memcmp(&hash_in->front(), digest_data, kHashSize); | |
372 if (res == 0) { | |
373 return S_OK; | |
374 } | |
375 | |
376 std::vector<byte> calculated_hash(kHashSize); | |
377 ::memcpy(&calculated_hash.front(), digest_data, kHashSize); | |
378 CStringA base64_encoded_hash; | |
379 Base64::Encode(calculated_hash, &base64_encoded_hash, false); | |
380 CString hash = AnsiToWideString(base64_encoded_hash, | |
381 base64_encoded_hash.GetLength()); | |
382 REPORT_LOG(L1, (_T("[actual hash=%s]"), hash)); | |
383 return SIGS_E_INVALID_SIGNATURE; | |
384 } else { | |
385 hash_out->resize(kHashSize); | |
386 ::memcpy(&hash_out->front(), digest_data, kHashSize); | |
387 return S_OK; | |
388 } | |
389 } | |
390 | |
391 HRESULT CryptoHash::ComputeOrValidate(const std::vector<byte>& buffer_in, | |
392 const std::vector<byte>* hash_in, | |
393 std::vector<byte>* hash_out) { | |
394 ASSERT1(hash_in && !hash_out || !hash_in && hash_out); | |
395 UTIL_LOG(L1, (_T("[CryptoHash::ComputeOrValidate]"))); | |
396 | |
397 CryptDetails::scoped_crypt_context scoped_csp_handle; | |
398 if (0 == ::CryptAcquireContext(address(scoped_csp_handle), | |
399 NULL, | |
400 NULL, // Use OS-default CSP. | |
401 kProviderType, | |
402 CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { | |
403 HRESULT hr = HRESULTFromLastError(); | |
404 UTIL_LOG(LE, (_T("[CryptAcquireContext failed][0x%08lX]"), hr)); | |
405 return hr; | |
406 } | |
407 | |
408 CryptDetails::scoped_crypt_hash scoped_hash_handle; | |
409 if (0 == ::CryptCreateHash(get(scoped_csp_handle), | |
410 kHashAlgorithm, | |
411 NULL, | |
412 0, | |
413 address(scoped_hash_handle))) { | |
414 HRESULT hr = HRESULTFromLastError(); | |
415 UTIL_LOG(LE, (_T("[CryptCreateHash failed][0x%08lX]"), hr)); | |
416 return hr; | |
417 } | |
418 | |
419 if (!buffer_in.empty()) { | |
420 if (0 == ::CryptHashData(get(scoped_hash_handle), | |
421 &buffer_in.front(), | |
422 buffer_in.size(), | |
423 0)) { | |
424 HRESULT hr = HRESULTFromLastError(); | |
425 UTIL_LOG(LE, (_T("[CryptHashData failed][0x%08lX]"), hr)); | |
426 return hr; | |
427 } | |
428 } | |
429 | |
430 DWORD digest_size = kHashSize; | |
431 byte digest_data[kHashSize] = {}; | |
432 if (0 == ::CryptGetHashParam(get(scoped_hash_handle), | |
433 HP_HASHVAL, | |
434 digest_data, | |
435 &digest_size, | |
436 0)) { | |
437 HRESULT hr = HRESULTFromLastError(); | |
438 UTIL_LOG(LE, (_T("[CryptGetHashParam failed][0x%08lX]"), hr)); | |
439 return hr; | |
440 } | |
441 if (digest_size != kHashSize) { | |
442 UTIL_LOG(LE, (_T("[CryptGetHashParam returned %d bytes]"), digest_size)); | |
443 return E_UNEXPECTED; | |
444 } | |
445 | |
446 if (hash_in) { | |
447 int res = ::memcmp(&hash_in->front(), digest_data, kHashSize); | |
448 return (res == 0) ? S_OK : SIGS_E_INVALID_SIGNATURE; | |
449 } else { | |
450 hash_out->resize(kHashSize); | |
451 ::memcpy(&hash_out->front(), digest_data, kHashSize); | |
452 return S_OK; | |
453 } | |
454 } | |
455 | |
456 // To sign data you need a CSP with the proper private key installed. | |
457 // To get a signing certificate you start with a PFX file. This file | |
458 // encodes a "certificate store" which can hold more than one | |
459 // certificate. (In general it can hold a certificate chain, but we | |
460 // only use the signing certificate.) There are special APIs to verify | |
461 // the format of a PFX file and read it into a new certificate store. A | |
462 // password must be specified to read the PFX file as it is encrypted. | |
463 // The password was set when the PFX file was exported or otherwise | |
464 // created. Then you search for the proper certificate in the store | |
465 // (using the subject_name which tells who the certificate was issued | |
466 // to). Finally, to get a CSP with the certificate's private key | |
467 // available there is a special API, CryptAcquireCertificatePrivateKey, | |
468 // that takes a CSP and a certificate and makes the private key of the | |
469 // certificate the private key of the CSP. | |
470 | |
471 CryptoSigningCertificate::CryptoSigningCertificate() : key_spec_(0) { | |
472 } | |
473 | |
474 CryptoSigningCertificate::~CryptoSigningCertificate() { | |
475 } | |
476 | |
477 HRESULT CryptoSigningCertificate::ImportCertificate( | |
478 const TCHAR * filepath, | |
479 const TCHAR * password, | |
480 const TCHAR * subject_name) { | |
481 ASSERT(filepath, (L"")); | |
482 ASSERT(password, (L"")); | |
483 | |
484 std::vector<byte> buffer; | |
485 HRESULT hr = ReadEntireFile(filepath, kMaxCertificateSize, &buffer); | |
486 if (FAILED(hr)) { | |
487 UTIL_LOG(LE, (L"[CryptoSigningCertificate::ImportCertificate]" | |
488 L"['%s' not read, hr 0x%08lx]", filepath, hr)); | |
489 return hr; | |
490 } | |
491 return ImportCertificate(buffer, password, subject_name); | |
492 } | |
493 | |
494 HRESULT CryptoSigningCertificate::ImportCertificate( | |
495 const std::vector<byte>& certificate_in, | |
496 const TCHAR * password, | |
497 const TCHAR * subject_name) { | |
498 ASSERT(password, (L"")); | |
499 ASSERT1(!certificate_in.empty()); | |
500 | |
501 UTIL_LOG(L2, (L"[CryptoSigningCertificate::ImportCertificate]" | |
502 L"[%d bytes, subject_name '%s']", | |
503 certificate_in.size(), subject_name ? subject_name : L"")); | |
504 | |
505 // CryptoAPI treats the certificate as a "blob" | |
506 CRYPT_DATA_BLOB blob; | |
507 blob.cbData = certificate_in.size(); | |
508 blob.pbData = const_cast<BYTE*>(&certificate_in.front()); | |
509 | |
510 // Ensure that it is PFX formatted | |
511 BOOL b = ::PFXIsPFXBlob(&blob); | |
512 if (!b) { | |
513 ASSERT(0, (L"Invalid PFX certificate, err 0x%08lx", ::GetLastError())); | |
514 return SIGS_E_INVALID_PFX_CERTIFICATE; | |
515 } | |
516 | |
517 // Make sure the password checks out | |
518 b = ::PFXVerifyPassword(&blob, password, 0 /* flags */); | |
519 if (!b) { | |
520 UTIL_LOG(LE, (L"[CryptoSigningCertificate::ImportCertificate]" | |
521 L"[invalid password, err 0x%08lx]", ::GetLastError())); | |
522 return SIGS_E_INVALID_PASSWORD; | |
523 } | |
524 | |
525 // Do the import from the certificate to a new certificate store | |
526 // TODO(omaha): Check that this is in fact a new certificate store, not an | |
527 // existing one. If it is an existing one we'll need to delete the | |
528 // certificate later. | |
529 // The last parameter to ::PFXImportCertStore() is 0, indicating that we want | |
530 // the CSP to be "silent"; i.e., not prompt. | |
531 reset(store_, ::PFXImportCertStore(&blob, password, 0)); | |
532 if (!store_) { | |
533 DWORD err = ::GetLastError(); | |
534 ASSERT(0, (L"Failed to import PFX certificate into a certificate store, " | |
535 L"err 0x%08lx", err)); | |
536 return HRESULT_FROM_WIN32(err); | |
537 } | |
538 UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]" | |
539 L"[new store 0x%08lx]", get(store_))); | |
540 | |
541 // Now that we have a store, look for the correct certificate. (There may | |
542 // have been more than one in the PFX file, e.g., a certificate chain.) | |
543 PCCERT_CONTEXT certificate_context = NULL; | |
544 while ((certificate_context = | |
545 ::CertEnumCertificatesInStore(get(store_), | |
546 certificate_context)) != NULL) { | |
547 // Have a certificate, does it look like the right one? Check the name | |
548 DWORD name_len = ::CertGetNameString(certificate_context, | |
549 kCertificateNameType, | |
550 0 /*flags*/, | |
551 NULL, | |
552 NULL, | |
553 0); | |
554 if (name_len <= 1) { | |
555 // Name attribute not found - should never happen | |
556 ASSERT(0, (L"CryptoSigningCertificate::ImportCertificate failed to get " | |
557 L"certificate name length, err 0x%08lx", ::GetLastError())); | |
558 continue; | |
559 } | |
560 // name_len includes the terminating null | |
561 | |
562 std::vector<TCHAR> name; | |
563 name.resize(name_len); | |
564 ASSERT1(!name.empty()); | |
565 DWORD name_len2 = ::CertGetNameString(certificate_context, | |
566 kCertificateNameType, | |
567 0, | |
568 NULL, | |
569 &name.front(), | |
570 name_len); | |
571 ASSERT(name_len2 == name_len, (L"")); | |
572 | |
573 UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]" | |
574 L"[found '%s' in store]", &name.front())); | |
575 | |
576 // Check the name if the user so desires. (If subject_name == NULL then | |
577 // the first certificate found is used.) | |
578 if (subject_name && (0 != String_StrNCmp(&name.front(), | |
579 subject_name, | |
580 ::lstrlen(subject_name), | |
581 false))) { | |
582 // name mismatch | |
583 UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]" | |
584 L"[not the right certificate, we're looking for '%s']", | |
585 subject_name)); | |
586 continue; | |
587 } | |
588 | |
589 // This is the right certificate | |
590 subject_name_ = &name.front(); | |
591 reset(certificate_, certificate_context); | |
592 UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]" | |
593 L"[new certificate 0x%08lx]", get(certificate_))); | |
594 break; | |
595 } | |
596 | |
597 return S_OK; | |
598 } | |
599 | |
600 HRESULT CryptoSigningCertificate::GetCSPContext(HCRYPTPROV* csp_context) { | |
601 ASSERT(csp_context, (L"")); | |
602 ASSERT(get(certificate_), (L"")); | |
603 | |
604 // CSP may have already been used - reset it | |
605 reset(csp_); | |
606 | |
607 // Create a CSP context using the private key of the certificate we imported | |
608 // earlier. | |
609 HCRYPTPROV csp = NULL; | |
610 BOOL must_free_csp = FALSE; | |
611 BOOL b = ::CryptAcquireCertificatePrivateKey(get(certificate_), | |
612 0 /*flags*/, | |
613 0 /*reserved*/, | |
614 &csp, | |
615 &key_spec_, | |
616 &must_free_csp); | |
617 if (!b) { | |
618 DWORD err = ::GetLastError(); | |
619 ASSERT(0, (L"CryptoSigningCertificate::GetCSPContext " | |
620 L"CryptAcquireCertificatePrivateKey failed, err 0x%08lx", err)); | |
621 return HRESULT_FROM_WIN32(err); | |
622 } | |
623 | |
624 // (Funky API returns a boolean which tells you whether it is your | |
625 // responsibility to delete the CSP context or not.) | |
626 if (must_free_csp) { | |
627 reset(csp_, csp); | |
628 } | |
629 if (get(csp_)) { | |
630 UTIL_LOG(L3, (L"[CryptoSigningCertificate::GetCSPContext new CSP 0x%08lx]", | |
631 get(csp_))); | |
632 } | |
633 | |
634 ASSERT(key_spec_ == AT_SIGNATURE || key_spec_ == AT_KEYEXCHANGE, (L"")); | |
635 if (key_spec_ != kKeyPairType) { | |
636 UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]" | |
637 L"[requires a AT_SIGNATURE type key]")); | |
638 return SIGS_E_INVALID_KEY_TYPE; | |
639 } | |
640 | |
641 #ifdef _DEBUG | |
642 // Which CSP did we get? | |
643 char csp_name[256] = {0}; | |
644 DWORD csp_name_len = arraysize(csp_name); | |
645 b = ::CryptGetProvParam(csp, | |
646 PP_NAME, | |
647 reinterpret_cast<BYTE*>(&csp_name[0]), | |
648 &csp_name_len, | |
649 0 /*flags*/); | |
650 if (!b) { | |
651 DWORD err = ::GetLastError(); | |
652 UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]" | |
653 L"[error getting CSP name, err 0x%08lx]", err)); | |
654 } | |
655 DWORD csp_prov_type; | |
656 DWORD csp_prov_type_len = sizeof(csp_prov_type); | |
657 b = ::CryptGetProvParam(csp, | |
658 PP_PROVTYPE, | |
659 reinterpret_cast<BYTE*>(&csp_prov_type), | |
660 &csp_prov_type_len, | |
661 0 /*flags*/); | |
662 if (!b) { | |
663 DWORD err = ::GetLastError(); | |
664 UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]" | |
665 L"[error getting CSP provtype, err 0x%08lx]", err)); | |
666 } | |
667 char csp_container[256] = {0}; | |
668 DWORD csp_container_len = arraysize(csp_container); | |
669 b = ::CryptGetProvParam(csp, | |
670 PP_CONTAINER, | |
671 reinterpret_cast<BYTE*>(&csp_container[0]), | |
672 &csp_container_len, | |
673 0 /*flags*/); | |
674 if (!b) { | |
675 DWORD err = ::GetLastError(); | |
676 UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]" | |
677 L"[error getting CSP current container name, err 0x%08lx]", | |
678 err)); | |
679 } | |
680 UTIL_LOG(L2, (L"[CryptoSigningCertificate::GetCSPContext]" | |
681 L"[have CSP '%S' (provtype %d) key container '%S']", | |
682 csp_name, csp_prov_type, csp_container)); | |
683 // End of which CSP did we get | |
684 #endif | |
685 | |
686 *csp_context = csp; | |
687 | |
688 UTIL_LOG(L2, (L"[CryptoSigningCertificate::GetCSPContext]" | |
689 L"[getting CSP with private key from certificate]" | |
690 L"[HCRYPTPROV 0x%08lx]", csp)); | |
691 | |
692 return S_OK; | |
693 } | |
694 | |
695 // To sign some data using CryptoAPI you first hash it into a hash | |
696 // object, then sign it using the CSP. The CSP needs to have the | |
697 // private key, of type AT_SIGNATURE, in it already, as it isn't a | |
698 // parameter of the CryptSignHash API. The CryptoSigningCertificate | |
699 // can provide such a CSP. | |
700 | |
701 CryptoComputeSignature::CryptoComputeSignature( | |
702 CryptoSigningCertificate* certificate) | |
703 : certificate_(certificate) { | |
704 } | |
705 | |
706 CryptoComputeSignature::~CryptoComputeSignature() { | |
707 } | |
708 | |
709 HRESULT CryptoComputeSignature::Sign(TCHAR const * const filepath, | |
710 uint32 max_len, | |
711 std::vector<byte>* signature_out) { | |
712 ASSERT(filepath, (L"")); | |
713 std::vector<byte> buffer; | |
714 HRESULT hr = ReadEntireFile(filepath, max_len, &buffer); | |
715 if (FAILED(hr)) { | |
716 UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]" | |
717 L"['%s not read, hr 0x%08lx]", filepath, hr)); | |
718 return hr; | |
719 } | |
720 return Sign(buffer, signature_out); | |
721 } | |
722 | |
723 HRESULT CryptoComputeSignature::Sign(const std::vector<byte>& buffer_in, | |
724 std::vector<byte>* signature_out) { | |
725 ASSERT(signature_out, (L"")); | |
726 ASSERT1(!buffer_in.empty()); | |
727 | |
728 UTIL_LOG(L2, (L"[CryptoComputeSignature::Sign]" | |
729 L"[buffer of %d bytes]", buffer_in.size())); | |
730 | |
731 // Get the proper CSP with the private key (certificate retains ownership) | |
732 HCRYPTPROV csp = NULL; | |
733 HRESULT hr = certificate_->GetCSPContext(&csp); | |
734 ASSERT(SUCCEEDED(hr) && csp, (L"")); | |
735 | |
736 // Hash the data | |
737 CryptDetails::scoped_crypt_hash hash; | |
738 BOOL b = ::CryptCreateHash(csp, kHashAlgorithm, 0, 0, address(hash)); | |
739 if (!b) { | |
740 // hash is now invalid, but might not be NULL, so stomp on it | |
741 DWORD err = ::GetLastError(); | |
742 ASSERT(!hash, (L"")); | |
743 UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]" | |
744 L"[could not create hash, err 0x%08lx]", err)); | |
745 return HRESULT_FROM_WIN32(err); | |
746 } | |
747 UTIL_LOG(L3, (L"CryptoComputeSignature::Sign new hash 0x%08lx", get(hash))); | |
748 | |
749 b = ::CryptHashData(get(hash), &buffer_in.front(), buffer_in.size(), 0); | |
750 if (!b) { | |
751 DWORD err = ::GetLastError(); | |
752 UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]" | |
753 L"[could not hash data, err 0x%08lx]", err)); | |
754 return HRESULT_FROM_WIN32(err); | |
755 } | |
756 | |
757 // Sign the hash (first get length, then allocate buffer and do real signing) | |
758 DWORD signature_len = 0; | |
759 b = ::CryptSignHash(get(hash), | |
760 kKeyPairType, | |
761 NULL, | |
762 0 /*flags*/, | |
763 NULL, | |
764 &signature_len); | |
765 if (!b && ::GetLastError() != ERROR_MORE_DATA) { | |
766 DWORD err = ::GetLastError(); | |
767 UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]" | |
768 L"[could not compute size of signature, err 0x%08lx]", err)); | |
769 return HRESULT_FROM_WIN32(err); | |
770 } | |
771 signature_out->resize(signature_len); | |
772 b = ::CryptSignHash(get(hash), | |
773 kKeyPairType, | |
774 NULL, | |
775 0, | |
776 &signature_out->front(), | |
777 &signature_len); | |
778 if (!b) { | |
779 DWORD err = ::GetLastError(); | |
780 UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]" | |
781 L"[could not compute signature, err 0x%08lx]", err)); | |
782 return HRESULT_FROM_WIN32(err); | |
783 } | |
784 ASSERT(signature_len == signature_out->size(), (L"")); | |
785 | |
786 UTIL_LOG(L3, (L"[CryptoComputeSignature::Sign]" | |
787 L"[have %d byte signature]", signature_out->size())); | |
788 | |
789 return S_OK; | |
790 } | |
791 | |
792 // To verify signed data you need a CSP, and you also need the public | |
793 // key extracted from a certificate. The CSP can be any RSA CSP on the | |
794 // machine, the default one is fine. To get the public key you start | |
795 // by importing a certificate in standard "DER encoded" format. That | |
796 // returns a giant data structure, one field of which is the public key | |
797 // in a format that CryptoAPI understands. You import this public key | |
798 // into the CSP with the CryptImportPublicKey() API, and then create a | |
799 // key object from it suitable for use with the verification API. | |
800 | |
801 CryptoSignatureVerificationCertificate::CryptoSignatureVerificationCertificate()
{ // NOLINT | |
802 } | |
803 | |
804 CryptoSignatureVerificationCertificate::~CryptoSignatureVerificationCertificate(
) { // NOLINT | |
805 } | |
806 | |
807 HRESULT CryptoSignatureVerificationCertificate::ImportCertificate( | |
808 const TCHAR * filepath, | |
809 const TCHAR * subject_name) { | |
810 ASSERT(filepath, (L"")); | |
811 std::vector<byte> buffer; | |
812 HRESULT hr = ReadEntireFile(filepath, kMaxCertificateSize, &buffer); | |
813 if (FAILED(hr)) { | |
814 UTIL_LOG(LE, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]" | |
815 L"['%s' not read, hr 0x%08lx]", filepath, hr)); | |
816 return hr; | |
817 } | |
818 return ImportCertificate(buffer, subject_name); | |
819 } | |
820 | |
821 HRESULT CryptoSignatureVerificationCertificate::ImportCertificate( | |
822 const std::vector<byte>& certificate_in, | |
823 const TCHAR * subject_name) { | |
824 // Import the certificate | |
825 ASSERT1(!certificate_in.empty()); | |
826 reset(certificate_, ::CertCreateCertificateContext(kEncodingType, | |
827 &certificate_in.front(), | |
828 certificate_in.size())); | |
829 if (!certificate_) { | |
830 DWORD err = ::GetLastError(); | |
831 UTIL_LOG(LE, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]" | |
832 L"[could not import certificate, err 0x%08lx]", err)); | |
833 return SIGS_E_INVALID_DER_CERTIFICATE; | |
834 } | |
835 UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]" | |
836 L"[new certificate 0x%08lx]", get(certificate_))); | |
837 | |
838 // Get certificate's subject name | |
839 DWORD name_len = ::CertGetNameString(get(certificate_), | |
840 kCertificateNameType, | |
841 0 /*flags*/, | |
842 NULL, | |
843 NULL, | |
844 0); | |
845 if (name_len <= 1) { | |
846 // Name attribute not found - should never happen | |
847 ASSERT(0, (L"CryptoSignatureVerificationCertificate failed to get " | |
848 L"certificate name length, err 0x%08lx", ::GetLastError())); | |
849 return E_FAIL; | |
850 } | |
851 // name_len includes the terminating NULL | |
852 | |
853 std::vector <TCHAR> name; | |
854 name.resize(name_len); | |
855 ASSERT1(!name.empty()); | |
856 DWORD name_len2 = ::CertGetNameString(get(certificate_), | |
857 kCertificateNameType, | |
858 0, | |
859 NULL, | |
860 &name.front(), | |
861 name_len); | |
862 ASSERT(name_len2 == name_len, (L"")); | |
863 | |
864 UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]" | |
865 L"['%s' is subject of certificate]", &name.front())); | |
866 | |
867 subject_name_ = &name.front(); | |
868 | |
869 // Check the name if the user so desires. | |
870 if (subject_name && (0 != String_StrNCmp(&name.front(), | |
871 subject_name, | |
872 ::lstrlen(subject_name), false))) { | |
873 // name mismatch | |
874 UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]" | |
875 L"[not the right certificate, we're looking for '%s']", | |
876 subject_name)); | |
877 return E_FAIL; | |
878 } | |
879 | |
880 return S_OK; | |
881 } | |
882 | |
883 HRESULT CryptoSignatureVerificationCertificate::GetCSPContextAndKey( | |
884 HCRYPTPROV* csp_context, | |
885 HCRYPTKEY* public_key) { | |
886 ASSERT(csp_context, (L"")); | |
887 ASSERT(public_key, (L"")); | |
888 ASSERT(get(certificate_), (L"")); | |
889 | |
890 // Get the public key out of the certificate | |
891 PCERT_INFO cert_info = get(certificate_)->pCertInfo; | |
892 ASSERT(cert_info, (L"")); | |
893 PCERT_PUBLIC_KEY_INFO public_key_info = &cert_info->SubjectPublicKeyInfo; | |
894 ASSERT(public_key_info, (L"")); | |
895 | |
896 // Reset the CSP and key in case it has been used already | |
897 reset(key_); | |
898 reset(csp_); | |
899 | |
900 // Get the default CSP. With CRYPT_VERIFYCONTEXT don't need to worry | |
901 // about creating/destroying a key container. | |
902 // TODO(omaha): Why wasn't PROV_RSA_SIG available? Maybe looking for the | |
903 // default isn't a good idea? | |
904 BOOL b = ::CryptAcquireContext(address(csp_), | |
905 NULL, | |
906 NULL, | |
907 kProviderType, | |
908 CRYPT_VERIFYCONTEXT|CRYPT_SILENT); | |
909 if (!b) { | |
910 DWORD err = ::GetLastError(); | |
911 UTIL_LOG(LE, (L"[GetCSPContextAndKey]" | |
912 L"[failed to acquire CSP, err 0x%08lx]", err)); | |
913 return HRESULT_FROM_WIN32(err); | |
914 } | |
915 UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::GetCSPContextAndKey]" | |
916 L"[new CSP 0x%08lx]", get(csp_))); | |
917 | |
918 // Convert the public key in encoded form into a CryptoAPI HCRYPTKEY | |
919 b = ::CryptImportPublicKeyInfo(get(csp_), | |
920 kEncodingType, | |
921 public_key_info, | |
922 address(key_)); | |
923 if (!b) { | |
924 DWORD err = ::GetLastError(); | |
925 UTIL_LOG(LE, (L"[GetCSPContextAndKey]" | |
926 L"[failed to import public key, err 0x%08lx]", err)); | |
927 return HRESULT_FROM_WIN32(err); | |
928 } | |
929 UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::GetCSPContextAndKey]" | |
930 L"[new key 0x%08lx]", get(key_))); | |
931 | |
932 *csp_context = get(csp_); | |
933 *public_key = get(key_); | |
934 | |
935 return S_OK; | |
936 } | |
937 | |
938 // To verify the signature of some data using CryptoAPI you first hash | |
939 // it into a hash object, then verify it using the CSP and a public key. | |
940 // In this case the CryptVerifySignature takes the key (of type | |
941 // AT_SIGNATURE) as a separate parameter. The | |
942 // CryptoSignatureVerificationCertificate can provide the proper CSP and | |
943 // the public key from the certificate. | |
944 | |
945 CryptoVerifySignature::CryptoVerifySignature( | |
946 CryptoSignatureVerificationCertificate& certificate) | |
947 : certificate_(&certificate) { | |
948 } | |
949 | |
950 CryptoVerifySignature::~CryptoVerifySignature() { | |
951 } | |
952 | |
953 HRESULT CryptoVerifySignature::Validate(const TCHAR* filepath, | |
954 uint32 max_len, | |
955 const std::vector<byte>& signature_in) { | |
956 ASSERT(filepath, (L"")); | |
957 std::vector<byte> buffer; | |
958 HRESULT hr = ReadEntireFile(filepath, max_len, &buffer); | |
959 if (FAILED(hr)) { | |
960 UTIL_LOG(LE, (L"[CryptoVerifySignature::Validate]" | |
961 L"['%s' not read, hr 0x%08lx]", filepath, hr)); | |
962 return hr; | |
963 } | |
964 return Validate(buffer, signature_in); | |
965 } | |
966 | |
967 HRESULT CryptoVerifySignature::Validate(const std::vector<byte>& buffer_in, | |
968 const std::vector<byte>& signature_in) { | |
969 ASSERT(certificate_, (L"")); | |
970 ASSERT1(!buffer_in.empty()); | |
971 ASSERT1(!signature_in.empty()); | |
972 | |
973 UTIL_LOG(L2, (L"[CryptoVerifySignature::Validate]" | |
974 L"[buffer of %d bytes, signature of %d bytes]", | |
975 buffer_in.size(), signature_in.size())); | |
976 | |
977 // Get the CSP context and the public key from the certificate | |
978 HCRYPTPROV csp = NULL; | |
979 HCRYPTKEY key = NULL; | |
980 HRESULT hr = certificate_->GetCSPContextAndKey(&csp, &key); | |
981 ASSERT(SUCCEEDED(hr) && csp && key, (L"")); | |
982 | |
983 // Hash the data | |
984 CryptDetails::scoped_crypt_hash hash; | |
985 BOOL b = ::CryptCreateHash(csp, kHashAlgorithm, 0, 0, address(hash)); | |
986 if (!b) { | |
987 // hash is now invalid, but might not be NULL, so stomp on it | |
988 DWORD err = ::GetLastError(); | |
989 ASSERT(!hash, (L"")); | |
990 UTIL_LOG(LE, (L"[CrypoVerifySignature::Validate]" | |
991 L"[could not create hash], err 0x%08lx", err)); | |
992 return HRESULT_FROM_WIN32(err); | |
993 } | |
994 UTIL_LOG(L3, (L"CryptoVerifySignature::Validate new hash 0x%08lx", hash)); | |
995 | |
996 b = ::CryptHashData(get(hash), | |
997 &buffer_in.front(), | |
998 buffer_in.size(), | |
999 0 /*flags*/); | |
1000 if (!b) { | |
1001 DWORD err = ::GetLastError(); | |
1002 UTIL_LOG(LE, (L"[CryptoVerifySignature::Validate]" | |
1003 L"[could not hash data, err 0x%08lx]", err)); | |
1004 return HRESULT_FROM_WIN32(err); | |
1005 } | |
1006 | |
1007 // Verify the hash | |
1008 b = ::CryptVerifySignature(get(hash), | |
1009 &signature_in.front(), | |
1010 signature_in.size(), | |
1011 key, | |
1012 NULL, | |
1013 0 /*flags*/); | |
1014 if (!b) { | |
1015 DWORD err = ::GetLastError(); | |
1016 #ifdef LOGGING | |
1017 CString encoded_signature; | |
1018 Base64::Encode(signature_in, &encoded_signature, false); | |
1019 | |
1020 UTIL_LOG(LE, (_T("CryptoVerifySignature::Validate could not ") | |
1021 _T("verify signature, err 0x%08lx with sig \"%s\""), | |
1022 err, encoded_signature)); | |
1023 #endif | |
1024 if (err == NTE_BAD_SIGNATURE) | |
1025 return SIGS_E_INVALID_SIGNATURE; | |
1026 else | |
1027 return HRESULT_FROM_WIN32(err); | |
1028 } | |
1029 | |
1030 return S_OK; | |
1031 } | |
1032 | |
1033 HRESULT SignData(const TCHAR* certificate_path, | |
1034 const TCHAR* certificate_password, | |
1035 const TCHAR* certificate_subject_name, | |
1036 const std::vector<byte>& data, | |
1037 CString* signature_base64) { | |
1038 ASSERT(certificate_path, (L"")); | |
1039 ASSERT(certificate_password, (L"")); | |
1040 // certificate_subject_name can be NULL | |
1041 ASSERT(signature_base64, (L"")); | |
1042 | |
1043 CryptoSigningCertificate certificate; | |
1044 RET_IF_FAILED(certificate.ImportCertificate(certificate_path, | |
1045 certificate_password, | |
1046 certificate_subject_name)); | |
1047 | |
1048 CryptoComputeSignature signer(&certificate); | |
1049 std::vector<byte> signature; | |
1050 RET_IF_FAILED(signer.Sign(data, &signature)); | |
1051 RET_IF_FAILED(Base64::Encode(signature, signature_base64, false)); | |
1052 | |
1053 return S_OK; | |
1054 } | |
1055 | |
1056 HRESULT VerifyData(const TCHAR* certificate_path, | |
1057 const TCHAR* certificate_subject_name, | |
1058 const std::vector<byte>& data, | |
1059 const TCHAR* signature_base64) { | |
1060 ASSERT(certificate_path, (L"")); | |
1061 // certificate_subject_name can be NULL | |
1062 ASSERT(signature_base64, (L"")); | |
1063 | |
1064 std::vector<byte> signature; | |
1065 RET_IF_FAILED(Base64::Decode(CString(signature_base64), &signature)); | |
1066 | |
1067 CryptoSignatureVerificationCertificate certificate; | |
1068 RET_IF_FAILED(certificate.ImportCertificate(certificate_path, | |
1069 certificate_subject_name)); | |
1070 | |
1071 CryptoVerifySignature verifier(certificate); | |
1072 RET_IF_FAILED(verifier.Validate(data, signature)); | |
1073 | |
1074 return S_OK; | |
1075 } | |
1076 | |
1077 HRESULT VerifyData(const std::vector<byte>& certificate_buffer, | |
1078 const TCHAR* certificate_subject_name, | |
1079 const std::vector<byte>& data, | |
1080 const TCHAR* signature_base64) { | |
1081 // certificate_subject_name can be NULL | |
1082 ASSERT(signature_base64, (L"")); | |
1083 | |
1084 std::vector<byte> signature; | |
1085 RET_IF_FAILED(Base64::Decode(CString(signature_base64), &signature)); | |
1086 | |
1087 CryptoSignatureVerificationCertificate certificate; | |
1088 RET_IF_FAILED(certificate.ImportCertificate(certificate_buffer, | |
1089 certificate_subject_name)); | |
1090 | |
1091 CryptoVerifySignature verifier(certificate); | |
1092 RET_IF_FAILED(verifier.Validate(data, signature)); | |
1093 | |
1094 return S_OK; | |
1095 } | |
1096 | |
1097 // TODO(omaha): function is missing the unit test. | |
1098 HRESULT AuthenticateFiles(const std::vector<CString>& files, | |
1099 const CString& hash) { | |
1100 ASSERT1(!files.empty()); | |
1101 | |
1102 std::vector<byte> hash_vector; | |
1103 RET_IF_FAILED(Base64::Decode(hash, &hash_vector)); | |
1104 if (hash_vector.size() != CryptoHash::kHashSize) { | |
1105 return E_INVALIDARG; | |
1106 } | |
1107 | |
1108 CryptoHash crypto; | |
1109 return crypto.Validate(files, kMaxFileSizeForAuthentication, hash_vector); | |
1110 } | |
1111 | |
1112 } // namespace omaha | |
1113 | |
OLD | NEW |