FreeRTOS / FreeRTOS-Cellular-Interface

FreeRTOS Cellular Interface implementation of the 3GPP TS v27.007 standard.
MIT License
85 stars 59 forks source link

Add secure socket layer options for modem ports #147

Closed chinglee-iot closed 7 months ago

chinglee-iot commented 1 year ago

Description

Cellular modem may support secure socket connection with modem specific APIs. This PR adds the secure socket layer options to enable secure socket connection with port layer APIs. Port has to implements the following functions with board specific AT commands:

For example, BG96 can define the following APIs in cellular_bg96_api.h for user to include and implement these APIs in cellular_bg96_api.c.

/* Upload credential to the file system. Later it can be used to configure the secure socket context. */                                              
CellularError_t Cellular_UploadFileToStorage( CellularHandle_t cellularHandle,
                                              const char* filename,
                                              const char* fileContent,
                                              uint32_t fileSize,
                                              uint32_t* pSentDataLength );

/* Configure the secure socket context. */
CellularError_t Cellular_ConfigureSSLContext( CellularHandle_t cellularHandle,
                                              uint8_t sslContextId,
                                              const char* sslConfigurationParameter,
                                              const char* inputArg );

BG96 has to support CELLULAR_SOCKET_OPTION_SSL_CONTEXT_ID and CELLULAR_SOCKET_OPTION_SSL_USAGE in the implementation of Cellular_SocketSetSockOpt. For example,

typedef struct CellularSocketSslConfig
{
    uint8_t useSsl;
    uint8_t sslContextId;
} CellularSocketSslConfig_t;

static CellularSocketSslConfig_t cellularSocketSslConfig[ CELLULAR_NUM_SOCKET_MAX ];

CellularError_t Cellular_CreateSocket( CellularHandle_t cellularHandle,
                                       uint8_t pdnContextId,
                                       CellularSocketDomain_t socketDomain,
                                       CellularSocketType_t socketType,
                                       CellularSocketProtocol_t socketProtocol,
                                       CellularSocketHandle_t * pSocketHandle )
{
    CellularError_t cellularStatus;
    CellularSocketContext_t * pSocketContext;

    cellularStatus = Cellular_CommonCreateSocket( cellularHandle, pdnContextId, socketDomain, socketType,
                                                  socketProtocol, pSocketHandle );
    if( cellularStatus == CELLULAR_SUCCESS )
    {
        /* pSocketHandle is checked in Cellular_CommonCreateSocket already. */
        pSocketContext = ( CellularSocketContext_t * )pSocketHandle;
        /* Make use of pModemData to store modem specific socket data. */
        pSocketContext->pModemData = &( cellularSocketSslConfig[ socketIndex ] );
    }
}

CellularError_t Cellular_SocketSetSockOpt( CellularHandle_t cellularHandle,
                                           CellularSocketHandle_t socketHandle,
                                           CellularSocketOptionLevel_t optionLevel,
                                           CellularSocketOption_t option,
                                           const uint8_t * pOptionValue,
                                           uint32_t optionValueLength )
{
    CellularError_t cellularStatus;
    CellularSocketContext_t * pSocketContext;
    CellularSocketSslConfig_t * pSocketSslConfig;

    cellularStatus = Cellular_CommonSocketSetSockOpt( cellularHandle, socketHandle, optionLevel, option,
                                            pOptionValue, optionValueLength );
    if( cellularStatus == CELLULAR_UNSUPPORTED )
    {
        /* pSocketHandle is checked in Cellular_CommonCreateSocket already. */
        pSocketContext = ( CellularSocketContext_t * )pSocketHandle;
        pSocketSslConfig = ( CellularSocketSslConfig_t * )pSocketContext->pModemData;

        if( optionLevel == CELLULAR_SOCKET_OPTION_LEVEL_SECURE )
        {
            if( option == CELLULAR_SOCKET_OPTION_SSL_CONTEXT_ID )
            {
                if( ( pSocketContext->socketState == SOCKETSTATE_ALLOCATED ) && ( optionValueLength == sizeof( uint8_t ) ) )
                {
                    pSocketSslConfig->sslContextId = *pOptionValue;
                    cellularStatus = CELLULAR_SUCCESS;
                }
                else
                {
                    LogError( ( "Cellular_SocketSetSockOpt: Cannot change the sslContextID in this state %d or length %d is invalid.",
                                pSocketContext->socketState, optionValueLength ) );
                    cellularStatus = CELLULAR_INTERNAL_FAILURE;
                }
            }
            else if( option == CELLULAR_SOCKET_OPTION_SSL_USAGE )
            {
                if( ( pSocketContext->socketState == SOCKETSTATE_ALLOCATED ) && ( optionValueLength == sizeof( uint8_t ) ) )
                {
                    pSocketSslConfig->useSsl = *pOptionValue;
                    cellularStatus = CELLULAR_SUCCESS;
                }
                else
                {
                    LogError( ( "Cellular_SocketSetSockOpt: Cannot change the useSsl in this state %d or length %d is invalid.",
                                pSocketContext->socketState, optionValueLength ) );
                    cellularStatus = CELLULAR_INTERNAL_FAILURE;
                }
            }
            else
            {
                /* This option is also not supported in port. */
            }
        }
        else
        {
            /* This option level is also not supported in port. */
        }
    }
    return cellularStatus;
}

