]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sldns/keyraw.c
import unbound 1.5.9
[FreeBSD/FreeBSD.git] / sldns / keyraw.c
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
28 size_t
29 sldns_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
89 uint16_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 */
116 ENGINE* sldns_gost_engine = NULL;
117
118 int
119 sldns_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
167 void 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
177 DSA *
178 sldns_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
210         /* create the key and set its properties */
211         if(!Q || !P || !G || !Y || !(dsa = DSA_new())) {
212                 BN_free(Q);
213                 BN_free(P);
214                 BN_free(G);
215                 BN_free(Y);
216                 return NULL;
217         }
218 #ifndef S_SPLINT_S
219         dsa->p = P;
220         dsa->q = Q;
221         dsa->g = G;
222         dsa->pub_key = Y;
223 #endif /* splint */
224
225         return dsa;
226 }
227
228 RSA *
229 sldns_key_buf2rsa_raw(unsigned char* key, size_t len)
230 {
231         uint16_t offset;
232         uint16_t exp;
233         uint16_t int16;
234         RSA *rsa;
235         BIGNUM *modulus;
236         BIGNUM *exponent;
237
238         if (len == 0)
239                 return NULL;
240         if (key[0] == 0) {
241                 if(len < 3)
242                         return NULL;
243                 memmove(&int16, key+1, 2);
244                 exp = ntohs(int16);
245                 offset = 3;
246         } else {
247                 exp = key[0];
248                 offset = 1;
249         }
250
251         /* key length at least one */
252         if(len < (size_t)offset + exp + 1)
253                 return NULL;
254
255         /* Exponent */
256         exponent = BN_new();
257         if(!exponent) return NULL;
258         (void) BN_bin2bn(key+offset, (int)exp, exponent);
259         offset += exp;
260
261         /* Modulus */
262         modulus = BN_new();
263         if(!modulus) {
264                 BN_free(exponent);
265                 return NULL;
266         }
267         /* length of the buffer must match the key length! */
268         (void) BN_bin2bn(key+offset, (int)(len - offset), modulus);
269
270         rsa = RSA_new();
271         if(!rsa) {
272                 BN_free(exponent);
273                 BN_free(modulus);
274                 return NULL;
275         }
276 #ifndef S_SPLINT_S
277         rsa->n = modulus;
278         rsa->e = exponent;
279 #endif /* splint */
280
281         return rsa;
282 }
283
284 #ifdef USE_GOST
285 EVP_PKEY*
286 sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
287 {
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;
295         if(keylen != 64) {
296                 /* key wrong size */
297                 return NULL;
298         }
299
300         /* create evp_key */
301         memmove(encoded, asn, 37);
302         memmove(encoded+37, key, 64);
303         pp = (unsigned char*)&encoded[0];
304
305         return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded));
306 }
307 #endif /* USE_GOST */
308
309 #ifdef USE_ECDSA
310 EVP_PKEY*
311 sldns_ecdsa2pkey_raw(unsigned char* key, size_t keylen, uint8_t algo)
312 {
313         unsigned char buf[256+2]; /* sufficient for 2*384/8+1 */
314         const unsigned char* pp = buf;
315         EVP_PKEY *evp_key;
316         EC_KEY *ec;
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);
324         } else    ec = NULL;
325         if(!ec) return NULL;
326         if(keylen+1 > sizeof(buf)) { /* sanity check */
327                 EC_KEY_free(ec);
328                 return NULL;
329         }
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)) {
335                 EC_KEY_free(ec);
336                 return NULL;
337         }
338         evp_key = EVP_PKEY_new();
339         if(!evp_key) {
340                 EC_KEY_free(ec);
341                 return NULL;
342         }
343         if (!EVP_PKEY_assign_EC_KEY(evp_key, ec)) {
344                 EVP_PKEY_free(evp_key);
345                 EC_KEY_free(ec);
346                 return NULL;
347         }
348         return evp_key;
349 }
350 #endif /* USE_ECDSA */
351
352 int
353 sldns_digest_evp(unsigned char* data, unsigned int len, unsigned char* dest,
354         const EVP_MD* md)
355 {
356         EVP_MD_CTX* ctx;
357         ctx = EVP_MD_CTX_create();
358         if(!ctx)
359                 return 0;
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);
364                 return 0;
365         }
366         EVP_MD_CTX_destroy(ctx);
367         return 1;
368 }
369 #endif /* HAVE_SSL */