とほほのOpenSSL入門

目次

OpenSSLとは

OpenSSLのインストール

下記の様にしてインストールします。

# CentOS 7
# yum -y install openssl
# openssl version
OpenSSL 1.0.2k-fips  26 Jan 2017

# CentOS 8(Rocky Linux/AlmaLinux)
# dnf -y install openssl
# openssl version
OpenSSL 1.1.1k  FIPS 25 Mar 2021

# Ubuntu 20.04
$ sudo apt -y install openssl
$ OpenSSL 1.1.1f  31 Mar 2020

OpenSSLのバージョンとサポート終了日

現在は 1.1.1 が主流のようです。

1.0.2  2015年1月22日リリース。2019年12月31日サポート終了
1.1.0  2016年8月25日リリース。2019年9月11日サポート終了
1.1.1  2018年9月11日リリース。2023年9月11日サポート終了予定。
3.0.1  2021年12月14日リリース。2026年9月7日サポート終了予定。
3.0.2  2022年3月15日リリース。2026年9月7日サポート終了予定。

参考:https://www.openssl.org/policies/releasestrat.html

OpenSSLの主なオプション

# コマンド
version     バージョンを表示する。
rand        ランダムデータを生成する。
enc         エンコードする。
genrsa      RSA秘密鍵を作成する。
rsa         RSA秘密鍵関連の処理を行う。
req         証明書署名要求関連の処理を行う。
x509        証明書関連の処理を行う。

# 入出力に関するもの
-key        秘密鍵を指定する。
-in         入力ファイルを指定する。
-out        出力ファイルを指定する。
-pubin      公開鍵を入力する。
-pubout     公開鍵を出力する。

# 暗号化に関するもの
-aes256     AES256で暗号化する。

# 出力形式に関するもの
-binary     バイナリ形式で出力する。
-text       テキスト形式で出力する。
-base64     BASE64形式で出力する。
-hex        16進数形式で出力する。
-noout      末尾にPEM(-----BEGIN...)を出力しない。

OpelSSLのコンフィグファイル

OpenSSL のコンフィグファイルは下記にあります。オプション省略時のデフォルト値やセキュリティレベルなどの設定があります。

# RHEL/CentOS系
/etc/pki/tls/openssl.cnf

# Ubuntu系
/etc/ssl/openssl.cnf

よく使われる拡張子

.pem      PEM形式(-----BEGIN ...)。中身は秘密鍵だったり公開鍵だったり証明書だったり
.key      鍵ファイル。秘密鍵や公開鍵。
.pub      公開鍵
.csr      証明書署名要求(Certificate Signing Request)
.crt      証明書(Certificate)
.ppk      PuTTYが扱う鍵ファイル形式

PEM形式

Privacy Enhanced Mail の略で、メールを暗号化して送信する際に利用されていた形式です。SSH の秘密鍵、HTTPS のサーバ証明書などにも利用されます。下記の様にバイナリ情報を BASE64 にエンコードし、前後を -----BEGIN XXXXXX----- と -----END XXXXXX----- で囲んだ形式となります。

-----BEGIN XXXXXX-----
MIIEpAIBAAKCAQEA6yA4UQQBRNIGMBh8JSxCclrBshUWFvXP6Pjxc1wBZG/ErN8b
oyNOK8YludLOn3/1l6j1jhSpjBdqMvo3nLzsml14N5MghrYa+kWi0pOaMCqqEkrv
(略)
JSl8tB9LdolgnY/HMeA/wzfC2JqMjNgWjz6cDpZbCnUkE3zl5O3UQZZ2fe/dbtPK
DpHX37TMrGjwU9u79YKhd0MUl6RBGvF4yflFKz+mNZq8joi2VndYyg==
-----END XXXXXX-----

パスフレーズが設定されている場合は、下記の様にどのアルゴリズムで暗号化されているかの情報が付加されます。

-----BEGIN XXXXXX-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,92EFA0DA4E5839445F2952109C6FC294

cifhGb9BDdKPx6KaC+YgvZX2XFvI6mpqzMY5XF9eiUjqHCFqKjA8ZxQqZ7QM8lYQ
RtrRdF7Z8Wxjh/y89lz09+i4OCMxeZyMHPfFoOqXLeFbSDlfApTlGl3OoNIAhzEt
(略)

