🔒

セキュアエレメント:ATECC608を用いた組込み開発

1. はじめに

システムゼウスでIoT開発をしている南坂です。

Microchip社製のATECC608A-TNGTLS(以降ECC608と呼ぶ)の実用例であるスマートロックデモシステムでの使い方を説明します。ECC608を用いた開発の参考になれば幸いです。

2. ECC608とは

ECC608はMicrochip社が提供するセキュアエレメントで主にprime256v1の秘密鍵などを扱えます。
セキュアエレメントとは耐タンパー性を持った暗号鍵を生成、保持などをするデバイスです。TPM(Trusted Platform Module)やHSM(Hardware Security Module)とも呼ばれます。

  • Microchip製品の日本語ドキュメントはこちら

3. スロット構成

ECC608は鍵などを保存する領域(Dataゾーン)がスロットという単位で分かれており、それぞれ保存できるものや、できることが決まっています。
WFI32-IoT Boardに内蔵されているECC608はTrust&GO仕様になっており、スロット構成が決まっています。

  • ATECC608A-TNGTLS CryptoAuthentication™データシートはこちら
  • Microchip 社の Trust Platform(Trust & Go含む)の説明PDFはこちら

以下の表はATECC608A-TNGTLSのスロット構成です。

Slot Use Case size[byte] 概要
0 Primary private key 36 プライマリ認証鍵
1 Internal sign private key 36 内部署名秘密鍵
2 Secondary private key1 36 その他用途向けの秘密鍵
3 Secondary private key2 36 その他用途向けの秘密鍵
4 Secondary private key3 36 その他用途向けの秘密鍵
5 Secret key - 予約済
6 IO protection key 36 I2Cの通信内容を保護するための鍵
7 Secure boot digest - 予約済
8 General data 416 一般的なストレージ
9 AES key 72 ECDHおよびKDF出力向けの中間鍵ストレージ
10 Device compressed certificate 72 デバイス圧縮証明書
11 Signer public key 72 署名者公開鍵
12 Signer compressed certificate 72 署名者圧縮証明書
13 Parent public key or general data - 予約済
14 Validated public key - 予約済
15 Secure boot public key - 予約済

スマートロックデモでは以下のスロットを使用します。

Slot Use Case size[byte] 概要
0 Primary private key 36 プライマリ認証鍵
8 General data 416 一般的なストレージ
10 Device compressed certificate 72 デバイス圧縮証明書
  • Slot0
    プライマリ認証鍵。これは変更不可能なデバイス固有のもので、TLS通信の時に使用されるX.509証明書(デバイス証明書)の公開鍵と対になる秘密鍵です。秘密鍵は取り出さずに、署名などを計算することができます。TLS通信時の共通鍵生成とCertificateVerify(署名)に使用されています。
  • Slot8
    一般データ。ユーザーが自由に使用できる領域で今回は、Wi-FiのSSIDやパスワード、クラウドのエンドポイントなど接続情報を保存しています。
    ※Wi-Fiのパスワードなどは安全だからECC608に保存しているのではなく、あくまでEEPROMとして使っています。
  • Slot10
    X.509で使用するデバイス証明書が圧縮されて保存されています。

デバイス証明書の圧縮保管と復元
slot10にはデバイス証明書の有効期限、署名などの重要な情報のみが保存されており、これを圧縮保管といいます。主体者や発行者などはソースコードに記載しておきます。公開鍵はslot0の秘密鍵から動的に生成されます。
デバイス証明書を取り出すときは、slot10にある要素とslot0から生成した公開鍵、ソースコードにある情報をもとにデバイス証明書を復元します。

4. ECC608の使い方

Cryptoauthlibというライブラリを使用することで簡単にECC608を使用することができます。

ここではいくつか代表的なAPIについて説明します。

Cryptoauthlibを使用するにあたってライブラリの初期化を行います。

#include "cryptoauthlib.h"
#include "atca_basic.h"
extern ATCAIfaceCfg atecc608_0_init_data;

ATCAIfaceCfg *ifacecfg = &atecc608_0_init_data;
atcab_release();
atcab_init(ifacecfg);

シリアル番号の取得

ECC608のシリアル番号を取得するには以下のようにします。

uint8_t sn[9] = {0};
atcab_read_serial_number(sn);

実行するとsnに以下のようなバイト列が格納されており、これがECC608のシリアル番号です。

01 23 78 32 D5 AC 64 A3 01

