Skip to content

Commit 4d7add1

Browse files
committed
Refactor
2 parents baec1c7 + 04b6adb commit 4d7add1

File tree

1 file changed

+119
-19
lines changed
  • core/src/main/java/com/onelogin/saml2/util

1 file changed

+119
-19
lines changed

core/src/main/java/com/onelogin/saml2/util/Util.java

Lines changed: 119 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,12 @@
2828
import java.security.cert.X509Certificate;
2929
import java.security.spec.PKCS8EncodedKeySpec;
3030
import java.util.Calendar;
31+
import java.util.HashMap;
3132
import java.util.HashSet;
3233
import java.util.Iterator;
3334
import java.util.List;
3435
import java.util.Locale;
36+
import java.util.Map;
3537
import java.util.Set;
3638
import java.util.TimeZone;
3739
import java.util.UUID;
@@ -67,7 +69,9 @@
6769
import org.apache.xml.security.encryption.XMLCipher;
6870
import org.apache.xml.security.exceptions.XMLSecurityException;
6971
import org.apache.xml.security.keys.KeyInfo;
72+
import org.apache.xml.security.keys.keyresolver.KeyResolverException;
7073
import org.apache.xml.security.signature.XMLSignature;
74+
import org.apache.xml.security.signature.XMLSignatureException;
7175
import org.apache.xml.security.transforms.Transforms;
7276
import org.apache.xml.security.utils.XMLUtils;
7377
import 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

Comments
 (0)