6

I want to verify a signature for a soap request on a soap server implemented in php.

The server code:

$Server = new SoapServer();

$d = new DOMDocument();
$d->load('php://input');

$s = new WSSESoapServer($d);
try {
    if($s->process()) {
        // Valid signature
        $Server->handle($s->saveXML());
    } else {
        throw new Exception('Invalid signature');
    }
} catch (Exception $e) {
    echo "server exception: " . $e;
}

The error:

exception 'Exception' with message 'Error loading key to handle Signature' in /<path>/wse/src/WSSESoapServer.php:146

I have implemented a Client to sign SOAP requests using this library: https://github.com/robrichards/wse-php. There are no examples of how to implement the server...

How do I load the public key to check the signature?

[Edit] I have now been able to load the supplied key using

    $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
    $key->loadKey(CERT, true);

I am no longer getting an error message when validating the signature:

$x = new XMLSecurityDSig();
$d = $x->locateSignature($soapDoc);
$valid = $x->verify($key);

However, $valid is always false. I have no idea if it's because the key is loaded wrong or is actually invalid. I can find very little information on implementing a SOAP server with PHP and no information on implementing a SOAP server that relies on checking a signed request.

CLARIFICATION

  1. My client talks to a remote web service and gets an acknowledgement.

  2. Then the remote server takes some time to process my request.

  3. A remote client (that I have no control over) then makes a request to my service.

The last step is where I have trouble verifying the signature

soulfreshner
  • 366
  • 1
  • 15
  • It seems to me that WSSESoapServer is automatically detecting and validating signatures within a soap message. So your first approach should be ok, you should not need to manually load a key or to verify. But: WSSESoapServer requires that the signed soap message includes the signature AND the public key to verify the signature. – smat88dd Nov 02 '15 at 18:26
  • Are you still interested on a solution or could you fix it yourself? I set up a testing client and server, and could post it as an answer !? Anyways, I could get it up running, the wsse server is validating the signatures without error. – smat88dd Nov 03 '15 at 11:29
  • @smat88dd I think my last edit fixed it by loading the signature. I have no control over the client making the request. I think the public key I have may be invalid because it always evaluates to false. If your solution differs from mine, I would still like to see it. If only to have *some* documentation to refer to. – soulfreshner Nov 03 '15 at 19:42
  • you have no control over the client? but in your initial post you said that you built a client with the library from https://github.com/robrichards/wse-php, and those library and the included examples sign a soap message _and_ include the public signature. what different client are you now using? – smat88dd Nov 04 '15 at 01:31
  • @smat88dd sorry. To clarify: I have a client that makes a request to a web service. This part works fine. The query takes some time to process. Then the client on the other end makes a request to my web service. I do not have control over the remote client, but I need to build the server to handle the request and I'm unsure if I implemented the server correctly. – soulfreshner Nov 04 '15 at 02:12

1 Answers1

0

Well anyways, your first approach looks fine to me, my server has the same structure. Unfortunately, WSSESoapServer does not inherit from SoapServer, thus is not really an SoapServer, but rather a SoapSignatureValidator and should be called like that. It would be easily possible to correct that behaviour, that one would not need a separate SoapServer instance (should be transparent and automatically).

<?php
require 'soap-server-wsse.php';

try {
    // get soap message
    $xmlSoap = DOMDocument::load('php://input');

    // validate signature
    $validateSignature = new WSSESoapServer($xmlSoap);
    if(!$validateSignature->process())
        file_put_contents("log.txt", "soapserver: SIGNATURE VALIDATION ERROR - CONTINUING WITHOUT SIGNATURE\n", FILE_APPEND);
        //throw new Exception('Invalid Signature'); # this would cancel the execution and not send an answer

    $sServer = new SoapServer($wsdl);
    // actually process the soap message and create & send answer
    //$sServer->setClass() or setObject() or set setFunction()
    $sServer->handle($validateSignature->saveXML());
} catch (Exception $fault) {
    file_put_contents("log.txt", "soapserver soapfault: ".print_r($fault, true), FILE_APPEND);
}
?>
smat88dd
  • 2,258
  • 2
  • 25
  • 38
  • Oh, btw - this code does actually work, but only when the public key of the signature is included in the soap message. If one wants to provide the public key themselves, changes to `WSSESoapServer` are neccessary. – smat88dd Nov 04 '15 at 11:53
  • ..but this does not answer the question at all. My entire problem is with loading the public key to check the signature. What changes are needed? Thanks for the help, though. At least I can see I'm on the right track – soulfreshner Nov 04 '15 at 19:48
  • I am sorry, let me clarify: WSSESoapServer has no option for you to load a public key. It is made to get the key from inside the soap message. My answer was just partial, because you also had asked how to make server with WSSESoapServer, because there were no examples. – smat88dd Nov 04 '15 at 21:16
  • Ah, ok. Thanks for that :) – soulfreshner Nov 04 '15 at 21:18
  • Uhm actually, I have answered your question in my answer. When you read carefully, I said that you would have to _modify_ the `WSSESoapServer` class to enable loading of user-provided public keys. – smat88dd Nov 04 '15 at 21:20