[OpenSAML] SAMLResponse signature verification

2,647 views
Skip to first unread message

jc.est...@cnamts.fr

unread,
Mar 2, 2010, 4:16:26 AM3/2/10
to mace-open...@internet2.edu
Hello,

I have to verify the signature of a signed SAMLResponse .

I obtain the exception :
org.opensaml.xml.validation.ValidationException: Signature did not validate against the credential's key

The used credential (X509 certificat) is the good one.
Putting the debug log for org.apache.xml.security.utils.
I obtain :
[org.apache.xml.security.utils.DigesterOutputStream] Pre-digested input:
[org.apache.xml.security.utils.DigesterOutputStream] <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Destination="https://comptePS/ACS" ID="_6bf020b4-2334-11df-833b-d91e3055817a" IssueInstant="2010-02-27T00:09:50Z" Version="2.0" xsi:schemaLocation="urn:oasis:names:tc:SAML:2.0:assertion http://docs.oasis-open.org/security/saml/v2.0/saml-schema-assertion-2.0.xsd">
<saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">urn:interops:samu:1.0</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"></samlp:StatusCode>
</samlp:Status>
</samlp:Response>
[org.apache.xml.security.signature.Reference] Verification failed for URI "#_6bf020b4-2334-11df-833b-d91e3055817a"
[org.apache.xml.security.signature.Reference] Expected Digest: oju8vu1ZMmqMfYMU4uJHT9sdPmQ=
[org.apache.xml.security.signature.Reference] Actual Digest: lCMYYIs+Pv0q2II32b1s7EXgS2Q=
[org.apache.xml.security.signature.Manifest] The Reference has Type


ONLY the saml:Issuer is included in pre-digest input. The saml assertion is not complete.

The signature URI is #_6bf020b4-2334-11df-833b-d91e3055817a and _6bf020b4-2334-11df-833b-d91e3055817a is the ID of the Response including the assertion.

The document is :
<samlp:Response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="_6bf020b4-2334-11df-833b-d91e3055817a" Version="2.0" IssueInstant="2010-02-27T00:09:50Z" Destination="https://comptePS/ACS" xsi:schemaLocation="urn:oasis:names:tc:SAML:2.0:assertion http://docs.oasis-open.org/security/saml/v2.0/saml-schema-assertion-2.0.xsd">
<saml:Issuer>urn:interops:samu:1.0</saml:Issuer><Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="#_6bf020b4-2334-11df-833b-d91e3055817a">
<Transforms>
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>oju8vu1ZMmqMfYMU4uJHT9sdPmQ=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>UCK9adw+i+rfgVdf7OICYsGV++dTqbpH30escUaoHxEGwai1kGPCrJmuyIMwu3Zu
nStX6OeQvD+jnUuz04IsX2lXCRxhJEa99BLGgbOkA93nqCL/bBGgfuQ4+5HnOR/R
FCaEm+bqKolXkj4lKgh0mC9GKfTcrpGyMrKJfAli7oY=</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIICiDCCAfGgAwIBAgIFFQHV8/MwDQYJKoZIhvcNAQEFBQAwOTELMAkGA1UEBhMC
RlIxFDASBgNVBAoTC0NOQU1UUy1URVNUMRQwEgYDVQQLEwtBQy1URVNULVNTTDAe
Fw0wOTAyMjUxMDIwNTFaFw0xOTAxMDQxMDIwNTFaMIGCMQswCQYDVQQGEwJGUjEP
MA0GA1UEChMGQ05BTVRTMRIwEAYDVQQLEwkxODAwMzUwMjQxIDAeBgNVBAMTF3Rl
c3QtaW50ZXJvcHMuY25hbXRzLmZyMSwwKgYKCZImiZPyLGQBARMcdGVzdC1pbnRl
cm9wcy5jbmFtdHMuZnItc2lnbjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
psGwOZyCTWp3aH9mVjUziYKKaPHBpaG8Dm8xhyR5IAzZ9wEPfHlLIYaVWhGoqswV
LC5kn0eq2EFsZSfTTV7AHB+7wBTJAsnflslWjQ9kFYHq05VgKpnGFblad8ATrsl6
jXZa2XknlnCuxsgt606ybm4CaWAOXn19GnNIqxgYmFMCAwEAAaNSMFAwLgYJYIZI
AYb4QgENBCEWH0NlcnRpZmljYXQgc2VydmV1ciBTU0wgaW50cmFuZXQwEQYJYIZI
AYb4QgEBBAQDAgZAMAsGA1UdDwQEAwIFoDANBgkqhkiG9w0BAQUFAAOBgQAUQLv5
dQl5YF62T96BwP93XbIfQ7A46gBtP2soLmDO58kQf0FubT5rAG2z1FLPuWFIeFIe
dlxB9Le20JWWAs8DISKjZxj/furjMWVHEeS9o9YnYUZAzOrFA5fYyD4MnSATHzJc
Z/ON4FYVZ4J4FxljGOOIGwmcRmiKKzcoyU7KEg==</X509Certificate>
</X509Data>
</KeyInfo>
</Signature>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion ID="_6bf039e6-2334-11df-833b-d91e3055817a" Version="2.0" IssueInstant="2010-02-27T00:09:50Z">
<saml:Issuer>urn:interops:samu:1.0</saml:Issuer>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">identifiantTest</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2010-02-27T00:19:50Z" Recipient="urn:interops:180035024:sp"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2010-02-27T00:04:50Z" NotOnOrAfter="2010-02-27T00:19:50Z">
<saml:AudienceRestriction>
<saml:Audience>urn:interops:service:test:samu:compte_ps</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2010-02-26T13:44:13Z" SessionIndex="_6bf039e6-2334-11df-833b-d91e3055817a">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="PAGM">
<saml:AttributeValue>COMPTE_PS</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>


