Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Verify digital signature in SAML response against certificate in PHP

Tags:

I am a newbie to SSL certificate thing. so a little cautious about what I've done so far. I am creating an application that uses SSO to authenticate the users using PHP 5.4. What I have: a certificate (.pfx) provided by the party. encrypted SAML in POST variable.

The de-crypted xml is almost similar to SAML: Why is the certificate within the Signature?

I need to verify that the response is from verified provider.. I have come to know while googling around that I need .pem instead of .pfx, So I have converted the .pfx file to .pem using ssl commands. I've used the code from http://www.php.net/manual/es/function.openssl-verify.php#62526. Here is my code.

$encxml=$_POST['SAMLResponse'];
$xml = new SimpleXMLElement(base64_decode($encxml)); 
$signature = ((string)$xml->Signature->SignatureValue);
var_dump($signature);


//do I need to do something with this X509Certificate value embedded in xml??
$cert = ((string)$xml->Signature->KeyInfo->X509Data->X509Certificate);
var_dump($cert);

//Or I need
$fp = fopen("xyz.pem", "r");
$priv_key = fread($fp, 8192);
fclose($fp);
print_r($priv_key);
$ok = openssl_verify($xml, $signature, $priv_key);

So should I ignore the X509Certificate embedded in xml or I need to check it as well... will openssl_verify suffice? and am I on the right path? please any guidance will be appreciated.

like image 936
MJ Khan Avatar asked Oct 23 '13 09:10

MJ Khan


People also ask

How do I verify a SAML signature?

In order to validate the signature, the X. 509 public certificate of the Identity Provider is required Check signature inside the assertion: Select assertion option if the signature will be present inside the SAML assertion itself. Base64. SAML protocol uses the base64 encoding algorithm when exchanging SAML messages.

What is signature in SAML response?

A SAML (Security Assertions Markup Language) authentication assertion is issued as proof of an authentication event. Typically an end-user will authenticate to an intermediary, who generates a SAML authentication assertion to prove that it has authenticated the user.

How do you validate a SAML assertion?

From Setup, enter Single Sign-On Settings in the Quick Find box, select Single Sign-On Settings, then click SAML Assertion Validator. Enter the SAML assertion into the text box, and click Validate. Note If your org has multiple SAML SSO configurations, the validator tries to detect the right one.


1 Answers

An XML signed using xmldsig syntax has 3 important parts:

  1. Signature -> KeyInfo contains information about the public key derived from the private key used to sign the data
  2. Signature -> SignedInfo contains the data which is gonna be signed using the private key mentioned above; the data contains information about how the verification should be computed, such as: CanonicalizationMethod, SignatureMethod, Reference
  3. Signature -> SignatureValue contains the value of the signature generated by signing Signature -> SignedInfo with the private key

Theoretically this is how the code should look for an rsa-sha1 algorithm(specified by Signature -> SignedInfo -> SignatureMethod), having the following canonicalization method: Exclusive XML Canonicalization 1.0 (omits comments), and the x509 certificate provided:

$xmlDoc = new DOMDocument();
$xmlDoc->loadXML($xmlString);

$xpath = new DOMXPath($xmlDoc);
$xpath->registerNamespace('secdsig', 'http://www.w3.org/2000/09/xmldsig#');

// fetch Signature node from XML
$query = ".//secdsig:Signature";
$nodeset = $xpath->query($query, $xmlDoc);
$signatureNode = $nodeset->item(0);

// fetch SignedInfo node from XML
$query = "./secdsig:SignedInfo";
$nodeset = $xpath->query($query, $signatureNode);
$signedInfoNode = $nodeset->item(0);

// canonicalize SignedInfo using the method descried in
// ./secdsig:SignedInfo/secdsig:CanonicalizationMethod/@Algorithm
$signedInfoNodeCanonicalized = $signedInfoNode->C14N(true, false);

// fetch the x509 certificate from XML
$query = 'string(./secdsig:KeyInfo/secdsig:X509Data/secdsig:X509Certificate)';
$x509cert = $xpath->evaluate($query, $signatureNode);
// we have to re-wrap the certificate from XML to respect the PEM standard
$x509cert = "-----BEGIN CERTIFICATE-----\n"
    . $x509cert . "\n"
    . "-----END CERTIFICATE-----";
// fetch public key from x509 certificate
$publicKey = openssl_get_publickey($x509cert);

// fetch the signature from XML
$query = 'string(./secdsig:SignatureValue)';
$signature = base64_decode($xpath->evaluate($query, $signatureNode));

// verify the signature
$ok = openssl_verify($signedInfoNodeCanonicalized, $signature, $publicKey);    

This lib does a good job at implementing xmldsig in php: xmlseclibs; an example of how to verify an xmldsig can be found here: https://github.com/robrichards/xmlseclibs/blob/master/tests/xmlsec-verify.phpt. This library also validates the digest value from Signature -> SignedInfo -> Reference, a step which I omitted above.

like image 61
godvsdeity Avatar answered Sep 19 '22 17:09

godvsdeity