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