Thanks for your help

JC Estienney

Brent Putman

unread,
Mar 2, 2010, 10:43:11 AM3/2/10
to mace-open...@internet2.edu

On 3/2/10 4:16 AM, jc.est...@cnamts.fr wrote:
>
> [org.apache.xml.security.utils.DigesterOutputStream] Pre-digested input:
> [org.apache.xml.security.utils.DigesterOutputStream] <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Destination="https://comptePS/ACS" ID="_6bf020b4-2334-11df-833b-d91e3055817a" IssueInstant="2010-02-27T00:09:50Z" Version="2.0" xsi:schemaLocation="urn:oasis:names:tc:SAML:2.0:assertion http://docs.oasis-open.org/security/saml/v2.0/saml-schema-assertion-2.0.xsd">
> <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">urn:interops:samu:1.0</saml:Issuer>
> <samlp:Status>
> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"></samlp:StatusCode>
> </samlp:Status>
> </samlp:Response>

It's good that you are noticing this info. In general, the way in which
this is useful, though, is you collect the pre-digested input from both
the signing and validation sides, and compare. In doing that you can
pretty easily spot the differences.

> [org.apache.xml.security.signature.Reference] Verification failed for URI "#_6bf020b4-2334-11df-833b-d91e3055817a"
> [org.apache.xml.security.signature.Reference] Expected Digest: oju8vu1ZMmqMfYMU4uJHT9sdPmQ=
> [org.apache.xml.security.signature.Reference] Actual Digest: lCMYYIs+Pv0q2II32b1s7EXgS2Q=

Yes, this is a clear indication that what you are validating has been
changed from what was signed.


> >
>
> ONLY the saml:Issuer is included in pre-digest input. The saml assertion is not complete.


At first I wasn't sure what you meant, but if you mean that what was
purportedly signed is below, but the validation above is only indicating
a subset of that, then it seems that there is something else majorly
wrong here, not with the signing. Can you visually confirm that the
Assertion is even in the Response that you are receiving? From the
above, it appears that the Assertion is actually omitted from the
Response you are being sent and trying to validate. If the signature was
being generated over the whole document as below, but later the
Assertion is stripped out somehow, that certainly counts as modifying
the document and breaking the signature...

JC Estienney

unread,
Mar 4, 2010, 2:19:03 AM3/4/10
to mace-open...@internet2.edu
Thanks for your answer,

I send this message again because it was rejected because too large.

The signed SamlResponse indicated at the end of my message if dumped just before the unmarshall operation.
After that when i get the assertion form the Response object :

