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