ããã«ã¡ã¯ãGMOã¤ã³ã¿ã¼ããã æ°éã§ãã
çµè¾¼ã¿ã»IoTçãªç«¯æ«ã§ããå©ç¨ããã¦ããmbedTLSã®ææ°ãã¼ã¸ã§ã³ã使ã£ã¦ãTLS 1.3ãQUICã®æå·åã¾ã§å®éã«ESP32ãå©ç¨ãã¦è¡ã£ã¦ã¿ã¾ãã
ç®æ¬¡
mbedTLS
mbedTLS ã¯çµè¾¼ã¿æ©å¨ãªã©ã§ä½¿ãããã³ã³ãã¯ããªãµã¤ãºã®SSL/TSLã©ã¤ãã©ãªã§ããããç¥ããã¦ããSSLã©ã¤ãã©ãªã§ã¯OpenSSL/BoringSSLãªã©ãããã¾ããããã ãIoTçãªç«¯æ«ãªã©ã§ã¯ã¹ããã¯ãéããããã®ã«ãªãã¾ããä¾ãã°ãåãå©ç¨ãã端æ«ã ã¨ã¢ããªã±ã¼ã·ã§ã³ãçµè¾¼ããé åãããã256Kbyteã¨ãããµã¤ãºã¨ãã ã£ãããã¾ãã
ãããã£ãIoTçãªæ©å¨ãçµè¾¼ã¿æ©å¨ã®ãããªã¹ããã¯ã§ãPCããµã¼ãã¼ã§å©ç¨ããã¦ãããããªSSL/TLSã©ã¤ãã©ãªãçµè¾¼ãã§ä½¿ãã®ã¯ã¹ããã¯çã«ãé£ããã§ããããã§ä½¿ãããã®ãçµè¾¼ã¿ç«¯æ«åãã®ã³ã³ãã¯ããªã©ã¤ãã©ãªã¨ããããã§ãã
mbedTLSã®ä»ã«ãçµè¾¼ã¿æ©å¨åããã¿ã¼ã²ããã«ããSSL/TSLã©ã¤ãã©ãªã« wolfSSL ãããã¾ããå人çã«ã¯mbedTLSãwolfSSLã¯çµè¾¼ã¿æ©å¨åãOSS SSL/TLSã§ããè¦ããã®ã§ãã
æ°ãã¤ããã…
ãããªmbedTLSãçµè¾¼ã¿ã§å©ç¨ãã¦ãã¦ãæ°ãã¤ããããã¼ã¸ã§ã³ã3.1.0ã«ãªã£ã¦ãã¾ãããä»ã«ããã¼ã¸ã§ã³ãä½åããã£ã¦ãç¾æç¹ã§ã¯…
ã»2.16.xãï¼Long Time Supportã®æå¾ã®ãã¼ã¸ã§ã³ã2.28ç³»ã¸ã®ç§»è¡ãå§ããã
ã»2.28.xãï¼2024å¹´æ«ã¾ã§ãã°ã»ã»ãã¥ãªãã£ãã£ãã¯ã¹ã®ãµãã¼ããè¡ãããã
ã»3.1.x ãï¼ææ°ã®ãã°ã»ã»ãã¥ãªãã£ãã£ãã¯ã¹ãæ©è½è¿½å ãè¡ãããã
åãå人çã«ã¡ã³ããã¦ããã©ã¤ãã©ãªã§ã¯2.16ç³»ã使ã£ã¦ããã®ã§ãã¨ãããã2.28.0ã«ã¢ãããã¼ããã¾ããããã®ã¨ããPSAï¼Platform Security Architectureï¼ã¨ããã¢ã¸ã¥ã¼ã«ã»ããã追å ããã¦å
¨ä½çã«ãã©ã¹ãã£ãã¯ã«æ§æãå¤ãã£ã¦ãã¦ãããããçµè¾¼ãã®ãå°å³ã«é¢åã§ããã
ãã ã2.28.xç³»ã¯ãã¨2å¹´å¼±ã§ãµãã¼ã対象ããå¤ãã¦ãã¾ãã¨ããäºããã£ã¦ãä»å¾ã®ã¢ãããã¼ããèããã¨ææ°ã®3.1ç³»ã追ããããæ¹ãè¯ãããã§ãã
mbedTLS 3.1ç³»ãè¦ã¦ã¿ã
mbedTLSã¯configï¼ããããã¡ã¤ã«ï¼ã§å©ç¨ããã¢ã«ã´ãªãºã ãè¨å®ãããã¨ãåºæ¥ã¾ããä¾ãã°ãDTLSã使ãããã£ãã”#define MBEDTLS_SSL_PROTO_DTLS”ãæ¸ãã¦ããã¨ãã£ãæãã§ããmbedTLS 3.1ç³»ã§ã¯è«¸ã ã®è¨å®ãæ¸ãã¦ããã®ã¯ mbedtls_confi.h ã«ãªã£ã¦ãã¾ããããã£ã¨è¦ã¦ã¿ã¦å人çã«ããï¼ã¨æã£ãç¹ã¯ãã®è¾ºã§ãã
ã»MBEDTLS_SSL_PROTO_TLS1_3ãå
¥ã£ã¦ããã
ã»TLS 1.0/1.1, 3DES, MD2, MD5, RC4, Blowfish, XTEAãç¡ããªã£ãã
ã»PSAå¨ãã®è¨å®ãå¢ãã¦ããã
MBEDTLS_SSL_PROTO_TLS1_3_EXPERIMENTALã ã£ãã®ããEXPERIMENTALãåãã¦ãã¾ãããããããçµè¾¼ã¿ãTLS 1.3ã«åãã£ã¦ããã!!ã¨ããæ°æã¡ãæãã¾ãã
TLS 1.3ãPCä¸ã§ä½¿ã£ã¦ã¿ã
ç¾æç¹ã§ã®ææ°ç mbedTLS 3.10 ãã¨ãããããã«ããã¦ãµã³ãã«ããã°ã©ã çµç±ã§ãwww.google.com ã«TLS 1.3ã§ã¢ã¯ã»ã¹ãã¦ã¿ã¾ããï¼ç°å¢ã¯Macãå©ç¨ãã¦ãã¾ãããã«ãã¨ã©ã¼ã§å¿ è¦ãªç©ã¯é©å®brewã§å ¥ãã¾ããï¼
wget https://github.com/Mbed-TLS/mbedtls/archive/refs/tags/v3.1.0.tar.gz
tar -zxvf v3.1.0.tar.gz
cd mbedtls-3.1.0
# include/mbedtls/mbedtls_config.h ãã
# MBEDTLS_SSL_PROTO_TLS1_3
# MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE
# ãã³ã¡ã³ãã¢ã¦ããã¦ãã«ã
make
# www.google.com ã«æ¥ç¶ãã¦ã¿ããRoot CAããã¦ã³ãã¼ã
wget https://pki.goog/repo/certs/gtsr1.pem
# force_version=tls13 ãä»ãã¦TLS 1.3ã§ã¢ã¯ã»ã¹
./programs/ssl/ssl_client2 server_name=www.google.com server_port=443 ca_file=./gtsr1.pem force_version=tls13ãã®ã¨ããæ¬å½ã«TLS 1.3ã§ã¢ã¯ã»ã¹ãã¦ããã®ãï¼Wiresharkã使ã£ã¦åæã«è¦³æ¸¬ãã¾ãã

