Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Signature Invalid error #50

Closed
eltiare opened this issue Apr 16, 2015 · 36 comments
Closed

Signature Invalid error #50

eltiare opened this issue Apr 16, 2015 · 36 comments

Comments

@eltiare
Copy link

eltiare commented Apr 16, 2015

I'm tearing my hair out over this one. It seems that no matter what I do I am getting Signature Invalid errors. I'm trying to set up a Shibboleth server to work with a Rails app, and I'm almost there except for this one error. I've put everything with repeatable steps into this example app:

https://github.com/eltiare/libsaml-shib-test

From my reading of the code, it seems that responses are not decrypted. Is that true?

@eltiare
Copy link
Author

eltiare commented Apr 16, 2015

I'm more than happy to write a fix and submit a pull request if you could point me in the right direction(s).

@benoist
Copy link
Contributor

benoist commented Apr 16, 2015

I'll have a look

@benoist
Copy link
Contributor

benoist commented Apr 16, 2015

<?xml version="1.0" encoding="UTF-8"?>
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://lvh.me:3000/saml/consume" ID="_a0194a70f9686e6308fb87b13415a02a" InResponseTo="_5c28e771e69b935fd230c5eb61ac214d59c6717c" IssueInstant="2015-04-16T06:21:00.903Z" Version="2.0">
  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://shibboleth.vagrant.dev/idp/shibboleth</saml2:Issuer>
  <saml2p:Status>
    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </saml2p:Status>
  <saml2:EncryptedAssertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
    <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="_0404ad08a663f724a146473fbe897ea8" Type="http://www.w3.org/2001/04/xmlenc#Element">
      <xenc:EncryptionMethod xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/>
      <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
        <xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="_601996582857612954bc148a5ffe18ef">
          <xenc:EncryptionMethod xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p">
            <ds:DigestMethod xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
          </xenc:EncryptionMethod>
          <ds:KeyInfo>
            <ds:X509Data>
              <ds:X509Certificate>MIIEETCCAvmgAwIBAgIJAL0BwTDFa0YRMA0GCSqGSIb3DQEBBQUAMGIxCzAJBgNVBAYTAlVTMRMw
