/src/libgcrypt/cipher/md.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* md.c - message digest dispatcher |
2 | | * Copyright (C) 1998, 1999, 2002, 2003, 2006, |
3 | | * 2008 Free Software Foundation, Inc. |
4 | | * Copyright (C) 2013, 2014 g10 Code GmbH |
5 | | * |
6 | | * This file is part of Libgcrypt. |
7 | | * |
8 | | * Libgcrypt is free software; you can redistribute it and/or modify |
9 | | * it under the terms of the GNU Lesser General Public License as |
10 | | * published by the Free Software Foundation; either version 2.1 of |
11 | | * the License, or (at your option) any later version. |
12 | | * |
13 | | * Libgcrypt is distributed in the hope that it will be useful, |
14 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | | * GNU Lesser General Public License for more details. |
17 | | * |
18 | | * You should have received a copy of the GNU Lesser General Public |
19 | | * License along with this program; if not, see <http://www.gnu.org/licenses/>. |
20 | | */ |
21 | | |
22 | | #include <config.h> |
23 | | #include <stdio.h> |
24 | | #include <stdlib.h> |
25 | | #include <string.h> |
26 | | #include <errno.h> |
27 | | |
28 | | #include "g10lib.h" |
29 | | #include "cipher.h" |
30 | | |
31 | | |
32 | | /* This is the list of the digest implementations included in |
33 | | libgcrypt. */ |
34 | | static const gcry_md_spec_t * const digest_list[] = |
35 | | { |
36 | | #if USE_CRC |
37 | | &_gcry_digest_spec_crc32, |
38 | | &_gcry_digest_spec_crc32_rfc1510, |
39 | | &_gcry_digest_spec_crc24_rfc2440, |
40 | | #endif |
41 | | #if USE_SHA1 |
42 | | &_gcry_digest_spec_sha1, |
43 | | #endif |
44 | | #if USE_SHA256 |
45 | | &_gcry_digest_spec_sha256, |
46 | | &_gcry_digest_spec_sha224, |
47 | | #endif |
48 | | #if USE_SHA512 |
49 | | &_gcry_digest_spec_sha512, |
50 | | &_gcry_digest_spec_sha384, |
51 | | &_gcry_digest_spec_sha512_256, |
52 | | &_gcry_digest_spec_sha512_224, |
53 | | #endif |
54 | | #if USE_SHA3 |
55 | | &_gcry_digest_spec_sha3_224, |
56 | | &_gcry_digest_spec_sha3_256, |
57 | | &_gcry_digest_spec_sha3_384, |
58 | | &_gcry_digest_spec_sha3_512, |
59 | | &_gcry_digest_spec_shake128, |
60 | | &_gcry_digest_spec_shake256, |
61 | | &_gcry_digest_spec_cshake128, |
62 | | &_gcry_digest_spec_cshake256, |
63 | | #endif |
64 | | #if USE_GOST_R_3411_94 |
65 | | &_gcry_digest_spec_gost3411_94, |
66 | | &_gcry_digest_spec_gost3411_cp, |
67 | | #endif |
68 | | #if USE_GOST_R_3411_12 |
69 | | &_gcry_digest_spec_stribog_256, |
70 | | &_gcry_digest_spec_stribog_512, |
71 | | #endif |
72 | | #if USE_WHIRLPOOL |
73 | | &_gcry_digest_spec_whirlpool, |
74 | | #endif |
75 | | #if USE_RMD160 |
76 | | &_gcry_digest_spec_rmd160, |
77 | | #endif |
78 | | #if USE_TIGER |
79 | | &_gcry_digest_spec_tiger, |
80 | | &_gcry_digest_spec_tiger1, |
81 | | &_gcry_digest_spec_tiger2, |
82 | | #endif |
83 | | #if USE_MD5 |
84 | | &_gcry_digest_spec_md5, |
85 | | #endif |
86 | | #if USE_MD4 |
87 | | &_gcry_digest_spec_md4, |
88 | | #endif |
89 | | #if USE_MD2 |
90 | | &_gcry_digest_spec_md2, |
91 | | #endif |
92 | | #if USE_BLAKE2 |
93 | | &_gcry_digest_spec_blake2b_512, |
94 | | &_gcry_digest_spec_blake2b_384, |
95 | | &_gcry_digest_spec_blake2b_256, |
96 | | &_gcry_digest_spec_blake2b_160, |
97 | | &_gcry_digest_spec_blake2s_256, |
98 | | &_gcry_digest_spec_blake2s_224, |
99 | | &_gcry_digest_spec_blake2s_160, |
100 | | &_gcry_digest_spec_blake2s_128, |
101 | | #endif |
102 | | #if USE_SM3 |
103 | | &_gcry_digest_spec_sm3, |
104 | | #endif |
105 | | NULL |
106 | | }; |
107 | | |
108 | | /* Digest implementations starting with index 0 (enum gcry_md_algos) */ |
109 | | static const gcry_md_spec_t * const digest_list_algo0[] = |
110 | | { |
111 | | NULL, /* GCRY_MD_NONE */ |
112 | | #if USE_MD5 |
113 | | &_gcry_digest_spec_md5, |
114 | | #else |
115 | | NULL, |
116 | | #endif |
117 | | #if USE_SHA1 |
118 | | &_gcry_digest_spec_sha1, |
119 | | #else |
120 | | NULL, |
121 | | #endif |
122 | | #if USE_RMD160 |
123 | | &_gcry_digest_spec_rmd160, |
124 | | #else |
125 | | NULL, |
126 | | #endif |
127 | | NULL, /* Unused index 4 */ |
128 | | #if USE_MD2 |
129 | | &_gcry_digest_spec_md2, |
130 | | #else |
131 | | NULL, |
132 | | #endif |
133 | | #if USE_TIGER |
134 | | &_gcry_digest_spec_tiger, |
135 | | #else |
136 | | NULL, |
137 | | #endif |
138 | | NULL, /* GCRY_MD_HAVAL */ |
139 | | #if USE_SHA256 |
140 | | &_gcry_digest_spec_sha256, |
141 | | #else |
142 | | NULL, |
143 | | #endif |
144 | | #if USE_SHA512 |
145 | | &_gcry_digest_spec_sha384, |
146 | | &_gcry_digest_spec_sha512, |
147 | | #else |
148 | | NULL, |
149 | | NULL, |
150 | | #endif |
151 | | #if USE_SHA256 |
152 | | &_gcry_digest_spec_sha224 |
153 | | #else |
154 | | NULL |
155 | | #endif |
156 | | }; |
157 | | |
158 | | /* Digest implementations starting with index 301 (enum gcry_md_algos) */ |
159 | | static const gcry_md_spec_t * const digest_list_algo301[] = |
160 | | { |
161 | | #if USE_MD4 |
162 | | &_gcry_digest_spec_md4, |
163 | | #else |
164 | | NULL, |
165 | | #endif |
166 | | #if USE_CRC |
167 | | &_gcry_digest_spec_crc32, |
168 | | &_gcry_digest_spec_crc32_rfc1510, |
169 | | &_gcry_digest_spec_crc24_rfc2440, |
170 | | #else |
171 | | NULL, |
172 | | NULL, |
173 | | NULL, |
174 | | #endif |
175 | | #if USE_WHIRLPOOL |
176 | | &_gcry_digest_spec_whirlpool, |
177 | | #else |
178 | | NULL, |
179 | | #endif |
180 | | #if USE_TIGER |
181 | | &_gcry_digest_spec_tiger1, |
182 | | &_gcry_digest_spec_tiger2, |
183 | | #else |
184 | | NULL, |
185 | | NULL, |
186 | | #endif |
187 | | #if USE_GOST_R_3411_94 |
188 | | &_gcry_digest_spec_gost3411_94, |
189 | | #else |
190 | | NULL, |
191 | | #endif |
192 | | #if USE_GOST_R_3411_12 |
193 | | &_gcry_digest_spec_stribog_256, |
194 | | &_gcry_digest_spec_stribog_512, |
195 | | #else |
196 | | NULL, |
197 | | NULL, |
198 | | #endif |
199 | | #if USE_GOST_R_3411_94 |
200 | | &_gcry_digest_spec_gost3411_cp, |
201 | | #else |
202 | | NULL, |
203 | | #endif |
204 | | #if USE_SHA3 |
205 | | &_gcry_digest_spec_sha3_224, |
206 | | &_gcry_digest_spec_sha3_256, |
207 | | &_gcry_digest_spec_sha3_384, |
208 | | &_gcry_digest_spec_sha3_512, |
209 | | &_gcry_digest_spec_shake128, |
210 | | &_gcry_digest_spec_shake256, |
211 | | #else |
212 | | NULL, |
213 | | NULL, |
214 | | NULL, |
215 | | NULL, |
216 | | NULL, |
217 | | NULL, |
218 | | #endif |
219 | | #if USE_BLAKE2 |
220 | | &_gcry_digest_spec_blake2b_512, |
221 | | &_gcry_digest_spec_blake2b_384, |
222 | | &_gcry_digest_spec_blake2b_256, |
223 | | &_gcry_digest_spec_blake2b_160, |
224 | | &_gcry_digest_spec_blake2s_256, |
225 | | &_gcry_digest_spec_blake2s_224, |
226 | | &_gcry_digest_spec_blake2s_160, |
227 | | &_gcry_digest_spec_blake2s_128, |
228 | | #else |
229 | | NULL, |
230 | | NULL, |
231 | | NULL, |
232 | | NULL, |
233 | | NULL, |
234 | | NULL, |
235 | | NULL, |
236 | | NULL, |
237 | | #endif |
238 | | #if USE_SM3 |
239 | | &_gcry_digest_spec_sm3, |
240 | | #else |
241 | | NULL, |
242 | | #endif |
243 | | #if USE_SHA512 |
244 | | &_gcry_digest_spec_sha512_256, |
245 | | &_gcry_digest_spec_sha512_224, |
246 | | #else |
247 | | NULL, |
248 | | NULL, |
249 | | #endif |
250 | | #if USE_SHA3 |
251 | | &_gcry_digest_spec_cshake128, |
252 | | &_gcry_digest_spec_cshake256 |
253 | | #else |
254 | | NULL, |
255 | | NULL |
256 | | #endif |
257 | | }; |
258 | | |
259 | | |
260 | | typedef struct gcry_md_list |
261 | | { |
262 | | const gcry_md_spec_t *spec; |
263 | | struct gcry_md_list *next; |
264 | | size_t actual_struct_size; /* Allocated size of this structure. */ |
265 | | PROPERLY_ALIGNED_TYPE context[1]; |
266 | | } GcryDigestEntry; |
267 | | |
268 | | /* This structure is put right after the gcry_md_hd_t buffer, so that |
269 | | * only one memory block is needed. */ |
270 | | struct gcry_md_context |
271 | | { |
272 | | int magic; |
273 | | struct { |
274 | | unsigned int secure:1; |
275 | | unsigned int finalized:1; |
276 | | unsigned int bugemu1:1; |
277 | | unsigned int hmac:1; |
278 | | } flags; |
279 | | size_t actual_handle_size; /* Allocated size of this handle. */ |
280 | | FILE *debug; |
281 | | GcryDigestEntry *list; |
282 | | }; |
283 | | |
284 | | |
285 | 10.7k | #define CTX_MAGIC_NORMAL 0x11071961 |
286 | 1.35k | #define CTX_MAGIC_SECURE 0x16917011 |
287 | | |
288 | | static gcry_err_code_t md_enable (gcry_md_hd_t hd, int algo); |
289 | | static void md_close (gcry_md_hd_t a); |
290 | | static void md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen); |
291 | | static byte *md_read( gcry_md_hd_t a, int algo ); |
292 | | static int md_get_algo( gcry_md_hd_t a ); |
293 | | static int md_digest_length( int algo ); |
294 | | static void md_start_debug ( gcry_md_hd_t a, const char *suffix ); |
295 | | static void md_stop_debug ( gcry_md_hd_t a ); |
296 | | |
297 | | |
298 | | |
299 | | static int |
300 | | map_algo (int algo) |
301 | 73.3k | { |
302 | 73.3k | return algo; |
303 | 73.3k | } |
304 | | |
305 | | |
306 | | /* Return the spec structure for the hash algorithm ALGO. For an |
307 | | unknown algorithm NULL is returned. */ |
308 | | static const gcry_md_spec_t * |
309 | | spec_from_algo (int algo) |
310 | 73.3k | { |
311 | 73.3k | const gcry_md_spec_t *spec = NULL; |
312 | | |
313 | 73.3k | algo = map_algo (algo); |
314 | | |
315 | 73.3k | if (algo >= 0 && algo < DIM(digest_list_algo0)) |
316 | 28.4k | spec = digest_list_algo0[algo]; |
317 | 44.9k | else if (algo >= 301 && algo < 301 + DIM(digest_list_algo301)) |
318 | 44.9k | spec = digest_list_algo301[algo - 301]; |
319 | | |
320 | 73.3k | if (spec) |
321 | 73.3k | gcry_assert (spec->algo == algo); |
322 | | |
323 | 0 | return spec; |
324 | 73.3k | } |
325 | | |
326 | | |
327 | | /* Lookup a hash's spec by its name. */ |
328 | | static const gcry_md_spec_t * |
329 | | spec_from_name (const char *name) |
330 | 0 | { |
331 | 0 | const gcry_md_spec_t *spec; |
332 | 0 | int idx; |
333 | |
|
334 | 0 | for (idx=0; (spec = digest_list[idx]); idx++) |
335 | 0 | { |
336 | 0 | if (!stricmp (name, spec->name)) |
337 | 0 | return spec; |
338 | 0 | } |
339 | | |
340 | 0 | return NULL; |
341 | 0 | } |
342 | | |
343 | | |
344 | | /* Lookup a hash's spec by its OID. */ |
345 | | static const gcry_md_spec_t * |
346 | | spec_from_oid (const char *oid) |
347 | 0 | { |
348 | 0 | const gcry_md_spec_t *spec; |
349 | 0 | const gcry_md_oid_spec_t *oid_specs; |
350 | 0 | int idx, j; |
351 | |
|
352 | 0 | for (idx=0; (spec = digest_list[idx]); idx++) |
353 | 0 | { |
354 | 0 | oid_specs = spec->oids; |
355 | 0 | if (oid_specs) |
356 | 0 | { |
357 | 0 | for (j = 0; oid_specs[j].oidstring; j++) |
358 | 0 | if (!stricmp (oid, oid_specs[j].oidstring)) |
359 | 0 | return spec; |
360 | 0 | } |
361 | 0 | } |
362 | | |
363 | 0 | return NULL; |
364 | 0 | } |
365 | | |
366 | | |
367 | | static const gcry_md_spec_t * |
368 | | search_oid (const char *oid, gcry_md_oid_spec_t *oid_spec) |
369 | 0 | { |
370 | 0 | const gcry_md_spec_t *spec; |
371 | 0 | int i; |
372 | |
|
373 | 0 | if (!oid) |
374 | 0 | return NULL; |
375 | | |
376 | 0 | if (!strncmp (oid, "oid.", 4) || !strncmp (oid, "OID.", 4)) |
377 | 0 | oid += 4; |
378 | |
|
379 | 0 | spec = spec_from_oid (oid); |
380 | 0 | if (spec && spec->oids) |
381 | 0 | { |
382 | 0 | for (i = 0; spec->oids[i].oidstring; i++) |
383 | 0 | if (!stricmp (oid, spec->oids[i].oidstring)) |
384 | 0 | { |
385 | 0 | if (oid_spec) |
386 | 0 | *oid_spec = spec->oids[i]; |
387 | 0 | return spec; |
388 | 0 | } |
389 | 0 | } |
390 | | |
391 | 0 | return NULL; |
392 | 0 | } |
393 | | |
394 | | |
395 | | /**************** |
396 | | * Map a string to the digest algo |
397 | | */ |
398 | | int |
399 | | _gcry_md_map_name (const char *string) |
400 | 0 | { |
401 | 0 | const gcry_md_spec_t *spec; |
402 | |
|
403 | 0 | if (!string) |
404 | 0 | return 0; |
405 | | |
406 | | /* If the string starts with a digit (optionally prefixed with |
407 | | either "OID." or "oid."), we first look into our table of ASN.1 |
408 | | object identifiers to figure out the algorithm */ |
409 | 0 | spec = search_oid (string, NULL); |
410 | 0 | if (spec) |
411 | 0 | return spec->algo; |
412 | | |
413 | | /* Not found, search a matching digest name. */ |
414 | 0 | spec = spec_from_name (string); |
415 | 0 | if (spec) |
416 | 0 | return spec->algo; |
417 | | |
418 | 0 | return 0; |
419 | 0 | } |
420 | | |
421 | | |
422 | | /**************** |
423 | | * This function simply returns the name of the algorithm or some constant |
424 | | * string when there is no algo. It will never return NULL. |
425 | | * Use the macro gcry_md_test_algo() to check whether the algorithm |
426 | | * is valid. |
427 | | */ |
428 | | const char * |
429 | | _gcry_md_algo_name (int algorithm) |
430 | 0 | { |
431 | 0 | const gcry_md_spec_t *spec; |
432 | |
|
433 | 0 | spec = spec_from_algo (algorithm); |
434 | 0 | return spec ? spec->name : "?"; |
435 | 0 | } |
436 | | |
437 | | |
438 | | static gcry_err_code_t |
439 | | check_digest_algo (int algorithm) |
440 | 0 | { |
441 | 0 | const gcry_md_spec_t *spec; |
442 | |
|
443 | 0 | spec = spec_from_algo (algorithm); |
444 | 0 | if (spec && !spec->flags.disabled && (spec->flags.fips || !fips_mode ())) |
445 | 0 | return 0; |
446 | | |
447 | 0 | return GPG_ERR_DIGEST_ALGO; |
448 | |
|
449 | 0 | } |
450 | | |
451 | | |
452 | | /**************** |
453 | | * Open a message digest handle for use with algorithm ALGO. |
454 | | * More algorithms may be added by md_enable(). The initial algorithm |
455 | | * may be 0. |
456 | | */ |
457 | | static gcry_err_code_t |
458 | | md_open (gcry_md_hd_t *h, int algo, unsigned int flags) |
459 | 6.07k | { |
460 | 6.07k | gcry_err_code_t err = 0; |
461 | 6.07k | int secure = !!(flags & GCRY_MD_FLAG_SECURE); |
462 | 6.07k | int hmac = !!(flags & GCRY_MD_FLAG_HMAC); |
463 | 6.07k | int bufsize = secure ? 512 : 1024; |
464 | 6.07k | gcry_md_hd_t hd; |
465 | 6.07k | size_t n; |
466 | | |
467 | | /* Allocate a memory area to hold the caller visible buffer with it's |
468 | | * control information and the data required by this module. Set the |
469 | | * context pointer at the beginning to this area. |
470 | | * We have to use this strange scheme because we want to hide the |
471 | | * internal data but have a variable sized buffer. |
472 | | * |
473 | | * +---+------+---........------+-------------+ |
474 | | * !ctx! bctl ! buffer ! private ! |
475 | | * +---+------+---........------+-------------+ |
476 | | * ! ^ |
477 | | * !---------------------------! |
478 | | * |
479 | | * We have to make sure that private is well aligned. |
480 | | */ |
481 | 6.07k | n = offsetof (struct gcry_md_handle, buf) + bufsize; |
482 | 6.07k | n = ((n + sizeof (PROPERLY_ALIGNED_TYPE) - 1) |
483 | 6.07k | / sizeof (PROPERLY_ALIGNED_TYPE)) * sizeof (PROPERLY_ALIGNED_TYPE); |
484 | | |
485 | | /* Allocate and set the Context pointer to the private data */ |
486 | 6.07k | if (secure) |
487 | 1.35k | hd = xtrymalloc_secure (n + sizeof (struct gcry_md_context)); |
488 | 4.72k | else |
489 | 4.72k | hd = xtrymalloc (n + sizeof (struct gcry_md_context)); |
490 | | |
491 | 6.07k | if (! hd) |
492 | 0 | err = gpg_err_code_from_errno (errno); |
493 | | |
494 | 6.07k | if (! err) |
495 | 6.07k | { |
496 | 6.07k | struct gcry_md_context *ctx; |
497 | | |
498 | 6.07k | ctx = (void *) (hd->buf - offsetof (struct gcry_md_handle, buf) + n); |
499 | | /* Setup the globally visible data (bctl in the diagram).*/ |
500 | 6.07k | hd->ctx = ctx; |
501 | 6.07k | hd->bufsize = n - offsetof (struct gcry_md_handle, buf); |
502 | 6.07k | hd->bufpos = 0; |
503 | | |
504 | | /* Initialize the private data. */ |
505 | 6.07k | wipememory2 (ctx, 0, sizeof *ctx); |
506 | 6.07k | ctx->magic = secure ? CTX_MAGIC_SECURE : CTX_MAGIC_NORMAL; |
507 | 6.07k | ctx->actual_handle_size = n + sizeof (struct gcry_md_context); |
508 | 6.07k | ctx->flags.secure = secure; |
509 | 6.07k | ctx->flags.hmac = hmac; |
510 | 6.07k | ctx->flags.bugemu1 = !!(flags & GCRY_MD_FLAG_BUGEMU1); |
511 | 6.07k | } |
512 | | |
513 | 6.07k | if (! err) |
514 | 6.07k | { |
515 | | /* Hmmm, should we really do that? - yes [-wk] */ |
516 | 6.07k | _gcry_fast_random_poll (); |
517 | | |
518 | 6.07k | if (algo) |
519 | 6.07k | { |
520 | 6.07k | err = md_enable (hd, algo); |
521 | 6.07k | if (err) |
522 | 0 | md_close (hd); |
523 | 6.07k | } |
524 | 6.07k | } |
525 | | |
526 | 6.07k | if (! err) |
527 | 6.07k | *h = hd; |
528 | | |
529 | 6.07k | return err; |
530 | 6.07k | } |
531 | | |
532 | | /* Create a message digest object for algorithm ALGO. FLAGS may be |
533 | | given as an bitwise OR of the gcry_md_flags values. ALGO may be |
534 | | given as 0 if the algorithms to be used are later set using |
535 | | gcry_md_enable. H is guaranteed to be a valid handle or NULL on |
536 | | error. */ |
537 | | gcry_err_code_t |
538 | | _gcry_md_open (gcry_md_hd_t *h, int algo, unsigned int flags) |
539 | 5.59k | { |
540 | 5.59k | gcry_err_code_t rc; |
541 | 5.59k | gcry_md_hd_t hd; |
542 | | |
543 | 5.59k | if ((flags & ~(GCRY_MD_FLAG_SECURE |
544 | 5.59k | | GCRY_MD_FLAG_HMAC |
545 | 5.59k | | GCRY_MD_FLAG_BUGEMU1))) |
546 | 0 | rc = GPG_ERR_INV_ARG; |
547 | 5.59k | else |
548 | 5.59k | rc = md_open (&hd, algo, flags); |
549 | | |
550 | 5.59k | *h = rc? NULL : hd; |
551 | 5.59k | return rc; |
552 | 5.59k | } |
553 | | |
554 | | |
555 | | |
556 | | static gcry_err_code_t |
557 | | md_enable (gcry_md_hd_t hd, int algorithm) |
558 | 6.07k | { |
559 | 6.07k | struct gcry_md_context *h = hd->ctx; |
560 | 6.07k | const gcry_md_spec_t *spec; |
561 | 6.07k | GcryDigestEntry *entry; |
562 | 6.07k | gcry_err_code_t err = 0; |
563 | | |
564 | 6.07k | for (entry = h->list; entry; entry = entry->next) |
565 | 0 | if (entry->spec->algo == algorithm) |
566 | 0 | return 0; /* Already enabled */ |
567 | | |
568 | 6.07k | spec = spec_from_algo (algorithm); |
569 | 6.07k | if (!spec) |
570 | 0 | { |
571 | 0 | log_debug ("md_enable: algorithm %d not available\n", algorithm); |
572 | 0 | err = GPG_ERR_DIGEST_ALGO; |
573 | 0 | } |
574 | | |
575 | 6.07k | if (!err && spec->flags.disabled) |
576 | 0 | err = GPG_ERR_DIGEST_ALGO; |
577 | | |
578 | | /* Any non-FIPS algorithm should go this way */ |
579 | 6.07k | if (!err && !spec->flags.fips && fips_mode ()) |
580 | 0 | err = GPG_ERR_DIGEST_ALGO; |
581 | | |
582 | 6.07k | if (!err && h->flags.hmac && spec->read == NULL) |
583 | 0 | { |
584 | | /* Expandable output function cannot act as part of HMAC. */ |
585 | 0 | err = GPG_ERR_DIGEST_ALGO; |
586 | 0 | } |
587 | | |
588 | 6.07k | if (!err) |
589 | 6.07k | { |
590 | 6.07k | size_t size = (sizeof (*entry) |
591 | 6.07k | + spec->contextsize * (h->flags.hmac? 3 : 1) |
592 | 6.07k | - sizeof (entry->context)); |
593 | | |
594 | | /* And allocate a new list entry. */ |
595 | 6.07k | if (h->flags.secure) |
596 | 1.35k | entry = xtrymalloc_secure (size); |
597 | 4.72k | else |
598 | 4.72k | entry = xtrymalloc (size); |
599 | | |
600 | 6.07k | if (! entry) |
601 | 0 | err = gpg_err_code_from_errno (errno); |
602 | 6.07k | else |
603 | 6.07k | { |
604 | 6.07k | entry->spec = spec; |
605 | 6.07k | entry->next = h->list; |
606 | 6.07k | entry->actual_struct_size = size; |
607 | 6.07k | h->list = entry; |
608 | | |
609 | | /* And init this instance. */ |
610 | 6.07k | entry->spec->init (entry->context, |
611 | 6.07k | h->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0); |
612 | 6.07k | } |
613 | 6.07k | } |
614 | | |
615 | 6.07k | return err; |
616 | 6.07k | } |
617 | | |
618 | | |
619 | | gcry_err_code_t |
620 | | _gcry_md_enable (gcry_md_hd_t hd, int algorithm) |
621 | 0 | { |
622 | 0 | return md_enable (hd, algorithm); |
623 | 0 | } |
624 | | |
625 | | |
626 | | static gcry_err_code_t |
627 | | md_copy (gcry_md_hd_t ahd, gcry_md_hd_t *b_hd) |
628 | 580 | { |
629 | 580 | gcry_err_code_t err = 0; |
630 | 580 | struct gcry_md_context *a = ahd->ctx; |
631 | 580 | struct gcry_md_context *b; |
632 | 580 | GcryDigestEntry *ar, *br; |
633 | 580 | gcry_md_hd_t bhd; |
634 | 580 | size_t n; |
635 | | |
636 | 580 | if (ahd->bufpos) |
637 | 465 | md_write (ahd, NULL, 0); |
638 | | |
639 | 580 | n = (char *) ahd->ctx - (char *) ahd; |
640 | 580 | if (a->flags.secure) |
641 | 526 | bhd = xtrymalloc_secure (n + sizeof (struct gcry_md_context)); |
642 | 54 | else |
643 | 54 | bhd = xtrymalloc (n + sizeof (struct gcry_md_context)); |
644 | | |
645 | 580 | if (!bhd) |
646 | 0 | { |
647 | 0 | err = gpg_err_code_from_syserror (); |
648 | 0 | goto leave; |
649 | 0 | } |
650 | | |
651 | 580 | bhd->ctx = b = (void *) ((char *) bhd + n); |
652 | | /* No need to copy the buffer due to the write above. */ |
653 | 580 | gcry_assert (ahd->bufsize == (n - offsetof (struct gcry_md_handle, buf))); |
654 | 0 | bhd->bufsize = ahd->bufsize; |
655 | 580 | bhd->bufpos = 0; |
656 | 580 | gcry_assert (! ahd->bufpos); |
657 | 0 | memcpy (b, a, sizeof *a); |
658 | 580 | b->list = NULL; |
659 | 580 | b->debug = NULL; |
660 | | |
661 | | /* Copy the complete list of algorithms. The copied list is |
662 | | reversed, but that doesn't matter. */ |
663 | 1.16k | for (ar = a->list; ar; ar = ar->next) |
664 | 580 | { |
665 | 580 | if (a->flags.secure) |
666 | 526 | br = xtrymalloc_secure (ar->actual_struct_size); |
667 | 54 | else |
668 | 54 | br = xtrymalloc (ar->actual_struct_size); |
669 | 580 | if (!br) |
670 | 0 | { |
671 | 0 | err = gpg_err_code_from_syserror (); |
672 | 0 | md_close (bhd); |
673 | 0 | goto leave; |
674 | 0 | } |
675 | | |
676 | 580 | memcpy (br, ar, ar->actual_struct_size); |
677 | 580 | br->next = b->list; |
678 | 580 | b->list = br; |
679 | 580 | } |
680 | | |
681 | 580 | if (a->debug) |
682 | 0 | md_start_debug (bhd, "unknown"); |
683 | | |
684 | 580 | *b_hd = bhd; |
685 | | |
686 | 580 | leave: |
687 | 580 | return err; |
688 | 580 | } |
689 | | |
690 | | |
691 | | gcry_err_code_t |
692 | | _gcry_md_copy (gcry_md_hd_t *handle, gcry_md_hd_t hd) |
693 | 580 | { |
694 | 580 | gcry_err_code_t rc; |
695 | | |
696 | 580 | rc = md_copy (hd, handle); |
697 | 580 | if (rc) |
698 | 0 | *handle = NULL; |
699 | 580 | return rc; |
700 | 580 | } |
701 | | |
702 | | |
703 | | /* |
704 | | * Reset all contexts and discard any buffered stuff. This may be used |
705 | | * instead of a md_close(); md_open(). |
706 | | */ |
707 | | void |
708 | | _gcry_md_reset (gcry_md_hd_t a) |
709 | 134k | { |
710 | 134k | GcryDigestEntry *r; |
711 | | |
712 | | /* Note: We allow this even in fips non operational mode. */ |
713 | | |
714 | 134k | a->bufpos = a->ctx->flags.finalized = 0; |
715 | | |
716 | 134k | if (a->ctx->flags.hmac) |
717 | 245k | for (r = a->ctx->list; r; r = r->next) |
718 | 122k | { |
719 | 122k | memcpy (r->context, (char *)r->context + r->spec->contextsize, |
720 | 122k | r->spec->contextsize); |
721 | 122k | } |
722 | 11.4k | else |
723 | 22.9k | for (r = a->ctx->list; r; r = r->next) |
724 | 11.4k | { |
725 | 11.4k | memset (r->context, 0, r->spec->contextsize); |
726 | 11.4k | (*r->spec->init) (r->context, |
727 | 11.4k | a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0); |
728 | 11.4k | } |
729 | 134k | } |
730 | | |
731 | | |
732 | | static void |
733 | | md_close (gcry_md_hd_t a) |
734 | 6.65k | { |
735 | 6.65k | GcryDigestEntry *r, *r2; |
736 | | |
737 | 6.65k | if (! a) |
738 | 1 | return; |
739 | 6.65k | if (a->ctx->debug) |
740 | 0 | md_stop_debug (a); |
741 | 13.3k | for (r = a->ctx->list; r; r = r2) |
742 | 6.65k | { |
743 | 6.65k | r2 = r->next; |
744 | 6.65k | wipememory (r, r->actual_struct_size); |
745 | 6.65k | xfree (r); |
746 | 6.65k | } |
747 | | |
748 | 6.65k | wipememory (a, a->ctx->actual_handle_size); |
749 | 6.65k | xfree(a); |
750 | 6.65k | } |
751 | | |
752 | | |
753 | | void |
754 | | _gcry_md_close (gcry_md_hd_t hd) |
755 | 6.17k | { |
756 | | /* Note: We allow this even in fips non operational mode. */ |
757 | 6.17k | md_close (hd); |
758 | 6.17k | } |
759 | | |
760 | | |
761 | | static void |
762 | | md_write (gcry_md_hd_t a, const void *inbuf, size_t inlen) |
763 | 887k | { |
764 | 887k | GcryDigestEntry *r; |
765 | | |
766 | 887k | if (a->ctx->debug) |
767 | 0 | { |
768 | 0 | if (a->bufpos && fwrite (a->buf, a->bufpos, 1, a->ctx->debug) != 1) |
769 | 0 | BUG(); |
770 | 0 | if (inlen && fwrite (inbuf, inlen, 1, a->ctx->debug) != 1) |
771 | 0 | BUG(); |
772 | 0 | } |
773 | | |
774 | 1.77M | for (r = a->ctx->list; r; r = r->next) |
775 | 887k | { |
776 | 887k | if (a->bufpos) |
777 | 570 | (*r->spec->write) (r->context, a->buf, a->bufpos); |
778 | 887k | (*r->spec->write) (r->context, inbuf, inlen); |
779 | 887k | } |
780 | 887k | a->bufpos = 0; |
781 | 887k | } |
782 | | |
783 | | |
784 | | /* Note that this function may be used after finalize and read to keep |
785 | | on writing to the transform function so to mitigate timing |
786 | | attacks. */ |
787 | | void |
788 | | _gcry_md_write (gcry_md_hd_t hd, const void *inbuf, size_t inlen) |
789 | 886k | { |
790 | 886k | md_write (hd, inbuf, inlen); |
791 | 886k | } |
792 | | |
793 | | |
794 | | static void |
795 | | md_final (gcry_md_hd_t a) |
796 | 147k | { |
797 | 147k | GcryDigestEntry *r; |
798 | | |
799 | 147k | if (a->ctx->flags.finalized) |
800 | 11.9k | return; |
801 | | |
802 | 135k | if (a->bufpos) |
803 | 5 | md_write (a, NULL, 0); |
804 | | |
805 | 270k | for (r = a->ctx->list; r; r = r->next) |
806 | 135k | (*r->spec->final) (r->context); |
807 | | |
808 | 135k | a->ctx->flags.finalized = 1; |
809 | | |
810 | 135k | if (!a->ctx->flags.hmac) |
811 | 14.3k | return; |
812 | | |
813 | 242k | for (r = a->ctx->list; r; r = r->next) |
814 | 121k | { |
815 | 121k | byte *p; |
816 | 121k | size_t dlen = r->spec->mdlen; |
817 | 121k | byte *hash; |
818 | 121k | gcry_err_code_t err; |
819 | | |
820 | 121k | if (r->spec->read == NULL) |
821 | 0 | continue; |
822 | | |
823 | 121k | p = r->spec->read (r->context); |
824 | | |
825 | 121k | if (a->ctx->flags.secure) |
826 | 982 | hash = xtrymalloc_secure (dlen); |
827 | 120k | else |
828 | 120k | hash = xtrymalloc (dlen); |
829 | 121k | if (!hash) |
830 | 0 | { |
831 | 0 | err = gpg_err_code_from_errno (errno); |
832 | 0 | _gcry_fatal_error (err, NULL); |
833 | 0 | } |
834 | | |
835 | 121k | memcpy (hash, p, dlen); |
836 | 121k | memcpy (r->context, (char *)r->context + r->spec->contextsize * 2, |
837 | 121k | r->spec->contextsize); |
838 | 121k | (*r->spec->write) (r->context, hash, dlen); |
839 | 121k | (*r->spec->final) (r->context); |
840 | 121k | xfree (hash); |
841 | 121k | } |
842 | 121k | } |
843 | | |
844 | | |
845 | | static gcry_err_code_t |
846 | | md_setkey (gcry_md_hd_t h, const unsigned char *key, size_t keylen) |
847 | 0 | { |
848 | 0 | gcry_err_code_t rc = 0; |
849 | 0 | GcryDigestEntry *r; |
850 | 0 | int algo_had_setkey = 0; |
851 | |
|
852 | 0 | if (!h->ctx->list) |
853 | 0 | return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */ |
854 | | |
855 | 0 | if (h->ctx->flags.hmac) |
856 | 0 | return GPG_ERR_DIGEST_ALGO; /* Tried md_setkey for HMAC md. */ |
857 | | |
858 | 0 | for (r = h->ctx->list; r; r = r->next) |
859 | 0 | { |
860 | 0 | switch (r->spec->algo) |
861 | 0 | { |
862 | 0 | #if USE_BLAKE2 |
863 | | /* TODO? add spec->init_with_key? */ |
864 | 0 | case GCRY_MD_BLAKE2B_512: |
865 | 0 | case GCRY_MD_BLAKE2B_384: |
866 | 0 | case GCRY_MD_BLAKE2B_256: |
867 | 0 | case GCRY_MD_BLAKE2B_160: |
868 | 0 | case GCRY_MD_BLAKE2S_256: |
869 | 0 | case GCRY_MD_BLAKE2S_224: |
870 | 0 | case GCRY_MD_BLAKE2S_160: |
871 | 0 | case GCRY_MD_BLAKE2S_128: |
872 | 0 | algo_had_setkey = 1; |
873 | 0 | memset (r->context, 0, r->spec->contextsize); |
874 | 0 | rc = _gcry_blake2_init_with_key (r->context, |
875 | 0 | h->ctx->flags.bugemu1 |
876 | 0 | ? GCRY_MD_FLAG_BUGEMU1:0, |
877 | 0 | key, keylen, r->spec->algo); |
878 | 0 | break; |
879 | 0 | #endif |
880 | 0 | default: |
881 | 0 | rc = GPG_ERR_DIGEST_ALGO; |
882 | 0 | break; |
883 | 0 | } |
884 | | |
885 | 0 | if (rc) |
886 | 0 | break; |
887 | 0 | } |
888 | | |
889 | 0 | if (rc && !algo_had_setkey) |
890 | 0 | { |
891 | | /* None of algorithms had setkey implementation, so contexts were not |
892 | | * modified. Just return error. */ |
893 | 0 | return rc; |
894 | 0 | } |
895 | 0 | else if (rc && algo_had_setkey) |
896 | 0 | { |
897 | | /* Some of the contexts have been modified, but got error. Reset |
898 | | * all contexts. */ |
899 | 0 | _gcry_md_reset (h); |
900 | 0 | return rc; |
901 | 0 | } |
902 | | |
903 | | /* Successful md_setkey implies reset. */ |
904 | 0 | h->bufpos = h->ctx->flags.finalized = 0; |
905 | |
|
906 | 0 | return 0; |
907 | 0 | } |
908 | | |
909 | | |
910 | | static gcry_err_code_t |
911 | | prepare_macpads (gcry_md_hd_t a, const unsigned char *key, size_t keylen) |
912 | 4.06k | { |
913 | 4.06k | GcryDigestEntry *r; |
914 | | |
915 | 4.06k | if (!a->ctx->list) |
916 | 0 | return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */ |
917 | | |
918 | 4.06k | if (!a->ctx->flags.hmac) |
919 | 0 | return GPG_ERR_DIGEST_ALGO; /* Tried prepare_macpads for non-HMAC md. */ |
920 | | |
921 | 8.13k | for (r = a->ctx->list; r; r = r->next) |
922 | 4.06k | { |
923 | 4.06k | const unsigned char *k; |
924 | 4.06k | size_t k_len; |
925 | 4.06k | unsigned char *key_allocated = NULL; |
926 | 4.06k | int macpad_Bsize; |
927 | 4.06k | int i; |
928 | | |
929 | 4.06k | switch (r->spec->algo) |
930 | 4.06k | { |
931 | | /* TODO: add spec->blocksize */ |
932 | 111 | case GCRY_MD_SHA3_224: |
933 | 111 | macpad_Bsize = 1152 / 8; |
934 | 111 | break; |
935 | 68 | case GCRY_MD_SHA3_256: |
936 | 68 | macpad_Bsize = 1088 / 8; |
937 | 68 | break; |
938 | 74 | case GCRY_MD_SHA3_384: |
939 | 74 | macpad_Bsize = 832 / 8; |
940 | 74 | break; |
941 | 103 | case GCRY_MD_SHA3_512: |
942 | 103 | macpad_Bsize = 576 / 8; |
943 | 103 | break; |
944 | 184 | case GCRY_MD_SHA384: |
945 | 454 | case GCRY_MD_SHA512: |
946 | 555 | case GCRY_MD_SHA512_256: |
947 | 617 | case GCRY_MD_SHA512_224: |
948 | 772 | case GCRY_MD_BLAKE2B_512: |
949 | 796 | case GCRY_MD_BLAKE2B_384: |
950 | 836 | case GCRY_MD_BLAKE2B_256: |
951 | 888 | case GCRY_MD_BLAKE2B_160: |
952 | 888 | macpad_Bsize = 128; |
953 | 888 | break; |
954 | 0 | case GCRY_MD_GOSTR3411_94: |
955 | 90 | case GCRY_MD_GOSTR3411_CP: |
956 | 90 | macpad_Bsize = 32; |
957 | 90 | break; |
958 | 2.73k | default: |
959 | 2.73k | macpad_Bsize = 64; |
960 | 2.73k | break; |
961 | 4.06k | } |
962 | | |
963 | 4.06k | if ( keylen > macpad_Bsize ) |
964 | 1.63k | { |
965 | 1.63k | k = key_allocated = xtrymalloc_secure (r->spec->mdlen); |
966 | 1.63k | if (!k) |
967 | 0 | return gpg_err_code_from_errno (errno); |
968 | 1.63k | _gcry_md_hash_buffer (r->spec->algo, key_allocated, key, keylen); |
969 | 1.63k | k_len = r->spec->mdlen; |
970 | 1.63k | gcry_assert ( k_len <= macpad_Bsize ); |
971 | 1.63k | } |
972 | 2.42k | else |
973 | 2.42k | { |
974 | 2.42k | k = key; |
975 | 2.42k | k_len = keylen; |
976 | 2.42k | } |
977 | | |
978 | 4.06k | (*r->spec->init) (r->context, |
979 | 4.06k | a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0); |
980 | 4.06k | a->bufpos = 0; |
981 | 121k | for (i=0; i < k_len; i++ ) |
982 | 117k | _gcry_md_putc (a, k[i] ^ 0x36); |
983 | 218k | for (; i < macpad_Bsize; i++ ) |
984 | 214k | _gcry_md_putc (a, 0x36); |
985 | 4.06k | (*r->spec->write) (r->context, a->buf, a->bufpos); |
986 | 4.06k | memcpy ((char *)r->context + r->spec->contextsize, r->context, |
987 | 4.06k | r->spec->contextsize); |
988 | | |
989 | 4.06k | (*r->spec->init) (r->context, |
990 | 4.06k | a->ctx->flags.bugemu1? GCRY_MD_FLAG_BUGEMU1:0); |
991 | 4.06k | a->bufpos = 0; |
992 | 121k | for (i=0; i < k_len; i++ ) |
993 | 117k | _gcry_md_putc (a, k[i] ^ 0x5c); |
994 | 218k | for (; i < macpad_Bsize; i++ ) |
995 | 214k | _gcry_md_putc (a, 0x5c); |
996 | 4.06k | (*r->spec->write) (r->context, a->buf, a->bufpos); |
997 | 4.06k | memcpy ((char *)r->context + r->spec->contextsize*2, r->context, |
998 | 4.06k | r->spec->contextsize); |
999 | | |
1000 | 4.06k | xfree (key_allocated); |
1001 | 4.06k | } |
1002 | | |
1003 | 4.06k | a->bufpos = 0; |
1004 | 4.06k | return 0; |
1005 | 4.06k | } |
1006 | | |
1007 | | |
1008 | | static gcry_err_code_t |
1009 | | md_customize (gcry_md_hd_t h, void *buffer, size_t buflen) |
1010 | 0 | { |
1011 | 0 | gcry_err_code_t rc = 0; |
1012 | 0 | GcryDigestEntry *r; |
1013 | 0 | int algo_had_customize = 0; |
1014 | |
|
1015 | 0 | if (!h->ctx->list) |
1016 | 0 | return GPG_ERR_DIGEST_ALGO; /* Might happen if no algo is enabled. */ |
1017 | | |
1018 | 0 | for (r = h->ctx->list; r; r = r->next) |
1019 | 0 | { |
1020 | 0 | switch (r->spec->algo) |
1021 | 0 | { |
1022 | 0 | case GCRY_MD_CSHAKE128: |
1023 | 0 | case GCRY_MD_CSHAKE256: |
1024 | 0 | algo_had_customize = 1; |
1025 | 0 | if (buflen != sizeof (struct gcry_cshake_customization)) |
1026 | 0 | rc = GPG_ERR_INV_ARG; |
1027 | 0 | else |
1028 | 0 | rc = _gcry_cshake_customize (r->context, buffer); |
1029 | 0 | break; |
1030 | 0 | default: |
1031 | 0 | rc = GPG_ERR_DIGEST_ALGO; |
1032 | 0 | break; |
1033 | 0 | } |
1034 | | |
1035 | 0 | if (rc) |
1036 | 0 | break; |
1037 | 0 | } |
1038 | | |
1039 | 0 | if (rc && !algo_had_customize) |
1040 | 0 | { |
1041 | | /* None of algorithms had customize implementation, so contexts were not |
1042 | | * modified. Just return error. */ |
1043 | 0 | return rc; |
1044 | 0 | } |
1045 | 0 | else if (rc && algo_had_customize) |
1046 | 0 | { |
1047 | | /* Some of the contexts have been modified, but got error. Reset |
1048 | | * all contexts. */ |
1049 | 0 | _gcry_md_reset (h); |
1050 | 0 | return rc; |
1051 | 0 | } |
1052 | | |
1053 | 0 | return 0; |
1054 | 0 | } |
1055 | | |
1056 | | |
1057 | | gcry_err_code_t |
1058 | | _gcry_md_ctl (gcry_md_hd_t hd, int cmd, void *buffer, size_t buflen) |
1059 | 146k | { |
1060 | 146k | gcry_err_code_t rc = 0; |
1061 | | |
1062 | 146k | (void)buflen; /* Currently not used. */ |
1063 | | |
1064 | 146k | switch (cmd) |
1065 | 146k | { |
1066 | 146k | case GCRYCTL_FINALIZE: |
1067 | 146k | md_final (hd); |
1068 | 146k | break; |
1069 | 0 | case GCRYCTL_START_DUMP: |
1070 | 0 | md_start_debug (hd, buffer); |
1071 | 0 | break; |
1072 | 0 | case GCRYCTL_STOP_DUMP: |
1073 | 0 | md_stop_debug ( hd ); |
1074 | 0 | break; |
1075 | 0 | case GCRYCTL_MD_CUSTOMIZE: |
1076 | 0 | rc = md_customize (hd, buffer, buflen); |
1077 | 0 | break; |
1078 | 0 | default: |
1079 | 0 | rc = GPG_ERR_INV_OP; |
1080 | 146k | } |
1081 | 146k | return rc; |
1082 | 146k | } |
1083 | | |
1084 | | |
1085 | | gcry_err_code_t |
1086 | | _gcry_md_setkey (gcry_md_hd_t hd, const void *key, size_t keylen) |
1087 | 4.06k | { |
1088 | 4.06k | gcry_err_code_t rc; |
1089 | | |
1090 | 4.06k | if (hd->ctx->flags.hmac) |
1091 | 4.06k | { |
1092 | 4.06k | rc = prepare_macpads (hd, key, keylen); |
1093 | 4.06k | if (!rc) |
1094 | 4.06k | _gcry_md_reset (hd); |
1095 | 4.06k | } |
1096 | 0 | else |
1097 | 0 | { |
1098 | 0 | rc = md_setkey (hd, key, keylen); |
1099 | 0 | } |
1100 | | |
1101 | 4.06k | return rc; |
1102 | 4.06k | } |
1103 | | |
1104 | | |
1105 | | /* The new debug interface. If SUFFIX is a string it creates an debug |
1106 | | file for the context HD. IF suffix is NULL, the file is closed and |
1107 | | debugging is stopped. */ |
1108 | | void |
1109 | | _gcry_md_debug (gcry_md_hd_t hd, const char *suffix) |
1110 | 0 | { |
1111 | 0 | if (suffix) |
1112 | 0 | md_start_debug (hd, suffix); |
1113 | 0 | else |
1114 | 0 | md_stop_debug (hd); |
1115 | 0 | } |
1116 | | |
1117 | | |
1118 | | /**************** |
1119 | | * If ALGO is null get the digest for the used algo (which should be |
1120 | | * only one) |
1121 | | */ |
1122 | | static byte * |
1123 | | md_read( gcry_md_hd_t a, int algo ) |
1124 | 135k | { |
1125 | 135k | GcryDigestEntry *r = a->ctx->list; |
1126 | | |
1127 | 135k | if (! algo) |
1128 | 73.4k | { |
1129 | | /* Return the first algorithm */ |
1130 | 73.4k | if (r) |
1131 | 73.4k | { |
1132 | 73.4k | if (r->next) |
1133 | 0 | log_debug ("more than one algorithm in md_read(0)\n"); |
1134 | 73.4k | if (r->spec->read) |
1135 | 73.4k | return r->spec->read (r->context); |
1136 | 73.4k | } |
1137 | 73.4k | } |
1138 | 61.8k | else |
1139 | 61.8k | { |
1140 | 61.8k | for (r = a->ctx->list; r; r = r->next) |
1141 | 61.8k | if (r->spec->algo == algo) |
1142 | 61.8k | { |
1143 | 61.8k | if (r->spec->read) |
1144 | 61.8k | return r->spec->read (r->context); |
1145 | 0 | break; |
1146 | 61.8k | } |
1147 | 61.8k | } |
1148 | | |
1149 | 0 | if (r && !r->spec->read) |
1150 | 0 | _gcry_fatal_error (GPG_ERR_DIGEST_ALGO, |
1151 | 0 | "requested algo has no fixed digest length"); |
1152 | 0 | else |
1153 | 0 | _gcry_fatal_error (GPG_ERR_DIGEST_ALGO, "requested algo not in md context"); |
1154 | 0 | return NULL; |
1155 | 0 | } |
1156 | | |
1157 | | |
1158 | | /* |
1159 | | * Read out the complete digest, this function implictly finalizes |
1160 | | * the hash. |
1161 | | */ |
1162 | | byte * |
1163 | | _gcry_md_read (gcry_md_hd_t hd, int algo) |
1164 | 134k | { |
1165 | | /* This function is expected to always return a digest, thus we |
1166 | | can't return an error which we actually should do in |
1167 | | non-operational state. */ |
1168 | 134k | _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); |
1169 | 134k | return md_read (hd, algo); |
1170 | 134k | } |
1171 | | |
1172 | | |
1173 | | /**************** |
1174 | | * If ALGO is null get the digest for the used algo (which should be |
1175 | | * only one) |
1176 | | */ |
1177 | | static gcry_err_code_t |
1178 | | md_extract(gcry_md_hd_t a, int algo, void *out, size_t outlen) |
1179 | 126 | { |
1180 | 126 | GcryDigestEntry *r = a->ctx->list; |
1181 | | |
1182 | 126 | if (!algo) |
1183 | 0 | { |
1184 | | /* Return the first algorithm */ |
1185 | 0 | if (r && r->spec->extract) |
1186 | 0 | { |
1187 | 0 | if (r->next) |
1188 | 0 | log_debug ("more than one algorithm in md_extract(0)\n"); |
1189 | |
|
1190 | 0 | return r->spec->extract (r->context, out, outlen); |
1191 | 0 | } |
1192 | 0 | } |
1193 | 126 | else |
1194 | 126 | { |
1195 | 126 | for (r = a->ctx->list; r; r = r->next) |
1196 | 126 | if (r->spec->algo == algo && r->spec->extract) |
1197 | 126 | { |
1198 | 126 | return r->spec->extract (r->context, out, outlen); |
1199 | 126 | } |
1200 | 126 | } |
1201 | | |
1202 | 0 | return GPG_ERR_DIGEST_ALGO; |
1203 | 126 | } |
1204 | | |
1205 | | |
1206 | | /* |
1207 | | * Expand the output from XOF class digest, this function implictly finalizes |
1208 | | * the hash. |
1209 | | */ |
1210 | | gcry_err_code_t |
1211 | | _gcry_md_extract (gcry_md_hd_t hd, int algo, void *out, size_t outlen) |
1212 | 126 | { |
1213 | 126 | _gcry_md_ctl (hd, GCRYCTL_FINALIZE, NULL, 0); |
1214 | 126 | return md_extract (hd, algo, out, outlen); |
1215 | 126 | } |
1216 | | |
1217 | | |
1218 | | /* |
1219 | | * Read out an intermediate digest. Not yet functional. |
1220 | | */ |
1221 | | gcry_err_code_t |
1222 | | _gcry_md_get (gcry_md_hd_t hd, int algo, byte *buffer, int buflen) |
1223 | 0 | { |
1224 | 0 | (void)hd; |
1225 | 0 | (void)algo; |
1226 | 0 | (void)buffer; |
1227 | 0 | (void)buflen; |
1228 | | |
1229 | | /*md_digest ... */ |
1230 | 0 | fips_signal_error ("unimplemented function called"); |
1231 | 0 | return GPG_ERR_INTERNAL; |
1232 | 0 | } |
1233 | | |
1234 | | |
1235 | | /* |
1236 | | * Shortcut function to hash a buffer with a given algo. The only |
1237 | | * guaranteed supported algorithms are RIPE-MD160 and SHA-1. The |
1238 | | * supplied digest buffer must be large enough to store the resulting |
1239 | | * hash. No error is returned, the function will abort on an invalid |
1240 | | * algo. DISABLED_ALGOS are ignored here. */ |
1241 | | void |
1242 | | _gcry_md_hash_buffer (int algo, void *digest, |
1243 | | const void *buffer, size_t length) |
1244 | 1.63k | { |
1245 | 1.63k | const gcry_md_spec_t *spec; |
1246 | | |
1247 | 1.63k | spec = spec_from_algo (algo); |
1248 | 1.63k | if (!spec) |
1249 | 0 | { |
1250 | 0 | log_debug ("md_hash_buffer: algorithm %d not available\n", algo); |
1251 | 0 | return; |
1252 | 0 | } |
1253 | | |
1254 | 1.63k | if (spec->hash_buffers != NULL) |
1255 | 1.16k | { |
1256 | 1.16k | gcry_buffer_t iov; |
1257 | | |
1258 | 1.16k | iov.size = 0; |
1259 | 1.16k | iov.data = (void *)buffer; |
1260 | 1.16k | iov.off = 0; |
1261 | 1.16k | iov.len = length; |
1262 | | |
1263 | 1.16k | if (spec->flags.disabled || (!spec->flags.fips && fips_mode ())) |
1264 | 0 | log_bug ("gcry_md_hash_buffer failed for algo %d: %s", |
1265 | 0 | algo, gpg_strerror (gcry_error (GPG_ERR_DIGEST_ALGO))); |
1266 | | |
1267 | 1.16k | spec->hash_buffers (digest, spec->mdlen, &iov, 1); |
1268 | 1.16k | } |
1269 | 477 | else |
1270 | 477 | { |
1271 | | /* For the others we do not have a fast function, so we use the |
1272 | | normal functions. */ |
1273 | 477 | gcry_md_hd_t h; |
1274 | 477 | gpg_err_code_t err; |
1275 | | |
1276 | 477 | err = md_open (&h, algo, 0); |
1277 | 477 | if (err) |
1278 | 0 | log_bug ("gcry_md_open failed for algo %d: %s", |
1279 | 0 | algo, gpg_strerror (gcry_error(err))); |
1280 | 477 | md_write (h, (byte *) buffer, length); |
1281 | 477 | md_final (h); |
1282 | 477 | memcpy (digest, md_read (h, algo), md_digest_length (algo)); |
1283 | 477 | md_close (h); |
1284 | 477 | } |
1285 | 1.63k | } |
1286 | | |
1287 | | |
1288 | | /* Shortcut function to hash multiple buffers with a given algo. In |
1289 | | contrast to gcry_md_hash_buffer, this function returns an error on |
1290 | | invalid arguments or on other problems; disabled algorithms are |
1291 | | _not_ ignored but flagged as an error. |
1292 | | |
1293 | | The data to sign is taken from the array IOV which has IOVCNT items. |
1294 | | |
1295 | | The only supported flag in FLAGS is GCRY_MD_FLAG_HMAC which turns |
1296 | | this function into a HMAC function; the first item in IOV is then |
1297 | | used as the key. |
1298 | | |
1299 | | On success 0 is returned and resulting hash or HMAC is stored at |
1300 | | DIGEST. DIGESTLEN may be given as -1, in which case DIGEST must |
1301 | | have been provided by the caller with an appropriate length. |
1302 | | DIGESTLEN may also be the appropriate length or, in case of XOF |
1303 | | algorithms, DIGESTLEN indicates number bytes to extract from XOF |
1304 | | to DIGEST. */ |
1305 | | gpg_err_code_t |
1306 | | _gcry_md_hash_buffers_extract (int algo, unsigned int flags, void *digest, |
1307 | | int digestlen, const gcry_buffer_t *iov, |
1308 | | int iovcnt) |
1309 | 0 | { |
1310 | 0 | const gcry_md_spec_t *spec; |
1311 | 0 | int is_xof; |
1312 | 0 | int hmac; |
1313 | |
|
1314 | 0 | if (!iov || iovcnt < 0) |
1315 | 0 | return GPG_ERR_INV_ARG; |
1316 | 0 | if (flags & ~(GCRY_MD_FLAG_HMAC)) |
1317 | 0 | return GPG_ERR_INV_ARG; |
1318 | | |
1319 | 0 | hmac = !!(flags & GCRY_MD_FLAG_HMAC); |
1320 | 0 | if (hmac && iovcnt < 1) |
1321 | 0 | return GPG_ERR_INV_ARG; |
1322 | | |
1323 | 0 | spec = spec_from_algo (algo); |
1324 | 0 | if (!spec) |
1325 | 0 | { |
1326 | 0 | log_debug ("md_hash_buffers: algorithm %d not available\n", algo); |
1327 | 0 | return GPG_ERR_DIGEST_ALGO; |
1328 | 0 | } |
1329 | | |
1330 | 0 | is_xof = spec->extract != NULL; |
1331 | 0 | if (!is_xof && digestlen != -1 && digestlen != spec->mdlen) |
1332 | 0 | return GPG_ERR_DIGEST_ALGO; |
1333 | | |
1334 | 0 | if (digestlen == -1) |
1335 | 0 | digestlen = spec->mdlen; |
1336 | |
|
1337 | 0 | if (!hmac && spec->hash_buffers) |
1338 | 0 | { |
1339 | 0 | if (spec->flags.disabled || (!spec->flags.fips && fips_mode ())) |
1340 | 0 | return GPG_ERR_DIGEST_ALGO; |
1341 | | |
1342 | 0 | spec->hash_buffers (digest, digestlen, iov, iovcnt); |
1343 | 0 | } |
1344 | 0 | else |
1345 | 0 | { |
1346 | | /* For the others we do not have a fast function, so we use the |
1347 | | normal functions. */ |
1348 | 0 | gcry_md_hd_t h; |
1349 | 0 | gpg_err_code_t rc; |
1350 | |
|
1351 | 0 | rc = md_open (&h, algo, (hmac? GCRY_MD_FLAG_HMAC:0)); |
1352 | 0 | if (rc) |
1353 | 0 | return rc; |
1354 | | |
1355 | 0 | if (hmac) |
1356 | 0 | { |
1357 | 0 | rc = _gcry_md_setkey (h, |
1358 | 0 | (const char*)iov[0].data + iov[0].off, |
1359 | 0 | iov[0].len); |
1360 | 0 | if (rc) |
1361 | 0 | { |
1362 | 0 | md_close (h); |
1363 | 0 | return rc; |
1364 | 0 | } |
1365 | 0 | iov++; iovcnt--; |
1366 | 0 | } |
1367 | 0 | for (;iovcnt; iov++, iovcnt--) |
1368 | 0 | md_write (h, (const char*)iov[0].data + iov[0].off, iov[0].len); |
1369 | 0 | md_final (h); |
1370 | 0 | if (digestlen == spec->mdlen) |
1371 | 0 | memcpy (digest, md_read (h, algo), spec->mdlen); |
1372 | 0 | else if (digestlen > 0) |
1373 | 0 | md_extract (h, algo, digest, digestlen); |
1374 | 0 | md_close (h); |
1375 | 0 | } |
1376 | | |
1377 | 0 | return 0; |
1378 | 0 | } |
1379 | | |
1380 | | |
1381 | | /* Shortcut function to hash multiple buffers with a given algo. In |
1382 | | contrast to gcry_md_hash_buffer, this function returns an error on |
1383 | | invalid arguments or on other problems; disabled algorithms are |
1384 | | _not_ ignored but flagged as an error. |
1385 | | |
1386 | | The data to sign is taken from the array IOV which has IOVCNT items. |
1387 | | |
1388 | | The only supported flag in FLAGS is GCRY_MD_FLAG_HMAC which turns |
1389 | | this function into a HMAC function; the first item in IOV is then |
1390 | | used as the key. |
1391 | | |
1392 | | On success 0 is returned and resulting hash or HMAC is stored at |
1393 | | DIGEST which must have been provided by the caller with an |
1394 | | appropriate length. */ |
1395 | | gpg_err_code_t |
1396 | | _gcry_md_hash_buffers (int algo, unsigned int flags, void *digest, |
1397 | | const gcry_buffer_t *iov, int iovcnt) |
1398 | 0 | { |
1399 | 0 | return _gcry_md_hash_buffers_extract(algo, flags, digest, -1, iov, iovcnt); |
1400 | 0 | } |
1401 | | |
1402 | | |
1403 | | static int |
1404 | | md_get_algo (gcry_md_hd_t a) |
1405 | 0 | { |
1406 | 0 | GcryDigestEntry *r = a->ctx->list; |
1407 | |
|
1408 | 0 | if (r && r->next) |
1409 | 0 | { |
1410 | 0 | fips_signal_error ("possible usage error"); |
1411 | 0 | log_error ("WARNING: more than one algorithm in md_get_algo()\n"); |
1412 | 0 | } |
1413 | 0 | return r ? r->spec->algo : 0; |
1414 | 0 | } |
1415 | | |
1416 | | |
1417 | | int |
1418 | | _gcry_md_get_algo (gcry_md_hd_t hd) |
1419 | 0 | { |
1420 | 0 | return md_get_algo (hd); |
1421 | 0 | } |
1422 | | |
1423 | | |
1424 | | /**************** |
1425 | | * Return the length of the digest |
1426 | | */ |
1427 | | static int |
1428 | | md_digest_length (int algorithm) |
1429 | 65.6k | { |
1430 | 65.6k | const gcry_md_spec_t *spec; |
1431 | | |
1432 | 65.6k | spec = spec_from_algo (algorithm); |
1433 | 65.6k | return spec? spec->mdlen : 0; |
1434 | 65.6k | } |
1435 | | |
1436 | | |
1437 | | /**************** |
1438 | | * Return the length of the digest in bytes. |
1439 | | * This function will return 0 in case of errors. |
1440 | | */ |
1441 | | unsigned int |
1442 | | _gcry_md_get_algo_dlen (int algorithm) |
1443 | 65.1k | { |
1444 | 65.1k | return md_digest_length (algorithm); |
1445 | 65.1k | } |
1446 | | |
1447 | | |
1448 | | /* Hmmm: add a mode to enumerate the OIDs |
1449 | | * to make g10/sig-check.c more portable */ |
1450 | | static const byte * |
1451 | | md_asn_oid (int algorithm, size_t *asnlen, size_t *mdlen) |
1452 | 0 | { |
1453 | 0 | const gcry_md_spec_t *spec; |
1454 | 0 | const byte *asnoid = NULL; |
1455 | |
|
1456 | 0 | spec = spec_from_algo (algorithm); |
1457 | 0 | if (spec) |
1458 | 0 | { |
1459 | 0 | if (asnlen) |
1460 | 0 | *asnlen = spec->asnlen; |
1461 | 0 | if (mdlen) |
1462 | 0 | *mdlen = spec->mdlen; |
1463 | 0 | asnoid = spec->asnoid; |
1464 | 0 | } |
1465 | 0 | else |
1466 | 0 | log_bug ("no ASN.1 OID for md algo %d\n", algorithm); |
1467 | | |
1468 | 0 | return asnoid; |
1469 | 0 | } |
1470 | | |
1471 | | |
1472 | | /**************** |
1473 | | * Return information about the given cipher algorithm |
1474 | | * WHAT select the kind of information returned: |
1475 | | * GCRYCTL_TEST_ALGO: |
1476 | | * Returns 0 when the specified algorithm is available for use. |
1477 | | * buffer and nbytes must be zero. |
1478 | | * GCRYCTL_GET_ASNOID: |
1479 | | * Return the ASNOID of the algorithm in buffer. if buffer is NULL, only |
1480 | | * the required length is returned. |
1481 | | * GCRYCTL_SELFTEST |
1482 | | * Helper for the regression tests - shall not be used by applications. |
1483 | | * |
1484 | | * Note: Because this function is in most cases used to return an |
1485 | | * integer value, we can make it easier for the caller to just look at |
1486 | | * the return value. The caller will in all cases consult the value |
1487 | | * and thereby detecting whether a error occurred or not (i.e. while checking |
1488 | | * the block size) |
1489 | | */ |
1490 | | gcry_err_code_t |
1491 | | _gcry_md_algo_info (int algo, int what, void *buffer, size_t *nbytes) |
1492 | 0 | { |
1493 | 0 | gcry_err_code_t rc; |
1494 | |
|
1495 | 0 | switch (what) |
1496 | 0 | { |
1497 | 0 | case GCRYCTL_TEST_ALGO: |
1498 | 0 | if (buffer || nbytes) |
1499 | 0 | rc = GPG_ERR_INV_ARG; |
1500 | 0 | else |
1501 | 0 | rc = check_digest_algo (algo); |
1502 | 0 | break; |
1503 | | |
1504 | 0 | case GCRYCTL_GET_ASNOID: |
1505 | | /* We need to check that the algo is available because |
1506 | | md_asn_oid would otherwise raise an assertion. */ |
1507 | 0 | rc = check_digest_algo (algo); |
1508 | 0 | if (!rc) |
1509 | 0 | { |
1510 | 0 | const char unsigned *asn; |
1511 | 0 | size_t asnlen; |
1512 | |
|
1513 | 0 | asn = md_asn_oid (algo, &asnlen, NULL); |
1514 | 0 | if (buffer && (*nbytes >= asnlen)) |
1515 | 0 | { |
1516 | 0 | memcpy (buffer, asn, asnlen); |
1517 | 0 | *nbytes = asnlen; |
1518 | 0 | } |
1519 | 0 | else if (!buffer && nbytes) |
1520 | 0 | *nbytes = asnlen; |
1521 | 0 | else |
1522 | 0 | { |
1523 | 0 | if (buffer) |
1524 | 0 | rc = GPG_ERR_TOO_SHORT; |
1525 | 0 | else |
1526 | 0 | rc = GPG_ERR_INV_ARG; |
1527 | 0 | } |
1528 | 0 | } |
1529 | 0 | break; |
1530 | | |
1531 | 0 | case GCRYCTL_SELFTEST: |
1532 | | /* Helper function for the regression tests. */ |
1533 | 0 | rc = gpg_err_code (_gcry_md_selftest (algo, nbytes? (int)*nbytes : 0, |
1534 | 0 | NULL)); |
1535 | 0 | break; |
1536 | | |
1537 | 0 | default: |
1538 | 0 | rc = GPG_ERR_INV_OP; |
1539 | 0 | break; |
1540 | 0 | } |
1541 | | |
1542 | 0 | return rc; |
1543 | 0 | } |
1544 | | |
1545 | | |
1546 | | static void |
1547 | | md_start_debug ( gcry_md_hd_t md, const char *suffix ) |
1548 | 0 | { |
1549 | 0 | static int idx=0; |
1550 | 0 | char buf[50]; |
1551 | |
|
1552 | 0 | if (fips_mode ()) |
1553 | 0 | return; |
1554 | | |
1555 | 0 | if ( md->ctx->debug ) |
1556 | 0 | { |
1557 | 0 | log_debug("Oops: md debug already started\n"); |
1558 | 0 | return; |
1559 | 0 | } |
1560 | 0 | idx++; |
1561 | 0 | snprintf (buf, DIM(buf)-1, "dbgmd-%05d.%.10s", idx, suffix ); |
1562 | 0 | md->ctx->debug = fopen(buf, "w"); |
1563 | 0 | if ( !md->ctx->debug ) |
1564 | 0 | log_debug("md debug: can't open %s\n", buf ); |
1565 | 0 | } |
1566 | | |
1567 | | |
1568 | | static void |
1569 | | md_stop_debug( gcry_md_hd_t md ) |
1570 | 0 | { |
1571 | 0 | if ( md->ctx->debug ) |
1572 | 0 | { |
1573 | 0 | if ( md->bufpos ) |
1574 | 0 | md_write ( md, NULL, 0 ); |
1575 | 0 | fclose (md->ctx->debug); |
1576 | 0 | md->ctx->debug = NULL; |
1577 | 0 | } |
1578 | |
|
1579 | 0 | { /* a kludge to pull in the __muldi3 for Solaris */ |
1580 | 0 | volatile u32 a = (u32)(uintptr_t)md; |
1581 | 0 | volatile u64 b = 42; |
1582 | 0 | volatile u64 c; |
1583 | 0 | c = a * b; |
1584 | 0 | (void)c; |
1585 | 0 | } |
1586 | 0 | } |
1587 | | |
1588 | | |
1589 | | |
1590 | | /* |
1591 | | * Return information about the digest handle. |
1592 | | * GCRYCTL_IS_SECURE: |
1593 | | * Returns 1 when the handle works on secured memory |
1594 | | * otherwise 0 is returned. There is no error return. |
1595 | | * GCRYCTL_IS_ALGO_ENABLED: |
1596 | | * Returns 1 if the algo is enabled for that handle. |
1597 | | * The algo must be passed as the address of an int. |
1598 | | */ |
1599 | | gcry_err_code_t |
1600 | | _gcry_md_info (gcry_md_hd_t h, int cmd, void *buffer, size_t *nbytes) |
1601 | 0 | { |
1602 | 0 | gcry_err_code_t rc = 0; |
1603 | |
|
1604 | 0 | switch (cmd) |
1605 | 0 | { |
1606 | 0 | case GCRYCTL_IS_SECURE: |
1607 | 0 | *nbytes = h->ctx->flags.secure; |
1608 | 0 | break; |
1609 | | |
1610 | 0 | case GCRYCTL_IS_ALGO_ENABLED: |
1611 | 0 | { |
1612 | 0 | GcryDigestEntry *r; |
1613 | 0 | int algo; |
1614 | |
|
1615 | 0 | if ( !buffer || !nbytes || *nbytes != sizeof (int)) |
1616 | 0 | rc = GPG_ERR_INV_ARG; |
1617 | 0 | else |
1618 | 0 | { |
1619 | 0 | algo = *(int*)buffer; |
1620 | |
|
1621 | 0 | *nbytes = 0; |
1622 | 0 | for(r=h->ctx->list; r; r = r->next ) { |
1623 | 0 | if (r->spec->algo == algo) |
1624 | 0 | { |
1625 | 0 | *nbytes = 1; |
1626 | 0 | break; |
1627 | 0 | } |
1628 | 0 | } |
1629 | 0 | } |
1630 | 0 | break; |
1631 | 0 | } |
1632 | | |
1633 | 0 | default: |
1634 | 0 | rc = GPG_ERR_INV_OP; |
1635 | 0 | } |
1636 | | |
1637 | 0 | return rc; |
1638 | 0 | } |
1639 | | |
1640 | | |
1641 | | /* Explicitly initialize this module. */ |
1642 | | gcry_err_code_t |
1643 | | _gcry_md_init (void) |
1644 | 10 | { |
1645 | 10 | return 0; |
1646 | 10 | } |
1647 | | |
1648 | | |
1649 | | int |
1650 | | _gcry_md_is_secure (gcry_md_hd_t a) |
1651 | 0 | { |
1652 | 0 | size_t value; |
1653 | |
|
1654 | 0 | if (_gcry_md_info (a, GCRYCTL_IS_SECURE, NULL, &value)) |
1655 | 0 | value = 1; /* It seems to be better to assume secure memory on |
1656 | | error. */ |
1657 | 0 | return value; |
1658 | 0 | } |
1659 | | |
1660 | | |
1661 | | int |
1662 | | _gcry_md_is_enabled (gcry_md_hd_t a, int algo) |
1663 | 0 | { |
1664 | 0 | size_t value; |
1665 | |
|
1666 | 0 | value = sizeof algo; |
1667 | 0 | if (_gcry_md_info (a, GCRYCTL_IS_ALGO_ENABLED, &algo, &value)) |
1668 | 0 | value = 0; |
1669 | 0 | return value; |
1670 | 0 | } |
1671 | | |
1672 | | |
1673 | | /* Run the selftests for digest algorithm ALGO with optional reporting |
1674 | | function REPORT. */ |
1675 | | gpg_error_t |
1676 | | _gcry_md_selftest (int algo, int extended, selftest_report_func_t report) |
1677 | 0 | { |
1678 | 0 | gcry_err_code_t ec = 0; |
1679 | 0 | const gcry_md_spec_t *spec; |
1680 | |
|
1681 | 0 | spec = spec_from_algo (algo); |
1682 | 0 | if (spec && !spec->flags.disabled |
1683 | 0 | && (spec->flags.fips || !fips_mode ()) |
1684 | 0 | && spec->selftest) |
1685 | 0 | ec = spec->selftest (algo, extended, report); |
1686 | 0 | else |
1687 | 0 | { |
1688 | 0 | ec = (spec && spec->selftest) ? GPG_ERR_DIGEST_ALGO |
1689 | 0 | /* */ : GPG_ERR_NOT_IMPLEMENTED; |
1690 | 0 | if (report) |
1691 | 0 | report ("digest", algo, "module", |
1692 | 0 | spec && !spec->flags.disabled |
1693 | 0 | && (spec->flags.fips || !fips_mode ())? |
1694 | 0 | "no selftest available" : |
1695 | 0 | spec? "algorithm disabled" : "algorithm not found"); |
1696 | 0 | } |
1697 | |
|
1698 | 0 | return gpg_error (ec); |
1699 | 0 | } |