9999 年間有効な SSL 証明書を作る

Debian vs Ubuntu Logo

OpenSSLGnuTLS を利用して、 任意の日時を有効期限に指定した自己署名証明書を生成するスクリプトを書きました。 だいぶニッチなスクリプトですが SSL のテストかなにかに使えるかもしれません。

さらにそれらを利用して、 有効期限がだいぶ長い (100 年間とか 9999 年間とか) SSL 証明書を作ろうとしてみました。

OpenSSL で 100 年間有効な証明書を作る

make-self-signed-cert-openssl.sh は OpenSSL のコマンドラインツールを使って自己署名証明書を生成するスクリプトです。

$ sudo apt-get install openssl
$ wget https://gist.githubusercontent.com/yaegashi/8004ca8677c5d03879bd/raw/a0c3ec4af0958ffaa85726b39ad8120c0f842f13/make-self-signed-cert-openssl.sh
$ chmod +x make-self-signed-cert-openssl.sh
$ ./make-self-signed-cert-openssl.sh 
Usage: ./make-self-signed-cert-openssl.sh <common name> <output> [ca options ...]

<common name> には Subject の名前 (通常は FQDN ホスト名) を指定します。 <output> には出力ファイルパスを指定します。 パスフレーズなしの秘密鍵と証明書が PEM 形式で連結されて出力されます。

[ca options ...] は署名を実行する openssl ca コマンドにそのまま渡されます。 ca の -startdate/-enddate オプションを使用することで 証明書の有効期限に任意の時刻が指定できるので、 次のようにすれば 100 年間有効な SSL 証明書が作れます。

$ ./make-self-signed-cert-openssl.sh blog.keshi.org cert.pem -startdate 19500101000000Z -enddate 20491231235959Z
Generating a 2048 bit RSA private key
...+++
........................................+++
writing new private key to '/tmp/tmp.fjyu9QOhx8/key.pem'
-----
Using configuration from /tmp/tmp.fjyu9QOhx8/ssleay.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :PRINTABLE:'blog.keshi.org'
Certificate is to be certified until Dec 31 23:59:59 2049 GMT

Write out database with 1 new entries
Data Base Updated

生成した証明書ファイルの内容は openssl x509 コマンドで確認できます。

$ openssl x509 -in cert.pem -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 0 (0x0)
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN=blog.keshi.org
        Validity
            Not Before: Jan  1 00:00:00 1950 GMT
            Not After : Dec 31 23:59:59 2049 GMT
        Subject: CN=blog.keshi.org
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:e6:6a:3c:02:e5:9b:8a:2a:a5:43:61:fb:bc:26:
                    c2:94:7e:f4:10:a4:ff:d0:c3:10:e9:a9:26:88:85:
                    26:fb:8d:ec:94:d6:59:86:c9:e7:c5:b6:50:1b:4a:
                    9f:90:ba:c9:ea:62:b6:4e:ad:67:94:cf:18:cd:2c:
                    0c:03:30:38:ac:7a:30:6e:77:02:6d:ba:1c:d0:c6:
                    8d:00:5d:b2:4a:fd:7d:85:ae:9c:eb:1d:51:3b:c2:
                    a9:31:76:80:88:4b:ef:db:52:76:11:6a:da:85:96:
                    73:9c:2e:2a:3e:fc:f4:75:10:c4:cf:c1:b5:08:55:
                    3f:0a:56:dd:08:ec:98:70:5c:9c:09:d9:c5:91:81:
                    80:0b:ee:91:90:ed:41:69:17:46:36:2d:f0:04:2a:
                    6a:66:6d:b0:1e:2c:01:54:e6:8e:ae:4f:ef:28:51:
                    2a:38:81:f9:7c:8f:f9:bf:a2:d7:ee:0b:c4:13:bb:
                    1b:b1:54:4d:f6:81:d1:45:11:23:72:35:13:27:f8:
                    cd:06:ae:4e:a1:de:9e:9d:5b:67:bb:b8:fd:11:16:
                    8c:e0:7d:b7:1d:cc:94:73:59:3f:d4:44:1a:93:c2:
                    eb:35:63:10:5d:67:1b:b9:ec:60:41:8b:a8:49:1b:
                    6a:61:75:61:f0:69:78:04:05:1f:e0:a5:fe:68:8c:
                    af:9b
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: 
                CA:FALSE
    Signature Algorithm: sha256WithRSAEncryption
         d2:d6:ce:cf:fd:00:a6:f8:81:10:f7:6c:7c:43:75:46:3d:30:
         db:82:51:6b:08:74:0a:7d:13:5e:1d:5b:e3:f4:e5:0f:b7:53:
         cc:fa:87:ea:e8:a5:2b:c2:7e:40:3c:a6:73:6c:08:ff:65:be:
         c2:8a:f1:11:6d:92:17:48:35:88:6b:53:24:76:b8:62:04:16:
         cb:d6:df:d6:47:81:1e:db:3e:58:ab:31:3b:fb:f6:ba:57:4e:
         71:33:30:0f:06:6d:1c:58:86:9e:b2:aa:72:76:ef:6a:63:cf:
         f1:48:5e:8c:41:72:02:15:2c:81:f6:0a:47:6c:90:0f:74:4d:
         14:32:a3:2d:c0:81:dd:b0:5e:96:8f:9d:6e:a5:3d:53:f7:dd:
         04:12:81:75:81:08:b3:01:1a:6f:64:92:30:b9:7b:a2:85:84:
         0b:6a:75:cc:99:38:21:81:a1:ce:58:08:1e:e9:bf:49:dc:d4:
         6c:69:5b:4a:55:ee:ff:dc:0a:0a:fb:c8:6c:04:17:61:9a:39:
         1b:3f:b4:1b:47:b4:7e:0b:a3:20:65:aa:af:40:c5:c5:b2:4d:
         f7:87:fe:1f:3f:4f:7b:84:e9:f7:97:82:81:3c:d9:ae:66:c0:
         a8:83:2c:fb:96:aa:13:bf:38:de:60:91:00:2c:ec:d4:85:36:
         be:e8:85:1d

以下、スクリプトの説明:

自己署名証明書を生成するだけなら openssl req コマンド-x509 オプションを使えば 1 行でできるのですが、 req では -days オプションで有効期限の終わりを指定することしかできません。 それが不満でこのスクリプトを作りました。

有効期限の始まりと終わりに任意の時刻を指定可能にするには -startdate/-enddate オプションを備える openssl ca コマンド を使う必要があります。 ca では事前に設定ファイルや出力用ディレクトリを準備する必要があるため だいぶ面倒なスクリプトになりました。

すでにお気づきかと思いますが -startdate/-enddate オプションが受け付ける時刻は 西暦 2 桁の YYMMDDHHMMSSZ の形式であるため、 1950年1月1日00:00:00+0000 から 2049年12月31日23:59:59+0000 までの 100 年有効な証明書しか作れません。 これは両オプションの引数が ASN.1 の UTCTime に準拠しているためです。

その一方で -days オプションを使えば、 終了時刻が 2050年以降の証明書を作ることが可能です。 この場合は GeneralizedTime が証明書に埋め込まれることになります。 GeneralizedTime を使えば西暦 1 年から 9999 年までの 9999 年間有効な証明書が作れるはずです。

しかしながら、そのような証明書を作ることは OpenSSL コマンドラインツールではどうやら無理そうです。 OpenSSL ライブラリ自体には問題はないようなので、 自分の好きな SSL 証明書を作りたければ もっとまともなフロントエンドツールないし別のソフトを使うべきということなのでしょう。

GnuTLS で 8030 年間有効な証明書を作る

そこで他のソフトに目を向けたところ GnuTLS では certtool コマンドactivation_date/expiration_date という設定が存在することがわかったので、 これを利用した make-self-signed-cert-gnutls.sh を書きました。

$ sudo apt-get install gnutls-bin
$ wget https://gist.githubusercontent.com/yaegashi/fafef425fc2080b2ced4/raw/7b56f2fb1b95d1e5049dfc0296e2f24e1f6739f3/make-self-signed-cert-gnutls.sh
$ chmod +x ./make-self-signed-cert-gnutls.sh
$ ./make-self-signed-cert-gnutls.sh 
Usage: ./make-self-signed-cert-gnutls.sh <common name> <output> [<start> <end>]

certtool コマンドを利用しますので Debian/Ubuntu では gnutls-bin パッケージを事前にインストールしてください。 ただし activation_date/expiration_date オプションが追加されたのは GnuTLS 3.2.7 からなので、 Debian では jessie 以降、 Ubuntu では utopic 以降である必要があります。

make-self-signed-cert-openssl.sh とは異なり 有効期限は <start> 引数と <end> 引数で直接指定します (GNU date コマンドと同じ書式が使えます)。 ということで 9999 年間有効な SSL 証明書を作ろうとしてみたのですが…

$ ./make-self-signed-cert-gnutls.sh blog.keshi.org hoge.pem "0001-01-01 00:00:00 +0000" "9999-12-31 23:59:59 +0000"
Generating a 2432 bit RSA private key...
Generating a self signed certificate...
X.509 Certificate Information:
	Version: 3
	Serial Number (hex): 54cd3fd6
	Validity:
		Not Before: Thu Jan 01 00:00:00 UTC 1970
		Not After: Fri Dec 31 23:59:59 UTC 9999
	Subject: CN=blog.keshi.org
	Subject Public Key Algorithm: RSA
	Algorithm Security Level: Normal (2432 bits)
		Modulus (bits 2432):
			00:b5:3a:16:ba:b6:12:5b:29:0d:bd:63:db:c8:39:28
			ce:f0:ca:b9:55:60:28:5a:d3:4e:f7:27:18:9d:f7:c6
			31:e4:ca:e0:f6:96:ff:eb:35:f6:83:25:6f:7b:21:08
			6d:a3:06:b6:9b:0e:67:60:bd:7e:49:a2:cc:1f:06:b0
			71:ec:c1:37:2c:f8:b1:cc:a3:03:03:f2:b3:92:af:7d
			66:37:c5:39:13:c8:c1:cb:0d:f1:f5:e8:5a:19:24:48
			29:b5:de:1b:1c:bd:55:5b:92:03:5e:d0:66:a2:dc:81
			49:a0:e6:b7:45:87:38:3d:8d:ba:51:e4:48:d9:87:b1
			f8:ca:37:f5:0f:14:0c:c2:5f:be:10:c3:55:8d:f9:a3
			b0:82:ad:df:81:af:53:ba:11:92:e0:b2:c2:bb:e1:9d
			c4:aa:fa:44:69:bc:5b:c3:82:f5:2a:72:5a:38:dc:b0
			cf:ee:20:e2:e6:c8:c5:40:90:ca:70:78:64:0b:d7:77
			d2:9f:dd:d3:cc:3b:60:d8:c3:1a:45:bb:eb:3d:20:c4
			5a:2c:15:b2:f4:71:42:c4:3b:b1:0d:3a:a0:a9:00:76
			a2:bb:34:69:fa:d8:b1:f2:f3:46:24:b8:36:ec:3d:85
			ce:4d:8b:67:82:08:36:2c:e5:55:d9:d3:d3:32:8d:78
			86:cd:ea:32:f3:95:11:93:92:b1:97:60:62:9d:2e:90
			5e:e8:4b:72:8e:b5:9e:44:a5:69:77:57:7e:59:ff:66
			d1:57:9f:b5:f0:b9:ff:1d:0c:55:80:0b:46:52:6a:34
			77
		Exponent (bits 24):
			01:00:01
	Extensions:
		Basic Constraints (critical):
			Certificate Authority (CA): FALSE
		Subject Key Identifier (not critical):
			a2ca4ee377b0b38cf149e04494a16e33b2132a6a
Other Information:
	Public Key ID:
		a2ca4ee377b0b38cf149e04494a16e33b2132a6a
	Public key's random art:
		+--[ RSA 2432]----+
		|  oo             |
		| o.              |
		|. .              |
		|..               |
		|o=o   . S        |
		|+=o... .         |
		|= = oo           |
		|oE O+..          |
		|o.*.=+           |
		+-----------------+



Signing certificate...

残念ながら 1970年1月1日00:00:00+0000 (Unix エポック) 開始の証明書しか作れませんでした。

GnuTLS の API を見ると gnutls_x509_crt_set_activation_time()gnutls_x509_crt_set_expiration_time() などで time_t を使って時刻をセットするようになっており、どうやらこれが仕様のようです。 ついでにいうと 32bit アーキテクチャでは time_t が 32bit のため 2038 年までの証明書しかつくることができませんでした。

おわりに

OpenSSL と GnuTLS の標準フロントエンドツールで 9999 年間有効な証明書を作ろうとしたけど、結局駄目だったというお話でした。 今のところ最高で 1950 年開始の SSL 証明書しか作れていません。

OpenSSL ライブラリであればそれより前の開始時刻にも対応していると思うので 自分でツールを書けば作れるのでしょうが、 そんな時間もないのでここらで終わりにしたいと思います。

2015/02/01 07:51:00 JST