1 /* module_hooks.c -- module load/unload hooks for libwolfssl.ko
2  *
3  * Copyright (C) 2006-2021 wolfSSL Inc.
4  *
5  * This file is part of wolfSSL.
6  *
7  * wolfSSL is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * wolfSSL is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20  */
21 
22 #ifndef WOLFSSL_LICENSE
23 #define WOLFSSL_LICENSE "GPL v2"
24 #endif
25 
26 #define FIPS_NO_WRAPPERS
27 
28 #define WOLFSSL_NEED_LINUX_CURRENT
29 
30 #ifdef HAVE_CONFIG_H
31     #include <config.h>
32 #endif
33 
34 #include <wolfssl/wolfcrypt/settings.h>
35 #include <wolfssl/wolfcrypt/error-crypt.h>
36 #include <wolfssl/ssl.h>
37 #ifdef HAVE_FIPS
38 #include <wolfssl/wolfcrypt/fips_test.h>
39 #endif
40 #ifndef NO_CRYPT_TEST
41 #include <wolfcrypt/test/test.h>
42 #include <linux/delay.h>
43 #endif
44 
libwolfssl_cleanup(void)45 static int libwolfssl_cleanup(void) {
46     int ret;
47 #ifdef WOLFCRYPT_ONLY
48     ret = wolfCrypt_Cleanup();
49     if (ret != 0)
50         pr_err("wolfCrypt_Cleanup() failed: %s\n", wc_GetErrorString(ret));
51     else
52         pr_info("wolfCrypt " LIBWOLFSSL_VERSION_STRING " cleanup complete.\n");
53 #else
54     ret = wolfSSL_Cleanup();
55     if (ret != WOLFSSL_SUCCESS)
56         pr_err("wolfSSL_Cleanup() failed: %s\n", wc_GetErrorString(ret));
57     else
58         pr_info("wolfSSL " LIBWOLFSSL_VERSION_STRING " cleanup complete.\n");
59 #endif
60 
61     return ret;
62 }
63 
64 #ifdef HAVE_LINUXKM_PIE_SUPPORT
65 
66 extern int wolfCrypt_PIE_first_function(void);
67 extern int wolfCrypt_PIE_last_function(void);
68 extern const unsigned int wolfCrypt_PIE_rodata_start[];
69 extern const unsigned int wolfCrypt_PIE_rodata_end[];
70 
71 /* cheap portable ad-hoc hash function to confirm bitwise stability of the PIE
72  * binary image.
73  */
hash_span(char * start,char * end)74 static unsigned int hash_span(char *start, char *end) {
75     unsigned int sum = 1;
76     while (start < end) {
77         unsigned int rotate_by;
78         sum ^= *start++;
79         rotate_by = (sum ^ (sum >> 5)) & 31;
80         sum = (sum << rotate_by) | (sum >> (32 - rotate_by));
81     }
82     return sum;
83 }
84 
85 #ifdef USE_WOLFSSL_LINUXKM_PIE_REDIRECT_TABLE
86 extern struct wolfssl_linuxkm_pie_redirect_table wolfssl_linuxkm_pie_redirect_table;
87 static int set_up_wolfssl_linuxkm_pie_redirect_table(void);
88 #endif /* USE_WOLFSSL_LINUXKM_PIE_REDIRECT_TABLE */
89 
90 #endif /* HAVE_LINUXKM_PIE_SUPPORT */
91 
92 #ifdef HAVE_FIPS
lkmFipsCb(int ok,int err,const char * hash)93 static void lkmFipsCb(int ok, int err, const char* hash)
94 {
95     if ((! ok) || (err != 0))
96         pr_err("libwolfssl FIPS error: %s\n", wc_GetErrorString(err));
97     if (err == IN_CORE_FIPS_E) {
98         pr_err("In-core integrity hash check failure.\n"
99                "Update verifyCore[] in fips_test.c with new hash \"%s\" and rebuild.\n",
100                hash ? hash : "<null>");
101     }
102 }
103 #endif
104 
105 #ifdef WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE
106 #ifndef CONFIG_MODULE_SIG
107 #error WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE requires a CONFIG_MODULE_SIG kernel.
108 #endif
109 static int updateFipsHash(void);
110 #endif
111 
112 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
wolfssl_init(void)113 static int __init wolfssl_init(void)
114 #else
115 static int wolfssl_init(void)
116 #endif
117 {
118     int ret;
119 
120 #ifdef WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE
121     if (THIS_MODULE->sig_ok == false) {
122         pr_err("wolfSSL module load aborted -- bad or missing module signature with FIPS dynamic hash.\n");
123         return -ECANCELED;
124     }
125     ret = updateFipsHash();
126     if (ret < 0) {
127         pr_err("wolfSSL module load aborted -- updateFipsHash: %s\n",wc_GetErrorString(ret));
128         return -ECANCELED;
129     }
130 #endif
131 
132 #ifdef USE_WOLFSSL_LINUXKM_PIE_REDIRECT_TABLE
133     ret = set_up_wolfssl_linuxkm_pie_redirect_table();
134     if (ret < 0)
135         return ret;
136 #endif
137 
138 #ifdef HAVE_LINUXKM_PIE_SUPPORT
139 
140 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
141     #define THIS_MODULE_BASE (THIS_MODULE->core_layout.base)
142     #define THIS_MODULE_TEXT_SIZE (THIS_MODULE->core_layout.text_size)
143     #define THIS_MODULE_RO_SIZE (THIS_MODULE->core_layout.ro_size)
144 #else
145     #define THIS_MODULE_BASE (THIS_MODULE->module_core)
146     #define THIS_MODULE_TEXT_SIZE (THIS_MODULE->core_text_size)
147     #define THIS_MODULE_RO_SIZE (THIS_MODULE->core_ro_size)
148 #endif
149 
150     {
151         char *pie_text_start = (char *)wolfCrypt_PIE_first_function;
152         char *pie_text_end = (char *)wolfCrypt_PIE_last_function;
153         char *pie_rodata_start = (char *)wolfCrypt_PIE_rodata_start;
154         char *pie_rodata_end = (char *)wolfCrypt_PIE_rodata_end;
155         unsigned int text_hash, rodata_hash;
156 
157         if ((pie_text_start < pie_text_end) &&
158             (pie_text_start >= (char *)THIS_MODULE_BASE) &&
159             (pie_text_end - (char *)THIS_MODULE_BASE <= THIS_MODULE_TEXT_SIZE))
160         {
161             text_hash = hash_span(pie_text_start, pie_text_end);
162         } else {
163             pr_info("out-of-bounds PIE fenceposts! pie_text_start=%px pie_text_end=%px (span=%lu)"
164                     " core_layout.base=%px text_end=%px\n",
165                     pie_text_start,
166                     pie_text_end,
167                     pie_text_end-pie_text_start,
168                     THIS_MODULE_BASE,
169                     (char *)THIS_MODULE_BASE + THIS_MODULE_TEXT_SIZE);
170             text_hash = 0;
171         }
172 
173         if ((pie_rodata_start < pie_rodata_end) &&
174             (pie_rodata_start >= (char *)THIS_MODULE_BASE + THIS_MODULE_TEXT_SIZE) &&
175             (pie_rodata_end - (char *)THIS_MODULE_BASE <= THIS_MODULE_RO_SIZE))
176         {
177             rodata_hash = hash_span(pie_rodata_start, pie_rodata_end);
178         } else {
179             pr_info("out-of-bounds PIE fenceposts! pie_rodata_start=%px pie_rodata_end=%px (span=%lu)"
180                     " core_layout.base+core_layout.text_size=%px rodata_end=%px\n",
181                     pie_rodata_start,
182                     pie_rodata_end,
183                     pie_rodata_end-pie_rodata_start,
184                     (char *)THIS_MODULE_BASE + THIS_MODULE_TEXT_SIZE,
185                     (char *)THIS_MODULE_BASE + THIS_MODULE_RO_SIZE);
186             rodata_hash = 0;
187         }
188 
189         /* note, "%pK" conceals the actual layout information.  "%px" exposes
190          * the true module start address, which is potentially useful to an
191          * attacker.
192          */
193         pr_info("wolfCrypt container hashes (spans): %x (%lu) %x (%lu), module base %pK\n",
194                 text_hash, pie_text_end-pie_text_start,
195                 rodata_hash, pie_rodata_end-pie_rodata_start,
196                 THIS_MODULE_BASE);
197     }
198 #endif /* HAVE_LINUXKM_PIE_SUPPORT */
199 
200 #ifdef HAVE_FIPS
201     ret = wolfCrypt_SetCb_fips(lkmFipsCb);
202     if (ret != 0) {
203         pr_err("wolfCrypt_SetCb_fips() failed: %s\n", wc_GetErrorString(ret));
204         return -ECANCELED;
205     }
206     fipsEntry();
207     ret = wolfCrypt_GetStatus_fips();
208     if (ret != 0) {
209         pr_err("wolfCrypt_GetStatus_fips() failed: %s\n", wc_GetErrorString(ret));
210         if (ret == IN_CORE_FIPS_E) {
211             const char *newhash = wolfCrypt_GetCoreHash_fips();
212             pr_err("Update verifyCore[] in fips_test.c with new hash \"%s\" and rebuild.\n",
213                    newhash ? newhash : "<null>");
214         }
215         return -ECANCELED;
216     }
217 
218     pr_info("wolfCrypt FIPS ["
219 
220 #if defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION == 3)
221             "ready"
222 #elif defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION == 2) \
223     && defined(WOLFCRYPT_FIPS_RAND)
224             "140-2 rand"
225 #elif defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION == 2)
226             "140-2"
227 #else
228             "140"
229 #endif
230             "] POST succeeded.\n");
231 #endif /* HAVE_FIPS */
232 
233 #ifdef WOLFCRYPT_ONLY
234     ret = wolfCrypt_Init();
235     if (ret != 0) {
236         pr_err("wolfCrypt_Init() failed: %s\n", wc_GetErrorString(ret));
237         return -ECANCELED;
238     }
239 #else
240     ret = wolfSSL_Init();
241     if (ret != WOLFSSL_SUCCESS) {
242         pr_err("wolfSSL_Init() failed: %s\n", wc_GetErrorString(ret));
243         return -ECANCELED;
244     }
245 #endif
246 
247 #ifndef NO_CRYPT_TEST
248 
249 #ifdef WC_RNG_SEED_CB
250     ret = wc_SetSeed_Cb(wc_GenerateSeed);
251     if (ret == 0)
252 #endif
253     {
254         ret = wolfcrypt_test(NULL);
255     }
256     if (ret < 0) {
257         pr_err("wolfcrypt self-test failed with return code %d.\n", ret);
258         (void)libwolfssl_cleanup();
259         msleep(10);
260         return -ECANCELED;
261     }
262     pr_info("wolfCrypt self-test passed.\n");
263 #endif
264 
265 #ifdef WOLFCRYPT_ONLY
266     pr_info("wolfCrypt " LIBWOLFSSL_VERSION_STRING " loaded%s"
267             ".\nSee https://www.wolfssl.com/ for more information.\n"
268             "wolfCrypt Copyright (C) 2006-present wolfSSL Inc.  Licensed under " WOLFSSL_LICENSE ".\n",
269 #ifdef CONFIG_MODULE_SIG
270             THIS_MODULE->sig_ok ? " with valid module signature" : " without valid module signature"
271 #else
272             ""
273 #endif
274         );
275 #else
276     pr_info("wolfSSL " LIBWOLFSSL_VERSION_STRING " loaded%s"
277             ".\nSee https://www.wolfssl.com/ for more information.\n"
278             "wolfSSL Copyright (C) 2006-present wolfSSL Inc.  Licensed under " WOLFSSL_LICENSE ".\n",
279 #ifdef CONFIG_MODULE_SIG
280             THIS_MODULE->sig_ok ? " with valid module signature" : " without valid module signature"
281 #else
282             ""
283 #endif
284         );
285 #endif
286 
287     return 0;
288 }
289 
290 module_init(wolfssl_init);
291 
292 #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
wolfssl_exit(void)293 static void __exit wolfssl_exit(void)
294 #else
295 static void wolfssl_exit(void)
296 #endif
297 {
298     (void)libwolfssl_cleanup();
299 
300     return;
301 }
302 
303 module_exit(wolfssl_exit);
304 
305 MODULE_LICENSE(WOLFSSL_LICENSE);
306 MODULE_AUTHOR("https://www.wolfssl.com/");
307 MODULE_DESCRIPTION("libwolfssl cryptographic and protocol facilities");
308 MODULE_VERSION(LIBWOLFSSL_VERSION_STRING);
309 
310 #ifdef USE_WOLFSSL_LINUXKM_PIE_REDIRECT_TABLE
311 
312 /* get_current() is an inline or macro, depending on the target -- sidestep the whole issue with a wrapper func. */
my_get_current_thread(void)313 static struct task_struct *my_get_current_thread(void) {
314     return get_current();
315 }
316 
317 /* ditto for preempt_count(). */
my_preempt_count(void)318 static int my_preempt_count(void) {
319     return preempt_count();
320 }
321 
322 #if defined(WOLFSSL_LINUXKM_SIMD_X86) && (LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0))
my_copy_fpregs_to_fpstate(struct fpu * fpu)323 static int my_copy_fpregs_to_fpstate(struct fpu *fpu) {
324     return copy_fpregs_to_fpstate(fpu);
325 }
my_copy_kernel_to_fpregs(union fpregs_state * fpstate)326 static void my_copy_kernel_to_fpregs(union fpregs_state *fpstate) {
327     copy_kernel_to_fpregs(fpstate);
328 }
329 #endif
330 
set_up_wolfssl_linuxkm_pie_redirect_table(void)331 static int set_up_wolfssl_linuxkm_pie_redirect_table(void) {
332     memset(
333         &wolfssl_linuxkm_pie_redirect_table,
334         0,
335         sizeof wolfssl_linuxkm_pie_redirect_table);
336 
337 #ifndef __ARCH_MEMCMP_NO_REDIRECT
338     wolfssl_linuxkm_pie_redirect_table.memcmp = memcmp;
339 #endif
340 #ifndef __ARCH_MEMCPY_NO_REDIRECT
341     wolfssl_linuxkm_pie_redirect_table.memcpy = memcpy;
342 #endif
343 #ifndef __ARCH_MEMSET_NO_REDIRECT
344     wolfssl_linuxkm_pie_redirect_table.memset = memset;
345 #endif
346 #ifndef __ARCH_MEMMOVE_NO_REDIRECT
347     wolfssl_linuxkm_pie_redirect_table.memmove = memmove;
348 #endif
349 #ifndef __ARCH_STRNCMP_NO_REDIRECT
350     wolfssl_linuxkm_pie_redirect_table.strncmp = strncmp;
351 #endif
352 #ifndef __ARCH_STRLEN_NO_REDIRECT
353     wolfssl_linuxkm_pie_redirect_table.strlen = strlen;
354 #endif
355 #ifndef __ARCH_STRSTR_NO_REDIRECT
356     wolfssl_linuxkm_pie_redirect_table.strstr = strstr;
357 #endif
358 #ifndef __ARCH_STRNCPY_NO_REDIRECT
359     wolfssl_linuxkm_pie_redirect_table.strncpy = strncpy;
360 #endif
361 #ifndef __ARCH_STRNCAT_NO_REDIRECT
362     wolfssl_linuxkm_pie_redirect_table.strncat = strncat;
363 #endif
364 #ifndef __ARCH_STRNCASECMP_NO_REDIRECT
365     wolfssl_linuxkm_pie_redirect_table.strncasecmp = strncasecmp;
366 #endif
367     wolfssl_linuxkm_pie_redirect_table.kstrtoll = kstrtoll;
368 
369     #if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 15, 0)
370         wolfssl_linuxkm_pie_redirect_table._printk = _printk;
371     #else
372         wolfssl_linuxkm_pie_redirect_table.printk = printk;
373     #endif
374     wolfssl_linuxkm_pie_redirect_table.snprintf = snprintf;
375 
376     wolfssl_linuxkm_pie_redirect_table._ctype = _ctype;
377 
378     wolfssl_linuxkm_pie_redirect_table.kmalloc = kmalloc;
379     wolfssl_linuxkm_pie_redirect_table.kfree = kfree;
380     wolfssl_linuxkm_pie_redirect_table.ksize = ksize;
381     wolfssl_linuxkm_pie_redirect_table.krealloc = krealloc;
382 #ifdef HAVE_KVMALLOC
383     wolfssl_linuxkm_pie_redirect_table.kvmalloc_node = kvmalloc_node;
384     wolfssl_linuxkm_pie_redirect_table.kvfree = kvfree;
385 #endif
386     wolfssl_linuxkm_pie_redirect_table.is_vmalloc_addr = is_vmalloc_addr;
387     wolfssl_linuxkm_pie_redirect_table.kmem_cache_alloc_trace =
388         kmem_cache_alloc_trace;
389     wolfssl_linuxkm_pie_redirect_table.kmalloc_order_trace =
390         kmalloc_order_trace;
391 
392     wolfssl_linuxkm_pie_redirect_table.get_random_bytes = get_random_bytes;
393     #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
394         wolfssl_linuxkm_pie_redirect_table.getnstimeofday =
395             getnstimeofday;
396     #elif LINUX_VERSION_CODE < KERNEL_VERSION(5, 0, 0)
397         wolfssl_linuxkm_pie_redirect_table.current_kernel_time64 =
398             current_kernel_time64;
399     #else
400         wolfssl_linuxkm_pie_redirect_table.ktime_get_coarse_real_ts64 =
401             ktime_get_coarse_real_ts64;
402     #endif
403 
404     wolfssl_linuxkm_pie_redirect_table.get_current = my_get_current_thread;
405     wolfssl_linuxkm_pie_redirect_table.preempt_count = my_preempt_count;
406 
407 #ifdef WOLFSSL_LINUXKM_SIMD_X86
408     wolfssl_linuxkm_pie_redirect_table.irq_fpu_usable = irq_fpu_usable;
409     #ifdef kernel_fpu_begin
410     wolfssl_linuxkm_pie_redirect_table.kernel_fpu_begin_mask =
411         kernel_fpu_begin_mask;
412     #else
413     wolfssl_linuxkm_pie_redirect_table.kernel_fpu_begin =
414         kernel_fpu_begin;
415     #endif
416     wolfssl_linuxkm_pie_redirect_table.kernel_fpu_end = kernel_fpu_end;
417     #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0)
418         wolfssl_linuxkm_pie_redirect_table.copy_fpregs_to_fpstate = my_copy_fpregs_to_fpstate;
419         wolfssl_linuxkm_pie_redirect_table.copy_kernel_to_fpregs = my_copy_kernel_to_fpregs;
420     #else
421         wolfssl_linuxkm_pie_redirect_table.save_fpregs_to_fpstate = save_fpregs_to_fpstate;
422         wolfssl_linuxkm_pie_redirect_table.__restore_fpregs_from_fpstate = __restore_fpregs_from_fpstate;
423         wolfssl_linuxkm_pie_redirect_table.xfeatures_mask_all = &xfeatures_mask_all;
424     #endif
425     wolfssl_linuxkm_pie_redirect_table.cpu_number = &cpu_number;
426     wolfssl_linuxkm_pie_redirect_table.nr_cpu_ids = &nr_cpu_ids;
427 #endif
428 
429     wolfssl_linuxkm_pie_redirect_table.__mutex_init = __mutex_init;
430     #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
431         wolfssl_linuxkm_pie_redirect_table.mutex_lock_nested = mutex_lock_nested;
432     #else
433         wolfssl_linuxkm_pie_redirect_table.mutex_lock = mutex_lock;
434     #endif
435     wolfssl_linuxkm_pie_redirect_table.mutex_unlock = mutex_unlock;
436     #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)
437         wolfssl_linuxkm_pie_redirect_table.mutex_destroy = mutex_destroy;
438     #endif
439 
440 #ifdef HAVE_FIPS
441     wolfssl_linuxkm_pie_redirect_table.wolfCrypt_FIPS_first =
442         wolfCrypt_FIPS_first;
443     wolfssl_linuxkm_pie_redirect_table.wolfCrypt_FIPS_last =
444         wolfCrypt_FIPS_last;
445 #endif
446 
447 #if !defined(WOLFCRYPT_ONLY) && !defined(NO_CERTS)
448     wolfssl_linuxkm_pie_redirect_table.GetCA = GetCA;
449 #ifndef NO_SKID
450     wolfssl_linuxkm_pie_redirect_table.GetCAByName = GetCAByName;
451 #endif
452 #endif
453 
454     /* runtime assert that the table has no null slots after initialization. */
455     {
456         unsigned long *i;
457         for (i = (unsigned long *)&wolfssl_linuxkm_pie_redirect_table;
458              i < (unsigned long *)&wolfssl_linuxkm_pie_redirect_table._last_slot;
459              ++i)
460             if (*i == 0) {
461                 pr_err("wolfCrypt container redirect table initialization was incomplete.\n");
462                 return -EFAULT;
463             }
464     }
465 
466     return 0;
467 }
468 
469 #endif /* USE_WOLFSSL_LINUXKM_PIE_REDIRECT_TABLE */
470 
471 
472 #ifdef WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE
473 
474 #include <wolfssl/wolfcrypt/coding.h>
475 
476 PRAGMA_GCC_DIAG_PUSH;
477 PRAGMA_GCC("GCC diagnostic ignored \"-Wnested-externs\"");
478 PRAGMA_GCC("GCC diagnostic ignored \"-Wpointer-arith\"");
479 #include <crypto/hash.h>
480 PRAGMA_GCC_DIAG_POP;
481 
482 extern char verifyCore[WC_SHA256_DIGEST_SIZE*2 + 1];
483 extern const char coreKey[WC_SHA256_DIGEST_SIZE*2 + 1];
484 extern const unsigned int wolfCrypt_FIPS_ro_start[];
485 extern const unsigned int wolfCrypt_FIPS_ro_end[];
486 
487 #define FIPS_IN_CORE_KEY_SZ 32
488 #define FIPS_IN_CORE_VERIFY_SZ FIPS_IN_CORE_KEY_SZ
489 typedef int (*fips_address_function)(void);
490 #define MAX_FIPS_DATA_SZ  100000
491 #define MAX_FIPS_CODE_SZ 1000000
492 extern int GenBase16_Hash(const byte* in, int length, char* out, int outSz);
493 
updateFipsHash(void)494 static int updateFipsHash(void)
495 {
496     struct crypto_shash *tfm = NULL;
497     struct shash_desc *desc = NULL;
498     word32 verifySz  = FIPS_IN_CORE_VERIFY_SZ;
499     word32 binCoreSz  = FIPS_IN_CORE_KEY_SZ;
500     int ret;
501     byte *hash = NULL;
502     char *base16_hash = NULL;
503     byte *binCoreKey = NULL;
504     byte *binVerify = NULL;
505 
506     fips_address_function first = wolfCrypt_FIPS_first;
507     fips_address_function last  = wolfCrypt_FIPS_last;
508 
509     char* start = (char*)wolfCrypt_FIPS_ro_start;
510     char* end   = (char*)wolfCrypt_FIPS_ro_end;
511 
512     unsigned long code_sz = (unsigned long)last - (unsigned long)first;
513     unsigned long data_sz = (unsigned long)end - (unsigned long)start;
514 
515     if (data_sz == 0 || data_sz > MAX_FIPS_DATA_SZ)
516         return BAD_FUNC_ARG;  /* bad fips data size */
517 
518     if (code_sz == 0 || code_sz > MAX_FIPS_CODE_SZ)
519         return BAD_FUNC_ARG;  /* bad fips code size */
520 
521     hash = XMALLOC(WC_SHA256_DIGEST_SIZE, 0, DYNAMIC_TYPE_TMP_BUFFER);
522     if (hash == NULL) {
523         ret = MEMORY_E;
524         goto out;
525     }
526     base16_hash = XMALLOC(WC_SHA256_DIGEST_SIZE*2 + 1, 0, DYNAMIC_TYPE_TMP_BUFFER);
527     if (base16_hash == NULL) {
528         ret = MEMORY_E;
529         goto out;
530     }
531     binCoreKey = XMALLOC(binCoreSz, 0, DYNAMIC_TYPE_TMP_BUFFER);
532     if (binCoreKey == NULL) {
533         ret = MEMORY_E;
534         goto out;
535     }
536     binVerify = XMALLOC(verifySz, 0, DYNAMIC_TYPE_TMP_BUFFER);
537     if (binVerify == NULL) {
538         ret = MEMORY_E;
539         goto out;
540     }
541 
542     {
543         word32 base16_out_len = binCoreSz;
544         ret = Base16_Decode((const byte *)coreKey, sizeof coreKey - 1, binCoreKey, &base16_out_len);
545         if (ret != 0) {
546             pr_err("Base16_Decode for coreKey: %s\n", wc_GetErrorString(ret));
547             goto out;
548         }
549         if (base16_out_len != binCoreSz) {
550             pr_err("unexpected output length %u for coreKey from Base16_Decode.\n",base16_out_len);
551             ret = BAD_STATE_E;
552             goto out;
553         }
554     }
555 
556     tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
557     if (IS_ERR(tfm)) {
558         if (PTR_ERR(tfm) == -ENOMEM) {
559             pr_err("crypto_alloc_shash failed: out of memory\n");
560             ret = MEMORY_E;
561         } else if (PTR_ERR(tfm) == -ENOENT) {
562             pr_err("crypto_alloc_shash failed: kernel is missing hmac(sha256) implementation\n");
563             pr_err("check for CONFIG_CRYPTO_SHA256 and CONFIG_CRYPTO_HMAC.\n");
564             ret = NOT_COMPILED_IN;
565         } else {
566             pr_err("crypto_alloc_shash failed with ret %ld\n",PTR_ERR(tfm));
567             ret = HASH_TYPE_E;
568         }
569         tfm = NULL;
570         goto out;
571     }
572 
573     {
574         size_t desc_size = crypto_shash_descsize(tfm) + sizeof *desc;
575         desc = XMALLOC(desc_size, NULL, DYNAMIC_TYPE_TMP_BUFFER);
576         if (desc == NULL) {
577             pr_err("failed allocating desc.");
578             ret = MEMORY_E;
579             goto out;
580         }
581         XMEMSET(desc, 0, desc_size);
582     }
583 
584     ret = crypto_shash_setkey(tfm, binCoreKey, binCoreSz);
585     if (ret) {
586         pr_err("crypto_ahash_setkey failed: err %d\n", ret);
587         ret = BAD_STATE_E;
588         goto out;
589     }
590 
591     desc->tfm = tfm;
592     ret = crypto_shash_init(desc);
593     if (ret) {
594         pr_err("crypto_shash_init failed: err %d\n", ret);
595         ret = BAD_STATE_E;
596         goto out;
597     }
598 
599     ret = crypto_shash_update(desc, (byte *)(wc_ptr_t)first, (word32)code_sz);
600     if (ret) {
601         pr_err("crypto_shash_update failed: err %d\n", ret);
602         ret = BAD_STATE_E;
603         goto out;
604     }
605 
606     /* don't hash verifyCore or changing verifyCore will change hash */
607     if (verifyCore >= start && verifyCore < end) {
608         data_sz = (unsigned long)verifyCore - (unsigned long)start;
609         ret = crypto_shash_update(desc, (byte*)start, (word32)data_sz);
610         if (ret) {
611                 pr_err("crypto_shash_update failed: err %d\n", ret);
612                 ret = BAD_STATE_E;
613                 goto out;
614         }
615         start   = (char*)verifyCore + sizeof(verifyCore);
616         data_sz = (unsigned long)end - (unsigned long)start;
617     }
618     ret = crypto_shash_update(desc, (byte*)start, (word32)data_sz);
619     if (ret) {
620         pr_err("crypto_shash_update failed: err %d\n", ret);
621         ret = BAD_STATE_E;
622         goto out;
623     }
624 
625     ret = crypto_shash_final(desc, hash);
626     if (ret) {
627         pr_err("crypto_shash_final failed: err %d\n", ret);
628         ret = BAD_STATE_E;
629         goto out;
630     }
631 
632     ret = GenBase16_Hash(hash, WC_SHA256_DIGEST_SIZE, base16_hash, WC_SHA256_DIGEST_SIZE*2 + 1);
633     if (ret != 0) {
634         pr_err("GenBase16_Hash failed: %s\n", wc_GetErrorString(ret));
635         goto out;
636     }
637 
638     {
639         word32 base16_out_len = verifySz;
640         ret = Base16_Decode((const byte *)verifyCore, sizeof verifyCore - 1, binVerify, &base16_out_len);
641         if (ret != 0) {
642             pr_err("Base16_Decode for verifyCore: %s\n", wc_GetErrorString(ret));
643             goto out;
644         }
645         if (base16_out_len != binCoreSz) {
646             pr_err("unexpected output length %u for verifyCore from Base16_Decode.\n",base16_out_len);
647             ret = BAD_STATE_E;
648             goto out;
649         }
650     }
651 
652     if (XMEMCMP(hash, binVerify, WC_SHA256_DIGEST_SIZE) == 0)
653         pr_info("updateFipsHash: verifyCore already matches.\n");
654     else {
655         XMEMCPY(verifyCore, base16_hash, WC_SHA256_DIGEST_SIZE*2 + 1);
656         pr_info("updateFipsHash: verifyCore updated.\n");
657     }
658 
659     ret = 0;
660 
661   out:
662 
663     if (tfm != NULL)
664         crypto_free_shash(tfm);
665     if (desc != NULL)
666         XFREE(desc, NULL, DYNAMIC_TYPE_TMP_BUFFER);
667     if (hash != NULL)
668         XFREE(hash, NULL, DYNAMIC_TYPE_TMP_BUFFER);
669     if (base16_hash != NULL)
670         XFREE(base16_hash, NULL, DYNAMIC_TYPE_TMP_BUFFER);
671     if (binCoreKey != NULL)
672         XFREE(binCoreKey, NULL, DYNAMIC_TYPE_TMP_BUFFER);
673     if (binVerify != NULL)
674         XFREE(binVerify, NULL, DYNAMIC_TYPE_TMP_BUFFER);
675 
676     return ret;
677 }
678 
679 #endif /* WOLFCRYPT_FIPS_CORE_DYNAMIC_HASH_VALUE */
680