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