#はじめに#
2019年5月にIoTLTにてLTをさせていただきました。
その内容のフォローを記入しながら自分なりに整理していきたいと思います。
発表内容:
スタートアップIoTデバイスのセキュリティを考える
#前回までのあらすじ#
セキュアなIoTデバイス通信をやってみた(MbedTLS移植編-Provision)でATECC608Aから抜き出した公開鍵を使って、自己認証局から署名を行いデバイス証明書を作成しました。
その後、証明書をATECC608Aへ保存するところまで行いました。
今回の記事に関連するソースコードは下記にて公開中。
kmwebnet/ECC608-httpsconnection
#https接続環境整備#
httpsサーバーを構築し、接続先として設定する。
下記を参考に、最新のApacheとOpenSSL1.1.1で環境を構築する。
Apache2.4.37 + OpenSSL1.1.1aをソースからインストール
■サーバー証明書作成
デバイス側から、サーバーを認証するためのサーバー証明書を
前回セキュアなIoTデバイス通信をやってみた(MbedTLS移植編-Provision)で使用した
root-ca.crt
root-ca.key
signer-ca.crt
signer-ca.key
を用意する。
Openssl1.1.1のインストール先/usr/local/openssl-1.1.1の配下へCAディレクトリを作成、上記4つをその中へコピー、その中で証明書作成を行う。
以下のようにディレクトリを整える
cd /usr/local/openssl-1.1.1
mkdir certs
mkdir private
mkdir crl
mkdir newcerts
mkdir revoke
chmod 700 private
echo "01" > serial
touch index.txt
cp /usr/local/openssl-1.1.1/ssl/openssl.cnf .
openssl.cnfの設定内容。変更点のみ。
####################################################################
[ CA_default ]
dir = /usr/local/openssl-1.1.1/CA # Where everything is kept
certs = $dir/certs # Where the issued certs are kept
crl_dir = $dir/crl # Where the issued crl are kept
database = $dir/index.txt # database index file.
#unique_subject = no # Set to 'no' to allow creation of
# several ctificates with same subject.
new_certs_dir = $dir/newcerts # default place for new certs.
certificate = $dir/signer-ca.pem # The CA certificate
serial = $dir/serial # The current serial number
crlnumber = $dir/crlnumber # the current crl number
# must be commented out to leave a V1 CRL
crl = $dir/crl.pem # The current CRL
private_key = $dir/private/signer-ca.key # The private key
RANDFILE = $dir/private/.rand # private random number file
default_days = 3650 # how long to certify for
default_crl_days= 90 # how long before next CRL
default_md = sha256 # use SHA-256 by default
preserve = no # keep passed DN ordering
# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
policy = policy_match
# For the CA policy
[ policy_match ]
countryName = optional
stateOrProvinceName = optional
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
# For the 'anything' policy
# At this point in time, you must list all acceptable 'object'
# types.
[ policy_anything ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ svr_cert ]
# These extensions are added when 'ca' signs a request.
# This goes against PKIX guidelines but some CAs do it and some software
# requires this to avoid interpreting an end user certificate as a CA.
basicConstraints=CA:FALSE
# Here are some examples of the usage of nsCertType. If it is omitted
# the certificate can be used for anything *except* object signing.
# This is OK for an SSL server.
nsCertType = server
# For an object signing certificate this would be used.
# nsCertType = objsign
# For normal client use this is typical
# nsCertType = client, email
# and for everything including object signing:
# nsCertType = client, email, objsign
# This is typical in keyUsage for a client certificate.
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
# This will be displayed in Netscape's comment listbox.
nsComment = "OpenSSL Generated Certificate"
# PKIX recommendations harmless if included in all certificates.
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
# This stuff is for subjectAltName and issuerAltname.
# Import the email address.
# subjectAltName=email:copy
# An alternative to produce certificates that aren't
# deprecated according to PKIX.
subjectAltName= @alt_names
[ alt_names ]
DNS.1 = iot.testcorp.com //変更
DNS.2 = *.testcorp.com //変更
■サーバー証明書の秘密鍵とCSRを作成
openssl req -new -config openssl.cnf -newkey ec:<(openssl ecparam -name prime256v1) -keyout server.key -subj "/O=testcorp/OU=iot/CN=iot.testcorp.com" -out server.csr
■サーバー証明書を中間CAで署名
openssl ca -config openssl.cnf -extensions svr_cert -keyfile signer-ca.key -cert signer-ca.crt -in server.csr -out server.crt -days 3650
■完成したサーバー証明書のチェーンを作成する
apache2.4.8以降では、サーバー証明書の設定の仕方が変わったとのこと。
apache 2.4におけるSSL証明書の設定
証明書チェーン作成に対応するため、スクリプトを使う。
下記をbundle.shで保存、chmod +xで実行権限をつける。
#!/bin/sh
#
# Convert PEM Certificate to ca-bundle.crt format
#
test ! $1 && printf "Usage: `basename $0` certificate" && exit 1
# Friendly Name and Underline Friendly Name with equal signs
openssl x509 -in $1 -text -noout | sed -e 's/^ *Subject:.*CN=\([^,]*\).*/\1/p;t c' -e 'd;:c' -e 's/./=/g'
# Output Fingerprint and swap = for :
openssl x509 -in $1 -noout -fingerprint | sed -e 's/=/: /'
# Output PEM Data:
echo 'PEM Data:'
# Output Certificate
openssl x509 -in $1
# Output Certificate text swapping Certificate with Certificate Ingredients
openssl x509 -in $1 -text -noout | sed -e 's/^Certificate:/Certificate Ingredients:/'
■bundle.shを使った証明書の連結
以下のように、サーバー証明書→中間証明書→ルートCA証明書の順番に連結させる。
[root@ CA]# ./bundle.sh server.crt > server.chain
[root@ CA]# ./bundle.sh signer-ca.pem >> server.chain
[root@ CA]# ./bundle.sh root-ca.pem >> server.chain
■接続htmlの準備
以下のようにテストページを用意する。
[root@ ~]# echo "<html><body><h1>It works</h1></body></html>" > /usr/local/httpd2/htdocs/index.html
■apache SSL設定
以下のように設定。変更点のみ記載。サーバー側からクライアント証明書を要求し、ATECC608Aからデバイス証明書を発行させる設定とする。
[root@ ~]# cat /usr/local/httpd2/conf/extra/httpd-ssl.conf
#
# When we also provide SSL we have to listen to the
# standard HTTP port (see above) and to the HTTPS port
#
Listen 4689
# SSL Cipher Suite:
# List the ciphers that the client is permitted to negotiate,
# and that httpd will negotiate as the client of a proxied server.
# See the OpenSSL documentation for a complete list of ciphers, and
# ensure these follow appropriate best practices for this deployment.
# httpd 2.2.30, 2.4.13 and later force-disable aNULL, eNULL and EXP ciphers,
# while OpenSSL disabled these by default in 0.9.8zf/1.0.0r/1.0.1m/1.0.2a.
#SSLCipherSuite HIGH:MEDIUM:!MD5:!RC4:!3DES
#SSLProxyCipherSuite HIGH:MEDIUM:!MD5:!RC4:!3DES
SSLCipherSuite "ECDHE-ECDSA-AES128-GCM-SHA256 \
ECDHE-ECDSA-AES256-GCM-SHA384 \
ECDHE-ECDSA-AES128-SHA \
ECDHE-ECDSA-AES256-SHA \
ECDHE-ECDSA-AES128-SHA256 \
ECDHE-ECDSA-AES256-SHA384 \
ECDHE-RSA-AES128-GCM-SHA256 \
ECDHE-RSA-AES256-GCM-SHA384 \
ECDHE-RSA-AES128-SHA \
ECDHE-RSA-AES256-SHA \
ECDHE-RSA-AES128-SHA256 \
ECDHE-RSA-AES256-SHA384 \
DHE-RSA-AES128-GCM-SHA256 \
DHE-RSA-AES256-GCM-SHA384 \
DHE-RSA-AES128-SHA \
DHE-RSA-AES256-SHA \
DHE-RSA-AES128-SHA256 \
DHE-RSA-AES256-SHA256"
# User agents such as web browsers are not configured for the user's
# own preference of either security or performance, therefore this
# must be the prerogative of the web server administrator who manages
# cpu load versus confidentiality, so enforce the server's cipher order.
SSLHonorCipherOrder off
# SSL Protocol support:
# List the protocol versions which clients are allowed to connect with.
# Disable SSLv3 by default (cf. RFC 7525 3.1.1). TLSv1 (1.0) should be
# disabled as quickly as practical. By the end of 2016, only the TLSv1.2
# protocol or later should remain in use.
SSLProtocol all -SSLv3
SSLProxyProtocol all -SSLv3
##
## SSL Virtual Host Context
##
SSLStrictSNIVHostCheck off
<VirtualHost *:4689>
# General setup for the virtual host
DocumentRoot "/usr/local/httpd2/htdocs"
ServerName iot.testcorp.com:4689
ServerAdmin you@example.com
LogLevel debug
ErrorLog "/usr/local/httpd2/logs/error_log"
TransferLog "/usr/local/httpd2/logs/access_log"
<Directory "/usr/local/httpd2/htdocs">
Options FollowSymLinks
AllowOverride None
Require all granted
</Directory>
# SSL Engine Switch:
# Enable/Disable SSL for this virtual host.
SSLEngine on
# Server Certificate:
# Point SSLCertificateFile at a PEM encoded certificate. If
# the certificate is encrypted, then you will be prompted for a
# pass phrase. Note that a kill -HUP will prompt again. Keep
# in mind that if you have both an RSA and a DSA certificate you
# can configure both in parallel (to also allow the use of DSA
# ciphers, etc.)
# Some ECC cipher suites (http://www.ietf.org/rfc/rfc4492.txt)
# require an ECC certificate which can also be configured in
# parallel.
SSLCertificateFile "/usr/local/openssl-1.1.1/CA/server.chain"
#SSLCertificateFile "/usr/local/httpd2/conf/server-dsa.crt"
#SSLCertificateFile "/usr/local/httpd2/conf/server-ecc.crt"
# Server Private Key:
# If the key is not combined with the certificate, use this
# directive to point at the key file. Keep in mind that if
# you've both a RSA and a DSA private key you can configure
# both in parallel (to also allow the use of DSA ciphers, etc.)
# ECC keys, when in use, can also be configured in parallel
SSLCertificateKeyFile "/usr/local/openssl-1.1.1/CA/server.key"
#SSLCertificateKeyFile "/usr/local/httpd2/conf/server-dsa.key"
#SSLCertificateKeyFile "/usr/local/httpd2/conf/server-ecc.key"
# Certificate Authority (CA):
# Set the CA certificate verification path where to find CA
# certificates for client authentication or alternatively one
# huge file containing all of them (file must be PEM encoded)
# Note: Inside SSLCACertificatePath you need hash symlinks
# to point to the certificate files. Use the provided
# Makefile to update the hash symlinks after changes.
#SSLCACertificatePath ""
SSLCACertificateFile "/usr/local/openssl-1.1.1/CA/root-ca.pem"
# Client Authentication (Type):
# Client certificate verification type and depth. Types are
# none, optional, require and optional_no_ca. Depth is a
# number which specifies how deeply to verify the certificate
# issuer chain before deciding the certificate is not valid.
SSLVerifyClient require
SSLVerifyDepth 10
</VirtualHost>
ここまでで接続先サーバーの準備が完了した。