XXXXXX の部分は下記などになります。

RSA PRIVATE KEY     RSA秘密鍵
PUBLIC KEY          公開鍵
CERTIFICATE REQUEST 証明書署名要求(CSR)
CERTIFICATE         証明書(CRT)

SSLとTLSについて

SSL は Secure Socket Layer の略でソケットを利用した通信を暗号化する技術です。TLS は Transport Layer Security の略で SSL の後継プロトコルです。HTTP を SSL/TLS で暗号化したものを HTTPS、SMTP を暗号化したものを SMTPS などと呼びます。

SSL 1.0   脆弱性のため未リリース。
SSL 2.0   1995年リリース。2011年3月廃止。
SSL 3.0   1996年リリース。2015年6月廃止。
TLS 1.0   1999年リリース。2021年3月廃止。SSL 3.0 の後継。
TLS 1.1   2006年リリース。2021年3月廃止。AES をサポート。
TLS 1.2   2008年リリース。SHA-256 をサポート。
TLS 1.3   2018年リリース。

SSL/TLS 通信を行う際は、下記などに注意する必要があります。現時点(2022年4月)では、TLSv1.2 以上、2048ビット以上、SHA256以上を使用することが推奨されています。

サポートするプロトコル:
  SSLv3.0 / TLSv1.0 / TLSv1.1 / TLSv1.2 / TLSv1.3
公開鍵の鍵長:
  1024ビット / 2048ビット
署名に使用されるメッセージダイジェスト種別:
  SHA1 / SHA256 / SHA512

OpenSSLのヘルプを表示する

下記の様にしてヘルプメッセージを表示することができます。

# コマンドの一覧を表示
$ openssl help

# コマンドの詳細を表示
$ openssl rsa -help

ランダムなデータを生成する

rand を用いると任意バイト長のランダムデータを生成することができます。

$ openssl rand 32 | base64
WgMRI5AN5FxP03BpE4kIQJ2WOmmd4h3P+fKHn+p0hpk=

ハッシュ値を生成する

入力データのハッシュ値を計算することができます。下記の例ではバイナリ形式で出力して base64 コマンドで BASE64 化しています。

# MD5ハッシュ値を生成する
$ echo -n "Message" | openssl md5 -binary | base64
9enH5C5L3tQh5EdnMgh63Q==

# SHA-1ハッシュ値を生成する
$ echo -n "Message" | openssl sha1 -binary | base64
hLeyrJXas/VZn/SPpf55oUEPg14=

# SHA-2(SHA256)ハッシュ値を生成する
# echo -n "Message" | openssl sha256 -binary | base64
S2zqHMKcwVfQCGFG5CLtQ08BKijZc4PFHSweUM+X0rA=

暗号化・復号する

データを暗号化・復号することもできます。下記は Message というデータを SecretKey というパスワードで AES 256 bits の CBC モードで暗号化します。-e は暗号化(encryption)、-d は復号(decryption) を意味します。-pass を省略すると標準入力から求められます。

# 暗号化する
$ echo -n "Message" | openssl enc -e -aes-256-cbc -pass pass:SecretKey | base64
U2FsdGVkX193jW9yuqubVWmDKy6HKHfnJLLJYa8G7pQ=

# 復号する
$ echo -n U2Fsd..(略)..G7pQ= | base64 -d | openssl enc -d -aes-256-cbc -pass pass:SecretKey
Message

上記は正確には、パスワードとランダム生成した Salt を元に 256 bits の秘密鍵と 16 bits の IV(初期化ベクトル)を作成して暗号化します。結果には Salt の情報も含むため、ライブラリなどを使用して独自に IV を指定して生成した暗号化情報とは異なります。下記の様にダンプすると先頭に数バイトの Salt が付加されていることが分かります。詳細は「暗号化入門」を参照してください。

$ echo -n "Message" | openssl enc -e -aes-256-cbc -pass pass:SecretKey | od -tx1z
0000000 53 61 6c 74 65 64 5f 5f 19 99 d8 62 1f fc f3 a9  >Salted__...b....<
0000020 ea da 81 17 c0 1e 67 da c4 25 27 67 d9 a9 a7 4c  >......g..%'g...L<
0000040

下記のようなワーニングが表示されることがあります。暗号化が単純すぎてセキュリティ的に弱いことを示しています。

