]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/opensslsigners.cc
Merge pull request #6950 from Habbie/ixfrdist-nits
[thirdparty/pdns.git] / pdns / opensslsigners.cc
CommitLineData
12471842
PL
1/*
2 * This file is part of PowerDNS or dnsdist.
3 * Copyright -- PowerDNS.COM B.V. and its contributors
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * In addition, for the avoidance of any doubt, permission is granted to
10 * link this program with OpenSSL and to (re)distribute the binaries
11 * produced as the result of such linking.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
7581a35b
KM
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
25#include <openssl/obj_mac.h>
74d83458 26#ifdef HAVE_LIBCRYPTO_ECDSA
7581a35b 27#include <openssl/ecdsa.h>
de4e1d0d 28#endif
7581a35b
KM
29#include <openssl/sha.h>
30#include <openssl/rand.h>
a41d80d1 31#include <openssl/rsa.h>
d366601f 32#include <openssl/opensslv.h>
42f01311 33#include "opensslsigners.hh"
7581a35b 34#include "dnssecinfra.hh"
86783480 35#include "dnsseckeeper.hh"
7581a35b 36
115f658e 37#if (OPENSSL_VERSION_NUMBER < 0x1010000fL || defined LIBRESSL_VERSION_NUMBER)
d366601f 38/* OpenSSL < 1.1.0 needs support for threading/locking in the calling application. */
42f01311 39static pthread_mutex_t *openssllocks;
40
41extern "C" {
42void openssl_pthreads_locking_callback(int mode, int type, const char *file, int line)
43{
44 if (mode & CRYPTO_LOCK) {
42f01311 45 pthread_mutex_lock(&(openssllocks[type]));
46
47 }else {
42f01311 48 pthread_mutex_unlock(&(openssllocks[type]));
49 }
50}
51
52unsigned long openssl_pthreads_id_callback()
53{
54 return (unsigned long)pthread_self();
55}
56}
57
58void openssl_thread_setup()
59{
42f01311 60 openssllocks = (pthread_mutex_t*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
61
62 for (int i = 0; i < CRYPTO_num_locks(); i++)
305c6abe 63 pthread_mutex_init(&(openssllocks[i]), NULL);
42f01311 64
65 CRYPTO_set_id_callback(openssl_pthreads_id_callback);
66 CRYPTO_set_locking_callback(openssl_pthreads_locking_callback);
67}
68
69void openssl_thread_cleanup()
70{
42f01311 71 CRYPTO_set_locking_callback(NULL);
72
73 for (int i=0; i<CRYPTO_num_locks(); i++) {
74 pthread_mutex_destroy(&(openssllocks[i]));
75 }
76
77 OPENSSL_free(openssllocks);
78}
888bc297 79
1648b8ff
RG
80#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL
81/* those symbols are defined in LibreSSL 2.7.0+ */
888bc297
CH
82/* compat helpers. These DO NOT do any of the checking that the libssl 1.1 functions do. */
83static inline void RSA_get0_key(const RSA* rsakey, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d) {
84 *n = rsakey->n;
85 *e = rsakey->e;
86 *d = rsakey->d;
87}
88
89static inline int RSA_set0_key(RSA* rsakey, BIGNUM* n, BIGNUM* e, BIGNUM* d) {
90 if (n) {
91 BN_clear_free(rsakey->n);
92 rsakey->n = n;
93 }
94 if (e) {
95 BN_clear_free(rsakey->e);
96 rsakey->e = e;
97 }
98 if (d) {
99 BN_clear_free(rsakey->d);
100 rsakey->d = d;
101 }
102 return 1;
103}
104
105static inline void RSA_get0_factors(const RSA* rsakey, const BIGNUM** p, const BIGNUM** q) {
106 *p = rsakey->p;
107 *q = rsakey->q;
108}
109
110static inline int RSA_set0_factors(RSA* rsakey, BIGNUM* p, BIGNUM* q) {
111 BN_clear_free(rsakey->p);
112 rsakey->p = p;
113 BN_clear_free(rsakey->q);
114 rsakey->q = q;
115 return 1;
116}
117
118static inline void RSA_get0_crt_params(const RSA* rsakey, const BIGNUM** dmp1, const BIGNUM** dmq1, const BIGNUM** iqmp) {
119 *dmp1 = rsakey->dmp1;
120 *dmq1 = rsakey->dmq1;
121 *iqmp = rsakey->iqmp;
122}
123
124static inline int RSA_set0_crt_params(RSA* rsakey, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp) {
125 BN_clear_free(rsakey->dmp1);
126 rsakey->dmp1 = dmp1;
127 BN_clear_free(rsakey->dmq1);
128 rsakey->dmq1 = dmq1;
129 BN_clear_free(rsakey->iqmp);
130 rsakey->iqmp = iqmp;
131 return 1;
132}
133
aa74d164 134#ifdef HAVE_LIBCRYPTO_ECDSA
888bc297
CH
135static inline void ECDSA_SIG_get0(const ECDSA_SIG* signature, const BIGNUM** pr, const BIGNUM** ps) {
136 *pr = signature->r;
137 *ps = signature->s;
138}
139
140static inline int ECDSA_SIG_set0(ECDSA_SIG* signature, BIGNUM* pr, BIGNUM* ps) {
141 BN_clear_free(signature->r);
142 BN_clear_free(signature->s);
143 signature->r = pr;
144 signature->s = ps;
145 return 1;
146}
aa74d164
RG
147#endif /* HAVE_LIBCRYPTO_ECDSA */
148
1648b8ff
RG
149#endif /* !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2070000fL */
150
d366601f
CH
151#else
152void openssl_thread_setup() {}
153void openssl_thread_cleanup() {}
154#endif
42f01311 155
888bc297 156
42f01311 157/* seeding PRNG */
158
159void openssl_seed()
160{
161 std::string entropy;
162 entropy.reserve(1024);
163
164 unsigned int r;
165 for(int i=0; i<1024; i+=4) {
166 r=dns_random(0xffffffff);
167 entropy.append((const char*)&r, 4);
168 }
169
170 RAND_seed((const unsigned char*)entropy.c_str(), 1024);
171}
172
173
a41d80d1
RG
174class OpenSSLRSADNSCryptoKeyEngine : public DNSCryptoKeyEngine
175{
176public:
177 explicit OpenSSLRSADNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo)
178 {
179 int ret = RAND_status();
180 if (ret != 1) {
181 throw runtime_error(getName()+" insufficient entropy");
182 }
a41d80d1
RG
183 }
184
185 ~OpenSSLRSADNSCryptoKeyEngine()
186 {
187 if (d_key)
188 RSA_free(d_key);
189 }
190
d12b259b
CH
191 string getName() const override { return "OpenSSL RSA"; }
192 int getBits() const override { return RSA_size(d_key) << 3; }
193
194 void create(unsigned int bits) override;
195 storvector_t convertToISCVector() const override;
196 std::string hash(const std::string& hash) const override;
197 std::string sign(const std::string& hash) const override;
198 bool verify(const std::string& hash, const std::string& signature) const override;
199 std::string getPubKeyHash() const override;
200 std::string getPublicKeyString() const override;
201 void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
202 void fromPublicKeyString(const std::string& content) override;
45c2bc60 203 bool checkKey() const override;
a41d80d1 204
e69c2dac 205 static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
a41d80d1 206 {
e69c2dac 207 return std::make_shared<OpenSSLRSADNSCryptoKeyEngine>(algorithm);
a41d80d1
RG
208 }
209
210private:
349384bf
RG
211 static int hashSizeToKind(size_t hashSize);
212
a41d80d1
RG
213 RSA* d_key{NULL};
214};
215
216
217void OpenSSLRSADNSCryptoKeyEngine::create(unsigned int bits)
218{
86783480
CH
219 if ((d_algorithm == DNSSECKeeper::RSASHA1 || d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1) && (bits < 512 || bits > 4096)) {
220 /* RFC3110 */
221 throw runtime_error(getName()+" RSASHA1 key generation failed for invalid bits size " + std::to_string(bits));
222 }
223 if (d_algorithm == DNSSECKeeper::RSASHA256 && (bits < 512 || bits > 4096)) {
224 /* RFC5702 */
225 throw runtime_error(getName()+" RSASHA256 key generation failed for invalid bits size " + std::to_string(bits));
226 }
227 if (d_algorithm == DNSSECKeeper::RSASHA512 && (bits < 1024 || bits > 4096)) {
228 /* RFC5702 */
229 throw runtime_error(getName()+" RSASHA512 key generation failed for invalid bits size " + std::to_string(bits));
230 }
231
a41d80d1
RG
232 BIGNUM *e = BN_new();
233 if (!e) {
234 throw runtime_error(getName()+" key generation failed, unable to allocate e");
235 }
236
237 /* RSA_F4 is a public exponent value of 65537 */
238 int res = BN_set_word(e, RSA_F4);
239
240 if (res == 0) {
241 BN_free(e);
242 throw runtime_error(getName()+" key generation failed while setting e");
243 }
244
62be6888
RG
245 RSA* key = RSA_new();
246 if (key == NULL) {
247 BN_free(e);
248 throw runtime_error(getName()+" allocation of key structure failed");
249 }
250
251 res = RSA_generate_key_ex(key, bits, e, NULL);
a41d80d1
RG
252 BN_free(e);
253 if (res == 0) {
62be6888 254 RSA_free(key);
a41d80d1
RG
255 throw runtime_error(getName()+" key generation failed");
256 }
62be6888
RG
257
258 if (d_key)
259 RSA_free(d_key);
260
261 d_key = key;
a41d80d1
RG
262}
263
264
265DNSCryptoKeyEngine::storvector_t OpenSSLRSADNSCryptoKeyEngine::convertToISCVector() const
266{
267 storvector_t storvect;
268 typedef vector<pair<string, const BIGNUM*> > outputs_t;
269 outputs_t outputs;
888bc297
CH
270 const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
271 RSA_get0_key(d_key, &n, &e, &d);
272 RSA_get0_factors(d_key, &p, &q);
273 RSA_get0_crt_params(d_key, &dmp1, &dmq1, &iqmp);
274 outputs.push_back(make_pair("Modulus", n));
275 outputs.push_back(make_pair("PublicExponent", e));
276 outputs.push_back(make_pair("PrivateExponent", d));
277 outputs.push_back(make_pair("Prime1", p));
278 outputs.push_back(make_pair("Prime2", q));
279 outputs.push_back(make_pair("Exponent1", dmp1));
280 outputs.push_back(make_pair("Exponent2", dmq1));
281 outputs.push_back(make_pair("Coefficient", iqmp));
a41d80d1
RG
282
283 string algorithm=std::to_string(d_algorithm);
284 switch(d_algorithm) {
902c4e9c
CH
285 case DNSSECKeeper::RSASHA1:
286 case DNSSECKeeper::RSASHA1NSEC3SHA1:
a41d80d1
RG
287 algorithm += " (RSASHA1)";
288 break;
902c4e9c 289 case DNSSECKeeper::RSASHA256:
a41d80d1
RG
290 algorithm += " (RSASHA256)";
291 break;
902c4e9c 292 case DNSSECKeeper::RSASHA512:
a41d80d1
RG
293 algorithm += " (RSASHA512)";
294 break;
349384bf
RG
295 default:
296 algorithm += " (?)";
a41d80d1
RG
297 }
298 storvect.push_back(make_pair("Algorithm", algorithm));
299
300 for(outputs_t::value_type value : outputs) {
e5f0dee1
RG
301 std::string tmp;
302 tmp.resize(BN_num_bytes(value.second));
303 int len = BN_bn2bin(value.second, reinterpret_cast<unsigned char*>(&tmp.at(0)));
304 if (len >= 0) {
305 tmp.resize(len);
306 storvect.push_back(make_pair(value.first, tmp));
307 }
a41d80d1
RG
308 }
309
310 return storvect;
311}
312
313
314std::string OpenSSLRSADNSCryptoKeyEngine::hash(const std::string& orig) const
315{
902c4e9c 316 if (d_algorithm == DNSSECKeeper::RSASHA1 || d_algorithm == DNSSECKeeper::RSASHA1NSEC3SHA1) {
a41d80d1
RG
317 unsigned char hash[SHA_DIGEST_LENGTH];
318 SHA1((unsigned char*) orig.c_str(), orig.length(), hash);
319 return string((char*) hash, sizeof(hash));
320 }
902c4e9c 321 else if (d_algorithm == DNSSECKeeper::RSASHA256) {
a41d80d1
RG
322 unsigned char hash[SHA256_DIGEST_LENGTH];
323 SHA256((unsigned char*) orig.c_str(), orig.length(), hash);
324 return string((char*) hash, sizeof(hash));
325 }
902c4e9c 326 else if (d_algorithm == DNSSECKeeper::RSASHA512) {
a41d80d1
RG
327 unsigned char hash[SHA512_DIGEST_LENGTH];
328 SHA512((unsigned char*) orig.c_str(), orig.length(), hash);
329 return string((char*) hash, sizeof(hash));
330 }
331
332 throw runtime_error(getName()+" does not support hash operation for algorithm "+std::to_string(d_algorithm));
333}
334
349384bf
RG
335int OpenSSLRSADNSCryptoKeyEngine::hashSizeToKind(const size_t hashSize)
336{
337 switch(hashSize) {
338 case SHA_DIGEST_LENGTH:
339 return NID_sha1;
340 case SHA256_DIGEST_LENGTH:
341 return NID_sha256;
342 case SHA384_DIGEST_LENGTH:
343 return NID_sha384;
344 case SHA512_DIGEST_LENGTH:
345 return NID_sha512;
346 default:
347 throw runtime_error("OpenSSL RSA does not handle hash of size " + std::to_string(hashSize));
348 }
349}
a41d80d1
RG
350
351std::string OpenSSLRSADNSCryptoKeyEngine::sign(const std::string& msg) const
352{
353 string hash = this->hash(msg);
349384bf 354 int hashKind = hashSizeToKind(hash.size());
e5f0dee1
RG
355 std::string signature;
356 signature.resize(RSA_size(d_key));
a41d80d1
RG
357 unsigned int signatureLen = 0;
358
e5f0dee1 359 int res = RSA_sign(hashKind, reinterpret_cast<unsigned char*>(&hash.at(0)), hash.length(), reinterpret_cast<unsigned char*>(&signature.at(0)), &signatureLen, d_key);
a41d80d1
RG
360 if (res != 1) {
361 throw runtime_error(getName()+" failed to generate signature");
362 }
363
e5f0dee1
RG
364 signature.resize(signatureLen);
365 return signature;
a41d80d1
RG
366}
367
368
369bool OpenSSLRSADNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const
370{
371 string hash = this->hash(msg);
349384bf 372 int hashKind = hashSizeToKind(hash.size());
a41d80d1
RG
373
374 int ret = RSA_verify(hashKind, (const unsigned char*) hash.c_str(), hash.length(), (unsigned char*) signature.c_str(), signature.length(), d_key);
375
376 return (ret == 1);
377}
378
379
380std::string OpenSSLRSADNSCryptoKeyEngine::getPubKeyHash() const
381{
888bc297
CH
382 const BIGNUM *n, *e, *d;
383 RSA_get0_key(d_key, &n, &e, &d);
e5f0dee1
RG
384 std::vector<unsigned char> tmp;
385 tmp.resize(std::max(BN_num_bytes(e), BN_num_bytes(n)));
a41d80d1
RG
386 unsigned char hash[SHA_DIGEST_LENGTH];
387 SHA_CTX ctx;
388
389 int res = SHA1_Init(&ctx);
390
391 if (res != 1) {
392 throw runtime_error(getName()+" failed to init hash context for generating the public key hash");
393 }
394
c2a16005
RG
395 int len = BN_bn2bin(e, tmp.data());
396 res = SHA1_Update(&ctx, tmp.data(), len);
a41d80d1
RG
397 if (res != 1) {
398 throw runtime_error(getName()+" failed to update hash context for generating the public key hash");
399 }
400
c2a16005
RG
401 len = BN_bn2bin(n, tmp.data());
402 res = SHA1_Update(&ctx, tmp.data(), len);
a41d80d1
RG
403 if (res != 1) {
404 throw runtime_error(getName()+" failed to update hash context for generating the public key hash");
405 }
406
407 res = SHA1_Final(hash, &ctx);
408 if (res != 1) {
409 throw runtime_error(getName()+" failed to finish hash context for generating the public key hash");
410 }
411
412 return string((char*) hash, sizeof(hash));
413}
414
415
416std::string OpenSSLRSADNSCryptoKeyEngine::getPublicKeyString() const
417{
888bc297
CH
418 const BIGNUM *n, *e, *d;
419 RSA_get0_key(d_key, &n, &e, &d);
a41d80d1 420 string keystring;
e5f0dee1
RG
421 std::string tmp;
422 tmp.resize(std::max(BN_num_bytes(e), BN_num_bytes(n)));
a41d80d1 423
e5f0dee1 424 int len = BN_bn2bin(e, reinterpret_cast<unsigned char*>(&tmp.at(0)));
a41d80d1
RG
425 if (len < 255) {
426 keystring.assign(1, (char) (unsigned int) len);
427 } else {
428 keystring.assign(1, 0);
429 uint16_t tempLen = len;
430 tempLen = htons(tempLen);
431 keystring.append((char*)&tempLen, 2);
432 }
e5f0dee1 433 keystring.append(&tmp.at(0), len);
a41d80d1 434
e5f0dee1
RG
435 len = BN_bn2bin(n, reinterpret_cast<unsigned char*>(&tmp.at(0)));
436 keystring.append(&tmp.at(0), len);
a41d80d1
RG
437
438 return keystring;
439}
440
441
442void OpenSSLRSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap)
443{
a41d80d1
RG
444 typedef map<string, BIGNUM**> places_t;
445 places_t places;
62be6888
RG
446 RSA* key = RSA_new();
447 if (key == NULL) {
448 throw runtime_error(getName()+" allocation of key structure failed");
449 }
a41d80d1 450
888bc297
CH
451 BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
452 n = BN_new();
453 if (n == NULL) {
454 RSA_free(key);
455 throw runtime_error(getName()+" allocation of BIGNUM n failed");
456 }
457 e = BN_new();
458 if (e == NULL) {
459 RSA_free(key);
460 BN_clear_free(n);
461 throw runtime_error(getName()+" allocation of BIGNUM e failed");
462 }
463 d = BN_new();
464 if (d == NULL) {
465 RSA_free(key);
466 BN_clear_free(n);
467 BN_clear_free(e);
468 throw runtime_error(getName()+" allocation of BIGNUM d failed");
469 }
470 RSA_set0_key(key, n, e, d);
471
472 p = BN_new();
473 if (p == NULL) {
474 RSA_free(key);
475 throw runtime_error(getName()+" allocation of BIGNUM p failed");
476 }
477 q = BN_new();
478 if (q == NULL) {
479 RSA_free(key);
480 BN_clear_free(p);
481 throw runtime_error(getName()+" allocation of BIGNUM q failed");
482 }
483 RSA_set0_factors(key, p, q);
484
485 dmp1 = BN_new();
486 if (dmp1 == NULL) {
487 RSA_free(key);
488 throw runtime_error(getName()+" allocation of BIGNUM dmp1 failed");
489 }
490 dmq1 = BN_new();
491 if (dmq1 == NULL) {
492 RSA_free(key);
493 BN_clear_free(dmp1);
494 throw runtime_error(getName()+" allocation of BIGNUM dmq1 failed");
495 }
496 iqmp = BN_new();
497 if (iqmp == NULL) {
498 RSA_free(key);
499 BN_clear_free(dmq1);
e4238b33 500 BN_clear_free(dmp1);
888bc297
CH
501 throw runtime_error(getName()+" allocation of BIGNUM iqmp failed");
502 }
503 RSA_set0_crt_params(key, dmp1, dmq1, iqmp);
504
505 places["Modulus"]=&n;
506 places["PublicExponent"]=&e;
507 places["PrivateExponent"]=&d;
508 places["Prime1"]=&p;
509 places["Prime2"]=&q;
510 places["Exponent1"]=&dmp1;
511 places["Exponent2"]=&dmq1;
512 places["Coefficient"]=&iqmp;
a41d80d1
RG
513
514 drc.d_algorithm = pdns_stou(stormap["algorithm"]);
515
516 string raw;
517 for(const places_t::value_type& val : places) {
518 raw=stormap[toLower(val.first)];
349384bf
RG
519
520 if (!val.second)
521 continue;
522
888bc297 523 *val.second = BN_bin2bn((unsigned char*) raw.c_str(), raw.length(), *val.second);
a41d80d1 524 if (!*val.second) {
62be6888 525 RSA_free(key);
a41d80d1
RG
526 throw runtime_error(getName()+" error loading " + val.first);
527 }
528 }
529
530 if (drc.d_algorithm != d_algorithm) {
62be6888 531 RSA_free(key);
a41d80d1
RG
532 throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc.d_algorithm)+" to a "+std::to_string(d_algorithm)+" key");
533 }
534
62be6888
RG
535 if (d_key)
536 RSA_free(d_key);
537
538 d_key = key;
a41d80d1
RG
539}
540
45c2bc60 541bool OpenSSLRSADNSCryptoKeyEngine::checkKey() const
8ca3ea33
RG
542{
543 return (RSA_check_key(d_key) == 1);
544}
545
a41d80d1
RG
546void OpenSSLRSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& input)
547{
548 string exponent, modulus;
349384bf 549 const size_t inputLen = input.length();
a41d80d1
RG
550 const unsigned char* raw = (const unsigned char*)input.c_str();
551
349384bf
RG
552 if (inputLen < 1) {
553 throw runtime_error(getName()+" invalid input size for the public key");
554 }
555
a41d80d1 556 if (raw[0] != 0) {
349384bf
RG
557 const size_t exponentSize = raw[0];
558 if (inputLen < (exponentSize + 2)) {
559 throw runtime_error(getName()+" invalid input size for the public key");
560 }
561 exponent = input.substr(1, exponentSize);
562 modulus = input.substr(exponentSize + 1);
a41d80d1 563 } else {
349384bf
RG
564 if (inputLen < 3) {
565 throw runtime_error(getName()+" invalid input size for the public key");
566 }
567 const size_t exponentSize = raw[1]*0xff + raw[2];
568 if (inputLen < (exponentSize + 4)) {
569 throw runtime_error(getName()+" invalid input size for the public key");
570 }
571 exponent = input.substr(3, exponentSize);
572 modulus = input.substr(exponentSize + 3);
a41d80d1
RG
573 }
574
62be6888
RG
575 RSA* key = RSA_new();
576 if (key == NULL) {
577 throw runtime_error(getName()+" allocation of key structure failed");
578 }
349384bf 579
888bc297
CH
580 BIGNUM *e = BN_bin2bn((unsigned char*)exponent.c_str(), exponent.length(), NULL);
581 if (!e) {
62be6888 582 RSA_free(key);
a41d80d1
RG
583 throw runtime_error(getName()+" error loading e value of public key");
584 }
888bc297
CH
585 BIGNUM *n = BN_bin2bn((unsigned char*)modulus.c_str(), modulus.length(), NULL);
586 if (!n) {
62be6888 587 RSA_free(key);
e4238b33 588 BN_clear_free(e);
a41d80d1
RG
589 throw runtime_error(getName()+" error loading n value of public key");
590 }
8ca3ea33 591
62be6888
RG
592 if (d_key)
593 RSA_free(d_key);
594
888bc297 595 RSA_set0_key(key, n, e, NULL);
62be6888 596 d_key = key;
a41d80d1 597}
7581a35b 598
74d83458 599#ifdef HAVE_LIBCRYPTO_ECDSA
7581a35b
KM
600class OpenSSLECDSADNSCryptoKeyEngine : public DNSCryptoKeyEngine
601{
602public:
603 explicit OpenSSLECDSADNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo)
c00bd468 604 {
7581a35b
KM
605
606 int ret = RAND_status();
607 if (ret != 1) {
608 throw runtime_error(getName()+" insufficient entropy");
609 }
610
611 d_eckey = EC_KEY_new();
612 if (d_eckey == NULL) {
613 throw runtime_error(getName()+" allocation of key structure failed");
614 }
615
616 if(d_algorithm == 13) {
617 d_ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
618 d_len = 32;
619 } else if (d_algorithm == 14) {
620 d_ecgroup = EC_GROUP_new_by_curve_name(NID_secp384r1);
621 d_len = 48;
622 } else {
b141d89b 623 EC_KEY_free(d_eckey);
7581a35b
KM
624 throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm));
625 }
b141d89b 626
7581a35b 627 if (d_ecgroup == NULL) {
b141d89b 628 EC_KEY_free(d_eckey);
7581a35b
KM
629 throw runtime_error(getName()+" allocation of group structure failed");
630 }
631
b141d89b 632 ret = EC_KEY_set_group(d_eckey, d_ecgroup);
7581a35b 633 if (ret != 1) {
b141d89b
RG
634 EC_KEY_free(d_eckey);
635 EC_GROUP_free(d_ecgroup);
7581a35b
KM
636 throw runtime_error(getName()+" setting key group failed");
637 }
638
639 }
640
641 ~OpenSSLECDSADNSCryptoKeyEngine()
642 {
643 EC_KEY_free(d_eckey);
644 EC_GROUP_free(d_ecgroup);
645 BN_CTX_free(d_ctx);
646 }
647
d12b259b
CH
648 string getName() const override { return "OpenSSL ECDSA"; }
649 int getBits() const override { return d_len << 3; }
7581a35b 650
d12b259b
CH
651 void create(unsigned int bits) override;
652 storvector_t convertToISCVector() const override;
653 std::string hash(const std::string& hash) const override;
654 std::string sign(const std::string& hash) const override;
655 bool verify(const std::string& hash, const std::string& signature) const override;
656 std::string getPubKeyHash() const override;
657 std::string getPublicKeyString() const override;
658 void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
659 void fromPublicKeyString(const std::string& content) override;
45c2bc60 660 bool checkKey() const override;
7581a35b 661
e69c2dac 662 static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
7581a35b 663 {
e69c2dac 664 return std::make_shared<OpenSSLECDSADNSCryptoKeyEngine>(algorithm);
7581a35b
KM
665 }
666
667private:
668 unsigned int d_len;
669
670 EC_KEY *d_eckey = NULL;
671 EC_GROUP *d_ecgroup = NULL;
672 BN_CTX *d_ctx = NULL;
673};
674
675
676void OpenSSLECDSADNSCryptoKeyEngine::create(unsigned int bits)
677{
678 if (bits >> 3 != d_len) {
679 throw runtime_error(getName()+" unknown key length of "+std::to_string(bits)+" bits requested");
680 }
681
682 int res = EC_KEY_generate_key(d_eckey);
683 if (res == 0) {
684 throw runtime_error(getName()+" key generation failed");
685 }
686}
687
688
689DNSCryptoKeyEngine::storvector_t OpenSSLECDSADNSCryptoKeyEngine::convertToISCVector() const
690{
691 storvector_t storvect;
692 string algorithm;
693
694 if(d_algorithm == 13)
695 algorithm = "13 (ECDSAP256SHA256)";
696 else if(d_algorithm == 14)
697 algorithm = "14 (ECDSAP384SHA384)";
698 else
699 algorithm = " ? (?)";
700
701 storvect.push_back(make_pair("Algorithm", algorithm));
702
703 const BIGNUM *key = EC_KEY_get0_private_key(d_eckey);
704 if (key == NULL) {
705 throw runtime_error(getName()+" private key not set");
706 }
707
e5f0dee1
RG
708 std::string tmp;
709 tmp.resize(BN_num_bytes(key));
710 int len = BN_bn2bin(key, reinterpret_cast<unsigned char*>(&tmp.at(0)));
7581a35b
KM
711
712 string prefix;
713 if (d_len - len)
714 prefix.append(d_len - len, 0x00);
715
e5f0dee1 716 storvect.push_back(make_pair("PrivateKey", prefix + tmp));
7581a35b
KM
717
718 return storvect;
719}
720
721
722std::string OpenSSLECDSADNSCryptoKeyEngine::hash(const std::string& orig) const
723{
724 if(getBits() == 256) {
725 unsigned char hash[SHA256_DIGEST_LENGTH];
726 SHA256((unsigned char*) orig.c_str(), orig.length(), hash);
727 return string((char*) hash, sizeof(hash));
728 }
729 else if(getBits() == 384) {
730 unsigned char hash[SHA384_DIGEST_LENGTH];
731 SHA384((unsigned char*) orig.c_str(), orig.length(), hash);
732 return string((char*) hash, sizeof(hash));
733 }
734
735 throw runtime_error(getName()+" does not support a hash size of "+std::to_string(getBits())+" bits");
736}
737
738
739std::string OpenSSLECDSADNSCryptoKeyEngine::sign(const std::string& msg) const
740{
741 string hash = this->hash(msg);
742
743 ECDSA_SIG *signature = ECDSA_do_sign((unsigned char*) hash.c_str(), hash.length(), d_eckey);
744 if (NULL == signature) {
745 throw runtime_error(getName()+" failed to generate signature");
746 }
747
748 string ret;
e5f0dee1
RG
749 std::string tmp;
750 tmp.resize(d_len);
7581a35b 751
888bc297
CH
752 const BIGNUM *pr, *ps;
753 ECDSA_SIG_get0(signature, &pr, &ps);
e5f0dee1 754 int len = BN_bn2bin(pr, reinterpret_cast<unsigned char*>(&tmp.at(0)));
7581a35b
KM
755 if (d_len - len)
756 ret.append(d_len - len, 0x00);
e5f0dee1 757 ret.append(&tmp.at(0), len);
7581a35b 758
e5f0dee1 759 len = BN_bn2bin(ps, reinterpret_cast<unsigned char*>(&tmp.at(0)));
7581a35b
KM
760 if (d_len - len)
761 ret.append(d_len - len, 0x00);
e5f0dee1 762 ret.append(&tmp.at(0), len);
7581a35b
KM
763
764 ECDSA_SIG_free(signature);
765
766 return ret;
767}
768
769
770bool OpenSSLECDSADNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const
771{
772 if (signature.length() != (d_len * 2)) {
773 throw runtime_error(getName()+" invalid signature size "+std::to_string(signature.length()));
774 }
775
776 string hash = this->hash(msg);
777
778 ECDSA_SIG *sig;
779 sig = ECDSA_SIG_new();
780 if (sig == NULL) {
781 throw runtime_error(getName()+" allocation of signature structure failed");
782 }
783
888bc297
CH
784 BIGNUM *r, *s;
785 r = BN_bin2bn((unsigned char*) signature.c_str(), d_len, NULL);
786 s = BN_bin2bn((unsigned char*) signature.c_str() + d_len, d_len, NULL);
787 if (!r || !s) {
788 if (r) {
789 BN_clear_free(r);
790 }
791 if (s) {
792 BN_clear_free(s);
793 }
7581a35b
KM
794 ECDSA_SIG_free(sig);
795 throw runtime_error(getName()+" invalid signature");
796 }
797
888bc297 798 ECDSA_SIG_set0(sig, r, s);
7581a35b
KM
799 int ret = ECDSA_do_verify((unsigned char*) hash.c_str(), hash.length(), sig, d_eckey);
800
801 ECDSA_SIG_free(sig);
802
803 if (ret == -1){
804 throw runtime_error(getName()+" verify error");
805 }
806
807 return (ret == 1);
808}
809
810
811std::string OpenSSLECDSADNSCryptoKeyEngine::getPubKeyHash() const
812{
813 string pubKey = getPublicKeyString();
814 unsigned char hash[SHA_DIGEST_LENGTH];
815 SHA1((unsigned char*) pubKey.c_str(), pubKey.length(), hash);
816 return string((char*) hash, sizeof(hash));
817}
818
819
820std::string OpenSSLECDSADNSCryptoKeyEngine::getPublicKeyString() const
821{
e5f0dee1
RG
822 std::string binaryPoint;
823 binaryPoint.resize((d_len * 2) + 1);
7581a35b 824
e5f0dee1 825 int ret = EC_POINT_point2oct(d_ecgroup, EC_KEY_get0_public_key(d_eckey), POINT_CONVERSION_UNCOMPRESSED, reinterpret_cast<unsigned char*>(&binaryPoint.at(0)), binaryPoint.size(), d_ctx);
7581a35b
KM
826 if (ret == 0) {
827 throw runtime_error(getName()+" exporting point to binary failed");
828 }
829
830 /* we skip the first byte as the other backends use
831 raw field elements, as opposed to the format described in
832 SEC1: "2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion" */
e5f0dee1
RG
833 binaryPoint.erase(0, 1);
834 return binaryPoint;
7581a35b
KM
835}
836
837
838void OpenSSLECDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap)
839{
840 drc.d_algorithm = atoi(stormap["algorithm"].c_str());
841
842 if (drc.d_algorithm != d_algorithm) {
843 throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc.d_algorithm)+" to a "+std::to_string(d_algorithm)+" key");
844 }
845
846 string privateKey = stormap["privatekey"];
847
848 BIGNUM *prv_key = BN_bin2bn((unsigned char*) privateKey.c_str(), privateKey.length(), NULL);
849 if (prv_key == NULL) {
850 throw runtime_error(getName()+" reading private key from binary failed");
851 }
852
853 int ret = EC_KEY_set_private_key(d_eckey, prv_key);
854 if (ret != 1) {
8a0010a9 855 BN_clear_free(prv_key);
7581a35b
KM
856 throw runtime_error(getName()+" setting private key failed");
857 }
858
859 EC_POINT *pub_key = EC_POINT_new(d_ecgroup);
860 if (pub_key == NULL) {
8a0010a9 861 BN_clear_free(prv_key);
7581a35b
KM
862 throw runtime_error(getName()+" allocation of public key point failed");
863 }
864
865 ret = EC_POINT_mul(d_ecgroup, pub_key, prv_key, NULL, NULL, d_ctx);
866 if (ret != 1) {
867 EC_POINT_free(pub_key);
8a0010a9 868 BN_clear_free(prv_key);
7581a35b
KM
869 throw runtime_error(getName()+" computing public key from private failed");
870 }
871
8a0010a9 872 BN_clear_free(prv_key);
7581a35b
KM
873
874 ret = EC_KEY_set_public_key(d_eckey, pub_key);
875 if (ret != 1) {
876 EC_POINT_free(pub_key);
877 throw runtime_error(getName()+" setting public key failed");
878 }
879
880 EC_POINT_free(pub_key);
7581a35b
KM
881}
882
45c2bc60 883bool OpenSSLECDSADNSCryptoKeyEngine::checkKey() const
8ca3ea33
RG
884{
885 return (EC_KEY_check_key(d_eckey) == 1);
886}
7581a35b
KM
887
888void OpenSSLECDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& input)
889{
890 /* uncompressed point, from SEC1:
891 "2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion" */
892 string ecdsaPoint= "\x04";
893 ecdsaPoint.append(input);
894
895 EC_POINT *pub_key = EC_POINT_new(d_ecgroup);
896 if (pub_key == NULL) {
897 throw runtime_error(getName()+" allocation of point structure failed");
898 }
899
900 int ret = EC_POINT_oct2point(d_ecgroup, pub_key, (unsigned char*) ecdsaPoint.c_str(), ecdsaPoint.length(), d_ctx);
901 if (ret != 1) {
2f5b0e17 902 EC_POINT_free(pub_key);
7581a35b
KM
903 throw runtime_error(getName()+" reading ECP point from binary failed");
904 }
905
906 ret = EC_KEY_set_private_key(d_eckey, NULL);
907 if (ret == 1) {
908 EC_POINT_free(pub_key);
909 throw runtime_error(getName()+" setting private key failed");
910 }
911
912 ret = EC_KEY_set_public_key(d_eckey, pub_key);
913 if (ret != 1) {
914 EC_POINT_free(pub_key);
915 throw runtime_error(getName()+" setting public key failed");
916 }
917
918 EC_POINT_free(pub_key);
7581a35b 919}
de4e1d0d 920#endif
7581a35b
KM
921
922
923namespace {
924 struct LoaderStruct
925 {
926 LoaderStruct()
927 {
a41d80d1
RG
928 DNSCryptoKeyEngine::report(5, &OpenSSLRSADNSCryptoKeyEngine::maker);
929 DNSCryptoKeyEngine::report(7, &OpenSSLRSADNSCryptoKeyEngine::maker);
930 DNSCryptoKeyEngine::report(8, &OpenSSLRSADNSCryptoKeyEngine::maker);
931 DNSCryptoKeyEngine::report(10, &OpenSSLRSADNSCryptoKeyEngine::maker);
74d83458 932#ifdef HAVE_LIBCRYPTO_ECDSA
7581a35b
KM
933 DNSCryptoKeyEngine::report(13, &OpenSSLECDSADNSCryptoKeyEngine::maker);
934 DNSCryptoKeyEngine::report(14, &OpenSSLECDSADNSCryptoKeyEngine::maker);
de4e1d0d 935#endif
7581a35b
KM
936 }
937 } loaderOpenSSL;
938}