2018/10/10

Python 3.5 を Ubuntu 18.04 上でビルドしたらテストが通らなかった

Ubuntu 18.04 で Python 3.5 系の動作確認をするためUbuntu 18.04 のデフォルトは Python 3.6 なので、ソースコードからビルドしてみました。



しかし、以下のように test_alpn_protocols が通りません。

```console
`gutter: false;
$ cd Python-3.5.6
$ ./configure --prefix=${HOME}/opt/python-3.5.6
$ make
$ make test

省略

======================================================================
FAIL: test_alpn_protocols (test.test_ssl.ThreadedTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/yusuke/Downloads/Python-3.5.6/Lib/test/test_ssl.py", line 3183, in test_alpn_protocols
    self.assertIsInstance(stats, ssl.SSLError)
AssertionError: {'client_npn_protocol': None, 'compression': None, 'server_npn_protocols': [None], 'server_alpn_protocols': [None], 'client_alpn_protocol': None, 'version': 'TLSv1.2', 'peercert': {}, 'server_shared_ciphers': [[('ECDHE-ECDSA-AES256-GCM-SHA384', 'TLSv1.2', 256), ('ECDHE-RSA-AES256-GCM-SHA384', 'TLSv1.2', 256), ('ECDHE-ECDSA-AES128-GCM-SHA256', 'TLSv1.2', 128), ('ECDHE-RSA-AES128-GCM-SHA256', 'TLSv1.2', 128), ('ECDHE-ECDSA-CHACHA20-POLY1305', 'TLSv1.2', 256), ('ECDHE-RSA-CHACHA20-POLY1305', 'TLSv1.2', 256), ('DHE-DSS-AES256-GCM-SHA384', 'TLSv1.2', 256), ('DHE-RSA-AES256-GCM-SHA384', 'TLSv1.2', 256), ('DHE-DSS-AES128-GCM-SHA256', 'TLSv1.2', 128), ('DHE-RSA-AES128-GCM-SHA256', 'TLSv1.2', 128), ('DHE-RSA-CHACHA20-POLY1305', 'TLSv1.2', 256), ('ECDHE-ECDSA-AES256-CCM8', 'TLSv1.2', 256), ('ECDHE-ECDSA-AES256-CCM', 'TLSv1.2', 256), ('ECDHE-ECDSA-AES256-SHA384', 'TLSv1.2', 256), ('ECDHE-RSA-AES256-SHA384', 'TLSv1.2', 256), ('ECDHE-ECDSA-AES256-SHA', 'TLSv1.0', 256), ('ECDHE-RSA-AES256-SHA', 'TLSv1.0', 256), ('DHE-RSA-AES256-CCM8', 'TLSv1.2', 256), ('DHE-RSA-AES256-CCM', 'TLSv1.2', 256), ('DHE-RSA-AES256-SHA256', 'TLSv1.2', 256), ('DHE-DSS-AES256-SHA256', 'TLSv1.2', 256), ('DHE-RSA-AES256-SHA', 'SSLv3', 256), ('DHE-DSS-AES256-SHA', 'SSLv3', 256), ('ECDHE-ECDSA-AES128-CCM8', 'TLSv1.2', 128), ('ECDHE-ECDSA-AES128-CCM', 'TLSv1.2', 128), ('ECDHE-ECDSA-AES128-SHA256', 'TLSv1.2', 128), ('ECDHE-RSA-AES128-SHA256', 'TLSv1.2', 128), ('ECDHE-ECDSA-AES128-SHA', 'TLSv1.0', 128), ('ECDHE-RSA-AES128-SHA', 'TLSv1.0', 128), ('DHE-RSA-AES128-CCM8', 'TLSv1.2', 128), ('DHE-RSA-AES128-CCM', 'TLSv1.2', 128), ('DHE-RSA-AES128-SHA256', 'TLSv1.2', 128), ('DHE-DSS-AES128-SHA256', 'TLSv1.2', 128), ('DHE-RSA-AES128-SHA', 'SSLv3', 128), ('DHE-DSS-AES128-SHA', 'SSLv3', 128), ('ECDHE-ECDSA-CAMELLIA256-SHA384', 'TLSv1.2', 256), ('ECDHE-RSA-CAMELLIA256-SHA384', 'TLSv1.2', 256), ('ECDHE-ECDSA-CAMELLIA128-SHA256', 'TLSv1.2', 128), ('ECDHE-RSA-CAMELLIA128-SHA256', 'TLSv1.2', 128), ('DHE-RSA-CAMELLIA256-SHA256', 'TLSv1.2', 256), ('DHE-DSS-CAMELLIA256-SHA256', 'TLSv1.2', 256), ('DHE-RSA-CAMELLIA128-SHA256', 'TLSv1.2', 128), ('DHE-DSS-CAMELLIA128-SHA256', 'TLSv1.2', 128), ('DHE-RSA-CAMELLIA256-SHA', 'SSLv3', 256), ('DHE-DSS-CAMELLIA256-SHA', 'SSLv3', 256), ('DHE-RSA-CAMELLIA128-SHA', 'SSLv3', 128), ('DHE-DSS-CAMELLIA128-SHA', 'SSLv3', 128), ('AES256-GCM-SHA384', 'TLSv1.2', 256), ('AES128-GCM-SHA256', 'TLSv1.2', 128), ('AES256-CCM8', 'TLSv1.2', 256), ('AES256-CCM', 'TLSv1.2', 256), ('AES128-CCM8', 'TLSv1.2', 128), ('AES128-CCM', 'TLSv1.2', 128), ('AES256-SHA256', 'TLSv1.2', 256), ('AES128-SHA256', 'TLSv1.2', 128), ('AES256-SHA', 'SSLv3', 256), ('AES128-SHA', 'SSLv3', 128), ('CAMELLIA256-SHA256', 'TLSv1.2', 256), ('CAMELLIA128-SHA256', 'TLSv1.2', 128), ('CAMELLIA256-SHA', 'SSLv3', 256), ('CAMELLIA128-SHA', 'SSLv3', 128)]], 'cipher': ('ECDHE-RSA-AES256-GCM-SHA384', 'TLSv1.2', 256)} is not an instance of 
```


### 原因
原因は OpenSSL の仕様がバージョン 1.1.0e 以降で変わったことのようです。

> 参考
> 
> [Issue 30714: test_ssl fails with openssl 1.1.0f: test_alpn_protocols() - Python tracker](https://bugs.python.org/issue30714)

私の環境で Open SSL のバージョンを調べてみると 1.1.0g
```console
`gutter: false;
$ openssl version
OpenSSL 1.1.0g  2 Nov 2017
```

上記 Issue は 2.7, 3.6, 3.7 では修正されているものの、3.5 は直されていないようです。

### 対策
3.6 用に入れられた修正を 3.5 にも適用するとテストが通るようになります。

[[3.6] bpo-30714: ALPN changes for OpenSSL 1.1.0f (#3093) · python/cpython@7f6a13b · GitHub](https://github.com/python/cpython/commit/7f6a13bd562ff6a265fc63a991327feaecb07a77)

```diff
--- test_ssl.py.bak 2018-08-02 05:19:12.000000000 -0400
+++ Lib/test/test_ssl.py 2018-10-09 16:07:47.721018740 -0400
@@ -3178,8 +3178,9 @@ else:
                 except ssl.SSLError as e:
                     stats = e
 
-                if expected is None and IS_OPENSSL_1_1:
-                    # OpenSSL 1.1.0 raises handshake error
+                if (expected is None and IS_OPENSSL_1_1
+                        and ssl.OPENSSL_VERSION_INFO < (1, 1, 0, 6)):
+                    # OpenSSL 1.1.0 to 1.1.0e raises handshake error
                     self.assertIsInstance(stats, ssl.SSLError)
                 else:
                     msg = "failed trying %s (s) and %s (c).\n" \
```

```console
`gutter: false;
$ make test

省略

377 tests OK.
21 tests skipped:
    test_bz2 test_dbm_gnu test_dbm_ndbm test_devpoll test_idle
    test_kqueue test_lzma test_msilib test_ossaudiodev test_readline
    test_sqlite test_startfile test_tcl test_tix test_tk
    test_ttk_guionly test_ttk_textonly test_turtle test_winreg
    test_winsound test_zipfile64
Tests result: SUCCESS
```
### 対策 (番外編)
仮想環境を作って、そこに 検証したい環境Ubuntu 16.04 等を完全に再現するのが実は正攻法かもしれません。

しかし Python には virtualenv があるので、そこまでしなくてもという気も。

0 件のコメント: