Home | History | Annotate | Download | only in crypto
      1 // Copyright (c) 2009 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 "base/crypto/rsa_private_key.h"
      6 
      7 #include <cryptohi.h>
      8 #include <keyhi.h>
      9 #include <pk11pub.h>
     10 
     11 #include <iostream>
     12 #include <list>
     13 
     14 #include "base/logging.h"
     15 #include "base/nss_util.h"
     16 #include "base/scoped_ptr.h"
     17 #include "base/string_util.h"
     18 
     19 // TODO(rafaelw): Consider refactoring common functions and definitions from
     20 // rsa_private_key_win.cc or using NSS's ASN.1 encoder.
     21 namespace {
     22 
     23 static bool ReadAttribute(SECKEYPrivateKey* key,
     24                           CK_ATTRIBUTE_TYPE type,
     25                           std::vector<uint8>* output) {
     26   SECItem item;
     27   SECStatus rv;
     28   rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item);
     29   if (rv != SECSuccess) {
     30     NOTREACHED();
     31     return false;
     32   }
     33 
     34   output->assign(item.data, item.data + item.len);
     35   SECITEM_FreeItem(&item, PR_FALSE);
     36   return true;
     37 }
     38 
     39 }  // namespace
     40 
     41 namespace base {
     42 
     43 // static
     44 RSAPrivateKey* RSAPrivateKey::Create(uint16 num_bits) {
     45   scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
     46 
     47   PK11SlotInfo *slot = PK11_GetInternalSlot();
     48   if (!slot)
     49     return NULL;
     50 
     51   PK11RSAGenParams param;
     52   param.keySizeInBits = num_bits;
     53   param.pe = 65537L;
     54   result->key_ = PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &param,
     55       &result->public_key_, PR_FALSE, PR_FALSE, NULL);
     56   PK11_FreeSlot(slot);
     57   if (!result->key_)
     58     return NULL;
     59 
     60   return result.release();
     61 }
     62 
     63 // static
     64 RSAPrivateKey* RSAPrivateKey::CreateFromPrivateKeyInfo(
     65     const std::vector<uint8>& input) {
     66   scoped_ptr<RSAPrivateKey> result(new RSAPrivateKey);
     67 
     68   PK11SlotInfo *slot = PK11_GetInternalSlot();
     69   if (!slot)
     70     return NULL;
     71 
     72   SECItem der_private_key_info;
     73   der_private_key_info.data = const_cast<unsigned char*>(&input.front());
     74   der_private_key_info.len = input.size();
     75   SECStatus rv =  PK11_ImportDERPrivateKeyInfoAndReturnKey(slot,
     76       &der_private_key_info, NULL, NULL, PR_FALSE, PR_FALSE,
     77       KU_DIGITAL_SIGNATURE, &result->key_, NULL);
     78   PK11_FreeSlot(slot);
     79   if (rv != SECSuccess) {
     80     NOTREACHED();
     81     return NULL;
     82   }
     83 
     84   result->public_key_ = SECKEY_ConvertToPublicKey(result->key_);
     85   if (!result->public_key_) {
     86     NOTREACHED();
     87     return NULL;
     88   }
     89 
     90   return result.release();
     91 }
     92 
     93 RSAPrivateKey::RSAPrivateKey() : key_(NULL), public_key_(NULL) {
     94   EnsureNSSInit();
     95 }
     96 
     97 RSAPrivateKey::~RSAPrivateKey() {
     98   if (key_)
     99     SECKEY_DestroyPrivateKey(key_);
    100   if (public_key_)
    101     SECKEY_DestroyPublicKey(public_key_);
    102 }
    103 
    104 bool RSAPrivateKey::ExportPrivateKey(std::vector<uint8>* output) {
    105   PrivateKeyInfoCodec private_key_info(true);
    106 
    107   // Manually read the component attributes of the private key and build up
    108   // the PrivateKeyInfo.
    109   if (!ReadAttribute(key_, CKA_MODULUS, private_key_info.modulus()) ||
    110       !ReadAttribute(key_, CKA_PUBLIC_EXPONENT,
    111           private_key_info.public_exponent()) ||
    112       !ReadAttribute(key_, CKA_PRIVATE_EXPONENT,
    113           private_key_info.private_exponent()) ||
    114       !ReadAttribute(key_, CKA_PRIME_1, private_key_info.prime1()) ||
    115       !ReadAttribute(key_, CKA_PRIME_2, private_key_info.prime2()) ||
    116       !ReadAttribute(key_, CKA_EXPONENT_1, private_key_info.exponent1()) ||
    117       !ReadAttribute(key_, CKA_EXPONENT_2, private_key_info.exponent2()) ||
    118       !ReadAttribute(key_, CKA_COEFFICIENT, private_key_info.coefficient())) {
    119     NOTREACHED();
    120     return false;
    121   }
    122 
    123   return private_key_info.Export(output);
    124 }
    125 
    126 bool RSAPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
    127   SECItem* der_pubkey = SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_);
    128   if (!der_pubkey) {
    129     NOTREACHED();
    130     return false;
    131   }
    132 
    133   for (size_t i = 0; i < der_pubkey->len; ++i)
    134     output->push_back(der_pubkey->data[i]);
    135 
    136   SECITEM_FreeItem(der_pubkey, PR_TRUE);
    137   return true;
    138 }
    139 
    140 }  // namespace base
    141