XMLHelper.prettyPrintXML( (Assertion)reponseSAML.getAssertions().get(0))
 give :

<?xml version="1.0" encoding="UTF-8"?>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_6bf039e6-2334-11df-833b-d91e3055817a" IssueInstant="2010-02-27T00:09:50Z" Version="2.0">

    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">urn:interops:samu:1.0</saml:Issuer>
    <saml:Subject xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">

      <saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">identifiantTest</saml:NameID>
      <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
        <saml:SubjectConfirmationData NotOnOrAfter="2010-02-27T00:19:50Z" Recipient="urn:interops:180035024:sp"/>
      </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2010-02-27T00:04:50Z" NotOnOrAfter="2010-02-27T00:19:50Z" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">

      <saml:AudienceRestriction>
        <saml:Audience>urn:interops:service:test:samu:compte_ps</saml:Audience>
      </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2010-02-26T13:44:13Z" SessionIndex="_6bf039e6-2334-11df-833b-d91e3055817a" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">

      <saml:AuthnContext>
        <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</saml:AuthnContextClassRef>
      </saml:AuthnContext>
    </saml:AuthnStatement>
    <saml:AttributeStatement xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">

      <saml:Attribute Name="PAGM">
        <saml:AttributeValue>COMPTE_PS</saml:AttributeValue>
      </saml:Attribute>
    </saml:AttributeStatement>
  </saml:Assertion>

I will work to obtain then exact digest stream of then signature operation.
It is not buid by openSaml2  but bye a third tool using C++ xmlsec API.

The verification with the same tool is ok.

Regards
JC Estienney
 

Brent Putman a écrit :


*****************************************************
"Le contenu de ce courriel et ses eventuelles pièces jointes sont confidentiels. Ils s'adressent exclusivement à la personne destinataire. Si cet envoi ne vous est pas destiné, ou si vous l'avez reçu par erreur, et afin de ne pas violer le secret des correspondances, vous ne devez pas le transmettre à d'autres personnes ni le reproduire. Merci de le renvoyer à l'émetteur et de le détruire.

Attention : L'Organisme de l'émetteur du message ne pourra être tenu responsable de l'altération du présent courriel. Il appartient au destinataire de vérifier que les messages et pièces jointes reçus ne contiennent pas de virus. Les opinions contenues dans ce courriel et ses éventuelles pièces jointes sont celles de l'émetteur. Elles ne reflètent pas la position de l'Organisme sauf s'il en est disposé autrement dans le présent courriel."
******************************************************

jc_estienney.vcf

Brent Putman

unread,
Mar 4, 2010, 4:09:28 PM3/4/10
to mace-open...@internet2.edu, JC Estienney

On 3/4/10 2:19 AM, JC Estienney wrote:
>
>
> The signed SamlResponse indicated at the end of my message if dumped
> just before the unmarshall operation.
> After that when i get the assertion form the Response object :
>
> XMLHelper.prettyPrintXML( (Assertion)reponseSAML.getAssertions().get(0))
> give :


Ok, well, the full response there looked ok, and the assertion looks ok
too, as far as I can tell.


>
> I will work to obtain then exact digest stream of then signature operation.
> It is not buid by openSaml2 but bye a third tool using C++ xmlsec API.
>
> The verification with the same tool is ok.


That's fine. The problem though, was this:


> [org.apache.xml.security.utils.DigesterOutputStream] <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Destination="https://comptePS/ACS" ID="_6bf020b4-2334-11df-833b-d91e3055817a" IssueInstant="2010-02-27T00:09:50Z" Version="2.0" xsi:schemaLocation="urn:oasis:names:tc:SAML:2.0:assertion http://docs.oasis-open.org/security/saml/v2.0/saml-schema-assertion-2.0.xsd">
> <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">urn:interops:samu:1.0</saml:Issuer>
> <samlp:Status>
> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"></samlp:StatusCode>
> </samlp:Status>
> </samlp:Response>


If this is the actual output from Apache xmlsec, and hasn't been edited,
etc., then something is wrong, because it's not including the Assertion
in the data over which it's calculating the digest. If you're saying
that you have a trace which shows that the Response does in fact include
the Assertion, then I don't have any explanation for that. Either
something very strange is going on with xmlsec, or there's a bug
somewhere else, maybe in how the DOM is being parsed and built.

