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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/signatures.h ('k') | base/signatures_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/signatures.cc
diff --git a/base/signatures.cc b/base/signatures.cc
deleted file mode 100644
index 6d40f8606edbbc03443899449b4bea9851142a4e..0000000000000000000000000000000000000000
--- a/base/signatures.cc
+++ /dev/null
@@ -1,1113 +0,0 @@
-// Copyright 2003-2010 Google Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// ========================================================================
-//
-// signatures.cpp
-//
-// Classes and functions related to crypto-hashes of buffers and digital
-// signatures of buffers.
-
-#include "omaha/base/signatures.h"
-#include <wincrypt.h>
-#include <memory.h>
-#pragma warning(disable : 4245)
-// C4245 : conversion from 'type1' to 'type2', signed/unsigned mismatch
-#include <atlenc.h>
-#pragma warning(default : 4245)
-#include <vector>
-#include "base/scoped_ptr.h"
-#include "omaha/base/const_utils.h"
-#include "omaha/base/debug.h"
-#include "omaha/base/error.h"
-#include "omaha/base/logging.h"
-#include "omaha/base/scoped_any.h"
-#include "omaha/base/string.h"
-#include "omaha/base/utils.h"
-
-namespace omaha {
-
-const ALG_ID kHashAlgorithm = CALG_SHA1;
-const DWORD kEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
-const DWORD kProviderType = PROV_RSA_FULL;
-const DWORD kCertificateNameType = CERT_NAME_SIMPLE_DISPLAY_TYPE;
-const DWORD kKeyPairType = AT_SIGNATURE;
-
-// Maximum file size allowed for performing authentication.
-const int kMaxFileSizeForAuthentication = 512 * 1024 * 1024; // 512MB
-
-// Buffer size used to read files from disk.
-const int kFileReadBufferSize = 128 * 1024;
-
-namespace CryptDetails {
-
- // Useful scoped pointers for working with CryptoAPI objects
-
- void crypt_release_context(HCRYPTPROV provider) {
- UTIL_LOG(L3, (L"Releasing HCRYPTPROV 0x%08lx", provider));
- BOOL b = ::CryptReleaseContext(provider, 0 /*flags*/);
- ASSERT(b, (L""));
- }
-
- void crypt_close_store(HCERTSTORE store) {
- UTIL_LOG(L3, (L"Releasing HCERTSTORE 0x%08lx", store));
- BOOL b = ::CertCloseStore(store, 0 /*flags*/);
- ASSERT(b, (L""));
- ASSERT(::GetLastError() != CRYPT_E_PENDING_CLOSE, (L""));
- }
-
- void crypt_free_certificate(PCCERT_CONTEXT certificate) {
- UTIL_LOG(L3, (L"Releasing PCCERT_CONTEXT 0x%08lx", certificate));
- BOOL b = ::CertFreeCertificateContext(certificate);
- ASSERT(b, (L""));
- }
-
- void crypt_destroy_key(HCRYPTKEY key) {
- UTIL_LOG(L3, (L"Releasing HCRYPTKEY 0x%08lx", key));
- BOOL b = ::CryptDestroyKey(key);
- ASSERT(b, (L""));
- }
-
- void crypt_destroy_hash(HCRYPTHASH hash) {
- UTIL_LOG(L3, (L"Releasing HCRYPTHASH 0x%08lx", hash));
- BOOL b = ::CryptDestroyHash(hash);
- ASSERT(b, (L""));
- }
-
- typedef close_fun<void (*)(HCRYPTHASH),
- crypt_destroy_hash> smart_destroy_hash;
- typedef scoped_any<HCRYPTHASH, smart_destroy_hash, null_t> scoped_crypt_hash;
-}
-
-// Base64 encode/decode functions are part of ATL Server
-HRESULT Base64::Encode(const std::vector<byte>& buffer_in,
- std::vector<byte>* encoded,
- bool break_into_lines) {
- ASSERT(encoded, (L""));
-
- if (buffer_in.empty()) {
- encoded->resize(0);
- return S_OK;
- }
-
- int32 encoded_len =
- Base64EncodeGetRequiredLength(
- buffer_in.size(),
- break_into_lines ? ATL_BASE64_FLAG_NONE : ATL_BASE64_FLAG_NOCRLF);
- ASSERT(encoded_len > 0, (L""));
-
- encoded->resize(encoded_len);
- int32 str_out_len = encoded_len;
-
- BOOL result = Base64Encode(
- &buffer_in.front(),
- buffer_in.size(),
- reinterpret_cast<char*>(&encoded->front()),
- &str_out_len,
- break_into_lines ? ATL_BASE64_FLAG_NONE : ATL_BASE64_FLAG_NOCRLF);
- if (!result)
- return E_FAIL;
- ASSERT(str_out_len <= encoded_len, (L""));
- if (str_out_len < encoded_len)
- encoded->resize(str_out_len);
-
- return S_OK;
-}
-
-HRESULT Base64::Encode(const std::vector<byte>& buffer_in,
- CStringA* encoded,
- bool break_into_lines) {
- ASSERT(encoded, (L""));
-
- if (buffer_in.empty()) {
- return S_OK;
- }
-
- std::vector<byte> buffer_out;
- RET_IF_FAILED(Encode(buffer_in, &buffer_out, break_into_lines));
- encoded->Append(reinterpret_cast<const char*>(&buffer_out.front()),
- buffer_out.size());
-
- return S_OK;
-}
-
-HRESULT Base64::Encode(const std::vector<byte>& buffer_in,
- CString* encoded,
- bool break_into_lines) {
- ASSERT(encoded, (L""));
-
- CStringA string_out;
- RET_IF_FAILED(Encode(buffer_in, &string_out, break_into_lines));
- *encoded = string_out;
-
- return S_OK;
-}
-
-HRESULT Base64::Decode(const std::vector<byte>& encoded,
- std::vector<byte>* buffer_out) {
- ASSERT(buffer_out, (L""));
-
- size_t encoded_len = encoded.size();
- int32 required_len = Base64DecodeGetRequiredLength(encoded_len);
-
- buffer_out->resize(required_len);
-
- if (required_len == 0) {
- return S_OK;
- }
-
- int32 bytes_written = required_len;
- BOOL result = Base64Decode(reinterpret_cast<const char*>(&encoded.front()),
- encoded_len,
- &buffer_out->front(),
- &bytes_written);
- if (!result)
- return E_FAIL;
- ASSERT(bytes_written <= required_len, (L""));
- if (bytes_written < required_len) {
- buffer_out->resize(bytes_written);
- }
-
- return S_OK;
-}
-
-HRESULT Base64::Decode(const CStringA& encoded, std::vector<byte>* buffer_out) {
- ASSERT(buffer_out, (L""));
-
- size_t encoded_len = encoded.GetLength();
- std::vector<byte> buffer_in(encoded_len);
- if (encoded_len != 0) {
- ::memcpy(&buffer_in.front(), encoded.GetString(), encoded_len);
- }
-
- return Decode(buffer_in, buffer_out);
-}
-
-// Base64 in a CString -> binary
-HRESULT Base64::Decode(const CString& encoded, std::vector<byte>* buffer_out) {
- ASSERT(buffer_out, (L""));
-
- CW2A encoded_a(encoded.GetString());
-
- size_t encoded_len = ::strlen(encoded_a);
- std::vector<byte> buffer_in(encoded_len);
- if (encoded_len != 0) {
- ::memcpy(&buffer_in.front(), encoded_a, encoded_len);
- }
-
- return Decode(buffer_in, buffer_out);
-}
-
-CryptoHash::CryptoHash() {
-}
-
-CryptoHash::~CryptoHash() {
-}
-
-HRESULT CryptoHash::Compute(const TCHAR* filepath,
- uint64 max_len,
- std::vector<byte>* hash_out) {
- ASSERT1(filepath);
- ASSERT1(hash_out);
-
- std::vector<CString> filepaths;
- filepaths.push_back(filepath);
- return Compute(filepaths, max_len, hash_out);
-}
-
-HRESULT CryptoHash::Compute(const std::vector<CString>& filepaths,
- uint64 max_len,
- std::vector<byte>* hash_out) {
- ASSERT1(filepaths.size() > 0);
- ASSERT1(hash_out);
-
- return ComputeOrValidate(filepaths, max_len, NULL, hash_out);
-}
-
-HRESULT CryptoHash::Compute(const std::vector<byte>& buffer_in,
- std::vector<byte>* hash_out) {
- ASSERT1(buffer_in.size() > 0);
- ASSERT1(hash_out);
-
- return ComputeOrValidate(buffer_in, NULL, hash_out);
-}
-
-HRESULT CryptoHash::Validate(const TCHAR* filepath,
- uint64 max_len,
- const std::vector<byte>& hash_in) {
- ASSERT1(filepath);
- ASSERT1(hash_in.size() == kHashSize);
-
- std::vector<CString> filepaths;
- filepaths.push_back(filepath);
- return Validate(filepaths, max_len, hash_in);
-}
-
-HRESULT CryptoHash::Validate(const std::vector<CString>& filepaths,
- uint64 max_len,
- const std::vector<byte>& hash_in) {
- ASSERT1(hash_in.size() == kHashSize);
-
- return ComputeOrValidate(filepaths, max_len, &hash_in, NULL);
-}
-
-
-HRESULT CryptoHash::Validate(const std::vector<byte>& buffer_in,
- const std::vector<byte>& hash_in) {
- ASSERT1(buffer_in.size() > 0);
- ASSERT1(hash_in.size() == kHashSize);
-
- return ComputeOrValidate(buffer_in, &hash_in, NULL);
-}
-
-HRESULT CryptoHash::ComputeOrValidate(const std::vector<CString>& filepaths,
- uint64 max_len,
- const std::vector<byte>* hash_in,
- std::vector<byte>* hash_out) {
- ASSERT1(filepaths.size() > 0);
- ASSERT1(hash_in && !hash_out || !hash_in && hash_out);
- UTIL_LOG(L1, (_T("[CryptoHash::ComputeOrValidate]")));
-
- std::vector<byte> buf(kFileReadBufferSize);
- uint64 curr_len = 0;
-
- CryptDetails::scoped_crypt_context scoped_csp_handle;
- if (0 == ::CryptAcquireContext(address(scoped_csp_handle),
- NULL,
- NULL, // Use OS-default CSP.
- kProviderType,
- CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[CryptAcquireContext failed][0x%08lX]"), hr));
- return hr;
- }
-
- CryptDetails::scoped_crypt_hash scoped_hash_handle;
- if (0 == ::CryptCreateHash(get(scoped_csp_handle),
- kHashAlgorithm,
- NULL,
- 0,
- address(scoped_hash_handle))) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[CryptCreateHash failed][0x%08lX]"), hr));
- return hr;
- }
-
- for (size_t i = 0; i < filepaths.size(); ++i) {
- scoped_hfile file_handle(::CreateFile(filepaths[i],
- FILE_READ_DATA,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL));
- if (!file_handle) {
- return HRESULTFromLastError();
- }
-
- if (max_len) {
- LARGE_INTEGER file_size = {0};
- if (!::GetFileSizeEx(get(file_handle), &file_size)) {
- return HRESULTFromLastError();
- }
- curr_len += file_size.QuadPart;
- if (curr_len > max_len) {
- UTIL_LOG(LE, (_T("[exceed max len][curr_len=%lu][max_len=%lu]"),
- curr_len, max_len));
- return E_FAIL;
- }
- }
-
- DWORD bytes_read = 0;
- do {
- if (!::ReadFile(get(file_handle),
- &buf[0],
- buf.size(),
- &bytes_read,
- NULL)) {
- return HRESULTFromLastError();
- }
-
- if (bytes_read > 0) {
- if (0 == ::CryptHashData(get(scoped_hash_handle),
- &buf[0],
- bytes_read,
- 0)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[CryptHashData failed][0x%08lX]"), hr));
- return hr;
- }
- }
- } while (bytes_read == buf.size());
- }
-
- DWORD digest_size = kHashSize;
- byte digest_data[kHashSize] = {};
- if (0 == ::CryptGetHashParam(get(scoped_hash_handle),
- HP_HASHVAL,
- digest_data,
- &digest_size,
- 0)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[CryptGetHashParam failed][0x%08lX]"), hr));
- return hr;
- }
- if (digest_size != kHashSize) {
- UTIL_LOG(LE, (_T("[CryptGetHashParam returned %d bytes]"), digest_size));
- return E_UNEXPECTED;
- }
-
- if (hash_in) {
- int res = ::memcmp(&hash_in->front(), digest_data, kHashSize);
- if (res == 0) {
- return S_OK;
- }
-
- std::vector<byte> calculated_hash(kHashSize);
- ::memcpy(&calculated_hash.front(), digest_data, kHashSize);
- CStringA base64_encoded_hash;
- Base64::Encode(calculated_hash, &base64_encoded_hash, false);
- CString hash = AnsiToWideString(base64_encoded_hash,
- base64_encoded_hash.GetLength());
- REPORT_LOG(L1, (_T("[actual hash=%s]"), hash));
- return SIGS_E_INVALID_SIGNATURE;
- } else {
- hash_out->resize(kHashSize);
- ::memcpy(&hash_out->front(), digest_data, kHashSize);
- return S_OK;
- }
-}
-
-HRESULT CryptoHash::ComputeOrValidate(const std::vector<byte>& buffer_in,
- const std::vector<byte>* hash_in,
- std::vector<byte>* hash_out) {
- ASSERT1(hash_in && !hash_out || !hash_in && hash_out);
- UTIL_LOG(L1, (_T("[CryptoHash::ComputeOrValidate]")));
-
- CryptDetails::scoped_crypt_context scoped_csp_handle;
- if (0 == ::CryptAcquireContext(address(scoped_csp_handle),
- NULL,
- NULL, // Use OS-default CSP.
- kProviderType,
- CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[CryptAcquireContext failed][0x%08lX]"), hr));
- return hr;
- }
-
- CryptDetails::scoped_crypt_hash scoped_hash_handle;
- if (0 == ::CryptCreateHash(get(scoped_csp_handle),
- kHashAlgorithm,
- NULL,
- 0,
- address(scoped_hash_handle))) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[CryptCreateHash failed][0x%08lX]"), hr));
- return hr;
- }
-
- if (!buffer_in.empty()) {
- if (0 == ::CryptHashData(get(scoped_hash_handle),
- &buffer_in.front(),
- buffer_in.size(),
- 0)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[CryptHashData failed][0x%08lX]"), hr));
- return hr;
- }
- }
-
- DWORD digest_size = kHashSize;
- byte digest_data[kHashSize] = {};
- if (0 == ::CryptGetHashParam(get(scoped_hash_handle),
- HP_HASHVAL,
- digest_data,
- &digest_size,
- 0)) {
- HRESULT hr = HRESULTFromLastError();
- UTIL_LOG(LE, (_T("[CryptGetHashParam failed][0x%08lX]"), hr));
- return hr;
- }
- if (digest_size != kHashSize) {
- UTIL_LOG(LE, (_T("[CryptGetHashParam returned %d bytes]"), digest_size));
- return E_UNEXPECTED;
- }
-
- if (hash_in) {
- int res = ::memcmp(&hash_in->front(), digest_data, kHashSize);
- return (res == 0) ? S_OK : SIGS_E_INVALID_SIGNATURE;
- } else {
- hash_out->resize(kHashSize);
- ::memcpy(&hash_out->front(), digest_data, kHashSize);
- return S_OK;
- }
-}
-
-// To sign data you need a CSP with the proper private key installed.
-// To get a signing certificate you start with a PFX file. This file
-// encodes a "certificate store" which can hold more than one
-// certificate. (In general it can hold a certificate chain, but we
-// only use the signing certificate.) There are special APIs to verify
-// the format of a PFX file and read it into a new certificate store. A
-// password must be specified to read the PFX file as it is encrypted.
-// The password was set when the PFX file was exported or otherwise
-// created. Then you search for the proper certificate in the store
-// (using the subject_name which tells who the certificate was issued
-// to). Finally, to get a CSP with the certificate's private key
-// available there is a special API, CryptAcquireCertificatePrivateKey,
-// that takes a CSP and a certificate and makes the private key of the
-// certificate the private key of the CSP.
-
-CryptoSigningCertificate::CryptoSigningCertificate() : key_spec_(0) {
-}
-
-CryptoSigningCertificate::~CryptoSigningCertificate() {
-}
-
-HRESULT CryptoSigningCertificate::ImportCertificate(
- const TCHAR * filepath,
- const TCHAR * password,
- const TCHAR * subject_name) {
- ASSERT(filepath, (L""));
- ASSERT(password, (L""));
-
- std::vector<byte> buffer;
- HRESULT hr = ReadEntireFile(filepath, kMaxCertificateSize, &buffer);
- if (FAILED(hr)) {
- UTIL_LOG(LE, (L"[CryptoSigningCertificate::ImportCertificate]"
- L"['%s' not read, hr 0x%08lx]", filepath, hr));
- return hr;
- }
- return ImportCertificate(buffer, password, subject_name);
-}
-
-HRESULT CryptoSigningCertificate::ImportCertificate(
- const std::vector<byte>& certificate_in,
- const TCHAR * password,
- const TCHAR * subject_name) {
- ASSERT(password, (L""));
- ASSERT1(!certificate_in.empty());
-
- UTIL_LOG(L2, (L"[CryptoSigningCertificate::ImportCertificate]"
- L"[%d bytes, subject_name '%s']",
- certificate_in.size(), subject_name ? subject_name : L""));
-
- // CryptoAPI treats the certificate as a "blob"
- CRYPT_DATA_BLOB blob;
- blob.cbData = certificate_in.size();
- blob.pbData = const_cast<BYTE*>(&certificate_in.front());
-
- // Ensure that it is PFX formatted
- BOOL b = ::PFXIsPFXBlob(&blob);
- if (!b) {
- ASSERT(0, (L"Invalid PFX certificate, err 0x%08lx", ::GetLastError()));
- return SIGS_E_INVALID_PFX_CERTIFICATE;
- }
-
- // Make sure the password checks out
- b = ::PFXVerifyPassword(&blob, password, 0 /* flags */);
- if (!b) {
- UTIL_LOG(LE, (L"[CryptoSigningCertificate::ImportCertificate]"
- L"[invalid password, err 0x%08lx]", ::GetLastError()));
- return SIGS_E_INVALID_PASSWORD;
- }
-
- // Do the import from the certificate to a new certificate store
- // TODO(omaha): Check that this is in fact a new certificate store, not an
- // existing one. If it is an existing one we'll need to delete the
- // certificate later.
- // The last parameter to ::PFXImportCertStore() is 0, indicating that we want
- // the CSP to be "silent"; i.e., not prompt.
- reset(store_, ::PFXImportCertStore(&blob, password, 0));
- if (!store_) {
- DWORD err = ::GetLastError();
- ASSERT(0, (L"Failed to import PFX certificate into a certificate store, "
- L"err 0x%08lx", err));
- return HRESULT_FROM_WIN32(err);
- }
- UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]"
- L"[new store 0x%08lx]", get(store_)));
-
- // Now that we have a store, look for the correct certificate. (There may
- // have been more than one in the PFX file, e.g., a certificate chain.)
- PCCERT_CONTEXT certificate_context = NULL;
- while ((certificate_context =
- ::CertEnumCertificatesInStore(get(store_),
- certificate_context)) != NULL) {
- // Have a certificate, does it look like the right one? Check the name
- DWORD name_len = ::CertGetNameString(certificate_context,
- kCertificateNameType,
- 0 /*flags*/,
- NULL,
- NULL,
- 0);
- if (name_len <= 1) {
- // Name attribute not found - should never happen
- ASSERT(0, (L"CryptoSigningCertificate::ImportCertificate failed to get "
- L"certificate name length, err 0x%08lx", ::GetLastError()));
- continue;
- }
- // name_len includes the terminating null
-
- std::vector<TCHAR> name;
- name.resize(name_len);
- ASSERT1(!name.empty());
- DWORD name_len2 = ::CertGetNameString(certificate_context,
- kCertificateNameType,
- 0,
- NULL,
- &name.front(),
- name_len);
- ASSERT(name_len2 == name_len, (L""));
-
- UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]"
- L"[found '%s' in store]", &name.front()));
-
- // Check the name if the user so desires. (If subject_name == NULL then
- // the first certificate found is used.)
- if (subject_name && (0 != String_StrNCmp(&name.front(),
- subject_name,
- ::lstrlen(subject_name),
- false))) {
- // name mismatch
- UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]"
- L"[not the right certificate, we're looking for '%s']",
- subject_name));
- continue;
- }
-
- // This is the right certificate
- subject_name_ = &name.front();
- reset(certificate_, certificate_context);
- UTIL_LOG(L3, (L"[CryptoSigningCertificate::ImportCertificate]"
- L"[new certificate 0x%08lx]", get(certificate_)));
- break;
- }
-
- return S_OK;
-}
-
-HRESULT CryptoSigningCertificate::GetCSPContext(HCRYPTPROV* csp_context) {
- ASSERT(csp_context, (L""));
- ASSERT(get(certificate_), (L""));
-
- // CSP may have already been used - reset it
- reset(csp_);
-
- // Create a CSP context using the private key of the certificate we imported
- // earlier.
- HCRYPTPROV csp = NULL;
- BOOL must_free_csp = FALSE;
- BOOL b = ::CryptAcquireCertificatePrivateKey(get(certificate_),
- 0 /*flags*/,
- 0 /*reserved*/,
- &csp,
- &key_spec_,
- &must_free_csp);
- if (!b) {
- DWORD err = ::GetLastError();
- ASSERT(0, (L"CryptoSigningCertificate::GetCSPContext "
- L"CryptAcquireCertificatePrivateKey failed, err 0x%08lx", err));
- return HRESULT_FROM_WIN32(err);
- }
-
- // (Funky API returns a boolean which tells you whether it is your
- // responsibility to delete the CSP context or not.)
- if (must_free_csp) {
- reset(csp_, csp);
- }
- if (get(csp_)) {
- UTIL_LOG(L3, (L"[CryptoSigningCertificate::GetCSPContext new CSP 0x%08lx]",
- get(csp_)));
- }
-
- ASSERT(key_spec_ == AT_SIGNATURE || key_spec_ == AT_KEYEXCHANGE, (L""));
- if (key_spec_ != kKeyPairType) {
- UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]"
- L"[requires a AT_SIGNATURE type key]"));
- return SIGS_E_INVALID_KEY_TYPE;
- }
-
-#ifdef _DEBUG
- // Which CSP did we get?
- char csp_name[256] = {0};
- DWORD csp_name_len = arraysize(csp_name);
- b = ::CryptGetProvParam(csp,
- PP_NAME,
- reinterpret_cast<BYTE*>(&csp_name[0]),
- &csp_name_len,
- 0 /*flags*/);
- if (!b) {
- DWORD err = ::GetLastError();
- UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]"
- L"[error getting CSP name, err 0x%08lx]", err));
- }
- DWORD csp_prov_type;
- DWORD csp_prov_type_len = sizeof(csp_prov_type);
- b = ::CryptGetProvParam(csp,
- PP_PROVTYPE,
- reinterpret_cast<BYTE*>(&csp_prov_type),
- &csp_prov_type_len,
- 0 /*flags*/);
- if (!b) {
- DWORD err = ::GetLastError();
- UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]"
- L"[error getting CSP provtype, err 0x%08lx]", err));
- }
- char csp_container[256] = {0};
- DWORD csp_container_len = arraysize(csp_container);
- b = ::CryptGetProvParam(csp,
- PP_CONTAINER,
- reinterpret_cast<BYTE*>(&csp_container[0]),
- &csp_container_len,
- 0 /*flags*/);
- if (!b) {
- DWORD err = ::GetLastError();
- UTIL_LOG(LE, (L"[CryptoSigningCertificate::GetCSPContext]"
- L"[error getting CSP current container name, err 0x%08lx]",
- err));
- }
- UTIL_LOG(L2, (L"[CryptoSigningCertificate::GetCSPContext]"
- L"[have CSP '%S' (provtype %d) key container '%S']",
- csp_name, csp_prov_type, csp_container));
- // End of which CSP did we get
-#endif
-
- *csp_context = csp;
-
- UTIL_LOG(L2, (L"[CryptoSigningCertificate::GetCSPContext]"
- L"[getting CSP with private key from certificate]"
- L"[HCRYPTPROV 0x%08lx]", csp));
-
- return S_OK;
-}
-
-// To sign some data using CryptoAPI you first hash it into a hash
-// object, then sign it using the CSP. The CSP needs to have the
-// private key, of type AT_SIGNATURE, in it already, as it isn't a
-// parameter of the CryptSignHash API. The CryptoSigningCertificate
-// can provide such a CSP.
-
-CryptoComputeSignature::CryptoComputeSignature(
- CryptoSigningCertificate* certificate)
- : certificate_(certificate) {
-}
-
-CryptoComputeSignature::~CryptoComputeSignature() {
-}
-
-HRESULT CryptoComputeSignature::Sign(TCHAR const * const filepath,
- uint32 max_len,
- std::vector<byte>* signature_out) {
- ASSERT(filepath, (L""));
- std::vector<byte> buffer;
- HRESULT hr = ReadEntireFile(filepath, max_len, &buffer);
- if (FAILED(hr)) {
- UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"
- L"['%s not read, hr 0x%08lx]", filepath, hr));
- return hr;
- }
- return Sign(buffer, signature_out);
-}
-
-HRESULT CryptoComputeSignature::Sign(const std::vector<byte>& buffer_in,
- std::vector<byte>* signature_out) {
- ASSERT(signature_out, (L""));
- ASSERT1(!buffer_in.empty());
-
- UTIL_LOG(L2, (L"[CryptoComputeSignature::Sign]"
- L"[buffer of %d bytes]", buffer_in.size()));
-
- // Get the proper CSP with the private key (certificate retains ownership)
- HCRYPTPROV csp = NULL;
- HRESULT hr = certificate_->GetCSPContext(&csp);
- ASSERT(SUCCEEDED(hr) && csp, (L""));
-
- // Hash the data
- CryptDetails::scoped_crypt_hash hash;
- BOOL b = ::CryptCreateHash(csp, kHashAlgorithm, 0, 0, address(hash));
- if (!b) {
- // hash is now invalid, but might not be NULL, so stomp on it
- DWORD err = ::GetLastError();
- ASSERT(!hash, (L""));
- UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"
- L"[could not create hash, err 0x%08lx]", err));
- return HRESULT_FROM_WIN32(err);
- }
- UTIL_LOG(L3, (L"CryptoComputeSignature::Sign new hash 0x%08lx", get(hash)));
-
- b = ::CryptHashData(get(hash), &buffer_in.front(), buffer_in.size(), 0);
- if (!b) {
- DWORD err = ::GetLastError();
- UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"
- L"[could not hash data, err 0x%08lx]", err));
- return HRESULT_FROM_WIN32(err);
- }
-
- // Sign the hash (first get length, then allocate buffer and do real signing)
- DWORD signature_len = 0;
- b = ::CryptSignHash(get(hash),
- kKeyPairType,
- NULL,
- 0 /*flags*/,
- NULL,
- &signature_len);
- if (!b && ::GetLastError() != ERROR_MORE_DATA) {
- DWORD err = ::GetLastError();
- UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"
- L"[could not compute size of signature, err 0x%08lx]", err));
- return HRESULT_FROM_WIN32(err);
- }
- signature_out->resize(signature_len);
- b = ::CryptSignHash(get(hash),
- kKeyPairType,
- NULL,
- 0,
- &signature_out->front(),
- &signature_len);
- if (!b) {
- DWORD err = ::GetLastError();
- UTIL_LOG(LE, (L"[CryptoComputeSignature::Sign]"
- L"[could not compute signature, err 0x%08lx]", err));
- return HRESULT_FROM_WIN32(err);
- }
- ASSERT(signature_len == signature_out->size(), (L""));
-
- UTIL_LOG(L3, (L"[CryptoComputeSignature::Sign]"
- L"[have %d byte signature]", signature_out->size()));
-
- return S_OK;
-}
-
-// To verify signed data you need a CSP, and you also need the public
-// key extracted from a certificate. The CSP can be any RSA CSP on the
-// machine, the default one is fine. To get the public key you start
-// by importing a certificate in standard "DER encoded" format. That
-// returns a giant data structure, one field of which is the public key
-// in a format that CryptoAPI understands. You import this public key
-// into the CSP with the CryptImportPublicKey() API, and then create a
-// key object from it suitable for use with the verification API.
-
-CryptoSignatureVerificationCertificate::CryptoSignatureVerificationCertificate() { // NOLINT
-}
-
-CryptoSignatureVerificationCertificate::~CryptoSignatureVerificationCertificate() { // NOLINT
-}
-
-HRESULT CryptoSignatureVerificationCertificate::ImportCertificate(
- const TCHAR * filepath,
- const TCHAR * subject_name) {
- ASSERT(filepath, (L""));
- std::vector<byte> buffer;
- HRESULT hr = ReadEntireFile(filepath, kMaxCertificateSize, &buffer);
- if (FAILED(hr)) {
- UTIL_LOG(LE, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"
- L"['%s' not read, hr 0x%08lx]", filepath, hr));
- return hr;
- }
- return ImportCertificate(buffer, subject_name);
-}
-
-HRESULT CryptoSignatureVerificationCertificate::ImportCertificate(
- const std::vector<byte>& certificate_in,
- const TCHAR * subject_name) {
- // Import the certificate
- ASSERT1(!certificate_in.empty());
- reset(certificate_, ::CertCreateCertificateContext(kEncodingType,
- &certificate_in.front(),
- certificate_in.size()));
- if (!certificate_) {
- DWORD err = ::GetLastError();
- UTIL_LOG(LE, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"
- L"[could not import certificate, err 0x%08lx]", err));
- return SIGS_E_INVALID_DER_CERTIFICATE;
- }
- UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"
- L"[new certificate 0x%08lx]", get(certificate_)));
-
- // Get certificate's subject name
- DWORD name_len = ::CertGetNameString(get(certificate_),
- kCertificateNameType,
- 0 /*flags*/,
- NULL,
- NULL,
- 0);
- if (name_len <= 1) {
- // Name attribute not found - should never happen
- ASSERT(0, (L"CryptoSignatureVerificationCertificate failed to get "
- L"certificate name length, err 0x%08lx", ::GetLastError()));
- return E_FAIL;
- }
- // name_len includes the terminating NULL
-
- std::vector <TCHAR> name;
- name.resize(name_len);
- ASSERT1(!name.empty());
- DWORD name_len2 = ::CertGetNameString(get(certificate_),
- kCertificateNameType,
- 0,
- NULL,
- &name.front(),
- name_len);
- ASSERT(name_len2 == name_len, (L""));
-
- UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"
- L"['%s' is subject of certificate]", &name.front()));
-
- subject_name_ = &name.front();
-
- // Check the name if the user so desires.
- if (subject_name && (0 != String_StrNCmp(&name.front(),
- subject_name,
- ::lstrlen(subject_name), false))) {
- // name mismatch
- UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::ImportCertificate]"
- L"[not the right certificate, we're looking for '%s']",
- subject_name));
- return E_FAIL;
- }
-
- return S_OK;
-}
-
-HRESULT CryptoSignatureVerificationCertificate::GetCSPContextAndKey(
- HCRYPTPROV* csp_context,
- HCRYPTKEY* public_key) {
- ASSERT(csp_context, (L""));
- ASSERT(public_key, (L""));
- ASSERT(get(certificate_), (L""));
-
- // Get the public key out of the certificate
- PCERT_INFO cert_info = get(certificate_)->pCertInfo;
- ASSERT(cert_info, (L""));
- PCERT_PUBLIC_KEY_INFO public_key_info = &cert_info->SubjectPublicKeyInfo;
- ASSERT(public_key_info, (L""));
-
- // Reset the CSP and key in case it has been used already
- reset(key_);
- reset(csp_);
-
- // Get the default CSP. With CRYPT_VERIFYCONTEXT don't need to worry
- // about creating/destroying a key container.
- // TODO(omaha): Why wasn't PROV_RSA_SIG available? Maybe looking for the
- // default isn't a good idea?
- BOOL b = ::CryptAcquireContext(address(csp_),
- NULL,
- NULL,
- kProviderType,
- CRYPT_VERIFYCONTEXT|CRYPT_SILENT);
- if (!b) {
- DWORD err = ::GetLastError();
- UTIL_LOG(LE, (L"[GetCSPContextAndKey]"
- L"[failed to acquire CSP, err 0x%08lx]", err));
- return HRESULT_FROM_WIN32(err);
- }
- UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::GetCSPContextAndKey]"
- L"[new CSP 0x%08lx]", get(csp_)));
-
- // Convert the public key in encoded form into a CryptoAPI HCRYPTKEY
- b = ::CryptImportPublicKeyInfo(get(csp_),
- kEncodingType,
- public_key_info,
- address(key_));
- if (!b) {
- DWORD err = ::GetLastError();
- UTIL_LOG(LE, (L"[GetCSPContextAndKey]"
- L"[failed to import public key, err 0x%08lx]", err));
- return HRESULT_FROM_WIN32(err);
- }
- UTIL_LOG(L3, (L"[CryptoSignatureVerificationCertificate::GetCSPContextAndKey]"
- L"[new key 0x%08lx]", get(key_)));
-
- *csp_context = get(csp_);
- *public_key = get(key_);
-
- return S_OK;
-}
-
-// To verify the signature of some data using CryptoAPI you first hash
-// it into a hash object, then verify it using the CSP and a public key.
-// In this case the CryptVerifySignature takes the key (of type
-// AT_SIGNATURE) as a separate parameter. The
-// CryptoSignatureVerificationCertificate can provide the proper CSP and
-// the public key from the certificate.
-
-CryptoVerifySignature::CryptoVerifySignature(
- CryptoSignatureVerificationCertificate& certificate)
- : certificate_(&certificate) {
-}
-
-CryptoVerifySignature::~CryptoVerifySignature() {
-}
-
-HRESULT CryptoVerifySignature::Validate(const TCHAR* filepath,
- uint32 max_len,
- const std::vector<byte>& signature_in) {
- ASSERT(filepath, (L""));
- std::vector<byte> buffer;
- HRESULT hr = ReadEntireFile(filepath, max_len, &buffer);
- if (FAILED(hr)) {
- UTIL_LOG(LE, (L"[CryptoVerifySignature::Validate]"
- L"['%s' not read, hr 0x%08lx]", filepath, hr));
- return hr;
- }
- return Validate(buffer, signature_in);
-}
-
-HRESULT CryptoVerifySignature::Validate(const std::vector<byte>& buffer_in,
- const std::vector<byte>& signature_in) {
- ASSERT(certificate_, (L""));
- ASSERT1(!buffer_in.empty());
- ASSERT1(!signature_in.empty());
-
- UTIL_LOG(L2, (L"[CryptoVerifySignature::Validate]"
- L"[buffer of %d bytes, signature of %d bytes]",
- buffer_in.size(), signature_in.size()));
-
- // Get the CSP context and the public key from the certificate
- HCRYPTPROV csp = NULL;
- HCRYPTKEY key = NULL;
- HRESULT hr = certificate_->GetCSPContextAndKey(&csp, &key);
- ASSERT(SUCCEEDED(hr) && csp && key, (L""));
-
- // Hash the data
- CryptDetails::scoped_crypt_hash hash;
- BOOL b = ::CryptCreateHash(csp, kHashAlgorithm, 0, 0, address(hash));
- if (!b) {
- // hash is now invalid, but might not be NULL, so stomp on it
- DWORD err = ::GetLastError();
- ASSERT(!hash, (L""));
- UTIL_LOG(LE, (L"[CrypoVerifySignature::Validate]"
- L"[could not create hash], err 0x%08lx", err));
- return HRESULT_FROM_WIN32(err);
- }
- UTIL_LOG(L3, (L"CryptoVerifySignature::Validate new hash 0x%08lx", hash));
-
- b = ::CryptHashData(get(hash),
- &buffer_in.front(),
- buffer_in.size(),
- 0 /*flags*/);
- if (!b) {
- DWORD err = ::GetLastError();
- UTIL_LOG(LE, (L"[CryptoVerifySignature::Validate]"
- L"[could not hash data, err 0x%08lx]", err));
- return HRESULT_FROM_WIN32(err);
- }
-
- // Verify the hash
- b = ::CryptVerifySignature(get(hash),
- &signature_in.front(),
- signature_in.size(),
- key,
- NULL,
- 0 /*flags*/);
- if (!b) {
- DWORD err = ::GetLastError();
-#ifdef LOGGING
- CString encoded_signature;
- Base64::Encode(signature_in, &encoded_signature, false);
-
- UTIL_LOG(LE, (_T("CryptoVerifySignature::Validate could not ")
- _T("verify signature, err 0x%08lx with sig \"%s\""),
- err, encoded_signature));
-#endif
- if (err == NTE_BAD_SIGNATURE)
- return SIGS_E_INVALID_SIGNATURE;
- else
- return HRESULT_FROM_WIN32(err);
- }
-
- return S_OK;
-}
-
-HRESULT SignData(const TCHAR* certificate_path,
- const TCHAR* certificate_password,
- const TCHAR* certificate_subject_name,
- const std::vector<byte>& data,
- CString* signature_base64) {
- ASSERT(certificate_path, (L""));
- ASSERT(certificate_password, (L""));
- // certificate_subject_name can be NULL
- ASSERT(signature_base64, (L""));
-
- CryptoSigningCertificate certificate;
- RET_IF_FAILED(certificate.ImportCertificate(certificate_path,
- certificate_password,
- certificate_subject_name));
-
- CryptoComputeSignature signer(&certificate);
- std::vector<byte> signature;
- RET_IF_FAILED(signer.Sign(data, &signature));
- RET_IF_FAILED(Base64::Encode(signature, signature_base64, false));
-
- return S_OK;
-}
-
-HRESULT VerifyData(const TCHAR* certificate_path,
- const TCHAR* certificate_subject_name,
- const std::vector<byte>& data,
- const TCHAR* signature_base64) {
- ASSERT(certificate_path, (L""));
- // certificate_subject_name can be NULL
- ASSERT(signature_base64, (L""));
-
- std::vector<byte> signature;
- RET_IF_FAILED(Base64::Decode(CString(signature_base64), &signature));
-
- CryptoSignatureVerificationCertificate certificate;
- RET_IF_FAILED(certificate.ImportCertificate(certificate_path,
- certificate_subject_name));
-
- CryptoVerifySignature verifier(certificate);
- RET_IF_FAILED(verifier.Validate(data, signature));
-
- return S_OK;
-}
-
-HRESULT VerifyData(const std::vector<byte>& certificate_buffer,
- const TCHAR* certificate_subject_name,
- const std::vector<byte>& data,
- const TCHAR* signature_base64) {
- // certificate_subject_name can be NULL
- ASSERT(signature_base64, (L""));
-
- std::vector<byte> signature;
- RET_IF_FAILED(Base64::Decode(CString(signature_base64), &signature));
-
- CryptoSignatureVerificationCertificate certificate;
- RET_IF_FAILED(certificate.ImportCertificate(certificate_buffer,
- certificate_subject_name));
-
- CryptoVerifySignature verifier(certificate);
- RET_IF_FAILED(verifier.Validate(data, signature));
-
- return S_OK;
-}
-
-// TODO(omaha): function is missing the unit test.
-HRESULT AuthenticateFiles(const std::vector<CString>& files,
- const CString& hash) {
- ASSERT1(!files.empty());
-
- std::vector<byte> hash_vector;
- RET_IF_FAILED(Base64::Decode(hash, &hash_vector));
- if (hash_vector.size() != CryptoHash::kHashSize) {
- return E_INVALIDARG;
- }
-
- CryptoHash crypto;
- return crypto.Validate(files, kMaxFileSizeForAuthentication, hash_vector);
-}
-
-} // namespace omaha
-
« 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