1 /*
2  * Copyright (c) 2019, NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/init.h>
8 #include <zephyr/device.h>
9 #include <zephyr/drivers/entropy.h>
10 #include <zephyr/kernel.h>
11 #include <string.h>
12 
13 #if !defined(CONFIG_MBEDTLS_CFG_FILE)
14 #include "mbedtls/config.h"
15 #else
16 #include CONFIG_MBEDTLS_CFG_FILE
17 #endif /* CONFIG_MBEDTLS_CFG_FILE */
18 #include <mbedtls/ctr_drbg.h>
19 
20 /*
21  * entropy_dev is initialized at runtime to allow first time initialization
22  * of the ctr_drbg engine.
23  */
24 static const struct device *entropy_dev;
25 static const unsigned char drbg_seed[] = CONFIG_CS_CTR_DRBG_PERSONALIZATION;
26 static bool ctr_initialised;
27 static struct k_mutex ctr_lock;
28 
29 static mbedtls_ctr_drbg_context ctr_ctx;
30 
ctr_drbg_entropy_func(void * ctx,unsigned char * buf,size_t len)31 static int ctr_drbg_entropy_func(void *ctx, unsigned char *buf, size_t len)
32 {
33 	return entropy_get_entropy(entropy_dev, (void *)buf, len);
34 }
35 
ctr_drbg_initialize(void)36 static int ctr_drbg_initialize(void)
37 {
38 	int ret;
39 
40 	entropy_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_entropy));
41 
42 	if (!device_is_ready(entropy_dev)) {
43 		__ASSERT(0, "Entropy device %s not ready", entropy_dev->name);
44 		return -ENODEV;
45 	}
46 
47 	mbedtls_ctr_drbg_init(&ctr_ctx);
48 
49 	ret = mbedtls_ctr_drbg_seed(&ctr_ctx,
50 				    ctr_drbg_entropy_func,
51 				    NULL,
52 				    drbg_seed,
53 				    sizeof(drbg_seed));
54 
55 	if (ret != 0) {
56 		mbedtls_ctr_drbg_free(&ctr_ctx);
57 		return -EIO;
58 	}
59 
60 	ctr_initialised = true;
61 	return 0;
62 }
63 
64 
z_impl_sys_csrand_get(void * dst,uint32_t outlen)65 int z_impl_sys_csrand_get(void *dst, uint32_t outlen)
66 {
67 	int ret;
68 
69 	k_mutex_lock(&ctr_lock, K_FOREVER);
70 
71 	if (unlikely(!ctr_initialised)) {
72 		ret = ctr_drbg_initialize();
73 		if (ret != 0) {
74 			ret = -EIO;
75 			goto end;
76 		}
77 	}
78 
79 	ret = mbedtls_ctr_drbg_random(&ctr_ctx, (unsigned char *)dst, outlen);
80 
81 end:
82 	k_mutex_unlock(&ctr_lock);
83 
84 	return ret;
85 }
86