git clone https:// 時の証明書エラー

HTTPSGitHub から clone しようとしたら証明書のエラーになる。

git clone --depth=1 https://github.com.example.com/repo.git
Cloning into 'repo'...
fatal: unable to access 'https://github.com.example.com/repo.git/': SSL certificate problem, verify that the CA cert is OK. Details:

メンテが微妙な共有サーバで cacert.pem が10年物で使い物にならない。それで仕方なくローカルに置いていたが、また古くなっているのかもしれない。
検索すると検証をオフにする話がよくヒットする。確かに GitHub に限っては ブラウザで commit ID を読めるので証明書の検証をオフにしても改竄は見つけられるが、それならば git プロトコルで clone したほうが楽そうだ。
そんなわけで今回検証を無効にせずに手探りで HTTPS のまま解決してみた。

解決法

http://curl.haxx.se/ca/cacert.pem
をダウンロードして git config の http.sslCAInfo に設定すればよい

git config --global http.sslCAInfo /path/to/cacert.pem

但し、libcurlが古いとgithub.comへTLS接続ができないのでそちらも更新する必要がある。

解決までの詳細

とりあえず認証局証明書を更新してみる。

wget http://curl.haxx.se/ca/cacert.pem -O $SSL_CERT_FILE.new
diff -U0 $SSL_CERT_FILE $SSL_CERT_FILE.new | less
mv $SSL_CERT_FILE.new $SSL_CERT_FILE

更新したのだが出力は変わらず。SSL_CERT_FILE を参照していないのか。git のドキュメントによると GIT_CURL_VERBOSE で詳しいエラーが出るらしい。

GIT_CURL_VERBOSE=1 git clone --depth=1 https://github.com.example.com/repo.git
Cloning into 'repo'...
* Couldn't find host github.com in the .netrc file, using defaults
* About to connect() to github.com port 443 (#0)
*   Trying 192.30.252.128... * Connected to github.com (192.30.252.128) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: /usr/local/share/curl/curl-ca-bundle.crt
  CApath: none
* SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
* Expire cleared
* Connection #0 to host github.com left intact
fatal: unable to access 'https://github.com.example.com/repo.git/': SSL certificate problem, verify that the CA cert is OK. Details:
error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

curlSSL_CERT_FILE を参照しないようだ。curlCURL_CA_BUNDLE を見るが、ヘルプによると git ではそれとは別に http.sslCAInfoGIT_SSL_CERTで設定するようだ。

git config --global http.sslCAInfo $SSL_CERT_FILE
GIT_CURL_VERBOSE=1 git clone --depth=1 https://github.com.example.com/repo.git
Cloning into 'repo'...
* Couldn't find host github.com in the .netrc file, using defaults
* About to connect() to github.com port 443 (#0)
*   Trying 192.30.252.130... * Connected to github.com (192.30.252.130) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: $SSL_CERT_FILE
  CApath: none
* error:0D0890A1:asn1 encoding routines:ASN1_verify:unknown message digest algorithm
* Expire cleared
* Connection #0 to host github.com left intact
fatal: unable to access 'https://github.com.example.com/repo.git/': error:0D0890A1:asn1 encoding routines:ASN1_verify:unknown message digest algorithm

証明書は通ったがハッシュアルゴリズムが未知と出る。

openssl s_client -trace -connect github.com:443 -verbose
...
SSL-Session:
    Protocol  : TLSv1.2
    Cipher    : ECDHE-RSA-AES128-GCM-SHA256
...
^C

openssl コマンドではネゴシエートでき繋がる。
なので cURL をなんとかすればよさそうな雰囲気だ。関係しそうなのは http.sslCipherList (GIT_SSL_CIPHER_LIST) だが、CURLOPT_SSL_CIPHER_LIST の説明を見て適当に指定してみてもメッセージが変わらない。

仕方がないのでこの8年前の cURL を使うのは諦めてビルドし直すことにした。root 権がないので --prefix を指定する。

./configure -C --prefix=$myBase --with-libidn --with-ca-bundle=$SSL_CERT_FILE
make install

これで curl コマンドは使えるが git 側が古い libiconv を使っていて、libcurl ではローカルの最新版を使ってしまい libiconv のミスマッチが起きた (Undefined symbol "locale_charset"と出る) ので git もビルドしなおす。

./configure -C --prefix=$myBase --with-libpcre

そのままでは make できず、MakefileCURL_LIBCURL-lcharset を追加して CURLDIR=$myBase make all した。(親切にも Makefile にヒントが書いてある。)

GIT_CURL_VERBOSE=1 git clone --depth=1 https://github.com.example.com/repo.git   Cloning into 'repo'...
Cloning into 'repo'...
* Couldn't find host github.com in the .netrc file; using defaults
*   Trying 192.30.252.129...
* Connected to github.com (192.30.252.129) port 443 (#0)
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: $SSL_CERT_FILE
  CApath: none
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
...

うっかり GIT_CURL_VERBOSE=1 のまま実行してしまって出力が大量になった。しかしようやく clone に成功した。

この共有サーバは PHPApache を近年バージョンアップするようになってまだ使えるかと思っていたのだが、基盤となるライブラリが古いままなので最近それらをリビルドするケースが増えてきた。
あまり手間が増えるようなら移ったほうがいいかもしれない。