EQYDVQQIEwpTb21lLVN0YXRlMREwDwYDVQQKEwhLdWFsaS5DbzEOMAwGA1UECxMFUmVhZHkxGzAZ
BgNVBAMTEnVybjpyZWFkeTprdWFsaS5jbzAgFw0xNTA0MTAxOTAwMDJaGA80NzUzMDMwNjE5MDAw
MlowYjELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUtU3RhdGUxETAPBgNVBAoTCEt1YWxpLkNv
MQ4wDAYDVQQLEwVSZWFkeTEbMBkGA1UEAxMSdXJuOnJlYWR5Omt1YWxpLmNvMIIBIjANBgkqhkiG
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Kp+1D20R3Qs1KbuKLXZcHAoofsvMmMuO8W/g+uggPr+glId
RKWCkjBQRfC0aP3S4HSP9MJGNilUUTUsl4PC7onIPSyKqc2X92SYYz3Im4IS301IUXnU1Br+beyL
R3qHcy/hEnu31hvIozYK6qswUyL2CYzJabpwNBIGWOZXtpnTjSio95+MiUElA4wNLTJDZjvK48He
QdiUaylx3l4oUsL+a5Fk4WpTQ6JFKnM+R0hpCj+TEzkM066I3/KrKgJeWoaBLHSTINnXRk2nzrqs
bLGy0ncyzv8w+d1X3k709W6x882ZMnOCA3IxktZh/LM4UAoxrrdKaYGjCyC0y3qVZwIDAQABo4HH
MIHEMB0GA1UdDgQWBBRX+glxNYzipJ9LltZsG+7uVucmoDCBlAYDVR0jBIGMMIGJgBRX+glxNYzi
pJ9LltZsG+7uVucmoKFmpGQwYjELMAkGA1UEBhMCVVMxEzARBgNVBAgTClNvbWUtU3RhdGUxETAP
BgNVBAoTCEt1YWxpLkNvMQ4wDAYDVQQLEwVSZWFkeTEbMBkGA1UEAxMSdXJuOnJlYWR5Omt1YWxp
LmNvggkAvQHBMMVrRhEwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAwfvJhr7pIIo4
tVeUMU8d/civ+5OPt35EyhIHj6fE9LgR0OGe7jR2zZ2GJNFGmgZDud6pJCQUopOnFCvbaHLoka7V
vIIDkR+dokqLBKjSdzfbGYHByygkol6h9/7gyeNhXdiZC/t6wP9TlIIG8GEDahePC8lkAc4DkcVD
pR1FIUsDa4Feej4LGlzIbfbyigB0b83vx6W/6AAHh+ywZF3Rxs92jA5+Of9FNjBGyYRE73PHsJKx
ttQTqOJyhTprL3cmIHXV/9xhtUUCtLuKo3katI+4uTHequV+oN0I7s049TDAitdLJlY3zzJ5EBJP
G4SnT0qG8/SyqyiDflBtj2Q3Bg==</ds:X509Certificate>
            </ds:X509Data>
          </ds:KeyInfo>
          <xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
            <xenc:CipherValue>wkCDA8smrPkg4yyO/i6GegUyxcBWDeqzUNmLpM2G1Lft55vqI5gR5SfE43BOKu/jotGPeGpozXlGvD8xW/4KJARNDYk0qDDmTGV/PUVLrhdT1bbpegV1wLzW23vD8pxl6gEluit04NX51a0SlS/OHvvf61yQJfKPNdQ6JU/3m6XfQaMv9yXJc3c0FDMzinCqkunWX6QZX1z0tONdxCL1Ym3JeftZnxSznf3hsQRFn9hoDH7ddTmck3C2AAP4tlzoHPFlmzXc2bkByPfkoUvgHlseKxr708z8dN21Klik03MVzt5tk4Ye/6ScC7Tb1nQefhG+vqDKludKa9zni/dE0A==</xenc:CipherValue>
          </xenc:CipherData>
        </xenc:EncryptedKey>
      </ds:KeyInfo>
      <xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
        <xenc:CipherValue>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</xenc:CipherValue>
      </xenc:CipherData>
    </xenc:EncryptedData>
  </saml2:EncryptedAssertion>
</saml2p:Response>

This is the response. It's encrypted but does not contain a signature. We always expect the response to have a signature. Decrypting an untrusted message could lead to potential risk hidden in the encrypted message.

@benoist
Copy link
Contributor

benoist commented Apr 16, 2015

I'm not a shibboleth expert and I don't know if you are allowed to make these changes but here's how I got it to work with the setup:

In the relying-party.xml.erb template in the vagrant folder is a block that looks like this

<rp:ProfileConfiguration xsi:type="saml:SAML2SSOProfile" includeAttributeStatement="true" 
                                 assertionLifetime="PT5M" assertionProxyCount="0" 
                                 signResponses="never" signAssertions="always" 
                                 encryptAssertions="conditional" encryptNameIds="never"
                                 includeConditionsNotBefore="true"/>

If you change that to

<rp:ProfileConfiguration xsi:type="saml:SAML2SSOProfile" includeAttributeStatement="true" 
                                 assertionLifetime="PT5M" assertionProxyCount="0" 
                                 signResponses="always" signAssertions="always" 
                                 encryptAssertions="never" encryptNameIds="never"
                                 includeConditionsNotBefore="true"/>

Changing signResponses into always and ecryptAssertions in to never shibboleth is configured successfully. You can also change this in your already configured vagrant box by changing this file

/opt/shibboleth-idp/conf/relying-party.xml

The other change is to change the standard IDP metadata generated by shibboleth. If you change
to

Also change this

def consume
    @response = Saml::Bindings::HTTPPost.receive_message(request, :response)
    if @response.success?
      if session[:authn_request_id] == @response.in_response_to
        render xml: @response.assertion.to_xml
      else
        # handle unrecognized response
      end
      reset_session # It's good practice to reset sessions after authenticating to mitigate session fixation attacks
    else
      # handle failure
    end
  end

restart the rails server

@eltiare
Copy link
Author

eltiare commented Apr 16, 2015

