1
1
# coding: utf-8
2
2
from __future__ import unicode_literals , division , absolute_import , print_function
3
3
4
- from asn1crypto import x509 , crl
5
- from oscrypto import asymmetric
6
- import oscrypto .errors
4
+ from asn1crypto import x509 , crl , algos
5
+ from asn1crypto .keys import PublicKeyInfo
6
+ from cryptography .exceptions import InvalidSignature
7
+ from cryptography .hazmat .primitives import hashes , serialization
8
+ from cryptography .hazmat .primitives .asymmetric import padding , rsa , ec , dsa
7
9
8
10
from ._errors import pretty_message
9
11
from ._types import str_cls , type_name
@@ -324,27 +326,23 @@ def _validate_path(validation_context, path, end_entity_name_override=None):
324
326
hash_algo
325
327
))
326
328
327
- if signature_algo == 'rsassa_pkcs1v15' :
328
- verify_func = asymmetric .rsa_pkcs1v15_verify
329
- elif signature_algo == 'dsa' :
330
- verify_func = asymmetric .dsa_verify
331
- elif signature_algo == 'ecdsa' :
332
- verify_func = asymmetric .ecdsa_verify
333
- else :
329
+ try :
330
+ _validate_sig (
331
+ signature = cert ['signature_value' ].native ,
332
+ signed_data = cert ['tbs_certificate' ].dump (),
333
+ public_key_info = working_public_key ,
334
+ sig_algo = signature_algo , hash_algo = hash_algo ,
335
+ parameters = cert ['signature_algorithm' ]['parameters' ]
336
+ )
337
+ except PSSParameterMismatch :
334
338
raise PathValidationError (pretty_message (
335
339
'''
336
- The path could not be validated because the signature of %s
337
- uses the unsupported algorithm %s
340
+ The signature parameters for %s do not match the constraints
341
+ on the public key.
338
342
''' ,
339
- _cert_type (index , last_index , end_entity_name_override , definite = True ),
340
- signature_algo
343
+ _cert_type (index , last_index , end_entity_name_override , definite = True )
341
344
))
342
-
343
- try :
344
- key_object = asymmetric .load_public_key (working_public_key )
345
- verify_func (key_object , cert ['signature_value' ].native , cert ['tbs_certificate' ].dump (), hash_algo )
346
-
347
- except (oscrypto .errors .SignatureError ):
345
+ except InvalidSignature :
348
346
raise PathValidationError (pretty_message (
349
347
'''
350
348
The path could not be validated because the signature of %s
@@ -638,6 +636,9 @@ def _validate_path(validation_context, path, end_entity_name_override=None):
638
636
639
637
# Handle inheritance of DSA parameters from a signing CA to the
640
638
# next in the chain
639
+ # NOTE: we don't perform this step for RSASSA-PSS since there the
640
+ # parameters are drawn form the signature parameters, where they
641
+ # must always be present.
641
642
copy_params = None
642
643
if cert .public_key .algorithm == 'dsa' and cert .public_key .hash_algo is None :
643
644
if working_public_key .algorithm == 'dsa' :
@@ -831,7 +832,7 @@ def _cert_type(index, last_index, end_entity_name_override, definite=False):
831
832
return prefix + 'end-entity certificate'
832
833
833
834
834
- def _self_signed (cert ):
835
+ def _self_signed (cert : x509 . Certificate ):
835
836
"""
836
837
Determines if a certificate is self-signed
837
838
@@ -853,27 +854,16 @@ def _self_signed(cert):
853
854
signature_algo = cert ['signature_algorithm' ].signature_algo
854
855
hash_algo = cert ['signature_algorithm' ].hash_algo
855
856
856
- if signature_algo == 'rsassa_pkcs1v15' :
857
- verify_func = asymmetric .rsa_pkcs1v15_verify
858
- elif signature_algo == 'dsa' :
859
- verify_func = asymmetric .dsa_verify
860
- elif signature_algo == 'ecdsa' :
861
- verify_func = asymmetric .ecdsa_verify
862
- else :
863
- raise PathValidationError (pretty_message (
864
- '''
865
- Unable to verify the signature of the certificate since it uses
866
- the unsupported algorithm %s
867
- ''' ,
868
- signature_algo
869
- ))
870
-
871
857
try :
872
- key_object = asymmetric .load_certificate (cert )
873
- verify_func (key_object , cert ['signature_value' ].native , cert ['tbs_certificate' ].dump (), hash_algo )
858
+ _validate_sig (
859
+ signature = cert ['signature_value' ].native ,
860
+ signed_data = cert ['tbs_certificate' ].dump (),
861
+ public_key_info = cert .public_key ,
862
+ sig_algo = signature_algo , hash_algo = hash_algo ,
863
+ parameters = cert ['signature_algorithm' ]['parameters' ]
864
+ )
874
865
return True
875
-
876
- except (oscrypto .errors .SignatureError ):
866
+ except InvalidSignature :
877
867
return False
878
868
879
869
@@ -1128,30 +1118,22 @@ def verify_ocsp_response(cert, path, validation_context, cert_description=None,
1128
1118
signature_algo = response ['signature_algorithm' ].signature_algo
1129
1119
hash_algo = response ['signature_algorithm' ].hash_algo
1130
1120
1131
- if signature_algo == 'rsassa_pkcs1v15' :
1132
- verify_func = asymmetric .rsa_pkcs1v15_verify
1133
- elif signature_algo == 'dsa' :
1134
- verify_func = asymmetric .dsa_verify
1135
- elif signature_algo == 'ecdsa' :
1136
- verify_func = asymmetric .ecdsa_verify
1137
- else :
1121
+ # Verify that the response was properly signed by the validated certificate
1122
+ try :
1123
+ _validate_sig (
1124
+ signature = response ['signature' ].native ,
1125
+ signed_data = tbs_response .dump (),
1126
+ public_key_info = signing_cert .public_key ,
1127
+ sig_algo = signature_algo , hash_algo = hash_algo ,
1128
+ parameters = response ['signature_algorithm' ]['parameters' ]
1129
+ )
1130
+ except PSSParameterMismatch :
1138
1131
failures .append ((
1139
- pretty_message (
1140
- '''
1141
- Unable to verify OCSP response since response signature
1142
- uses the unsupported algorithm %s
1143
- ''' ,
1144
- signature_algo
1145
- ),
1132
+ 'The signature parameters on the OCSP response do not match '
1133
+ 'the constraints on the public key' ,
1146
1134
ocsp_response
1147
1135
))
1148
- continue
1149
-
1150
- # Verify that the response was properly signed by the validated certificate
1151
- try :
1152
- key_object = asymmetric .load_certificate (signing_cert )
1153
- verify_func (key_object , response ['signature' ].native , tbs_response .dump (), hash_algo )
1154
- except (oscrypto .errors .SignatureError ):
1136
+ except InvalidSignature :
1155
1137
failures .append ((
1156
1138
'Unable to verify OCSP response signature' ,
1157
1139
ocsp_response
@@ -1828,30 +1810,19 @@ def _verify_signature(certificate_list, crl_issuer):
1828
1810
signature_algo = certificate_list ['signature_algorithm' ].signature_algo
1829
1811
hash_algo = certificate_list ['signature_algorithm' ].hash_algo
1830
1812
1831
- if signature_algo == 'rsassa_pkcs1v15' :
1832
- verify_func = asymmetric .rsa_pkcs1v15_verify
1833
- elif signature_algo == 'dsa' :
1834
- verify_func = asymmetric .dsa_verify
1835
- elif signature_algo == 'ecdsa' :
1836
- verify_func = asymmetric .ecdsa_verify
1837
- else :
1838
- raise CRLValidationError (pretty_message (
1839
- '''
1840
- Unable to verify the CertificateList since the signature uses the
1841
- unsupported algorithm %s
1842
- ''' ,
1843
- signature_algo
1844
- ))
1845
-
1846
1813
try :
1847
- key_object = asymmetric . load_certificate ( crl_issuer )
1848
- verify_func (
1849
- key_object ,
1850
- certificate_list [ 'signature' ]. native ,
1851
- certificate_list [ 'tbs_cert_list' ]. dump () ,
1852
- hash_algo
1814
+ _validate_sig (
1815
+ signature = certificate_list [ 'signature' ]. native ,
1816
+ signed_data = certificate_list [ 'tbs_cert_list' ]. dump () ,
1817
+ public_key_info = crl_issuer . public_key ,
1818
+ sig_algo = signature_algo , hash_algo = hash_algo ,
1819
+ parameters = certificate_list [ 'signature_algorithm' ][ 'parameters' ]
1853
1820
)
1854
- except (oscrypto .errors .SignatureError ):
1821
+ except PSSParameterMismatch as e :
1822
+ raise CRLValidationError (
1823
+ 'Invalid signature parameters on CertificateList'
1824
+ ) from e
1825
+ except InvalidSignature :
1855
1826
raise CRLValidationError ('Unable to verify the signature of the CertificateList' )
1856
1827
1857
1828
@@ -2038,3 +2009,60 @@ def __init__(self, valid_policy, qualifier_set, expected_policy_set):
2038
2009
self .qualifier_set = qualifier_set
2039
2010
self .expected_policy_set = expected_policy_set
2040
2011
self .children = []
2012
+
2013
+
2014
+ class PSSParameterMismatch (InvalidSignature ):
2015
+ pass
2016
+
2017
+
2018
+ def _validate_sig (signature : bytes , signed_data : bytes ,
2019
+ public_key_info : PublicKeyInfo ,
2020
+ sig_algo : str , hash_algo : str , parameters = None ):
2021
+
2022
+ hash_algo = getattr (hashes , hash_algo .upper ())()
2023
+
2024
+ # pyca/cryptography can't load PSS-exclusive keys without some help:
2025
+ if public_key_info .algorithm == 'rsassa_pss' :
2026
+ public_key_info = public_key_info .copy ()
2027
+ assert isinstance (parameters , algos .RSASSAPSSParams )
2028
+ pss_key_params = public_key_info ['algorithm' ]['parameters' ].native
2029
+ if pss_key_params is not None and pss_key_params != parameters .native :
2030
+ raise PSSParameterMismatch (
2031
+ "Public key info includes PSS parameters that do not match "
2032
+ "those on the signature"
2033
+ )
2034
+ # set key type to generic RSA, discard parameters
2035
+ public_key_info ['algorithm' ] = {'algorithm' : 'rsa' }
2036
+
2037
+ pub_key = serialization .load_der_public_key (public_key_info .dump ())
2038
+
2039
+ if sig_algo == 'rsassa_pkcs1v15' :
2040
+ assert isinstance (pub_key , rsa .RSAPublicKey )
2041
+ pub_key .verify (signature , signed_data , padding .PKCS1v15 (), hash_algo )
2042
+ elif sig_algo == 'rsassa_pss' :
2043
+ assert isinstance (pub_key , rsa .RSAPublicKey )
2044
+ assert isinstance (parameters , algos .RSASSAPSSParams )
2045
+ mga : algos .MaskGenAlgorithm = parameters ['mask_gen_algorithm' ]
2046
+ if not mga ['algorithm' ].native == 'mgf1' :
2047
+ raise NotImplementedError ("Only MFG1 is supported" )
2048
+
2049
+ mgf_md_name = mga ['parameters' ]['algorithm' ].native
2050
+
2051
+ salt_len : int = parameters ['salt_length' ].native
2052
+
2053
+ mgf_md = getattr (hashes , mgf_md_name .upper ())()
2054
+ pss_padding = padding .PSS (
2055
+ mgf = padding .MGF1 (algorithm = mgf_md ),
2056
+ salt_length = salt_len
2057
+ )
2058
+ pub_key .verify (signature , signed_data , pss_padding , hash_algo )
2059
+ elif sig_algo == 'dsa' :
2060
+ assert isinstance (pub_key , dsa .DSAPublicKey )
2061
+ pub_key .verify (signature , signed_data , hash_algo )
2062
+ elif sig_algo == 'ecdsa' :
2063
+ assert isinstance (pub_key , ec .EllipticCurvePublicKey )
2064
+ pub_key .verify (signature , signed_data , ec .ECDSA (hash_algo ))
2065
+ else : # pragma: nocover
2066
+ raise NotImplementedError (
2067
+ f"Signature mechanism { sig_algo } is not supported."
2068
+ )
0 commit comments