[squidでhttpsプロキシ] 中間CA証明書をチェインしていないwebサーバへアクセスしたときのエラーを解消する。

# はじめに
sslインターセプトするhttpsプロキシを運用していて、不具合があった点が解消できましたので、記録します。
利用する環境は、前回構築した以下のものです。
**[squidでActiveDirectory連携とSSLインターセプトするProxyをdockerで手軽につくる](https://qiita.com/bashaway/items/6adc75265973de9b5fcc)**

# なにが起こったのか
以下のサイトに接続しようとすると、エラーが発生。
https://learningnetwork.cisco.com/s/

証明書の発行元が不明なためエラーとなっている様子。
うまくチェインがたどれないのであろう。
[![Screenshot from Gyazo](https://gyazo.com/45d64723397bba96bf4c9892086762df/raw)](https://gyazo.com/45d64723397bba96bf4c9892086762df)

# 原因調査

## ログ調査
ログを見ると、squidがサーバ証明書を受け取る際に、不足した中間CA証明書を取得しようとして、DENIEDされている。
そのせいで証明書ベリファイできてない（＝チェーンがたどれない）みたいだ。

```:squid_access.log
 TCP_DENIED/407 4118 CONNECT learningnetwork.cisco.com:443 - HIER_NONE/- text/html
 TCP_DENIED/407 4488 CONNECT learningnetwork.cisco.com:443 - HIER_NONE/- text/html
 NONE/200 0 CONNECT learningnetwork.cisco.com:443 PROSPER2\\USERNAME HIER_NONE/- -
 TCP_DENIED/407 3616 GET http://trust.quovadisglobal.com/hydsslg2.crt - HIER_NONE/- text/html;charset=utf-8
 TCP_MISS/503 7165 GET https://learningnetwork.cisco.com/s/jp-cln PROSPER2\\USERNAME HIER_DIRECT/161.71.178.161 text/html
```

```:squid_cache.log
kid1| ALE missing IDENT
kid1| ERROR: negotiating TLS on FD 23: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed (1/-1/0)
```

squidの4以降では、中間証明書を自動的に取得してくれる機能がついているようなのですが。。。

> Squid-4 is capable of downloading missing intermediate CA certificates, like popular browsers do.

出典：https://wiki.squid-cache.org/ConfigExamples/Intercept/SslBumpExplicit#Missing_intermediate_certificates

ログから確認できた通り、証明書を取得するためのURLへの通信が許可されていないため、うまく動作していないようだ。



## 実際に証明書を取得してみる

### learningnetwork.cisco.comの場合
証明書を取得してみたところ、チェーンがたどれるようにCAの証明書を付けてくれてないみたい。

```sh
#  openssl s_client -connect learningnetwork.cisco.com:443 -showcerts | grep [si]:
depth=0 C = US, ST = California, L = San Jose, O = "Cisco Systems, Inc.", CN = learningnetwork.cisco.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 C = US, ST = California, L = San Jose, O = "Cisco Systems, Inc.", CN = learningnetwork.cisco.com
verify error:num=21:unable to verify the first certificate
verify return:1
 0 s:C = US, ST = California, L = San Jose, O = "Cisco Systems, Inc.", CN = learningnetwork.cisco.com
   i:C = US, O = HydrantID (Avalanche Cloud Corporation), CN = HydrantID SSL ICA G2
```

### cisco.comの場合
こちら側は、ちゃんとチェーンがたどれるようにしてくれてるのに。。。

```sh
#  openssl s_client -connect www.cisco.com:443 -showcerts | grep [si]:
depth=2 C = BM, O = QuoVadis Limited, CN = QuoVadis Root CA 2
verify return:1
depth=1 C = US, O = HydrantID (Avalanche Cloud Corporation), CN = HydrantID SSL ICA G2
verify return:1
depth=0 C = US, ST = California, L = San Jose, O = "Cisco Systems, Inc.", CN = www.cisco.com
verify return:1
 0 s:C = US, ST = California, L = San Jose, O = "Cisco Systems, Inc.", CN = www.cisco.com
   i:C = US, O = HydrantID (Avalanche Cloud Corporation), CN = HydrantID SSL ICA G2
 1 s:C = US, O = HydrantID (Avalanche Cloud Corporation), CN = HydrantID SSL ICA G2
   i:C = BM, O = QuoVadis Limited, CN = QuoVadis Root CA 2
```


# 解決方法

つまり、取得できなかった中間CA証明書が取得できるようになればよい、ということのはず。


## 解決方法その１

ホワイトリストに中間証明書を取得するURLを追加する。

```:whitelist
^(https*://)*([^/][^/]*\.)*quovadisglobal\.com(:443|:80)*(/.*)*$
```



## 解決方法その２

squidのサーバに欠落対象となる中間CA証明書を保管しておいて、外部の中間CAとしてその証明書を指定する。
squidはDERの証明書が利用できないぽい（？）ので、PEMにして保管します。

```
# curl -L http://trust.quovadisglobal.com/hydsslg2.crt --output - | openssl x509 -inform DER > /etc/squid/certs/ca3rd/hydsslg2.crt
```

`squid.conf` で取得した証明書を指定します。

```:squid.conf
sslproxy_foreign_intermediate_certs /etc/squid/certs/ca3rd/hydsslg2.crt
```

これでうまく見れるようになった。

[![Screenshot from Gyazo](https://gyazo.com/d6fdbada60ba77e4c86baad4c2e8f80d/raw)](https://gyazo.com/d6fdbada60ba77e4c86baad4c2e8f80d)

# 出典
以下の参考にさせていただきました。
[opensslコマンドの使い方](https://qiita.com/hana_shin/items/6d9de0847a06d8ee95cc)
https://wiki.squid-cache.org/ConfigExamples/Intercept/SslBumpExplicit