SSL/TLS embedded for IoT #4

Embedded SSL 2017.06.15 10:43 Posted by Dwarp

SSL/TLS embedded for IoT


이 글은 embedded IoT device의 보안에 관한 글입니다.


embedded SSL/TLS 네번째입니다.


이번 글쓰기는 시간이 오래걸렸습니다. 기다려주시는 분들께 죄송한 마음뿐입니다.


바로 시작하겠습니다.



저번 포스팅까지는 기본적인 환경 구축을 완료했습니다. mbedTLS 소스와 ioLibrary도 추가했지요. 본격적으로 소스를 보겠습니다.




아무것도 없는 main을 보니 공허하네요 ㅠㅠ 저도 갑자기 하는 포팅이라 약간 가슴이 답답합니다. ㅎㅎㅎ 그래도 해보도록 하시지요~


먼저 iolibrary부터 포팅해서 ethernet이 원활하게 되는지 확인하도록 하겠습니다.


W5500을 사용하기 위해서는 3단계 정도만 거치면 됩니다.



1. SPI를 위한 GPIO 초기화


2. SPI 초기화


3. Read/Write 등록.



간단하지요? 우선 보드 초기화를 하기 위해 board.h라는 파일을 하나 만들겠습니다. (새로운 파일은 어떻게 만드나요? 같은 질문을 하시는 분들은 없으시겠지요?) 아래와 같이 작성합니다. 대략적으로 설명드리면 SPI1 사용하고 GPIOA 5,6,7 번이 SPI1으로 사용됩니다. reset port도 정의해주고, interrupt 핀도 정의 합니다.

#ifndef __BOARD_H_
#define __BOARD_H_

#define W5500_SPI			SPI1

#define W5500_RESET_PORT		GPIOC
#define W5500_RESET_PIN			GPIO_PIN_7

#define W5500_INT_PORT 			GPIOB
#define W5500_INT_PIN			GPIO_PIN_5

#define W5500_CS_PORT			GPIOB
#define W5500_CS_PIN			GPIO_PIN_6

#define W5500_SPI_GPIO_PORT		GPIOA
#define W5500_CLK_PIN			GPIO_PIN_5

#define W5500_MISO_PIN			GPIO_PIN_6

#define W5500_MOSI_PIN			GPIO_PIN_7

#endif


작성이 되었으면 이제 W5500를 위한 Peripheral을 초기화하는 W5500HardwareDriver.c를 작성해 봅시다.

#include "Board.h"

/*Include: Header file*/
#include "W5500HardwareDriver.h"

/*Include: W5500 Library*/
#include "wizchip_conf.h"

/*include: Standard IO library*/
#include <stdio.h>

SPI_HandleTypeDef hspi1W5500;

void W5500HardwareInitilize(void)
{
  __GPIOH_CLK_ENABLE();
  /*W5500 CS/INT/RST Clock enable*/
  __GPIOB_CLK_ENABLE();
  __GPIOC_CLK_ENABLE();
  
  /*W5500 GPIO&SPI1 Clock enable*/
  __GPIOA_CLK_ENABLE();
  
  /*Initialize GPIO Structure*/
  GPIO_InitTypeDef	GPIO_InitStructure;

  /*Initialize CS Pin*/
  GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStructure.Pin = W5500_CS_PIN;
  GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStructure.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(W5500_CS_PORT,&GPIO_InitStructure);
  
  /*Initialize INT Pin*/
  GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStructure.Pin = W5500_INT_PIN;
  GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
  GPIO_InitStructure.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(W5500_INT_PORT,&GPIO_InitStructure);

  /*Ethernet shield does not have individual reset pin*/
  /* ==> Remove R23 and connect RSTN - D9 pin
        Now D9 is Reset pin.*/
  GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
  GPIO_InitStructure.Pin = W5500_RESET_PIN;
  GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStructure.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(W5500_RESET_PORT,&GPIO_InitStructure);
  
  /*SPI init*/
  hspi1W5500.Instance = W5500_SPI;
  hspi1W5500.Init.Mode = SPI_MODE_MASTER;
  hspi1W5500.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1W5500.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi1W5500.Init.CLKPolarity = SPI_POLARITY_HIGH;
  hspi1W5500.Init.CLKPhase = SPI_PHASE_2EDGE;
  hspi1W5500.Init.NSS = SPI_NSS_SOFT;
  hspi1W5500.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1W5500.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1W5500.Init.TIMode = SPI_TIMODE_DISABLED;
  hspi1W5500.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED;
  hspi1W5500.Init.CRCPolynomial = 10;
  HAL_SPI_Init(&hspi1W5500);
  
  W5500HardwareReset();
}

