Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Validating XML Signatures / SSL Certificate question (using Net::SAML)

by MattP (Novice)
on Apr 04, 2017 at 19:28 UTC ( [id://1187040]=perlquestion: print w/replies, xml ) Need Help??

MattP has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks!

Thanks to help from some of you yesterday I have installed XML::Sig with the hope of being able to validate some XML signatures. I'm not yet having a huge lot of luck with this. I'm actually trying to validate a SAML assertion. I have the Net::SAML2 module installed as well, which seems to have it's own modified version of XML::Sig. The provider of the SAML assertion has my public certificate, and they are successfully sending me assertions - I can read the XML and do what I need to do apart from verifying the signature.

The documentation in the Net::SAML2 module says "When using XML::Sig exclusively to verify a signature, no key needs to be specified during initialization given that the public key should be transmitted with the signature." This has confused the people who are sending me the signed XML as they say the whole point is I need to do whatever it is I need to do with it?! with my own key - presumably my private key - in order to validate the signature.

I am trying to find out exactly what that is as the module isn't doing any of it by the looks of it.

However, I have got as far as getting a certificate out of the signature - as they say it is transmitted with the signature. The certificate that is coming out however is not the same one as I have sent them to use, I'm not sure if it should look identical or not, I have a feeling it should be though. I have also managed to get a public key out of that certificate. There is also a digestValue node in the XML, which should be everything I need to validate the signature.

I have then run my $cert = Crypt::OpenSSL::X509->new_from_string($certificate);. This is the $certificate that they have sent me. The particular line of code I can see that checks the validity is:

if ($rsa_pub->verify( $canonical, $bin_signature )) {

- at this point I have base64 decoded the signature to $bin_signature, $canonical contains the digestValue. $rsa_pub has already been initialised with the public key that I have got out of the certificate.

This verify function consistently returns 0, I am trying to work out why. Knowing very little about certificates I'm not even sure I'm formulating this question very well.

If anyone has had any experience with any of this - done any work with decoding XML signatures or SAML processing, I'd be hugely happy to hear from them right now!

Many thanks - Matt.

Replies are listed 'Best First'.
Re: Validating XML Signatures / SSL Certificate question (using Net::SAML)
by hippo (Bishop) on Apr 04, 2017 at 22:15 UTC
    they say the whole point is I need to do whatever it is I need to do with it?! with my own key - presumably my private key - in order to validate the signature.

    That doesn't sound right to me. The way PKI works in general is that you verify a signature against the public key of the signer and that is, as you hinted, the certificate (which is in essence a public key) which is transmitted as part of the SAML assertion. You should not have sent the signer your public key for them to use in signing because it will be useless to them. The signer signs with their private key and the recipient validates it with the signer's public key.

    Top tip number 1: use the XML::Sig that comes with Net::SAML2. It is in better shape than the standalone version on CPAN.

    Top tip number 2: check everything as you go along in your script and add debugging statements at every turn: extracting the cert, extracting the sig, extracting the signed data, validating that the cert is the one you are expecting, validating the sig, etc. It's very easy to get confused with all this so the more debugging you have the better.

    I've wrestled with this kind of thing several times and it seems that every implementation of SAML is subtly different so be prepared to massage the XML into some sort of standard form.

    Good luck.

      Thank you Hippo for your response.

      As you have probably worked out, I'm pretty new to this sort of thing, it turns out I sent them my key in order that they can check my signatures from my SAML requests - just haven't got to that bit yet.

      So I now understand that they have signed this with their *private* key, and I can do (whatever it is I need to do) by using their public key which is sent as part of the SAML assertion, and I don't need any of my own keys for this. Is that correct? :p

      I have noticed that the XML::Sig module supplied with Net::SAML2 is wildly different from the standalone, thanks. I have been debugging with this, printing out all the bits as I go.

      I can see that it's calling my $rsa_pub = Crypt::OpenSSL::RSA->new_public_key($cert->pubkey) - and the public key in $cert->pubkey looks like a perfectly good public key to me - starting with the text -----BEGIN RSA PUBLIC KEY----, ending with the END - etc.

      Then it calls if ($rsa_pub->verify( $canonical,  $bin_signature )) {

      $bin_signature is a base 64 decoded version of the signature node. $canonical appears to be the value of the "digestValue" node. This is also base64 encoded and I am told it is actually a binary value, but the module doesn't b64 decode this - I don't know if it should or not.

      Either way, trying b64 decoded and the regular $canonical value, the response from this verify command is consistently false.

      Does any of this mean anything to you?!

      Thanks,
      Matt

        So I now understand that they have signed this with their *private* key, and I can do (whatever it is I need to do) by using their public key which is sent as part of the SAML assertion, and I don't need any of my own keys for this. Is that correct? :p

        Yes, that is correct.

        I've had problems in the past with XML::Sig failing to extract the signer's certificate correctly. You might try initialising the XML::Sig object with a local copy of that certificate just in case. eg:

        my $verifier = XML::Sig->new ({ cert => '/path/to/signer/cert.pem' }) +; if ($verifier->verify ($saml_string_decoded) { # now do something with it

        Also this specific version of XML::Sig has proven useful in the past, so you might try it as an alternative to see if it helps any. It does sound now like you are on the right road.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1187040]
Approved by stevieb
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others imbibing at the Monastery: (2)
As of 2024-04-24 16:36 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found