Amazon SES + mailx で「Error in certificate: Peer's certificate issuer is not recognized.」が出た時の対処法

# １．前書き
Amazon SESとmailxでメール送信できる仕組みを作ったのですが、
メール送信のたびに「Error in certificate: Peer's certificate issuer is not recognized.」が出力していました。
メール送信自体は成功しているので問題は無いのかもしれませんが、エラーが出たままなのは精神衛生上よろしくないので、四苦八苦しながら対処しました。

これは、その時の対処法を記載しています。

# ２．環境
- Centos7.6
- mailx-12.5-19

### 前提
 - Amazon SES には送信元メールアドレス登録＆承認済み
 - mailx はインストール済み
 - ~/.mailrc には以下のように設定

```bash:~/.mailrc
set smtp-use-starttls
set smtp=smtp://email-smtp.us-east-1.amazonaws.com:587
set smtp-auth=login
set smtp-auth-user=<Access key ID>
set smtp-auth-password=<Secret access key>
set ssl-verify=ignore
set nss-config-dir=/etc/pki/nssdb/
set from=<From Mail Address>
```
# ３．調査
### エラーが出るタイミング
`mail -v` で確認したところ、Amazon SESのメールサーバへTLS通信を開始した際に出力されているようです。

``` 
>>> STARTTLS
220 Ready to start TLS
Error in certificate: Peer's certificate issuer is not recognized.  --★
Comparing DNS name: "email-smtp.us-east-1.amazonaws.com"
SSL parameters: cipher=AES-256-GCM, keysize=256, secretkeysize=256,
issuer=CN=Amazon,OU=Server CA 1B,O=Amazon,C=US
subject=CN=email-smtp.us-east-1.amazonaws.com
```
Google翻訳にかけると、「Error in certificate: Peer's certificate issuer is not recognized.(証明書のエラー：ピアの証明書発行者が認識されません。)」って言っているので、怪しいのは証明書のよう。
`~/.mailrc`でも指定した、証明書のデータベース`/etc/pki/nssdb/`を確認してみます。

```
$ sudo certutil -L -d /etc/pki/nssdb/

Certificate Nickname                                         Trust Attributes
                                                             SSL,S/MIME,JAR/XPI
```
何も入っていませんでした。
指定した証明書のデータベースに証明書が無いために起こったエラーだったことが判ります。

# ４．対処
Amazonの証明書をインポートして対処します。
## 4-1 Firefox の証明書データベースを流用する場合
Firefoxから取得済みの証明書をインポートする方法が一番手軽だったので、その方法で対処していきます。
※別途Firefoxのインストールと、GUI環境が必要となります。
### 1. Firefox の現在の証明書を確認
Firefox が所持している証明書を確認します。

```
$ certutil -L -d ~/.mozilla/firefox/<xxxxxxxx>.default/

Certificate Nickname                                         Trust Attributes
                                                             SSL,S/MIME,JAR/XPI
```
※Firefoxにも証明書が無い場合、一度FirefoxでAmazonのサイトを閲覧しましょう。
　閲覧後に再度確認すると、「Amazon」の証明書が追加されるはずです。

```
$ certutil -L -d ~/.mozilla/firefox/<xxxxxxxx>.default/

Certificate Nickname                                         Trust Attributes
                                                             SSL,S/MIME,JAR/XPI

Amazon                                                       ,,
```
### 2. Firefox の証明書データベースを流用
新たに証明書データベース用のディレクトリを作成し、そこにFirefoxの証明書データベースをコピーします。

```
$ mkdir -m700 ~/.certs
$ cp -p ~/.mozilla/firefox/<xxxxxxxx>.default/{cert8.db,key3.db,secmod.db} ~/.certs
```
### 3. Amazonの証明書に信頼性を指定する
Firefoxから流用した証明書は信頼性が何も指定されていません。
そのため、証明書をエクスポート→インポートし、インポート時に信頼性の指定を行います。

```
$ certutil -L -n 'Amazon'  -d ~/.certs -a > amazon.cert.asc  # 証明書エクスポート
$ certutil -A -t "C,," -n 'Amazon'  -d ~/.certs -i amazon.cert.asc  # 信頼性を指定して証明書インポート
```
こうすることで、「Trust Attributes」の項目が`C,,`[^1]に変更されます。

```
$ certutil -L -d ~/.certs/

Certificate Nickname                                         Trust Attributes
                                                             SSL,S/MIME,JAR/XPI

Amazon                                                       C,,
```
## 4-2 直接ルート証明書をインポートする場合
えー、FirefoxもGUI環境も用意しなきゃならないの？　という場合は、直接証明書をインポートする方法があります。

### 1. 新規の証明書データベース格納ディレクトリを作成する

```
$ mkdir -m700 ~/.certs
$ certutil -N -d ~/.certs
Enter a password which will be used to encrypt your keys.
The password should be at least 8 characters long,
and should contain at least one non-alphabetic character.

Enter new password: <空エンター>
Re-enter password: <空エンター>
```
### 2. Amazonからルート証明書をダウンロードする
[こちら](https://www.amazontrust.com/repository/)からルート証明書を入手します。

```
$ wget https://www.amazontrust.com/repository/AmazonRootCA1.pem
$ mv AmazonRootCA1.pem ~/.certs/
```
### 3. 入手したルート証明書をインポートする
「Trust Attributes」の項目を`C,,`[^1]の形でインポートします。

```
$ certutil -A -n "Amazon" -t "C,," -d ~/.certs -i ~/.certs/AmazonRootCA1.pem -a
$ certutil -L -d ~/.certs/

Certificate Nickname                                         Trust Attributes
                                                             SSL,S/MIME,JAR/XPI

Amazon                                                       C,,
```
# ５．確認
上記の対処が完了したら`.mailrc`の設定を変更して、メールを送信してみましょう。


```bash:~/.mailrc
set nss-config-dir=/etc/pki/nssdb/
  ↓
set nss-config-dir=~/.certs/
```
```
$ echo -e "test mail" | mail -v -s "test mail title" -r "<From Mail Address>" "<To Mail Address>"
~~
>>> STARTTLS
220 Ready to start TLS
Comparing DNS name: "email-smtp.us-east-1.amazonaws.com"
SSL parameters: cipher=AES-256-GCM, keysize=256, secretkeysize=256,
issuer=CN=Amazon,OU=Server CA 1B,O=Amazon,C=US
subject=CN=email-smtp.us-east-1.amazonaws.com
~~
```
「Error in certificate: Peer's certificate issuer is not recognized.」が出力されなければ対処完了です。

# ６．まとめ
以上、対処法でした。
TLS通信における証明書の役割など、まだぼんやりとしか理解してないので、今後の課題になりそうです。
ですが、エラーが解決できると気持ちいいですね。

# 以下、参考にさせて頂いたサイト
[Linuxからプロセスの動作状況をスマホに通知する](https://ark-n.hatenablog.com/entry/2017/06/18/230154)
[certutilによる証明書管理 [Fedora14]](http://www.nina.jp/server/redhat/certutil/certutil.html)
[^1]: `C`は「サーバ証明書発行元として信頼しているCAの証明書」を示す。