はじめに
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
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
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
を次の内容で作成する。
#include <nuttx/config.h>
#include <stdio.h>
#include "mbedtls/md5.h"
#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は楽しい。