@@ -3824,6 +3824,145 @@ def test_reuse(self):
3824
3824
assert store_ctx .verify_certificate () is None
3825
3825
assert store_ctx .verify_certificate () is None
3826
3826
3827
+ @pytest .mark .parametrize (
3828
+ "root_cert, chain, verified_cert" ,
3829
+ [
3830
+ pytest .param (
3831
+ root_cert ,
3832
+ [intermediate_cert ],
3833
+ intermediate_server_cert ,
3834
+ id = "intermediate in chain" ,
3835
+ ),
3836
+ pytest .param (
3837
+ root_cert ,
3838
+ [],
3839
+ intermediate_cert ,
3840
+ id = "empty chain" ,
3841
+ ),
3842
+ pytest .param (
3843
+ root_cert ,
3844
+ [root_cert , intermediate_server_cert , intermediate_cert ],
3845
+ intermediate_server_cert ,
3846
+ id = "extra certs in chain" ,
3847
+ ),
3848
+ ],
3849
+ )
3850
+ def test_verify_success_with_chain (self , root_cert , chain , verified_cert ):
3851
+ store = X509Store ()
3852
+ store .add_cert (root_cert )
3853
+ store_ctx = X509StoreContext (store , verified_cert , chain = chain )
3854
+ assert store_ctx .verify_certificate () is None
3855
+
3856
+ def test_valid_untrusted_chain_reuse (self ):
3857
+ """
3858
+ `verify_certificate` using an untrusted chain can be called multiple
3859
+ times with the same ``X509StoreContext`` instance to produce the same
3860
+ result.
3861
+ """
3862
+ store = X509Store ()
3863
+ store .add_cert (self .root_cert )
3864
+ chain = [self .intermediate_cert ]
3865
+
3866
+ store_ctx = X509StoreContext (
3867
+ store , self .intermediate_server_cert , chain = chain
3868
+ )
3869
+ assert store_ctx .verify_certificate () is None
3870
+ assert store_ctx .verify_certificate () is None
3871
+
3872
+ def test_chain_reference (self ):
3873
+ """
3874
+ ``X509StoreContext`` properly keeps references to the untrusted chain
3875
+ certificates.
3876
+ """
3877
+ store = X509Store ()
3878
+ store .add_cert (self .root_cert )
3879
+ chain = [load_certificate (FILETYPE_PEM , intermediate_cert_pem )]
3880
+
3881
+ store_ctx = X509StoreContext (
3882
+ store , self .intermediate_server_cert , chain = chain
3883
+ )
3884
+
3885
+ del chain
3886
+ assert store_ctx .verify_certificate () is None
3887
+
3888
+ @pytest .mark .parametrize (
3889
+ "root_cert, chain, verified_cert" ,
3890
+ [
3891
+ pytest .param (
3892
+ root_cert ,
3893
+ [],
3894
+ intermediate_server_cert ,
3895
+ id = "intermediate missing" ,
3896
+ ),
3897
+ pytest .param (
3898
+ None ,
3899
+ [intermediate_cert ],
3900
+ intermediate_server_cert ,
3901
+ id = "no trusted root" ,
3902
+ ),
3903
+ pytest .param (
3904
+ None ,
3905
+ [root_cert , intermediate_cert ],
3906
+ intermediate_server_cert ,
3907
+ id = "untrusted root, full chain is available" ,
3908
+ ),
3909
+ pytest .param (
3910
+ intermediate_cert ,
3911
+ [root_cert , intermediate_cert ],
3912
+ intermediate_server_cert ,
3913
+ id = "untrusted root, intermediate is trusted and in chain" ,
3914
+ ),
3915
+ ],
3916
+ )
3917
+ def test_verify_fail_with_chain (self , root_cert , chain , verified_cert ):
3918
+ store = X509Store ()
3919
+ if root_cert :
3920
+ store .add_cert (root_cert )
3921
+
3922
+ store_ctx = X509StoreContext (store , verified_cert , chain = chain )
3923
+
3924
+ with pytest .raises (X509StoreContextError ):
3925
+ store_ctx .verify_certificate ()
3926
+
3927
+ @pytest .mark .parametrize (
3928
+ "chain, expected_error" ,
3929
+ [
3930
+ pytest .param (
3931
+ [intermediate_cert , "This is not a certificate" ],
3932
+ TypeError ,
3933
+ id = "non-certificate in chain" ,
3934
+ ),
3935
+ pytest .param (
3936
+ 42 ,
3937
+ TypeError ,
3938
+ id = "non-list chain" ,
3939
+ ),
3940
+ ],
3941
+ )
3942
+ def test_untrusted_chain_wrong_args (self , chain , expected_error ):
3943
+ """
3944
+ Creating ``X509StoreContext`` with wrong chain raises an exception.
3945
+ """
3946
+ store = X509Store ()
3947
+ store .add_cert (self .root_cert )
3948
+
3949
+ with pytest .raises (expected_error ):
3950
+ X509StoreContext (store , self .intermediate_server_cert , chain = chain )
3951
+
3952
+ def test_failure_building_untrusted_chain_raises (self , monkeypatch ):
3953
+ """
3954
+ Creating ``X509StoreContext`` raises ``OpenSSL.crypto.Error`` when
3955
+ the underlying lib fails to add the certificate to the stack.
3956
+ """
3957
+ monkeypatch .setattr (_lib , "sk_X509_push" , lambda _stack , _x509 : - 1 )
3958
+
3959
+ store = X509Store ()
3960
+ store .add_cert (self .root_cert )
3961
+ chain = [self .intermediate_cert ]
3962
+
3963
+ with pytest .raises (Error ):
3964
+ X509StoreContext (store , self .intermediate_server_cert , chain = chain )
3965
+
3827
3966
def test_trusted_self_signed (self ):
3828
3967
"""
3829
3968
`verify_certificate` returns ``None`` when called with a self-signed
0 commit comments