とほほのOpenSSL入門

トップ > とほほの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 "Message" | openssl md5 -binary | base64
9enH5C5L3tQh5EdnMgh63Q==

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

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

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

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

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

# BASE64をデコードする
$ echo "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 "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 "Message" | openssl aes-256-cbc -e -pass file:mypass.txt > secret.dat

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

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

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

# 公開鍵で暗号化する
$ echo "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)

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

# オレオレ認証局のファイル
/etc/pki/CA/private/cakey.pem   - 認証局の秘密鍵
/etc/pki/CA/cacert.csr          - 認証局の証明書署名要求
/etc/pki/CA/cacert.pem          - 認証局の証明書

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

まず、オレオレ認証局を作成します。手順は CentOS8(Rocky Linux/AlmaLinux)で確認しています。

# OpenSSLをインストールする
# dnf -y install openssl
# openssl version
OpenSSL 1.1.1k  FIPS 25 Mar 2021

# 必要なディレクトリを作成する
# mkdir -p /etc/pki/CA/private
# cd /etc/pki/CA

# 認証局の秘密鍵を作成する
# openssl genrsa -aes256 2048 > ./private/cakey.pem

# 認証局の証明書署名要求を作成する
# openssl req -new -key ./private/cakey.pem > ./cacert.csr

# 認証局の証明書を作成する
# cat ./cacert.csr | openssl x509 -req -signkey ./private/cakey.pem > ./cacert.pem

# その他必要なディレクトリやファイルを作成する
# mkdir /etc/pki/CA/newcerts
# touch /etc/pki/CA/index.txt
# echo 00 > /etc/pki/CA/serial

ここで作成したディレクトリやファイル名は /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

次にサーバ側でサーバの秘密鍵と証明書署名要求を作成します。

# dnf -y install httpd mod_ssl
# mkdir /etc/httpd/certs
# cd /etc/httpd/certs
# openssl genrsa 2048 > ./server.key
# openssl req -new -key ./server.key > ./server.csr

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

# echo "subjectAltName = DNS:www.example.com" > san.txt
# openssl ca -in ./server.csr -policy policy_anything -extfile san.txt -out ./server.crt

作成した秘密鍵と証明書を mod_ssl の設定ファイル /etc/httpd/conf.d/ssl.conf に設定します。

<VirtualHost _default_:443>
  SSLCertificateFile /etc/httpd/certs/server.crt
  SSLCertificateKeyFile /etc/httpd/certs/server.key
    :

オレオレ認証局の証明書 cacert.pem の拡張子を .cer に変更し、Windows のルート証明書に取り込むことにより、オレオレ認証局でも警告の出ない HTTPS 通信を行うことができるようになります。

エラーメッセージ

クライアントが 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

Copyright (C) 2022 杜甫々
初版:2022年4月3日 最終更新:2022年4月3日
http://www.tohoho-web.com/ex/openssl.html