66import os
77from functools import lru_cache
88from ipaddress import IPv4Address
9- from typing import Optional
9+ from typing import Optional , Type
1010
1111import pytest
1212
1313from cryptography import utils , x509
1414from cryptography .hazmat ._oid import ExtendedKeyUsageOID
15- from cryptography .x509 .extensions import ExtendedKeyUsage
15+ from cryptography .x509 .extensions import (
16+ ExtendedKeyUsage ,
17+ ExtensionType ,
18+ )
1619from cryptography .x509 .general_name import DNSName , IPAddress
1720from cryptography .x509 .verification import (
1821 Criticality ,
@@ -300,6 +303,18 @@ def test_error_message(self):
300303 verifier .verify (leaf , [])
301304
302305
306+ TESTED_EXTENSION_TYPES = (
307+ x509 .AuthorityInformationAccess ,
308+ x509 .AuthorityKeyIdentifier ,
309+ x509 .SubjectKeyIdentifier ,
310+ x509 .KeyUsage ,
311+ x509 .SubjectAlternativeName ,
312+ x509 .BasicConstraints ,
313+ x509 .NameConstraints ,
314+ x509 .ExtendedKeyUsage ,
315+ )
316+
317+
303318class TestCustomExtensionPolicies :
304319 leaf = _load_cert (
305320 os .path .join ("x509" , "cryptography.io.pem" ),
@@ -345,71 +360,103 @@ class _Extension:
345360 None ,
346361 )
347362
348- @staticmethod
349- def _eku_validator_cb (policy , cert , ext : Optional [ExtendedKeyUsage ]):
350- assert isinstance (policy , Policy )
351- assert (
352- policy .validation_time
353- == TestCustomExtensionPolicies .validation_time .replace (tzinfo = None )
363+ def test_unsupported_extension (self ):
364+ ext_policy = ExtensionPolicy .permit_all ()
365+ message = (
366+ f"Unsupported extension OID: { x509 .Admissions .oid .dotted_string } "
354367 )
355- assert isinstance (cert , x509 .Certificate )
356- assert ext is None or isinstance (ext , x509 .ExtendedKeyUsage )
368+ with pytest .raises (
369+ ValueError ,
370+ match = message ,
371+ ):
372+ ext_policy .may_be_present (
373+ x509 .Admissions ,
374+ Criticality .AGNOSTIC ,
375+ None ,
376+ )
357377
358- def test_custom_cb_pass (self ):
359- ca_ext_policy = ExtensionPolicy .webpki_defaults_ca ()
360- ee_ext_policy = ExtensionPolicy .webpki_defaults_ee ()
378+ @staticmethod
379+ def _make_validator_cb (extension_type : Type [ExtensionType ]):
380+ def validator_cb (policy , cert , ext : Optional [ExtensionType ]):
381+ assert isinstance (policy , Policy )
382+ assert (
383+ policy .validation_time
384+ == TestCustomExtensionPolicies .validation_time .replace (
385+ tzinfo = None
386+ )
387+ )
388+ assert isinstance (cert , x509 .Certificate )
389+ assert ext is None or isinstance (ext , extension_type )
361390
362- ee_ext_policy = ee_ext_policy .may_be_present (
363- ExtendedKeyUsage , Criticality .AGNOSTIC , self ._eku_validator_cb
364- )
365- ca_ext_policy = ca_ext_policy .may_be_present (
366- ExtendedKeyUsage , Criticality .AGNOSTIC , self ._eku_validator_cb
367- )
391+ return validator_cb
368392
369- ca_validator_called = False
393+ # def test_all_extension_types(self):
394+ # ca_ext_policy = ExtensionPolicy.webpki_defaults_ca()
395+ # ee_ext_policy = ExtensionPolicy.webpki_defaults_ee()
370396
371- def ca_basic_constraints_validator (policy , cert , ext ):
372- assert cert == self .ca
373- assert isinstance (policy , Policy )
374- assert isinstance (cert , x509 .Certificate )
375- assert isinstance (ext , x509 .BasicConstraints )
376- nonlocal ca_validator_called
377- ca_validator_called = True
397+ # ca_validator_called = False
378398
379- ca_ext_policy = ca_ext_policy .may_be_present (
380- x509 .BasicConstraints ,
399+ # extension_types = [
400+ # AuthorityInformationAccess,
401+ # AuthorityKeyIdentifier,
402+ # SubjectKeyIdentifier,
403+ # KeyUsage,
404+ # SubjectAlternativeName,
405+ # BasicConstraints,
406+ # ]
407+
408+ # for
409+
410+ # ca_ext_policy = ca_ext_policy.may_be_present(
411+ # x509.BasicConstraints,
412+ # Criticality.AGNOSTIC,
413+ # ca_basic_constraints_validator,
414+ # )
415+
416+ # builder = PolicyBuilder().store(self.store)
417+ # builder = builder.time(self.validation_time)
418+ # builder = builder.extension_policies(ca_ext_policy, ee_ext_policy)
419+
420+ # builder.build_client_verifier().verify(self.leaf, [])
421+
422+ @pytest .mark .parametrize (
423+ "extension_type" ,
424+ TESTED_EXTENSION_TYPES ,
425+ )
426+ def test_custom_cb_pass (self , extension_type : Type [x509 .ExtensionType ]):
427+ ca_ext_policy = ExtensionPolicy .webpki_defaults_ca ()
428+ ee_ext_policy = ExtensionPolicy .webpki_defaults_ee ()
429+
430+ ee_ext_policy = ee_ext_policy .may_be_present (
431+ extension_type ,
381432 Criticality .AGNOSTIC ,
382- ca_basic_constraints_validator ,
433+ self . _make_validator_cb ( extension_type ) ,
383434 )
384435
385436 builder = PolicyBuilder ().store (self .store )
386437 builder = builder .time (self .validation_time ).max_chain_depth (16 )
387438 builder = builder .extension_policies (ca_ext_policy , ee_ext_policy )
388439
389440 builder .build_client_verifier ().verify (self .leaf , [])
390- assert ca_validator_called
391- ca_validator_called = False
392441
393442 path = builder .build_server_verifier (
394443 DNSName ("cryptography.io" )
395444 ).verify (self .leaf , [])
396- assert ca_validator_called
397445 assert path == [self .leaf , self .ca ]
398446
399- def test_custom_cb_no_retval_enforced (self ):
447+ @pytest .mark .parametrize (
448+ "extension_type" ,
449+ TESTED_EXTENSION_TYPES ,
450+ )
451+ def test_custom_cb_exception_fails_verification (self , extension_type ):
400452 ca_ext_policy = ExtensionPolicy .webpki_defaults_ca ()
401453 ee_ext_policy = ExtensionPolicy .webpki_defaults_ee ()
402454
403455 def validator (* _ ):
404- return False
456+ raise ValueError ( "test" )
405457
406458 ca_ext_policy = ca_ext_policy .may_be_present (
407- x509 .BasicConstraints ,
408- Criticality .AGNOSTIC ,
409- validator ,
410- )
411- ee_ext_policy = ee_ext_policy .may_be_present (
412- ExtendedKeyUsage ,
459+ extension_type ,
413460 Criticality .AGNOSTIC ,
414461 validator ,
415462 )
@@ -423,22 +470,17 @@ def validator(*_):
423470 ):
424471 with pytest .raises (
425472 VerificationError ,
426- match = "Python validator must return None. " ,
473+ match = "Python extension validator failed: ValueError: test " ,
427474 ):
428475 verifier .verify (self .leaf , [])
429476
430- def test_custom_cb_exception_fails_verification (self ):
477+ def test_custom_cb_no_retval_enforced (self ):
431478 ca_ext_policy = ExtensionPolicy .webpki_defaults_ca ()
432479 ee_ext_policy = ExtensionPolicy .webpki_defaults_ee ()
433480
434481 def validator (* _ ):
435- raise ValueError ( "test" )
482+ return False
436483
437- ca_ext_policy = ca_ext_policy .may_be_present (
438- x509 .BasicConstraints ,
439- Criticality .AGNOSTIC ,
440- validator ,
441- )
442484 ee_ext_policy = ee_ext_policy .may_be_present (
443485 ExtendedKeyUsage ,
444486 Criticality .AGNOSTIC ,
@@ -454,6 +496,6 @@ def validator(*_):
454496 ):
455497 with pytest .raises (
456498 VerificationError ,
457- match = "Python extension validator failed: ValueError: test " ,
499+ match = "Python validator must return None. " ,
458500 ):
459501 verifier .verify (self .leaf , [])
0 commit comments