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