1 /*
2  * FreeRTOS V202212.00
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * https://www.FreeRTOS.org
23  * https://github.com/FreeRTOS
24  *
25  */
26 
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "FreeRTOSConfig.h"
31 
32 /* FreeRTOS includes. */
33 #include "FreeRTOS.h"
34 #include "semphr.h"
35 
36 /* mbed TLS includes. */
37 #if defined( MBEDTLS_CONFIG_FILE )
38     #include MBEDTLS_CONFIG_FILE
39 #else
40     #include "mbedtls/mbedtls_config.h"
41 #endif
42 #include "mbedtls/entropy.h"
43 
44 #include "entropy_poll.h"
45 
46 #include "mbedtls_freertos_port.h"
47 
48 /*-----------------------------------------------------------*/
49 
50 /**
51  * @brief Allocates memory for an array of members.
52  *
53  * @param[in] nmemb Number of members that need to be allocated.
54  * @param[in] size Size of each member.
55  *
56  * @return Pointer to the beginning of newly allocated memory.
57  */
mbedtls_platform_calloc(size_t nmemb,size_t size)58 void * mbedtls_platform_calloc( size_t nmemb,
59                                 size_t size )
60 {
61     size_t totalSize = nmemb * size;
62     void * pBuffer = NULL;
63 
64     /* Check that neither nmemb nor size were 0. */
65     if( totalSize > 0 )
66     {
67         /* Overflow check. */
68         if( ( totalSize / size ) == nmemb )
69         {
70             pBuffer = pvPortMalloc( totalSize );
71 
72             if( pBuffer != NULL )
73             {
74                 ( void ) memset( pBuffer, 0U, totalSize );
75             }
76         }
77     }
78 
79     return pBuffer;
80 }
81 
82 /*-----------------------------------------------------------*/
83 
84 /**
85  * @brief Frees the space previously allocated by calloc.
86  *
87  * @param[in] ptr Pointer to the memory to be freed.
88  */
mbedtls_platform_free(void * ptr)89 void mbedtls_platform_free( void * ptr )
90 {
91     if( ptr != NULL )
92     {
93         vPortFree( ptr );
94     }
95 }
96 
97 /*-----------------------------------------------------------*/
98 
99 #if defined( MBEDTLS_THREADING_C )
100 
101 /**
102  * @brief Creates a mutex.
103  *
104  * @param[in, out] pMutex mbedtls mutex handle.
105  */
mbedtls_platform_mutex_init(mbedtls_threading_mutex_t * pMutex)106     static void mbedtls_platform_mutex_init( mbedtls_threading_mutex_t * pMutex )
107     {
108         configASSERT( pMutex != NULL );
109 
110         #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
111 
112             /* Create a statically-allocated FreeRTOS mutex. This should never fail as
113              * storage is provided. */
114 
115             pMutex->mutexHandle = xSemaphoreCreateMutexStatic( &( pMutex->mutexStorage ) );
116         #elif ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
117             pMutex->mutexHandle = xSemaphoreCreateMutex();
118         #endif
119 
120         configASSERT( pMutex->mutexHandle != NULL );
121     }
122 
123 /*-----------------------------------------------------------*/
124 
125 /**
126  * @brief Frees a mutex.
127  *
128  * @param[in] pMutex mbedtls mutex handle.
129  *
130  * @note This function is an empty stub as nothing needs to be done to free
131  * a statically allocated FreeRTOS mutex.
132  */
mbedtls_platform_mutex_free(mbedtls_threading_mutex_t * pMutex)133     static void mbedtls_platform_mutex_free( mbedtls_threading_mutex_t * pMutex )
134     {
135         vSemaphoreDelete( pMutex->mutexHandle );
136         pMutex->mutexHandle = NULL;
137     }
138 
139 /*-----------------------------------------------------------*/
140 
141 /**
142  * @brief Function to lock a mutex.
143  *
144  * @param[in] pMutex mbedtls mutex handle.
145  *
146  * @return 0 (success) is always returned as any other failure is asserted.
147  */
mbedtls_platform_mutex_lock(mbedtls_threading_mutex_t * pMutex)148     static int mbedtls_platform_mutex_lock( mbedtls_threading_mutex_t * pMutex )
149     {
150         BaseType_t mutexStatus = 0;
151 
152         configASSERT( pMutex != NULL );
153         configASSERT( pMutex->mutexHandle != NULL );
154 
155         /* mutexStatus is not used if asserts are disabled. */
156         ( void ) mutexStatus;
157 
158         /* This function should never fail if the mutex is initialized. */
159         mutexStatus = xSemaphoreTake( pMutex->mutexHandle, portMAX_DELAY );
160 
161         configASSERT( mutexStatus == pdTRUE );
162 
163         return 0;
164     }
165 
166 /*-----------------------------------------------------------*/
167 
168 /**
169  * @brief Function to unlock a mutex.
170  *
171  * @param[in] pMutex mbedtls mutex handle.
172  *
173  * @return 0 is always returned as any other failure is asserted.
174  */
mbedtls_platform_mutex_unlock(mbedtls_threading_mutex_t * pMutex)175     static int mbedtls_platform_mutex_unlock( mbedtls_threading_mutex_t * pMutex )
176     {
177         BaseType_t mutexStatus = 0;
178 
179         configASSERT( pMutex != NULL );
180         configASSERT( pMutex->mutexHandle != NULL );
181         /* mutexStatus is not used if asserts are disabled. */
182         ( void ) mutexStatus;
183 
184         /* This function should never fail if the mutex is initialized. */
185         mutexStatus = xSemaphoreGive( pMutex->mutexHandle );
186         configASSERT( mutexStatus == pdTRUE );
187 
188         return 0;
189     }
190 
191 /*-----------------------------------------------------------*/
192 
193     #if defined( MBEDTLS_THREADING_ALT )
mbedtls_platform_threading_init(void)194         int mbedtls_platform_threading_init( void )
195         {
196             mbedtls_threading_set_alt( mbedtls_platform_mutex_init,
197                                        mbedtls_platform_mutex_free,
198                                        mbedtls_platform_mutex_lock,
199                                        mbedtls_platform_mutex_unlock );
200             return 0;
201         }
202 
203     #else /* !MBEDTLS_THREADING_ALT */
204 
205         void (* mbedtls_mutex_init)( mbedtls_threading_mutex_t * mutex ) = mbedtls_platform_mutex_init;
206         void (* mbedtls_mutex_free)( mbedtls_threading_mutex_t * mutex ) = mbedtls_platform_mutex_free;
207         int (* mbedtls_mutex_lock)( mbedtls_threading_mutex_t * mutex ) = mbedtls_platform_mutex_lock;
208         int (* mbedtls_mutex_unlock)( mbedtls_threading_mutex_t * mutex ) = mbedtls_platform_mutex_unlock;
209 
210     #endif /* !MBEDTLS_THREADING_ALT */
211 
212 #endif /* MBEDTLS_THREADING_C */
213 /*-----------------------------------------------------------*/
214 
215 #if defined( MBEDTLS_ENTROPY_HARDWARE_ALT )
216     /* Determine which API is available */
217     #if defined( _WIN32 )
218         #define RNG_SOURCE_WINDOWS_CRYPT
219     #elif defined( __linux__ )
220         #include <unistd.h>
221         #include <sys/syscall.h>
222         #if defined( SYS_getrandom )
223             #define RNG_SOURCE_GETRANDOM
224         #endif /* SYS_getrandom */
225     #elif defined( ARM_RDI_MONITOR ) || defined( SEMIHOSTING )
226         #define RNG_SOURCE_SEMIHOST
227     #else
228         #define RNG_SOURCE_DEV_RANDOM
229     #endif /* if defined( _WIN32 ) */
230 
231     #if defined( RNG_SOURCE_WINDOWS_CRYPT )
232         #include <windows.h>
233         #include <wincrypt.h>
mbedtls_hardware_poll(void * data,unsigned char * output,size_t len,size_t * olen)234         int mbedtls_hardware_poll( void * data,
235                                    unsigned char * output,
236                                    size_t len,
237                                    size_t * olen )
238         {
239             int lStatus = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
240             HCRYPTPROV hProv = 0;
241 
242             /* Unreferenced parameter. */
243             ( void ) data;
244 
245             /*
246              * This is port-specific for the Windows simulator, so just use Crypto API.
247              */
248 
249             if( TRUE == CryptAcquireContextA(
250                     &hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) )
251             {
252                 if( TRUE == CryptGenRandom( hProv, len, output ) )
253                 {
254                     lStatus = 0;
255                     *olen = len;
256                 }
257 
258                 CryptReleaseContext( hProv, 0 );
259             }
260 
261             return lStatus;
262         }
263     #elif defined( RNG_SOURCE_GETRANDOM )
mbedtls_hardware_poll(void * data,unsigned char * output,size_t len,size_t * olen)264         int mbedtls_hardware_poll( void * data,
265                                    unsigned char * output,
266                                    size_t len,
267                                    size_t * olen )
268         {
269             ( void ) data;
270             int rslt = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
271 
272             configASSERT( olen != NULL );
273 
274             rslt = getrandom( output, len, 0 );
275 
276             if( rslt >= 0 )
277             {
278                 *olen = ( size_t ) rslt;
279                 rslt = 0;
280             }
281             else
282             {
283                 rslt = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
284             }
285 
286             return rslt;
287         }
288     #elif defined( RNG_SOURCE_SEMIHOST )
mbedtls_hardware_poll(void * data,unsigned char * output,size_t len,size_t * olen)289         int mbedtls_hardware_poll( void * data,
290                                    unsigned char * output,
291                                    size_t len,
292                                    size_t * olen )
293         {
294             int rslt = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
295             int file;
296 
297             ( void ) data;
298 
299             configASSERT( olen != NULL );
300             configASSERT( output != NULL );
301 
302             file = _open( "/dev/urandom", O_RDONLY );
303 
304             if( file >= 0 )
305             {
306                 rslt = _read( file, ( char * ) output, len );
307             }
308 
309             if( rslt >= 0 )
310             {
311                 *olen = len;
312             }
313 
314             if( rslt >= 0 )
315             {
316                 *olen = len;
317                 rslt = 0;
318             }
319             else
320             {
321                 rslt = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
322             }
323 
324             ( void ) _close( file );
325             return rslt;
326         }
327     #else /* if defined( RNG_SOURCE_WINDOWS_CRYPT ) */
328         #include <stdio.h>
mbedtls_hardware_poll(void * data,unsigned char * output,size_t len,size_t * olen)329         int mbedtls_hardware_poll( void * data,
330                                    unsigned char * output,
331                                    size_t len,
332                                    size_t * olen )
333         {
334             int rslt = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
335             FILE * file;
336             size_t read_length = 0U;
337 
338             configASSERT( olen != NULL );
339             configASSERT( output != NULL );
340 
341             file = fopen( "/dev/urandom", "rb" );
342 
343             if( file != NULL )
344             {
345                 rslt = fread( output, 1, len, file );
346                 fclose( file );
347             }
348 
349             if( rslt >= 0 )
350             {
351                 *olen = len;
352                 rslt = 0;
353             }
354             else
355             {
356                 rslt = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED;
357             }
358 
359             return rslt;
360         }
361     #endif /* if defined( RNG_SOURCE_WINDOWS_CRYPT ) */
362 #endif /* if defined( MBEDTLS_ENTROPY_HARDWARE_ALT ) */
363 /*-----------------------------------------------------------*/
364