summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-18 15:43:43 +0000
committerjoth@chromium.org <joth@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-11-18 15:43:43 +0000
commitbe796bb642e82b4702fb84cfb451a09a37890c58 (patch)
treee79b76ae9f378ef3ff25ee70880e5f99a987a6ec
parent86b96f011269b5f697cedae35596314fa844687c (diff)
downloadchromium_src-be796bb642e82b4702fb84cfb451a09a37890c58.zip
chromium_src-be796bb642e82b4702fb84cfb451a09a37890c58.tar.gz
chromium_src-be796bb642e82b4702fb84cfb451a09a37890c58.tar.bz2
Implements Signature Creator & Verifier for openssl
Also adds a little more infrastructure to assist in openssl error handling. BUG=None TEST=base_unittests RSA* and Sign* Review URL: http://codereview.chromium.org/5105003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@66622 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/crypto/encryptor_openssl.cc2
-rw-r--r--base/crypto/rsa_private_key.h4
-rw-r--r--base/crypto/rsa_private_key_openssl.cc10
-rw-r--r--base/crypto/signature_creator.h9
-rw-r--r--base/crypto/signature_creator_openssl.cc33
-rw-r--r--base/crypto/signature_verifier.h5
-rw-r--r--base/crypto/signature_verifier_openssl.cc66
-rw-r--r--base/crypto/symmetric_key_openssl.cc28
-rw-r--r--base/openssl_util.cc6
-rw-r--r--base/openssl_util.h35
-rw-r--r--net/base/cert_test_util.cc2
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;
}
}