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