1 //
2 // EVPPKey.h
3 //
4 //
5 // Library: Crypto
6 // Package: CryptoCore
7 // Module: EVPPKey
8 //
9 // Definition of the EVPPKey class.
10 //
11 // Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
12 // and Contributors.
13 //
14 // SPDX-License-Identifier: BSL-1.0
15 //
16
17
18 #ifndef Crypto_EVPPKeyImpl_INCLUDED
19 #define Crypto_EVPPKeyImpl_INCLUDED
20
21
22 #include "Poco/Crypto/Crypto.h"
23 #include "Poco/Crypto/CryptoException.h"
24 #include "Poco/StreamCopier.h"
25 #include <openssl/ec.h>
26 #include <openssl/rsa.h>
27 #include <openssl/evp.h>
28 #include <openssl/pem.h>
29 #include <sstream>
30 #include <typeinfo>
31
32
33 namespace Poco {
34 namespace Crypto {
35
36
37 class ECKey;
38 class RSAKey;
39
40
41 class Crypto_API EVPPKey
42 /// Utility class for conversion of native keys to EVP.
43 /// Currently, only RSA and EC keys are supported.
44 {
45 public:
46 explicit EVPPKey(const std::string& ecCurveName);
47 /// Constructs EVPPKey from ECC curve name.
48 ///
49 /// Only EC keys can be wrapped by an EVPPKey
50 /// created using this constructor.
51
52 explicit EVPPKey(const char* ecCurveName);
53 /// Constructs EVPPKey from ECC curve name.
54 ///
55 /// Only EC keys can be wrapped by an EVPPKey
56 /// created using this constructor.
57
58 explicit EVPPKey(EVP_PKEY* pEVPPKey);
59 /// Constructs EVPPKey from EVP_PKEY pointer.
60 /// The content behind the supplied pointer is internally duplicated.
61
62 template<typename K>
EVPPKey(K * pKey)63 explicit EVPPKey(K* pKey): _pEVPPKey(EVP_PKEY_new())
64 /// Constructs EVPPKey from a "native" OpenSSL (RSA or EC_KEY),
65 /// or a Poco wrapper (RSAKey, ECKey) key pointer.
66 {
67 if (!_pEVPPKey) throw OpenSSLException();
68 setKey(pKey);
69 }
70
71 EVPPKey(const std::string& publicKeyFile, const std::string& privateKeyFile, const std::string& privateKeyPassphrase = "");
72 /// Creates the EVPPKey, by reading public and private key from the given files and
73 /// using the given passphrase for the private key. Can only by used for signing if
74 /// a private key is available.
75
76 EVPPKey(std::istream* pPublicKeyStream, std::istream* pPrivateKeyStream, const std::string& privateKeyPassphrase = "");
77 /// Creates the EVPPKey. Can only by used for signing if pPrivKey
78 /// is not null. If a private key file is specified, you don't need to
79 /// specify a public key file. OpenSSL will auto-create it from the private key.
80
81 EVPPKey(const EVPPKey& other);
82 /// Copy constructor.
83
84 EVPPKey(EVPPKey&& other) noexcept;
85 /// Move constructor.
86
87 EVPPKey& operator = (const EVPPKey& other);
88 /// Assignment operator.
89
90 EVPPKey& operator = (EVPPKey&& other) noexcept;
91 /// Assignment move operator.
92
93 ~EVPPKey();
94 /// Destroys the EVPPKey.
95
96 bool operator == (const EVPPKey& other) const;
97 /// Comparison operator.
98 /// Returns true if public key components and parameters
99 /// of the other key are equal to this key.
100 ///
101 /// Works as expected when one key contains only public key,
102 /// while the other one contains private (thus also public) key.
103
104 bool operator != (const EVPPKey& other) const;
105 /// Comparison operator.
106 /// Returns true if public key components and parameters
107 /// of the other key are different from this key.
108 ///
109 /// Works as expected when one key contains only public key,
110 /// while the other one contains private (thus also public) key.
111
112 void save(const std::string& publicKeyFile, const std::string& privateKeyFile = "", const std::string& privateKeyPassphrase = "") const;
113 /// Exports the public and/or private keys to the given files.
114 ///
115 /// If an empty filename is specified, the corresponding key
116 /// is not exported.
117
118 void save(std::ostream* pPublicKeyStream, std::ostream* pPrivateKeyStream = 0, const std::string& privateKeyPassphrase = "") const;
119 /// Exports the public and/or private key to the given streams.
120 ///
121 /// If a null pointer is passed for a stream, the corresponding
122 /// key is not exported.
123
124 int type() const;
125 /// Retuns the EVPPKey type NID.
126
127 bool isSupported(int type) const;
128 /// Returns true if OpenSSL type is supported
129
130 operator const EVP_PKEY*() const;
131 /// Returns const pointer to the OpenSSL EVP_PKEY structure.
132
133 operator EVP_PKEY*();
134 /// Returns pointer to the OpenSSL EVP_PKEY structure.
135
136 static EVP_PKEY* duplicate(const EVP_PKEY* pFromKey, EVP_PKEY** pToKey);
137 /// Duplicates pFromKey into *pToKey and returns
138 // the pointer to duplicated EVP_PKEY.
139
140 private:
141 EVPPKey();
142
143 static int type(const EVP_PKEY* pEVPPKey);
144 void newECKey(const char* group);
145 void duplicate(EVP_PKEY* pEVPPKey);
146
147 void setKey(ECKey* pKey);
148 void setKey(RSAKey* pKey);
149 void setKey(EC_KEY* pKey);
150 void setKey(RSA* pKey);
151 static int passCB(char* buf, int size, int, void* pass);
152
153 typedef EVP_PKEY* (*PEM_read_FILE_Key_fn)(FILE*, EVP_PKEY**, pem_password_cb*, void*);
154 typedef EVP_PKEY* (*PEM_read_BIO_Key_fn)(BIO*, EVP_PKEY**, pem_password_cb*, void*);
155 typedef void* (*EVP_PKEY_get_Key_fn)(EVP_PKEY*);
156
157 // The following load*() functions are used by both native and EVP_PKEY type key
158 // loading from BIO/FILE.
159 // When used for EVP key loading, getFunc is null (ie. native key is not extracted
160 // from the loaded EVP_PKEY).
161 template <typename K, typename F>
162 static bool loadKey(K** ppKey,
163 PEM_read_FILE_Key_fn readFunc,
164 F getFunc,
165 const std::string& keyFile,
166 const std::string& pass = "")
167 {
168 poco_assert_dbg (((typeid(K*) == typeid(RSA*) || typeid(K*) == typeid(EC_KEY*)) && getFunc) ||
169 ((typeid(K*) == typeid(EVP_PKEY*)) && !getFunc));
170 poco_check_ptr (ppKey);
171 poco_assert_dbg (!*ppKey);
172
173 FILE* pFile = 0;
174 if (!keyFile.empty())
175 {
176 if (!getFunc) *ppKey = (K*)EVP_PKEY_new();
177 EVP_PKEY* pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY*)*ppKey;
178 if (pKey)
179 {
180 pFile = fopen(keyFile.c_str(), "r");
181 if (pFile)
182 {
183 pem_password_cb* pCB = pass.empty() ? (pem_password_cb*)0 : &passCB;
184 void* pPassword = pass.empty() ? (void*)0 : (void*)pass.c_str();
185 if (readFunc(pFile, &pKey, pCB, pPassword))
186 {
187 fclose(pFile); pFile = 0;
188 if(getFunc)
189 {
190 *ppKey = (K*)getFunc(pKey);
191 EVP_PKEY_free(pKey);
192 }
193 else
194 {
195 poco_assert_dbg (typeid(K*) == typeid(EVP_PKEY*));
196 *ppKey = (K*)pKey;
197 }
198 if(!*ppKey) goto error;
199 return true;
200 }
201 goto error;
202 }
203 else
204 {
205 if (getFunc) EVP_PKEY_free(pKey);
206 throw IOException("ECKeyImpl, cannot open file", keyFile);
207 }
208 }
209 else goto error;
210 }
211 return false;
212
213 error:
214 if (pFile) fclose(pFile);
215 throw OpenSSLException("EVPKey::loadKey(string)");
216 }
217
218 template <typename K, typename F>
219 static bool loadKey(K** ppKey,
220 PEM_read_BIO_Key_fn readFunc,
221 F getFunc,
222 std::istream* pIstr,
223 const std::string& pass = "")
224 {
225 poco_assert_dbg (((typeid(K*) == typeid(RSA*) || typeid(K*) == typeid(EC_KEY*)) && getFunc) ||
226 ((typeid(K*) == typeid(EVP_PKEY*)) && !getFunc));
227 poco_check_ptr(ppKey);
228 poco_assert_dbg(!*ppKey);
229
230 BIO* pBIO = 0;
231 if (pIstr)
232 {
233 std::ostringstream ostr;
234 Poco::StreamCopier::copyStream(*pIstr, ostr);
235 std::string key = ostr.str();
236 pBIO = BIO_new_mem_buf(const_cast<char*>(key.data()), static_cast<int>(key.size()));
237 if (pBIO)
238 {
239 if (!getFunc) *ppKey = (K*)EVP_PKEY_new();
240 EVP_PKEY* pKey = getFunc ? EVP_PKEY_new() : (EVP_PKEY*)*ppKey;
241 if (pKey)
242 {
243 pem_password_cb* pCB = pass.empty() ? (pem_password_cb*)0 : &passCB;
244 void* pPassword = pass.empty() ? (void*)0 : (void*)pass.c_str();
245 if (readFunc(pBIO, &pKey, pCB, pPassword))
246 {
247 BIO_free(pBIO); pBIO = 0;
248 if (getFunc)
249 {
250 *ppKey = (K*)getFunc(pKey);
251 EVP_PKEY_free(pKey);
252 }
253 else
254 {
255 poco_assert_dbg (typeid(K*) == typeid(EVP_PKEY*));
256 *ppKey = (K*)pKey;
257 }
258 if (!*ppKey) goto error;
259 return true;
260 }
261 if (getFunc) EVP_PKEY_free(pKey);
262 goto error;
263 }
264 else goto error;
265 }
266 else goto error;
267 }
268 return false;
269
270 error:
271 if (pBIO) BIO_free(pBIO);
272 throw OpenSSLException("EVPKey::loadKey(stream)");
273 }
274
275 EVP_PKEY* _pEVPPKey;
276
277 friend class ECKeyImpl;
278 friend class RSAKeyImpl;
279 };
280
281
282 //
283 // inlines
284 //
285
286
287 inline bool EVPPKey::operator == (const EVPPKey& other) const
288 {
289 poco_check_ptr (other._pEVPPKey);
290 poco_check_ptr (_pEVPPKey);
291 return (1 == EVP_PKEY_cmp(_pEVPPKey, other._pEVPPKey));
292 }
293
294
295 inline bool EVPPKey::operator != (const EVPPKey& other) const
296 {
297 return !(other == *this);
298 }
299
300
type(const EVP_PKEY * pEVPPKey)301 inline int EVPPKey::type(const EVP_PKEY* pEVPPKey)
302 {
303 if (!pEVPPKey) return NID_undef;
304
305 return EVP_PKEY_type(EVP_PKEY_id(pEVPPKey));
306 }
307
308
type()309 inline int EVPPKey::type() const
310 {
311 return type(_pEVPPKey);
312 }
313
314
isSupported(int type)315 inline bool EVPPKey::isSupported(int type) const
316 {
317 return type == EVP_PKEY_EC || type == EVP_PKEY_RSA;
318 }
319
320
321 inline EVPPKey::operator const EVP_PKEY*() const
322 {
323 return _pEVPPKey;
324 }
325
326
327 inline EVPPKey::operator EVP_PKEY*()
328 {
329 return _pEVPPKey;
330 }
331
332
setKey(EC_KEY * pKey)333 inline void EVPPKey::setKey(EC_KEY* pKey)
334 {
335 if (!EVP_PKEY_set1_EC_KEY(_pEVPPKey, pKey))
336 throw OpenSSLException();
337 }
338
339
setKey(RSA * pKey)340 inline void EVPPKey::setKey(RSA* pKey)
341 {
342 if (!EVP_PKEY_set1_RSA(_pEVPPKey, pKey))
343 throw OpenSSLException();
344 }
345
346
347 } } // namespace Poco::Crypto
348
349
350 #endif // Crypto_EVPPKeyImpl_INCLUDED
351