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 /**
28 * @file using_wolfSSL.c
29 * @brief TLS transport interface implementations. This implementation uses
30 * wolfSSL.
31 */
32
33 /* Standard includes. */
34 #include <string.h>
35
36 /* FreeRTOS includes. */
37 #include "FreeRTOS.h"
38
39 /* FreeRTOS+TCP includes. */
40 #include "FreeRTOS_IP.h"
41 #include "FreeRTOS_Sockets.h"
42
43 /* TLS transport header. */
44 #include "transport_wolfSSL.h"
45
46 /* FreeRTOS Socket wrapper include. */
47 #include "tcp_sockets_wrapper.h"
48
49 /* wolfSSL user settings header */
50 #include "user_settings.h"
51
52 /* Demo Specific configs. */
53 #include "demo_config.h"
54
55 /**
56 * @brief Initialize the TLS structures in a network connection.
57 *
58 * @param[in] pSslContext The SSL context to initialize.
59 */
60 static void sslContextInit( SSLContext_t * pSslContext );
61
62 /**
63 * @brief Free the TLS structures in a network connection.
64 *
65 * @param[in] pSslContext The SSL context to free.
66 */
67 static void sslContextFree( SSLContext_t * pSslContext );
68
69 /**
70 * @brief Set up TLS on a TCP connection.
71 *
72 * @param[in] pNetworkContext Network context.
73 * @param[in] pHostName Remote host name, used for server name indication.
74 * @param[in] pNetworkCredentials TLS setup parameters.
75 *
76 * @return #TLS_TRANSPORT_SUCCESS, #TLS_TRANSPORT_INSUFFICIENT_MEMORY, #TLS_TRANSPORT_INVALID_CREDENTIALS,
77 * #TLS_TRANSPORT_HANDSHAKE_FAILED, or #TLS_TRANSPORT_INTERNAL_ERROR.
78 */
79 static TlsTransportStatus_t tlsSetup( NetworkContext_t * pNetworkContext,
80 const char * pHostName,
81 const NetworkCredentials_t * pNetworkCredentials );
82
83 /**
84 * @brief Initialize TLS component.
85 *
86 * @return #TLS_TRANSPORT_SUCCESS, #TLS_TRANSPORT_INSUFFICIENT_MEMORY, or #TLS_TRANSPORT_INTERNAL_ERROR.
87 */
88 static TlsTransportStatus_t initTLS( void );
89
90 /*
91 * @brief Receive date from the socket passed as the context
92 *
93 * @param[in] ssl WOLFSSL object.
94 * @param[in] buf Buffer for received data
95 * @param[in] sz Size to receive
96 * @param[in] context Socket to be received from
97 *
98 * @return received size( > 0 ), #WOLFSSL_CBIO_ERR_CONN_CLOSE, #WOLFSSL_CBIO_ERR_WANT_READ.
99 */
100 static int wolfSSL_IORecvGlue( WOLFSSL * ssl,
101 char * buf,
102 int sz,
103 void * context );
104
105 /*
106 * @brief Send date to the socket passed as the context
107 *
108 * @param[in] ssl WOLFSSL object.
109 * @param[in] buf Buffer for data to be sent
110 * @param[in] sz Size to send
111 * @param[in] context Socket to be sent to
112 *
113 * @return received size( > 0 ), #WOLFSSL_CBIO_ERR_CONN_CLOSE, #WOLFSSL_CBIO_ERR_WANT_WRITE.
114 */
115 static int wolfSSL_IOSendGlue( WOLFSSL * ssl,
116 char * buf,
117 int sz,
118 void * context );
119
120 /*
121 * @brief Load credentials from file/buffer
122 *
123 * @param[in] pNetCtx NetworkContext_t
124 * @param[in] pNetCred NetworkCredentials_t
125 *
126 * @return #TLS_TRANSPORT_SUCCESS, #TLS_TRANSPORT_INVALID_CREDENTIALS.
127 */
128 static TlsTransportStatus_t loadCredentials( NetworkContext_t * pNetCtx,
129 const NetworkCredentials_t * pNetCred );
130
131 /*-----------------------------------------------------------*/
wolfSSL_IORecvGlue(WOLFSSL * ssl,char * buf,int sz,void * context)132 static int wolfSSL_IORecvGlue( WOLFSSL * ssl,
133 char * buf,
134 int sz,
135 void * context )
136 {
137 ( void ) ssl; /* to prevent unused warning*/
138 BaseType_t read = 0;
139
140 Socket_t xSocket = ( Socket_t ) context;
141
142
143 read = TCP_Sockets_Recv( xSocket, ( void * ) buf, ( size_t ) sz );
144
145 if( ( read == 0 ) ||
146 ( read == TCP_SOCKETS_ERRNO_EWOULDBLOCK ) )
147 {
148 read = WOLFSSL_CBIO_ERR_WANT_READ;
149 }
150 else if( read == TCP_SOCKETS_ERRNO_ENOTCONN )
151 {
152 read = WOLFSSL_CBIO_ERR_CONN_CLOSE;
153 }
154 else
155 {
156 /* do nothing */
157 }
158
159 return ( int ) read;
160 }
161 /*-----------------------------------------------------------*/
162
wolfSSL_IOSendGlue(WOLFSSL * ssl,char * buf,int sz,void * context)163 static int wolfSSL_IOSendGlue( WOLFSSL * ssl,
164 char * buf,
165 int sz,
166 void * context )
167 {
168 ( void ) ssl; /* to prevent unused warning*/
169 Socket_t xSocket = ( Socket_t ) context;
170 BaseType_t sent = TCP_Sockets_Send( xSocket, ( void * ) buf, ( size_t ) sz );
171
172 if( sent == TCP_SOCKETS_ERRNO_EWOULDBLOCK )
173 {
174 sent = WOLFSSL_CBIO_ERR_WANT_WRITE;
175 }
176 else if( sent == TCP_SOCKETS_ERRNO_ENOTCONN )
177 {
178 sent = WOLFSSL_CBIO_ERR_CONN_CLOSE;
179 }
180 else
181 {
182 /* do nothing */
183 }
184
185 return ( int ) sent;
186 }
187
188 /*-----------------------------------------------------------*/
initTLS(void)189 static TlsTransportStatus_t initTLS( void )
190 {
191 /* initialize wolfSSL */
192 wolfSSL_Init();
193
194 #ifdef DEBUG_WOLFSSL
195 wolfSSL_Debugging_ON();
196 #endif
197
198 return TLS_TRANSPORT_SUCCESS;
199 }
200
201 /*-----------------------------------------------------------*/
loadCredentials(NetworkContext_t * pNetCtx,const NetworkCredentials_t * pNetCred)202 static TlsTransportStatus_t loadCredentials( NetworkContext_t * pNetCtx,
203 const NetworkCredentials_t * pNetCred )
204 {
205 TlsTransportStatus_t returnStatus = TLS_TRANSPORT_SUCCESS;
206
207 configASSERT( pNetCtx != NULL );
208 configASSERT( pNetCred != NULL );
209
210 #if defined( democonfigCREDENTIALS_IN_BUFFER )
211 if( wolfSSL_CTX_load_verify_buffer( pNetCtx->sslContext.ctx,
212 ( const byte * ) ( pNetCred->pRootCa ), ( long ) ( pNetCred->rootCaSize ),
213 SSL_FILETYPE_PEM ) == SSL_SUCCESS )
214 {
215 if( wolfSSL_CTX_use_certificate_buffer( pNetCtx->sslContext.ctx,
216 ( const byte * ) ( pNetCred->pClientCert ), ( long ) ( pNetCred->clientCertSize ),
217 SSL_FILETYPE_PEM ) == SSL_SUCCESS )
218 {
219 if( wolfSSL_CTX_use_PrivateKey_buffer( pNetCtx->sslContext.ctx,
220 ( const byte * ) ( pNetCred->pPrivateKey ), ( long ) ( pNetCred->privateKeySize ),
221 SSL_FILETYPE_PEM ) == SSL_SUCCESS )
222 {
223 returnStatus = TLS_TRANSPORT_SUCCESS;
224 }
225 else
226 {
227 LogError( ( "Failed to load client-private-key from buffer" ) );
228 returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS;
229 }
230 }
231 else
232 {
233 LogError( ( "Failed to load client-certificate from buffer" ) );
234 returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS;
235 }
236 }
237 else
238 {
239 LogError( ( "Failed to load ca-certificate from buffer" ) );
240 returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS;
241 }
242
243 return returnStatus;
244 #else /* if defined( democonfigCREDENTIALS_IN_BUFFER ) */
245 if( wolfSSL_CTX_load_verify_locations( pNetCtx->sslContext.ctx,
246 ( const char * ) ( pNetCred->pRootCa ), NULL ) == SSL_SUCCESS )
247 {
248 if( wolfSSL_CTX_use_certificate_file( pNetCtx->sslContext.ctx,
249 ( const char * ) ( pNetCred->pClientCert ), SSL_FILETYPE_PEM )
250 == SSL_SUCCESS )
251 {
252 if( wolfSSL_CTX_use_PrivateKey_file( pNetCtx->sslContext.ctx,
253 ( const char * ) ( pNetCred->pPrivateKey ), SSL_FILETYPE_PEM )
254 == SSL_SUCCESS )
255 {
256 returnStatus = TLS_TRANSPORT_SUCCESS;
257 }
258 else
259 {
260 LogError( ( "Failed to load client-private-key file" ) );
261 returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS;
262 }
263 }
264 else
265 {
266 LogError( ( "Failed to load client-certificate file" ) );
267 returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS;
268 }
269 }
270 else
271 {
272 LogError( ( "Failed to load ca-certificate file" ) );
273 returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS;
274 }
275 return returnStatus;
276 #endif /* if defined( democonfigCREDENTIALS_IN_BUFFER ) */
277 }
278
279 /*-----------------------------------------------------------*/
280
tlsSetup(NetworkContext_t * pNetCtx,const char * pHostName,const NetworkCredentials_t * pNetCred)281 static TlsTransportStatus_t tlsSetup( NetworkContext_t * pNetCtx,
282 const char * pHostName,
283 const NetworkCredentials_t * pNetCred )
284 {
285 TlsTransportStatus_t returnStatus = TLS_TRANSPORT_SUCCESS;
286 Socket_t xSocket = { 0 };
287
288 configASSERT( pNetCtx != NULL );
289 configASSERT( pHostName != NULL );
290 configASSERT( pNetCred != NULL );
291 configASSERT( pNetCred->pRootCa != NULL );
292 configASSERT( pNetCtx->tcpSocket != NULL );
293
294 if( pNetCtx->sslContext.ctx == NULL )
295 {
296 /* Attempt to create a context that uses the TLS 1.3 or 1.2 */
297 pNetCtx->sslContext.ctx =
298 wolfSSL_CTX_new( wolfSSLv23_client_method_ex( NULL ) );
299 }
300
301 if( pNetCtx->sslContext.ctx != NULL )
302 {
303 /* load credentials from file */
304 if( loadCredentials( pNetCtx, pNetCred ) == TLS_TRANSPORT_SUCCESS )
305 {
306 /* create a ssl object */
307 pNetCtx->sslContext.ssl =
308 wolfSSL_new( pNetCtx->sslContext.ctx );
309
310 if( pNetCtx->sslContext.ssl != NULL )
311 {
312 xSocket = pNetCtx->tcpSocket;
313
314 /* set Recv/Send glue functions to the WOLFSSL object */
315 wolfSSL_SSLSetIORecv( pNetCtx->sslContext.ssl,
316 wolfSSL_IORecvGlue );
317 wolfSSL_SSLSetIOSend( pNetCtx->sslContext.ssl,
318 wolfSSL_IOSendGlue );
319
320 /* set socket as a context of read/send glue funcs */
321 wolfSSL_SetIOReadCtx( pNetCtx->sslContext.ssl, xSocket );
322 wolfSSL_SetIOWriteCtx( pNetCtx->sslContext.ssl, xSocket );
323
324 /* let wolfSSL perform tls handshake */
325 if( wolfSSL_connect( pNetCtx->sslContext.ssl )
326 == SSL_SUCCESS )
327 {
328 returnStatus = TLS_TRANSPORT_SUCCESS;
329 }
330 else
331 {
332 wolfSSL_shutdown( pNetCtx->sslContext.ssl );
333 wolfSSL_free( pNetCtx->sslContext.ssl );
334 pNetCtx->sslContext.ssl = NULL;
335 wolfSSL_CTX_free( pNetCtx->sslContext.ctx );
336 pNetCtx->sslContext.ctx = NULL;
337
338 LogError( ( "Failed to establish a TLS connection" ) );
339 returnStatus = TLS_TRANSPORT_HANDSHAKE_FAILED;
340 }
341 }
342 else
343 {
344 wolfSSL_CTX_free( pNetCtx->sslContext.ctx );
345 pNetCtx->sslContext.ctx = NULL;
346
347 LogError( ( "Failed to create wolfSSL object" ) );
348 returnStatus = TLS_TRANSPORT_INTERNAL_ERROR;
349 }
350 }
351 else
352 {
353 wolfSSL_CTX_free( pNetCtx->sslContext.ctx );
354 pNetCtx->sslContext.ctx = NULL;
355
356 LogError( ( "Failed to load credentials" ) );
357 returnStatus = TLS_TRANSPORT_INVALID_CREDENTIALS;
358 }
359 }
360 else
361 {
362 LogError( ( "Failed to create a wolfSSL_CTX" ) );
363 returnStatus = TLS_TRANSPORT_CONNECT_FAILURE;
364 }
365
366 return returnStatus;
367 }
368
369 /*-----------------------------------------------------------*/
370
371
372 /*-----------------------------------------------------------*/
373
TLS_FreeRTOS_Connect(NetworkContext_t * pNetworkContext,const char * pHostName,uint16_t port,const NetworkCredentials_t * pNetworkCredentials,uint32_t receiveTimeoutMs,uint32_t sendTimeoutMs)374 TlsTransportStatus_t TLS_FreeRTOS_Connect( NetworkContext_t * pNetworkContext,
375 const char * pHostName,
376 uint16_t port,
377 const NetworkCredentials_t * pNetworkCredentials,
378 uint32_t receiveTimeoutMs,
379 uint32_t sendTimeoutMs )
380 {
381 TlsTransportStatus_t returnStatus = TLS_TRANSPORT_SUCCESS;
382 BaseType_t socketStatus = 0;
383 BaseType_t isSocketConnected = pdFALSE;
384
385 if( ( pNetworkContext == NULL ) ||
386 ( pHostName == NULL ) ||
387 ( pNetworkCredentials == NULL ) )
388 {
389 LogError( ( "Invalid input parameter(s): Arguments cannot be NULL. pNetworkContext=%p, "
390 "pHostName=%p, pNetworkCredentials=%p.",
391 pNetworkContext,
392 pHostName,
393 pNetworkCredentials ) );
394 returnStatus = TLS_TRANSPORT_INVALID_PARAMETER;
395 }
396 else if( ( pNetworkCredentials->pRootCa == NULL ) )
397 {
398 LogError( ( "pRootCa cannot be NULL." ) );
399 returnStatus = TLS_TRANSPORT_INVALID_PARAMETER;
400 }
401
402 /* Establish a TCP connection with the server. */
403 if( returnStatus == TLS_TRANSPORT_SUCCESS )
404 {
405 pNetworkContext->tcpSocket = NULL;
406
407 socketStatus = TCP_Sockets_Connect( &( pNetworkContext->tcpSocket ),
408 pHostName,
409 port,
410 receiveTimeoutMs,
411 sendTimeoutMs );
412
413 if( socketStatus != 0 )
414 {
415 LogError( ( "Failed to connect to %s with error %d.",
416 pHostName,
417 socketStatus ) );
418 returnStatus = TLS_TRANSPORT_CONNECT_FAILURE;
419 }
420 }
421
422 /* Initialize tls. */
423 if( returnStatus == TLS_TRANSPORT_SUCCESS )
424 {
425 isSocketConnected = pdTRUE;
426
427 returnStatus = initTLS();
428 }
429
430 /* Perform TLS handshake. */
431 if( returnStatus == TLS_TRANSPORT_SUCCESS )
432 {
433 returnStatus = tlsSetup( pNetworkContext, pHostName, pNetworkCredentials );
434 }
435
436 /* Clean up on failure. */
437 if( returnStatus != TLS_TRANSPORT_SUCCESS )
438 {
439 if( isSocketConnected == pdTRUE )
440 {
441 TCP_Sockets_Disconnect( pNetworkContext->tcpSocket );
442 pNetworkContext->tcpSocket = NULL;
443 }
444 }
445 else
446 {
447 LogInfo( ( "(Network connection %p) Connection to %s established.",
448 pNetworkContext,
449 pHostName ) );
450 }
451
452 return returnStatus;
453 }
454
455 /*-----------------------------------------------------------*/
456
TLS_FreeRTOS_Disconnect(NetworkContext_t * pNetworkContext)457 void TLS_FreeRTOS_Disconnect( NetworkContext_t * pNetworkContext )
458 {
459 WOLFSSL * pSsl = pNetworkContext->sslContext.ssl;
460 WOLFSSL_CTX * pCtx = NULL;
461
462 /* shutdown an active TLS connection */
463 wolfSSL_shutdown( pSsl );
464
465 /* cleanup WOLFSSL object */
466 wolfSSL_free( pSsl );
467 pNetworkContext->sslContext.ssl = NULL;
468
469 /* Call socket shutdown function to close connection. */
470 TCP_Sockets_Disconnect( pNetworkContext->tcpSocket );
471
472 /* free WOLFSSL_CTX object*/
473 pCtx = pNetworkContext->sslContext.ctx;
474
475 wolfSSL_CTX_free( pCtx );
476 pNetworkContext->sslContext.ctx = NULL;
477
478 wolfSSL_Cleanup();
479 }
480
481 /*-----------------------------------------------------------*/
482
TLS_FreeRTOS_recv(NetworkContext_t * pNetworkContext,void * pBuffer,size_t bytesToRecv)483 int32_t TLS_FreeRTOS_recv( NetworkContext_t * pNetworkContext,
484 void * pBuffer,
485 size_t bytesToRecv )
486 {
487 int32_t tlsStatus = 0;
488 int iResult = 0;
489 WOLFSSL * pSsl = NULL;
490
491 if( ( pNetworkContext == NULL ) || ( pNetworkContext->sslContext.ssl == NULL ) )
492 {
493 LogError( ( "invalid input, pNetworkContext=%p", pNetworkContext ) );
494 tlsStatus = -1;
495 }
496 else if( pBuffer == NULL )
497 {
498 LogError( ( "invalid input, pBuffer == NULL" ) );
499 tlsStatus = -1;
500 }
501 else if( bytesToRecv == 0 )
502 {
503 LogError( ( "invalid input, bytesToRecv == 0" ) );
504 tlsStatus = -1;
505 }
506 else
507 {
508 pSsl = pNetworkContext->sslContext.ssl;
509
510 iResult = wolfSSL_read( pSsl, pBuffer, bytesToRecv );
511
512 if( iResult > 0 )
513 {
514 tlsStatus = iResult;
515 }
516 else if( wolfSSL_want_read( pSsl ) == 1 )
517 {
518 tlsStatus = 0;
519 }
520 else
521 {
522 tlsStatus = wolfSSL_state( pSsl );
523 LogError( ( "Error from wolfSSL_read %d : %s ",
524 iResult, wolfSSL_ERR_reason_error_string( tlsStatus ) ) );
525 }
526 }
527
528 return tlsStatus;
529 }
530
531 /*-----------------------------------------------------------*/
532
TLS_FreeRTOS_send(NetworkContext_t * pNetworkContext,const void * pBuffer,size_t bytesToSend)533 int32_t TLS_FreeRTOS_send( NetworkContext_t * pNetworkContext,
534 const void * pBuffer,
535 size_t bytesToSend )
536 {
537 int32_t tlsStatus = 0;
538 int iResult = 0;
539 WOLFSSL * pSsl = NULL;
540
541 if( ( pNetworkContext == NULL ) || ( pNetworkContext->sslContext.ssl == NULL ) )
542 {
543 LogError( ( "invalid input, pNetworkContext=%p", pNetworkContext ) );
544 tlsStatus = -1;
545 }
546 else if( pBuffer == NULL )
547 {
548 LogError( ( "invalid input, pBuffer == NULL" ) );
549 tlsStatus = -1;
550 }
551 else if( bytesToSend == 0 )
552 {
553 LogError( ( "invalid input, bytesToSend == 0" ) );
554 tlsStatus = -1;
555 }
556 else
557 {
558 pSsl = pNetworkContext->sslContext.ssl;
559
560 iResult = wolfSSL_write( pSsl, pBuffer, bytesToSend );
561
562 if( iResult > 0 )
563 {
564 tlsStatus = iResult;
565 }
566 else if( wolfSSL_want_write( pSsl ) == 1 )
567 {
568 tlsStatus = 0;
569 }
570 else
571 {
572 tlsStatus = wolfSSL_state( pSsl );
573 LogError( ( "Error from wolfSL_write %d : %s ",
574 iResult, wolfSSL_ERR_reason_error_string( tlsStatus ) ) );
575 }
576 }
577
578 return tlsStatus;
579 }
580 /*-----------------------------------------------------------*/
581