$ echo -n "Message" | openssl enc -e -aes-256-cbc -pass pass:HukuZaTsuNaPassword | base64
*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
U2FsdGVkX19p0RP/Eg5nMMJzPCKhmYKm+zAQ1ONfsUA=

-iter で繰り返し回数を指定したり、-pbkdf2 で PBKDF2 アルゴリズムを適用することにより暗号化の強度を高めることができます。

$ echo -n "Message" | openssl enc -e -aes-256-cbc -iter 10000 -pass pass:HukuZaTsuNaPassword | base64
U2FsdGVkX197dUAoyZrMlLh6tnUXKq26f+zhKkhP9dw=
$ echo -n "Message" | openssl enc -e -aes-256-cbc -pbkdf2 -pass pass:HukuZaTsuNaPassword | base64
U2FsdGVkX1+m+fgeNvlOiMvg01SwMeeNBD+DfRvz2H0=

HMAC-HASH値を生成する

HMAC は暗号化とハッシュを用いて認証等に利用可能はハッシュ値を生成する技術です。HMAC-MD5, HMAC-SHA256 などがありますが、例えば、OpenSSL を用いて HMAC-SHA256 値を求めるには下記の様にします。

$ echo -n "Message" | openssl dgst -sha256 -hmac 'SecretKey' -binary | base64
QMg4nWFOcdaQJK269XQV0HH4PcusbA9wmp09QucGv2E=

BASE64エンコード・デコードする

base64 コマンドでもできますが、下記の様に BASE64 エンコード・デコードすることができます。

# BASE64でエンコードする
$ echo -n "Message" | openssl enc -e -base64
TWVzc2FnZQo=

# BASE64をデコードする
$ echo -n "TWVzc2FnZQo=" | openssl enc -d -base64
Message

秘密鍵を作成する(パスフレーズ無し)

秘密鍵を作成します。アルゴリズムは RSA、鍵長は 2048 ビットがよく利用されます。1024 ビットは許可しないシステムも増えてきました。

$ openssl genrsa 2048 > private.key
Generating RSA private key, 2048 bit long modulus (2 primes)
........................................................+++++
.......................................................................+++++
e is 65537 (0x010001)

秘密鍵ファイルの中身は下記のような PEM 形式のテキストになっています。15行程度であれば 1024 ビット長、27行程度であれば 2048 ビット長です。

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA6yA4UQQBRNIGMBh8JSxCclrBshUWFvXP6Pjxc1wBZG/ErN8b
oyNOK8YludLOn3/1l6j1jhSpjBdqMvo3nLzsml14N5MghrYa+kWi0pOaMCqqEkrv
(略)
JSl8tB9LdolgnY/HMeA/wzfC2JqMjNgWjz6cDpZbCnUkE3zl5O3UQZZ2fe/dbtPK
DpHX37TMrGjwU9u79YKhd0MUl6RBGvF4yflFKz+mNZq8joi2VndYyg==
-----END RSA PRIVATE KEY-----

秘密鍵の中身を確認するには次のようにします。-text はデフォルトのPEM形式ではなくテキスト形式で表示すること、-noout は末尾にPEM形式の情報を出力しないことを意味します。

$ cat private.key | openssl rsa -text -noout
RSA Private-Key: (2048 bit, 2 primes)
modulus:
    00:b7:bc:26:4d:e4:1b:3a:37:a4:cb:a0:fb:22:02:
    19:36:3c:bc:d0:75:ac:5e:50:fc:f7:c1:a0:31:d6:
(略)

秘密鍵を作成する(パスフレーズ有り)

秘密鍵は安全のためにパスフレーズをつけて暗号化することができます。暗号化アルゴリズムとしては DES, DES3, AES128, AES256 などがありますが、最近では AES256 を使用することが多いようです。

$ openssl genrsa -aes256 2048 > private.key
Generating RSA private key, 2048 bit long modulus (2 primes)
........................................+++++
.+++++
e is 65537 (0x010001)
Enter pass phrase:               ← パスワードを入力
Verifying - Enter pass phrase:   ← パスワードを入力
$

パスフレーズ付きの秘密鍵には、下記の様に何で暗号化されているかの情報が付加されます。

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-256-CBC,92EFA0DA4E5839445F2952109C6FC294

