/src/gnutls/lib/hash_int.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (C) 2000-2012 Free Software Foundation, Inc. |
3 | | * |
4 | | * Author: Nikos Mavrogiannopoulos |
5 | | * |
6 | | * This file is part of GnuTLS. |
7 | | * |
8 | | * The GnuTLS is free software; you can redistribute it and/or |
9 | | * modify it under the terms of the GNU Lesser General Public License |
10 | | * as published by the Free Software Foundation; either version 2.1 of |
11 | | * the License, or (at your option) any later version. |
12 | | * |
13 | | * This library is distributed in the hope that it will be useful, but |
14 | | * WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | | * Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public License |
19 | | * along with this program. If not, see <https://www.gnu.org/licenses/> |
20 | | * |
21 | | */ |
22 | | |
23 | | /* This file handles all the internal functions that cope with hashes |
24 | | * and HMACs. |
25 | | */ |
26 | | |
27 | | #include "gnutls_int.h" |
28 | | #include "hash_int.h" |
29 | | #include "errors.h" |
30 | | #include "algorithms.h" |
31 | | #include "fips.h" |
32 | | |
33 | | int _gnutls_hash_init(digest_hd_st *dig, const mac_entry_st *e) |
34 | 0 | { |
35 | 0 | int result; |
36 | 0 | const gnutls_crypto_digest_st *cc = NULL; |
37 | |
|
38 | 0 | FAIL_IF_LIB_ERROR; |
39 | | |
40 | 0 | if (unlikely(e == NULL || e->id == GNUTLS_MAC_NULL)) |
41 | 0 | return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
42 | | |
43 | 0 | dig->e = e; |
44 | | |
45 | | /* check if a digest has been registered |
46 | | */ |
47 | 0 | cc = _gnutls_get_crypto_digest((gnutls_digest_algorithm_t)e->id); |
48 | 0 | if (cc != NULL && cc->init) { |
49 | 0 | if (cc->init((gnutls_digest_algorithm_t)e->id, &dig->handle) < |
50 | 0 | 0) { |
51 | 0 | gnutls_assert(); |
52 | 0 | return GNUTLS_E_HASH_FAILED; |
53 | 0 | } |
54 | | |
55 | 0 | dig->hash = cc->hash; |
56 | 0 | dig->output = cc->output; |
57 | 0 | dig->deinit = cc->deinit; |
58 | 0 | dig->copy = cc->copy; |
59 | |
|
60 | 0 | return 0; |
61 | 0 | } |
62 | | |
63 | 0 | result = _gnutls_digest_ops.init((gnutls_digest_algorithm_t)e->id, |
64 | 0 | &dig->handle); |
65 | 0 | if (result < 0) { |
66 | 0 | gnutls_assert(); |
67 | 0 | return result; |
68 | 0 | } |
69 | | |
70 | 0 | dig->hash = _gnutls_digest_ops.hash; |
71 | 0 | dig->output = _gnutls_digest_ops.output; |
72 | 0 | dig->deinit = _gnutls_digest_ops.deinit; |
73 | 0 | dig->copy = _gnutls_digest_ops.copy; |
74 | |
|
75 | 0 | return 0; |
76 | 0 | } |
77 | | |
78 | | /* Returns true(non-zero) or false(0) if the |
79 | | * provided hash exists |
80 | | */ |
81 | | int _gnutls_digest_exists(gnutls_digest_algorithm_t algo) |
82 | 0 | { |
83 | 0 | const gnutls_crypto_digest_st *cc = NULL; |
84 | |
|
85 | 0 | if (!is_mac_algo_allowed(DIG_TO_MAC(algo))) |
86 | 0 | return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); |
87 | | |
88 | 0 | cc = _gnutls_get_crypto_digest(algo); |
89 | 0 | if (cc != NULL) |
90 | 0 | return 1; |
91 | | |
92 | 0 | return _gnutls_digest_ops.exists(algo); |
93 | 0 | } |
94 | | |
95 | | int _gnutls_hash_copy(const digest_hd_st *handle, digest_hd_st *dst) |
96 | 0 | { |
97 | 0 | if (handle->copy == NULL) |
98 | 0 | return gnutls_assert_val(GNUTLS_E_HASH_FAILED); |
99 | | |
100 | 0 | *dst = *handle; /* copy data */ |
101 | 0 | dst->handle = handle->copy(handle->handle); |
102 | |
|
103 | 0 | if (dst->handle == NULL) |
104 | 0 | return GNUTLS_E_HASH_FAILED; |
105 | | |
106 | 0 | return 0; |
107 | 0 | } |
108 | | |
109 | | void _gnutls_hash_deinit(digest_hd_st *handle, void *digest) |
110 | 0 | { |
111 | 0 | if (handle->handle == NULL) { |
112 | 0 | return; |
113 | 0 | } |
114 | | |
115 | 0 | if (digest != NULL) |
116 | 0 | _gnutls_hash_output(handle, digest); |
117 | |
|
118 | 0 | handle->deinit(handle->handle); |
119 | 0 | handle->handle = NULL; |
120 | 0 | } |
121 | | |
122 | | int _gnutls_hash_fast(gnutls_digest_algorithm_t algorithm, const void *text, |
123 | | size_t textlen, void *digest) |
124 | 0 | { |
125 | 0 | int ret; |
126 | 0 | const gnutls_crypto_digest_st *cc = NULL; |
127 | |
|
128 | 0 | FAIL_IF_LIB_ERROR; |
129 | | |
130 | | /* check if a digest has been registered |
131 | | */ |
132 | 0 | cc = _gnutls_get_crypto_digest(algorithm); |
133 | 0 | if (cc != NULL) { |
134 | 0 | if (cc->fast(algorithm, text, textlen, digest) < 0) { |
135 | 0 | gnutls_assert(); |
136 | 0 | return GNUTLS_E_HASH_FAILED; |
137 | 0 | } |
138 | | |
139 | 0 | return 0; |
140 | 0 | } |
141 | | |
142 | 0 | ret = _gnutls_digest_ops.fast(algorithm, text, textlen, digest); |
143 | 0 | if (ret < 0) { |
144 | 0 | gnutls_assert(); |
145 | 0 | return ret; |
146 | 0 | } |
147 | | |
148 | 0 | return 0; |
149 | 0 | } |
150 | | |
151 | | int _gnutls_hash_squeeze(digest_hd_st *handle, void *output, size_t length) |
152 | 0 | { |
153 | 0 | if (handle->output == NULL) |
154 | 0 | return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
155 | | |
156 | 0 | if (!(handle->e->flags & GNUTLS_MAC_FLAG_XOF)) |
157 | 0 | return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
158 | | |
159 | 0 | handle->output(handle->handle, output, length); |
160 | 0 | return 0; |
161 | 0 | } |
162 | | |
163 | | /* HMAC interface */ |
164 | | |
165 | | int _gnutls_mac_fast(gnutls_mac_algorithm_t algorithm, const void *key, |
166 | | int keylen, const void *text, size_t textlen, void *digest) |
167 | 0 | { |
168 | 0 | int ret; |
169 | 0 | const gnutls_crypto_mac_st *cc = NULL; |
170 | |
|
171 | 0 | FAIL_IF_LIB_ERROR; |
172 | | |
173 | | /* check if a digest has been registered |
174 | | */ |
175 | 0 | cc = _gnutls_get_crypto_mac(algorithm); |
176 | 0 | if (cc != NULL) { |
177 | 0 | if (cc->fast(algorithm, NULL, 0, key, keylen, text, textlen, |
178 | 0 | digest) < 0) { |
179 | 0 | gnutls_assert(); |
180 | 0 | return GNUTLS_E_HASH_FAILED; |
181 | 0 | } |
182 | | |
183 | 0 | return 0; |
184 | 0 | } |
185 | | |
186 | 0 | ret = _gnutls_mac_ops.fast(algorithm, NULL, 0, key, keylen, text, |
187 | 0 | textlen, digest); |
188 | 0 | if (ret < 0) { |
189 | 0 | gnutls_assert(); |
190 | 0 | return ret; |
191 | 0 | } |
192 | | |
193 | 0 | return 0; |
194 | 0 | } |
195 | | |
196 | | /* Returns true(non-zero) or false(0) if the |
197 | | * provided hash exists |
198 | | */ |
199 | | int _gnutls_mac_exists(gnutls_mac_algorithm_t algo) |
200 | 0 | { |
201 | 0 | const gnutls_crypto_mac_st *cc = NULL; |
202 | | |
203 | | /* exceptionally it exists, as it is not a real MAC */ |
204 | 0 | if (algo == GNUTLS_MAC_AEAD) |
205 | 0 | return 1; |
206 | | |
207 | 0 | if (!is_mac_algo_allowed(algo)) |
208 | 0 | return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); |
209 | | |
210 | 0 | cc = _gnutls_get_crypto_mac(algo); |
211 | 0 | if (cc != NULL) |
212 | 0 | return 1; |
213 | | |
214 | 0 | return _gnutls_mac_ops.exists(algo); |
215 | 0 | } |
216 | | |
217 | | int _gnutls_mac_init(mac_hd_st *mac, const mac_entry_st *e, const void *key, |
218 | | int keylen) |
219 | 0 | { |
220 | 0 | int result; |
221 | 0 | const gnutls_crypto_mac_st *cc = NULL; |
222 | |
|
223 | 0 | FAIL_IF_LIB_ERROR; |
224 | | |
225 | 0 | if (unlikely(e == NULL || e->id == GNUTLS_MAC_NULL)) |
226 | 0 | return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
227 | | |
228 | 0 | mac->e = e; |
229 | 0 | mac->mac_len = _gnutls_mac_get_algo_len(e); |
230 | | |
231 | | /* check if a digest has been registered |
232 | | */ |
233 | 0 | cc = _gnutls_get_crypto_mac(e->id); |
234 | 0 | if (cc != NULL && cc->init != NULL) { |
235 | 0 | if (cc->init(e->id, &mac->handle) < 0) { |
236 | 0 | gnutls_assert(); |
237 | 0 | return GNUTLS_E_HASH_FAILED; |
238 | 0 | } |
239 | | |
240 | 0 | if (cc->setkey(mac->handle, key, keylen) < 0) { |
241 | 0 | gnutls_assert(); |
242 | 0 | cc->deinit(mac->handle); |
243 | 0 | return GNUTLS_E_HASH_FAILED; |
244 | 0 | } |
245 | | |
246 | 0 | mac->hash = cc->hash; |
247 | 0 | mac->setnonce = cc->setnonce; |
248 | 0 | mac->output = cc->output; |
249 | 0 | mac->deinit = cc->deinit; |
250 | 0 | mac->copy = cc->copy; |
251 | 0 | mac->setkey = cc->setkey; |
252 | |
|
253 | 0 | return 0; |
254 | 0 | } |
255 | | |
256 | 0 | result = _gnutls_mac_ops.init(e->id, &mac->handle); |
257 | 0 | if (result < 0) { |
258 | 0 | gnutls_assert(); |
259 | 0 | return result; |
260 | 0 | } |
261 | | |
262 | 0 | mac->hash = _gnutls_mac_ops.hash; |
263 | 0 | mac->setnonce = _gnutls_mac_ops.setnonce; |
264 | 0 | mac->output = _gnutls_mac_ops.output; |
265 | 0 | mac->deinit = _gnutls_mac_ops.deinit; |
266 | 0 | mac->copy = _gnutls_mac_ops.copy; |
267 | 0 | mac->setkey = _gnutls_mac_ops.setkey; |
268 | |
|
269 | 0 | if (_gnutls_mac_ops.setkey(mac->handle, key, keylen) < 0) { |
270 | 0 | gnutls_assert(); |
271 | 0 | mac->deinit(mac->handle); |
272 | 0 | return GNUTLS_E_HASH_FAILED; |
273 | 0 | } |
274 | | |
275 | 0 | return 0; |
276 | 0 | } |
277 | | |
278 | | int _gnutls_mac_copy(const mac_hd_st *handle, mac_hd_st *dst) |
279 | 0 | { |
280 | 0 | if (handle->copy == NULL) |
281 | 0 | return gnutls_assert_val(GNUTLS_E_HASH_FAILED); |
282 | | |
283 | 0 | *dst = *handle; /* copy data */ |
284 | 0 | dst->handle = handle->copy(handle->handle); |
285 | |
|
286 | 0 | if (dst->handle == NULL) |
287 | 0 | return GNUTLS_E_HASH_FAILED; |
288 | | |
289 | 0 | return 0; |
290 | 0 | } |
291 | | |
292 | | void _gnutls_mac_deinit(mac_hd_st *handle, void *digest) |
293 | 0 | { |
294 | 0 | if (handle->handle == NULL) { |
295 | 0 | return; |
296 | 0 | } |
297 | | |
298 | 0 | if (digest) |
299 | 0 | _gnutls_mac_output(handle, digest); |
300 | |
|
301 | 0 | handle->deinit(handle->handle); |
302 | 0 | handle->handle = NULL; |
303 | 0 | } |
304 | | |
305 | | #ifdef ENABLE_SSL3 |
306 | | inline static int get_padsize(gnutls_mac_algorithm_t algorithm) |
307 | | { |
308 | | switch (algorithm) { |
309 | | case GNUTLS_MAC_MD5: |
310 | | return 48; |
311 | | case GNUTLS_MAC_SHA1: |
312 | | return 40; |
313 | | default: |
314 | | return 0; |
315 | | } |
316 | | } |
317 | | |
318 | | /* Special functions for SSL3 MAC |
319 | | */ |
320 | | |
321 | | int _gnutls_mac_init_ssl3(digest_hd_st *ret, const mac_entry_st *e, void *key, |
322 | | int keylen) |
323 | | { |
324 | | uint8_t ipad[48]; |
325 | | int padsize, result; |
326 | | |
327 | | FAIL_IF_LIB_ERROR; |
328 | | |
329 | | padsize = get_padsize(e->id); |
330 | | if (padsize == 0) { |
331 | | gnutls_assert(); |
332 | | return GNUTLS_E_HASH_FAILED; |
333 | | } |
334 | | |
335 | | memset(ipad, 0x36, padsize); |
336 | | |
337 | | result = _gnutls_hash_init(ret, e); |
338 | | if (result < 0) { |
339 | | gnutls_assert(); |
340 | | return result; |
341 | | } |
342 | | |
343 | | ret->key = key; |
344 | | ret->keysize = keylen; |
345 | | |
346 | | if (keylen > 0) |
347 | | _gnutls_hash(ret, key, keylen); |
348 | | _gnutls_hash(ret, ipad, padsize); |
349 | | |
350 | | return 0; |
351 | | } |
352 | | |
353 | | int _gnutls_mac_output_ssl3(digest_hd_st *handle, void *digest) |
354 | | { |
355 | | uint8_t ret[MAX_HASH_SIZE]; |
356 | | digest_hd_st td; |
357 | | uint8_t opad[48]; |
358 | | int padsize; |
359 | | int block, rc; |
360 | | |
361 | | padsize = get_padsize(handle->e->id); |
362 | | if (padsize == 0) { |
363 | | gnutls_assert(); |
364 | | return GNUTLS_E_INTERNAL_ERROR; |
365 | | } |
366 | | |
367 | | memset(opad, 0x5C, padsize); |
368 | | |
369 | | rc = _gnutls_hash_init(&td, handle->e); |
370 | | if (rc < 0) { |
371 | | gnutls_assert(); |
372 | | return rc; |
373 | | } |
374 | | |
375 | | if (handle->keysize > 0) |
376 | | _gnutls_hash(&td, handle->key, handle->keysize); |
377 | | |
378 | | _gnutls_hash(&td, opad, padsize); |
379 | | block = _gnutls_mac_get_algo_len(handle->e); |
380 | | _gnutls_hash_output(handle, ret); /* get the previous hash */ |
381 | | _gnutls_hash(&td, ret, block); |
382 | | |
383 | | _gnutls_hash_deinit(&td, digest); |
384 | | |
385 | | /* reset handle */ |
386 | | memset(opad, 0x36, padsize); |
387 | | |
388 | | if (handle->keysize > 0) |
389 | | _gnutls_hash(handle, handle->key, handle->keysize); |
390 | | _gnutls_hash(handle, opad, padsize); |
391 | | |
392 | | return 0; |
393 | | } |
394 | | |
395 | | int _gnutls_mac_deinit_ssl3(digest_hd_st *handle, void *digest) |
396 | | { |
397 | | int ret = 0; |
398 | | |
399 | | if (digest != NULL) |
400 | | ret = _gnutls_mac_output_ssl3(handle, digest); |
401 | | _gnutls_hash_deinit(handle, NULL); |
402 | | |
403 | | return ret; |
404 | | } |
405 | | |
406 | | int _gnutls_mac_deinit_ssl3_handshake(digest_hd_st *handle, void *digest, |
407 | | uint8_t *key, uint32_t key_size) |
408 | | { |
409 | | uint8_t ret[MAX_HASH_SIZE]; |
410 | | digest_hd_st td; |
411 | | uint8_t opad[48]; |
412 | | uint8_t ipad[48]; |
413 | | int padsize; |
414 | | int block, rc; |
415 | | |
416 | | padsize = get_padsize(handle->e->id); |
417 | | if (padsize == 0) { |
418 | | gnutls_assert(); |
419 | | rc = GNUTLS_E_INTERNAL_ERROR; |
420 | | goto cleanup; |
421 | | } |
422 | | |
423 | | memset(opad, 0x5C, padsize); |
424 | | memset(ipad, 0x36, padsize); |
425 | | |
426 | | rc = _gnutls_hash_init(&td, handle->e); |
427 | | if (rc < 0) { |
428 | | gnutls_assert(); |
429 | | goto cleanup; |
430 | | } |
431 | | |
432 | | if (key_size > 0) |
433 | | _gnutls_hash(&td, key, key_size); |
434 | | |
435 | | _gnutls_hash(&td, opad, padsize); |
436 | | block = _gnutls_mac_get_algo_len(handle->e); |
437 | | |
438 | | if (key_size > 0) |
439 | | _gnutls_hash(handle, key, key_size); |
440 | | _gnutls_hash(handle, ipad, padsize); |
441 | | _gnutls_hash_deinit(handle, ret); /* get the previous hash */ |
442 | | |
443 | | _gnutls_hash(&td, ret, block); |
444 | | |
445 | | _gnutls_hash_deinit(&td, digest); |
446 | | |
447 | | return 0; |
448 | | |
449 | | cleanup: |
450 | | _gnutls_hash_deinit(handle, NULL); |
451 | | return rc; |
452 | | } |
453 | | |
454 | | static int ssl3_sha(int i, uint8_t *secret, int secret_len, uint8_t *rnd, |
455 | | int rnd_len, void *digest) |
456 | | { |
457 | | int j, ret; |
458 | | uint8_t text1[26]; |
459 | | |
460 | | digest_hd_st td; |
461 | | |
462 | | for (j = 0; j < i + 1; j++) { |
463 | | text1[j] = 65 + i; /* A==65 */ |
464 | | } |
465 | | |
466 | | ret = _gnutls_hash_init(&td, mac_to_entry(GNUTLS_MAC_SHA1)); |
467 | | if (ret < 0) { |
468 | | gnutls_assert(); |
469 | | return ret; |
470 | | } |
471 | | |
472 | | _gnutls_hash(&td, text1, i + 1); |
473 | | _gnutls_hash(&td, secret, secret_len); |
474 | | _gnutls_hash(&td, rnd, rnd_len); |
475 | | |
476 | | _gnutls_hash_deinit(&td, digest); |
477 | | return 0; |
478 | | } |
479 | | |
480 | | #define SHA1_DIGEST_OUTPUT 20 |
481 | | #define MD5_DIGEST_OUTPUT 16 |
482 | | |
483 | | static int ssl3_md5(int i, uint8_t *secret, int secret_len, uint8_t *rnd, |
484 | | int rnd_len, void *digest) |
485 | | { |
486 | | uint8_t tmp[MAX_HASH_SIZE]; |
487 | | digest_hd_st td; |
488 | | int ret; |
489 | | |
490 | | ret = _gnutls_hash_init(&td, mac_to_entry(GNUTLS_MAC_MD5)); |
491 | | if (ret < 0) { |
492 | | gnutls_assert(); |
493 | | return ret; |
494 | | } |
495 | | |
496 | | _gnutls_hash(&td, secret, secret_len); |
497 | | |
498 | | ret = ssl3_sha(i, secret, secret_len, rnd, rnd_len, tmp); |
499 | | if (ret < 0) { |
500 | | gnutls_assert(); |
501 | | _gnutls_hash_deinit(&td, digest); |
502 | | return ret; |
503 | | } |
504 | | |
505 | | _gnutls_hash(&td, tmp, SHA1_DIGEST_OUTPUT); |
506 | | |
507 | | _gnutls_hash_deinit(&td, digest); |
508 | | return 0; |
509 | | } |
510 | | |
511 | | int _gnutls_ssl3_generate_random(void *secret, int secret_len, void *rnd, |
512 | | int rnd_len, int ret_bytes, uint8_t *ret) |
513 | | { |
514 | | int i = 0, copy, output_bytes; |
515 | | uint8_t digest[MAX_HASH_SIZE]; |
516 | | int block = MD5_DIGEST_OUTPUT; |
517 | | int result, times; |
518 | | |
519 | | output_bytes = 0; |
520 | | do { |
521 | | output_bytes += block; |
522 | | } while (output_bytes < ret_bytes); |
523 | | |
524 | | times = output_bytes / block; |
525 | | |
526 | | for (i = 0; i < times; i++) { |
527 | | result = ssl3_md5(i, secret, secret_len, rnd, rnd_len, digest); |
528 | | if (result < 0) { |
529 | | gnutls_assert(); |
530 | | return result; |
531 | | } |
532 | | |
533 | | if ((1 + i) * block < ret_bytes) { |
534 | | copy = block; |
535 | | } else { |
536 | | copy = ret_bytes - (i)*block; |
537 | | } |
538 | | |
539 | | memcpy(&ret[i * block], digest, copy); |
540 | | } |
541 | | |
542 | | return 0; |
543 | | } |
544 | | |
545 | | #endif |