2828import java .security .cert .X509Certificate ;
2929import java .security .spec .PKCS8EncodedKeySpec ;
3030import java .util .Calendar ;
31+ import java .util .HashMap ;
3132import java .util .HashSet ;
3233import java .util .Iterator ;
3334import java .util .List ;
3435import java .util .Locale ;
36+ import java .util .Map ;
3537import java .util .Set ;
3638import java .util .TimeZone ;
3739import java .util .UUID ;
6769import org .apache .xml .security .encryption .XMLCipher ;
6870import org .apache .xml .security .exceptions .XMLSecurityException ;
6971import org .apache .xml .security .keys .KeyInfo ;
72+ import org .apache .xml .security .keys .keyresolver .KeyResolverException ;
7073import org .apache .xml .security .signature .XMLSignature ;
74+ import org .apache .xml .security .signature .XMLSignatureException ;
7175import org .apache .xml .security .transforms .Transforms ;
7276import org .apache .xml .security .utils .XMLUtils ;
7377import org .joda .time .DateTime ;
@@ -924,12 +928,38 @@ public static boolean validateSign(final Document doc, final List<X509Certificat
924928
925929 if (signatures .getLength () == 1 ) {
926930 final Node signNode = signatures .item (0 );
931+
932+ Map <String ,Object > signatureData = getSignatureData (signNode , alg );
933+ if (signatureData .isEmpty ()) {
934+ return false ;
935+ }
936+ XMLSignature signature = (XMLSignature ) signatureData .get ("signature" );
937+ X509Certificate extractedCert = (X509Certificate ) signatureData .get ("cert" );
938+ String extractedFingerprint = (String ) signatureData .get ("fingerprint" );
939+
927940 if (certList == null || certList .isEmpty ()) {
928- return validateSignNode (signNode , null , fingerprint , alg );
941+ return validateSignNode (signature , null , fingerprint , extractedCert , extractedFingerprint );
929942 } else {
943+ Boolean certMatches = false ;
930944 for (X509Certificate cert : certList ) {
931- if (validateSignNode (signNode , cert , fingerprint , alg ))
932- return true ;
945+ if (cert != null && extractedFingerprint != null ) {
946+ if (extractedFingerprint .equals (calculateX509Fingerprint (cert , alg ))) {
947+ certMatches = true ;
948+
949+ if (validateSignNode (signature , cert , null , null , null )) {
950+ return true ;
951+ }
952+ } else {
953+ continue ;
954+ }
955+ } else {
956+ if (validateSignNode (signature , cert , fingerprint , extractedCert , extractedFingerprint )) {
957+ return true ;
958+ }
959+ }
960+ }
961+ if (certMatches == false ) {
962+ LOGGER .warn ("Certificate used in the document does not match any registered certificate" );
933963 }
934964 }
935965 }
@@ -982,6 +1012,51 @@ public static Boolean validateMetadataSign(Document doc, X509Certificate cert, S
9821012 }
9831013
9841014 /**
1015+ * Validate signature (Metadata).
1016+ *
1017+ * @param doc
1018+ * The document we should validate
1019+ * @param cert
1020+ * The public certificate
1021+ * @param fingerprint
1022+ * The fingerprint of the public certificate
1023+ * @param alg
1024+ * The signature algorithm method
1025+ *
1026+ * @return True if the sign is valid, false otherwise.
1027+ */
1028+ private static Map <String ,Object > getSignatureData (Node signNode , String alg ) {
1029+ Map <String ,Object > signatureData = new HashMap <>();
1030+ try {
1031+ Element sigElement = (Element ) signNode ;
1032+ XMLSignature signature = new XMLSignature (sigElement , "" , true );
1033+
1034+ String sigMethodAlg = signature .getSignedInfo ().getSignatureMethodURI ();
1035+ if (!isAlgorithmWhitelisted (sigMethodAlg )){
1036+ throw new Exception (sigMethodAlg + " is not a valid supported algorithm" );
1037+ }
1038+
1039+ signatureData .put ("signature" , signature );
1040+
1041+ String extractedFingerprint = null ;
1042+ X509Certificate extractedCert = null ;
1043+ KeyInfo keyInfo = signature .getKeyInfo ();
1044+ if (keyInfo != null && keyInfo .containsX509Data ()) {
1045+ extractedCert = keyInfo .getX509Certificate ();
1046+ extractedFingerprint = calculateX509Fingerprint (extractedCert , alg );
1047+
1048+ signatureData .put ("cert" , extractedCert );
1049+ signatureData .put ("fingerprint" , extractedFingerprint );
1050+ } else {
1051+ LOGGER .debug ("No KeyInfo or not x509CertificateData" );
1052+ }
1053+ } catch (Exception e ) {
1054+ LOGGER .warn ("Error executing getSignatureData: " + e .getMessage (), e );
1055+ }
1056+ return signatureData ;
1057+ }
1058+
1059+ /**
9851060 * Validate signature of the Node.
9861061 *
9871062 * @param signNode
@@ -994,31 +1069,56 @@ public static Boolean validateMetadataSign(Document doc, X509Certificate cert, S
9941069 * The signature algorithm method
9951070 *
9961071 * @return True if the sign is valid, false otherwise.
1072+ *
1073+ * @throws Exception
9971074 */
9981075 public static Boolean validateSignNode (Node signNode , X509Certificate cert , String fingerprint , String alg ) {
999- Boolean res = false ;
1000- try {
1001- Element sigElement = ( Element ) signNode ;
1002- XMLSignature signature = new XMLSignature ( sigElement , "" , true );
1076+ Map < String , Object > signatureData = getSignatureData ( signNode , alg ) ;
1077+ if ( signatureData . isEmpty ()) {
1078+ return false ;
1079+ }
10031080
1004- String sigMethodAlg = signature .getSignedInfo ().getSignatureMethodURI ();
1005- if (!isAlgorithmWhitelisted (sigMethodAlg )){
1006- throw new Exception (sigMethodAlg + " is not a valid supported algorithm" );
1007- }
1081+ XMLSignature signature = (XMLSignature ) signatureData .get ("signature" );
1082+ X509Certificate extractedCert = (X509Certificate ) signatureData .get ("cert" );
1083+ String extractedFingerprint = (String ) signatureData .get ("fingerprint" );
1084+
1085+ return validateSignNode (signature , cert , fingerprint , extractedCert , extractedFingerprint );
1086+ }
10081087
1088+ /**
1089+ * Validate signature of the Node.
1090+ *
1091+ * @param signature
1092+ * XMLSignature we should validate
1093+ * @param cert
1094+ * The public certificate
1095+ * @param fingerprint
1096+ * The fingerprint of the public certificate
1097+ * @param extractedCert
1098+ * The cert extracted from the signNode
1099+ * @param extractedFingerprint
1100+ * The fingerprint extracted from the signNode
1101+ *
1102+ * @return True if the sign is valid, false otherwise.
1103+ */
1104+ public static Boolean validateSignNode (XMLSignature signature , X509Certificate cert , String fingerprint , X509Certificate extractedCert , String extractedFingerprint ) {
1105+ Boolean res = false ;
1106+ try {
10091107 if (cert != null ) {
10101108 res = signature .checkSignatureValue (cert );
1011- } else {
1012- KeyInfo keyInfo = signature .getKeyInfo ();
1013- if (fingerprint != null && keyInfo != null && keyInfo .containsX509Data ()) {
1014- X509Certificate providedCert = keyInfo .getX509Certificate ();
1015- String calculatedFingerprint = calculateX509Fingerprint (providedCert , alg );
1016- for (String fingerprintStr : fingerprint .split ("," )) {
1017- if (calculatedFingerprint .equalsIgnoreCase (fingerprintStr .trim ())) {
1018- res = signature .checkSignatureValue (providedCert );
1109+ } else if (extractedCert != null && fingerprint != null && extractedFingerprint != null ) {
1110+ Boolean fingerprintMatches = false ;
1111+ for (String fingerprintStr : fingerprint .split ("," )) {
1112+ if (extractedFingerprint .equalsIgnoreCase (fingerprintStr .trim ())) {
1113+ fingerprintMatches = true ;
1114+ if (res = signature .checkSignatureValue (extractedCert )) {
1115+ break ;
10191116 }
10201117 }
10211118 }
1119+ if (fingerprintMatches == false ) {
1120+ LOGGER .warn ("Fingerprint of the certificate used in the document does not match any registered fingerprints" );
1121+ }
10221122 }
10231123 } catch (Exception e ) {
10241124 LOGGER .warn ("Error executing validateSignNode: " + e .getMessage (), e );
0 commit comments