cifhGb9BDdKPx6KaC+YgvZX2XFvI6mpqzMY5XF9eiUjqHCFqKjA8ZxQqZ7QM8lYQ
RtrRdF7Z8Wxjh/y89lz09+i4OCMxeZyMHPfFoOqXLeFbSDlfApTlGl3OoNIAhzEt
(略)

パスフレーズ無しの秘密鍵にパスフレーズをつけるには次のようにします。

$ cat private-no-pass.key | openssl rsa -aes256 > private-with-pass.key

パスフレーズ付きの秘密鍵のパスフレーズを外すには次の様にします。

$ cat private-with-pass.key | openssl rsa > private-no-pass.key

公開鍵を作成する

秘密鍵を元に公開鍵を作成します。

$ cat private.key | openssl rsa -pubout > public.key

公開鍵もPEM形式で作成されます。PUBLIC KEY とコメントされます。

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnyrVwJxKtO0kJIHiMDWI
AX8HWTUK9FHWoNSGWiX64IikBFSRhwcEKWcc+82Uc1ZL2a42s8U3eKAPowHLWaHt
(略)
mwndXcwrULmccR7i4gznBKQBRHqfS7/m/DA978knWxDxpuf3wh5TNhRMOub3UFZp
PwIDAQAB
-----END PUBLIC KEY-----

公開鍵の中身を確認するには次のようにします。

$ cat public.key | openssl rsa -text -pubin -noout
RSA Public-Key: (2048 bit)
Modulus:
    00:9f:2a:d5:c0:9c:4a:b4:ed:24:24:81:e2:30:35:
    88:01:7f:07:59:35:0a:f4:51:d6:a0:d4:86:5a:25:
(略)

証明書署名要求(CSR)を作成する

サーバ証明書を作成する際など、まず、自分の秘密鍵を用いて証明書署名要求(CSR: Certificate Signing Request)を作成します。

$ openssl req -new -key private.key > server.csr
(略)
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Tokyo
Locality Name (eg, city) [Default City]:Minato-ku
Organization Name (eg, company) [Default Company Ltd]:Example Company
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:www.example.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
$

証明書署名要求もPEM形式で作成されます。CERTIFICATE REQUEST とコメントされます。

-----BEGIN CERTIFICATE REQUEST-----
MIICqjCCAZICAQAwZTELMAkGA1UEBhMCSlAxDjAMBgNVBAgMBVRva3lvMRIwEAYD
VQQHDAlNaW5hdG8ta3UxGDAWBgNVBAoMD0V4YW1wbGUgQ29tcGFueTEYMBYGA1UE
(略)
nj72TIcihlAkNWHWylWQrBnZyovVmSAwW+YjItIsPSXvU83GwVY+BqIS+PjHyMNL
rc0S6AgpoF52+HBsydc=
-----END CERTIFICATE REQUEST-----

証明書署名要求の中身を確認するには次のようにします。

$ cat server.csr | openssl req -text -noout
Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject: C = JP, ST = Tokyo, L = Minato-ku, O = Example Company, CN = www.example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:fb:3c:81:06:3d:7e:13:64:36:74:c5:27:81:5d:
                    ff:d0:5d:35:92:f3:bb:29:fb:e8:ff:b3:a5:3c:9d:
(略)

証明書(CRT)を作成する

サーバの管理者が発行した証明書署名要求(CSR)に対して、認証局(CA)がCAの秘密鍵で署名を行ったものが証明書(CRT)です。CAの秘密鍵を cs-private.key とすると下記の様に作成します。推奨される証明書の有効期限は昔は5年が多かったですが、2015年には3年、2018年に2年、2020年には1年と1カ月(398日)と短くなってきました。

$ cat server.csr | openssl x509 -req -days 398 -signkey ca-private.key > server.crt
Signature ok
subject=C = JP, ST = Tokyo, L = Minato-ku, O = Example Company, CN = www.example.com
Getting Private key

証明書もPEM形式で作成されます。CERTIFICATE をコメントされます。

