はじめに
NuttXでmbed TLSを動かす。
3年ほど前にMarceloさんが一度移植したらしいので、ここを参考にする。
ただし情報が古くその間にNuttXも新しくなっているのでこのままではうまく行かない。
今回使用するターゲットはSTM32F4Discovery。
NuttX
まずはNuttXのソースを取ってくる。
ディレクトリ構成
全体のディレクトリ構成が次のようになるようにする。
. ├── apps ├── mbedtls └── nuttx
ソースの取得
$ git clone https://bitbucket.org/nuttx/nuttx.git $ git clone https://bitbucket.org/nuttx/apps.git
mbedtls
ソースの取得
mbed TLSはgithubでソースも公開しているのでこれを使う。
$ git clone https://github.com/ARMmbed/mbedtls.git
ファイルのコピー
mbed TLSのソースをNuttXのソースツリーに組み込む。
mbed TLSのツリー
mbed TLSのソースツリーは次のようになっている。
ここでは使用する分を抜粋する。
mbedtls ├── configs // コンフィグヘッダ ├── include │ └── mbedtls // ヘッダファイル └── library // ソースファイル
NuttX側
NuttXには次のようになるようにする。
nuttx └── mbedtls // ソースファイル └── mbedtls // ヘッダファイル └── configs // コンフィグヘッダ
出力ディレクトリの作成
mbed TLSのソースディレクトリに移動し、出力先ディレクトリの作成。
$ cd mbedtls $ mkdir ../nuttx/mbedtls
ソースファイルのコピー
インクルードファイルのコピー
$ cp -ra ./include/mbedtls ../nuttx/mbedtls/
コンフィグヘッダのコピー
configs
以下のファイルから参照されることがあるためcheck_config.h
をconfigs
にコピーする。
また、mbedtls/mbedtls/config.hはKconfigでの設定を反映できるように修正するため、もとのファイルをmbedtls/mbedtls/configs/config-default.h
としてコピーしておく。
$ cp -ra ./configs ../nuttx/mbedtls/mbedtls/ $ cp ./include/mbedtls/config.h ../nuttx/mbedtls/mbedtls/configs/config-default.h $ cp ./include/mbedtls/check_config.h ../nuttx/mbedtls/mbedtls/configs/
ソースファイルのコピー
$ cp -ra ./library/*.c ../nuttx/mbedtls/
ライセンスとREADMEのコピー
$ cp -a ./LICENSE ../nuttx/mbedtls $ cp -a ./apache-2.0.txt ../nuttx/mbedtls $ cp -a ./README.md ../nuttx/mbedtls
ビルドに必要なファイルの作成
nuttx
以下に次のファイルを作成する。
- mbedtls/Kconfig
- mbedtls/Makefile
- mbedtls/mbedtls/config.h
Kconfig
mbedtls/Kconfig
を次の内容で作成する。
config MBED_TLS_LIB bool "mbed TLS Support" default n ---help--- Enable or disable mbed TLS support if MBED_TLS_LIB choice prompt "mbed Configuration Profile" default MBED_PROFILE_DEFAULT config MBED_PROFILE_SUITE_B bool "Suite B" config MBED_PROFILE_CCM_PSK_TLS_1_2 bool "CCM, PSK and TLS 1.2" config MBED_PROFILE_MINI_TLS_1_1 bool "Mini TLS 1.1" config MBED_PROFILE_THREAD bool "Thread" config MBED_PROFILE_NOENTROPY bool "No entropy" config MBED_PROFILE_DEFAULT bool "Default configuration" endchoice endif # MBED_TLS_LIB
Makefile
mbedtls/Makefile
を次の内容で作成する。
-include $(TOPDIR)/Make.defs ASRCS = CSRCS = ifeq ($(CONFIG_MBED_TLS_LIB),y) CSRCS += aes.c asn1parse.c asn1write.c base64.c \ bignum.c blowfish.c camellia.c \ ccm.c cipher.c cipher_wrap.c \ ctr_drbg.c des.c dhm.c \ ecdh.c ecdsa.c ecjpake.c \ ecp.c ecp_curves.c entropy.c \ entropy_poll.c error.c gcm.c \ havege.c hmac_drbg.c md.c \ md2.c md4.c md5.c \ md_wrap.c memory_buffer_alloc.c oid.c \ padlock.c pem.c pk.c \ pk_wrap.c pkcs12.c pkcs5.c \ pkparse.c pkwrite.c platform.c \ ripemd160.c rsa.c sha1.c \ sha256.c sha512.c threading.c \ timing.c version_features.c version.c \ xtea.c x509_create.c x509_crl.c \ x509_crt.c x509_csr.c x509write_crt.c \ x509write_csr.c ssl_ciphersuites.c ssl_cli.c \ ssl_cookie.c ssl_srv.c ssl_ticket.c \ ssl_tls.c platform_util.c endif # CONFIG_MBED_TLS_LIB AOBJS = $(ASRCS:.S=$(OBJEXT)) COBJS = $(CSRCS:.c=$(OBJEXT)) SRCS = $(ASRCS) $(CSRCS) OBJS = $(AOBJS) $(COBJS) BIN = libmbedtls$(LIBEXT) all: $(BIN) .PHONY: depend clean distclean $(AOBJS): %$(OBJEXT): %.S $(call ASSEMBLE, $<, $@) $(COBJS): %$(OBJEXT): %.c $(call COMPILE, $<, $@) $(BIN): $(OBJS) $(call ARCHIVE, $@, $(OBJS)) .depend: Makefile $(SRCS) ifeq ($(CONFIG_MBED_TLS_LIB),y) $(Q) $(MKDEP) --dep-path . "$(CC)" -- $(CFLAGS) -- $(SRCS) >Make.dep endif $(Q) touch $@ depend: .depend clean: $(call DELFILE, $(BIN)) $(call CLEAN) distclean: clean $(call DELFILE, Make.dep) $(call DELFILE, .depend) -include Make.dep
config.h
Kconfigの内容を反映できるようにするために、既存のmbedtls/mbedtls/config.h
を破棄し、次の内容で作成する。
#include <nuttx/config.h> #if defined(CONFIG_MBED_PROFILE_SUITE_B) #include "mbedtls/configs/config-suite-b.h" #elif defined(CONFIG_MBED_PROFILE_CCM_PSK_TLS_1_2) #include "mbedtls/configs/config-ccm-psk-tls1_2.h" #elif defined(CONFIG_MBED_PROFILE_MINI_TLS_1_1) #include "mbedtls/configs/config-mini-tls1_1.h" #elif defined(CONFIG_MBED_PROFILE_THREAD) #include "mbedtls/configs/config-thread.h" #elif defined(CONFIG_MBED_PROFILE_NOENTROPY) #include "mbedtls/configs/config-no-entropy.h" #elif defined(CONFIG_MBED_PROFILE_DEFAULT) #include "mbedtls/configs/config-default.h" #else #error "mbed TLS configuration file was not set" #endif
config-default.h
先程コピーしたmbedtls/mbedtls/configs/config-default.h
は、このままではビルドに失敗するため、次の2つのコンフィグを変更しておく。
diff --git a/mbedtls/mbedtls/configs/config-default.h b/mbedtls/mbedtls/configs/config-default.h index fd91d7074c..878f4e67cf 100644 --- a/mbedtls/mbedtls/configs/config-default.h +++ b/mbedtls/mbedtls/configs/config-default.h @@ -1149,7 +1149,7 @@ * * Uncomment this macro to disable the built-in platform entropy functions. */ -//#define MBEDTLS_NO_PLATFORM_ENTROPY +#define MBEDTLS_NO_PLATFORM_ENTROPY /** * \def MBEDTLS_ENTROPY_FORCE_SHA256 @@ -3018,7 +3018,7 @@ * * This module is used by the HAVEGE random number generator. */ -#define MBEDTLS_TIMING_C +//#define MBEDTLS_TIMING_C /** * \def MBEDTLS_VERSION_C
既存ファイルの修正
ビルド対象に含めるためにNuttX側のファイルを修正する。
今回は次のファイルを修正する。
- Kconfig
- tools/Directories.mk
- tools/FlatLibs.mk
- tools/KernelLibs.mk
- tools/LibTargets.mk
- tools/ProtectedLibs.mk
Kconfig
NuttXのソースツリーのルートにあるKconfig
を次のように修正する。
diff --git a/Kconfig b/Kconfig index dbcf9ee9ff..1ea6383698 100644 --- a/Kconfig +++ b/Kconfig @@ -1698,6 +1698,10 @@ source libs/libxx/Kconfig source libs/libdsp/Kconfig endmenu +menu "mbed TLS Support" +source mbedtls/Kconfig +endmenu + menu "Application Configuration" source "$APPSDIR/Kconfig" endmenu
Directories.mk
tools/Directories.mk
を次のように修正する。
diff --git a/tools/Directories.mk b/tools/Directories.mk index 7c17510789..8b66691dfa 100644 --- a/tools/Directories.mk +++ b/tools/Directories.mk @@ -183,3 +183,8 @@ ifeq ($(CONFIG_CRYPTO),y) KERNDEPDIRS += crypto endif CLEANDIRS += crypto + +ifeq ($(CONFIG_MBED_TLS_LIB),y) +KERNDEPDIRS += mbedtls +endif +CLEANDIRS += mbedtls
FlatLibs.mk
tools/FlatLibs.mk
を次のように修正する。
diff --git a/tools/FlatLibs.mk b/tools/FlatLibs.mk index 0ad2cc335b..fde3dd8c6e 100644 --- a/tools/FlatLibs.mk +++ b/tools/FlatLibs.mk @@ -93,6 +93,12 @@ ifeq ($(CONFIG_NET),y) NUTTXLIBS += staging$(DELIM)libnet$(LIBEXT) endif +# Add libraries for mbed TLS + +ifeq ($(CONFIG_MBED_TLS_LIB),y) +NUTTXLIBS += staging$(DELIM)libmbedtls$(LIBEXT) +endif + # Add libraries for Crypto API support ifeq ($(CONFIG_CRYPTO),y)
KernelLibs.mk
tools/KernelLibs.mk
を次のように修正する。
diff --git a/tools/KernelLibs.mk b/tools/KernelLibs.mk index f36d8d6ce5..1f14159d87 100644 --- a/tools/KernelLibs.mk +++ b/tools/KernelLibs.mk @@ -91,6 +91,12 @@ ifeq ($(CONFIG_CRYPTO),y) NUTTXLIBS += staging$(DELIM)libcrypto$(LIBEXT) endif +# Add libraries for mbed TLS + +ifeq ($(CONFIG_MBED_TLS_LIB),y) +NUTTXLIBS += staging$(DELIM)libmbedtls$(LIBEXT) +endif + # Add libraries for file system support NUTTXLIBS += staging$(DELIM)libfs$(LIBEXT) staging$(DELIM)libbinfmt$(LIBEXT)
LibTargets.mk
tools/LibTargets.mk
を次のように修正する。
diff --git a/tools/LibTargets.mk b/tools/LibTargets.mk index 188e4fb403..df5421ae89 100644 --- a/tools/LibTargets.mk +++ b/tools/LibTargets.mk @@ -94,6 +94,12 @@ crypto$(DELIM)libcrypto$(LIBEXT): context staging$(DELIM)libcrypto$(LIBEXT): crypto$(DELIM)libcrypto$(LIBEXT) $(Q) $(call INSTALL_LIB,$<,$@) +mbedtls$(DELIM)libmbedtls$(LIBEXT): context + $(Q) $(MAKE) -C mbedtls TOPDIR="$(TOPDIR)" libmbedtls$(LIBEXT) KERNEL=y EXTRADEFINES=$(KDEFINE) + +staging$(DELIM)libmbedtls$(LIBEXT): mbedtls$(DELIM)libmbedtls$(LIBEXT) + $(Q) $(call INSTALL_LIB,$<,$@) + fs$(DELIM)libfs$(LIBEXT): context $(Q) $(MAKE) -C fs TOPDIR="$(TOPDIR)" libfs$(LIBEXT) KERNEL=y EXTRADEFINES=$(KDEFINE)
インデントはスペースではなくタブであることに注意すること。
ProtectedLibs.mk
tools/ProtectedLibs.mk
を次のように修正する。
diff --git a/tools/ProtectedLibs.mk b/tools/ProtectedLibs.mk index 4bb3d19424..8ed6e3e461 100644 --- a/tools/ProtectedLibs.mk +++ b/tools/ProtectedLibs.mk @@ -98,6 +98,12 @@ ifeq ($(CONFIG_CRYPTO),y) NUTTXLIBS += staging$(DELIM)libcrypto$(LIBEXT) endif +# Add libraries for mbed TLS + +ifeq ($(CONFIG_MBED_TLS_LIB),y) +NUTTXLIBS += staging$(DELIM)libmbedtls$(LIBEXT) +endif + # Add libraries for file system support NUTTXLIBS += staging$(DELIM)libfs$(LIBEXT) staging$(DELIM)libbinfmt$(LIBEXT)
サンプルプログラム
簡単に動作を確認するためMD5を動かしてみる。
プログラムはtlssample
とする。
新規に作成するアプリケーションのために、次のファイルをapps
以下に追加する。
external/tlssample/Kconfig
external/tlssample/Make.defs
external/tlssample/Makefile
external/tlssample/tlssample_main.c
ディレクトリ作成
次のコマンドでプログラムのためのディレクトリを作成する。
$ cd apps $ mkdir -p external/tlssample $ ln -s external/tlssample tlssample
appsから1つ下の階層のディレクトリにあるMakefileは自動的にビルド対象に追加されるため、
external/tlssample
へのシンボリックリンクを作成する。
Kconfig
external/tlssample/Kconfig
を次の内容で作成する。
config EXTERNAL_TLSSAMPLE tristate "\"Tlssample\" example" default n ---help--- Enable the \"Tlssample\" example if EXTERNAL_TLSSAMPLE config EXTERNAL_TLSSAMPLE_PROGNAME string "Program name" default "tlssample" depends on BUILD_LOADABLE ---help--- This is the name of the program that will be use when the NSH ELF program is installed. config EXTERNAL_TLSSAMPLE_PRIORITY int "Tlssample task priority" default 100 config EXTERNAL_TLSSAMPLE_STACKSIZE int "Tlssample stack size" default 2048 endif
Make.defs
external/tlssample/Make.defs
を次の内容で作成する。
ifneq ($(CONFIG_EXTERNAL_TLSSAMPLE),) CONFIGURED_APPS += tlssample endif
Makefile
external/tlssample/Makefile
を次の内容で作成する。
-include $(TOPDIR)/Make.defs # Tlssample, World! built-in application info CONFIG_EXTERNAL_TLSSAMPLE_PRIORITY ?= SCHED_PRIORITY_DEFAULT CONFIG_EXTERNAL_TLSSAMPLE_STACKSIZE ?= 2048 APPNAME = tlssample PRIORITY = $(CONFIG_EXTERNAL_TLSSAMPLE_PRIORITY) STACKSIZE = $(CONFIG_EXTERNAL_TLSSAMPLE_STACKSIZE) # Tlssample, World! Example ASRCS = CSRCS = MAINSRC = tlssample_main.c CFLAGS += -I$(TOPDIR)/mbedtls CONFIG_EXTERNAL_TLSSAMPLE_PROGNAME ?= tlssample$(EXEEXT) PROGNAME = $(CONFIG_EXTERNAL_TLSSAMPLE_PROGNAME) MODULE = CONFIG_EXTERNAL_TLSSAMPLE include $(APPDIR)/Application.mk
tlssample_main.c
external/tlssample/tlssample_main.c
を次の内容で作成する。
/**************************************************************************** * Included Files ****************************************************************************/ #include <nuttx/config.h> #include <stdio.h> #include "mbedtls/md5.h" /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * tlssample_main ****************************************************************************/ #if defined(BUILD_MODULE) int main(int argc, FAR char *argv[]) #else int tlssample_main(int argc, char *argv[]) #endif { unsigned char buf[32] = "hello world"; unsigned char out[16]; int i = 0; int n; n = strlen(buf); printf("source = %s, %d\n", buf, n); mbedtls_md5_ret(buf, n, out); printf("-----\n"); for (i = 0; i < 16; ++i) { printf("%02x ", out[i]); } printf("\n-----\n"); mbedtls_md5_self_test(1); return 0; }
ビルド
ここまででmbedtlsを含んだNuttXのビルドは可能となった。
STM32F4Discoveryのusbnsh環境向けにビルドしてみる。
$ tools/configure.sh configs/stm32f4discovery/usbnsh -l $ make menuconfig
mbed TLSの有効化
次のような感じで設定する。
現時点ではDefault configuration
とNo entropy
以外では次のチェックで引っかかる。
#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) #if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ !defined(__APPLE__) && !defined(_WIN32) && !defined(__QNXNTO__) && \ !defined(__HAIKU__) #error "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h" #endif
Linnux、Mac OS、QNX、HAIKU、Windows以外のOSでは機能が足りないと判断されるためエラーとなる。
今回は試していないが、NuttXはPOSIX LikeなOSなのでここのチェックを騙して、 ちょっと修正すれば他のコンフィグレーションでも動作するようになると思われる。
サンプルプログラムの有効化
次のような感じで設定する。
実行
プログラムの書き込み
st-flashでnuttx.binを書き込む。
$ st-flash write nuttx.bin 0x8000000
プログラムの実行
STM32F4DiscoveryとPCをマイクロUSBケーブルで接続しボードをリセットすると、PC側に/dev/ttyACM0
が見えるようになる。
このデバイスをminicomなどで開いてnshにアクセスする。
nsh> tlssample source = hello world, 11 ----- 5e b6 3b bb e0 1e ee d0 93 cb 22 bb 8f 5a cd c3 ----- MD5 test #1: passed MD5 test #2: passed MD5 test #3: passed MD5 test #4: passed MD5 test #5: passed MD5 test #6: passed MD5 test #7: passed nsh>
hello world
のMD5は5e b6 3b bb e0 1e ee d0 93 cb 22 bb 8f 5a cd c3
となる。
確認方法
Linuxで次のコマンドを実行し同じになることを確認する。
$ echo -n "hello world" | md5sum 5eb63bbbe01eeed093cb22bb8f5acdc3
同じ結果になった。
まとめ
既存のライブラリをNuttXのソースツリーに持っていきビルドする方法を確認した。 サンプルプログラムを作成し、きちんと機能することも確認できた。
以前にmbed TLSを移植したMarceloさんは各コンフィグをそれぞれ選択できるようにカスタムメニューを作成しているが、 今回は省略した。
今のところNuttXは割と素直に動いてくれていて、 Linux経験者がMCUに世界に飛び込むにはかなりとっつきやすい印象。
ただ、移植にはライブラリが求めている機能をNuttXが持っているかどうかなど条件があり、 これを満たすようにするためには、いろいろと修正しなければならない場合がある。
NuttXでOSSのライブラリを使用するには、事前にそのライブラリの移植性やその難易度を予め調査するのが良さそう。 以前にNuttXに移植された実績があるかどうかなども、結構重要なポイントとなる。
規模の大きいものや複雑なものを使用したい場合は注意が必要。
ただ、NuttXは楽しい。