署名生成、検証

  1. ハッシュ値(ダイジェスト)の算出

    メッセージのSHA256ハッシュ値を算出するには以下のようにします。

    uint8_t message[] = "test message";
    uint8_t digest[32] = {0};
    atcab_sha(strlen(message), message, digest);
    

    実行するとdigestに以下のようなバイト列が格納されており、これがメッセージのダイジェストです。

    3F 0A 37 7B A0 A4 A4 60 EC B6 16 F6 50 7C E0 D8
    CF A3 E7 04 02 5D 4F DA 3E D0 C5 CA 05 46 87 28
    
  2. 署名作成

    ダイジェストから署名を生成するには以下のようにします。

    uint8_t sign[64] = {0};
    atcab_sign(0, digest, sign);
    

    実行するとsignに以下のようなバイト列が格納されており、これが署名です。

    A8 D8 83 78 DA B7 9B 7B 53 87 39 83 CA E9 31 16
    A9 1B 96 28 46 C9 26 3B F0 45 A0 55 EB C4 37 FC
    91 00 DC 69 65 5E DF 97 FE 80 26 04 48 91 C6 C7
    3B 5A B0 5A 47 11 15 0B EA 7E 5E 19 0D EF E9 E3
    
  3. 公開鍵の取得

    slot0の公開鍵を取得するには以下のようにします。

    uint8_t pubkey[64] = {0};
    atcab_get_pubkey(0, pubkey);
    

    実行するとpubkeyに以下のようなバイト列が格納されており、これがslot0の公開鍵です。

    A2 69 58 E1 55 FC F7 C0 91 D4 91 67 A5 8C D3 89
    3B 60 6B 8D 6E 97 35 56 2C 8E 44 93 5F 08 CF 9F
    13 FB EE 8F 97 F4 83 D2 7B 3C A3 13 72 DA 73 A5
    5D 66 9F BB D9 5D AF 98 87 49 3F A2 DB 00 A8 F8
    
  4. 署名検証

    取得した公開鍵で署名検証を行うには以下のようにします。

    bool result;
    atcab_verify_extern(digest, sign, pubkey, &result);
    

    実行し、resultがtrueになり署名検証成功です。もしfalseであれば署名検証失敗となり、改ざんか鍵が違う場合が考えられます。

slot8のデータ読み書き

slot8は416Byteありますが、例えば先頭から(オフセット)12Byte目に8Byteのデータを読み書きする場合は以下のようにします。

uint8_t slot_id = 8;
uint8_t offset = 12;

// Write
uint8_t write_message[9] = "@message";
atcab_write_bytes_zone(ATCA_ZONE_DATA, slot_id, offset, write_message, strlen(write_message));

// Read
uint8_t read_message[8] ={0} ;
atcab_read_bytes_zone(ATCA_ZONE_DATA, slot_id, offset, read_message, 8);

実行するとread_messageには40 6D 65 73 73 61 67のバイト列が格納されており、@messageが保存されています。

デバイス証明書の取り出し

デバイス証明書を取得するには以下のようにします。

#include "atcacert/atcacert_def.h"
extern atcacert_def_t g_tngtls_cert_def_2_device;

uint8_t cert[1024] = {0};
size_t cert_size = sizeof(cert);
atcacert_read_cert(&g_tngtls_cert_def_2_device, NULL, cert, &cert_size);

実行するとcertに以下のようなバイトが格納されており、これがデバイス証明書(DER形式)です。

