diff --git a/SOURCES/00316-mark-bdist_wininst-unsupported.patch b/SOURCES/00316-mark-bdist_wininst-unsupported.patch new file mode 100644 index 0000000..c091be0 --- /dev/null +++ b/SOURCES/00316-mark-bdist_wininst-unsupported.patch @@ -0,0 +1,14 @@ +diff --git a/Lib/distutils/command/bdist_wininst.py b/Lib/distutils/command/bdist_wininst.py +index fde5675..15434c3 100644 +--- a/Lib/distutils/command/bdist_wininst.py ++++ b/Lib/distutils/command/bdist_wininst.py +@@ -55,6 +55,9 @@ class bdist_wininst(Command): + boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize', + 'skip-build'] + ++ # bpo-10945: bdist_wininst requires mbcs encoding only available on Windows ++ _unsupported = (sys.platform != "win32") ++ + def initialize_options(self): + self.bdist_dir = None + self.plat_name = None diff --git a/SOURCES/00318-fixes-for-tls-13.patch b/SOURCES/00318-fixes-for-tls-13.patch new file mode 100644 index 0000000..8f4a1b0 --- /dev/null +++ b/SOURCES/00318-fixes-for-tls-13.patch @@ -0,0 +1,949 @@ +From 412ccf4c6f8c417006c0a93392a8274a425074c0 Mon Sep 17 00:00:00 2001 +From: Victor Stinner +Date: Wed, 29 May 2019 04:04:54 +0200 +Subject: [PATCH 1/5] bpo-32947: test_ssl fixes for TLS 1.3 and OpenSSL 1.1.1 + (GH-11612) + +Backport partially commit 529525fb5a8fd9b96ab4021311a598c77588b918: +complete the previous partial backport (commit +2a4ee8aa01d61b6a9c8e9c65c211e61bdb471826. + +Co-Authored-By: Christian Heimes +--- + Lib/test/test_ssl.py | 15 +++++++++++++++ + .../2019-01-18-17-46-10.bpo-32947.Hk0KnM.rst | 1 + + 2 files changed, 16 insertions(+) + create mode 100644 Misc/NEWS.d/next/Tests/2019-01-18-17-46-10.bpo-32947.Hk0KnM.rst + +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +index cb0acda..639109f 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -2043,6 +2043,16 @@ if _have_threads: + sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n" + % (msg, ctype, msg.lower(), ctype)) + self.write(msg.lower()) ++ except ConnectionResetError: ++ # XXX: OpenSSL 1.1.1 sometimes raises ConnectionResetError ++ # when connection is not shut down gracefully. ++ if self.server.chatty and support.verbose: ++ sys.stdout.write( ++ " Connection reset by peer: {}\n".format( ++ self.addr) ++ ) ++ self.close() ++ self.running = False + except OSError: + if self.server.chatty: + handle_error("Test server failure:\n") +@@ -2122,6 +2132,11 @@ if _have_threads: + pass + except KeyboardInterrupt: + self.stop() ++ except BaseException as e: ++ if support.verbose and self.chatty: ++ sys.stdout.write( ++ ' connection handling failed: ' + repr(e) + '\n') ++ + self.sock.close() + + def stop(self): +diff --git a/Misc/NEWS.d/next/Tests/2019-01-18-17-46-10.bpo-32947.Hk0KnM.rst b/Misc/NEWS.d/next/Tests/2019-01-18-17-46-10.bpo-32947.Hk0KnM.rst +new file mode 100644 +index 0000000..f508504 +--- /dev/null ++++ b/Misc/NEWS.d/next/Tests/2019-01-18-17-46-10.bpo-32947.Hk0KnM.rst +@@ -0,0 +1 @@ ++test_ssl fixes for TLS 1.3 and OpenSSL 1.1.1. +-- +2.21.0 + + +From 6b728ec778067849dd1f0d9b73cf1ac47dafa270 Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Wed, 25 Sep 2019 09:12:59 -0700 +Subject: [PATCH 2/5] bpo-38271: encrypt private key test files with AES256 + (GH-16385) + +The private keys for test_ssl were encrypted with 3DES in traditional +PKCSGH-5 format. 3DES and the digest algorithm of PKCSGH-5 are blocked by +some strict crypto policies. Use PKCSGH-8 format with AES256 encryption +instead. + +Signed-off-by: Christian Heimes + +https://bugs.python.org/issue38271 + +Automerge-Triggered-By: @tiran +(cherry picked from commit bfd0c963d88f3df69489ee250655e2b8f3d235bd) + +Co-authored-by: Christian Heimes +--- + Lib/test/keycert.passwd.pem | 85 ++++++++++--------- + Lib/test/make_ssl_certs.py | 4 +- + Lib/test/ssl_key.passwd.pem | 84 +++++++++--------- + .../2019-09-25-13-11-29.bpo-38271.iHXNIg.rst | 4 + + 4 files changed, 91 insertions(+), 86 deletions(-) + create mode 100644 Misc/NEWS.d/next/Tests/2019-09-25-13-11-29.bpo-38271.iHXNIg.rst + +diff --git a/Lib/test/keycert.passwd.pem b/Lib/test/keycert.passwd.pem +index cbb3c3b..c330c36 100644 +--- a/Lib/test/keycert.passwd.pem ++++ b/Lib/test/keycert.passwd.pem +@@ -1,45 +1,45 @@ +------BEGIN RSA PRIVATE KEY----- +-Proc-Type: 4,ENCRYPTED +-DEK-Info: DES-EDE3-CBC,D134E931C96D9DEC +- +-nuGFEej7vIjkYWSMz5OJeVTNntDRQi6ZM4DBm3g8T7i/0odr3WFqGMMKZcIhLYQf +-rgRq7RSKtrJ1y5taVucMV+EuCjyfzDo0TsYt+ZrXv/D08eZhjRmkhoHnGVF0TqQm +-nQEXM/ERT4J2RM78dnG+homMkI76qOqxgGbRqQqJo6AiVRcAZ45y8s96bru2TAB8 +-+pWjO/v0Je7AFVdwSU52N8OOY6uoSAygW+0UY1WVxbVGJF2XfRsNpPX+YQHYl6e+ +-3xM5XBVCgr6kmdAyub5qUJ38X3TpdVGoR0i+CVS9GTr2pSRib1zURAeeHnlqiUZM +-4m0Gn9s72nJevU1wxED8pwOhR8fnHEmMKGD2HPhKoOCbzDhwwBZO27TNa1uWeM3f +-M5oixKDi2PqMn3y2cDx1NjJtP661688EcJ5a2Ih9BgO9xpnhSyzBWEKcAn0tJB0H +-/56M0FW6cdOOIzMveGGL7sHW5E+iOdI1n5e7C6KJUzew78Y9qJnhS53EdI6qTz9R +-wsIsj1i070Fk6RbPo6zpLlF6w7Zj8GlZaZA7OZZv9wo5VEV/0ST8gmiiBOBc4C6Y +-u9hyLIIu4dFEBKyQHRvBnQSLNpKx6or1OGFDVBay2In9Yh2BHh1+vOj/OIz/wq48 +-EHOIV27fRJxLu4jeK5LIGDhuPnMJ8AJYQ0bQOUP6fd7p+TxWkAQZPB/Dx/cs3hxr +-nFEdzx+eO+IAsObx/b1EGZyEJyETBslu4GwYX7/KK3HsJhDJ1bdZ//28jOCaoir6 +-ZOMT72GRwmVoQTJ0XpccfjHfKJDRLT7C1xvzo4Eibth0hpTZkA75IUYUp6qK/PuJ +-kH/qdiC7QIkRKtsrawW4vEDna3YtxIYhQqz9+KwO6u/0gzooZtv1RU4U3ifMDB5u +-5P5GAzACRqlY8QYBkM869lvWqzQPHvybC4ak9Yx6/heMO9ddjdIW9BaK8BLxvN/6 +-UCD936Y4fWltt09jHZIoxWFykouBwmd7bXooNYXmDRNmjTdVhKJuOEOQw8hDzx7e +-pWFJ9Z/V4Qm1tvXbCD7QFqMCDoY3qFvVG8DBqXpmxe1yPfz21FWrT7IuqDXAD3ns +-vxfN/2a+Cy04U9FBNVCvWqWIs5AgNpdCMJC2FlXKTy+H3/7rIjNyFyvbX0vxIXtK +-liOVNXiyVM++KZXqktqMUDlsJENmIHV9B046luqbgW018fHkyEYlL3iRZGbYegwr +-XO9VVIKVPw1BEvJ8VNdGFGuZGepd8qX2ezfYADrNR+4t85HDm8inbjTobSjWuljs +-ftUNkOeCHqAvWCFQTLCfdykvV08EJfVY79y7yFPtfRV2gxYokXFifjo3su9sVQr1 +-UiIS5ZAsIC1hBXWeXoBN7QVTkFi7Yto6E1q2k10LiT3obpUUUQ/oclhrJOCJVjrS +-oRcj2QBy8OT4T9slJr5maTWdgd7Lt6+I6cGQXPaDvjGOJl0eBYM14vhx4rRQWytJ +-k07hhHFO4+9CGCuHS8AAy2gR6acYFWt2ZiiNZ0z/iPIHNK4YEyy9aLf6uZH/KQjE +-jmHToo7XD6QvCAEC5qTHby3o3LfHIhyZi/4L+AhS4FKUHF6M0peeyYt4z3HaK2d2 +-N6mHLPdjwNjra7GOmcns4gzcrdfoF+R293KpPal4PjknvR3dZL4kKP/ougTAM5zv +-qDIvRbkHzjP8ChTpoLcJsNVXykNcNkjcSi0GHtIpYjh6QX6P2uvR/S4+Bbb9p9rn +-hIy/ovu9tWN2hiPxGPe6torF6BulAxsTYlDercC204AyzsrdA0pr6HBgJH9C6ML1 +-TchwodbFJqn9rSv91i1liusAGoOvE81AGBdrXY7LxfSNhYY1IK6yR/POJPTd53sA +-uX2/j6Rtoksd/2BHPM6AUnI/2B9slhuzWX2aCtWLeuwvXDS6rYuTigaQmLkzTRfM +-dlMI3s9KLXxgi5YVumUZleJWXwBNP7KiKajd+VTSD+7WAhyhM5FIG5wVOaxmy4G2 +-TyqZ/Ax9d2VEjTQHWvQlLPQ4Mp0EIz0aEl94K/S8CK8bJRH6+PRkar+dJi1xqlL+ +-BYb42At9mEJ8odLlFikvNi1+t7jqXk5jRi5C0xFKx3nTtzoH2zNUeuA3R6vSocVK +-45jnze9IkKmxMlJ4loR5sgszdpDCD3kXqjtCcbMTmcrGyzJek3HSOTpiEORoTFOe +-Rhg6jH5lm+QcC263oipojS0qEQcnsWJP2CylNYMYHR9O/9NQxT3o2lsRHqZTMELV +-uQa/SFH+paQNbZOj8MRwPSqqiIxJFuLswKte1R+W7LKn1yBSM7Pp39lNbzGvJD2E +-YRfnCwFpJ54voVAuQ4jXJvigCW2qeCjXlxeD6K2j4eGJEEOmIjIW1wjubyBY6OI3 +------END RSA PRIVATE KEY----- ++-----BEGIN ENCRYPTED PRIVATE KEY----- ++MIIHbTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQIhD+rJdxqb6ECAggA ++MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBDTdyjCP3riOSUfxix4aXEvBIIH ++ECGkbsFabrcFMZcplw5jHMaOlG7rYjUzwDJ80JM8uzbv2Jb8SvNlns2+xmnEvH/M ++mNvRmnXmplbVjH3XBMK8o2Psnr2V/a0j7/pgqpRxHykG+koOY4gzdt3MAg8JPbS2 ++hymSl+Y5EpciO3xLfz4aFL1ZNqspQbO/TD13Ij7DUIy7xIRBMp4taoZCrP0cEBAZ +++wgu9m23I4dh3E8RUBzWyFFNic2MVVHrui6JbHc4dIHfyKLtXJDhUcS0vIC9PvcV ++jhorh3UZC4lM+/jjXV5AhzQ0VrJ2tXAUX2dA144XHzkSH2QmwfnajPsci7BL2CGC ++rjyTy4NfB/lDwU+55dqJZQSKXMxAapJMrtgw7LD5CKQcN6zmfhXGssJ7HQUXKkaX ++I1YOFzuUD7oo56BVCnVswv0jX9RxrE5QYNreMlOP9cS+kIYH65N+PAhlURuQC14K ++PgDkHn5knSa2UQA5tc5f7zdHOZhGRUfcjLP+KAWA3nh+/2OKw/X3zuPx75YT/FKe ++tACPw5hjEpl62m9Xa0eWepZXwqkIOkzHMmCyNCsbC0mmRoEjmvfnslfsmnh4Dg/c ++4YsTYMOLLIeCa+WIc38aA5W2lNO9lW0LwLhX1rP+GRVPv+TVHXlfoyaI+jp0iXrJ ++t3xxT0gaiIR/VznyS7Py68QV/zB7VdqbsNzS7LdquHK1k8+7OYiWjY3gqyU40Iu2 ++d1eSnIoDvQJwyYp7XYXbOlXNLY+s1Qb7yxcW3vXm0Bg3gKT8r1XHWJ9rj+CxAn5r ++ysfkPs1JsesxzzQjwTiDNvHnBnZnwxuxfBr26ektEHmuAXSl8V6dzLN/aaPjpTj4 ++CkE7KyqX3U9bLkp+ztl4xWKEmW44nskzm0+iqrtrxMyTfvvID4QrABjZL4zmWIqc ++e3ZfA3AYk9VDIegk/YKGC5VZ8YS7ZXQ0ASK652XqJ7QlMKTxxV7zda6Fp4uW6/qN ++ezt5wgbGGhZQXj2wDQmWNQYyG/juIgYTpCUA54U5XBIjuR6pg+Ytm0UrvNjsUoAC ++wGelyqaLDq8U8jdIFYVTJy9aJjQOYXjsUJ0dZN2aGHSlju0ZGIZc49cTIVQ9BTC5 ++Yc0Vlwzpl+LuA25DzKZNSb/ci0lO/cQGJ2uXQQgaNgdsHlu8nukENGJhnIzx4fzK ++wEh3yHxhTRCzPPwDfXmx0IHXrPqJhSpAgaXBVIm8OjvmMxO+W75W4uLfNY/B7e2H ++3cjklGuvkofOf7sEOrGUYf4cb6Obg8FpvHgpKo5Twwmoh/qvEKckBFqNhZXDDl88 ++GbGlSEgyaAV1Ig8s1NJKBolWFa0juyPAwJ8vT1T4iwW7kQ7KXKt2UNn96K/HxkLu ++pikvukz8oRHMlfVHa0R48UB1fFHwZLzPmwkpu6ancIxk3uO3yfhf6iDk3bmnyMlz ++g3k/b6MrLYaOVByRxay85jH3Vvgqfgn6wa6BJ7xQ81eZ8B45gFuTH0J5JtLL7SH8 ++darRPLCYfA+Ums9/H6pU5EXfd3yfjMIbvhCXHkJrrljkZ+th3p8dyto6wmYqIY6I ++qR9sU+o6DhRaiP8tCICuhHxQpXylUM6WeJkJwduTJ8KWIvzsj4mReIKOl/oC2jSd ++gIdKhb9Q3zj9ce4N5m6v66tyvjxGZ+xf3BvUPDD+LwZeXgf7OBsNVbXzQbzto594 ++nbCzPocFi3gERE50ru4K70eQCy08TPG5NpOz+DDdO5vpAuMLYEuI7O3L+3GjW40Q ++G5bu7H5/i7o/RWR67qhG/7p9kPw3nkUtYgnvnWaPMIuTfb4c2d069kjlfgWjIbbI ++tpSKmm5DHlqTE4/ECAbIEDtSaw9dXHCdL3nh5+n428xDdGbjN4lT86tfu17EYKzl ++ydH1RJ1LX3o3TEj9UkmDPt7LnftvwybMFEcP7hM2xD4lC++wKQs7Alg6dTkBnJV4 ++5xU78WRntJkJTU7kFkpPKA0QfyCuSF1fAMoukDBkqUdOj6jE0BlJQlHk5iwgnJlt ++uEdkTjHZEjIUxWC6llPcAzaPNlmnD45AgfEW+Jn21IvutmJiQAz5lm9Z9PXaR0C8 ++hXB6owRY67C0YKQwXhoNf6xQun2xGBGYy5rPEEezX1S1tUH5GR/KW1Lh+FzFqHXI ++ZEb5avfDqHKehGAjPON+Br7akuQ125M9LLjKuSyPaQzeeCAy356Xd7XzVwbPddbm ++9S9WSPqzaPgh10chIHoNoC8HMd33dB5j9/Q6jrbU/oPlptu/GlorWblvJdcTuBGI ++IVn45RFnkG8hCz0GJSNzW7+70YdESQbfJW79vssWMaiSjFE0pMyFXrFR5lBywBTx ++PiGEUWtvrKG94X1TMlGUzDzDJOQNZ9dT94bonNe9pVmP5BP4/DzwwiWh6qrzWk6p ++j8OE4cfCSh2WvHnhJbH7/N0v+JKjtxeIeJ16jx/K2oK5 ++-----END ENCRYPTED PRIVATE KEY----- + -----BEGIN CERTIFICATE----- + MIIEWTCCAsGgAwIBAgIJAJinz4jHSjLtMA0GCSqGSIb3DQEBCwUAMF8xCzAJBgNV + BAYTAlhZMRcwFQYDVQQHDA5DYXN0bGUgQW50aHJheDEjMCEGA1UECgwaUHl0aG9u +@@ -66,3 +66,4 @@ jMqTFlmO7kpf/jpCSmamp3/JSEE1BJKHwQ6Ql4nzRA2N1mnvWH7Zxcv043gkHeAu + 9Wc2uXpw9xF8itV4Uvcdr3dwqByvIqn7iI/gB+4l41e0u8OmH2MKOx4Nxlly5TNW + HcVKQHyOeyvnINuBAQ== + -----END CERTIFICATE----- ++ +diff --git a/Lib/test/make_ssl_certs.py b/Lib/test/make_ssl_certs.py +index 3622765..41b5f46 100644 +--- a/Lib/test/make_ssl_certs.py ++++ b/Lib/test/make_ssl_certs.py +@@ -206,8 +206,8 @@ if __name__ == '__main__': + with open('ssl_key.pem', 'w') as f: + f.write(key) + print("password protecting ssl_key.pem in ssl_key.passwd.pem") +- check_call(['openssl','rsa','-in','ssl_key.pem','-out','ssl_key.passwd.pem','-des3','-passout','pass:somepass']) +- check_call(['openssl','rsa','-in','ssl_key.pem','-out','keycert.passwd.pem','-des3','-passout','pass:somepass']) ++ check_call(['openssl','pkey','-in','ssl_key.pem','-out','ssl_key.passwd.pem','-aes256','-passout','pass:somepass']) ++ check_call(['openssl','pkey','-in','ssl_key.pem','-out','keycert.passwd.pem','-aes256','-passout','pass:somepass']) + + with open('keycert.pem', 'w') as f: + f.write(key) +diff --git a/Lib/test/ssl_key.passwd.pem b/Lib/test/ssl_key.passwd.pem +index e4f1370..46de61a 100644 +--- a/Lib/test/ssl_key.passwd.pem ++++ b/Lib/test/ssl_key.passwd.pem +@@ -1,42 +1,42 @@ +------BEGIN RSA PRIVATE KEY----- +-Proc-Type: 4,ENCRYPTED +-DEK-Info: DES-EDE3-CBC,8064BE1494B24B13 +- +-KJrffOMbo8M0I3PzcYxRZGMpKD1yB3Ii4+bT5XoanxjIJ+4fdx6LfZ0Rsx+riyzs +-tymsQu/iYY9j+4rCvN9+eetsL1X6iZpiimKsLexcid9M3fb0vxED5Sgw0dvunCUA +-xhqjLIKR92MKbODHf6KrDKCpsiPbjq4gZ7P+uCGXAMHL3MXIJSC0hW9rK7Ce6oyO +-CjpIcgB8x+GUWZZZhAFdlzIHMZrteNP2P5HK6QcaT71P034Dz1hhqoj4Q0t+Fta2 +-4tfsM/bnTR/l6hwlhPa1e3Uj322tDTDWBScgWANn5+sEWldLmozMaWhZsn22pfk2 +-KjRMGXG024JVheV882nbdOBvG7oq+lxkZ/ZP+vvqJqnvYtf7WtM8UivzYpe5Hz5b +-kVvWzPjBLUSZ9whM9rDLqSSqMPyPvDTuEmLkuq+xm7pYJmsLqIMP2klZLqRxLX6K +-uqwplb8UG440qauxgnQ905PId1l2fJEnRtV+7vXprA0L0QotgXLVHBhLmTFM+3PH +-9H3onf31dionUAPrn3nfVE36HhvVgRyvDBnBzJSIMighgq21Qx/d1dk0DRYi1hUI +-nCHl0YJPXheVcXR7JiSF2XQCAaFuS1Mr7NCXfWZOZQC/0dkvmHnl9DUAhuqq9BNZ +-1cKhZXcKHadg2/r0Zup/oDzmHPUEfTAXT0xbqoWlhkdwbF2veWQ96A/ncx3ISTb4 +-PkXBlX9rdia8nmtyQDQRn4NuvchbaGkj4WKFC8pF8Hn7naHqwjpHaDUimBc0CoQW +-edNJqruKWwtSVLuwKHCC2gZFX9AXSKJXJz/QRSUlhFGOhuF/J6yKaXj6n5lxWNiQ +-54J+OP/hz2aS95CD2+Zf1SKpxdWiLZSIQqESpmmUrXROixNJZ/Z7gI74Dd9dSJOH +-W+3AU03vrrFZVrJVZhjcINHoH1Skh6JKscH18L6x4U868nSr4SrRLX8BhHllOQyD +-bmU+PZAjF8ZBIaCtTGulDXD29F73MeAZeTSsgQjFu0iKLj1wPiphbx8i/SUtR4YP +-X6PVA04g66r1NBw+3RQASVorZ3g1MSFvITHXcbKkBDeJH2z1+c6t/VVyTONnQhM5 +-lLgRSk6HCbetvT9PKxWrWutA12pdBYEHdZhMHVf2+xclky7l09w8hg2/qqcdGRGe +-oAOZ72t0l5ObNyaruDKUS6f4AjOyWq/Xj5xuFtf1n3tQHyslSyCTPcAbQhDfTHUx +-vixb/V9qvYPt7OCn8py7v1M69NH42QVFAvwveDIFjZdqfIKBoJK2V4qPoevJI6uj +-Q5ByMt8OXOjSXNpHXpYQWUiWeCwOEBXJX8rzCHdMtg37jJ0zCmeErR1NTdg+EujM +-TWYgd06jlT67tURST0aB2kg4ijKgUJefD313LW1zC6gVsTbjSZxYyRbPfSP6flQB +-yCi1C19E2OsgleqbkBVC5GlYUzaJT7SGjCRmGx1eqtbrALu+LVH24Wceexlpjydl +-+s2nf/DZlKun/tlPh6YioifPCJjByZMQOCEfIox6BkemZETz8uYA4TTWimG13Z03 +-gyDGC2jdpEW414J2qcQDvrdUgJ+HlhrAAHaWpMQDbXYxBGoZ+3+ORvQV4kAsCwL8 +-k3EIrVpePdik+1xgOWsyLj6QxFXlTMvL6Wc5pnArFPORsgHEolJvxSPTf9aAHNPn +-V2WBvxiLBtYpGrujAUM40Syx/aN2RPtcXYPAusHUBw+S8/p+/8Kg8GZmnIXG3F89 +-45Eepl2quZYIrou7a1fwIpIIZ0hFiBQ1mlHVMFtxwVHS1bQb3SU2GeO+JcGjdVXc +-04qeGuQ5M164eQ5C0T7ZQ1ULiUlFWKD30m+cjqmZzt3d7Q0mKpMKuESIuZJo/wpD +-Nas432aLKUhcNx/pOYLkKJRpGZKOupQoD5iUj/j44o8JoFkDK33v2S57XB5QGz28 +-9Zuhx49b3W8mbM6EBanlQKLWJGCxXqc/jhYhFWn+b0MhidynFgA0oeWvf6ZDyt6H +-Yi5Etxsar09xp0Do3NxtQXLuSUu0ji2pQzSIKuoqQWKqldm6VrpwojiqJhy4WQBQ +-aVVyFeWBC7G3Zj76dO+yp2sfJ0itJUQ8AIB9Cg0f34rEZu+r9luPmqBoUeL95Tk7 +-YvCOU3Jl8Iqysv8aNpVXT8sa8rrSbruWCByEePZ37RIdHLMVBwVY0eVaFQjrjU7E +-mXmM9eaoYLfXOllsQ+M2+qPFUITr/GU3Qig13DhK/+yC1R6V2a0l0WRhMltIPYKW +-Ztvvr4hK5LcYCeS113BLiMbDIMMZZYGDZGMdC8DnnVbT2loF0Rfmp80Af31KmMQ4 +-6XvMatW9UDjBoY5a/YMpdm7SRwm+MgV2KNPpc2kST87/yi9oprGAb8qiarHiHTM0 +------END RSA PRIVATE KEY----- ++-----BEGIN ENCRYPTED PRIVATE KEY----- ++MIIHbTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQI072N7W+PDDMCAggA ++MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBA/AuaRNi4vE4KGqI4In+70BIIH ++ENGS5Vex5NID873frmd1UZEHZ+O/Bd0wDb+NUpIqesHkRYf7kKi6Gnr+nKQ/oVVn ++Lm3JjE7c8ECP0OkOOXmiXuWL1SkzBBWqCI4stSGUPvBiHsGwNnvJAaGjUffgMlcC ++aJOA2+dnejLkzblq4CB2LQdm06N3Xoe9tyqtQaUHxfzJAf5Ydd8uj7vpKN2MMhY7 ++icIPJwSyh0N7S6XWVtHEokr9Kp4y2hS5a+BgCWV1/1z0aF7agnSVndmT1VR+nWmc ++lM14k+lethmHMB+fsNSjnqeJ7XOPlOTHqhiZ9bBSTgF/xr5Bck/NiKRzHjdovBox ++TKg+xchaBhpRh7wBPBIlNJeHmIjv+8obOKjKU98Ig/7R9+IryZaNcKAH0PuOT+Sw ++QHXiCGQbOiYHB9UyhDTWiB7YVjd8KHefOFxfHzOQb/iBhbv1x3bTl3DgepvRN6VO ++dIsPLoIZe42sdf9GeMsk8mGJyZUQ6AzsfhWk3grb/XscizPSvrNsJ2VL1R7YTyT3 ++3WA4ZXR1EqvXnWL7N/raemQjy62iOG6t7fcF5IdP9CMbWP+Plpsz4cQW7FtesCTq ++a5ZXraochQz361ODFNIeBEGU+0qqXUtZDlmos/EySkZykSeU/L0bImS62VGE3afo ++YXBmznTTT9kkFkqv7H0MerfJsrE/wF8puP3GM01DW2JRgXRpSWlvbPV/2LnMtRuD ++II7iH4rWDtTjCN6BWKAgDOnPkc9sZ4XulqT32lcUeV6LTdMBfq8kMEc8eDij1vUT ++maVCRpuwaq8EIT3lVgNLufHiG96ojlyYtj3orzw22IjkgC/9ee8UDik9CqbMVmFf ++fVHhsw8LNSg8Q4bmwm5Eg2w2it2gtI68+mwr75oCxuJ/8OMjW21Prj8XDh5reie2 ++c0lDKQOFZ9UnLU1bXR/6qUM+JFKR4DMq+fOCuoQSVoyVUEOsJpvBOYnYZN9cxsZm ++vh9dKafMEcKZ8flsbr+gOmOw7+Py2ifSlf25E/Frb1W4gtbTb0LQVHb6+drutrZj ++8HEu4CnHYFCD4ZnOJb26XlZCb8GFBddW86yJYyUqMMV6Q1aJfAOAglsTo1LjIMOZ ++byo0BTAmwUevU/iuOXQ4qRBXXcoidDcTCrxfUSPG9wdt9l+m5SdQpWqfQ+fx5O7m ++SLlrHyZCiPSFMtC9DxqjIklHjf5W3wslGLgaD30YXa4VDYkRihf3CNsxGQ+tVvef ++l0ZjoAitF7Gaua06IESmKnpHe23dkr1cjYq+u2IV+xGH8LeExdwsQ9kpuTeXPnQs ++JOA99SsFx1ct32RrwjxnDDsiNkaViTKo9GDkV3jQTfoFgAVqfSgg9wGXpqUqhNG7 ++TiSIHCowllLny2zn4XrXCy2niD3VDt0skb3l/PaegHE2z7S5YY85nQtYwpLiwB9M ++SQ08DYKxPBZYKtS2iZ/fsA1gjSRQDPg/SIxMhUC3M3qH8iWny1Lzl25F2Uq7VVEX ++LdTUtaby49jRTT3CQGr5n6z7bMbUegiY7h8WmOekuThGDH+4xZp6+rDP4GFk4FeK ++JcF70vMQYIjQZhadic6olv+9VtUP42ltGG/yP9a3eWRkzfAf2eCh6B1rYdgEWwE8 ++rlcZzwM+y6eUmeNF2FVWB8iWtTMQHy+dYNPM+Jtus1KQKxiiq/yCRs7nWvzWRFWA ++HRyqV0J6/lqgm4FvfktFt1T0W+mDoLJOR2/zIwMy2lgL5zeHuR3SaMJnCikJbqKS ++HB3UvrhAWUcZqdH29+FhVWeM7ybyF1Wccmf+IIC/ePLa6gjtqPV8lG/5kbpcpnB6 ++UQY8WWaKMxyr3jJ9bAX5QKshchp04cDecOLZrpFGNNQngR8RxSEkiIgAqNxWunIu ++KrdBDrupv/XAgEOclmgToY3iywLJSV5gHAyHWDUhRH4cFCLiGPl4XIcnXOuTze3H ++3j+EYSiS3v3DhHjp33YU2pXlJDjiYsKzAXejEh66++Y8qaQdCAad3ruWRCzW3kgk ++Md0A1VGzntTnQsewvExQEMZH2LtYIsPv3KCYGeSAuLabX4tbGk79PswjnjLLEOr0 ++Ghf6RF6qf5/iFyJoG4vrbKT8kx6ywh0InILCdjUunuDskIBxX6tEcr9XwajoIvb2 ++kcmGdjam5kKLS7QOWQTl8/r/cuFes0dj34cX5Qpq+Gd7tRq/D+b0207926Cxvftv ++qQ1cVn8HiLxKkZzd3tpf2xnoV1zkTL0oHrNg+qzxoxXUTUcwtIf1d/HRbYEAhi/d ++bBBoFeftEHWNq+sJgS9bH+XNzo/yK4u04B5miOq8v4CSkJdzu+ZdF22d4cjiGmtQ ++8BTmcn0Unzm+u5H0+QSZe54QBHJGNXXOIKMTkgnOdW27g4DbI1y7fCqJiSMbRW6L ++oHmMfbdB3GWqGbsUkhY8i6h9op0MU6WOX7ea2Rxyt4t6 ++-----END ENCRYPTED PRIVATE KEY----- +diff --git a/Misc/NEWS.d/next/Tests/2019-09-25-13-11-29.bpo-38271.iHXNIg.rst b/Misc/NEWS.d/next/Tests/2019-09-25-13-11-29.bpo-38271.iHXNIg.rst +new file mode 100644 +index 0000000..8f43d32 +--- /dev/null ++++ b/Misc/NEWS.d/next/Tests/2019-09-25-13-11-29.bpo-38271.iHXNIg.rst +@@ -0,0 +1,4 @@ ++The private keys for test_ssl were encrypted with 3DES in traditional ++PKCS#5 format. 3DES and the digest algorithm of PKCS#5 are blocked by ++some strict crypto policies. Use PKCS#8 format with AES256 encryption ++instead. +-- +2.21.0 + + +From d8584f9bb3fb841a1b21ed25abc2237ea8bbc206 Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Tue, 26 Nov 2019 23:57:21 +0100 +Subject: [PATCH 3/5] Use PROTOCOL_TLS_CLIENT/SERVER + +Replaces PROTOCOL_TLSv* and PROTOCOL_SSLv23 with PROTOCOL_TLS_CLIENT and +PROTOCOL_TLS_SERVER. + +Partially backports a170fa162dc03f0a014373349e548954fff2e567 +--- + Lib/ssl.py | 7 +- + Lib/test/test_logging.py | 2 +- + Lib/test/test_ssl.py | 169 +++++++++++++++++++-------------------- + 3 files changed, 87 insertions(+), 91 deletions(-) + +diff --git a/Lib/ssl.py b/Lib/ssl.py +index 0114387..c5c5529 100644 +--- a/Lib/ssl.py ++++ b/Lib/ssl.py +@@ -473,7 +473,7 @@ def create_default_context(purpose=Purpose.SERVER_AUTH, *, cafile=None, + context.load_default_certs(purpose) + return context + +-def _create_unverified_context(protocol=PROTOCOL_TLS, *, cert_reqs=None, ++def _create_unverified_context(protocol=PROTOCOL_TLS, *, cert_reqs=CERT_NONE, + check_hostname=False, purpose=Purpose.SERVER_AUTH, + certfile=None, keyfile=None, + cafile=None, capath=None, cadata=None): +@@ -492,9 +492,12 @@ def _create_unverified_context(protocol=PROTOCOL_TLS, *, cert_reqs=None, + # by default. + context = SSLContext(protocol) + ++ if not check_hostname: ++ context.check_hostname = False + if cert_reqs is not None: + context.verify_mode = cert_reqs +- context.check_hostname = check_hostname ++ if check_hostname: ++ context.check_hostname = True + + if keyfile and not certfile: + raise ValueError("certfile must be specified") +diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py +index 763a5d1..d5c63b4 100644 +--- a/Lib/test/test_logging.py ++++ b/Lib/test/test_logging.py +@@ -1830,7 +1830,7 @@ class HTTPHandlerTest(BaseTest): + else: + here = os.path.dirname(__file__) + localhost_cert = os.path.join(here, "keycert.pem") +- sslctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) ++ sslctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + sslctx.load_cert_chain(localhost_cert) + + context = ssl.create_default_context(cafile=localhost_cert) +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +index 639109f..a7bf2f7 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -155,6 +155,8 @@ def test_wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLS, *, + **kwargs): + context = ssl.SSLContext(ssl_version) + if cert_reqs is not None: ++ if cert_reqs == ssl.CERT_NONE: ++ context.check_hostname = False + context.verify_mode = cert_reqs + if ca_certs is not None: + context.load_verify_locations(ca_certs) +@@ -1377,7 +1379,7 @@ class ContextTests(unittest.TestCase): + self._assert_context_options(ctx) + + def test_check_hostname(self): +- ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ ctx = ssl.SSLContext(ssl.PROTOCOL_TLS) + self.assertFalse(ctx.check_hostname) + + # Requires CERT_REQUIRED or CERT_OPTIONAL +@@ -2386,17 +2388,13 @@ if _have_threads: + server_params_test(context, context, + chatty=True, connectionchatty=True) + +- client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) +- client_context.load_verify_locations(SIGNING_CA) +- server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) +- # server_context.load_verify_locations(SIGNING_CA) +- server_context.load_cert_chain(SIGNED_CERTFILE2) ++ client_context, server_context, hostname = testing_context() + + with self.subTest(client=ssl.PROTOCOL_TLS_CLIENT, server=ssl.PROTOCOL_TLS_SERVER): + server_params_test(client_context=client_context, + server_context=server_context, + chatty=True, connectionchatty=True, +- sni_name='fakehostname') ++ sni_name='localhost') + + client_context.check_hostname = False + with self.subTest(client=ssl.PROTOCOL_TLS_SERVER, server=ssl.PROTOCOL_TLS_CLIENT): +@@ -2404,7 +2402,7 @@ if _have_threads: + server_params_test(client_context=server_context, + server_context=client_context, + chatty=True, connectionchatty=True, +- sni_name='fakehostname') ++ sni_name='localhost') + self.assertIn('called a function you should not call', + str(e.exception)) + +@@ -2469,39 +2467,38 @@ if _have_threads: + if support.verbose: + sys.stdout.write("\n") + +- server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- server_context.load_cert_chain(SIGNED_CERTFILE) ++ client_context, server_context, hostname = testing_context() + +- context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- context.verify_mode = ssl.CERT_REQUIRED +- context.load_verify_locations(SIGNING_CA) + tf = getattr(ssl, "VERIFY_X509_TRUSTED_FIRST", 0) +- self.assertEqual(context.verify_flags, ssl.VERIFY_DEFAULT | tf) ++ self.assertEqual(client_context.verify_flags, ssl.VERIFY_DEFAULT | tf) + + # VERIFY_DEFAULT should pass + server = ThreadedEchoServer(context=server_context, chatty=True) + with server: +- with context.wrap_socket(socket.socket()) as s: ++ with client_context.wrap_socket(socket.socket(), ++ server_hostname=hostname) as s: + s.connect((HOST, server.port)) + cert = s.getpeercert() + self.assertTrue(cert, "Can't get peer certificate.") + + # VERIFY_CRL_CHECK_LEAF without a loaded CRL file fails +- context.verify_flags |= ssl.VERIFY_CRL_CHECK_LEAF ++ client_context.verify_flags |= ssl.VERIFY_CRL_CHECK_LEAF + + server = ThreadedEchoServer(context=server_context, chatty=True) + with server: +- with context.wrap_socket(socket.socket()) as s: ++ with client_context.wrap_socket(socket.socket(), ++ server_hostname=hostname) as s: + with self.assertRaisesRegex(ssl.SSLError, + "certificate verify failed"): + s.connect((HOST, server.port)) + + # now load a CRL file. The CRL file is signed by the CA. +- context.load_verify_locations(CRLFILE) ++ client_context.load_verify_locations(CRLFILE) + + server = ThreadedEchoServer(context=server_context, chatty=True) + with server: +- with context.wrap_socket(socket.socket()) as s: ++ with client_context.wrap_socket(socket.socket(), ++ server_hostname=hostname) as s: + s.connect((HOST, server.port)) + cert = s.getpeercert() + self.assertTrue(cert, "Can't get peer certificate.") +@@ -2510,19 +2507,13 @@ if _have_threads: + if support.verbose: + sys.stdout.write("\n") + +- server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- server_context.load_cert_chain(SIGNED_CERTFILE) +- +- context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- context.verify_mode = ssl.CERT_REQUIRED +- context.check_hostname = True +- context.load_verify_locations(SIGNING_CA) ++ client_context, server_context, hostname = testing_context() + + # correct hostname should verify + server = ThreadedEchoServer(context=server_context, chatty=True) + with server: +- with context.wrap_socket(socket.socket(), +- server_hostname="localhost") as s: ++ with client_context.wrap_socket(socket.socket(), ++ server_hostname=hostname) as s: + s.connect((HOST, server.port)) + cert = s.getpeercert() + self.assertTrue(cert, "Can't get peer certificate.") +@@ -2530,7 +2521,7 @@ if _have_threads: + # incorrect hostname should raise an exception + server = ThreadedEchoServer(context=server_context, chatty=True) + with server: +- with context.wrap_socket(socket.socket(), ++ with client_context.wrap_socket(socket.socket(), + server_hostname="invalid") as s: + with self.assertRaisesRegex(ssl.CertificateError, + "hostname 'invalid' doesn't match 'localhost'"): +@@ -2542,7 +2533,7 @@ if _have_threads: + with socket.socket() as s: + with self.assertRaisesRegex(ValueError, + "check_hostname requires server_hostname"): +- context.wrap_socket(s) ++ client_context.wrap_socket(s) + + def test_wrong_cert(self): + """Connecting when the server rejects the client's certificate +@@ -2767,7 +2758,6 @@ if _have_threads: + msgs = (b"msg 1", b"MSG 2", b"STARTTLS", b"MSG 3", b"msg 4", b"ENDTLS", b"msg 5", b"msg 6") + + server = ThreadedEchoServer(CERTFILE, +- ssl_version=ssl.PROTOCOL_TLSv1, + starttls_server=True, + chatty=True, + connectionchatty=True) +@@ -2795,7 +2785,7 @@ if _have_threads: + sys.stdout.write( + " client: read %r from server, starting TLS...\n" + % msg) +- conn = test_wrap_socket(s, ssl_version=ssl.PROTOCOL_TLSv1) ++ conn = test_wrap_socket(s) + wrapped = True + elif indata == b"ENDTLS" and msg.startswith(b"ok"): + # ENDTLS ok, switch back to clear text +@@ -2882,7 +2872,7 @@ if _have_threads: + + server = ThreadedEchoServer(CERTFILE, + certreqs=ssl.CERT_NONE, +- ssl_version=ssl.PROTOCOL_TLSv1, ++ ssl_version=ssl.PROTOCOL_TLS_SERVER, + cacerts=CERTFILE, + chatty=True, + connectionchatty=False) +@@ -2892,7 +2882,7 @@ if _have_threads: + certfile=CERTFILE, + ca_certs=CERTFILE, + cert_reqs=ssl.CERT_NONE, +- ssl_version=ssl.PROTOCOL_TLSv1) ++ ssl_version=ssl.PROTOCOL_TLS_CLIENT) + s.connect((HOST, server.port)) + # helper methods for standardising recv* method signatures + def _recv_into(): +@@ -3034,7 +3024,7 @@ if _have_threads: + def test_nonblocking_send(self): + server = ThreadedEchoServer(CERTFILE, + certreqs=ssl.CERT_NONE, +- ssl_version=ssl.PROTOCOL_TLSv1, ++ ssl_version=ssl.PROTOCOL_TLS_SERVER, + cacerts=CERTFILE, + chatty=True, + connectionchatty=False) +@@ -3044,7 +3034,7 @@ if _have_threads: + certfile=CERTFILE, + ca_certs=CERTFILE, + cert_reqs=ssl.CERT_NONE, +- ssl_version=ssl.PROTOCOL_TLSv1) ++ ssl_version=ssl.PROTOCOL_TLS_CLIENT) + s.connect((HOST, server.port)) + s.setblocking(False) + +@@ -3190,9 +3180,11 @@ if _have_threads: + Basic tests for SSLSocket.version(). + More tests are done in the test_protocol_*() methods. + """ +- context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) ++ context.check_hostname = False ++ context.verify_mode = ssl.CERT_NONE + with ThreadedEchoServer(CERTFILE, +- ssl_version=ssl.PROTOCOL_TLSv1, ++ ssl_version=ssl.PROTOCOL_TLS_SERVER, + chatty=False) as server: + with context.wrap_socket(socket.socket()) as s: + self.assertIs(s.version(), None) +@@ -3247,7 +3239,7 @@ if _have_threads: + + server = ThreadedEchoServer(CERTFILE, + certreqs=ssl.CERT_NONE, +- ssl_version=ssl.PROTOCOL_TLSv1, ++ ssl_version=ssl.PROTOCOL_TLS_SERVER, + cacerts=CERTFILE, + chatty=True, + connectionchatty=False) +@@ -3257,7 +3249,7 @@ if _have_threads: + certfile=CERTFILE, + ca_certs=CERTFILE, + cert_reqs=ssl.CERT_NONE, +- ssl_version=ssl.PROTOCOL_TLSv1) ++ ssl_version=ssl.PROTOCOL_TLS_CLIENT) + s.connect((HOST, server.port)) + # get the data + cb_data = s.get_channel_binding("tls-unique") +@@ -3282,7 +3274,7 @@ if _have_threads: + certfile=CERTFILE, + ca_certs=CERTFILE, + cert_reqs=ssl.CERT_NONE, +- ssl_version=ssl.PROTOCOL_TLSv1) ++ ssl_version=ssl.PROTOCOL_TLS_CLIENT) + s.connect((HOST, server.port)) + new_cb_data = s.get_channel_binding("tls-unique") + if support.verbose: +@@ -3299,32 +3291,35 @@ if _have_threads: + s.close() + + def test_compression(self): +- context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- context.load_cert_chain(CERTFILE) +- stats = server_params_test(context, context, +- chatty=True, connectionchatty=True) ++ client_context, server_context, hostname = testing_context() ++ stats = server_params_test(client_context, server_context, ++ chatty=True, connectionchatty=True, ++ sni_name=hostname) + if support.verbose: + sys.stdout.write(" got compression: {!r}\n".format(stats['compression'])) + self.assertIn(stats['compression'], { None, 'ZLIB', 'RLE' }) + ++ + @unittest.skipUnless(hasattr(ssl, 'OP_NO_COMPRESSION'), + "ssl.OP_NO_COMPRESSION needed for this test") + def test_compression_disabled(self): +- context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- context.load_cert_chain(CERTFILE) +- context.options |= ssl.OP_NO_COMPRESSION +- stats = server_params_test(context, context, +- chatty=True, connectionchatty=True) ++ client_context, server_context, hostname = testing_context() ++ client_context.options |= ssl.OP_NO_COMPRESSION ++ server_context.options |= ssl.OP_NO_COMPRESSION ++ stats = server_params_test(client_context, server_context, ++ chatty=True, connectionchatty=True, ++ sni_name=hostname) + self.assertIs(stats['compression'], None) + + def test_dh_params(self): + # Check we can get a connection with ephemeral Diffie-Hellman +- context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- context.load_cert_chain(CERTFILE) +- context.load_dh_params(DHFILE) +- context.set_ciphers("kEDH") +- stats = server_params_test(context, context, +- chatty=True, connectionchatty=True) ++ client_context, server_context, hostname = testing_context() ++ server_context.load_dh_params(DHFILE) ++ server_context.set_ciphers("kEDH") ++ server_context.options |= ssl.OP_NO_TLSv1_3 ++ stats = server_params_test(client_context, server_context, ++ chatty=True, connectionchatty=True, ++ sni_name=hostname) + cipher = stats["cipher"][0] + parts = cipher.split("-") + if "ADH" not in parts and "EDH" not in parts and "DHE" not in parts: +@@ -3332,22 +3327,20 @@ if _have_threads: + + def test_selected_alpn_protocol(self): + # selected_alpn_protocol() is None unless ALPN is used. +- context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- context.load_cert_chain(CERTFILE) +- stats = server_params_test(context, context, +- chatty=True, connectionchatty=True) ++ client_context, server_context, hostname = testing_context() ++ stats = server_params_test(client_context, server_context, ++ chatty=True, connectionchatty=True, ++ sni_name=hostname) + self.assertIs(stats['client_alpn_protocol'], None) + + @unittest.skipUnless(ssl.HAS_ALPN, "ALPN support required") + def test_selected_alpn_protocol_if_server_uses_alpn(self): + # selected_alpn_protocol() is None unless ALPN is used by the client. +- client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- client_context.load_verify_locations(CERTFILE) +- server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- server_context.load_cert_chain(CERTFILE) ++ client_context, server_context, hostname = testing_context() + server_context.set_alpn_protocols(['foo', 'bar']) + stats = server_params_test(client_context, server_context, +- chatty=True, connectionchatty=True) ++ chatty=True, connectionchatty=True, ++ sni_name=hostname) + self.assertIs(stats['client_alpn_protocol'], None) + + @unittest.skipUnless(ssl.HAS_ALPN, "ALPN support needed for this test") +@@ -3394,10 +3387,10 @@ if _have_threads: + + def test_selected_npn_protocol(self): + # selected_npn_protocol() is None unless NPN is used +- context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- context.load_cert_chain(CERTFILE) +- stats = server_params_test(context, context, +- chatty=True, connectionchatty=True) ++ client_context, server_context, hostname = testing_context() ++ stats = server_params_test(client_context, server_context, ++ chatty=True, connectionchatty=True, ++ sni_name=hostname) + self.assertIs(stats['client_npn_protocol'], None) + + @unittest.skipUnless(ssl.HAS_NPN, "NPN support needed for this test") +@@ -3430,12 +3423,11 @@ if _have_threads: + self.assertEqual(server_result, expected, msg % (server_result, "server")) + + def sni_contexts(self): +- server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ server_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + server_context.load_cert_chain(SIGNED_CERTFILE) +- other_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ++ other_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) + other_context.load_cert_chain(SIGNED_CERTFILE2) +- client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- client_context.verify_mode = ssl.CERT_REQUIRED ++ client_context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + client_context.load_verify_locations(SIGNING_CA) + return server_context, other_context, client_context + +@@ -3448,6 +3440,8 @@ if _have_threads: + calls = [] + server_context, other_context, client_context = self.sni_contexts() + ++ client_context.check_hostname = False ++ + def servername_cb(ssl_sock, server_name, initial_context): + calls.append((server_name, initial_context)) + if server_name is not None: +@@ -3533,11 +3527,7 @@ if _have_threads: + self.assertIn("TypeError", stderr.getvalue()) + + def test_shared_ciphers(self): +- server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- server_context.load_cert_chain(SIGNED_CERTFILE) +- client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- client_context.verify_mode = ssl.CERT_REQUIRED +- client_context.load_verify_locations(SIGNING_CA) ++ client_context, server_context, hostname = testing_context() + if ssl.OPENSSL_VERSION_INFO >= (1, 0, 2): + client_context.set_ciphers("AES128:AES256") + server_context.set_ciphers("AES256") +@@ -3555,7 +3545,8 @@ if _have_threads: + # TLS 1.3 ciphers are always enabled + expected_algs.extend(["TLS_CHACHA20", "TLS_AES"]) + +- stats = server_params_test(client_context, server_context) ++ stats = server_params_test(client_context, server_context, ++ sni_name=hostname) + ciphers = stats['server_shared_ciphers'][0] + self.assertGreater(len(ciphers), 0) + for name, tls_version, bits in ciphers: +@@ -3595,14 +3586,13 @@ if _have_threads: + self.assertEqual(s.recv(1024), TEST_DATA) + + def test_session(self): +- server_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- server_context.load_cert_chain(SIGNED_CERTFILE) +- client_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) +- client_context.verify_mode = ssl.CERT_REQUIRED +- client_context.load_verify_locations(SIGNING_CA) ++ client_context, server_context, hostname = testing_context() ++ # TODO: sessions aren't compatible with TLSv1.3 yet ++ client_context.options |= ssl.OP_NO_TLSv1_3 + + # first connection without session +- stats = server_params_test(client_context, server_context) ++ stats = server_params_test(client_context, server_context, ++ sni_name=hostname) + session = stats['session'] + self.assertTrue(session.id) + self.assertGreater(session.time, 0) +@@ -3616,7 +3606,8 @@ if _have_threads: + self.assertEqual(sess_stat['hits'], 0) + + # reuse session +- stats = server_params_test(client_context, server_context, session=session) ++ stats = server_params_test(client_context, server_context, ++ session=session, sni_name=hostname) + sess_stat = server_context.session_stats() + self.assertEqual(sess_stat['accept'], 2) + self.assertEqual(sess_stat['hits'], 1) +@@ -3629,7 +3620,8 @@ if _have_threads: + self.assertGreaterEqual(session2.timeout, session.timeout) + + # another one without session +- stats = server_params_test(client_context, server_context) ++ stats = server_params_test(client_context, server_context, ++ sni_name=hostname) + self.assertFalse(stats['session_reused']) + session3 = stats['session'] + self.assertNotEqual(session3.id, session.id) +@@ -3639,7 +3631,8 @@ if _have_threads: + self.assertEqual(sess_stat['hits'], 1) + + # reuse session again +- stats = server_params_test(client_context, server_context, session=session) ++ stats = server_params_test(client_context, server_context, ++ session=session, sni_name=hostname) + self.assertTrue(stats['session_reused']) + session4 = stats['session'] + self.assertEqual(session4.id, session.id) +-- +2.21.0 + + +From 743c3e09b485092b51a982ab9859ffc79cbb7791 Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Wed, 27 Nov 2019 00:01:17 +0100 +Subject: [PATCH 4/5] Adjust some tests for TLS 1.3 compatibility + +Partially backports some changes from 529525fb5a8fd9b96ab4021311a598c77588b918 +and 2614ed4c6e4b32eafb683f2378ed20e87d42976d +--- + Lib/test/test_ssl.py | 17 ++++++++++++++--- + 1 file changed, 14 insertions(+), 3 deletions(-) + +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +index a7bf2f7..43c2dbc 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -3189,7 +3189,12 @@ if _have_threads: + with context.wrap_socket(socket.socket()) as s: + self.assertIs(s.version(), None) + s.connect((HOST, server.port)) +- self.assertEqual(s.version(), 'TLSv1') ++ if IS_OPENSSL_1_1: ++ self.assertEqual(s.version(), 'TLSv1.3') ++ elif ssl.OPENSSL_VERSION_INFO >= (1, 0, 2): ++ self.assertEqual(s.version(), 'TLSv1.2') ++ else: # 0.9.8 to 1.0.1 ++ self.assertIn(s.version(), ('TLSv1', 'TLSv1.2')) + self.assertIs(s.version(), None) + + @unittest.skipUnless(ssl.HAS_TLSv1_3, +@@ -3259,7 +3264,10 @@ if _have_threads: + + # check if it is sane + self.assertIsNotNone(cb_data) +- self.assertEqual(len(cb_data), 12) # True for TLSv1 ++ if s.version() == 'TLSv1.3': ++ self.assertEqual(len(cb_data), 48) ++ else: ++ self.assertEqual(len(cb_data), 12) # True for TLSv1 + + # and compare with the peers version + s.write(b"CB tls-unique\n") +@@ -3283,7 +3291,10 @@ if _have_threads: + # is it really unique + self.assertNotEqual(cb_data, new_cb_data) + self.assertIsNotNone(cb_data) +- self.assertEqual(len(cb_data), 12) # True for TLSv1 ++ if s.version() == 'TLSv1.3': ++ self.assertEqual(len(cb_data), 48) ++ else: ++ self.assertEqual(len(cb_data), 12) # True for TLSv1 + s.write(b"CB tls-unique\n") + peer_data_repr = s.read().strip() + self.assertEqual(peer_data_repr, +-- +2.21.0 + + +From cd250c8a782f36c7a6f5ffabc922cb75744fa9c0 Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Tue, 26 Nov 2019 23:18:10 +0100 +Subject: [PATCH 5/5] Skip the ssl tests that rely on TLSv1 and TLSv1.1 + availability + +--- + Lib/test/test_ssl.py | 32 +++++++++++++++++++++++--------- + 1 file changed, 23 insertions(+), 9 deletions(-) + +diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py +index 43c2dbc..b35db25 100644 +--- a/Lib/test/test_ssl.py ++++ b/Lib/test/test_ssl.py +@@ -39,6 +39,13 @@ IS_LIBRESSL = ssl.OPENSSL_VERSION.startswith('LibreSSL') + IS_OPENSSL_1_1 = not IS_LIBRESSL and ssl.OPENSSL_VERSION_INFO >= (1, 1, 0) + PY_SSL_DEFAULT_CIPHERS = sysconfig.get_config_var('PY_SSL_DEFAULT_CIPHERS') + ++# On RHEL8 openssl disables TLSv1 and TLSv1.1 on runtime. ++# Since we don't have a good way to detect runtime changes ++# on the allowed protocols, we hardcode the default config ++# with those flags. ++TLSv1_enabled = False ++TLSv1_1_enabled = False ++ + def data_file(*name): + return os.path.join(os.path.dirname(__file__), *name) + +@@ -2380,7 +2387,8 @@ if _have_threads: + if support.verbose: + sys.stdout.write("\n") + for protocol in PROTOCOLS: +- if protocol in {ssl.PROTOCOL_TLS_CLIENT, ssl.PROTOCOL_TLS_SERVER}: ++ if protocol in {ssl.PROTOCOL_TLS_CLIENT, ssl.PROTOCOL_TLS_SERVER, ++ ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_1}: + continue + with self.subTest(protocol=ssl._PROTOCOL_NAMES[protocol]): + context = ssl.SSLContext(protocol) +@@ -2650,17 +2658,20 @@ if _have_threads: + if hasattr(ssl, 'PROTOCOL_SSLv3'): + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, False) + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True) +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1') ++ if TLSv1_enabled: ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1') + + if hasattr(ssl, 'PROTOCOL_SSLv3'): + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, False, ssl.CERT_OPTIONAL) + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_OPTIONAL) +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL) ++ if TLSv1_enabled: ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL) + + if hasattr(ssl, 'PROTOCOL_SSLv3'): + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv3, False, ssl.CERT_REQUIRED) + try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_SSLv23, True, ssl.CERT_REQUIRED) +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED) ++ if TLSv1_enabled: ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED) + + # Server with specific SSL options + if hasattr(ssl, 'PROTOCOL_SSLv3'): +@@ -2698,9 +2709,10 @@ if _have_threads: + """Connecting to a TLSv1 server with various client options""" + if support.verbose: + sys.stdout.write("\n") +- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1') +- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL) +- try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED) ++ if TLSv1_enabled: ++ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1') ++ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_OPTIONAL) ++ try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1, 'TLSv1', ssl.CERT_REQUIRED) + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_SSLv2, False) + if hasattr(ssl, 'PROTOCOL_SSLv3'): +@@ -2716,7 +2728,8 @@ if _have_threads: + Testing against older TLS versions.""" + if support.verbose: + sys.stdout.write("\n") +- try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1') ++ if TLSv1_1_enabled: ++ try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1') + if hasattr(ssl, 'PROTOCOL_SSLv2'): + try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv2, False) + if hasattr(ssl, 'PROTOCOL_SSLv3'): +@@ -2724,7 +2737,8 @@ if _have_threads: + try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_SSLv23, False, + client_options=ssl.OP_NO_TLSv1_1) + +- try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1') ++ if TLSv1_1_enabled: ++ try_protocol_combo(ssl.PROTOCOL_SSLv23, ssl.PROTOCOL_TLSv1_1, 'TLSv1.1') + try_protocol_combo(ssl.PROTOCOL_TLSv1_1, ssl.PROTOCOL_TLSv1, False) + try_protocol_combo(ssl.PROTOCOL_TLSv1, ssl.PROTOCOL_TLSv1_1, False) + +-- +2.21.0 + diff --git a/SOURCES/00318-test-ssl-fix-for-tls-13.patch b/SOURCES/00318-test-ssl-fix-for-tls-13.patch deleted file mode 100644 index 7b00d75..0000000 --- a/SOURCES/00318-test-ssl-fix-for-tls-13.patch +++ /dev/null @@ -1,44 +0,0 @@ -bpo-32947: test_ssl fixes for TLS 1.3 and OpenSSL 1.1.1 - -Backport partially commit 529525fb5a8fd9b96ab4021311a598c77588b918: -complete the previous partial backport (commit -2a4ee8aa01d61b6a9c8e9c65c211e61bdb471826. - -Reported upstream: - -* https://bugs.python.org/issue32947#msg333990 -* https://github.com/python/cpython/pull/11612 - -diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py -index 7f8f636..05c09a6 100644 ---- a/Lib/test/test_ssl.py -+++ b/Lib/test/test_ssl.py -@@ -2021,6 +2021,16 @@ if _have_threads: - sys.stdout.write(" server: read %r (%s), sending back %r (%s)...\n" - % (msg, ctype, msg.lower(), ctype)) - self.write(msg.lower()) -+ except ConnectionResetError: -+ # XXX: OpenSSL 1.1.1 sometimes raises ConnectionResetError -+ # when connection is not shut down gracefully. -+ if self.server.chatty and support.verbose: -+ sys.stdout.write( -+ " Connection reset by peer: {}\n".format( -+ self.addr) -+ ) -+ self.close() -+ self.running = False - except OSError: - if self.server.chatty: - handle_error("Test server failure:\n") -@@ -2100,6 +2110,11 @@ if _have_threads: - pass - except KeyboardInterrupt: - self.stop() -+ except BaseException as e: -+ if support.verbose and self.chatty: -+ sys.stdout.write( -+ ' connection handling failed: ' + repr(e) + '\n') -+ - self.sock.close() - - def stop(self): diff --git a/SOURCES/00329-fips.patch b/SOURCES/00329-fips.patch index b1ec9f8..e250caa 100644 --- a/SOURCES/00329-fips.patch +++ b/SOURCES/00329-fips.patch @@ -1,267 +1,1046 @@ -From f85cd78683a7f4216f85439ff12bde07c8118597 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Thu, 25 Jul 2019 16:19:52 +0200 -Subject: [PATCH 01/36] Expose OpenSSL FIPS_mode() as hashlib.get_fips_mode() +From 53d108c5103c99079f1f231b0e731f3f47a142fc Mon Sep 17 00:00:00 2001 +From: "Miss Islington (bot)" + <31488909+miss-islington@users.noreply.github.com> +Date: Wed, 25 Sep 2019 08:50:31 -0700 +Subject: [PATCH 01/36] [3.8] bpo-38270: Check for hash digest algorithms and + avoid MD5 (GH-16382) (GH-16393) + +Make it easier to run and test Python on systems with restrict crypto policies: + +* add requires_hashdigest to test.support to check if a hash digest algorithm is available and working +* avoid MD5 in test_hmac +* replace MD5 with SHA256 in test_tarfile +* mark network tests that require MD5 for MD5-based digest auth or CRAM-MD5 +https://bugs.python.org/issue38270 +(cherry picked from commit c64a1a61e6fc542cada40eb069a239317e1af36e) + +Co-authored-by: Christian Heimes + +https://bugs.python.org/issue38270 + +Automerge-Triggered-By: @tiran --- - Lib/hashlib.py | 5 +++++ - Modules/_hashopenssl.c | 36 +++++++++++++++++++++++++++++++++ - Modules/clinic/_hashopenssl.c.h | 25 ++++++++++++++++++++++- - 3 files changed, 65 insertions(+), 1 deletion(-) + Lib/test/support/__init__.py | 22 ++++++++++ + Lib/test/test_hmac.py | 67 +++++++++++++++++++------------ + Lib/test/test_imaplib.py | 6 ++- + Lib/test/test_poplib.py | 2 + + Lib/test/test_smtplib.py | 11 ++++- + Lib/test/test_tarfile.py | 56 ++++++++++++++------------ + Lib/test/test_urllib2_localnet.py | 1 + + 7 files changed, 112 insertions(+), 53 deletions(-) -diff --git a/Lib/hashlib.py b/Lib/hashlib.py -index 98d2d7981a38..ae17c5851109 100644 ---- a/Lib/hashlib.py -+++ b/Lib/hashlib.py -@@ -236,6 +236,11 @@ def prf(msg, inner=inner, outer=outer): - except ImportError: - pass +diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py +index 66c0fed8411..a43819904e0 100644 +--- a/Lib/test/support/__init__.py ++++ b/Lib/test/support/__init__.py +@@ -11,6 +11,7 @@ import faulthandler + import fnmatch + import functools + import gc ++import hashlib + import importlib + import importlib.util + import io +@@ -627,6 +628,27 @@ def requires_mac_ver(*min_version): + return wrapper + return decorator + ++def requires_hashdigest(digestname): ++ """Decorator raising SkipTest if a hashing algorithm is not available ++ ++ The hashing algorithm could be missing or blocked by a strict crypto ++ policy. ++ ++ ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS ++ ValueError: unsupported hash type md4 ++ """ ++ def decorator(func): ++ @functools.wraps(func) ++ def wrapper(*args, **kwargs): ++ try: ++ hashlib.new(digestname) ++ except ValueError: ++ raise unittest.SkipTest( ++ f"hash digest '{digestname}' is not available." ++ ) ++ return func(*args, **kwargs) ++ return wrapper ++ return decorator + + # Don't use "localhost", since resolving it uses the DNS under recent + # Windows versions (see issue #18792). +diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py +index 067e13f1079..81c3485f761 100644 +--- a/Lib/test/test_hmac.py ++++ b/Lib/test/test_hmac.py +@@ -4,6 +4,8 @@ import hashlib + import unittest + import warnings -+try: -+ from _hashlib import get_fips_mode -+except ImportError: -+ pass ++from test.support import requires_hashdigest + - for __func_name in __always_supported: - # try them all, some may not work due to the OpenSSL -diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c -index 84edd72c85a3..4876a7f7aa76 100644 ---- a/Modules/_hashopenssl.c -+++ b/Modules/_hashopenssl.c -@@ -25,6 +25,9 @@ - #include - #include "openssl/err.h" + def ignore_warning(func): + @functools.wraps(func) +@@ -17,6 +19,7 @@ def ignore_warning(func): -+/* Expose FIPS_mode */ -+#include -+ - #include "clinic/_hashopenssl.c.h" - /*[clinic input] - module _hashlib -@@ -987,6 +990,38 @@ GEN_CONSTRUCTOR(sha256) - GEN_CONSTRUCTOR(sha384) - GEN_CONSTRUCTOR(sha512) + class TestVectorsTestCase(unittest.TestCase): -+/*[clinic input] -+_hashlib.get_fips_mode -+ -+Determine the OpenSSL FIPS mode of operation. -+ -+Effectively any non-zero return value indicates FIPS mode; -+values other than 1 may have additional significance. -+ -+See OpenSSL documentation for the FIPS_mode() function for details. -+[clinic start generated code]*/ -+ -+static PyObject * -+_hashlib_get_fips_mode_impl(PyObject *module) -+/*[clinic end generated code: output=ad8a7793310d3f98 input=f42a2135df2a5e11]*/ -+{ -+ int result = FIPS_mode(); -+ if (result == 0) { -+ // "If the library was built without support of the FIPS Object Module, -+ // then the function will return 0 with an error code of -+ // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." -+ // But 0 is also a valid result value. -+ -+ unsigned long errcode = ERR_peek_last_error(); -+ if (errcode) { -+ _setException(PyExc_ValueError); -+ return NULL; -+ } -+ } -+ return PyLong_FromLong(result); -+} -+ -+ - /* List of functions exported by this module */ ++ @requires_hashdigest('md5') + def test_md5_vectors(self): + # Test the HMAC module against test vectors from the RFC. - static struct PyMethodDef EVP_functions[] = { -@@ -996,6 +1031,7 @@ static struct PyMethodDef EVP_functions[] = { - pbkdf2_hmac__doc__}, - #endif - _HASHLIB_SCRYPT_METHODDEF -+ _HASHLIB_GET_FIPS_MODE_METHODDEF - CONSTRUCTOR_METH_DEF(md5), - CONSTRUCTOR_METH_DEF(sha1), - CONSTRUCTOR_METH_DEF(sha224), -diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h -index 04453526040b..8828e2776e95 100644 ---- a/Modules/clinic/_hashopenssl.c.h -+++ b/Modules/clinic/_hashopenssl.c.h -@@ -54,7 +54,30 @@ _hashlib_scrypt(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *k +@@ -63,6 +66,7 @@ class TestVectorsTestCase(unittest.TestCase): + b"and Larger Than One Block-Size Data"), + "6f630fad67cda0ee1fb1f562db3aa53e") - #endif /* (OPENSSL_VERSION_NUMBER > 0x10100000L && !defined(OPENSSL_NO_SCRYPT) && !defined(LIBRESSL_VERSION_NUMBER)) */ ++ @requires_hashdigest('sha1') + def test_sha_vectors(self): + def shatest(key, data, digest): + h = hmac.HMAC(key, data, digestmod=hashlib.sha1) +@@ -230,23 +234,28 @@ class TestVectorsTestCase(unittest.TestCase): + '134676fb6de0446065c97440fa8c6a58', + }) -+PyDoc_STRVAR(_hashlib_get_fips_mode__doc__, -+"get_fips_mode($module, /)\n" -+"--\n" -+"\n" -+"Determine the OpenSSL FIPS mode of operation.\n" -+"\n" -+"Effectively any non-zero return value indicates FIPS mode;\n" -+"values other than 1 may have additional significance.\n" -+"\n" -+"See OpenSSL documentation for the FIPS_mode() function for details."); -+ -+#define _HASHLIB_GET_FIPS_MODE_METHODDEF \ -+ {"get_fips_mode", (PyCFunction)_hashlib_get_fips_mode, METH_NOARGS, _hashlib_get_fips_mode__doc__}, -+ -+static PyObject * -+_hashlib_get_fips_mode_impl(PyObject *module); -+ -+static PyObject * -+_hashlib_get_fips_mode(PyObject *module, PyObject *Py_UNUSED(ignored)) -+{ -+ return _hashlib_get_fips_mode_impl(module); -+} -+ - #ifndef _HASHLIB_SCRYPT_METHODDEF - #define _HASHLIB_SCRYPT_METHODDEF - #endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */ --/*[clinic end generated code: output=118cd7036fa0fb52 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=7d683c930bbb7c36 input=a9049054013a1b77]*/ - -From b8c716a651d5884e0dfdbb2cfefb0f49a0ee0540 Mon Sep 17 00:00:00 2001 -From: Charalampos Stratakis -Date: Thu, 25 Jul 2019 17:04:06 +0200 -Subject: [PATCH 02/36] Use python's fall backs for the crypto it implements - only if we are not in FIPS mode - ---- - Lib/hashlib.py | 209 +++++++++++++++------------------------ - Lib/test/test_hashlib.py | 1 + - 2 files changed, 81 insertions(+), 129 deletions(-) - -diff --git a/Lib/hashlib.py b/Lib/hashlib.py -index ae17c5851109..7db1e02601fe 100644 ---- a/Lib/hashlib.py -+++ b/Lib/hashlib.py -@@ -67,56 +67,64 @@ - __all__ = __always_supported + ('new', 'algorithms_guaranteed', - 'algorithms_available', 'pbkdf2_hmac') ++ @requires_hashdigest('sha224') + def test_sha224_rfc4231(self): + self._rfc4231_test_cases(hashlib.sha224, 'sha224', 28, 64) -- --__builtin_constructor_cache = {} -- --def __get_builtin_constructor(name): -- cache = __builtin_constructor_cache -- constructor = cache.get(name) -- if constructor is not None: -- return constructor -- try: -- if name in ('SHA1', 'sha1'): -- import _sha1 -- cache['SHA1'] = cache['sha1'] = _sha1.sha1 -- elif name in ('MD5', 'md5'): -- import _md5 -- cache['MD5'] = cache['md5'] = _md5.md5 -- elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): -- import _sha256 -- cache['SHA224'] = cache['sha224'] = _sha256.sha224 -- cache['SHA256'] = cache['sha256'] = _sha256.sha256 -- elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): -- import _sha512 -- cache['SHA384'] = cache['sha384'] = _sha512.sha384 -- cache['SHA512'] = cache['sha512'] = _sha512.sha512 -- elif name in ('blake2b', 'blake2s'): -- import _blake2 -- cache['blake2b'] = _blake2.blake2b -- cache['blake2s'] = _blake2.blake2s -- elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', -- 'shake_128', 'shake_256'}: -- import _sha3 -- cache['sha3_224'] = _sha3.sha3_224 -- cache['sha3_256'] = _sha3.sha3_256 -- cache['sha3_384'] = _sha3.sha3_384 -- cache['sha3_512'] = _sha3.sha3_512 -- cache['shake_128'] = _sha3.shake_128 -- cache['shake_256'] = _sha3.shake_256 -- except ImportError: -- pass # no extension module, this hash is unsupported. -- -- constructor = cache.get(name) -- if constructor is not None: -- return constructor -- -- raise ValueError('unsupported hash type ' + name) -+try: -+ from _hashlib import get_fips_mode -+except ImportError: -+ def get_fips_mode(): -+ return 0 -+ -+ -+if not get_fips_mode(): -+ __builtin_constructor_cache = {} -+ -+ def __get_builtin_constructor(name): -+ cache = __builtin_constructor_cache -+ constructor = cache.get(name) -+ if constructor is not None: -+ return constructor -+ try: -+ if name in ('SHA1', 'sha1'): -+ import _sha1 -+ cache['SHA1'] = cache['sha1'] = _sha1.sha1 -+ elif name in ('MD5', 'md5'): -+ import _md5 -+ cache['MD5'] = cache['md5'] = _md5.md5 -+ elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): -+ import _sha256 -+ cache['SHA224'] = cache['sha224'] = _sha256.sha224 -+ cache['SHA256'] = cache['sha256'] = _sha256.sha256 -+ elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): -+ import _sha512 -+ cache['SHA384'] = cache['sha384'] = _sha512.sha384 -+ cache['SHA512'] = cache['sha512'] = _sha512.sha512 -+ elif name in ('blake2b', 'blake2s'): -+ import _blake2 -+ cache['blake2b'] = _blake2.blake2b -+ cache['blake2s'] = _blake2.blake2s -+ elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', -+ 'shake_128', 'shake_256'}: -+ import _sha3 -+ cache['sha3_224'] = _sha3.sha3_224 -+ cache['sha3_256'] = _sha3.sha3_256 -+ cache['sha3_384'] = _sha3.sha3_384 -+ cache['sha3_512'] = _sha3.sha3_512 -+ cache['shake_128'] = _sha3.shake_128 -+ cache['shake_256'] = _sha3.shake_256 -+ except ImportError: -+ pass # no extension module, this hash is unsupported. -+ -+ constructor = cache.get(name) -+ if constructor is not None: -+ return constructor -+ -+ raise ValueError('unsupported hash type ' + name) ++ @requires_hashdigest('sha256') + def test_sha256_rfc4231(self): + self._rfc4231_test_cases(hashlib.sha256, 'sha256', 32, 64) ++ @requires_hashdigest('sha384') + def test_sha384_rfc4231(self): + self._rfc4231_test_cases(hashlib.sha384, 'sha384', 48, 128) - def __get_openssl_constructor(name): -- if name in {'blake2b', 'blake2s'}: -- # Prefer our blake2 implementation. -- return __get_builtin_constructor(name) -+ if not get_fips_mode(): -+ if name in {'blake2b', 'blake2s'}: -+ # Prefer our blake2 implementation. -+ return __get_builtin_constructor(name) - try: - f = getattr(_hashlib, 'openssl_' + name) - # Allow the C module to raise ValueError. The function will be -@@ -125,27 +133,30 @@ def __get_openssl_constructor(name): - # Use the C function directly (very fast) - return f - except (AttributeError, ValueError): -+ if get_fips_mode(): -+ raise - return __get_builtin_constructor(name) ++ @requires_hashdigest('sha512') + def test_sha512_rfc4231(self): + self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128) -- --def __py_new(name, data=b'', **kwargs): -- """new(name, data=b'', **kwargs) - Return a new hashing object using the -- named algorithm; optionally initialized with data (which must be ++ @requires_hashdigest('sha256') + def test_legacy_block_size_warnings(self): + class MockCrazyHash(object): + """Ain't no block_size attribute here.""" + def __init__(self, *args): +- self._x = hashlib.sha1(*args) ++ self._x = hashlib.sha256(*args) + self.digest_size = self._x.digest_size + def update(self, v): + self._x.update(v) +@@ -273,76 +282,80 @@ class TestVectorsTestCase(unittest.TestCase): + self.assertEqual(h.hexdigest().upper(), digest) + + ++ + class ConstructorTestCase(unittest.TestCase): + ++ expected = ( ++ "6c845b47f52b3b47f6590c502db7825aad757bf4fadc8fa972f7cd2e76a5bdeb" ++ ) + @ignore_warning ++ @requires_hashdigest('sha256') + def test_normal(self): + # Standard constructor call. +- failed = 0 + try: +- h = hmac.HMAC(b"key") ++ hmac.HMAC(b"key", digestmod='sha256') + except Exception: + self.fail("Standard constructor call raised exception.") + + @ignore_warning ++ @requires_hashdigest('sha256') + def test_with_str_key(self): + # Pass a key of type str, which is an error, because it expects a key + # of type bytes + with self.assertRaises(TypeError): +- h = hmac.HMAC("key") ++ h = hmac.HMAC("key", digestmod='sha256') + +- @ignore_warning ++ @requires_hashdigest('sha256') + def test_dot_new_with_str_key(self): + # Pass a key of type str, which is an error, because it expects a key + # of type bytes + with self.assertRaises(TypeError): +- h = hmac.new("key") ++ h = hmac.HMAC("key", digestmod='sha256') + + @ignore_warning ++ @requires_hashdigest('sha256') + def test_withtext(self): + # Constructor call with text. + try: +- h = hmac.HMAC(b"key", b"hash this!") ++ h = hmac.HMAC(b"key", b"hash this!", digestmod='sha256') + except Exception: + self.fail("Constructor call with text argument raised exception.") +- self.assertEqual(h.hexdigest(), '34325b639da4cfd95735b381e28cb864') ++ self.assertEqual(h.hexdigest(), self.expected) + ++ @requires_hashdigest('sha256') + def test_with_bytearray(self): + try: + h = hmac.HMAC(bytearray(b"key"), bytearray(b"hash this!"), +- digestmod="md5") ++ digestmod="sha256") + except Exception: + self.fail("Constructor call with bytearray arguments raised exception.") +- self.assertEqual(h.hexdigest(), '34325b639da4cfd95735b381e28cb864') ++ self.assertEqual(h.hexdigest(), self.expected) + ++ @requires_hashdigest('sha256') + def test_with_memoryview_msg(self): + try: +- h = hmac.HMAC(b"key", memoryview(b"hash this!"), digestmod="md5") ++ h = hmac.HMAC(b"key", memoryview(b"hash this!"), digestmod="sha256") + except Exception: + self.fail("Constructor call with memoryview msg raised exception.") +- self.assertEqual(h.hexdigest(), '34325b639da4cfd95735b381e28cb864') ++ self.assertEqual(h.hexdigest(), self.expected) + ++ @requires_hashdigest('sha256') + def test_withmodule(self): + # Constructor call with text and digest module. + try: +- h = hmac.HMAC(b"key", b"", hashlib.sha1) ++ h = hmac.HMAC(b"key", b"", hashlib.sha256) + except Exception: +- self.fail("Constructor call with hashlib.sha1 raised exception.") ++ self.fail("Constructor call with hashlib.sha256 raised exception.") + +-class SanityTestCase(unittest.TestCase): + +- @ignore_warning +- def test_default_is_md5(self): +- # Testing if HMAC defaults to MD5 algorithm. +- # NOTE: this whitebox test depends on the hmac class internals +- h = hmac.HMAC(b"key") +- self.assertEqual(h.digest_cons, hashlib.md5) ++class SanityTestCase(unittest.TestCase): + ++ @requires_hashdigest('sha256') + def test_exercise_all_methods(self): + # Exercising all methods once. + # This must not raise any exceptions + try: +- h = hmac.HMAC(b"my secret key", digestmod="md5") ++ h = hmac.HMAC(b"my secret key", digestmod="sha256") + h.update(b"compute the hash of this text!") + dig = h.digest() + dig = h.hexdigest() +@@ -350,11 +363,13 @@ class SanityTestCase(unittest.TestCase): + except Exception: + self.fail("Exception raised during normal usage of HMAC class.") + ++ + class CopyTestCase(unittest.TestCase): + ++ @requires_hashdigest('sha256') + def test_attributes(self): + # Testing if attributes are of same type. +- h1 = hmac.HMAC(b"key", digestmod="md5") ++ h1 = hmac.HMAC(b"key", digestmod="sha256") + h2 = h1.copy() + self.assertTrue(h1.digest_cons == h2.digest_cons, + "digest constructors don't match.") +@@ -363,9 +378,10 @@ class CopyTestCase(unittest.TestCase): + self.assertEqual(type(h1.outer), type(h2.outer), + "Types of outer don't match.") + ++ @requires_hashdigest('sha256') + def test_realcopy(self): + # Testing if the copy method created a real copy. +- h1 = hmac.HMAC(b"key", digestmod="md5") ++ h1 = hmac.HMAC(b"key", digestmod="sha256") + h2 = h1.copy() + # Using id() in case somebody has overridden __eq__/__ne__. + self.assertTrue(id(h1) != id(h2), "No real copy of the HMAC instance.") +@@ -374,9 +390,10 @@ class CopyTestCase(unittest.TestCase): + self.assertTrue(id(h1.outer) != id(h2.outer), + "No real copy of the attribute 'outer'.") + ++ @requires_hashdigest('sha256') + def test_equality(self): + # Testing if the copy has the same digests. +- h1 = hmac.HMAC(b"key", digestmod="md5") ++ h1 = hmac.HMAC(b"key", digestmod="sha256") + h1.update(b"some random text") + h2 = h1.copy() + self.assertEqual(h1.digest(), h2.digest(), +diff --git a/Lib/test/test_imaplib.py b/Lib/test/test_imaplib.py +index 0593a3756b0..086cc0ac4e0 100644 +--- a/Lib/test/test_imaplib.py ++++ b/Lib/test/test_imaplib.py +@@ -14,7 +14,8 @@ import calendar + import inspect + + from test.support import (reap_threads, verbose, transient_internet, +- run_with_tz, run_with_locale, cpython_only) ++ run_with_tz, run_with_locale, cpython_only, ++ requires_hashdigest) + import unittest + from unittest import mock + from datetime import datetime, timezone, timedelta +@@ -369,6 +370,7 @@ class NewIMAPTestsMixin(): + self.assertEqual(code, 'OK') + self.assertEqual(server.response, b'ZmFrZQ==\r\n') # b64 encoded 'fake' + ++ @requires_hashdigest('md5') + def test_login_cram_md5_bytes(self): + class AuthHandler(SimpleIMAPHandler): + capabilities = 'LOGINDISABLED AUTH=CRAM-MD5' +@@ -386,6 +388,7 @@ class NewIMAPTestsMixin(): + ret, _ = client.login_cram_md5("tim", b"tanstaaftanstaaf") + self.assertEqual(ret, "OK") + ++ @requires_hashdigest('md5') + def test_login_cram_md5_plain_text(self): + class AuthHandler(SimpleIMAPHandler): + capabilities = 'LOGINDISABLED AUTH=CRAM-MD5' +@@ -797,6 +800,7 @@ class ThreadedNetworkedTests(unittest.TestCase): + b'ZmFrZQ==\r\n') # b64 encoded 'fake' + + @reap_threads ++ @requires_hashdigest('md5') + def test_login_cram_md5(self): + + class AuthHandler(SimpleIMAPHandler): +diff --git a/Lib/test/test_poplib.py b/Lib/test/test_poplib.py +index 234c855545c..b8146be3a8c 100644 +--- a/Lib/test/test_poplib.py ++++ b/Lib/test/test_poplib.py +@@ -304,9 +304,11 @@ class TestPOP3Class(TestCase): + def test_rpop(self): + self.assertOK(self.client.rpop('foo')) + ++ @test_support.requires_hashdigest('md5') + def test_apop_normal(self): + self.assertOK(self.client.apop('foo', 'dummypassword')) + ++ @test_support.requires_hashdigest('md5') + def test_apop_REDOS(self): + # Replace welcome with very long evil welcome. + # NB The upper bound on welcome length is currently 2048. +diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py +index 87047514e7a..64b3201254a 100644 +--- a/Lib/test/test_smtplib.py ++++ b/Lib/test/test_smtplib.py +@@ -4,6 +4,7 @@ import email.mime.text + from email.message import EmailMessage + from email.base64mime import body_encode as encode_base64 + import email.utils ++import hashlib + import hmac + import socket + import smtpd +@@ -18,6 +19,7 @@ import textwrap + + import unittest + from test import support, mock_socket ++from test.support import requires_hashdigest + from unittest.mock import Mock + + HOST = "localhost" +@@ -968,6 +970,7 @@ class SMTPSimTests(unittest.TestCase): + self.assertEqual(resp, (235, b'Authentication Succeeded')) + smtp.close() + ++ @requires_hashdigest('md5') + def testAUTH_CRAM_MD5(self): + self.serv.add_feature("AUTH CRAM-MD5") + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) +@@ -984,7 +987,13 @@ class SMTPSimTests(unittest.TestCase): + smtp.close() + + def test_auth_function(self): +- supported = {'CRAM-MD5', 'PLAIN', 'LOGIN'} ++ supported = {'PLAIN', 'LOGIN'} ++ try: ++ hashlib.md5() ++ except ValueError: ++ pass ++ else: ++ supported.add('CRAM-MD5') + for mechanism in supported: + self.serv.add_feature("AUTH {}".format(mechanism)) + for mechanism in supported: +diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py +index 4cd7d5370f5..b5e855e0d7e 100644 +--- a/Lib/test/test_tarfile.py ++++ b/Lib/test/test_tarfile.py +@@ -1,7 +1,7 @@ + import sys + import os + import io +-from hashlib import md5 ++from hashlib import sha256 + from contextlib import contextmanager + from random import Random + import pathlib +@@ -11,7 +11,7 @@ import unittest.mock + import tarfile + + from test import support +-from test.support import script_helper ++from test.support import script_helper, requires_hashdigest + + # Check for our compression modules. + try: +@@ -27,8 +27,8 @@ try: + except ImportError: + lzma = None + +-def md5sum(data): +- return md5(data).hexdigest() ++def sha256sum(data): ++ return sha256(data).hexdigest() + + TEMPDIR = os.path.abspath(support.TESTFN) + "-tardir" + tarextdir = TEMPDIR + '-extract-test' +@@ -39,8 +39,12 @@ xzname = os.path.join(TEMPDIR, "testtar.tar.xz") + tmpname = os.path.join(TEMPDIR, "tmp.tar") + dotlessname = os.path.join(TEMPDIR, "testtar") + +-md5_regtype = "65f477c818ad9e15f7feab0c6d37742f" +-md5_sparse = "a54fbc4ca4f4399a90e1b27164012fc6" ++sha256_regtype = ( ++ "e09e4bc8b3c9d9177e77256353b36c159f5f040531bbd4b024a8f9b9196c71ce" ++) ++sha256_sparse = ( ++ "4f05a776071146756345ceee937b33fc5644f5a96b9780d1c7d6a32cdf164d7b" ++) + + + class TarTest: +@@ -95,7 +99,7 @@ class UstarReadTest(ReadTest, unittest.TestCase): + data = fobj.read() + self.assertEqual(len(data), tarinfo.size, + "regular file extraction failed") +- self.assertEqual(md5sum(data), md5_regtype, ++ self.assertEqual(sha256sum(data), sha256_regtype, + "regular file extraction failed") + + def test_fileobj_readlines(self): +@@ -180,7 +184,7 @@ class UstarReadTest(ReadTest, unittest.TestCase): + with self.tar.extractfile("ustar/regtype") as fobj: + fobj = io.TextIOWrapper(fobj) + data = fobj.read().encode("iso8859-1") +- self.assertEqual(md5sum(data), md5_regtype) ++ self.assertEqual(sha256sum(data), sha256_regtype) + try: + fobj.seek(100) + except AttributeError: +@@ -546,13 +550,13 @@ class MiscReadTestBase(CommonReadTest): + self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/lnktype")) + with open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb") as f: + data = f.read() +- self.assertEqual(md5sum(data), md5_regtype) ++ self.assertEqual(sha256sum(data), sha256_regtype) + + tar.extract("ustar/symtype", TEMPDIR) + self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/symtype")) + with open(os.path.join(TEMPDIR, "ustar/symtype"), "rb") as f: + data = f.read() +- self.assertEqual(md5sum(data), md5_regtype) ++ self.assertEqual(sha256sum(data), sha256_regtype) + + def test_extractall(self): + # Test if extractall() correctly restores directory permissions +@@ -687,7 +691,7 @@ class StreamReadTest(CommonReadTest, unittest.TestCase): + data = fobj.read() + self.assertEqual(len(data), tarinfo.size, + "regular file extraction failed") +- self.assertEqual(md5sum(data), md5_regtype, ++ self.assertEqual(sha256sum(data), sha256_regtype, + "regular file extraction failed") + + def test_provoke_stream_error(self): +@@ -799,8 +803,8 @@ class MemberReadTest(ReadTest, unittest.TestCase): + def _test_member(self, tarinfo, chksum=None, **kwargs): + if chksum is not None: + with self.tar.extractfile(tarinfo) as f: +- self.assertEqual(md5sum(f.read()), chksum, +- "wrong md5sum for %s" % tarinfo.name) ++ self.assertEqual(sha256sum(f.read()), chksum, ++ "wrong sha256sum for %s" % tarinfo.name) + + kwargs["mtime"] = 0o7606136617 + kwargs["uid"] = 1000 +@@ -815,11 +819,11 @@ class MemberReadTest(ReadTest, unittest.TestCase): + + def test_find_regtype(self): + tarinfo = self.tar.getmember("ustar/regtype") +- self._test_member(tarinfo, size=7011, chksum=md5_regtype) ++ self._test_member(tarinfo, size=7011, chksum=sha256_regtype) + + def test_find_conttype(self): + tarinfo = self.tar.getmember("ustar/conttype") +- self._test_member(tarinfo, size=7011, chksum=md5_regtype) ++ self._test_member(tarinfo, size=7011, chksum=sha256_regtype) + + def test_find_dirtype(self): + tarinfo = self.tar.getmember("ustar/dirtype") +@@ -851,28 +855,28 @@ class MemberReadTest(ReadTest, unittest.TestCase): + + def test_find_sparse(self): + tarinfo = self.tar.getmember("ustar/sparse") +- self._test_member(tarinfo, size=86016, chksum=md5_sparse) ++ self._test_member(tarinfo, size=86016, chksum=sha256_sparse) + + def test_find_gnusparse(self): + tarinfo = self.tar.getmember("gnu/sparse") +- self._test_member(tarinfo, size=86016, chksum=md5_sparse) ++ self._test_member(tarinfo, size=86016, chksum=sha256_sparse) + + def test_find_gnusparse_00(self): + tarinfo = self.tar.getmember("gnu/sparse-0.0") +- self._test_member(tarinfo, size=86016, chksum=md5_sparse) ++ self._test_member(tarinfo, size=86016, chksum=sha256_sparse) + + def test_find_gnusparse_01(self): + tarinfo = self.tar.getmember("gnu/sparse-0.1") +- self._test_member(tarinfo, size=86016, chksum=md5_sparse) ++ self._test_member(tarinfo, size=86016, chksum=sha256_sparse) + + def test_find_gnusparse_10(self): + tarinfo = self.tar.getmember("gnu/sparse-1.0") +- self._test_member(tarinfo, size=86016, chksum=md5_sparse) ++ self._test_member(tarinfo, size=86016, chksum=sha256_sparse) + + def test_find_umlauts(self): + tarinfo = self.tar.getmember("ustar/umlauts-" + "\xc4\xd6\xdc\xe4\xf6\xfc\xdf") +- self._test_member(tarinfo, size=7011, chksum=md5_regtype) ++ self._test_member(tarinfo, size=7011, chksum=sha256_regtype) + + def test_find_ustar_longname(self): + name = "ustar/" + "12345/" * 39 + "1234567/longname" +@@ -880,7 +884,7 @@ class MemberReadTest(ReadTest, unittest.TestCase): + + def test_find_regtype_oldv7(self): + tarinfo = self.tar.getmember("misc/regtype-old-v7") +- self._test_member(tarinfo, size=7011, chksum=md5_regtype) ++ self._test_member(tarinfo, size=7011, chksum=sha256_regtype) + + def test_find_pax_umlauts(self): + self.tar.close() +@@ -888,7 +892,7 @@ class MemberReadTest(ReadTest, unittest.TestCase): + encoding="iso8859-1") + tarinfo = self.tar.getmember("pax/umlauts-" + "\xc4\xd6\xdc\xe4\xf6\xfc\xdf") +- self._test_member(tarinfo, size=7011, chksum=md5_regtype) ++ self._test_member(tarinfo, size=7011, chksum=sha256_regtype) + + + class LongnameTest: +@@ -950,8 +954,8 @@ class GNUReadTest(LongnameTest, ReadTest, unittest.TestCase): + filename = os.path.join(TEMPDIR, name) + with open(filename, "rb") as fobj: + data = fobj.read() +- self.assertEqual(md5sum(data), md5_sparse, +- "wrong md5sum for %s" % name) ++ self.assertEqual(sha256sum(data), sha256_sparse, ++ "wrong sha256sum for %s" % name) + + if self._fs_supports_holes(): + s = os.stat(filename) +@@ -2431,7 +2435,7 @@ class LinkEmulationTest(ReadTest, unittest.TestCase): + self.tar.extract(name, TEMPDIR) + with open(os.path.join(TEMPDIR, name), "rb") as f: + data = f.read() +- self.assertEqual(md5sum(data), md5_regtype) ++ self.assertEqual(sha256sum(data), sha256_regtype) + + # See issues #1578269, #8879, and #17689 for some history on these skips + @unittest.skipIf(hasattr(os.path, "islink"), +diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py +index ef0091c4930..895f97cc09a 100644 +--- a/Lib/test/test_urllib2_localnet.py ++++ b/Lib/test/test_urllib2_localnet.py +@@ -325,6 +325,7 @@ class ProxyAuthTests(unittest.TestCase): + PASSWD = "test123" + REALM = "TestRealm" + ++ @support.requires_hashdigest("md5") + def setUp(self): + super(ProxyAuthTests, self).setUp() + # Ignore proxy bypass settings in the environment. +-- +2.21.0 + + +From 75d9613294e1cbd5aab9363cf3c435871a25f065 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Mon, 30 Sep 2019 09:10:38 +0200 +Subject: [PATCH 02/36] [3.8] bpo-38270: More fixes for strict crypto policy + (GH-16418) (#16437) + +test_hmac and test_hashlib test built-in hashing implementations and +OpenSSL-based hashing implementations. Add more checks to skip OpenSSL +implementations when a strict crypto policy is active. + +Use EVP_DigestInit_ex() instead of EVP_DigestInit() to initialize the +EVP context. The EVP_DigestInit() function clears alls flags and breaks +usedforsecurity flag again. + +Signed-off-by: Christian Heimes + +https://bugs.python.org/issue38270. +(cherry picked from commit 90558158093c0ad893102158fd3c2dd9f864e82e) + +Co-authored-by: Christian Heimes +--- + Lib/test/support/__init__.py | 19 ++++++++++++++++--- + Lib/test/test_hashlib.py | 3 +++ + Lib/test/test_hmac.py | 12 ++++++------ + 3 files changed, 25 insertions(+), 9 deletions(-) + +diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py +index a43819904e0..3342218cf0a 100644 +--- a/Lib/test/support/__init__.py ++++ b/Lib/test/support/__init__.py +@@ -71,6 +71,11 @@ try: + except ImportError: + resource = None + ++try: ++ import _hashlib ++except ImportError: ++ _hashlib = None ++ + __all__ = [ + # globals + "PIPE_MAX_SIZE", "verbose", "max_memuse", "use_resources", "failfast", +@@ -88,7 +93,8 @@ __all__ = [ + "create_empty_file", "can_symlink", "fs_is_case_insensitive", + # unittest + "is_resource_enabled", "requires", "requires_freebsd_version", +- "requires_linux_version", "requires_mac_ver", "check_syntax_error", ++ "requires_linux_version", "requires_mac_ver", "requires_hashdigest", ++ "check_syntax_error", + "TransientResource", "time_out", "socket_peer_reset", "ioerror_peer_reset", + "transient_internet", "BasicTestRunner", "run_unittest", "run_doctest", + "skip_unless_symlink", "requires_gzip", "requires_bz2", "requires_lzma", +@@ -628,12 +634,16 @@ def requires_mac_ver(*min_version): + return wrapper + return decorator + +-def requires_hashdigest(digestname): ++def requires_hashdigest(digestname, openssl=None): + """Decorator raising SkipTest if a hashing algorithm is not available + + The hashing algorithm could be missing or blocked by a strict crypto + policy. + ++ If 'openssl' is True, then the decorator checks that OpenSSL provides ++ the algorithm. Otherwise the check falls back to built-in ++ implementations. ++ + ValueError: [digital envelope routines: EVP_DigestInit_ex] disabled for FIPS + ValueError: unsupported hash type md4 + """ +@@ -641,7 +651,10 @@ def requires_hashdigest(digestname): + @functools.wraps(func) + def wrapper(*args, **kwargs): + try: +- hashlib.new(digestname) ++ if openssl and _hashlib is not None: ++ _hashlib.new(digestname) ++ else: ++ hashlib.new(digestname) + except ValueError: + raise unittest.SkipTest( + f"hash digest '{digestname}' is not available." +diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py +index 9711856853d..1b1b4d54112 100644 +--- a/Lib/test/test_hashlib.py ++++ b/Lib/test/test_hashlib.py +@@ -8,6 +8,7 @@ + + import array + from binascii import unhexlify ++import functools + import hashlib + import importlib + import itertools +@@ -21,6 +22,7 @@ import unittest + import warnings + from test import support + from test.support import _4G, bigmemtest, import_fresh_module ++from test.support import requires_hashdigest + from http.client import HTTPException + + # Were we compiled --with-pydebug or with #define Py_DEBUG? +@@ -117,6 +119,7 @@ class HashLibTestCase(unittest.TestCase): + constructors.add(_test_algorithm_via_hashlib_new) + + _hashlib = self._conditional_import_module('_hashlib') ++ self._hashlib = _hashlib + if _hashlib: + # These two algorithms should always be present when this module + # is compiled. If not, something was compiled wrong. +diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py +index 81c3485f761..2a5a0d3d061 100644 +--- a/Lib/test/test_hmac.py ++++ b/Lib/test/test_hmac.py +@@ -19,7 +19,7 @@ def ignore_warning(func): + + class TestVectorsTestCase(unittest.TestCase): + +- @requires_hashdigest('md5') ++ @requires_hashdigest('md5', openssl=True) + def test_md5_vectors(self): + # Test the HMAC module against test vectors from the RFC. + +@@ -66,7 +66,7 @@ class TestVectorsTestCase(unittest.TestCase): + b"and Larger Than One Block-Size Data"), + "6f630fad67cda0ee1fb1f562db3aa53e") + +- @requires_hashdigest('sha1') ++ @requires_hashdigest('sha1', openssl=True) + def test_sha_vectors(self): + def shatest(key, data, digest): + h = hmac.HMAC(key, data, digestmod=hashlib.sha1) +@@ -234,19 +234,19 @@ class TestVectorsTestCase(unittest.TestCase): + '134676fb6de0446065c97440fa8c6a58', + }) + +- @requires_hashdigest('sha224') ++ @requires_hashdigest('sha224', openssl=True) + def test_sha224_rfc4231(self): + self._rfc4231_test_cases(hashlib.sha224, 'sha224', 28, 64) + +- @requires_hashdigest('sha256') ++ @requires_hashdigest('sha256', openssl=True) + def test_sha256_rfc4231(self): + self._rfc4231_test_cases(hashlib.sha256, 'sha256', 32, 64) + +- @requires_hashdigest('sha384') ++ @requires_hashdigest('sha384', openssl=True) + def test_sha384_rfc4231(self): + self._rfc4231_test_cases(hashlib.sha384, 'sha384', 48, 128) + +- @requires_hashdigest('sha512') ++ @requires_hashdigest('sha512', openssl=True) + def test_sha512_rfc4231(self): + self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128) + +-- +2.21.0 + + +From 19a40f7e820bb991c03e03c05dc832539b676983 Mon Sep 17 00:00:00 2001 +From: stratakis +Date: Tue, 3 Dec 2019 16:35:54 +0100 +Subject: [PATCH 03/36] bpo-38270: Fix indentation of test_hmac assertions + (GH-17446) + +Since https://github.com/python/cpython/commit/c64a1a61e6fc542cada40eb069a239317e1af36e two assertions were indented and thus ignored when running test_hmac. + +This PR fixes it. As the change is quite trivial I didn't add a NEWS entry. + + +https://bugs.python.org/issue38270 +--- + Lib/test/test_hmac.py | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py +index 2a5a0d3d061..338e0215a41 100644 +--- a/Lib/test/test_hmac.py ++++ b/Lib/test/test_hmac.py +@@ -329,7 +329,7 @@ class ConstructorTestCase(unittest.TestCase): + digestmod="sha256") + except Exception: + self.fail("Constructor call with bytearray arguments raised exception.") +- self.assertEqual(h.hexdigest(), self.expected) ++ self.assertEqual(h.hexdigest(), self.expected) + + @requires_hashdigest('sha256') + def test_with_memoryview_msg(self): +@@ -337,7 +337,7 @@ class ConstructorTestCase(unittest.TestCase): + h = hmac.HMAC(b"key", memoryview(b"hash this!"), digestmod="sha256") + except Exception: + self.fail("Constructor call with memoryview msg raised exception.") +- self.assertEqual(h.hexdigest(), self.expected) ++ self.assertEqual(h.hexdigest(), self.expected) + + @requires_hashdigest('sha256') + def test_withmodule(self): +-- +2.21.0 + + +From 5fa96205b380f2cb555ac346e6b7039746cb51ca Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Thu, 25 Jul 2019 16:19:52 +0200 +Subject: [PATCH 04/36] Expose OpenSSL FIPS_mode() as hashlib.get_fips_mode() + +--- + Lib/hashlib.py | 5 +++++ + Modules/_hashopenssl.c | 36 +++++++++++++++++++++++++++++++++ + Modules/clinic/_hashopenssl.c.h | 25 ++++++++++++++++++++++- + 3 files changed, 65 insertions(+), 1 deletion(-) + +diff --git a/Lib/hashlib.py b/Lib/hashlib.py +index 98d2d7981a3..ae17c585110 100644 +--- a/Lib/hashlib.py ++++ b/Lib/hashlib.py +@@ -236,6 +236,11 @@ try: + except ImportError: + pass + ++try: ++ from _hashlib import get_fips_mode ++except ImportError: ++ pass ++ + + for __func_name in __always_supported: + # try them all, some may not work due to the OpenSSL +diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c +index 84edd72c85a..4876a7f7aa7 100644 +--- a/Modules/_hashopenssl.c ++++ b/Modules/_hashopenssl.c +@@ -25,6 +25,9 @@ + #include + #include "openssl/err.h" + ++/* Expose FIPS_mode */ ++#include ++ + #include "clinic/_hashopenssl.c.h" + /*[clinic input] + module _hashlib +@@ -987,6 +990,38 @@ GEN_CONSTRUCTOR(sha256) + GEN_CONSTRUCTOR(sha384) + GEN_CONSTRUCTOR(sha512) + ++/*[clinic input] ++_hashlib.get_fips_mode ++ ++Determine the OpenSSL FIPS mode of operation. ++ ++Effectively any non-zero return value indicates FIPS mode; ++values other than 1 may have additional significance. ++ ++See OpenSSL documentation for the FIPS_mode() function for details. ++[clinic start generated code]*/ ++ ++static PyObject * ++_hashlib_get_fips_mode_impl(PyObject *module) ++/*[clinic end generated code: output=ad8a7793310d3f98 input=f42a2135df2a5e11]*/ ++{ ++ int result = FIPS_mode(); ++ if (result == 0) { ++ // "If the library was built without support of the FIPS Object Module, ++ // then the function will return 0 with an error code of ++ // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." ++ // But 0 is also a valid result value. ++ ++ unsigned long errcode = ERR_peek_last_error(); ++ if (errcode) { ++ _setException(PyExc_ValueError); ++ return NULL; ++ } ++ } ++ return PyLong_FromLong(result); ++} ++ ++ + /* List of functions exported by this module */ + + static struct PyMethodDef EVP_functions[] = { +@@ -996,6 +1031,7 @@ static struct PyMethodDef EVP_functions[] = { + pbkdf2_hmac__doc__}, + #endif + _HASHLIB_SCRYPT_METHODDEF ++ _HASHLIB_GET_FIPS_MODE_METHODDEF + CONSTRUCTOR_METH_DEF(md5), + CONSTRUCTOR_METH_DEF(sha1), + CONSTRUCTOR_METH_DEF(sha224), +diff --git a/Modules/clinic/_hashopenssl.c.h b/Modules/clinic/_hashopenssl.c.h +index 04453526040..8828e2776e9 100644 +--- a/Modules/clinic/_hashopenssl.c.h ++++ b/Modules/clinic/_hashopenssl.c.h +@@ -54,7 +54,30 @@ exit: + + #endif /* (OPENSSL_VERSION_NUMBER > 0x10100000L && !defined(OPENSSL_NO_SCRYPT) && !defined(LIBRESSL_VERSION_NUMBER)) */ + ++PyDoc_STRVAR(_hashlib_get_fips_mode__doc__, ++"get_fips_mode($module, /)\n" ++"--\n" ++"\n" ++"Determine the OpenSSL FIPS mode of operation.\n" ++"\n" ++"Effectively any non-zero return value indicates FIPS mode;\n" ++"values other than 1 may have additional significance.\n" ++"\n" ++"See OpenSSL documentation for the FIPS_mode() function for details."); ++ ++#define _HASHLIB_GET_FIPS_MODE_METHODDEF \ ++ {"get_fips_mode", (PyCFunction)_hashlib_get_fips_mode, METH_NOARGS, _hashlib_get_fips_mode__doc__}, ++ ++static PyObject * ++_hashlib_get_fips_mode_impl(PyObject *module); ++ ++static PyObject * ++_hashlib_get_fips_mode(PyObject *module, PyObject *Py_UNUSED(ignored)) ++{ ++ return _hashlib_get_fips_mode_impl(module); ++} ++ + #ifndef _HASHLIB_SCRYPT_METHODDEF + #define _HASHLIB_SCRYPT_METHODDEF + #endif /* !defined(_HASHLIB_SCRYPT_METHODDEF) */ +-/*[clinic end generated code: output=118cd7036fa0fb52 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=7d683c930bbb7c36 input=a9049054013a1b77]*/ +-- +2.21.0 + + +From e60cc93037b913ca2a410d73b52d8301ab0d76cd Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Thu, 25 Jul 2019 17:04:06 +0200 +Subject: [PATCH 05/36] Use python's fall backs for the crypto it implements + only if we are not in FIPS mode + +--- + Lib/hashlib.py | 209 +++++++++++++++------------------------ + Lib/test/test_hashlib.py | 1 + + 2 files changed, 81 insertions(+), 129 deletions(-) + +diff --git a/Lib/hashlib.py b/Lib/hashlib.py +index ae17c585110..7db1e02601f 100644 +--- a/Lib/hashlib.py ++++ b/Lib/hashlib.py +@@ -67,56 +67,64 @@ algorithms_available = set(__always_supported) + __all__ = __always_supported + ('new', 'algorithms_guaranteed', + 'algorithms_available', 'pbkdf2_hmac') + +- +-__builtin_constructor_cache = {} +- +-def __get_builtin_constructor(name): +- cache = __builtin_constructor_cache +- constructor = cache.get(name) +- if constructor is not None: +- return constructor +- try: +- if name in ('SHA1', 'sha1'): +- import _sha1 +- cache['SHA1'] = cache['sha1'] = _sha1.sha1 +- elif name in ('MD5', 'md5'): +- import _md5 +- cache['MD5'] = cache['md5'] = _md5.md5 +- elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): +- import _sha256 +- cache['SHA224'] = cache['sha224'] = _sha256.sha224 +- cache['SHA256'] = cache['sha256'] = _sha256.sha256 +- elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): +- import _sha512 +- cache['SHA384'] = cache['sha384'] = _sha512.sha384 +- cache['SHA512'] = cache['sha512'] = _sha512.sha512 +- elif name in ('blake2b', 'blake2s'): +- import _blake2 +- cache['blake2b'] = _blake2.blake2b +- cache['blake2s'] = _blake2.blake2s +- elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', +- 'shake_128', 'shake_256'}: +- import _sha3 +- cache['sha3_224'] = _sha3.sha3_224 +- cache['sha3_256'] = _sha3.sha3_256 +- cache['sha3_384'] = _sha3.sha3_384 +- cache['sha3_512'] = _sha3.sha3_512 +- cache['shake_128'] = _sha3.shake_128 +- cache['shake_256'] = _sha3.shake_256 +- except ImportError: +- pass # no extension module, this hash is unsupported. +- +- constructor = cache.get(name) +- if constructor is not None: +- return constructor +- +- raise ValueError('unsupported hash type ' + name) ++try: ++ from _hashlib import get_fips_mode ++except ImportError: ++ def get_fips_mode(): ++ return 0 ++ ++ ++if not get_fips_mode(): ++ __builtin_constructor_cache = {} ++ ++ def __get_builtin_constructor(name): ++ cache = __builtin_constructor_cache ++ constructor = cache.get(name) ++ if constructor is not None: ++ return constructor ++ try: ++ if name in ('SHA1', 'sha1'): ++ import _sha1 ++ cache['SHA1'] = cache['sha1'] = _sha1.sha1 ++ elif name in ('MD5', 'md5'): ++ import _md5 ++ cache['MD5'] = cache['md5'] = _md5.md5 ++ elif name in ('SHA256', 'sha256', 'SHA224', 'sha224'): ++ import _sha256 ++ cache['SHA224'] = cache['sha224'] = _sha256.sha224 ++ cache['SHA256'] = cache['sha256'] = _sha256.sha256 ++ elif name in ('SHA512', 'sha512', 'SHA384', 'sha384'): ++ import _sha512 ++ cache['SHA384'] = cache['sha384'] = _sha512.sha384 ++ cache['SHA512'] = cache['sha512'] = _sha512.sha512 ++ elif name in ('blake2b', 'blake2s'): ++ import _blake2 ++ cache['blake2b'] = _blake2.blake2b ++ cache['blake2s'] = _blake2.blake2s ++ elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', ++ 'shake_128', 'shake_256'}: ++ import _sha3 ++ cache['sha3_224'] = _sha3.sha3_224 ++ cache['sha3_256'] = _sha3.sha3_256 ++ cache['sha3_384'] = _sha3.sha3_384 ++ cache['sha3_512'] = _sha3.sha3_512 ++ cache['shake_128'] = _sha3.shake_128 ++ cache['shake_256'] = _sha3.shake_256 ++ except ImportError: ++ pass # no extension module, this hash is unsupported. ++ ++ constructor = cache.get(name) ++ if constructor is not None: ++ return constructor ++ ++ raise ValueError('unsupported hash type ' + name) + + + def __get_openssl_constructor(name): +- if name in {'blake2b', 'blake2s'}: +- # Prefer our blake2 implementation. +- return __get_builtin_constructor(name) ++ if not get_fips_mode(): ++ if name in {'blake2b', 'blake2s'}: ++ # Prefer our blake2 implementation. ++ return __get_builtin_constructor(name) + try: + f = getattr(_hashlib, 'openssl_' + name) + # Allow the C module to raise ValueError. The function will be +@@ -125,27 +133,30 @@ def __get_openssl_constructor(name): + # Use the C function directly (very fast) + return f + except (AttributeError, ValueError): ++ if get_fips_mode(): ++ raise + return __get_builtin_constructor(name) + +- +-def __py_new(name, data=b'', **kwargs): +- """new(name, data=b'', **kwargs) - Return a new hashing object using the +- named algorithm; optionally initialized with data (which must be - a bytes-like object). - """ - return __get_builtin_constructor(name)(data, **kwargs) @@ -303,7 +1082,7 @@ index ae17c5851109..7db1e02601fe 100644 return __get_builtin_constructor(name)(data) -@@ -163,72 +176,14 @@ def __hash_new(name, data=b'', **kwargs): +@@ -163,72 +176,14 @@ try: algorithms_available = algorithms_available.union( _hashlib.openssl_md_meth_names) except ImportError: @@ -380,7 +1159,7 @@ index ae17c5851109..7db1e02601fe 100644 try: # OpenSSL's scrypt requires OpenSSL 1.1+ -@@ -236,12 +191,6 @@ def prf(msg, inner=inner, outer=outer): +@@ -236,12 +191,6 @@ try: except ImportError: pass @@ -393,7 +1172,7 @@ index ae17c5851109..7db1e02601fe 100644 for __func_name in __always_supported: # try them all, some may not work due to the OpenSSL # version not supporting that algorithm. -@@ -254,4 +203,6 @@ def prf(msg, inner=inner, outer=outer): +@@ -254,4 +203,6 @@ for __func_name in __always_supported: # Cleanup locals() del __always_supported, __func_name, __get_hash @@ -402,10 +1181,10 @@ index ae17c5851109..7db1e02601fe 100644 +if not get_fips_mode(): + del __py_new diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py -index 9711856853de..c67d2f6d00aa 100644 +index 1b1b4d54112..4e6b5b607a9 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py -@@ -930,6 +930,7 @@ def _test_pbkdf2_hmac(self, pbkdf2): +@@ -933,6 +933,7 @@ class KDFTests(unittest.TestCase): iterations=1, dklen=None) self.assertEqual(out, self.pbkdf2_results['sha1'][0][0]) @@ -413,11 +1192,14 @@ index 9711856853de..c67d2f6d00aa 100644 def test_pbkdf2_hmac_py(self): self._test_pbkdf2_hmac(py_hashlib.pbkdf2_hmac) +-- +2.21.0 -From 88185ade926f6a629acd8d24f00dfd10bfa9de0e Mon Sep 17 00:00:00 2001 + +From 4803386d980b9ad1a9bdde829e8642676acd8bf4 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 25 Jul 2019 17:19:06 +0200 -Subject: [PATCH 03/36] Disable Python's hash implementations in FIPS mode, +Subject: [PATCH 06/36] Disable Python's hash implementations in FIPS mode, forcing OpenSSL --- @@ -433,7 +1215,7 @@ Subject: [PATCH 03/36] Disable Python's hash implementations in FIPS mode, diff --git a/Include/_hashopenssl.h b/Include/_hashopenssl.h new file mode 100644 -index 000000000000..a726c0d3fbf3 +index 00000000000..a726c0d3fbf --- /dev/null +++ b/Include/_hashopenssl.h @@ -0,0 +1,66 @@ @@ -504,7 +1286,7 @@ index 000000000000..a726c0d3fbf3 + +#endif // !Py_HASHOPENSSL_H diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c -index 418c0184006d..341e67a8fcc4 100644 +index 418c0184006..341e67a8fcc 100644 --- a/Modules/_blake2/blake2b_impl.c +++ b/Modules/_blake2/blake2b_impl.c @@ -14,6 +14,7 @@ @@ -534,7 +1316,7 @@ index 418c0184006d..341e67a8fcc4 100644 #ifdef WITH_THREAD diff --git a/Modules/_blake2/blake2module.c b/Modules/_blake2/blake2module.c -index e2a3d420d4eb..817b71656844 100644 +index e2a3d420d4e..817b7165684 100644 --- a/Modules/_blake2/blake2module.c +++ b/Modules/_blake2/blake2module.c @@ -9,6 +9,7 @@ @@ -555,7 +1337,7 @@ index e2a3d420d4eb..817b71656844 100644 if (m == NULL) return NULL; diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c -index 24e529b6596a..0dfe0586b570 100644 +index 24e529b6596..0dfe0586b57 100644 --- a/Modules/_blake2/blake2s_impl.c +++ b/Modules/_blake2/blake2s_impl.c @@ -14,6 +14,7 @@ @@ -585,7 +1367,7 @@ index 24e529b6596a..0dfe0586b570 100644 #ifdef WITH_THREAD diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c -index 4876a7f7aa76..02cf6087a2ea 100644 +index 4876a7f7aa7..02cf6087a2e 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -17,16 +17,13 @@ @@ -645,7 +1427,7 @@ index 4876a7f7aa76..02cf6087a2ea 100644 newEVPobject(PyObject *name) { diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c -index 2c2b2dbc5c7d..624f7f247d4f 100644 +index 2c2b2dbc5c7..624f7f247d4 100644 --- a/Modules/_sha3/sha3module.c +++ b/Modules/_sha3/sha3module.c @@ -18,6 +18,7 @@ @@ -682,10 +1464,10 @@ index 2c2b2dbc5c7d..624f7f247d4f 100644 return NULL; } diff --git a/setup.py b/setup.py -index e2c18982532b..e2e659ef7950 100644 +index e2c18982532..e2e659ef795 100644 --- a/setup.py +++ b/setup.py -@@ -901,31 +901,30 @@ def detect_modules(self): +@@ -901,31 +901,30 @@ class PyBuildExt(build_ext): have_usable_openssl = (have_any_openssl and openssl_ver >= min_openssl_ver) @@ -730,7 +1512,7 @@ index e2c18982532b..e2e659ef7950 100644 blake2_deps = glob(os.path.join(os.getcwd(), srcdir, 'Modules/_blake2/impl/*')) -@@ -944,6 +943,7 @@ def detect_modules(self): +@@ -944,6 +943,7 @@ class PyBuildExt(build_ext): '_blake2/blake2b_impl.c', '_blake2/blake2s_impl.c'], define_macros=blake2_macros, @@ -738,7 +1520,7 @@ index e2c18982532b..e2e659ef7950 100644 depends=blake2_deps) ) sha3_deps = glob(os.path.join(os.getcwd(), srcdir, -@@ -951,7 +951,8 @@ def detect_modules(self): +@@ -951,7 +951,8 @@ class PyBuildExt(build_ext): sha3_deps.append('hashlib.h') exts.append( Extension('_sha3', ['_sha3/sha3module.c'], @@ -748,11 +1530,14 @@ index e2c18982532b..e2e659ef7950 100644 # Modules that provide persistent dictionary-like semantics. You will # probably want to arrange for at least one of them to be available on +-- +2.21.0 + -From ced78ca1f37efca7a43dc467756a4ff5b5669555 Mon Sep 17 00:00:00 2001 +From 0f35f480e2134c7d5c4ea3d68d8c0af14f56afa3 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 25 Jul 2019 17:35:27 +0200 -Subject: [PATCH 04/36] Expose all hashes available to OpenSSL, using a list +Subject: [PATCH 07/36] Expose all hashes available to OpenSSL, using a list --- Modules/_hashopenssl.c | 44 ++++++++++++++----------------------- @@ -761,7 +1546,7 @@ Subject: [PATCH 04/36] Expose all hashes available to OpenSSL, using a list create mode 100644 Modules/_hashopenssl_list.h diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c -index 02cf6087a2ea..7dfd70822b99 100644 +index 02cf6087a2e..7dfd70822b9 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -66,12 +66,9 @@ static PyTypeObject EVPtype; @@ -858,7 +1643,7 @@ index 02cf6087a2ea..7dfd70822b99 100644 } diff --git a/Modules/_hashopenssl_list.h b/Modules/_hashopenssl_list.h new file mode 100644 -index 000000000000..3c11b2eb6c62 +index 00000000000..3c11b2eb6c6 --- /dev/null +++ b/Modules/_hashopenssl_list.h @@ -0,0 +1,21 @@ @@ -883,11 +1668,14 @@ index 000000000000..3c11b2eb6c62 +_HASH(sha3_512, "sha3-512") +_HASH(shake_128, "shake128") +_HASH(shake_256, "shake256") +-- +2.21.0 -From c05359891debdfd0f2b320c6c396e9baf4a9f6ab Mon Sep 17 00:00:00 2001 + +From 7e5b74b7268e4fb7d473d24cd023493e4e87eb76 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Thu, 25 Jul 2019 18:13:45 +0200 -Subject: [PATCH 05/36] Fix tests +Subject: [PATCH 08/36] Fix tests --- Lib/hashlib.py | 5 +++- @@ -895,10 +1683,10 @@ Subject: [PATCH 05/36] Fix tests 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/Lib/hashlib.py b/Lib/hashlib.py -index 7db1e02601fe..2def0a310c66 100644 +index 7db1e02601f..2def0a310c6 100644 --- a/Lib/hashlib.py +++ b/Lib/hashlib.py -@@ -122,7 +122,10 @@ def __get_builtin_constructor(name): +@@ -122,7 +122,10 @@ if not get_fips_mode(): def __get_openssl_constructor(name): if not get_fips_mode(): @@ -911,10 +1699,10 @@ index 7db1e02601fe..2def0a310c66 100644 return __get_builtin_constructor(name) try: diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py -index c67d2f6d00aa..645a3d01b91d 100644 +index 4e6b5b607a9..e57c93b42f5 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py -@@ -179,7 +179,9 @@ def test_hash_array(self): +@@ -182,7 +182,9 @@ class HashLibTestCase(unittest.TestCase): a = array.array("b", range(10)) for cons in self.hash_constructors: c = cons(a) @@ -925,7 +1713,7 @@ index c67d2f6d00aa..645a3d01b91d 100644 c.hexdigest(16) else: c.hexdigest() -@@ -226,7 +228,9 @@ def test_get_builtin_constructor(self): +@@ -229,7 +231,9 @@ class HashLibTestCase(unittest.TestCase): def test_hexdigest(self): for cons in self.hash_constructors: h = cons() @@ -936,7 +1724,7 @@ index c67d2f6d00aa..645a3d01b91d 100644 self.assertIsInstance(h.digest(16), bytes) self.assertEqual(hexstr(h.digest(16)), h.hexdigest(16)) else: -@@ -240,6 +244,8 @@ def test_digest_length_overflow(self): +@@ -243,6 +247,8 @@ class HashLibTestCase(unittest.TestCase): h = cons() if h.name not in self.shakes: continue @@ -945,7 +1733,7 @@ index c67d2f6d00aa..645a3d01b91d 100644 for digest in h.digest, h.hexdigest: with self.assertRaises((ValueError, OverflowError)): digest(-10) -@@ -269,7 +275,9 @@ def test_large_update(self): +@@ -272,7 +278,9 @@ class HashLibTestCase(unittest.TestCase): m1.update(bees) m1.update(cees) m1.update(dees) @@ -956,7 +1744,7 @@ index c67d2f6d00aa..645a3d01b91d 100644 args = (16,) else: args = () -@@ -296,15 +304,36 @@ def check(self, name, data, hexdigest, shake=False, **kwargs): +@@ -299,15 +307,36 @@ class HashLibTestCase(unittest.TestCase): # 2 is for hashlib.name(...) and hashlib.new(name, ...) self.assertGreaterEqual(len(constructors), 2) for hash_object_constructor in constructors: @@ -995,7 +1783,7 @@ index c67d2f6d00aa..645a3d01b91d 100644 digest = bytes.fromhex(hexdigest) self.assertEqual(computed, digest) if not shake: -@@ -344,12 +373,14 @@ def check_blocksize_name(self, name, block_size=0, digest_size=0, +@@ -347,12 +376,14 @@ class HashLibTestCase(unittest.TestCase): for hash_object_constructor in constructors: m = hash_object_constructor() self.assertEqual(m.block_size, block_size) @@ -1015,7 +1803,7 @@ index c67d2f6d00aa..645a3d01b91d 100644 else: self.assertEqual(len(m.digest()), digest_size) self.assertEqual(len(m.hexdigest()), 2*digest_size) -@@ -379,9 +410,10 @@ def check_sha3(self, name, capacity, rate, suffix): +@@ -382,9 +413,10 @@ class HashLibTestCase(unittest.TestCase): for hash_object_constructor in constructors: m = hash_object_constructor() self.assertEqual(capacity + rate, 1600) @@ -1029,11 +1817,14 @@ index c67d2f6d00aa..645a3d01b91d 100644 @requires_sha3 def test_extra_sha3(self): +-- +2.21.0 + -From b9238e7d197c315d2c9c7aa34e5c8a4b728b25a0 Mon Sep 17 00:00:00 2001 +From d6618795dd079acd8585f830b129d7f2fc9a6c52 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 26 Jul 2019 11:27:57 +0200 -Subject: [PATCH 06/36] Change FIPS exceptions from _blake2, _sha3 module init +Subject: [PATCH 09/36] Change FIPS exceptions from _blake2, _sha3 module init to ImportError --- @@ -1045,7 +1836,7 @@ Subject: [PATCH 06/36] Change FIPS exceptions from _blake2, _sha3 module init 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/Include/_hashopenssl.h b/Include/_hashopenssl.h -index a726c0d3fbf3..47ed00304220 100644 +index a726c0d3fbf..47ed0030422 100644 --- a/Include/_hashopenssl.h +++ b/Include/_hashopenssl.h @@ -39,7 +39,7 @@ _setException(PyObject *exc) @@ -1081,7 +1872,7 @@ index a726c0d3fbf3..47ed00304220 100644 #endif // !Py_HASHOPENSSL_H diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c -index 341e67a8fcc4..f6bfce823b8f 100644 +index 341e67a8fcc..f6bfce823b8 100644 --- a/Modules/_blake2/blake2b_impl.c +++ b/Modules/_blake2/blake2b_impl.c @@ -104,7 +104,7 @@ py_blake2b_new_impl(PyTypeObject *type, PyObject *data, int digest_size, @@ -1103,7 +1894,7 @@ index 341e67a8fcc4..f6bfce823b8f 100644 GET_BUFFER_VIEW_OR_ERROUT(data, &buf); diff --git a/Modules/_blake2/blake2module.c b/Modules/_blake2/blake2module.c -index 817b71656844..a9c7cbc7ebe9 100644 +index 817b7165684..a9c7cbc7ebe 100644 --- a/Modules/_blake2/blake2module.c +++ b/Modules/_blake2/blake2module.c @@ -58,7 +58,7 @@ PyInit__blake2(void) @@ -1116,7 +1907,7 @@ index 817b71656844..a9c7cbc7ebe9 100644 m = PyModule_Create(&blake2_module); if (m == NULL) diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c -index 0dfe0586b570..28ae5b651019 100644 +index 0dfe0586b57..28ae5b65101 100644 --- a/Modules/_blake2/blake2s_impl.c +++ b/Modules/_blake2/blake2s_impl.c @@ -104,7 +104,7 @@ py_blake2s_new_impl(PyTypeObject *type, PyObject *data, int digest_size, @@ -1138,7 +1929,7 @@ index 0dfe0586b570..28ae5b651019 100644 GET_BUFFER_VIEW_OR_ERROUT(data, &buf); diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c -index 624f7f247d4f..2783a75644fc 100644 +index 624f7f247d4..2783a75644f 100644 --- a/Modules/_sha3/sha3module.c +++ b/Modules/_sha3/sha3module.c @@ -163,7 +163,7 @@ static PyTypeObject SHAKE256type; @@ -1168,18 +1959,21 @@ index 624f7f247d4f..2783a75644fc 100644 if ((m = PyModule_Create(&_SHA3module)) == NULL) { return NULL; +-- +2.21.0 -From d9cf1f68ed7c7d10846119d146583d6fd2d52143 Mon Sep 17 00:00:00 2001 + +From eb78e4b4179842185f53edba2073ab7644db7ad3 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 26 Jul 2019 11:24:09 +0200 -Subject: [PATCH 07/36] Make hashlib importable under FIPS mode +Subject: [PATCH 10/36] Make hashlib importable under FIPS mode --- Lib/hashlib.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Lib/hashlib.py b/Lib/hashlib.py -index 2def0a310c66..ca1dd2022515 100644 +index 2def0a310c6..ca1dd202251 100644 --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -132,12 +132,14 @@ def __get_openssl_constructor(name): @@ -1200,11 +1994,14 @@ index 2def0a310c66..ca1dd2022515 100644 return __get_builtin_constructor(name) if not get_fips_mode(): +-- +2.21.0 + -From 5b21c029a9b69b06f9ef245264db2ddd227011f9 Mon Sep 17 00:00:00 2001 +From 0f313f65457f1e7d0e7238a71935f5d4e0d197ee Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Fri, 26 Jul 2019 15:41:10 +0200 -Subject: [PATCH 08/36] Implement hmac.new using new built-in module, +Subject: [PATCH 11/36] Implement hmac.new using new built-in module, _hmacopenssl --- @@ -1217,10 +2014,10 @@ Subject: [PATCH 08/36] Implement hmac.new using new built-in module, create mode 100644 Modules/clinic/_hmacopenssl.c.h diff --git a/Lib/hmac.py b/Lib/hmac.py -index 121029aa670b..ed98406bd2e1 100644 +index 121029aa670..ed98406bd2e 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py -@@ -6,6 +6,8 @@ +@@ -6,6 +6,8 @@ Implements the HMAC algorithm as described by RFC 2104. import warnings as _warnings from _operator import _compare_digest as compare_digest import hashlib as _hashlib @@ -1229,7 +2026,7 @@ index 121029aa670b..ed98406bd2e1 100644 trans_5C = bytes((x ^ 0x5C) for x in range(256)) trans_36 = bytes((x ^ 0x36) for x in range(256)) -@@ -37,6 +39,11 @@ def __init__(self, key, msg = None, digestmod = None): +@@ -37,6 +39,11 @@ class HMAC: Note: key and msg must be a bytes or bytearray objects. """ @@ -1241,7 +2038,7 @@ index 121029aa670b..ed98406bd2e1 100644 if not isinstance(key, (bytes, bytearray)): raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) -@@ -90,6 +97,8 @@ def name(self): +@@ -90,6 +97,8 @@ class HMAC: def update(self, msg): """Update this hashing object with the string msg. """ @@ -1250,7 +2047,7 @@ index 121029aa670b..ed98406bd2e1 100644 self.inner.update(msg) def copy(self): -@@ -130,6 +139,19 @@ def hexdigest(self): +@@ -130,6 +139,19 @@ class HMAC: h = self._current() return h.hexdigest() @@ -1287,7 +2084,7 @@ index 121029aa670b..ed98406bd2e1 100644 + return HMAC(key, msg, digestmod) diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c new file mode 100644 -index 000000000000..ca95d725f019 +index 00000000000..ca95d725f01 --- /dev/null +++ b/Modules/_hmacopenssl.c @@ -0,0 +1,396 @@ @@ -1300,1918 +2097,1606 @@ index 000000000000..ca95d725f019 + * Licensed to PSF under a Contributor Agreement. + * + * Derived from a skeleton of shamodule.c containing work performed by: -+ * -+ * Andrew Kuchling (amk@amk.ca) -+ * Greg Stein (gstein@lyra.org) -+ * -+ */ -+ -+#define PY_SSIZE_T_CLEAN -+ -+#include "Python.h" -+#include "structmember.h" -+#include "hashlib.h" -+#include "pystrhex.h" -+#include "_hashopenssl.h" -+ -+ -+#include -+ -+static PyTypeObject HmacType; -+ -+typedef struct { -+ PyObject_HEAD -+ PyObject *name; /* name of the hash algorithm */ -+ HMAC_CTX *ctx; /* OpenSSL hmac context */ -+ PyThread_type_lock lock; /* HMAC context lock */ -+} HmacObject; -+ -+#include "clinic/_hmacopenssl.c.h" -+/*[clinic input] -+module _hmacopenssl -+class _hmacopenssl.HMAC "HmacObject *" "&HmacType" -+[clinic start generated code]*/ -+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c98d3f2af591c085]*/ -+ -+ -+/*[clinic input] -+_hmacopenssl.new -+ -+ key: Py_buffer -+ * -+ digestmod: str -+ -+Return a new hmac object. -+[clinic start generated code]*/ -+ -+static PyObject * -+_hmacopenssl_new_impl(PyObject *module, Py_buffer *key, -+ const char *digestmod) -+/*[clinic end generated code: output=46f1cb4e02921922 input=be8c0c2e4fad508c]*/ -+{ -+ if (digestmod == NULL) { -+ PyErr_SetString(PyExc_ValueError, "digestmod must be specified"); -+ return NULL; -+ } -+ -+ /* name mut be lowercase */ -+ for (int i=0; digestmod[i]; i++) { -+ if ( -+ ((digestmod[i] < 'a') || (digestmod[i] > 'z')) -+ && ((digestmod[i] < '0') || (digestmod[i] > '9')) -+ && digestmod[i] != '-' -+ ) { -+ PyErr_SetString(PyExc_ValueError, "digestmod must be lowercase"); -+ return NULL; -+ } -+ } -+ -+ const EVP_MD *digest = EVP_get_digestbyname(digestmod); -+ if (!digest) { -+ PyErr_SetString(PyExc_ValueError, "unknown hash function"); -+ return NULL; -+ } -+ -+ PyObject *name = NULL; -+ HMAC_CTX *ctx = NULL; -+ HmacObject *retval = NULL; -+ -+ name = PyUnicode_FromFormat("hmac-%s", digestmod); -+ if (name == NULL) { -+ goto error; -+ } -+ -+ ctx = HMAC_CTX_new(); -+ if (ctx == NULL) { -+ _setException(PyExc_ValueError); -+ goto error; -+ } -+ -+ int r = HMAC_Init_ex( -+ ctx, -+ (const char*)key->buf, -+ key->len, -+ digest, -+ NULL /*impl*/); -+ if (r == 0) { -+ _setException(PyExc_ValueError); -+ goto error; -+ } -+ -+ retval = (HmacObject *)PyObject_New(HmacObject, &HmacType); -+ if (retval == NULL) { -+ goto error; -+ } -+ -+ retval->name = name; -+ retval->ctx = ctx; -+ retval->lock = NULL; -+ -+ return (PyObject*)retval; -+ -+error: -+ if (ctx) HMAC_CTX_free(ctx); -+ if (name) Py_DECREF(name); -+ if (retval) PyObject_Del(name); -+ return NULL; -+} -+ -+/*[clinic input] -+_hmacopenssl.HMAC.copy -+ -+Return a copy (“clone”) of the HMAC object. -+[clinic start generated code]*/ -+ -+static PyObject * -+_hmacopenssl_HMAC_copy_impl(HmacObject *self) -+/*[clinic end generated code: output=fe5ee41faf30dcf0 input=f5ed20feec42d8d0]*/ -+{ -+ HmacObject *retval = (HmacObject *)PyObject_New(HmacObject, &HmacType); -+ if (retval == NULL) { -+ return NULL; -+ } -+ -+ Py_INCREF(self->name); -+ retval->name = self->name; -+ -+ int r = HMAC_CTX_copy(retval->ctx, self->ctx); -+ if (r == 0) { -+ PyObject_Del(retval); -+ return _setException(PyExc_ValueError); -+ } -+ -+ return (PyObject*)retval; -+} -+ -+static void -+_hmac_dealloc(HmacObject *self) -+{ -+ if (self->lock != NULL) { -+ PyThread_free_lock(self->lock); -+ } -+ HMAC_CTX_free(self->ctx); -+ Py_XDECREF(self->name); -+ PyObject_Del(self); -+} -+ -+static PyObject * -+_hmac_repr(HmacObject *self) -+{ -+ return PyUnicode_FromFormat("<%U HMAC object @ %p>", self->name, self); -+} -+ -+/*[clinic input] -+_hmacopenssl.HMAC.update -+ -+ msg: Py_buffer -+ -+Update the HMAC object with msg. -+[clinic start generated code]*/ -+ -+static PyObject * -+_hmacopenssl_HMAC_update_impl(HmacObject *self, Py_buffer *msg) -+/*[clinic end generated code: output=0efeee663a98cee5 input=0683d64f35808cb9]*/ -+{ -+ if (self->lock == NULL && msg->len >= HASHLIB_GIL_MINSIZE) { -+ self->lock = PyThread_allocate_lock(); -+ /* fail? lock = NULL and we fail over to non-threaded code. */ -+ } ++ * ++ * Andrew Kuchling (amk@amk.ca) ++ * Greg Stein (gstein@lyra.org) ++ * ++ */ + -+ int r; ++#define PY_SSIZE_T_CLEAN + -+ if (self->lock != NULL) { -+ Py_BEGIN_ALLOW_THREADS -+ PyThread_acquire_lock(self->lock, 1); -+ r = HMAC_Update(self->ctx, (const unsigned char*)msg->buf, msg->len); -+ PyThread_release_lock(self->lock); -+ Py_END_ALLOW_THREADS -+ } else { -+ r = HMAC_Update(self->ctx, (const unsigned char*)msg->buf, msg->len); -+ } ++#include "Python.h" ++#include "structmember.h" ++#include "hashlib.h" ++#include "pystrhex.h" ++#include "_hashopenssl.h" + -+ if (r == 0) { -+ _setException(PyExc_ValueError); -+ return NULL; -+ } -+ Py_RETURN_NONE; -+} + -+static unsigned int -+_digest_size(HmacObject *self) -+{ -+ const EVP_MD *md = HMAC_CTX_get_md(self->ctx); -+ if (md == NULL) { -+ _setException(PyExc_ValueError); -+ return 0; -+ } -+ return EVP_MD_size(md); -+} ++#include + -+static int -+_digest(HmacObject *self, unsigned char *buf, unsigned int len) -+{ -+ HMAC_CTX *temp_ctx = HMAC_CTX_new(); -+ if (temp_ctx == NULL) { -+ PyErr_NoMemory(); -+ return 0; -+ } -+ int r = HMAC_CTX_copy(temp_ctx, self->ctx); -+ if (r == 0) { -+ _setException(PyExc_ValueError); -+ return 0; -+ } -+ r = HMAC_Final(temp_ctx, buf, &len); -+ HMAC_CTX_free(temp_ctx); -+ if (r == 0) { -+ _setException(PyExc_ValueError); -+ return 0; -+ } -+ return 1; -+} ++static PyTypeObject HmacType; + -+/*[clinic input] -+_hmacopenssl.HMAC.digest ++typedef struct { ++ PyObject_HEAD ++ PyObject *name; /* name of the hash algorithm */ ++ HMAC_CTX *ctx; /* OpenSSL hmac context */ ++ PyThread_type_lock lock; /* HMAC context lock */ ++} HmacObject; + -+Return the digest of the bytes passed to the update() method so far. ++#include "clinic/_hmacopenssl.c.h" ++/*[clinic input] ++module _hmacopenssl ++class _hmacopenssl.HMAC "HmacObject *" "&HmacType" +[clinic start generated code]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c98d3f2af591c085]*/ + -+static PyObject * -+_hmacopenssl_HMAC_digest_impl(HmacObject *self) -+/*[clinic end generated code: output=3aa6dbfc46ec4957 input=bf769a10b1d9edd9]*/ -+{ -+ unsigned int digest_size = _digest_size(self); -+ if (digest_size == 0) { -+ return _setException(PyExc_ValueError); -+ } -+ unsigned char buf[digest_size]; /* FIXME: C99 feature */ -+ int r = _digest(self, buf, digest_size); -+ if (r == 0) { -+ return NULL; -+ } -+ return PyBytes_FromStringAndSize((const char *)buf, digest_size); -+} + +/*[clinic input] -+_hmacopenssl.HMAC.hexdigest ++_hmacopenssl.new + -+Return hexadecimal digest of the bytes passed to the update() method so far. ++ key: Py_buffer ++ * ++ digestmod: str + -+This may be used to exchange the value safely in email or other non-binary -+environments. ++Return a new hmac object. +[clinic start generated code]*/ + +static PyObject * -+_hmacopenssl_HMAC_hexdigest_impl(HmacObject *self) -+/*[clinic end generated code: output=630f6fa89f9f1e48 input=b8e60ec8b811c4cd]*/ ++_hmacopenssl_new_impl(PyObject *module, Py_buffer *key, ++ const char *digestmod) ++/*[clinic end generated code: output=46f1cb4e02921922 input=be8c0c2e4fad508c]*/ +{ -+ unsigned int digest_size = _digest_size(self); -+ if (digest_size == 0) { -+ return _setException(PyExc_ValueError); -+ } -+ unsigned char buf[digest_size]; /* FIXME: C99 feature */ -+ int r = _digest(self, buf, digest_size); -+ if (r == 0) { ++ if (digestmod == NULL) { ++ PyErr_SetString(PyExc_ValueError, "digestmod must be specified"); + return NULL; + } -+ return _Py_strhex((const char *)buf, digest_size); -+} -+ -+ -+ -+static PyObject * -+_hmacopenssl_get_digest_size(HmacObject *self, void *closure) -+{ -+ unsigned int digest_size = _digest_size(self); -+ if (digest_size == 0) { -+ return _setException(PyExc_ValueError); -+ } -+ return PyLong_FromLong(digest_size); -+} + -+static PyObject * -+_hmacopenssl_get_block_size(HmacObject *self, void *closure) -+{ -+ const EVP_MD *md = HMAC_CTX_get_md(self->ctx); -+ if (md == NULL) { -+ return _setException(PyExc_ValueError); ++ /* name mut be lowercase */ ++ for (int i=0; digestmod[i]; i++) { ++ if ( ++ ((digestmod[i] < 'a') || (digestmod[i] > 'z')) ++ && ((digestmod[i] < '0') || (digestmod[i] > '9')) ++ && digestmod[i] != '-' ++ ) { ++ PyErr_SetString(PyExc_ValueError, "digestmod must be lowercase"); ++ return NULL; ++ } + } -+ return PyLong_FromLong(EVP_MD_size(md)); -+} -+ -+static PyMethodDef Hmac_methods[] = { -+ _HMACOPENSSL_HMAC_UPDATE_METHODDEF -+ _HMACOPENSSL_HMAC_DIGEST_METHODDEF -+ _HMACOPENSSL_HMAC_HEXDIGEST_METHODDEF -+ _HMACOPENSSL_HMAC_COPY_METHODDEF -+ {NULL, NULL} /* sentinel */ -+}; -+ -+static PyGetSetDef Hmac_getset[] = { -+ {"digest_size", (getter)_hmacopenssl_get_digest_size, NULL, NULL, NULL}, -+ {"block_size", (getter)_hmacopenssl_get_block_size, NULL, NULL, NULL}, -+ {NULL} /* Sentinel */ -+}; -+ -+static PyMemberDef Hmac_members[] = { -+ {"name", T_OBJECT, offsetof(HmacObject, name), READONLY, PyDoc_STR("HMAC name")}, -+}; -+ -+PyDoc_STRVAR(hmactype_doc, -+"The object used to calculate HMAC of a message.\n\ -+\n\ -+Methods:\n\ -+\n\ -+update() -- updates the current digest with an additional string\n\ -+digest() -- return the current digest value\n\ -+hexdigest() -- return the current digest as a string of hexadecimal digits\n\ -+copy() -- return a copy of the current hash object\n\ -+\n\ -+Attributes:\n\ -+\n\ -+name -- the name, including the hash algorithm used by this object\n\ -+digest_size -- number of bytes in digest() output\n"); -+ -+static PyTypeObject HmacType = { -+ PyVarObject_HEAD_INIT(NULL, 0) -+ "_hmacopenssl.HMAC", /*tp_name*/ -+ sizeof(HmacObject), /*tp_basicsize*/ -+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, -+ .tp_doc = hmactype_doc, -+ .tp_repr = (reprfunc)_hmac_repr, -+ .tp_dealloc = (destructor)_hmac_dealloc, -+ .tp_methods = Hmac_methods, -+ .tp_getset = Hmac_getset, -+ .tp_members = Hmac_members, -+}; -+ -+static struct PyMethodDef hmacopenssl_functions[] = { -+ _HMACOPENSSL_NEW_METHODDEF -+ {NULL, NULL} /* Sentinel */ -+}; -+ -+ -+ -+/* Initialize this module. */ -+ -+ -+static struct PyModuleDef _hmacopenssl_module = { -+ PyModuleDef_HEAD_INIT, -+ "_hmacopenssl", -+ NULL, -+ -1, -+ hmacopenssl_functions, -+ NULL, -+ NULL, -+ NULL, -+ NULL -+}; -+ -+PyMODINIT_FUNC -+PyInit__hmacopenssl(void) -+{ -+ /* TODO build EVP_functions openssl_* entries dynamically based -+ * on what hashes are supported rather than listing many -+ * but having some be unsupported. Only init appropriate -+ * constants. */ -+ -+ Py_TYPE(&HmacType) = &PyType_Type; -+ if (PyType_Ready(&HmacType) < 0) -+ return NULL; + -+ PyObject *m = PyModule_Create(&_hmacopenssl_module); -+ if (m == NULL) -+ return NULL; -+ -+ Py_INCREF((PyObject *)&HmacType); -+ PyModule_AddObject(m, "HMAC", (PyObject *)&HmacType); -+ -+ return m; -+} -diff --git a/Modules/clinic/_hmacopenssl.c.h b/Modules/clinic/_hmacopenssl.c.h -new file mode 100644 -index 000000000000..b472a6eddd34 ---- /dev/null -+++ b/Modules/clinic/_hmacopenssl.c.h -@@ -0,0 +1,133 @@ -+/*[clinic input] -+preserve -+[clinic start generated code]*/ -+ -+PyDoc_STRVAR(_hmacopenssl_new__doc__, -+"new($module, /, key, *, digestmod)\n" -+"--\n" -+"\n" -+"Return a new hmac object."); -+ -+#define _HMACOPENSSL_NEW_METHODDEF \ -+ {"new", (PyCFunction)_hmacopenssl_new, METH_FASTCALL, _hmacopenssl_new__doc__}, -+ -+static PyObject * -+_hmacopenssl_new_impl(PyObject *module, Py_buffer *key, -+ const char *digestmod); ++ const EVP_MD *digest = EVP_get_digestbyname(digestmod); ++ if (!digest) { ++ PyErr_SetString(PyExc_ValueError, "unknown hash function"); ++ return NULL; ++ } + -+static PyObject * -+_hmacopenssl_new(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) -+{ -+ PyObject *return_value = NULL; -+ static const char * const _keywords[] = {"key", "digestmod", NULL}; -+ static _PyArg_Parser _parser = {"y*$s:new", _keywords, 0}; -+ Py_buffer key = {NULL, NULL}; -+ const char *digestmod; ++ PyObject *name = NULL; ++ HMAC_CTX *ctx = NULL; ++ HmacObject *retval = NULL; + -+ if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, -+ &key, &digestmod)) { -+ goto exit; ++ name = PyUnicode_FromFormat("hmac-%s", digestmod); ++ if (name == NULL) { ++ goto error; + } -+ return_value = _hmacopenssl_new_impl(module, &key, digestmod); + -+exit: -+ /* Cleanup for key */ -+ if (key.obj) { -+ PyBuffer_Release(&key); ++ ctx = HMAC_CTX_new(); ++ if (ctx == NULL) { ++ _setException(PyExc_ValueError); ++ goto error; + } + -+ return return_value; -+} ++ int r = HMAC_Init_ex( ++ ctx, ++ (const char*)key->buf, ++ key->len, ++ digest, ++ NULL /*impl*/); ++ if (r == 0) { ++ _setException(PyExc_ValueError); ++ goto error; ++ } + -+PyDoc_STRVAR(_hmacopenssl_HMAC_copy__doc__, -+"copy($self, /)\n" -+"--\n" -+"\n" -+"Return a copy (“clone”) of the HMAC object."); ++ retval = (HmacObject *)PyObject_New(HmacObject, &HmacType); ++ if (retval == NULL) { ++ goto error; ++ } + -+#define _HMACOPENSSL_HMAC_COPY_METHODDEF \ -+ {"copy", (PyCFunction)_hmacopenssl_HMAC_copy, METH_NOARGS, _hmacopenssl_HMAC_copy__doc__}, ++ retval->name = name; ++ retval->ctx = ctx; ++ retval->lock = NULL; + -+static PyObject * -+_hmacopenssl_HMAC_copy_impl(HmacObject *self); ++ return (PyObject*)retval; + -+static PyObject * -+_hmacopenssl_HMAC_copy(HmacObject *self, PyObject *Py_UNUSED(ignored)) -+{ -+ return _hmacopenssl_HMAC_copy_impl(self); ++error: ++ if (ctx) HMAC_CTX_free(ctx); ++ if (name) Py_DECREF(name); ++ if (retval) PyObject_Del(name); ++ return NULL; +} + -+PyDoc_STRVAR(_hmacopenssl_HMAC_update__doc__, -+"update($self, /, msg)\n" -+"--\n" -+"\n" -+"Update the HMAC object with msg."); -+ -+#define _HMACOPENSSL_HMAC_UPDATE_METHODDEF \ -+ {"update", (PyCFunction)_hmacopenssl_HMAC_update, METH_FASTCALL, _hmacopenssl_HMAC_update__doc__}, ++/*[clinic input] ++_hmacopenssl.HMAC.copy + -+static PyObject * -+_hmacopenssl_HMAC_update_impl(HmacObject *self, Py_buffer *msg); ++Return a copy (“clone”) of the HMAC object. ++[clinic start generated code]*/ + +static PyObject * -+_hmacopenssl_HMAC_update(HmacObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) ++_hmacopenssl_HMAC_copy_impl(HmacObject *self) ++/*[clinic end generated code: output=fe5ee41faf30dcf0 input=f5ed20feec42d8d0]*/ +{ -+ PyObject *return_value = NULL; -+ static const char * const _keywords[] = {"msg", NULL}; -+ static _PyArg_Parser _parser = {"y*:update", _keywords, 0}; -+ Py_buffer msg = {NULL, NULL}; -+ -+ if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, -+ &msg)) { -+ goto exit; ++ HmacObject *retval = (HmacObject *)PyObject_New(HmacObject, &HmacType); ++ if (retval == NULL) { ++ return NULL; + } -+ return_value = _hmacopenssl_HMAC_update_impl(self, &msg); + -+exit: -+ /* Cleanup for msg */ -+ if (msg.obj) { -+ PyBuffer_Release(&msg); ++ Py_INCREF(self->name); ++ retval->name = self->name; ++ ++ int r = HMAC_CTX_copy(retval->ctx, self->ctx); ++ if (r == 0) { ++ PyObject_Del(retval); ++ return _setException(PyExc_ValueError); + } + -+ return return_value; ++ return (PyObject*)retval; +} + -+PyDoc_STRVAR(_hmacopenssl_HMAC_digest__doc__, -+"digest($self, /)\n" -+"--\n" -+"\n" -+"Return the digest of the bytes passed to the update() method so far."); -+ -+#define _HMACOPENSSL_HMAC_DIGEST_METHODDEF \ -+ {"digest", (PyCFunction)_hmacopenssl_HMAC_digest, METH_NOARGS, _hmacopenssl_HMAC_digest__doc__}, -+ -+static PyObject * -+_hmacopenssl_HMAC_digest_impl(HmacObject *self); ++static void ++_hmac_dealloc(HmacObject *self) ++{ ++ if (self->lock != NULL) { ++ PyThread_free_lock(self->lock); ++ } ++ HMAC_CTX_free(self->ctx); ++ Py_XDECREF(self->name); ++ PyObject_Del(self); ++} + +static PyObject * -+_hmacopenssl_HMAC_digest(HmacObject *self, PyObject *Py_UNUSED(ignored)) ++_hmac_repr(HmacObject *self) +{ -+ return _hmacopenssl_HMAC_digest_impl(self); ++ return PyUnicode_FromFormat("<%U HMAC object @ %p>", self->name, self); +} + -+PyDoc_STRVAR(_hmacopenssl_HMAC_hexdigest__doc__, -+"hexdigest($self, /)\n" -+"--\n" -+"\n" -+"Return hexadecimal digest of the bytes passed to the update() method so far.\n" -+"\n" -+"This may be used to exchange the value safely in email or other non-binary\n" -+"environments."); ++/*[clinic input] ++_hmacopenssl.HMAC.update + -+#define _HMACOPENSSL_HMAC_HEXDIGEST_METHODDEF \ -+ {"hexdigest", (PyCFunction)_hmacopenssl_HMAC_hexdigest, METH_NOARGS, _hmacopenssl_HMAC_hexdigest__doc__}, ++ msg: Py_buffer + -+static PyObject * -+_hmacopenssl_HMAC_hexdigest_impl(HmacObject *self); ++Update the HMAC object with msg. ++[clinic start generated code]*/ + +static PyObject * -+_hmacopenssl_HMAC_hexdigest(HmacObject *self, PyObject *Py_UNUSED(ignored)) ++_hmacopenssl_HMAC_update_impl(HmacObject *self, Py_buffer *msg) ++/*[clinic end generated code: output=0efeee663a98cee5 input=0683d64f35808cb9]*/ +{ -+ return _hmacopenssl_HMAC_hexdigest_impl(self); -+} -+/*[clinic end generated code: output=10b6e8cac6d7a2c9 input=a9049054013a1b77]*/ -diff --git a/setup.py b/setup.py -index e2e659ef7950..282aa4178ed3 100644 ---- a/setup.py -+++ b/setup.py -@@ -922,6 +922,10 @@ def detect_modules(self): - openssl_ver) - missing.append('_hashlib') - -+ exts.append( Extension('_hmacopenssl', ['_hmacopenssl.c'], -+ depends = ['hashlib.h'], -+ **ssl_args)) -+ - # RHEL: Always force OpenSSL for md5, sha1, sha256, sha512; - # don't build Python's implementations. - # sha3 and blake2 have extra functionality, so do build those: - -From 7eb3d47afdad9052f505ecbbbfab065dbbc240e0 Mon Sep 17 00:00:00 2001 -From: Marcel Plch -Date: Mon, 29 Jul 2019 12:45:11 +0200 -Subject: [PATCH 09/36] FIPS review - -* Port _hmacopenssl to multiphase init. -* Make _hmacopenssl.HMAC.copy create same type as self. -* hmac.py cosmetic nitpick ---- - Lib/hmac.py | 2 +- - Modules/_hmacopenssl.c | 112 +++++++++++++++++++++++++---------------- - 2 files changed, 70 insertions(+), 44 deletions(-) - -diff --git a/Lib/hmac.py b/Lib/hmac.py -index ed98406bd2e1..b9bf16b84ca0 100644 ---- a/Lib/hmac.py -+++ b/Lib/hmac.py -@@ -42,7 +42,7 @@ def __init__(self, key, msg = None, digestmod = None): - if _hashlib.get_fips_mode(): - raise ValueError( - 'hmac.HMAC is not available in FIPS mode. ' -- + 'Use hmac.new().' -+ 'Use hmac.new().' - ) - - if not isinstance(key, (bytes, bytearray)): -diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c -index ca95d725f019..216ed04f2360 100644 ---- a/Modules/_hmacopenssl.c -+++ b/Modules/_hmacopenssl.c -@@ -24,7 +24,10 @@ - - #include - --static PyTypeObject HmacType; -+typedef struct hmacopenssl_state { -+ PyTypeObject *HmacType; -+} hmacopenssl_state; -+ - - typedef struct { - PyObject_HEAD -@@ -36,9 +39,9 @@ typedef struct { - #include "clinic/_hmacopenssl.c.h" - /*[clinic input] - module _hmacopenssl --class _hmacopenssl.HMAC "HmacObject *" "&HmacType" -+class _hmacopenssl.HMAC "HmacObject *" "PyModule_GetState(module)->HmacType" - [clinic start generated code]*/ --/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c98d3f2af591c085]*/ -+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=204b7f45847f57b4]*/ - - - /*[clinic input] -@@ -56,11 +59,18 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, - const char *digestmod) - /*[clinic end generated code: output=46f1cb4e02921922 input=be8c0c2e4fad508c]*/ - { -+ hmacopenssl_state *state; -+ - if (digestmod == NULL) { - PyErr_SetString(PyExc_ValueError, "digestmod must be specified"); - return NULL; - } - -+ state = PyModule_GetState(module); -+ if (state == NULL) { -+ return NULL; ++ if (self->lock == NULL && msg->len >= HASHLIB_GIL_MINSIZE) { ++ self->lock = PyThread_allocate_lock(); ++ /* fail? lock = NULL and we fail over to non-threaded code. */ + } + - /* name mut be lowercase */ - for (int i=0; digestmod[i]; i++) { - if ( -@@ -105,7 +115,7 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, - goto error; - } - -- retval = (HmacObject *)PyObject_New(HmacObject, &HmacType); -+ retval = (HmacObject *)PyObject_New(HmacObject, state->HmacType); - if (retval == NULL) { - goto error; - } -@@ -133,7 +143,9 @@ static PyObject * - _hmacopenssl_HMAC_copy_impl(HmacObject *self) - /*[clinic end generated code: output=fe5ee41faf30dcf0 input=f5ed20feec42d8d0]*/ - { -- HmacObject *retval = (HmacObject *)PyObject_New(HmacObject, &HmacType); -+ HmacObject *retval; -+ -+ retval = (HmacObject *)PyObject_New(HmacObject, (PyTypeObject *)PyObject_Type((PyObject *)self)); - if (retval == NULL) { - return NULL; - } -@@ -147,7 +159,7 @@ _hmacopenssl_HMAC_copy_impl(HmacObject *self) - return _setException(PyExc_ValueError); - } - -- return (PyObject*)retval; -+ return (PyObject *)retval; - } - - static void -@@ -338,19 +350,24 @@ Attributes:\n\ - name -- the name, including the hash algorithm used by this object\n\ - digest_size -- number of bytes in digest() output\n"); - --static PyTypeObject HmacType = { -- PyVarObject_HEAD_INIT(NULL, 0) -- "_hmacopenssl.HMAC", /*tp_name*/ -- sizeof(HmacObject), /*tp_basicsize*/ -- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, -- .tp_doc = hmactype_doc, -- .tp_repr = (reprfunc)_hmac_repr, -- .tp_dealloc = (destructor)_hmac_dealloc, -- .tp_methods = Hmac_methods, -- .tp_getset = Hmac_getset, -- .tp_members = Hmac_members, -+static PyType_Slot HmacType_slots[] = { -+ {Py_tp_doc, hmactype_doc}, -+ {Py_tp_repr, (reprfunc)_hmac_repr}, -+ {Py_tp_dealloc,(destructor)_hmac_dealloc}, -+ {Py_tp_methods, Hmac_methods}, -+ {Py_tp_getset, Hmac_getset}, -+ {Py_tp_members, Hmac_members}, -+ {0, NULL} -+}; ++ int r; + -+PyType_Spec HmacType_spec = { -+ "_hmacopenssl.HMAC", /* name */ -+ sizeof(HmacObject), /* basicsize */ -+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, -+ .slots = HmacType_slots, - }; - ++ if (self->lock != NULL) { ++ Py_BEGIN_ALLOW_THREADS ++ PyThread_acquire_lock(self->lock, 1); ++ r = HMAC_Update(self->ctx, (const unsigned char*)msg->buf, msg->len); ++ PyThread_release_lock(self->lock); ++ Py_END_ALLOW_THREADS ++ } else { ++ r = HMAC_Update(self->ctx, (const unsigned char*)msg->buf, msg->len); ++ } ++ ++ if (r == 0) { ++ _setException(PyExc_ValueError); ++ return NULL; ++ } ++ Py_RETURN_NONE; ++} ++ ++static unsigned int ++_digest_size(HmacObject *self) ++{ ++ const EVP_MD *md = HMAC_CTX_get_md(self->ctx); ++ if (md == NULL) { ++ _setException(PyExc_ValueError); ++ return 0; ++ } ++ return EVP_MD_size(md); ++} + - static struct PyMethodDef hmacopenssl_functions[] = { - _HMACOPENSSL_NEW_METHODDEF - {NULL, NULL} /* Sentinel */ -@@ -360,37 +377,46 @@ static struct PyMethodDef hmacopenssl_functions[] = { - - /* Initialize this module. */ - -- --static struct PyModuleDef _hmacopenssl_module = { -- PyModuleDef_HEAD_INIT, -- "_hmacopenssl", -- NULL, -- -1, -- hmacopenssl_functions, -- NULL, -- NULL, -- NULL, -- NULL --}; -- --PyMODINIT_FUNC --PyInit__hmacopenssl(void) --{ +static int -+hmacopenssl_exec(PyObject *m) { - /* TODO build EVP_functions openssl_* entries dynamically based - * on what hashes are supported rather than listing many -- * but having some be unsupported. Only init appropriate -+ * and having some unsupported. Only init appropriate - * constants. */ -+ PyObject *temp; - -- Py_TYPE(&HmacType) = &PyType_Type; -- if (PyType_Ready(&HmacType) < 0) -- return NULL; -+ temp = PyType_FromSpec(&HmacType_spec); -+ if (temp == NULL) { -+ goto fail; ++_digest(HmacObject *self, unsigned char *buf, unsigned int len) ++{ ++ HMAC_CTX *temp_ctx = HMAC_CTX_new(); ++ if (temp_ctx == NULL) { ++ PyErr_NoMemory(); ++ return 0; + } - -- PyObject *m = PyModule_Create(&_hmacopenssl_module); -- if (m == NULL) -- return NULL; -+ if (PyModule_AddObject(m, "HMAC", temp) == -1) { -+ goto fail; ++ int r = HMAC_CTX_copy(temp_ctx, self->ctx); ++ if (r == 0) { ++ _setException(PyExc_ValueError); ++ return 0; ++ } ++ r = HMAC_Final(temp_ctx, buf, &len); ++ HMAC_CTX_free(temp_ctx); ++ if (r == 0) { ++ _setException(PyExc_ValueError); ++ return 0; + } ++ return 1; ++} + -+ return 0; - -- Py_INCREF((PyObject *)&HmacType); -- PyModule_AddObject(m, "HMAC", (PyObject *)&HmacType); -+fail: -+ Py_XDECREF(temp); -+ return -1; ++/*[clinic input] ++_hmacopenssl.HMAC.digest ++ ++Return the digest of the bytes passed to the update() method so far. ++[clinic start generated code]*/ ++ ++static PyObject * ++_hmacopenssl_HMAC_digest_impl(HmacObject *self) ++/*[clinic end generated code: output=3aa6dbfc46ec4957 input=bf769a10b1d9edd9]*/ ++{ ++ unsigned int digest_size = _digest_size(self); ++ if (digest_size == 0) { ++ return _setException(PyExc_ValueError); ++ } ++ unsigned char buf[digest_size]; /* FIXME: C99 feature */ ++ int r = _digest(self, buf, digest_size); ++ if (r == 0) { ++ return NULL; ++ } ++ return PyBytes_FromStringAndSize((const char *)buf, digest_size); +} - -- return m; -+static PyModuleDef_Slot hmacopenssl_slots[] = { -+ {Py_mod_exec, hmacopenssl_exec}, -+ {0, NULL}, -+}; + -+static struct PyModuleDef _hmacopenssl_def = { -+ PyModuleDef_HEAD_INIT, /* m_base */ -+ .m_name = "_hmacopenssl", -+ .m_methods = hmacopenssl_functions, -+ .m_slots = hmacopenssl_slots, -+ .m_size = sizeof(hmacopenssl_state) -+}; ++/*[clinic input] ++_hmacopenssl.HMAC.hexdigest ++ ++Return hexadecimal digest of the bytes passed to the update() method so far. + ++This may be used to exchange the value safely in email or other non-binary ++environments. ++[clinic start generated code]*/ + -+PyMODINIT_FUNC -+PyInit__hmacopenssl(void) ++static PyObject * ++_hmacopenssl_HMAC_hexdigest_impl(HmacObject *self) ++/*[clinic end generated code: output=630f6fa89f9f1e48 input=b8e60ec8b811c4cd]*/ +{ -+ return PyModuleDef_Init(&_hmacopenssl_def); - } - -From 641e76725f2660da75490ea0c10da52688093778 Mon Sep 17 00:00:00 2001 -From: Marcel Plch -Date: Mon, 29 Jul 2019 13:05:04 +0200 -Subject: [PATCH 10/36] revert cosmetic nitpick and remove trailing whitespace - ---- - Lib/hmac.py | 2 +- - Modules/_hmacopenssl.c | 4 ++-- - 2 files changed, 3 insertions(+), 3 deletions(-) - -diff --git a/Lib/hmac.py b/Lib/hmac.py -index b9bf16b84ca0..ed98406bd2e1 100644 ---- a/Lib/hmac.py -+++ b/Lib/hmac.py -@@ -42,7 +42,7 @@ def __init__(self, key, msg = None, digestmod = None): - if _hashlib.get_fips_mode(): - raise ValueError( - 'hmac.HMAC is not available in FIPS mode. ' -- 'Use hmac.new().' -+ + 'Use hmac.new().' - ) - - if not isinstance(key, (bytes, bytearray)): -diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c -index 216ed04f2360..221714ca4349 100644 ---- a/Modules/_hmacopenssl.c -+++ b/Modules/_hmacopenssl.c -@@ -363,7 +363,7 @@ static PyType_Slot HmacType_slots[] = { - PyType_Spec HmacType_spec = { - "_hmacopenssl.HMAC", /* name */ - sizeof(HmacObject), /* basicsize */ -- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, -+ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .slots = HmacType_slots, - }; - -@@ -407,7 +407,7 @@ static PyModuleDef_Slot hmacopenssl_slots[] = { - }; - - static struct PyModuleDef _hmacopenssl_def = { -- PyModuleDef_HEAD_INIT, /* m_base */ -+ PyModuleDef_HEAD_INIT, /* m_base */ - .m_name = "_hmacopenssl", - .m_methods = hmacopenssl_functions, - .m_slots = hmacopenssl_slots, - -From 0a1522aacb0b070632f7feaad6f92bfe8fc9c89b Mon Sep 17 00:00:00 2001 -From: Charalampos Stratakis -Date: Wed, 31 Jul 2019 15:43:43 +0200 -Subject: [PATCH 11/36] Add initial tests for various hashes under FIPS mode - ---- - Lib/test/test_fips.py | 64 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 64 insertions(+) - create mode 100644 Lib/test/test_fips.py - -diff --git a/Lib/test/test_fips.py b/Lib/test/test_fips.py -new file mode 100644 -index 000000000000..bee911ef405a ---- /dev/null -+++ b/Lib/test/test_fips.py -@@ -0,0 +1,64 @@ -+import unittest -+import hmac, _hmacopenssl -+import hashlib, _hashlib ++ unsigned int digest_size = _digest_size(self); ++ if (digest_size == 0) { ++ return _setException(PyExc_ValueError); ++ } ++ unsigned char buf[digest_size]; /* FIXME: C99 feature */ ++ int r = _digest(self, buf, digest_size); ++ if (r == 0) { ++ return NULL; ++ } ++ return _Py_strhex((const char *)buf, digest_size); ++} + + + -+class HashlibFipsTests(unittest.TestCase): ++static PyObject * ++_hmacopenssl_get_digest_size(HmacObject *self, void *closure) ++{ ++ unsigned int digest_size = _digest_size(self); ++ if (digest_size == 0) { ++ return _setException(PyExc_ValueError); ++ } ++ return PyLong_FromLong(digest_size); ++} + -+ @unittest.skipUnless(hashlib.get_fips_mode(), "Test only when FIPS is enabled") -+ def test_fips_imports(self): -+ """blake2s and blake2b should fail to import in FIPS mode -+ """ -+ with self.assertRaises(ValueError, msg='blake2s not available in FIPS'): -+ m = hashlib.blake2s() -+ with self.assertRaises(ValueError, msg='blake2b not available in FIPS'): -+ m = hashlib.blake2b() ++static PyObject * ++_hmacopenssl_get_block_size(HmacObject *self, void *closure) ++{ ++ const EVP_MD *md = HMAC_CTX_get_md(self->ctx); ++ if (md == NULL) { ++ return _setException(PyExc_ValueError); ++ } ++ return PyLong_FromLong(EVP_MD_size(md)); ++} + -+ def compare_hashes(self, python_hash, openssl_hash): -+ """ -+ Compare between the python implementation and the openssl one that the digests -+ are the same -+ """ -+ if python_hash.name.startswith('shake_128'): -+ m = python_hash.hexdigest(16) -+ elif python_hash.name.startswith('shake_256'): -+ m = python_hash.hexdigest(32) -+ else: -+ m = python_hash.hexdigest() -+ h = openssl_hash.hexdigest() ++static PyMethodDef Hmac_methods[] = { ++ _HMACOPENSSL_HMAC_UPDATE_METHODDEF ++ _HMACOPENSSL_HMAC_DIGEST_METHODDEF ++ _HMACOPENSSL_HMAC_HEXDIGEST_METHODDEF ++ _HMACOPENSSL_HMAC_COPY_METHODDEF ++ {NULL, NULL} /* sentinel */ ++}; + -+ self.assertEqual(m, h) ++static PyGetSetDef Hmac_getset[] = { ++ {"digest_size", (getter)_hmacopenssl_get_digest_size, NULL, NULL, NULL}, ++ {"block_size", (getter)_hmacopenssl_get_block_size, NULL, NULL, NULL}, ++ {NULL} /* Sentinel */ ++}; + -+ @unittest.skipIf(hashlib.get_fips_mode(), "blake2 hashes are not available under FIPS") -+ def test_blake2_hashes(self): -+ self.compare_hashes(hashlib.blake2b(b'abc'), _hashlib.openssl_blake2b(b'abc')) -+ self.compare_hashes(hashlib.blake2s(b'abc'), _hashlib.openssl_blake2s(b'abc')) ++static PyMemberDef Hmac_members[] = { ++ {"name", T_OBJECT, offsetof(HmacObject, name), READONLY, PyDoc_STR("HMAC name")}, ++}; + -+ def test_sha3_hashes(self): -+ self.compare_hashes(hashlib.sha3_224(b'abc'), _hashlib.openssl_sha3_224(b'abc')) -+ self.compare_hashes(hashlib.sha3_256(b'abc'), _hashlib.openssl_sha3_256(b'abc')) -+ self.compare_hashes(hashlib.sha3_384(b'abc'), _hashlib.openssl_sha3_384(b'abc')) -+ self.compare_hashes(hashlib.sha3_512(b'abc'), _hashlib.openssl_sha3_512(b'abc')) ++PyDoc_STRVAR(hmactype_doc, ++"The object used to calculate HMAC of a message.\n\ ++\n\ ++Methods:\n\ ++\n\ ++update() -- updates the current digest with an additional string\n\ ++digest() -- return the current digest value\n\ ++hexdigest() -- return the current digest as a string of hexadecimal digits\n\ ++copy() -- return a copy of the current hash object\n\ ++\n\ ++Attributes:\n\ ++\n\ ++name -- the name, including the hash algorithm used by this object\n\ ++digest_size -- number of bytes in digest() output\n"); + -+ @unittest.skipIf(hashlib.get_fips_mode(), "shake hashes are not available under FIPS") -+ def test_shake_hashes(self): -+ self.compare_hashes(hashlib.shake_128(b'abc'), _hashlib.openssl_shake_128(b'abc')) -+ self.compare_hashes(hashlib.shake_256(b'abc'), _hashlib.openssl_shake_256(b'abc')) ++static PyTypeObject HmacType = { ++ PyVarObject_HEAD_INIT(NULL, 0) ++ "_hmacopenssl.HMAC", /*tp_name*/ ++ sizeof(HmacObject), /*tp_basicsize*/ ++ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, ++ .tp_doc = hmactype_doc, ++ .tp_repr = (reprfunc)_hmac_repr, ++ .tp_dealloc = (destructor)_hmac_dealloc, ++ .tp_methods = Hmac_methods, ++ .tp_getset = Hmac_getset, ++ .tp_members = Hmac_members, ++}; + -+ def test_sha(self): -+ self.compare_hashes(hashlib.sha1(b'abc'), _hashlib.openssl_sha1(b'abc')) -+ self.compare_hashes(hashlib.sha224(b'abc'), _hashlib.openssl_sha224(b'abc')) -+ self.compare_hashes(hashlib.sha256(b'abc'), _hashlib.openssl_sha256(b'abc')) -+ self.compare_hashes(hashlib.sha384(b'abc'), _hashlib.openssl_sha384(b'abc')) -+ self.compare_hashes(hashlib.sha512(b'abc'), _hashlib.openssl_sha512(b'abc')) ++static struct PyMethodDef hmacopenssl_functions[] = { ++ _HMACOPENSSL_NEW_METHODDEF ++ {NULL, NULL} /* Sentinel */ ++}; + -+ def test_hmac_digests(self): -+ self.compare_hashes(_hmacopenssl.new(b'My hovercraft is full of eels', digestmod='sha384'), -+ hmac.new(b'My hovercraft is full of eels', digestmod='sha384')) + + ++/* Initialize this module. */ + + -+if __name__ == "__main__": -+ unittest.main() - -From f20b01bb18523587cb5beedc67a8ee08a502788d Mon Sep 17 00:00:00 2001 -From: Marcel Plch -Date: Thu, 1 Aug 2019 16:39:37 +0200 -Subject: [PATCH 12/36] Initialize HMAC type. - ---- - Modules/_hmacopenssl.c | 12 ++++++++---- - 1 file changed, 8 insertions(+), 4 deletions(-) - -diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c -index 221714ca4349..239445a0831b 100644 ---- a/Modules/_hmacopenssl.c -+++ b/Modules/_hmacopenssl.c -@@ -22,12 +22,12 @@ - #include "_hashopenssl.h" - - --#include - - typedef struct hmacopenssl_state { - PyTypeObject *HmacType; - } hmacopenssl_state; - -+#include - - typedef struct { - PyObject_HEAD -@@ -39,7 +39,7 @@ typedef struct { - #include "clinic/_hmacopenssl.c.h" - /*[clinic input] - module _hmacopenssl --class _hmacopenssl.HMAC "HmacObject *" "PyModule_GetState(module)->HmacType" -+class _hmacopenssl.HMAC "HmacObject *" "((hmacopenssl_state *)PyModule_GetState(module))->HmacType" - [clinic start generated code]*/ - /*[clinic end generated code: output=da39a3ee5e6b4b0d input=204b7f45847f57b4]*/ - -@@ -71,7 +71,7 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, - return NULL; - } - -- /* name mut be lowercase */ -+ /* name must be lowercase */ - for (int i=0; digestmod[i]; i++) { - if ( - ((digestmod[i] < 'a') || (digestmod[i] > 'z')) -@@ -383,7 +383,8 @@ hmacopenssl_exec(PyObject *m) { - * on what hashes are supported rather than listing many - * and having some unsupported. Only init appropriate - * constants. */ -- PyObject *temp; -+ PyObject *temp = NULL; -+ hmacopenssl_state *state; - - temp = PyType_FromSpec(&HmacType_spec); - if (temp == NULL) { -@@ -394,6 +395,9 @@ hmacopenssl_exec(PyObject *m) { - goto fail; - } - -+ state = PyModule_GetState(m); -+ state->HmacType = (PyTypeObject *)temp; ++static struct PyModuleDef _hmacopenssl_module = { ++ PyModuleDef_HEAD_INIT, ++ "_hmacopenssl", ++ NULL, ++ -1, ++ hmacopenssl_functions, ++ NULL, ++ NULL, ++ NULL, ++ NULL ++}; + - return 0; - - fail: - -From b819ca654873ea36144ce1cb6f8c422a6d2f5d7d Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Thu, 1 Aug 2019 17:57:05 +0200 -Subject: [PATCH 13/36] Use a stronger hash in multiprocessing handshake - -Adapted from patch by David Malcolm, -https://bugs.python.org/issue17258 ---- - Lib/multiprocessing/connection.py | 8 ++++++-- - 1 file changed, 6 insertions(+), 2 deletions(-) - -diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py -index d3797503a755..a0b1538f88b3 100644 ---- a/Lib/multiprocessing/connection.py -+++ b/Lib/multiprocessing/connection.py -@@ -42,6 +42,10 @@ - # A very generous timeout when it comes to local connections... - CONNECTION_TIMEOUT = 20. - -+# The hmac module implicitly defaults to using MD5. -+# Support using a stronger algorithm for the challenge/response code: -+HMAC_DIGEST_NAME='sha256' ++PyMODINIT_FUNC ++PyInit__hmacopenssl(void) ++{ ++ /* TODO build EVP_functions openssl_* entries dynamically based ++ * on what hashes are supported rather than listing many ++ * but having some be unsupported. Only init appropriate ++ * constants. */ + - _mmap_counter = itertools.count() - - default_family = 'AF_INET' -@@ -718,7 +722,7 @@ def deliver_challenge(connection, authkey): - assert isinstance(authkey, bytes) - message = os.urandom(MESSAGE_LENGTH) - connection.send_bytes(CHALLENGE + message) -- digest = hmac.new(authkey, message, 'md5').digest() -+ digest = hmac.new(authkey, message, HMAC_DIGEST_NAME).digest() - response = connection.recv_bytes(256) # reject large message - if response == digest: - connection.send_bytes(WELCOME) -@@ -732,7 +736,7 @@ def answer_challenge(connection, authkey): - message = connection.recv_bytes(256) # reject large message - assert message[:len(CHALLENGE)] == CHALLENGE, 'message = %r' % message - message = message[len(CHALLENGE):] -- digest = hmac.new(authkey, message, 'md5').digest() -+ digest = hmac.new(authkey, message, HMAC_DIGEST_NAME).digest() - connection.send_bytes(digest) - response = connection.recv_bytes(256) # reject large message - if response != WELCOME: - -From 01950bb63c0a52faf5304e3978a6308641305a03 Mon Sep 17 00:00:00 2001 -From: Marcel Plch -Date: Fri, 2 Aug 2019 17:36:01 +0200 -Subject: [PATCH 14/36] Fix refcounting - ---- - Modules/_hmacopenssl.c | 35 ++++++++++++++++++++++++++++++++++- - 1 file changed, 34 insertions(+), 1 deletion(-) - -diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c -index 239445a0831b..9c2882833d1c 100644 ---- a/Modules/_hmacopenssl.c -+++ b/Modules/_hmacopenssl.c -@@ -373,6 +373,34 @@ static struct PyMethodDef hmacopenssl_functions[] = { - {NULL, NULL} /* Sentinel */ - }; - -+static int -+hmacopenssl_traverse(PyObject *self, visitproc visit, void *arg) ++ Py_TYPE(&HmacType) = &PyType_Type; ++ if (PyType_Ready(&HmacType) < 0) ++ return NULL; ++ ++ PyObject *m = PyModule_Create(&_hmacopenssl_module); ++ if (m == NULL) ++ return NULL; ++ ++ Py_INCREF((PyObject *)&HmacType); ++ PyModule_AddObject(m, "HMAC", (PyObject *)&HmacType); ++ ++ return m; ++} +diff --git a/Modules/clinic/_hmacopenssl.c.h b/Modules/clinic/_hmacopenssl.c.h +new file mode 100644 +index 00000000000..b472a6eddd3 +--- /dev/null ++++ b/Modules/clinic/_hmacopenssl.c.h +@@ -0,0 +1,133 @@ ++/*[clinic input] ++preserve ++[clinic start generated code]*/ ++ ++PyDoc_STRVAR(_hmacopenssl_new__doc__, ++"new($module, /, key, *, digestmod)\n" ++"--\n" ++"\n" ++"Return a new hmac object."); ++ ++#define _HMACOPENSSL_NEW_METHODDEF \ ++ {"new", (PyCFunction)_hmacopenssl_new, METH_FASTCALL, _hmacopenssl_new__doc__}, ++ ++static PyObject * ++_hmacopenssl_new_impl(PyObject *module, Py_buffer *key, ++ const char *digestmod); ++ ++static PyObject * ++_hmacopenssl_new(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +{ -+ hmacopenssl_state *state; ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"key", "digestmod", NULL}; ++ static _PyArg_Parser _parser = {"y*$s:new", _keywords, 0}; ++ Py_buffer key = {NULL, NULL}; ++ const char *digestmod; + -+ state = PyModule_GetState(self); ++ if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, ++ &key, &digestmod)) { ++ goto exit; ++ } ++ return_value = _hmacopenssl_new_impl(module, &key, digestmod); + -+ if (state) { -+ Py_VISIT(state->HmacType); ++exit: ++ /* Cleanup for key */ ++ if (key.obj) { ++ PyBuffer_Release(&key); + } + -+ return 0; ++ return return_value; +} + -+static int -+hmacopenssl_clear(PyObject *self) ++PyDoc_STRVAR(_hmacopenssl_HMAC_copy__doc__, ++"copy($self, /)\n" ++"--\n" ++"\n" ++"Return a copy (“clone”) of the HMAC object."); ++ ++#define _HMACOPENSSL_HMAC_COPY_METHODDEF \ ++ {"copy", (PyCFunction)_hmacopenssl_HMAC_copy, METH_NOARGS, _hmacopenssl_HMAC_copy__doc__}, ++ ++static PyObject * ++_hmacopenssl_HMAC_copy_impl(HmacObject *self); ++ ++static PyObject * ++_hmacopenssl_HMAC_copy(HmacObject *self, PyObject *Py_UNUSED(ignored)) +{ -+ hmacopenssl_state *state; ++ return _hmacopenssl_HMAC_copy_impl(self); ++} + -+ state = PyModule_GetState(self); ++PyDoc_STRVAR(_hmacopenssl_HMAC_update__doc__, ++"update($self, /, msg)\n" ++"--\n" ++"\n" ++"Update the HMAC object with msg."); + -+ if (state) { -+ Py_CLEAR(state->HmacType); ++#define _HMACOPENSSL_HMAC_UPDATE_METHODDEF \ ++ {"update", (PyCFunction)_hmacopenssl_HMAC_update, METH_FASTCALL, _hmacopenssl_HMAC_update__doc__}, ++ ++static PyObject * ++_hmacopenssl_HMAC_update_impl(HmacObject *self, Py_buffer *msg); ++ ++static PyObject * ++_hmacopenssl_HMAC_update(HmacObject *self, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) ++{ ++ PyObject *return_value = NULL; ++ static const char * const _keywords[] = {"msg", NULL}; ++ static _PyArg_Parser _parser = {"y*:update", _keywords, 0}; ++ Py_buffer msg = {NULL, NULL}; ++ ++ if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, ++ &msg)) { ++ goto exit; + } ++ return_value = _hmacopenssl_HMAC_update_impl(self, &msg); + -+ return 0; ++exit: ++ /* Cleanup for msg */ ++ if (msg.obj) { ++ PyBuffer_Release(&msg); ++ } ++ ++ return return_value; +} + - - - /* Initialize this module. */ -@@ -396,7 +424,10 @@ hmacopenssl_exec(PyObject *m) { - } - - state = PyModule_GetState(m); ++PyDoc_STRVAR(_hmacopenssl_HMAC_digest__doc__, ++"digest($self, /)\n" ++"--\n" ++"\n" ++"Return the digest of the bytes passed to the update() method so far."); + - state->HmacType = (PyTypeObject *)temp; -+ Py_INCREF(temp); ++#define _HMACOPENSSL_HMAC_DIGEST_METHODDEF \ ++ {"digest", (PyCFunction)_hmacopenssl_HMAC_digest, METH_NOARGS, _hmacopenssl_HMAC_digest__doc__}, + - - return 0; - -@@ -415,7 +446,9 @@ static struct PyModuleDef _hmacopenssl_def = { - .m_name = "_hmacopenssl", - .m_methods = hmacopenssl_functions, - .m_slots = hmacopenssl_slots, -- .m_size = sizeof(hmacopenssl_state) -+ .m_size = sizeof(hmacopenssl_state), -+ .m_traverse = hmacopenssl_traverse, -+ .m_clear = hmacopenssl_clear - }; - - - -From 823eae4610e3235f60a89715ba37a970c18a7c0b Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Mon, 5 Aug 2019 13:37:05 +0200 -Subject: [PATCH 15/36] hmac: Don't default to md5 in FIPS mode - ---- - Lib/hmac.py | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/Lib/hmac.py b/Lib/hmac.py -index ed98406bd2e1..7b8821edd582 100644 ---- a/Lib/hmac.py -+++ b/Lib/hmac.py -@@ -165,7 +165,7 @@ def new(key, msg = None, digestmod = None): - """ - if _hashlib.get_fips_mode(): - if digestmod is None: -- digestmod = 'md5' -+ raise ValueError("'digestmod' argument is mandatory in FIPS mode") - name = _get_openssl_name(digestmod) - result = _hmacopenssl.new(key, digestmod=name) - if msg: - -From fd74d1c00d95542eef3c238f990da5bc7fc05619 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Mon, 5 Aug 2019 14:20:58 +0200 -Subject: [PATCH 16/36] Make _hmacopenssl.HMAC subclassable; subclass it as - hmac.HMAC under FIPS - -This removes the _hmacopenssl.new function. ---- - Lib/hmac.py | 27 +++++++----- - Lib/test/test_fips.py | 2 +- - Modules/_hmacopenssl.c | 75 ++++++++++++++++----------------- - Modules/clinic/_hmacopenssl.c.h | 39 +---------------- - 4 files changed, 56 insertions(+), 87 deletions(-) - -diff --git a/Lib/hmac.py b/Lib/hmac.py -index 7b8821edd582..d479c5a4492f 100644 ---- a/Lib/hmac.py -+++ b/Lib/hmac.py -@@ -141,6 +141,8 @@ def hexdigest(self): - - - def _get_openssl_name(digestmod): -+ if digestmod is None: -+ raise ValueError("'digestmod' argument is mandatory in FIPS mode") - if isinstance(digestmod, str): - return digestmod.lower() - elif callable(digestmod): -@@ -152,6 +154,20 @@ def _get_openssl_name(digestmod): - - return digestmod.name.lower().replace('_', '-') - ++static PyObject * ++_hmacopenssl_HMAC_digest_impl(HmacObject *self); + -+class HMAC_openssl(_hmacopenssl.HMAC): -+ def __new__(cls, key, msg = None, digestmod = None): -+ name = _get_openssl_name(digestmod) -+ result = _hmacopenssl.HMAC.__new__(cls, key, digestmod=name) -+ if msg: -+ result.update(msg) -+ return result ++static PyObject * ++_hmacopenssl_HMAC_digest(HmacObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ return _hmacopenssl_HMAC_digest_impl(self); ++} + ++PyDoc_STRVAR(_hmacopenssl_HMAC_hexdigest__doc__, ++"hexdigest($self, /)\n" ++"--\n" ++"\n" ++"Return hexadecimal digest of the bytes passed to the update() method so far.\n" ++"\n" ++"This may be used to exchange the value safely in email or other non-binary\n" ++"environments."); + -+if _hashlib.get_fips_mode(): -+ HMAC = HMAC_openssl ++#define _HMACOPENSSL_HMAC_HEXDIGEST_METHODDEF \ ++ {"hexdigest", (PyCFunction)_hmacopenssl_HMAC_hexdigest, METH_NOARGS, _hmacopenssl_HMAC_hexdigest__doc__}, + ++static PyObject * ++_hmacopenssl_HMAC_hexdigest_impl(HmacObject *self); + - def new(key, msg = None, digestmod = None): - """Create a new hashing object and return it. - -@@ -163,13 +179,4 @@ def new(key, msg = None, digestmod = None): - method, and can ask for the hash value at any time by calling its digest() - method. - """ -- if _hashlib.get_fips_mode(): -- if digestmod is None: -- raise ValueError("'digestmod' argument is mandatory in FIPS mode") -- name = _get_openssl_name(digestmod) -- result = _hmacopenssl.new(key, digestmod=name) -- if msg: -- result.update(msg) -- return result -- else: -- return HMAC(key, msg, digestmod) -+ return HMAC(key, msg, digestmod) -diff --git a/Lib/test/test_fips.py b/Lib/test/test_fips.py -index bee911ef405a..34812e6098ae 100644 ---- a/Lib/test/test_fips.py -+++ b/Lib/test/test_fips.py -@@ -54,7 +54,7 @@ def test_sha(self): - self.compare_hashes(hashlib.sha512(b'abc'), _hashlib.openssl_sha512(b'abc')) - - def test_hmac_digests(self): -- self.compare_hashes(_hmacopenssl.new(b'My hovercraft is full of eels', digestmod='sha384'), -+ self.compare_hashes(_hmacopenssl.HMAC(b'My hovercraft is full of eels', digestmod='sha384'), - hmac.new(b'My hovercraft is full of eels', digestmod='sha384')) ++static PyObject * ++_hmacopenssl_HMAC_hexdigest(HmacObject *self, PyObject *Py_UNUSED(ignored)) ++{ ++ return _hmacopenssl_HMAC_hexdigest_impl(self); ++} ++/*[clinic end generated code: output=10b6e8cac6d7a2c9 input=a9049054013a1b77]*/ +diff --git a/setup.py b/setup.py +index e2e659ef795..282aa4178ed 100644 +--- a/setup.py ++++ b/setup.py +@@ -922,6 +922,10 @@ class PyBuildExt(build_ext): + openssl_ver) + missing.append('_hashlib') ++ exts.append( Extension('_hmacopenssl', ['_hmacopenssl.c'], ++ depends = ['hashlib.h'], ++ **ssl_args)) ++ + # RHEL: Always force OpenSSL for md5, sha1, sha256, sha512; + # don't build Python's implementations. + # sha3 and blake2 have extra functionality, so do build those: +-- +2.21.0 + + +From 37797b4d89e7b4859dc4728da91cbebf5fdb2a52 Mon Sep 17 00:00:00 2001 +From: Marcel Plch +Date: Mon, 29 Jul 2019 12:45:11 +0200 +Subject: [PATCH 12/36] FIPS review + +* Port _hmacopenssl to multiphase init. +* Make _hmacopenssl.HMAC.copy create same type as self. +* hmac.py cosmetic nitpick +--- + Lib/hmac.py | 2 +- + Modules/_hmacopenssl.c | 112 +++++++++++++++++++++++++---------------- + 2 files changed, 70 insertions(+), 44 deletions(-) + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index ed98406bd2e..b9bf16b84ca 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -42,7 +42,7 @@ class HMAC: + if _hashlib.get_fips_mode(): + raise ValueError( + 'hmac.HMAC is not available in FIPS mode. ' +- + 'Use hmac.new().' ++ 'Use hmac.new().' + ) + if not isinstance(key, (bytes, bytearray)): diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c -index 9c2882833d1c..7d3d9739f3ab 100644 +index ca95d725f01..216ed04f236 100644 --- a/Modules/_hmacopenssl.c +++ b/Modules/_hmacopenssl.c -@@ -41,33 +41,25 @@ typedef struct { +@@ -24,7 +24,10 @@ + + #include + +-static PyTypeObject HmacType; ++typedef struct hmacopenssl_state { ++ PyTypeObject *HmacType; ++} hmacopenssl_state; ++ + + typedef struct { + PyObject_HEAD +@@ -36,9 +39,9 @@ typedef struct { + #include "clinic/_hmacopenssl.c.h" + /*[clinic input] module _hmacopenssl - class _hmacopenssl.HMAC "HmacObject *" "((hmacopenssl_state *)PyModule_GetState(module))->HmacType" +-class _hmacopenssl.HMAC "HmacObject *" "&HmacType" ++class _hmacopenssl.HMAC "HmacObject *" "PyModule_GetState(module)->HmacType" [clinic start generated code]*/ --/*[clinic end generated code: output=da39a3ee5e6b4b0d input=204b7f45847f57b4]*/ -+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=9fe07a087adc2cf9]*/ +-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c98d3f2af591c085]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=204b7f45847f57b4]*/ --/*[clinic input] --_hmacopenssl.new -- -- key: Py_buffer -- * -- digestmod: str -- --Return a new hmac object. --[clinic start generated code]*/ -- - static PyObject * --_hmacopenssl_new_impl(PyObject *module, Py_buffer *key, -- const char *digestmod) --/*[clinic end generated code: output=46f1cb4e02921922 input=be8c0c2e4fad508c]*/ -+Hmac_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) + /*[clinic input] +@@ -56,11 +59,18 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, + const char *digestmod) + /*[clinic end generated code: output=46f1cb4e02921922 input=be8c0c2e4fad508c]*/ { -- hmacopenssl_state *state; -- -- if (digestmod == NULL) { -- PyErr_SetString(PyExc_ValueError, "digestmod must be specified"); -+ static char *kwarg_names[] = {"key", "digestmod", NULL}; -+ Py_buffer key = {NULL, NULL}; -+ char *digestmod = NULL; ++ hmacopenssl_state *state; + -+ int ret = PyArg_ParseTupleAndKeywords( -+ args, kwds, "y*|$s:_hmacopenssl.HMAC", kwarg_names, -+ &key, &digestmod); -+ if (ret == 0) { + if (digestmod == NULL) { + PyErr_SetString(PyExc_ValueError, "digestmod must be specified"); return NULL; } -- state = PyModule_GetState(module); -- if (state == NULL) { -+ if (digestmod == NULL) { -+ PyErr_SetString(PyExc_ValueError, "digestmod must be specified"); - return NULL; ++ state = PyModule_GetState(module); ++ if (state == NULL) { ++ return NULL; ++ } ++ + /* name mut be lowercase */ + for (int i=0; digestmod[i]; i++) { + if ( +@@ -105,7 +115,7 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, + goto error; } -@@ -106,8 +98,8 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, - - int r = HMAC_Init_ex( - ctx, -- (const char*)key->buf, -- key->len, -+ (const char*)key.buf, -+ key.len, - digest, - NULL /*impl*/); - if (r == 0) { -@@ -115,7 +107,10 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, +- retval = (HmacObject *)PyObject_New(HmacObject, &HmacType); ++ retval = (HmacObject *)PyObject_New(HmacObject, state->HmacType); + if (retval == NULL) { goto error; } - -- retval = (HmacObject *)PyObject_New(HmacObject, state->HmacType); -+ PyBuffer_Release(&key); -+ key.buf = NULL; +@@ -133,7 +143,9 @@ static PyObject * + _hmacopenssl_HMAC_copy_impl(HmacObject *self) + /*[clinic end generated code: output=fe5ee41faf30dcf0 input=f5ed20feec42d8d0]*/ + { +- HmacObject *retval = (HmacObject *)PyObject_New(HmacObject, &HmacType); ++ HmacObject *retval; + -+ retval = (HmacObject *)subtype->tp_alloc(subtype, 0); ++ retval = (HmacObject *)PyObject_New(HmacObject, (PyTypeObject *)PyObject_Type((PyObject *)self)); if (retval == NULL) { - goto error; + return NULL; } -@@ -130,6 +125,7 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, - if (ctx) HMAC_CTX_free(ctx); - if (name) Py_DECREF(name); - if (retval) PyObject_Del(name); -+ if (key.buf) PyBuffer_Release(&key); - return NULL; +@@ -147,7 +159,7 @@ _hmacopenssl_HMAC_copy_impl(HmacObject *self) + return _setException(PyExc_ValueError); + } + +- return (PyObject*)retval; ++ return (PyObject *)retval; } -@@ -145,19 +141,27 @@ _hmacopenssl_HMAC_copy_impl(HmacObject *self) - { - HmacObject *retval; + static void +@@ -338,19 +350,24 @@ Attributes:\n\ + name -- the name, including the hash algorithm used by this object\n\ + digest_size -- number of bytes in digest() output\n"); -- retval = (HmacObject *)PyObject_New(HmacObject, (PyTypeObject *)PyObject_Type((PyObject *)self)); -+ HMAC_CTX *ctx = HMAC_CTX_new(); -+ if (ctx == NULL) { -+ return _setException(PyExc_ValueError); -+ } +-static PyTypeObject HmacType = { +- PyVarObject_HEAD_INIT(NULL, 0) +- "_hmacopenssl.HMAC", /*tp_name*/ +- sizeof(HmacObject), /*tp_basicsize*/ +- .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, +- .tp_doc = hmactype_doc, +- .tp_repr = (reprfunc)_hmac_repr, +- .tp_dealloc = (destructor)_hmac_dealloc, +- .tp_methods = Hmac_methods, +- .tp_getset = Hmac_getset, +- .tp_members = Hmac_members, ++static PyType_Slot HmacType_slots[] = { ++ {Py_tp_doc, hmactype_doc}, ++ {Py_tp_repr, (reprfunc)_hmac_repr}, ++ {Py_tp_dealloc,(destructor)_hmac_dealloc}, ++ {Py_tp_methods, Hmac_methods}, ++ {Py_tp_getset, Hmac_getset}, ++ {Py_tp_members, Hmac_members}, ++ {0, NULL} ++}; + -+ int r = HMAC_CTX_copy(ctx, self->ctx); -+ if (r == 0) { -+ HMAC_CTX_free(ctx); -+ return _setException(PyExc_ValueError); -+ } ++PyType_Spec HmacType_spec = { ++ "_hmacopenssl.HMAC", /* name */ ++ sizeof(HmacObject), /* basicsize */ ++ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, ++ .slots = HmacType_slots, + }; + + -+ retval = (HmacObject *)Py_TYPE(self)->tp_alloc(Py_TYPE(self), 0); - if (retval == NULL) { -+ HMAC_CTX_free(ctx); - return NULL; - } + static struct PyMethodDef hmacopenssl_functions[] = { + _HMACOPENSSL_NEW_METHODDEF + {NULL, NULL} /* Sentinel */ +@@ -360,37 +377,46 @@ static struct PyMethodDef hmacopenssl_functions[] = { + + /* Initialize this module. */ + - -+ retval->ctx = ctx; - Py_INCREF(self->name); - retval->name = self->name; +-static struct PyModuleDef _hmacopenssl_module = { +- PyModuleDef_HEAD_INIT, +- "_hmacopenssl", +- NULL, +- -1, +- hmacopenssl_functions, +- NULL, +- NULL, +- NULL, +- NULL +-}; +- +-PyMODINIT_FUNC +-PyInit__hmacopenssl(void) +-{ ++static int ++hmacopenssl_exec(PyObject *m) { + /* TODO build EVP_functions openssl_* entries dynamically based + * on what hashes are supported rather than listing many +- * but having some be unsupported. Only init appropriate ++ * and having some unsupported. Only init appropriate + * constants. */ ++ PyObject *temp; -- int r = HMAC_CTX_copy(retval->ctx, self->ctx); -- if (r == 0) { -- PyObject_Del(retval); -- return _setException(PyExc_ValueError); -- } -+ retval->lock = NULL; +- Py_TYPE(&HmacType) = &PyType_Type; +- if (PyType_Ready(&HmacType) < 0) +- return NULL; ++ temp = PyType_FromSpec(&HmacType_spec); ++ if (temp == NULL) { ++ goto fail; ++ } - return (PyObject *)retval; - } -@@ -169,8 +173,8 @@ _hmac_dealloc(HmacObject *self) - PyThread_free_lock(self->lock); - } - HMAC_CTX_free(self->ctx); -- Py_XDECREF(self->name); -- PyObject_Del(self); -+ Py_CLEAR(self->name); -+ Py_TYPE(self)->tp_free(self); +- PyObject *m = PyModule_Create(&_hmacopenssl_module); +- if (m == NULL) +- return NULL; ++ if (PyModule_AddObject(m, "HMAC", temp) == -1) { ++ goto fail; ++ } ++ ++ return 0; + +- Py_INCREF((PyObject *)&HmacType); +- PyModule_AddObject(m, "HMAC", (PyObject *)&HmacType); ++fail: ++ Py_XDECREF(temp); ++ return -1; ++} + +- return m; ++static PyModuleDef_Slot hmacopenssl_slots[] = { ++ {Py_mod_exec, hmacopenssl_exec}, ++ {0, NULL}, ++}; ++ ++static struct PyModuleDef _hmacopenssl_def = { ++ PyModuleDef_HEAD_INIT, /* m_base */ ++ .m_name = "_hmacopenssl", ++ .m_methods = hmacopenssl_functions, ++ .m_slots = hmacopenssl_slots, ++ .m_size = sizeof(hmacopenssl_state) ++}; ++ ++ ++PyMODINIT_FUNC ++PyInit__hmacopenssl(void) ++{ ++ return PyModuleDef_Init(&_hmacopenssl_def); } +-- +2.21.0 + + +From 9a3bf73d382cda99a665cab8438f3cd0388256b0 Mon Sep 17 00:00:00 2001 +From: Marcel Plch +Date: Mon, 29 Jul 2019 13:05:04 +0200 +Subject: [PATCH 13/36] revert cosmetic nitpick and remove trailing whitespace + +--- + Lib/hmac.py | 2 +- + Modules/_hmacopenssl.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index b9bf16b84ca..ed98406bd2e 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -42,7 +42,7 @@ class HMAC: + if _hashlib.get_fips_mode(): + raise ValueError( + 'hmac.HMAC is not available in FIPS mode. ' +- 'Use hmac.new().' ++ + 'Use hmac.new().' + ) - static PyObject * -@@ -357,6 +361,7 @@ static PyType_Slot HmacType_slots[] = { - {Py_tp_methods, Hmac_methods}, - {Py_tp_getset, Hmac_getset}, - {Py_tp_members, Hmac_members}, -+ {Py_tp_new, Hmac_new}, - {0, NULL} + if not isinstance(key, (bytes, bytearray)): +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +index 216ed04f236..221714ca434 100644 +--- a/Modules/_hmacopenssl.c ++++ b/Modules/_hmacopenssl.c +@@ -363,7 +363,7 @@ static PyType_Slot HmacType_slots[] = { + PyType_Spec HmacType_spec = { + "_hmacopenssl.HMAC", /* name */ + sizeof(HmacObject), /* basicsize */ +- .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, ++ .flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .slots = HmacType_slots, }; -@@ -368,11 +373,6 @@ PyType_Spec HmacType_spec = { +@@ -407,7 +407,7 @@ static PyModuleDef_Slot hmacopenssl_slots[] = { }; - --static struct PyMethodDef hmacopenssl_functions[] = { -- _HMACOPENSSL_NEW_METHODDEF -- {NULL, NULL} /* Sentinel */ --}; -- - static int - hmacopenssl_traverse(PyObject *self, visitproc visit, void *arg) - { -@@ -444,7 +444,6 @@ static PyModuleDef_Slot hmacopenssl_slots[] = { static struct PyModuleDef _hmacopenssl_def = { - PyModuleDef_HEAD_INIT, /* m_base */ +- PyModuleDef_HEAD_INIT, /* m_base */ ++ PyModuleDef_HEAD_INIT, /* m_base */ .m_name = "_hmacopenssl", -- .m_methods = hmacopenssl_functions, + .m_methods = hmacopenssl_functions, .m_slots = hmacopenssl_slots, - .m_size = sizeof(hmacopenssl_state), - .m_traverse = hmacopenssl_traverse, -diff --git a/Modules/clinic/_hmacopenssl.c.h b/Modules/clinic/_hmacopenssl.c.h -index b472a6eddd34..861acc11bfd9 100644 ---- a/Modules/clinic/_hmacopenssl.c.h -+++ b/Modules/clinic/_hmacopenssl.c.h -@@ -2,43 +2,6 @@ - preserve - [clinic start generated code]*/ - --PyDoc_STRVAR(_hmacopenssl_new__doc__, --"new($module, /, key, *, digestmod)\n" --"--\n" --"\n" --"Return a new hmac object."); -- --#define _HMACOPENSSL_NEW_METHODDEF \ -- {"new", (PyCFunction)_hmacopenssl_new, METH_FASTCALL, _hmacopenssl_new__doc__}, -- --static PyObject * --_hmacopenssl_new_impl(PyObject *module, Py_buffer *key, -- const char *digestmod); -- --static PyObject * --_hmacopenssl_new(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) --{ -- PyObject *return_value = NULL; -- static const char * const _keywords[] = {"key", "digestmod", NULL}; -- static _PyArg_Parser _parser = {"y*$s:new", _keywords, 0}; -- Py_buffer key = {NULL, NULL}; -- const char *digestmod; -- -- if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, -- &key, &digestmod)) { -- goto exit; -- } -- return_value = _hmacopenssl_new_impl(module, &key, digestmod); -- --exit: -- /* Cleanup for key */ -- if (key.obj) { -- PyBuffer_Release(&key); -- } -- -- return return_value; --} -- - PyDoc_STRVAR(_hmacopenssl_HMAC_copy__doc__, - "copy($self, /)\n" - "--\n" -@@ -130,4 +93,4 @@ _hmacopenssl_HMAC_hexdigest(HmacObject *self, PyObject *Py_UNUSED(ignored)) - { - return _hmacopenssl_HMAC_hexdigest_impl(self); - } --/*[clinic end generated code: output=10b6e8cac6d7a2c9 input=a9049054013a1b77]*/ -+/*[clinic end generated code: output=d93ad460795d49b5 input=a9049054013a1b77]*/ +-- +2.21.0 -From d3b322a12c10890fee2bc4837a3d37f0a81455a6 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Mon, 5 Aug 2019 16:10:36 +0200 -Subject: [PATCH 17/36] Fix _hmacopenssl.HMAC.block_size + +From b2853963d35c60595cec7e5cd40f31b1c9c59426 Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Wed, 31 Jul 2019 15:43:43 +0200 +Subject: [PATCH 14/36] Add initial tests for various hashes under FIPS mode --- - Modules/_hmacopenssl.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) + Lib/test/test_fips.py | 64 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 64 insertions(+) + create mode 100644 Lib/test/test_fips.py + +diff --git a/Lib/test/test_fips.py b/Lib/test/test_fips.py +new file mode 100644 +index 00000000000..bee911ef405 +--- /dev/null ++++ b/Lib/test/test_fips.py +@@ -0,0 +1,64 @@ ++import unittest ++import hmac, _hmacopenssl ++import hashlib, _hashlib ++ ++ ++ ++class HashlibFipsTests(unittest.TestCase): ++ ++ @unittest.skipUnless(hashlib.get_fips_mode(), "Test only when FIPS is enabled") ++ def test_fips_imports(self): ++ """blake2s and blake2b should fail to import in FIPS mode ++ """ ++ with self.assertRaises(ValueError, msg='blake2s not available in FIPS'): ++ m = hashlib.blake2s() ++ with self.assertRaises(ValueError, msg='blake2b not available in FIPS'): ++ m = hashlib.blake2b() ++ ++ def compare_hashes(self, python_hash, openssl_hash): ++ """ ++ Compare between the python implementation and the openssl one that the digests ++ are the same ++ """ ++ if python_hash.name.startswith('shake_128'): ++ m = python_hash.hexdigest(16) ++ elif python_hash.name.startswith('shake_256'): ++ m = python_hash.hexdigest(32) ++ else: ++ m = python_hash.hexdigest() ++ h = openssl_hash.hexdigest() ++ ++ self.assertEqual(m, h) ++ ++ @unittest.skipIf(hashlib.get_fips_mode(), "blake2 hashes are not available under FIPS") ++ def test_blake2_hashes(self): ++ self.compare_hashes(hashlib.blake2b(b'abc'), _hashlib.openssl_blake2b(b'abc')) ++ self.compare_hashes(hashlib.blake2s(b'abc'), _hashlib.openssl_blake2s(b'abc')) ++ ++ def test_sha3_hashes(self): ++ self.compare_hashes(hashlib.sha3_224(b'abc'), _hashlib.openssl_sha3_224(b'abc')) ++ self.compare_hashes(hashlib.sha3_256(b'abc'), _hashlib.openssl_sha3_256(b'abc')) ++ self.compare_hashes(hashlib.sha3_384(b'abc'), _hashlib.openssl_sha3_384(b'abc')) ++ self.compare_hashes(hashlib.sha3_512(b'abc'), _hashlib.openssl_sha3_512(b'abc')) ++ ++ @unittest.skipIf(hashlib.get_fips_mode(), "shake hashes are not available under FIPS") ++ def test_shake_hashes(self): ++ self.compare_hashes(hashlib.shake_128(b'abc'), _hashlib.openssl_shake_128(b'abc')) ++ self.compare_hashes(hashlib.shake_256(b'abc'), _hashlib.openssl_shake_256(b'abc')) ++ ++ def test_sha(self): ++ self.compare_hashes(hashlib.sha1(b'abc'), _hashlib.openssl_sha1(b'abc')) ++ self.compare_hashes(hashlib.sha224(b'abc'), _hashlib.openssl_sha224(b'abc')) ++ self.compare_hashes(hashlib.sha256(b'abc'), _hashlib.openssl_sha256(b'abc')) ++ self.compare_hashes(hashlib.sha384(b'abc'), _hashlib.openssl_sha384(b'abc')) ++ self.compare_hashes(hashlib.sha512(b'abc'), _hashlib.openssl_sha512(b'abc')) ++ ++ def test_hmac_digests(self): ++ self.compare_hashes(_hmacopenssl.new(b'My hovercraft is full of eels', digestmod='sha384'), ++ hmac.new(b'My hovercraft is full of eels', digestmod='sha384')) ++ ++ ++ ++ ++if __name__ == "__main__": ++ unittest.main() +-- +2.21.0 + + +From b3a8214b5afe4809983e6a5e5d339527e8238318 Mon Sep 17 00:00:00 2001 +From: Marcel Plch +Date: Thu, 1 Aug 2019 16:39:37 +0200 +Subject: [PATCH 15/36] Initialize HMAC type. + +--- + Modules/_hmacopenssl.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c -index 7d3d9739f3ab..a24c8ba0229d 100644 +index 221714ca434..239445a0831 100644 --- a/Modules/_hmacopenssl.c +++ b/Modules/_hmacopenssl.c -@@ -318,7 +318,7 @@ _hmacopenssl_get_block_size(HmacObject *self, void *closure) - if (md == NULL) { - return _setException(PyExc_ValueError); +@@ -22,12 +22,12 @@ + #include "_hashopenssl.h" + + +-#include + + typedef struct hmacopenssl_state { + PyTypeObject *HmacType; + } hmacopenssl_state; + ++#include + + typedef struct { + PyObject_HEAD +@@ -39,7 +39,7 @@ typedef struct { + #include "clinic/_hmacopenssl.c.h" + /*[clinic input] + module _hmacopenssl +-class _hmacopenssl.HMAC "HmacObject *" "PyModule_GetState(module)->HmacType" ++class _hmacopenssl.HMAC "HmacObject *" "((hmacopenssl_state *)PyModule_GetState(module))->HmacType" + [clinic start generated code]*/ + /*[clinic end generated code: output=da39a3ee5e6b4b0d input=204b7f45847f57b4]*/ + +@@ -71,7 +71,7 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, + return NULL; + } + +- /* name mut be lowercase */ ++ /* name must be lowercase */ + for (int i=0; digestmod[i]; i++) { + if ( + ((digestmod[i] < 'a') || (digestmod[i] > 'z')) +@@ -383,7 +383,8 @@ hmacopenssl_exec(PyObject *m) { + * on what hashes are supported rather than listing many + * and having some unsupported. Only init appropriate + * constants. */ +- PyObject *temp; ++ PyObject *temp = NULL; ++ hmacopenssl_state *state; + + temp = PyType_FromSpec(&HmacType_spec); + if (temp == NULL) { +@@ -394,6 +395,9 @@ hmacopenssl_exec(PyObject *m) { + goto fail; } -- return PyLong_FromLong(EVP_MD_size(md)); -+ return PyLong_FromLong(EVP_MD_block_size(md)); - } - static PyMethodDef Hmac_methods[] = { ++ state = PyModule_GetState(m); ++ state->HmacType = (PyTypeObject *)temp; ++ + return 0; + + fail: +-- +2.21.0 -From e643e9c61bce62bcc3caed8c022f1afee979feb8 Mon Sep 17 00:00:00 2001 + +From 5bd6eb14097fe4ff2bb639e5c50260b1379d0a69 Mon Sep 17 00:00:00 2001 From: Petr Viktorin -Date: Mon, 5 Aug 2019 14:45:52 +0200 -Subject: [PATCH 18/36] Skip hanging test +Date: Thu, 1 Aug 2019 17:57:05 +0200 +Subject: [PATCH 16/36] Use a stronger hash in multiprocessing handshake +Adapted from patch by David Malcolm, +https://bugs.python.org/issue17258 --- - Lib/test/test_logging.py | 3 +++ - 1 file changed, 3 insertions(+) + Lib/multiprocessing/connection.py | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) -diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py -index 763a5d1df0e3..0b229465983c 100644 ---- a/Lib/test/test_logging.py -+++ b/Lib/test/test_logging.py -@@ -46,6 +46,8 @@ - import unittest - import warnings - import weakref -+import hashlib +diff --git a/Lib/multiprocessing/connection.py b/Lib/multiprocessing/connection.py +index d3797503a75..a0b1538f88b 100644 +--- a/Lib/multiprocessing/connection.py ++++ b/Lib/multiprocessing/connection.py +@@ -42,6 +42,10 @@ BUFSIZE = 8192 + # A very generous timeout when it comes to local connections... + CONNECTION_TIMEOUT = 20. + ++# The hmac module implicitly defaults to using MD5. ++# Support using a stronger algorithm for the challenge/response code: ++HMAC_DIGEST_NAME='sha256' + - try: - import threading - # The following imports are needed only for tests which -@@ -1815,6 +1817,7 @@ def handle_request(self, request): - request.end_headers() - self.handled.set() + _mmap_counter = itertools.count() -+ @unittest.skipIf(hashlib.get_fips_mode(), 'Hangs in FIPS mode.') - def test_output(self): - # The log message sent to the HTTPHandler is properly received. - logger = logging.getLogger("http") + default_family = 'AF_INET' +@@ -718,7 +722,7 @@ def deliver_challenge(connection, authkey): + assert isinstance(authkey, bytes) + message = os.urandom(MESSAGE_LENGTH) + connection.send_bytes(CHALLENGE + message) +- digest = hmac.new(authkey, message, 'md5').digest() ++ digest = hmac.new(authkey, message, HMAC_DIGEST_NAME).digest() + response = connection.recv_bytes(256) # reject large message + if response == digest: + connection.send_bytes(WELCOME) +@@ -732,7 +736,7 @@ def answer_challenge(connection, authkey): + message = connection.recv_bytes(256) # reject large message + assert message[:len(CHALLENGE)] == CHALLENGE, 'message = %r' % message + message = message[len(CHALLENGE):] +- digest = hmac.new(authkey, message, 'md5').digest() ++ digest = hmac.new(authkey, message, HMAC_DIGEST_NAME).digest() + connection.send_bytes(digest) + response = connection.recv_bytes(256) # reject large message + if response != WELCOME: +-- +2.21.0 -From 30e11ab9d19beea8dafe96da7f47bf1513849f3d Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Mon, 5 Aug 2019 15:02:08 +0200 -Subject: [PATCH 19/36] distutils upload: Skip md5 checksum in FIPS mode + +From 1dd4b2d6c4797b828ac38d8c62f1e69fce49f1e9 Mon Sep 17 00:00:00 2001 +From: Marcel Plch +Date: Fri, 2 Aug 2019 17:36:01 +0200 +Subject: [PATCH 17/36] Fix refcounting --- - Lib/distutils/command/upload.py | 11 ++++++++++- - Lib/distutils/tests/test_upload.py | 13 +++++++++++-- - 2 files changed, 21 insertions(+), 3 deletions(-) + Modules/_hmacopenssl.c | 35 ++++++++++++++++++++++++++++++++++- + 1 file changed, 34 insertions(+), 1 deletion(-) -diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py -index 32dda359badb..0edb39efd4cb 100644 ---- a/Lib/distutils/command/upload.py -+++ b/Lib/distutils/command/upload.py -@@ -102,7 +102,6 @@ def upload_file(self, command, pyversion, filename): - 'content': (os.path.basename(filename),content), - 'filetype': command, - 'pyversion': pyversion, -- 'md5_digest': hashlib.md5(content).hexdigest(), +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +index 239445a0831..9c2882833d1 100644 +--- a/Modules/_hmacopenssl.c ++++ b/Modules/_hmacopenssl.c +@@ -373,6 +373,34 @@ static struct PyMethodDef hmacopenssl_functions[] = { + {NULL, NULL} /* Sentinel */ + }; - # additional meta-data - 'metadata_version': '1.0', -@@ -121,6 +120,16 @@ def upload_file(self, command, pyversion, filename): - 'requires': meta.get_requires(), - 'obsoletes': meta.get_obsoletes(), - } -+ try: -+ digest = hashlib.md5(content).hexdigest() -+ except ValueError as e: -+ msg = 'calculating md5 checksum failed: %s' % e -+ self.announce(msg, log.ERROR) -+ if not hashlib.get_fips_mode(): -+ # this really shouldn't fail -+ raise -+ else: -+ data['md5_digest'] = digest - comment = '' - if command == 'bdist_rpm': - dist, version, id = platform.dist() -diff --git a/Lib/distutils/tests/test_upload.py b/Lib/distutils/tests/test_upload.py -index c17d8e7d54e9..b4b64e97737d 100644 ---- a/Lib/distutils/tests/test_upload.py -+++ b/Lib/distutils/tests/test_upload.py -@@ -3,6 +3,7 @@ - import unittest - import unittest.mock as mock - from urllib.request import HTTPError -+import hashlib ++static int ++hmacopenssl_traverse(PyObject *self, visitproc visit, void *arg) ++{ ++ hmacopenssl_state *state; ++ ++ state = PyModule_GetState(self); ++ ++ if (state) { ++ Py_VISIT(state->HmacType); ++ } ++ ++ return 0; ++} ++ ++static int ++hmacopenssl_clear(PyObject *self) ++{ ++ hmacopenssl_state *state; ++ ++ state = PyModule_GetState(self); ++ ++ if (state) { ++ Py_CLEAR(state->HmacType); ++ } ++ ++ return 0; ++} ++ - from test.support import run_unittest -@@ -130,7 +131,11 @@ def test_upload(self): + /* Initialize this module. */ +@@ -396,7 +424,10 @@ hmacopenssl_exec(PyObject *m) { + } - # what did we send ? - headers = dict(self.last_open.req.headers) -- self.assertEqual(headers['Content-length'], '2162') -+ if hashlib.get_fips_mode(): -+ # md5 hash is omitted -+ self.assertEqual(headers['Content-length'], '2020') -+ else: -+ self.assertEqual(headers['Content-length'], '2162') - content_type = headers['Content-type'] - self.assertTrue(content_type.startswith('multipart/form-data')) - self.assertEqual(self.last_open.req.get_method(), 'POST') -@@ -166,7 +171,11 @@ def test_upload_correct_cr(self): - cmd.run() + state = PyModule_GetState(m); ++ + state->HmacType = (PyTypeObject *)temp; ++ Py_INCREF(temp); ++ - headers = dict(self.last_open.req.headers) -- self.assertEqual(headers['Content-length'], '2172') -+ if hashlib.get_fips_mode(): -+ # md5 hash is omitted -+ self.assertEqual(headers['Content-length'], '2030') -+ else: -+ self.assertEqual(headers['Content-length'], '2172') - self.assertIn(b'long description\r', self.last_open.req.data) + return 0; - def test_upload_fails(self): +@@ -415,7 +446,9 @@ static struct PyModuleDef _hmacopenssl_def = { + .m_name = "_hmacopenssl", + .m_methods = hmacopenssl_functions, + .m_slots = hmacopenssl_slots, +- .m_size = sizeof(hmacopenssl_state) ++ .m_size = sizeof(hmacopenssl_state), ++ .m_traverse = hmacopenssl_traverse, ++ .m_clear = hmacopenssl_clear + }; + + +-- +2.21.0 + -From 8eb2ce39572904704ada072e25d8e6bf5727f492 Mon Sep 17 00:00:00 2001 +From 4e1351cc2d704e8da7bb8125ad0ab194e8a02ec4 Mon Sep 17 00:00:00 2001 From: Petr Viktorin -Date: Mon, 5 Aug 2019 15:32:25 +0200 -Subject: [PATCH 20/36] Fix HMAC tests on FIPS mode +Date: Mon, 5 Aug 2019 13:37:05 +0200 +Subject: [PATCH 18/36] hmac: Don't default to md5 in FIPS mode --- - Lib/hmac.py | 3 +++ - Lib/test/test_hmac.py | 50 ++++++++++++++++++++++++++++++++++--------- - 2 files changed, 43 insertions(+), 10 deletions(-) + Lib/hmac.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/hmac.py b/Lib/hmac.py -index d479c5a4492f..7af94c39ed63 100644 +index ed98406bd2e..7b8821edd58 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py -@@ -157,6 +157,9 @@ def _get_openssl_name(digestmod): - - class HMAC_openssl(_hmacopenssl.HMAC): - def __new__(cls, key, msg = None, digestmod = None): -+ if not isinstance(key, (bytes, bytearray)): -+ raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) -+ +@@ -165,7 +165,7 @@ def new(key, msg = None, digestmod = None): + """ + if _hashlib.get_fips_mode(): + if digestmod is None: +- digestmod = 'md5' ++ raise ValueError("'digestmod' argument is mandatory in FIPS mode") name = _get_openssl_name(digestmod) - result = _hmacopenssl.HMAC.__new__(cls, key, digestmod=name) + result = _hmacopenssl.new(key, digestmod=name) if msg: -diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py -index 067e13f1079a..6f53a6d1fd5b 100644 ---- a/Lib/test/test_hmac.py -+++ b/Lib/test/test_hmac.py -@@ -17,6 +17,7 @@ def wrapper(*args, **kwargs): +-- +2.21.0 + + +From ea44160c242101f14d22242a0722e730ef304b8b Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 5 Aug 2019 14:20:58 +0200 +Subject: [PATCH 19/36] Make _hmacopenssl.HMAC subclassable; subclass it as + hmac.HMAC under FIPS + +This removes the _hmacopenssl.new function. +--- + Lib/hmac.py | 27 +++++++----- + Lib/test/test_fips.py | 2 +- + Modules/_hmacopenssl.c | 75 ++++++++++++++++----------------- + Modules/clinic/_hmacopenssl.c.h | 39 +---------------- + 4 files changed, 56 insertions(+), 87 deletions(-) + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index 7b8821edd58..d479c5a4492 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -141,6 +141,8 @@ class HMAC: + + + def _get_openssl_name(digestmod): ++ if digestmod is None: ++ raise ValueError("'digestmod' argument is mandatory in FIPS mode") + if isinstance(digestmod, str): + return digestmod.lower() + elif callable(digestmod): +@@ -152,6 +154,20 @@ def _get_openssl_name(digestmod): + + return digestmod.name.lower().replace('_', '-') + ++ ++class HMAC_openssl(_hmacopenssl.HMAC): ++ def __new__(cls, key, msg = None, digestmod = None): ++ name = _get_openssl_name(digestmod) ++ result = _hmacopenssl.HMAC.__new__(cls, key, digestmod=name) ++ if msg: ++ result.update(msg) ++ return result ++ ++ ++if _hashlib.get_fips_mode(): ++ HMAC = HMAC_openssl ++ ++ + def new(key, msg = None, digestmod = None): + """Create a new hashing object and return it. + +@@ -163,13 +179,4 @@ def new(key, msg = None, digestmod = None): + method, and can ask for the hash value at any time by calling its digest() + method. + """ +- if _hashlib.get_fips_mode(): +- if digestmod is None: +- raise ValueError("'digestmod' argument is mandatory in FIPS mode") +- name = _get_openssl_name(digestmod) +- result = _hmacopenssl.new(key, digestmod=name) +- if msg: +- result.update(msg) +- return result +- else: +- return HMAC(key, msg, digestmod) ++ return HMAC(key, msg, digestmod) +diff --git a/Lib/test/test_fips.py b/Lib/test/test_fips.py +index bee911ef405..34812e6098a 100644 +--- a/Lib/test/test_fips.py ++++ b/Lib/test/test_fips.py +@@ -54,7 +54,7 @@ class HashlibFipsTests(unittest.TestCase): + self.compare_hashes(hashlib.sha512(b'abc'), _hashlib.openssl_sha512(b'abc')) - class TestVectorsTestCase(unittest.TestCase): + def test_hmac_digests(self): +- self.compare_hashes(_hmacopenssl.new(b'My hovercraft is full of eels', digestmod='sha384'), ++ self.compare_hashes(_hmacopenssl.HMAC(b'My hovercraft is full of eels', digestmod='sha384'), + hmac.new(b'My hovercraft is full of eels', digestmod='sha384')) -+ @unittest.skipIf(hashlib.get_fips_mode(), 'md5 unacceptable in FIPS mode.') - def test_md5_vectors(self): - # Test the HMAC module against test vectors from the RFC. -@@ -242,6 +243,7 @@ def test_sha384_rfc4231(self): - def test_sha512_rfc4231(self): - self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128) +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +index 9c2882833d1..7d3d9739f3a 100644 +--- a/Modules/_hmacopenssl.c ++++ b/Modules/_hmacopenssl.c +@@ -41,33 +41,25 @@ typedef struct { + module _hmacopenssl + class _hmacopenssl.HMAC "HmacObject *" "((hmacopenssl_state *)PyModule_GetState(module))->HmacType" + [clinic start generated code]*/ +-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=204b7f45847f57b4]*/ ++/*[clinic end generated code: output=da39a3ee5e6b4b0d input=9fe07a087adc2cf9]*/ -+ @unittest.skipIf(hashlib.get_fips_mode(), 'MockCrazyHash unacceptable in FIPS mode.') - def test_legacy_block_size_warnings(self): - class MockCrazyHash(object): - """Ain't no block_size attribute here.""" -@@ -264,6 +266,7 @@ def digest(self): - hmac.HMAC(b'a', b'b', digestmod=MockCrazyHash) - self.fail('Expected warning about small block_size') -+ @unittest.skipIf(hashlib.get_fips_mode(), 'md5 is not default in FIPS mode.') - def test_with_digestmod_warning(self): - with self.assertWarns(PendingDeprecationWarning): - key = b"\x0b" * 16 -@@ -275,6 +278,7 @@ def test_with_digestmod_warning(self): +-/*[clinic input] +-_hmacopenssl.new +- +- key: Py_buffer +- * +- digestmod: str +- +-Return a new hmac object. +-[clinic start generated code]*/ +- + static PyObject * +-_hmacopenssl_new_impl(PyObject *module, Py_buffer *key, +- const char *digestmod) +-/*[clinic end generated code: output=46f1cb4e02921922 input=be8c0c2e4fad508c]*/ ++Hmac_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) + { +- hmacopenssl_state *state; +- +- if (digestmod == NULL) { +- PyErr_SetString(PyExc_ValueError, "digestmod must be specified"); ++ static char *kwarg_names[] = {"key", "digestmod", NULL}; ++ Py_buffer key = {NULL, NULL}; ++ char *digestmod = NULL; ++ ++ int ret = PyArg_ParseTupleAndKeywords( ++ args, kwds, "y*|$s:_hmacopenssl.HMAC", kwarg_names, ++ &key, &digestmod); ++ if (ret == 0) { + return NULL; + } - class ConstructorTestCase(unittest.TestCase): +- state = PyModule_GetState(module); +- if (state == NULL) { ++ if (digestmod == NULL) { ++ PyErr_SetString(PyExc_ValueError, "digestmod must be specified"); + return NULL; + } -+ @unittest.skipIf(hashlib.get_fips_mode(), 'md5 is not default in FIPS mode.') - @ignore_warning - def test_normal(self): - # Standard constructor call. -@@ -284,6 +288,14 @@ def test_normal(self): - except Exception: - self.fail("Standard constructor call raised exception.") +@@ -106,8 +98,8 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, -+ def test_normal_digestmod(self): -+ # Standard constructor call. -+ failed = 0 -+ try: -+ h = hmac.HMAC(b"key", digestmod='sha1') -+ except Exception: -+ self.fail("Standard constructor call raised exception.") -+ - @ignore_warning - def test_with_str_key(self): - # Pass a key of type str, which is an error, because it expects a key -@@ -302,25 +314,25 @@ def test_dot_new_with_str_key(self): - def test_withtext(self): - # Constructor call with text. - try: -- h = hmac.HMAC(b"key", b"hash this!") -+ h = hmac.HMAC(b"key", b"hash this!", digestmod='sha1') - except Exception: - self.fail("Constructor call with text argument raised exception.") -- self.assertEqual(h.hexdigest(), '34325b639da4cfd95735b381e28cb864') -+ self.assertEqual(h.hexdigest(), '3f2e20f3e2f006270db98760b9725a008c5bd114') + int r = HMAC_Init_ex( + ctx, +- (const char*)key->buf, +- key->len, ++ (const char*)key.buf, ++ key.len, + digest, + NULL /*impl*/); + if (r == 0) { +@@ -115,7 +107,10 @@ _hmacopenssl_new_impl(PyObject *module, Py_buffer *key, + goto error; + } - def test_with_bytearray(self): - try: - h = hmac.HMAC(bytearray(b"key"), bytearray(b"hash this!"), -- digestmod="md5") -+ digestmod="sha1") - except Exception: - self.fail("Constructor call with bytearray arguments raised exception.") -- self.assertEqual(h.hexdigest(), '34325b639da4cfd95735b381e28cb864') -+ self.assertEqual(h.hexdigest(), '3f2e20f3e2f006270db98760b9725a008c5bd114') +- retval = (HmacObject *)PyObject_New(HmacObject, state->HmacType); ++ PyBuffer_Release(&key); ++ key.buf = NULL; ++ ++ retval = (HmacObject *)subtype->tp_alloc(subtype, 0); + if (retval == NULL) { + goto error; + } +@@ -130,6 +125,7 @@ error: + if (ctx) HMAC_CTX_free(ctx); + if (name) Py_DECREF(name); + if (retval) PyObject_Del(name); ++ if (key.buf) PyBuffer_Release(&key); + return NULL; + } - def test_with_memoryview_msg(self): - try: -- h = hmac.HMAC(b"key", memoryview(b"hash this!"), digestmod="md5") -+ h = hmac.HMAC(b"key", memoryview(b"hash this!"), digestmod="sha1") - except Exception: - self.fail("Constructor call with memoryview msg raised exception.") -- self.assertEqual(h.hexdigest(), '34325b639da4cfd95735b381e28cb864') -+ self.assertEqual(h.hexdigest(), '3f2e20f3e2f006270db98760b9725a008c5bd114') +@@ -145,19 +141,27 @@ _hmacopenssl_HMAC_copy_impl(HmacObject *self) + { + HmacObject *retval; - def test_withmodule(self): - # Constructor call with text and digest module. -@@ -331,6 +343,7 @@ def test_withmodule(self): +- retval = (HmacObject *)PyObject_New(HmacObject, (PyTypeObject *)PyObject_Type((PyObject *)self)); ++ HMAC_CTX *ctx = HMAC_CTX_new(); ++ if (ctx == NULL) { ++ return _setException(PyExc_ValueError); ++ } ++ ++ int r = HMAC_CTX_copy(ctx, self->ctx); ++ if (r == 0) { ++ HMAC_CTX_free(ctx); ++ return _setException(PyExc_ValueError); ++ } ++ ++ retval = (HmacObject *)Py_TYPE(self)->tp_alloc(Py_TYPE(self), 0); + if (retval == NULL) { ++ HMAC_CTX_free(ctx); + return NULL; + } +- ++ retval->ctx = ctx; + Py_INCREF(self->name); + retval->name = self->name; - class SanityTestCase(unittest.TestCase): +- int r = HMAC_CTX_copy(retval->ctx, self->ctx); +- if (r == 0) { +- PyObject_Del(retval); +- return _setException(PyExc_ValueError); +- } ++ retval->lock = NULL; -+ @unittest.skipIf(hashlib.get_fips_mode(), "md5 is not default in FIPS mode") - @ignore_warning - def test_default_is_md5(self): - # Testing if HMAC defaults to MD5 algorithm. -@@ -342,7 +355,7 @@ def test_exercise_all_methods(self): - # Exercising all methods once. - # This must not raise any exceptions - try: -- h = hmac.HMAC(b"my secret key", digestmod="md5") -+ h = hmac.HMAC(b"my secret key", digestmod="sha1") - h.update(b"compute the hash of this text!") - dig = h.digest() - dig = h.hexdigest() -@@ -352,9 +365,10 @@ def test_exercise_all_methods(self): + return (PyObject *)retval; + } +@@ -169,8 +173,8 @@ _hmac_dealloc(HmacObject *self) + PyThread_free_lock(self->lock); + } + HMAC_CTX_free(self->ctx); +- Py_XDECREF(self->name); +- PyObject_Del(self); ++ Py_CLEAR(self->name); ++ Py_TYPE(self)->tp_free(self); + } - class CopyTestCase(unittest.TestCase): + static PyObject * +@@ -357,6 +361,7 @@ static PyType_Slot HmacType_slots[] = { + {Py_tp_methods, Hmac_methods}, + {Py_tp_getset, Hmac_getset}, + {Py_tp_members, Hmac_members}, ++ {Py_tp_new, Hmac_new}, + {0, NULL} + }; -+ @unittest.skipIf(hashlib.get_fips_mode(), "Internal attributes unavailable in FIPS mode") - def test_attributes(self): - # Testing if attributes are of same type. -- h1 = hmac.HMAC(b"key", digestmod="md5") -+ h1 = hmac.HMAC(b"key", digestmod="sha1") - h2 = h1.copy() - self.assertTrue(h1.digest_cons == h2.digest_cons, - "digest constructors don't match.") -@@ -363,9 +377,10 @@ def test_attributes(self): - self.assertEqual(type(h1.outer), type(h2.outer), - "Types of outer don't match.") +@@ -368,11 +373,6 @@ PyType_Spec HmacType_spec = { + }; -+ @unittest.skipIf(hashlib.get_fips_mode(), "Internal attributes unavailable in FIPS mode") - def test_realcopy(self): - # Testing if the copy method created a real copy. -- h1 = hmac.HMAC(b"key", digestmod="md5") -+ h1 = hmac.HMAC(b"key", digestmod="sha1") - h2 = h1.copy() - # Using id() in case somebody has overridden __eq__/__ne__. - self.assertTrue(id(h1) != id(h2), "No real copy of the HMAC instance.") -@@ -374,9 +389,24 @@ def test_realcopy(self): - self.assertTrue(id(h1.outer) != id(h2.outer), - "No real copy of the attribute 'outer'.") -+ def test_realcopy(self): -+ # Testing if the copy method created a real copy. -+ h1 = hmac.HMAC(b"key", digestmod="sha1") -+ h2 = h1.copy() -+ # Using id() in case somebody has overridden __eq__/__ne__. -+ self.assertTrue(id(h1) != id(h2), "No real copy of the HMAC instance.") -+ old_digest = h1.digest() -+ assert h1.digest() == h2.digest() -+ h1.update(b'hi') -+ assert h1.digest() != h2.digest() -+ assert h2.digest() == old_digest -+ new_digest = h1.digest() -+ h2.update(b'hi') -+ assert h1.digest() == h2.digest() == new_digest -+ - def test_equality(self): - # Testing if the copy has the same digests. -- h1 = hmac.HMAC(b"key", digestmod="md5") -+ h1 = hmac.HMAC(b"key", digestmod="sha1") - h1.update(b"some random text") - h2 = h1.copy() - self.assertEqual(h1.digest(), h2.digest(), +-static struct PyMethodDef hmacopenssl_functions[] = { +- _HMACOPENSSL_NEW_METHODDEF +- {NULL, NULL} /* Sentinel */ +-}; +- + static int + hmacopenssl_traverse(PyObject *self, visitproc visit, void *arg) + { +@@ -444,7 +444,6 @@ static PyModuleDef_Slot hmacopenssl_slots[] = { + static struct PyModuleDef _hmacopenssl_def = { + PyModuleDef_HEAD_INIT, /* m_base */ + .m_name = "_hmacopenssl", +- .m_methods = hmacopenssl_functions, + .m_slots = hmacopenssl_slots, + .m_size = sizeof(hmacopenssl_state), + .m_traverse = hmacopenssl_traverse, +diff --git a/Modules/clinic/_hmacopenssl.c.h b/Modules/clinic/_hmacopenssl.c.h +index b472a6eddd3..861acc11bfd 100644 +--- a/Modules/clinic/_hmacopenssl.c.h ++++ b/Modules/clinic/_hmacopenssl.c.h +@@ -2,43 +2,6 @@ + preserve + [clinic start generated code]*/ + +-PyDoc_STRVAR(_hmacopenssl_new__doc__, +-"new($module, /, key, *, digestmod)\n" +-"--\n" +-"\n" +-"Return a new hmac object."); +- +-#define _HMACOPENSSL_NEW_METHODDEF \ +- {"new", (PyCFunction)_hmacopenssl_new, METH_FASTCALL, _hmacopenssl_new__doc__}, +- +-static PyObject * +-_hmacopenssl_new_impl(PyObject *module, Py_buffer *key, +- const char *digestmod); +- +-static PyObject * +-_hmacopenssl_new(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) +-{ +- PyObject *return_value = NULL; +- static const char * const _keywords[] = {"key", "digestmod", NULL}; +- static _PyArg_Parser _parser = {"y*$s:new", _keywords, 0}; +- Py_buffer key = {NULL, NULL}; +- const char *digestmod; +- +- if (!_PyArg_ParseStack(args, nargs, kwnames, &_parser, +- &key, &digestmod)) { +- goto exit; +- } +- return_value = _hmacopenssl_new_impl(module, &key, digestmod); +- +-exit: +- /* Cleanup for key */ +- if (key.obj) { +- PyBuffer_Release(&key); +- } +- +- return return_value; +-} +- + PyDoc_STRVAR(_hmacopenssl_HMAC_copy__doc__, + "copy($self, /)\n" + "--\n" +@@ -130,4 +93,4 @@ _hmacopenssl_HMAC_hexdigest(HmacObject *self, PyObject *Py_UNUSED(ignored)) + { + return _hmacopenssl_HMAC_hexdigest_impl(self); + } +-/*[clinic end generated code: output=10b6e8cac6d7a2c9 input=a9049054013a1b77]*/ ++/*[clinic end generated code: output=d93ad460795d49b5 input=a9049054013a1b77]*/ +-- +2.21.0 -From d7ac1f3fe2f7024d582ba9d0f10008499f832b76 Mon Sep 17 00:00:00 2001 + +From e3d6a5adbe0032726dff0b1f6473ce3ff63fad51 Mon Sep 17 00:00:00 2001 From: Petr Viktorin -Date: Mon, 5 Aug 2019 16:24:40 +0200 -Subject: [PATCH 21/36] test_smtplib: Skip tests of CRAM-MD5 auth +Date: Mon, 5 Aug 2019 16:10:36 +0200 +Subject: [PATCH 20/36] Fix _hmacopenssl.HMAC.block_size --- - Lib/test/test_smtplib.py | 4 ++++ - 1 file changed, 4 insertions(+) + Modules/_hmacopenssl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) -diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py -index 87047514e7aa..150e9fbcf053 100644 ---- a/Lib/test/test_smtplib.py -+++ b/Lib/test/test_smtplib.py -@@ -15,6 +15,7 @@ - import select - import errno - import textwrap -+import hashlib - - import unittest - from test import support, mock_socket -@@ -968,6 +969,7 @@ def testAUTH_LOGIN(self): - self.assertEqual(resp, (235, b'Authentication Succeeded')) - smtp.close() - -+ @unittest.skipIf(hashlib.get_fips_mode(), "md5 auth unacceptable in FIPS mode") - def testAUTH_CRAM_MD5(self): - self.serv.add_feature("AUTH CRAM-MD5") - smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) -@@ -975,6 +977,7 @@ def testAUTH_CRAM_MD5(self): - self.assertEqual(resp, (235, b'Authentication Succeeded')) - smtp.close() - -+ @unittest.skipIf(hashlib.get_fips_mode(), "md5 auth unacceptable in FIPS mode") - def testAUTH_multiple(self): - # Test that multiple authentication methods are tried. - self.serv.add_feature("AUTH BOGUS PLAIN LOGIN CRAM-MD5") -@@ -983,6 +986,7 @@ def testAUTH_multiple(self): - self.assertEqual(resp, (235, b'Authentication Succeeded')) - smtp.close() +diff --git a/Modules/_hmacopenssl.c b/Modules/_hmacopenssl.c +index 7d3d9739f3a..a24c8ba0229 100644 +--- a/Modules/_hmacopenssl.c ++++ b/Modules/_hmacopenssl.c +@@ -318,7 +318,7 @@ _hmacopenssl_get_block_size(HmacObject *self, void *closure) + if (md == NULL) { + return _setException(PyExc_ValueError); + } +- return PyLong_FromLong(EVP_MD_size(md)); ++ return PyLong_FromLong(EVP_MD_block_size(md)); + } -+ @unittest.skipIf(hashlib.get_fips_mode(), "md5 auth unacceptable in FIPS mode") - def test_auth_function(self): - supported = {'CRAM-MD5', 'PLAIN', 'LOGIN'} - for mechanism in supported: + static PyMethodDef Hmac_methods[] = { +-- +2.21.0 + -From d1e2300f593d8c32bd3d23cd43eae02192e3eb03 Mon Sep 17 00:00:00 2001 +From f925a1165d7b07fb4d0bba216f7dbc387b94e94d Mon Sep 17 00:00:00 2001 From: Petr Viktorin -Date: Mon, 5 Aug 2019 16:34:49 +0200 -Subject: [PATCH 22/36] test_tarfile: Replace md5 checksums with sha1 +Date: Mon, 5 Aug 2019 15:02:08 +0200 +Subject: [PATCH 21/36] distutils upload: Skip md5 checksum in FIPS mode --- - Lib/test/test_tarfile.py | 50 ++++++++++++++++++++-------------------- - 1 file changed, 25 insertions(+), 25 deletions(-) + Lib/distutils/command/upload.py | 11 ++++++++++- + Lib/distutils/tests/test_upload.py | 13 +++++++++++-- + 2 files changed, 21 insertions(+), 3 deletions(-) -diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py -index 4cd7d5370f58..c8c8eebd3194 100644 ---- a/Lib/test/test_tarfile.py -+++ b/Lib/test/test_tarfile.py -@@ -1,7 +1,7 @@ - import sys - import os - import io --from hashlib import md5 -+from hashlib import sha1 - from contextlib import contextmanager - from random import Random - import pathlib -@@ -27,8 +27,8 @@ - except ImportError: - lzma = None - --def md5sum(data): -- return md5(data).hexdigest() -+def sha1sum(data): -+ return sha1(data).hexdigest() - - TEMPDIR = os.path.abspath(support.TESTFN) + "-tardir" - tarextdir = TEMPDIR + '-extract-test' -@@ -39,8 +39,8 @@ def md5sum(data): - tmpname = os.path.join(TEMPDIR, "tmp.tar") - dotlessname = os.path.join(TEMPDIR, "testtar") - --md5_regtype = "65f477c818ad9e15f7feab0c6d37742f" --md5_sparse = "a54fbc4ca4f4399a90e1b27164012fc6" -+sha1_regtype = "bc5bb0da4d26c3e37a76d2fbf89a2a9972aeceaa" -+sha1_sparse = "693f6a770ef62ebdffc5666bd426b9506e6d8285" - - - class TarTest: -@@ -95,7 +95,7 @@ def test_fileobj_regular_file(self): - data = fobj.read() - self.assertEqual(len(data), tarinfo.size, - "regular file extraction failed") -- self.assertEqual(md5sum(data), md5_regtype, -+ self.assertEqual(sha1sum(data), sha1_regtype, - "regular file extraction failed") - - def test_fileobj_readlines(self): -@@ -180,7 +180,7 @@ def test_fileobj_text(self): - with self.tar.extractfile("ustar/regtype") as fobj: - fobj = io.TextIOWrapper(fobj) - data = fobj.read().encode("iso8859-1") -- self.assertEqual(md5sum(data), md5_regtype) -+ self.assertEqual(sha1sum(data), sha1_regtype) - try: - fobj.seek(100) - except AttributeError: -@@ -546,13 +546,13 @@ def test_extract_hardlink(self): - self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/lnktype")) - with open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb") as f: - data = f.read() -- self.assertEqual(md5sum(data), md5_regtype) -+ self.assertEqual(sha1sum(data), sha1_regtype) - - tar.extract("ustar/symtype", TEMPDIR) - self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/symtype")) - with open(os.path.join(TEMPDIR, "ustar/symtype"), "rb") as f: - data = f.read() -- self.assertEqual(md5sum(data), md5_regtype) -+ self.assertEqual(sha1sum(data), sha1_regtype) - - def test_extractall(self): - # Test if extractall() correctly restores directory permissions -@@ -687,7 +687,7 @@ def test_fileobj_regular_file(self): - data = fobj.read() - self.assertEqual(len(data), tarinfo.size, - "regular file extraction failed") -- self.assertEqual(md5sum(data), md5_regtype, -+ self.assertEqual(sha1sum(data), sha1_regtype, - "regular file extraction failed") - - def test_provoke_stream_error(self): -@@ -799,8 +799,8 @@ class MemberReadTest(ReadTest, unittest.TestCase): - def _test_member(self, tarinfo, chksum=None, **kwargs): - if chksum is not None: - with self.tar.extractfile(tarinfo) as f: -- self.assertEqual(md5sum(f.read()), chksum, -- "wrong md5sum for %s" % tarinfo.name) -+ self.assertEqual(sha1sum(f.read()), chksum, -+ "wrong sha1sum for %s" % tarinfo.name) - - kwargs["mtime"] = 0o7606136617 - kwargs["uid"] = 1000 -@@ -815,11 +815,11 @@ def _test_member(self, tarinfo, chksum=None, **kwargs): - - def test_find_regtype(self): - tarinfo = self.tar.getmember("ustar/regtype") -- self._test_member(tarinfo, size=7011, chksum=md5_regtype) -+ self._test_member(tarinfo, size=7011, chksum=sha1_regtype) - - def test_find_conttype(self): - tarinfo = self.tar.getmember("ustar/conttype") -- self._test_member(tarinfo, size=7011, chksum=md5_regtype) -+ self._test_member(tarinfo, size=7011, chksum=sha1_regtype) - - def test_find_dirtype(self): - tarinfo = self.tar.getmember("ustar/dirtype") -@@ -851,28 +851,28 @@ def test_find_fifotype(self): +diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py +index 32dda359bad..0edb39efd4c 100644 +--- a/Lib/distutils/command/upload.py ++++ b/Lib/distutils/command/upload.py +@@ -102,7 +102,6 @@ class upload(PyPIRCCommand): + 'content': (os.path.basename(filename),content), + 'filetype': command, + 'pyversion': pyversion, +- 'md5_digest': hashlib.md5(content).hexdigest(), - def test_find_sparse(self): - tarinfo = self.tar.getmember("ustar/sparse") -- self._test_member(tarinfo, size=86016, chksum=md5_sparse) -+ self._test_member(tarinfo, size=86016, chksum=sha1_sparse) + # additional meta-data + 'metadata_version': '1.0', +@@ -121,6 +120,16 @@ class upload(PyPIRCCommand): + 'requires': meta.get_requires(), + 'obsoletes': meta.get_obsoletes(), + } ++ try: ++ digest = hashlib.md5(content).hexdigest() ++ except ValueError as e: ++ msg = 'calculating md5 checksum failed: %s' % e ++ self.announce(msg, log.ERROR) ++ if not hashlib.get_fips_mode(): ++ # this really shouldn't fail ++ raise ++ else: ++ data['md5_digest'] = digest + comment = '' + if command == 'bdist_rpm': + dist, version, id = platform.dist() +diff --git a/Lib/distutils/tests/test_upload.py b/Lib/distutils/tests/test_upload.py +index c17d8e7d54e..b4b64e97737 100644 +--- a/Lib/distutils/tests/test_upload.py ++++ b/Lib/distutils/tests/test_upload.py +@@ -3,6 +3,7 @@ import os + import unittest + import unittest.mock as mock + from urllib.request import HTTPError ++import hashlib - def test_find_gnusparse(self): - tarinfo = self.tar.getmember("gnu/sparse") -- self._test_member(tarinfo, size=86016, chksum=md5_sparse) -+ self._test_member(tarinfo, size=86016, chksum=sha1_sparse) + from test.support import run_unittest - def test_find_gnusparse_00(self): - tarinfo = self.tar.getmember("gnu/sparse-0.0") -- self._test_member(tarinfo, size=86016, chksum=md5_sparse) -+ self._test_member(tarinfo, size=86016, chksum=sha1_sparse) +@@ -130,7 +131,11 @@ class uploadTestCase(BasePyPIRCCommandTestCase): - def test_find_gnusparse_01(self): - tarinfo = self.tar.getmember("gnu/sparse-0.1") -- self._test_member(tarinfo, size=86016, chksum=md5_sparse) -+ self._test_member(tarinfo, size=86016, chksum=sha1_sparse) + # what did we send ? + headers = dict(self.last_open.req.headers) +- self.assertEqual(headers['Content-length'], '2162') ++ if hashlib.get_fips_mode(): ++ # md5 hash is omitted ++ self.assertEqual(headers['Content-length'], '2020') ++ else: ++ self.assertEqual(headers['Content-length'], '2162') + content_type = headers['Content-type'] + self.assertTrue(content_type.startswith('multipart/form-data')) + self.assertEqual(self.last_open.req.get_method(), 'POST') +@@ -166,7 +171,11 @@ class uploadTestCase(BasePyPIRCCommandTestCase): + cmd.run() - def test_find_gnusparse_10(self): - tarinfo = self.tar.getmember("gnu/sparse-1.0") -- self._test_member(tarinfo, size=86016, chksum=md5_sparse) -+ self._test_member(tarinfo, size=86016, chksum=sha1_sparse) + headers = dict(self.last_open.req.headers) +- self.assertEqual(headers['Content-length'], '2172') ++ if hashlib.get_fips_mode(): ++ # md5 hash is omitted ++ self.assertEqual(headers['Content-length'], '2030') ++ else: ++ self.assertEqual(headers['Content-length'], '2172') + self.assertIn(b'long description\r', self.last_open.req.data) - def test_find_umlauts(self): - tarinfo = self.tar.getmember("ustar/umlauts-" - "\xc4\xd6\xdc\xe4\xf6\xfc\xdf") -- self._test_member(tarinfo, size=7011, chksum=md5_regtype) -+ self._test_member(tarinfo, size=7011, chksum=sha1_regtype) + def test_upload_fails(self): +-- +2.21.0 + + +From 936a7835a1873952eab8f7ec3b9b67f63786c001 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 5 Aug 2019 15:32:25 +0200 +Subject: [PATCH 22/36] Fix HMAC tests on FIPS mode + +--- + Lib/hmac.py | 3 +++ + Lib/test/test_hmac.py | 26 ++++++++++++++++++++++++++ + 2 files changed, 29 insertions(+) + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index d479c5a4492..7af94c39ed6 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -157,6 +157,9 @@ def _get_openssl_name(digestmod): - def test_find_ustar_longname(self): - name = "ustar/" + "12345/" * 39 + "1234567/longname" -@@ -880,7 +880,7 @@ def test_find_ustar_longname(self): + class HMAC_openssl(_hmacopenssl.HMAC): + def __new__(cls, key, msg = None, digestmod = None): ++ if not isinstance(key, (bytes, bytearray)): ++ raise TypeError("key: expected bytes or bytearray, but got %r" % type(key).__name__) ++ + name = _get_openssl_name(digestmod) + result = _hmacopenssl.HMAC.__new__(cls, key, digestmod=name) + if msg: +diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py +index 338e0215a41..5b090727ef6 100644 +--- a/Lib/test/test_hmac.py ++++ b/Lib/test/test_hmac.py +@@ -250,6 +250,7 @@ class TestVectorsTestCase(unittest.TestCase): + def test_sha512_rfc4231(self): + self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128) - def test_find_regtype_oldv7(self): - tarinfo = self.tar.getmember("misc/regtype-old-v7") -- self._test_member(tarinfo, size=7011, chksum=md5_regtype) -+ self._test_member(tarinfo, size=7011, chksum=sha1_regtype) ++ @unittest.skipIf(hashlib.get_fips_mode(), 'MockCrazyHash unacceptable in FIPS mode.') + @requires_hashdigest('sha256') + def test_legacy_block_size_warnings(self): + class MockCrazyHash(object): +@@ -298,6 +299,14 @@ class ConstructorTestCase(unittest.TestCase): + self.fail("Standard constructor call raised exception.") - def test_find_pax_umlauts(self): - self.tar.close() -@@ -888,7 +888,7 @@ def test_find_pax_umlauts(self): - encoding="iso8859-1") - tarinfo = self.tar.getmember("pax/umlauts-" - "\xc4\xd6\xdc\xe4\xf6\xfc\xdf") -- self._test_member(tarinfo, size=7011, chksum=md5_regtype) -+ self._test_member(tarinfo, size=7011, chksum=sha1_regtype) + @ignore_warning ++ def test_normal_digestmod(self): ++ # Standard constructor call. ++ failed = 0 ++ try: ++ h = hmac.HMAC(b"key", digestmod='sha1') ++ except Exception: ++ self.fail("Standard constructor call raised exception.") ++ + @requires_hashdigest('sha256') + def test_with_str_key(self): + # Pass a key of type str, which is an error, because it expects a key +@@ -366,6 +375,7 @@ class SanityTestCase(unittest.TestCase): + class CopyTestCase(unittest.TestCase): - class LongnameTest: -@@ -950,8 +950,8 @@ def _test_sparse_file(self, name): - filename = os.path.join(TEMPDIR, name) - with open(filename, "rb") as fobj: - data = fobj.read() -- self.assertEqual(md5sum(data), md5_sparse, -- "wrong md5sum for %s" % name) -+ self.assertEqual(sha1sum(data), sha1_sparse, -+ "wrong sha1sum for %s" % name) ++ @unittest.skipIf(hashlib.get_fips_mode(), "Internal attributes unavailable in FIPS mode") + @requires_hashdigest('sha256') + def test_attributes(self): + # Testing if attributes are of same type. +@@ -378,6 +388,7 @@ class CopyTestCase(unittest.TestCase): + self.assertEqual(type(h1.outer), type(h2.outer), + "Types of outer don't match.") - if self._fs_supports_holes(): - s = os.stat(filename) -@@ -2431,7 +2431,7 @@ def _test_link_extraction(self, name): - self.tar.extract(name, TEMPDIR) - with open(os.path.join(TEMPDIR, name), "rb") as f: - data = f.read() -- self.assertEqual(md5sum(data), md5_regtype) -+ self.assertEqual(sha1sum(data), sha1_regtype) ++ @unittest.skipIf(hashlib.get_fips_mode(), "Internal attributes unavailable in FIPS mode") + @requires_hashdigest('sha256') + def test_realcopy(self): + # Testing if the copy method created a real copy. +@@ -390,6 +401,21 @@ class CopyTestCase(unittest.TestCase): + self.assertTrue(id(h1.outer) != id(h2.outer), + "No real copy of the attribute 'outer'.") - # See issues #1578269, #8879, and #17689 for some history on these skips - @unittest.skipIf(hasattr(os.path, "islink"), ++ def test_realcopy(self): ++ # Testing if the copy method created a real copy. ++ h1 = hmac.HMAC(b"key", digestmod="sha1") ++ h2 = h1.copy() ++ # Using id() in case somebody has overridden __eq__/__ne__. ++ self.assertTrue(id(h1) != id(h2), "No real copy of the HMAC instance.") ++ old_digest = h1.digest() ++ assert h1.digest() == h2.digest() ++ h1.update(b'hi') ++ assert h1.digest() != h2.digest() ++ assert h2.digest() == old_digest ++ new_digest = h1.digest() ++ h2.update(b'hi') ++ assert h1.digest() == h2.digest() == new_digest ++ + @requires_hashdigest('sha256') + def test_equality(self): + # Testing if the copy has the same digests. +-- +2.21.0 -From 4e35a5240d0bf99b60a76d3d25a82f9b8c901d59 Mon Sep 17 00:00:00 2001 + +From 264c6eed5a5d060fe7bad7e4410d920cecbb083c Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 5 Aug 2019 16:37:12 +0200 Subject: [PATCH 23/36] test_tools: Skip md5sum tests in FIPS mode @@ -3221,10 +3706,10 @@ Subject: [PATCH 23/36] test_tools: Skip md5sum tests in FIPS mode 1 file changed, 4 insertions(+) diff --git a/Lib/test/test_tools/test_md5sum.py b/Lib/test/test_tools/test_md5sum.py -index fb565b73778f..7028a4dc2143 100644 +index fb565b73778..7028a4dc214 100644 --- a/Lib/test/test_tools/test_md5sum.py +++ b/Lib/test/test_tools/test_md5sum.py -@@ -4,11 +4,15 @@ +@@ -4,11 +4,15 @@ import os import unittest from test import support from test.support.script_helper import assert_python_ok, assert_python_failure @@ -3240,70 +3725,21 @@ index fb565b73778f..7028a4dc2143 100644 class MD5SumTests(unittest.TestCase): @classmethod def setUpClass(cls): +-- +2.21.0 -From 82d94582bf36170c924b26f33b56c6177a1e30f7 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Mon, 5 Aug 2019 16:43:13 +0200 -Subject: [PATCH 24/36] test_urllib2_localnet: Skip tests of md5 auth - ---- - Lib/test/test_urllib2_localnet.py | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py -index ef0091c49300..2d0d62f610ef 100644 ---- a/Lib/test/test_urllib2_localnet.py -+++ b/Lib/test/test_urllib2_localnet.py -@@ -317,6 +317,7 @@ def test_basic_auth_httperror(self): - self.assertRaises(urllib.error.HTTPError, urllib.request.urlopen, self.server_url) - - -+@unittest.skipIf(hashlib.get_fips_mode(), "md5 digest auth unacceptable in FIPS mode") - @unittest.skipUnless(threading, "Threading required for this test.") - class ProxyAuthTests(unittest.TestCase): - URL = "http://localhost" - -From 78d82fdbe050e6fb27f5d736f3030357046cb60e Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Mon, 5 Aug 2019 16:45:21 +0200 -Subject: [PATCH 25/36] test_uuid: Skip uuid3 test - ---- - Lib/test/test_uuid.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py -index aa3de74cef0a..a4ec69058889 100644 ---- a/Lib/test/test_uuid.py -+++ b/Lib/test/test_uuid.py -@@ -6,6 +6,7 @@ - import shutil - import subprocess - import uuid -+import hashlib - - def importable(name): - try: -@@ -366,6 +367,7 @@ def test_uuid1(self): - equal(((u.clock_seq_hi_variant & 0x3f) << 8) | - u.clock_seq_low, 0x3fff) - -+ @unittest.skipIf(hashlib.get_fips_mode(), "uuid3 (md5-based) unacceptable in FIPS mode") - def test_uuid3(self): - equal = self.assertEqual - -From c7bfe61f072475b900bb68c824aa0b1fa696a975 Mon Sep 17 00:00:00 2001 +From c5373f5e7ae4ecfe8337ee3c73b594b5f0ebb411 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 5 Aug 2019 17:21:16 +0200 -Subject: [PATCH 26/36] _hashopenssl: Include hash name in the error message +Subject: [PATCH 24/36] _hashopenssl: Include hash name in the error message --- Modules/_hashopenssl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c -index 7dfd70822b99..0563473c627e 100644 +index 7dfd70822b9..0563473c627 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -431,7 +431,7 @@ EVPnew(PyObject *name_obj, @@ -3324,11 +3760,14 @@ index 7dfd70822b99..0563473c627e 100644 goto end; } +-- +2.21.0 -From 5c732e6288270c247cc443fe2c2fd4fb4d95442b Mon Sep 17 00:00:00 2001 + +From c3f9e194eb5f86ebec4db2820b8968d6896abc8b Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 5 Aug 2019 18:23:57 +0200 -Subject: [PATCH 27/36] Make hashlib tests pass in FIPS mode (with some hashlib +Subject: [PATCH 25/36] Make hashlib tests pass in FIPS mode (with some hashlib changes) --- @@ -3338,7 +3777,7 @@ Subject: [PATCH 27/36] Make hashlib tests pass in FIPS mode (with some hashlib 3 files changed, 78 insertions(+), 21 deletions(-) diff --git a/Lib/hashlib.py b/Lib/hashlib.py -index ca1dd2022515..d3344f60b2ea 100644 +index ca1dd202251..d3344f60b2e 100644 --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -155,7 +155,18 @@ def __hash_new(name, data=b'', **kwargs): @@ -3374,10 +3813,10 @@ index ca1dd2022515..d3344f60b2ea 100644 # If the _hashlib module (OpenSSL) doesn't support the named # hash, try using our builtin implementations. diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py -index 645a3d01b91d..30b6abcbef90 100644 +index e57c93b42f5..9745bfd6fa2 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py -@@ -29,6 +29,11 @@ +@@ -31,6 +31,11 @@ COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount') c_hashlib = import_fresh_module('hashlib', fresh=['_hashlib']) py_hashlib = import_fresh_module('hashlib', blocked=['_hashlib']) @@ -3389,7 +3828,7 @@ index 645a3d01b91d..30b6abcbef90 100644 try: import _blake2 except ImportError: -@@ -84,6 +89,11 @@ class HashLibTestCase(unittest.TestCase): +@@ -86,6 +91,11 @@ class HashLibTestCase(unittest.TestCase): # Issue #14693: fallback modules are always compiled under POSIX _warn_on_extension_import = os.name == 'posix' or COMPILED_WITH_PYDEBUG @@ -3401,7 +3840,7 @@ index 645a3d01b91d..30b6abcbef90 100644 def _conditional_import_module(self, module_name): """Import a module and return a reference to it or None on failure.""" try: -@@ -91,8 +101,20 @@ def _conditional_import_module(self, module_name): +@@ -93,8 +103,20 @@ class HashLibTestCase(unittest.TestCase): except ModuleNotFoundError as error: if self._warn_on_extension_import: warnings.warn('Did a C extension fail to compile? %s' % error) @@ -3422,7 +3861,7 @@ index 645a3d01b91d..30b6abcbef90 100644 def __init__(self, *args, **kwargs): algorithms = set() for algorithm in self.supported_hash_names: -@@ -179,15 +201,13 @@ def test_hash_array(self): +@@ -182,15 +204,13 @@ class HashLibTestCase(unittest.TestCase): a = array.array("b", range(10)) for cons in self.hash_constructors: c = cons(a) @@ -3440,7 +3879,7 @@ index 645a3d01b91d..30b6abcbef90 100644 set(_algo for _algo in self.supported_hash_names if _algo.islower())) -@@ -199,6 +219,12 @@ def test_unknown_hash(self): +@@ -202,6 +222,12 @@ class HashLibTestCase(unittest.TestCase): self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam') self.assertRaises(TypeError, hashlib.new, 1) @@ -3453,7 +3892,7 @@ index 645a3d01b91d..30b6abcbef90 100644 def test_get_builtin_constructor(self): get_builtin_constructor = getattr(hashlib, '__get_builtin_constructor') -@@ -228,9 +254,7 @@ def test_get_builtin_constructor(self): +@@ -231,9 +257,7 @@ class HashLibTestCase(unittest.TestCase): def test_hexdigest(self): for cons in self.hash_constructors: h = cons() @@ -3464,7 +3903,7 @@ index 645a3d01b91d..30b6abcbef90 100644 self.assertIsInstance(h.digest(16), bytes) self.assertEqual(hexstr(h.digest(16)), h.hexdigest(16)) else: -@@ -242,9 +266,7 @@ def test_digest_length_overflow(self): +@@ -245,9 +269,7 @@ class HashLibTestCase(unittest.TestCase): large_sizes = (2**29, 2**32-10, 2**32+10, 2**61, 2**64-10, 2**64+10) for cons in self.hash_constructors: h = cons() @@ -3475,7 +3914,7 @@ index 645a3d01b91d..30b6abcbef90 100644 continue for digest in h.digest, h.hexdigest: with self.assertRaises((ValueError, OverflowError)): -@@ -275,9 +297,7 @@ def test_large_update(self): +@@ -278,9 +300,7 @@ class HashLibTestCase(unittest.TestCase): m1.update(bees) m1.update(cees) m1.update(dees) @@ -3486,7 +3925,7 @@ index 645a3d01b91d..30b6abcbef90 100644 args = (16,) else: args = () -@@ -346,7 +366,8 @@ def check_no_unicode(self, algorithm_name): +@@ -349,7 +369,8 @@ class HashLibTestCase(unittest.TestCase): self.assertRaises(TypeError, hash_object_constructor, 'spam') def test_no_unicode(self): @@ -3496,7 +3935,7 @@ index 645a3d01b91d..30b6abcbef90 100644 self.check_no_unicode('sha1') self.check_no_unicode('sha224') self.check_no_unicode('sha256') -@@ -389,7 +410,8 @@ def check_blocksize_name(self, name, block_size=0, digest_size=0, +@@ -392,7 +413,8 @@ class HashLibTestCase(unittest.TestCase): self.assertIn(name.split("_")[0], repr(m)) def test_blocksize_name(self): @@ -3506,7 +3945,7 @@ index 645a3d01b91d..30b6abcbef90 100644 self.check_blocksize_name('sha1', 64, 20) self.check_blocksize_name('sha224', 64, 28) self.check_blocksize_name('sha256', 64, 32) -@@ -429,22 +451,27 @@ def test_blocksize_name_blake2(self): +@@ -432,22 +454,27 @@ class HashLibTestCase(unittest.TestCase): self.check_blocksize_name('blake2b', 128, 64) self.check_blocksize_name('blake2s', 64, 32) @@ -3534,7 +3973,7 @@ index 645a3d01b91d..30b6abcbef90 100644 @unittest.skipIf(sys.maxsize < _4G - 1, 'test cannot run on 32-bit systems') @bigmemtest(size=_4G - 1, memuse=1, dry_run=False) def test_case_md5_uintmax(self, size): -@@ -826,14 +853,16 @@ def test_gil(self): +@@ -829,14 +856,16 @@ class HashLibTestCase(unittest.TestCase): m = cons(b'x' * gil_minsize) m.update(b'1') @@ -3556,7 +3995,7 @@ index 645a3d01b91d..30b6abcbef90 100644 @unittest.skipUnless(threading, 'Threading required for this test.') @support.reap_threads diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c -index 0563473c627e..e330423e2662 100644 +index 0563473c627..e330423e266 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -256,11 +256,25 @@ EVP_update(EVPobject *self, PyObject *args) @@ -3585,107 +4024,14 @@ index 0563473c627e..e330423e2662 100644 {NULL, NULL} /* sentinel */ }; +-- +2.21.0 -From 9f8dde4113dc93248ed376f17ceef349bcd2f855 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Mon, 5 Aug 2019 19:12:38 +0200 -Subject: [PATCH 28/36] Fixups - -- Adjust error message of the original hmac.HMAC class -- Don't duplicate a atest name ---- - Lib/hmac.py | 2 +- - Lib/test/test_hmac.py | 2 +- - 2 files changed, 2 insertions(+), 2 deletions(-) - -diff --git a/Lib/hmac.py b/Lib/hmac.py -index 7af94c39ed63..33b5be613d96 100644 ---- a/Lib/hmac.py -+++ b/Lib/hmac.py -@@ -41,7 +41,7 @@ def __init__(self, key, msg = None, digestmod = None): - """ - if _hashlib.get_fips_mode(): - raise ValueError( -- 'hmac.HMAC is not available in FIPS mode. ' -+ 'This class is not available in FIPS mode. ' - + 'Use hmac.new().' - ) - -diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py -index 6f53a6d1fd5b..17ffcf37eb14 100644 ---- a/Lib/test/test_hmac.py -+++ b/Lib/test/test_hmac.py -@@ -389,7 +389,7 @@ def test_realcopy(self): - self.assertTrue(id(h1.outer) != id(h2.outer), - "No real copy of the attribute 'outer'.") - -- def test_realcopy(self): -+ def test_realcopy_by_digest(self): - # Testing if the copy method created a real copy. - h1 = hmac.HMAC(b"key", digestmod="sha1") - h2 = h1.copy() - -From 0056a10cb639a97b6deac312752be9ed0f19f2cf Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Mon, 19 Aug 2019 13:59:40 +0200 -Subject: [PATCH 29/36] Make uuid.uuid3 work (using libuuid via ctypes) - ---- - Lib/test/test_uuid.py | 1 - - Lib/uuid.py | 9 +++++++++ - 2 files changed, 9 insertions(+), 1 deletion(-) - -diff --git a/Lib/test/test_uuid.py b/Lib/test/test_uuid.py -index a4ec69058889..17e03388ce7b 100644 ---- a/Lib/test/test_uuid.py -+++ b/Lib/test/test_uuid.py -@@ -367,7 +367,6 @@ def test_uuid1(self): - equal(((u.clock_seq_hi_variant & 0x3f) << 8) | - u.clock_seq_low, 0x3fff) - -- @unittest.skipIf(hashlib.get_fips_mode(), "uuid3 (md5-based) unacceptable in FIPS mode") - def test_uuid3(self): - equal = self.assertEqual - -diff --git a/Lib/uuid.py b/Lib/uuid.py -index db8b2ef94ed4..42291ff5e0d6 100644 ---- a/Lib/uuid.py -+++ b/Lib/uuid.py -@@ -476,6 +476,7 @@ def _netbios_getnode(): - # If ctypes is available, use it to find system routines for UUID generation. - # XXX This makes the module non-thread-safe! - _uuid_generate_time = _UuidCreate = None -+_uuid_generate_md5 = None - try: - import ctypes, ctypes.util - import sys -@@ -492,6 +493,8 @@ def _netbios_getnode(): - continue - if hasattr(lib, 'uuid_generate_time'): - _uuid_generate_time = lib.uuid_generate_time -+ # The library that has uuid_generate_time should have md5 too. -+ _uuid_generate_md5 = getattr(lib, 'uuid_generate_md5') - break - del _libnames - -@@ -614,6 +617,12 @@ def uuid1(node=None, clock_seq=None): - - def uuid3(namespace, name): - """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" -+ if _uuid_generate_md5: -+ name_b = bytes(name, "utf-8") -+ _buffer = ctypes.create_string_buffer(16) -+ _uuid_generate_md5(_buffer, namespace.bytes, name_b, len(name_b)) -+ return UUID(bytes=bytes_(_buffer.raw)) -+ - from hashlib import md5 - hash = md5(namespace.bytes + bytes(name, "utf-8")).digest() - return UUID(bytes=hash[:16], version=3) -From 27805c1110b734c5aa039443f4cf217f0d2da44d Mon Sep 17 00:00:00 2001 +From a40d1cb8672bc2c5403b6e9ff6eaa3324282de09 Mon Sep 17 00:00:00 2001 From: Lumir Balhar Date: Wed, 14 Aug 2019 14:43:07 +0200 -Subject: [PATCH 30/36] distutils upload: only add md5 if available, but +Subject: [PATCH 26/36] distutils upload: only add md5 if available, but *always* use sha256 --- @@ -3694,10 +4040,10 @@ Subject: [PATCH 30/36] distutils upload: only add md5 if available, but 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py -index 0edb39efd4cb..170acb3d6b65 100644 +index 0edb39efd4c..170acb3d6b6 100644 --- a/Lib/distutils/command/upload.py +++ b/Lib/distutils/command/upload.py -@@ -102,6 +102,7 @@ def upload_file(self, command, pyversion, filename): +@@ -102,6 +102,7 @@ class upload(PyPIRCCommand): 'content': (os.path.basename(filename),content), 'filetype': command, 'pyversion': pyversion, @@ -3705,7 +4051,7 @@ index 0edb39efd4cb..170acb3d6b65 100644 # additional meta-data 'metadata_version': '1.0', -@@ -124,7 +125,7 @@ def upload_file(self, command, pyversion, filename): +@@ -124,7 +125,7 @@ class upload(PyPIRCCommand): digest = hashlib.md5(content).hexdigest() except ValueError as e: msg = 'calculating md5 checksum failed: %s' % e @@ -3715,10 +4061,10 @@ index 0edb39efd4cb..170acb3d6b65 100644 # this really shouldn't fail raise diff --git a/Lib/distutils/tests/test_upload.py b/Lib/distutils/tests/test_upload.py -index b4b64e97737d..f720a7905dd8 100644 +index b4b64e97737..f720a7905dd 100644 --- a/Lib/distutils/tests/test_upload.py +++ b/Lib/distutils/tests/test_upload.py -@@ -132,10 +132,11 @@ def test_upload(self): +@@ -132,10 +132,11 @@ class uploadTestCase(BasePyPIRCCommandTestCase): # what did we send ? headers = dict(self.last_open.req.headers) if hashlib.get_fips_mode(): @@ -3733,7 +4079,7 @@ index b4b64e97737d..f720a7905dd8 100644 content_type = headers['Content-type'] self.assertTrue(content_type.startswith('multipart/form-data')) self.assertEqual(self.last_open.req.get_method(), 'POST') -@@ -172,10 +173,11 @@ def test_upload_correct_cr(self): +@@ -172,10 +173,11 @@ class uploadTestCase(BasePyPIRCCommandTestCase): headers = dict(self.last_open.req.headers) if hashlib.get_fips_mode(): @@ -3748,11 +4094,14 @@ index b4b64e97737d..f720a7905dd8 100644 self.assertIn(b'long description\r', self.last_open.req.data) def test_upload_fails(self): +-- +2.21.0 -From 584d432c6a3e987fdd661e994626befaed523a40 Mon Sep 17 00:00:00 2001 + +From e0d2cca338186bbc5cb9c67bb4402dec38fed5a7 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 26 Aug 2019 15:55:48 +0200 -Subject: [PATCH 31/36] Add the usedforsecurity argument back +Subject: [PATCH 27/36] Add the usedforsecurity argument back --- Lib/hashlib.py | 4 ++- @@ -3760,7 +4109,7 @@ Subject: [PATCH 31/36] Add the usedforsecurity argument back 2 files changed, 65 insertions(+), 21 deletions(-) diff --git a/Lib/hashlib.py b/Lib/hashlib.py -index d3344f60b2ea..cd3b035b1d76 100644 +index d3344f60b2e..cd3b035b1d7 100644 --- a/Lib/hashlib.py +++ b/Lib/hashlib.py @@ -174,7 +174,9 @@ def __hash_new(name, data=b'', **kwargs): @@ -3775,7 +4124,7 @@ index d3344f60b2ea..cd3b035b1d76 100644 retval._set_name(orig_name) return retval diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c -index e330423e2662..b621c330c32d 100644 +index e330423e266..b621c330c32 100644 --- a/Modules/_hashopenssl.c +++ b/Modules/_hashopenssl.c @@ -318,6 +318,25 @@ EVP_repr(EVPobject *self) @@ -3951,11 +4300,14 @@ index e330423e2662..b621c330c32d 100644 PyDoc_STR("Returns a " #NAME \ " hash object; optionally initialized with a string") \ }, +-- +2.21.0 + -From 07c8dd0441a76fe841461a1b81d4c7f9c697d643 Mon Sep 17 00:00:00 2001 +From 0d169ad7d9aa48bdb3313b6d72682d097dc9dea5 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 26 Aug 2019 18:59:15 +0200 -Subject: [PATCH 32/36] Add no-op usedforsecurity argument to internal hash +Subject: [PATCH 28/36] Add no-op usedforsecurity argument to internal hash implementations --- @@ -3967,7 +4319,7 @@ Subject: [PATCH 32/36] Add no-op usedforsecurity argument to internal hash 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/Modules/_blake2/blake2b_impl.c b/Modules/_blake2/blake2b_impl.c -index f6bfce823b8f..ae9d244200ab 100644 +index f6bfce823b8..ae9d244200a 100644 --- a/Modules/_blake2/blake2b_impl.c +++ b/Modules/_blake2/blake2b_impl.c @@ -87,6 +87,8 @@ _blake2.blake2b.__new__ as py_blake2b_new @@ -3991,7 +4343,7 @@ index f6bfce823b8f..ae9d244200ab 100644 BLAKE2bObject *self = NULL; Py_buffer buf; diff --git a/Modules/_blake2/blake2s_impl.c b/Modules/_blake2/blake2s_impl.c -index 28ae5b651019..bf80d6b7428c 100644 +index 28ae5b65101..bf80d6b7428 100644 --- a/Modules/_blake2/blake2s_impl.c +++ b/Modules/_blake2/blake2s_impl.c @@ -87,6 +87,8 @@ _blake2.blake2s.__new__ as py_blake2s_new @@ -4015,7 +4367,7 @@ index 28ae5b651019..bf80d6b7428c 100644 BLAKE2sObject *self = NULL; Py_buffer buf; diff --git a/Modules/_blake2/clinic/blake2b_impl.c.h b/Modules/_blake2/clinic/blake2b_impl.c.h -index 9b2965eb6b31..9688c04dda80 100644 +index 9b2965eb6b3..9688c04dda8 100644 --- a/Modules/_blake2/clinic/blake2b_impl.c.h +++ b/Modules/_blake2/clinic/blake2b_impl.c.h @@ -5,7 +5,8 @@ preserve @@ -4069,7 +4421,7 @@ index 9b2965eb6b31..9688c04dda80 100644 -/*[clinic end generated code: output=0eb559f418fc0a21 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=d5f214b052c75135 input=a9049054013a1b77]*/ diff --git a/Modules/_blake2/clinic/blake2s_impl.c.h b/Modules/_blake2/clinic/blake2s_impl.c.h -index 42b87b7099df..5653e93044d1 100644 +index 42b87b7099d..5653e93044d 100644 --- a/Modules/_blake2/clinic/blake2s_impl.c.h +++ b/Modules/_blake2/clinic/blake2s_impl.c.h @@ -5,7 +5,8 @@ preserve @@ -4123,7 +4475,7 @@ index 42b87b7099df..5653e93044d1 100644 -/*[clinic end generated code: output=13d4b08ea9ee2d62 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=2373a3b3fa542e89 input=a9049054013a1b77]*/ diff --git a/Modules/_sha3/sha3module.c b/Modules/_sha3/sha3module.c -index 2783a75644fc..62db9cb5616f 100644 +index 2783a75644f..62db9cb5616 100644 --- a/Modules/_sha3/sha3module.c +++ b/Modules/_sha3/sha3module.c @@ -185,6 +185,11 @@ py_sha3_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) @@ -4138,29 +4490,32 @@ index 2783a75644fc..62db9cb5616f 100644 if (!_PyArg_NoKeywords(type->tp_name, kwargs)) { return NULL; } +-- +2.21.0 -From 595066f4993f94838f53f06b2729739f30a60eb8 Mon Sep 17 00:00:00 2001 + +From c451744d82f78f42bfa947b782a24ff7c8c6ad9d Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 26 Aug 2019 19:09:39 +0200 -Subject: [PATCH 33/36] Test the usedforsecurity flag +Subject: [PATCH 29/36] Test the usedforsecurity flag --- Lib/test/test_hashlib.py | 82 ++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 28 deletions(-) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py -index 30b6abcbef90..b359c4fb14a9 100644 +index 9745bfd6fa2..19a2fbdf294 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py -@@ -22,6 +22,7 @@ - from test import support +@@ -24,6 +24,7 @@ from test import support from test.support import _4G, bigmemtest, import_fresh_module + from test.support import requires_hashdigest from http.client import HTTPException +from functools import partial # Were we compiled --with-pydebug or with #define Py_DEBUG? COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount') -@@ -30,8 +31,10 @@ +@@ -32,8 +33,10 @@ c_hashlib = import_fresh_module('hashlib', fresh=['_hashlib']) py_hashlib = import_fresh_module('hashlib', blocked=['_hashlib']) if hashlib.get_fips_mode(): @@ -4172,7 +4527,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 FIPS_DISABLED = set() try: -@@ -76,6 +79,15 @@ def read_vectors(hash_name): +@@ -78,6 +81,15 @@ def read_vectors(hash_name): yield parts @@ -4188,7 +4543,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 class HashLibTestCase(unittest.TestCase): supported_hash_names = ( 'md5', 'MD5', 'sha1', 'SHA1', 'sha224', 'SHA224', 'sha256', 'SHA256', -@@ -91,8 +103,6 @@ class HashLibTestCase(unittest.TestCase): +@@ -93,8 +105,6 @@ class HashLibTestCase(unittest.TestCase): if hashlib.get_fips_mode(): shakes = set() @@ -4197,7 +4552,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 def _conditional_import_module(self, module_name): """Import a module and return a reference to it or None on failure.""" -@@ -118,7 +128,8 @@ def _has_shake_extras(self, hasher): +@@ -120,7 +130,8 @@ class HashLibTestCase(unittest.TestCase): def __init__(self, *args, **kwargs): algorithms = set() for algorithm in self.supported_hash_names: @@ -4207,7 +4562,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 _blake2 = self._conditional_import_module('_blake2') if _blake2: -@@ -128,15 +139,21 @@ def __init__(self, *args, **kwargs): +@@ -130,15 +141,21 @@ class HashLibTestCase(unittest.TestCase): for algorithm in algorithms: self.constructors_to_test[algorithm] = set() @@ -4230,8 +4585,8 @@ index 30b6abcbef90..b359c4fb14a9 100644 + _add_constructor(algorithm, _test_algorithm_via_hashlib_new) _hashlib = self._conditional_import_module('_hashlib') - if _hashlib: -@@ -147,7 +164,7 @@ def _test_algorithm_via_hashlib_new(data=None, _alg=algorithm, **kwargs): + self._hashlib = _hashlib +@@ -150,7 +167,7 @@ class HashLibTestCase(unittest.TestCase): for algorithm, constructors in self.constructors_to_test.items(): constructor = getattr(_hashlib, 'openssl_'+algorithm, None) if constructor: @@ -4240,7 +4595,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 def add_builtin_constructor(name): constructor = getattr(hashlib, "__get_builtin_constructor")(name) -@@ -207,7 +224,7 @@ def test_hash_array(self): +@@ -210,7 +227,7 @@ class HashLibTestCase(unittest.TestCase): c.hexdigest() def test_algorithms_guaranteed(self): @@ -4249,7 +4604,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 set(_algo for _algo in self.supported_hash_names if _algo.islower())) -@@ -283,7 +300,9 @@ def test_name_attribute(self): +@@ -286,7 +303,9 @@ class HashLibTestCase(unittest.TestCase): self.assertIn(h.name, self.supported_hash_names) else: self.assertNotIn(h.name, self.supported_hash_names) @@ -4260,7 +4615,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 def test_large_update(self): aas = b'a' * 128 -@@ -325,13 +344,15 @@ def check(self, name, data, hexdigest, shake=False, **kwargs): +@@ -328,13 +347,15 @@ class HashLibTestCase(unittest.TestCase): self.assertGreaterEqual(len(constructors), 2) for hash_object_constructor in constructors: if ( @@ -4279,7 +4634,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 if length > m.digest_size: # OpenSSL doesn't give long digests return -@@ -348,7 +369,7 @@ def check(self, name, data, hexdigest, shake=False, **kwargs): +@@ -351,7 +372,7 @@ class HashLibTestCase(unittest.TestCase): % (name, hash_object_constructor, computed, len(data), hexdigest)) if shake: @@ -4288,7 +4643,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 computed = m.digest()[:length] else: computed = m.digest(length) -@@ -366,8 +387,7 @@ def check_no_unicode(self, algorithm_name): +@@ -369,8 +390,7 @@ class HashLibTestCase(unittest.TestCase): self.assertRaises(TypeError, hash_object_constructor, 'spam') def test_no_unicode(self): @@ -4298,7 +4653,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 self.check_no_unicode('sha1') self.check_no_unicode('sha224') self.check_no_unicode('sha256') -@@ -394,10 +414,10 @@ def check_blocksize_name(self, name, block_size=0, digest_size=0, +@@ -397,10 +417,10 @@ class HashLibTestCase(unittest.TestCase): for hash_object_constructor in constructors: m = hash_object_constructor() self.assertEqual(m.block_size, block_size) @@ -4311,7 +4666,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 self.assertEqual(len(m.digest(digest_length)), digest_length) self.assertEqual(len(m.hexdigest(digest_length)), -@@ -432,7 +452,7 @@ def check_sha3(self, name, capacity, rate, suffix): +@@ -435,7 +455,7 @@ class HashLibTestCase(unittest.TestCase): for hash_object_constructor in constructors: m = hash_object_constructor() self.assertEqual(capacity + rate, 1600) @@ -4320,7 +4675,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 self.assertEqual(m._capacity_bits, capacity) self.assertEqual(m._rate_bits, rate) self.assertEqual(m._suffix, suffix) -@@ -451,31 +471,27 @@ def test_blocksize_name_blake2(self): +@@ -454,31 +474,27 @@ class HashLibTestCase(unittest.TestCase): self.check_blocksize_name('blake2b', 128, 64) self.check_blocksize_name('blake2s', 64, 32) @@ -4358,7 +4713,7 @@ index 30b6abcbef90..b359c4fb14a9 100644 # use the three examples from Federal Information Processing Standards # Publication 180-1, Secure Hash Standard, 1995 April 17 -@@ -901,6 +917,16 @@ def hash_in_chunks(chunk_size): +@@ -904,6 +920,16 @@ class HashLibTestCase(unittest.TestCase): self.assertEqual(expected_hash, hasher.hexdigest()) @@ -4373,10 +4728,181 @@ index 30b6abcbef90..b359c4fb14a9 100644 + 'd41d8cd98f00b204e9800998ecf8427e') + - class KDFTests(unittest.TestCase): + class KDFTests(unittest.TestCase): + +-- +2.21.0 + + +From 327707f185572cf13da66851e0af824a81d65aa9 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Thu, 29 Aug 2019 10:25:28 +0200 +Subject: [PATCH 30/36] Skip error checking in _hashlib.get_fips_mode + +Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1745499 +--- + Modules/_hashopenssl.c | 30 ++++++++++++++++-------------- + 1 file changed, 16 insertions(+), 14 deletions(-) + +diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c +index b621c330c32..6bfb12c5618 100644 +--- a/Modules/_hashopenssl.c ++++ b/Modules/_hashopenssl.c +@@ -1021,20 +1021,22 @@ static PyObject * + _hashlib_get_fips_mode_impl(PyObject *module) + /*[clinic end generated code: output=ad8a7793310d3f98 input=f42a2135df2a5e11]*/ + { +- int result = FIPS_mode(); +- if (result == 0) { +- // "If the library was built without support of the FIPS Object Module, +- // then the function will return 0 with an error code of +- // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." +- // But 0 is also a valid result value. +- +- unsigned long errcode = ERR_peek_last_error(); +- if (errcode) { +- _setException(PyExc_ValueError); +- return NULL; +- } +- } +- return PyLong_FromLong(result); ++ // XXX: This function skips error checking. ++ // This is only appropriate for RHEL. ++ ++ // From the OpenSSL docs: ++ // "If the library was built without support of the FIPS Object Module, ++ // then the function will return 0 with an error code of ++ // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." ++ // In RHEL: ++ // * we do build with FIPS, so the function always succeeds ++ // * even if it didn't, people seem used to errors being left on the ++ // OpenSSL error stack. ++ ++ // For more info, see: ++ // https://bugzilla.redhat.com/show_bug.cgi?id=1745499 ++ ++ return PyLong_FromLong(FIPS_mode()); + } + + +-- +2.21.0 + + +From 695039674b78b19d9ff26d637c11acea99c44807 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Thu, 10 Oct 2019 13:04:50 +0200 +Subject: [PATCH 31/36] Skip error checking in _Py_hashlib_fips_error + +https://bugzilla.redhat.com/show_bug.cgi?id=1760106 +--- + Include/_hashopenssl.h | 12 +++--------- + 1 file changed, 3 insertions(+), 9 deletions(-) + +diff --git a/Include/_hashopenssl.h b/Include/_hashopenssl.h +index 47ed0030422..d4cbdef984d 100644 +--- a/Include/_hashopenssl.h ++++ b/Include/_hashopenssl.h +@@ -42,16 +42,10 @@ static int + _Py_hashlib_fips_error(PyObject *exc, char *name) { + int result = FIPS_mode(); + if (result == 0) { +- // "If the library was built without support of the FIPS Object Module, +- // then the function will return 0 with an error code of +- // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." +- // But 0 is also a valid result value. ++ // XXX: This function skips error checking. ++ // This is only appropriate for RHEL. ++ // See _hashlib.get_fips_mode for details. + +- unsigned long errcode = ERR_peek_last_error(); +- if (errcode) { +- _setException(exc); +- return 1; +- } + return 0; + } + PyErr_Format(exc, "%s is not available in FIPS mode", name); +-- +2.21.0 + + +From 0f9008e92b62f5f22e2bfd0a73d5325d16eedf6f Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Thu, 21 Nov 2019 00:20:09 +0100 +Subject: [PATCH 32/36] Use usedforsecurity=False in uuid + +Partially backport commit 7cad53e6b084435a220e6604010f1fa5778bd0b1 +only for uuid +--- + Lib/uuid.py | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/Lib/uuid.py b/Lib/uuid.py +index db8b2ef94ed..7e680a24d06 100644 +--- a/Lib/uuid.py ++++ b/Lib/uuid.py +@@ -615,8 +615,11 @@ def uuid1(node=None, clock_seq=None): + def uuid3(namespace, name): + """Generate a UUID from the MD5 hash of a namespace UUID and a name.""" + from hashlib import md5 +- hash = md5(namespace.bytes + bytes(name, "utf-8")).digest() +- return UUID(bytes=hash[:16], version=3) ++ digest = md5( ++ namespace.bytes + bytes(name, "utf-8"), ++ usedforsecurity=False ++ ).digest() ++ return UUID(bytes=digest[:16], version=3) + + def uuid4(): + """Generate a random UUID.""" +-- +2.21.0 + + +From 75829df72b65fb573f3b310033978e493ff700b4 Mon Sep 17 00:00:00 2001 +From: Petr Viktorin +Date: Mon, 5 Aug 2019 19:12:38 +0200 +Subject: [PATCH 33/36] Fixups + +- Adjust error message of the original hmac.HMAC class +- Don't duplicate a test name +--- + Lib/hmac.py | 2 +- + Lib/test/test_hmac.py | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/Lib/hmac.py b/Lib/hmac.py +index 7af94c39ed6..33b5be613d9 100644 +--- a/Lib/hmac.py ++++ b/Lib/hmac.py +@@ -41,7 +41,7 @@ class HMAC: + """ + if _hashlib.get_fips_mode(): + raise ValueError( +- 'hmac.HMAC is not available in FIPS mode. ' ++ 'This class is not available in FIPS mode. ' + + 'Use hmac.new().' + ) + +diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py +index 5b090727ef6..449b1366314 100644 +--- a/Lib/test/test_hmac.py ++++ b/Lib/test/test_hmac.py +@@ -401,7 +401,7 @@ class CopyTestCase(unittest.TestCase): + self.assertTrue(id(h1.outer) != id(h2.outer), + "No real copy of the attribute 'outer'.") +- def test_realcopy(self): ++ def test_realcopy_by_digest(self): + # Testing if the copy method created a real copy. + h1 = hmac.HMAC(b"key", digestmod="sha1") + h2 = h1.copy() +-- +2.21.0 + -From 723bfe45d5a7666a75a12633b21a9f153805eccf Mon Sep 17 00:00:00 2001 +From 86f1f161b5aab08975379dbae6ebac08a697e3d7 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Mon, 26 Aug 2019 19:39:48 +0200 Subject: [PATCH 34/36] Don't re-export get_fips_mode from hashlib @@ -4389,18 +4915,18 @@ Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1745685 Lib/hmac.py | 6 +++--- Lib/test/test_fips.py | 6 +++--- Lib/test/test_hashlib.py | 16 +++++++++------- - Lib/test/test_hmac.py | 15 ++++++++------- - Lib/test/test_logging.py | 3 ++- - Lib/test/test_smtplib.py | 7 ++++--- + Lib/test/test_hmac.py | 8 +++++--- + Lib/test/test_logging.py | 1 + + Lib/test/test_smtplib.py | 4 +++- Lib/test/test_tools/test_md5sum.py | 4 ++-- - Lib/test/test_urllib2_localnet.py | 3 ++- - 11 files changed, 50 insertions(+), 41 deletions(-) + Lib/test/test_urllib2_localnet.py | 1 + + 11 files changed, 44 insertions(+), 33 deletions(-) diff --git a/Lib/distutils/command/upload.py b/Lib/distutils/command/upload.py -index 170acb3d6b65..d0a4aee001ea 100644 +index 170acb3d6b6..d0a4aee001e 100644 --- a/Lib/distutils/command/upload.py +++ b/Lib/distutils/command/upload.py -@@ -126,7 +126,8 @@ def upload_file(self, command, pyversion, filename): +@@ -126,7 +126,8 @@ class upload(PyPIRCCommand): except ValueError as e: msg = 'calculating md5 checksum failed: %s' % e self.announce(msg, log.INFO) @@ -4411,10 +4937,10 @@ index 170acb3d6b65..d0a4aee001ea 100644 raise else: diff --git a/Lib/distutils/tests/test_upload.py b/Lib/distutils/tests/test_upload.py -index f720a7905dd8..a198b213577b 100644 +index f720a7905dd..a198b213577 100644 --- a/Lib/distutils/tests/test_upload.py +++ b/Lib/distutils/tests/test_upload.py -@@ -4,6 +4,7 @@ +@@ -4,6 +4,7 @@ import unittest import unittest.mock as mock from urllib.request import HTTPError import hashlib @@ -4422,7 +4948,7 @@ index f720a7905dd8..a198b213577b 100644 from test.support import run_unittest -@@ -131,7 +132,7 @@ def test_upload(self): +@@ -131,7 +132,7 @@ class uploadTestCase(BasePyPIRCCommandTestCase): # what did we send ? headers = dict(self.last_open.req.headers) @@ -4431,7 +4957,7 @@ index f720a7905dd8..a198b213577b 100644 # only sha256 hash is used self.assertEqual(headers['Content-length'], '2197') else: -@@ -172,7 +173,7 @@ def test_upload_correct_cr(self): +@@ -172,7 +173,7 @@ class uploadTestCase(BasePyPIRCCommandTestCase): cmd.run() headers = dict(self.last_open.req.headers) @@ -4441,10 +4967,10 @@ index f720a7905dd8..a198b213577b 100644 self.assertEqual(headers['Content-length'], '2207') else: diff --git a/Lib/hashlib.py b/Lib/hashlib.py -index cd3b035b1d76..3e9a4aa27a79 100644 +index cd3b035b1d7..3e9a4aa27a7 100644 --- a/Lib/hashlib.py +++ b/Lib/hashlib.py -@@ -68,13 +68,13 @@ +@@ -68,13 +68,13 @@ __all__ = __always_supported + ('new', 'algorithms_guaranteed', 'algorithms_available', 'pbkdf2_hmac') try: @@ -4461,7 +4987,7 @@ index cd3b035b1d76..3e9a4aa27a79 100644 __builtin_constructor_cache = {} def __get_builtin_constructor(name): -@@ -121,7 +121,7 @@ def __get_builtin_constructor(name): +@@ -121,7 +121,7 @@ if not get_fips_mode(): def __get_openssl_constructor(name): @@ -4515,7 +5041,7 @@ index cd3b035b1d76..3e9a4aa27a79 100644 raise return __get_builtin_constructor(name)(data) -@@ -197,7 +197,7 @@ def __hash_new(name, data=b'', **kwargs): +@@ -197,7 +197,7 @@ try: algorithms_available = algorithms_available.union( _hashlib.openssl_md_meth_names) except ImportError: @@ -4524,7 +5050,7 @@ index cd3b035b1d76..3e9a4aa27a79 100644 raise new = __py_new __get_hash = __get_builtin_constructor -@@ -225,5 +225,6 @@ def __hash_new(name, data=b'', **kwargs): +@@ -225,5 +225,6 @@ for __func_name in __always_supported: # Cleanup locals() del __always_supported, __func_name, __get_hash del __hash_new, __get_openssl_constructor @@ -4533,10 +5059,10 @@ index cd3b035b1d76..3e9a4aa27a79 100644 del __py_new +del _hashlib_get_fips_mode diff --git a/Lib/hmac.py b/Lib/hmac.py -index 33b5be613d96..ca83d9dc0d35 100644 +index 33b5be613d9..ca83d9dc0d3 100644 --- a/Lib/hmac.py +++ b/Lib/hmac.py -@@ -39,7 +39,7 @@ def __init__(self, key, msg = None, digestmod = None): +@@ -39,7 +39,7 @@ class HMAC: Note: key and msg must be a bytes or bytearray objects. """ @@ -4545,7 +5071,7 @@ index 33b5be613d96..ca83d9dc0d35 100644 raise ValueError( 'This class is not available in FIPS mode. ' + 'Use hmac.new().' -@@ -97,7 +97,7 @@ def name(self): +@@ -97,7 +97,7 @@ class HMAC: def update(self, msg): """Update this hashing object with the string msg. """ @@ -4554,7 +5080,7 @@ index 33b5be613d96..ca83d9dc0d35 100644 raise ValueError('hmac.HMAC is not available in FIPS mode') self.inner.update(msg) -@@ -167,7 +167,7 @@ def __new__(cls, key, msg = None, digestmod = None): +@@ -167,7 +167,7 @@ class HMAC_openssl(_hmacopenssl.HMAC): return result @@ -4564,10 +5090,10 @@ index 33b5be613d96..ca83d9dc0d35 100644 diff --git a/Lib/test/test_fips.py b/Lib/test/test_fips.py -index 34812e6098ae..86e61e29c0b4 100644 +index 34812e6098a..86e61e29c0b 100644 --- a/Lib/test/test_fips.py +++ b/Lib/test/test_fips.py -@@ -6,7 +6,7 @@ +@@ -6,7 +6,7 @@ import hashlib, _hashlib class HashlibFipsTests(unittest.TestCase): @@ -4576,7 +5102,7 @@ index 34812e6098ae..86e61e29c0b4 100644 def test_fips_imports(self): """blake2s and blake2b should fail to import in FIPS mode """ -@@ -30,7 +30,7 @@ def compare_hashes(self, python_hash, openssl_hash): +@@ -30,7 +30,7 @@ class HashlibFipsTests(unittest.TestCase): self.assertEqual(m, h) @@ -4585,7 +5111,7 @@ index 34812e6098ae..86e61e29c0b4 100644 def test_blake2_hashes(self): self.compare_hashes(hashlib.blake2b(b'abc'), _hashlib.openssl_blake2b(b'abc')) self.compare_hashes(hashlib.blake2s(b'abc'), _hashlib.openssl_blake2s(b'abc')) -@@ -41,7 +41,7 @@ def test_sha3_hashes(self): +@@ -41,7 +41,7 @@ class HashlibFipsTests(unittest.TestCase): self.compare_hashes(hashlib.sha3_384(b'abc'), _hashlib.openssl_sha3_384(b'abc')) self.compare_hashes(hashlib.sha3_512(b'abc'), _hashlib.openssl_sha3_512(b'abc')) @@ -4595,10 +5121,10 @@ index 34812e6098ae..86e61e29c0b4 100644 self.compare_hashes(hashlib.shake_128(b'abc'), _hashlib.openssl_shake_128(b'abc')) self.compare_hashes(hashlib.shake_256(b'abc'), _hashlib.openssl_shake_256(b'abc')) diff --git a/Lib/test/test_hashlib.py b/Lib/test/test_hashlib.py -index b359c4fb14a9..eadfb7968be8 100644 +index 19a2fbdf294..a6f9a353fd1 100644 --- a/Lib/test/test_hashlib.py +++ b/Lib/test/test_hashlib.py -@@ -30,7 +30,9 @@ +@@ -32,7 +32,9 @@ COMPILED_WITH_PYDEBUG = hasattr(sys, 'gettotalrefcount') c_hashlib = import_fresh_module('hashlib', fresh=['_hashlib']) py_hashlib = import_fresh_module('hashlib', blocked=['_hashlib']) @@ -4609,7 +5135,7 @@ index b359c4fb14a9..eadfb7968be8 100644 FIPS_UNAVAILABLE = {'blake2b', 'blake2s'} FIPS_DISABLED = {'md5', 'MD5', *FIPS_UNAVAILABLE} else: -@@ -101,7 +103,7 @@ class HashLibTestCase(unittest.TestCase): +@@ -103,7 +105,7 @@ class HashLibTestCase(unittest.TestCase): # Issue #14693: fallback modules are always compiled under POSIX _warn_on_extension_import = os.name == 'posix' or COMPILED_WITH_PYDEBUG @@ -4618,7 +5144,7 @@ index b359c4fb14a9..eadfb7968be8 100644 shakes = set() def _conditional_import_module(self, module_name): -@@ -112,7 +114,7 @@ def _conditional_import_module(self, module_name): +@@ -114,7 +116,7 @@ class HashLibTestCase(unittest.TestCase): if self._warn_on_extension_import: warnings.warn('Did a C extension fail to compile? %s' % error) except ImportError as error: @@ -4627,7 +5153,7 @@ index b359c4fb14a9..eadfb7968be8 100644 raise return None -@@ -236,12 +238,12 @@ def test_unknown_hash(self): +@@ -239,12 +241,12 @@ class HashLibTestCase(unittest.TestCase): self.assertRaises(ValueError, hashlib.new, 'spam spam spam spam spam') self.assertRaises(TypeError, hashlib.new, 1) @@ -4642,7 +5168,7 @@ index b359c4fb14a9..eadfb7968be8 100644 def test_get_builtin_constructor(self): get_builtin_constructor = getattr(hashlib, '__get_builtin_constructor') -@@ -430,7 +432,7 @@ def check_blocksize_name(self, name, block_size=0, digest_size=0, +@@ -433,7 +435,7 @@ class HashLibTestCase(unittest.TestCase): self.assertIn(name.split("_")[0], repr(m)) def test_blocksize_name(self): @@ -4651,7 +5177,7 @@ index b359c4fb14a9..eadfb7968be8 100644 self.check_blocksize_name('md5', 64, 16) self.check_blocksize_name('sha1', 64, 20) self.check_blocksize_name('sha224', 64, 28) -@@ -917,7 +919,7 @@ def hash_in_chunks(chunk_size): +@@ -920,7 +922,7 @@ class HashLibTestCase(unittest.TestCase): self.assertEqual(expected_hash, hasher.hexdigest()) @@ -4661,145 +5187,91 @@ index b359c4fb14a9..eadfb7968be8 100644 """Make sure usedforsecurity flag isn't copied to other contexts""" for i in range(3): diff --git a/Lib/test/test_hmac.py b/Lib/test/test_hmac.py -index 17ffcf37eb14..7fbbe057d736 100644 +index 449b1366314..35b893509cb 100644 --- a/Lib/test/test_hmac.py +++ b/Lib/test/test_hmac.py -@@ -3,6 +3,7 @@ +@@ -3,6 +3,7 @@ import hmac import hashlib import unittest import warnings +from _hashlib import get_fips_mode + from test.support import requires_hashdigest - def ignore_warning(func): -@@ -17,7 +18,7 @@ def wrapper(*args, **kwargs): - - class TestVectorsTestCase(unittest.TestCase): - -- @unittest.skipIf(hashlib.get_fips_mode(), 'md5 unacceptable in FIPS mode.') -+ @unittest.skipIf(get_fips_mode(), 'md5 unacceptable in FIPS mode.') - def test_md5_vectors(self): - # Test the HMAC module against test vectors from the RFC. - -@@ -243,7 +244,7 @@ def test_sha384_rfc4231(self): +@@ -250,7 +251,7 @@ class TestVectorsTestCase(unittest.TestCase): def test_sha512_rfc4231(self): self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128) - @unittest.skipIf(hashlib.get_fips_mode(), 'MockCrazyHash unacceptable in FIPS mode.') + @unittest.skipIf(get_fips_mode(), 'MockCrazyHash unacceptable in FIPS mode.') + @requires_hashdigest('sha256') def test_legacy_block_size_warnings(self): class MockCrazyHash(object): - """Ain't no block_size attribute here.""" -@@ -266,7 +267,7 @@ def digest(self): +@@ -274,6 +275,7 @@ class TestVectorsTestCase(unittest.TestCase): hmac.HMAC(b'a', b'b', digestmod=MockCrazyHash) self.fail('Expected warning about small block_size') -- @unittest.skipIf(hashlib.get_fips_mode(), 'md5 is not default in FIPS mode.') + @unittest.skipIf(get_fips_mode(), 'md5 is not default in FIPS mode.') def test_with_digestmod_warning(self): with self.assertWarns(PendingDeprecationWarning): key = b"\x0b" * 16 -@@ -278,7 +279,7 @@ def test_with_digestmod_warning(self): - - class ConstructorTestCase(unittest.TestCase): - -- @unittest.skipIf(hashlib.get_fips_mode(), 'md5 is not default in FIPS mode.') -+ @unittest.skipIf(get_fips_mode(), 'md5 is not default in FIPS mode.') - @ignore_warning - def test_normal(self): - # Standard constructor call. -@@ -343,7 +344,7 @@ def test_withmodule(self): - - class SanityTestCase(unittest.TestCase): - -- @unittest.skipIf(hashlib.get_fips_mode(), "md5 is not default in FIPS mode") -+ @unittest.skipIf(get_fips_mode(), "md5 is not default in FIPS mode") - @ignore_warning - def test_default_is_md5(self): - # Testing if HMAC defaults to MD5 algorithm. -@@ -365,7 +366,7 @@ def test_exercise_all_methods(self): +@@ -375,7 +377,7 @@ class SanityTestCase(unittest.TestCase): class CopyTestCase(unittest.TestCase): - @unittest.skipIf(hashlib.get_fips_mode(), "Internal attributes unavailable in FIPS mode") + @unittest.skipIf(get_fips_mode(), "Internal attributes unavailable in FIPS mode") + @requires_hashdigest('sha256') def test_attributes(self): # Testing if attributes are of same type. - h1 = hmac.HMAC(b"key", digestmod="sha1") -@@ -377,7 +378,7 @@ def test_attributes(self): +@@ -388,7 +390,7 @@ class CopyTestCase(unittest.TestCase): self.assertEqual(type(h1.outer), type(h2.outer), "Types of outer don't match.") - @unittest.skipIf(hashlib.get_fips_mode(), "Internal attributes unavailable in FIPS mode") + @unittest.skipIf(get_fips_mode(), "Internal attributes unavailable in FIPS mode") + @requires_hashdigest('sha256') def test_realcopy(self): # Testing if the copy method created a real copy. - h1 = hmac.HMAC(b"key", digestmod="sha1") diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py -index 0b229465983c..0028ae05a1b5 100644 +index d5c63b483ee..45b72e3bc7e 100644 --- a/Lib/test/test_logging.py +++ b/Lib/test/test_logging.py -@@ -47,6 +47,7 @@ +@@ -46,6 +46,7 @@ import time + import unittest import warnings import weakref - import hashlib -+from _hashlib import get_fips_mode - ++ try: import threading -@@ -1817,7 +1818,7 @@ def handle_request(self, request): - request.end_headers() - self.handled.set() - -- @unittest.skipIf(hashlib.get_fips_mode(), 'Hangs in FIPS mode.') -+ @unittest.skipIf(get_fips_mode(), 'Hangs in FIPS mode.') - def test_output(self): - # The log message sent to the HTTPHandler is properly received. - logger = logging.getLogger("http") + # The following imports are needed only for tests which diff --git a/Lib/test/test_smtplib.py b/Lib/test/test_smtplib.py -index 150e9fbcf053..987b114f99ef 100644 +index 64b3201254a..704b2bc0d35 100644 --- a/Lib/test/test_smtplib.py +++ b/Lib/test/test_smtplib.py -@@ -16,6 +16,7 @@ +@@ -16,6 +16,8 @@ import time + import select import errno import textwrap - import hashlib ++import hashlib +from _hashlib import get_fips_mode import unittest from test import support, mock_socket -@@ -969,7 +970,7 @@ def testAUTH_LOGIN(self): - self.assertEqual(resp, (235, b'Authentication Succeeded')) - smtp.close() - -- @unittest.skipIf(hashlib.get_fips_mode(), "md5 auth unacceptable in FIPS mode") -+ @unittest.skipIf(get_fips_mode(), "md5 auth unacceptable in FIPS mode") - def testAUTH_CRAM_MD5(self): - self.serv.add_feature("AUTH CRAM-MD5") - smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) -@@ -977,7 +978,7 @@ def testAUTH_CRAM_MD5(self): - self.assertEqual(resp, (235, b'Authentication Succeeded')) - smtp.close() +@@ -980,7 +982,7 @@ class SMTPSimTests(unittest.TestCase): -- @unittest.skipIf(hashlib.get_fips_mode(), "md5 auth unacceptable in FIPS mode") -+ @unittest.skipIf(get_fips_mode(), "md5 auth unacceptable in FIPS mode") def testAUTH_multiple(self): # Test that multiple authentication methods are tried. - self.serv.add_feature("AUTH BOGUS PLAIN LOGIN CRAM-MD5") -@@ -986,7 +987,7 @@ def testAUTH_multiple(self): +- self.serv.add_feature("AUTH BOGUS PLAIN LOGIN CRAM-MD5") ++ self.serv.add_feature("AUTH BOGUS PLAIN LOGIN") + smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15) + resp = smtp.login(sim_auth[0], sim_auth[1]) self.assertEqual(resp, (235, b'Authentication Succeeded')) - smtp.close() - -- @unittest.skipIf(hashlib.get_fips_mode(), "md5 auth unacceptable in FIPS mode") -+ @unittest.skipIf(get_fips_mode(), "md5 auth unacceptable in FIPS mode") - def test_auth_function(self): - supported = {'CRAM-MD5', 'PLAIN', 'LOGIN'} - for mechanism in supported: diff --git a/Lib/test/test_tools/test_md5sum.py b/Lib/test/test_tools/test_md5sum.py -index 7028a4dc2143..3ba1ca0f146c 100644 +index 7028a4dc214..3ba1ca0f146 100644 --- a/Lib/test/test_tools/test_md5sum.py +++ b/Lib/test/test_tools/test_md5sum.py -@@ -4,13 +4,13 @@ +@@ -4,13 +4,13 @@ import os import unittest from test import support from test.support.script_helper import assert_python_ok, assert_python_failure @@ -4816,10 +5288,10 @@ index 7028a4dc2143..3ba1ca0f146c 100644 class MD5SumTests(unittest.TestCase): diff --git a/Lib/test/test_urllib2_localnet.py b/Lib/test/test_urllib2_localnet.py -index 2d0d62f610ef..84831ab2ac0e 100644 +index 895f97cc09a..b4fb13ad092 100644 --- a/Lib/test/test_urllib2_localnet.py +++ b/Lib/test/test_urllib2_localnet.py -@@ -6,6 +6,7 @@ +@@ -6,6 +6,7 @@ import urllib.request import http.server import unittest import hashlib @@ -4827,99 +5299,273 @@ index 2d0d62f610ef..84831ab2ac0e 100644 from test import support -@@ -317,7 +318,7 @@ def test_basic_auth_httperror(self): - self.assertRaises(urllib.error.HTTPError, urllib.request.urlopen, self.server_url) - - --@unittest.skipIf(hashlib.get_fips_mode(), "md5 digest auth unacceptable in FIPS mode") -+@unittest.skipIf(get_fips_mode(), "md5 digest auth unacceptable in FIPS mode") - @unittest.skipUnless(threading, "Threading required for this test.") - class ProxyAuthTests(unittest.TestCase): - URL = "http://localhost" +-- +2.21.0 -From 60afcf719206757577b6fc8c6ea119e02130a0f4 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Thu, 29 Aug 2019 10:25:28 +0200 -Subject: [PATCH 35/36] Skip error checking in _hashlib.get_fips_mode -Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1745499 +From 3538f31cc15c633f1df2d6ed18471c1f771c4a52 Mon Sep 17 00:00:00 2001 +From: Christian Heimes +Date: Wed, 20 Nov 2019 10:59:25 +0100 +Subject: [PATCH 35/36] Use FIPS compliant CSPRNG + +Kernel's getrandom() source is not yet FIPS compliant. Use OpenSSL's +DRBG in FIPS mode and disable os.getrandom() function. + +Signed-off-by: Christian Heimes --- - Modules/_hashopenssl.c | 30 ++++++++++++++++-------------- - 1 file changed, 16 insertions(+), 14 deletions(-) + Lib/test/test_os.py | 5 +++ + Makefile.pre.in | 2 +- + Modules/posixmodule.c | 8 +++++ + Python/random.c | 75 +++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 89 insertions(+), 1 deletion(-) -diff --git a/Modules/_hashopenssl.c b/Modules/_hashopenssl.c -index b621c330c32d..6bfb12c5618b 100644 ---- a/Modules/_hashopenssl.c -+++ b/Modules/_hashopenssl.c -@@ -1021,20 +1021,22 @@ static PyObject * - _hashlib_get_fips_mode_impl(PyObject *module) - /*[clinic end generated code: output=ad8a7793310d3f98 input=f42a2135df2a5e11]*/ - { -- int result = FIPS_mode(); -- if (result == 0) { -- // "If the library was built without support of the FIPS Object Module, -- // then the function will return 0 with an error code of -- // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." -- // But 0 is also a valid result value. -- -- unsigned long errcode = ERR_peek_last_error(); -- if (errcode) { -- _setException(PyExc_ValueError); -- return NULL; -- } -- } -- return PyLong_FromLong(result); -+ // XXX: This function skips error checking. -+ // This is only appropriate for RHEL. -+ -+ // From the OpenSSL docs: -+ // "If the library was built without support of the FIPS Object Module, -+ // then the function will return 0 with an error code of -+ // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." -+ // In RHEL: -+ // * we do build with FIPS, so the function always succeeds -+ // * even if it didn't, people seem used to errors being left on the -+ // OpenSSL error stack. +diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py +index 7a839c83fe4..91816afa47d 100644 +--- a/Lib/test/test_os.py ++++ b/Lib/test/test_os.py +@@ -1362,6 +1362,11 @@ class GetRandomTests(unittest.TestCase): + raise unittest.SkipTest("getrandom() syscall fails with ENOSYS") + else: + raise ++ except ValueError as exc: ++ if exc.args[0] == "getrandom is not FIPS compliant": ++ raise unittest.SkipTest("Skip in FIPS mode") ++ else: ++ raise + + def test_getrandom_type(self): + data = os.getrandom(16) +diff --git a/Makefile.pre.in b/Makefile.pre.in +index d15d93509d1..40502fc36d6 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -112,7 +112,7 @@ CFLAGSFORSHARED=@CFLAGSFORSHARED@ + # C flags used for building the interpreter object files + PY_CORE_CFLAGS= $(PY_CFLAGS) $(PY_CFLAGS_NODIST) $(PY_CPPFLAGS) $(CFLAGSFORSHARED) -DPy_BUILD_CORE + # Linker flags used for building the interpreter object files +-PY_CORE_LDFLAGS=$(PY_LDFLAGS) $(PY_LDFLAGS_NODIST) ++PY_CORE_LDFLAGS=$(PY_LDFLAGS) $(PY_LDFLAGS_NODIST) -lcrypto + # Strict or non-strict aliasing flags used to compile dtoa.c, see above + CFLAGS_ALIASING=@CFLAGS_ALIASING@ + +diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c +index 776a3d249a8..647dbd3b4d6 100644 +--- a/Modules/posixmodule.c ++++ b/Modules/posixmodule.c +@@ -397,6 +397,9 @@ static int win32_can_symlink = 0; + #define MODNAME "posix" + #endif + ++/* for FIPS check in os.getrandom() */ ++#include + -+ // For more info, see: -+ // https://bugzilla.redhat.com/show_bug.cgi?id=1745499 + #ifdef MS_WINDOWS + /* defined in fileutils.c */ + PyAPI_FUNC(void) _Py_time_t_to_FILE_TIME(time_t, int, FILETIME *); +@@ -12196,6 +12199,11 @@ os_getrandom_impl(PyObject *module, Py_ssize_t size, int flags) + return posix_error(); + } + ++ if (FIPS_mode()) { ++ PyErr_SetString(PyExc_ValueError, "getrandom is not FIPS compliant"); ++ return NULL; ++ } + -+ return PyLong_FromLong(FIPS_mode()); + bytes = PyBytes_FromStringAndSize(NULL, size); + if (bytes == NULL) { + PyErr_NoMemory(); +diff --git a/Python/random.c b/Python/random.c +index d4747d61eb8..ab3cee29a39 100644 +--- a/Python/random.c ++++ b/Python/random.c +@@ -410,6 +410,77 @@ dev_urandom_close(void) } + #endif /* !MS_WINDOWS */ + ++#include ++#include ++#include ++ ++#if (OPENSSL_VERSION_NUMBER < 0x10101000L) || defined(LIBRESSL_VERSION_NUMBER) ++# error "py_openssl_drbg_urandom requires OpenSSL 1.1.1 for fork safety" ++#endif ++ ++static void ++py_openssl_set_exception(PyObject* exc) { ++ unsigned long errcode; ++ const char *lib, *func, *reason; ++ ++ errcode = ERR_peek_last_error(); ++ if (!errcode) { ++ PyErr_SetString(exc, "unknown reasons"); ++ } ++ ERR_clear_error(); ++ ++ lib = ERR_lib_error_string(errcode); ++ func = ERR_func_error_string(errcode); ++ reason = ERR_reason_error_string(errcode); ++ ++ if (lib && func) { ++ PyErr_Format(exc, "[%s: %s] %s", lib, func, reason); ++ } ++ else if (lib) { ++ PyErr_Format(exc, "[%s] %s", lib, reason); ++ } ++ else { ++ PyErr_SetString(exc, reason); ++ } ++} ++ ++static int ++py_openssl_drbg_urandom(char *buffer, Py_ssize_t size, int raise) ++{ ++ int res; ++ static int init = 0; ++ ++ if (!init) { ++ init = 1; ++ res = OPENSSL_init_crypto(OPENSSL_INIT_ATFORK, NULL); ++ if (res == 0) { ++ if (raise) { ++ py_openssl_set_exception(PyExc_RuntimeError); ++ } ++ return 0; ++ } ++ } ++ ++ if (size > INT_MAX) { ++ if (raise) { ++ PyErr_Format(PyExc_OverflowError, ++ "RAND_bytes() size is limited to 2GB."); ++ } ++ return -1; ++ } ++ ++ res = RAND_bytes((unsigned char*)buffer, (int)size); ++ ++ if (res == 1) { ++ return 1; ++ } else { ++ if (raise) { ++ py_openssl_set_exception(PyExc_RuntimeError); ++ } ++ return 0; ++ } ++} ++ + /* Fill buffer with pseudo-random bytes generated by a linear congruent + generator (LCG): +@@ -494,6 +565,10 @@ pyurandom(void *buffer, Py_ssize_t size, int blocking, int raise) + return 0; + } -From 68b3c51d9c7d6bb635174e8d02db5c73ab521ea0 Mon Sep 17 00:00:00 2001 -From: Petr Viktorin -Date: Thu, 10 Oct 2019 13:04:50 +0200 -Subject: [PATCH] Skip error checking in _Py_hashlib_fips_error ++ if (FIPS_mode()) { ++ return py_openssl_drbg_urandom(buffer, size, raise); ++ } ++ + #ifdef MS_WINDOWS + return win32_urandom((unsigned char *)buffer, size, raise); + #else +-- +2.21.0 + + +From ed4103bbd15a09bff4fb94a38d1b3f02df5e7c96 Mon Sep 17 00:00:00 2001 +From: Charalampos Stratakis +Date: Thu, 28 Nov 2019 17:26:02 +0100 +Subject: [PATCH 36/36] Fixups for FIPS compliant CSPRNG -https://bugzilla.redhat.com/show_bug.cgi?id=1760106 --- - Include/_hashopenssl.h | 12 +++--------- - 1 file changed, 3 insertions(+), 9 deletions(-) + Lib/test/test_os.py | 3 ++- + Python/random.c | 33 +++------------------------------ + 2 files changed, 5 insertions(+), 31 deletions(-) -diff --git a/Include/_hashopenssl.h b/Include/_hashopenssl.h -index 47ed003042209..d4cbdef984d83 100644 ---- a/Include/_hashopenssl.h -+++ b/Include/_hashopenssl.h -@@ -42,16 +42,10 @@ static int - _Py_hashlib_fips_error(PyObject *exc, char *name) { - int result = FIPS_mode(); - if (result == 0) { -- // "If the library was built without support of the FIPS Object Module, -- // then the function will return 0 with an error code of -- // CRYPTO_R_FIPS_MODE_NOT_SUPPORTED (0x0f06d065)." -- // But 0 is also a valid result value. -+ // XXX: This function skips error checking. -+ // This is only appropriate for RHEL. -+ // See _hashlib.get_fips_mode for details. +diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py +index 91816afa47d..f2572bb6c44 100644 +--- a/Lib/test/test_os.py ++++ b/Lib/test/test_os.py +@@ -27,6 +27,7 @@ import time + import unittest + import uuid + import warnings ++from _hashlib import get_fips_mode + from test import support + try: + import threading +@@ -1363,7 +1364,7 @@ class GetRandomTests(unittest.TestCase): + else: + raise + except ValueError as exc: +- if exc.args[0] == "getrandom is not FIPS compliant": ++ if get_fips_mode() and exc.args[0] == "getrandom is not FIPS compliant": + raise unittest.SkipTest("Skip in FIPS mode") + else: + raise +diff --git a/Python/random.c b/Python/random.c +index ab3cee29a39..222d651407c 100644 +--- a/Python/random.c ++++ b/Python/random.c +@@ -410,40 +410,13 @@ dev_urandom_close(void) + } + #endif /* !MS_WINDOWS */ -- unsigned long errcode = ERR_peek_last_error(); -- if (errcode) { -- _setException(exc); -- return 1; -- } +-#include +-#include + #include ++#include <_hashopenssl.h> + + #if (OPENSSL_VERSION_NUMBER < 0x10101000L) || defined(LIBRESSL_VERSION_NUMBER) + # error "py_openssl_drbg_urandom requires OpenSSL 1.1.1 for fork safety" + #endif + +-static void +-py_openssl_set_exception(PyObject* exc) { +- unsigned long errcode; +- const char *lib, *func, *reason; +- +- errcode = ERR_peek_last_error(); +- if (!errcode) { +- PyErr_SetString(exc, "unknown reasons"); +- } +- ERR_clear_error(); +- +- lib = ERR_lib_error_string(errcode); +- func = ERR_func_error_string(errcode); +- reason = ERR_reason_error_string(errcode); +- +- if (lib && func) { +- PyErr_Format(exc, "[%s: %s] %s", lib, func, reason); +- } +- else if (lib) { +- PyErr_Format(exc, "[%s] %s", lib, reason); +- } +- else { +- PyErr_SetString(exc, reason); +- } +-} +- + static int + py_openssl_drbg_urandom(char *buffer, Py_ssize_t size, int raise) + { +@@ -455,7 +428,7 @@ py_openssl_drbg_urandom(char *buffer, Py_ssize_t size, int raise) + res = OPENSSL_init_crypto(OPENSSL_INIT_ATFORK, NULL); + if (res == 0) { + if (raise) { +- py_openssl_set_exception(PyExc_RuntimeError); ++ _setException(PyExc_RuntimeError); + } + return 0; + } +@@ -475,7 +448,7 @@ py_openssl_drbg_urandom(char *buffer, Py_ssize_t size, int raise) + return 1; + } else { + if (raise) { +- py_openssl_set_exception(PyExc_RuntimeError); ++ _setException(PyExc_RuntimeError); + } return 0; } - PyErr_Format(exc, "%s is not available in FIPS mode", name); +-- +2.21.0 diff --git a/SOURCES/00330-CVE-2018-20852.patch b/SOURCES/00330-CVE-2018-20852.patch new file mode 100644 index 0000000..380fc33 --- /dev/null +++ b/SOURCES/00330-CVE-2018-20852.patch @@ -0,0 +1,93 @@ +diff --git a/Lib/http/cookiejar.py b/Lib/http/cookiejar.py +index adf956d..97599d4 100644 +--- a/Lib/http/cookiejar.py ++++ b/Lib/http/cookiejar.py +@@ -1148,6 +1148,11 @@ class DefaultCookiePolicy(CookiePolicy): + req_host, erhn = eff_request_host(request) + domain = cookie.domain + ++ if domain and not domain.startswith("."): ++ dotdomain = "." + domain ++ else: ++ dotdomain = domain ++ + # strict check of non-domain cookies: Mozilla does this, MSIE5 doesn't + if (cookie.version == 0 and + (self.strict_ns_domain & self.DomainStrictNonDomain) and +@@ -1160,7 +1165,7 @@ class DefaultCookiePolicy(CookiePolicy): + _debug(" effective request-host name %s does not domain-match " + "RFC 2965 cookie domain %s", erhn, domain) + return False +- if cookie.version == 0 and not ("."+erhn).endswith(domain): ++ if cookie.version == 0 and not ("."+erhn).endswith(dotdomain): + _debug(" request-host %s does not match Netscape cookie domain " + "%s", req_host, domain) + return False +@@ -1174,7 +1179,11 @@ class DefaultCookiePolicy(CookiePolicy): + req_host = "."+req_host + if not erhn.startswith("."): + erhn = "."+erhn +- if not (req_host.endswith(domain) or erhn.endswith(domain)): ++ if domain and not domain.startswith("."): ++ dotdomain = "." + domain ++ else: ++ dotdomain = domain ++ if not (req_host.endswith(dotdomain) or erhn.endswith(dotdomain)): + #_debug(" request domain %s does not match cookie domain %s", + # req_host, domain) + return False +diff --git a/Lib/test/test_http_cookiejar.py b/Lib/test/test_http_cookiejar.py +index abc625d..6e1b308 100644 +--- a/Lib/test/test_http_cookiejar.py ++++ b/Lib/test/test_http_cookiejar.py +@@ -415,6 +415,7 @@ class CookieTests(unittest.TestCase): + ("http://foo.bar.com/", ".foo.bar.com", True), + ("http://foo.bar.com/", "foo.bar.com", True), + ("http://foo.bar.com/", ".bar.com", True), ++ ("http://foo.bar.com/", "bar.com", True), + ("http://foo.bar.com/", "com", True), + ("http://foo.com/", "rhubarb.foo.com", False), + ("http://foo.com/", ".foo.com", True), +@@ -425,6 +426,8 @@ class CookieTests(unittest.TestCase): + ("http://foo/", "foo", True), + ("http://foo/", "foo.local", True), + ("http://foo/", ".local", True), ++ ("http://barfoo.com", ".foo.com", False), ++ ("http://barfoo.com", "foo.com", False), + ]: + request = urllib.request.Request(url) + r = pol.domain_return_ok(domain, request) +@@ -959,6 +962,33 @@ class CookieTests(unittest.TestCase): + c.add_cookie_header(req) + self.assertFalse(req.has_header("Cookie")) + ++ c.clear() ++ ++ pol.set_blocked_domains([]) ++ req = urllib.request.Request("http://acme.com/") ++ res = FakeResponse(headers, "http://acme.com/") ++ cookies = c.make_cookies(res, req) ++ c.extract_cookies(res, req) ++ self.assertEqual(len(c), 1) ++ ++ req = urllib.request.Request("http://acme.com/") ++ c.add_cookie_header(req) ++ self.assertTrue(req.has_header("Cookie")) ++ ++ req = urllib.request.Request("http://badacme.com/") ++ c.add_cookie_header(req) ++ self.assertFalse(pol.return_ok(cookies[0], req)) ++ self.assertFalse(req.has_header("Cookie")) ++ ++ p = pol.set_blocked_domains(["acme.com"]) ++ req = urllib.request.Request("http://acme.com/") ++ c.add_cookie_header(req) ++ self.assertFalse(req.has_header("Cookie")) ++ ++ req = urllib.request.Request("http://badacme.com/") ++ c.add_cookie_header(req) ++ self.assertFalse(req.has_header("Cookie")) ++ + def test_secure(self): + for ns in True, False: + for whitespace in " ", "": diff --git a/SOURCES/00332-CVE-2019-16056.patch b/SOURCES/00332-CVE-2019-16056.patch new file mode 100644 index 0000000..ca2e3d4 --- /dev/null +++ b/SOURCES/00332-CVE-2019-16056.patch @@ -0,0 +1,95 @@ +diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py +index 737951e4b1b1..bc9c9b6241d4 100644 +--- a/Lib/email/_header_value_parser.py ++++ b/Lib/email/_header_value_parser.py +@@ -1561,6 +1561,8 @@ def get_domain(value): + token, value = get_dot_atom(value) + except errors.HeaderParseError: + token, value = get_atom(value) ++ if value and value[0] == '@': ++ raise errors.HeaderParseError('Invalid Domain') + if leader is not None: + token[:0] = [leader] + domain.append(token) +diff --git a/Lib/email/_parseaddr.py b/Lib/email/_parseaddr.py +index cdfa3729adc7..41ff6f8c000d 100644 +--- a/Lib/email/_parseaddr.py ++++ b/Lib/email/_parseaddr.py +@@ -379,7 +379,12 @@ def getaddrspec(self): + aslist.append('@') + self.pos += 1 + self.gotonext() +- return EMPTYSTRING.join(aslist) + self.getdomain() ++ domain = self.getdomain() ++ if not domain: ++ # Invalid domain, return an empty address instead of returning a ++ # local part to denote failed parsing. ++ return EMPTYSTRING ++ return EMPTYSTRING.join(aslist) + domain + + def getdomain(self): + """Get the complete domain name from an address.""" +@@ -394,6 +399,10 @@ def getdomain(self): + elif self.field[self.pos] == '.': + self.pos += 1 + sdlist.append('.') ++ elif self.field[self.pos] == '@': ++ # bpo-34155: Don't parse domains with two `@` like ++ # `a@malicious.org@important.com`. ++ return EMPTYSTRING + elif self.field[self.pos] in self.atomends: + break + else: +diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py +index a2c900fa7fd2..02ef3e1006c6 100644 +--- a/Lib/test/test_email/test__header_value_parser.py ++++ b/Lib/test/test_email/test__header_value_parser.py +@@ -1418,6 +1418,16 @@ def test_get_addr_spec_dot_atom(self): + self.assertEqual(addr_spec.domain, 'example.com') + self.assertEqual(addr_spec.addr_spec, 'star.a.star@example.com') + ++ def test_get_addr_spec_multiple_domains(self): ++ with self.assertRaises(errors.HeaderParseError): ++ parser.get_addr_spec('star@a.star@example.com') ++ ++ with self.assertRaises(errors.HeaderParseError): ++ parser.get_addr_spec('star@a@example.com') ++ ++ with self.assertRaises(errors.HeaderParseError): ++ parser.get_addr_spec('star@172.17.0.1@example.com') ++ + # get_obs_route + + def test_get_obs_route_simple(self): +diff --git a/Lib/test/test_email/test_email.py b/Lib/test/test_email/test_email.py +index f97ccc6711cc..68d052279987 100644 +--- a/Lib/test/test_email/test_email.py ++++ b/Lib/test/test_email/test_email.py +@@ -3035,6 +3035,20 @@ def test_parseaddr_empty(self): + self.assertEqual(utils.parseaddr('<>'), ('', '')) + self.assertEqual(utils.formataddr(utils.parseaddr('<>')), '') + ++ def test_parseaddr_multiple_domains(self): ++ self.assertEqual( ++ utils.parseaddr('a@b@c'), ++ ('', '') ++ ) ++ self.assertEqual( ++ utils.parseaddr('a@b.c@c'), ++ ('', '') ++ ) ++ self.assertEqual( ++ utils.parseaddr('a@172.17.0.1@c'), ++ ('', '') ++ ) ++ + def test_noquote_dump(self): + self.assertEqual( + utils.formataddr(('A Silly Person', 'person@dom.ain')), +diff --git a/Misc/NEWS.d/next/Security/2019-05-04-13-33-37.bpo-34155.MJll68.rst b/Misc/NEWS.d/next/Security/2019-05-04-13-33-37.bpo-34155.MJll68.rst +new file mode 100644 +index 000000000000..50292e29ed1d +--- /dev/null ++++ b/Misc/NEWS.d/next/Security/2019-05-04-13-33-37.bpo-34155.MJll68.rst +@@ -0,0 +1 @@ ++Fix parsing of invalid email addresses with more than one ``@`` (e.g. a@b@c.com.) to not return the part before 2nd ``@`` as valid email address. Patch by maxking & jpic. diff --git a/SOURCES/00333-reduce-pgo-tests.patch b/SOURCES/00333-reduce-pgo-tests.patch new file mode 100644 index 0000000..7dcd3b9 --- /dev/null +++ b/SOURCES/00333-reduce-pgo-tests.patch @@ -0,0 +1,296 @@ +diff --git a/Lib/test/libregrtest/cmdline.py b/Lib/test/libregrtest/cmdline.py +index 538ff05..e7f2013 100644 +--- a/Lib/test/libregrtest/cmdline.py ++++ b/Lib/test/libregrtest/cmdline.py +@@ -263,7 +263,9 @@ def _create_parser(): + help='only write the name of test cases that will be run' + ' , don\'t execute them') + group.add_argument('-P', '--pgo', dest='pgo', action='store_true', +- help='enable Profile Guided Optimization training') ++ help='enable Profile Guided Optimization (PGO) training') ++ group.add_argument('--pgo-extended', action='store_true', ++ help='enable extended PGO training (slower training)') + group.add_argument('--fail-env-changed', action='store_true', + help='if a test file alters the environment, mark ' + 'the test as failed') +@@ -339,6 +341,8 @@ def _parse_args(args, **kwargs): + parser.error("-G/--failfast needs either -v or -W") + if ns.pgo and (ns.verbose or ns.verbose2 or ns.verbose3): + parser.error("--pgo/-v don't go together!") ++ if ns.pgo_extended: ++ ns.pgo = True # pgo_extended implies pgo + + if ns.nowindows: + print("Warning: the --nowindows (-n) option is deprecated. " +diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py +index b6d05f6..524dbfa 100644 +--- a/Lib/test/libregrtest/main.py ++++ b/Lib/test/libregrtest/main.py +@@ -17,6 +17,7 @@ from test.libregrtest.runtest import ( + INTERRUPTED, CHILD_ERROR, TEST_DID_NOT_RUN, + PROGRESS_MIN_TIME, format_test_result) + from test.libregrtest.setup import setup_tests ++from test.libregrtest.pgo import setup_pgo_tests + from test.libregrtest.utils import removepy, count, format_duration, printlist + from test import support + try: +@@ -214,6 +215,10 @@ class Regrtest: + + removepy(self.tests) + ++ if self.ns.pgo: ++ # add default PGO tests if no tests are specified ++ setup_pgo_tests(self.ns) ++ + stdtests = STDTESTS[:] + nottests = NOTTESTS.copy() + if self.ns.exclude: +@@ -601,6 +606,7 @@ class Regrtest: + input("Press any key to continue...") + + support.PGO = self.ns.pgo ++ support.PGO_EXTENDED = self.ns.pgo_extended + + setup_tests(self.ns) + +diff --git a/Lib/test/libregrtest/pgo.py b/Lib/test/libregrtest/pgo.py +new file mode 100644 +index 0000000..379ff05 +--- /dev/null ++++ b/Lib/test/libregrtest/pgo.py +@@ -0,0 +1,55 @@ ++# Set of tests run by default if --pgo is specified. The tests below were ++# chosen based on the following criteria: either they exercise a commonly used ++# C extension module or type, or they run some relatively typical Python code. ++# Long running tests should be avoided because the PGO instrumented executable ++# runs slowly. ++PGO_TESTS = [ ++ 'test_array', ++ 'test_base64', ++ 'test_binascii', ++ 'test_binop', ++ 'test_bisect', ++ 'test_bytes', ++ 'test_bz2', ++ 'test_cmath', ++ 'test_codecs', ++ 'test_collections', ++ 'test_complex', ++ 'test_dataclasses', ++ 'test_datetime', ++ 'test_decimal', ++ 'test_difflib', ++ 'test_embed', ++ 'test_float', ++ 'test_fstring', ++ 'test_functools', ++ 'test_generators', ++ 'test_hashlib', ++ 'test_heapq', ++ 'test_int', ++ 'test_itertools', ++ 'test_json', ++ 'test_long', ++ 'test_lzma', ++ 'test_math', ++ 'test_memoryview', ++ 'test_operator', ++ 'test_ordered_dict', ++ 'test_pickle', ++ 'test_pprint', ++ 'test_re', ++ 'test_set', ++ 'test_sqlite', ++ 'test_statistics', ++ 'test_struct', ++ 'test_tabnanny', ++ 'test_time', ++ 'test_unicode', ++ 'test_xml_etree', ++ 'test_xml_etree_c', ++] ++ ++def setup_pgo_tests(ns): ++ if not ns.args and not ns.pgo_extended: ++ # run default set of tests for PGO training ++ ns.args = PGO_TESTS[:] +diff --git a/Lib/test/pickletester.py b/Lib/test/pickletester.py +index 764057a..468ee46 100644 +--- a/Lib/test/pickletester.py ++++ b/Lib/test/pickletester.py +@@ -2039,6 +2039,7 @@ class AbstractPickleTests(unittest.TestCase): + + FRAME_SIZE_TARGET = 64 * 1024 + ++ @support.skip_if_pgo_task + def check_frame_opcodes(self, pickled): + """ + Check the arguments of FRAME opcodes in a protocol 4+ pickle. +@@ -2059,6 +2060,7 @@ class AbstractPickleTests(unittest.TestCase): + frame_size = len(pickled) - last_pos - frame_opcode_size + self.assertEqual(frame_size, last_arg) + ++ @support.skip_if_pgo_task + def test_framing_many_objects(self): + obj = list(range(10**5)) + for proto in range(4, pickle.HIGHEST_PROTOCOL + 1): +diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py +index 66c0fed..e80a819 100644 +--- a/Lib/test/support/__init__.py ++++ b/Lib/test/support/__init__.py +@@ -953,6 +953,10 @@ SAVEDCWD = os.getcwd() + # useful for PGO + PGO = False + ++# Set by libregrtest/main.py if we are running the extended (time consuming) ++# PGO task. If this is True, PGO is also True. ++PGO_EXTENDED = False ++ + @contextlib.contextmanager + def temp_dir(path=None, quiet=False): + """Return a context manager that creates a temporary directory. +@@ -2442,6 +2446,11 @@ def skip_unless_xattr(test): + msg = "no non-broken extended attribute support" + return test if ok else unittest.skip(msg)(test) + ++def skip_if_pgo_task(test): ++ """Skip decorator for tests not run in (non-extended) PGO task""" ++ ok = not PGO or PGO_EXTENDED ++ msg = "Not run for (non-extended) PGO task" ++ return test if ok else unittest.skip(msg)(test) + + def fs_is_case_insensitive(directory): + """Detects if the file system for the specified directory is case-insensitive.""" +diff --git a/Lib/test/test_bz2.py b/Lib/test/test_bz2.py +index f340f23..ebb151c 100644 +--- a/Lib/test/test_bz2.py ++++ b/Lib/test/test_bz2.py +@@ -654,6 +654,7 @@ class BZ2CompressorTest(BaseTest): + data += bz2c.flush() + self.assertEqual(ext_decompress(data), self.TEXT) + ++ @support.skip_if_pgo_task + @bigmemtest(size=_4G + 100, memuse=2) + def testCompress4G(self, size): + # "Test BZ2Compressor.compress()/flush() with >4GiB input" +@@ -712,6 +713,7 @@ class BZ2DecompressorTest(BaseTest): + self.assertRaises(EOFError, bz2d.decompress, b"anything") + self.assertRaises(EOFError, bz2d.decompress, b"") + ++ @support.skip_if_pgo_task + @bigmemtest(size=_4G + 100, memuse=3.3) + def testDecompress4G(self, size): + # "Test BZ2Decompressor.decompress() with >4GiB input" +diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py +index 9317951..8c1d016 100644 +--- a/Lib/test/test_itertools.py ++++ b/Lib/test/test_itertools.py +@@ -2023,6 +2023,7 @@ class RegressionTests(unittest.TestCase): + self.assertRaises(AssertionError, list, cycle(gen1())) + self.assertEqual(hist, [0,1]) + ++ @support.skip_if_pgo_task + def test_long_chain_of_empty_iterables(self): + # Make sure itertools.chain doesn't run into recursion limits when + # dealing with long chains of empty iterables. Even with a high +diff --git a/Lib/test/test_lzma.py b/Lib/test/test_lzma.py +index 3dc2c1e..117de0a 100644 +--- a/Lib/test/test_lzma.py ++++ b/Lib/test/test_lzma.py +@@ -333,6 +333,7 @@ class CompressorDecompressorTestCase(unittest.TestCase): + + # Test with inputs larger than 4GiB. + ++ @support.skip_if_pgo_task + @bigmemtest(size=_4G + 100, memuse=2) + def test_compressor_bigmem(self, size): + lzc = LZMACompressor() +@@ -344,6 +345,7 @@ class CompressorDecompressorTestCase(unittest.TestCase): + finally: + ddata = None + ++ @support.skip_if_pgo_task + @bigmemtest(size=_4G + 100, memuse=3) + def test_decompressor_bigmem(self, size): + lzd = LZMADecompressor() +diff --git a/Lib/test/test_regrtest.py b/Lib/test/test_regrtest.py +index 5347bb1..9d83217 100644 +--- a/Lib/test/test_regrtest.py ++++ b/Lib/test/test_regrtest.py +@@ -6,6 +6,7 @@ Note: test_regrtest cannot be run twice in parallel. + + import contextlib + import faulthandler ++import glob + import io + import os.path + import platform +@@ -532,6 +533,31 @@ class BaseTestCase(unittest.TestCase): + return proc.stdout + + ++class CheckActualTests(BaseTestCase): ++ """ ++ Check that regrtest appears to find the expected set of tests. ++ """ ++ ++ def test_finds_expected_number_of_tests(self): ++ args = ['-Wd', '-E', '-bb', '-m', 'test.regrtest', '--list-tests'] ++ output = self.run_python(args) ++ rough_number_of_tests_found = len(output.splitlines()) ++ actual_testsuite_glob = os.path.join(os.path.dirname(__file__), ++ 'test*.py') ++ rough_counted_test_py_files = len(glob.glob(actual_testsuite_glob)) ++ # We're not trying to duplicate test finding logic in here, ++ # just give a rough estimate of how many there should be and ++ # be near that. This is a regression test to prevent mishaps ++ # such as https://bugs.python.org/issue37667 in the future. ++ # If you need to change the values in here during some ++ # mythical future test suite reorganization, don't go ++ # overboard with logic and keep that goal in mind. ++ self.assertGreater(rough_number_of_tests_found, ++ rough_counted_test_py_files*9//10, ++ msg='Unexpectedly low number of tests found in:\n' ++ f'{", ".join(output.splitlines())}') ++ ++ + class ProgramsTestCase(BaseTestCase): + """ + Test various ways to run the Python test suite. Use options close +diff --git a/Makefile.pre.in b/Makefile.pre.in +index b452289..cc428ac 100644 +--- a/Makefile.pre.in ++++ b/Makefile.pre.in +@@ -247,9 +247,10 @@ TCLTK_INCLUDES= @TCLTK_INCLUDES@ + TCLTK_LIBS= @TCLTK_LIBS@ + + # The task to run while instrumented when building the profile-opt target. +-# We exclude unittests with -x that take a rediculious amount of time to +-# run in the instrumented training build or do not provide much value. +-PROFILE_TASK=-m test.regrtest --pgo ++# To speed up profile generation, we don't run the full unit test suite ++# by default. The default is "-m test --pgo". To run more tests, use ++# PROFILE_TASK="-m test --pgo-extended" ++PROFILE_TASK= @PROFILE_TASK@ + + # report files for gcov / lcov coverage report + COVERAGE_INFO= $(abs_builddir)/coverage.info +diff --git a/configure.ac b/configure.ac +index c071ec3..816fc5a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1308,6 +1308,14 @@ else + DEF_MAKE_RULE="all" + fi + ++AC_ARG_VAR(PROFILE_TASK, Python args for PGO generation task) ++AC_MSG_CHECKING(PROFILE_TASK) ++if test -z "$PROFILE_TASK" ++then ++ PROFILE_TASK='-m test --pgo' ++fi ++AC_MSG_RESULT($PROFILE_TASK) ++ + # Make llvm-relatec checks work on systems where llvm tools are not installed with their + # normal names in the default $PATH (ie: Ubuntu). They exist under the + # non-suffixed name in their versioned llvm directory. diff --git a/SPECS/python3.spec b/SPECS/python3.spec index 7d8e0bc..d786e5c 100644 --- a/SPECS/python3.spec +++ b/SPECS/python3.spec @@ -14,7 +14,7 @@ URL: https://www.python.org/ # WARNING When rebasing to a new Python version, # remember to update the python3-docs package as well Version: %{pybasever}.8 -Release: 15.1%{?dist} +Release: 23%{?dist} License: Python @@ -30,13 +30,7 @@ License: Python %bcond_without rpmwheels # Expensive optimizations (mainly, profile-guided optimizations) -%ifarch %{ix86} x86_64 %bcond_without optimizations -%else -# On some architectures, the optimized build takes tens of hours, possibly -# longer than Koji's 24-hour timeout. Disable optimizations here. -%bcond_with optimizations -%endif # Run the test suite in %%check %bcond_without tests @@ -357,6 +351,13 @@ Patch274: 00274-fix-arch-names.patch # See also: https://bugzilla.redhat.com/show_bug.cgi?id=1489816 Patch294: 00294-define-TLS-cipher-suite-on-build-time.patch +# 00316 # +# We remove the exe files from distutil's bdist_wininst +# So we mark the command as unsupported - and the tests are skipped +# Fixed upstream and backported from the 3.7 branch: https://bugs.python.org/issue10945 +# Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1754040 +Patch316: 00316-mark-bdist_wininst-unsupported.patch + # 00317 # # Security fix for CVE-2019-5010: Fix segfault in ssl's cert parser # https://bugzilla.redhat.com/show_bug.cgi?id=1666789 @@ -364,11 +365,29 @@ Patch294: 00294-define-TLS-cipher-suite-on-build-time.patch Patch317: 00317-CVE-2019-5010.patch # 00318 # -# test_ssl fixes for TLS 1.3 and OpenSSL 1.1.1 +# Various fixes for TLS 1.3 and OpenSSL 1.1.1 # https://bugzilla.redhat.com/show_bug.cgi?id=1639531 + +# test_ssl fixes for TLS 1.3 and OpenSSL 1.1.1 # https://bugs.python.org/issue32947#msg333990 # https://github.com/python/cpython/pull/11612 -Patch318: 00318-test-ssl-fix-for-tls-13.patch + +# Encrypt private key test files with AES256 +# https://bugs.python.org/issue38271 +# https://github.com/python/cpython/pull/16396 + +# Prefer PROTOCOL_TLS_CLIENT/SERVER (partial backport) +# https://bugs.python.org/issue31346 +# https://github.com/python/cpython/pull/3058 + +# Enable TLS 1.3 in tests (partial backport) +# https://bugs.python.org/issue33618 +# https://github.com/python/cpython/pull/7082 + +# OpenSSL 1.1.1-pre1 / TLS 1.3 fixes (partial backport) +# https://bugs.python.org/issue32947 +# https://github.com/python/cpython/pull/5923 +Patch318: 00318-fixes-for-tls-13.patch # 00319 # # Fix test_tarfile on ppc64 @@ -419,6 +438,8 @@ Patch327: 00327-enable-tls-1.3-PHA-in-http.client.patch # - add a new "usedforsecurity" keyword argument to the various digest # algorithms in hashlib so that you can whitelist a callsite with # "usedforsecurity=False" +# The change has been implemented upstream since Python 3.9: +# https://bugs.python.org/issue9216 # - OpenSSL wrappers for the hashes blake2{b512,s256}, # sha3_{224,256,384,512}, shake_{128,256} are now exported from _hashlib # - In FIPS mode, the blake2, sha3 and shake hashes use OpenSSL wrappers @@ -426,9 +447,47 @@ Patch327: 00327-enable-tls-1.3-PHA-in-http.client.patch # - In FIPS mode, hmac.HMAC can only be instantiated with an OpenSSL wrapper # or an string with OpenSSL hash name as the "digestmod" argument. # The argument must be specified (instead of defaulting to ‘md5’). +# +# - Also while in FIPS mode, we utilize OpenSSL's DRBG and disable the +# os.getrandom() function. +# +# Upstream changes that have also been backported with this patch +# to allow tests to pass on stricter environments: +# +# Avoid MD5 or check for MD5 availablity +# https://bugs.python.org/issue38270 +# https://github.com/python/cpython/pull/16393 +# https://github.com/python/cpython/pull/16437 +# https://github.com/python/cpython/pull/17446 +# +# add usedforsecurity to hashlib constructors (partial backport for fixing a uuid test) +# https://github.com/python/cpython/pull/16044 # Resolves: rhbz#1731424 Patch329: 00329-fips.patch +# 00330 # +# Fix CVE-2018-20852: cookie domain check returning incorrect results +# Fixed upstream: https://bugs.python.org/issue35121 +# Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1741553 +Patch330: 00330-CVE-2018-20852.patch + +# 00332 # +# Fix CVE-2019-16056: Don't parse email addresses containing +# multiple '@' characters. +# Fixed upstream: https://bugs.python.org/issue34155 +# Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1750776 +Patch332: 00332-CVE-2019-16056.patch + +# 00333 # +# Reduce the number of tests run during the profile guided optimizations build, +# as running the whole test suite during profiling increases the build time +# substantially, with negligible performance gain. +# Fixed upstream and backported from the 3.8 branch: +# https://bugs.python.org/issue36044 +# https://bugs.python.org/issue37667 +# Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1749576 +Patch333: 00333-reduce-pgo-tests.patch + # (New patches go here ^^^) # # When adding new patches to "python" and "python3" in Fedora, EL, etc., @@ -456,16 +515,20 @@ Requires: %{name}-libs%{?_isa} = %{version}-%{release} %if %{with rpmwheels} -# RHEL8 was forked from F28 and thus required python3-setuptools/pip here +# RHEL8 was forked from F28 and thus required python3-setuptools here # for the rewheel module to work. We've since backported the use of RPM # prepared wheels from F29+ into RHEL8, and thus this dependency isn't # strictly needed. # However, it is possible, that some packages in BaseOS actually depend on -# setuptools/pip without declaring the dependency in their spec file. Thus -# we're keeping these dependencies here to avoid the possibility of breaking +# setuptools without declaring the dependency in their spec file. Thus +# we're keeping this dependency here to avoid the possibility of breaking # them. Requires: platform-python-setuptools -Requires: platform-python-pip +# For python3-pip the Requires has been reduced to Recommends, as there are +# generally less packages that depend on pip than packages that depend on +# setuptools at runtime, and thus there's less chance of breakage. +# (rhbz#1756217). +Recommends: platform-python-pip Requires: python3-setuptools-wheel Requires: python3-pip-wheel @@ -727,6 +790,7 @@ rm Lib/ensurepip/_bundled/*.whl %patch262 -p1 %patch274 -p1 %patch294 -p1 +%patch316 -p1 %patch317 -p1 %patch318 -p1 %patch319 -p1 @@ -736,6 +800,9 @@ rm Lib/ensurepip/_bundled/*.whl %patch326 -p1 %patch327 -p1 %patch329 -p1 +%patch330 -p1 +%patch332 -p1 +%patch333 -p1 # Remove files that should be generated by the build @@ -823,7 +890,7 @@ BuildPython() { %{nil} # Invoke the build - make EXTRA_CFLAGS="$CFLAGS $MoreCFlags" %{?_smp_mflags} + %make_build CFLAGS_NODIST="$CFLAGS_NODIST $MoreCFlags" popd echo FINISHED: BUILD OF PYTHON FOR CONFIGURATION: $ConfName @@ -1162,20 +1229,10 @@ CheckPython() { WITHIN_PYTHON_RPM_BUILD= \ LD_LIBRARY_PATH=$ConfDir $ConfDir/python -m test.regrtest \ -wW --slowest --findleaks \ - -x test_distutils \ -x test_bdist_rpm \ - %ifarch %{arm} - -x test_gdb \ - %endif %ifarch %{mips64} -x test_ctypes \ %endif - %ifarch s390x - -x test_gdb \ - %endif - %ifarch ppc64le - -x test_gdb \ - %endif echo FINISHED: CHECKING OF PYTHON FOR CONFIGURATION: $ConfName @@ -1663,11 +1720,42 @@ fi # ====================================================== %changelog -* Fri Oct 11 2019 Tomas Orsava - 3.6.8-15.1 +* Wed Nov 27 2019 Charalampos Stratakis - 3.6.8-23 +- Modify the test suite to better handle disabled SSL/TLS versions and FIPS mode +- Use OpenSSL's DRBG and disable os.getrandom() function in FIPS mode +Resolves: rhbz#1754028, rhbz#1754027, rhbz#1754026, rhbz#1774471 + +* Thu Oct 24 2019 Tomas Orsava - 3.6.8-22 +- Changed Requires into Recommends for python3-pip to allow a lower RHEL8 + footprint for containers and other minimal environments +Resolves: rhbz#1756217 + +* Wed Oct 16 2019 Tomas Orsava - 3.6.8-21 - Patch 329 (FIPS) modified: Added workaround for mod_ssl: Skip error checking in _Py_hashlib_fips_error Resolves: rhbz#1760106 +* Mon Oct 14 2019 Charalampos Stratakis - 3.6.8-20 +- Security fix for CVE-2019-16056 +Resolves: rhbz#1750776 + +* Wed Oct 09 2019 Charalampos Stratakis - 3.6.8-19 +- Skip windows specific test_get_exe_bytes test case and enable test_distutils +Resolves: rhbz#1754040 + +* Mon Oct 07 2019 Charalampos Stratakis - 3.6.8-18 +- Reduce the number of tests running during the profile guided optimizations build +- Enable profile guided optimizations for all the supported architectures +Resolves: rhbz#1749576 + +* Mon Oct 07 2019 Charalampos Stratakis - 3.6.8-17 +- Security fix for CVE-2018-20852 +Resolves: rhbz#1741553 + +* Fri Oct 04 2019 Charalampos Stratakis - 3.6.8-16 +- Properly pass the -Og optimization flag to the debug build +Resolves: rhbz#1712977 and rhbz#1714733 + * Thu Aug 29 2019 Tomas Orsava - 3.6.8-15 - Patch 329 that adds support for OpenSSL FIPS mode has been improved and bugfixed