Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(735)

Side by Side Diff: base/signatures.cc

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/signatures.h ('k') | base/signatures_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « base/signatures.h ('k') | base/signatures_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698