2 * keyraw.c - raw key operations and conversions
4 * (c) NLnet Labs, 2004-2008
6 * See the file LICENSE for the license
10 * Implementation of raw DNSKEY functions (work on wire rdata).
14 #include "sldns/keyraw.h"
15 #include "sldns/rrdef.h"
18 #include <openssl/ssl.h>
19 #include <openssl/evp.h>
20 #include <openssl/rand.h>
21 #include <openssl/err.h>
22 #include <openssl/md5.h>
23 #ifdef HAVE_OPENSSL_ENGINE_H
24 # include <openssl/engine.h>
26 #ifdef HAVE_OPENSSL_BN_H
27 #include <openssl/bn.h>
29 #ifdef HAVE_OPENSSL_RSA_H
30 #include <openssl/rsa.h>
32 #ifdef HAVE_OPENSSL_DSA_H
33 #include <openssl/dsa.h>
38 sldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
39 const size_t len, int alg)
48 switch ((sldns_algorithm)alg) {
60 case LDNS_RSASHA1_NSEC3:
66 if (keydata[0] == 0) {
69 memmove(&int16, keydata + 1, 2);
71 return (len - exp - 3)*8;
88 case LDNS_ECDSAP256SHA256:
90 case LDNS_ECDSAP384SHA384:
98 uint16_t sldns_calc_keytag_raw(uint8_t* key, size_t keysize)
103 /* look at the algorithm field, copied from 2535bis */
104 if (key[3] == LDNS_RSAMD5) {
107 memmove(&ac16, key + keysize - 3, 2);
110 return (uint16_t) ac16;
114 for (i = 0; i < keysize; ++i) {
115 ac32 += (i & 1) ? key[i] : key[i] << 8;
117 ac32 += (ac32 >> 16) & 0xFFFF;
118 return (uint16_t) (ac32 & 0xFFFF);
124 /** store GOST engine reference loaded into OpenSSL library */
125 ENGINE* sldns_gost_engine = NULL;
128 sldns_key_EVP_load_gost_id(void)
130 static int gost_id = 0;
131 const EVP_PKEY_ASN1_METHOD* meth;
134 if(gost_id) return gost_id;
136 /* see if configuration loaded gost implementation from other engine*/
137 meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1);
139 EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
143 /* see if engine can be loaded already */
144 e = ENGINE_by_id("gost");
146 /* load it ourself, in case statically linked */
147 ENGINE_load_builtin_engines();
148 ENGINE_load_dynamic();
149 e = ENGINE_by_id("gost");
152 /* no gost engine in openssl */
155 if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
161 meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1);
168 /* Note: do not ENGINE_finish and ENGINE_free the acquired engine
169 * on some platforms this frees up the meth and unloads gost stuff */
170 sldns_gost_engine = e;
172 EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
176 void sldns_key_EVP_unload_gost(void)
178 if(sldns_gost_engine) {
179 ENGINE_finish(sldns_gost_engine);
180 ENGINE_free(sldns_gost_engine);
181 sldns_gost_engine = NULL;
184 #endif /* USE_GOST */
187 sldns_key_buf2dsa_raw(unsigned char* key, size_t len)
193 BIGNUM *Q; BIGNUM *P;
194 BIGNUM *G; BIGNUM *Y;
199 length = (64 + T * 8);
205 if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length)
208 Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL);
209 offset += SHA_DIGEST_LENGTH;
211 P = BN_bin2bn(key+offset, (int)length, NULL);
214 G = BN_bin2bn(key+offset, (int)length, NULL);
217 Y = BN_bin2bn(key+offset, (int)length, NULL);
219 /* create the key and set its properties */
220 if(!Q || !P || !G || !Y || !(dsa = DSA_new())) {
227 #if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
235 #else /* OPENSSL_VERSION_NUMBER */
236 if (!DSA_set0_pqg(dsa, P, Q, G)) {
237 /* QPG not yet attached, need to free */
246 if (!DSA_set0_key(dsa, Y, NULL)) {
247 /* QPG attached, cleaned up by DSA_fre() */
258 sldns_key_buf2rsa_raw(unsigned char* key, size_t len)
272 memmove(&int16, key+1, 2);
280 /* key length at least one */
281 if(len < (size_t)offset + exp + 1)
286 if(!exponent) return NULL;
287 (void) BN_bin2bn(key+offset, (int)exp, exponent);
296 /* length of the buffer must match the key length! */
297 (void) BN_bin2bn(key+offset, (int)(len - offset), modulus);
305 #if OPENSSL_VERSION_NUMBER < 0x10100000 || defined(HAVE_LIBRESSL)
311 #else /* OPENSSL_VERSION_NUMBER */
312 if (!RSA_set0_key(rsa, modulus, exponent, NULL)) {
325 sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
327 /* prefix header for X509 encoding */
328 uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
329 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85,
330 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03,
331 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40};
332 unsigned char encoded[37+64];
333 const unsigned char* pp;
340 memmove(encoded, asn, 37);
341 memmove(encoded+37, key, 64);
342 pp = (unsigned char*)&encoded[0];
344 return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded));
346 #endif /* USE_GOST */
350 sldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo)
352 unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */
353 const unsigned char* pp = buf;
356 /* check length, which uncompressed must be 2 bignums */
357 if(algo == LDNS_ECDSAP256SHA256) {
358 if(keylen != 2*256/8) return NULL;
359 ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
360 } else if(algo == LDNS_ECDSAP384SHA384) {
361 if(keylen != 2*384/8) return NULL;
362 ec = EC_KEY_new_by_curve_name(NID_secp384r1);
365 if(keylen+1 > sizeof(buf)) { /* sanity check */
369 /* prepend the 0x02 (from docs) (or actually 0x04 from implementation
370 * of openssl) for uncompressed data */
371 buf[0] = POINT_CONVERSION_UNCOMPRESSED;
372 memmove(buf+1, key, keylen);
373 if(!o2i_ECPublicKey(&ec, &pp, (int)keylen+1)) {
377 evp_key = EVP_PKEY_new();
382 if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
383 EVP_PKEY_free(evp_key);
389 #endif /* USE_ECDSA */
393 sldns_ed255192pkey_raw(const unsigned char* key, size_t keylen)
395 /* ASN1 for ED25519 is 302a300506032b6570032100 <32byteskey> */
396 uint8_t pre[] = {0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65,
397 0x70, 0x03, 0x21, 0x00};
401 /* pp gets modified by d2i() */
402 const unsigned char* pp = (unsigned char*)buf;
403 if(keylen != 32 || keylen + pre_len > sizeof(buf))
404 return NULL; /* wrong length */
405 memmove(buf, pre, pre_len);
406 memmove(buf+pre_len, key, keylen);
407 evp_key = d2i_PUBKEY(NULL, &pp, (int)(pre_len+keylen));
410 #endif /* USE_ED25519 */
413 sldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest,
417 ctx = EVP_MD_CTX_create();
420 if(!EVP_DigestInit_ex(ctx, md, NULL) ||
421 !EVP_DigestUpdate(ctx, data, len) ||
422 !EVP_DigestFinal_ex(ctx, dest, NULL)) {
423 EVP_MD_CTX_destroy(ctx);
426 EVP_MD_CTX_destroy(ctx);
429 #endif /* HAVE_SSL */