Merge from vendor branch LESS:
[dragonfly.git] / contrib / bind-9.3 / lib / dns / hmac_link.c
1 /*
2  * Portions Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 1999-2002  Internet Software Consortium.
4  * Portions Copyright (C) 1995-2000 by Network Associates, Inc.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
11  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12  * WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE
13  * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
16  * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 /*
20  * Principal Author: Brian Wellington
21  * $Id: hmac_link.c,v 1.1.4.1 2004/12/09 04:07:17 marka Exp $
22  */
23
24 #include <config.h>
25
26 #include <isc/buffer.h>
27 #include <isc/hmacmd5.h>
28 #include <isc/md5.h>
29 #include <isc/mem.h>
30 #include <isc/string.h>
31 #include <isc/util.h>
32
33 #include <dst/result.h>
34
35 #include "dst_internal.h"
36 #include "dst_parse.h"
37
38 #define HMAC_LEN        64
39 #define HMAC_IPAD       0x36
40 #define HMAC_OPAD       0x5c
41
42 static isc_result_t hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data);
43
44 typedef struct hmackey {
45         unsigned char key[HMAC_LEN];
46 } HMAC_Key;
47
48 static isc_result_t
49 hmacmd5_createctx(dst_key_t *key, dst_context_t *dctx) {
50         isc_hmacmd5_t *hmacmd5ctx;
51         HMAC_Key *hkey = key->opaque;
52
53         hmacmd5ctx = isc_mem_get(dctx->mctx, sizeof(isc_hmacmd5_t));
54         if (hmacmd5ctx == NULL)
55                 return (ISC_R_NOMEMORY);
56         isc_hmacmd5_init(hmacmd5ctx, hkey->key, HMAC_LEN);
57         dctx->opaque = hmacmd5ctx;
58         return (ISC_R_SUCCESS);
59 }
60
61 static void
62 hmacmd5_destroyctx(dst_context_t *dctx) {
63         isc_hmacmd5_t *hmacmd5ctx = dctx->opaque;
64
65         if (hmacmd5ctx != NULL) {
66                 isc_hmacmd5_invalidate(hmacmd5ctx);
67                 isc_mem_put(dctx->mctx, hmacmd5ctx, sizeof(isc_hmacmd5_t));
68                 dctx->opaque = NULL;
69         }
70 }
71
72 static isc_result_t
73 hmacmd5_adddata(dst_context_t *dctx, const isc_region_t *data) {
74         isc_hmacmd5_t *hmacmd5ctx = dctx->opaque;
75
76         isc_hmacmd5_update(hmacmd5ctx, data->base, data->length);
77         return (ISC_R_SUCCESS);
78 }
79
80 static isc_result_t
81 hmacmd5_sign(dst_context_t *dctx, isc_buffer_t *sig) {
82         isc_hmacmd5_t *hmacmd5ctx = dctx->opaque;
83         unsigned char *digest;
84
85         if (isc_buffer_availablelength(sig) < ISC_MD5_DIGESTLENGTH)
86                 return (ISC_R_NOSPACE);
87         digest = isc_buffer_used(sig);
88         isc_hmacmd5_sign(hmacmd5ctx, digest);
89         isc_buffer_add(sig, ISC_MD5_DIGESTLENGTH);
90
91         return (ISC_R_SUCCESS);
92 }
93
94 static isc_result_t
95 hmacmd5_verify(dst_context_t *dctx, const isc_region_t *sig) {
96         isc_hmacmd5_t *hmacmd5ctx = dctx->opaque;
97
98         if (sig->length < ISC_MD5_DIGESTLENGTH)
99                 return (DST_R_VERIFYFAILURE);
100
101         if (isc_hmacmd5_verify(hmacmd5ctx, sig->base))
102                 return (ISC_R_SUCCESS);
103         else
104                 return (DST_R_VERIFYFAILURE);
105 }
106
107 static isc_boolean_t
108 hmacmd5_compare(const dst_key_t *key1, const dst_key_t *key2) {
109         HMAC_Key *hkey1, *hkey2;
110
111         hkey1 = (HMAC_Key *)key1->opaque;
112         hkey2 = (HMAC_Key *)key2->opaque;
113
114         if (hkey1 == NULL && hkey2 == NULL)
115                 return (ISC_TRUE);
116         else if (hkey1 == NULL || hkey2 == NULL)
117                 return (ISC_FALSE);
118
119         if (memcmp(hkey1->key, hkey2->key, HMAC_LEN) == 0)
120                 return (ISC_TRUE);
121         else
122                 return (ISC_FALSE);
123 }
124
125 static isc_result_t
126 hmacmd5_generate(dst_key_t *key, int pseudorandom_ok) {
127         isc_buffer_t b;
128         isc_result_t ret;
129         int bytes;
130         unsigned char data[HMAC_LEN];
131
132         bytes = (key->key_size + 7) / 8;
133         if (bytes > 64) {
134                 bytes = 64;
135                 key->key_size = 512;
136         }
137
138         memset(data, 0, HMAC_LEN);
139         ret = dst__entropy_getdata(data, bytes, ISC_TF(pseudorandom_ok != 0));
140
141         if (ret != ISC_R_SUCCESS)
142                 return (ret);
143
144         isc_buffer_init(&b, data, bytes);
145         isc_buffer_add(&b, bytes);
146         ret = hmacmd5_fromdns(key, &b);
147         memset(data, 0, HMAC_LEN);
148
149         return (ret);
150 }
151
152 static isc_boolean_t
153 hmacmd5_isprivate(const dst_key_t *key) {
154         UNUSED(key);
155         return (ISC_TRUE);
156 }
157
158 static void
159 hmacmd5_destroy(dst_key_t *key) {
160         HMAC_Key *hkey = key->opaque;
161         memset(hkey, 0, sizeof(HMAC_Key));
162         isc_mem_put(key->mctx, hkey, sizeof(HMAC_Key));
163         key->opaque = NULL;
164 }
165
166 static isc_result_t
167 hmacmd5_todns(const dst_key_t *key, isc_buffer_t *data) {
168         HMAC_Key *hkey;
169         unsigned int bytes;
170
171         REQUIRE(key->opaque != NULL);
172
173         hkey = (HMAC_Key *) key->opaque;
174
175         bytes = (key->key_size + 7) / 8;
176         if (isc_buffer_availablelength(data) < bytes)
177                 return (ISC_R_NOSPACE);
178         isc_buffer_putmem(data, hkey->key, bytes);
179
180         return (ISC_R_SUCCESS);
181 }
182
183 static isc_result_t
184 hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) {
185         HMAC_Key *hkey;
186         int keylen;
187         isc_region_t r;
188         isc_md5_t md5ctx;
189
190         isc_buffer_remainingregion(data, &r);
191         if (r.length == 0)
192                 return (ISC_R_SUCCESS);
193
194         hkey = (HMAC_Key *) isc_mem_get(key->mctx, sizeof(HMAC_Key));
195         if (hkey == NULL)
196                 return (ISC_R_NOMEMORY);
197
198         memset(hkey->key, 0, sizeof(hkey->key));
199
200         if (r.length > HMAC_LEN) {
201                 isc_md5_init(&md5ctx);
202                 isc_md5_update(&md5ctx, r.base, r.length);
203                 isc_md5_final(&md5ctx, hkey->key);
204                 keylen = ISC_MD5_DIGESTLENGTH;
205         }
206         else {
207                 memcpy(hkey->key, r.base, r.length);
208                 keylen = r.length;
209         }
210
211         key->key_size = keylen * 8;
212         key->opaque = hkey;
213
214         return (ISC_R_SUCCESS);
215 }
216
217 static isc_result_t
218 hmacmd5_tofile(const dst_key_t *key, const char *directory) {
219         int cnt = 0;
220         HMAC_Key *hkey;
221         dst_private_t priv;
222         int bytes = (key->key_size + 7) / 8;
223
224         if (key->opaque == NULL)
225                 return (DST_R_NULLKEY);
226
227         hkey = (HMAC_Key *) key->opaque;
228
229         priv.elements[cnt].tag = TAG_HMACMD5_KEY;
230         priv.elements[cnt].length = bytes;
231         priv.elements[cnt++].data = hkey->key;
232
233         priv.nelements = cnt;
234         return (dst__privstruct_writefile(key, &priv, directory));
235 }
236
237 static isc_result_t
238 hmacmd5_parse(dst_key_t *key, isc_lex_t *lexer) {
239         dst_private_t priv;
240         isc_result_t ret;
241         isc_buffer_t b;
242         isc_mem_t *mctx = key->mctx;
243
244         /* read private key file */
245         ret = dst__privstruct_parse(key, DST_ALG_HMACMD5, lexer, mctx, &priv);
246         if (ret != ISC_R_SUCCESS)
247                 return (ret);
248
249         isc_buffer_init(&b, priv.elements[0].data, priv.elements[0].length);
250         isc_buffer_add(&b, priv.elements[0].length);
251         ret = hmacmd5_fromdns(key, &b);
252         dst__privstruct_free(&priv, mctx);
253         memset(&priv, 0, sizeof(priv));
254         return (ret);
255 }
256
257 static dst_func_t hmacmd5_functions = {
258         hmacmd5_createctx,
259         hmacmd5_destroyctx,
260         hmacmd5_adddata,
261         hmacmd5_sign,
262         hmacmd5_verify,
263         NULL, /* computesecret */
264         hmacmd5_compare,
265         NULL, /* paramcompare */
266         hmacmd5_generate,
267         hmacmd5_isprivate,
268         hmacmd5_destroy,
269         hmacmd5_todns,
270         hmacmd5_fromdns,
271         hmacmd5_tofile,
272         hmacmd5_parse,
273         NULL, /* cleanup */
274 };
275
276 isc_result_t
277 dst__hmacmd5_init(dst_func_t **funcp) {
278         REQUIRE(funcp != NULL);
279         if (*funcp == NULL)
280                 *funcp = &hmacmd5_functions;
281         return (ISC_R_SUCCESS);
282 }