보안 IoT 장치 통신을 시도했다 (MbedTLS 이식편-MQTTS)

소개



2019년 5월에 IoTLT에서 LT를 했습니다.
그 내용의 팔로우를 기입하면서 나름대로 정리해 가고 싶습니다.

발표 내용:
스타트업 IoT 디바이스 보안 고려

마지막까지의 개요



보안 IoT 장치 통신을 시도했습니다 (MbedTLS 이식편 - https 테스트 - 연결) 에서 https에서 기본 GET 요청을 보내고 응답을 받았습니다.

이번 기사와 관련된 소스 코드는 아래에서 공개 중.
kmwebnet/ECC608-mqtts-client

MQTT 연결을 위한 포팅



디바이스 측에서 MQTTS를 통해 브로커에 연결하여 게시 및 구독을 테스트합니다.
이번 대상 MQTT 브로커는 CentOS7에 OpenSSL1.1.1 및 Mosquitto1.6 설치
환경을 사용합니다.
이번에도 코드에서 포팅 포인트를 정리합니다.

MQTT 클라이언트 내장



ESP-IDF 용 MQTT 코드를 src/mqtt에 배치합니다.
그 중, transport_ssl.c의 ssl_connect 함수에, 디바이스의 증명서를 ATECC608A로부터 추출해 포함하는 루틴을 넣는다.
    /* Convert to an mbedtls key */
    if (0 != atca_mbedtls_pk_init(&pkey, 0))
    {
        printf("Failed to parse key from device\n");
        goto exit;
    }

    /* Extract the device certificate and convert to mbedtls cert */
    if (0 != atca_mbedtls_cert_add(&ssl->cert, &g_cert_def_2_device))
    {
        printf("Failed to parse cert from device\n");
        goto exit;
    }

    status = atcab_release();
     if (ATCA_SUCCESS != (status = atcab_init(&cfg)))
     {
         printf("Failed to init: %d\r\n", status);
     }

    /* Extract the signer certificate, convert, then attach to the chain */
    if (0 != atca_mbedtls_cert_add(&ssl->cert, &g_cert_def_1_signer))
    {
        printf("Failed to parse cert from device\n");
        goto exit;
    }


    /* Attach the certificate chain and private key to the SSL/TLS context */
    printf("  . Set up the client credentials.");
    fflush(stdout);
    if(0 != (ret = mbedtls_ssl_conf_own_cert(
            &ssl->conf, &ssl->cert, &pkey)))
    {
        printf(" failed\n ! mbedtls_ssl_conf_own_cert returned %d\r\n", ret);
        goto exit;
    }
    printf(" ok\n");


메인 처리에 대해서



main.c 내의 분석.
실제의 MQTT의 처리는, 우선 mqtt_app_start 내의 하기, 접속처 URL의 설정과 클라이언트의 기동이 행해진다.
    const esp_mqtt_client_config_t mqtt_cfg = {
        .uri = "mqtts://testcorp.com:8883",
//        .host = "",
//        .port = ,
        .event_handle = mqtt_event_handler,
        .cert_pem = (const char *)rootcacert,
    };

    ESP_LOGI(TAG, "[APP] Free memory: %d bytes", esp_get_free_heap_size());
    esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
    esp_mqtt_client_start(client);

esp_mqtt_client_start (client);는 내부적으로 구독 FreeRTOS 작업을 시작합니다.
MQTT 메시지를 기다리는 상태가 됩니다.

그 후, BME280의 초기화가 행해진 후, 다음의 루프에 들어간다.
    while(1) {

…

            com_rslt = bme280_read_uncomp_pressure_temperature_humidity(
          &v_uncomp_pressure_s32, &v_uncomp_temperature_s32, &v_uncomp_humidity_s32);

…

    sprintf(pubMessage, 
        "{\"Temparature\": \"%f\" , " 
        "\"Pressure\": \"%f\" , " 
        "\"Humidity\": \"%f\"}",         
        bme280_compensate_temperature_double(v_uncomp_temperature_s32),
        bme280_compensate_pressure_double(v_uncomp_pressure_s32)/100,
        bme280_compensate_humidity_double(v_uncomp_humidity_s32)) ;


esp_mqtt_client_publish(client, "/topic/qos0", pubMessage, 0, 0, 0);

const portTickType yDelay = 10000 / portTICK_RATE_MS; // 1000ms

vTaskDelay(yDelay);

    }

처리의 흐름으로서는,
1, BME280의 측정 결과 취득
2, JSON의 형태로 데이터를 성형
3, esp_mqtt_client_publish로 데이터 게시
4, 10초 웨이트

이 반복이 된다.

/topic/qos0이 주제 이름이 되고 다른 노드에서 이 주제로 게시하면
mqtt_event_handler의 MQTT_EVENT_DATA가 잡히고 콘솔에 표시하는 동작을 수행한다.
I (24175) ECC608: Stack remaining for task 'main' is 1904 bytes
I (24185) MQTT_CLIENT: deliver_publish, message_length_read=97, message_length=97
I (24185) ECC608: MQTT_EVENT_DATA
TOPIC=/topic/qos0
DATA={"Temparature": "26.485141" , "Pressure": "1004.483107" , "Humidity": "53.987691"}
I (25325) MQTT_CLIENT: deliver_publish, message_length_read=97, message_length=97
I (25325) ECC608: MQTT_EVENT_DATA
TOPIC=/topic/qos0
DATA={"Temparature": "26.947010" , "Pressure": "1005.009985" , "Humidity": "59.377412"}

그리고는 Node-RED로 데이터를 추출하여 시각화할 수 있다.

좋은 웹페이지 즐겨찾기