blob: da8d9c39b153c80c948f367dcfd9aff3d59a3487 [file] [log] [blame]
davidben85bad9e2015-05-11 20:20:101// 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>
rsleevia3ad8d02016-06-07 18:22:3310#include <secmod.h>
avidd373b8b2015-12-21 21:34:4311#include <stdint.h>
davidben85bad9e2015-05-11 20:20:1012
thakisd1a18472016-04-08 22:30:4113#include <memory>
14
davidben85bad9e2015-05-11 20:20:1015#include "base/logging.h"
davidben85bad9e2015-05-11 20:20:1016#include "crypto/nss_util.h"
davidben85bad9e2015-05-11 20:20:1017#include "crypto/nss_util_internal.h"
davidben85bad9e2015-05-11 20:20:1018
19namespace crypto {
20
21namespace {
22
davidben85bad9e2015-05-11 20:20:1023struct PublicKeyInfoDeleter {
24 inline void operator()(CERTSubjectPublicKeyInfo* spki) {
25 SECKEY_DestroySubjectPublicKeyInfo(spki);
26 }
27};
28
thakisd1a18472016-04-08 22:30:4129typedef std::unique_ptr<CERTSubjectPublicKeyInfo, PublicKeyInfoDeleter>
davidben85bad9e2015-05-11 20:20:1030 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.
34ScopedSECItem MakeIDFromSPKI(const std::vector<uint8_t>& input) {
35 // First, decode and save the public key.
36 SECItem key_der;
37 key_der.type = siBuffer;
davidben4507eaa2015-11-19 19:07:0638 key_der.data = const_cast<unsigned char*>(input.data());
davidben85bad9e2015-05-11 20:20:1039 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
davidben85bad9e2015-05-11 20:20:1057} // namespace
58
59bool 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
80ScopedSECKEYPrivateKey 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;
davidben4507eaa2015-11-19 19:07:0692 input_item.data = const_cast<unsigned char*>(input.data());
davidben85bad9e2015-05-11 20:20:1093 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
davidben85bad9e2015-05-11 20:20:10114ScopedSECKEYPrivateKey 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)
dchenge48600452015-12-28 02:24:50133 return key;
davidben85bad9e2015-05-11 20:20:10134 }
135 }
136
137 // The key wasn't found in any module.
138 return nullptr;
139}
140
141ScopedSECKEYPrivateKey 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
davidben85bad9e2015-05-11 20:20:10154} // namespace crypto