-----BEGIN CERTIFICATE-----
MIIDUTCCAjkCFB34d2rzf++4hgRzjy5nFTUpKeCGMA0GCSqGSIb3DQEBCwUAMGUx
CzAJBgNVBAYTAkpQMQ4wDAYDVQQIDAVUb2t5bzESMBAGA1UEBwwJTWluYXRvLWt1
(略)
XQhvCzu1h8w6iTVxMKgBl8wQFPTu9YCcM5bg7gZgUvuR0JV9mGVDsNmeKwX3Lr0l
BtF9CPStkjy/Vr/GPEtuolK5CBlKrh7MFwiejuCbV2Ck4TkvAw==
-----END CERTIFICATE-----

証明書の中身を確認するには次のようにします。署名アルゴリズムとして SHA256、有効期限が 2023年5月6日、RSA の鍵長が 2048ビットであることが確認できます。

# cat server.crt | openssl x509 -text -noout
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            1d:f8:77:6a:f3:7f:ef:b8:86:04:73:8f:2e:67:15:35:29:29:e0:86
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = JP, ST = Tokyo, L = Minato-ku, O = Example Company, CN = www.example.com
        Validity
            Not Before: Apr  3 01:49:19 2022 GMT
            Not After : May  6 01:49:19 2023 GMT
        Subject: C = JP, ST = Tokyo, L = Minato-ku, O = Example Company, CN = www.example.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                RSA Public-Key: (2048 bit)
                Modulus:
                    00:ac:1b:95:fd:ce:f3:ee:8d:0f:e1:7e:6e:9b:16:
                    7d:d4:83:ac:c4:60:35:d5:0f:bb:cf:0c:b0:51:22:
(略)

共通鍵を用いて暗号化・復号化する

AES256(CBCモード)でデータを暗号化するには次のようにします。

# AES256(CBCモード)で暗号化する
$ echo -n "Message" | openssl aes-256-cbc -e > secret.dat
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:

# AES256(CBCモード)で復号化する
$ cat secret.dat | openssl aes-256-cbc -d
enter aes-256-cbc decryption password:
Message

-pass オプションを用いると、パスワードをファイルや環境変数で指定することができます。

# パスワードを mypass.txt からよみこむ
$ echo -n "Message" | openssl aes-256-cbc -e -pass file:mypass.txt > secret.dat

# パスワードを環境変数 MYPASS からよみこむ
$ echo -n "Message" | openssl aes-256-cbc -e -pass env:MYPASS > secret.dat

公開鍵を用いて暗号化・復号化する

公開鍵を用いて暗号化し、秘密鍵を用いて復号化する例を示します。

# 公開鍵で暗号化する
$ echo -n "Message" | openssl rsautl -encrypt -pubin -inkey public.key | base64 > encrypt.dat

# 秘密鍵で復号化する
$ cat encrypt.dat | base64 -d | openssl rsautl -decrypt -inkey private.key
Message

サーバと接続テストを行う

s_client コマンドを用いると、サーバと接続を試みて、サポートするバージョンや鍵長などの詳細情報を表示します。

$ openssl s_client -connect www.example.com:443

-tls1_1 などを指定すると TLS 1.1/1.2/1.3 のサポートの有無を調べることができます。no peer certificate available のメッセージが含まれていれば、サーバ側がそのプロトコルをサポートしていません。

$ openssl s_client -tls1_1 -connect www.example.com:443
(略)
no peer certificate available
(略)

自己署名証明書(オレオレ証明書)

自己署名証明書(俗称:オレオレ証明書)を作成して Apache に設定する簡単な手順を説明します。

# opensslをインストールする
# yum -y install openssl

# 秘密鍵(KEY)を作成する
# openssl genrsa 2048 > server.key

# 証明書署名要求(CSR)を作成する
# openssl req -new -key server.key > server.csr

# 証明書署名要求(CSR)を自分の秘密鍵で署名する
# cat server.csr | openssl x509 -req -signkey server.key > server.crt

# Apacheとmod_sslをインストールする
# yum -y install httpd mod_ssl

# コンフィグファイルを修正する
# sed -i 's/^#ServerName .*/ServerName www.example.com/' /etc/httpd/conf/httpd.conf
# sed -i 's/^SSLCertificateFile .*/SSLCertificateFile \/root\/server.crt/' /etc/httpd/conf.d/ssl.conf
# sed -i 's/^SSLCertificateKeyFile .*/SSLCertificateKeyFile \/root\/server.key/' /etc/httpd/conf.d/ssl.conf

