Skip to Main Content

Code failing to validate SAML Response on digest

jason.lyleFeb 1 2017 — edited Feb 1 2017

I am attempting to write some java code to verify the XML digital signature of a SAML response. I have verified the SAML response with other tools, so I know it is valid (excluding timing issues, not a factor to the digital signature). Below is the code I have used that I believe should be able to do this validation as well as the signature I am trying to validate.

When I run the code, I get the following output

Signature 0:
..Signature failed core validation
....signature validation status: true
....ref[0, #id14167335278088961501144300] validation status: false

Signature 1:
..Signature passed core validation
....signature validation status: true
....ref[0, #id141673352781342501524143644] validation status: true

I have no idea why the digest for reference id14167335278088961501144300 is not validating. Can anyone shed some light on what I am doing wrong?

Note: I am loading the XSD from a URL in this example so I don't have to include 4 XSD files in my question. However, because of this, the program can take a minute to run. I know this slowdown can be eliminated with local XSD files, it just is not feasible to do that way with the posted code.

XMLDSigVerifier.java:

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Iterator;

import javax.xml.XMLConstants;
import javax.xml.crypto.MarshalException;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.test.dsig.X509KeySelector;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;

import sun.security.provider.X509Factory;

public class XMLDSigVerifier {
  
public static void main (String[] args) throws ParserConfigurationException, SAXException, IOException, KeyStoreException, MarshalException, XMLSignatureException, NoSuchAlgorithmException, CertificateException {
  
//Get XML as a string, will be parameter in final version
  
String sigString = new String(Files.readAllBytes(Paths.get("src/signature.xml")), StandardCharsets.UTF_8);
  
InputSource is = new InputSource();
  is
.setCharacterStream(new StringReader(sigString));

  
//Get X509Certificate as a string, will be parameter in final version
  
String samlCertString= "-----BEGIN CERTIFICATE-----MIIDpDCCAoygAwIBAgIGAVjUwdcaMA0GCSqGSIb3DQEBBQUAMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi02NjI2ODExHDAaBgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wHhcNMTYxMjA2MTUyOTIzWhcNMjYxMjA2MTUzMDIzWjCBkjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtNjYyNjgxMRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvLvIOJ11216IzuqZAbTiAoJy6WYxWuGXeUn4rpYkXLGOO0OoDahzhyquCQgLQC8mGlxCAq8gETQcdL+SX7lOlavHcNYiaYUD9IipMV0Kqt8TgfLO8UuYLb2jNNaQp+0tbcYv4SHpC4nXTndlo2nk3cJVELvXYfvjqKzDvtMwACy37Vc01GZbFQXhSEfBt9J2aQzLPFzH/RxKeOjzKW0kxWgYpfP0NZPtwkHrsdZaqpaR+039v5bckVSQvs0ZMz1Ionv+keWzM6YpQg7sF/OsvN05u0tkrGYDq1BoM9yH1h11bXrVhLvdOjo4bSVjeiAZ2LNOTurGO4JfH+CqT15c5wIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQC8jLBoAM35/6pwtUJ86BhYKvtjB6t3k+5uFRUx8rBWYL5atirRPF73W4f6AIkIp36zkS0os0RHuFK0bG2FPnjQj+FpErd8zji8PVFQ2LZ0WPNLYP7g7BWxAoNct2q0Iw3TACY6h722Cq6WS9ZP4O2iv3kkpo4A7JZvuf4yGGY2nVfx5nLZAmcEA9bZmHhcgmPLs2FBYpLYPs/5P4nd2HeiTJW+F6M75g9E4wG+sf3q2zqzh+AmV5kHffWnGx2MPdUmyFPU80zcDzEpodVU73YUxJIJScwjjXzytuQSB2FcM0TMqwYUq2qGVAPhBw4nnAxeScbMyMbFVDrNyMeejDhq-----END CERTIFICATE-----";
  X509Certificate samlCert
;

  samlCert
= parseCertificate(samlCertString);

  
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());

  ks
.load(null, null);
  ks
.setCertificateEntry("a", samlCert);

  
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
// File xsd = new File("src/saml-schema-protocol-2.0.xsd");
// Schema schema = schemaFactory.newSchema(xsd);
  
Schema schema = schemaFactory.newSchema(new URL("http://docs.oasis-open.org/security/saml/v2.0/saml-schema-protocol-2.0.xsd"));
  
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
  dbf
.setNamespaceAware(true);
  dbf
.setSchema(schema);
  
DocumentBuilder builder = dbf.newDocumentBuilder();
  
Document doc = builder.parse(is);

  
NodeList signatureNodeList = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
  
Node signatureNode;

  
for (int sigIndex = 0; sigIndex < signatureNodeList.getLength(); sigIndex++) {
  signatureNode
= signatureNodeList.item(sigIndex);

  
if (sigIndex > 0) {
  
System.out.println("");
  
}
  
System.out.println("Signature " + sigIndex + ":");

  
DOMValidateContext valContext = new DOMValidateContext(new X509KeySelector(ks), signatureNode);
  valContext
.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE);

  
XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM");
  
XMLSignature signature = factory.unmarshalXMLSignature(valContext);
  
boolean coreValidity = signature.validate(valContext);

  
//Check Validity
  
if (coreValidity == false) {
  
System.err.println("..Signature failed core validation");
  
try {
  
//Sleep because of eclipse bug
  
Thread.sleep(5);
  
} catch (InterruptedException e) {
  e
.printStackTrace();
  
}
  
} else {
  
System.out.println("..Signature passed core validation");
  
}

  
//Check validity Parts
  
//Validity Part 1: Check Signature Validation
  
boolean sv = signature.getSignatureValue().validate(valContext);
  
System.out.println("....signature validation status: " + sv);

  
//Validity Part 2: Check References 
  
Iterator<?> i = signature.getSignedInfo().getReferences().iterator();
  
for (int j = 0; i.hasNext(); j++) {
  
Reference ref = (Reference) i.next();
  
boolean refValid = ref.validate(valContext);
  
System.out.println("....ref[" + j + ", " + ref.getURI() + "] validation status: " + refValid);
  
}
  
}
  
}

  
public static X509Certificate parseCertificate(String certStr) throws CertificateException{

  
byte [] decoded = Base64.decode(
  certStr
  
.replaceAll(X509Factory.BEGIN_CERT, "")
  
.replaceAll(X509Factory.END_CERT, "")
  
);

  
return (X509Certificate)CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(decoded));
  
}
}

signature.xml

<?xml version="1.0" encoding="UTF-8"?><saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="https://apps.surdellpartners.com/ords/kohls_wmj/workamajig/okta/acs/" ID="id14167335278088961501144300" IssueInstant="2017-01-27T18:21:53.483Z" Version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk8y9z9v7FSYL34Y0h7</saml2:Issuer><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/><ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/><ds:Reference URI="#id14167335278088961501144300"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"><ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/></ds:Transform></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>7HyoOBjYlu8fbvSMNIY4O0fc6BhrkAUaPrF9EYWq/wE=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>dOhPiIwGvLJac40XW4x5Xn5soIzImitr/HAxRojDwSbAbfRp9t/VuRFT2Rat5oGgV3tWHedN7VBNpSGzBfZsYMBB/s/WYH0EQisTuS8i

Comments
Post Details
Added on Feb 1 2017
0 comments
2,308 views