mirror of https://github.com/python/cpython
bpo-38270: Check for hash digest algorithms and avoid MD5 (GH-16382)
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
This commit is contained in:
parent
417089e88b
commit
c64a1a61e6
|
@ -12,6 +12,7 @@ import fnmatch
|
||||||
import functools
|
import functools
|
||||||
import gc
|
import gc
|
||||||
import glob
|
import glob
|
||||||
|
import hashlib
|
||||||
import importlib
|
import importlib
|
||||||
import importlib.util
|
import importlib.util
|
||||||
import locale
|
import locale
|
||||||
|
@ -648,6 +649,29 @@ def requires_mac_ver(*min_version):
|
||||||
return decorator
|
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
|
||||||
|
|
||||||
|
|
||||||
HOST = "localhost"
|
HOST = "localhost"
|
||||||
HOSTv4 = "127.0.0.1"
|
HOSTv4 = "127.0.0.1"
|
||||||
HOSTv6 = "::1"
|
HOSTv6 = "::1"
|
||||||
|
|
|
@ -6,6 +6,8 @@ import unittest
|
||||||
import unittest.mock
|
import unittest.mock
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
from test.support import requires_hashdigest
|
||||||
|
|
||||||
|
|
||||||
def ignore_warning(func):
|
def ignore_warning(func):
|
||||||
@functools.wraps(func)
|
@functools.wraps(func)
|
||||||
|
@ -19,6 +21,7 @@ def ignore_warning(func):
|
||||||
|
|
||||||
class TestVectorsTestCase(unittest.TestCase):
|
class TestVectorsTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
@requires_hashdigest('md5')
|
||||||
def test_md5_vectors(self):
|
def test_md5_vectors(self):
|
||||||
# Test the HMAC module against test vectors from the RFC.
|
# Test the HMAC module against test vectors from the RFC.
|
||||||
|
|
||||||
|
@ -76,6 +79,7 @@ class TestVectorsTestCase(unittest.TestCase):
|
||||||
b"and Larger Than One Block-Size Data"),
|
b"and Larger Than One Block-Size Data"),
|
||||||
"6f630fad67cda0ee1fb1f562db3aa53e")
|
"6f630fad67cda0ee1fb1f562db3aa53e")
|
||||||
|
|
||||||
|
@requires_hashdigest('sha1')
|
||||||
def test_sha_vectors(self):
|
def test_sha_vectors(self):
|
||||||
def shatest(key, data, digest):
|
def shatest(key, data, digest):
|
||||||
h = hmac.HMAC(key, data, digestmod=hashlib.sha1)
|
h = hmac.HMAC(key, data, digestmod=hashlib.sha1)
|
||||||
|
@ -268,23 +272,28 @@ class TestVectorsTestCase(unittest.TestCase):
|
||||||
'134676fb6de0446065c97440fa8c6a58',
|
'134676fb6de0446065c97440fa8c6a58',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@requires_hashdigest('sha224')
|
||||||
def test_sha224_rfc4231(self):
|
def test_sha224_rfc4231(self):
|
||||||
self._rfc4231_test_cases(hashlib.sha224, 'sha224', 28, 64)
|
self._rfc4231_test_cases(hashlib.sha224, 'sha224', 28, 64)
|
||||||
|
|
||||||
|
@requires_hashdigest('sha256')
|
||||||
def test_sha256_rfc4231(self):
|
def test_sha256_rfc4231(self):
|
||||||
self._rfc4231_test_cases(hashlib.sha256, 'sha256', 32, 64)
|
self._rfc4231_test_cases(hashlib.sha256, 'sha256', 32, 64)
|
||||||
|
|
||||||
|
@requires_hashdigest('sha384')
|
||||||
def test_sha384_rfc4231(self):
|
def test_sha384_rfc4231(self):
|
||||||
self._rfc4231_test_cases(hashlib.sha384, 'sha384', 48, 128)
|
self._rfc4231_test_cases(hashlib.sha384, 'sha384', 48, 128)
|
||||||
|
|
||||||
|
@requires_hashdigest('sha512')
|
||||||
def test_sha512_rfc4231(self):
|
def test_sha512_rfc4231(self):
|
||||||
self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128)
|
self._rfc4231_test_cases(hashlib.sha512, 'sha512', 64, 128)
|
||||||
|
|
||||||
|
@requires_hashdigest('sha256')
|
||||||
def test_legacy_block_size_warnings(self):
|
def test_legacy_block_size_warnings(self):
|
||||||
class MockCrazyHash(object):
|
class MockCrazyHash(object):
|
||||||
"""Ain't no block_size attribute here."""
|
"""Ain't no block_size attribute here."""
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
self._x = hashlib.sha1(*args)
|
self._x = hashlib.sha256(*args)
|
||||||
self.digest_size = self._x.digest_size
|
self.digest_size = self._x.digest_size
|
||||||
def update(self, v):
|
def update(self, v):
|
||||||
self._x.update(v)
|
self._x.update(v)
|
||||||
|
@ -308,65 +317,78 @@ class TestVectorsTestCase(unittest.TestCase):
|
||||||
data = b"Hi There"
|
data = b"Hi There"
|
||||||
hmac.HMAC(key, data, digestmod=None)
|
hmac.HMAC(key, data, digestmod=None)
|
||||||
|
|
||||||
|
|
||||||
class ConstructorTestCase(unittest.TestCase):
|
class ConstructorTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
expected = (
|
||||||
|
"6c845b47f52b3b47f6590c502db7825aad757bf4fadc8fa972f7cd2e76a5bdeb"
|
||||||
|
)
|
||||||
|
|
||||||
|
@requires_hashdigest('sha256')
|
||||||
def test_normal(self):
|
def test_normal(self):
|
||||||
# Standard constructor call.
|
# Standard constructor call.
|
||||||
failed = 0
|
|
||||||
try:
|
try:
|
||||||
h = hmac.HMAC(b"key", digestmod='md5')
|
hmac.HMAC(b"key", digestmod='sha256')
|
||||||
except Exception:
|
except Exception:
|
||||||
self.fail("Standard constructor call raised exception.")
|
self.fail("Standard constructor call raised exception.")
|
||||||
|
|
||||||
|
@requires_hashdigest('sha256')
|
||||||
def test_with_str_key(self):
|
def test_with_str_key(self):
|
||||||
# Pass a key of type str, which is an error, because it expects a key
|
# Pass a key of type str, which is an error, because it expects a key
|
||||||
# of type bytes
|
# of type bytes
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
h = hmac.HMAC("key", digestmod='md5')
|
h = hmac.HMAC("key", digestmod='sha256')
|
||||||
|
|
||||||
|
@requires_hashdigest('sha256')
|
||||||
def test_dot_new_with_str_key(self):
|
def test_dot_new_with_str_key(self):
|
||||||
# Pass a key of type str, which is an error, because it expects a key
|
# Pass a key of type str, which is an error, because it expects a key
|
||||||
# of type bytes
|
# of type bytes
|
||||||
with self.assertRaises(TypeError):
|
with self.assertRaises(TypeError):
|
||||||
h = hmac.new("key", digestmod='md5')
|
h = hmac.new("key", digestmod='sha256')
|
||||||
|
|
||||||
|
@requires_hashdigest('sha256')
|
||||||
def test_withtext(self):
|
def test_withtext(self):
|
||||||
# Constructor call with text.
|
# Constructor call with text.
|
||||||
try:
|
try:
|
||||||
h = hmac.HMAC(b"key", b"hash this!", digestmod='md5')
|
h = hmac.HMAC(b"key", b"hash this!", digestmod='sha256')
|
||||||
except Exception:
|
except Exception:
|
||||||
self.fail("Constructor call with text argument raised 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):
|
def test_with_bytearray(self):
|
||||||
try:
|
try:
|
||||||
h = hmac.HMAC(bytearray(b"key"), bytearray(b"hash this!"),
|
h = hmac.HMAC(bytearray(b"key"), bytearray(b"hash this!"),
|
||||||
digestmod="md5")
|
digestmod="sha256")
|
||||||
except Exception:
|
except Exception:
|
||||||
self.fail("Constructor call with bytearray arguments raised 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):
|
def test_with_memoryview_msg(self):
|
||||||
try:
|
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:
|
except Exception:
|
||||||
self.fail("Constructor call with memoryview msg raised 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):
|
def test_withmodule(self):
|
||||||
# Constructor call with text and digest module.
|
# Constructor call with text and digest module.
|
||||||
try:
|
try:
|
||||||
h = hmac.HMAC(b"key", b"", hashlib.sha1)
|
h = hmac.HMAC(b"key", b"", hashlib.sha256)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.fail("Constructor call with hashlib.sha1 raised exception.")
|
self.fail("Constructor call with hashlib.sha256 raised exception.")
|
||||||
|
|
||||||
|
|
||||||
class SanityTestCase(unittest.TestCase):
|
class SanityTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
@requires_hashdigest('sha256')
|
||||||
def test_exercise_all_methods(self):
|
def test_exercise_all_methods(self):
|
||||||
# Exercising all methods once.
|
# Exercising all methods once.
|
||||||
# This must not raise any exceptions
|
# This must not raise any exceptions
|
||||||
try:
|
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!")
|
h.update(b"compute the hash of this text!")
|
||||||
dig = h.digest()
|
dig = h.digest()
|
||||||
dig = h.hexdigest()
|
dig = h.hexdigest()
|
||||||
|
@ -374,11 +396,13 @@ class SanityTestCase(unittest.TestCase):
|
||||||
except Exception:
|
except Exception:
|
||||||
self.fail("Exception raised during normal usage of HMAC class.")
|
self.fail("Exception raised during normal usage of HMAC class.")
|
||||||
|
|
||||||
|
|
||||||
class CopyTestCase(unittest.TestCase):
|
class CopyTestCase(unittest.TestCase):
|
||||||
|
|
||||||
|
@requires_hashdigest('sha256')
|
||||||
def test_attributes(self):
|
def test_attributes(self):
|
||||||
# Testing if attributes are of same type.
|
# Testing if attributes are of same type.
|
||||||
h1 = hmac.HMAC(b"key", digestmod="md5")
|
h1 = hmac.HMAC(b"key", digestmod="sha256")
|
||||||
h2 = h1.copy()
|
h2 = h1.copy()
|
||||||
self.assertTrue(h1.digest_cons == h2.digest_cons,
|
self.assertTrue(h1.digest_cons == h2.digest_cons,
|
||||||
"digest constructors don't match.")
|
"digest constructors don't match.")
|
||||||
|
@ -387,9 +411,10 @@ class CopyTestCase(unittest.TestCase):
|
||||||
self.assertEqual(type(h1.outer), type(h2.outer),
|
self.assertEqual(type(h1.outer), type(h2.outer),
|
||||||
"Types of outer don't match.")
|
"Types of outer don't match.")
|
||||||
|
|
||||||
|
@requires_hashdigest('sha256')
|
||||||
def test_realcopy(self):
|
def test_realcopy(self):
|
||||||
# Testing if the copy method created a real copy.
|
# 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()
|
h2 = h1.copy()
|
||||||
# Using id() in case somebody has overridden __eq__/__ne__.
|
# Using id() in case somebody has overridden __eq__/__ne__.
|
||||||
self.assertTrue(id(h1) != id(h2), "No real copy of the HMAC instance.")
|
self.assertTrue(id(h1) != id(h2), "No real copy of the HMAC instance.")
|
||||||
|
@ -398,9 +423,10 @@ class CopyTestCase(unittest.TestCase):
|
||||||
self.assertTrue(id(h1.outer) != id(h2.outer),
|
self.assertTrue(id(h1.outer) != id(h2.outer),
|
||||||
"No real copy of the attribute 'outer'.")
|
"No real copy of the attribute 'outer'.")
|
||||||
|
|
||||||
|
@requires_hashdigest('sha256')
|
||||||
def test_equality(self):
|
def test_equality(self):
|
||||||
# Testing if the copy has the same digests.
|
# 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")
|
h1.update(b"some random text")
|
||||||
h2 = h1.copy()
|
h2 = h1.copy()
|
||||||
self.assertEqual(h1.digest(), h2.digest(),
|
self.assertEqual(h1.digest(), h2.digest(),
|
||||||
|
|
|
@ -10,7 +10,8 @@ import threading
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
from test.support import (reap_threads, verbose, transient_internet,
|
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
|
import unittest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
from datetime import datetime, timezone, timedelta
|
from datetime import datetime, timezone, timedelta
|
||||||
|
@ -370,6 +371,7 @@ class NewIMAPTestsMixin():
|
||||||
self.assertEqual(code, 'OK')
|
self.assertEqual(code, 'OK')
|
||||||
self.assertEqual(server.response, b'ZmFrZQ==\r\n') # b64 encoded 'fake'
|
self.assertEqual(server.response, b'ZmFrZQ==\r\n') # b64 encoded 'fake'
|
||||||
|
|
||||||
|
@requires_hashdigest('md5')
|
||||||
def test_login_cram_md5_bytes(self):
|
def test_login_cram_md5_bytes(self):
|
||||||
class AuthHandler(SimpleIMAPHandler):
|
class AuthHandler(SimpleIMAPHandler):
|
||||||
capabilities = 'LOGINDISABLED AUTH=CRAM-MD5'
|
capabilities = 'LOGINDISABLED AUTH=CRAM-MD5'
|
||||||
|
@ -387,6 +389,7 @@ class NewIMAPTestsMixin():
|
||||||
ret, _ = client.login_cram_md5("tim", b"tanstaaftanstaaf")
|
ret, _ = client.login_cram_md5("tim", b"tanstaaftanstaaf")
|
||||||
self.assertEqual(ret, "OK")
|
self.assertEqual(ret, "OK")
|
||||||
|
|
||||||
|
@requires_hashdigest('md5')
|
||||||
def test_login_cram_md5_plain_text(self):
|
def test_login_cram_md5_plain_text(self):
|
||||||
class AuthHandler(SimpleIMAPHandler):
|
class AuthHandler(SimpleIMAPHandler):
|
||||||
capabilities = 'LOGINDISABLED AUTH=CRAM-MD5'
|
capabilities = 'LOGINDISABLED AUTH=CRAM-MD5'
|
||||||
|
@ -797,6 +800,7 @@ class ThreadedNetworkedTests(unittest.TestCase):
|
||||||
b'ZmFrZQ==\r\n') # b64 encoded 'fake'
|
b'ZmFrZQ==\r\n') # b64 encoded 'fake'
|
||||||
|
|
||||||
@reap_threads
|
@reap_threads
|
||||||
|
@requires_hashdigest('md5')
|
||||||
def test_login_cram_md5(self):
|
def test_login_cram_md5(self):
|
||||||
|
|
||||||
class AuthHandler(SimpleIMAPHandler):
|
class AuthHandler(SimpleIMAPHandler):
|
||||||
|
|
|
@ -309,9 +309,11 @@ class TestPOP3Class(TestCase):
|
||||||
def test_rpop(self):
|
def test_rpop(self):
|
||||||
self.assertOK(self.client.rpop('foo'))
|
self.assertOK(self.client.rpop('foo'))
|
||||||
|
|
||||||
|
@test_support.requires_hashdigest('md5')
|
||||||
def test_apop_normal(self):
|
def test_apop_normal(self):
|
||||||
self.assertOK(self.client.apop('foo', 'dummypassword'))
|
self.assertOK(self.client.apop('foo', 'dummypassword'))
|
||||||
|
|
||||||
|
@test_support.requires_hashdigest('md5')
|
||||||
def test_apop_REDOS(self):
|
def test_apop_REDOS(self):
|
||||||
# Replace welcome with very long evil welcome.
|
# Replace welcome with very long evil welcome.
|
||||||
# NB The upper bound on welcome length is currently 2048.
|
# NB The upper bound on welcome length is currently 2048.
|
||||||
|
|
|
@ -4,6 +4,7 @@ import email.mime.text
|
||||||
from email.message import EmailMessage
|
from email.message import EmailMessage
|
||||||
from email.base64mime import body_encode as encode_base64
|
from email.base64mime import body_encode as encode_base64
|
||||||
import email.utils
|
import email.utils
|
||||||
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
import socket
|
import socket
|
||||||
import smtpd
|
import smtpd
|
||||||
|
@ -21,6 +22,7 @@ import unittest
|
||||||
from test import support, mock_socket
|
from test import support, mock_socket
|
||||||
from test.support import HOST
|
from test.support import HOST
|
||||||
from test.support import threading_setup, threading_cleanup, join_thread
|
from test.support import threading_setup, threading_cleanup, join_thread
|
||||||
|
from test.support import requires_hashdigest
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|
||||||
|
|
||||||
|
@ -1009,6 +1011,7 @@ class SMTPSimTests(unittest.TestCase):
|
||||||
self.assertEqual(resp, (235, b'Authentication Succeeded'))
|
self.assertEqual(resp, (235, b'Authentication Succeeded'))
|
||||||
smtp.close()
|
smtp.close()
|
||||||
|
|
||||||
|
@requires_hashdigest('md5')
|
||||||
def testAUTH_CRAM_MD5(self):
|
def testAUTH_CRAM_MD5(self):
|
||||||
self.serv.add_feature("AUTH CRAM-MD5")
|
self.serv.add_feature("AUTH CRAM-MD5")
|
||||||
smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15)
|
smtp = smtplib.SMTP(HOST, self.port, local_hostname='localhost', timeout=15)
|
||||||
|
@ -1025,7 +1028,13 @@ class SMTPSimTests(unittest.TestCase):
|
||||||
smtp.close()
|
smtp.close()
|
||||||
|
|
||||||
def test_auth_function(self):
|
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:
|
for mechanism in supported:
|
||||||
self.serv.add_feature("AUTH {}".format(mechanism))
|
self.serv.add_feature("AUTH {}".format(mechanism))
|
||||||
for mechanism in supported:
|
for mechanism in supported:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import io
|
import io
|
||||||
from hashlib import md5
|
from hashlib import sha256
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from random import Random
|
from random import Random
|
||||||
import pathlib
|
import pathlib
|
||||||
|
@ -11,7 +11,7 @@ import unittest.mock
|
||||||
import tarfile
|
import tarfile
|
||||||
|
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import script_helper
|
from test.support import script_helper, requires_hashdigest
|
||||||
|
|
||||||
# Check for our compression modules.
|
# Check for our compression modules.
|
||||||
try:
|
try:
|
||||||
|
@ -27,8 +27,8 @@ try:
|
||||||
except ImportError:
|
except ImportError:
|
||||||
lzma = None
|
lzma = None
|
||||||
|
|
||||||
def md5sum(data):
|
def sha256sum(data):
|
||||||
return md5(data).hexdigest()
|
return sha256(data).hexdigest()
|
||||||
|
|
||||||
TEMPDIR = os.path.abspath(support.TESTFN) + "-tardir"
|
TEMPDIR = os.path.abspath(support.TESTFN) + "-tardir"
|
||||||
tarextdir = TEMPDIR + '-extract-test'
|
tarextdir = TEMPDIR + '-extract-test'
|
||||||
|
@ -39,8 +39,12 @@ xzname = os.path.join(TEMPDIR, "testtar.tar.xz")
|
||||||
tmpname = os.path.join(TEMPDIR, "tmp.tar")
|
tmpname = os.path.join(TEMPDIR, "tmp.tar")
|
||||||
dotlessname = os.path.join(TEMPDIR, "testtar")
|
dotlessname = os.path.join(TEMPDIR, "testtar")
|
||||||
|
|
||||||
md5_regtype = "65f477c818ad9e15f7feab0c6d37742f"
|
sha256_regtype = (
|
||||||
md5_sparse = "a54fbc4ca4f4399a90e1b27164012fc6"
|
"e09e4bc8b3c9d9177e77256353b36c159f5f040531bbd4b024a8f9b9196c71ce"
|
||||||
|
)
|
||||||
|
sha256_sparse = (
|
||||||
|
"4f05a776071146756345ceee937b33fc5644f5a96b9780d1c7d6a32cdf164d7b"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TarTest:
|
class TarTest:
|
||||||
|
@ -95,7 +99,7 @@ class UstarReadTest(ReadTest, unittest.TestCase):
|
||||||
data = fobj.read()
|
data = fobj.read()
|
||||||
self.assertEqual(len(data), tarinfo.size,
|
self.assertEqual(len(data), tarinfo.size,
|
||||||
"regular file extraction failed")
|
"regular file extraction failed")
|
||||||
self.assertEqual(md5sum(data), md5_regtype,
|
self.assertEqual(sha256sum(data), sha256_regtype,
|
||||||
"regular file extraction failed")
|
"regular file extraction failed")
|
||||||
|
|
||||||
def test_fileobj_readlines(self):
|
def test_fileobj_readlines(self):
|
||||||
|
@ -178,7 +182,7 @@ class UstarReadTest(ReadTest, unittest.TestCase):
|
||||||
with self.tar.extractfile("ustar/regtype") as fobj:
|
with self.tar.extractfile("ustar/regtype") as fobj:
|
||||||
fobj = io.TextIOWrapper(fobj)
|
fobj = io.TextIOWrapper(fobj)
|
||||||
data = fobj.read().encode("iso8859-1")
|
data = fobj.read().encode("iso8859-1")
|
||||||
self.assertEqual(md5sum(data), md5_regtype)
|
self.assertEqual(sha256sum(data), sha256_regtype)
|
||||||
try:
|
try:
|
||||||
fobj.seek(100)
|
fobj.seek(100)
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
|
@ -543,13 +547,13 @@ class MiscReadTestBase(CommonReadTest):
|
||||||
self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/lnktype"))
|
self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/lnktype"))
|
||||||
with open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb") as f:
|
with open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb") as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
self.assertEqual(md5sum(data), md5_regtype)
|
self.assertEqual(sha256sum(data), sha256_regtype)
|
||||||
|
|
||||||
tar.extract("ustar/symtype", TEMPDIR)
|
tar.extract("ustar/symtype", TEMPDIR)
|
||||||
self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/symtype"))
|
self.addCleanup(support.unlink, os.path.join(TEMPDIR, "ustar/symtype"))
|
||||||
with open(os.path.join(TEMPDIR, "ustar/symtype"), "rb") as f:
|
with open(os.path.join(TEMPDIR, "ustar/symtype"), "rb") as f:
|
||||||
data = f.read()
|
data = f.read()
|
||||||
self.assertEqual(md5sum(data), md5_regtype)
|
self.assertEqual(sha256sum(data), sha256_regtype)
|
||||||
|
|
||||||
def test_extractall(self):
|
def test_extractall(self):
|
||||||
# Test if extractall() correctly restores directory permissions
|
# Test if extractall() correctly restores directory permissions
|
||||||
|
@ -684,7 +688,7 @@ class StreamReadTest(CommonReadTest, unittest.TestCase):
|
||||||
data = fobj.read()
|
data = fobj.read()
|
||||||
self.assertEqual(len(data), tarinfo.size,
|
self.assertEqual(len(data), tarinfo.size,
|
||||||
"regular file extraction failed")
|
"regular file extraction failed")
|
||||||
self.assertEqual(md5sum(data), md5_regtype,
|
self.assertEqual(sha256sum(data), sha256_regtype,
|
||||||
"regular file extraction failed")
|
"regular file extraction failed")
|
||||||
|
|
||||||
def test_provoke_stream_error(self):
|
def test_provoke_stream_error(self):
|
||||||
|
@ -796,8 +800,8 @@ class MemberReadTest(ReadTest, unittest.TestCase):
|
||||||
def _test_member(self, tarinfo, chksum=None, **kwargs):
|
def _test_member(self, tarinfo, chksum=None, **kwargs):
|
||||||
if chksum is not None:
|
if chksum is not None:
|
||||||
with self.tar.extractfile(tarinfo) as f:
|
with self.tar.extractfile(tarinfo) as f:
|
||||||
self.assertEqual(md5sum(f.read()), chksum,
|
self.assertEqual(sha256sum(f.read()), chksum,
|
||||||
"wrong md5sum for %s" % tarinfo.name)
|
"wrong sha256sum for %s" % tarinfo.name)
|
||||||
|
|
||||||
kwargs["mtime"] = 0o7606136617
|
kwargs["mtime"] = 0o7606136617
|
||||||
kwargs["uid"] = 1000
|
kwargs["uid"] = 1000
|
||||||
|
@ -812,11 +816,11 @@ class MemberReadTest(ReadTest, unittest.TestCase):
|
||||||
|
|
||||||
def test_find_regtype(self):
|
def test_find_regtype(self):
|
||||||
tarinfo = self.tar.getmember("ustar/regtype")
|
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):
|
def test_find_conttype(self):
|
||||||
tarinfo = self.tar.getmember("ustar/conttype")
|
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):
|
def test_find_dirtype(self):
|
||||||
tarinfo = self.tar.getmember("ustar/dirtype")
|
tarinfo = self.tar.getmember("ustar/dirtype")
|
||||||
|
@ -848,28 +852,28 @@ class MemberReadTest(ReadTest, unittest.TestCase):
|
||||||
|
|
||||||
def test_find_sparse(self):
|
def test_find_sparse(self):
|
||||||
tarinfo = self.tar.getmember("ustar/sparse")
|
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):
|
def test_find_gnusparse(self):
|
||||||
tarinfo = self.tar.getmember("gnu/sparse")
|
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):
|
def test_find_gnusparse_00(self):
|
||||||
tarinfo = self.tar.getmember("gnu/sparse-0.0")
|
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):
|
def test_find_gnusparse_01(self):
|
||||||
tarinfo = self.tar.getmember("gnu/sparse-0.1")
|
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):
|
def test_find_gnusparse_10(self):
|
||||||
tarinfo = self.tar.getmember("gnu/sparse-1.0")
|
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):
|
def test_find_umlauts(self):
|
||||||
tarinfo = self.tar.getmember("ustar/umlauts-"
|
tarinfo = self.tar.getmember("ustar/umlauts-"
|
||||||
"\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
|
"\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):
|
def test_find_ustar_longname(self):
|
||||||
name = "ustar/" + "12345/" * 39 + "1234567/longname"
|
name = "ustar/" + "12345/" * 39 + "1234567/longname"
|
||||||
|
@ -877,7 +881,7 @@ class MemberReadTest(ReadTest, unittest.TestCase):
|
||||||
|
|
||||||
def test_find_regtype_oldv7(self):
|
def test_find_regtype_oldv7(self):
|
||||||
tarinfo = self.tar.getmember("misc/regtype-old-v7")
|
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):
|
def test_find_pax_umlauts(self):
|
||||||
self.tar.close()
|
self.tar.close()
|
||||||
|
@ -885,7 +889,7 @@ class MemberReadTest(ReadTest, unittest.TestCase):
|
||||||
encoding="iso8859-1")
|
encoding="iso8859-1")
|
||||||
tarinfo = self.tar.getmember("pax/umlauts-"
|
tarinfo = self.tar.getmember("pax/umlauts-"
|
||||||
"\xc4\xd6\xdc\xe4\xf6\xfc\xdf")
|
"\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:
|
class LongnameTest:
|
||||||
|
@ -947,8 +951,8 @@ class GNUReadTest(LongnameTest, ReadTest, unittest.TestCase):
|
||||||
filename = os.path.join(TEMPDIR, name)
|
filename = os.path.join(TEMPDIR, name)
|
||||||
with open(filename, "rb") as fobj:
|
with open(filename, "rb") as fobj:
|
||||||
data = fobj.read()
|
data = fobj.read()
|
||||||
self.assertEqual(md5sum(data), md5_sparse,
|
self.assertEqual(sha256sum(data), sha256_sparse,
|
||||||
"wrong md5sum for %s" % name)
|
"wrong sha256sum for %s" % name)
|
||||||
|
|
||||||
if self._fs_supports_holes():
|
if self._fs_supports_holes():
|
||||||
s = os.stat(filename)
|
s = os.stat(filename)
|
||||||
|
@ -2443,7 +2447,7 @@ class LinkEmulationTest(ReadTest, unittest.TestCase):
|
||||||
self.tar.extract(name, TEMPDIR)
|
self.tar.extract(name, TEMPDIR)
|
||||||
with open(os.path.join(TEMPDIR, name), "rb") as f:
|
with open(os.path.join(TEMPDIR, name), "rb") as f:
|
||||||
data = f.read()
|
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
|
# See issues #1578269, #8879, and #17689 for some history on these skips
|
||||||
@unittest.skipIf(hasattr(os.path, "islink"),
|
@unittest.skipIf(hasattr(os.path, "islink"),
|
||||||
|
|
|
@ -322,6 +322,7 @@ class ProxyAuthTests(unittest.TestCase):
|
||||||
PASSWD = "test123"
|
PASSWD = "test123"
|
||||||
REALM = "TestRealm"
|
REALM = "TestRealm"
|
||||||
|
|
||||||
|
@support.requires_hashdigest("md5")
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(ProxyAuthTests, self).setUp()
|
super(ProxyAuthTests, self).setUp()
|
||||||
# Ignore proxy bypass settings in the environment.
|
# Ignore proxy bypass settings in the environment.
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
test.support now has a helper function to check for availibility of a
|
||||||
|
hash digest function. Several tests are refactored avoid MD5 and use
|
||||||
|
SHA256 instead. Other tests are marked to use MD5 and skipped when MD5 is
|
||||||
|
disabled.
|
Loading…
Reference in New Issue