# Apacheを再起動する
# systemctl restart httpd

オレオレ認証局(CA)

上記のオレオレ証明書の場合、ブラウザでアクセスする度に証明書が怪しいと警告が出ます。もう少し本格的にオレオレ認証局を作成し、オレオレ認証局がサーバの証明書に署名する手順を紹介します。オレオレ認証局のルート証明書をクライアントにインストールすることでブラウザが警告なしでアクセスすることができるようになります。

下記手順は AlmaLinux 9 で確認しています。サンプル FQDN として www.example.com を使用しています。[コマンドプロンプト] を右クリックから管理者モードで実行し、www.example.com にサーバのIPアドレスを割り当ててやることで、https://www.example.com でアクセスすることが可能となります。

C:\Windows\System32>notepad \Windows\System32\drivers\etc\hosts
192.168.100.1   www.example.com

下記のファイルを作成していきます。

# オレオレ認証局のファイル
my-ca.key - 認証局の秘密鍵
my-ca.csr - 認証局の証明書署名要求
my-ca.crt - 認証局の証明書

# HTTPサーバのファイル
my-server.key - サーバの秘密鍵
my-server.csr - サーバの証明書署名要求
my-server.crt - サーバの証明書

まず、オレオレ認証局を作成します。証明書署名要求の Organization Name に CA を識別するための名前を指定してください。他は空で構いません。有効期限は約10年(3650日)にしています。

# OpenSSLをインストールする
# dnf -y install openssl
# openssl version
OpenSSL 3.0.7 1 Nov 2022 (Library: OpenSSL 3.0.7 1 Nov 2022)

# 認証局の秘密鍵を作成する
# openssl genrsa 4096 > ./my-ca.key

# 認証局の証明書署名要求を作成する
# openssl req -new -key ./my-ca.key > ./my-ca.csr
Organization Name (eg, company) [Default Company Ltd]:My Example CA

# 認証局の証明書を作成する
# cat ./my-ca.csr | openssl x509 -req -signkey ./my-ca.key -days=3650 > ./my-ca.crt

上記で作成したファイルなどを /etc/pki/tls/openssl.cnf の下記設定と合わせて設置していきます。

dir             = /etc/pki/CA
private_key     = $dir/private/cakey.pem
certificate     = $dir/cacert.pem
new_certs_dir   = $dir/newcerts
database        = $dir/index.txt
serial          = $dir/serial
# mkdir -p /etc/pki/CA/private
# cp ./my-ca.key /etc/pki/CA/private/cakey.pem
# cp ./my-ca.crt /etc/pki/CA/cacert.pem
# mkdir /etc/pki/CA/newcerts
# touch /etc/pki/CA/index.txt
# echo 00 > /etc/pki/CA/serial

サーバの秘密鍵と証明書署名要求を作成します。Common Name にはサーバの FQDN を指定してください。他は空でも動作はします。

