diff options
-rw-r--r-- | base/crypto/encryptor_openssl.cc | 2 | ||||
-rw-r--r-- | base/crypto/rsa_private_key.h | 4 | ||||
-rw-r--r-- | base/crypto/rsa_private_key_openssl.cc | 10 | ||||
-rw-r--r-- | base/crypto/signature_creator.h | 9 | ||||
-rw-r--r-- | base/crypto/signature_creator_openssl.cc | 33 | ||||
-rw-r--r-- | base/crypto/signature_verifier.h | 5 | ||||
-rw-r--r-- | base/crypto/signature_verifier_openssl.cc | 66 | ||||
-rw-r--r-- | base/crypto/symmetric_key_openssl.cc | 28 | ||||
-rw-r--r-- | base/openssl_util.cc | 6 | ||||
-rw-r--r-- | base/openssl_util.h | 35 | ||||
-rw-r--r-- | net/base/cert_test_util.cc | 2 |
11 files changed, 150 insertions, 50 deletions
diff --git a/base/crypto/encryptor_openssl.cc b/base/crypto/encryptor_openssl.cc index 44ae932..7e09545 100644 --- a/base/crypto/encryptor_openssl.cc +++ b/base/crypto/encryptor_openssl.cc @@ -34,7 +34,7 @@ class ScopedCipherCTX { } ~ScopedCipherCTX() { EVP_CIPHER_CTX_cleanup(&ctx_); - ClearOpenSSLERRStack(); + ClearOpenSSLERRStack(FROM_HERE); } EVP_CIPHER_CTX* get() { return &ctx_; } diff --git a/base/crypto/rsa_private_key.h b/base/crypto/rsa_private_key.h index ea5daac..ecec015 100644 --- a/base/crypto/rsa_private_key.h +++ b/base/crypto/rsa_private_key.h @@ -204,7 +204,9 @@ class RSAPrivateKey { ~RSAPrivateKey(); -#if defined(USE_NSS) +#if defined(USE_OPENSSL) + EVP_PKEY* key() { return key_; } +#elif defined(USE_NSS) SECKEYPrivateKeyStr* key() { return key_; } #elif defined(OS_WIN) HCRYPTPROV provider() { return provider_; } diff --git a/base/crypto/rsa_private_key_openssl.cc b/base/crypto/rsa_private_key_openssl.cc index e14965f..0776b63 100644 --- a/base/crypto/rsa_private_key_openssl.cc +++ b/base/crypto/rsa_private_key_openssl.cc @@ -29,10 +29,10 @@ bool ExportKey(EVP_PKEY* key, if (!key) return false; + OpenSSLErrStackTracer err_tracer(FROM_HERE); ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new(BIO_s_mem())); int res = export_fn(bio.get(), key); - ClearOpenSSLERRStack(); if (!res) return false; @@ -49,11 +49,9 @@ bool ExportKey(EVP_PKEY* key, // static RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) { - EnsureOpenSSLInit(); - + OpenSSLErrStackTracer err_tracer(FROM_HERE); ScopedOpenSSL<RSA, RSA_free> rsa_key(RSA_generate_key(num_bits, 65537L, NULL, NULL)); - ClearOpenSSLERRStack(); if (!rsa_key.get()) return NULL; @@ -74,7 +72,7 @@ RSAPrivateKey* RSAPrivateKey::CreateSensitive(uint16 num_bits) { // static RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( const std::vector<uint8>& input) { - EnsureOpenSSLInit(); + OpenSSLErrStackTracer err_tracer(FROM_HERE); // BIO_new_mem_buf is not const aware, but it does not modify the buffer. char* data = reinterpret_cast<char*>(const_cast<uint8*>(input.data())); @@ -87,13 +85,11 @@ RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo( // Info structure returned. ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free> p8inf( d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL)); - ClearOpenSSLERRStack(); if (!p8inf.get()) return NULL; scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey); result->key_ = EVP_PKCS82PKEY(p8inf.get()); - ClearOpenSSLERRStack(); if (!result->key_) return NULL; diff --git a/base/crypto/signature_creator.h b/base/crypto/signature_creator.h index 38e327b..c405560 100644 --- a/base/crypto/signature_creator.h +++ b/base/crypto/signature_creator.h @@ -8,7 +8,10 @@ #include "build/build_config.h" -#if defined(USE_NSS) +#if defined(USE_OPENSSL) +// Forward declaration for openssl/*.h +typedef struct env_md_ctx_st EVP_MD_CTX; +#elif defined(USE_NSS) // Forward declaration. struct SGNContextStr; #elif defined(OS_MACOSX) @@ -48,7 +51,9 @@ class SignatureCreator { RSAPrivateKey* key_; -#if defined(USE_NSS) +#if defined(USE_OPENSSL) + EVP_MD_CTX* sign_context_; +#elif defined(USE_NSS) SGNContextStr* sign_context_; #elif defined(OS_MACOSX) CSSM_CC_HANDLE sig_handle_; diff --git a/base/crypto/signature_creator_openssl.cc b/base/crypto/signature_creator_openssl.cc index 5d70f01..7eed379 100644 --- a/base/crypto/signature_creator_openssl.cc +++ b/base/crypto/signature_creator_openssl.cc @@ -4,29 +4,50 @@ #include "base/crypto/signature_creator.h" +#include <openssl/evp.h> + #include "base/logging.h" +#include "base/openssl_util.h" +#include "base/scoped_ptr.h" namespace base { // static SignatureCreator* SignatureCreator::Create(RSAPrivateKey* key) { - return NULL; + OpenSSLErrStackTracer err_tracer(FROM_HERE); + scoped_ptr<SignatureCreator> result(new SignatureCreator); + result->key_ = key; + if (!EVP_SignInit_ex(result->sign_context_, EVP_sha1(), NULL)) + return NULL; + return result.release(); } -SignatureCreator::SignatureCreator() { +SignatureCreator::SignatureCreator() + : sign_context_(EVP_MD_CTX_create()) { } SignatureCreator::~SignatureCreator() { + EVP_MD_CTX_destroy(sign_context_); } bool SignatureCreator::Update(const uint8* data_part, int data_part_len) { - NOTIMPLEMENTED(); - return false; + OpenSSLErrStackTracer err_tracer(FROM_HERE); + return EVP_SignUpdate(sign_context_, data_part, data_part_len) == 1; } bool SignatureCreator::Final(std::vector<uint8>* signature) { - NOTIMPLEMENTED(); - return false; + OpenSSLErrStackTracer err_tracer(FROM_HERE); + EVP_PKEY* key = key_->key(); + signature->resize(EVP_PKEY_size(key)); + + unsigned int len = 0; + int rv = EVP_SignFinal(sign_context_, signature->data(), &len, key); + if (!rv) { + signature->clear(); + return false; + } + signature->resize(len); + return true; } } // namespace base diff --git a/base/crypto/signature_verifier.h b/base/crypto/signature_verifier.h index 4746edc..e2b61af 100644 --- a/base/crypto/signature_verifier.h +++ b/base/crypto/signature_verifier.h @@ -83,7 +83,10 @@ class SignatureVerifier { std::vector<uint8> signature_; -#if defined(USE_NSS) +#if defined(USE_OPENSSL) + struct VerifyContext; + VerifyContext* verify_context_; +#elif defined(USE_NSS) VFYContext* vfy_context_; #elif defined(OS_MACOSX) std::vector<uint8> public_key_info_; diff --git a/base/crypto/signature_verifier_openssl.cc b/base/crypto/signature_verifier_openssl.cc index 49b5e07..b4fff78 100644 --- a/base/crypto/signature_verifier_openssl.cc +++ b/base/crypto/signature_verifier_openssl.cc @@ -4,14 +4,28 @@ #include "base/crypto/signature_verifier.h" +#include <openssl/evp.h> +#include <openssl/x509.h> + +#include <vector> + #include "base/logging.h" +#include "base/openssl_util.h" +#include "base/scoped_ptr.h" namespace base { -SignatureVerifier::SignatureVerifier() { +struct SignatureVerifier::VerifyContext { + ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> public_key; + ScopedOpenSSL<EVP_MD_CTX, EVP_MD_CTX_destroy> ctx; +}; + +SignatureVerifier::SignatureVerifier() + : verify_context_(NULL) { } SignatureVerifier::~SignatureVerifier() { + Reset(); } bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm, @@ -20,22 +34,60 @@ bool SignatureVerifier::VerifyInit(const uint8* signature_algorithm, int signature_len, const uint8* public_key_info, int public_key_info_len) { - NOTIMPLEMENTED(); - return false; + DCHECK(!verify_context_); + verify_context_ = new VerifyContext; + OpenSSLErrStackTracer err_tracer(FROM_HERE); + + ScopedOpenSSL<X509_ALGOR, X509_ALGOR_free> algorithm( + d2i_X509_ALGOR(NULL, &signature_algorithm, signature_algorithm_len)); + if (!algorithm.get()) + return false; + + const EVP_MD* digest = EVP_get_digestbyobj(algorithm.get()->algorithm); + DCHECK(digest); + + signature_.assign(signature, signature + signature_len); + + // BIO_new_mem_buf is not const aware, but it does not modify the buffer. + char* data = reinterpret_cast<char*>(const_cast<uint8*>(public_key_info)); + ScopedOpenSSL<BIO, BIO_free_all> bio(BIO_new_mem_buf(data, + public_key_info_len)); + if (!bio.get()) + return false; + + verify_context_->public_key.reset(d2i_PUBKEY_bio(bio.get(), NULL)); + if (!verify_context_->public_key.get()) + return false; + + verify_context_->ctx.reset(EVP_MD_CTX_create()); + int rv = EVP_VerifyInit_ex(verify_context_->ctx.get(), digest, NULL); + return rv == 1; } void SignatureVerifier::VerifyUpdate(const uint8* data_part, int data_part_len) { - NOTIMPLEMENTED(); + DCHECK(verify_context_); + OpenSSLErrStackTracer err_tracer(FROM_HERE); + int rv = EVP_VerifyUpdate(verify_context_->ctx.get(), + data_part, data_part_len); + DCHECK_EQ(rv, 1); } bool SignatureVerifier::VerifyFinal() { - NOTIMPLEMENTED(); - return false; + DCHECK(verify_context_); + OpenSSLErrStackTracer err_tracer(FROM_HERE); + int rv = EVP_VerifyFinal(verify_context_->ctx.get(), + signature_.data(), signature_.size(), + verify_context_->public_key.get()); + DCHECK_GE(rv, 0); + Reset(); + return rv == 1; } void SignatureVerifier::Reset() { - NOTIMPLEMENTED(); + delete verify_context_; + verify_context_ = NULL; + signature_.clear(); } } // namespace base diff --git a/base/crypto/symmetric_key_openssl.cc b/base/crypto/symmetric_key_openssl.cc index 9f0ad38..409cce4 100644 --- a/base/crypto/symmetric_key_openssl.cc +++ b/base/crypto/symmetric_key_openssl.cc @@ -30,18 +30,13 @@ SymmetricKey* SymmetricKey::GenerateRandomKey(Algorithm algorithm, if (key_size_in_bits == 0) return NULL; - EnsureOpenSSLInit(); + OpenSSLErrStackTracer err_tracer(FROM_HERE); scoped_ptr<SymmetricKey> key(new SymmetricKey); uint8* key_data = reinterpret_cast<uint8*>(WriteInto(&key->key_, key_size_in_bytes + 1)); - int res = RAND_bytes(key_data, key_size_in_bytes); - if (res != 1) { - DLOG(ERROR) << "RAND_bytes failed. res = " << res; - ClearOpenSSLERRStack(); - return NULL; - } - return key.release(); + int rv = RAND_bytes(key_data, key_size_in_bytes); + return rv == 1 ? key.release() : NULL; } // static @@ -54,20 +49,15 @@ SymmetricKey* SymmetricKey::DeriveKeyFromPassword(Algorithm algorithm, int key_size_in_bytes = key_size_in_bits / 8; DCHECK_EQ(static_cast<int>(key_size_in_bits), key_size_in_bytes * 8); - EnsureOpenSSLInit(); + OpenSSLErrStackTracer err_tracer(FROM_HERE); scoped_ptr<SymmetricKey> key(new SymmetricKey); uint8* key_data = reinterpret_cast<uint8*>(WriteInto(&key->key_, key_size_in_bytes + 1)); - int res = PKCS5_PBKDF2_HMAC_SHA1(password.data(), password.length(), - reinterpret_cast<const uint8*>(salt.data()), - salt.length(), iterations, - key_size_in_bytes, key_data); - if (res != 1) { - DLOG(ERROR) << "HMAC SHA1 failed. res = " << res; - ClearOpenSSLERRStack(); - return NULL; - } - return key.release(); + int rv = PKCS5_PBKDF2_HMAC_SHA1(password.data(), password.length(), + reinterpret_cast<const uint8*>(salt.data()), + salt.length(), iterations, + key_size_in_bytes, key_data); + return rv == 1 ? key.release() : NULL; } // static diff --git a/base/openssl_util.cc b/base/openssl_util.cc index 894c710..1cbc304 100644 --- a/base/openssl_util.cc +++ b/base/openssl_util.cc @@ -67,13 +67,15 @@ void EnsureOpenSSLInit() { (void)Singleton<OpenSSLInitSingleton>::get(); } -void ClearOpenSSLERRStack() { +void ClearOpenSSLERRStack(const tracked_objects::Location& location) { if (logging::DEBUG_MODE && VLOG_IS_ON(1)) { int error_num = ERR_get_error(); if (error_num == 0) return; - DVLOG(1) << "OpenSSL ERR_get_error stack:"; + std::string message; + location.Write(true, true, &message); + DVLOG(1) << "OpenSSL ERR_get_error stack from " << message; char buf[140]; do { ERR_error_string_n(error_num, buf, arraysize(buf)); diff --git a/base/openssl_util.h b/base/openssl_util.h index 1d290ae..9362302 100644 --- a/base/openssl_util.h +++ b/base/openssl_util.h @@ -16,10 +16,17 @@ namespace base { template <typename T, void (*destructor)(T*)> class ScopedOpenSSL { public: - explicit ScopedOpenSSL(T* ptr_) : ptr_(ptr_) { } + ScopedOpenSSL() : ptr_(NULL) { } + explicit ScopedOpenSSL(T* ptr) : ptr_(ptr) { } ~ScopedOpenSSL() { if (ptr_) (*destructor)(ptr_); } T* get() const { return ptr_; } + void reset(T* ptr) { + if (ptr != ptr_) { + if (ptr_) (*destructor)(ptr_); + ptr_ = ptr; + } + } private: T* ptr_; @@ -72,8 +79,30 @@ class ScopedOpenSSLSafeSizeBuffer { void EnsureOpenSSLInit(); // Drains the OpenSSL ERR_get_error stack. On a debug build the error codes -// are send to VLOG(1), on a release build they are disregarded. -void ClearOpenSSLERRStack(); +// are send to VLOG(1), on a release build they are disregarded. In most +// cases you should pass FROM_HERE as the |location|. +void ClearOpenSSLERRStack(const tracked_objects::Location& location); + +// Place an instance of this class on the call stack to automatically clear +// the OpenSSL error stack on function exit. +class OpenSSLErrStackTracer { + public: + // Pass FROM_HERE as |location|, to help track the source of OpenSSL error + // messages. Note any diagnostic emitted will be tagged with the location of + // the constructor call as it's not possible to trace a destructor's callsite. + explicit OpenSSLErrStackTracer(const tracked_objects::Location& location) + : location_(location) { + EnsureOpenSSLInit(); + } + ~OpenSSLErrStackTracer() { + ClearOpenSSLERRStack(location_); + } + + private: + const tracked_objects::Location location_; + + DISALLOW_IMPLICIT_CONSTRUCTORS(OpenSSLErrStackTracer); +}; } // namespace base diff --git a/net/base/cert_test_util.cc b/net/base/cert_test_util.cc index d5c678e..df00b9d 100644 --- a/net/base/cert_test_util.cc +++ b/net/base/cert_test_util.cc @@ -32,7 +32,7 @@ X509Certificate* AddTemporaryRootCertToStore(X509* x509_cert) { unsigned long error_code = ERR_get_error(); if (ERR_GET_LIB(error_code) != ERR_LIB_X509 || ERR_GET_REASON(error_code) != X509_R_CERT_ALREADY_IN_HASH_TABLE) { - base::ClearOpenSSLERRStack(); + base::ClearOpenSSLERRStack(FROM_HERE); return NULL; } } |