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