/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 | | /* HMAC interface */ |
152 | | |
153 | | int _gnutls_mac_fast(gnutls_mac_algorithm_t algorithm, const void *key, |
154 | | int keylen, const void *text, size_t textlen, void *digest) |
155 | 0 | { |
156 | 0 | int ret; |
157 | 0 | const gnutls_crypto_mac_st *cc = NULL; |
158 | |
|
159 | 0 | FAIL_IF_LIB_ERROR; |
160 | | |
161 | | /* check if a digest has been registered |
162 | | */ |
163 | 0 | cc = _gnutls_get_crypto_mac(algorithm); |
164 | 0 | if (cc != NULL) { |
165 | 0 | if (cc->fast(algorithm, NULL, 0, key, keylen, text, textlen, |
166 | 0 | digest) < 0) { |
167 | 0 | gnutls_assert(); |
168 | 0 | return GNUTLS_E_HASH_FAILED; |
169 | 0 | } |
170 | | |
171 | 0 | return 0; |
172 | 0 | } |
173 | | |
174 | 0 | ret = _gnutls_mac_ops.fast(algorithm, NULL, 0, key, keylen, text, |
175 | 0 | textlen, digest); |
176 | 0 | if (ret < 0) { |
177 | 0 | gnutls_assert(); |
178 | 0 | return ret; |
179 | 0 | } |
180 | | |
181 | 0 | return 0; |
182 | 0 | } |
183 | | |
184 | | /* Returns true(non-zero) or false(0) if the |
185 | | * provided hash exists |
186 | | */ |
187 | | int _gnutls_mac_exists(gnutls_mac_algorithm_t algo) |
188 | 0 | { |
189 | 0 | const gnutls_crypto_mac_st *cc = NULL; |
190 | | |
191 | | /* exceptionally it exists, as it is not a real MAC */ |
192 | 0 | if (algo == GNUTLS_MAC_AEAD) |
193 | 0 | return 1; |
194 | | |
195 | 0 | if (!is_mac_algo_allowed(algo)) |
196 | 0 | return gnutls_assert_val(GNUTLS_E_UNWANTED_ALGORITHM); |
197 | | |
198 | 0 | cc = _gnutls_get_crypto_mac(algo); |
199 | 0 | if (cc != NULL) |
200 | 0 | return 1; |
201 | | |
202 | 0 | return _gnutls_mac_ops.exists(algo); |
203 | 0 | } |
204 | | |
205 | | int _gnutls_mac_init(mac_hd_st *mac, const mac_entry_st *e, const void *key, |
206 | | int keylen) |
207 | 0 | { |
208 | 0 | int result; |
209 | 0 | const gnutls_crypto_mac_st *cc = NULL; |
210 | |
|
211 | 0 | FAIL_IF_LIB_ERROR; |
212 | | |
213 | 0 | if (unlikely(e == NULL || e->id == GNUTLS_MAC_NULL)) |
214 | 0 | return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); |
215 | | |
216 | 0 | mac->e = e; |
217 | 0 | mac->mac_len = _gnutls_mac_get_algo_len(e); |
218 | | |
219 | | /* check if a digest has been registered |
220 | | */ |
221 | 0 | cc = _gnutls_get_crypto_mac(e->id); |
222 | 0 | if (cc != NULL && cc->init != NULL) { |
223 | 0 | if (cc->init(e->id, &mac->handle) < 0) { |
224 | 0 | gnutls_assert(); |
225 | 0 | return GNUTLS_E_HASH_FAILED; |
226 | 0 | } |
227 | | |
228 | 0 | if (cc->setkey(mac->handle, key, keylen) < 0) { |
229 | 0 | gnutls_assert(); |
230 | 0 | cc->deinit(mac->handle); |
231 | 0 | return GNUTLS_E_HASH_FAILED; |
232 | 0 | } |
233 | | |
234 | 0 | mac->hash = cc->hash; |
235 | 0 | mac->setnonce = cc->setnonce; |
236 | 0 | mac->output = cc->output; |
237 | 0 | mac->deinit = cc->deinit; |
238 | 0 | mac->copy = cc->copy; |
239 | 0 | mac->setkey = cc->setkey; |
240 | |
|
241 | 0 | return 0; |
242 | 0 | } |
243 | | |
244 | 0 | result = _gnutls_mac_ops.init(e->id, &mac->handle); |
245 | 0 | if (result < 0) { |
246 | 0 | gnutls_assert(); |
247 | 0 | return result; |
248 | 0 | } |
249 | | |
250 | 0 | mac->hash = _gnutls_mac_ops.hash; |
251 | 0 | mac->setnonce = _gnutls_mac_ops.setnonce; |
252 | 0 | mac->output = _gnutls_mac_ops.output; |
253 | 0 | mac->deinit = _gnutls_mac_ops.deinit; |
254 | 0 | mac->copy = _gnutls_mac_ops.copy; |
255 | 0 | mac->setkey = _gnutls_mac_ops.setkey; |
256 | |
|
257 | 0 | if (_gnutls_mac_ops.setkey(mac->handle, key, keylen) < 0) { |
258 | 0 | gnutls_assert(); |
259 | 0 | mac->deinit(mac->handle); |
260 | 0 | return GNUTLS_E_HASH_FAILED; |
261 | 0 | } |
262 | | |
263 | 0 | return 0; |
264 | 0 | } |
265 | | |
266 | | int _gnutls_mac_copy(const mac_hd_st *handle, mac_hd_st *dst) |
267 | 0 | { |
268 | 0 | if (handle->copy == NULL) |
269 | 0 | return gnutls_assert_val(GNUTLS_E_HASH_FAILED); |
270 | | |
271 | 0 | *dst = *handle; /* copy data */ |
272 | 0 | dst->handle = handle->copy(handle->handle); |
273 | |
|
274 | 0 | if (dst->handle == NULL) |
275 | 0 | return GNUTLS_E_HASH_FAILED; |
276 | | |
277 | 0 | return 0; |
278 | 0 | } |
279 | | |
280 | | void _gnutls_mac_deinit(mac_hd_st *handle, void *digest) |
281 | 0 | { |
282 | 0 | if (handle->handle == NULL) { |
283 | 0 | return; |
284 | 0 | } |
285 | | |
286 | 0 | if (digest) |
287 | 0 | _gnutls_mac_output(handle, digest); |
288 | |
|
289 | 0 | handle->deinit(handle->handle); |
290 | 0 | handle->handle = NULL; |
291 | 0 | } |
292 | | |
293 | | #ifdef ENABLE_SSL3 |
294 | | inline static int get_padsize(gnutls_mac_algorithm_t algorithm) |
295 | | { |
296 | | switch (algorithm) { |
297 | | case GNUTLS_MAC_MD5: |
298 | | return 48; |
299 | | case GNUTLS_MAC_SHA1: |
300 | | return 40; |
301 | | default: |
302 | | return 0; |
303 | | } |
304 | | } |
305 | | |
306 | | /* Special functions for SSL3 MAC |
307 | | */ |
308 | | |
309 | | int _gnutls_mac_init_ssl3(digest_hd_st *ret, const mac_entry_st *e, void *key, |
310 | | int keylen) |
311 | | { |
312 | | uint8_t ipad[48]; |
313 | | int padsize, result; |
314 | | |
315 | | FAIL_IF_LIB_ERROR; |
316 | | |
317 | | padsize = get_padsize(e->id); |
318 | | if (padsize == 0) { |
319 | | gnutls_assert(); |
320 | | return GNUTLS_E_HASH_FAILED; |
321 | | } |
322 | | |
323 | | memset(ipad, 0x36, padsize); |
324 | | |
325 | | result = _gnutls_hash_init(ret, e); |
326 | | if (result < 0) { |
327 | | gnutls_assert(); |
328 | | return result; |
329 | | } |
330 | | |
331 | | ret->key = key; |
332 | | ret->keysize = keylen; |
333 | | |
334 | | if (keylen > 0) |
335 | | _gnutls_hash(ret, key, keylen); |
336 | | _gnutls_hash(ret, ipad, padsize); |
337 | | |
338 | | return 0; |
339 | | } |
340 | | |
341 | | int _gnutls_mac_output_ssl3(digest_hd_st *handle, void *digest) |
342 | | { |
343 | | uint8_t ret[MAX_HASH_SIZE]; |
344 | | digest_hd_st td; |
345 | | uint8_t opad[48]; |
346 | | int padsize; |
347 | | int block, rc; |
348 | | |
349 | | padsize = get_padsize(handle->e->id); |
350 | | if (padsize == 0) { |
351 | | gnutls_assert(); |
352 | | return GNUTLS_E_INTERNAL_ERROR; |
353 | | } |
354 | | |
355 | | memset(opad, 0x5C, padsize); |
356 | | |
357 | | rc = _gnutls_hash_init(&td, handle->e); |
358 | | if (rc < 0) { |
359 | | gnutls_assert(); |
360 | | return rc; |
361 | | } |
362 | | |
363 | | if (handle->keysize > 0) |
364 | | _gnutls_hash(&td, handle->key, handle->keysize); |
365 | | |
366 | | _gnutls_hash(&td, opad, padsize); |
367 | | block = _gnutls_mac_get_algo_len(handle->e); |
368 | | _gnutls_hash_output(handle, ret); /* get the previous hash */ |
369 | | _gnutls_hash(&td, ret, block); |
370 | | |
371 | | _gnutls_hash_deinit(&td, digest); |
372 | | |
373 | | /* reset handle */ |
374 | | memset(opad, 0x36, padsize); |
375 | | |
376 | | if (handle->keysize > 0) |
377 | | _gnutls_hash(handle, handle->key, handle->keysize); |
378 | | _gnutls_hash(handle, opad, padsize); |
379 | | |
380 | | return 0; |
381 | | } |
382 | | |
383 | | int _gnutls_mac_deinit_ssl3(digest_hd_st *handle, void *digest) |
384 | | { |
385 | | int ret = 0; |
386 | | |
387 | | if (digest != NULL) |
388 | | ret = _gnutls_mac_output_ssl3(handle, digest); |
389 | | _gnutls_hash_deinit(handle, NULL); |
390 | | |
391 | | return ret; |
392 | | } |
393 | | |
394 | | int _gnutls_mac_deinit_ssl3_handshake(digest_hd_st *handle, void *digest, |
395 | | uint8_t *key, uint32_t key_size) |
396 | | { |
397 | | uint8_t ret[MAX_HASH_SIZE]; |
398 | | digest_hd_st td; |
399 | | uint8_t opad[48]; |
400 | | uint8_t ipad[48]; |
401 | | int padsize; |
402 | | int block, rc; |
403 | | |
404 | | padsize = get_padsize(handle->e->id); |
405 | | if (padsize == 0) { |
406 | | gnutls_assert(); |
407 | | rc = GNUTLS_E_INTERNAL_ERROR; |
408 | | goto cleanup; |
409 | | } |
410 | | |
411 | | memset(opad, 0x5C, padsize); |
412 | | memset(ipad, 0x36, padsize); |
413 | | |
414 | | rc = _gnutls_hash_init(&td, handle->e); |
415 | | if (rc < 0) { |
416 | | gnutls_assert(); |
417 | | goto cleanup; |
418 | | } |
419 | | |
420 | | if (key_size > 0) |
421 | | _gnutls_hash(&td, key, key_size); |
422 | | |
423 | | _gnutls_hash(&td, opad, padsize); |
424 | | block = _gnutls_mac_get_algo_len(handle->e); |
425 | | |
426 | | if (key_size > 0) |
427 | | _gnutls_hash(handle, key, key_size); |
428 | | _gnutls_hash(handle, ipad, padsize); |
429 | | _gnutls_hash_deinit(handle, ret); /* get the previous hash */ |
430 | | |
431 | | _gnutls_hash(&td, ret, block); |
432 | | |
433 | | _gnutls_hash_deinit(&td, digest); |
434 | | |
435 | | return 0; |
436 | | |
437 | | cleanup: |
438 | | _gnutls_hash_deinit(handle, NULL); |
439 | | return rc; |
440 | | } |
441 | | |
442 | | static int ssl3_sha(int i, uint8_t *secret, int secret_len, uint8_t *rnd, |
443 | | int rnd_len, void *digest) |
444 | | { |
445 | | int j, ret; |
446 | | uint8_t text1[26]; |
447 | | |
448 | | digest_hd_st td; |
449 | | |
450 | | for (j = 0; j < i + 1; j++) { |
451 | | text1[j] = 65 + i; /* A==65 */ |
452 | | } |
453 | | |
454 | | ret = _gnutls_hash_init(&td, mac_to_entry(GNUTLS_MAC_SHA1)); |
455 | | if (ret < 0) { |
456 | | gnutls_assert(); |
457 | | return ret; |
458 | | } |
459 | | |
460 | | _gnutls_hash(&td, text1, i + 1); |
461 | | _gnutls_hash(&td, secret, secret_len); |
462 | | _gnutls_hash(&td, rnd, rnd_len); |
463 | | |
464 | | _gnutls_hash_deinit(&td, digest); |
465 | | return 0; |
466 | | } |
467 | | |
468 | | #define SHA1_DIGEST_OUTPUT 20 |
469 | | #define MD5_DIGEST_OUTPUT 16 |
470 | | |
471 | | static int ssl3_md5(int i, uint8_t *secret, int secret_len, uint8_t *rnd, |
472 | | int rnd_len, void *digest) |
473 | | { |
474 | | uint8_t tmp[MAX_HASH_SIZE]; |
475 | | digest_hd_st td; |
476 | | int ret; |
477 | | |
478 | | ret = _gnutls_hash_init(&td, mac_to_entry(GNUTLS_MAC_MD5)); |
479 | | if (ret < 0) { |
480 | | gnutls_assert(); |
481 | | return ret; |
482 | | } |
483 | | |
484 | | _gnutls_hash(&td, secret, secret_len); |
485 | | |
486 | | ret = ssl3_sha(i, secret, secret_len, rnd, rnd_len, tmp); |
487 | | if (ret < 0) { |
488 | | gnutls_assert(); |
489 | | _gnutls_hash_deinit(&td, digest); |
490 | | return ret; |
491 | | } |
492 | | |
493 | | _gnutls_hash(&td, tmp, SHA1_DIGEST_OUTPUT); |
494 | | |
495 | | _gnutls_hash_deinit(&td, digest); |
496 | | return 0; |
497 | | } |
498 | | |
499 | | int _gnutls_ssl3_generate_random(void *secret, int secret_len, void *rnd, |
500 | | int rnd_len, int ret_bytes, uint8_t *ret) |
501 | | { |
502 | | int i = 0, copy, output_bytes; |
503 | | uint8_t digest[MAX_HASH_SIZE]; |
504 | | int block = MD5_DIGEST_OUTPUT; |
505 | | int result, times; |
506 | | |
507 | | output_bytes = 0; |
508 | | do { |
509 | | output_bytes += block; |
510 | | } while (output_bytes < ret_bytes); |
511 | | |
512 | | times = output_bytes / block; |
513 | | |
514 | | for (i = 0; i < times; i++) { |
515 | | result = ssl3_md5(i, secret, secret_len, rnd, rnd_len, digest); |
516 | | if (result < 0) { |
517 | | gnutls_assert(); |
518 | | return result; |
519 | | } |
520 | | |
521 | | if ((1 + i) * block < ret_bytes) { |
522 | | copy = block; |
523 | | } else { |
524 | | copy = ret_bytes - (i)*block; |
525 | | } |
526 | | |
527 | | memcpy(&ret[i * block], digest, copy); |
528 | | } |
529 | | |
530 | | return 0; |
531 | | } |
532 | | |
533 | | #endif |