blob: 1a6fc08de9d9466c5c0a9f685f58697f404ee142 [file] [log] [blame]
Yingdi Yu202a2e92015-07-12 16:49:25 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Luca Keidel941fd8c2017-07-24 15:21:22 +02002/*
Davide Pesavento3c7969f2018-09-08 15:31:35 -04003 * Copyright (c) 2013-2018 Regents of the University of California.
Yingdi Yu202a2e92015-07-12 16:49:25 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
20 */
21
22#include "private-key.hpp"
Yingdi Yu202a2e92015-07-12 16:49:25 -070023#include "base64-decode.hpp"
Davide Pesaventoe1789892017-02-26 15:50:52 -050024#include "base64-encode.hpp"
25#include "buffer-source.hpp"
Yingdi Yu202a2e92015-07-12 16:49:25 -070026#include "stream-sink.hpp"
Davide Pesaventoe1789892017-02-26 15:50:52 -050027#include "stream-source.hpp"
Yingdi Yu202a2e92015-07-12 16:49:25 -070028#include "../detail/openssl-helper.hpp"
29#include "../key-params.hpp"
Davide Pesaventoe1789892017-02-26 15:50:52 -050030#include "../../encoding/buffer-stream.hpp"
Yingdi Yu202a2e92015-07-12 16:49:25 -070031
Davide Pesaventof45fa212017-09-14 17:23:56 -040032#include <boost/lexical_cast.hpp>
Davide Pesaventoe1789892017-02-26 15:50:52 -050033#include <cstring>
Yingdi Yu202a2e92015-07-12 16:49:25 -070034
35#define ENSURE_PRIVATE_KEY_LOADED(key) \
36 do { \
Davide Pesaventof45fa212017-09-14 17:23:56 -040037 if ((key) == nullptr) \
Yingdi Yu202a2e92015-07-12 16:49:25 -070038 BOOST_THROW_EXCEPTION(Error("Private key has not been loaded yet")); \
39 } while (false)
40
Davide Pesaventof45fa212017-09-14 17:23:56 -040041#define ENSURE_PRIVATE_KEY_NOT_LOADED(key) \
42 do { \
43 if ((key) != nullptr) \
44 BOOST_THROW_EXCEPTION(Error("Private key has already been loaded")); \
45 } while (false)
46
Yingdi Yu202a2e92015-07-12 16:49:25 -070047namespace ndn {
48namespace security {
49namespace transform {
50
Luca Keidel941fd8c2017-07-24 15:21:22 +020051static void
52opensslInitAlgorithms()
53{
54#if OPENSSL_VERSION_NUMBER < 0x1010000fL
55 static bool isInitialized = false;
56 if (!isInitialized) {
57 OpenSSL_add_all_algorithms();
58 isInitialized = true;
59 }
60#endif // OPENSSL_VERSION_NUMBER < 0x1010000fL
61}
62
Yingdi Yu202a2e92015-07-12 16:49:25 -070063class PrivateKey::Impl
64{
65public:
Davide Pesaventof45fa212017-09-14 17:23:56 -040066 Impl() noexcept
Yingdi Yu202a2e92015-07-12 16:49:25 -070067 : key(nullptr)
68 {
69 }
70
71 ~Impl()
72 {
73 EVP_PKEY_free(key);
74 }
75
76public:
77 EVP_PKEY* key;
78};
79
80PrivateKey::PrivateKey()
Davide Pesaventof45fa212017-09-14 17:23:56 -040081 : m_impl(make_unique<Impl>())
Yingdi Yu202a2e92015-07-12 16:49:25 -070082{
83}
84
85PrivateKey::~PrivateKey() = default;
86
Davide Pesavento06f1bdf2017-09-16 18:59:15 -040087KeyType
88PrivateKey::getKeyType() const
89{
90 if (!m_impl->key)
91 return KeyType::NONE;
92
93 switch (detail::getEvpPkeyType(m_impl->key)) {
94 case EVP_PKEY_RSA:
95 return KeyType::RSA;
96 case EVP_PKEY_EC:
97 return KeyType::EC;
98 default:
99 return KeyType::NONE;
100 }
101}
102
Yingdi Yu202a2e92015-07-12 16:49:25 -0700103void
104PrivateKey::loadPkcs1(const uint8_t* buf, size_t size)
105{
Davide Pesaventof45fa212017-09-14 17:23:56 -0400106 ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key);
107 opensslInitAlgorithms();
Yingdi Yu202a2e92015-07-12 16:49:25 -0700108
Davide Pesaventof45fa212017-09-14 17:23:56 -0400109 if (d2i_AutoPrivateKey(&m_impl->key, &buf, static_cast<long>(size)) == nullptr)
110 BOOST_THROW_EXCEPTION(Error("Failed to load private key"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700111}
112
113void
114PrivateKey::loadPkcs1(std::istream& is)
115{
116 OBufferStream os;
117 streamSource(is) >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400118 this->loadPkcs1(os.buf()->data(), os.buf()->size());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700119}
120
121void
122PrivateKey::loadPkcs1Base64(const uint8_t* buf, size_t size)
123{
124 OBufferStream os;
125 bufferSource(buf, size) >> base64Decode() >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400126 this->loadPkcs1(os.buf()->data(), os.buf()->size());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700127}
128
129void
130PrivateKey::loadPkcs1Base64(std::istream& is)
131{
132 OBufferStream os;
133 streamSource(is) >> base64Decode() >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400134 this->loadPkcs1(os.buf()->data(), os.buf()->size());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700135}
136
137void
138PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
139{
140 BOOST_ASSERT(std::strlen(pw) == pwLen);
Davide Pesaventof45fa212017-09-14 17:23:56 -0400141 ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key);
Luca Keidel941fd8c2017-07-24 15:21:22 +0200142 opensslInitAlgorithms();
Yingdi Yu202a2e92015-07-12 16:49:25 -0700143
Davide Pesaventof45fa212017-09-14 17:23:56 -0400144 detail::Bio membio(BIO_s_mem());
145 if (!membio.write(buf, size))
146 BOOST_THROW_EXCEPTION(Error("Failed to copy buffer"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700147
Davide Pesaventof45fa212017-09-14 17:23:56 -0400148 if (d2i_PKCS8PrivateKey_bio(membio, &m_impl->key, nullptr, const_cast<char*>(pw)) == nullptr)
149 BOOST_THROW_EXCEPTION(Error("Failed to load private key"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700150}
151
152static inline int
Davide Pesaventof45fa212017-09-14 17:23:56 -0400153passwordCallbackWrapper(char* buf, int size, int rwflag, void* u)
Yingdi Yu202a2e92015-07-12 16:49:25 -0700154{
Luca Keidel941fd8c2017-07-24 15:21:22 +0200155 BOOST_ASSERT(size >= 0);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700156 auto cb = reinterpret_cast<PrivateKey::PasswordCallback*>(u);
Luca Keidel941fd8c2017-07-24 15:21:22 +0200157 return (*cb)(buf, static_cast<size_t>(size), rwflag);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700158}
159
160void
161PrivateKey::loadPkcs8(const uint8_t* buf, size_t size, PasswordCallback pwCallback)
162{
Davide Pesaventof45fa212017-09-14 17:23:56 -0400163 ENSURE_PRIVATE_KEY_NOT_LOADED(m_impl->key);
Luca Keidel941fd8c2017-07-24 15:21:22 +0200164 opensslInitAlgorithms();
165
Davide Pesaventof45fa212017-09-14 17:23:56 -0400166 detail::Bio membio(BIO_s_mem());
167 if (!membio.write(buf, size))
168 BOOST_THROW_EXCEPTION(Error("Failed to copy buffer"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700169
170 if (pwCallback)
Davide Pesaventof45fa212017-09-14 17:23:56 -0400171 m_impl->key = d2i_PKCS8PrivateKey_bio(membio, nullptr, &passwordCallbackWrapper, &pwCallback);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700172 else
Davide Pesaventof45fa212017-09-14 17:23:56 -0400173 m_impl->key = d2i_PKCS8PrivateKey_bio(membio, nullptr, nullptr, nullptr);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700174
Davide Pesaventof45fa212017-09-14 17:23:56 -0400175 if (m_impl->key == nullptr)
176 BOOST_THROW_EXCEPTION(Error("Failed to load private key"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700177}
178
179void
180PrivateKey::loadPkcs8(std::istream& is, const char* pw, size_t pwLen)
181{
182 OBufferStream os;
183 streamSource(is) >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400184 this->loadPkcs8(os.buf()->data(), os.buf()->size(), pw, pwLen);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700185}
186
187void
188PrivateKey::loadPkcs8(std::istream& is, PasswordCallback pwCallback)
189{
190 OBufferStream os;
191 streamSource(is) >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400192 this->loadPkcs8(os.buf()->data(), os.buf()->size(), pwCallback);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700193}
194
195void
196PrivateKey::loadPkcs8Base64(const uint8_t* buf, size_t size, const char* pw, size_t pwLen)
197{
198 OBufferStream os;
199 bufferSource(buf, size) >> base64Decode() >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400200 this->loadPkcs8(os.buf()->data(), os.buf()->size(), pw, pwLen);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700201}
202
203void
204PrivateKey::loadPkcs8Base64(const uint8_t* buf, size_t size, PasswordCallback pwCallback)
205{
206 OBufferStream os;
207 bufferSource(buf, size) >> base64Decode() >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400208 this->loadPkcs8(os.buf()->data(), os.buf()->size(), pwCallback);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700209}
210
211void
212PrivateKey::loadPkcs8Base64(std::istream& is, const char* pw, size_t pwLen)
213{
214 OBufferStream os;
215 streamSource(is) >> base64Decode() >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400216 this->loadPkcs8(os.buf()->data(), os.buf()->size(), pw, pwLen);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700217}
218
219void
220PrivateKey::loadPkcs8Base64(std::istream& is, PasswordCallback pwCallback)
221{
222 OBufferStream os;
223 streamSource(is) >> base64Decode() >> streamSink(os);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400224 this->loadPkcs8(os.buf()->data(), os.buf()->size(), pwCallback);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700225}
226
227void
228PrivateKey::savePkcs1(std::ostream& os) const
229{
230 bufferSource(*this->toPkcs1()) >> streamSink(os);
231}
232
233void
234PrivateKey::savePkcs1Base64(std::ostream& os) const
235{
236 bufferSource(*this->toPkcs1()) >> base64Encode() >> streamSink(os);
237}
238
239void
240PrivateKey::savePkcs8(std::ostream& os, const char* pw, size_t pwLen) const
241{
242 bufferSource(*this->toPkcs8(pw, pwLen)) >> streamSink(os);
243}
244
245void
246PrivateKey::savePkcs8(std::ostream& os, PasswordCallback pwCallback) const
247{
248 bufferSource(*this->toPkcs8(pwCallback)) >> streamSink(os);
249}
250
251void
252PrivateKey::savePkcs8Base64(std::ostream& os, const char* pw, size_t pwLen) const
253{
254 bufferSource(*this->toPkcs8(pw, pwLen)) >> base64Encode() >> streamSink(os);
255}
256
257void
258PrivateKey::savePkcs8Base64(std::ostream& os, PasswordCallback pwCallback) const
259{
260 bufferSource(*this->toPkcs8(pwCallback)) >> base64Encode() >> streamSink(os);
261}
262
263ConstBufferPtr
264PrivateKey::derivePublicKey() const
265{
266 ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
267
268 uint8_t* pkcs8 = nullptr;
269 int len = i2d_PUBKEY(m_impl->key, &pkcs8);
Davide Pesaventof45fa212017-09-14 17:23:56 -0400270 if (len < 0)
Yingdi Yu202a2e92015-07-12 16:49:25 -0700271 BOOST_THROW_EXCEPTION(Error("Failed to derive public key"));
272
273 auto result = make_shared<Buffer>(pkcs8, len);
274 OPENSSL_free(pkcs8);
275
276 return result;
277}
278
279ConstBufferPtr
280PrivateKey::decrypt(const uint8_t* cipherText, size_t cipherLen) const
281{
282 ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
283
Davide Pesaventoc21979d2017-09-16 14:52:17 -0400284 int keyType = detail::getEvpPkeyType(m_impl->key);
Davide Pesaventof45fa212017-09-14 17:23:56 -0400285 switch (keyType) {
286 case EVP_PKEY_NONE:
287 BOOST_THROW_EXCEPTION(Error("Failed to determine key type"));
Luca Keidel941fd8c2017-07-24 15:21:22 +0200288 case EVP_PKEY_RSA:
289 return rsaDecrypt(cipherText, cipherLen);
290 default:
Davide Pesaventof45fa212017-09-14 17:23:56 -0400291 BOOST_THROW_EXCEPTION(Error("Decryption is not supported for key type " + to_string(keyType)));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700292 }
293}
294
295void*
296PrivateKey::getEvpPkey() const
297{
298 return m_impl->key;
299}
300
301ConstBufferPtr
302PrivateKey::toPkcs1() const
303{
304 ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
Luca Keidel941fd8c2017-07-24 15:21:22 +0200305 opensslInitAlgorithms();
Yingdi Yu202a2e92015-07-12 16:49:25 -0700306
Davide Pesaventof45fa212017-09-14 17:23:56 -0400307 detail::Bio membio(BIO_s_mem());
308 if (!i2d_PrivateKey_bio(membio, m_impl->key))
309 BOOST_THROW_EXCEPTION(Error("Cannot convert key to PKCS #1 format"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700310
Davide Pesaventof45fa212017-09-14 17:23:56 -0400311 auto buffer = make_shared<Buffer>(BIO_pending(membio));
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400312 membio.read(buffer->data(), buffer->size());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700313
314 return buffer;
315}
316
317ConstBufferPtr
318PrivateKey::toPkcs8(const char* pw, size_t pwLen) const
319{
Yingdi Yu202a2e92015-07-12 16:49:25 -0700320 BOOST_ASSERT(std::strlen(pw) == pwLen);
Luca Keidel941fd8c2017-07-24 15:21:22 +0200321 ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
322 opensslInitAlgorithms();
Yingdi Yu202a2e92015-07-12 16:49:25 -0700323
Davide Pesaventof45fa212017-09-14 17:23:56 -0400324 detail::Bio membio(BIO_s_mem());
Davide Pesaventoee77ca02018-10-10 01:45:24 -0400325 if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(), nullptr, 0,
Davide Pesaventof45fa212017-09-14 17:23:56 -0400326 nullptr, const_cast<char*>(pw)))
327 BOOST_THROW_EXCEPTION(Error("Cannot convert key to PKCS #8 format"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700328
Davide Pesaventof45fa212017-09-14 17:23:56 -0400329 auto buffer = make_shared<Buffer>(BIO_pending(membio));
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400330 membio.read(buffer->data(), buffer->size());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700331
332 return buffer;
333}
334
335ConstBufferPtr
336PrivateKey::toPkcs8(PasswordCallback pwCallback) const
337{
338 ENSURE_PRIVATE_KEY_LOADED(m_impl->key);
Luca Keidel941fd8c2017-07-24 15:21:22 +0200339 opensslInitAlgorithms();
Yingdi Yu202a2e92015-07-12 16:49:25 -0700340
Davide Pesaventof45fa212017-09-14 17:23:56 -0400341 detail::Bio membio(BIO_s_mem());
Davide Pesaventoee77ca02018-10-10 01:45:24 -0400342 if (!i2d_PKCS8PrivateKey_bio(membio, m_impl->key, EVP_aes_256_cbc(), nullptr, 0,
Davide Pesaventof45fa212017-09-14 17:23:56 -0400343 &passwordCallbackWrapper, &pwCallback))
344 BOOST_THROW_EXCEPTION(Error("Cannot convert key to PKCS #8 format"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700345
Davide Pesaventof45fa212017-09-14 17:23:56 -0400346 auto buffer = make_shared<Buffer>(BIO_pending(membio));
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400347 membio.read(buffer->data(), buffer->size());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700348
349 return buffer;
350}
351
352ConstBufferPtr
353PrivateKey::rsaDecrypt(const uint8_t* cipherText, size_t cipherLen) const
354{
355 detail::EvpPkeyCtx ctx(m_impl->key);
356
Davide Pesaventof45fa212017-09-14 17:23:56 -0400357 if (EVP_PKEY_decrypt_init(ctx) <= 0)
Yingdi Yu202a2e92015-07-12 16:49:25 -0700358 BOOST_THROW_EXCEPTION(Error("Failed to initialize decryption context"));
359
Davide Pesaventof45fa212017-09-14 17:23:56 -0400360 if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
Yingdi Yu202a2e92015-07-12 16:49:25 -0700361 BOOST_THROW_EXCEPTION(Error("Failed to set padding"));
362
363 size_t outlen = 0;
364 // Determine buffer length
Davide Pesaventof45fa212017-09-14 17:23:56 -0400365 if (EVP_PKEY_decrypt(ctx, nullptr, &outlen, cipherText, cipherLen) <= 0)
Yingdi Yu202a2e92015-07-12 16:49:25 -0700366 BOOST_THROW_EXCEPTION(Error("Failed to estimate output length"));
367
368 auto out = make_shared<Buffer>(outlen);
Davide Pesavento5d0b0102017-10-07 13:43:16 -0400369 if (EVP_PKEY_decrypt(ctx, out->data(), &outlen, cipherText, cipherLen) <= 0)
Davide Pesaventof45fa212017-09-14 17:23:56 -0400370 BOOST_THROW_EXCEPTION(Error("Failed to decrypt ciphertext"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700371
372 out->resize(outlen);
373 return out;
374}
375
Davide Pesaventof45fa212017-09-14 17:23:56 -0400376unique_ptr<PrivateKey>
377PrivateKey::generateRsaKey(uint32_t keySize)
Yingdi Yu202a2e92015-07-12 16:49:25 -0700378{
379 detail::EvpPkeyCtx kctx(EVP_PKEY_RSA);
380
Davide Pesaventof45fa212017-09-14 17:23:56 -0400381 if (EVP_PKEY_keygen_init(kctx) <= 0)
382 BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to initialize RSA keygen context"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700383
Davide Pesaventof45fa212017-09-14 17:23:56 -0400384 if (EVP_PKEY_CTX_set_rsa_keygen_bits(kctx, static_cast<int>(keySize)) <= 0)
385 BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to set RSA key length"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700386
387 auto privateKey = make_unique<PrivateKey>();
Davide Pesaventof45fa212017-09-14 17:23:56 -0400388 if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0)
389 BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to generate RSA key"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700390
391 return privateKey;
392}
393
Davide Pesaventof45fa212017-09-14 17:23:56 -0400394unique_ptr<PrivateKey>
395PrivateKey::generateEcKey(uint32_t keySize)
Yingdi Yu202a2e92015-07-12 16:49:25 -0700396{
Davide Pesaventof45fa212017-09-14 17:23:56 -0400397 detail::EvpPkeyCtx pctx(EVP_PKEY_EC);
Yingdi Yu202a2e92015-07-12 16:49:25 -0700398
Davide Pesaventof45fa212017-09-14 17:23:56 -0400399 if (EVP_PKEY_paramgen_init(pctx) <= 0)
400 BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to initialize EC paramgen context"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700401
Davide Pesaventof45fa212017-09-14 17:23:56 -0400402 int ret;
Yingdi Yu202a2e92015-07-12 16:49:25 -0700403 switch (keySize) {
Davide Pesavento3c7969f2018-09-08 15:31:35 -0400404 case 224:
405 ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp224r1);
406 break;
407 case 256:
408 ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1); // same as secp256r1
409 break;
410 case 384:
411 ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp384r1);
412 break;
413 case 521:
414 ret = EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_secp521r1);
415 break;
416 default:
417 BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported EC key length " + to_string(keySize)));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700418 }
Davide Pesaventof45fa212017-09-14 17:23:56 -0400419 if (ret <= 0)
420 BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to set EC curve"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700421
Davide Pesaventof45fa212017-09-14 17:23:56 -0400422 Impl params;
423 if (EVP_PKEY_paramgen(pctx, &params.key) <= 0)
424 BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to generate EC parameters"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700425
Davide Pesaventof45fa212017-09-14 17:23:56 -0400426 detail::EvpPkeyCtx kctx(params.key);
427 if (EVP_PKEY_keygen_init(kctx) <= 0)
428 BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to initialize EC keygen context"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700429
430 auto privateKey = make_unique<PrivateKey>();
Davide Pesaventof45fa212017-09-14 17:23:56 -0400431 if (EVP_PKEY_keygen(kctx, &privateKey->m_impl->key) <= 0)
432 BOOST_THROW_EXCEPTION(PrivateKey::Error("Failed to generate EC key"));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700433
434 return privateKey;
435}
436
437unique_ptr<PrivateKey>
438generatePrivateKey(const KeyParams& keyParams)
439{
440 switch (keyParams.getKeyType()) {
441 case KeyType::RSA: {
442 const RsaKeyParams& rsaParams = static_cast<const RsaKeyParams&>(keyParams);
Davide Pesaventof45fa212017-09-14 17:23:56 -0400443 return PrivateKey::generateRsaKey(rsaParams.getKeySize());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700444 }
445 case KeyType::EC: {
Spyridon Mastorakis1ece2e32015-08-27 18:52:21 -0700446 const EcKeyParams& ecParams = static_cast<const EcKeyParams&>(keyParams);
Davide Pesaventof45fa212017-09-14 17:23:56 -0400447 return PrivateKey::generateEcKey(ecParams.getKeySize());
Yingdi Yu202a2e92015-07-12 16:49:25 -0700448 }
449 default:
Davide Pesaventof45fa212017-09-14 17:23:56 -0400450 BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported asymmetric key type " +
451 boost::lexical_cast<std::string>(keyParams.getKeyType())));
Yingdi Yu202a2e92015-07-12 16:49:25 -0700452 }
453}
454
455} // namespace transform
456} // namespace security
457} // namespace ndn