!!!OpenBSD Webサーバ の SSL(TSL) 接続 (httpd on OpenBSD ==6.8== 7.0) {{category OpenBSD,nolink}}OpenBSD の Webサーバ httpd(relayd) で、SSL(TSL) 接続する。 自己証明書(オレオレ証明書) と ACME client を用いての Let's Encrypt の証明書の取得と更新をする。 httpd 自体を動かす設定は、[[OpenBSD/httpd/68(relayd)]] を参照。 * 関連 man → [httpd(8)|https://man.openbsd.org/httpd.8], [httpd.conf(5)|https://man.openbsd.org/httpd.conf.5], [openssl(1)|https://man.openbsd.org/openssl.1], [acme-client(1)|https://man.openbsd.org/acme-client.1] !!!自己証明書で SSL(TSL) 接続 !!秘密鍵と証明書の作成 LibreSSL の openssl コマンドを使って、サーバの秘密鍵と証明書(自己署名証明書)を作成する。 !秘密鍵の作成 bbb# openssl genrsa -out /etc/ssl/private/server.key 2048 Generating RSA private key, 2048 bit long modulus ..........................+++++ ..............+++++ e is 65537 (0x10001) !証明書署名要求(CSR)の作成 -subj オプションの内容は、対象のサーバに合わせて変える。指定しなければ、対話形式で入力となる。 特に CN については、実際のホスト名(URL の FDQN)に合わせる。 bbb# openssl req -new -key /etc/ssl/private/server.key -out /etc/ssl/private/server.csr -subj "/C=JP/ST=Tokyo/L=Chuo-Ku/CN=example.com" !証明書(CRT)の作成 bbb# openssl x509 -days 3650 -req -signkey /etc/ssl/private/server.key -in /etc/ssl/private/server.csr -out /etc/ssl/server.crt Signature ok subject=/C=JP/ST=Tokyo/L=Chuo-Ku/CN=example.com Getting Private key !秘密鍵ファイルの内容を確認 bbb# openssl rsa -text -noout -in /etc/ssl/private/server.key RSA Private-Key: (2048 bit) modulus:   :以下略 !証明書署名要求の内容を確認 bbb# openssl req -text -noout -in /etc/ssl/private/server.csr Certificate Request: Data: Version: 0 (0x0) Subject: C=JP, ST=Tokyo, L=Chuo-Ku, CN=example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus:   :以下略 !証明書ファイルの内容を確認 bbb# openssl x509 -text -noout -in /etc/ssl/server.crt Certificate: Data: Version: 1 (0x0) Serial Number: ac:fd:4f:7d:d5:52:9b:a0 Signature Algorithm: sha256WithRSAEncryption Issuer: C=JP, ST=Tokyo, L=Chuo-Ku, CN=example.com Validity Not Before: Dec 5 11:02:41 2021 GMT Not After : Dec 3 11:02:41 2031 GMT Subject: C=JP, ST=Tokyo, L=Chuo-Ku, CN=example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption RSA Public-Key: (2048 bit) Modulus:   :以下略 !! Webサーバ(httpd) の設定 '''/etc/httpd.conf''' に設定する。 TSL(HTTP over SSL/TLS)接続で待つポート番号と、作成したキーファイル /etc/ssl/private/server.key 、証明書 /etc/ssl/server.crt を指定する。 server "default" { listen on * port 80 listen on * tls port 443 tls { certificate "/etc/ssl/server.crt" key "/etc/ssl/private/server.key" } # :中略 } !! HTTPS通信の疎通確認 まぁ、ブラウザでアクセスして、期待するページが表示されれば OK なんだけど。 ! curl curl コマンドでアクセスして確認する。 自己証明書なので '''-k''' (--insecure) オプションをつけて、安全でないSSL接続も許可するようにする。 bbb$ curl -svk https://localhost:443/ 1> /dev/null * Trying 127.0.0.1:443... * Connected to localhost (127.0.0.1) port 8443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem CApath: none * (304) (OUT), TLS handshake, Client hello (1): } [314 bytes data] * (304) (IN), TLS handshake, Server hello (2): { [122 bytes data] * (304) (IN), TLS handshake, Unknown (8): { [10 bytes data] * (304) (IN), TLS handshake, Certificate (11): { [795 bytes data] * (304) (IN), TLS handshake, CERT verify (15): { [264 bytes data] * (304) (IN), TLS handshake, Finished (20): { [36 bytes data] * (304) (OUT), TLS handshake, Finished (20): } [36 bytes data] * SSL connection using unknown / AEAD-CHACHA20-POLY1305-SHA256 * ALPN, server did not agree to a protocol * Server certificate: * subject: C=JP; ST=Tokyo; L=Chuo-Ku; CN=example.com * start date: Dec 5 11:02:41 2021 GMT * expire date: Dec 3 11:02:41 2031 GMT * issuer: C=JP; ST=Tokyo; L=Chuo-Ku; CN=example.com * SSL certificate verify result: self signed certificate (18), continuing anyway. > GET / HTTP/1.1 > Host: localhost:443 > User-Agent: curl/7.72.0 > Accept: */* > * Mark bundle as not supporting multiuse < HTTP/1.1 200 OK < Connection: keep-alive < Content-Length: 170 < Content-Type: text/html < Date: Fri, 14 Jan 2022 23:49:29 GMT < Last-Modified: Wed, 13 Jan 2021 15:54:49 GMT < Server: OpenBSD httpd < { [170 bytes data] * Connection #0 to host localhost left intact また、'''--tlsv1'''(-1) または、'''--sslv2'''(-2)、'''--sslv3'''(-3) を指定することで、 TLSv1.0 以上 または、SSLv2、SSLv3 で接続する。もっとも、LibreSSL は SSLv2 および SSLv3 をサポートしない。 さらに、'''--tlsv1.0''' や '''--tlsv1.1'''、'''--tlsv1.2'''、'''--tlsv1.3''' で、TLSv1.0 以上、TLSv1.1 以上… となる。 bbb$ curl -svk -ssl3 https://localhost:443/ 1> /dev/null * Trying 127.0.0.1:443... * Connected to localhost (127.0.0.1) port 443 (#0) * LibreSSL was built without SSLv3 support * Closing connection 0 bbb$ bbb$ curl -svk -tsl1 https://localhost:443/ 1> /dev/null * Trying 127.0.0.1:443... * Connected to localhost (127.0.0.1) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem   :後略 bbb$ bbb$ curl -svk -tsl1.3 https://localhost:443/ 1> /dev/null * Trying 127.0.0.1:443... * Connected to localhost (127.0.0.1) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/cert.pem   :後略 ! openssl s_client LibreSSL の openssl コマンドの s_client を利用して、TSL接続を確認する。 '''-connect''' ''localhost:443'' で接続先のホストとポート番号を指定し、 '''-showcerts''' でサーバ証明書を表示する。 また、SNI(Server Name Indication) の場合、'''-servername''' ''localhost'' でサーバ名も指定する。 s_client は、SSL/TSL通信クライアントなので、サーバにコマンドを送るために標準入力の入力待ちとなる。 エンターキーを押すか、nullディバイスを標準入力に渡す('''< /dev/null''')。 bbb$ openssl s_client -showcerts -connect localhost:443 -servername localhost < /dev/null CONNECTED(00000003) depth=0 C = JP, ST = Tokyo, L = Chuo-Ku, CN = example.com verify error:num=18:self signed certificate verify return:1 write W BLOCK --- Certificate chain 0 s:/C=JP/ST=Tokyo/L=Chuo-Ku/CN=example.com i:/C=JP/ST=Tokyo/L=Chuo-Ku/CN=example.com -----BEGIN CERTIFICATE-----   :中略 -----END CERTIFICATE----- --- Server certificate subject=/C=JP/ST=Tokyo/L=Chuo-Ku/CN=example.com issuer=/C=JP/ST=Tokyo/L=Chuo-Ku/CN=example.com --- No client certificate CA names sent Server Temp Key: ECDH, X25519, 253 bits --- SSL handshake has read 1326 bytes and written 369 bytes --- New, TLSv1/SSLv3, Cipher is AEAD-CHACHA20-POLY1305-SHA256 Server public key is 2048 bit Secure Renegotiation IS NOT supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1.3 Cipher : AEAD-CHACHA20-POLY1305-SHA256 Session-ID: Session-ID-ctx: Master-Key: Start Time: 1642210666 Timeout : 7200 (sec) Verify return code: 0 (ok) --- DONE bbb$ 使用するTLSのバージョン指定(-tls1 | -tls1_1 | -tls1_2 | -tls1_3)、制限(-no_tls1 | -no_tls1_1 | -no_tls1_2 | -no_tls1_3)、 使用する暗号スイートを指定(-cipher cipherlist)(リストは ciphers コマンドで確認)ができる。 bbb$ openssl ciphers -v AEAD-CHACHA20-POLY1305-SHA256 TLSv1.3 Kx=TLSv1.3 Au=TLSv1.3 Enc=ChaCha20-Poly1305 Mac=AEAD   :中略 AES256-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(256) Mac=SHA256   :中略 AES128-SHA256 TLSv1.2 Kx=RSA Au=RSA Enc=AES(128) Mac=SHA256   :中略 bbb$ bbb$ openssl s_client -showcerts -connect localhost:443 -servername localhost -tls1_2 -cipher AES128-SHA256 < /dev/null CONNECTED(00000003) depth=0 C = JP, ST = Tokyo, L = Chuo-Ku, CN = example.com verify error:num=18:self signed certificate verify return:1 write W BLOCK ---   :中略 --- New, TLSv1/SSLv3, Cipher is AES128-SHA256 Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE No ALPN negotiated SSL-Session: Protocol : TLSv1.2 Cipher : AES128-SHA256 Session-ID: Session-ID-ctx: Master-Key: 1335A8833AC1494CFE00E7D4B2633859D62CC5330268B4132E47E0C25FEDFB2A5F3123B28F10601CA706726E761B45B8 Start Time: 1642212400 Timeout : 7200 (sec) Verify return code: 0 (ok) --- DONE bbb$ !!! Let's Encrypt の証明書で SSL(TSL) 接続 OpenBSD 6.1 から追加された ACME クライアントを利用して、Let's Encrypt の取得・更新を行い、SSL(TSL) 接続する。 !! acme-client の設定 '''/etc/acme-client.conf''' に設定する。サンプルが /etc/examples/acme-client.conf にある。 bbb# cp -p /etc/examples/acme-client.conf /etc/ サンプルをコピーして、末尾の domain 部分の example.com 等を自分のドメインに変更する。 複数のドメイン名に対応する Subject Alternative Names(SANs) を利用する場合は、'''alternative names''' にカンマまたはスペース区切りで列挙する。 domain example.com { #alternative names { secure.example.com } domain key "/etc/ssl/private/example.com.key" domain full chain certificate "/etc/ssl/example.com.fullchain.pem" sign with letsencrypt #challengedir /var/www/acme } !! Webサーバ(httpd) の設定 '''/etc/httpd.conf''' に設定する。サンプルが /etc/examples/httpd.conf にある。 必要になるのは、ドメイン名の検証を行う HTTP-01 チャレンジ の応答を返すための設定と、取得した証明書(とその秘密鍵)ファイルを参照するようにする。 server "default" { listen on * port 80 listen on * tls port 443 tls { certificate "/etc/ssl/example.com.fullchain.pem" key "/etc/ssl/private/example.com.key" } location "/.well-known/acme-challenge/*" { root "/acme" request strip 2 } } !! 証明書の取得 acme-client を実行して、証明書が取得できたら、httpd を再起動して、秘密鍵と証明書を読み込み直す。 bbb# rcctl restart httpd httpd(ok) httpd(ok) bbb# acme-client -v example.com acme-client: /etc/acme/letsencrypt-privkey.pem: generated RSA account key acme-client: /etc/ssl/private/example.com.key: generated RSA domain key acme-client: https://acme-v02.api.letsencrypt.org/directory: directories acme-client: acme-v02.api.letsencrypt.org: DNS: 172.65.32.248 acme-client: dochngreq: https://acme-v02.api.letsencrypt.org/acme/authz-v3/00000000000 acme-client: challenge, token: **********, uri: https://acme-v02.api.letsencrypt.org/acme/chall-v3/00000000000/XXXXXX, status: 0 acme-client: /var/www/acme/**********: created acme-client: https://acme-v02.api.letsencrypt.org/acme/chall-v3/00000000000/XXXXXX: challenge acme-client: order.status 1 acme-client: https://acme-v02.api.letsencrypt.org/acme/finalize/111111111/22222222222: certificate acme-client: order.status 3 acme-client: https://acme-v02.api.letsencrypt.org/acme/cert/zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz: certificate acme-client: /etc/ssl/example.com.fullchain.pem: created bbb# rcctl restart httpd httpd(ok) httpd(ok) bbb# !! 証明書の自動更新 Let's Encrypt の証明書の有効期限は '''90日''' で作成される。このため、証明書を維持するには、定期的に更新が必要となる。 acme-client は、有効期限が30日を切ると更新を行うようになるので、 ''acme-client example.com && rcctl reload httpd'' とコマンドをつなげて、証明書の更新と再起動を行うように、cron に設定するか、''/etc/daily.local'' や ''/etc/weekly.local'' にコマンドを記載して実行させる。 bbb# cat /etc/daily.local # update Let's Encrypt certificate. acme-client example.com && rcctl reload httpd bbb#