TLS 1.3ã§ã¢ã¯ã»ã¹ãã¦ããããã§ãã1-RTTã§çµããã¯ããããªããã¯ã©ã¤ã¢ã³ãå´ããChange Cipher Specãé£ãã§ãã¾ããããã¯MBEDTLS_SSL_TLS1_3_COMPATIBILITY_MODE ã®èª¬æã«ããéãï¼RFC 8446 D.4. Middlebox Compatibility Modeï¼ãããã«ããã¯ã¹ã®ä¸ä½äºææ§ã®ããã«æãã¦ãã空ã®Change Cipher Specã§ããã
ESP32ããTLS 1.3ã使ã£ã¦ã¿ã
ã¨ããããTLS 1.3ã§éä¿¡ãåºæ¥ãã®ã§ãå®éã«çµè¾¼ã¿ã§ä½¿ããããªãã®ã¯äººã®æ§ã§ãããã
ããã§ã¯ESP32 Devboardããã¢ã¯ã»ã¹ãã¦ä½¿ã£ã¦ã¿ã¾ããã¨ããã®ããESP32 IDF(Arduino IDEã§ã)ã§ã¯mbedTLSãå©ç¨ããã¦ãã¦ãã¨ããããåããã¦ã¿ãã®ã«ã¯ã¡ããã©è¯ãã£ãã®ãããã¾ãã
ããã§å©ç¨ããã®ã¯ãESP-WROOM-32ãã¬ã¤ã¯ã¢ã¦ãSD+ã§ãã

ESP-IDF ã®mbedTLSã®çµè¾¼ã¿å®è£
ãè¦ã¦ã¿ãã¨ããããªãã¸ããªã®ææ°ã¯æ¢ã«3.1.0åãã«ãªã£ã¦ãã¾ãããreleaseãã¼ã¸ã§ã³ã§ã¯ã¾ã ã§ãããä»å¾ã¯ESP32ã®TLSã§ãmbedTLS 3.1ç³»ãå©ç¨ããããã¨ãæ³åããã¾ãã
ã¨ãããã esp-idf çµç±ã§å
ç¨ã¨åãã www.google.com ã«TLS1.3ã§ã¢ã¯ã»ã¹ãã¦ã¿ã¾ãã
# release ãã¼ã¸ã§ã³ã§ã¯ãªããææ°ã®repoããå
¨é¨åå¾ãã¦ããã
git clone --recursive https://github.com/espressif/esp-idf.git
cd esp-idf
# esp-idf ã®ç°å¢æ§ç¯æé
# https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/linux-macos-setup.html
# æé ã«å¾ã£ã¦ç°å¢ãæºåããã
# å¿
è¦ãªããã±ã¼ã¸ãã¤ã³ã¹ãã¼ã«ã»æé ã«å¾ã£ã¦ãã«ãç°å¢ãæ´åããã
# ãããããæ¬çª
cp -r examples/protocols/https_mbedtls/ .
cd https_mbedtls
idf.py set-target esp32
idf.py menuconfigPCä¸ã§ã¯mbedTLSã®configãç´æ¥å¤æ´ãã¾ããããesp idfã§ã¯menuconfigããè¨å®ãããã¨ãåºæ¥ã¾ããmenuconfigã® âComponent configâ -> âmbedTLSâ -> âmbedTLS v3.x relatedâ -> âSupport TLS 1.3 protocolâ ãæå¹ã«ãã¾ãããã®æãWiFiã®æ¥ç¶è¨å®ã âExample Connection Configurationâ ããè¡ã£ã¦ãNWã«æ¥ç¶ã§ããããã«ãã¦ããã


