Home | History | Annotate | Download | only in crypto
      1 // Copyright (c) 2011 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 "crypto/rsa_private_key.h"
      6 
      7 #include <openssl/bio.h>
      8 #include <openssl/bn.h>
      9 #include <openssl/evp.h>
     10 #include <openssl/pkcs12.h>
     11 #include <openssl/rsa.h>
     12 #include <stdint.h>
     13 
     14 #include "base/logging.h"
     15 #include "base/memory/scoped_ptr.h"
     16 #include "crypto/openssl_util.h"
     17 #include "crypto/scoped_openssl_types.h"
     18 
     19 namespace crypto {
     20 
     21 namespace {
     22 
     23 using ScopedPKCS8_PRIV_KEY_INFO =
     24     ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
     25 
     26 // Function pointer definition, for injecting the required key export function
     27 // into ExportKey, below. The supplied function should export EVP_PKEY into
     28 // the supplied BIO, returning 1 on success or 0 on failure.
     29 using ExportFunction = int (*)(BIO*, EVP_PKEY*);
     30 
     31 // Helper to export |key| into |output| via the specified ExportFunction.
     32 bool ExportKey(EVP_PKEY* key,
     33                ExportFunction export_fn,
     34                std::vector<uint8_t>* output) {
     35   if (!key)
     36     return false;
     37 
     38   OpenSSLErrStackTracer err_tracer(FROM_HERE);
     39   ScopedBIO bio(BIO_new(BIO_s_mem()));
     40 
     41   int res = export_fn(bio.get(), key);
     42   if (!res)
     43     return false;
     44 
     45   char* data = NULL;
     46   long len = BIO_get_mem_data(bio.get(), &data);
     47   if (!data || len < 0)
     48     return false;
     49 
     50   output->assign(data, data + len);
     51   return true;
     52 }
     53 
     54 }  // namespace
     55 
     56 // static
     57 RSAPrivateKey* RSAPrivateKey::Create(uint16_t num_bits) {
     58   OpenSSLErrStackTracer err_tracer(FROM_HERE);
     59 
     60   ScopedRSA rsa_key(RSA_new());
     61   ScopedBIGNUM bn(BN_new());
     62   if (!rsa_key.get() || !bn.get() || !BN_set_word(bn.get(), 65537L))
     63     return NULL;
     64 
     65   if (!RSA_generate_key_ex(rsa_key.get(), num_bits, bn.get(), NULL))
     66     return NULL;
     67 
     68   scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
     69   result->key_ = EVP_PKEY_new();
     70   if (!result->key_ || !EVP_PKEY_set1_RSA(result->key_, rsa_key.get()))
     71     return NULL;
     72 
     73   return result.release();
     74 }
     75 
     76 // static
     77 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
     78     const std::vector<uint8_t>& input) {
     79   if (input.empty())
     80     return NULL;
     81 
     82   OpenSSLErrStackTracer err_tracer(FROM_HERE);
     83 
     84   // Importing is a little more involved than exporting, as we must first
     85   // PKCS#8 decode the input, and then import the EVP_PKEY from Private Key
     86   // Info structure returned.
     87   const uint8_t* ptr = &input[0];
     88   ScopedPKCS8_PRIV_KEY_INFO p8inf(
     89       d2i_PKCS8_PRIV_KEY_INFO(nullptr, &ptr, input.size()));
     90   if (!p8inf.get() || ptr != &input[0] + input.size())
     91     return NULL;
     92 
     93   scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
     94   result->key_ = EVP_PKCS82PKEY(p8inf.get());
     95   if (!result->key_ || EVP_PKEY_id(result->key_) != EVP_PKEY_RSA)
     96     return NULL;
     97 
     98   return result.release();
     99 }
    100 
    101 // static
    102 RSAPrivateKey* RSAPrivateKey::CreateFromKey(EVP_PKEY* key) {
    103   DCHECK(key);
    104   if (EVP_PKEY_type(key->type) != EVP_PKEY_RSA)
    105     return NULL;
    106   RSAPrivateKey* copy = new RSAPrivateKey();
    107   copy->key_ = EVP_PKEY_up_ref(key);
    108   return copy;
    109 }
    110 
    111 RSAPrivateKey::RSAPrivateKey()
    112     : key_(NULL) {
    113 }
    114 
    115 RSAPrivateKey::~RSAPrivateKey() {
    116   if (key_)
    117     EVP_PKEY_free(key_);
    118 }
    119 
    120 RSAPrivateKey* RSAPrivateKey::Copy() const {
    121   scoped_ptr<RSAPrivateKey> copy(new RSAPrivateKey());
    122   ScopedRSA rsa(EVP_PKEY_get1_RSA(key_));
    123   if (!rsa)
    124     return NULL;
    125   copy->key_ = EVP_PKEY_new();
    126   if (!EVP_PKEY_set1_RSA(copy->key_, rsa.get()))
    127     return NULL;
    128   return copy.release();
    129 }
    130 
    131 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8_t>* output) const {
    132   return ExportKey(key_, i2d_PKCS8PrivateKeyInfo_bio, output);
    133 }
    134 
    135 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8_t>* output) const {
    136   return ExportKey(key_, i2d_PUBKEY_bio, output);
    137 }
    138 
    139 }  // namespace crypto
    140