mirror of
https://github.com/certbot/certbot.git
synced 2026-06-04 14:26:10 -04:00
* cert signature validation for certificates subcommand + a test * refactoring validation + adding in a check for making sure that the private key matches the certificate * adding testing certs * assertIsNone(x) -> assertEqual(None,x) to unbreak the py2.6 tests * modifying test_verifu_renewable_cert_failure to hopefully appease python 3 test timeouts * updating cryptography to be >=1.2 so that we can use verify * removing unused, old testing certificate * adding better error handling/logging * adding test for IOError * switching to a 2048 bit rsa key
This commit is contained in:
parent
001d90e106
commit
d7f9859c3f
10 changed files with 301 additions and 4 deletions
|
|
@ -6,6 +6,7 @@ import pytz
|
|||
import traceback
|
||||
import zope.component
|
||||
|
||||
from certbot import crypto_util
|
||||
from certbot import errors
|
||||
from certbot import interfaces
|
||||
from certbot import ocsp
|
||||
|
|
@ -73,6 +74,7 @@ def certificates(config):
|
|||
for renewal_file in storage.renewal_conf_files(config):
|
||||
try:
|
||||
renewal_candidate = storage.RenewableCert(renewal_file, config)
|
||||
crypto_util.verify_renewable_cert(renewal_candidate)
|
||||
parsed_certs.append(renewal_candidate)
|
||||
except Exception as e: # pylint: disable=broad-except
|
||||
logger.warning("Renewal configuration file %s produced an "
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import OpenSSL
|
|||
import pyrfc3339
|
||||
import six
|
||||
import zope.component
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography import x509
|
||||
|
||||
from acme import crypto_util as acme_crypto_util
|
||||
from acme import jose
|
||||
|
|
@ -206,6 +208,95 @@ def valid_privkey(privkey):
|
|||
return False
|
||||
|
||||
|
||||
def verify_renewable_cert(renewable_cert):
|
||||
"""For checking that your certs were not corrupted on disk.
|
||||
|
||||
Several things are checked:
|
||||
1. Signature verification for the cert.
|
||||
2. That fullchain matches cert and chain when concatenated.
|
||||
3. Check that the private key matches the certificate.
|
||||
|
||||
:param `.storage.RenewableCert` renewable_cert: cert to verify
|
||||
|
||||
:raises errors.Error: If verification fails.
|
||||
"""
|
||||
verify_renewable_cert_sig(renewable_cert)
|
||||
verify_fullchain(renewable_cert)
|
||||
verify_cert_matches_priv_key(renewable_cert)
|
||||
|
||||
|
||||
def verify_renewable_cert_sig(renewable_cert):
|
||||
""" Verifies the signature of a `.storage.RenewableCert` object.
|
||||
|
||||
:param `.storage.RenewableCert` renewable_cert: cert to verify
|
||||
|
||||
:raises errors.Error: If signature verification fails.
|
||||
"""
|
||||
try:
|
||||
with open(renewable_cert.chain, 'rb') as chain:
|
||||
chain, _ = pyopenssl_load_certificate(chain.read())
|
||||
with open(renewable_cert.cert, 'rb') as cert:
|
||||
cert = x509.load_pem_x509_certificate(cert.read(), default_backend())
|
||||
hash_name = cert.signature_hash_algorithm.name
|
||||
OpenSSL.crypto.verify(chain, cert.signature, cert.tbs_certificate_bytes, hash_name)
|
||||
except (IOError, ValueError, OpenSSL.crypto.Error) as e:
|
||||
error_str = "verifying the signature of the cert located at {0} has failed. \
|
||||
Details: {1}".format(renewable_cert.cert, e)
|
||||
logger.exception(error_str)
|
||||
raise errors.Error(error_str)
|
||||
|
||||
|
||||
def verify_cert_matches_priv_key(renewable_cert):
|
||||
""" Verifies that the private key and cert match.
|
||||
|
||||
:param `.storage.RenewableCert` renewable_cert: cert to verify
|
||||
|
||||
:raises errors.Error: If they don't match.
|
||||
"""
|
||||
try:
|
||||
with open(renewable_cert.cert) as cert:
|
||||
cert = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert.read())
|
||||
with open(renewable_cert.privkey) as privkey:
|
||||
privkey = OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, privkey.read())
|
||||
context = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
|
||||
context.use_privatekey(privkey)
|
||||
context.use_certificate(cert)
|
||||
context.check_privatekey()
|
||||
except (IOError, OpenSSL.SSL.Error) as e:
|
||||
error_str = "verifying the cert located at {0} matches the \
|
||||
private key located at {1} has failed. \
|
||||
Details: {2}".format(renewable_cert.cert,
|
||||
renewable_cert.privkey, e)
|
||||
logger.exception(error_str)
|
||||
raise errors.Error(error_str)
|
||||
|
||||
|
||||
def verify_fullchain(renewable_cert):
|
||||
""" Verifies that fullchain is indeed cert concatenated with chain.
|
||||
|
||||
:param `.storage.RenewableCert` renewable_cert: cert to verify
|
||||
|
||||
:raises errors.Error: If cert and chain do not combine to fullchain.
|
||||
"""
|
||||
try:
|
||||
with open(renewable_cert.chain) as chain:
|
||||
chain = chain.read()
|
||||
with open(renewable_cert.cert) as cert:
|
||||
cert = cert.read()
|
||||
with open(renewable_cert.fullchain) as fullchain:
|
||||
fullchain = fullchain.read()
|
||||
if (cert + chain) != fullchain:
|
||||
error_str = "fullchain does not match cert + chain for {0}!"
|
||||
error_str = error_str.format(renewable_cert.lineagename)
|
||||
raise errors.Error(error_str)
|
||||
except IOError as e:
|
||||
error_str = "reading one of cert, chain, or fullchain has failed: {0}".format(e)
|
||||
logger.exception(error_str)
|
||||
raise errors.Error(error_str)
|
||||
except errors.Error as e:
|
||||
raise e
|
||||
|
||||
|
||||
def pyopenssl_load_certificate(data):
|
||||
"""Load PEM/DER certificate.
|
||||
|
||||
|
|
@ -340,6 +431,7 @@ def _notAfterBefore(cert_path, method):
|
|||
:rtype: :class:`datetime.datetime`
|
||||
|
||||
"""
|
||||
# pylint: disable=redefined-outer-name
|
||||
with open(cert_path) as f:
|
||||
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM,
|
||||
f.read())
|
||||
|
|
|
|||
|
|
@ -149,12 +149,14 @@ class CertificatesTest(BaseCertManagerTest):
|
|||
self.assertFalse(mock_utility.notification.called)
|
||||
self.assertTrue(mock_logger.warning.called) #pylint: disable=no-member
|
||||
|
||||
@mock.patch('certbot.crypto_util.verify_renewable_cert')
|
||||
@mock.patch('certbot.cert_manager.logger')
|
||||
@test_util.patch_get_utility()
|
||||
@mock.patch("certbot.storage.RenewableCert")
|
||||
@mock.patch('certbot.cert_manager._report_human_readable')
|
||||
def test_certificates_parse_success(self, mock_report, mock_renewable_cert,
|
||||
mock_utility, mock_logger):
|
||||
mock_utility, mock_logger, mock_verifier):
|
||||
mock_verifier.return_value = None
|
||||
mock_report.return_value = ""
|
||||
self._certificates(self.cli_config)
|
||||
self.assertFalse(mock_logger.warning.called) #pylint: disable=no-member
|
||||
|
|
|
|||
|
|
@ -14,11 +14,14 @@ import certbot.tests.util as test_util
|
|||
|
||||
|
||||
RSA256_KEY = test_util.load_vector('rsa256_key.pem')
|
||||
RSA256_KEY_PATH = test_util.vector_path('rsa256_key.pem')
|
||||
RSA512_KEY = test_util.load_vector('rsa512_key.pem')
|
||||
RSA2048_KEY_PATH = test_util.vector_path('rsa2048_key.pem')
|
||||
CERT_PATH = test_util.vector_path('cert.pem')
|
||||
CERT = test_util.load_vector('cert.pem')
|
||||
SAN_CERT = test_util.load_vector('cert-san.pem')
|
||||
|
||||
SS_CERT_PATH = test_util.vector_path('self_signed_cert.pem')
|
||||
SS_CERT = test_util.load_vector('self_signed_cert.pem')
|
||||
|
||||
class InitSaveKeyTest(test_util.TempDirTestCase):
|
||||
"""Tests for certbot.crypto_util.init_save_key."""
|
||||
|
|
@ -194,6 +197,101 @@ class MakeKeyTest(unittest.TestCase): # pylint: disable=too-few-public-methods
|
|||
OpenSSL.crypto.FILETYPE_PEM, make_key(1024))
|
||||
|
||||
|
||||
class VerifyCertSetup(unittest.TestCase):
|
||||
"""Refactoring for verification tests."""
|
||||
|
||||
def setUp(self):
|
||||
super(VerifyCertSetup, self).setUp()
|
||||
|
||||
self.renewable_cert = mock.MagicMock()
|
||||
self.renewable_cert.cert = SS_CERT_PATH
|
||||
self.renewable_cert.chain = SS_CERT_PATH
|
||||
self.renewable_cert.privkey = RSA2048_KEY_PATH
|
||||
self.renewable_cert.fullchain = test_util.vector_path('self_signed_fullchain.pem')
|
||||
|
||||
self.bad_renewable_cert = mock.MagicMock()
|
||||
self.bad_renewable_cert.chain = SS_CERT_PATH
|
||||
self.bad_renewable_cert.cert = SS_CERT_PATH
|
||||
self.bad_renewable_cert.fullchain = SS_CERT_PATH
|
||||
|
||||
|
||||
class VerifyRenewableCertTest(VerifyCertSetup):
|
||||
"""Tests for certbot.crypto_util.verify_renewable_cert."""
|
||||
|
||||
def setUp(self):
|
||||
super(VerifyRenewableCertTest, self).setUp()
|
||||
|
||||
def _call(self, renewable_cert):
|
||||
from certbot.crypto_util import verify_renewable_cert
|
||||
return verify_renewable_cert(renewable_cert)
|
||||
|
||||
def test_verify_renewable_cert(self):
|
||||
self.assertEqual(None, self._call(self.renewable_cert))
|
||||
|
||||
@mock.patch('certbot.crypto_util.verify_renewable_cert_sig', side_effect=errors.Error(""))
|
||||
def test_verify_renewable_cert_failure(self, unused_verify_renewable_cert_sign):
|
||||
self.assertRaises(errors.Error, self._call, self.bad_renewable_cert)
|
||||
|
||||
|
||||
class VerifyRenewableCertSigTest(VerifyCertSetup):
|
||||
"""Tests for certbot.crypto_util.verify_renewable_cert."""
|
||||
|
||||
def setUp(self):
|
||||
super(VerifyRenewableCertSigTest, self).setUp()
|
||||
|
||||
def _call(self, renewable_cert):
|
||||
from certbot.crypto_util import verify_renewable_cert_sig
|
||||
return verify_renewable_cert_sig(renewable_cert)
|
||||
|
||||
def test_cert_sig_match(self):
|
||||
self.assertEqual(None, self._call(self.renewable_cert))
|
||||
|
||||
def test_cert_sig_mismatch(self):
|
||||
self.bad_renewable_cert.cert = test_util.vector_path('self_signed_cert_bad.pem')
|
||||
self.assertRaises(errors.Error, self._call, self.bad_renewable_cert)
|
||||
|
||||
|
||||
class VerifyFullchainTest(VerifyCertSetup):
|
||||
"""Tests for certbot.crypto_util.verify_fullchain."""
|
||||
|
||||
def setUp(self):
|
||||
super(VerifyFullchainTest, self).setUp()
|
||||
|
||||
def _call(self, renewable_cert):
|
||||
from certbot.crypto_util import verify_fullchain
|
||||
return verify_fullchain(renewable_cert)
|
||||
|
||||
def test_fullchain_matches(self):
|
||||
self.assertEqual(None, self._call(self.renewable_cert))
|
||||
|
||||
def test_fullchain_mismatch(self):
|
||||
self.assertRaises(errors.Error, self._call, self.bad_renewable_cert)
|
||||
|
||||
def test_fullchain_ioerror(self):
|
||||
self.bad_renewable_cert.chain = "dog"
|
||||
self.assertRaises(errors.Error, self._call, self.bad_renewable_cert)
|
||||
|
||||
|
||||
class VerifyCertMatchesPrivKeyTest(VerifyCertSetup):
|
||||
"""Tests for certbot.crypto_util.verify_cert_matches_priv_key."""
|
||||
|
||||
def setUp(self):
|
||||
super(VerifyCertMatchesPrivKeyTest, self).setUp()
|
||||
|
||||
def _call(self, renewable_cert):
|
||||
from certbot.crypto_util import verify_cert_matches_priv_key
|
||||
return verify_cert_matches_priv_key(renewable_cert)
|
||||
|
||||
def test_cert_priv_key_match(self):
|
||||
self.assertEqual(None, self._call(self.renewable_cert))
|
||||
|
||||
def test_cert_priv_key_mismatch(self):
|
||||
self.bad_renewable_cert.privkey = RSA256_KEY_PATH
|
||||
self.bad_renewable_cert.cert = SS_CERT_PATH
|
||||
|
||||
self.assertRaises(errors.Error, self._call, self.bad_renewable_cert)
|
||||
|
||||
|
||||
class ValidPrivkeyTest(unittest.TestCase):
|
||||
"""Tests for certbot.crypto_util.valid_privkey."""
|
||||
|
||||
|
|
|
|||
28
certbot/tests/testdata/rsa2048_key.pem
vendored
Normal file
28
certbot/tests/testdata/rsa2048_key.pem
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDm1WIecnHjL4Fs
|
||||
JvxDP27GyeqnXKc41HsRP9cv4z+NDjE94mDgva5ndieiA9xZ0Sh7LXtZcGDcpGop
|
||||
+D7s+oh0apV6idIJ9eEPUegYlGxOFJQnZ8re6hD7MaAlNZEVhZrwJvrGy6rTFpi3
|
||||
DaNokGn7r3s2nrQ9aziljkWRp1PnTBnRNgOdi3c1IB2f4+2PdykjihxlnYUuI4Wf
|
||||
5QU5pFx60a2mdTVDC+bKAP22IvuQnnkHgJYYS/oMxFCT9QR4xQRPOx7U2RWVrFDV
|
||||
MJ3mIB8FOW6JXfQSmaZZr46xclbEIr4QQ6RcPWvcJ1cCV1idFjEmufi52sV7r1Bf
|
||||
3nCJFk1fAgMBAAECggEAJkhbVntagfgd+cbZbXm2sIdKQGlwXk92/Zxd3tZMcuNY
|
||||
rU+/C2bJ5uTEm+0R/V9f3FXlsCagGde2t7ExFnJScSRAGCuFRxudMMI/wNvUvnpR
|
||||
O9vN3HxrRo2rZqBkqHIZCR0d2Bxs/0cvGqTLZgsVWKV4xM07TThcE7DtvsNGegRn
|
||||
WFxfsRcRypkIvZoba1HagvCituRBEa07R7mQp8kRhP9ZeRq3bZws9qBmqzj1cylG
|
||||
q8QA4Foq7sK8P78bpIhrcOFBDAr+Vr1ZGY6u01J0w13MUtl6iIx4VCjQKt4NkzsK
|
||||
dj2q+GAMwhReR2ZS42o8LiyGpwusj+dKIFfFekgK2QKBgQD4wwmRDgvt85brQTNF
|
||||
Tkhui0eToz5oXt8mVDb58nwkpojFQOv87ZyNsEqm7S0t/3RtEViVio2aymTMsrz4
|
||||
21vRq46dvhINQ3DoMok6xIchEOEgMeonOilkURWtrMjD/Kn297Asv7zOqI5BCNiP
|
||||
3FFcRqf+CaqbhnOgMkcI5z6b7QKBgQDtjM1otFFHyS7ctyLRuMeFyxWUSbWHvi8U
|
||||
xjUW256c6wpQ2DBLSVB61VQjfrSjkZ5DJVFGnbw42HxSDafL11mzTbY1vDbgtgLK
|
||||
YiuVHG7OYZJTLaZoM68BseX4xHN8FztnvvP1ttuk5oFb+vD8q6ODZSEawRd3PvtX
|
||||
D7RtNouc+wKBgQDiwBWGTUF+gt18T5BGilbnvLlf0Btg06mgrH74UpnqZoqhEs6J
|
||||
XKWpWZqSkfruxL4BdSBEH2l4QSiklgA+7uTBOBnlm42k3WaboQUJtn5eG5651AXV
|
||||
/+Qe9vJFvwu56iObZKcIAzY9QdN5YHDWoULgU99pZrJG1cWrrmilqvOc+QKBgQCB
|
||||
iOslslY0N+926eJxzDn4qkJtJzh2+e1AfcjLWx0F4mEwroK/Ow5IvPVxmZE1NJ3B
|
||||
baMBR9gwg1RfhhS+4gKG9NRsPuMJ7BZfd+LeH7AImEorU1RPtAc1fGW0HqP+wchi
|
||||
DU2I6pqhNBTMLG2myo2Sg93mce6y1sRFuEmh2EGPawKBgQC3uUEdjQekXaxXfYHi
|
||||
1Dk3Ht1a9t8XxwoCVRqicE7lqlwDtS2y9lHAeUP7JNy8ZGNjx8srRZpkYVMztugo
|
||||
Ecw26UA7FbNqJP5OPkGjfiFqtOq70h9vlfLdiAPmoqyOx//RkgiNXt9m5xcDzzdB
|
||||
7EtBK59KSiQkB8fHtooy7Ipiiw==
|
||||
-----END PRIVATE KEY-----
|
||||
20
certbot/tests/testdata/self_signed_cert.pem
vendored
Normal file
20
certbot/tests/testdata/self_signed_cert.pem
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDSjCCAjKgAwIBAgIJAIYLtIQHBBG0MA0GCSqGSIb3DQEBCwUAMDoxCzAJBgNV
|
||||
BAYTAkNBMQswCQYDVQQIDAJPTjEQMA4GA1UEBwwHVG9yb250bzEMMAoGA1UECgwD
|
||||
RUZGMB4XDTE3MDUyOTA3NDIwMVoXDTQ4MDMzMDA3NDIwMVowOjELMAkGA1UEBhMC
|
||||
Q0ExCzAJBgNVBAgMAk9OMRAwDgYDVQQHDAdUb3JvbnRvMQwwCgYDVQQKDANFRkYw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDm1WIecnHjL4FsJvxDP27G
|
||||
yeqnXKc41HsRP9cv4z+NDjE94mDgva5ndieiA9xZ0Sh7LXtZcGDcpGop+D7s+oh0
|
||||
apV6idIJ9eEPUegYlGxOFJQnZ8re6hD7MaAlNZEVhZrwJvrGy6rTFpi3DaNokGn7
|
||||
r3s2nrQ9aziljkWRp1PnTBnRNgOdi3c1IB2f4+2PdykjihxlnYUuI4Wf5QU5pFx6
|
||||
0a2mdTVDC+bKAP22IvuQnnkHgJYYS/oMxFCT9QR4xQRPOx7U2RWVrFDVMJ3mIB8F
|
||||
OW6JXfQSmaZZr46xclbEIr4QQ6RcPWvcJ1cCV1idFjEmufi52sV7r1Bf3nCJFk1f
|
||||
AgMBAAGjUzBRMB0GA1UdDgQWBBSdJ++M23AW3LkFD7LKhsH7gL6/2jAfBgNVHSME
|
||||
GDAWgBSdJ++M23AW3LkFD7LKhsH7gL6/2jAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQCV5kSt1HTFzUPdBvxT455YrLd3jIsRt1pRNuGjVaUYIRxh
|
||||
vds8NN1Z8h/8Cdzz8NVkIdCuYb2lFaDjs3zNVUQxCyVcH7xVyPwFI85NR27+HPRv
|
||||
xzz2rwzST+NKYst6ZBg086BKjqFtxs16lpU/TD6tOJqg86TBbfP6gib/ocGeER2D
|
||||
HEEik69FjmUCziT6uXyYW5y1PxD15UWO3RWoTpao0vGtTPceTeeuO05PVeCUlx8X
|
||||
YXg9zoVWBba0GF+qQJ67zT5nvfc2KJcgnWRIRr/90YXzBf+FdFVuC4xFHINBI1OJ
|
||||
5XBLJOv61Zu+Du/nmlBVcb8KL/Vd2oZyfoH+0oCN
|
||||
-----END CERTIFICATE-----
|
||||
15
certbot/tests/testdata/self_signed_cert_bad.pem
vendored
Normal file
15
certbot/tests/testdata/self_signed_cert_bad.pem
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIICYzCCAg2gAwIBAgIJAPvqv4TcAtuFMA0GCSqGSIb3DQEBCwUAMIGMMQswCQYD
|
||||
VQQGEwJDQTEQMA4GA1UECAwHT250YXJpbzEQMA4GA1UEBwwHVG9yb250bzEMMAoG
|
||||
A1UECgwDRUZGMRYwFAYDVQQLDA1UZWNoIFByb2plY3RzMQ4wDAYDVQQDDAVZb21u
|
||||
YTEjMCEGCSqGSIb3DQEJARYUeW9tbmEubmFzc2VyQGVmZi5vcmcwHhcNMTcwMzI0
|
||||
MjIzMjUxWhcNNDgwMTI0MjIzMjUxWjCBjDELMAkGA1UEBhMCQ0ExEDAOBgNVBAgM
|
||||
B09udGFyaW8xEDAOBgNVBAcMB1Rvcm9udG8xDDAKBgNVBAoMA0VGRjEWMBQGA1UE
|
||||
CwwNVGVjaCBQcm9qZWN0czEOMAwGA1UEAwwFWW9tbmExIzAhBgkqhkiG9w0BCQEW
|
||||
FHlvbW5hLm5hc3NlckBlZmYub3JnMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKx1
|
||||
c7RR7R/drnBSQ/zfx1vQLHUbFLh1AQQQ5R8DZUXd36efNK79vukFhN9HFoHZiUvO
|
||||
jm0c+pVE6K+EdE/twuUCAwEAAaNQME4wHQYDVR0OBBYEFCbPyO1L15Sy5CUDWCSP
|
||||
BMB01ZeKMB8GA1UdIwQYMBaAFCbPyO1L15Sy5CUDWCSPBMB01ZeKMAwGA1UdEwQF
|
||||
MAMBAf8wDQYJKoZIhvcNAQELBQADQQAeWDdcrJOolFHr3m8TrlDJ/Ca4SfJya2jb
|
||||
K1wahbX83sC42834HbDOQASGBhoLYDhC1cMPbKDDjMbR9rjYuf7T
|
||||
-----END CERTIFICATE-----
|
||||
40
certbot/tests/testdata/self_signed_fullchain.pem
vendored
Normal file
40
certbot/tests/testdata/self_signed_fullchain.pem
vendored
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIDSjCCAjKgAwIBAgIJAIYLtIQHBBG0MA0GCSqGSIb3DQEBCwUAMDoxCzAJBgNV
|
||||
BAYTAkNBMQswCQYDVQQIDAJPTjEQMA4GA1UEBwwHVG9yb250bzEMMAoGA1UECgwD
|
||||
RUZGMB4XDTE3MDUyOTA3NDIwMVoXDTQ4MDMzMDA3NDIwMVowOjELMAkGA1UEBhMC
|
||||
Q0ExCzAJBgNVBAgMAk9OMRAwDgYDVQQHDAdUb3JvbnRvMQwwCgYDVQQKDANFRkYw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDm1WIecnHjL4FsJvxDP27G
|
||||
yeqnXKc41HsRP9cv4z+NDjE94mDgva5ndieiA9xZ0Sh7LXtZcGDcpGop+D7s+oh0
|
||||
apV6idIJ9eEPUegYlGxOFJQnZ8re6hD7MaAlNZEVhZrwJvrGy6rTFpi3DaNokGn7
|
||||
r3s2nrQ9aziljkWRp1PnTBnRNgOdi3c1IB2f4+2PdykjihxlnYUuI4Wf5QU5pFx6
|
||||
0a2mdTVDC+bKAP22IvuQnnkHgJYYS/oMxFCT9QR4xQRPOx7U2RWVrFDVMJ3mIB8F
|
||||
OW6JXfQSmaZZr46xclbEIr4QQ6RcPWvcJ1cCV1idFjEmufi52sV7r1Bf3nCJFk1f
|
||||
AgMBAAGjUzBRMB0GA1UdDgQWBBSdJ++M23AW3LkFD7LKhsH7gL6/2jAfBgNVHSME
|
||||
GDAWgBSdJ++M23AW3LkFD7LKhsH7gL6/2jAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQCV5kSt1HTFzUPdBvxT455YrLd3jIsRt1pRNuGjVaUYIRxh
|
||||
vds8NN1Z8h/8Cdzz8NVkIdCuYb2lFaDjs3zNVUQxCyVcH7xVyPwFI85NR27+HPRv
|
||||
xzz2rwzST+NKYst6ZBg086BKjqFtxs16lpU/TD6tOJqg86TBbfP6gib/ocGeER2D
|
||||
HEEik69FjmUCziT6uXyYW5y1PxD15UWO3RWoTpao0vGtTPceTeeuO05PVeCUlx8X
|
||||
YXg9zoVWBba0GF+qQJ67zT5nvfc2KJcgnWRIRr/90YXzBf+FdFVuC4xFHINBI1OJ
|
||||
5XBLJOv61Zu+Du/nmlBVcb8KL/Vd2oZyfoH+0oCN
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDSjCCAjKgAwIBAgIJAIYLtIQHBBG0MA0GCSqGSIb3DQEBCwUAMDoxCzAJBgNV
|
||||
BAYTAkNBMQswCQYDVQQIDAJPTjEQMA4GA1UEBwwHVG9yb250bzEMMAoGA1UECgwD
|
||||
RUZGMB4XDTE3MDUyOTA3NDIwMVoXDTQ4MDMzMDA3NDIwMVowOjELMAkGA1UEBhMC
|
||||
Q0ExCzAJBgNVBAgMAk9OMRAwDgYDVQQHDAdUb3JvbnRvMQwwCgYDVQQKDANFRkYw
|
||||
ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDm1WIecnHjL4FsJvxDP27G
|
||||
yeqnXKc41HsRP9cv4z+NDjE94mDgva5ndieiA9xZ0Sh7LXtZcGDcpGop+D7s+oh0
|
||||
apV6idIJ9eEPUegYlGxOFJQnZ8re6hD7MaAlNZEVhZrwJvrGy6rTFpi3DaNokGn7
|
||||
r3s2nrQ9aziljkWRp1PnTBnRNgOdi3c1IB2f4+2PdykjihxlnYUuI4Wf5QU5pFx6
|
||||
0a2mdTVDC+bKAP22IvuQnnkHgJYYS/oMxFCT9QR4xQRPOx7U2RWVrFDVMJ3mIB8F
|
||||
OW6JXfQSmaZZr46xclbEIr4QQ6RcPWvcJ1cCV1idFjEmufi52sV7r1Bf3nCJFk1f
|
||||
AgMBAAGjUzBRMB0GA1UdDgQWBBSdJ++M23AW3LkFD7LKhsH7gL6/2jAfBgNVHSME
|
||||
GDAWgBSdJ++M23AW3LkFD7LKhsH7gL6/2jAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
|
||||
SIb3DQEBCwUAA4IBAQCV5kSt1HTFzUPdBvxT455YrLd3jIsRt1pRNuGjVaUYIRxh
|
||||
vds8NN1Z8h/8Cdzz8NVkIdCuYb2lFaDjs3zNVUQxCyVcH7xVyPwFI85NR27+HPRv
|
||||
xzz2rwzST+NKYst6ZBg086BKjqFtxs16lpU/TD6tOJqg86TBbfP6gib/ocGeER2D
|
||||
HEEik69FjmUCziT6uXyYW5y1PxD15UWO3RWoTpao0vGtTPceTeeuO05PVeCUlx8X
|
||||
YXg9zoVWBba0GF+qQJ67zT5nvfc2KJcgnWRIRr/90YXzBf+FdFVuC4xFHINBI1OJ
|
||||
5XBLJOv61Zu+Du/nmlBVcb8KL/Vd2oZyfoH+0oCN
|
||||
-----END CERTIFICATE-----
|
||||
2
setup.py
2
setup.py
|
|
@ -41,7 +41,7 @@ install_requires = [
|
|||
# in which we added 2.6 support (see #2243), so we relax the requirement.
|
||||
'ConfigArgParse>=0.9.3',
|
||||
'configobj',
|
||||
'cryptography>=0.7', # load_pem_x509_certificate
|
||||
'cryptography>=1.2', # load_pem_x509_certificate
|
||||
'mock',
|
||||
'parsedatetime>=1.3', # Calendar.parseDT
|
||||
'PyOpenSSL',
|
||||
|
|
|
|||
2
tox.ini
2
tox.ini
|
|
@ -79,7 +79,7 @@ setenv =
|
|||
# https://github.com/shazow/urllib3/pull/930
|
||||
deps =
|
||||
py{26,27}-oldest: cffi<=1.7
|
||||
py{26,27}-oldest: cryptography==0.8
|
||||
py{26,27}-oldest: cryptography==1.2
|
||||
py{26,27}-oldest: configargparse==0.10.0
|
||||
py{26,27}-oldest: PyOpenSSL==0.13
|
||||
py{26,27}-oldest: requests<=2.11.1
|
||||
|
|
|
|||
Loading…
Reference in a new issue