ec_private_key_nss.cc revision f2477e01787aa58f445919b809d89e252beef54f
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/ec_private_key.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" {
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Work around NSS missing SEC_BEGIN_PROTOS in secmodt.h.  This must come before
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// other NSS headers.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <secmodt.h>
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <cryptohi.h>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <keyhi.h>
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <pk11pub.h>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <secmod.h>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/nss_util.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/nss_util_internal.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/scoped_nss_types.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "crypto/third_party/nss/chromium-nss.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
28f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)PK11SlotInfo* GetTempKeySlot() {
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return PK11_GetInternalSlot();
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class EllipticCurveSupportChecker {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EllipticCurveSupportChecker() {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NOTE: we can do this check here only because we use the NSS internal
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // slot.  If we support other slots in the future, checking whether they
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // support ECDSA may block NSS, and the value may also change as devices are
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // inserted/removed, so we would need to re-check on every use.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    crypto::EnsureNSSInit();
40f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    crypto::ScopedPK11Slot slot(GetTempKeySlot());
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    supported_ = PK11_DoesMechanism(slot.get(), CKM_EC_KEY_PAIR_GEN) &&
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        PK11_DoesMechanism(slot.get(), CKM_ECDSA);
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Supported() {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return supported_;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool supported_;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static base::LazyInstance<EllipticCurveSupportChecker>::Leaky
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    g_elliptic_curve_supported = LAZY_INSTANCE_INITIALIZER;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copied from rsa_private_key_nss.cc.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static bool ReadAttribute(SECKEYPrivateKey* key,
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          CK_ATTRIBUTE_TYPE type,
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                          std::vector<uint8>* output) {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem item;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rv = PK11_ReadRawAttribute(PK11_TypePrivKey, key, type, &item);
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != SECSuccess) {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "PK11_ReadRawAttribute: " << PORT_GetError();
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->assign(item.data, item.data + item.len);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECITEM_FreeItem(&item, PR_FALSE);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace crypto {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ECPrivateKey::~ECPrivateKey() {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (key_)
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SECKEY_DestroyPrivateKey(key_);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (public_key_)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SECKEY_DestroyPublicKey(public_key_);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ECPrivateKey::IsSupported() {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_elliptic_curve_supported.Get().Supported();
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ECPrivateKey* ECPrivateKey::Create() {
91f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EnsureNSSInit();
92f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
93f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ScopedPK11Slot slot(GetTempKeySlot());
94f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return CreateWithParams(slot.get(),
95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          false /* not permanent */,
96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                          false /* not sensitive */);
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_NSS)
100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static
101f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ECPrivateKey* ECPrivateKey::CreateSensitive(PK11SlotInfo* slot) {
102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  return CreateWithParams(
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      slot, true /* permanent */, true /* sensitive */);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfo(
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& password,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<uint8>& encrypted_private_key_info,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<uint8>& subject_public_key_info) {
112f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  EnsureNSSInit();
113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
114f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  ScopedPK11Slot slot(GetTempKeySlot());
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CreateFromEncryptedPrivateKeyInfoWithParams(
116f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      slot.get(),
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password,
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      encrypted_private_key_info,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      subject_public_key_info,
120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      false /* not permanent */,
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      false /* not sensitive */);
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
124f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#if defined(USE_NSS)
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ECPrivateKey* ECPrivateKey::CreateSensitiveFromEncryptedPrivateKeyInfo(
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    PK11SlotInfo* slot,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& password,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<uint8>& encrypted_private_key_info,
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<uint8>& subject_public_key_info) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return CreateFromEncryptedPrivateKeyInfoWithParams(
132f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      slot,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password,
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      encrypted_private_key_info,
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      subject_public_key_info,
136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      true /* permanent */,
137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      true /* sensitive */);
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
139f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#endif
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ECPrivateKey::ImportFromEncryptedPrivateKeyInfo(
143f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    PK11SlotInfo* slot,
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& password,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const uint8* encrypted_private_key_info,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    size_t encrypted_private_key_info_len,
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CERTSubjectPublicKeyInfo* decoded_spki,
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool permanent,
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool sensitive,
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SECKEYPrivateKey** key,
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SECKEYPublicKey** public_key) {
152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!slot)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *public_key = SECKEY_ExtractPublicKey(decoded_spki);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!*public_key) {
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "SECKEY_ExtractPublicKey: " << PORT_GetError();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem encoded_epki = {
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    siBuffer,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const_cast<unsigned char*>(encrypted_private_key_info),
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<unsigned>(encrypted_private_key_info_len)
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECKEYEncryptedPrivateKeyInfo epki;
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&epki, 0, sizeof(epki));
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = SEC_QuickDERDecodeItem(
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      arena.get(),
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &epki,
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate),
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &encoded_epki);
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != SECSuccess) {
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "SEC_QuickDERDecodeItem: " << PORT_GetError();
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SECKEY_DestroyPublicKey(*public_key);
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *public_key = NULL;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem password_item = {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    siBuffer,
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())),
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<unsigned>(password.size())
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rv = ImportEncryptedECPrivateKeyInfoAndReturnKey(
191f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      slot,
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &epki,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &password_item,
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL,  // nickname
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &(*public_key)->u.ec.publicValue,
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      permanent,
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sensitive,
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL);  // wincx
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != SECSuccess) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: "
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                << PORT_GetError();
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SECKEY_DestroyPublicKey(*public_key);
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *public_key = NULL;
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ECPrivateKey::ExportEncryptedPrivateKey(
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& password,
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int iterations,
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<uint8>* output) {
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We export as an EncryptedPrivateKeyInfo bundle instead of a plain PKCS #8
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PrivateKeyInfo because PK11_ImportDERPrivateKeyInfoAndReturnKey doesn't
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // support EC keys.
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // https://bugzilla.mozilla.org/show_bug.cgi?id=327773
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem password_item = {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    siBuffer,
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())),
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<unsigned>(password.size())
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECKEYEncryptedPrivateKeyInfo* encrypted = PK11_ExportEncryptedPrivKeyInfo(
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL, // Slot, optional.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &password_item,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key_,
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iterations,
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL); // wincx.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!encrypted) {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "PK11_ExportEncryptedPrivKeyInfo: " << PORT_GetError();
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem der_key = {siBuffer, NULL, 0};
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem* encoded_item = SEC_ASN1EncodeItem(
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      arena.get(),
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &der_key,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      encrypted,
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate));
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECKEY_DestroyEncryptedPrivateKeyInfo(encrypted, PR_TRUE);
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!encoded_item) {
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "SEC_ASN1EncodeItem: " << PORT_GetError();
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->assign(der_key.data, der_key.data + der_key.len);
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ECPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedSECItem der_pubkey(
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_));
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!der_pubkey.get()) {
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len);
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ECPrivateKey::ExportValue(std::vector<uint8>* output) {
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ReadAttribute(key_, CKA_VALUE, output);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ReadAttribute(key_, CKA_EC_PARAMS, output);
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ECPrivateKey::ECPrivateKey() : key_(NULL), public_key_(NULL) {}
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
278f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ECPrivateKey* ECPrivateKey::CreateWithParams(PK11SlotInfo* slot,
279f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                             bool permanent,
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             bool sensitive) {
281f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!slot)
282f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return NULL;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ECPrivateKey> result(new ECPrivateKey);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!oid_data) {
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError();
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // value.  For a named curve, that is just the OBJECT IDENTIFIER of the curve.
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In addition to the oid data, the encoding requires one byte for the ASN.1
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // tag and one byte for the length (assuming the length is <= 127).
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(oid_data->oid.len, 127U);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<unsigned char> parameters_buf(2 + oid_data->oid.len);
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECKEYECParams ec_parameters = {
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    siDEROID, &parameters_buf[0],
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<unsigned>(parameters_buf.size())
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ec_parameters.data[0] = SEC_ASN1_OBJECT_ID;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ec_parameters.data[1] = oid_data->oid.len;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len);
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
307f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  result->key_ = PK11_GenerateKeyPair(slot,
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      CKM_EC_KEY_PAIR_GEN,
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &ec_parameters,
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &result->public_key_,
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      permanent,
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      sensitive,
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      NULL);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result->key_) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "PK11_GenerateKeyPair: " << PORT_GetError();
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result.release();
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfoWithParams(
324f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    PK11SlotInfo* slot,
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& password,
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<uint8>& encrypted_private_key_info,
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<uint8>& subject_public_key_info,
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool permanent,
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool sensitive) {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ECPrivateKey> result(new ECPrivateKey);
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem encoded_spki = {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    siBuffer,
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const_cast<unsigned char*>(&subject_public_key_info[0]),
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<unsigned>(subject_public_key_info.size())
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTSubjectPublicKeyInfo* decoded_spki = SECKEY_DecodeDERSubjectPublicKeyInfo(
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &encoded_spki);
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!decoded_spki) {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError();
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
344f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool success = ImportFromEncryptedPrivateKeyInfo(
345f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      slot,
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password,
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &encrypted_private_key_info[0],
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      encrypted_private_key_info.size(),
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      decoded_spki,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      permanent,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sensitive,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &result->key_,
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &result->public_key_);
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECKEY_DestroySubjectPublicKeyInfo(decoded_spki);
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (success)
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result.release();
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace crypto
364