Coverage Report

Created: 2025-03-06 07:58

/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