Cool. I will give it a go tomorrow. I'm having to integrate with several different Shibboleth servers - hopefully they will all sign their messages. I suppose on my end I can list the certificate only for signing, not for encrypting. Is there any reason why decryption is not supported in the library for responses?

Thanks so much for your help, btw.

@benoist
Copy link
Contributor

benoist commented Apr 16, 2015

Sure no problem. We really benefit from these cases as we deal with different setups from different clients. So having a library that can work well with other libraries is a win for us.

I'll see if I can change the certificate lookup, so that setting the use is not a requirement.

Decryption is supported, but not documented (yet). There are rspecs written for it so you can find it there for now.
It would be nice if the response object could figure out if it needs decrypting without having to write the code yourself and still have the "@saml_response.assertion" api

update:
I forgot to say that for encrypting and decrypting we use a different library
https://github.com/digidentity/xmlenc
We are using that in production.

@benoist
Copy link
Contributor

benoist commented Apr 16, 2015

I've pushed a change and now it should not be necessary to add the "use" attribute.

@eltiare
Copy link
Author

eltiare commented Apr 16, 2015

Seems like it'd be pretty easy to add xmlenc to this. Just do a detect for the cipher tags and then decrypt the XML before passing it to the other methods.

@benoist
Copy link
Contributor

benoist commented Apr 16, 2015

It's simpler than that, encrypted assertions have there own element.
We just need to decrypt them and add the result to the assertions array on a response.

edit:
Oh shame on me, there is already a function available on a Saml::Response

if you call response.decrypt_assertions(private_key) the assertions are decrypted and added to the assertions list.

@eltiare
Copy link
Author

eltiare commented Apr 16, 2015

Sweet. I'll look into it. I'll update my test app for anyone who wants an example of how to integrate using this library. Thanks again!

@eltiare eltiare closed this as completed Apr 16, 2015
@eltiare
Copy link
Author

eltiare commented Apr 18, 2015

Oy, having trouble with this again. Sorry to be a bother. Turns out that the Shibboleth server that I don't have control over indeed sends back encrypted responses. To handle this, I yanked the code from the library to create the response object and modified it a bit:

omessage = Saml::Encoding.decode_64(request.params["SAMLResponse"])
message = Xmlenc::EncryptedDocument.new(omessage).decrypt(private_key) # This part works just fine
request_or_response = Saml.parse_message(message, :response)
verified_request_or_response = Saml::Util.verify_xml(request_or_response, omessage) # Throws the invalid signature
verified_request_or_response.actual_destination = request.url
verified_request_or_response

I have tried the message variable instead of the omessage variable. I get the same error.

@eltiare eltiare reopened this Apr 18, 2015
@eltiare
Copy link
Author

eltiare commented Apr 18, 2015

Also of note when I attempted to use the request_or_response.decrypt_assertions(private_key), I got a "no method on nil" type of error.

@benoist
Copy link
Contributor

benoist commented Apr 18, 2015

No problem. I'll have a look

@benoist
Copy link
Contributor

benoist commented Apr 18, 2015

Hmm I'm running in to cipher errors. How did you assign the private key variable used in the decrypt method call?

@benoist
Copy link
Contributor

benoist commented Apr 18, 2015

The reason why the signature is invalid might have something to do with whitespaces.
If you can post the base64 encoded version of message

message = Xmlenc::EncryptedDocument.new(omessage).decrypt(private_key)
Base64.encode64(message)

Then I can check the reason why the signature validation might be failing.

Also which version of ruby and which version of OpenSSL do you have installed?

@eltiare
Copy link
Author

eltiare commented Apr 18, 2015

Here's the gist with the updated code and the SAML response: https://gist.github.com/eltiare/d67139fc3bdd3ec52d28

ruby 2.2.1p85
OpenSSL 0.9.8zc 15 Oct 2014

If you send an email to eltiare at gmail.com I will send you the updated metadata.

@eltiare
Copy link
Author

eltiare commented Apr 18, 2015

nm, I just updated the metadata in the gist.

@eltiare
Copy link
Author

eltiare commented Apr 19, 2015

