406 lines
13 KiB
C
406 lines
13 KiB
C
/**
|
|
*
|
|
* \file
|
|
*
|
|
* \brief WINC SSL Interface.
|
|
*
|
|
* Copyright (c) 2017-2018 Microchip Technology Inc. and its subsidiaries.
|
|
*
|
|
* \asf_license_start
|
|
*
|
|
* \page License
|
|
*
|
|
* Subject to your compliance with these terms, you may use Microchip
|
|
* software and any derivatives exclusively with Microchip products.
|
|
* It is your responsibility to comply with third party license terms applicable
|
|
* to your use of third party software (including open source software) that
|
|
* may accompany Microchip software.
|
|
*
|
|
* THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
|
|
* WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
|
|
* INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
|
|
* AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
|
|
* LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
|
|
* LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
|
|
* SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
|
|
* POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
|
|
* ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
|
|
* RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
|
|
* THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
|
|
*
|
|
* \asf_license_stop
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
|
INCLUDES
|
|
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
|
|
|
#include "driver/include/m2m_ssl.h"
|
|
#include "driver/source/m2m_hif.h"
|
|
#include "driver/source/nmasic.h"
|
|
#include <stdlib.h>
|
|
|
|
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
|
MACROS
|
|
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
|
|
|
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
|
DATA TYPES
|
|
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
|
static tpfAppSSLCb gpfAppSSLCb = NULL;
|
|
static uint32 gu32HIFAddr = 0;
|
|
static tenuTlsFlashStatus genuStatus = TLS_FLASH_ERR_UNKNOWN;
|
|
|
|
/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
|
|
FUNCTION PROTOTYPES
|
|
*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
|
|
|
|
/*!
|
|
@fn \ m2m_ssl_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr)
|
|
@brief SSL callback function
|
|
@param [in] u8OpCode
|
|
HIF Opcode type.
|
|
@param [in] u16DataSize
|
|
HIF data length.
|
|
@param [in] u32Addr
|
|
HIF address.
|
|
*/
|
|
static void m2m_ssl_cb(uint8 u8OpCode, uint16 u16DataSize, uint32 u32Addr)
|
|
{
|
|
sint8 s8tmp = M2M_SUCCESS;
|
|
switch(u8OpCode)
|
|
{
|
|
case M2M_SSL_REQ_ECC:
|
|
{
|
|
tstrEccReqInfo strEccREQ;
|
|
s8tmp = hif_receive(u32Addr, (uint8*)&strEccREQ, sizeof(tstrEccReqInfo), 0);
|
|
if(s8tmp == M2M_SUCCESS)
|
|
{
|
|
if (gpfAppSSLCb)
|
|
{
|
|
gu32HIFAddr = u32Addr + sizeof(tstrEccReqInfo);
|
|
gpfAppSSLCb(M2M_SSL_REQ_ECC, &strEccREQ);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case M2M_SSL_RESP_SET_CS_LIST:
|
|
{
|
|
tstrSslSetActiveCsList strCsList;
|
|
s8tmp = hif_receive(u32Addr, (uint8*)&strCsList, sizeof(tstrSslSetActiveCsList), 0);
|
|
if(s8tmp == M2M_SUCCESS)
|
|
{
|
|
if (gpfAppSSLCb)
|
|
gpfAppSSLCb(M2M_SSL_RESP_SET_CS_LIST, &strCsList);
|
|
}
|
|
}
|
|
break;
|
|
case M2M_SSL_RESP_WRITE_OWN_CERTS:
|
|
{
|
|
tstrTlsSrvChunkHdr strTlsSrvChunkRsp;
|
|
uint8 bCallApp = 1;
|
|
|
|
s8tmp = hif_receive(u32Addr, (uint8*)&strTlsSrvChunkRsp, sizeof(tstrTlsSrvChunkHdr), 0);
|
|
if(s8tmp == M2M_SUCCESS)
|
|
{
|
|
uint16 offset = strTlsSrvChunkRsp.u16Offset32;
|
|
uint16 chunk_size = strTlsSrvChunkRsp.u16Size32;
|
|
uint16 total_size = strTlsSrvChunkRsp.u16TotalSize32;
|
|
tenuTlsFlashStatus status = (tenuTlsFlashStatus)(strTlsSrvChunkRsp.u16Sig);
|
|
|
|
/* If first chunk, reset status. */
|
|
if (offset == 0)
|
|
genuStatus = TLS_FLASH_OK_NO_CHANGE;
|
|
/* Only send status to app when processing last chunk. */
|
|
if (offset + chunk_size != total_size)
|
|
bCallApp = 0;
|
|
|
|
switch (status)
|
|
{
|
|
case TLS_FLASH_OK:
|
|
// Good flash write. Update status if no errors yet.
|
|
if (genuStatus == TLS_FLASH_OK_NO_CHANGE)
|
|
genuStatus = status;
|
|
break;
|
|
case TLS_FLASH_OK_NO_CHANGE:
|
|
// No change, don't update status.
|
|
break;
|
|
case TLS_FLASH_ERR_CORRUPT:
|
|
// Corrupt. Always update status.
|
|
genuStatus = status;
|
|
break;
|
|
case TLS_FLASH_ERR_NO_CHANGE:
|
|
// Failed flash write. Update status if no more serious error.
|
|
if ((genuStatus != TLS_FLASH_ERR_CORRUPT) && (genuStatus != TLS_FLASH_ERR_UNKNOWN))
|
|
genuStatus = status;
|
|
break;
|
|
default:
|
|
// Don't expect any other case. Ensure we don't mask a previous corrupt error.
|
|
if (genuStatus != TLS_FLASH_ERR_CORRUPT)
|
|
genuStatus = TLS_FLASH_ERR_UNKNOWN;
|
|
break;
|
|
}
|
|
}
|
|
if (bCallApp && gpfAppSSLCb)
|
|
gpfAppSSLCb(M2M_SSL_RESP_WRITE_OWN_CERTS, &genuStatus);
|
|
}
|
|
break;
|
|
}
|
|
if(s8tmp != M2M_SUCCESS)
|
|
{
|
|
M2M_ERR("Error receiving SSL from the HIF\n");
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
@fn \ m2m_ssl_handshake_rsp(tstrEccReqInfo* strECCResp, uint8* pu8RspDataBuff, uint16 u16RspDataSz)
|
|
@brief Sends ECC responses to the WINC
|
|
@param [in] strECCResp
|
|
ECC Response struct.
|
|
@param [in] pu8RspDataBuffe
|
|
Pointer of the response data to be sent.
|
|
@param [in] u16RspDataSz
|
|
Response data size.
|
|
@return The function SHALL return 0 for success and a negative value otherwise.
|
|
*/
|
|
NMI_API sint8 m2m_ssl_handshake_rsp(tstrEccReqInfo* strECCResp, uint8* pu8RspDataBuff, uint16 u16RspDataSz)
|
|
{
|
|
sint8 s8Ret = M2M_SUCCESS;
|
|
|
|
s8Ret = hif_send(M2M_REQ_GROUP_SSL, (M2M_SSL_RESP_ECC | M2M_REQ_DATA_PKT), (uint8*)strECCResp, sizeof(tstrEccReqInfo), pu8RspDataBuff, u16RspDataSz, sizeof(tstrEccReqInfo));
|
|
|
|
return s8Ret;
|
|
}
|
|
|
|
/*!
|
|
@fn \ m2m_ssl_send_certs_to_winc(uint8* sector_buffer, uint32 sector_size)
|
|
@brief Sends certificates to the WINC
|
|
@param [in] pu8Buffer
|
|
Pointer to the certificates.
|
|
@param [in] u32BufferSz
|
|
Size of the certificates.
|
|
@return The function SHALL return 0 for success and a negative value otherwise.
|
|
*/
|
|
NMI_API sint8 m2m_ssl_send_certs_to_winc(uint8* pu8Buffer, uint32 u32BufferSz)
|
|
{
|
|
sint8 s8Ret = M2M_SUCCESS;
|
|
#define TXLIMIT (256 * 6)
|
|
|
|
if(u32BufferSz <= TXLIMIT)
|
|
{
|
|
// set chunk header for one chunk
|
|
tstrTlsSrvChunkHdr *pchkhdr = (tstrTlsSrvChunkHdr *)pu8Buffer;
|
|
pchkhdr->u16Sig = TLS_CERTS_CHUNKED_SIG_VALUE;
|
|
pchkhdr->u16TotalSize32 = (u32BufferSz + 3) >> 2;
|
|
pchkhdr->u16Offset32 = 0;
|
|
pchkhdr->u16Size32 = (u32BufferSz + 3) >> 2;
|
|
s8Ret = hif_send(M2M_REQ_GROUP_SSL, (M2M_SSL_REQ_WRITE_OWN_CERTS | M2M_REQ_DATA_PKT), NULL, 0, pu8Buffer, u32BufferSz, 0);
|
|
M2M_INFO("Transferred %u bytes of cert data NON-CHUNKED\n", u32BufferSz);
|
|
}
|
|
else
|
|
{
|
|
// chunk it
|
|
// We are sneaking in a header - tstrTlsSrvChunkHdr
|
|
#define CHUNKHDRSZ (sizeof(tstrTlsSrvChunkHdr))
|
|
#define CHUNKSZ (TXLIMIT - 256) // divisible by 4
|
|
uint8 saveblob[CHUNKHDRSZ];
|
|
uint32 ofs = 0;
|
|
uint32 thischunksz = 0;
|
|
|
|
// first is special - over writing our header
|
|
m2m_memcpy(saveblob, &pu8Buffer[ofs], CHUNKHDRSZ);
|
|
thischunksz = min(CHUNKSZ,u32BufferSz-ofs); // no need to round up to quad words this time
|
|
|
|
tstrTlsSrvChunkHdr* pchkhdr = (tstrTlsSrvChunkHdr*)&pu8Buffer[ofs];
|
|
pchkhdr->u16Sig = TLS_CERTS_CHUNKED_SIG_VALUE;
|
|
pchkhdr->u16TotalSize32 = ((u32BufferSz + 3) >> 2);
|
|
pchkhdr->u16Offset32 = ((ofs + 3) >> 2);
|
|
pchkhdr->u16Size32 = ((thischunksz + 3) >> 2);
|
|
s8Ret = hif_send(M2M_REQ_GROUP_SSL, (M2M_SSL_REQ_WRITE_OWN_CERTS | M2M_REQ_DATA_PKT), NULL, 0, &pu8Buffer[ofs], thischunksz, 0);
|
|
M2M_INFO("Transferred %u bytes of cert data CHUNKED to offset %u total %u\n", thischunksz, ofs, u32BufferSz);
|
|
m2m_memcpy(&pu8Buffer[ofs], saveblob, CHUNKHDRSZ);
|
|
ofs += thischunksz;
|
|
|
|
while (ofs < u32BufferSz)
|
|
{
|
|
// Subsequent chunks write header before and send a little more
|
|
m2m_memcpy(saveblob, &pu8Buffer[ofs-CHUNKHDRSZ], CHUNKHDRSZ);
|
|
thischunksz = min(CHUNKSZ,u32BufferSz-ofs);
|
|
thischunksz = (thischunksz + 3) & 0xFFFFFFFC; // needs to round up to quad word length
|
|
pchkhdr = (tstrTlsSrvChunkHdr*)&pu8Buffer[ofs - CHUNKHDRSZ];
|
|
pchkhdr->u16Sig = TLS_CERTS_CHUNKED_SIG_VALUE;
|
|
pchkhdr->u16TotalSize32 = ((u32BufferSz + 3) >> 2);
|
|
pchkhdr->u16Offset32 = ((ofs + 3) >> 2);
|
|
pchkhdr->u16Size32 = ((thischunksz + 3) >> 2);
|
|
s8Ret = hif_send(M2M_REQ_GROUP_SSL, (M2M_SSL_REQ_WRITE_OWN_CERTS | M2M_REQ_DATA_PKT), NULL, 0, &pu8Buffer[ofs - CHUNKHDRSZ], thischunksz + CHUNKHDRSZ, 0);
|
|
M2M_INFO("Transferred %u bytes of cert data CHUNKED to offset %u total %u\n", thischunksz, ofs, u32BufferSz);
|
|
m2m_memcpy(&pu8Buffer[ofs - CHUNKHDRSZ], saveblob, CHUNKHDRSZ);
|
|
ofs += thischunksz;
|
|
}
|
|
}
|
|
|
|
return s8Ret;
|
|
}
|
|
|
|
/*!
|
|
@fn \ m2m_ssl_retrieve_cert(uint32 u32ReadAddr, uint16* pu16CurveType, uint8* pu8Hash, uint8* pu8Sig, tstrECPoint* pu8Key)
|
|
@brief Retrieve the certificate to be verified from the WINC
|
|
@param [in] pu16CurveType
|
|
Pointer to the certificate curve type.
|
|
@param [in] pu8Hash
|
|
Pointer to the certificate hash.
|
|
@param [in] pu8Sig
|
|
Pointer to the certificate signature.
|
|
@param [in] pu8Key
|
|
Pointer to the certificate Key.
|
|
@return The function SHALL return 0 for success and a negative value otherwise.
|
|
*/
|
|
NMI_API sint8 m2m_ssl_retrieve_cert(uint16* pu16CurveType, uint8* pu8Hash, uint8* pu8Sig, tstrECPoint* pu8Key)
|
|
{
|
|
uint8 bSetRxDone = 1;
|
|
uint16 u16HashSz, u16SigSz, u16KeySz;
|
|
sint8 s8Ret = M2M_SUCCESS;
|
|
|
|
if(gu32HIFAddr == 0) return M2M_ERR_FAIL;
|
|
|
|
if(hif_receive(gu32HIFAddr, (uint8*)pu16CurveType, 2, 0) != M2M_SUCCESS) goto __ERR;
|
|
gu32HIFAddr += 2;
|
|
|
|
if(hif_receive(gu32HIFAddr, (uint8*)&u16KeySz, 2, 0) != M2M_SUCCESS) goto __ERR;
|
|
gu32HIFAddr += 2;
|
|
|
|
if(hif_receive(gu32HIFAddr, (uint8*)&u16HashSz, 2, 0) != M2M_SUCCESS) goto __ERR;
|
|
gu32HIFAddr += 2;
|
|
|
|
if(hif_receive(gu32HIFAddr, (uint8*)&u16SigSz, 2, 0) != M2M_SUCCESS) goto __ERR;
|
|
gu32HIFAddr += 2;
|
|
|
|
(*pu16CurveType)= _htons((*pu16CurveType));
|
|
pu8Key->u16Size = _htons(u16KeySz);
|
|
u16HashSz = _htons(u16HashSz);
|
|
u16SigSz = _htons(u16SigSz);
|
|
|
|
if(hif_receive(gu32HIFAddr, pu8Key->X, pu8Key->u16Size * 2, 0) != M2M_SUCCESS) goto __ERR;
|
|
gu32HIFAddr += (pu8Key->u16Size * 2);
|
|
|
|
if(hif_receive(gu32HIFAddr, pu8Hash, u16HashSz, 0) != M2M_SUCCESS) goto __ERR;
|
|
gu32HIFAddr += u16HashSz;
|
|
|
|
if(hif_receive(gu32HIFAddr, pu8Sig, u16SigSz, 0) != M2M_SUCCESS) goto __ERR;
|
|
gu32HIFAddr += u16SigSz;
|
|
|
|
bSetRxDone = 0;
|
|
|
|
__ERR:
|
|
if(bSetRxDone)
|
|
{
|
|
s8Ret = M2M_ERR_FAIL;
|
|
hif_receive(0, NULL, 0, 1);
|
|
}
|
|
return s8Ret;
|
|
}
|
|
|
|
/*!
|
|
@fn \ m2m_ssl_retrieve_hash(uint32 u32ReadAddr, uint8* pu8Hash, uint16 u16HashSz)
|
|
@brief Retrieve the certificate hash
|
|
@param [in] pu8Hash
|
|
Pointer to the certificate hash.
|
|
@param [in] u16HashSz
|
|
Hash size.
|
|
@return The function SHALL return 0 for success and a negative value otherwise.
|
|
*/
|
|
NMI_API sint8 m2m_ssl_retrieve_hash(uint8* pu8Hash, uint16 u16HashSz)
|
|
{
|
|
uint8 bSetRxDone = 1;
|
|
sint8 s8Ret = M2M_SUCCESS;
|
|
|
|
if(gu32HIFAddr == 0) return M2M_ERR_FAIL;
|
|
|
|
if(hif_receive(gu32HIFAddr, pu8Hash, u16HashSz, 0) != M2M_SUCCESS) goto __ERR;
|
|
|
|
bSetRxDone = 0;
|
|
|
|
__ERR:
|
|
if(bSetRxDone)
|
|
{
|
|
s8Ret = M2M_ERR_FAIL;
|
|
hif_receive(0, NULL, 0, 1);
|
|
}
|
|
return s8Ret;
|
|
}
|
|
|
|
/*!
|
|
@fn \ m2m_ssl_stop_processing_certs(void)
|
|
@brief Stops receiving from the HIF
|
|
*/
|
|
NMI_API void m2m_ssl_stop_processing_certs(void)
|
|
{
|
|
hif_receive(0, NULL, 0, 1);
|
|
}
|
|
|
|
/*!
|
|
@fn \ m2m_ssl_ecc_process_done(void)
|
|
@brief Stops receiving from the HIF
|
|
*/
|
|
NMI_API void m2m_ssl_ecc_process_done(void)
|
|
{
|
|
gu32HIFAddr = 0;
|
|
}
|
|
|
|
/*!
|
|
@fn \
|
|
m2m_ssl_set_active_ciphersuites(uint32 u32SslCsBMP);
|
|
Override the default Active SSL ciphers in the SSL module with a certain combination selected by the caller in the form of
|
|
a bitmap containing the required ciphers to be on.
|
|
There is no need to call this function if the application will not change the default ciphersuites.
|
|
|
|
@param [in] u32SslCsBMP
|
|
Bitmap containing the desired ciphers to be enabled for the SSL module. The ciphersuites are defined in
|
|
@ref SSLCipherSuiteID.
|
|
The default ciphersuites are all ciphersuites supported by the firmware with the exception of ECC ciphersuites.
|
|
The caller can override the default with any desired combination, except for combinations involving both RSA
|
|
and ECC; if any RSA ciphersuite is enabled, then firmware will disable all ECC ciphersuites.
|
|
If u32SslCsBMP does not contain any ciphersuites supported by firmware, then the current active list will not
|
|
be changed.
|
|
|
|
@return
|
|
- [SOCK_ERR_NO_ERROR](@ref SOCK_ERR_NO_ERROR)
|
|
- [SOCK_ERR_INVALID_ARG](@ref SOCK_ERR_INVALID_ARG)
|
|
*/
|
|
sint8 m2m_ssl_set_active_ciphersuites(uint32 u32SslCsBMP)
|
|
{
|
|
sint8 s8Ret = M2M_SUCCESS;
|
|
tstrSslSetActiveCsList strCsList;
|
|
|
|
strCsList.u32CsBMP = u32SslCsBMP;
|
|
s8Ret = hif_send(M2M_REQ_GROUP_SSL, M2M_SSL_REQ_SET_CS_LIST, (uint8*)&strCsList, sizeof(tstrSslSetActiveCsList), NULL, 0, 0);
|
|
|
|
return s8Ret;
|
|
}
|
|
|
|
/*!
|
|
@fn \ m2m_ssl_init(tpfAppSslCb pfAppSslCb);
|
|
@brief Initializes the SSL layer.
|
|
@param [in] pfAppSslCb
|
|
Application SSL callback function.
|
|
@return The function SHALL return 0 for success and a negative value otherwise.
|
|
*/
|
|
NMI_API sint8 m2m_ssl_init(tpfAppSSLCb pfAppSSLCb)
|
|
{
|
|
sint8 s8Ret = M2M_SUCCESS;
|
|
|
|
gpfAppSSLCb = pfAppSSLCb;
|
|
gu32HIFAddr = 0;
|
|
genuStatus = TLS_FLASH_ERR_UNKNOWN;
|
|
|
|
s8Ret = hif_register_cb(M2M_REQ_GROUP_SSL,m2m_ssl_cb);
|
|
if (s8Ret != M2M_SUCCESS)
|
|
{
|
|
M2M_ERR("hif_register_cb() failed with ret=%d", s8Ret);
|
|
}
|
|
return s8Ret;
|
|
} |