OpenSSL の使い方練習

## 参考

* とてもわかり易いサイト
    * https://qiita.com/kunichiko/items/12cbccaadcbf41c72735
    * https://qiita.com/kunichiko/items/3c0b1a2915e9dacbd4c1
* OpenSSL Cookbook (必読)
    * https://www.feistyduck.com/library/openssl-cookbook/
    * 日本語版: https://www.lambdanote.com/products/openssl

## 用語

* DER format とは? ASN.1 バイナリ形式
* PEM format とは? ASN.1 の Base64 --BEGIN から始まる。

## この練習で使うファイル

* private-key.pem: 秘密鍵
* public-key.pem: 公開鍵
* request.csr: 証明書署名要求
* public-key.crt: 証明書 (最初オレオレ証明書を作って後で他の証明書でサインする)
* root-ca/root-ca.crt: ルート証明書
* private/root-ca.key: ルート証明書用の秘密鍵
* short.txt: 短いテキスト
* short.rsaenc: rsautl で暗号化したもの
* short.rsasig: rsautl で作った署名
* long.txt: 長いテキスト
* long.dgst: dgst で作った署名
* long.der: smime pkcs7 で作った署名

## オレオレ証明書を作る

RSA 秘密鍵の生成 (genrsa は古い):　-> private-key.pem

(`-aes-128-cbc` をつけるとパスフレーズを設定できる。)

    openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -aes-128-cbc > private-key.pem
    
RSA 秘密鍵の中身を見る

    openssl pkey -text -noout < private-key.pem

RSA公開鍵の生成: private-key.pem -> public-key.pem

    openssl pkey -pubout < private-key.pem > public-key.pem

RSA 公開鍵の中身を見る

    openssl pkey -text -noout -pubin < public-key.pem

証明書署名要求(CSR) の作成: private-key.pem -> request.csr

    openssl req -new -key private-key.pem > request.csr

証明書署名要求(CSR) の中身を見る

    openssl req -text -noout < request.csr 

オレオレ証明書(署名付き公開鍵)の作成: request.csr, private-key.pem -> public-key.crt

    openssl x509 -req -days 36500 -signkey private-key.pem < request.csr > public-key.crt

証明書の中を中身を見る -noout 無しだと PEM 形式証明書が末尾に付く。

    openssl x509 -text -noout < public-key.crt

証明書から公開鍵を取り出す: public-key.crt -> public-key.pem と同じ物が出る。(ここまでOK)

    openssl x509 -pubkey -noout < public-key.crt


## dgst を使ったハッシュ値の取得と署名

openssl dgst ではハッシュ値の取得と署名検証を行えます。デフォルトで SHA256 が選ばれます。

単純にハッシュ値を得る。

    openssl dgst long.txt
    SHA256(long.txt)= 497ea784506cfa79fa4a4eff25bc7fb4fd907040f23e7e095f71f405633e80c3

秘密鍵で long.txt を署名する: private-key.pem, long.txt -> long.dgst

    openssl dgst -sign private-key.pem long.txt > long.dgst

long.txt と署名を公開鍵で検証する: public-key.pem, long.dgst, long.txt -> 成功失敗

    openssl dgst -verify public-key.pem -signature long.dgst long.txt

## rsautl を使った署名、検証、暗号、復号

openssl rsautl では RSA を使った署名、検証、暗号、復号が行えます。ただあまり長いデータは使えません。RSA の勉強にはなりますが実用途は無いと思います。

公開鍵で short.txt を暗号化する: public-key.pem, short.txt -> short.encrypted

    openssl rsautl -encrypt -pubin -inkey public-key.pem < short.txt > short.rsaenc

秘密鍵で復号する: private-key.pem, short.rsaenc -> short.txt と同じ物が出る。

    openssl rsautl -decrypt -inkey private-key.pem < short.rsaenc

秘密鍵で short.txt を署名する: private-key.pem, long.txt -> long.dgst

    openssl rsautl -sign -inkey private-key.pem < short.txt > short.rsasig

公開鍵で署名を検証する:public-key.pem, short.rsasig -> short.txt と同じ物が出る。

    openssl rsautl -verify -pubin -inkey public-key.pem < short.rsasig

## Root CA (ルート認証局) を作る

ディレクトリ構成を作る。

```
mkdir root-ca
cd root-ca
mkdir certs db private
chmod 700 private
touch db/index
openssl rand -hex 16  > db/serial
echo 1001 > db/crlnumber
```

https://www.feistyduck.com/library/openssl-cookbook/online/openssl-command-line/private-ca-creating-root.html を参考に設定ファイル root-ca/ に root-ca.conf を作る。

