robrichards / xmlseclibs

A PHP library for XML Security
BSD 3-Clause "New" or "Revised" License
388 stars 181 forks source link

Signing node and invalid Signature #209

Closed slavo210 closed 4 years ago

slavo210 commented 4 years ago

Hello Guys, I have a problem with signing node in my XML envelope. My code is below:

<?php
session_start();
function getUniqueID($length){
    $chars = "abcdef0123456789";
    $uniqueID1 = "";
    for ($i = 0; $i < $length; $i++) {
        $uniqueID1 .= substr($chars, rand(0, 15), 1);
    }
    $uniqueID2 = "";
    for ($i = 0; $i < $length; $i++) {
        $uniqueID2 .= substr($chars, rand(0, 15), 1);
    }
    return "IS_" . $uniqueID1 . "_" . $uniqueID2;
}

$t = microtime(true);
$micro = sprintf("%06d", ($t - floor($t)) * 1000000);
$d = new DateTime(date('Y-m-d H:i:s.' . $micro, $t));
$IssueInstant = trim($d->format("Y-m-d\TH:i:s.v\Z"));
$Issuer = trim('https://system(...).pl');
$SSOIDvalue = trim(getUniqueID(16));
$SAMLart = trim($_POST['SAMLart']);

require_once 'pz/WSSESoap.php';
require_once 'pz/src/XMLSecurityDSig.php';
require_once 'pz/src/XMLSecurityKey.php';

use RobRichards\XMLSecLibs\XMLSecurityDSig;
use RobRichards\XMLSecLibs\XMLSecurityKey;
use RobRichards\XMLSecLibs\XMLSecEnc;

$xml = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header/><soapenv:Body><saml2p:ArtifactResolve xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Version="2.0" ID="' . $SSOIDvalue . '" IssueInstant="' . $IssueInstant . '"><saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">' . $Issuer . '</saml2:Issuer><saml2p:Artifact>' . $SAMLart . '</saml2p:Artifact></saml2p:ArtifactResolve></soapenv:Body></soapenv:Envelope>';

$results = array();

$doc = new DOMDocument();
$doc->loadXML($xml);
$xp = new DOMXPath($doc);
$xp->registerNamespace('soapenv', 'http://schemas.xmlsoap.org/soap/envelope/');
$xp->registerNamespace('saml2p', 'urn:oasis:names:tc:SAML:2.0:protocol');
$xp->registerNamespace('saml2', 'urn:oasis:names:tc:SAML:2.0:assertion');
$xp->registerNamespace('ds', XMLSecurityDSig::XMLDSIGNS);

$artifactResolveNode = $xp->query('/*[local-name()=\'Envelope\']/*[local-name()=\'Body\']/*[local-name()=\'ArtifactResolve\']')->item(0);
$artifactNode = $xp->query('/*[local-name()=\'Envelope\']/*[local-name()=\'Body\']/*[local-name()=\'ArtifactResolve\']/*[local-name()=\'Artifact\']')->item(0);

if ($artifactResolveNode) {
    $objDSig = new XMLSecurityDSig();
    $objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
    $objDSig->addReference($artifactResolveNode,
        XMLSecurityDSig::SHA256,
        array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', 'http://www.w3.org/2001/10/xml-exc-c14n#'),
        array('id_name' => 'ID', 'overwrite' => false));
    $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type' => 'private'));
    $objKey->loadKey('system(...).pem', TRUE);
    $objKey->passphrase = "passw0rd";
    $objDSig->sign($objKey);
    //$objDSig->sign($objKey, $artifactResolveNode); // this doesn't work too
    $objDSig->add509Cert($results['cert']);
    $objDSig->insertSignature($artifactResolveNode, $artifactNode);
    $envelope = $doc->saveXML();
    echo $envelope;
}

Complete XML Envelope:

<?xml version="1.0"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <soapenv:Header/>
    <soapenv:Body>
        <saml2p:ArtifactResolve xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" Version="2.0"
                                ID="IS_25cb505364e2d986_587fa62a681d2bc8" IssueInstant="2020-06-03T06:45:11.279Z">
            <saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">https://system(...).pl
            </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="#IS_25cb505364e2d986_587fa62a681d2bc8">
                        <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/2001/04/xmlenc#sha256"/>
                        <ds:DigestValue>uVqDL0bTYAsgJG7/3p4DV/GvyNW4dmP3F61C27we2E4=</ds:DigestValue>
                    </ds:Reference>
                </ds:SignedInfo>
                <ds:SignatureValue>
                    TXEzcnFPa25sTENqWmtFLzM5WG(...)GRCNGdRPT0=
                </ds:SignatureValue>
                <ds:KeyInfo>
                    <ds:X509Data>
                        <ds:X509Certificate>
                            MIIEHjCCAw(...)kGJxkgM=
                        </ds:X509Certificate>
                    </ds:X509Data>
                </ds:KeyInfo>
            </ds:Signature>
            <saml2p:Artifact>AAQAAKFbFR94fxqmioAqjJUwfyUtjJbvTvwVmBDXXjy3k+XHwJWWkpwJwaU=</saml2p:Artifact>
        </saml2p:ArtifactResolve>
    </soapenv:Body>
</soapenv:Envelope>

When I validate the envelope on https://tools.chilkat.io/xmlDsigVerify.cshtml I get error: "Signature is Invalid Number of Reference Digests = 1 Reference 1 digest is valid." I try to change code but with no success. Do you see any error in my code?