I've made some simple pull requests with changes I needed to make in order to get the code to act like it's working. With those pull requests I have the following code which is throwing the error

    def decode(str)
      unbased = Base64.decode64(str)
      Saml::Encoding.decode_gzip(unbased) || unbased
    end

    def parse_response
      message = decode(params["SAMLResponse"])
      response = Saml.parse_message(message, :response)
      response.decrypt_assertions(response.provider.private_key)
      verified_response = Saml::Util.verify_xml(response, message)
      verified_response.actual_destination = request.url
      verified_response
    end

If I comment out the verified_response parts of parse_response and just return the response variable, I cannot see any of the user attributes being passed by the IDP.

@eltiare
Copy link
Author

eltiare commented Apr 19, 2015

Is there anything else you need from me? I'm at an utter loss as to why I can't get this to work. Every time I try I seem to end up at a dead-end.

@benoist
Copy link
Contributor

benoist commented Apr 19, 2015

I'll have a look tomorrow.


Sent from Mailbox

On Sun, Apr 19, 2015 at 10:41 PM, Jeremy Nicoll notifications@github.com
wrote:

Is there anything else you need from me? I'm at an utter loss as to why I can't get this to work. Every time I try I seem to end up at a dead-end.

Reply to this email directly or view it on GitHub:
#50 (comment)

@eltiare
Copy link
Author

eltiare commented Apr 19, 2015

Thanks. If you can help me resolve this then I will gladly help with the documentation and examples.

@benoist
Copy link
Contributor

benoist commented Apr 20, 2015

Have you changed any settings in the shibboleth server. I've started fresh, followed your instructions in the github repo and I cannot get the document decrypted.

It fails here:
omessage = Saml::Encoding.decode_64(request.params["SAMLResponse"])
message = Xmlenc::EncryptedDocument.new(omessage).decrypt(private_key) # This part works just fine

So I assume you can decrypt the documents with the same code, but I cannot. I've copied the response over to my Xmlenc library to debug further, but it's just not decrypting the cipher value with the assertion in it.

@benoist
Copy link
Contributor

benoist commented Apr 20, 2015

Ok so I've found a tool that will decrypt the message.
This is the response I'm getting

<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Destination="http://lvh.me:3000/saml/consume" ID="_70566d518f1655ba37985b23f7169298" InResponseTo="_9a0411fe3d0cf28644525a3e39469a23368c082e" IssueInstant="2015-04-20T07:37:25.323Z" Version="2.0">
  <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://shibboleth.vagrant.dev/idp/shibboleth
  </saml2:Issuer>
  <saml2p:Status>
    <saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
  </saml2p:Status>
  <saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" ID="_f3be21a4420268b5a4d0f362b59079a4" IssueInstant="2015-04-20T07:37:25.323Z" Version="2.0"><saml2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://shibboleth.vagrant.dev/idp/shibboleth</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/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="#_f3be21a4420268b5a4d0f362b59079a4"><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#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>HZfcJ8WkEGokMWQj00MKOUFSTu0=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>eEL7t2VTTgSoUTzIpf+OYm3CrTJq6A+EEIRAyNLxVEJkjNRY6abKRBhPNharJGBbsbEh9yVW0sRuIU9HFaidzNaFok2oFoX7gm5nMhBL3n3bEmijWFastoc3PQOKYnATXziCfnyRq44rVaqrjKfYOdvifhZ8gjiBExEBHCoJkRp7jiMvbPqy31qAsNzL/IHZLDv5QILCi8iqjVdhNvdOh/2ajKYLrEiSUEb6Wv/8SxOWjMeSrkTLGJ7l0oWaJWeSCCwE3+2+ssBxWsHLOUTf7x9dRsR9RkliTA1zp22EpUpzTgBRnFrnxpLwCG5Iod0/pP+/klpoZ5pnS0U8c0fObg==</ds:SignatureValue><ds:KeyInfo><ds:X509Data><ds:X509Certificate>MIIDRDCCAiygAwIBAgIVAOBBjAUVutk42CWL0RcirPc0cv9/MA0GCSqGSIb3DQEBBQUAMCExHzAd