User of cellular interface can make use of port specific APIs to create a secure socket connection with the following example.

#include "cellular_bg96_api.h"
/* Upload the credential to modem storage. Bind the credential with name and type. */
Cellular_UploadFileToStorage( CellularHandle,
                              SERCURITY_PROFILE_NAME_ROOT_CA,
                              pRootCa,
                              rootCaSize,
                              &uxSentDataLength );

Cellular_UploadFileToStorage( CellularHandle,
                              SERCURITY_PROFILE_NAME_CERTIFICATE,
                              pClientCert,
                              clientCertSize,
                              &uxSentDataLength );

Cellular_UploadFileToStorage( CellularHandle,
                              SERCURITY_PROFILE_NAME_PRIVATE_KEY,
                              pPrivateKey,
                              privateKeySize,
                              &uxSentDataLength );

/* Bind the security profile ID with cipher suite and credentials. */
uint8_t sslContextId = 0;
Cellular_ConfigureSSLContext( cellularHandle,
                              sslContextId,
                              "sslversion",
                              "1" );

Cellular_ConfigureSSLContext( cellularHandle,
                              sslContextId,
                              "siphersuite",
                              "0xffff" );

Cellular_ConfigureSSLContext( cellularHandle,
                              sslContextId,
                              "cacert",
                              SERCURITY_PROFILE_NAME_ROOT_CA );

...
/* Create a new TCP socket. */
Cellular_CreateSocket( CellularHandle,
                        CellularSocketPdnContextId,
                        CELLULAR_SOCKET_DOMAIN_AF_INET,
                        CELLULAR_SOCKET_TYPE_STREAM,
                       CELLULAR_SOCKET_PROTOCOL_TCP,
                        &cellularSocketHandle );

Cellular_SocketSetSockOpt( CellularHandle,
                            cellularSocketHandle,
                            CELLULAR_SOCKET_OPTION_LEVEL_SECURE,
                            CELLULAR_SOCKET_OPTION_SSL_CONTEXT_ID,
                            ( const uint8_t * ) &sslContextId,
                            sizeof( uint8_t ) );

sslUsage = 1;
Cellular_SocketSetSockOpt( CellularHandle,
                            cellularSocketHandle,
                            CELLULAR_SOCKET_OPTION_LEVEL_SECURE,
                            CELLULAR_SOCKET_OPTION_SSL_USAGE,
                            ( const uint8_t * ) &sslUsage,
                            sizeof( uint8_t ) );

Cellular_SocketConnect( CellularHandle,
                        cellularSocketHandle,
                        CELLULAR_ACCESSMODE_BUFFER,
                        &serverAddress );

Cellular_SocketSend( CellularHandle,
                      cellularSocketHandle,
                      buf,
                      bytesToSend,
                      &sentLength );

Cellular_SocketRecv( CellularHandle,
                     cellularSocketHandle,
                     buf,
                     len,
                     &recvLength );

Test Steps

Checklist:

Related Issue

146

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

chinglee-iot commented 7 months ago

Close this PR due to no response. Feel free to reopen it if any further update.

azeater commented 3 weeks ago

Hi @chinglee-iot, I've tested your changes with the BG96 successfully. What would need to be done to get this PR merged into the main branch? A lot of cellular modules allow for SSL native sockets so I think support would be great.