From 5d66966032a1efbcbf093804a19951f399c2a6eb Mon Sep 17 00:00:00 2001 From: Paul Kehrer Date: Mon, 11 Sep 2017 09:16:34 +0800 Subject: [WIP] add support for the TLSFeature extension in x509 (#3899) * add support for the TLSFeature extension in x509 This extension is used for OCSP Must-Staple. * fix changelog link * pep8 * refactor to support the sequence properly and add status_request_v2 * update some language * add test vector, implement eq/ne/hash on TLSFeature * address review comments --- tests/x509/test_x509.py | 52 +++++++++++++++++++++++++++++++++++++ tests/x509/test_x509_ext.py | 63 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) (limited to 'tests') diff --git a/tests/x509/test_x509.py b/tests/x509/test_x509.py index 533862ab..e41fdc76 100644 --- a/tests/x509/test_x509.py +++ b/tests/x509/test_x509.py @@ -1092,6 +1092,18 @@ class TestRSACertificate(object): "graphy.io')>])>, ...)>" ) + def test_parse_tls_feature_extension(self, backend): + cert = _load_cert( + os.path.join("x509", "tls-feature-ocsp-staple.pem"), + x509.load_pem_x509_certificate, + backend + ) + ext = cert.extensions.get_extension_for_class(x509.TLSFeature) + assert ext.critical is False + assert ext.value == x509.TLSFeature( + [x509.TLSFeatureType.status_request] + ) + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) @@ -2608,6 +2620,46 @@ class TestCertificateBuilder(object): ) assert ext.value == nc + @pytest.mark.requires_backend_interface(interface=RSABackend) + @pytest.mark.requires_backend_interface(interface=X509Backend) + @pytest.mark.parametrize( + "add_ext", + [ + x509.TLSFeature([x509.TLSFeatureType.status_request]), + x509.TLSFeature([x509.TLSFeatureType.status_request_v2]), + x509.TLSFeature([ + x509.TLSFeatureType.status_request, + x509.TLSFeatureType.status_request_v2 + ]) + ] + ) + def test_tls_feature(self, add_ext, backend): + issuer_private_key = RSA_KEY_2048.private_key(backend) + subject_private_key = RSA_KEY_2048.private_key(backend) + + not_valid_before = datetime.datetime(2002, 1, 1, 12, 1) + not_valid_after = datetime.datetime(2030, 12, 31, 8, 30) + + cert = x509.CertificateBuilder().subject_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + ).issuer_name( + x509.Name([x509.NameAttribute(NameOID.COUNTRY_NAME, u'US')]) + ).not_valid_before( + not_valid_before + ).not_valid_after( + not_valid_after + ).public_key( + subject_private_key.public_key() + ).serial_number( + 123 + ).add_extension( + add_ext, critical=False + ).sign(issuer_private_key, hashes.SHA256(), backend) + + ext = cert.extensions.get_extension_for_class(x509.TLSFeature) + assert ext.critical is False + assert ext.value == add_ext + @pytest.mark.requires_backend_interface(interface=RSABackend) @pytest.mark.requires_backend_interface(interface=X509Backend) def test_key_usage(self, backend): diff --git a/tests/x509/test_x509_ext.py b/tests/x509/test_x509_ext.py index fc8651c8..5b9fb347 100644 --- a/tests/x509/test_x509_ext.py +++ b/tests/x509/test_x509_ext.py @@ -92,6 +92,69 @@ class TestExtension(object): assert ext1 != object() +class TestTLSFeature(object): + def test_not_enum_type(self): + with pytest.raises(TypeError): + x509.TLSFeature([3]) + + def test_empty_list(self): + with pytest.raises(TypeError): + x509.TLSFeature([]) + + def test_repr(self): + ext1 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + assert repr(ext1) == ( + "])>" + ) + + def test_eq(self): + ext1 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + ext2 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + assert ext1 == ext2 + + def test_ne(self): + ext1 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + ext2 = x509.TLSFeature([x509.TLSFeatureType.status_request_v2]) + ext3 = x509.TLSFeature([ + x509.TLSFeatureType.status_request, + x509.TLSFeatureType.status_request_v2 + ]) + assert ext1 != ext2 + assert ext1 != ext3 + assert ext1 != object() + + def test_hash(self): + ext1 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + ext2 = x509.TLSFeature([x509.TLSFeatureType.status_request]) + ext3 = x509.TLSFeature([ + x509.TLSFeatureType.status_request, + x509.TLSFeatureType.status_request_v2 + ]) + assert hash(ext1) == hash(ext2) + assert hash(ext1) != hash(ext3) + + def test_iter(self): + ext1_features = [x509.TLSFeatureType.status_request] + ext1 = x509.TLSFeature(ext1_features) + assert len(ext1) == 1 + assert list(ext1) == ext1_features + ext2_features = [ + x509.TLSFeatureType.status_request, + x509.TLSFeatureType.status_request_v2, + ] + ext2 = x509.TLSFeature(ext2_features) + assert len(ext2) == 2 + assert list(ext2) == ext2_features + + def test_indexing(self): + ext = x509.TLSFeature([ + x509.TLSFeatureType.status_request, + x509.TLSFeatureType.status_request_v2, + ]) + assert ext[-1] == ext[1] + assert ext[0] == x509.TLSFeatureType.status_request + + class TestUnrecognizedExtension(object): def test_invalid_oid(self): with pytest.raises(TypeError): -- cgit v1.2.3