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-2022 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 #include <openssl/rsa.h>
32 #include <openssl/x509.h>
33 
34 #define ENSURE_PUBLIC_KEY_LOADED(key) \
35  do { \
36  if ((key) == nullptr) \
37  NDN_THROW(Error("Public key has not been loaded yet")); \
38  } while (false)
39 
40 #define ENSURE_PUBLIC_KEY_NOT_LOADED(key) \
41  do { \
42  if ((key) != nullptr) \
43  NDN_THROW(Error("Public key has already been loaded")); \
44  } while (false)
45 
46 namespace ndn {
47 namespace security {
48 namespace transform {
49 
50 class PublicKey::Impl : noncopyable
51 {
52 public:
53  Impl() noexcept
54  : key(nullptr)
55  {
56  }
57 
58  ~Impl()
59  {
60  EVP_PKEY_free(key);
61  }
62 
63 public:
64  EVP_PKEY* key;
65 };
66 
68  : m_impl(make_unique<Impl>())
69 {
70 }
71 
72 PublicKey::~PublicKey() = default;
73 
74 KeyType
76 {
77  if (!m_impl->key)
78  return KeyType::NONE;
79 
80  switch (detail::getEvpPkeyType(m_impl->key)) {
81  case EVP_PKEY_RSA:
82  return KeyType::RSA;
83  case EVP_PKEY_EC:
84  return KeyType::EC;
85  default:
86  return KeyType::NONE;
87  }
88 }
89 
90 size_t
92 {
93  switch (getKeyType()) {
94  case KeyType::RSA:
95  case KeyType::EC:
96  return static_cast<size_t>(EVP_PKEY_bits(m_impl->key));
97  default:
98  return 0;
99  }
100 }
101 
102 void
103 PublicKey::loadPkcs8(span<const uint8_t> buf)
104 {
105  ENSURE_PUBLIC_KEY_NOT_LOADED(m_impl->key);
106 
107  auto ptr = buf.data();
108  if (d2i_PUBKEY(&m_impl->key, &ptr, static_cast<long>(buf.size())) == nullptr)
109  NDN_THROW(Error("Failed to load public key"));
110 }
111 
112 void
113 PublicKey::loadPkcs8(std::istream& is)
114 {
115  OBufferStream os;
116  streamSource(is) >> streamSink(os);
117  loadPkcs8(*os.buf());
118 }
119 
120 void
121 PublicKey::loadPkcs8Base64(span<const uint8_t> buf)
122 {
123  OBufferStream os;
124  bufferSource(buf) >> base64Decode() >> streamSink(os);
125  loadPkcs8(*os.buf());
126 }
127 
128 void
129 PublicKey::loadPkcs8Base64(std::istream& is)
130 {
131  OBufferStream os;
132  streamSource(is) >> base64Decode() >> streamSink(os);
133  loadPkcs8(*os.buf());
134 }
135 
136 void
137 PublicKey::savePkcs8(std::ostream& os) const
138 {
139  bufferSource(*toPkcs8()) >> streamSink(os);
140 }
141 
142 void
143 PublicKey::savePkcs8Base64(std::ostream& os) const
144 {
145  bufferSource(*toPkcs8()) >> base64Encode() >> streamSink(os);
146 }
147 
149 PublicKey::encrypt(span<const uint8_t> plainText) const
150 {
151  ENSURE_PUBLIC_KEY_LOADED(m_impl->key);
152 
153  int keyType = detail::getEvpPkeyType(m_impl->key);
154  switch (keyType) {
155  case EVP_PKEY_NONE:
156  NDN_THROW(Error("Failed to determine key type"));
157  case EVP_PKEY_RSA:
158  return rsaEncrypt(plainText);
159  default:
160  NDN_THROW(Error("Encryption is not supported for key type " + to_string(keyType)));
161  }
162 }
163 
164 void*
165 PublicKey::getEvpPkey() const
166 {
167  return m_impl->key;
168 }
169 
171 PublicKey::toPkcs8() const
172 {
173  ENSURE_PUBLIC_KEY_LOADED(m_impl->key);
174 
175  uint8_t* pkcs8 = nullptr;
176  int len = i2d_PUBKEY(m_impl->key, &pkcs8);
177  if (len < 0)
178  NDN_THROW(Error("Cannot convert key to PKCS #8 format"));
179 
180  auto buffer = make_shared<Buffer>(pkcs8, len);
181  OPENSSL_free(pkcs8);
182 
183  return buffer;
184 }
185 
187 PublicKey::rsaEncrypt(span<const uint8_t> plainText) const
188 {
189  detail::EvpPkeyCtx ctx(m_impl->key);
190 
191  if (EVP_PKEY_encrypt_init(ctx) <= 0)
192  NDN_THROW(Error("Failed to initialize encryption context"));
193 
194  if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING) <= 0)
195  NDN_THROW(Error("Failed to set padding"));
196 
197  size_t outlen = 0;
198  // Determine buffer length
199  if (EVP_PKEY_encrypt(ctx, nullptr, &outlen, plainText.data(), plainText.size()) <= 0)
200  NDN_THROW(Error("Failed to estimate output length"));
201 
202  auto out = make_shared<Buffer>(outlen);
203  if (EVP_PKEY_encrypt(ctx, out->data(), &outlen, plainText.data(), plainText.size()) <= 0)
204  NDN_THROW(Error("Failed to encrypt plaintext"));
205 
206  out->resize(outlen);
207  return out;
208 }
209 
210 } // namespace transform
211 } // namespace security
212 } // namespace ndn
An output stream that writes to a Buffer.
shared_ptr< Buffer > buf()
Return a 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:121
void loadPkcs8(span< const uint8_t > buf)
Load the public key in PKCS#8 format from a buffer buf.
Definition: public-key.cpp:103
KeyType getKeyType() const
Return the type of the public key.
Definition: public-key.cpp:75
void savePkcs8Base64(std::ostream &os) const
Save the public key in base64-encoded PKCS#8 format into a stream os.
Definition: public-key.cpp:143
ConstBufferPtr encrypt(span< const uint8_t > plainText) const
Definition: public-key.cpp:149
void savePkcs8(std::ostream &os) const
Save the public key in PKCS#8 format into a stream os.
Definition: public-key.cpp:137
size_t getKeySize() const
Return the size of the public key in bits.
Definition: public-key.cpp:91
PublicKey()
Create an empty public key instance.
Definition: public-key.cpp:67
#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:40
#define ENSURE_PUBLIC_KEY_LOADED(key)
Definition: public-key.cpp:34