次ã«ã½ã¼ã¹ã³ã¼ããå°ãä¿®æ£ãã¾ãããã®ã¾ã¾ã ã¨TLS 1.2ã§æ¥ç¶ããã®ã§ããµã³ãã«ã® https_mbedtls_example_main.c ã以ä¸ã®ããã«ä¿®æ£ãã¾ãããµã³ãã«ã³ã¼ããªã®ã§å ¨ä½ãè¼ãã¦ããã¾ãã
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "esp_netif.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include "lwip/netdb.h"
#include "lwip/dns.h"
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/esp_debug.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "esp_crt_bundle.h"
// æ¥ç¶å
ã¯Google
#define WEB_SERVER "www.google.com"
#define WEB_PORT "443"
#define WEB_URL "/"
static const char *TAG = "example";
static const char *REQUEST = "GET " WEB_URL " HTTP/1.0\r\n"
"Host: "WEB_SERVER"\r\n"
"User-Agent: esp-idf/1.0 esp32\r\n"
"\r\n";
// GTS Root R1 ã®PEMãåã£ã¦ãã¦ç½®ãã¨ã
#define GTSR1_CA_PEM \
"-----BEGIN CERTIFICATE-----\r\n" \
"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\r\n" \
"bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c\r\n" \
"-----END CERTIFICATE-----"
const unsigned char gtsr1_pem[] = GTSR1_CA_PEM;
static void https_get_task(void *pvParameters) {
char buf[512];
int ret, flags, len;
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_x509_crt cacert;
mbedtls_ssl_config conf;
mbedtls_net_context server_fd;
mbedtls_ssl_init(&ssl);
mbedtls_x509_crt_init(&cacert);
mbedtls_ctr_drbg_init(&ctr_drbg);
ESP_LOGI(TAG, "Seeding the random number generator");
mbedtls_ssl_config_init(&conf);
mbedtls_entropy_init(&entropy);
if((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
NULL, 0)) != 0) {
ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned %d", ret);
abort();
}
ESP_LOGI(TAG, "Attaching the certificate bundle...");
ret = esp_crt_bundle_attach(&conf);
if(ret < 0) {
ESP_LOGE(TAG, "esp_crt_bundle_attach returned -0x%x\n\n", -ret);
abort();
}
ESP_LOGI(TAG, "Setting hostname for TLS session...");
/* Hostname set here should match CN in server certificate */
if((ret = mbedtls_ssl_set_hostname(&ssl, WEB_SERVER)) != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%x", -ret);
abort();
}
ESP_LOGI(TAG, "Setting up the SSL/TLS structure...");
if((ret = mbedtls_ssl_config_defaults(&conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned %d", ret);
goto exit;
}
/* MBEDTLS_SSL_VERIFY_OPTIONAL is bad for security, in this example it will print
a warning if CA verification fails but it will continue to connect.
You should consider using MBEDTLS_SSL_VERIFY_REQUIRED in your own code.
*/
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
// root caã®èªã¿è¾¼ã¿ã¨ã»ãã·ã§ã³ãã±ãããæå¹ã«ãã¦ããã
// ãã¨ã¯TLSã®éµäº¤æã¢ã¼ãã®è¨å®ãre-negotiationã¯ã¨ããããç¡å¹ã«
// TLSã®æå¤§ã»æå°ãã¼ã¸ã§ã³ãTLS 1.3åºå®
// ä¸è¨ã®è¨è¼ã®ã¨ããããµã³ãã«ãªã®ã§ãæ¬æ¥ã¯ã¡ããã¨VERIFYãããã¨!!
mbedtls_x509_crt_parse( &cacert, gtsr1_pem, sizeof(gtsr1_pem) );
mbedtls_ssl_conf_session_tickets( &conf, MBEDTLS_SSL_SESSION_TICKETS_ENABLED );
mbedtls_ssl_conf_tls13_key_exchange_modes( &conf, MBEDTLS_SSL_TLS1_3_KEY_EXCHANGE_MODE_ALL );
mbedtls_ssl_conf_renegotiation( &conf, MBEDTLS_SSL_RENEGOTIATION_DISABLED );
mbedtls_ssl_conf_min_version( &conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4 );
mbedtls_ssl_conf_max_version( &conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_4 );
mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
#ifdef CONFIG_MBEDTLS_DEBUG
mbedtls_esp_enable_debug_log(&conf, CONFIG_MBEDTLS_DEBUG_LEVEL);
#endif
if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) {
ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x\n\n", -ret);
goto exit;
}
while(1) {
mbedtls_net_init(&server_fd);
ESP_LOGI(TAG, "Connecting to %s:%s...", WEB_SERVER, WEB_PORT);
if ((ret = mbedtls_net_connect(&server_fd, WEB_SERVER,
WEB_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) {
ESP_LOGE(TAG, "mbedtls_net_connect returned -%x", -ret);
goto exit;
}
ESP_LOGI(TAG, "Connected.");
mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
ESP_LOGI(TAG, "Performing the SSL/TLS handshake...");
while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret);
goto exit;
}
}
ESP_LOGI(TAG, "Verifying peer X.509 certificate...");
if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) {
/* In real life, we probably want to close connection if ret != 0 */
ESP_LOGW(TAG, "Failed to verify peer certificate!");
bzero(buf, sizeof(buf));
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
ESP_LOGW(TAG, "verification info: %s", buf);
} else {
ESP_LOGI(TAG, "Certificate verified.");
}
ESP_LOGI(TAG, "Cipher suite is %s", mbedtls_ssl_get_ciphersuite(&ssl));
ESP_LOGI(TAG, "Writing HTTP request...");
size_t written_bytes = 0;
do {
ret = mbedtls_ssl_write(&ssl,
(const unsigned char *)REQUEST + written_bytes,
strlen(REQUEST) - written_bytes);
if (ret >= 0) {
ESP_LOGI(TAG, "%d bytes written", ret);
written_bytes += ret;
} else if (ret != MBEDTLS_ERR_SSL_WANT_WRITE && ret != MBEDTLS_ERR_SSL_WANT_READ) {
ESP_LOGE(TAG, "mbedtls_ssl_write returned -0x%x", -ret);
goto exit;
}
} while(written_bytes < strlen(REQUEST));
ESP_LOGI(TAG, "Reading HTTP response...");
do {
len = sizeof(buf) - 1;
bzero(buf, sizeof(buf));
ret = mbedtls_ssl_read(&ssl, (unsigned char *)buf, len);
if(ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
continue;
if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
ret = 0;
break;
}
if(ret < 0) {
ESP_LOGE(TAG, "mbedtls_ssl_read returned -0x%x", -ret);
break;
}
if(ret == 0) {
ESP_LOGI(TAG, "connection closed");
break;
}
len = ret;
ESP_LOGD(TAG, "%d bytes read", len);
/* Print response directly to stdout as it is read */
for(int i = 0; i < len; i++) {
putchar(buf[i]);
}
} while(1);
mbedtls_ssl_close_notify(&ssl);
exit:
mbedtls_ssl_session_reset(&ssl);
mbedtls_net_free(&server_fd);
if(ret != 0) {
mbedtls_strerror(ret, buf, 100);
ESP_LOGE(TAG, "Last error was: -0x%x - %s", -ret, buf);
}
putchar('\n'); // JSON output doesn't have a newline at end
static int request_count;
ESP_LOGI(TAG, "Completed %d requests", ++request_count);
printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
for(int countdown = 10; countdown >= 0; countdown--) {
ESP_LOGI(TAG, "%d...", countdown);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
ESP_LOGI(TAG, "Starting again!");
}
}
void app_main(void) {
ESP_ERROR_CHECK( nvs_flash_init() );
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(&https_get_task, "https_get_task", 8192, NULL, 5, NULL);
}ãã¨ã¯ESP32ã«ãã©ãã·ã¥ãã¦å®éã«ã·ãªã¢ã«çµç±ã§æ¸ãè¾¼ãã§ãå®éã«TLS 1.3ã§ www.google.com ã«ã¢ã¯ã»ã¹ã§ãããã¨ã確èªãã¾ãã