30 82 01 F5 30 82 01 9B A0 03 02 01 02 02 10 55
CE 2E 8F F6 1C 62 50 B7 E1 68 03 54 14 1C 94 30
0A 06 08 2A 86 48 CE 3D 04 03 02 30 4F 31 21 30
1F 06 03 55 04 0A 0C 18 4D 69 63 72 6F 63 68 69
70 20 54 65 63 68 6E 6F 6C 6F 67 79 20 49 6E 63
31 2A 30 28 06 03 55 04 03 0C 21 43 72 79 70 74
6F 20 41 75 74 68 65 6E 74 69 63 61 74 69 6F 6E
20 53 69 67 6E 65 72 20 46 46 46 46 30 20 17 0D
31 38 31 31 30 38 30 35 30 30 30 30 5A 18 0F 32
30 34 36 31 31 30 38 30 35 30 30 30 30 5A 30 46
31 21 30 1F 06 03 55 04 0A 0C 18 4D 69 63 72 6F
63 68 69 70 20 54 65 63 68 6E 6F 6C 6F 67 79 20
49 6E 63 31 21 30 1F 06 03 55 04 03 0C 18 30 31
32 33 30 31 30 32 30 33 30 34 30 35 30 36 30 31
20 41 54 45 43 43 30 59 30 13 06 07 2A 86 48 CE
3D 02 01 06 08 2A 86 48 CE 3D 03 01 07 03 42 00
04 71 F1 A7 0D A3 79 A3 FD ED 6B 50 10 BD AD 6E
1F B9 E8 EB A7 DF 2C 4B 5C 67 D3 5E BA 84 DA 09
E7 7A E8 DB 2C CB 96 28 EE EB 85 CD AA B3 5C 92
E5 3E 1C 44 D5 5A 2B A7 A0 24 AA 92 60 3B 68 94
8A A3 60 30 5E 30 0C 06 03 55 1D 13 01 01 FF 04
02 30 00 30 0E 06 03 55 1D 0F 01 01 FF 04 04 03
02 03 88 30 1D 06 03 55 1D 0E 04 16 04 14 1A 90
B2 22 37 A4 51 B7 57 DD 36 D1 3A 85 2B E1 3D 2E
F2 CA 30 1F 06 03 55 1D 23 04 18 30 16 80 14 BC
D4 FD E8 80 8A 2D C9 0B 6D 01 A8 C5 B9 B2 47 33
7E BD DA 30 0A 06 08 2A 86 48 CE 3D 04 03 02 03
48 00 30 45 02 20 31 0D 58 C9 D5 F8 96 D3 FA 8B
EA 6A 13 53 7E 14 10 54 B5 AD 17 38 A6 65 B1 42
F8 FF E9 EF BC A8 02 21 00 D6 23 3A 8B 1A 10 93
AE A1 43 B1 0C 96 80 56 6E 19 41 82 EB 84 FF 1F
D3 9F 3D F6 3E E5 B3 7A 19

このままだとバイト列(DER形式)で分かりにくいので、見た目に分かりやすい形に変換してみます。
以下のコマンドはWSLで実行しています。これでデバイス証明書の内容が分かると思います。

$ touch device.txt # <- 上記のバイト列文字列をコピーしたファイルを作成
$ xxd -r -p device.txt > device.der # <- 16進数文字列からバイト列に変換
$ openssl x509 -in device.der -inform der -out device.crt -outform pem
$ ls 
device.crt  device.der  device.txt
$ openssl x509 -text -noout -in device.crt
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            55:ce:2e:8f:f6:1c:62:50:b7:e1:68:03:54:14:1c:94
        Signature Algorithm: ecdsa-with-SHA256
        Issuer: O = Microchip Technology Inc, CN = Crypto Authentication Signer FFFF
        Validity
            Not Before: Nov  8 05:00:00 2018 GMT
            Not After : Nov  8 05:00:00 2046 GMT
        Subject: O = Microchip Technology Inc, CN = 012301020304050601 ATECC
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:71:f1:a7:0d:a3:79:a3:fd:ed:6b:50:10:bd:ad:
                    6e:1f:b9:e8:eb:a7:df:2c:4b:5c:67:d3:5e:ba:84:
                    da:09:e7:7a:e8:db:2c:cb:96:28:ee:eb:85:cd:aa:
                    b3:5c:92:e5:3e:1c:44:d5:5a:2b:a7:a0:24:aa:92:
                    60:3b:68:94:8a
                ASN1 OID: prime256v1
                NIST CURVE: P-256
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Key Usage: critical
                Digital Signature, Key Agreement
            X509v3 Subject Key Identifier:
                1A:90:B2:22:37:A4:51:B7:57:DD:36:D1:3A:85:2B:E1:3D:2E:F2:CA
            X509v3 Authority Key Identifier:
                keyid:BC:D4:FD:E8:80:8A:2D:C9:0B:6D:01:A8:C5:B9:B2:47:33:7E:BD:DA

    Signature Algorithm: ecdsa-with-SHA256
         30:45:02:20:31:0d:58:c9:d5:f8:96:d3:fa:8b:ea:6a:13:53:
         7e:14:10:54:b5:ad:17:38:a6:65:b1:42:f8:ff:e9:ef:bc:a8:
         02:21:00:d6:23:3a:8b:1a:10:93:ae:a1:43:b1:0c:96:80:56:
         6e:19:41:82:eb:84:ff:1f:d3:9f:3d:f6:3e:e5:b3:7a:19

さらに生成されたdevice.crtをWindows上にコピーすると、証明書のViewerで確認することができます。

免責事項

作者または著作権者は、本記事に起因または関連して生じる一切の請求、損害、その他の義務について何ら責任を負いません。

株式会社システムゼウス

Discussion