public-key.cpp
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2013-2021 Regents of the University of California.
4  *
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 
28 #include "ndn-cxx/security/impl/openssl-helper.hpp"
30 
31 #define ENSURE_PUBLIC_KEY_LOADED(key) \
32  do { \
33  if ((key) == nullptr) \
34  NDN_THROW(Error("Public key has not been loaded yet")); \
35  } while (false)
36 
37 #define ENSURE_PUBLIC_KEY_NOT_LOADED(key) \
38  do { \
39  if ((key) != nullptr) \
40  NDN_THROW(Error("Public key has already been loaded")); \
41  } while (false)
42 
43 namespace ndn {
44 namespace security {
45 namespace transform {
46 
47 class PublicKey::Impl : noncopyable
48 {
49 public:
50  Impl() noexcept
51  : key(nullptr)
52  {
53  }
54 
55  ~Impl()
56  {
57  EVP_PKEY_free(key);
58  }
59 
60 public:
61  EVP_PKEY* key;
62 };
63 
65  : m_impl(make_unique<Impl>())
66 {
67 }
68 
69 PublicKey::~PublicKey() = default;
70 
71 KeyType
73 {
74  if (!m_impl->key)
75  return KeyType::NONE;
76 
77  switch (detail::getEvpPkeyType(m_impl->key)) {
78  case EVP_PKEY_RSA:
79  return KeyType::RSA;
80  case EVP_PKEY_EC:
81  return KeyType::EC;
82  default:
83  return KeyType::NONE;
84  }
85 }
86 
87 void
88 PublicKey::loadPkcs8(span<const uint8_t> buf)
89 {
90  ENSURE_PUBLIC_KEY_NOT_LOADED(m_impl->key);
91 
92  auto ptr = buf.data();
93  if (d2i_PUBKEY(&m_impl->key, &ptr, static_cast<long>(buf.size())) == nullptr)
94  NDN_THROW(Error("Failed to load public key"));
95 }
96 
97 void
98 PublicKey::loadPkcs8(std::istream& is)
99 {
100  OBufferStream os;
101  streamSource(is) >> streamSink(os);
102  loadPkcs8(*os.buf());
103 }
104 
105 void
106 PublicKey::loadPkcs8Base64(span<const uint8_t> buf)
107 {
108  OBufferStream os;
109  bufferSource(buf) >> base64Decode() >> streamSink(os);
110  loadPkcs8(*os.buf());
111 }
112 
113 void
114 PublicKey::loadPkcs8Base64(std::istream& is)
115 {
116  OBufferStream os;
117  streamSource(is) >> base64Decode() >> streamSink(os);
118  loadPkcs8(*os.buf());
119 }
120 
121 void
122 PublicKey::savePkcs8(std::ostream& os) const
123 {
124  bufferSource(*toPkcs8()) >> streamSink(os);
125 }
126 
127 void
128 PublicKey::savePkcs8Base64(std::ostream& os) const
129 {
130  bufferSource(*toPkcs8()) >> base64Encode() >> streamSink(os);
131 }
132 
134 PublicKey::encrypt(span<const uint8_t> plainText) const
135 {
136  ENSURE_PUBLIC_KEY_LOADED(m_impl->key);
137 
138  int keyType = detail::getEvpPkeyType(m_impl->key);
139  switch (keyType) {
140  case EVP_PKEY_NONE:
141  NDN_THROW(Error("Failed to determine key type"));
142  case EVP_PKEY_RSA:
143  return rsaEncrypt(plainText);
144  default:
145  NDN_THROW(Error("Encryption is not supported for key type " + to_string(keyType)));
146  }
147 }
148 
149 void*
150 PublicKey::getEvpPkey() const
151 {
152  return m_impl->key;
153 }
154 
156 PublicKey::toPkcs8() const
157 {
158  ENSURE_PUBLIC_KEY_LOADED(m_impl->key);
159 
160  uint8_t* pkcs8 = nullptr;
161  int len = i2d_PUBKEY(m_impl->key, &pkcs8);
162  if (len < 0)
163  NDN_THROW(Error("Cannot convert key to PKCS #8 format"));
164 
165  auto buffer = make_shared<Buffer>(pkcs8, len);
166  OPENSSL_free(pkcs8);
167 
168  return buffer;
169 }
170 
172 PublicKey::rsaEncrypt(span<const uint8_t> plainText) const
173 {
174  detail::EvpPkeyCtx ctx(m_impl->key);
175 
176  if (EVP_PKEY_encrypt_init(ctx) <= 0)
177  NDN_THROW(Error("Failed to initialize encryption context"));
178 
179  if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
180  NDN_THROW(Error("Failed to set padding"));
181 
182  size_t outlen = 0;
183  // Determine buffer length
184  if (EVP_PKEY_encrypt(ctx, nullptr, &outlen, plainText.data(), plainText.size()) <= 0)
185  NDN_THROW(Error("Failed to estimate output length"));
186 
187  auto out = make_shared<Buffer>(outlen);
188  if (EVP_PKEY_encrypt(ctx, out->data(), &outlen, plainText.data(), plainText.size()) <= 0)
189  NDN_THROW(Error("Failed to encrypt plaintext"));
190 
191  out->resize(outlen);
192  return out;
193 }
194 
195 } // namespace transform
196 } // namespace security
197 } // namespace ndn
implements an output stream that constructs ndn::Buffer
shared_ptr< Buffer > buf()
Flush written data to the stream and return shared pointer to the underlying buffer.
void loadPkcs8Base64(span< const uint8_t > buf)
Load the public key in base64-encoded PKCS#8 format from a buffer buf.
Definition: public-key.cpp:106
void loadPkcs8(span< const uint8_t > buf)
Load the public key in PKCS#8 format from a buffer buf.
Definition: public-key.cpp:88
KeyType getKeyType() const
Get the type of the public key.
Definition: public-key.cpp:72
void savePkcs8Base64(std::ostream &os) const
Save the public key in base64-encoded PKCS#8 format into a stream os.
Definition: public-key.cpp:128
ConstBufferPtr encrypt(span< const uint8_t > plainText) const
Definition: public-key.cpp:134
void savePkcs8(std::ostream &os) const
Save the public key in PKCS#8 format into a stream os.
Definition: public-key.cpp:122
PublicKey()
Create an empty public key instance.
Definition: public-key.cpp:64
#define NDN_THROW(e)
Definition: exception.hpp:61
std::string to_string(const errinfo_stacktrace &x)
Definition: exception.cpp:31
unique_ptr< Sink > streamSink(std::ostream &os)
Definition: stream-sink.cpp:53
unique_ptr< Transform > base64Encode(bool needBreak)
unique_ptr< Transform > base64Decode(bool expectNewlineEvery64Bytes)
Definition: data.cpp:25
shared_ptr< const Buffer > ConstBufferPtr
Definition: buffer.hpp:139
KeyType
The type of a cryptographic key.
@ EC
Elliptic Curve key (e.g. for ECDSA), supports sign/verify operations.
@ RSA
RSA key, supports sign/verify and encrypt/decrypt operations.
@ NONE
Unknown or unsupported key type.
#define ENSURE_PUBLIC_KEY_NOT_LOADED(key)
Definition: public-key.cpp:37
#define ENSURE_PUBLIC_KEY_LOADED(key)
Definition: public-key.cpp:31