Skip to content

Commit 02a6d2a

Browse files
committed
Improve addSign method. Support DigestMethod. On decrypt method, verify that there is encrypted data
1 parent 1ebbb36 commit 02a6d2a

File tree

8 files changed

+302
-44
lines changed

8 files changed

+302
-44
lines changed

core/src/main/java/com/onelogin/saml2/authn/SamlResponse.java

+10-3
Original file line numberDiff line numberDiff line change
@@ -1065,20 +1065,27 @@ private NodeList query(String nameQuery, Node context) throws XPathExpressionExc
10651065
* @throws SAXException
10661066
* @throws ParserConfigurationException
10671067
* @throws SettingsException
1068+
* @throws ValidationError
10681069
*/
1069-
private Document decryptAssertion(Document dom) throws XPathExpressionException, ParserConfigurationException, SAXException, IOException, SettingsException {
1070+
private Document decryptAssertion(Document dom) throws XPathExpressionException, ParserConfigurationException, SAXException, IOException, SettingsException, ValidationError {
10701071
PrivateKey key = settings.getSPkey();
10711072

10721073
if (key == null) {
10731074
throw new SettingsException("No private key available for decrypt, check settings", SettingsException.PRIVATE_KEY_NOT_FOUND);
10741075
}
10751076

10761077
NodeList encryptedDataNodes = Util.query(dom, "/samlp:Response/saml:EncryptedAssertion/xenc:EncryptedData");
1078+
if (encryptedDataNodes.getLength() == 0) {
1079+
throw new ValidationError("No /samlp:Response/saml:EncryptedAssertion/xenc:EncryptedData element found", ValidationError.MISSING_ENCRYPTED_ELEMENT);
1080+
}
10771081
Element encryptedData = (Element) encryptedDataNodes.item(0);
10781082
Util.decryptElement(encryptedData, key);
10791083

10801084
// We need to Remove the saml:EncryptedAssertion Node
10811085
NodeList AssertionDataNodes = Util.query(dom, "/samlp:Response/saml:EncryptedAssertion/saml:Assertion");
1086+
if (encryptedDataNodes.getLength() == 0) {
1087+
throw new ValidationError("No /samlp:Response/saml:EncryptedAssertion/saml:Assertion element found", ValidationError.MISSING_ENCRYPTED_ELEMENT);
1088+
}
10821089
Node assertionNode = AssertionDataNodes.item(0);
10831090
assertionNode.getParentNode().getParentNode().replaceChild(assertionNode, assertionNode.getParentNode());
10841091

@@ -1099,7 +1106,7 @@ public String getSAMLResponseXml() {
10991106
if (encrypted) {
11001107
xml = Util.convertDocumentToString(decryptedDocument);
11011108
} else {
1102-
xml = samlResponseString;
1109+
xml = samlResponseString;
11031110
}
11041111
return xml;
11051112
}
@@ -1113,7 +1120,7 @@ protected Document getSAMLResponseDocument() {
11131120
if (encrypted) {
11141121
doc = decryptedDocument;
11151122
} else {
1116-
doc = samlResponseDocument;
1123+
doc = samlResponseDocument;
11171124
}
11181125
return doc;
11191126
}

core/src/main/java/com/onelogin/saml2/settings/Metadata.java

+27-3
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.onelogin.saml2.model.Organization;
2424
import com.onelogin.saml2.model.AttributeConsumingService;
2525
import com.onelogin.saml2.model.RequestedAttribute;
26+
import com.onelogin.saml2.util.Constants;
2627
import com.onelogin.saml2.util.Util;
2728

2829
/**
@@ -377,9 +378,32 @@ public final String getMetadataString() {
377378
*/
378379
public static String signMetadata(String metadata, PrivateKey key, X509Certificate cert, String signAlgorithm) throws XPathExpressionException, XMLSecurityException
379380
{
380-
Document metadataDoc = Util.loadXML(metadata);
381-
String signedMetadata = Util.addSign(metadataDoc, key, cert, signAlgorithm);
382-
LOGGER.debug("Signed metadata --> " + signedMetadata);
381+
return signMetadata(metadata, key, cert, signAlgorithm, Constants.SHA1);
382+
}
383+
384+
/**
385+
* Signs the metadata with the key/cert provided
386+
*
387+
* @param metadata
388+
* SAML Metadata XML
389+
* @param key
390+
* Private Key
391+
* @param cert
392+
* x509 Public certificate
393+
* @param signAlgorithm
394+
* Signature Algorithm
395+
* @param digestAlgorithm
396+
* Digest Algorithm
397+
*
398+
* @return string Signed Metadata
399+
* @throws XMLSecurityException
400+
* @throws XPathExpressionException
401+
*/
402+
public static String signMetadata(String metadata, PrivateKey key, X509Certificate cert, String signAlgorithm, String digestAlgorithm) throws XPathExpressionException, XMLSecurityException
403+
{
404+
Document metadataDoc = Util.loadXML(metadata);
405+
String signedMetadata = Util.addSign(metadataDoc, key, cert, signAlgorithm, digestAlgorithm);
406+
LOGGER.debug("Signed metadata --> " + signedMetadata);
383407
return signedMetadata;
384408
}
385409
}

core/src/main/java/com/onelogin/saml2/settings/Saml2Settings.java

+20-1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ public class Saml2Settings {
7171
private String requestedAuthnContextComparison = "exact";
7272
private boolean wantXMLValidation = true;
7373
private String signatureAlgorithm = Constants.RSA_SHA1;
74+
private String digestAlgorithm = Constants.SHA1;
7475
private boolean rejectUnsolicitedResponsesWithInResponseTo = false;
7576

7677
// Compress
@@ -318,6 +319,13 @@ public String getSignatureAlgorithm() {
318319
return signatureAlgorithm;
319320
}
320321

322+
/**
323+
* @return the digestAlgorithm setting value
324+
*/
325+
public String getDigestAlgorithm() {
326+
return digestAlgorithm;
327+
}
328+
321329
/**
322330
* @return SP Contact info
323331
*/
@@ -681,6 +689,16 @@ public void setSignatureAlgorithm(String signatureAlgorithm) {
681689
this.signatureAlgorithm = signatureAlgorithm;
682690
}
683691

692+
/**
693+
* Set the digestAlgorithm setting value
694+
*
695+
* @param digestAlgorithm
696+
* the digestAlgorithm value to be set.
697+
*/
698+
public void setDigestAlgorithm(String digestAlgorithm) {
699+
this.digestAlgorithm = digestAlgorithm;
700+
}
701+
684702
/**
685703
* Controls if unsolicited Responses are rejected if they contain an InResponseTo value.
686704
*
@@ -951,7 +969,8 @@ public String getSPMetadata() throws CertificateEncodingException {
951969
metadataString,
952970
this.getSPkey(),
953971
this.getSPcert(),
954-
this.getSignatureAlgorithm()
972+
this.getSignatureAlgorithm(),
973+
this.getDigestAlgorithm()
955974
);
956975
} catch (Exception e) {
957976
LOGGER.debug("Error executing signMetadata: " + e.getMessage(), e);

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

+83-29
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
* A class that contains several auxiliary methods related to the SAML protocol
9797
*/
9898
public final class Util {
99+
99100
/**
100101
* Private property to construct a logger for this class.
101102
*/
@@ -109,6 +110,11 @@ public final class Util {
109110
/** Indicates if JAXP 1.5 support has been detected. */
110111
private static boolean JAXP_15_SUPPORTED = isJaxp15Supported();
111112

113+
static {
114+
System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true");
115+
org.apache.xml.security.Init.init();
116+
}
117+
112118
private Util() {
113119
//not called
114120
}
@@ -380,7 +386,6 @@ public static Document parseXML(InputSource inputSource) throws ParserConfigurat
380386
* @return the Document object
381387
*/
382388
public static String convertDocumentToString(Document doc, Boolean c14n) {
383-
org.apache.xml.security.Init.init();
384389
ByteArrayOutputStream baos = new ByteArrayOutputStream();
385390
if (c14n) {
386391
XMLUtils.outputDOMc14nWithComments(doc, baos);
@@ -525,8 +530,6 @@ public static X509Certificate loadCert(String certString) throws CertificateExce
525530
* @throws GeneralSecurityException
526531
*/
527532
public static PrivateKey loadPrivateKey(String keyString) throws GeneralSecurityException {
528-
org.apache.xml.security.Init.init();
529-
530533
String extractedKey = formatPrivateKey(keyString, false);
531534
extractedKey = chunkString(extractedKey, 64);
532535
KeyFactory kf = KeyFactory.getInstance("RSA");
@@ -808,8 +811,6 @@ public static String urlDecoder(String input) {
808811
* @throws SignatureException
809812
*/
810813
public static byte[] sign(String text, PrivateKey key, String signAlgorithm) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
811-
org.apache.xml.security.Init.init();
812-
813814
if (signAlgorithm == null) {
814815
signAlgorithm = Constants.RSA_SHA1;
815816
}
@@ -964,8 +965,6 @@ public static Boolean validateMetadataSign(Document doc, X509Certificate cert, S
964965
public static Boolean validateSignNode(Node signNode, X509Certificate cert, String fingerprint, String alg) {
965966
Boolean res = false;
966967
try {
967-
org.apache.xml.security.Init.init();
968-
969968
Element sigElement = (Element) signNode;
970969
XMLSignature signature = new XMLSignature(sigElement, "", true);
971970

@@ -1034,8 +1033,6 @@ public static boolean isAlgorithmWhitelisted(String alg) {
10341033
*/
10351034
public static void decryptElement(Element encryptedDataElement, PrivateKey inputKey) {
10361035
try {
1037-
org.apache.xml.security.Init.init();
1038-
10391036
XMLCipher xmlCipher = XMLCipher.getInstance();
10401037
xmlCipher.init(XMLCipher.DECRYPT_MODE, null);
10411038

@@ -1111,15 +1108,36 @@ public static Document copyDocument(Document source) throws ParserConfigurationE
11111108
* The public certificate
11121109
* @param signAlgorithm
11131110
* Signature Algorithm
1114-
*
1111+
*
11151112
* @return the signed document in string format
1116-
*
1113+
*
11171114
* @throws XMLSecurityException
11181115
* @throws XPathExpressionException
11191116
*/
11201117
public static String addSign(Document document, PrivateKey key, X509Certificate certificate, String signAlgorithm) throws XMLSecurityException, XPathExpressionException {
1121-
org.apache.xml.security.Init.init();
1118+
return addSign(document, key, certificate, signAlgorithm, Constants.SHA1);
1119+
}
11221120

1121+
/**
1122+
* Signs the Document using the specified signature algorithm with the private key and the public certificate.
1123+
*
1124+
* @param document
1125+
* The document to be signed
1126+
* @param key
1127+
* The private key
1128+
* @param certificate
1129+
* The public certificate
1130+
* @param signAlgorithm
1131+
* Signature Algorithm
1132+
* @param digestAlgorithm
1133+
* Digest Algorithm
1134+
*
1135+
* @return the signed document in string format
1136+
*
1137+
* @throws XMLSecurityException
1138+
* @throws XPathExpressionException
1139+
*/
1140+
public static String addSign(Document document, PrivateKey key, X509Certificate certificate, String signAlgorithm, String digestAlgorithm) throws XMLSecurityException, XPathExpressionException {
11231141
// Check arguments.
11241142
if (document == null) {
11251143
throw new IllegalArgumentException("Provided document was null");
@@ -1132,18 +1150,21 @@ public static String addSign(Document document, PrivateKey key, X509Certificate
11321150
if (key == null) {
11331151
throw new IllegalArgumentException("Provided key was null");
11341152
}
1135-
1153+
11361154
if (certificate == null) {
11371155
throw new IllegalArgumentException("Provided certificate was null");
11381156
}
11391157

11401158
if (signAlgorithm == null || signAlgorithm.isEmpty()) {
11411159
signAlgorithm = Constants.RSA_SHA1;
11421160
}
1161+
if (digestAlgorithm == null || digestAlgorithm.isEmpty()) {
1162+
digestAlgorithm = Constants.SHA1;
1163+
}
11431164

1144-
// document.normalizeDocument();
1165+
document.normalizeDocument();
11451166

1146-
String c14nMethod = Constants.C14NEXC_WC;
1167+
String c14nMethod = Constants.C14NEXC;
11471168

11481169
// Signature object
11491170
XMLSignature sig = new XMLSignature(document, null, signAlgorithm, c14nMethod);
@@ -1155,30 +1176,42 @@ public static String addSign(Document document, PrivateKey key, X509Certificate
11551176

11561177
// If Issuer, locate Signature after Issuer, Otherwise as first child.
11571178
NodeList issuerNodes = Util.query(document, "//saml:Issuer", null);
1179+
Element elemToSign = null;
11581180
if (issuerNodes.getLength() > 0) {
11591181
Node issuer = issuerNodes.item(0);
11601182
root.insertBefore(sig.getElement(), issuer.getNextSibling());
1183+
elemToSign = (Element) issuer.getParentNode();
11611184
} else {
1162-
root.insertBefore(sig.getElement(), root.getFirstChild());
1185+
NodeList entitiesDescriptorNodes = Util.query(document, "//md:EntitiesDescriptor", null);
1186+
if (entitiesDescriptorNodes.getLength() > 0) {
1187+
elemToSign = (Element)entitiesDescriptorNodes.item(0);
1188+
} else {
1189+
NodeList entityDescriptorNodes = Util.query(document, "//md:EntityDescriptor", null);
1190+
if (entityDescriptorNodes.getLength() > 0) {
1191+
elemToSign = (Element)entityDescriptorNodes.item(0);
1192+
} else {
1193+
elemToSign = root;
1194+
}
1195+
}
1196+
root.insertBefore(sig.getElement(), elemToSign.getFirstChild());
11631197
}
11641198

1165-
String id = root.getAttribute("ID");
1199+
String id = elemToSign.getAttribute("ID");
11661200

11671201
String reference = id;
11681202
if (!id.isEmpty()) {
1169-
root.setIdAttributeNS(null, "ID", true);
1203+
elemToSign.setIdAttributeNS(null, "ID", true);
11701204
reference = "#" + id;
11711205
}
11721206

11731207
// Create the transform for the document
11741208
Transforms transforms = new Transforms(document);
11751209
transforms.addTransform(Constants.ENVSIG);
1176-
//transforms.addTransform(Transforms.TRANSFORM_C14N_OMIT_COMMENTS);
11771210
transforms.addTransform(c14nMethod);
1178-
sig.addDocument(reference, transforms, Constants.SHA1);
1211+
sig.addDocument(reference, transforms, digestAlgorithm);
11791212

11801213
// Add the certification info
1181-
sig.addKeyInfo(certificate);
1214+
sig.addKeyInfo(certificate);
11821215

11831216
// Sign the document
11841217
sig.sign(key);
@@ -1197,14 +1230,16 @@ public static String addSign(Document document, PrivateKey key, X509Certificate
11971230
* The public certificate
11981231
* @param signAlgorithm
11991232
* Signature Algorithm
1200-
*
1233+
* @param digestAlgorithm
1234+
* Digest Algorithm
1235+
*
12011236
* @return the signed document in string format
12021237
*
12031238
* @throws ParserConfigurationException
12041239
* @throws XMLSecurityException
12051240
* @throws XPathExpressionException
12061241
*/
1207-
public static String addSign(Node node, PrivateKey key, X509Certificate certificate, String signAlgorithm) throws ParserConfigurationException, XPathExpressionException, XMLSecurityException {
1242+
public static String addSign(Node node, PrivateKey key, X509Certificate certificate, String signAlgorithm, String digestAlgorithm) throws ParserConfigurationException, XPathExpressionException, XMLSecurityException {
12081243
// Check arguments.
12091244
if (node == null) {
12101245
throw new IllegalArgumentException("Provided node was null");
@@ -1216,9 +1251,31 @@ public static String addSign(Node node, PrivateKey key, X509Certificate certific
12161251
Node newNode = doc.importNode(node, true);
12171252
doc.appendChild(newNode);
12181253

1219-
return addSign(doc, key, certificate, signAlgorithm);
1220-
}
1221-
1254+
return addSign(doc, key, certificate, signAlgorithm, digestAlgorithm);
1255+
}
1256+
1257+
/**
1258+
* Signs a Node using the specified signature algorithm with the private key and the public certificate.
1259+
*
1260+
* @param node
1261+
* The Node to be signed
1262+
* @param key
1263+
* The private key
1264+
* @param certificate
1265+
* The public certificate
1266+
* @param signAlgorithm
1267+
* Signature Algorithm
1268+
*
1269+
* @return the signed document in string format
1270+
*
1271+
* @throws ParserConfigurationException
1272+
* @throws XMLSecurityException
1273+
* @throws XPathExpressionException
1274+
*/
1275+
public static String addSign(Node node, PrivateKey key, X509Certificate certificate, String signAlgorithm) throws ParserConfigurationException, XPathExpressionException, XMLSecurityException {
1276+
return addSign(node, key, certificate, signAlgorithm, Constants.SHA1);
1277+
}
1278+
12221279
/**
12231280
* Validates signed binary data (Used to validate GET Signature).
12241281
*
@@ -1241,8 +1298,6 @@ public static String addSign(Node node, PrivateKey key, X509Certificate certific
12411298
public static Boolean validateBinarySignature(String signedQuery, byte[] signature, X509Certificate cert, String signAlg) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException {
12421299
Boolean valid = false;
12431300
try {
1244-
org.apache.xml.security.Init.init();
1245-
12461301
String convertedSigAlg = signatureAlgConversion(signAlg);
12471302

12481303
Signature sig = Signature.getInstance(convertedSigAlg); //, provider);
@@ -1278,7 +1333,6 @@ public static Boolean validateBinarySignature(String signedQuery, byte[] signatu
12781333
public static Boolean validateBinarySignature(String signedQuery, byte[] signature, List<X509Certificate> certList, String signAlg) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException {
12791334
Boolean valid = false;
12801335

1281-
org.apache.xml.security.Init.init();
12821336
String convertedSigAlg = signatureAlgConversion(signAlg);
12831337
Signature sig = Signature.getInstance(convertedSigAlg); //, provider);
12841338

0 commit comments

Comments
 (0)