# openssl genrsa 4096 > ./my-server.key
# openssl req -new -key ./my-server.key > ./my-server.csr
Common Name (eg, your name or your server's hostname) []:www.example.com

これをオレオレ認証局側で署名します。-policy policy_anything をつけない場合認証局とサーバ側で Common Name が異なると The stateOrProvinceName field is different between CA certificate (XXXXX) and the request (YYYYY) エラーとなります。また、最近のブラウザでは証明書の CN 情報ではなく DNS 情報を参照するため、下記の様に san.txt を作成し、-extfile で読み込むことにより DNS 情報を組み込んでいます。有効期限は約1年と1ヵ月(398日)にしています。

# echo "subjectAltName = DNS:www.example.com" > san.txt
# openssl ca -in ./my-server.csr -days=398 -policy policy_anything -extfile san.txt -out ./my-server.crt
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y

下記は Apache の場合のサーバ証明書設定手順です。

# dnf -y install httpd mod_ssl
# mkdir /etc/httpd/cert
# cp ./my-server.key /etc/httpd/cert
# cp ./my-server.crt /etc/httpd/cert
# vi /etc/httpd/conf.d/ssl.conf
<VirtualHost _default_:443>
  ServerName www.example.com
  SSLCertificateFile /etc/httpd/cert/my-server.crt
  SSLCertificateKeyFile /etc/httpd/cert/my-server.key
    :

Nginx の場合は次のようにします。

# dnf -y install nginx
# mkdir /etc/nginx/cert
# cp my-server.crt /etc/nginx/cert
# cp my-server.key /etc/nginx/cert
# vi /etc/nginx/nginx.conf
server {
    listen                 443 ssl;
    server_name            www.example.com;
    ssl_certificate        /etc/nginx/cert/my-server.crt;
    ssl_certificate_key    /etc/nginx/cert/my-server.key;

    # listen       80;
    # listen       [::]:80;
    # server_name  _;
        :

[Windows] キーを押して検索欄から「証明書」を検索して「ユーザー証明書の管理」を起動し、[信頼されたルート証明書]-[証明書] を右クリックし [すべてのタスク]-[インポート] から上記で作成した my-ca.crt を読み込むことにより、オレオレ認証局でも警告の出ない HTTPS 通信を行うことができるようになります。my-ca.crt を読み込む前でも、ブラウザのキャッシュを削除しないと、警告が出ないことがあります。

クライアント証明書

上記で作成したオレオレ認証局を用いてクライアント証明書を作成します。証明書署名要求 Organization Name には CA とは異なる名前を指定してください。他は空で構いません。有効期限は1年1ヵ月(398日)にしています。

# openssl genrsa 4096 > ./my-client.key
# openssl req -new -key ./my-client.key > ./my-client.csr
Organization Name (eg, company) [Default Company Ltd]:My Example Client
# openssl x509 -req -days 398 -CA ./my-ca.crt -CAkey ./my-ca.key < ./my-client.csr > ./my-client.crt

Windows に取り込むための PFX(Personal Information Exchange)ファイルを作成します。パスワードには任意のパスワードを設定してください。

# openssl pkcs12 -export -inkey ./my-client.key -in ./my-client.crt -certfile ./my-ca.crt > ./my-client.pfx
Enter Export Password:********
Verifying - Enter Export Password:********

Apache の場合下記の様に設定します。

# cp ./my-ca.crt /etc/httpd/cert
# vi /etc/httpd/conf.d/ssl.conf
<VirtualHost *:443>
  ServerName www.example.com
  SSLCertificateFile /etc/httpd/cert/my-server.crt
  SSLCertificateKeyFile /etc/httpd/cert/my-server.key
  SSLCACertificateFile /etc/httpd/cert/my-ca.crt
  SSLVerifyClient require
  SSLVerifyDepth 10
    :

Nginx の場合下記の様に設定します。

# cp ./my-ca.crt /etc/nginx/cert
# vi /etc/nginx/nginx.conf
server {
    listen                 443 ssl;
    server_name            www.example.com;
    ssl_certificate        /etc/nginx/cert/my-server.crt;
    ssl_certificate_key    /etc/nginx/cert/my-server.key;
    ssl_verify_client      on;
    ssl_client_certificate /etc/nginx/cert/my-ca.crt;

[Windows] キーを押して検索欄から「証明書」を検索して「ユーザー証明書の管理」を起動し、[個人]-[証明書] を右クリックし [すべてのタスク]-[インポート] から上記で作成した my-client.pfx を読み込むことにより、クライアント認証を用いた通信ができるようになります。

エラーメッセージ

クライアントが SSL 3.0 で通信したいのにサーバが SSL 3.0 をサポートしていない場合、下記のエラーメッセージが表示されることがあります。

sslv3 alert handshake failure:ssl/record/rec_layer_s3.c:1544:SSL alert number 40

SHA1 と SHA-2(SHA256等) や、1024ビットと 2048ビットなど、クライアントとサーバが要求するセキュリティレベルがあっていない場合にこのエラーとなります。openssl.cnf の SECLEVEL を 2 から 1 に下げることでセキュリティレベルは下がりますが対応できることがあります。

curl: (35) error:0A000172:SSL routines::wrong signature type

対応する鍵長やアルゴリズムの差異によりクライアント証明書などを読み込めなかった時に発生するようです。バージョンの差異だけではないようですが Windows 標準の curl.exe (7.79.1) だとクライアント証明書をうまく読み込めず、https://curl.se/download.html からダウンロードした最新版 curl.exe (7.82.0) でも NG。Windows版 Git に含まれる curl.exe (7.81.0) だと読み込めたという事象もありました。

curl: (58) schannel: Failed to import cert file