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)
162116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (SECKEY_GetPublicKeyType(*public_key) != ecKey) {
163116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    DLOG(ERROR) << "The public key is not an EC key";
164116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    SECKEY_DestroyPublicKey(*public_key);
165116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    *public_key = NULL;
166116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
167116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
168116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem encoded_epki = {
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    siBuffer,
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const_cast<unsigned char*>(encrypted_private_key_info),
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<unsigned>(encrypted_private_key_info_len)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECKEYEncryptedPrivateKeyInfo epki;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memset(&epki, 0, sizeof(epki));
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECStatus rv = SEC_QuickDERDecodeItem(
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      arena.get(),
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &epki,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate),
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &encoded_epki);
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != SECSuccess) {
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "SEC_QuickDERDecodeItem: " << PORT_GetError();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SECKEY_DestroyPublicKey(*public_key);
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *public_key = NULL;
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem password_item = {
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    siBuffer,
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())),
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<unsigned>(password.size())
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  rv = ImportEncryptedECPrivateKeyInfoAndReturnKey(
198f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      slot,
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &epki,
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &password_item,
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL,  // nickname
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &(*public_key)->u.ec.publicValue,
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      permanent,
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sensitive,
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key,
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL);  // wincx
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (rv != SECSuccess) {
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "ImportEncryptedECPrivateKeyInfoAndReturnKey: "
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                << PORT_GetError();
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SECKEY_DestroyPublicKey(*public_key);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *public_key = NULL;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
218116680a4aac90f2aa7413d9095a592090648e557Ben MurdochECPrivateKey* ECPrivateKey::Copy() const {
219116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<ECPrivateKey> copy(new ECPrivateKey);
220116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (key_) {
221116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    copy->key_ = SECKEY_CopyPrivateKey(key_);
222116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!copy->key_)
223116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return NULL;
224116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
225116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (public_key_) {
226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    copy->public_key_ = SECKEY_CopyPublicKey(public_key_);
227116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (!copy->public_key_)
228116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      return NULL;
229116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
230116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return copy.release();
231116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
232116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ECPrivateKey::ExportEncryptedPrivateKey(
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& password,
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int iterations,
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<uint8>* output) {
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We export as an EncryptedPrivateKeyInfo bundle instead of a plain PKCS #8
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // PrivateKeyInfo because PK11_ImportDERPrivateKeyInfoAndReturnKey doesn't
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // support EC keys.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // https://bugzilla.mozilla.org/show_bug.cgi?id=327773
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem password_item = {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    siBuffer,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reinterpret_cast<unsigned char*>(const_cast<char*>(password.data())),
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<unsigned>(password.size())
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECKEYEncryptedPrivateKeyInfo* encrypted = PK11_ExportEncryptedPrivKeyInfo(
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NULL,  // Slot, optional.
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &password_item,
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      key_,
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      iterations,
2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NULL);  // wincx.
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!encrypted) {
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "PK11_ExportEncryptedPrivKeyInfo: " << PORT_GetError();
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem der_key = {siBuffer, NULL, 0};
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem* encoded_item = SEC_ASN1EncodeItem(
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      arena.get(),
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &der_key,
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      encrypted,
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate));
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECKEY_DestroyEncryptedPrivateKeyInfo(encrypted, PR_TRUE);
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!encoded_item) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "SEC_ASN1EncodeItem: " << PORT_GetError();
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->assign(der_key.data, der_key.data + der_key.len);
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ECPrivateKey::ExportPublicKey(std::vector<uint8>* output) {
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ScopedSECItem der_pubkey(
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      SECKEY_EncodeDERSubjectPublicKeyInfo(public_key_));
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!der_pubkey.get()) {
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  output->assign(der_pubkey->data, der_pubkey->data + der_pubkey->len);
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
289116680a4aac90f2aa7413d9095a592090648e557Ben Murdochbool ECPrivateKey::ExportRawPublicKey(std::string* output) {
290116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // public_key_->u.ec.publicValue is an ANSI X9.62 public key which, for
291116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // a P-256 key, is 0x04 (meaning uncompressed) followed by the x and y field
292116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // elements as 32-byte, big-endian numbers.
293116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  static const unsigned int kExpectedKeyLength = 65;
294116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
295116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(public_key_));
296116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const unsigned char* const data = public_key_->u.ec.publicValue.data;
297116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  const unsigned int len = public_key_->u.ec.publicValue.len;
298116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (len != kExpectedKeyLength || data[0] != 0x04)
299116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    return false;
300116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
301116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  output->assign(reinterpret_cast<const char*>(data + 1),
302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                 kExpectedKeyLength - 1);
303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  return true;
304116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch}
305116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ECPrivateKey::ExportValue(std::vector<uint8>* output) {
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ReadAttribute(key_, CKA_VALUE, output);
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ECPrivateKey::ExportECParams(std::vector<uint8>* output) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ReadAttribute(key_, CKA_EC_PARAMS, output);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ECPrivateKey::ECPrivateKey() : key_(NULL), public_key_(NULL) {}
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)ECPrivateKey* ECPrivateKey::CreateWithParams(PK11SlotInfo* slot,
318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                             bool permanent,
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                             bool sensitive) {
320f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  if (!slot)
321f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    return NULL;
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ECPrivateKey> result(new ECPrivateKey);
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECOidData* oid_data = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!oid_data) {
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "SECOID_FindOIDByTag: " << PORT_GetError();
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // SECKEYECParams is a SECItem containing the DER encoded ASN.1 ECParameters
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // value.  For a named curve, that is just the OBJECT IDENTIFIER of the curve.
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // In addition to the oid data, the encoding requires one byte for the ASN.1
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // tag and one byte for the length (assuming the length is <= 127).
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(oid_data->oid.len, 127U);
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<unsigned char> parameters_buf(2 + oid_data->oid.len);
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECKEYECParams ec_parameters = {
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    siDEROID, &parameters_buf[0],
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<unsigned>(parameters_buf.size())
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ec_parameters.data[0] = SEC_ASN1_OBJECT_ID;
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ec_parameters.data[1] = oid_data->oid.len;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(ec_parameters.data + 2, oid_data->oid.data, oid_data->oid.len);
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
346f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  result->key_ = PK11_GenerateKeyPair(slot,
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      CKM_EC_KEY_PAIR_GEN,
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &ec_parameters,
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      &result->public_key_,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      permanent,
3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      sensitive,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                      NULL);
3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!result->key_) {
3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "PK11_GenerateKeyPair: " << PORT_GetError();
3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
357116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(result->public_key_));
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return result.release();
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ECPrivateKey* ECPrivateKey::CreateFromEncryptedPrivateKeyInfoWithParams(
364f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    PK11SlotInfo* slot,
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& password,
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<uint8>& encrypted_private_key_info,
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::vector<uint8>& subject_public_key_info,
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool permanent,
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    bool sensitive) {
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ECPrivateKey> result(new ECPrivateKey);
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECItem encoded_spki = {
3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    siBuffer,
3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const_cast<unsigned char*>(&subject_public_key_info[0]),
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static_cast<unsigned>(subject_public_key_info.size())
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CERTSubjectPublicKeyInfo* decoded_spki = SECKEY_DecodeDERSubjectPublicKeyInfo(
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &encoded_spki);
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!decoded_spki) {
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DLOG(ERROR) << "SECKEY_DecodeDERSubjectPublicKeyInfo: " << PORT_GetError();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
384f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  bool success = ImportFromEncryptedPrivateKeyInfo(
385f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      slot,
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      password,
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &encrypted_private_key_info[0],
3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      encrypted_private_key_info.size(),
3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      decoded_spki,
3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      permanent,
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      sensitive,
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &result->key_,
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      &result->public_key_);
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SECKEY_DestroySubjectPublicKeyInfo(decoded_spki);
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
397116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  if (success) {
398116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    CHECK_EQ(ecKey, SECKEY_GetPublicKeyType(result->public_key_));
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return result.release();
400116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  }
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace crypto
406