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>
29 sldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
30 const size_t len, int alg)
39 switch ((sldns_algorithm)alg) {
51 case LDNS_RSASHA1_NSEC3:
57 if (keydata[0] == 0) {
60 memmove(&int16, keydata + 1, 2);
62 return (len - exp - 3)*8;
79 case LDNS_ECDSAP256SHA256:
81 case LDNS_ECDSAP384SHA384:
89 uint16_t sldns_calc_keytag_raw(uint8_t* key, size_t keysize)
94 /* look at the algorithm field, copied from 2535bis */
95 if (key[3] == LDNS_RSAMD5) {
98 memmove(&ac16, key + keysize - 3, 2);
101 return (uint16_t) ac16;
105 for (i = 0; i < keysize; ++i) {
106 ac32 += (i & 1) ? key[i] : key[i] << 8;
108 ac32 += (ac32 >> 16) & 0xFFFF;
109 return (uint16_t) (ac32 & 0xFFFF);
115 /** store GOST engine reference loaded into OpenSSL library */
116 ENGINE* sldns_gost_engine = NULL;
119 sldns_key_EVP_load_gost_id(void)
121 static int gost_id = 0;
122 const EVP_PKEY_ASN1_METHOD* meth;
125 if(gost_id) return gost_id;
127 /* see if configuration loaded gost implementation from other engine*/
128 meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1);
130 EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
134 /* see if engine can be loaded already */
135 e = ENGINE_by_id("gost");
137 /* load it ourself, in case statically linked */
138 ENGINE_load_builtin_engines();
139 ENGINE_load_dynamic();
140 e = ENGINE_by_id("gost");
143 /* no gost engine in openssl */
146 if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
152 meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1);
159 /* Note: do not ENGINE_finish and ENGINE_free the acquired engine
160 * on some platforms this frees up the meth and unloads gost stuff */
161 sldns_gost_engine = e;
163 EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
167 void sldns_key_EVP_unload_gost(void)
169 if(sldns_gost_engine) {
170 ENGINE_finish(sldns_gost_engine);
171 ENGINE_free(sldns_gost_engine);
172 sldns_gost_engine = NULL;
175 #endif /* USE_GOST */
178 sldns_key_buf2dsa_raw(unsigned char* key, size_t len)
184 BIGNUM *Q; BIGNUM *P;
185 BIGNUM *G; BIGNUM *Y;
190 length = (64 + T * 8);
196 if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length)
199 Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL);
200 offset += SHA_DIGEST_LENGTH;
202 P = BN_bin2bn(key+offset, (int)length, NULL);
205 G = BN_bin2bn(key+offset, (int)length, NULL);
208 Y = BN_bin2bn(key+offset, (int)length, NULL);
210 /* create the key and set its properties */
211 if(!Q || !P || !G || !Y || !(dsa = DSA_new())) {
229 sldns_key_buf2rsa_raw(unsigned char* key, size_t len)
243 memmove(&int16, key+1, 2);
251 /* key length at least one */
252 if(len < (size_t)offset + exp + 1)
257 if(!exponent) return NULL;
258 (void) BN_bin2bn(key+offset, (int)exp, exponent);
267 /* length of the buffer must match the key length! */
268 (void) BN_bin2bn(key+offset, (int)(len - offset), modulus);
286 sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
288 /* prefix header for X509 encoding */
289 uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
290 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85,
291 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03,
292 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40};
293 unsigned char encoded[37+64];
294 const unsigned char* pp;
301 memmove(encoded, asn, 37);
302 memmove(encoded+37, key, 64);
303 pp = (unsigned char*)&encoded[0];
305 return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded));
307 #endif /* USE_GOST */
311 sldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo)
313 unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */
314 const unsigned char* pp = buf;
317 /* check length, which uncompressed must be 2 bignums */
318 if(algo == LDNS_ECDSAP256SHA256) {
319 if(keylen != 2*256/8) return NULL;
320 ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
321 } else if(algo == LDNS_ECDSAP384SHA384) {
322 if(keylen != 2*384/8) return NULL;
323 ec = EC_KEY_new_by_curve_name(NID_secp384r1);
326 if(keylen+1 > sizeof(buf)) { /* sanity check */
330 /* prepend the 0x02 (from docs) (or actually 0x04 from implementation
331 * of openssl) for uncompressed data */
332 buf[0] = POINT_CONVERSION_UNCOMPRESSED;
333 memmove(buf+1, key, keylen);
334 if(!o2i_ECPublicKey(&ec, &pp, (int)keylen+1)) {
338 evp_key = EVP_PKEY_new();
343 if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
344 EVP_PKEY_free(evp_key);
350 #endif /* USE_ECDSA */
353 sldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest,
357 ctx = EVP_MD_CTX_create();
360 if(!EVP_DigestInit_ex(ctx, md, NULL) ||
361 !EVP_DigestUpdate(ctx, data, len) ||
362 !EVP_DigestFinal_ex(ctx, dest, NULL)) {
363 EVP_MD_CTX_destroy(ctx);
366 EVP_MD_CTX_destroy(ctx);
369 #endif /* HAVE_SSL */