ã©ãããããããªã¢ã¯ã»ã¹ã§ãã¦ããããã§ãããã®æã¯Windows PCã®ã¢ãã¤ã«ãããã¹ããããå©ç¨ãã¦ãWiresharkã§ãã±ãããã£ããã£ã¼ããã¾ãããããã¡ããTLS 1.3ã§ã¢ã¯ã»ã¹ãã¦ãããã°ãåãã¾ããã
QUICã®æå·åãè¡ã
ããã¾ã§ãã£ãããmbedTLS ã使ã£ã¦QUICã®æå·åã»å¾©å·åãããããªãã®ã¯äººã®æ§ã§ãããããã§ã¯ãRFC 9001ã®Appendix Aã«ãããµã³ãã«ãã±ããã使ã£ã¦ãã£ã¦ã¿ã¾ãã
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common.h"
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/hmac_drbg.h"
#include "mbedtls/x509.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#include "mbedtls/timing.h"
#include "mbedtls/base64.h"
#include "mbedtls/hkdf.h"
#include "mbedtls/gcm.h"
#include <ssl_misc.h>
#include "ssl_tls13_keys.h"
#define BUFFER_SIZE 2000
// RFC 9001, 5.2. Initial Secrets, salt
unsigned char salt[20] = {
0x38,0x76,0x2c,0xf7,0xf5,0x59,0x34,0xb3,0x4d,0x17,0x9a,0xe6,0xa4,0xc8,0x0c,0xad,
0xcc,0xbb,0x7f,0x0a};
// RFC 9001, Appendix A.2. Client Initial QUIC long header
// c300000001088394c8f03e5157080000449e00000002
// c3 = long header(1byte)
// 00 00 00 01 = version (4byte)
// 08 = DCID Len (1byte)
// 83 94 c8 f0 3e 51 57 08 = Destination Connection ID (8byte)
// 00 = SCID Len(1byte)
// 00 = Token Length (1byte)
// 449e = length = 1182 (2byte)
// 00 00 00 02 = packet number = 2(pn_length)
unsigned char plane_header[22] = {
0xc3,0x00,0x00,0x00,0x01,0x08,0x83,0x94,0xc8,0xf0,0x3e,0x51,0x57,0x08,0x00,0x00,
0x44,0x9e,0x00,0x00,0x00,0x02};
// RFC 9001, Appendix A.2. Client Initial payload
unsigned char plane_payload[245] = {
0x06,0x00,0x40,0xf1,0x01,0x00,0x00,0xed,0x03,0x03,0xeb,0xf8,0xfa,0x56,0xf1,0x29,
0x39,0xb9,0x58,0x4a,0x38,0x96,0x47,0x2e,0xc4,0x0b,0xb8,0x63,0xcf,0xd3,0xe8,0x68,
0x04,0xfe,0x3a,0x47,0xf0,0x6a,0x2b,0x69,0x48,0x4c,0x00,0x00,0x04,0x13,0x01,0x13,
0x02,0x01,0x00,0x00,0xc0,0x00,0x00,0x00,0x10,0x00,0x0e,0x00,0x00,0x0b,0x65,0x78,
0x61,0x6d,0x70,0x6c,0x65,0x2e,0x63,0x6f,0x6d,0xff,0x01,0x00,0x01,0x00,0x00,0x0a,
0x00,0x08,0x00,0x06,0x00,0x1d,0x00,0x17,0x00,0x18,0x00,0x10,0x00,0x07,0x00,0x05,
0x04,0x61,0x6c,0x70,0x6e,0x00,0x05,0x00,0x05,0x01,0x00,0x00,0x00,0x00,0x00,0x33,
0x00,0x26,0x00,0x24,0x00,0x1d,0x00,0x20,0x93,0x70,0xb2,0xc9,0xca,0xa4,0x7f,0xba,
0xba,0xf4,0x55,0x9f,0xed,0xba,0x75,0x3d,0xe1,0x71,0xfa,0x71,0xf5,0x0f,0x1c,0xe1,
0x5d,0x43,0xe9,0x94,0xec,0x74,0xd7,0x48,0x00,0x2b,0x00,0x03,0x02,0x03,0x04,0x00,
0x0d,0x00,0x10,0x00,0x0e,0x04,0x03,0x05,0x03,0x06,0x03,0x02,0x03,0x08,0x04,0x08,
0x05,0x08,0x06,0x00,0x2d,0x00,0x02,0x01,0x01,0x00,0x1c,0x00,0x02,0x40,0x01,0x00,
0x39,0x00,0x32,0x04,0x08,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x05,0x04,0x80,
0x00,0xff,0xff,0x07,0x04,0x80,0x00,0xff,0xff,0x08,0x01,0x10,0x01,0x04,0x80,0x00,
0x75,0x30,0x09,0x01,0x10,0x0f,0x08,0x83,0x94,0xc8,0xf0,0x3e,0x51,0x57,0x08,0x06,
0x04,0x80,0x00,0xff,0xff};
// 16é²ãã³ãç¨
void keydump(unsigned char *key, int length) {
for (int i = 0; i < length; i++) {
if (i != 0 && i % 32 == 0) printf("\n");
else if (i != 0 && i % 16 == 0) printf(" ");
printf ("%02x", key[i]);
}
printf("\n");
}
// mbedTLSã使ã£ã¦AES128_GCM æå·å(ã¨ãããããµã³ãã«ãªã®ã§retã¯ã¹ã«ã¼)
int encrypt_payload(unsigned char *key, size_t keylen,
unsigned char *iv, size_t ivsize,
unsigned char *ad, size_t adsize,
unsigned char *from, size_t fromsize,
unsigned char *to, size_t tosize, size_t *olen) {
int ret;
mbedtls_gcm_context ctx;
mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES;
int output_len;
unsigned char tag_output[16];
size_t tag_len = sizeof(tag_output);
size_t tmpolen;
// éµã»Associated Dataã黿ãè¨å®ãã¦æå·å
mbedtls_gcm_init(&ctx);
ret = mbedtls_gcm_setkey(&ctx, cipher, key, keylen);
// mbedtls_gcm_crypt_and_tag ã¨åçã®å¦ç
ret = mbedtls_gcm_starts(&ctx, MBEDTLS_GCM_ENCRYPT, iv, ivsize);
ret = mbedtls_gcm_update_ad(&ctx, ad, adsize);
ret = mbedtls_gcm_update(&ctx, from, fromsize, to, tosize, olen);
ret = mbedtls_gcm_finish(&ctx, NULL, 0, &tmpolen, tag_output, sizeof(tag_output) );
// æå¾ã«tagãä»ä¸ãã
memcpy(to + *olen, tag_output, sizeof(tag_output));
*olen = *olen + 16;
mbedtls_gcm_free(&ctx);
return ret;
}
int main() {
int ret = 0;
unsigned char enc_payload[BUFFER_SIZE + 1];
// ãããã°ã¬ãã«ã3ã«ãã¦ãã
mbedtls_debug_set_threshold( 3 );
// client secret/key/iv/hp ã salt, did(distinatin connection id) ããåå¾
const mbedtls_md_info_t *md = mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 );
unsigned char initial_secret[mbedtls_md_get_size(md)];
ret = mbedtls_hkdf_extract( md, salt, 20, plane_header+6, 8, &initial_secret);
unsigned char client_secret[32];
unsigned char client_key[16];
unsigned char client_iv[12];
unsigned char client_hp[16];
mbedtls_ssl_tls13_hkdf_expand_label(MBEDTLS_MD_SHA256, initial_secret, 32, "client in", 9, NULL, 0, &client_secret, 32);
mbedtls_ssl_tls13_hkdf_expand_label(MBEDTLS_MD_SHA256, client_secret, 32, "quic key", 8, NULL, 0, &client_key, 16);
mbedtls_ssl_tls13_hkdf_expand_label(MBEDTLS_MD_SHA256, client_secret, 32, "quic iv", 7, NULL, 0, &client_iv, 12);
mbedtls_ssl_tls13_hkdf_expand_label(MBEDTLS_MD_SHA256, client_secret, 32, "quic hp", 7, NULL, 0, &client_hp, 16);
keydump(initial_secret, mbedtls_md_get_size(md));
keydump(client_secret, 32);
keydump(client_key, 16);
keydump(client_iv, 12);
keydump(client_hp, 16);
// æå·åãããã¤ãã¼ãã®æºåããã
int padding = 1200 // QUIC UDP initialize packet size
- 1 // Flags
- 4 // version
- 1 // Destination Connectin ID length
- 8 // Destination Connectin ID
- 1 // Source Connection ID length
- 0 // Source Connection ID
- 1 // Token Length
- 2 // length len
- ((plane_header[0] & 0x03) + 1) // packet number length
- sizeof(plane_payload)
- 16;
uint32_t packet_number = *(plane_header + 18) << 24
| *(plane_header + 19) << 16
| *(plane_header + 20) << 8
| *(plane_header + 21) << 0;
unsigned char payload[padding + sizeof(plane_payload)];
// å®éã«éä¿¡ãããã¼ã¿ãã0ããã£ã³ã°ãã
memset(payload, 0, sizeof(payload));
memcpy(payload, plane_payload, sizeof(plane_payload));
// æå·åããããã®nonceãç¨æãã RFC9001 5.3. AEAD Usage
unsigned char nonce[12];
unsigned int olen;
memcpy(nonce, client_iv, sizeof(client_iv));
nonce[11] = nonce[11] ^ packet_number;
keydump(nonce, 12);
// ãã¤ãã¼ãã®æå·åå®è¡
encrypt_payload(client_key, sizeof(client_key)*8,
nonce, sizeof(nonce),
plane_header, sizeof(plane_header),
payload, sizeof(payload),
enc_payload, sizeof(enc_payload), &olen);
keydump(enc_payload, olen);
// QUICãããã®ä¿è·ã®ããã®ãã¹ã¯ãç¨æ RFC9001 5.4.2. Header Protection Sample
// sample_offset : 22(payloadã®å
é 16byte)
mbedtls_aes_context aes;
unsigned char header_mask[16];
mbedtls_aes_init(&aes);
mbedtls_aes_setkey_enc( &aes, (const unsigned char*) client_hp, sizeof(client_hp) * 8 );
mbedtls_aes_crypt_ecb( &aes, MBEDTLS_AES_ENCRYPT, (const unsigned char*)enc_payload, header_mask);
mbedtls_aes_free( &aes );
keydump(header_mask, 16);
// ãããã«ãã¹ã¯
plane_header[0] ^= header_mask[0] & 0x0f;
for (int i = 0; i < 4; i++)
plane_header[18 + i] ^= header_mask[1 + i];
keydump(plane_header, sizeof(plane_header));
// [ä¿è·ãããããã + æå·åããããã¤ãã¼ã] ã«ãã¦ãã³ã
unsigned char encpacket[olen + sizeof(plane_header)];
memcpy(encpacket, plane_header, sizeof(plane_header));
memcpy(encpacket + sizeof(plane_header), enc_payload, olen);
keydump(encpacket, olen + sizeof(plane_header));
return 0;
}ããã§”ä¿è·ãããããã+æå·åããããã¤ãã¼ã”ã®ä¿è·ããããã±ãããï¼enc_payloadï¼ã”c000000001088 …. 018ab0856972e194cd934″ ã¨A.2. Client Initialã®çµæã¨åè´ãã¦ããã¯ãã§ãã復å·åã¯ãã®éãããã°OKã¨ãã£ãæãã§ãããã®æå·åã»å¾©å·åãesp-idf(ESP32)ã§ã®åä½ç¢ºèªãåºæ¥ã¾ããã
å®éã«ãããã³ã«ãçè§£ããã«ã¯ãå
éã®å®è£
ããµã³ãã«ãåèã«ããããRFCãèªã¿ãªãããµã³ãã«ã³ã¼ããæ¸ãã¦åããã¦ãWiresharkã§ãã±ããã観å¯ã㦅ã¨ããå°éãªæ¹æ³ãè¯ãããªã¨æã£ã¦ããããã¾ããæå·åã»å¾©å·åãmbedTLSã使ã£ã¦åºæ¥ãããªã®ã§ã次ã¯çµè¾¼ã¿ç«¯æ«ä¸ã§QUICã§éä¿¡ãè¡ãæã¾ã§ãã£ã¦ã¿ããããªã¨ã
ãã ããããåãå©ç¨ãã端æ«ã ã¨æå»ãæã£ã¦ããªãã£ããï¼gettimeç³»ãªã©ã¯èªä½ããï¼ãéä¿¡ç³»ã®ã¤ã³ã¿ãã§ã¤ã¹ãç¬èªã ã£ããï¼lwipã¯ããè¦ã¾ããï¼ãå©ç¨ããçµè¾¼ã¿ç°å¢ã«ãã¾ãåãã㦅ã¨ãã£ãæãã«ãªã£ã¦ãã¾ããã
ããã°ã®èè æ¬
æ¡ç¨æ å ±
é¢é£è¨äº
KEYWORD
CATEGORY
-
æè¡æ å ±ï¼562ï¼
- ãã¬ã¼ã ã¯ã¼ã¯ï¼4ï¼
- ã¢ãã¤ã«ï¼2ï¼
- ããã«ã¦ã§ã¢ï¼1ï¼
- ããããï¼8ï¼
- 3DCGï¼2ï¼
- ã¤ã³ãã©ï¼148ï¼
- ã¯ã©ã¦ãï¼21ï¼
- ã»ãã¥ãªãã£ï¼56ï¼
- ãããã¯ã¼ã¯ï¼26ï¼
- ããã³ãã¨ã³ãï¼23ï¼
- ããã¯ã¨ã³ãï¼21ï¼
- AI/æ©æ¢°å¦ç¿ï¼102ï¼
- æ¥åå¹çåï¼81ï¼
- ããã¸ã¡ã³ãï¼21ï¼
- developerï¼23ï¼
- ç»å£ã¬ãã¼ãï¼96ï¼
-
ã¤ãã³ãï¼209ï¼
-
ã«ã«ãã£ã¼ï¼54ï¼
-
ãã¶ã¤ã³ï¼54ï¼
-
ã¤ã³ã¿ã¼ã³ã·ããï¼2ï¼
TAG
- "eVTOL"
- "Japan Drone"
- "ãããã£ã¯ã¹"
- "空é£ã¶ã¯ã«ã"
- 5G
- Adam byGMO
- AdventCalender
- AGI
- AI
- AI æ©æ¢°å¦ç¿å¼·åå¦ç¿
- AIã¨ã¼ã¸ã§ã³ã
- AI人財
- AMD
- APTæ»æ
- AWX
- BIT VALLEY
- Blade
- blockchain
- Canva
- ChatGPT
- ChatGPT Team
- Claude Team
- cloudflare
- cloudnative
- CloudStack
- CM
- CNDO
- CNDT
- CODEBLUE
- CODEGYM Academy
- ConoHa
- ConoHaãDify
- CS
- CSS
- CTF
- DC
- design
- Designship
- Desiner
- DeveloperExper
- DeveloperExpert
- DevRel
- DevSecOpsThon
- DiceCTF
- Dify
- DNS
- Docker
- DTF
- Excel
- Expert
- Experts
- Felo
- GitLab
- GMO AIR
- GMO AIãããã£ã¯ã¹å¤§ä¼è°ï¼è¡¨å½°å¼
- GMO DESIGN AWARD
- GMO Developers Day
- GMO Developers Night
- GMO Developers ããã°
- GMO Flatt Security
- GMO GPUã¯ã©ã¦ã
- GMO Hacking Night
- GMO kitaQ
- GMO SONIC
- GMOã¢ããã¼ããã¼ãº
- GMOã¢ããã¼ã±ãã£ã³ã°
- GMOã¤ã¨ã©ã¨
- GMOã¤ã³ã¿ã¼ããã
- GMOã¤ã³ã¿ã¼ãããã°ã«ã¼ã
- GMOã¯ã©ã¦ã]
- GMOã°ãã¼ãã«ãµã¤ã³
- GMOã³ãã¯ã
- GMOãµã¤ãã¼ã»ãã¥ãªãã£byã¤ã¨ã©ã¨
- GMOãµã¤ãã¼ã»ãã¥ãªãã£å¤§ä¼è°
- GMOãµã¤ãã¼ã»ãã¥ãªãã£å¤§ä¼è°ï¼è¡¨å½°å¼
- GMOã½ãªã¥ã¼ã·ã§ã³ãã¼ããã¼
- GMOãã¸ãããº
- GMOãã©ã³ãã»ãã¥ãªãã£
- GMOãã¤ã¡ã³ãã²ã¼ãã¦ã§ã¤
- GMOããã
- GMOã¡ãã£ã¢
- GMOãªãµã¼ã
- GMO大ä¼è°
- Go
- GPU
- GPUã¯ã©ã¦ã
- GTB
- Hardning
- Harvester
- HCI
- INCYBER Forum
- iOS
- IoT
- ISUCON
- JapanDrone
- Java
- JJUG
- K8s
- Kaigi on Rails
- Kids VALLEY
- KidsVALLEY
- Linux
- LLM
- MCP
- MetaMask
- MySQL
- NFT
- NVIDIA
- NWæ§æå³
- NWè¨å®
- Ollama
- OpenStack
- Perl
- perplexity
- PHP
- PHPcon
- PHPerKaigi
- PHPã«ã³ãã¡ã¬ã³ã¹
- Python
- QUIC
- Rancher
- RPA
- Ruby
- Selenium
- Slack
- Slackæ´»ç¨
- Spectrum Tokyo Meetup
- splunk
- SRE
- sshd
- SSL
- Terraform
- TLS
- TypeScript
- UI/UX
- vibe
- VLAN
- VS Code
- Webã¢ããªã±ã¼ã·ã§ã³
- WEBãã£ã¬ã¯ã¿ã¼
- XSS
- ã¢ããã³ãã«ã¬ã³ãã¼
- ã¤ãã³ãã¬ãã¼ã
- ã¤ã³ã¿ã¼ã³ã·ãã
- ã¤ã³ãã¦ã¹
- ãªãã¸ã§ã¯ãæå
- ãªã³ãã¼ãã£ã³ã°
- ãåå.com
- ã«ã«ãã£ã¼
- ã¯ãªã¨ã¤ã¿ã¼
- ã¯ãªã¨ã¤ãã£ã
- ã³ã¼ãã£ã³ã°
- ã³ã³ãã
- ãµã¤ãã¼ã»ãã¥ãªãã£
- ãµãã¼ã¤ã³ã¿ã¼ã³
- ã·ã¹ãã ç ä¿®
- ã¹ã¯ã©ã
- ã¹ãã·ã£ãªã¹ã
- ã»ãã¥ãªãã£
- ã½ããã¦ã§ã¢ãã¹ã
- ãã¼ã ãã«ãã£ã³ã°
- ãã¶ã¤ãã¼
- ãã¶ã¤ã³
- ãã¹ã
- ããã¼ã³
- ãããã®ã»ãã¥ãªãã£ãGMO
- ãããã¯ã¼ã¯
- ãã¸ãã¹è·
- ãã¥ã¼ããã¤ã
- ãã¥ã¼ããã¤ããããã
- ãã£ã¸ã«ã«AI
- ããã°ã©ãã³ã°æè²
- ãããã¯ãã§ã¼ã³
- ãã¤ãºçµ±è¨å¦
- ãã¤ã¯ããµã¼ãã¹
- ãã«ããã¬ã¤
- ããã«ã¦ã§ã¢
- ã¢ãã¤ã«
- ããã¿ããã¯ã¼ã¯
- ãªã¢ã¼ãã¯ã¼ã¯
- ã¬ã³ã¿ã«ãµã¼ãã¼
- ãããã
- 京大ãã¼ãã¢ãã
- äººææ´¾é£
- åºå±ã¬ãã¼ã
- åç»
- åè³ã¬ãã¼ã
- åºç¤
- 夿 ç¹éçº
- 大妿æ¥
- å®®å´ãªãã£ã¹
- å±ç¤ºä¼
- åºå
- å¼·åå¦ç¿
- å½¢
- å¿ç¨
- æ å ±ä¼é
- æè²ããã¸ã§ã¯ã
- æè¡åºå ±
- æè¡æ¸å ¸
- æ¡ç¨
- æ¡ç¨ãµã¤ããªãã¥ã¼ã¢ã«
- æ¡ç¨æ´»å
- æ°å
- æ°åç ä¿®
- æ¥æ¬ç§å¦æªæ¥é¤¨
- æ å
- æ åã¯ãªã¨ã¤ã¿ã¼
- æå·
- æ¥åå¹çå
- æ¥åæé忏
- æ©æ¢°å¦ç¿
- 決æ¸
- ç©çæå·
- çæAI
- è²
- è¦è¦æå·
- éçºçç£æ§
- éçºçç£æ§åä¸
- é層ãã¤ãº
- 髿©è½æå·
PICKUP
-
å±äººåÃã¬ã©ãã´ã¹åããã®è±å´ï¼èª²éåºç¤æ¹åããã¸ã§ã¯ãã®èå°è£
æè¡æ å ±
-
ConoHa VPSã§ä½ã BungeeCordï¼è¤æ°Minecraftãµã¼ãæ§æå ¥é
æè¡æ å ±
-
VPSåºç¤ã«ãããCPUé¸å®ã®æèããã»ã¹
æè¡æ å ±
-
ãã¤ã³ãã¦ã¹åç»ãµããã2026ãé嬿±ºå®ï¼
ã¤ãã³ã
-
ãã¨ã³ã¸ãã¢ã®æé·ãã¹ãããããçç±ã¨ãã®å¯¾çã
æè¡æ å ±
-
ãã£ã¸ã«ã«AI à ãããã£ã¯ã¹ã®ç¾å®¶äºé³´ – CES 2026ç¾å°å ±åã¬ãã¼ã
æè¡æ å ±