wolfTips: IoTデバイスのセキュリティライブラリ wolfSSL を使いこなすためのヒント集
--- 鍵、証明書編 ---
##概要
サーバ認証のためには、そのサイトのサーバ証明書に署名した認証局のCA証明書を使います。パソコンのブラウザなどではそうした証明書について意識する機会あまりありませんが、IoTデバイスのような組み込みシステムでは、証明書を自分で用意する必要があります。ここでは、実験や評価用にブラウザを使って必要な認証局を調べ、簡単にCA証明書を持ってくる方法について解説します。後半は、入手した証明書を使ってwolfSSL の Example クライアントプログラムやOpenSSL のコマンドでサーバ認証行ったうえで、サーバにアクセスしてみます。
ChromeやEdgeのようなパソコンのウェブブラウザにはサーバーが送信する証明書のパスを表示し、エクスポートする機能があります。ここではその機能を利用しルートCA証明書を取得します。ただし、単純にウェブブラウザの表示する「証明書のパス」だけではルートCA証明書まで辿れないケースもあります。それぞれの例として、次の二つのサイトのサーバ認証用CA証明書を入手してみます。
ルートCA証明書まで辿れる例:azure.microsoft.com
ルートCA証明書まで辿れない例:aws.amzon.com
##ルートCA証明書まで辿れる場合
まず、ルートCA証明書まで辿れる例としてazure.mirosoft.com にアクセスする場合を説明します。Chromeの場合を例に説明します。
azureのURLにアクセスし、アドレスバー上の鍵マークをクリックし、「証明書のパス」タブを開きます。下記図のような画面になるので、ルート証明書(ツリー構造の根っこ)を選択し、証明書の表示をクリックします。
開いた画面の「詳細」タブを開き、ファイルのコピーをクリックします。
証明書のエクスポートウィザードが表示されるので、“Base64 Encoded X.509”を選択し、「次へ」をクリックし、ファイルをエクスポートします。
##入手した証明書でWebページにアクセスしてみる
次に、クライアントプログラムを使って入手した証明書でWebページに実際にアクセスしてみますが、まずはサーバー認証を行わずにアクセスを確認します。
wolfSSLの場合、次のようにクライアントのサンプルプログラムを使います。
./examples/client/client -h azure.microsoft.com -p 443 -g -d
-h : ホスト名
-p : ポート番号
-g : HTTP GET を発行
-d : サーバー認証を行わない
ここで、”-d”オプションを指定することでサーバー認証をスキップしアクセスしています。サーバー認証を行うには、“-A”オプションを使ってCA証明書を新たにロードします。
openSSL の場合は、以下のようなコマンドでアクセスします。
$ openssl s_client -connect azure.microsoft.com:443 < /dev/null
ただし、OpenSSLの場合、サーバー認証はデフォルト無効です。有効にするには、”-verify 検証階層の深さ”を指定します。OpenSSLはデフォルトで証明書フォルダーを参照しています。参照しているフォルダーは、システムで異なりLinuxの場合、下記で確認することが出来ます。
$ openssl version -d
OPENSSLDIR: “/usr/lib/ssl”
$ ls -al /usr/lib/ssl/
total 0
drwxr-xr-x 1 root root 4096 May 28 13:16 .
drwxr-xr-x 1 root root 4096 Jul 9 15:55 ..
lrwxrwxrwx 1 root root 14 Nov 23 2018 certs -> /etc/ssl/certs
drwxr-xr-x 1 root root 4096 May 28 13:16 misc
lrwxrwxrwx 1 root root 20 Apr 22 04:45 openssl.cnf -> /etc/ssl/openssl.cnf
lrwxrwxrwx 1 root root 16 Nov 23 2018 private -> /etc/ssl/private
/etc/ssl/certs が参照しているフォルダーになります。
次に、wolfSSLで出力した証明書を使ってサーバーにアクセスしてみます。
$./examples/client/client -h azure.microsoft.com -p 443 -g -A /path/to/azure_microsoftCA.cer
SSL version is TLSv1.2
SSL cipher suite is TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
SSL curve name is SECP384R1
SSL connect ok, sending GET...
HTTP/1.1 400 Bad Request
X-MSEdge-Ref: 0C3EWXwAAAABGAWDS2klTTKsuleLHTSqqT1NBMzBFREdFMDQxNgBFZGdl
Date: Tue, 21 Jul 2020 04:37
:30 GMT
Connection: close
<h2>Our services aren't available right now</h2><p>We're working to restore all services as soon
-A: CA証明書へのパス
アクセスが成功し、サーバーを認証していることがわかります。
OpenSSL の場合は次の通りです。
$ openssl s_client -connect azure.microsoft.com:443 -verify 1 -CAfile /path/to/azure_microsoftCA.cer < /dev/null
verify depth is 1
CONNECTED(00000003)
depth=2 C = IE, O = Baltimore, OU = CyberTrust, CN = Baltimore CyberTrust Root
verify return:1
depth=1 C = US, ST = Washington, L = Redmond, O = Microsoft Corporation, OU = Microsoft IT, CN = Microsoft IT TLS CA 1
verify return:1
depth=0 CN = azure.microsoft.com
verify return:1
…
---
No client certificate CA names sent
Peer signing digest: SHA256
Peer signature type: RSA
Server Temp Key: ECDH, P-384, 384 bits
---
SSL handshake has read 4381 bytes and written 469 bytes
Verification: OK
…
Start Time: 1595842451
Timeout : 7200 (sec)
Verify return code: 0 (ok)
Extended master secret: yes
---
DONE
“Verification :OK”となっていれば、サーバー認証が成功しています。上記の例では、”-CAfile” オプションでルートCA証明書を指定していますが、上述したようにデフォルトの証明書フォルダーに既にルートCA証明書が存在する場合、オプションを省略しても成功します。
##ルートCA証明書まで辿れない場合
次にルートCA証明書まで辿れない場合の例として aws.amazon.com にアクセスしてみます。aws.amazon.com の場合、azureのサイトとことなりルートCAまでのパスを表示してくれません。少し詳しく見てみます。
下図は、aws.amazon.com にChromeアクセスした際の証明書ツリー(チェーン)です。ルート証明書は、“Amazon Root CA 1” となっています。"Amazon Root CA 1" は、Amazon が提供する Amazon Trust Service で提供される自社認証局の一つです。この認証局が信頼されるルート証明書機関として PC に登録されている場合、下図のような証明書ツリーになります。
この証明書を azure のときと同じくファイルにエクスポートし、クライアントプログラムでアクセスします。
$ ./examples/client/client -h aws.amazon.com -p 443 -g -A /path/to/AmazonRootCA1.cer
wolfSSL_connect error -188, ASN no signer error to confirm failure
wolfSSL error: wolfSSL_connect failed
失敗してしまいます。Wiresharkを使ってサーバーがどのような証明書(チェーン)を送信しているか確認します。
サーバーからは、
+ aws.amazon.com
+ Amazon
+ Amazon Root CA 1
- Starfield Services Root Certificate Authority - G2
という証明書チェーンが渡ってきています。この証明書チェーンを認証するには渡ってきたチェーンのルート証明書Starfield Services Root Certificate Authority - G2 を発行した認証局の証明書が必要になります。発行元を調べるには、証明書の issuer 項を確認します。
どうやら、Starfield Class 2 Certification という認証局が発行したようです。Webブラウザからインストール済み証明書一覧を検索する方法と、OS自体にインストールされた証明書の一覧を検索する方法があります。ここではOSにインストールされている一覧から探してみます。
Windowsの場合は、名前を指定して実行から、「certmgr.msc」と入力し certmgr を起動します。
信頼されたルート証明書機関の中にありました。エクスポートし、再度、アクセスしてみます。
$./examples/client/client -h aws.amazon.com -p 443 -g -A /path/to/StarfieldClass2Cert.cer
SSL version is TLSv1.2
SSL cipher suite is TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
SSL curve name is SECP256R1
SSL connect ok, sending GET...
HTTP/1.1 400 Bad Request
Server: CloudFront
Date: Tue, 21 Jul 2020 06:17:51 GMT
Content-Type: text/html
Content-Length: 915
Connection: close
X-Cache: Error from cloudfront
Via: 1.1 c7b74e12b97e13a0b0116342d7b1e06c.cloudfront.net (CloudFront)
-A: CA証明書へのパス
今度は上手く行くはずです。
Linux上でシステムにインストール済み証明書は、/etc/ssl/certs にある場合があるので確認してみてください。OpenSSLはデフォルトで /etc/ssl/certsを参照している場合があります。その場合、証明書一覧にルート証明書が登録されている場合、改めて指定しなくても成功します。改めてルートCA証明書を指定する場合は、”-CAfile file” オプションを指定します。
##まとめ
今回、ルートCA証明書を簡単に取得しクライアントプログラムでサーバー認証を行う例を見てきましたが、本格的な利用のためのCA証明書はそれぞれの認証局から入手してください。