Getting the digest stream from the signing side will be helpful in the
long run, but until you figure what's going on here with the missing
Assertion in digest calculation, it's not going to help.

--Brent

JC Estienney

unread,
Mar 10, 2010, 3:26:37 AM3/10/10
to mace-open...@internet2.edu
Hi,

Please excuse this late answer, my responses was rejected because of
their size.
So i tunk it this time dropping the assertions samples..

I found the problème : as you suggested it the SAMLResponse was altered
: by a "printed function :-("
A mashalling operation on the assersion between the Response object
contsruction and the verification had broken this object.
I got the assertion and marshall it to print it but a lot of elements of
the assertion was droped from the response object.
A sample (without signature verification) :

String fic_response = "response.txt";

//Logger logger =
LoggerFactory.getLogger(PbVerifSAML.class.getName());
//logger.info(PbVerifSAML.class.getName());

// Init Config OpenSAML
DefaultBootstrap.bootstrap();

// Configuration du processeur de serialisation
unmarshallerFactory = Configuration.getUnmarshallerFactory();

// Lecture le la reponse SAML et parsing
// Get parser pool manager
BasicParserPool ppMgr = new BasicParserPool();
ppMgr.setNamespaceAware(true);

InputStream is = new ByteArrayInputStream(
Base64.decodeFromFile(fic_response) );
Document inCommonMDDoc = ppMgr.parse(is);
Element racine = inCommonMDDoc.getDocumentElement();

// Preparation de la deserialisation de la racine du doc
Unmarshaller unmarshaller =
unmarshallerFactory.getUnmarshaller(racine);

Response reponseSAML = (Response)
unmarshaller.unmarshall(racine);
System.out.println("Destination : " +
reponseSAML.getDestination());

System.out.println(XMLHelper.prettyPrintXML(reponseSAML.getDOM()));

System.out.println(XMLHelper.prettyPrintXML(reponseSAML.getSignature().getDOM()));
Assertion assertion =
(Assertion)reponseSAML.getAssertions().get(0);
//Validation structurelle de l'assertion SAML
assertion.validate(true);
AssertionMarshaller marshaller = new AssertionMarshaller();
// HERE IS THE PB
Element element = marshaller.marshall(assertion);
// THE object reponseSAML is altered
System.out.println(XMLHelper.prettyPrintXML(element));

System.out.println(XMLHelper.prettyPrintXML(reponseSAML.getSignature().getDOM()));
// THE output is different 2

If i get the assertion after signature verification. it is OK

Excuse me for the inconvenience (and for my english)

JC Estienney

jc_estienney.vcf

Brent Putman

unread,
Mar 10, 2010, 6:21:46 PM3/10/10
to mace-open...@internet2.edu

On 3/10/10 3:26 AM, JC Estienney wrote:
>
>
> // Preparation de la deserialisation de la racine du doc
> Unmarshaller unmarshaller =
> unmarshallerFactory.getUnmarshaller(racine);
>
> Response reponseSAML = (Response)
> unmarshaller.unmarshall(racine);
> System.out.println("Destination : " +
> reponseSAML.getDestination());
>
> System.out.println(XMLHelper.prettyPrintXML(reponseSAML.getDOM()));
>
> System.out.println(XMLHelper.prettyPrintXML(reponseSAML.getSignature().getDOM()));
> Assertion assertion =
> (Assertion)reponseSAML.getAssertions().get(0);
> //Validation structurelle de l'assertion SAML
> assertion.validate(true);
> AssertionMarshaller marshaller = new AssertionMarshaller();
> // HERE IS THE PB
> Element element = marshaller.marshall(assertion);
> // THE object reponseSAML is altered
> System.out.println(XMLHelper.prettyPrintXML(element));
>
>


