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