1/*
2 * keyraw.c - raw key operations and conversions
3 *
4 * (c) NLnet Labs, 2004-2008
5 *
6 * See the file LICENSE for the license
7 */
8/**
9 * \file
10 * Implementation of raw DNSKEY functions (work on wire rdata).
11 */
12
13#include "config.h"
14#include "sldns/keyraw.h"
15#include "sldns/rrdef.h"
16
17#ifdef HAVE_SSL
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>
25#endif
26#endif /* HAVE_SSL */
27
28size_t
29sldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
30	const size_t len, int alg)
31{
32	/* for DSA keys */
33	uint8_t t;
34
35	/* for RSA keys */
36	uint16_t exp;
37	uint16_t int16;
38
39	switch ((sldns_algorithm)alg) {
40	case LDNS_DSA:
41	case LDNS_DSA_NSEC3:
42		if (len > 0) {
43			t = keydata[0];
44			return (64 + t*8)*8;
45		} else {
46			return 0;
47		}
48		break;
49	case LDNS_RSAMD5:
50	case LDNS_RSASHA1:
51	case LDNS_RSASHA1_NSEC3:
52#ifdef USE_SHA2
53	case LDNS_RSASHA256:
54	case LDNS_RSASHA512:
55#endif
56		if (len > 0) {
57			if (keydata[0] == 0) {
58				/* big exponent */
59				if (len > 3) {
60					memmove(&int16, keydata + 1, 2);
61					exp = ntohs(int16);
62					return (len - exp - 3)*8;
63				} else {
64					return 0;
65				}
66			} else {
67				exp = keydata[0];
68				return (len-exp-1)*8;
69			}
70		} else {
71			return 0;
72		}
73		break;
74#ifdef USE_GOST
75	case LDNS_ECC_GOST:
76		return 512;
77#endif
78#ifdef USE_ECDSA
79        case LDNS_ECDSAP256SHA256:
80                return 256;
81        case LDNS_ECDSAP384SHA384:
82                return 384;
83#endif
84	default:
85		return 0;
86	}
87}
88
89uint16_t sldns_calc_keytag_raw(uint8_t* key, size_t keysize)
90{
91	if(keysize < 4) {
92		return 0;
93	}
94	/* look at the algorithm field, copied from 2535bis */
95	if (key[3] == LDNS_RSAMD5) {
96		uint16_t ac16 = 0;
97		if (keysize > 4) {
98			memmove(&ac16, key + keysize - 3, 2);
99		}
100		ac16 = ntohs(ac16);
101		return (uint16_t) ac16;
102	} else {
103		size_t i;
104		uint32_t ac32 = 0;
105		for (i = 0; i < keysize; ++i) {
106			ac32 += (i & 1) ? key[i] : key[i] << 8;
107		}
108		ac32 += (ac32 >> 16) & 0xFFFF;
109		return (uint16_t) (ac32 & 0xFFFF);
110	}
111}
112
113#ifdef HAVE_SSL
114#ifdef USE_GOST
115/** store GOST engine reference loaded into OpenSSL library */
116ENGINE* sldns_gost_engine = NULL;
117
118int
119sldns_key_EVP_load_gost_id(void)
120{
121	static int gost_id = 0;
122	const EVP_PKEY_ASN1_METHOD* meth;
123	ENGINE* e;
124
125	if(gost_id) return gost_id;
126
127	/* see if configuration loaded gost implementation from other engine*/
128	meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1);
129	if(meth) {
130		EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
131		return gost_id;
132	}
133
134	/* see if engine can be loaded already */
135	e = ENGINE_by_id("gost");
136	if(!e) {
137		/* load it ourself, in case statically linked */
138		ENGINE_load_builtin_engines();
139		ENGINE_load_dynamic();
140		e = ENGINE_by_id("gost");
141	}
142	if(!e) {
143		/* no gost engine in openssl */
144		return 0;
145	}
146	if(!ENGINE_set_default(e, ENGINE_METHOD_ALL)) {
147		ENGINE_finish(e);
148		ENGINE_free(e);
149		return 0;
150	}
151
152	meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1);
153	if(!meth) {
154		/* algo not found */
155		ENGINE_finish(e);
156		ENGINE_free(e);
157		return 0;
158	}
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;
162
163	EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
164	return gost_id;
165}
166
167void sldns_key_EVP_unload_gost(void)
168{
169        if(sldns_gost_engine) {
170                ENGINE_finish(sldns_gost_engine);
171                ENGINE_free(sldns_gost_engine);
172                sldns_gost_engine = NULL;
173        }
174}
175#endif /* USE_GOST */
176
177DSA *
178sldns_key_buf2dsa_raw(unsigned char* key, size_t len)
179{
180	uint8_t T;
181	uint16_t length;
182	uint16_t offset;
183	DSA *dsa;
184	BIGNUM *Q; BIGNUM *P;
185	BIGNUM *G; BIGNUM *Y;
186
187	if(len == 0)
188		return NULL;
189	T = (uint8_t)key[0];
190	length = (64 + T * 8);
191	offset = 1;
192
193	if (T > 8) {
194		return NULL;
195	}
196	if(len < (size_t)1 + SHA_DIGEST_LENGTH + 3*length)
197		return NULL;
198
199	Q = BN_bin2bn(key+offset, SHA_DIGEST_LENGTH, NULL);
200	offset += SHA_DIGEST_LENGTH;
201
202	P = BN_bin2bn(key+offset, (int)length, NULL);
203	offset += length;
204
205	G = BN_bin2bn(key+offset, (int)length, NULL);
206	offset += length;
207
208	Y = BN_bin2bn(key+offset, (int)length, NULL);
209	offset += length;
210
211	/* create the key and set its properties */
212	if(!Q || !P || !G || !Y || !(dsa = DSA_new())) {
213		BN_free(Q);
214		BN_free(P);
215		BN_free(G);
216		BN_free(Y);
217		return NULL;
218	}
219#ifndef S_SPLINT_S
220	dsa->p = P;
221	dsa->q = Q;
222	dsa->g = G;
223	dsa->pub_key = Y;
224#endif /* splint */
225
226	return dsa;
227}
228
229RSA *
230sldns_key_buf2rsa_raw(unsigned char* key, size_t len)
231{
232	uint16_t offset;
233	uint16_t exp;
234	uint16_t int16;
235	RSA *rsa;
236	BIGNUM *modulus;
237	BIGNUM *exponent;
238
239	if (len == 0)
240		return NULL;
241	if (key[0] == 0) {
242		if(len < 3)
243			return NULL;
244		memmove(&int16, key+1, 2);
245		exp = ntohs(int16);
246		offset = 3;
247	} else {
248		exp = key[0];
249		offset = 1;
250	}
251
252	/* key length at least one */
253	if(len < (size_t)offset + exp + 1)
254		return NULL;
255
256	/* Exponent */
257	exponent = BN_new();
258	if(!exponent) return NULL;
259	(void) BN_bin2bn(key+offset, (int)exp, exponent);
260	offset += exp;
261
262	/* Modulus */
263	modulus = BN_new();
264	if(!modulus) {
265		BN_free(exponent);
266		return NULL;
267	}
268	/* length of the buffer must match the key length! */
269	(void) BN_bin2bn(key+offset, (int)(len - offset), modulus);
270
271	rsa = RSA_new();
272	if(!rsa) {
273		BN_free(exponent);
274		BN_free(modulus);
275		return NULL;
276	}
277#ifndef S_SPLINT_S
278	rsa->n = modulus;
279	rsa->e = exponent;
280#endif /* splint */
281
282	return rsa;
283}
284
285#ifdef USE_GOST
286EVP_PKEY*
287sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
288{
289	/* prefix header for X509 encoding */
290	uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
291		0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85,
292		0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03,
293		0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40};
294	unsigned char encoded[37+64];
295	const unsigned char* pp;
296	if(keylen != 64) {
297		/* key wrong size */
298		return NULL;
299	}
300
301	/* create evp_key */
302	memmove(encoded, asn, 37);
303	memmove(encoded+37, key, 64);
304	pp = (unsigned char*)&encoded[0];
305
306	return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded));
307}
308#endif /* USE_GOST */
309
310#ifdef USE_ECDSA
311EVP_PKEY*
312sldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo)
313{
314	unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */
315        const unsigned char* pp = buf;
316        EVP_PKEY *evp_key;
317        EC_KEY *ec;
318	/* check length, which uncompressed must be 2 bignums */
319        if(algo == LDNS_ECDSAP256SHA256) {
320		if(keylen != 2*256/8) return NULL;
321                ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
322        } else if(algo == LDNS_ECDSAP384SHA384) {
323		if(keylen != 2*384/8) return NULL;
324                ec = EC_KEY_new_by_curve_name(NID_secp384r1);
325        } else    ec = NULL;
326        if(!ec) return NULL;
327	if(keylen+1 > sizeof(buf)) { /* sanity check */
328                EC_KEY_free(ec);
329		return NULL;
330	}
331	/* prepend the 0x02 (from docs) (or actually 0x04 from implementation
332	 * of openssl) for uncompressed data */
333	buf[0] = POINT_CONVERSION_UNCOMPRESSED;
334	memmove(buf+1, key, keylen);
335        if(!o2i_ECPublicKey(&ec, &pp, (int)keylen+1)) {
336                EC_KEY_free(ec);
337                return NULL;
338        }
339        evp_key = EVP_PKEY_new();
340        if(!evp_key) {
341                EC_KEY_free(ec);
342                return NULL;
343        }
344        if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
345		EVP_PKEY_free(evp_key);
346		EC_KEY_free(ec);
347		return NULL;
348	}
349        return evp_key;
350}
351#endif /* USE_ECDSA */
352
353int
354sldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest,
355	const EVP_MD* md)
356{
357	EVP_MD_CTX* ctx;
358	ctx = EVP_MD_CTX_create();
359	if(!ctx)
360		return 0;
361	if(!EVP_DigestInit_ex(ctx, md, NULL) ||
362		!EVP_DigestUpdate(ctx, data, len) ||
363		!EVP_DigestFinal_ex(ctx, dest, NULL)) {
364		EVP_MD_CTX_destroy(ctx);
365		return 0;
366	}
367	EVP_MD_CTX_destroy(ctx);
368	return 1;
369}
370#endif /* HAVE_SSL */
371