Ah! Ok, now I see what is going on. Yes, that marshalling operation on
the Assertion is absolutely causing that weird behavior of the Response
with the missing Assertion. The reason: The single-arg
marshall(XMLObject) method impl actually marshalls the XMLObject into a
newly constructed Document. If the XMLObject is already marshalled,
it's not a no-op as you might think, it actually winds up
unconditionally adopting the DOM Element subtree into the new Document,
which removes it from the original DOM tree. Off-hand, I don't know why
the marshaller always unconditionally marshalls into a new Document like
that, rather than detecting whether the target is already marshalled.
Chad might be able to comment further, but it's possible we might need
to look at changing that behavior, or at least provide some option for
not doing that, like an overloaded marshall(XMLObject target, boolean
newDocumentIfAlreadyMarshalled) or something similar. At the very least,
unnecessarily adopting into a new Document is somewhat expensive.

In any case, you probably realize that you don't really need to
re-marshall there, since you just unmarshalled the object, and so it
already has a DOM. Although this perhaps highlights a similar issue
with the API - it nominally wasn't intended that people call getDOM() to
get the XMLObject's Element, but instead call marshall(XMLObject) - but
if marshall() always has potentially unwanted side-effects as it does,
then that's a problem too. For now I suppose the only option is just
use getDOM(), if you need a sub-Element from an already marshalled (or
unmarshalled) tree.

--Brent

Scott Cantor

unread,
Mar 10, 2010, 7:50:42 PM3/10/10
to mace-open...@internet2.edu
> Chad might be able to comment further, but it's possible we might need
> to look at changing that behavior, or at least provide some option for
> not doing that, like an overloaded marshall(XMLObject target, boolean
> newDocumentIfAlreadyMarshalled) or something similar. At the very least,
> unnecessarily adopting into a new Document is somewhat expensive.

FWIW, my code doesn't give you the option, it just reuses the DOM tree if
it's cached, or uses a new document if none is supplied in the call. If I
needed it to do what you're describing, I'd just create my own document to
give it, or release the DOM first.

> In any case, you probably realize that you don't really need to
> re-marshall there, since you just unmarshalled the object, and so it
> already has a DOM. Although this perhaps highlights a similar issue
> with the API - it nominally wasn't intended that people call getDOM() to
> get the XMLObject's Element, but instead call marshall(XMLObject) - but
> if marshall() always has potentially unwanted side-effects as it does,
> then that's a problem too. For now I suppose the only option is just
> use getDOM(), if you need a sub-Element from an already marshalled (or
> unmarshalled) tree.

In my case, I definitely count on the fact that XMLObject::marshall()
returns the existing DOM if I need it, because getDOM() would return NULL if
it didn't have one, pushing extra checks into my code.

-- Scott

winmail.dat

JC Estienney

unread,
Mar 11, 2010, 2:10:00 AM3/11/10
to mace-open...@internet2.edu
OK Thank you for these explanations

Jean-Côme

Scott Cantor a écrit :
Chad might be able to comment further, but it's possible we might need
to look at changing that behavior, or at least provide some option for
not doing that, like an overloaded marshall(XMLObject target, boolean
newDocumentIfAlreadyMarshalled) or something similar. At the very least,
unnecessarily adopting into a new Document is somewhat expensive.
    
FWIW, my code doesn't give you the option, it just reuses the DOM tree if
it's cached, or uses a new document if none is supplied in the call. If I
needed it to do what you're describing, I'd just create my own document to
give it, or release the DOM first.

  
In any case, you probably realize that you don't really need to
re-marshall there, since you just unmarshalled the object, and so it
already has a DOM.  Although this perhaps highlights a similar issue
with the API - it nominally wasn't intended that people call getDOM() to
get the XMLObject's Element, but instead call marshall(XMLObject) - but
if marshall() always has potentially unwanted side-effects as it does,
then that's a problem too.  For now I suppose the only option is just
use getDOM(), if you need a sub-Element from an already marshalled (or
unmarshalled) tree.
    
In my case, I definitely count on the fact that XMLObject::marshall()
returns the existing DOM if I need it, because getDOM() would return NULL if
it didn't have one, pushing extra checks into my code.

-- Scott

  


jc_estienney.vcf

Tom Delorenzi

