ECKeyImpl.cpp 6.1 KB

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