void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(hspi->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspInit 0 */

  /* USER CODE END SPI1_MspInit 0 */
    /* Peripheral clock enable */
    __SPI1_CLK_ENABLE();
  
    /**SPI1 GPIO Configuration    
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI 
    */
    GPIO_InitStruct.Pin = W5500_CLK_PIN|W5500_MISO_PIN|W5500_MOSI_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
    HAL_GPIO_Init(W5500_SPI_GPIO_PORT, &GPIO_InitStruct);

  /* USER CODE BEGIN SPI1_MspInit 1 */

  /* USER CODE END SPI1_MspInit 1 */
  }
}

void HAL_SPI_MspDeInit(SPI_HandleTypeDef* hspi)
{

  if(hspi->Instance==SPI1)
  {
  /* USER CODE BEGIN SPI1_MspDeInit 0 */

  /* USER CODE END SPI1_MspDeInit 0 */
    /* Peripheral clock disable */
    __SPI1_CLK_DISABLE();
  
    /**SPI1 GPIO Configuration    
    PA5     ------> SPI1_SCK
    PA6     ------> SPI1_MISO
    PA7     ------> SPI1_MOSI 
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7);

  }
  /* USER CODE BEGIN SPI1_MspDeInit 1 */

  /* USER CODE END SPI1_MspDeInit 1 */
} 

void W5500HardwareReset(void)
{
  uint32_t tempTick;
  HAL_GPIO_WritePin(W5500_RESET_PORT,W5500_RESET_PIN,GPIO_PIN_RESET);
  tempTick = HAL_GetTick();
  while((HAL_GetTick() - tempTick) < W5500_RESET_TIME){/*1 ms Delay: Do nothing*/}
  HAL_GPIO_WritePin(W5500_RESET_PORT,W5500_RESET_PIN,GPIO_PIN_SET);
}

void W5500WriteByte(unsigned char txByte)
{
  unsigned char rtnByte;
  while (HAL_SPI_GetState(&hspi1W5500) != HAL_SPI_STATE_READY);
  HAL_SPI_TransmitReceive(&hspi1W5500,&txByte,&rtnByte,1,10);
}

unsigned char W5500ReadByte(void)
{
  unsigned char txByte = 0xff;//dummy
  unsigned char rtnByte;
  while (HAL_SPI_GetState(&hspi1W5500) != HAL_SPI_STATE_READY);
  HAL_SPI_TransmitReceive(&hspi1W5500,&txByte,&rtnByte,1,10);
  return rtnByte;
}

void W5500Select(void)
{
  HAL_GPIO_WritePin(W5500_CS_PORT,W5500_CS_PIN,GPIO_PIN_RESET);
}

void W5500DeSelect(void)
{
  HAL_GPIO_WritePin(W5500_CS_PORT,W5500_CS_PIN,GPIO_PIN_SET);
}


.c 파일을 만들었으니 .h 파일도 만들어 볼까요?


#ifndef __W5500HARDWAREDRIVER_H_
#define __W5500HARDWAREDRIVER_H_

#ifdef __cplusplus
 extern "C" {
#endif
   
#include "stm32f4xx_hal.h"

#define W5500_RESET_TIME	1 //ms
extern SPI_HandleTypeDef hspi1W5500;

void W5500HardwareInitilize(void);
void W5500Initialze(void);
void W5500HardwareReset(void);
void W5500WriteByte(unsigned char byte);
unsigned char W5500ReadByte(void);
void W5500Select(void);
void W5500DeSelect(void);
unsigned char wizchip_read(void);
void  wizchip_write(unsigned char wb);

#ifdef __cplusplus
}
#endif
#endif /*__W5500HARDWAREDRIVER_H_ */


이제 main()문에 살짝 넣어보고 시험 삼아 컴파일을 해볼게요.


#include "W5500HardwareDriver.h"

int main(void)
{

	W5500HardwareInitilize();

    while(1)
    {
    }
}


에러가 많이 나네요 ㅠㅠ;; 하지만 내용을 보시면 거의다 mbedtls와 관련된 내용입니다.



이제부터 조금 짜증 나는 내용입니다. mbedtls를 include 시킨 적도 없는데 에러가 나는 건 컴파일 에러가 나는 거라고 보시면 됩니다. 옵션이 안맞으니 #error를 통해서 에러를 주라고 프로그래밍 되어 있는 것이죠. 그럼 한번 고쳐 봅시다 ㅎㅎ


아마 여기에서 포기하시는 분들이 많을 거라고 생각됩니다. 왜냐하면 config.h를 수정해야하는데 2600줄짜리 config입니다. 각종 옵션과 암호화 방식, 인증 방식 등 수많은 것들이 우릴 기다리고 있으니까요. 언제 공부해서 언제 코딩합니까? ㅎㅎ


결론은!!!! config.h를 버립시다!


mbedTLS의 모든 파일들은 다음과 같이 시작합니다. 굳이 해설하자면

#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif

"MBEDTLS_CONFIG_FILE이 없으면 mbedtls/config.h를 include합시다. 그렇지 않다면 MBEDTLS_CONFIG_FILE을 참조합시다~"

라고 되어 있습니다.


따라서 MBEDTLS_CONFIG_FILE를 다시 define하면 그만입니다. 2600줄짜리 코드가지고 한줄한줄 읽어가면서 고생하지 마세요.


그래서 새로운 config 파일을 하나 더 만들도록 하겠습니다. 이름은 SSLConfig.h라는 이름으로 하고 생성한 후에 저를 믿고 그냥 복붙하세요.!!컨트롤 + c, 컨트롤 + v~ 고고!!


#ifndef MBEDTLS_CONFIG_H
#define MBEDTLS_CONFIG_H

/************************ macro define ***********************************/
#define MBEDTLS_SSL_CLI_C   //complie SSL cleint protocols

/*
   The following setting is base on the protocol for gmail & yahoo servers (TLS v1.2)
*/

//#defien SSL_CLIENT_SUPPOR_AILPAY

/************************ ssl config *************************************/

/* System supports functions */
//#define MBEDTLS_FS_IO    //

/* ssl features supports functions */
//#define MBEDTLS_PROTO_TLS1    //supports TLS v1.0
//#define MBEDTLS_PROTO_TLS1_1  //supports TLS v1.1
#define MBEDTLS_SSL_PROTO_TLS1_2        //supports TL v1.2
//#define MBEDTLS_PROTO_SSL3         //supports SSL v3.0

#define MBEDTLS_CIPHER_MODE_CBC //Use verify certificate function
#define MBEDTLS_PKCS1_V15       //define public key padding method

//#define MBEDTLS_SRV_SUPPORT_SSLV2_CLIENT_HELLO //define suppots SSL v2

/* ssl function supports */
//#define MBEDTLS_CERTS_C             //define to use certication testing function
#define MBEDTLS_RSA_C               //define public key encryption method (Using RSA) !!!

//#define MBEDTLS_ECDH_C  //LIU
//#define MBEDTLS_ECP_C

//#define #define MBEDTLS_ARC4_C      //define public key encryption method (Using RC4)

#define MBEDTLS_X509_USE_C          //Using X509 frame function
#define MBEDTLS_X509_CRT_PARSE_C    //define supporting ssl x.509 certificate analyze !!!
#define MBEDTLS_PK_C                //Using private key encryption function
#define MBEDTLS_PK_PARSE_C          //Using private key encryption analyze function

#define MBEDTLS_BIGNUM_C            //define using Big number function !!!
#define MBEDTLS_CIPHER_C            //define using certificate function

//#define MBEDTLS_ENTROPY_C           //define using Entropy calcuation !!!
#define MBEDTLS_SHA512_C            //define using SHA512 calcuation
#define MBEDTLS_SHA1_C            //define using SHA128 calcuation
#define MBEDTLS_SHA256_C          //define using SHA256 calcuation

#define MBEDTLS_MD_C              //define using MD calculation
#define MBEDTLS_MD5_C             //define using MD5 calculation

#define MBEDTLS_CTR_DRBG_C          //define using random number function !!!

#define MBEDTLS_AES_C               //define using AES function (after handshake - communicate stage)
//#define MBEDTLS_DES_C                     //define using DES function
#define MBEDTLS_ASN1_PARSE_C        //define using ASN analysis function
#define MBEDTLS_ASN1_WRITE_C        //define using ASN write function
#define MBEDTLS_OID_C              //define using OID function

#define MBEDTLS_SSL_TLS_C           //define using TLS support function !!!

//#define MBEDTLS_ERROR_C             //define using ERROR function (Showing error message)
//#define MBEDTLS_DEBUG_C             //define using debug function (Showing debug message)

/* Testing certificate procedure */
#define MBEDTLS_CERTS_C        //define using certificate testing function
#define MBEDTLS_PEM_PARSE_C    //define testing certifcate will use ASCII format (Sending PEM file)
#define MBEDTLS_BASE64_C       //define testing certificate is in ASCII format

//define communicate encrytion methods 
//#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED
//#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSDEBUG_DFL_MODEA_ENABLED

#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED        //
//#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED   //
//#define MBEDTLS_GCM_C    //AES in GCM mode짙짭base on parallel design짙짭therefore it can good performance on speed,cost and less delay
//#define MBEDTLS_CCM_C    //

//define encryption and discrete methods
#define MBEDTLS_SSL_CIPHERSUITES                    \
        MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA,       \
		    MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA,       \
			  MBEDTLS_TLS_RSA_WITH_RC4_128_SHA
				//TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
			 // TLS_RSA_WITH_AES_128_GCM_SHA256

//Save RAM 
#define MBEDTLS_MPI_MAX_SIZE   256
//#define MBEDTLS_ENTROPY_MAX_SOURCES   2

//#define SSL_MAX_CONTENT_LEN    4096

//According to SSL requested data length to define, if the data is long, it takes a larger RAM space 

#if defined (MBEDTLS_CLIENT_SUPPOR_AILPAY) //defines for alipay
		#define MBEDTLS_SSL_MAX_CONTENT_LEN   5120   //define SSL client for connection to AILPAY
#else
		#define MBEDTLS_SSL_MAX_CONTENT_LEN    4096 //2048
#endif

#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION

#include "mbedtls/check_config.h"
#endif /* ssl_config */

새로운 config 파일을 만들었으면 이제 조건에 맞게 define을 해줘야 하겠죠? 컴파일러 옵션으로 이동해서 추가하도록 하겠습니다.



위 그림처럼 Configuration -> Compile -> Advance setting에서 Misc Controls에 -DMBEDTLS_CONFIG_FILE=<SSLConfig>를 추가합니다. 그리고 나면 preview에서 뒤가 짤리는데 신경쓰지 마세요. 거기서만 안보일 뿐이지 컴파일은 정상적으로 됩니다.


그리고 C99 옵션 선택합니다. 추후에 Time 함수같은거 사용할 수도 있으니까요 ㅎㅎ 그리고 컴파일을 해봅시~~~드아~~~~~


컴파일이 정상적으로 되나요? 휴휴~ 그러면 한숨은 돌렸습니다.


힘드네요.. 오늘은 여기까지만 하고 다음 포스팅은 최대한 빠르게 진행하도록 하겠습니다.(저도 오랜만에 하다보니 자꾸 까먹어서 ㅎ


그럼 안녕~~

저작자 표시
신고

'Embedded SSL' 카테고리의 다른 글

SSL/TLS embedded for IoT #6  (0) 2017.06.17
SSL/TLS embedded for IoT #5  (0) 2017.06.16
SSL/TLS embedded for IoT #4  (0) 2017.06.15
SSL/TLS embedded for IoT #3  (6) 2016.12.28
SSL/TLS embedded for IoT #2  (0) 2016.12.27
SSL/TLS for embedded IoT #1  (0) 2016.12.27