diff --git a/src/winc1500/include/programmer/programmer.h b/src/winc1500/include/programmer/programmer.h new file mode 100644 index 000000000..57c679df7 --- /dev/null +++ b/src/winc1500/include/programmer/programmer.h @@ -0,0 +1,61 @@ +/** + * + * \file + * + * \brief Programmer APIs. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#ifndef IMAGE_DOWNLOADER_H_INCLUDED +#define IMAGE_DOWNLOADER_H_INCLUDED + +#include "spi_flash/include/spi_flash_map.h" +#include "spi_flash/include/spi_flash.h" +#include "programmer/programmer_apis.h" + +#define ROOT_CERT_SIZE M2M_TLS_FLASH_ROOTCERT_CACHE_SIZE + +#define programmer_get_flash_size() (((spi_flash_get_size() * 1024) / 8) * 1024) +#define programmer_write(pu8Buf, u32Offset, u32Sz) spi_flash_write(pu8Buf, u32Offset, u32Sz) +#define programmer_erase(u32Offset, u32Sz) spi_flash_erase(u32Offset, u32Sz) +#define programmer_eraseall() programmer_erase(0, programmer_get_flash_size()) +#define programmer_read(pu8Buf, u32Offset, u32Sz) spi_flash_read(pu8Buf, u32Offset, u32Sz) + +int burn_firmware(void); +int verify_firmware(void); +int burn_certificates(void); +int verify_certificates(void); +#endif /* IMAGE_DOWNLOADER_H_INCLUDED */ diff --git a/src/winc1500/include/programmer/programmer_apis.h b/src/winc1500/include/programmer/programmer_apis.h new file mode 100644 index 000000000..376bf37ee --- /dev/null +++ b/src/winc1500/include/programmer/programmer_apis.h @@ -0,0 +1,56 @@ +/** + * + * \file + * + * \brief Programmer APIs. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#ifndef FIRMWARE_PROGRAMMER_APIS_H_INCLUDED +#define FIRMWARE_PROGRAMMER_APIS_H_INCLUDED + +#include "common/include/nm_common.h" +#include "spi_flash/include/spi_flash_map.h" + +#define programmer_write_cert_image(buff) programmer_write((uint8*)buff, M2M_TLS_FLASH_ROOTCERT_CACHE_OFFSET, M2M_TLS_FLASH_ROOTCERT_CACHE_SIZE) +#define programmer_read_cert_image(buff) programmer_read((uint8*)buff, M2M_TLS_FLASH_ROOTCERT_CACHE_OFFSET, M2M_TLS_FLASH_ROOTCERT_CACHE_SIZE) +#define programmer_erase_cert_image() programmer_erase(M2M_TLS_FLASH_ROOTCERT_CACHE_OFFSET, M2M_TLS_FLASH_ROOTCERT_CACHE_SIZE) + +#define programmer_write_firmware_image(buff,offSet,sz) programmer_write((uint8*)buff, offSet, sz) +#define programmer_read_firmware_image(buff,offSet,sz) programmer_read((uint8*)buff, offSet, sz) + +#define programmer_erase_all() programmer_erase(0, programmer_get_flash_size()) +#endif /* FIRMWARE_PROGRAMMER_APIS_H_INCLUDED */ diff --git a/src/winc1500/include/root_cert/root_setup.h b/src/winc1500/include/root_cert/root_setup.h new file mode 100644 index 000000000..c9d0ed34c --- /dev/null +++ b/src/winc1500/include/root_cert/root_setup.h @@ -0,0 +1,49 @@ +/** + * + * \file + * + * \brief Root Certificate Setup. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#ifndef ROOT_CERT_SETUP_H_INCLUDED +#define ROOT_CERT_SETUP_H_INCLUDED + +#include "programmer/programmer.h" + +int WriteRootCertificate(const char *filename, char *pcRootCertFileData, uint32 u32FileSize); + +#endif /* ROOT_CERT_SETUP_H_INCLUDED */ diff --git a/src/winc1500/include/root_cert/x509/asn1.h b/src/winc1500/include/root_cert/x509/asn1.h new file mode 100644 index 000000000..3d3846e0c --- /dev/null +++ b/src/winc1500/include/root_cert/x509/asn1.h @@ -0,0 +1,84 @@ +/** + * + * \file + * + * \brief ASN1. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#ifndef ASN1_H_INCLUDED +#define ASN1_H_INCLUDED + +#include "common/include/nm_common.h" + +/* ASN.1 TAG DEFINITIONS. */ +#define ASN1_INVALID 0x00 +#define ASN1_BOOLEAN 0x01 +#define ASN1_INTEGER 0x02 +#define ASN1_BIT_STRING 0x03 +#define ASN1_OCTET_STRING 0x04 +#define ASN1_NULL 0x05 +#define ASN1_OBJECT_IDENTIFIER 0x06 +#define ASN1_UTF8_DTRING 0x0C +#define ASN1_PRINTABLE_STRING 0x13 +#define ASN1_TELETEX_STRING 0x14 +#define ASN1_UTC_TIME 0x17 +#define ASN1_GENERALIZED_TIME 0x18 +#define ASN1_SEQUENCE 0x30 +#define ASN1_SET 0x31 + +#define ASN1_SUCCESS 0 + +#define ASN1_FAIL -1 + +typedef struct { + uint8 *pu8Buff; + uint8 *pu8Data; + uint16 u16BuffLen; +} tstrAsn1Context; + +typedef struct { + uint32 u32Length; + uint8 u8Tag; +} tstrAsn1Element; + +uint16 ASN1_GetNextElement(tstrAsn1Context *pstrAsn1Ctxt, tstrAsn1Element *pstrElement); + +uint16 ASN1_Read(tstrAsn1Context *pstrAsn1Cxt, uint32 u32ReadLength, uint8 *pu8ReadBuffer); + +uint16 ASN1_ReadReference(tstrAsn1Context *pstrAsn1Cxt, uint32 u32ReadLength, uint8 **ppu8ReadBuffer); + +#endif /* ASN1_H_INCLUDED */ diff --git a/src/winc1500/include/root_cert/x509/common.h b/src/winc1500/include/root_cert/x509/common.h new file mode 100644 index 000000000..4bbe398fc --- /dev/null +++ b/src/winc1500/include/root_cert/x509/common.h @@ -0,0 +1,101 @@ +/** + * + * \file + * + * \brief Common Functions. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#ifndef COMMON_H_INCLUDED +#define COMMON_H_INCLUDED + +#include "common/include/nm_common.h" +#include +#ifdef WIN32 +#include +#endif + +typedef struct { + uint16 u16BufferSize; + uint8 *pu8Data; +} tstrBuffer; + +/* Used for time storage. */ +typedef struct { + uint16 u16Year; + uint8 u8Month; + uint8 u8Day; + uint8 u8Hour; + uint8 u8Minute; + uint8 u8Second; +} tstrSystemTime; + +#define SIZE_128_BITS (16) +#define SIZE_256_BITS (32) +#define SIZE_512_BITS (64) +#define SIZE_1024_BITS (128) +#define SIZE_1536_BITS (192) +#define SIZE_2048_BITS (256) + +#define GETU16(BUF, OFFSET) ((((uint16)((BUF)[OFFSET]) << 8)) | (((uint16)(BUF)[OFFSET + 1]))) + +/*!< Retrieve 2 bytes from the given buffer at the given + * offset as 16-bit unsigned integer in the Network byte order. + */ + +#define GETU32(BUF,OFFSET) ((((uint32)((BUF)[OFFSET]) << 24)) | (((uint32)((BUF)[OFFSET + 1]) << 16)) | \ + (((uint32)((BUF)[OFFSET + 2]) << 8)) | ((uint32)((BUF)[OFFSET + 3]))) +/*!< Retrieve 4 bytes from the given buffer at the given + offset as 32-bit unsigned integer in the Network byte order. +*/ + +#define PUTU32(VAL32, BUF, OFFSET) \ + do \ + { \ + (BUF)[OFFSET ] = BYTE_3((VAL32)); \ + (BUF)[OFFSET + 1 ] = BYTE_2((VAL32)); \ + (BUF)[OFFSET + 2 ] = BYTE_1((VAL32)); \ + (BUF)[OFFSET + 3 ] = BYTE_0((VAL32)); \ + } while (0) + +#define PUTU16(VAL16, BUF, OFFSET) \ + do \ + { \ + (BUF)[OFFSET ] = BYTE_1((VAL16)); \ + (BUF)[OFFSET + 1 ] = BYTE_0((VAL16)); \ + } while (0) + +#endif /* COMMON_H_INCLUDED */ diff --git a/src/winc1500/include/root_cert/x509/hash.h b/src/winc1500/include/root_cert/x509/hash.h new file mode 100644 index 000000000..1dfbbd457 --- /dev/null +++ b/src/winc1500/include/root_cert/x509/hash.h @@ -0,0 +1,112 @@ +/** + * + * \file + * + * \brief Hash Functions. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#ifndef HASH_H_INCLUDED +#define HASH_H_INCLUDED + +#include "common.h" + +#define SHA_BLOCK_SIZE 64 + +#define MD5_DIGEST_SIZE (16) +#define SHA1_DIGEST_SIZE (20) +#define SHA256_DIGEST_SIZE 32 + +#define SHA_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE + +#define SHA_FLAGS_INIT 0x01 + +/*!< A flag to tell the hash function to + * start hash from the initial state. + */ + +#define SHA_FLAGS_UPDATE 0x02 + +/*!< Update the current hash with the + * given data. + */ + +#define SHA_FLAGS_FINISH 0x04 + +/*!< Finalize the hashing and calculate + * the final result. + */ + +#define SHA_FLAGS_FULL_HASH (SHA_FLAGS_INIT | SHA_FLAGS_UPDATE | SHA_FLAGS_FINISH) + +#define SHA1_INIT(ctxt) SHA1_Hash((ctxt), SHA_FLAGS_INIT, NULL, 0, NULL) +#define SHA1_UPDATE(ctxt, data, dataLen) SHA1_Hash((ctxt), SHA_FLAGS_UPDATE, (data), (dataLen), NULL) +#define SHA1_FINISH(ctxt, digest) SHA1_Hash((ctxt), SHA_FLAGS_FINISH, NULL, 0, digest) + +#define MD5_INIT(ctxt) MD5_Hash((ctxt), SHA_FLAGS_INIT, NULL, 0, NULL) +#define MD5_UPDATE(ctxt, data, dataLen) MD5_Hash((ctxt), SHA_FLAGS_UPDATE, (data), (dataLen), NULL) +#define MD5_FINISH(ctxt, digest) MD5_Hash((ctxt), SHA_FLAGS_FINISH, NULL, 0, digest) + +typedef void (*tpfHashProcessBlock)(uint32 *pu32HashState, const uint8 *pu8MessageBlock); + +typedef struct { + uint32 au32HashState[SHA_MAX_DIGEST_SIZE / 4]; + uint8 au8CurrentBlock[SHA_BLOCK_SIZE]; + uint32 u32TotalLength; + tpfHashProcessBlock fpHash; + uint8 u8BlockSize; + uint8 u8DigestSize; +} tstrHashContext; + +typedef tstrHashContext tstrMd5Context; +typedef tstrHashContext tstrSha1Context; +typedef tstrHashContext tstrSha256Context; + +typedef void (*tpfHash) +( + tstrHashContext *pstrHashContext, + uint8 u8Flags, + uint8 *pu8Data, + uint32 u32DataLength, + uint8 *pu8Digest +); + +void MD5_Hash(tstrHashContext *pstrMD5Context, uint8 u8Flags, uint8 *pu8Data, uint32 u32DataLength, uint8 *pu8Digest); +void HMAC_Vector(tpfHash fpHash, uint8 *pu8Key, uint32 u32KeyLength, tstrBuffer *pstrInData, uint8 u8NumInputs, uint8 *pu8Out); +void SHA1_Hash(tstrHashContext *pstrSha1Context, uint8 u8Flags, uint8 *pu8Data, uint32 u32DataLength, uint8 *pu8Digest); +void SHA256_Hash(tstrHashContext *pstrSha256Context, uint8 u8Flags, uint8 *pu8Data, uint32 u32DataLength, uint8 *pu8Digest); + +#endif /* HASH_H_INCLUDED */ diff --git a/src/winc1500/include/root_cert/x509/x509_cert.h b/src/winc1500/include/root_cert/x509/x509_cert.h new file mode 100644 index 000000000..1e738f145 --- /dev/null +++ b/src/winc1500/include/root_cert/x509/x509_cert.h @@ -0,0 +1,177 @@ +/** + * + * \file + * + * \brief X509 Certificate Functions. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#ifndef X509_CERT_H_INCLUDED +#define X509_CERT_H_INCLUDED + +#include "common.h" +#include "hash.h" + +#define X509_SUCCESS 0 +#define X509_FAIL -1 + +#define X509_SERIAL_NO_MAX_LENGTH 20 + +/* X509 ALGORITHMS. */ +#define X509_ALG_NULL 0 +#define X509_PUB_RSA 1 +#define X509_SIGN_MD5RSA 2 +#define X509_SIGN_SHA1RSA 3 +#define X509_SIGN_SHA256RSA 4 +#define X509_SIGN_SHA384RSA 5 +#define X509_SIGN_SHA512RSA 6 + +#define X509_STATUS_VALID 0 +/*!< + * The X.509 certificate is valid. + */ + +#define X509_STATUS_EXPIRED 1 +/*!< + * The X.509 certificate is expired. + */ + +#define X509_STATUS_REVOKED 2 +/*!< + * The X.509 certificate is marked as revoked and should not + * be trusted. + */ + +#define X509_STATUS_DECODE_ERR 4 +/*!< + * Error decoding the certificate time. + */ + +#define X509_CERT_DUMP X509Cert_Dump +#define X509_CERT_IS_VALID X509Cert_IsValid + +typedef enum { + PUBKEY_ALG_RSA, + PUBKEY_ALG_DH, + PUBKEY_ALG_ECDH +} tenuPubKeyAlg; + +typedef enum { + SIGN_VERIFY, + SIGN_GEN +} tenuSignMode; + +/*! + * @struct tstrDHPublicKey + * + * @brief Diffie-Hellman Public Key Definition + */ +typedef struct { + uint8 *pu8P; + uint8 *pu8G; + uint8 *pu8Key; + uint16 u16PSize; + uint16 u16GSize; + uint16 u16KeySize; +} tstrDHPublicKey; + +/*! + * @struct tstrRSAPublicKey + * + * @brief RSA Public Key Definition + */ +typedef struct { + uint16 u16NSize; + uint16 u16ESize; + uint8 *pu8N; + uint8 *pu8E; +} tstrRSAPublicKey; + +typedef struct { + tenuPubKeyAlg enuType; + union { + tstrRSAPublicKey strRSAKey; + tstrDHPublicKey strDHKey; + }; +} tstrPublicKey; + +typedef struct { + char acCmnName[65]; + char acOrg[65]; + char acOrgUnit[65]; + uint8 au8NameSHA1[SHA1_DIGEST_SIZE]; +} tstrX520Name; + +typedef struct { + uint8 au8Time[20]; +} tstrX509Time; + +typedef struct { + uint8 u8Version; + /*!< + * X509 version. + */ + + uint8 u8SerialNumberLength; + /*!< + * X509 certificate serial number Length in bytes. + */ + + uint8 au8SerialNo[X509_SERIAL_NO_MAX_LENGTH]; + /*!< + * X509 certificate serial number. + */ + + uint8 u8SignAlg; + /*!< + * X509 certificate serial number Length in bytes. + */ + + uint8 u8ValidityStatus; + tstrX520Name strIssuer; + tstrX509Time strStartDate; + tstrX509Time strExpiryDate; + tstrX520Name strSubject; + tstrPublicKey strPubKey; + tstrBuffer strSignature; + uint8 *pu8TBSCert; + uint16 u16TBSCertSize; +} tstrX509Cert; + +sint8 X509Cert_Decode(uint8 *pu8X509Buffer, uint32 u32CertSize, tstrX509Cert *pstrCert, uint8 bDumpX509); +void X509Cert_Dump(void *pvCert); + +#endif /* X509_CERT_H_INCLUDED */ diff --git a/src/winc1500/include/spi_flash/include/spi_flash.h b/src/winc1500/include/spi_flash/include/spi_flash.h new file mode 100644 index 000000000..ed2d9e734 --- /dev/null +++ b/src/winc1500/include/spi_flash/include/spi_flash.h @@ -0,0 +1,223 @@ +/** + * + * \file + * + * \brief WINC1500 SPI Flash. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +/** \defgroup SPIFLASH Spi Flash + * @file spi_flash.h + * @brief This file describe SPI flash APIs, how to use it and limitations with each one. + * @section Example + * This example illustrates a complete guide of how to use these APIs. + * @code{.c} + #include "spi_flash.h" + + #define DATA_TO_REPLACE "THIS IS A NEW SECTOR IN FLASH" + + int main() + { + uint8 au8FlashContent[FLASH_SECTOR_SZ] = {0}; + uint32 u32FlashTotalSize = 0; + uint32 u32FlashOffset = 0; + + ret = m2m_wifi_download_mode(); + if(M2M_SUCCESS != ret) + { + printf("Unable to enter download mode\r\n"); + } + else + { + u32FlashTotalSize = spi_flash_get_size(); + } + + while((u32FlashTotalSize > u32FlashOffset) && (M2M_SUCCESS == ret)) + { + ret = spi_flash_read(au8FlashContent, u32FlashOffset, FLASH_SECTOR_SZ); + if(M2M_SUCCESS != ret) + { + printf("Unable to read SPI sector\r\n"); + break; + } + memcpy(au8FlashContent, DATA_TO_REPLACE, strlen(DATA_TO_REPLACE)); + + ret = spi_flash_erase(u32FlashOffset, FLASH_SECTOR_SZ); + if(M2M_SUCCESS != ret) + { + printf("Unable to erase SPI sector\r\n"); + break; + } + + ret = spi_flash_write(au8FlashContent, u32FlashOffset, FLASH_SECTOR_SZ); + if(M2M_SUCCESS != ret) + { + printf("Unable to write SPI sector\r\n"); + break; + } + u32FlashOffset += FLASH_SECTOR_SZ; + } + + if(M2M_SUCCESS == ret) + { + printf("Successful operations\r\n"); + } + else + { + printf("Failed operations\r\n"); + } + + while(1); + return M2M_SUCCESS; + } + * @endcode + */ + +#ifndef __SPI_FLASH_H__ +#define __SPI_FLASH_H__ +#include "common/include/nm_common.h" +#include "bus_wrapper/include/nm_bus_wrapper.h" +#include "driver/include/nmbus.h" +#include "driver/include/nmasic.h" +#include "spi_flash/include/spi_flash_map.h" + +/** + * @fn spi_flash_enable + * @brief Enable spi flash operations + * @version 1.0 + */ +sint8 spi_flash_enable(uint8 enable); +/** \defgroup SPIFLASHAPI Function + * @ingroup SPIFLASH + */ + + /** @defgroup SPiFlashGetFn spi_flash_get_size + * @ingroup SPIFLASHAPI + */ + /**@{*/ +/*! + * @fn uint32 spi_flash_get_size(void); + * @brief Returns with \ref uint32 value which is total flash size\n + * @note Returned value in Mb (Mega Bit). + * @return SPI flash size in case of success and a ZERO value in case of failure. + */ +uint32 spi_flash_get_size(void); + /**@}*/ + + /** @defgroup SPiFlashRead spi_flash_read + * @ingroup SPIFLASHAPI + */ + /**@{*/ +/*! + * @fn sint8 spi_flash_read(uint8 *, uint32, uint32); + * @brief Read a specified portion of data from SPI Flash.\n + * @param [out] pu8Buf + * Pointer to data buffer which will fill in with data in case of successful operation. + * @param [in] u32Addr + * Address (Offset) to read from at the SPI flash. + * @param [in] u32Sz + * Total size of data to be read in bytes + * @warning + * - Address (offset) plus size of data must not exceed flash size.\n + * - No firmware is required for reading from SPI flash.\n + * - In case of there is a running firmware, it is required to pause your firmware first + * before any trial to access SPI flash to avoid any racing between host and running firmware on bus using + * @ref m2m_wifi_download_mode + * @note + * - It is blocking function\n + * @sa m2m_wifi_download_mode, spi_flash_get_size + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + */ +sint8 spi_flash_read(uint8 *pu8Buf, uint32 u32Addr, uint32 u32Sz); + /**@}*/ + + /** @defgroup SPiFlashWrite spi_flash_write + * @ingroup SPIFLASHAPI + */ + /**@{*/ +/*! + * @fn sint8 spi_flash_write(uint8 *, uint32, uint32); + * @brief Write a specified portion of data to SPI Flash.\n + * @param [in] pu8Buf + * Pointer to data buffer which contains the required to be written. + * @param [in] u32Offset + * Address (Offset) to write at the SPI flash. + * @param [in] u32Sz + * Total number of size of data bytes + * @note + * - It is blocking function\n + * - It is user's responsibility to verify that data has been written successfully + * by reading data again and compare it with the original. + * @warning + * - Address (offset) plus size of data must not exceed flash size.\n + * - No firmware is required for writing to SPI flash.\n + * - In case of there is a running firmware, it is required to pause your firmware first + * before any trial to access SPI flash to avoid any racing between host and running firmware on bus using + * @ref m2m_wifi_download_mode. + * - Before writing to any section, it is required to erase it first. + * @sa m2m_wifi_download_mode, spi_flash_get_size, spi_flash_erase + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + + */ +sint8 spi_flash_write(uint8* pu8Buf, uint32 u32Offset, uint32 u32Sz); + /**@}*/ + + /** @defgroup SPiFlashErase spi_flash_erase + * @ingroup SPIFLASHAPI + */ + /**@{*/ +/*! + * @fn sint8 spi_flash_erase(uint32, uint32); + * @brief Erase a specified portion of SPI Flash.\n + * @param [in] u32Offset + * Address (Offset) to erase from the SPI flash. + * @param [in] u32Sz + * Size of SPI flash required to be erased. + * @note It is blocking function \n +* @warning +* - Address (offset) plus size of data must not exceed flash size.\n +* - No firmware is required for writing to SPI flash.\n + * - In case of there is a running firmware, it is required to pause your firmware first + * before any trial to access SPI flash to avoid any racing between host and running firmware on bus using + * @ref m2m_wifi_download_mode + * - It is blocking function\n + * @sa m2m_wifi_download_mode, spi_flash_get_size + * @return The function returns @ref M2M_SUCCESS for successful operations and a negative value otherwise. + + */ +sint8 spi_flash_erase(uint32 u32Offset, uint32 u32Sz); + /**@}*/ +#endif //__SPI_FLASH_H__ diff --git a/src/winc1500/include/spi_flash/include/spi_flash_map.h b/src/winc1500/include/spi_flash/include/spi_flash_map.h new file mode 100644 index 000000000..740ba1e63 --- /dev/null +++ b/src/winc1500/include/spi_flash/include/spi_flash_map.h @@ -0,0 +1,230 @@ +/** + * + * \file + * + * \brief SPI Flash Memory Mapping. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#ifndef SPI_FLASH_MAP_H_INCLUDED +#define SPI_FLASH_MAP_H_INCLUDED + +#define FLASH_MAP_VER_0 (0) +#define FLAAH_MAP_VER_1 (1) + +#define FLASH_MAP_VERSION FLAAH_MAP_VER_1 + +//#define DOWNLOAD_ROLLBACK +//#define OTA_GEN +#define _PROGRAM_POWER_SAVE_ + +/* =======*=======*=======*=======*======= + * General Sizes for Flash Memory + * =======*=======*=======*=======*======= + */ + +#define FLASH_START_ADDR (0UL) +/*! location :xxxK + * "S:xxxK" -means-> Size is :xxxK + */ + +/* + * Boot Firmware: which used to select which firmware to run + * + */ +#define M2M_BOOT_FIRMWARE_STARTING_ADDR (FLASH_START_ADDR) +#define M2M_BOOT_FIRMWARE_FLASH_SZ (FLASH_SECTOR_SZ) + +/* + * Control Section: which used by Boot firmware + * + */ +#define M2M_CONTROL_FLASH_OFFSET (M2M_BOOT_FIRMWARE_STARTING_ADDR + M2M_BOOT_FIRMWARE_FLASH_SZ) +#define M2M_CONTROL_FLASH_BKP_OFFSET (M2M_CONTROL_FLASH_OFFSET + FLASH_SECTOR_SZ) +#define M2M_CONTROL_FLASH_SEC_SZ (FLASH_SECTOR_SZ) +#define M2M_CONTROL_FLASH_TOTAL_SZ (FLASH_SECTOR_SZ * 2) + +/* + * LUT for PLL and TX Gain settings: + * + */ +#define M2M_PLL_FLASH_OFFSET (M2M_CONTROL_FLASH_OFFSET + M2M_CONTROL_FLASH_TOTAL_SZ) +#define M2M_PLL_FLASH_SZ (1024 * 1) +#define M2M_GAIN_FLASH_OFFSET (M2M_PLL_FLASH_OFFSET + M2M_PLL_FLASH_SZ) +#define M2M_GAIN_FLASH_SZ (M2M_CONFIG_SECT_TOTAL_SZ - M2M_PLL_FLASH_SZ) +#define M2M_CONFIG_SECT_TOTAL_SZ (FLASH_SECTOR_SZ) + +/* + * Certificate: + * + */ +#define M2M_TLS_FLASH_ROOTCERT_CACHE_OFFSET (M2M_PLL_FLASH_OFFSET + M2M_CONFIG_SECT_TOTAL_SZ) +#define M2M_TLS_FLASH_ROOTCERT_CACHE_SIZE (FLASH_SECTOR_SZ * 1) + +/* + * Scratch: + * + */ +#define M2M_TLS_FLASH_SESSION_CACHE_OFFSET (M2M_TLS_FLASH_ROOTCERT_CACHE_OFFSET + M2M_TLS_FLASH_ROOTCERT_CACHE_SIZE) +#define M2M_TLS_FLASH_SESSION_CACHE_SIZE (FLASH_SECTOR_SZ * 1) + +/* + * reserved section + * + */ +#define M2M_RESERVED_FLASH_OFFSET (M2M_TLS_FLASH_SESSION_CACHE_OFFSET + M2M_TLS_FLASH_SESSION_CACHE_SIZE) +#define M2M_RESERVED_FLASH_SZ (FLASH_SECTOR_SZ * 1) +/* + * HTTP Files + * + */ +#define M2M_HTTP_MEM_FLASH_OFFSET (M2M_RESERVED_FLASH_OFFSET + M2M_RESERVED_FLASH_SZ) +#define M2M_HTTP_MEM_FLASH_SZ (FLASH_SECTOR_SZ * 2) +/* + * Saved Connection Parameters: + * + */ +#define M2M_CACHED_CONNS_FLASH_OFFSET (M2M_HTTP_MEM_FLASH_OFFSET + M2M_HTTP_MEM_FLASH_SZ) +#define M2M_CACHED_CONNS_FLASH_SZ (FLASH_SECTOR_SZ * 1) + +/* + * + * Common section size + */ + +#define M2M_COMMON_DATA_SEC (M2M_BOOT_FIRMWARE_FLASH_SZ + M2M_CONTROL_FLASH_TOTAL_SZ + M2M_CONFIG_SECT_TOTAL_SZ + \ + M2M_TLS_FLASH_ROOTCERT_CACHE_SIZE + M2M_TLS_FLASH_SESSION_CACHE_SIZE + \ + M2M_HTTP_MEM_FLASH_SZ + M2M_CACHED_CONNS_FLASH_SZ + M2M_RESERVED_FLASH_SZ) +/* + * + * OTA image1 Offset + */ + +#define M2M_OTA_IMAGE1_OFFSET (M2M_CACHED_CONNS_FLASH_OFFSET + M2M_CACHED_CONNS_FLASH_SZ) +/* + * Firmware Offset + * + */ +#if (defined _FIRMWARE_)||(defined OTA_GEN) +#define M2M_FIRMWARE_FLASH_OFFSET (0UL) +#else +#if (defined DOWNLOAD_ROLLBACK) +#define M2M_FIRMWARE_FLASH_OFFSET (M2M_OTA_IMAGE2_OFFSET) +#else +#define M2M_FIRMWARE_FLASH_OFFSET (M2M_OTA_IMAGE1_OFFSET) +#endif +#endif +/* + * + * Firmware + */ +#define M2M_FIRMWARE_FLASH_SZ (236*1024UL) +/** + * + * OTA image Size + */ +#define OTA_IMAGE_SIZE (M2M_FIRMWARE_FLASH_SZ) +/** + * + * Flash Total size + */ +#define FLASH_IMAGE1_CONTENT_SZ (M2M_COMMON_DATA_SEC + OTA_IMAGE_SIZE) + +/** + * + * OTA image 2 offset + */ +#define M2M_OTA_IMAGE2_OFFSET (FLASH_IMAGE1_CONTENT_SZ) + +/* + * App(Cortus App 4M): App. which runs over firmware + * + */ +#define M2M_APP_4M_MEM_FLASH_SZ (FLASH_SECTOR_SZ * 10) +#define M2M_APP_4M_MEM_FLASH_OFFSET (FLASH_4M_TOTAL_SZ - M2M_APP_4M_MEM_FLASH_SZ) + +/* Check if total size of content + * don't exceed total size of memory allowed + **/ +#if (M2M_COMMON_DATA_SEC + (OTA_IMAGE_SIZE *2)> FLASH_4M_TOTAL_SZ) +#error "Excced 4M Flash Size" +#endif /* (FLASH_CONTENT_SZ > FLASH_TOTAL_SZ) */ + +#endif /* SPI_FLASH_MAP_H_INCLUDED */ diff --git a/src/winc1500/src/asn1.c b/src/winc1500/src/asn1.c new file mode 100644 index 000000000..d1febaa12 --- /dev/null +++ b/src/winc1500/src/asn1.c @@ -0,0 +1,120 @@ +/** + * + * \file + * + * \brief ASN1. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#include "root_cert/x509/asn1.h" + +uint16 ASN1_GetNextElement(tstrAsn1Context *pstrAsn1Ctxt, tstrAsn1Element *pstrElement) +{ + uint16 u16ElemLength = 0; + + if ((pstrElement != NULL) && (pstrAsn1Ctxt != NULL)) { + uint8 u8NLenBytes; + + do { + u8NLenBytes = 0; + + /* Get the ASN.1 Element Tag. */ + pstrElement->u8Tag = *pstrAsn1Ctxt->pu8Data++; + + /* Get the ASN.1 element length. */ + pstrElement->u32Length = *pstrAsn1Ctxt->pu8Data++; + pstrElement->u32Length &= 0xFF; + if (pstrElement->u32Length & NBIT7) { + uint8 u8Idx; + uint8 au8Tmp[4]; + + /* Multiple Length octets. */ + u8NLenBytes = (uint8)(pstrElement->u32Length & 0x03); + pstrElement->u32Length = 0; + + m2m_memcpy(au8Tmp, pstrAsn1Ctxt->pu8Data, u8NLenBytes); + pstrAsn1Ctxt->pu8Data += u8NLenBytes; + + for (u8Idx = 0; u8Idx < u8NLenBytes; u8Idx++) { + pstrElement->u32Length += + (uint32)(au8Tmp[u8Idx] << ((u8NLenBytes - u8Idx - 1) * 8)); + } + } + + u16ElemLength += u8NLenBytes + 2 + (uint16)pstrElement->u32Length; + } while (pstrElement->u8Tag == ASN1_NULL); + } + + return u16ElemLength; +} + +uint16 ASN1_Read(tstrAsn1Context *pstrAsn1Cxt, uint32 u32ReadLength, uint8 *pu8ReadBuffer) +{ + uint16 u16Read = 0; + + if (pstrAsn1Cxt != NULL) { + uint16 u16RemLen = pstrAsn1Cxt->u16BuffLen - (uint16)(pstrAsn1Cxt->pu8Data - pstrAsn1Cxt->pu8Buff); + + u16Read = (uint16)((u32ReadLength <= u16RemLen) ? u32ReadLength : u16RemLen); + + if (pu8ReadBuffer != NULL) { + m2m_memcpy(pu8ReadBuffer, pstrAsn1Cxt->pu8Data, u16Read); + } + + pstrAsn1Cxt->pu8Data += u16Read; + } + + return u16Read; +} + +uint16 ASN1_ReadReference(tstrAsn1Context *pstrAsn1Cxt, uint32 u32ReadLength, uint8 **ppu8ReadBuffer) +{ + uint16 u16Read = 0; + + if (pstrAsn1Cxt != NULL) { + uint16 u16RemLen = pstrAsn1Cxt->u16BuffLen - (uint16)(pstrAsn1Cxt->pu8Data - pstrAsn1Cxt->pu8Buff); + + u16Read = (uint16)((u32ReadLength <= u16RemLen) ? u32ReadLength : u16RemLen); + + if (ppu8ReadBuffer != NULL) { + *ppu8ReadBuffer = pstrAsn1Cxt->pu8Data; + } + + pstrAsn1Cxt->pu8Data += u16Read; + } + + return u16Read; +} diff --git a/src/winc1500/src/hash.c b/src/winc1500/src/hash.c new file mode 100644 index 000000000..b6fb9a8d2 --- /dev/null +++ b/src/winc1500/src/hash.c @@ -0,0 +1,527 @@ +/** + * + * \file + * + * \brief Hash Functions. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#include "root_cert/x509/hash.h" + +#define SHA_SHR(x, n) ((x & 0xFFFFFFFF) >> n) +#define SHA_SHL(x, n) ((x & 0xFFFFFFFF) << n) +#define SHA_ROTR(x, n) (SHA_SHR(x, n) | SHA_SHL(x, (32 - n))) +#define SHA_ROTL(x, n) (SHA_SHL(x, n) | SHA_SHR(x, (32 - n))) + +/* MD5 specific defines. */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +#define MD5_INERMEDIATE(A, B, C, D, W, K, S) \ + { \ + W += A + K; \ + W = B + SHA_ROTL(W, S); \ + A = D; \ + D = C; \ + C = B; \ + B = W; \ + } + +/* SHA1 specific defines. */ +#define SHA1_CH(x, y, z) (((x) & (y)) | ((~(x)) & (z))) +#define SHA1_MAJ(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) +#define SHA_PARITY(x, y, z) ((x) ^ (y) ^ (z)) +#define SHA1_INERMEDIATE(A, B, C, D, E, W, K) \ + { \ + W += SHA_ROTL(A, 5) + E + K; \ + E = D; \ + D = C; \ + C = SHA_ROTL(B, 30); \ + B = A; \ + A = W; \ + } + +#define SHA_PAD_BYTE 0x80 + +/* SHA256 specific defines. */ +#define SHA256_SMALL_SIGMA0(x) (SHA_ROTR(x, 7) ^ SHA_ROTR(x, 18) ^ SHA_SHR(x, 3)) +#define SHA256_SMALL_SIGMA1(x) (SHA_ROTR(x, 17) ^ SHA_ROTR(x, 19) ^ SHA_SHR(x, 10)) +#define SHA256_CAP_SIGMA0(x) (SHA_ROTR(x, 2) ^ SHA_ROTR(x, 13) ^ SHA_ROTR(x, 22)) +#define SHA256_CAP_SIGMA1(x) (SHA_ROTR(x, 6) ^ SHA_ROTR(x, 11) ^ SHA_ROTR(x, 25)) +#define SHA256_MAJ(x, y, z) ((x & y) | (z & (x | y))) +#define SHA256_CH(x, y, z) (z ^ (x & (y ^ z))) + +static void MD5ProcessBlock(uint32 *pu32Md5State, const uint8 *pu8MessageBlock) +{ + const uint32 T[] = { + 0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE, 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501, + 0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE, 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821, + 0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA, 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8, + 0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED, 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A, + 0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C, 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70, + 0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05, 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665, + 0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039, 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1, + 0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1, 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391 + }; + uint8 S[] = { + 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, + 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, + 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, + 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 + }; + uint32 A, B, C, D; + uint32 W = 0; + uint32 X[16]; + uint8 u8Idx, u8Count; + + A = pu32Md5State[0]; + B = pu32Md5State[1]; + C = pu32Md5State[2]; + D = pu32Md5State[3]; + + memcpy(X, pu8MessageBlock, 64); + + for (u8Idx = 0; u8Idx < 16; u8Idx++) { + W = F(B, C, D) + X[u8Idx]; + MD5_INERMEDIATE(A, B, C, D, W, T[u8Idx], S[u8Idx]); + } + + for (u8Idx = 16, u8Count = 1; u8Idx < 32; u8Idx++, u8Count += 5) { + W = G(B, C, D) + X[u8Count & 0x0F]; + MD5_INERMEDIATE(A, B, C, D, W, T[u8Idx], S[u8Idx]); + } + + for (u8Idx = 32, u8Count = 5; u8Idx < 48; u8Idx++, u8Count += 3) { + W = H(B, C, D) + X[u8Count & 0x0F]; + MD5_INERMEDIATE(A, B, C, D, W, T[u8Idx], S[u8Idx]); + } + + for (u8Idx = 48, u8Count = 0; u8Idx < 64; u8Idx++, u8Count += 7) { + W = I(B, C, D) + X[u8Count & 0x0F]; + MD5_INERMEDIATE(A, B, C, D, W, T[u8Idx], S[u8Idx]); + } + + pu32Md5State[0] += A; + pu32Md5State[1] += B; + pu32Md5State[2] += C; + pu32Md5State[3] += D; +} + +static void SHA1ProcessBlock(uint32 *pu32Sha1State, const uint8 *pu8MessageBlock) +{ + /* Constants defined in FIPS-180-2, section 4.2.1 */ + const uint32 K[4] = { + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + uint32 W[80]; /* Word sequence */ + uint32 A, B, C, D, E; /* Word buffers */ + + /* Initialize the first 16 words in the array W. */ + for (t = 0; t < 16; t++) { + W[t] = GETU32(pu8MessageBlock, (t * 4)); + } + + for (t = 16; t < 80; t++) { + W[t] = SHA_ROTL((W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]), 1); + } + + A = pu32Sha1State[0]; + B = pu32Sha1State[1]; + C = pu32Sha1State[2]; + D = pu32Sha1State[3]; + E = pu32Sha1State[4]; + + for (t = 0; t < 20; t++) { + W[t] += SHA1_CH(B, C, D); + SHA1_INERMEDIATE(A, B, C, D, E, W[t], K[0]) + } + + for (t = 20; t < 40; t++) { + W[t] += SHA_PARITY(B, C, D); + SHA1_INERMEDIATE(A, B, C, D, E, W[t], K[1]) + } + + for (t = 40; t < 60; t++) { + W[t] += SHA1_MAJ(B, C, D); + SHA1_INERMEDIATE(A, B, C, D, E, W[t], K[2]) + } + + for (t = 60; t < 80; t++) { + W[t] += SHA_PARITY(B, C, D); + SHA1_INERMEDIATE(A, B, C, D, E, W[t], K[3]) + } + + pu32Sha1State[0] += A; + pu32Sha1State[1] += B; + pu32Sha1State[2] += C; + pu32Sha1State[3] += D; + pu32Sha1State[4] += E; +} + +static void SHA256ProcessBlock(uint32 *pu32Sha256State, const uint8 *pu8Data) +{ + /* Hardcoded when using for loop unrolling. */ + /* Constants defined in SHA-256. */ + const uint32 K[] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + uint32 t; /* Loop counter */ + uint32 temp1, temp2; /* Temporary word value */ + uint32 W[64]; /* Word sequence */ + uint32 A, B, C, D, E, F, G, H; /* Word buffers */ + + A = pu32Sha256State[0]; + B = pu32Sha256State[1]; + C = pu32Sha256State[2]; + D = pu32Sha256State[3]; + E = pu32Sha256State[4]; + F = pu32Sha256State[5]; + G = pu32Sha256State[6]; + H = pu32Sha256State[7]; + + /* Initialize the first 16 words in the array W */ + for (t = 16; (t--) != 0;) { + W[t] = pu8Data[t * 4] << 24; + W[t] |= pu8Data[t * 4 + 1] << 16; + W[t] |= pu8Data[t * 4 + 2] << 8; + W[t] |= pu8Data[t * 4 + 3]; + } + + for (t = 16; t < 64; t++) { + W[t] = SHA256_SMALL_SIGMA1(W[t - 2]) + W[t - 7] + + SHA256_SMALL_SIGMA0(W[t - 15]) + W[t - 16]; + } + + for (t = 0; t < 64; t++) { + temp1 = H + SHA256_CAP_SIGMA1(E) + SHA256_CH(E, F, G) + K[t] + W[t]; + temp2 = SHA256_CAP_SIGMA0(A) + SHA256_MAJ(A, B, C); + + H = G; + G = F; + F = E; + E = D + temp1; + D = C; + C = B; + B = A; + A = temp1 + temp2; + } + + pu32Sha256State[0] += A; + pu32Sha256State[1] += B; + pu32Sha256State[2] += C; + pu32Sha256State[3] += D; + pu32Sha256State[4] += E; + pu32Sha256State[5] += F; + pu32Sha256State[6] += G; + pu32Sha256State[7] += H; +} + +static void Sha_HashUpdate(tstrHashContext *pstrHashCxt, uint8 *pu8Data, uint32 u32DataLength) +{ + if ((pstrHashCxt != NULL) && (pu8Data != NULL) && (u32DataLength != 0)) { + if (pstrHashCxt->fpHash != NULL) { + uint32 u32ResidualBytes; + uint32 u32NBlocks; + uint32 u32Offset; + uint32 u32BlockCount; + + /* Get the remaining bytes from the previous update (if the length is not block alligned). */ + u32ResidualBytes = pstrHashCxt->u32TotalLength % pstrHashCxt->u8BlockSize; + + /* Update the total data length. */ + pstrHashCxt->u32TotalLength += u32DataLength; + + if (u32ResidualBytes != 0) { + if ((u32ResidualBytes + u32DataLength) >= pstrHashCxt->u8BlockSize) { + u32Offset = pstrHashCxt->u8BlockSize - u32ResidualBytes; + memcpy(&pstrHashCxt->au8CurrentBlock[u32ResidualBytes], pu8Data, u32Offset); + pu8Data += u32Offset; + u32DataLength -= u32Offset; + pstrHashCxt->fpHash(pstrHashCxt->au32HashState, pstrHashCxt->au8CurrentBlock); + } else { + memcpy(&pstrHashCxt->au8CurrentBlock[u32ResidualBytes], pu8Data, u32DataLength); + u32DataLength = 0; + } + } + + /* Get the number of HASH BLOCKs and the residual bytes. */ + u32NBlocks = u32DataLength / pstrHashCxt->u8BlockSize; + u32ResidualBytes = u32DataLength % pstrHashCxt->u8BlockSize; + for (u32BlockCount = 0; u32BlockCount < u32NBlocks; u32BlockCount++) { + pstrHashCxt->fpHash(pstrHashCxt->au32HashState, pu8Data); + pu8Data += pstrHashCxt->u8BlockSize; + } + + if (u32ResidualBytes != 0) { + memcpy(pstrHashCxt->au8CurrentBlock, pu8Data, u32ResidualBytes); + } + } + } +} + +static void Sha_HashFinish(tstrHashContext *pstrHashCxt, uint8 *pu8LengthPadding) +{ + if (pstrHashCxt != NULL) { + if (pstrHashCxt->fpHash != NULL) { + uint32 u32Offset; + uint32 u32PaddingLength; + + /* Calculate the offset of the last data byte in the current block. */ + u32Offset = pstrHashCxt->u32TotalLength % pstrHashCxt->u8BlockSize; + + /* Add the padding byte 0x80. */ + pstrHashCxt->au8CurrentBlock[u32Offset++] = SHA_PAD_BYTE; + + /* Calculate the required padding to complete one Hash Block Size. */ + u32PaddingLength = pstrHashCxt->u8BlockSize - u32Offset; + memset(&pstrHashCxt->au8CurrentBlock[u32Offset], 0, u32PaddingLength); + + /* If the padding count is not enough to hold 64-bit representation */ + /* of the total input message length, one padding block is required. */ + if (u32PaddingLength < 8) { + pstrHashCxt->fpHash(pstrHashCxt->au32HashState, pstrHashCxt->au8CurrentBlock); + memset(pstrHashCxt->au8CurrentBlock, 0, pstrHashCxt->u8BlockSize); + } + + memcpy(&pstrHashCxt->au8CurrentBlock[pstrHashCxt->u8BlockSize - 8], pu8LengthPadding, 8); + pstrHashCxt->fpHash(pstrHashCxt->au32HashState, pstrHashCxt->au8CurrentBlock); + } + } +} + +void SHA1_Hash(tstrHashContext *pstrSha1Context, uint8 u8Flags, uint8 *pu8Data, uint32 u32DataLength, uint8 *pu8Digest) { + if (pstrSha1Context != NULL) { + /* SHA1 HASH INITIALIZATION. */ + if (u8Flags & SHA_FLAGS_INIT) { + /* Initialize the Hash Context. */ + memset(pstrSha1Context, 0, sizeof(tstrHashContext)); + + /* Define SHA1 Specific parameters. */ + pstrSha1Context->fpHash = SHA1ProcessBlock; + pstrSha1Context->u8BlockSize = SHA_BLOCK_SIZE; + pstrSha1Context->u8DigestSize = SHA1_DIGEST_SIZE; + + /* Set the Hash state to the initial value (specified by the standard). */ + pstrSha1Context->au32HashState[0] = 0x67452301; + pstrSha1Context->au32HashState[1] = 0xEFCDAB89; + pstrSha1Context->au32HashState[2] = 0x98BADCFE; + pstrSha1Context->au32HashState[3] = 0x10325476; + pstrSha1Context->au32HashState[4] = 0xC3D2E1F0; + } + + /* SHA1 HASH UPDATE. */ + if ((u8Flags & SHA_FLAGS_UPDATE) && (pu8Data != NULL)) { + Sha_HashUpdate(pstrSha1Context, pu8Data, u32DataLength); + } + + /* SHA1 HASH FINISH. */ + if (u8Flags & SHA_FLAGS_FINISH) { + uint8 au8Tmp[8]; + + /* Pack the length at the end of the padding block. */ + PUTU32(pstrSha1Context->u32TotalLength >> 29, au8Tmp, 0); + PUTU32(pstrSha1Context->u32TotalLength << 3, au8Tmp, 4); + Sha_HashFinish(pstrSha1Context, au8Tmp); + + /* Compute digest. */ + PUTU32(pstrSha1Context->au32HashState[0], pu8Digest, 0); + PUTU32(pstrSha1Context->au32HashState[1], pu8Digest, 4); + PUTU32(pstrSha1Context->au32HashState[2], pu8Digest, 8); + PUTU32(pstrSha1Context->au32HashState[3], pu8Digest, 12); + PUTU32(pstrSha1Context->au32HashState[4], pu8Digest, 16); + } + } +} + +void SHA256_Hash(tstrHashContext *pstrSha256Context, uint8 u8Flags, uint8 *pu8Data, uint32 u32DataLength, uint8 *pu8Digest) +{ + if (pstrSha256Context != NULL) { + /* SHA256 HASH INITIALIZATION. */ + if (u8Flags & SHA_FLAGS_INIT) { + /* Initialize the Hash Context. */ + memset(pstrSha256Context, 0, sizeof(tstrHashContext)); + + /* Define SHA256 specific parameters. */ + pstrSha256Context->fpHash = SHA256ProcessBlock; + pstrSha256Context->u8BlockSize = SHA_BLOCK_SIZE; + pstrSha256Context->u8DigestSize = SHA256_DIGEST_SIZE; + + /* Set the Hash state to the initial value (specified by the standard). */ + pstrSha256Context->au32HashState[0] = 0x6A09E667; + pstrSha256Context->au32HashState[1] = 0xBB67AE85; + pstrSha256Context->au32HashState[2] = 0x3C6EF372; + pstrSha256Context->au32HashState[3] = 0xA54FF53A; + pstrSha256Context->au32HashState[4] = 0x510E527F; + pstrSha256Context->au32HashState[5] = 0x9B05688C; + pstrSha256Context->au32HashState[6] = 0x1F83D9AB; + pstrSha256Context->au32HashState[7] = 0x5BE0CD19; + } + + /* SHA256 HASH UPDATE. */ + if ((u8Flags & SHA_FLAGS_UPDATE) && (pu8Data != NULL)) { + Sha_HashUpdate(pstrSha256Context, pu8Data, u32DataLength); + } + + /* SHA256 HASH FINISH. */ + if ((u8Flags & SHA_FLAGS_FINISH) && (pu8Digest != NULL)) { + uint8 au8Tmp[8]; + + /* Pack the length at the end of the padding block. */ + PUTU32(pstrSha256Context->u32TotalLength >> 29, au8Tmp, 0); + PUTU32(pstrSha256Context->u32TotalLength << 3, au8Tmp, 4); + Sha_HashFinish(pstrSha256Context, au8Tmp); + + /* Compute digest. */ + PUTU32(pstrSha256Context->au32HashState[0], pu8Digest, 0); + PUTU32(pstrSha256Context->au32HashState[1], pu8Digest, 4); + PUTU32(pstrSha256Context->au32HashState[2], pu8Digest, 8); + PUTU32(pstrSha256Context->au32HashState[3], pu8Digest, 12); + PUTU32(pstrSha256Context->au32HashState[4], pu8Digest, 16); + PUTU32(pstrSha256Context->au32HashState[5], pu8Digest, 20); + PUTU32(pstrSha256Context->au32HashState[6], pu8Digest, 24); + PUTU32(pstrSha256Context->au32HashState[7], pu8Digest, 28); + } + } +} + +void MD5_Hash( tstrHashContext *pstrMD5Context, uint8 u8Flags, uint8 *pu8Data, uint32 u32DataLength, uint8 *pu8Digest) +{ + if (pstrMD5Context != NULL) { + /* SHA256 HASH INITIALIZATION. */ + if (u8Flags & 1) { + /* Initialize the Hash Context. */ + memset(pstrMD5Context, 0, sizeof(tstrHashContext)); + + /* Define SHA256 specific parameters. */ + pstrMD5Context->fpHash = MD5ProcessBlock; + pstrMD5Context->u8BlockSize = 64; + pstrMD5Context->u8DigestSize = 16; + + pstrMD5Context->au32HashState[0] = 0x67452301; + pstrMD5Context->au32HashState[1] = 0xEFCDAB89; + pstrMD5Context->au32HashState[2] = 0x98BADCFE; + pstrMD5Context->au32HashState[3] = 0x10325476; + } + + /* SHA256 HASH UPDATE. */ + if ((u8Flags & 2) && (pu8Data != NULL)) { + Sha_HashUpdate(pstrMD5Context, pu8Data, u32DataLength); + } + + /* SHA256 HASH FINISH. */ + if ((u8Flags & 4) && (pu8Digest != NULL)) { + uint8 au8Tmp[8] = {0}; + uint8 u8Idx, u8ByteIdx = 0; + uint32 u32LengthBits = pstrMD5Context->u32TotalLength << 3; + + /* Pack the length at the end of the padding block. */ + au8Tmp[0] = BYTE_0(u32LengthBits); + au8Tmp[1] = BYTE_1(u32LengthBits); + au8Tmp[2] = BYTE_2(u32LengthBits); + au8Tmp[3] = BYTE_3(u32LengthBits); + + Sha_HashFinish(pstrMD5Context, au8Tmp); + + /* Compute digest. */ + for (u8Idx = 0; u8Idx < (MD5_DIGEST_SIZE / 4); u8Idx++) { + pu8Digest[u8ByteIdx++] = BYTE_0(pstrMD5Context->au32HashState[u8Idx]); + pu8Digest[u8ByteIdx++] = BYTE_1(pstrMD5Context->au32HashState[u8Idx]); + pu8Digest[u8ByteIdx++] = BYTE_2(pstrMD5Context->au32HashState[u8Idx]); + pu8Digest[u8ByteIdx++] = BYTE_3(pstrMD5Context->au32HashState[u8Idx]); + } + } + } +} + +/** + * \brief Perform the HMAC operation on a given vector of data streams. + */ +void HMAC_Vector(tpfHash fpHash, uint8 *pu8Key, uint32 u32KeyLength, tstrBuffer *pstrInData, uint8 u8NumInputs, uint8 *pu8Out) +{ + if ((pu8Key != NULL) && (pstrInData != NULL) && (pu8Out != NULL) && (fpHash != NULL)) { + tstrHashContext strHashContext; + uint32 i; + uint8 au8TmpBuffer[SHA_BLOCK_SIZE]; + uint8 au8TmpHash[SHA_MAX_DIGEST_SIZE]; + uint8 au8TmpKey[SHA_MAX_DIGEST_SIZE]; + + /* HMAC INIT. */ + /* Adjust the key size. */ + if (u32KeyLength > SHA_BLOCK_SIZE) { + fpHash(&strHashContext, SHA_FLAGS_FULL_HASH, pu8Key, u32KeyLength, pu8Key); + u32KeyLength = strHashContext.u8DigestSize; + pu8Key = au8TmpKey; + } + + memset(au8TmpBuffer, 0x36, SHA_BLOCK_SIZE); + for (i = 0; i < u32KeyLength; i++) { + au8TmpBuffer[i] ^= pu8Key[i]; + } + + /* Start hashing. */ + fpHash(&strHashContext, SHA_FLAGS_INIT | SHA_FLAGS_UPDATE, au8TmpBuffer, SHA_BLOCK_SIZE, NULL); + + /* HMAC UPDATE. */ + for (i = 0; i < u8NumInputs; i++) { + fpHash(&strHashContext, SHA_FLAGS_UPDATE, pstrInData[i].pu8Data, pstrInData[i].u16BufferSize, NULL); + } + + fpHash(&strHashContext, SHA_FLAGS_FINISH, NULL, 0, au8TmpHash); + + /* HMAC Finalize. */ + memset(au8TmpBuffer, 0x5C, SHA_BLOCK_SIZE); + for (i = 0; i < u32KeyLength; i++) { + au8TmpBuffer[i] ^= pu8Key[i]; + } + + fpHash(&strHashContext, SHA_FLAGS_INIT | SHA_FLAGS_UPDATE, au8TmpBuffer, SHA_BLOCK_SIZE, NULL); + fpHash(&strHashContext, SHA_FLAGS_UPDATE | SHA_FLAGS_FINISH, au8TmpHash, strHashContext.u8DigestSize, pu8Out); + } +} diff --git a/src/winc1500/src/programmer.c b/src/winc1500/src/programmer.c new file mode 100644 index 000000000..0d536fa44 --- /dev/null +++ b/src/winc1500/src/programmer.c @@ -0,0 +1,194 @@ +#include +#include +#include "fb_alloc.h" + +#include "programmer/programmer.h" +#include "root_cert/root_setup.h" +#include "spi_flash/include/spi_flash_map.h" + +#define FW_PATH "/firmware/bin/m2m_aio_3a0.bin" +#define CERT_DIGI_PATH "/firmware/cert/DigiCert_Root.cer" +#define CERT_DIGISHA2_PATH "/firmware/cert/DigiCertSHA2_Root.cer" +#define CERT_GEOTRUST_PATH "/firmware/cert/GeoTrustGlobalCA_Root.cer" +#define CERT_RADIUS_PATH "/firmware/cert/Radius_Root.cer" +#define CERT_VERISIGN_PATH "/firmware/cert/VeriSign_Root.cer" + +#define MIN(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + +/** + * Program firmware to WINC1500 memory. + * + * return M2M_SUCCESS on success, error code otherwise. + */ +int burn_firmware() +{ + FIL fp; + uint32_t offset = 0; + UINT bytes = 0, bytes_out=0; + + int ret = M2M_ERR_FAIL; + uint8_t *buf = fb_alloc(FLASH_SECTOR_SZ); + + if (f_open(&fp, FW_PATH, FA_READ|FA_OPEN_EXISTING) != FR_OK) { + goto error; + } + + // Firmware image size + uint32_t size = f_size(&fp); + + while (size) { + // Read a chuck (max FLASH_SECTOR_SZ bytes). + bytes = MIN(size, FLASH_SECTOR_SZ); + if (f_read(&fp, buf, bytes, &bytes_out) != FR_OK || bytes != bytes_out) { + printf("burn_firmware: file read error!\n"); + goto error; + } + + // Write firmware sector to the WINC1500 memory. + if (programmer_write_firmware_image(buf, offset, bytes) != M2M_SUCCESS) { + printf("burn_firmware: write error!\n"); + goto error; + } + + size -= bytes; + offset += bytes; + } + + ret = M2M_SUCCESS; + +error: + fb_free(); + f_close(&fp); + return ret; +} + +/** + * Verify WINC1500 firmware + * return M2M_SUCCESS on success, error code otherwise. + */ +int verify_firmware() +{ + FIL fp; + uint32_t offset = 0; + UINT bytes = 0, bytes_out=0; + + int ret = M2M_ERR_FAIL; + uint8_t *file_buf = fb_alloc(FLASH_SECTOR_SZ); + uint8_t *flash_buf = fb_alloc(FLASH_SECTOR_SZ); + + if (f_open(&fp, FW_PATH, FA_READ|FA_OPEN_EXISTING) != FR_OK) { + goto error; + } + + // Firmware image size + uint32_t size = f_size(&fp); + + while (size) { + // Firmware chuck size (max FLASH_SECTOR_SZ bytes). + bytes = MIN(size, FLASH_SECTOR_SZ); + + if (f_read(&fp, file_buf, bytes, &bytes_out) != FR_OK || bytes_out != bytes) { + printf("burn_firmware: file read error!\n"); + goto error; + } + + if (programmer_read_firmware_image(flash_buf, offset, bytes) != M2M_SUCCESS) { + printf("verify_firmware: read access failed on firmware section!\r\n"); + return M2M_ERR_FAIL; + } + + for (int i=0; iRoot certificate verified OK.\n"); + *ppu8CertificateBuffer = pcRootCertFileData; + ret = 0; + } else { + ret = -1; + } + + return ret; +} + +/** + * \brief Update the root certificate list. + * + * \return M2M_SUCCESS on success, error code otherwise. + */ +static sint8 UpdateRootList(tstrX509Cert *pstrRootCert, uint8 *gau8RootCertMem) +{ + uint32 u32Idx; + uint8 bIncrement = 0; + uint32 u32nStoredCerts = 0; + uint8 au8StartPattern[] = ROOT_CERT_FLASH_START_PATTERN; + tstrRootCertFlashHeader *pstrRootFlashHdr; + tstrRootCertEntryHeader *pstrEntryHDR; + uint16 u16BufferOffset; + uint16 u16WriteSize; + tstrRSAPublicKey *pstrKey; + + pstrKey = &pstrRootCert->strPubKey.strRSAKey; + pstrRootFlashHdr = (tstrRootCertFlashHeader *)((void *)gau8RootCertMem); + u16BufferOffset = sizeof(tstrRootCertFlashHeader); + u16WriteSize = pstrKey->u16ESize + pstrKey->u16NSize + sizeof(tstrRootCertEntryHeader); + + /* Check if the flash has been written before. */ + if (!memcmp(au8StartPattern, pstrRootFlashHdr->au8StartPattern, ROOT_CERT_FLASH_START_PATTERN_LENGTH)) { + u32nStoredCerts = pstrRootFlashHdr->u32nCerts; + bIncrement = 1; + + for (u32Idx = 0; u32Idx < u32nStoredCerts; u32Idx++) { + pstrEntryHDR = (tstrRootCertEntryHeader *)((void *)&gau8RootCertMem[u16BufferOffset]); + + /* Check for match (equivalent NameSHA1). */ + if (!memcmp(pstrRootCert->strSubject.au8NameSHA1, pstrEntryHDR->au8SHA1NameHash, SHA1_DIGEST_SIZE)) { + /* The current entry will be overwritten. */ + bIncrement = 0; + break; + } + + u16BufferOffset += sizeof(tstrRootCertEntryHeader) + WORD_ALIGN(pstrEntryHDR->u16NSize + pstrEntryHDR->u16ESize); + } + } else { + pstrRootFlashHdr->u32nCerts = 0; + memcpy(pstrRootFlashHdr->au8StartPattern, au8StartPattern, ROOT_CERT_FLASH_START_PATTERN_LENGTH); + bIncrement = 1; + } + + if (bIncrement) { + /* A new certificate is to be inserted into the flash. */ + /* Increment the number of stored Certificates. */ + if (u16BufferOffset + u16WriteSize > M2M_TLS_FLASH_ROOTCERT_CACHE_SIZE) { + printf("(ERROR) Root Certificate Flash is Full\n"); + return -1; + } + + pstrRootFlashHdr->u32nCerts++; + } + + /* Write Root Certificate to flash. The entry is ordered as follows: + - SHA1_DIGEST_SIZE --> NameSHA1 of the Root certificate. + - uint16 --> N_SIZE (Byte count for the RSA modulus N). + - uint16 --> E_SIZE (Byte count for the RSA public exponent E). + - START_DATE --> Start date of the root certificate(20 bytes). + - EXPIRATION_DATE --> Expiration date of the root certificate(20 bytes). + - N_SIZE --> RSA Modulus N. + - E_SIZE --> RSA Public exponent. + */ + + pstrEntryHDR = (tstrRootCertEntryHeader *)((void *)&gau8RootCertMem[u16BufferOffset]); + + /* NameSHA1 */ + memcpy(pstrEntryHDR->au8SHA1NameHash, pstrRootCert->strSubject.au8NameSHA1, SHA1_DIGEST_SIZE); + + /* N_SIZE */ + pstrEntryHDR->u16NSize = pstrKey->u16NSize; + + /* E_SIZE */ + pstrEntryHDR->u16ESize = pstrKey->u16ESize; + + /* Start Date */ + memcpy(pstrEntryHDR->au8ValidityStartDate, pstrRootCert->strStartDate.au8Time, 20); + + /* Expiration Date */ + memcpy(pstrEntryHDR->au8ValidityExpDate, pstrRootCert->strExpiryDate.au8Time, 20); + u16BufferOffset += sizeof(tstrRootCertEntryHeader); + + /* N */ + memcpy(&gau8RootCertMem[u16BufferOffset], pstrKey->pu8N, pstrKey->u16NSize); + + /* E */ + memcpy(&gau8RootCertMem[u16BufferOffset + pstrKey->u16NSize], pstrKey->pu8E, pstrKey->u16ESize); + + return 0; +} + +/** + * \brief Write root certificate to flash. + * + * \return M2M_SUCCESS on success, error code otherwise. + */ +int WriteRootCertificate(const char *filename, char *pcRootCertFileData, uint32 u32FileSize) +{ + uint8 *pu8CertBuffer; + tstrX509Cert strX509Root; +#ifdef ENABLE_VERIFICATION + uint32 u32Idx; +#endif + int ret = -1; + + uint8 *gau8RootCertMem = fb_alloc(M2M_TLS_FLASH_ROOTCERT_CACHE_SIZE); + + /* Read Certificate File. */ + if (GetRootCertificate((uint8 *)pcRootCertFileData, u32FileSize, &strX509Root, &pu8CertBuffer) == 0) { + programmer_read_cert_image(gau8RootCertMem); + + if (UpdateRootList(&strX509Root, gau8RootCertMem) == 0) { + /* Erase memory. */ + ret = programmer_erase_cert_image(); + if (M2M_SUCCESS != ret) { + goto END; + } + + nm_bsp_sleep(50); + + /* Write. */ + printf(">Writing the certificate to SPI flash...\r\n"); + ret = programmer_write_cert_image(gau8RootCertMem); + if (M2M_SUCCESS != ret) { + goto END; + } + + printf("Done\r\n"); + +#ifdef ENABLE_VERIFICATION + /* Verification. */ + memset(gau8Verify, 0, M2M_TLS_FLASH_ROOTCERT_CACHE_SIZE); + programmer_read_cert_image(gau8Verify); + + for (u32Idx = 0; u32Idx < M2M_TLS_FLASH_ROOTCERT_CACHE_SIZE; u32Idx++) { + if (gau8RootCertMem[u32Idx] != gau8Verify[u32Idx]) { + printf("ERROR verification failed at %u\n", u32Idx); + ret = -1; + break; + } + } +#endif + } + } else { + printf("\r\n>>>Invalid root certificate %s\n", filename); + } + +END: + fb_free(); + return ret; +} diff --git a/src/winc1500/src/spi_flash.c b/src/winc1500/src/spi_flash.c new file mode 100644 index 000000000..11cd750b6 --- /dev/null +++ b/src/winc1500/src/spi_flash.c @@ -0,0 +1,690 @@ +/** + * + * \file + * + * \brief WINC1500 SPI Flash. + * + * Copyright (c) 2015 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * \asf_license_stop + * + */ + +#include "spi_flash/include/spi_flash.h" +#define DUMMY_REGISTER (0x1084) +#define HOST_SHARE_MEM_BASE (0xd0000UL) +#define CORTUS_SHARE_MEM_BASE (0x60000000UL) +#define NMI_SPI_FLASH_ADDR (0x111c) +/*********************************************************** +SPI Flash DMA +***********************************************************/ +#define GET_UINT32(X,Y) (X[0+Y] + ((uint32)X[1+Y]<<8) + ((uint32)X[2+Y]<<16) +((uint32)X[3+Y]<<24)) +#define SPI_FLASH_BASE (0x10200) +#define SPI_FLASH_MODE (SPI_FLASH_BASE + 0x00) +#define SPI_FLASH_CMD_CNT (SPI_FLASH_BASE + 0x04) +#define SPI_FLASH_DATA_CNT (SPI_FLASH_BASE + 0x08) +#define SPI_FLASH_BUF1 (SPI_FLASH_BASE + 0x0c) +#define SPI_FLASH_BUF2 (SPI_FLASH_BASE + 0x10) +#define SPI_FLASH_BUF_DIR (SPI_FLASH_BASE + 0x14) +#define SPI_FLASH_TR_DONE (SPI_FLASH_BASE + 0x18) +#define SPI_FLASH_DMA_ADDR (SPI_FLASH_BASE + 0x1c) +#define SPI_FLASH_MSB_CTL (SPI_FLASH_BASE + 0x20) +#define SPI_FLASH_TX_CTL (SPI_FLASH_BASE + 0x24) + +/*********************************************/ +/* STATIC FUNCTIONS */ +/*********************************************/ + +/** +* @fn spi_flash_read_status_reg +* @brief Read status register +* @param[OUT] val + value of status reg +* @return Status of execution +*/ +static sint8 spi_flash_read_status_reg(uint8 * val) +{ + sint8 ret = M2M_SUCCESS; + uint8 cmd[1]; + uint32 reg; + + cmd[0] = 0x05; + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 4); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, DUMMY_REGISTER); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)®); + if(M2M_SUCCESS != ret) break; + } + while(reg != 1); + + reg = (M2M_SUCCESS == ret)?(nm_read_reg(DUMMY_REGISTER)):(0); + *val = (uint8)(reg & 0xff); + return ret; +} + +#ifdef DISABLE_UNSED_FLASH_FUNCTIONS +/** +* @fn spi_flash_read_security_reg +* @brief Read security register +* @return Security register value +*/ +static uint8 spi_flash_read_security_reg(void) +{ + uint8 cmd[1]; + uint32 reg; + sint8 ret = M2M_SUCCESS; + + cmd[0] = 0x2b; + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 1); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, DUMMY_REGISTER); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)®); + if(M2M_SUCCESS != ret) break; + } + while(reg != 1); + reg = (M2M_SUCCESS == ret)?(nm_read_reg(DUMMY_REGISTER)):(0); + + return (sint8)reg & 0xff; +} + +/** +* @fn spi_flash_gang_unblock +* @brief Unblock all flash area +*/ +static sint8 spi_flash_gang_unblock(void) +{ + uint8 cmd[1]; + uint32 val = 0; + sint8 ret = M2M_SUCCESS; + + cmd[0] = 0x98; + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val); + if(M2M_SUCCESS != ret) break; + } + while(val != 1); + + return ret; +} + +/** +* @fn spi_flash_clear_security_flags +* @brief Clear all security flags +*/ +static sint8 spi_flash_clear_security_flags(void) +{ + uint8 cmd[1]; + uint32 val = 0; + sint8 ret = M2M_SUCCESS; + + cmd[0] = 0x30; + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val); + if(M2M_SUCCESS != ret) break; + } + while(val != 1); + + return ret; +} +#endif + +/** +* @fn spi_flash_load_to_cortus_mem +* @brief Load data from SPI flash into cortus memory +* @param[IN] u32MemAdr +* Cortus load address. It must be set to its AHB access address +* @param[IN] u32FlashAdr +* Address to read from at the SPI flash +* @param[IN] u32Sz +* Data size +* @return Status of execution +*/ +static sint8 spi_flash_load_to_cortus_mem(uint32 u32MemAdr, uint32 u32FlashAdr, uint32 u32Sz) +{ + uint8 cmd[5]; + uint32 val = 0; + sint8 ret = M2M_SUCCESS; + + cmd[0] = 0x0b; + cmd[1] = (uint8)(u32FlashAdr >> 16); + cmd[2] = (uint8)(u32FlashAdr >> 8); + cmd[3] = (uint8)(u32FlashAdr); + cmd[4] = 0xA5; + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, u32Sz); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]|(cmd[1]<<8)|(cmd[2]<<16)|(cmd[3]<<24)); + ret += nm_write_reg(SPI_FLASH_BUF2, cmd[4]); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x1f); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, u32MemAdr); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 5 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val); + if(M2M_SUCCESS != ret) break; + } + while(val != 1); + + return ret; +} + +/** +* @fn spi_flash_sector_erase +* @brief Erase sector (4KB) +* @param[IN] u32FlashAdr +* Any memory address within the sector +* @return Status of execution +*/ +static sint8 spi_flash_sector_erase(uint32 u32FlashAdr) +{ + uint8 cmd[4]; + uint32 val = 0; + sint8 ret = M2M_SUCCESS; + + cmd[0] = 0x20; + cmd[1] = (uint8)(u32FlashAdr >> 16); + cmd[2] = (uint8)(u32FlashAdr >> 8); + cmd[3] = (uint8)(u32FlashAdr); + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]|(cmd[1]<<8)|(cmd[2]<<16)|(cmd[3]<<24)); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x0f); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 4 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val); + if(M2M_SUCCESS != ret) break; + } + while(val != 1); + + return ret; +} + +/** +* @fn spi_flash_write_enable +* @brief Send write enable command to SPI flash +* @return Status of execution +*/ +static sint8 spi_flash_write_enable(void) +{ + uint8 cmd[1]; + uint32 val = 0; + sint8 ret = M2M_SUCCESS; + + cmd[0] = 0x06; + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val); + if(M2M_SUCCESS != ret) break; + } + while(val != 1); + + return ret; +} + +/** +* @fn spi_flash_write_disable +* @brief Send write disable command to SPI flash +*/ +static sint8 spi_flash_write_disable(void) +{ + uint8 cmd[1]; + uint32 val = 0; + sint8 ret = M2M_SUCCESS; + cmd[0] = 0x04; + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x01); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, 0); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val); + if(M2M_SUCCESS != ret) break; + } + while(val != 1); + + return ret; +} + +/** +* @fn spi_flash_page_program +* @brief Write data (less than page size) from cortus memory to SPI flash +* @param[IN] u32MemAdr +* Cortus data address. It must be set to its AHB access address +* @param[IN] u32FlashAdr +* Address to write to at the SPI flash +* @param[IN] u32Sz +* Data size +*/ +static sint8 spi_flash_page_program(uint32 u32MemAdr, uint32 u32FlashAdr, uint32 u32Sz) +{ + uint8 cmd[4]; + uint32 val = 0; + sint8 ret = M2M_SUCCESS; + + cmd[0] = 0x02; + cmd[1] = (uint8)(u32FlashAdr >> 16); + cmd[2] = (uint8)(u32FlashAdr >> 8); + cmd[3] = (uint8)(u32FlashAdr); + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 0); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]|(cmd[1]<<8)|(cmd[2]<<16)|(cmd[3]<<24)); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x0f); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, u32MemAdr); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 4 | (1<<7) | ((u32Sz & 0xfffff) << 8)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)&val); + if(M2M_SUCCESS != ret) break; + } + while(val != 1); + + return ret; +} + +/** +* @fn spi_flash_read_internal +* @brief Read from data from SPI flash +* @param[OUT] pu8Buf +* Pointer to data buffer +* @param[IN] u32Addr +* Address to read from at the SPI flash +* @param[IN] u32Sz +* Data size +*/ +static sint8 spi_flash_read_internal(uint8 *pu8Buf, uint32 u32Addr, uint32 u32Sz) +{ + sint8 ret = M2M_SUCCESS; + /* read size must be < 64KB */ + ret = spi_flash_load_to_cortus_mem(HOST_SHARE_MEM_BASE, u32Addr, u32Sz); + if(M2M_SUCCESS != ret) goto ERR; + ret = nm_read_block(HOST_SHARE_MEM_BASE, pu8Buf, u32Sz); +ERR: + return ret; +} + +/** +* @fn spi_flash_pp +* @brief Program data of size less than a page (256 bytes) at the SPI flash +* @param[IN] u32Offset +* Address to write to at the SPI flash +* @param[IN] pu8Buf +* Pointer to data buffer +* @param[IN] u32Sz +* Data size +* @return Status of execution +*/ +static sint8 spi_flash_pp(uint32 u32Offset, uint8 *pu8Buf, uint16 u16Sz) +{ + sint8 ret = M2M_SUCCESS; + uint8 tmp; + spi_flash_write_enable(); + /* use shared packet memory as temp mem */ + ret += nm_write_block(HOST_SHARE_MEM_BASE, pu8Buf, u16Sz); + ret += spi_flash_page_program(HOST_SHARE_MEM_BASE, u32Offset, u16Sz); + ret += spi_flash_read_status_reg(&tmp); + do + { + if(ret != M2M_SUCCESS) goto ERR; + ret += spi_flash_read_status_reg(&tmp); + }while(tmp & 0x01); + ret += spi_flash_write_disable(); +ERR: + return ret; +} + +/** +* @fn spi_flash_rdid +* @brief Read SPI Flash ID +* @return SPI FLash ID +*/ +static uint32 spi_flash_rdid(void) +{ + unsigned char cmd[1]; + uint32 reg = 0; + uint32 cnt = 0; + sint8 ret = M2M_SUCCESS; + + cmd[0] = 0x9f; + + ret += nm_write_reg(SPI_FLASH_DATA_CNT, 4); + ret += nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + ret += nm_write_reg(SPI_FLASH_BUF_DIR, 0x1); + ret += nm_write_reg(SPI_FLASH_DMA_ADDR, DUMMY_REGISTER); + ret += nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1<<7)); + do + { + ret += nm_read_reg_with_ret(SPI_FLASH_TR_DONE, (uint32 *)®); + if(M2M_SUCCESS != ret) break; + if(++cnt > 500) + { + ret = M2M_ERR_INIT; + break; + } + } + while(reg != 1); + reg = (M2M_SUCCESS == ret)?(nm_read_reg(DUMMY_REGISTER)):(0); + M2M_PRINT("Flash ID %x \n",(unsigned int)reg); + return reg; +} + +/** +* @fn spi_flash_unlock +* @brief Unlock SPI Flash +*/ +#if 0 +static void spi_flash_unlock(void) +{ + uint8 tmp; + tmp = spi_flash_read_security_reg(); + spi_flash_clear_security_flags(); + if(tmp & 0x80) + { + spi_flash_write_enable(); + spi_flash_gang_unblock(); + } +} +#endif +static void spi_flash_enter_low_power_mode(void) { + volatile unsigned long tmp; + unsigned char* cmd = (unsigned char*) &tmp; + + cmd[0] = 0xb9; + + nm_write_reg(SPI_FLASH_DATA_CNT, 0); + nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + nm_write_reg(SPI_FLASH_BUF_DIR, 0x1); + nm_write_reg(SPI_FLASH_DMA_ADDR, 0); + nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7)); + while(nm_read_reg(SPI_FLASH_TR_DONE) != 1); +} + + +static void spi_flash_leave_low_power_mode(void) { + volatile unsigned long tmp; + unsigned char* cmd = (unsigned char*) &tmp; + + cmd[0] = 0xab; + + nm_write_reg(SPI_FLASH_DATA_CNT, 0); + nm_write_reg(SPI_FLASH_BUF1, cmd[0]); + nm_write_reg(SPI_FLASH_BUF_DIR, 0x1); + nm_write_reg(SPI_FLASH_DMA_ADDR, 0); + nm_write_reg(SPI_FLASH_CMD_CNT, 1 | (1 << 7)); + while(nm_read_reg(SPI_FLASH_TR_DONE) != 1); +} +/*********************************************/ +/* GLOBAL FUNCTIONS */ +/*********************************************/ +/** + * @fn spi_flash_enable + * @brief Enable spi flash operations + */ +sint8 spi_flash_enable(uint8 enable) +{ + sint8 s8Ret = M2M_SUCCESS; + if(REV(nmi_get_chipid()) >= REV_3A0) { + uint32 u32Val; + + /* Enable pinmux to SPI flash. */ + s8Ret = nm_read_reg_with_ret(0x1410, &u32Val); + if(s8Ret != M2M_SUCCESS) { + goto ERR1; + } + /* GPIO15/16/17/18 */ + u32Val &= ~((0x7777ul) << 12); + u32Val |= ((0x1111ul) << 12); + nm_write_reg(0x1410, u32Val); + if(enable) { + spi_flash_leave_low_power_mode(); + } else { + spi_flash_enter_low_power_mode(); + } + /* Disable pinmux to SPI flash to minimize leakage. */ + u32Val &= ~((0x7777ul) << 12); + u32Val |= ((0x0010ul) << 12); + nm_write_reg(0x1410, u32Val); + } +ERR1: + return s8Ret; +} +/** +* @fn spi_flash_read +* @brief Read from data from SPI flash +* @param[OUT] pu8Buf +* Pointer to data buffer +* @param[IN] u32offset +* Address to read from at the SPI flash +* @param[IN] u32Sz +* Data size +* @return Status of execution +* @note Data size is limited by the SPI flash size only +*/ +sint8 spi_flash_read(uint8 *pu8Buf, uint32 u32offset, uint32 u32Sz) +{ + sint8 ret = M2M_SUCCESS; + if(u32Sz > FLASH_BLOCK_SIZE) + { + do + { + ret = spi_flash_read_internal(pu8Buf, u32offset, FLASH_BLOCK_SIZE); + if(M2M_SUCCESS != ret) goto ERR; + u32Sz -= FLASH_BLOCK_SIZE; + u32offset += FLASH_BLOCK_SIZE; + pu8Buf += FLASH_BLOCK_SIZE; + } while(u32Sz > FLASH_BLOCK_SIZE); + } + + ret = spi_flash_read_internal(pu8Buf, u32offset, u32Sz); + +ERR: + return ret; +} + +/** +* @fn spi_flash_write +* @brief Proram SPI flash +* @param[IN] pu8Buf +* Pointer to data buffer +* @param[IN] u32Offset +* Address to write to at the SPI flash +* @param[IN] u32Sz +* Data size +* @return Status of execution +*/ +sint8 spi_flash_write(uint8* pu8Buf, uint32 u32Offset, uint32 u32Sz) +{ +#ifdef PROFILING + uint32 t1 = 0; + uint32 percent =0; + uint32 tpercent =0; +#endif + sint8 ret = M2M_SUCCESS; + uint32 u32wsz; + uint32 u32off; + uint32 u32Blksz; + u32Blksz = FLASH_PAGE_SZ; + u32off = u32Offset % u32Blksz; +#ifdef PROFILING + tpercent = (u32Sz/u32Blksz)+((u32Sz%u32Blksz)>0); + t1 = GetTickCount(); + M2M_PRINT(">Start programming...\r\n"); +#endif + if(u32Sz<=0) + { + M2M_ERR("Data size = %d",(int)u32Sz); + ret = M2M_ERR_FAIL; + goto ERR; + } + + if (u32off)/*first part of data in the address page*/ + { + u32wsz = u32Blksz - u32off; + if(spi_flash_pp(u32Offset, pu8Buf, (uint16)BSP_MIN(u32Sz, u32wsz))!=M2M_SUCCESS) + { + ret = M2M_ERR_FAIL; + goto ERR; + } + if (u32Sz < u32wsz) goto EXIT; + pu8Buf += u32wsz; + u32Offset += u32wsz; + u32Sz -= u32wsz; + } + while (u32Sz > 0) + { + u32wsz = BSP_MIN(u32Sz, u32Blksz); + + /*write complete page or the remaining data*/ + if(spi_flash_pp(u32Offset, pu8Buf, (uint16)u32wsz)!=M2M_SUCCESS) + { + ret = M2M_ERR_FAIL; + goto ERR; + } + pu8Buf += u32wsz; + u32Offset += u32wsz; + u32Sz -= u32wsz; +#ifdef PROFILING + percent++; + printf("\r>Complete Percentage = %d%%.\r",((percent*100)/tpercent)); +#endif + } +EXIT: +#ifdef PROFILING + M2M_PRINT("\rDone\t\t\t\t\t\t"); + M2M_PRINT("\n#Programming time = %f sec\n\r",(GetTickCount() - t1)/1000.0); +#endif +ERR: + return ret; +} + +/** +* @fn spi_flash_erase +* @brief Erase from data from SPI flash +* @param[IN] u32Offset +* Address to write to at the SPI flash +* @param[IN] u32Sz +* Data size +* @return Status of execution +* @note Data size is limited by the SPI flash size only +*/ +sint8 spi_flash_erase(uint32 u32Offset, uint32 u32Sz) +{ + uint32 i = 0; + sint8 ret = M2M_SUCCESS; + uint8 tmp = 0; +#ifdef PROFILING + uint32 t; + t = GetTickCount(); +#endif + M2M_PRINT("\r\n>Start erasing...\r\n"); + for(i = u32Offset; i < (u32Sz +u32Offset); i += (16*FLASH_PAGE_SZ)) + { + ret += spi_flash_write_enable(); + ret += spi_flash_read_status_reg(&tmp); + ret += spi_flash_sector_erase(i + 10); + ret += spi_flash_read_status_reg(&tmp); + do + { + if(ret != M2M_SUCCESS) goto ERR; + ret += spi_flash_read_status_reg(&tmp); + }while(tmp & 0x01); + + } + M2M_PRINT("Done\r\n"); +#ifdef PROFILING + M2M_PRINT("#Erase time = %f sec\n", (GetTickCount()-t)/1000.0); +#endif +ERR: + return ret; +} + +/** +* @fn spi_flash_get_size +* @brief Get size of SPI Flash +* @return Size of Flash +*/ +uint32 spi_flash_get_size(void) +{ + uint32 u32FlashId = 0, u32FlashPwr = 0; + static uint32 gu32InernalFlashSize= 0; + + if(!gu32InernalFlashSize) + { + u32FlashId = spi_flash_rdid();//spi_flash_probe(); + if(u32FlashId != 0xffffffff) + { + /*flash size is the third byte from the FLASH RDID*/ + u32FlashPwr = ((u32FlashId>>16)&0xff) - 0x11; /*2MBIT is the min*/ + /*That number power 2 to get the flash size*/ + gu32InernalFlashSize = 1<u16Year = (uint16)winTime.wYear; + pstrSysTime->u8Month = (uint8)winTime.wMonth; + pstrSysTime->u8Day = (uint8)winTime.wDay; + pstrSysTime->u8Hour = (uint8)winTime.wHour; + pstrSysTime->u8Minute = (uint8)winTime.wMinute; + pstrSysTime->u8Second = (uint8)winTime.wSecond; +#else + pstrSysTime->u16Year = (uint16)(2015); + pstrSysTime->u8Month = (uint8)8; + pstrSysTime->u8Day = (uint8)6; + pstrSysTime->u8Hour = (uint8)9; + pstrSysTime->u8Minute = (uint8)39; + pstrSysTime->u8Second = (uint8)10; +#endif + + return M2M_SUCCESS; +} + +/** + * \brief Perform decoding to the data type "AlgorithmIdentifier". + */ +uint8 Cert_DecodeAlgID(tstrAsn1Context *pstrX509Asn1Cxt, uint32 u32Size) +{ + /* + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters NULL + * } + */ + + const uint8 gau8SecAlgorithms[][16] = { + RSA_ENCRYPTION, + MD5_WITH_RSA_ENCRYPTION, + SHA1_WITH_RSA_ENCRYPTION, + SHA256_WITH_RSA_ENCRYPTION, + SHA384_WITH_RSA_ENCRYPTION, + SHA512_WITH_RSA_ENCRYPTION + }; + #define X509_NUM_SUPPORTED_SEC_ALGORITHMS (sizeof(gau8SecAlgorithms) / sizeof(gau8SecAlgorithms[0])) + + uint8 u8Alg = X509_ALG_NULL; + + if (pstrX509Asn1Cxt != NULL) { + tstrAsn1Element strElem; + + /* Initialize a decoding object for this SEQUENCE. */ + ASN1_GetNextElement(pstrX509Asn1Cxt, &strElem); + if (strElem.u8Tag == ASN1_OBJECT_IDENTIFIER) { + if (strElem.u32Length <= 16) { + uint8 u8Idx; + uint8 au8AlgID[16]; + ASN1_Read(pstrX509Asn1Cxt, strElem.u32Length, au8AlgID); + for (u8Idx = 0; u8Idx < X509_NUM_SUPPORTED_SEC_ALGORITHMS; u8Idx++) { + if (!m2m_memcmp(au8AlgID, (uint8 *)gau8SecAlgorithms[u8Idx], strElem.u32Length)) { + u8Alg = u8Idx + 1; + break; + } + } + } + } + } + + return u8Alg; +} + +sint8 Cert_DecodeDistinguishedName(tstrAsn1Context *pstrX509Asn1Cxt, uint32 u32Size, tstrX520DistinguishedName *pstrDN) +{ + sint8 s8Ret = X509_FAIL; + + if ((pstrX509Asn1Cxt != NULL) && (pstrDN != NULL)) { + tstrAsn1Element strElem; + + ASN1_GetNextElement(pstrX509Asn1Cxt, &strElem); + if (strElem.u8Tag == ASN1_OBJECT_IDENTIFIER) { + uint8 au8CmnNameID[4] = ID_AT_COMMONNAME; + uint8 au8TempID[16]; + + pstrDN->u8Type = 0; + ASN1_Read(pstrX509Asn1Cxt, strElem.u32Length, au8TempID); + if (!m2m_memcmp(au8CmnNameID, au8TempID, strElem.u32Length)) { + pstrDN->u8Type = X520_COMMON_NAME; + } + + if (ASN1_GetNextElement(pstrX509Asn1Cxt, &strElem) != ASN1_FAIL) { + pstrDN->u8Length = (uint8)strElem.u32Length; + ASN1_ReadReference(pstrX509Asn1Cxt, strElem.u32Length, &pstrDN->pu8Name); + s8Ret = X509_SUCCESS; + } + } + } + + return s8Ret; +} + +sint8 Cert_DecodeX520Name(tstrAsn1Context *pstrX509Asn1Cxt, uint32 u32Size, tstrX520Name *pstrName) +{ + /* + * Name ::= CHOICE { -- only one possibility for now -- + * rdnSequence RDNSequence + * } + * + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= + * SET SIZE (1..MAX) OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue + * } + * + * AttributeType ::= OBJECT IDENTIFIER + * AttributeValue ::= ANY -- DEFINED BY AttributeType + * + * DirectoryString ::= CHOICE { + * teletexString TeletexString (SIZE (1..MAX)), + * printableString PrintableString (SIZE (1..MAX)), + * universalString UniversalString (SIZE (1..MAX)), + * utf8String UTF8String (SIZE (1..MAX)), + * bmpString BMPString (SIZE (1..MAX)) + * } + */ + sint8 s8Ret = X509_SUCCESS; + + if ((pstrX509Asn1Cxt != NULL) && (pstrName != NULL)) { + tstrAsn1Element strSetElem, strSeqElem; + tstrX520DistinguishedName strDN; + tstrSha1Context strSha1Cxt; + uint16 u16Offset = 0; + + SHA1_INIT(&strSha1Cxt); + + /* RelativeDistinguishedName. */ + while (u16Offset < u32Size) { + u16Offset += ASN1_GetNextElement(pstrX509Asn1Cxt, &strSetElem); + if (strSetElem.u8Tag == ASN1_SET) { + ASN1_GetNextElement(pstrX509Asn1Cxt, &strSeqElem); + if (strSeqElem.u8Tag != ASN1_SEQUENCE) { + s8Ret = X509_FAIL; + break; + } + + if (Cert_DecodeDistinguishedName(pstrX509Asn1Cxt, strSeqElem.u32Length, &strDN) != X509_SUCCESS) { + s8Ret = X509_FAIL; + break; + } + + if (strDN.u8Type == X520_COMMON_NAME) { + m2m_memcpy((uint8 *)pstrName->acCmnName, strDN.pu8Name, strDN.u8Length); + pstrName->acCmnName[strDN.u8Length] = '\0'; + } else if (strDN.u8Type == X520_ORG_UNIT) { + if (pstrName->acOrgUnit[0] == 0) { + m2m_memcpy((uint8 *)pstrName->acOrgUnit, strDN.pu8Name, strDN.u8Length); + pstrName->acOrgUnit[strDN.u8Length] = '\0'; + } + } else if (strDN.u8Type == X520_ORG) { + m2m_memcpy((uint8 *)pstrName->acOrg, strDN.pu8Name, strDN.u8Length); + pstrName->acOrg[strDN.u8Length] = '\0'; + } + + SHA1_UPDATE(&strSha1Cxt, strDN.pu8Name, strDN.u8Length); + } else { + break; + } + } + SHA1_FINISH(&strSha1Cxt, pstrName->au8NameSHA1); + } + + return s8Ret; +} + +sint8 Cert_DecodeRSAPubKey(tstrAsn1Context *pstrX509Asn1Cxt, uint32 u32KeySize, tstrRSAPublicKey *pstrRsaPublicKey) +{ + /* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ + sint8 s8Ret = X509_FAIL; + if ((pstrX509Asn1Cxt != NULL) && (pstrRsaPublicKey != NULL)) { + tstrAsn1Element strElem; + + ASN1_GetNextElement(pstrX509Asn1Cxt, &strElem); + if (strElem.u8Tag == ASN1_SEQUENCE) { + ASN1_GetNextElement(pstrX509Asn1Cxt, &strElem); + if (strElem.u8Tag == ASN1_INTEGER) { + ASN1_ReadReference(pstrX509Asn1Cxt, strElem.u32Length, &pstrRsaPublicKey->pu8N); + while (*pstrRsaPublicKey->pu8N == 0) { + pstrRsaPublicKey->pu8N++; + strElem.u32Length--; + } + pstrRsaPublicKey->u16NSize = (uint16)strElem.u32Length; + + ASN1_GetNextElement(pstrX509Asn1Cxt, &strElem); + if (strElem.u8Tag == ASN1_INTEGER) { + ASN1_ReadReference(pstrX509Asn1Cxt, strElem.u32Length, &pstrRsaPublicKey->pu8E); + while (*pstrRsaPublicKey->pu8E == 0) { + pstrRsaPublicKey->pu8E++; + strElem.u32Length--; + } + pstrRsaPublicKey->u16ESize = (uint16)strElem.u32Length; + s8Ret = X509_SUCCESS; + } + } + } + } + + return s8Ret; +} + +sint8 Cert_DecodeSubjectPubKey(tstrAsn1Context *pstrX509Asn1Cxt, uint32 u32Size, tstrPublicKey *pstrPubKey) +{ + /* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING + * } + */ + sint8 s8Ret = X509_SUCCESS; + + if ((pstrX509Asn1Cxt != NULL) && (pstrPubKey != NULL)) { + tstrAsn1Element strElem; + uint8 u8PubKeyAlg = 0; + uint16 u16Offset = 0; + + while (u16Offset < u32Size) { + u16Offset += ASN1_GetNextElement(pstrX509Asn1Cxt, &strElem); + if (strElem.u8Tag == ASN1_SEQUENCE) { + u8PubKeyAlg = Cert_DecodeAlgID(pstrX509Asn1Cxt, strElem.u32Length); + } else if (strElem.u8Tag == ASN1_BIT_STRING) { + if (u8PubKeyAlg != X509_PUB_RSA) { + s8Ret = X509_FAIL; + break; + } + + pstrPubKey->enuType = PUBKEY_ALG_RSA; + ASN1_Read(pstrX509Asn1Cxt, 1, NULL); + s8Ret = Cert_DecodeRSAPubKey(pstrX509Asn1Cxt, strElem.u32Length - 1, &pstrPubKey->strRSAKey); + break; + } + } + } + + return s8Ret; +} + +sint8 Cert_DecodeValidity(tstrAsn1Context *pstrX509Asn1Cxt, uint32 u32Size, tstrX509Time *pstrNotBefore, tstrX509Time *pstrNotAfter) +{ + /* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time + * } + */ + sint8 s8Ret = X509_FAIL; + + if ((pstrX509Asn1Cxt != 0) && (pstrNotAfter != NULL) && (pstrNotBefore != NULL)) { + tstrAsn1Element strElem; + + if (ASN1_GetNextElement(pstrX509Asn1Cxt, &strElem) != ASN1_INVALID) { + /* Start time. */ + ASN1_Read(pstrX509Asn1Cxt, strElem.u32Length, pstrNotBefore->au8Time); + pstrNotBefore->au8Time[strElem.u32Length] = '\0'; + + if (ASN1_GetNextElement(pstrX509Asn1Cxt, &strElem) != ASN1_INVALID) { + /* End time. */ + ASN1_Read(pstrX509Asn1Cxt, strElem.u32Length, pstrNotAfter->au8Time); + pstrNotAfter->au8Time[strElem.u32Length] = '\0'; + s8Ret = X509_SUCCESS; + } + } + } + + return s8Ret; +} + +sint8 Cert_DecodeTBSCertificate(tstrAsn1Context *pstrX509Asn1Cxt, uint16 u16CertSize, tstrX509Cert *pstrCert) +{ + /* + * TBSCertificate ::= SEQUENCE { + * version [0] + * Version DEFAULT v1, + * serialNumber CertificateSerialNumber, + * signature AlgorithmIdentifier, + * issuer Name, + * validity Validity, + * subject Name, + * subjectPublicKeyInfo SubjectPublicKeyInfo, + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, If present, version MUST be v2 or v3 + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, If present, version MUST be v2 or v3 + * extensions [3] Extensions OPTIONAL If present, version MUST be v3 + * } + * + */ + sint8 s8Ret = X509_SUCCESS; + + if ((pstrX509Asn1Cxt != NULL) && (pstrCert != NULL)) { + uint16 u16ReadOffset = 0; + tstrAsn1Element strElement; + uint8 u8CertState = CERT_VERSION_PENDING; + + /* Loop on the elements of the certificate until finishing. */ + while (u16ReadOffset < u16CertSize) { + u16ReadOffset += ASN1_GetNextElement(pstrX509Asn1Cxt, &strElement); + switch (u8CertState) { + case CERT_VERSION_PENDING: + + /* Version. */ + if (strElement.u8Tag == X509_VERSION) { + /* The encoding of version is on the form A0 03 02 01 ver. */ + if (strElement.u32Length < 3) { + s8Ret = X509_FAIL; + } + + ASN1_Read(pstrX509Asn1Cxt, 2, NULL); + ASN1_Read(pstrX509Asn1Cxt, 1, &pstrCert->u8Version); + u8CertState = CERT_SERIAL_PENDING; + } else if (strElement.u8Tag == X509_SERIAL_NO) { + /* The certificate version number is absent from the certificate. */ + /* It will be set to the default value Version 1.0. */ + pstrCert->u8Version = X509_VER_1; + + /* The first field is the serial number. */ + if (strElement.u32Length > X509_SERIAL_NO_MAX_LENGTH) { + strElement.u32Length = X509_SERIAL_NO_MAX_LENGTH; + } + + pstrCert->u8SerialNumberLength = (uint8)strElement.u32Length; + ASN1_Read(pstrX509Asn1Cxt, strElement.u32Length, pstrCert->au8SerialNo); + u8CertState = CERT_SIGNATURE_PENDING; + } + + break; + + case CERT_SERIAL_PENDING: + + /* SerialNumber. */ + if (strElement.u8Tag == X509_SERIAL_NO) { + /* The first field is the serial number. */ + if (strElement.u32Length > X509_SERIAL_NO_MAX_LENGTH) { + strElement.u32Length = X509_SERIAL_NO_MAX_LENGTH; + } + + pstrCert->u8SerialNumberLength = (uint8)strElement.u32Length; + ASN1_Read(pstrX509Asn1Cxt, strElement.u32Length, pstrCert->au8SerialNo); + u8CertState = CERT_SIGNATURE_PENDING; + } + + break; + + case CERT_SIGNATURE_PENDING: + + /* Signature. */ + if (strElement.u8Tag == X509_SIGNATURE) { + pstrCert->u8SignAlg = Cert_DecodeAlgID(pstrX509Asn1Cxt, strElement.u32Length); + u8CertState = CERT_ISSUER_PENDING; + } + + break; + + case CERT_ISSUER_PENDING: + + /* Issuer. */ + if (strElement.u8Tag == X509_ISSUER) { + Cert_DecodeX520Name(pstrX509Asn1Cxt, strElement.u32Length, &pstrCert->strIssuer); + u8CertState = CERT_VALIDITY_PENDING; + } + + break; + + case CERT_VALIDITY_PENDING: + + /* Validity. */ + if (strElement.u8Tag == X509_VALIDITY) { + Cert_DecodeValidity(pstrX509Asn1Cxt, strElement.u32Length, + &pstrCert->strStartDate, &pstrCert->strExpiryDate); + u8CertState = CERT_SUBJECT_PENDING; + } + + break; + + case CERT_SUBJECT_PENDING: + + /* Subject. */ + if (strElement.u8Tag == X509_SUBJECT) { + Cert_DecodeX520Name(pstrX509Asn1Cxt, strElement.u32Length, &pstrCert->strSubject); + u8CertState = CERT_SUBECTKEYINFO_PENDING; + } + + break; + + case CERT_SUBECTKEYINFO_PENDING: + + /* SubjectPublicKeyInfo. */ + if (strElement.u8Tag == X509_SUBJECT_KEY_INFO) { + Cert_DecodeSubjectPubKey(pstrX509Asn1Cxt, strElement.u32Length, &pstrCert->strPubKey); + u8CertState = CERT_EXTENSIONS_PENDING; + } + + break; + + case CERT_EXTENSIONS_PENDING: + ASN1_Read(pstrX509Asn1Cxt, strElement.u32Length, NULL); + break; + } + } + } + + return s8Ret; +} + +sint8 X509Cert_Decode(uint8 *pu8X509Buffer, uint32 u32CertSize, tstrX509Cert *pstrCert, uint8 bDumpX509) +{ + /* + * + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING } + * + */ + sint8 s8Ret = X509_FAIL; + + if ((pu8X509Buffer != NULL) && (pstrCert != NULL)) { + tstrAsn1Context strX509ASN1Cxt; + tstrAsn1Element strElement; + uint8 u8SignAlgorithm = X509_ALG_NULL; + + /* Initialize the certificate structure. */ + m2m_memset((uint8 *)pstrCert, 0, sizeof(tstrX509Cert)); + + /* Initialize the ASN1 Decoding operation. */ + strX509ASN1Cxt.pu8Buff = pu8X509Buffer; + strX509ASN1Cxt.pu8Data = pu8X509Buffer; + + ASN1_GetNextElement(&strX509ASN1Cxt, &strElement); + if ((strElement.u8Tag == ASN1_SEQUENCE) && (strElement.u32Length < u32CertSize)) { + /* Copy the TBS certificate. It shall be used later to calculate the certificate HASH. */ + pstrCert->pu8TBSCert = strX509ASN1Cxt.pu8Data; + + /* tbsCertificate. */ + pstrCert->u16TBSCertSize = ASN1_GetNextElement(&strX509ASN1Cxt, &strElement); + if (strElement.u8Tag == ASN1_SEQUENCE) { + if (Cert_DecodeTBSCertificate(&strX509ASN1Cxt, (uint16)strElement.u32Length, pstrCert) == 0) { + /* signatureAlgorithm. */ + ASN1_GetNextElement(&strX509ASN1Cxt, &strElement); + if (strElement.u8Tag == ASN1_SEQUENCE) { + /* Check if the signatureAlgorithm ID obtained in this element matches */ + /* the signature field of the TBS Certificate. */ + u8SignAlgorithm = Cert_DecodeAlgID(&strX509ASN1Cxt, strElement.u32Length); + if (u8SignAlgorithm == pstrCert->u8SignAlg) { + /* signature. */ + ASN1_GetNextElement(&strX509ASN1Cxt, &strElement); + if (strElement.u8Tag == ASN1_BIT_STRING) { + /* Store the obtained signature. */ + pstrCert->strSignature.u16BufferSize = (uint16)strElement.u32Length - 1; + + /* Jump one byte. */ + ASN1_Read(&strX509ASN1Cxt, 1, NULL); + + /* Get the signature value. */ + ASN1_ReadReference(&strX509ASN1Cxt, pstrCert->strSignature.u16BufferSize, + &pstrCert->strSignature.pu8Data); + + /* Dump the certificate contents. */ + if (bDumpX509) { + X509_CERT_DUMP(pstrCert); + } + + s8Ret = X509_SUCCESS; + } + } + } + } + } + } + } + + return s8Ret; +} + +#define X509_UTC_TIME_LENGTH 0x0D + +/*!< + * The UTC time for the X.509 encoding takes the format + * YYMMDDHHMMSSZ. Each digit is BCD encoded as ASCII digit. + */ + +#define X509_GENERALIZED_TIME_LENGTH 0x0F + +/*!< + * The UTC time for the X.509 encoding takes the format + * YYYYMMDDHHMMSSZ. Each digit is BCD encoded as ASCII digit. + */ + +#define GET_VAL(BUF, OFFSET) (((BUF)[OFFSET] * 10) + ((BUF)[OFFSET + 1])) + +sint8 Cert_DecodeTime(uint8 *pu8Time, tstrSystemTime *pstrTime) +{ + sint8 s8Ret = X509_FAIL; + + if (pu8Time != NULL) { + uint8 u8TimeLength = (uint8)strlen((char *)pu8Time); + uint8 au8Time[20]; + uint8 u8Idx; + + memcpy(au8Time, pu8Time, 20); + + if ((u8TimeLength >= X509_UTC_TIME_LENGTH) && (u8TimeLength <= X509_GENERALIZED_TIME_LENGTH)) { + if (au8Time[u8TimeLength - 1] == 'Z') { + for (u8Idx = 0; u8Idx < (u8TimeLength - 1); u8Idx++) { + au8Time[u8Idx] -= '0'; + } + + if (u8TimeLength == X509_UTC_TIME_LENGTH) { + pstrTime->u16Year = (au8Time[0] * 10) + au8Time[1]; + pstrTime->u16Year += (pstrTime->u16Year < 50 ? 2000 : 1900); + u8Idx = 2; + } else { + pstrTime->u16Year = (au8Time[0] * 1000) + (au8Time[1] * 100) + (au8Time[2] * 10) + au8Time[3]; + u8Idx = 4; + } + + pstrTime->u8Month = GET_VAL(au8Time, u8Idx); + u8Idx += 2; + + pstrTime->u8Day = GET_VAL(au8Time, u8Idx); + u8Idx += 2; + + pstrTime->u8Hour = GET_VAL(au8Time, u8Idx); + u8Idx += 2; + + pstrTime->u8Minute = GET_VAL(au8Time, u8Idx); + u8Idx += 2; + + pstrTime->u8Second = GET_VAL(au8Time, u8Idx); + + s8Ret = X509_SUCCESS; + } + } + } + + return s8Ret; +} + +sint8 Cert_CompareTime(tstrSystemTime *pstrT1, tstrSystemTime *pstrT2) +{ + sint8 s8Cmp = 1; + + if ((pstrT1 != NULL) && (pstrT2 != NULL)) { + /* YEAR. */ + if (pstrT1->u16Year == pstrT2->u16Year) { + /* MONTH. */ + if (pstrT1->u8Month == pstrT2->u8Month) { + /* DAY */ + if (pstrT1->u8Day == pstrT2->u8Day) { + s8Cmp = pstrT1->u8Hour - pstrT2->u8Hour; + } else { + s8Cmp = pstrT1->u8Day - pstrT2->u8Day; + } + } else { + s8Cmp = pstrT1->u8Month - pstrT2->u8Month; + } + } else { + s8Cmp = pstrT1->u16Year - pstrT2->u16Year; + } + } + + return s8Cmp; +} + +uint8 X509Cert_IsValid(void *pvX509) +{ + tstrX509Cert *pstrX509 = (tstrX509Cert *)pvX509; + uint8 u8Status = X509_STATUS_VALID; + + if (pstrX509 != NULL) { + tstrSystemTime strExpirationDate = {0}; + + if (Cert_DecodeTime(pstrX509->strExpiryDate.au8Time, &strExpirationDate) == X509_SUCCESS) { + M2M_DBG("Expiration Date\n\t%d-%02d-%02d %02d:%02d:%02d\n", + strExpirationDate.u16Year, strExpirationDate.u8Month, strExpirationDate.u8Day, + strExpirationDate.u8Hour, strExpirationDate.u8Minute, strExpirationDate.u8Second); + + if (strExpirationDate.u16Year != 9999) { +#ifdef WIN32 + if (M2M_GetTimeOfDay(&strSystemTime) == M2M_SUCCESS) { + if (Cert_CompareTime(&strExpirationDate, &strSystemTime) <= 0) { + u8Status = X509_STATUS_EXPIRED; + } + } +#endif + } + } else { + u8Status = X509_STATUS_DECODE_ERR; + } + } else { + u8Status = X509_STATUS_DECODE_ERR; + } + + return u8Status; +} + +void X509Cert_Dump(void *pvCert) +{ + tstrX509Cert *pstrCert = (tstrX509Cert *)pvCert; + if (pstrCert != NULL) { +#define X509_DUMP_ENABLE +#ifdef X509_DUMP_ENABLE + uint32 i; + tstrSystemTime strTime = {0}; + + printf("\r\n"); + printf("*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\r\n"); + printf(" ROOT CERTIFICATE \r\n"); + printf("*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\r\n"); + + printf("VERSION %u\r\n", pstrCert->u8Version + 1); + printf("SERIAL NO "); + for (i = 0; i < pstrCert->u8SerialNumberLength; i++) { + printf("%02X ", pstrCert->au8SerialNo[i]); + } + printf("\r\n"); + + printf("SIGNATURE ALGORITHM "); + if (pstrCert->u8SignAlg == X509_SIGN_MD5RSA) { + printf("md5WithRsaEncryption"); + } else if (pstrCert->u8SignAlg == X509_SIGN_SHA1RSA) { + printf("shaWithRsaEncryption"); + } else if (pstrCert->u8SignAlg == X509_SIGN_SHA256RSA) { + printf("sha256WithRsaEncryption"); + } else if (pstrCert->u8SignAlg == X509_SIGN_SHA384RSA) { + printf("sha384WithRsaEncryption"); + } else if (pstrCert->u8SignAlg == X509_SIGN_SHA512RSA) { + printf("sha512WithRsaEncryption"); + } + + printf("\r\n"); + + printf("ISSUER "); + if (strlen(pstrCert->strIssuer.acCmnName) != 0) { + printf("%s", pstrCert->strIssuer.acCmnName); + } + + printf("\r\n"); + + printf("SUBJECT "); + if (strlen(pstrCert->strSubject.acCmnName) != 0) { + printf("%s", pstrCert->strSubject.acCmnName); + } + + printf("\r\n"); + + printf("VALIDITY\n"); + printf(" Not Before : "); + Cert_DecodeTime(pstrCert->strStartDate.au8Time, &strTime); + printf("%d-%02d-%02d %02d:%02d:%02d\r\n", + strTime.u16Year, strTime.u8Month, strTime.u8Day, + strTime.u8Hour, strTime.u8Minute, strTime.u8Second); + + printf(" Not After : "); + Cert_DecodeTime(pstrCert->strExpiryDate.au8Time, &strTime); + printf("%d-%02d-%02d %02d:%02d:%02d\r\n", + strTime.u16Year, strTime.u8Month, strTime.u8Day, + strTime.u8Hour, strTime.u8Minute, strTime.u8Second); + + if (pstrCert->strPubKey.enuType == PUBKEY_ALG_RSA) { + printf("PUBLIC KEY "); + printf("RSA\n\n"); + printf("\tModulus"); + for (i = 0; i < pstrCert->strPubKey.strRSAKey.u16NSize; i++) { + if (!(i % 16)) { + printf("\r\n\t\t"); + } + + printf("%02X ", pstrCert->strPubKey.strRSAKey.pu8N[i]); + } + printf("\r\n"); + + printf("\tExponent"); + for (i = 0; i < pstrCert->strPubKey.strRSAKey.u16ESize; i++) { + if (!(i % 16)) { + printf("\r\n\t\t"); + } + + printf("%02X ", pstrCert->strPubKey.strRSAKey.pu8E[i]); + } + } + + printf("\r\n"); + + printf("SIGNATURE"); + for (i = 0; i < pstrCert->strSignature.u16BufferSize; i++) { + if (!(i % 16)) { + printf("\r\n\t"); + } + + printf("%02X ", pstrCert->strSignature.pu8Data[i]); + } + printf("\r\n"); + printf("*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=\n"); +#else + M2M_INFO("*=*=* X509 *=*=*\n"); + M2M_INFO("\tSubject <%s>\n", ((strlen(pstrCert->strSubject.acCmnName) != 0) ? pstrCert->strSubject.acCmnName : " ")); + M2M_INFO("\tIssuer <%s>\n", ((strlen(pstrCert->strIssuer.acCmnName) != 0) ? pstrCert->strIssuer.acCmnName : " ")); +#endif + } +}