Home | History | Annotate | Download | only in crypto
      1 // Copyright 2015 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/nss_key_util.h"
      6 
      7 #include <cryptohi.h>
      8 #include <keyhi.h>
      9 #include <pk11pub.h>
     10 #include <secmod.h>
     11 #include <stdint.h>
     12 
     13 #include <memory>
     14 
     15 #include "base/logging.h"
     16 #include "crypto/nss_util.h"
     17 #include "crypto/nss_util_internal.h"
     18 
     19 namespace crypto {
     20 
     21 namespace {
     22 
     23 struct PublicKeyInfoDeleter {
     24   inline void operator()(CERTSubjectPublicKeyInfo* spki) {
     25     SECKEY_DestroySubjectPublicKeyInfo(spki);
     26   }
     27 };
     28 
     29 typedef std::unique_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter>
     30     ScopedPublicKeyInfo;
     31 
     32 // Decodes |input| as a SubjectPublicKeyInfo and returns a SECItem containing
     33 // the CKA_ID of that public key or nullptr on error.
     34 ScopedSECItem MakeIDFromSPKI(const std::vector<uint8_t>& input) {
     35   // First, decode and save the public key.
     36   SECItem key_der;
     37   key_der.type = siBuffer;
     38   key_der.data = const_cast<unsigned char*>(input.data());
     39   key_der.len = input.size();
     40 
     41   ScopedPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&key_der));
     42   if (!spki)
     43     return nullptr;
     44 
     45   ScopedSECKEYPublicKey result(SECKEY_ExtractPublicKey(spki.get()));
     46   if (!result)
     47     return nullptr;
     48 
     49   // See pk11_MakeIDFromPublicKey from NSS. For now, only RSA keys are
     50   // supported.
     51   if (SECKEY_GetPublicKeyType(result.get()) != rsaKey)
     52     return nullptr;
     53 
     54   return ScopedSECItem(PK11_MakeIDFromPubKey(&result->u.rsa.modulus));
     55 }
     56 
     57 }  // namespace
     58 
     59 bool GenerateRSAKeyPairNSS(PK11SlotInfo* slot,
     60                            uint16_t num_bits,
     61                            bool permanent,
     62                            ScopedSECKEYPublicKey* public_key,
     63                            ScopedSECKEYPrivateKey* private_key) {
     64   DCHECK(slot);
     65 
     66   PK11RSAGenParams param;
     67   param.keySizeInBits = num_bits;
     68   param.pe = 65537L;
     69   SECKEYPublicKey* public_key_raw = nullptr;
     70   private_key->reset(PK11_GenerateKeyPair(slot, CKM_RSA_PKCS_KEY_PAIR_GEN,
     71                                           &param, &public_key_raw, permanent,
     72                                           permanent /* sensitive */, nullptr));
     73   if (!*private_key)
     74     return false;
     75 
     76   public_key->reset(public_key_raw);
     77   return true;
     78 }
     79 
     80 ScopedSECKEYPrivateKey ImportNSSKeyFromPrivateKeyInfo(
     81     PK11SlotInfo* slot,
     82     const std::vector<uint8_t>& input,
     83     bool permanent) {
     84   DCHECK(slot);
     85 
     86   ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
     87   DCHECK(arena);
     88 
     89   // Excess data is illegal, but NSS silently accepts it, so first ensure that
     90   // |input| consists of a single ASN.1 element.
     91   SECItem input_item;
     92   input_item.data = const_cast<unsigned char*>(input.data());
     93   input_item.len = input.size();
     94   SECItem der_private_key_info;
     95   SECStatus rv =
     96       SEC_QuickDERDecodeItem(arena.get(), &der_private_key_info,
     97                              SEC_ASN1_GET(SEC_AnyTemplate), &input_item);
     98   if (rv != SECSuccess)
     99     return nullptr;
    100 
    101   // Allow the private key to be used for key unwrapping, data decryption,
    102   // and signature generation.
    103   const unsigned int key_usage =
    104       KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT | KU_DIGITAL_SIGNATURE;
    105   SECKEYPrivateKey* key_raw = nullptr;
    106   rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
    107       slot, &der_private_key_info, nullptr, nullptr, permanent,
    108       permanent /* sensitive */, key_usage, &key_raw, nullptr);
    109   if (rv != SECSuccess)
    110     return nullptr;
    111   return ScopedSECKEYPrivateKey(key_raw);
    112 }
    113 
    114 ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfo(
    115     const std::vector<uint8_t>& input) {
    116   EnsureNSSInit();
    117 
    118   ScopedSECItem cka_id(MakeIDFromSPKI(input));
    119   if (!cka_id)
    120     return nullptr;
    121 
    122   // Search all slots in all modules for the key with the given ID.
    123   AutoSECMODListReadLock auto_lock;
    124   const SECMODModuleList* head = SECMOD_GetDefaultModuleList();
    125   for (const SECMODModuleList* item = head; item != nullptr;
    126        item = item->next) {
    127     int slot_count = item->module->loaded ? item->module->slotCount : 0;
    128     for (int i = 0; i < slot_count; i++) {
    129       // Look for the key in slot |i|.
    130       ScopedSECKEYPrivateKey key(
    131           PK11_FindKeyByKeyID(item->module->slots[i], cka_id.get(), nullptr));
    132       if (key)
    133         return key;
    134     }
    135   }
    136 
    137   // The key wasn't found in any module.
    138   return nullptr;
    139 }
    140 
    141 ScopedSECKEYPrivateKey FindNSSKeyFromPublicKeyInfoInSlot(
    142     const std::vector<uint8_t>& input,
    143     PK11SlotInfo* slot) {
    144   DCHECK(slot);
    145 
    146   ScopedSECItem cka_id(MakeIDFromSPKI(input));
    147   if (!cka_id)
    148     return nullptr;
    149 
    150   return ScopedSECKEYPrivateKey(
    151       PK11_FindKeyByKeyID(slot, cka_id.get(), nullptr));
    152 }
    153 
    154 }  // namespace crypto
    155