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