@@ -820,7 +820,6 @@ def verify(self, data, require_x509=True, x509_cert=None, cert_subject_name=None
820820 algorithm = c14n_algorithm ,
821821 inclusive_ns_prefixes = inclusive_ns_prefixes )
822822
823- # TODO: if both X509Data and KeyValue is present, match one against the other and raise an error on mismatch
824823 if x509_data is not None or self .require_x509 :
825824 from OpenSSL .crypto import load_certificate , X509 , FILETYPE_PEM , verify , Error as OpenSSLCryptoError
826825
@@ -869,10 +868,19 @@ def verify(self, data, require_x509=True, x509_cert=None, cert_subject_name=None
869868 reason = e
870869 raise InvalidSignature ("Signature verification failed: {}" .format (reason ))
871870
872- if ignore_ambiguous_key_info is False :
873- if key_value is not None or der_encoded_key_value is not None :
874- raise InvalidInput ("Both X509Data and KeyValue found. Use verify(ignore_ambiguous_key_info=True) "
875- "to ignore KeyValue and validate using X509Data only." )
871+ # If both X509Data and KeyValue are present, match one against the other and raise an error on mismatch
872+ if key_value is not None :
873+ if self .check_key_value_matches_cert_public_key (key_value , signing_cert .get_pubkey (), signature_alg ) is False :
874+ if ignore_ambiguous_key_info is False :
875+ raise InvalidInput ("Both X509Data and KeyValue found and they represent different public keys. "
876+ "Use verify(ignore_ambiguous_key_info=True) to ignore KeyValue and validate using X509Data only." )
877+
878+ # If both X509Data and DEREncodedKeyValue are present, match one against the other and raise an error on mismatch
879+ if der_encoded_key_value is not None :
880+ if self .check_der_key_value_matches_cert_public_key (der_encoded_key_value , signing_cert .get_pubkey (), signature_alg ) is False :
881+ if ignore_ambiguous_key_info is False :
882+ raise InvalidInput ("Both X509Data and DEREncodedKeyValue found and they represent different public keys. "
883+ "Use verify(ignore_ambiguous_key_info=True) to ignore DEREncodedKeyValue and validate using X509Data only." )
876884
877885 # TODO: CN verification goes here
878886 # TODO: require one of the following to be set: either x509_cert or (ca_pem_file or ca_path) or common_name
@@ -923,6 +931,91 @@ def verify(self, data, require_x509=True, x509_cert=None, cert_subject_name=None
923931
924932 return verify_results if expect_references > 1 else verify_results [0 ]
925933
934+ def check_key_value_matches_cert_public_key (self , key_value , public_key , signature_alg ):
935+ if "ecdsa-" in signature_alg \
936+ and isinstance (public_key .to_cryptography_key (), ec .EllipticCurvePublicKey ):
937+ ec_key_value = self ._find (key_value , "ECKeyValue" , namespace = "dsig11" )
938+ named_curve = self ._find (ec_key_value , "NamedCurve" , namespace = "dsig11" )
939+ public_key = self ._find (ec_key_value , "PublicKey" , namespace = "dsig11" )
940+ key_data = b64decode (public_key .text )[1 :]
941+ x = bytes_to_long (key_data [:len (key_data )// 2 ])
942+ y = bytes_to_long (key_data [len (key_data )// 2 :])
943+ curve_class = self .known_ecdsa_curves [named_curve .get ("URI" )]
944+
945+ pubk_curve = public_key .to_cryptography_key ().public_numbers ().curve
946+ pubk_x = public_key .to_cryptography_key ().public_numbers ().x
947+ pubk_y = public_key .to_cryptography_key ().public_numbers ().y
948+
949+ return curve_class == pubk_curve and x == pubk_x and y == pubk_y
950+
951+ elif "dsa-" in signature_alg \
952+ and isinstance (public_key .to_cryptography_key (), dsa .DSAPublicKey ):
953+ dsa_key_value = self ._find (key_value , "DSAKeyValue" )
954+ p = self ._get_long (dsa_key_value , "P" )
955+ q = self ._get_long (dsa_key_value , "Q" )
956+ g = self ._get_long (dsa_key_value , "G" , require = False )
957+
958+ pubk_p = public_key .to_cryptography_key ().public_numbers ().p
959+ pubk_q = public_key .to_cryptography_key ().public_numbers ().q
960+ pubk_g = public_key .to_cryptography_key ().public_numbers ().g
961+
962+ return p == pubk_p and q == pubk_q and g == pubk_g
963+
964+ elif "rsa-" in signature_alg \
965+ and isinstance (public_key .to_cryptography_key (), rsa .RSAPublicKey ):
966+ rsa_key_value = self ._find (key_value , "RSAKeyValue" )
967+ n = self ._get_long (rsa_key_value , "Modulus" )
968+ e = self ._get_long (rsa_key_value , "Exponent" )
969+
970+ pubk_n = public_key .to_cryptography_key ().public_numbers ().n
971+ pubk_e = public_key .to_cryptography_key ().public_numbers ().e
972+
973+ return n == pubk_n and e == pubk_e
974+
975+ raise NotImplementedError ()
976+
977+ def check_der_key_value_matches_cert_public_key (self , der_encoded_key_value , public_key , signature_alg ):
978+ der_public_key = load_der_public_key (b64decode (der_encoded_key_value .text ), backend = default_backend ())
979+
980+ if "ecdsa-" in signature_alg \
981+ and isinstance (der_public_key , ec .EllipticCurvePublicKey ) \
982+ and isinstance (public_key .to_cryptography_key (), ec .EllipticCurvePublicKey ):
983+ curve_class = der_public_key .public_numbers ().curve
984+ x = der_public_key .public_numbers ().x
985+ y = der_public_key .public_numbers ().y
986+
987+ pubk_curve = public_key .to_cryptography_key ().public_numbers ().curve
988+ pubk_x = public_key .to_cryptography_key ().public_numbers ().x
989+ pubk_y = public_key .to_cryptography_key ().public_numbers ().y
990+
991+ return curve_class == pubk_curve and x == pubk_x and y == pubk_y
992+
993+ elif "dsa-" in signature_alg \
994+ and isinstance (der_public_key , dsa .DSAPublicKey ) \
995+ and isinstance (public_key .to_cryptography_key (), dsa .DSAPublicKey ):
996+ p = der_public_key .public_numbers ().parameter_numbers ().p
997+ q = der_public_key .public_numbers ().parameter_numbers ().q
998+ g = der_public_key .public_numbers ().parameter_numbers ().g
999+
1000+ pubk_p = public_key .to_cryptography_key ().public_numbers ().p
1001+ pubk_q = public_key .to_cryptography_key ().public_numbers ().q
1002+ pubk_g = public_key .to_cryptography_key ().public_numbers ().g
1003+
1004+ return p == pubk_p and q == pubk_q and g == pubk_g
1005+
1006+ elif "rsa-" in signature_alg \
1007+ and isinstance (der_public_key , rsa .RSAPublicKey ) \
1008+ and isinstance (public_key .to_cryptography_key (), rsa .RSAPublicKey ):
1009+ n = der_public_key .public_numbers ().n
1010+ e = der_public_key .public_numbers ().e
1011+
1012+ pubk_n = public_key .to_cryptography_key ().public_numbers ().n
1013+ pubk_e = public_key .to_cryptography_key ().public_numbers ().e
1014+
1015+ return n == pubk_n and e == pubk_e
1016+
1017+ raise NotImplementedError ()
1018+
9261019 def _get_long (self , element , query , require = True ):
9271020 result = self ._find (element , query , require = require )
9281021 if result is not None :
0 commit comments