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