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