1//
2// ECKeyImpl.cpp
3//
4//
5// Library: Crypto
6// Package: EC
7// Module: ECKeyImpl
8//
9// Copyright (c) 2008, Applied Informatics Software Engineering GmbH.
10// and Contributors.
11//
12// SPDX-License-Identifier: BSL-1.0
13//
14
15
16#include "Poco/Crypto/ECKeyImpl.h"
17#include "Poco/Crypto/X509Certificate.h"
18#include "Poco/Crypto/PKCS12Container.h"
19#include "Poco/FileStream.h"
20#include "Poco/Format.h"
21#include <sstream>
22#include <openssl/evp.h>
23#if OPENSSL_VERSION_NUMBER >= 0x00908000L
24#include <openssl/bn.h>
25#endif
26
27
28namespace Poco {
29namespace Crypto {
30
31
32ECKeyImpl::ECKeyImpl(const EVPPKey& key):
33 KeyPairImpl("ec", KT_EC_IMPL),
34 _pEC(EVP_PKEY_get1_EC_KEY(const_cast<EVP_PKEY*>((const EVP_PKEY*)key)))
35{
36 checkEC("ECKeyImpl(const EVPPKey&)", "EVP_PKEY_get1_EC_KEY()");
37}
38
39
40ECKeyImpl::ECKeyImpl(const X509Certificate& cert):
41 KeyPairImpl("ec", KT_EC_IMPL),
42 _pEC(0)
43{
44 const X509* pCert = cert.certificate();
45 if (pCert)
46 {
47 EVP_PKEY* pKey = X509_get_pubkey(const_cast<X509*>(pCert));
48 if (pKey)
49 {
50 _pEC = EVP_PKEY_get1_EC_KEY(pKey);
51 EVP_PKEY_free(pKey);
52 checkEC("ECKeyImpl(const const X509Certificate&)", "EVP_PKEY_get1_EC_KEY()");
53 return;
54 }
55 }
56 throw OpenSSLException("ECKeyImpl(const X509Certificate&)");
57}
58
59
60ECKeyImpl::ECKeyImpl(const PKCS12Container& cont):
61 KeyPairImpl("ec", KT_EC_IMPL),
62 _pEC(EVP_PKEY_get1_EC_KEY(cont.getKey()))
63{
64 checkEC("ECKeyImpl(const PKCS12Container&)", "EVP_PKEY_get1_EC_KEY()");
65}
66
67
68ECKeyImpl::ECKeyImpl(int curve):
69 KeyPairImpl("ec", KT_EC_IMPL),
70 _pEC(EC_KEY_new_by_curve_name(curve))
71{
72 poco_check_ptr(_pEC);
73 EC_KEY_set_asn1_flag(_pEC, OPENSSL_EC_NAMED_CURVE);
74 if (!(EC_KEY_generate_key(_pEC)))
75 throw OpenSSLException("ECKeyImpl(int curve): EC_KEY_generate_key()");
76 checkEC("ECKeyImpl(int curve)", "EC_KEY_generate_key()");
77}
78
79
80ECKeyImpl::ECKeyImpl(const std::string& publicKeyFile,
81 const std::string& privateKeyFile,
82 const std::string& privateKeyPassphrase): KeyPairImpl("ec", KT_EC_IMPL), _pEC(0)
83{
84 if (EVPPKey::loadKey(&_pEC, PEM_read_PrivateKey, EVP_PKEY_get1_EC_KEY, privateKeyFile, privateKeyPassphrase))
85 {
86 checkEC(Poco::format("ECKeyImpl(%s, %s, %s)",
87 publicKeyFile, privateKeyFile, privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
88 "PEM_read_PrivateKey() or EVP_PKEY_get1_EC_KEY()");
89 return; // private key is enough
90 }
91
92 // no private key, this must be public key only, otherwise throw
93 if (!EVPPKey::loadKey(&_pEC, PEM_read_PUBKEY, EVP_PKEY_get1_EC_KEY, publicKeyFile))
94 {
95 throw OpenSSLException("ECKeyImpl(const string&, const string&, const string&");
96 }
97 checkEC(Poco::format("ECKeyImpl(%s, %s, %s)",
98 publicKeyFile, privateKeyFile, privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
99 "PEM_read_PUBKEY() or EVP_PKEY_get1_EC_KEY()");
100}
101
102
103ECKeyImpl::ECKeyImpl(std::istream* pPublicKeyStream,
104 std::istream* pPrivateKeyStream,
105 const std::string& privateKeyPassphrase): KeyPairImpl("ec", KT_EC_IMPL), _pEC(0)
106{
107 if (EVPPKey::loadKey(&_pEC, PEM_read_bio_PrivateKey, EVP_PKEY_get1_EC_KEY, pPrivateKeyStream, privateKeyPassphrase))
108 {
109 checkEC(Poco::format("ECKeyImpl(stream, stream, %s)",
110 privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
111 "PEM_read_bio_PrivateKey() or EVP_PKEY_get1_EC_KEY()");
112 return; // private key is enough
113 }
114
115 // no private key, this must be public key only, otherwise throw
116 if (!EVPPKey::loadKey(&_pEC, PEM_read_bio_PUBKEY, EVP_PKEY_get1_EC_KEY, pPublicKeyStream))
117 {
118 throw OpenSSLException("ECKeyImpl(istream*, istream*, const string&");
119 }
120 checkEC(Poco::format("ECKeyImpl(stream, stream, %s)",
121 privateKeyPassphrase.empty() ? privateKeyPassphrase : std::string("***")),
122 "PEM_read_bio_PUBKEY() or EVP_PKEY_get1_EC_KEY()");
123}
124
125
126ECKeyImpl::~ECKeyImpl()
127{
128 freeEC();
129}
130
131
132void ECKeyImpl::checkEC(const std::string& method, const std::string& func) const
133{
134 if (!_pEC) throw OpenSSLException(Poco::format("%s: %s", method, func));
135 if (!EC_KEY_check_key(_pEC))
136 throw OpenSSLException(Poco::format("%s: EC_KEY_check_key()", method));
137}
138
139
140void ECKeyImpl::freeEC()
141{
142 if (_pEC)
143 {
144 EC_KEY_free(_pEC);
145 _pEC = 0;
146 }
147}
148
149
150int ECKeyImpl::size() const
151{
152 int sz = -1;
153 EVP_PKEY* pKey = EVP_PKEY_new();
154 if (pKey && EVP_PKEY_set1_EC_KEY(pKey, _pEC))
155 {
156 sz = EVP_PKEY_bits(pKey);
157 EVP_PKEY_free(pKey);
158 return sz;
159 }
160 throw OpenSSLException("ECKeyImpl::size()");
161}
162
163
164int ECKeyImpl::groupId() const
165{
166 if (_pEC)
167 {
168 const EC_GROUP* ecGroup = EC_KEY_get0_group(_pEC);
169 if (ecGroup)
170 {
171 return EC_GROUP_get_curve_name(ecGroup);
172 }
173 else
174 {
175 throw OpenSSLException("ECKeyImpl::groupId()");
176 }
177 }
178 throw NullPointerException("ECKeyImpl::groupId() => _pEC");
179}
180
181
182std::string ECKeyImpl::getCurveName(int nid)
183{
184 std::string curveName;
185 size_t len = EC_get_builtin_curves(NULL, 0);
186 EC_builtin_curve* pCurves =
187 (EC_builtin_curve*) OPENSSL_malloc(static_cast<int>(sizeof(EC_builtin_curve) * len));
188 if (!pCurves) return curveName;
189
190 if (!EC_get_builtin_curves(pCurves, len))
191 {
192 OPENSSL_free(pCurves);
193 return curveName;
194 }
195
196 if (-1 == nid) nid = pCurves[0].nid;
197 const int bufLen = 128;
198 char buf[bufLen];
199 std::memset(buf, 0, bufLen);
200 OBJ_obj2txt(buf, bufLen, OBJ_nid2obj(nid), 0);
201 curveName = buf;
202 OPENSSL_free(pCurves);
203 return curveName;
204}
205
206
207int ECKeyImpl::getCurveNID(std::string& name)
208{
209 std::string curveName;
210 size_t len = EC_get_builtin_curves(NULL, 0);
211 EC_builtin_curve* pCurves =
212 (EC_builtin_curve*)OPENSSL_malloc(static_cast<int>(sizeof(EC_builtin_curve) * len));
213 if (!pCurves) return -1;
214
215 if (!EC_get_builtin_curves(pCurves, len))
216 {
217 OPENSSL_free(pCurves);
218 return -1;
219 }
220
221 int nid = -1;
222 const int bufLen = 128;
223 char buf[bufLen];
224 if (name.empty())
225 {
226 std::memset(buf, 0, bufLen);
227 OBJ_obj2txt(buf, bufLen, OBJ_nid2obj(nid), 0);
228 name = buf;
229 nid = pCurves[0].nid;
230 }
231 else
232 {
233 for (int i = 0; i < len; ++i)
234 {
235 std::memset(buf, 0, bufLen);
236 OBJ_obj2txt(buf, bufLen, OBJ_nid2obj(pCurves[i].nid), 0);
237 if (strncmp(name.c_str(), buf, name.size() > bufLen ? bufLen : name.size()) == 0)
238 {
239 nid = pCurves[i].nid;
240 break;
241 }
242 }
243 }
244
245 OPENSSL_free(pCurves);
246 return nid;
247}
248
249
250bool ECKeyImpl::hasCurve(const std::string& name)
251{
252 std::string tmp(name);
253 return (-1 != getCurveNID(tmp));
254}
255
256
257} } // namespace Poco::Crypto
258