Home | History | Annotate | Download | only in ssl
      1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/ssl/openssl_client_key_store.h"
      6 
      7 #include <openssl/evp.h>
      8 #include <openssl/x509.h>
      9 
     10 #include "base/memory/scoped_ptr.h"
     11 #include "base/memory/singleton.h"
     12 #include "net/cert/x509_certificate.h"
     13 
     14 namespace net {
     15 
     16 namespace {
     17 
     18 // Return the EVP_PKEY holding the public key of a given certificate.
     19 // |cert| is a certificate.
     20 // Returns a scoped EVP_PKEY for it.
     21 crypto::ScopedEVP_PKEY GetOpenSSLPublicKey(const X509Certificate* cert) {
     22   // X509_PUBKEY_get() increments the reference count of its result.
     23   // Unlike X509_get_X509_PUBKEY() which simply returns a direct pointer.
     24   EVP_PKEY* pkey =
     25       X509_PUBKEY_get(X509_get_X509_PUBKEY(cert->os_cert_handle()));
     26   if (!pkey)
     27     LOG(ERROR) << "Can't extract private key from certificate!";
     28   return crypto::ScopedEVP_PKEY(pkey);
     29 }
     30 
     31 }  // namespace
     32 
     33 OpenSSLClientKeyStore::OpenSSLClientKeyStore() {
     34 }
     35 
     36 OpenSSLClientKeyStore::~OpenSSLClientKeyStore() {
     37 }
     38 
     39 OpenSSLClientKeyStore::KeyPair::KeyPair(EVP_PKEY* pub_key,
     40                                         EVP_PKEY* priv_key)
     41     : public_key(EVP_PKEY_dup(pub_key)),
     42       private_key(EVP_PKEY_dup(priv_key)) {
     43 }
     44 
     45 OpenSSLClientKeyStore::KeyPair::~KeyPair() {
     46 }
     47 
     48 OpenSSLClientKeyStore::KeyPair::KeyPair(const KeyPair& other)
     49     : public_key(EVP_PKEY_dup(other.public_key.get())),
     50       private_key(EVP_PKEY_dup(other.private_key.get())) {
     51 }
     52 
     53 void OpenSSLClientKeyStore::KeyPair::operator=(const KeyPair& other) {
     54   // Use a temporary ScopedEVP_PKEY because scoped_ptr does not allow resetting
     55   // to the current value, even though it's safe here.
     56   crypto::ScopedEVP_PKEY public_key_tmp(EVP_PKEY_dup(other.public_key.get()));
     57   crypto::ScopedEVP_PKEY private_key_tmp(EVP_PKEY_dup(other.private_key.get()));
     58   public_key.reset();
     59   public_key = public_key_tmp.Pass();
     60   private_key.reset();
     61   private_key = private_key_tmp.Pass();
     62 }
     63 
     64 int OpenSSLClientKeyStore::FindKeyPairIndex(EVP_PKEY* public_key) {
     65   if (!public_key)
     66     return -1;
     67   for (size_t n = 0; n < pairs_.size(); ++n) {
     68     if (EVP_PKEY_cmp(pairs_[n].public_key.get(), public_key) == 1)
     69       return static_cast<int>(n);
     70   }
     71   return -1;
     72 }
     73 
     74 void OpenSSLClientKeyStore::AddKeyPair(EVP_PKEY* pub_key,
     75                                        EVP_PKEY* private_key) {
     76   int index = FindKeyPairIndex(pub_key);
     77   if (index < 0)
     78     pairs_.push_back(KeyPair(pub_key, private_key));
     79 }
     80 
     81 // Common code for OpenSSLClientKeyStore. Shared by all OpenSSL-based
     82 // builds.
     83 bool OpenSSLClientKeyStore::RecordClientCertPrivateKey(
     84     const X509Certificate* client_cert,
     85     EVP_PKEY* private_key) {
     86   // Sanity check.
     87   if (!client_cert || !private_key)
     88     return false;
     89 
     90   // Get public key from certificate.
     91   crypto::ScopedEVP_PKEY pub_key(GetOpenSSLPublicKey(client_cert));
     92   if (!pub_key.get())
     93     return false;
     94 
     95   AddKeyPair(pub_key.get(), private_key);
     96   return true;
     97 }
     98 
     99 crypto::ScopedEVP_PKEY OpenSSLClientKeyStore::FetchClientCertPrivateKey(
    100     const X509Certificate* client_cert) {
    101   if (!client_cert)
    102     return crypto::ScopedEVP_PKEY();
    103 
    104   crypto::ScopedEVP_PKEY pub_key(GetOpenSSLPublicKey(client_cert));
    105   if (!pub_key.get())
    106     return crypto::ScopedEVP_PKEY();
    107 
    108   int index = FindKeyPairIndex(pub_key.get());
    109   if (index < 0)
    110     return crypto::ScopedEVP_PKEY();
    111 
    112   return crypto::ScopedEVP_PKEY(EVP_PKEY_dup(pairs_[index].private_key.get()));
    113 }
    114 
    115 void OpenSSLClientKeyStore::Flush() {
    116   pairs_.clear();
    117 }
    118 
    119 OpenSSLClientKeyStore* OpenSSLClientKeyStore::GetInstance() {
    120   return Singleton<OpenSSLClientKeyStore>::get();
    121 }
    122 
    123 }  // namespace net
    124 
    125 
    126