BgNVBAMTFnNoaWJib2xldGgudmFncmFudC5kZXYwHhcNMTUwNDIwMDcyOTQ1WhcNMzUwNDIwMDcy
OTQ1WjAhMR8wHQYDVQQDExZzaGliYm9sZXRoLnZhZ3JhbnQuZGV2MIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAmyH0D44rQzlgYzHr7RvfhYwcPhYS+GaFGpBj2AZ5152NyTLn7L4UH/lj
WvirJ16K5Qhl4S0vEdCnrtPB6HUfzw9h8iZABfvQ4O1VEkKIeJGskqKleItXdlWYR45d9ATGqFbg
wIpUcUYkpnepi8pJd1etPxEVoDT6kFuabrQBXorJ/Q59+eHfFH8oYG8mEVS0bWwyxFu7Rz8GBRcm
KmzVeObnGQY5izY69/drLK/NbEX1MZRVOpT2L6LbmLXEZZQ7jd/L2mfEjzDBxfQaTs8Fgnl6vqhb
Me1l3ci5SyJObZ3UwXkFy4LDnezs7ghENoSzP6Ah/Sq58kwvWwJ5JTE/QwIDAQABo3MwcTBQBgNV
HREESTBHghZzaGliYm9sZXRoLnZhZ3JhbnQuZGV2hi1odHRwczovL3NoaWJib2xldGgudmFncmFu
dC5kZXYvaWRwL3NoaWJib2xldGgwHQYDVR0OBBYEFHSLABA1TYmg3IH2qUa/2E3yFh4XMA0GCSqG
SIb3DQEBBQUAA4IBAQCMrVvvrEcLtlKZXAV03waZjopDeiq5ByVqLjbyHnmuPixFzvxGDfvRH3rR
ITBTENNHoB6xDnYrw48F+RKtz58b01/SyMvVSQ6UAEtwq1aCxJdWdbfVeBEgbKcPAERQuOZdm13R
Kod2iAu+jlfLIqwVlSgo9YPqw7cfZzXB6ZrKFtjA8SHEmv26Y67EXAUkXd8nXOwXV2MJehfhBwUA
wLxnC7RuVcdR2LRgf7oXbgwiyCJXdNP8S93s2tdLb7+K+Em8iaw4c3wfrBMUWs00P1iUs0KJaCTd
G++LODBKt9wGUIB/AJiV+o4WqRh/jxiybmCVSlNUqoAP8t05jrtm6clF</ds:X509Certificate></ds:X509Data></ds:KeyInfo></ds:Signature><saml2:Subject><saml2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified" NameQualifier="https://shibboleth.vagrant.dev/idp/shibboleth">shibadmin</saml2:NameID><saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"><saml2:SubjectConfirmationData Address="192.168.66.1" InResponseTo="_9a0411fe3d0cf28644525a3e39469a23368c082e" NotOnOrAfter="2015-04-20T07:42:25.323Z" Recipient="http://lvh.me:3000/saml/consume"/></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore="2015-04-20T07:37:25.323Z" NotOnOrAfter="2015-04-20T07:42:25.323Z"><saml2:AudienceRestriction><saml2:Audience>urn:testing:app</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AuthnStatement AuthnInstant="2015-04-20T07:31:04.345Z" SessionIndex="_a2388aad0bff623245c6ae72576004e6"><saml2:SubjectLocality Address="192.168.66.1"/><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement></saml2:Assertion>
</saml2p:Response>

When I run that through the Xmldsig library it can validate the signature.
I've added this as a test case to my library (https://github.com/benoist/xmldsig/tree/master/spec/fixtures/signed)

So the only problem I have now is decrypting the EncryptedAssertion.

@benoist
Copy link
Contributor

benoist commented Apr 20, 2015

Can you show me your stack trace of the error message you are getting?

@eltiare
Copy link
Author

eltiare commented Apr 20, 2015

@benoist The reply and the related metadata that I am working with I posted in the gist earlier. It is more representative of what I will be working with as it is a client dev setup. They know more about Shibboleth than I do. Is it possible for you to use the information in the gist, or do I need to make the necessary changes in the example app? Unfortunately the only way I've been able to decrypt the message from the test setup included in the project is to set the encryption padding to 0 in xmlenc.

http://ruby-doc.org/stdlib-2.0/libdoc/openssl/rdoc/OpenSSL/Cipher.html#method-i-padding-3D

@eltiare
Copy link
Author

