Merge from vendor branch NTPD:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / dns / sec / dst / hmac_link.c
1 /*
2  * Portions Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 1999-2001  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.53.2.2 2004/03/09 06:11:41 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 isc_boolean_t
159 hmacmd5_issymmetric(void) {
160         return (ISC_TRUE);
161 }
162
163 static void
164 hmacmd5_destroy(dst_key_t *key) {
165         HMAC_Key *hkey = key->opaque;
166         memset(hkey, 0, sizeof(HMAC_Key));
167         isc_mem_put(key->mctx, hkey, sizeof(HMAC_Key));
168         key->opaque = NULL;
169 }
170
171 static isc_result_t
172 hmacmd5_todns(const dst_key_t *key, isc_buffer_t *data) {
173         HMAC_Key *hkey;
174         unsigned int bytes;
175
176         REQUIRE(key->opaque != NULL);
177
178         hkey = (HMAC_Key *) key->opaque;
179
180         bytes = (key->key_size + 7) / 8;
181         if (isc_buffer_availablelength(data) < bytes)
182                 return (ISC_R_NOSPACE);
183         isc_buffer_putmem(data, hkey->key, bytes);
184
185         return (ISC_R_SUCCESS);
186 }
187
188 static isc_result_t
189 hmacmd5_fromdns(dst_key_t *key, isc_buffer_t *data) {
190         HMAC_Key *hkey;
191         int keylen;
192         isc_region_t r;
193         isc_md5_t md5ctx;
194
195         isc_buffer_remainingregion(data, &r);
196         if (r.length == 0)
197                 return (ISC_R_SUCCESS);
198
199         hkey = (HMAC_Key *) isc_mem_get(key->mctx, sizeof(HMAC_Key));
200         if (hkey == NULL)
201                 return (ISC_R_NOMEMORY);
202
203         memset(hkey->key, 0, sizeof(hkey->key));
204
205         if (r.length > HMAC_LEN) {
206                 isc_md5_init(&md5ctx);
207                 isc_md5_update(&md5ctx, r.base, r.length);
208                 isc_md5_final(&md5ctx, hkey->key);
209                 keylen = ISC_MD5_DIGESTLENGTH;
210         }
211         else {
212                 memcpy(hkey->key, r.base, r.length);
213                 keylen = r.length;
214         }
215
216         key->key_size = keylen * 8;
217         key->opaque = hkey;
218
219         return (ISC_R_SUCCESS);
220 }
221
222 static isc_result_t
223 hmacmd5_tofile(const dst_key_t *key, const char *directory) {
224         int cnt = 0;
225         HMAC_Key *hkey;
226         dst_private_t priv;
227         int bytes = (key->key_size + 7) / 8;
228
229         if (key->opaque == NULL)
230                 return (DST_R_NULLKEY);
231
232         hkey = (HMAC_Key *) key->opaque;
233
234         priv.elements[cnt].tag = TAG_HMACMD5_KEY;
235         priv.elements[cnt].length = bytes;
236         priv.elements[cnt++].data = hkey->key;
237
238         priv.nelements = cnt;
239         return (dst__privstruct_writefile(key, &priv, directory));
240 }
241
242 static isc_result_t
243 hmacmd5_fromfile(dst_key_t *key, const char *filename) {
244         dst_private_t priv;
245         isc_result_t ret;
246         isc_buffer_t b;
247         isc_mem_t *mctx = key->mctx;
248
249         /* read private key file */
250         ret = dst__privstruct_parsefile(key, filename, mctx, &priv);
251         if (ret != ISC_R_SUCCESS)
252                 return (ret);
253
254         isc_buffer_init(&b, priv.elements[0].data, priv.elements[0].length);
255         isc_buffer_add(&b, priv.elements[0].length);
256         ret = hmacmd5_fromdns(key, &b);
257         dst__privstruct_free(&priv, mctx);
258         memset(&priv, 0, sizeof(priv));
259         return (ret);
260 }
261
262 static dst_func_t hmacmd5_functions = {
263         hmacmd5_createctx,
264         hmacmd5_destroyctx,
265         hmacmd5_adddata,
266         hmacmd5_sign,
267         hmacmd5_verify,
268         NULL, /* computesecret */
269         hmacmd5_compare,
270         NULL, /* paramcompare */
271         hmacmd5_generate,
272         hmacmd5_isprivate,
273         hmacmd5_issymmetric,
274         hmacmd5_destroy,
275         hmacmd5_todns,
276         hmacmd5_fromdns,
277         hmacmd5_tofile,
278         hmacmd5_fromfile,
279 };
280
281 isc_result_t
282 dst__hmacmd5_init(dst_func_t **funcp) {
283         REQUIRE(funcp != NULL && *funcp == NULL);
284         *funcp = &hmacmd5_functions;
285         return (ISC_R_SUCCESS);
286 }
287
288 void
289 dst__hmacmd5_destroy(void) {
290 }