証明書署名要求(CSR) の作成: -> root-ca.csr, private/root-ca.key

    openssl req -new  -config root-ca.conf -out root-ca.csr -keyout private/root-ca.key

オレオレ証明書の作成: root-ca.csr -> root-ca.crt

root-ca.conf 内の ca_ext セクション `critical,CA:true` で、この証明書が CA である事を示す。

    openssl ca -selfsign -config root-ca.conf -in root-ca.csr -out root-ca.crt -extensions ca_ext

CRL (失効リスト) の作成

    openssl ca -gencrl -config root-ca.conf -out root-ca.crl

## Root CA (ルート認証局) で 証明書署名要求(CSR) を署名する

いよいよここで証明書を作るが、ちょっと趣向を凝らして S/MIME の署名と暗号ができる証明書を作ってみる。

[x509(1)](https://www.openssl.org/docs/man1.1.1/man1/x509.html) の S/MIME Signing, Encryption の項目によると S/MIME を有効にするには次のような妙な条件を満たす必要がある。

* S/MIME Signing には Common S/MIME client tests が有効で keyUsage の digitalSignature が有効である必要がある。
* S/MIME Encryption には Common S/MIME client tests が有効で keyUsage の keyEncipherment が有効である必要がある。
* Common S/MIME client test には extendedKeyUsage の emailProtection が有効である必要がある。

これに対応する設定ファイル `root-ca.conf` の項目 `[sub_ca_ext]` は次のようになる。

```
[sub_ca_ext]
...
extendedKeyUsage        = clientAuth,serverAuth,emailProtection
keyUsage                = critical,keyCertSign,cRLSign,digitalSignature,keyEncipherment
```

ついでに、サンプルのままだとルート証明書と同じ国名の証明書しか署名できないので、制限を緩めるために `[policy_c_o_match]` の項目を編集する。

```
countryName             = supplied
```

設定ファイルの `[sub_ca_ext]` の利用用途に `emailProtection` を追加する。これで S/MIME 用の証明書を作れる。詳しくは [x509v3_config(5)](https://www.openssl.org/docs/man1.1.1/man5/x509v3_config.html)。

    extendedKeyUsage        = clientAuth,serverAuth,emailProtection

ついに証明書の発行。例えば最初に作った `request.csr` を署名してみる。設定ファイルは `-config root-ca.conf` として、extension (利用用途)の設定は `-extensions [sub_ca_ext]` として指定する。

    openssl ca -config root-ca.conf -in ../request.csr -out ../public-key.crt -extensions sub_ca_ext

* OCSP とは? 証明書の失効情報を伝えるプロトコルらしい: https://www.openssl.org/docs/man1.1.1/man1/ocsp.html
* 参考: config ファイルの説明がわかりやすい: https://qiita.com/3244/items/780469306a3c3051c9fe

`openssl x509 -text` の `-purpose` オプションで `S/MIME signing : Yes` `S/MIME encryption : Yes` の行が出たら完成！

```
openssl x509 -text -noout -purpose < ../public-key.crt
...
S/MIME signing : Yes
S/MIME encryption : Yes
```

## smime

秘密鍵で long.txt を smime 署名: private-key.pem, long.txt -> long.smime

    cd ..
    openssl smime -sign -text -inkey private-key.pem -signer public-key.crt < long.txt > long.smime

long.txt と long.smime を公開鍵で検証する: public-key.pem, long.smime -> 成功失敗

もしも S/MIME に purpose が設定されていない証明書なら `-purpose any` が必要になる。

    openssl smime -verify -CAfile root-ca/root-ca.crt < long.smime > /dev/null

秘密鍵で long.txt を smime 署名 (PKCS7 DER): private-key.pem, long.txt -> long.der (-binary がトリッキー！！)

    openssl smime -sign -outform der -binary -inkey private-key.pem -signer public-key.crt < long.txt > long.der

long.der の中を見る

    openssl pkcs7 -in long.der -inform DER -print

long.txt と long.der を公開鍵で検証する: public-key.pem, long.der -> 成功失敗

    openssl smime -verify -inform der -CAfile root-ca/root-ca.crt -content long.txt < long.der > /dev/null

## smime (gnutls certtool 利用)

秘密鍵で long.txt を smime 署名 (PKCS7 DER): private-key.pem, long.txt -> long.der

    certtool --p7-detached-sign  --infile=long.txt --load-certificate=public-key.crt --load-privkey=private-key.pem --outder > long.der

long.txt と long.der を公開鍵で検証する: public-key.pem, long.der -> 成功失敗

    certtool --p7-verify --infile=long.der --inder --load-ca-certificate=root-ca/root-ca.crt --load-data=long.txt