eltiare commented Apr 20, 2015

For posterity, this is what I am using to inspect SAML messages: http://www.ssocircle.com/en/1203/saml-request-online-decoder-encoder/

@eltiare
Copy link
Author

eltiare commented Apr 20, 2015

Here is the gist again, just to make sure. The 64 encoded response is named "response.xml.text".

https://gist.github.com/eltiare/d67139fc3bdd3ec52d28

@benoist
Copy link
Contributor

benoist commented Apr 20, 2015

Ah ok, so you were getting the decrypt error as well. That was a vital piece of the puzzle.
From there I can get it to work, it's just the nasty padding issue between java and ruby we need to address. Setting the padding to 0 adds garbage to the end of the assertion. It's most likely that the garbage bytes mess up the signature validation.

@eltiare
Copy link
Author

eltiare commented Apr 20, 2015

Possibly. I didn't need to do it for the client response in the gist, though. I ran into other errors, which is why I made the pull requests.

@benoist
Copy link
Contributor

benoist commented Apr 20, 2015

Yeah I understand, but they way I think libsaml should be working wasn't working because of the cipher error. I will fix that first and the see what errors we run in to next.

@eltiare
Copy link
Author

eltiare commented Apr 20, 2015

Cool. With so many things going on I fear that some things may get lost in translation.

@benoist
Copy link
Contributor

benoist commented Apr 20, 2015

Just an update. I've fixed the padding issue in Xmlenc. Zooming in to the errors you were talking about now. The utility functions are not working properly. The are creating more elements and causing the signature invalid issues.

@eltiare
Copy link
Author

eltiare commented Apr 20, 2015

You have no idea how insanely happy this makes me.

@benoist
Copy link
Contributor

benoist commented Apr 20, 2015

Ok I've got it working with the consume method looking like this and version 2.6.0 of libsaml:

  def consume
    private_key = OpenSSL::PKey::RSA.new(File.open(Rails.root.join('config/ssl/key.pem')).read)

    message     = Saml::Encoding.decode_64(request.params["SAMLResponse"])
    message     = Xmlenc::EncryptedDocument.new(message).decrypt(private_key).gsub!(/>\s*</, "><")

    response = Saml.parse_message(message, :response)
    document = Xmldsig::SignedDocument.new(message)

    signature_valid = document.validate do |signature, data, signature_algorithm|
      response.provider.verify(signature_algorithm, signature, data, response.signature.key_name)
    end

    raise Saml::Errors::SignatureInvalid.new unless signature_valid

    render xml: response.assertion.to_xml
  end

Now there are still 2 big issues with this method:

  1. Xmlenc decryption modifies the assertion, it adds indentation. the gsub removes the whitespace nokogiri added. This only works when the IDP generates messages without whitespace. That is not the case for all IDPS, so depending on the gsub is not the way forward.
  2. Libsaml expects the root element to be signed. In this case it's the response. This is a security measure against attacks where a hacker injects an unsigned element and leaving the signed elements in the xml to fool the signature validation that all signatures are valid.

Issue 1 really needs to be fixed.
Issue 2 I have difficulty with fixing. This is a real security measure. It's bad practice to have unsigned responses. According to the saml spec security considerations (https://www.oasis-open.org/committees/download.php/8733/sstc-saml-sec-consider-2.0-draft-05-diff.pdf) section 6.4.3 actually states that Responses must be signed when using the POST binding.

@eltiare
Copy link
Author

eltiare commented Apr 20, 2015

Yeah, I wouldn't expect you to fix issue 2. I have notified the client that they will need to sign the response element. Will signing the response negate the need to sign the encrypted assertion?

Thanks for the workaround for issue 1. I will use that for now.

And also: holy crap dude. Great work. I look forward to helping write documentation for the project. I'll be taking a break from work this week, but will be coming back next and then I will get on that.

@benoist
Copy link
Contributor

benoist commented Apr 21, 2015

Yes signing the response will negate the need to sign the assertion. There are some use cases where signing both is preferred. This would be the case if an intermediate broker is placed in between and the original assertion needs to be validated at the last SP against the originating IDP.

No problem. It was a challenge but I wouldn't be fun otherwise :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants