robrichards / xmlseclibs

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

Signing a request #128

Open PeterPan73 opened 7 years ago

PeterPan73 commented 7 years ago

Hi everyone, So, I'm not very aware of signing certificate requests, please get some help. I have to signing a request with a signature, I have the certificate in the following variants: "cer, csr, key and pfx". I downloaded the library, but I do not know how to run it on a localhost and how to include the files and the certificate. Here's how the final look should look like. I would be very grateful if someone suggested how to do it. There will be beer from me. :)


    <s:Header>
        <wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
            <wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" u:Id="pfx42d63835-893d-9407-1865-5d720a079a94" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">MIIEATCCA..</wsse:BinarySecurityToken>
            <wsu:Timestamp xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="pfxa4b7cfe4-a26a-7eb2-c688-abbd6743084c">
                <wsu:Created>2015-02-03T14:45:38Z</wsu:Created>
                <wsu:Expires>2015-02-03T15:45:38Z</wsu:Expires>
            </wsu:Timestamp>
            <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="#pfxa4b7cfe4-a26a-7eb2-c688-abbd6743084c">
                        <ds:Transforms>
                            <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>exJttinm+zUS5ZnbRfg1yRJ...</ds:DigestValue>
                    </ds:Reference>
                </ds:SignedInfo>
                <ds:SignatureValue>FiUCaQVm8Nmo+0oWdFgmv1Kb75La4CFJqXMJvx3S6Su1X0pmq3451PADhTN....</ds:SignatureValue>
                <ds:KeyInfo>
                    <wsse:SecurityTokenReference>
                        <wsse:Reference URI="#pfx42d63835-893d-9407-1865-5d720a079a94" />
                    </wsse:SecurityTokenReference>
                </ds:KeyInfo>
            </ds:Signature>
        </wsse:Security>
    </s:Header>
    <s:Body></s:Body>
</s:Envelope>`
thijzert commented 7 years ago

Here's a fullish example of creating a signature, hope it helps:

$doc = new DOMDocument();
$root = $doc->createElementNS( SOAPENV, "soap:Envelope" );
$root->setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns:soap", "http://schemas.xmlsoap.org/soap/envelope/" );
$root->setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns:wssec", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" );
$root->setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" );
$root->setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns:wsa", "http://www.w3.org/2005/08/addressing" );
$root->setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns:ds", "http://www.w3.org/2000/09/xmldsig#" );
$doc->appendChild( $root );

$header = $doc->createElementNS( "http://schemas.xmlsoap.org/soap/envelope/", "soap:Header" );
$body = $doc->createElementNS( "http://schemas.xmlsoap.org/soap/envelope/", "soap:Body" );
$root->appendChild( $header );
$root->appendChild( $body );

$signed_refs = [ $body ];

$security_node = $doc->createElementNS( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "wssec:Security" );
$header->appendChild( $security_node );

$ts = $doc->createElementNS( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Timestamp" );
$ts->appendChild( $doc->createElementNS( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Created", gmdate("Y-m-d\\TH:i:s\\Z") ) );
$security_node->appendChild( $ts );
$signed_refs[] = $ts;

$SOAPAction = "http://example.org/i/friggin/hate/SOAP/exampleRequest";
$endpoint = "https://api.example.org/exampleService/1.3";
if ( $endpoint === null )
    $endpoint = "http://www.w3.org/2005/08/addressing/anonymous";

$header->appendChild( $signed_refs[] = $doc->createElementNS( "http://www.w3.org/2005/08/addressing", "wsa:Action", $SOAPAction ) );
$header->appendChild( $signed_refs[] = $doc->createElementNS( "http://www.w3.org/2005/08/addressing", "wsa:To", $endpoint ) );
$header->appendChild( $signed_refs[] = $doc->createElementNS( "http://www.w3.org/2005/08/addressing", "wsa:MessageID", new_guid() ) );

sign_here_please( $doc, $security_node, $signed_refs );
echo $doc->saveXml();

$cert_file = "/path/to/certificate.cer";
$cert_key  = "/path/to/certificate.key";
$password  = "monkey";

function sign_here_please( DOMDocument &$doc, DOMElement &$dotted_line, $refs = [] )
{
    global $cert_file, $cert_key, $password;

    // Create a new Security object 
    $objDSig = new XMLSecurityDSig();
    // $objDSig->sigNode->ownerDocument->formatOutput = true;

    // Use the c14n exclusive canonicalization
    $objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);

    foreach ( $refs as $ref )
        $ref->setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" );

    if ( count($refs) == 0 )
        $refs = [ $doc ];

    // Sign using SHA-256
    $objDSig->addReferenceList(
        $refs,
        XMLSecurityDSig::SHA1,
        [ "http://www.w3.org/2001/10/xml-exc-c14n#" ],
        [ "prefix" => "wsu", "id_name" => "Id", "prefix_ns" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "overwrite" => false ]
    );

    // Create a new (private) Security key object
    $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private'));

    // Load the private key
    $objKey->loadKey( $cert_key, TRUE );
    if ( !empty($pass) )
        $objKey->passphrase = $passsword;

    // Sign the XML file
    $objDSig->sign($objKey);

    // Add the associated public key to the signature
    $objDSig->add509CertByReference( file_get_contents($cert_file) );

    // Append the signature to the XML
    $objDSig->appendSignature( $dotted_line, true );
}
PeterPan73 commented 7 years ago

@thijzert Hi thijzert, thanks for the reply. I can not structure the query as it should be (as I gave it above), I've been trying out the code for 10 days, but without success. Do you have any idea what to change to get it?

gmisterk commented 5 years ago

Hi thijzert,

thank you for your code.

Do have any idea how can i add a signed timestamp ?

Regards

thijzert commented 5 years ago

The code above already takes care of adding a wsu:Timestamp containing a wsu:Created, which is signed.

However, this question sounds eerily familiar. Are you asking because you're getting the error A required timestamp is not found? If so, you may want to try setting the Content-Type of your transport request to text/xml rather than application/xml. (Yes, I'm serious.)

gmisterk commented 5 years ago

Hi,

Thank for your reply

Just a precision : When i use SOAPUI, it’works fine !

In the outgoing WS security configuration tab, i add a timestamp WSS entry and my signature entry (so two items)

Like this screenshot.

https://ibb.co/zbBFMJR

gmisterk commented 5 years ago

I am little bit confused by your code, first, i don't have add509CertByReference() function, i've got only add509Cert() and second, how can execute this request with my parameters ? (see $demande)

Thanks for your help so herewith my complete code :

`

require 'vendor/autoload.php';

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

$doc = new DOMDocument(); $root = $doc->createElementNS( 'http://schemas.xmlsoap.org/soap/envelope/', "soap:Envelope" ); $root->setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns:soap", "http://schemas.xmlsoap.org/soap/envelope/" ); $root->setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns:wssec", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" ); $root->setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" ); $root->setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns:wsa", "http://www.w3.org/2005/08/addressing" ); $root->setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns:ds", "http://www.w3.org/2000/09/xmldsig#" ); $doc->appendChild( $root );

$header = $doc->createElementNS( "http://schemas.xmlsoap.org/soap/envelope/", "soap:Header" ); $body = $doc->createElementNS( "http://schemas.xmlsoap.org/soap/envelope/", "soap:Body" ); $root->appendChild( $header ); $root->appendChild( $body );

$signed_refs = [ $body ];

$security_node = $doc->createElementNS( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "wssec:Security" ); $header->appendChild( $security_node );

$ts = $doc->createElementNS( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Timestamp" ); $ts->appendChild( $doc->createElementNS( "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "wsu:Created", gmdate("Y-m-d\TH:i:s\Z") ) ); $security_node->appendChild( $ts ); $signed_refs[] = $ts;

$SOAPAction = "./WSDLfiles/inscr/inscr.wsdl"; $endpoint = "https://mydomaine/inscr/v1";

if ( $endpoint === null ) $endpoint = "http://www.w3.org/2005/08/addressing/anonymous";

$header->appendChild( $signed_refs[] = $doc->createElementNS( "http://www.w3.org/2005/08/addressing", "wsa:Action", $SOAPAction ) ); $header->appendChild( $signed_refs[] = $doc->createElementNS( "http://www.w3.org/2005/08/addressing", "wsa:To", $endpoint ) ); $header->appendChild( $signed_refs[] = $doc->createElementNS( "http://www.w3.org/2005/08/addressing", "wsa:MessageID", gen_uuid() ) );

$cert_file = "cert.crt"; $cert_key = "cert.key"; $password = "mypassword";

sign_here_please( $doc, $security_node, $signed_refs );

function sign_here_please( DOMDocument &$doc, DOMElement &$dotted_line, $refs = [] ) { global $cert_file, $cert_key, $password;

          // Create a new Security object 
          $objDSig = new XMLSecurityDSig();
          // $objDSig->sigNode->ownerDocument->formatOutput = true;

          // Use the c14n exclusive canonicalization
          $objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);

          foreach ( $refs as $ref )
                        $ref->setAttributeNS( "http://www.w3.org/2000/xmlns/", "xmlns:wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" );

          if ( count($refs) == 0 )
                        $refs = [ $doc ];

          // Sign using SHA-256
          $objDSig->addReferenceList(
                        $refs,
                        XMLSecurityDSig::SHA1,
                        [ "http://www.w3.org/2001/10/xml-exc-c14n#" ],
                        [ "prefix" => "wsu", "id_name" => "Id", "prefix_ns" => "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "overwrite" => false ]
          );

          // Create a new (private) Security key object
          $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private'));

          // Load the private key
          $objKey->loadKey( $cert_key, TRUE );
          if ( !empty($pass) )
                        $objKey->passphrase = $passsword;

          // Sign the XML file
          $objDSig->sign($objKey);

          // Add the associated public key to the signature
         // $objDSig->add509CertByReference( file_get_contents($cert_file) );

//////////function add509CertByReference don't exist $objDSig->add509Cert( file_get_contents($cert_file) );

          // Append the signature to the XML
          $objDSig->appendSignature( $dotted_line, true );

          return $objDSig;

}

$myxml = $doc->saveXml();

$demande = array( "requestIdentification" => gen_uuid(), "privacyLog" => array( "context" => 'ADD_FILE', "number" => 847773), "request" => array( "pumber" => 8123, ) );

$sc = new SoapClient($SOAPAction); $max = $sc->__doRequest($myxml, $endpoint, $SOAPAction, 1);

var_dump($sig); try {

$reponse = $sc->inscr($demande);

var_dump($reponse);

//var_dump($sc->__getLastResponse());

} catch (SoapFault $fault) {

var_dump($fault);

} `

thijzert commented 5 years ago

Ah. I added that function in pull request #96, but that was rejected. You can manually merge that branch in your environment, or find some other way to add the key to the document.

thijzert commented 5 years ago

As for your second question, I think you're using the wrong library for creating a SOAP client. Try following this example: https://github.com/robrichards/wse-php/blob/master/examples/soap-wsa-example.php

gmisterk commented 5 years ago

Hi have tried this new download, but whitout success (2 weeks in the black hole !!)

here is my final xml that work in SOAPUI but not in php

`

$uuid $timestamp INTEGRATOR 123456789 123456789 2018-06-21 2018-09-01 ` I know that my server need a x509 certificat, and signed timestamp, a ticket and timestampSent value. when i use mySoap, he don't add all requered namespace. now, i have this message 'The access to that operation is not allowed', i know that my key and cert are fine (it work with SOAPUI. thank you for any help
gmisterk commented 5 years ago

ok, so now i think i have found something : when i put my xml string to __dorequest() it's work !

exemple :

function __doRequest($request, $location, $saction, $version, $one_way = 0) { $request = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://mywebsite/insc/messages/v1" xmlns:v3="mywebsite/insc/common/identification/v3" xmlns:v5="mywebsite/insc/common/privacylog/v5" xmlns:v11="mywebsite/insc//data/common/date/v1"> <soapenv:Header/> <soapenv:Body> <v1:insc> <v3:requestIdentification> <ticket> $uuid</ticket> <timestampSent> $timestamp </timestampSent> </v3:requestIdentification> <v5:privacyLog> <context>INTEGRATOR</context> <treatmentManagerNumber>123456789</treatmentManagerNumber> </v5:privacyLog> <v1:request> <v1:personNumber>123456789</v1:personNumber> <v1:period> <v11:beginDate>2018-06-21</v11:beginDate> <v11:endDate>2018-09-01</v11:endDate> </v1:period> </v1:request> </v1:insc> </soapenv:Body> </soapenv:Envelope>', $dom = new DOMDocument(); $dom->loadXML($request); ....... }

so maybe my imported xsd don't work fine with this lib ???