unread,
Mar 16, 2010, 10:18:27 AM3/16/10
to mace-open...@internet2.edu
We were never able to confirm wether my code was rejecting signatuers as invalid was because of our testbed saml simulator was not signing them correctly or if I was not verifying correctly. We finally got to go up against an existing system machine in a known working situation and unfortunately I am still claiming their signatures are invalid. I know its not as secure but for now we just want to use the public key in the assertion to validate the assertion. Here is what I am doing:
 

KeyInfoCredentialResolver resolver = SecurityHelper.buildBasicInlineKeyInfoResolver();
KeyInfo keyInfo = sig.getKeyInfo();
CriteriaSet criteriaSet =
new
CriteriaSet(new KeyInfoCriteria(keyInfo));
try
{
  for
(Credential cred : resolver.resolve(criteriaSet))
  {
    SignatureValidator sigValidator = new SignatureValidator(cred);
    sigValidator.validate(sig); 
  }
}

Where sig is the signature i pulled out of the SamlResponse. Inspecting the signature shows that it has the right key in there as far as I can tell.

I have had it fail in 2 different spots for 2 different test scenarios. First was using our simulator(homgrown) and the 2nd was having a apache server return back a precanned signed response that our customer provided.
 
The simulator failed in XMLSignature which for me was line 625 doing:

// have SignatureAlgorithm sign the input bytes and compare them to

// the bytes that were stored in the signature.
if (!sa.verify(sigBytes))
 
The precanned one passed that but failed a bit later in Reference.verify() in the following block

byte
[] elemDig = this.getDigestValue();
byte[] calcDig = this.calculateDigest(true);
boolean equal = MessageDigestAlgorithm.isEqual(elemDig, calcDig);
if (!equal) {
  log
.warn("Verification failed for URI \"" + this.getURI() + "\"");
  log.warn("Expected Digest: " + Base64.encode(elemDig));
  log.warn("Actual Digest: " + Base64.encode(calcDig));
}
 
If anyone has any suggestions let me know. Thanks!

Chad La Joie

unread,
Mar 16, 2010, 10:23:37 AM3/16/10
to mace-open...@internet2.edu
Are you sure the document being served by Apache has a valid signature?

On 3/16/10 3:18 PM, Tom Delorenzi wrote:
> We were never able to confirm wether my code was rejecting signatuers as
> invalid was because of our testbed saml simulator was not signing them
> correctly or if I was not verifying correctly. We finally got to go up
> against an existing system machine in a known working situation and
> unfortunately I am still claiming their signatures are invalid. I know
> its not as secure but for now we just want to use the public key in the
> assertion to validate the assertion. Here is what I am doing:
>
>
> KeyInfoCredentialResolver resolver =

> SecurityHelper./buildBasicInlineKeyInfoResolver/();


> KeyInfo keyInfo = sig.getKeyInfo();
> CriteriaSet criteriaSet = new CriteriaSet(new KeyInfoCriteria(keyInfo));
> try
> {
> for (Credential cred : resolver.resolve(criteriaSet))
> {
> SignatureValidator sigValidator = new SignatureValidator(cred);
> sigValidator.validate(sig);
> }
> }
>
> Where sig is the signature i pulled out of the SamlResponse. Inspecting
> the signature shows that it has the right key in there as far as I can tell.
>
> I have had it fail in 2 different spots for 2 different test scenarios.
> First was using our simulator(homgrown) and the 2nd was having a apache
> server return back a precanned signed response that our customer provided.
>
> The simulator failed in XMLSignature which for me was line 625 doing:
>
> // have SignatureAlgorithm sign the input bytes and compare them to
> // the bytes that were stored in the signature.
>
> if (!sa.verify(sigBytes))
>
>
> The precanned one passed that but failed a bit later in
> Reference.verify() in the following block
>
> byte[] elemDig = this.getDigestValue();
> byte[] calcDig = this.calculateDigest(true);

> boolean equal = MessageDigestAlgorithm./isEqual/(elemDig, calcDig);
> if (!equal) {
> / log/.warn("Verification failed for URI \"" + this.getURI() + "\"");
> / log/.warn("Expected Digest: " + Base64./encode/(elemDig));
> / log/.warn("Actual Digest: " + Base64./encode/(calcDig));


> }
>
> If anyone has any suggestions let me know. Thanks!

