summaryrefslogtreecommitdiffstats
path: root/base/crypto
diff options
context:
space:
mode:
authorwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-10 16:36:34 +0000
committerwtc@chromium.org <wtc@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-04-10 16:36:34 +0000
commitdb7286d3355528b36de6f0d7fa7f8d9929566511 (patch)
tree11034e15b9b3da3715b3da7bdb164baf0471e280 /base/crypto
parente30d979b70b4cb4b8e59f36b20c13a8d7b1257e5 (diff)
downloadchromium_src-db7286d3355528b36de6f0d7fa7f8d9929566511.zip
chromium_src-db7286d3355528b36de6f0d7fa7f8d9929566511.tar.gz
chromium_src-db7286d3355528b36de6f0d7fa7f8d9929566511.tar.bz2
Implement the signature verification API.
R=erikkay,avi BUG=6305 Review URL: http://codereview.chromium.org/63089 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@13508 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/crypto')
-rw-r--r--base/crypto/cssm_init.cc72
-rw-r--r--base/crypto/cssm_init.h17
-rw-r--r--base/crypto/signature_verifier.h105
-rw-r--r--base/crypto/signature_verifier_mac.cc143
-rw-r--r--base/crypto/signature_verifier_nss.cc114
-rw-r--r--base/crypto/signature_verifier_unittest.cc259
-rw-r--r--base/crypto/signature_verifier_win.cc148
7 files changed, 858 insertions, 0 deletions
diff --git a/base/crypto/cssm_init.cc b/base/crypto/cssm_init.cc
new file mode 100644
index 0000000..3483ef9
--- /dev/null
+++ b/base/crypto/cssm_init.cc
@@ -0,0 +1,72 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/crypto/cssm_init.h"
+
+#include <Security/cssm.h>
+
+#include "base/logging.h"
+#include "base/singleton.h"
+
+// When writing crypto code for Mac OS X, you may find the following
+// documentation useful:
+// - Common Security: CDSA and CSSM, Version 2 (with corrigenda)
+// http://www.opengroup.org/security/cdsa.htm
+// - Apple Cryptographic Service Provider Functional Specification
+// - CryptoSample: http://developer.apple.com/SampleCode/CryptoSample/
+
+namespace {
+
+class CSSMInitSingleton {
+ public:
+ CSSMInitSingleton() : inited_(false), loaded_(false) {
+ static CSSM_VERSION version = {2, 0};
+ // TODO(wtc): what should our caller GUID be?
+ static const CSSM_GUID test_guid = {
+ 0xFADE, 0, 0, { 1, 2, 3, 4, 5, 6, 7, 0 }
+ };
+ CSSM_RETURN crtn;
+ CSSM_PVC_MODE pvc_policy = CSSM_PVC_NONE;
+ crtn = CSSM_Init(&version, CSSM_PRIVILEGE_SCOPE_NONE, &test_guid,
+ CSSM_KEY_HIERARCHY_NONE, &pvc_policy, NULL);
+ if (crtn) {
+ NOTREACHED();
+ return;
+ }
+ inited_ = true;
+
+ crtn = CSSM_ModuleLoad(&gGuidAppleCSP, CSSM_KEY_HIERARCHY_NONE, NULL, NULL);
+ if (crtn) {
+ NOTREACHED();
+ return;
+ }
+ loaded_ = true;
+ }
+
+ ~CSSMInitSingleton() {
+ CSSM_RETURN crtn;
+ if (loaded_) {
+ crtn = CSSM_ModuleUnload(&gGuidAppleCSP, NULL, NULL);
+ DCHECK(crtn == CSSM_OK);
+ }
+ if (inited_) {
+ crtn = CSSM_Terminate();
+ DCHECK(crtn == CSSM_OK);
+ }
+ }
+
+ private:
+ bool inited_; // True if CSSM_Init has been called successfully.
+ bool loaded_; // True if CSSM_ModuleLoad has been called successfully.
+};
+
+} // namespace
+
+namespace base {
+
+void EnsureCSSMInit() {
+ Singleton<CSSMInitSingleton>::get();
+}
+
+} // namespace base
diff --git a/base/crypto/cssm_init.h b/base/crypto/cssm_init.h
new file mode 100644
index 0000000..20eda50
--- /dev/null
+++ b/base/crypto/cssm_init.h
@@ -0,0 +1,17 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CRYPTO_CSSM_INIT_H_
+#define BASE_CRYPTO_CSSM_INIT_H_
+
+namespace base {
+
+// Initialize CSSM if it isn't already initialized. This must be called before
+// any other CSSM functions. This function is thread-safe, and CSSM will only
+// ever be initialized once. CSSM will be properly shut down on program exit.
+void EnsureCSSMInit();
+
+} // namespace base
+
+#endif // BASE_CRYPTO_CSSM_INIT_H_
diff --git a/base/crypto/signature_verifier.h b/base/crypto/signature_verifier.h
new file mode 100644
index 0000000..c7e532d
--- /dev/null
+++ b/base/crypto/signature_verifier.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CRYPTO_SIGNATURE_VERIFIER_H_
+#define BASE_CRYPTO_SIGNATURE_VERIFIER_H_
+
+#include "build/build_config.h"
+
+#if defined(OS_LINUX)
+#include <cryptoht.h>
+#elif defined(OS_MACOSX)
+#include <Security/cssm.h>
+#elif defined(OS_WIN)
+#include <windows.h>
+#include <wincrypt.h>
+#endif
+
+#include <vector>
+
+#include "base/basictypes.h"
+
+namespace base {
+
+// The SignatureVerifier class verifies a signature using a bare public key
+// (as opposed to a certificate).
+class SignatureVerifier {
+ public:
+ SignatureVerifier();
+ ~SignatureVerifier();
+
+ // Streaming interface:
+
+ // Initiates a signature verification operation. This should be followed
+ // by one or more VerifyUpdate calls and a VerifyFinal call.
+ //
+ // The signature algorithm is specified as a DER encoded ASN.1
+ // AlgorithmIdentifier structure:
+ // AlgorithmIdentifier ::= SEQUENCE {
+ // algorithm OBJECT IDENTIFIER,
+ // parameters ANY DEFINED BY algorithm OPTIONAL }
+ //
+ // The signature is encoded according to the signature algorithm, but it
+ // must not be further encoded in an ASN.1 BIT STRING.
+ // Note: An RSA signatures is actually a big integer. It must be in the
+ // big-endian byte order.
+ //
+ // The public key is specified as a DER encoded ASN.1 SubjectPublicKeyInfo
+ // structure, which contains not only the public key but also its type
+ // (algorithm):
+ // SubjectPublicKeyInfo ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier,
+ // subjectPublicKey BIT STRING }
+ bool VerifyInit(const uint8* signature_algorithm,
+ int signature_algorithm_len,
+ const uint8* signature,
+ int signature_len,
+ const uint8* public_key_info,
+ int public_key_info_len);
+
+ // Feeds a piece of the data to the signature verifier.
+ void VerifyUpdate(const uint8* data_part, int data_part_len);
+
+ // Concludes a signature verification operation. Returns true if the
+ // signature is valid. Returns false if the signature is invalid or an
+ // error occurred.
+ bool VerifyFinal();
+
+ // Note: we can provide a one-shot interface if there is interest:
+ // bool Verify(const uint8* data,
+ // int data_len,
+ // const uint8* signature_algorithm,
+ // int signature_algorithm_len,
+ // const uint8* signature,
+ // int signature_len,
+ // const uint8* public_key_info,
+ // int public_key_info_len);
+
+ private:
+ void Reset();
+
+ std::vector<uint8> signature_;
+
+#if defined(OS_LINUX)
+ VFYContext* vfy_context_;
+#elif defined(OS_MACOSX)
+ std::vector<uint8> public_key_info_;
+
+ CSSM_CSP_HANDLE csp_handle_;
+
+ CSSM_CC_HANDLE sig_handle_;
+
+ CSSM_KEY public_key_;
+#elif defined(OS_WIN)
+ HCRYPTPROV provider_;
+
+ HCRYPTHASH hash_object_;
+
+ HCRYPTKEY public_key_;
+#endif
+};
+
+} // namespace base
+
+#endif // BASE_CRYPTO_SIGNATURE_VERIFIER_H_
diff --git a/base/crypto/signature_verifier_mac.cc b/base/crypto/signature_verifier_mac.cc
new file mode 100644
index 0000000..7dcd869
--- /dev/null
+++ b/base/crypto/signature_verifier_mac.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/crypto/signature_verifier.h"
+
+#include <stdlib.h>
+
+#include "base/crypto/cssm_init.h"
+#include "base/logging.h"
+
+namespace {
+
+void* AppMalloc(CSSM_SIZE size, void *alloc_ref) {
+ return malloc(size);
+}
+
+void AppFree(void* mem_ptr, void* alloc_ref) {
+ free(mem_ptr);
+}
+
+void* AppRealloc(void* ptr, CSSM_SIZE size, void* alloc_ref) {
+ return realloc(ptr, size);
+}
+
+void* AppCalloc(uint32 num, CSSM_SIZE size, void* alloc_ref) {
+ return calloc(num, size);
+}
+
+const CSSM_API_MEMORY_FUNCS mem_funcs = {
+ AppMalloc,
+ AppFree,
+ AppRealloc,
+ AppCalloc,
+ NULL
+};
+
+} // namespace
+
+namespace base {
+
+SignatureVerifier::SignatureVerifier() : csp_handle_(0), sig_handle_(0) {
+ EnsureCSSMInit();
+
+ static CSSM_VERSION version = {2, 0};
+ CSSM_RETURN crtn;
+ crtn = CSSM_ModuleAttach(&gGuidAppleCSP, &version, &mem_funcs, 0,
+ CSSM_SERVICE_CSP, 0, CSSM_KEY_HIERARCHY_NONE,
+ NULL, 0, NULL, &csp_handle_);
+ DCHECK(crtn == CSSM_OK);
+}
+
+SignatureVerifier::~SignatureVerifier() {
+ Reset();
+ if (csp_handle_) {
+ CSSM_RETURN crtn = CSSM_ModuleDetach(csp_handle_);
+ DCHECK(crtn == CSSM_OK);
+ }
+}
+
+bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
+ int signature_algorithm_len,
+ const uint8* signature,
+ int signature_len,
+ const uint8* public_key_info,
+ int public_key_info_len) {
+ signature_.assign(signature, signature + signature_len);
+ public_key_info_.assign(public_key_info,
+ public_key_info + public_key_info_len);
+
+ CSSM_ALGORITHMS key_alg = CSSM_ALGID_RSA; // TODO(wtc): hardcoded.
+
+ memset(&public_key_, 0, sizeof(public_key_));
+ public_key_.KeyData.Data = const_cast<uint8*>(&public_key_info_[0]);
+ public_key_.KeyData.Length = public_key_info_.size();
+ public_key_.KeyHeader.HeaderVersion = CSSM_KEYHEADER_VERSION;
+ public_key_.KeyHeader.BlobType = CSSM_KEYBLOB_RAW;
+ public_key_.KeyHeader.Format = CSSM_KEYBLOB_RAW_FORMAT_X509;
+ public_key_.KeyHeader.AlgorithmId = key_alg;
+ public_key_.KeyHeader.KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
+ public_key_.KeyHeader.KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
+ public_key_.KeyHeader.KeyUsage = CSSM_KEYUSE_VERIFY;
+ CSSM_KEY_SIZE key_size;
+ CSSM_RETURN crtn;
+ crtn = CSSM_QueryKeySizeInBits(csp_handle_, NULL, &public_key_, &key_size);
+ if (crtn) {
+ NOTREACHED() << "CSSM_QueryKeySizeInBits failed: " << crtn;
+ return false;
+ }
+ public_key_.KeyHeader.LogicalKeySizeInBits = key_size.LogicalKeySizeInBits;
+
+ // TODO(wtc): decode signature_algorithm...
+ CSSM_ALGORITHMS sig_alg = CSSM_ALGID_SHA1WithRSA;
+
+ crtn = CSSM_CSP_CreateSignatureContext(csp_handle_, sig_alg, NULL,
+ &public_key_, &sig_handle_);
+ if (crtn) {
+ NOTREACHED();
+ return false;
+ }
+ crtn = CSSM_VerifyDataInit(sig_handle_);
+ if (crtn) {
+ NOTREACHED();
+ return false;
+ }
+ return true;
+}
+
+void SignatureVerifier::VerifyUpdate(const uint8* data_part,
+ int data_part_len) {
+ CSSM_DATA data;
+ data.Data = const_cast<uint8*>(data_part);
+ data.Length = data_part_len;
+ CSSM_RETURN crtn = CSSM_VerifyDataUpdate(sig_handle_, &data, 1);
+ DCHECK(crtn == CSSM_OK);
+}
+
+bool SignatureVerifier::VerifyFinal() {
+ CSSM_DATA sig;
+ sig.Data = const_cast<uint8*>(&signature_[0]);
+ sig.Length = signature_.size();
+ CSSM_RETURN crtn = CSSM_VerifyDataFinal(sig_handle_, &sig);
+ Reset();
+
+ // crtn is CSSMERR_CSP_VERIFY_FAILED if signature verification fails.
+ return (crtn == CSSM_OK);
+}
+
+void SignatureVerifier::Reset() {
+ CSSM_RETURN crtn;
+ if (sig_handle_) {
+ crtn = CSSM_DeleteContext(sig_handle_);
+ DCHECK(crtn == CSSM_OK);
+ sig_handle_ = 0;
+ }
+ signature_.clear();
+
+ // Can't call CSSM_FreeKey on public_key_ because we constructed
+ // public_key_ manually.
+}
+
+} // namespace base
+
diff --git a/base/crypto/signature_verifier_nss.cc b/base/crypto/signature_verifier_nss.cc
new file mode 100644
index 0000000..901f1fc
--- /dev/null
+++ b/base/crypto/signature_verifier_nss.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/crypto/signature_verifier.h"
+
+#include <cryptohi.h>
+#include <keyhi.h>
+#include <stdlib.h>
+
+#include "base/logging.h"
+#include "base/nss_init.h"
+
+namespace base {
+
+SignatureVerifier::SignatureVerifier() : vfy_context_(NULL) {
+ EnsureNSSInit();
+}
+
+SignatureVerifier::~SignatureVerifier() {
+ Reset();
+}
+
+bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
+ int signature_algorithm_len,
+ const uint8* signature,
+ int signature_len,
+ const uint8* public_key_info,
+ int public_key_info_len) {
+ signature_.assign(signature, signature + signature_len);
+
+ CERTSubjectPublicKeyInfo* spki = NULL;
+ SECItem spki_der;
+ spki_der.type = siBuffer;
+ spki_der.data = const_cast<uint8*>(public_key_info);
+ spki_der.len = public_key_info_len;
+ spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spki_der);
+ if (!spki)
+ return false;
+ SECKEYPublicKey* public_key = SECKEY_ExtractPublicKey(spki);
+ SECKEY_DestroySubjectPublicKeyInfo(spki); // Done with spki.
+ if (!public_key)
+ return false;
+
+ PLArenaPool* arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena) {
+ SECKEY_DestroyPublicKey(public_key);
+ return false;
+ }
+
+ SECItem sig_alg_der;
+ sig_alg_der.type = siBuffer;
+ sig_alg_der.data = const_cast<uint8*>(signature_algorithm);
+ sig_alg_der.len = signature_algorithm_len;
+ SECAlgorithmID sig_alg_id;
+ SECStatus rv;
+ rv = SEC_QuickDERDecodeItem(arena, &sig_alg_id, SECOID_AlgorithmIDTemplate,
+ &sig_alg_der);
+ if (rv != SECSuccess) {
+ SECKEY_DestroyPublicKey(public_key);
+ PORT_FreeArena(arena, PR_TRUE);
+ return false;
+ }
+
+ SECItem sig;
+ sig.type = siBuffer;
+ sig.data = const_cast<uint8*>(signature);
+ sig.len = signature_len;
+ SECOidTag hash_alg_tag;
+ vfy_context_ = VFY_CreateContextWithAlgorithmID(public_key, &sig,
+ &sig_alg_id, &hash_alg_tag,
+ NULL);
+ SECKEY_DestroyPublicKey(public_key); // Done with public_key.
+ PORT_FreeArena(arena, PR_TRUE); // Done with sig_alg_id.
+ if (!vfy_context_) {
+ // A corrupted RSA signature could be detected without the data, so
+ // VFY_CreateContextWithAlgorithmID may fail with SEC_ERROR_BAD_SIGNATURE
+ // (-8182).
+ return false;
+ }
+
+ rv = VFY_Begin(vfy_context_);
+ if (rv != SECSuccess) {
+ NOTREACHED();
+ return false;
+ }
+ return true;
+}
+
+void SignatureVerifier::VerifyUpdate(const uint8* data_part,
+ int data_part_len) {
+ SECStatus rv = VFY_Update(vfy_context_, data_part, data_part_len);
+ DCHECK(rv == SECSuccess);
+}
+
+bool SignatureVerifier::VerifyFinal() {
+ SECStatus rv = VFY_End(vfy_context_);
+ Reset();
+
+ // If signature verification fails, the error code is
+ // SEC_ERROR_BAD_SIGNATURE (-8182).
+ return (rv == SECSuccess);
+}
+
+void SignatureVerifier::Reset() {
+ if (vfy_context_) {
+ VFY_DestroyContext(vfy_context_, PR_TRUE);
+ vfy_context_ = NULL;
+ }
+ signature_.clear();
+}
+
+} // namespace base
+
diff --git a/base/crypto/signature_verifier_unittest.cc b/base/crypto/signature_verifier_unittest.cc
new file mode 100644
index 0000000..6c7fdd9
--- /dev/null
+++ b/base/crypto/signature_verifier_unittest.cc
@@ -0,0 +1,259 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/crypto/signature_verifier.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(SignatureVerifierTest, BasicTest) {
+ // The input data in this test comes from real certificates.
+ //
+ // tbs_certificate ("to-be-signed certificate", the part of a certificate
+ // that is signed), signature_algorithm, and algorithm come from the
+ // certificate of bugs.webkit.org.
+ //
+ // public_key_info comes from the certificate of the issuer, Go Daddy Secure
+ // Certification Authority.
+ //
+ // The bytes in the array initializers are formatted to expose the DER
+ // encoding of the ASN.1 structures.
+
+ // The data that is signed is the following ASN.1 structure:
+ // TBSCertificate ::= SEQUENCE {
+ // ... -- omitted, not important
+ // }
+ const uint8 tbs_certificate[1017] = {
+ 0x30, 0x82, 0x03, 0xf5, // a SEQUENCE of length 1013 (0x3f5)
+ 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x03, 0x43, 0xdd, 0x63, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
+ 0x00, 0x30, 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
+ 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55,
+ 0x04, 0x08, 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31,
+ 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63,
+ 0x6f, 0x74, 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18,
+ 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64,
+ 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e,
+ 0x31, 0x33, 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68,
+ 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
+ 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64,
+ 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73,
+ 0x69, 0x74, 0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55,
+ 0x04, 0x03, 0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79,
+ 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74,
+ 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75,
+ 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06,
+ 0x03, 0x55, 0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32,
+ 0x38, 0x37, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x38, 0x30, 0x33, 0x31, 0x38,
+ 0x32, 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30,
+ 0x33, 0x31, 0x38, 0x32, 0x33, 0x33, 0x35, 0x31, 0x39, 0x5a, 0x30, 0x79,
+ 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55,
+ 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a,
+ 0x43, 0x61, 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x31, 0x12,
+ 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x09, 0x43, 0x75, 0x70,
+ 0x65, 0x72, 0x74, 0x69, 0x6e, 0x6f, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
+ 0x55, 0x04, 0x0a, 0x13, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49,
+ 0x6e, 0x63, 0x2e, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0b,
+ 0x13, 0x0c, 0x4d, 0x61, 0x63, 0x20, 0x4f, 0x53, 0x20, 0x46, 0x6f, 0x72,
+ 0x67, 0x65, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
+ 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69, 0x74, 0x2e, 0x6f, 0x72,
+ 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30,
+ 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xa7, 0x62, 0x79, 0x41, 0xda, 0x28,
+ 0xf2, 0xc0, 0x4f, 0xe0, 0x25, 0xaa, 0xa1, 0x2e, 0x3b, 0x30, 0x94, 0xb5,
+ 0xc9, 0x26, 0x3a, 0x1b, 0xe2, 0xd0, 0xcc, 0xa2, 0x95, 0xe2, 0x91, 0xc0,
+ 0xf0, 0x40, 0x9e, 0x27, 0x6e, 0xbd, 0x6e, 0xde, 0x7c, 0xb6, 0x30, 0x5c,
+ 0xb8, 0x9b, 0x01, 0x2f, 0x92, 0x04, 0xa1, 0xef, 0x4a, 0xb1, 0x6c, 0xb1,
+ 0x7e, 0x8e, 0xcd, 0xa6, 0xf4, 0x40, 0x73, 0x1f, 0x2c, 0x96, 0xad, 0xff,
+ 0x2a, 0x6d, 0x0e, 0xba, 0x52, 0x84, 0x83, 0xb0, 0x39, 0xee, 0xc9, 0x39,
+ 0xdc, 0x1e, 0x34, 0xd0, 0xd8, 0x5d, 0x7a, 0x09, 0xac, 0xa9, 0xee, 0xca,
+ 0x65, 0xf6, 0x85, 0x3a, 0x6b, 0xee, 0xe4, 0x5c, 0x5e, 0xf8, 0xda, 0xd1,
+ 0xce, 0x88, 0x47, 0xcd, 0x06, 0x21, 0xe0, 0xb9, 0x4b, 0xe4, 0x07, 0xcb,
+ 0x57, 0xdc, 0xca, 0x99, 0x54, 0xf7, 0x0e, 0xd5, 0x17, 0x95, 0x05, 0x2e,
+ 0xe9, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x82, 0x01, 0xce, 0x30,
+ 0x82, 0x01, 0xca, 0x30, 0x09, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02,
+ 0x30, 0x00, 0x30, 0x0b, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03,
+ 0x02, 0x05, 0xa0, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x16,
+ 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01,
+ 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30, 0x57,
+ 0x06, 0x03, 0x55, 0x1d, 0x1f, 0x04, 0x50, 0x30, 0x4e, 0x30, 0x4c, 0xa0,
+ 0x4a, 0xa0, 0x48, 0x86, 0x46, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f,
+ 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73,
+ 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d,
+ 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f,
+ 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x65, 0x78, 0x74, 0x65, 0x6e,
+ 0x64, 0x65, 0x64, 0x69, 0x73, 0x73, 0x75, 0x69, 0x6e, 0x67, 0x33, 0x2e,
+ 0x63, 0x72, 0x6c, 0x30, 0x52, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04, 0x4b,
+ 0x30, 0x49, 0x30, 0x47, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd,
+ 0x6d, 0x01, 0x07, 0x17, 0x02, 0x30, 0x38, 0x30, 0x36, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x2a, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
+ 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79,
+ 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74,
+ 0x6f, 0x72, 0x79, 0x30, 0x7f, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
+ 0x07, 0x01, 0x01, 0x04, 0x73, 0x30, 0x71, 0x30, 0x23, 0x06, 0x08, 0x2b,
+ 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x17, 0x68, 0x74, 0x74,
+ 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64,
+ 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x30, 0x4a, 0x06, 0x08,
+ 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68, 0x74,
+ 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69,
+ 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64,
+ 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69,
+ 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x65,
+ 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x74,
+ 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x48,
+ 0xdf, 0x60, 0x32, 0xcc, 0x89, 0x01, 0xb6, 0xdc, 0x2f, 0xe3, 0x73, 0xb5,
+ 0x9c, 0x16, 0x58, 0x32, 0x68, 0xa9, 0xc3, 0x30, 0x1f, 0x06, 0x03, 0x55,
+ 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xfd, 0xac, 0x61, 0x32,
+ 0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee, 0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76,
+ 0x99, 0x68, 0xcc, 0xe7, 0x30, 0x23, 0x06, 0x03, 0x55, 0x1d, 0x11, 0x04,
+ 0x1c, 0x30, 0x1a, 0x82, 0x0c, 0x2a, 0x2e, 0x77, 0x65, 0x62, 0x6b, 0x69,
+ 0x74, 0x2e, 0x6f, 0x72, 0x67, 0x82, 0x0a, 0x77, 0x65, 0x62, 0x6b, 0x69,
+ 0x74, 0x2e, 0x6f, 0x72, 0x67
+ };
+
+ // The signature algorithm is specified as the following ASN.1 structure:
+ // AlgorithmIdentifier ::= SEQUENCE {
+ // algorithm OBJECT IDENTIFIER,
+ // parameters ANY DEFINED BY algorithm OPTIONAL }
+ //
+ const uint8 signature_algorithm[15] = {
+ 0x30, 0x0d, // a SEQUENCE of length 13 (0xd)
+ 0x06, 0x09, // an OBJECT IDENTIFIER of length 9
+ // 1.2.840.113549.1.1.5 - sha1WithRSAEncryption
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05,
+ 0x05, 0x00, // a NULL of length 0
+ };
+
+ // RSA signature, a big integer in the big-endian byte order.
+ const uint8 signature[256] = {
+ 0x1e, 0x6a, 0xe7, 0xe0, 0x4f, 0xe7, 0x4d, 0xd0, 0x69, 0x7c, 0xf8, 0x8f,
+ 0x99, 0xb4, 0x18, 0x95, 0x36, 0x24, 0x0f, 0x0e, 0xa3, 0xea, 0x34, 0x37,
+ 0xf4, 0x7d, 0xd5, 0x92, 0x35, 0x53, 0x72, 0x76, 0x3f, 0x69, 0xf0, 0x82,
+ 0x56, 0xe3, 0x94, 0x7a, 0x1d, 0x1a, 0x81, 0xaf, 0x9f, 0xc7, 0x43, 0x01,
+ 0x64, 0xd3, 0x7c, 0x0d, 0xc8, 0x11, 0x4e, 0x4a, 0xe6, 0x1a, 0xc3, 0x01,
+ 0x74, 0xe8, 0x35, 0x87, 0x5c, 0x61, 0xaa, 0x8a, 0x46, 0x06, 0xbe, 0x98,
+ 0x95, 0x24, 0x9e, 0x01, 0xe3, 0xe6, 0xa0, 0x98, 0xee, 0x36, 0x44, 0x56,
+ 0x8d, 0x23, 0x9c, 0x65, 0xea, 0x55, 0x6a, 0xdf, 0x66, 0xee, 0x45, 0xe8,
+ 0xa0, 0xe9, 0x7d, 0x9a, 0xba, 0x94, 0xc5, 0xc8, 0xc4, 0x4b, 0x98, 0xff,
+ 0x9a, 0x01, 0x31, 0x6d, 0xf9, 0x2b, 0x58, 0xe7, 0xe7, 0x2a, 0xc5, 0x4d,
+ 0xbb, 0xbb, 0xcd, 0x0d, 0x70, 0xe1, 0xad, 0x03, 0xf5, 0xfe, 0xf4, 0x84,
+ 0x71, 0x08, 0xd2, 0xbc, 0x04, 0x7b, 0x26, 0x1c, 0xa8, 0x0f, 0x9c, 0xd8,
+ 0x12, 0x6a, 0x6f, 0x2b, 0x67, 0xa1, 0x03, 0x80, 0x9a, 0x11, 0x0b, 0xe9,
+ 0xe0, 0xb5, 0xb3, 0xb8, 0x19, 0x4e, 0x0c, 0xa4, 0xd9, 0x2b, 0x3b, 0xc2,
+ 0xca, 0x20, 0xd3, 0x0c, 0xa4, 0xff, 0x93, 0x13, 0x1f, 0xfc, 0xba, 0x94,
+ 0x93, 0x8c, 0x64, 0x15, 0x2e, 0x28, 0xa9, 0x55, 0x8c, 0x2c, 0x48, 0xd3,
+ 0xd3, 0xc1, 0x50, 0x69, 0x19, 0xe8, 0x34, 0xd3, 0xf1, 0x04, 0x9f, 0x0a,
+ 0x7a, 0x21, 0x87, 0xbf, 0xb9, 0x59, 0x37, 0x2e, 0xf4, 0x71, 0xa5, 0x3e,
+ 0xbe, 0xcd, 0x70, 0x83, 0x18, 0xf8, 0x8a, 0x72, 0x85, 0x45, 0x1f, 0x08,
+ 0x01, 0x6f, 0x37, 0xf5, 0x2b, 0x7b, 0xea, 0xb9, 0x8b, 0xa3, 0xcc, 0xfd,
+ 0x35, 0x52, 0xdd, 0x66, 0xde, 0x4f, 0x30, 0xc5, 0x73, 0x81, 0xb6, 0xe8,
+ 0x3c, 0xd8, 0x48, 0x8a
+ };
+
+ // The public key is specified as the following ASN.1 structure:
+ // SubjectPublicKeyInfo ::= SEQUENCE {
+ // algorithm AlgorithmIdentifier,
+ // subjectPublicKey BIT STRING }
+ const uint8 public_key_info[294] = {
+ 0x30, 0x82, 0x01, 0x22, // a SEQUENCE of length 290 (0x122)
+ // algorithm
+ 0x30, 0x0d, // a SEQUENCE of length 13
+ 0x06, 0x09, // an OBJECT IDENTIFIER of length 9
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
+ 0x05, 0x00, // a NULL of length 0
+ // subjectPublicKey
+ 0x03, 0x82, 0x01, 0x0f, // a BIT STRING of length 271 (0x10f)
+ 0x00, // number of unused bits
+ 0x30, 0x82, 0x01, 0x0a, // a SEQUENCE of length 266 (0x10a)
+ // modulus
+ 0x02, 0x82, 0x01, 0x01, // an INTEGER of length 257 (0x101)
+ 0x00, 0xc4, 0x2d, 0xd5, 0x15, 0x8c, 0x9c, 0x26, 0x4c, 0xec,
+ 0x32, 0x35, 0xeb, 0x5f, 0xb8, 0x59, 0x01, 0x5a, 0xa6, 0x61,
+ 0x81, 0x59, 0x3b, 0x70, 0x63, 0xab, 0xe3, 0xdc, 0x3d, 0xc7,
+ 0x2a, 0xb8, 0xc9, 0x33, 0xd3, 0x79, 0xe4, 0x3a, 0xed, 0x3c,
+ 0x30, 0x23, 0x84, 0x8e, 0xb3, 0x30, 0x14, 0xb6, 0xb2, 0x87,
+ 0xc3, 0x3d, 0x95, 0x54, 0x04, 0x9e, 0xdf, 0x99, 0xdd, 0x0b,
+ 0x25, 0x1e, 0x21, 0xde, 0x65, 0x29, 0x7e, 0x35, 0xa8, 0xa9,
+ 0x54, 0xeb, 0xf6, 0xf7, 0x32, 0x39, 0xd4, 0x26, 0x55, 0x95,
+ 0xad, 0xef, 0xfb, 0xfe, 0x58, 0x86, 0xd7, 0x9e, 0xf4, 0x00,
+ 0x8d, 0x8c, 0x2a, 0x0c, 0xbd, 0x42, 0x04, 0xce, 0xa7, 0x3f,
+ 0x04, 0xf6, 0xee, 0x80, 0xf2, 0xaa, 0xef, 0x52, 0xa1, 0x69,
+ 0x66, 0xda, 0xbe, 0x1a, 0xad, 0x5d, 0xda, 0x2c, 0x66, 0xea,
+ 0x1a, 0x6b, 0xbb, 0xe5, 0x1a, 0x51, 0x4a, 0x00, 0x2f, 0x48,
+ 0xc7, 0x98, 0x75, 0xd8, 0xb9, 0x29, 0xc8, 0xee, 0xf8, 0x66,
+ 0x6d, 0x0a, 0x9c, 0xb3, 0xf3, 0xfc, 0x78, 0x7c, 0xa2, 0xf8,
+ 0xa3, 0xf2, 0xb5, 0xc3, 0xf3, 0xb9, 0x7a, 0x91, 0xc1, 0xa7,
+ 0xe6, 0x25, 0x2e, 0x9c, 0xa8, 0xed, 0x12, 0x65, 0x6e, 0x6a,
+ 0xf6, 0x12, 0x44, 0x53, 0x70, 0x30, 0x95, 0xc3, 0x9c, 0x2b,
+ 0x58, 0x2b, 0x3d, 0x08, 0x74, 0x4a, 0xf2, 0xbe, 0x51, 0xb0,
+ 0xbf, 0x87, 0xd0, 0x4c, 0x27, 0x58, 0x6b, 0xb5, 0x35, 0xc5,
+ 0x9d, 0xaf, 0x17, 0x31, 0xf8, 0x0b, 0x8f, 0xee, 0xad, 0x81,
+ 0x36, 0x05, 0x89, 0x08, 0x98, 0xcf, 0x3a, 0xaf, 0x25, 0x87,
+ 0xc0, 0x49, 0xea, 0xa7, 0xfd, 0x67, 0xf7, 0x45, 0x8e, 0x97,
+ 0xcc, 0x14, 0x39, 0xe2, 0x36, 0x85, 0xb5, 0x7e, 0x1a, 0x37,
+ 0xfd, 0x16, 0xf6, 0x71, 0x11, 0x9a, 0x74, 0x30, 0x16, 0xfe,
+ 0x13, 0x94, 0xa3, 0x3f, 0x84, 0x0d, 0x4f,
+ // public exponent
+ 0x02, 0x03, // an INTEGER of length 3
+ 0x01, 0x00, 0x01
+ };
+
+ // We use the signature verifier to perform four signature verification
+ // tests.
+ base::SignatureVerifier verifier;
+ bool ok;
+
+ // Test 1: feed all of the data to the verifier at once (a single
+ // VerifyUpdate call).
+ ok = verifier.VerifyInit(signature_algorithm,
+ sizeof(signature_algorithm),
+ signature, sizeof(signature),
+ public_key_info, sizeof(public_key_info));
+ EXPECT_TRUE(ok);
+ verifier.VerifyUpdate(tbs_certificate, sizeof(tbs_certificate));
+ ok = verifier.VerifyFinal();
+ EXPECT_TRUE(ok);
+
+ // Test 2: feed the data to the verifier in three parts (three VerifyUpdate
+ // calls).
+ ok = verifier.VerifyInit(signature_algorithm,
+ sizeof(signature_algorithm),
+ signature, sizeof(signature),
+ public_key_info, sizeof(public_key_info));
+ EXPECT_TRUE(ok);
+ verifier.VerifyUpdate(tbs_certificate, 256);
+ verifier.VerifyUpdate(tbs_certificate + 256, 256);
+ verifier.VerifyUpdate(tbs_certificate + 512, sizeof(tbs_certificate) - 512);
+ ok = verifier.VerifyFinal();
+ EXPECT_TRUE(ok);
+
+ // Test 3: verify the signature with incorrect data.
+ uint8 bad_tbs_certificate[sizeof(tbs_certificate)];
+ memcpy(bad_tbs_certificate, tbs_certificate, sizeof(tbs_certificate));
+ bad_tbs_certificate[10] += 1; // Corrupt one byte of the data.
+ ok = verifier.VerifyInit(signature_algorithm,
+ sizeof(signature_algorithm),
+ signature, sizeof(signature),
+ public_key_info, sizeof(public_key_info));
+ EXPECT_TRUE(ok);
+ verifier.VerifyUpdate(bad_tbs_certificate, sizeof(bad_tbs_certificate));
+ ok = verifier.VerifyFinal();
+ EXPECT_FALSE(ok);
+
+ // Test 4: verify a bad signature.
+ uint8 bad_signature[sizeof(signature)];
+ memcpy(bad_signature, signature, sizeof(signature));
+ bad_signature[10] += 1; // Corrupt one byte of the signature.
+ ok = verifier.VerifyInit(signature_algorithm,
+ sizeof(signature_algorithm),
+ bad_signature, sizeof(bad_signature),
+ public_key_info, sizeof(public_key_info));
+
+ // A crypto library (e.g., NSS) may detect that the signature is corrupted
+ // and cause VerifyInit to return false, so it is fine for 'ok' to be false.
+ if (ok) {
+ verifier.VerifyUpdate(tbs_certificate, sizeof(tbs_certificate));
+ ok = verifier.VerifyFinal();
+ EXPECT_FALSE(ok);
+ }
+}
diff --git a/base/crypto/signature_verifier_win.cc b/base/crypto/signature_verifier_win.cc
new file mode 100644
index 0000000..be1ecec
--- /dev/null
+++ b/base/crypto/signature_verifier_win.cc
@@ -0,0 +1,148 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/crypto/signature_verifier.h"
+
+#include "base/logging.h"
+
+#pragma comment(lib, "crypt32.lib")
+
+namespace {
+
+// Wrappers of malloc and free for CRYPT_DECODE_PARA, which requires the
+// WINAPI calling convention.
+void* WINAPI MyCryptAlloc(size_t size) {
+ return malloc(size);
+}
+
+void WINAPI MyCryptFree(void* p) {
+ free(p);
+}
+
+} // namespace
+
+namespace base {
+
+SignatureVerifier::SignatureVerifier() : hash_object_(0), public_key_(0) {
+ if (!CryptAcquireContext(&provider_, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ provider_ = 0;
+}
+
+SignatureVerifier::~SignatureVerifier() {
+ Reset();
+ if (provider_) {
+ BOOL ok = CryptReleaseContext(provider_, 0);
+ DCHECK(ok);
+ }
+}
+
+bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm,
+ int signature_algorithm_len,
+ const uint8* signature,
+ int signature_len,
+ const uint8* public_key_info,
+ int public_key_info_len) {
+ signature_.reserve(signature_len);
+ // CryptoAPI uses big integers in the little-endian byte order, so we need
+ // to first swap the order of signature bytes.
+ for (int i = signature_len - 1; i >= 0; --i)
+ signature_.push_back(signature[i]);
+
+ CRYPT_DECODE_PARA decode_para;
+ decode_para.cbSize = sizeof(decode_para);
+ decode_para.pfnAlloc = MyCryptAlloc;
+ decode_para.pfnFree = MyCryptFree;
+ CERT_PUBLIC_KEY_INFO* cert_public_key_info = NULL;
+ DWORD struct_len = 0;
+ BOOL ok;
+ ok = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ X509_PUBLIC_KEY_INFO,
+ public_key_info,
+ public_key_info_len,
+ CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
+ &decode_para,
+ &cert_public_key_info,
+ &struct_len);
+ if (!ok)
+ return false;
+
+ ok = CryptImportPublicKeyInfo(provider_,
+ X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ cert_public_key_info, &public_key_);
+ free(cert_public_key_info);
+ if (!ok)
+ return false;
+
+ CRYPT_ALGORITHM_IDENTIFIER* signature_algorithm_id;
+ struct_len = 0;
+ ok = CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
+ X509_ALGORITHM_IDENTIFIER,
+ signature_algorithm,
+ signature_algorithm_len,
+ CRYPT_DECODE_ALLOC_FLAG | CRYPT_DECODE_NOCOPY_FLAG,
+ &decode_para,
+ &signature_algorithm_id,
+ &struct_len);
+ DCHECK(ok || GetLastError() == ERROR_FILE_NOT_FOUND);
+ ALG_ID hash_alg_id;
+ if (ok) {
+ hash_alg_id = CALG_MD4; // Initialize to a weak hash algorithm that we
+ // don't support.
+ if (!strcmp(signature_algorithm_id->pszObjId, szOID_RSA_SHA1RSA))
+ hash_alg_id = CALG_SHA1;
+ else if (!strcmp(signature_algorithm_id->pszObjId, szOID_RSA_MD5RSA))
+ hash_alg_id = CALG_MD5;
+ free(signature_algorithm_id);
+ DCHECK(hash_alg_id != CALG_MD4);
+ if (hash_alg_id == CALG_MD4)
+ return false; // Unsupported hash algorithm.
+ } else if (GetLastError() == ERROR_FILE_NOT_FOUND) {
+ // TODO(wtc): X509_ALGORITHM_IDENTIFIER isn't supported on XP SP2. We
+ // may be able to encapsulate signature_algorithm in a dummy SignedContent
+ // and decode it with X509_CERT into a CERT_SIGNED_CONTENT_INFO. For now,
+ // just hardcode the hash algorithm to be SHA-1.
+ hash_alg_id = CALG_SHA1;
+ } else {
+ return false;
+ }
+
+ ok = CryptCreateHash(provider_, hash_alg_id, 0, 0, &hash_object_);
+ if (!ok)
+ return false;
+ return true;
+}
+
+void SignatureVerifier::VerifyUpdate(const uint8* data_part,
+ int data_part_len) {
+ BOOL ok = CryptHashData(hash_object_, data_part, data_part_len, 0);
+ DCHECK(ok) << "CryptHashData failed: " << GetLastError();
+}
+
+bool SignatureVerifier::VerifyFinal() {
+ BOOL ok = CryptVerifySignature(hash_object_, &signature_[0],
+ signature_.size(), public_key_, NULL, 0);
+ Reset();
+ if (!ok)
+ return false;
+ return true;
+}
+
+void SignatureVerifier::Reset() {
+ BOOL ok;
+ if (hash_object_) {
+ ok = CryptDestroyHash(hash_object_);
+ DCHECK(ok);
+ hash_object_ = 0;
+ }
+ if (public_key_) {
+ ok = CryptDestroyKey(public_key_);
+ DCHECK(ok);
+ public_key_ = 0;
+ }
+ signature_.clear();
+}
+
+} // namespace base
+