1 /*
2 * Portions Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 *
11 * Portions Copyright (C) Network Associates, Inc.
12 *
13 * Permission to use, copy, modify, and/or distribute this software for any
14 * purpose with or without fee is hereby granted, provided that the above
15 * copyright notice and this permission notice appear in all copies.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC AND NETWORK ASSOCIATES DISCLAIMS
18 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE
20 * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
21 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
22 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
23 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 */
25
26 #include <stdbool.h>
27 #ifndef WIN32
28 #include <arpa/inet.h>
29 #endif /* WIN32 */
30
31 #include <isc/buffer.h>
32 #include <isc/hmac.h>
33 #include <isc/md.h>
34 #include <isc/mem.h>
35 #include <isc/nonce.h>
36 #include <isc/random.h>
37 #include <isc/safe.h>
38 #include <isc/string.h>
39 #include <isc/util.h>
40
41 #include <pk11/site.h>
42
43 #include <dst/result.h>
44
45 #include "dst_internal.h"
46 #ifdef HAVE_FIPS_MODE
47 #include "dst_openssl.h" /* FIPS_mode() prototype */
48 #endif /* ifdef HAVE_FIPS_MODE */
49 #include "dst_parse.h"
50
51 #define ISC_MD_md5 ISC_MD_MD5
52 #define ISC_MD_sha1 ISC_MD_SHA1
53 #define ISC_MD_sha224 ISC_MD_SHA224
54 #define ISC_MD_sha256 ISC_MD_SHA256
55 #define ISC_MD_sha384 ISC_MD_SHA384
56 #define ISC_MD_sha512 ISC_MD_SHA512
57
58 #define hmac_register_algorithm(alg) \
59 static isc_result_t hmac##alg##_createctx(dst_key_t *key, \
60 dst_context_t *dctx) { \
61 return (hmac_createctx(ISC_MD_##alg, key, dctx)); \
62 } \
63 static void hmac##alg##_destroyctx(dst_context_t *dctx) { \
64 hmac_destroyctx(dctx); \
65 } \
66 static isc_result_t hmac##alg##_adddata(dst_context_t *dctx, \
67 const isc_region_t *data) { \
68 return (hmac_adddata(dctx, data)); \
69 } \
70 static isc_result_t hmac##alg##_sign(dst_context_t *dctx, \
71 isc_buffer_t *sig) { \
72 return (hmac_sign(dctx, sig)); \
73 } \
74 static isc_result_t hmac##alg##_verify(dst_context_t *dctx, \
75 const isc_region_t *sig) { \
76 return (hmac_verify(dctx, sig)); \
77 } \
78 static bool hmac##alg##_compare(const dst_key_t *key1, \
79 const dst_key_t *key2) { \
80 return (hmac_compare(ISC_MD_##alg, key1, key2)); \
81 } \
82 static isc_result_t hmac##alg##_generate( \
83 dst_key_t *key, int pseudorandom_ok, void (*callback)(int)) { \
84 UNUSED(pseudorandom_ok); \
85 UNUSED(callback); \
86 return (hmac_generate(ISC_MD_##alg, key)); \
87 } \
88 static bool hmac##alg##_isprivate(const dst_key_t *key) { \
89 return (hmac_isprivate(key)); \
90 } \
91 static void hmac##alg##_destroy(dst_key_t *key) { hmac_destroy(key); } \
92 static isc_result_t hmac##alg##_todns(const dst_key_t *key, \
93 isc_buffer_t *data) { \
94 return (hmac_todns(key, data)); \
95 } \
96 static isc_result_t hmac##alg##_fromdns(dst_key_t *key, \
97 isc_buffer_t *data) { \
98 return (hmac_fromdns(ISC_MD_##alg, key, data)); \
99 } \
100 static isc_result_t hmac##alg##_tofile(const dst_key_t *key, \
101 const char *directory) { \
102 return (hmac_tofile(ISC_MD_##alg, key, directory)); \
103 } \
104 static isc_result_t hmac##alg##_parse( \
105 dst_key_t *key, isc_lex_t *lexer, dst_key_t *pub) { \
106 return (hmac_parse(ISC_MD_##alg, key, lexer, pub)); \
107 } \
108 static dst_func_t hmac##alg##_functions = { \
109 hmac##alg##_createctx, \
110 NULL, /*%< createctx2 */ \
111 hmac##alg##_destroyctx, \
112 hmac##alg##_adddata, \
113 hmac##alg##_sign, \
114 hmac##alg##_verify, \
115 NULL, /*%< verify2 */ \
116 NULL, /*%< computesecret */ \
117 hmac##alg##_compare, \
118 NULL, /*%< paramcompare */ \
119 hmac##alg##_generate, \
120 hmac##alg##_isprivate, \
121 hmac##alg##_destroy, \
122 hmac##alg##_todns, \
123 hmac##alg##_fromdns, \
124 hmac##alg##_tofile, \
125 hmac##alg##_parse, \
126 NULL, /*%< cleanup */ \
127 NULL, /*%< fromlabel */ \
128 NULL, /*%< dump */ \
129 NULL, /*%< restore */ \
130 }; \
131 isc_result_t dst__hmac##alg##_init(dst_func_t **funcp) { \
132 REQUIRE(funcp != NULL); \
133 if (*funcp == NULL) { \
134 *funcp = &hmac##alg##_functions; \
135 } \
136 return (ISC_R_SUCCESS); \
137 }
138
139 static isc_result_t
140 hmac_fromdns(const isc_md_type_t *type, dst_key_t *key, isc_buffer_t *data);
141
142 struct dst_hmac_key {
143 uint8_t key[ISC_MAX_BLOCK_SIZE];
144 };
145
146 static inline isc_result_t
getkeybits(dst_key_t * key,struct dst_private_element * element)147 getkeybits(dst_key_t *key, struct dst_private_element *element) {
148 uint16_t *bits = (uint16_t *)element->data;
149
150 if (element->length != 2) {
151 return (DST_R_INVALIDPRIVATEKEY);
152 }
153
154 key->key_bits = ntohs(*bits);
155
156 return (ISC_R_SUCCESS);
157 }
158
159 static inline isc_result_t
hmac_createctx(const isc_md_type_t * type,const dst_key_t * key,dst_context_t * dctx)160 hmac_createctx(const isc_md_type_t *type, const dst_key_t *key,
161 dst_context_t *dctx) {
162 isc_result_t result;
163 const dst_hmac_key_t *hkey = key->keydata.hmac_key;
164 isc_hmac_t *ctx = isc_hmac_new(); /* Either returns or abort()s */
165
166 result = isc_hmac_init(ctx, hkey->key, isc_md_type_get_block_size(type),
167 type);
168 if (result != ISC_R_SUCCESS) {
169 return (DST_R_UNSUPPORTEDALG);
170 }
171
172 dctx->ctxdata.hmac_ctx = ctx;
173 return (ISC_R_SUCCESS);
174 }
175
176 static inline void
hmac_destroyctx(dst_context_t * dctx)177 hmac_destroyctx(dst_context_t *dctx) {
178 isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx;
179 REQUIRE(ctx != NULL);
180
181 isc_hmac_free(ctx);
182 dctx->ctxdata.hmac_ctx = NULL;
183 }
184
185 static inline isc_result_t
hmac_adddata(const dst_context_t * dctx,const isc_region_t * data)186 hmac_adddata(const dst_context_t *dctx, const isc_region_t *data) {
187 isc_result_t result;
188 isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx;
189
190 REQUIRE(ctx != NULL);
191
192 result = isc_hmac_update(ctx, data->base, data->length);
193 if (result != ISC_R_SUCCESS) {
194 return (DST_R_OPENSSLFAILURE);
195 }
196
197 return (ISC_R_SUCCESS);
198 }
199
200 static inline isc_result_t
hmac_sign(const dst_context_t * dctx,isc_buffer_t * sig)201 hmac_sign(const dst_context_t *dctx, isc_buffer_t *sig) {
202 isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx;
203 REQUIRE(ctx != NULL);
204 unsigned int digestlen;
205 unsigned char digest[ISC_MAX_MD_SIZE];
206
207 if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) {
208 return (DST_R_OPENSSLFAILURE);
209 }
210
211 if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) {
212 return (DST_R_OPENSSLFAILURE);
213 }
214
215 if (isc_buffer_availablelength(sig) < digestlen) {
216 return (ISC_R_NOSPACE);
217 }
218
219 isc_buffer_putmem(sig, digest, digestlen);
220
221 return (ISC_R_SUCCESS);
222 }
223
224 static inline isc_result_t
hmac_verify(const dst_context_t * dctx,const isc_region_t * sig)225 hmac_verify(const dst_context_t *dctx, const isc_region_t *sig) {
226 isc_hmac_t *ctx = dctx->ctxdata.hmac_ctx;
227 unsigned int digestlen;
228 unsigned char digest[ISC_MAX_MD_SIZE];
229
230 REQUIRE(ctx != NULL);
231
232 if (isc_hmac_final(ctx, digest, &digestlen) != ISC_R_SUCCESS) {
233 return (DST_R_OPENSSLFAILURE);
234 }
235
236 if (isc_hmac_reset(ctx) != ISC_R_SUCCESS) {
237 return (DST_R_OPENSSLFAILURE);
238 }
239
240 if (sig->length > digestlen) {
241 return (DST_R_VERIFYFAILURE);
242 }
243
244 return (isc_safe_memequal(digest, sig->base, sig->length)
245 ? ISC_R_SUCCESS
246 : DST_R_VERIFYFAILURE);
247 }
248
249 static inline bool
hmac_compare(const isc_md_type_t * type,const dst_key_t * key1,const dst_key_t * key2)250 hmac_compare(const isc_md_type_t *type, const dst_key_t *key1,
251 const dst_key_t *key2) {
252 dst_hmac_key_t *hkey1, *hkey2;
253
254 hkey1 = key1->keydata.hmac_key;
255 hkey2 = key2->keydata.hmac_key;
256
257 if (hkey1 == NULL && hkey2 == NULL) {
258 return (true);
259 } else if (hkey1 == NULL || hkey2 == NULL) {
260 return (false);
261 }
262
263 return (isc_safe_memequal(hkey1->key, hkey2->key,
264 isc_md_type_get_block_size(type)));
265 }
266
267 static inline isc_result_t
hmac_generate(const isc_md_type_t * type,dst_key_t * key)268 hmac_generate(const isc_md_type_t *type, dst_key_t *key) {
269 isc_buffer_t b;
270 isc_result_t ret;
271 unsigned int bytes, len;
272 unsigned char data[ISC_MAX_MD_SIZE] = { 0 };
273
274 len = isc_md_type_get_block_size(type);
275
276 bytes = (key->key_size + 7) / 8;
277
278 if (bytes > len) {
279 bytes = len;
280 key->key_size = len * 8;
281 }
282
283 isc_nonce_buf(data, bytes);
284
285 isc_buffer_init(&b, data, bytes);
286 isc_buffer_add(&b, bytes);
287
288 ret = hmac_fromdns(type, key, &b);
289
290 isc_safe_memwipe(data, sizeof(data));
291
292 return (ret);
293 }
294
295 static inline bool
hmac_isprivate(const dst_key_t * key)296 hmac_isprivate(const dst_key_t *key) {
297 UNUSED(key);
298 return (true);
299 }
300
301 static inline void
hmac_destroy(dst_key_t * key)302 hmac_destroy(dst_key_t *key) {
303 dst_hmac_key_t *hkey = key->keydata.hmac_key;
304 isc_safe_memwipe(hkey, sizeof(*hkey));
305 isc_mem_put(key->mctx, hkey, sizeof(*hkey));
306 key->keydata.hmac_key = NULL;
307 }
308
309 static inline isc_result_t
hmac_todns(const dst_key_t * key,isc_buffer_t * data)310 hmac_todns(const dst_key_t *key, isc_buffer_t *data) {
311 REQUIRE(key != NULL && key->keydata.hmac_key != NULL);
312 dst_hmac_key_t *hkey = key->keydata.hmac_key;
313 unsigned int bytes;
314
315 bytes = (key->key_size + 7) / 8;
316 if (isc_buffer_availablelength(data) < bytes) {
317 return (ISC_R_NOSPACE);
318 }
319 isc_buffer_putmem(data, hkey->key, bytes);
320
321 return (ISC_R_SUCCESS);
322 }
323
324 static inline isc_result_t
hmac_fromdns(const isc_md_type_t * type,dst_key_t * key,isc_buffer_t * data)325 hmac_fromdns(const isc_md_type_t *type, dst_key_t *key, isc_buffer_t *data) {
326 dst_hmac_key_t *hkey;
327 unsigned int keylen;
328 isc_region_t r;
329
330 isc_buffer_remainingregion(data, &r);
331 if (r.length == 0) {
332 return (ISC_R_SUCCESS);
333 }
334
335 hkey = isc_mem_get(key->mctx, sizeof(dst_hmac_key_t));
336
337 memset(hkey->key, 0, sizeof(hkey->key));
338
339 /* Hash the key if the key is longer then chosen MD block size */
340 if (r.length > (unsigned int)isc_md_type_get_block_size(type)) {
341 if (isc_md(type, r.base, r.length, hkey->key, &keylen) !=
342 ISC_R_SUCCESS) {
343 isc_mem_put(key->mctx, hkey, sizeof(dst_hmac_key_t));
344 return (DST_R_OPENSSLFAILURE);
345 }
346 } else {
347 memmove(hkey->key, r.base, r.length);
348 keylen = r.length;
349 }
350
351 key->key_size = keylen * 8;
352 key->keydata.hmac_key = hkey;
353
354 isc_buffer_forward(data, r.length);
355
356 return (ISC_R_SUCCESS);
357 }
358
359 static inline int
hmac__get_tag_key(const isc_md_type_t * type)360 hmac__get_tag_key(const isc_md_type_t *type) {
361 if (type == ISC_MD_MD5) {
362 return (TAG_HMACMD5_KEY);
363 } else if (type == ISC_MD_SHA1) {
364 return (TAG_HMACSHA1_KEY);
365 } else if (type == ISC_MD_SHA224) {
366 return (TAG_HMACSHA224_KEY);
367 } else if (type == ISC_MD_SHA256) {
368 return (TAG_HMACSHA256_KEY);
369 } else if (type == ISC_MD_SHA384) {
370 return (TAG_HMACSHA384_KEY);
371 } else if (type == ISC_MD_SHA512) {
372 return (TAG_HMACSHA512_KEY);
373 } else {
374 INSIST(0);
375 ISC_UNREACHABLE();
376 }
377 }
378
379 static inline int
hmac__get_tag_bits(const isc_md_type_t * type)380 hmac__get_tag_bits(const isc_md_type_t *type) {
381 if (type == ISC_MD_MD5) {
382 return (TAG_HMACMD5_BITS);
383 } else if (type == ISC_MD_SHA1) {
384 return (TAG_HMACSHA1_BITS);
385 } else if (type == ISC_MD_SHA224) {
386 return (TAG_HMACSHA224_BITS);
387 } else if (type == ISC_MD_SHA256) {
388 return (TAG_HMACSHA256_BITS);
389 } else if (type == ISC_MD_SHA384) {
390 return (TAG_HMACSHA384_BITS);
391 } else if (type == ISC_MD_SHA512) {
392 return (TAG_HMACSHA512_BITS);
393 } else {
394 INSIST(0);
395 ISC_UNREACHABLE();
396 }
397 }
398
399 static inline isc_result_t
hmac_tofile(const isc_md_type_t * type,const dst_key_t * key,const char * directory)400 hmac_tofile(const isc_md_type_t *type, const dst_key_t *key,
401 const char *directory) {
402 dst_hmac_key_t *hkey;
403 dst_private_t priv;
404 int bytes = (key->key_size + 7) / 8;
405 uint16_t bits;
406
407 if (key->keydata.hmac_key == NULL) {
408 return (DST_R_NULLKEY);
409 }
410
411 if (key->external) {
412 return (DST_R_EXTERNALKEY);
413 }
414
415 hkey = key->keydata.hmac_key;
416
417 priv.elements[0].tag = hmac__get_tag_key(type);
418 priv.elements[0].length = bytes;
419 priv.elements[0].data = hkey->key;
420
421 bits = htons(key->key_bits);
422
423 priv.elements[1].tag = hmac__get_tag_bits(type);
424 priv.elements[1].length = sizeof(bits);
425 priv.elements[1].data = (uint8_t *)&bits;
426
427 priv.nelements = 2;
428
429 return (dst__privstruct_writefile(key, &priv, directory));
430 }
431
432 static inline int
hmac__to_dst_alg(const isc_md_type_t * type)433 hmac__to_dst_alg(const isc_md_type_t *type) {
434 if (type == ISC_MD_MD5) {
435 return (DST_ALG_HMACMD5);
436 } else if (type == ISC_MD_SHA1) {
437 return (DST_ALG_HMACSHA1);
438 } else if (type == ISC_MD_SHA224) {
439 return (DST_ALG_HMACSHA224);
440 } else if (type == ISC_MD_SHA256) {
441 return (DST_ALG_HMACSHA256);
442 } else if (type == ISC_MD_SHA384) {
443 return (DST_ALG_HMACSHA384);
444 } else if (type == ISC_MD_SHA512) {
445 return (DST_ALG_HMACSHA512);
446 } else {
447 INSIST(0);
448 ISC_UNREACHABLE();
449 }
450 }
451
452 static inline isc_result_t
hmac_parse(const isc_md_type_t * type,dst_key_t * key,isc_lex_t * lexer,dst_key_t * pub)453 hmac_parse(const isc_md_type_t *type, dst_key_t *key, isc_lex_t *lexer,
454 dst_key_t *pub) {
455 dst_private_t priv;
456 isc_result_t result, tresult;
457 isc_buffer_t b;
458 isc_mem_t *mctx = key->mctx;
459 unsigned int i;
460
461 UNUSED(pub);
462 /* read private key file */
463 result = dst__privstruct_parse(key, hmac__to_dst_alg(type), lexer, mctx,
464 &priv);
465 if (result != ISC_R_SUCCESS) {
466 return (result);
467 }
468
469 if (key->external) {
470 result = DST_R_EXTERNALKEY;
471 }
472
473 key->key_bits = 0;
474 for (i = 0; i < priv.nelements && result == ISC_R_SUCCESS; i++) {
475 switch (priv.elements[i].tag) {
476 case TAG_HMACMD5_KEY:
477 case TAG_HMACSHA1_KEY:
478 case TAG_HMACSHA224_KEY:
479 case TAG_HMACSHA256_KEY:
480 case TAG_HMACSHA384_KEY:
481 case TAG_HMACSHA512_KEY:
482 isc_buffer_init(&b, priv.elements[i].data,
483 priv.elements[i].length);
484 isc_buffer_add(&b, priv.elements[i].length);
485 tresult = hmac_fromdns(type, key, &b);
486 if (tresult != ISC_R_SUCCESS) {
487 result = tresult;
488 }
489 break;
490 case TAG_HMACMD5_BITS:
491 case TAG_HMACSHA1_BITS:
492 case TAG_HMACSHA224_BITS:
493 case TAG_HMACSHA256_BITS:
494 case TAG_HMACSHA384_BITS:
495 case TAG_HMACSHA512_BITS:
496 tresult = getkeybits(key, &priv.elements[i]);
497 if (tresult != ISC_R_SUCCESS) {
498 result = tresult;
499 }
500 break;
501 default:
502 result = DST_R_INVALIDPRIVATEKEY;
503 break;
504 }
505 }
506 dst__privstruct_free(&priv, mctx);
507 isc_safe_memwipe(&priv, sizeof(priv));
508 return (result);
509 }
510
511 hmac_register_algorithm(md5);
512 hmac_register_algorithm(sha1);
513 hmac_register_algorithm(sha224);
514 hmac_register_algorithm(sha256);
515 hmac_register_algorithm(sha384);
516 hmac_register_algorithm(sha512);
517
518 /*! \file */
519