--
Chad La Joie
www.itumi.biz
trusted identities, delivered

Tom Delorenzi

unread,
Mar 16, 2010, 10:52:29 AM3/16/10
to mace-open...@internet2.edu
Well when I wrote this message I was sure since it's a server that is used in an existing solution. Somebody just came by my desk and told me that some enginer working for the customer told her they may have a bug. I don't know how they could be running in real mode before now if they have a bug but who knows. Does what I did look ok?

Brent Putman

unread,
Mar 16, 2010, 3:46:39 PM3/16/10
to mace-open...@internet2.edu

On 3/16/10 10:18 AM, Tom Delorenzi wrote:
> >
>
> KeyInfoCredentialResolver resolver =
> SecurityHelper./buildBasicInlineKeyInfoResolver/();


> KeyInfo keyInfo = sig.getKeyInfo();
> CriteriaSet criteriaSet = new CriteriaSet(new KeyInfoCriteria(keyInfo));
> try
> {
> for (Credential cred : resolver.resolve(criteriaSet))
> {
> SignatureValidator sigValidator = new SignatureValidator(cred);
> sigValidator.validate(sig);
> }
> }

That code looks fine to me, as far as just validating the signature
against the KeyInfo-supplied key. That code itself can't be causing any
of your problems, it's too simple and too high level. Your failures are
much lower down at the Apache xmlsec layer.


>
> The simulator failed in XMLSignature which for me was line 625 doing:
>
> // have SignatureAlgorithm sign the input bytes and compare them to
> // the bytes that were stored in the signature.
>
> if (!sa.verify(sigBytes))
>


That's indicating a failure to validate the SignedInfo with the supplied
key. I don't think we see this failing as much as the next case.

Nominally either 1) the key is wrong, or else 2) the SignedInfo has been
modified from what was signed, or is at least being evaluated
differently by the verifier than the signer. Assuming the latter is the
case, and that they aren't any obvious ways in which the document is
being modified (intentionally or unintentially reformatted after
signing, possibly by some aspect the
serialization/deserialization/unmarshalling process), one thing you
might check is the canonicalization algorithm in use. If it's not one
of the exclusive ones, then that might be causing it, e.g signing
environment is different than the validation one wrt parent element
namespace decls and so forth.


>
> The precanned one passed that but failed a bit later in
> Reference.verify() in the following block
>
> byte[] elemDig = this.getDigestValue();
> byte[] calcDig = this.calculateDigest(true);

> boolean equal = MessageDigestAlgorithm./isEqual/(elemDig, calcDig);
> if (!equal) {

> / log/.warn("Verification failed for URI \"" + this.getURI() + "\"");


> / log/.warn("Expected Digest: " + Base64./encode/(elemDig));
> / log/.warn("Actual Digest: " + Base64./encode/(calcDig));
> }

That's the more typical case that the target of the signature that was
signed (the target of the Reference) is in some way not the same bytes
that are being verified. That's almost always due to some unintentional
modification of the data (reformattting after the signature, etc), but
could also be the c14n issue above, I'd check that.


>
> If anyone has any suggestions let me know. Thanks!


As always, you'll get some useful info from turning on the Apache xmlsec
logs at DEBUG for categories:


org.apache.xml.security.utils.SignerOutputStream (for the SignedInfo)
org.apache.xml.security.utils.DigesterOutputStream (for the Reference)


Looking at those closely by themselves alone might give you some hints
(i.e. look for what namespace decls might be getting pulled in there by
the canonicalizer), but they are mostly only useful if you have the same
data from the signing side with which to compare. If you can get both,
the problem usually becomes immediately clear - you'll see what the
differences are, and can then usually infer what is causing them in the
source document in the processing flow.

--Brent


Tom Delorenzi

unread,
Mar 16, 2010, 4:13:37 PM3/16/10
to mace-open...@internet2.edu
Thanks brent. Good info.

-----Original Message-----
From: Brent Putman [mailto:put...@georgetown.edu]
Sent: Tuesday, March 16, 2010 2:47 PM
To: mace-open...@internet2.edu
Subject: Re: [OpenSAML] Yet another signature verification problem

Reply all
Reply to author
Forward
0 new messages