Can xmlseclibs help me with ws-security headers for PHP:SOAP?

2,784 views
Skip to first unread message

Bernd

unread,
Mar 30, 2009, 6:25:11 PM3/30/09
to xmlseclibs
Hey everyone!

I'm currently working on my BA thesis, writing a webservice using the
official SOAP extension of PHP 5. This is kind of the first time I use
SOAP, so this stuff is still quite new to me. Today I realised in
horror that the service provider expects me to use ws-security
headers. Obviously the SOAP extension does not support wss headers, so
I'm a litte lost right now. There seems to be some kind of alternative
SOAP framework for PHP that supports wss, but I already implemented
most of my application using PHP:SOAP.

So is there any way to "extend" the official SOAP extension to support
wss? There's not much information on xmlseclibs' Google page, but I
dim this lib could help me. Is this correct or am I mistaken?
Unfortunately I could not find any documentation or examples on how to
use this piece of code.

Eventually my SOAP header should look like this (I stripped some IDs
and signatures, cuz I think they might be confidential):



=============================



<soapenv:Envelope xmlns="" xmlns:soapenv="http://schemas.xmlsoap.org/
soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header xmlns="">
<wsse:Security xmlns="" xmlns:wsse="http://docs.oasis-open.org/wss/
2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:BinarySecurityToken EncodingType="http://docs.oasis-open.org/
wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary"
ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-
x509-token-profile-1.0#X509v3" wsu:Id="CertId-XXXXXXX" xmlns=""
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-
wssecurity-utility-1.0.xsd">A WHOLE BLOCK OF WEIRD CHARACTERS</
wsse:BinarySecurityToken>
<ds:Signature xmlns="" xmlns:ds="http://www.w3.org/2000/09/
xmldsig#">
<ds:SignedInfo xmlns="">
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/
xml-exc-c14n#" xmlns=""/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/
xmldsig#rsa-sha1" xmlns=""/>
<ds:Reference URI="#id-XXXXXXX" xmlns="">
<ds:Transforms xmlns="">
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-
c14n#" xmlns=""/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/
xmldsig#sha1" xmlns=""/>
<ds:DigestValue xmlns="">MORE WEIRD CHARACTERS</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#id-XXXXXXX" xmlns="">
<ds:Transforms xmlns="">
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-
c14n#" xmlns=""/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/
xmldsig#sha1" xmlns=""/>
<ds:DigestValue xmlns="">AND EVEN MORE WEIRD CHARACTERS</
ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue xmlns="">
FURTHER WEIRD CHARACTER SEQUENCES
</ds:SignatureValue>
<ds:KeyInfo Id="KeyId-XXXXXXX" xmlns="">
<wsse:SecurityTokenReference wsu:Id="STRId-XXXXXXX" xmlns=""
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-
wssecurity-utility-1.0.xsd">
<wsse:Reference URI="#CertId-XXXXXXX" ValueType="http://
docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-
profile-1.0#X509v3" xmlns=""/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
<wsu:Timestamp wsu:Id="id-XXXXXXX" xmlns="" xmlns:wsu="http://
docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-
utility-1.0.xsd">
<wsu:Created xmlns="">2009-03-30T10:32:05Z</wsu:Created>
<wsu:Expires xmlns="">2009-03-30T10:37:05Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
</soapenv:Header>



=============================



I guess __setSoapHeaders() won't help a lot, as I don't know how to
create those IDs, signatures and timestamps (do they change on each
request...?). So can xmlseclibs help me with this or am I totally
barking up the wrong tree here?

Thanks in advance for any enlightening hints!

Bernd

Rob Richards

unread,
Mar 31, 2009, 6:23:19 AM3/31/09
to xmlse...@googlegroups.com, xmlse...@discardmail.com
Hi Bernd,

Bernd wrote:
> Hey everyone!
>
> I'm currently working on my BA thesis, writing a webservice using the
> official SOAP extension of PHP 5. This is kind of the first time I use
> SOAP, so this stuff is still quite new to me. Today I realised in
> horror that the service provider expects me to use ws-security
> headers. Obviously the SOAP extension does not support wss headers, so
> I'm a litte lost right now. There seems to be some kind of alternative
> SOAP framework for PHP that supports wss, but I already implemented
> most of my application using PHP:SOAP.
>
> So is there any way to "extend" the official SOAP extension to support
> wss? There's not much information on xmlseclibs' Google page, but I
> dim this lib could help me. Is this correct or am I mistaken?
> Unfortunately I could not find any documentation or examples on how to
> use this piece of code.
>
> Eventually my SOAP header should look like this (I stripped some IDs
> and signatures, cuz I think they might be confidential):
>
>
>

I really need to get around to updating the info page with some of this
stuff.
You can find the related WS-* code and some examples here:
http://cdatazone.org/index.php?/pages/source.html
Let me know if you have any problems.

Rob

Bernd

unread,
Apr 3, 2009, 4:14:42 AM4/3/09
to xmlseclibs
On 31 Mrz., 12:23, Rob Richards <rricha...@cdatazone.org> wrote:
> Hi Bernd,
>
> I really need to get around to updating the info page with some of this
> stuff.
> You can find the related WS-* code and some examples here:http://cdatazone.org/index.php?/pages/source.html
> Let me know if you have any problems.
>
> Rob

Hi Rob,

Thanks for responding. Did I get you right that your xmlseclibs can
generally help me with my problem?

I tried adopting the WS-Security example, but I ran into a problem
very early. Using my keyfile I get this message:

Warning: openssl_sign() [function.openssl-sign]: supplied key param
cannot be coerced into a private key in /var/www/esep/xmlseclibs.php
on line 399

The exception's text is "Failure Signing Data". I'm not entirely sure
whether my keyfile has the correct format at all. I created the file
following the service provider's instructions, using the Java keytool.

Create keystore:
keytool -genkey -keyalg RSA -alias test -keystore test.key

Generate certificate signing request:
keytool -certreq -keystore test.key -alias test -file request.csr

Send CRT to service provider and got my signed cert + CA cert.

Import signed cert + CA cert into keystore:
keytool -import -keystore test.key -alias test -file cert.crt

Finally I used my keystore as PRIVATE_KEY in your example. The
keystore is password-protected, so this won't work out at all, right?
It's quite confusing with all those different file extensions and
encodings.

Bernd

Rob Richards

unread,
Apr 3, 2009, 9:03:25 AM4/3/09
to xmlse...@googlegroups.com, xmlse...@discardmail.com
Bernd wrote:
> On 31 Mrz., 12:23, Rob Richards <rricha...@cdatazone.org> wrote:
>
>> Hi Bernd,
>>
>> I really need to get around to updating the info page with some of this
>> stuff.
>> You can find the related WS-* code and some examples here:http://cdatazone.org/index.php?/pages/source.html
>> Let me know if you have any problems.
>>
>> Rob
>>
>
> Hi Rob,
>
> Thanks for responding. Did I get you right that your xmlseclibs can
> generally help me with my problem?
>
Yes, xmlseclibs serves as the foundation for the WS-Security SOAP wrapper.

> I tried adopting the WS-Security example, but I ran into a problem
> very early. Using my keyfile I get this message:
>
> Warning: openssl_sign() [function.openssl-sign]: supplied key param
> cannot be coerced into a private key in /var/www/esep/xmlseclibs.php
> on line 399
>
> The exception's text is "Failure Signing Data". I'm not entirely sure
> whether my keyfile has the correct format at all. I created the file
> following the service provider's instructions, using the Java keytool.
>
> Create keystore:
> keytool -genkey -keyalg RSA -alias test -keystore test.key
>
> Generate certificate signing request:
> keytool -certreq -keystore test.key -alias test -file request.csr
>
> Send CRT to service provider and got my signed cert + CA cert.
>
> Import signed cert + CA cert into keystore:
> keytool -import -keystore test.key -alias test -file cert.crt
>
> Finally I used my keystore as PRIVATE_KEY in your example. The
> keystore is password-protected, so this won't work out at all, right?
> It's quite confusing with all those different file extensions and
> encodings.
>
>
The keystore is not going to work. That's specific to the java security
stuff.
You need to use files compatible with openssl in order to use the libraries.

For the public cert, you can do the following and pipe it to a file:
keytool -alias {asliasname} -export -rfc

PRIVATE_KEY should be the file containing the private key. Unfortunately
keytool doesn't provide a way to export the private key, so you have to
get at it programatically. something like the following:
example code which output is put into file {pkey}
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("keystorefile"), "password".toCharArray());
Key key = ks.getKey("alais", "password".toCharArray());
System.out.write(key.getEncoded())

openssl enc -in {pkey} -a

The private key file would contain:
-----BEGIN PRIVATE KEY-----
{openssl output}
-----END PRIVATE KEY-----

Hope that helps.

Rob

Bernd

unread,
Apr 3, 2009, 10:57:12 AM4/3/09
to xmlseclibs
Hi Rob,

Thanks again, I really appreciate your support. I read through several
articles about Java keystores (JKS) and PEM files earlier this day.
Furthermore I had a closer look at openssl_sign() in the PHP manual.
They have an example using openssl_get_privatekey() /
openssl_pkey_get_private(). The documentation of these functions
explicitly says, the key has to be passed PEM-formatted. As you
already pointed out, Java keystores aren't PEM formatted and the
keytool cannot export as PEM. I found some pages on Google,
recommending a tool called Keytool GUI to convert the keystore, but
this software didn't work out for me. Then I found Portecle at
http://sourceforge.net/projects/portecle and managed to convert my
keystore to a PEM file.


Just a short how-to, maybe others can take advantage of this:

1. unzip portecle-<version>.zip

2. cd portecle-<version>/

3. java -jar portecle.jar &

4. File -> Open keystore file... -> Select keystore file. -> Enter
keystore passphrase.

5. Right click on Alias. Select export type "Private key and
certificates" and export format "PEM".

6. Confirm, re-enter passphrase and finish export.

Now one gets a PEM file consisting of (at least in my case) two BEGIN-
END CERTIFICATE blocks and a BEGIN-END RSA PRIVATE KEY block.


I then checked the key with this script, I found in the PHP manual's
comments section:

<?php

$passphrase="test";
$priv_key_file_name = ("./private.key");

if (openssl_pkey_get_private(array("file://$priv_key_file_name",
$passphrase)))
{
print "\nPrivate Key OK\n\n";
}
else
{
print "\nPrivate key NOT OK\n\n";
}

?>

The key seems to be okay, even though it's called RSA PRIVATE KEY, not
PRIVATE KEY as you assumed. Is this a problem or will a RSA key work
as well?

In your wss example you don't use a passphrase, so I checked lines
311-315 in xmlseclibs.php. The passphrase is just mentioned twice in
the whole script (member declaration and line 314) und is never set
(correct me, if I am mistaken). Possibly this is a bug or can I set
the password via cryptParams (guess not)?

Anyway, I replaced $this->passphrase with a string containing my
password for testing purposes and the warning disappeared.
Unfortunately there still wasn't a signature added to my SOAP header.
Is this due to my RSA PRIVATE KEY?

Have a good weekend,

Bernd

Rob Richards

unread,
Apr 3, 2009, 12:19:58 PM4/3/09
to xmlse...@googlegroups.com, xmlse...@discardmail.com
Bernd wrote:

<snip />


>
> The key seems to be okay, even though it's called RSA PRIVATE KEY, not
> PRIVATE KEY as you assumed. Is this a problem or will a RSA key work
> as well?
>

Sorry, typo on my side. That code was from the top of my head and I was
thinking about the constant I use within the xmlseclibs library.


> In your wss example you don't use a passphrase, so I checked lines
> 311-315 in xmlseclibs.php. The passphrase is just mentioned twice in
> the whole script (member declaration and line 314) und is never set
> (correct me, if I am mistaken). Possibly this is a bug or can I set
> the password via cryptParams (guess not)?
>

You can set the passphrase on the XMLSecurityKey object prior to loading
the private key.

For example, based on me WS-* Amazon example:
http://www.cdatazone.org/files/ws-amazon.phps

/* create new XMLSec Key using RSA SHA-1 and type is private key */
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1,
array('type'=>'private'));

$objKey->passphrase = {passphrase};

/* load the private key from file - last arg is bool if key in file
(TRUE) or is string (FALSE) */
$objKey->loadKey(PRIVATE_KEY, TRUE);


> Anyway, I replaced $this->passphrase with a string containing my
> password for testing purposes and the warning disappeared.
> Unfortunately there still wasn't a signature added to my SOAP header.
> Is this due to my RSA PRIVATE KEY?
>
>
>

What does your code look like? If the private key was bad, you would
have gotten a warning/error that it couldn't load he key, so I would
assume its good.

Rob

Bernd

unread,
Apr 6, 2009, 4:52:57 AM4/6/09
to xmlseclibs
Good morning Rob,

thanks again for getting back to me.

>
> You can set the passphrase on the XMLSecurityKey object prior to loading
> the private key.
>
Oh sure, passphrase is a public member! Sometime one does not see the
wood for the trees. :-)

My code looks like this right now:

<?php

require_once('soap-wsse.php');

define('PRIVATE_KEY', './private.key');
define('CERT_FILE', './cert.crt');

class MySoapClient extends SoapClient
{
function __doRequest($request, $location, $saction, $version)
{
$doc = new DOMDocument('1.0');
$doc->loadXML($request);

$objWSSE = new WSSESoap($doc);

/* timestamp expires after five minutes */
$objWSSE->addTimestamp(300);

/* create key object, set passphrase and load key */
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array
('type'=>'private'));
$objKey->passphrase = 'My password.';
$objKey->loadKey(PRIVATE_KEY, TRUE);

/* sign message */
$objWSSE->signSoapDoc($objKey);

/* add certificate */
$token = $objWSSE->addBinaryToken(file_get_contents(CERT_FILE));
$objWSSE->attachTokentoSig($token);

// this DOES print the header
// echo $objWSSE->saveXML();

return parent::__doRequest($objWSSE->saveXML(), $location,
$saction, $version);
}
}

// connection options
$options = array(
'soap_version' => SOAP_1_1,
'local_cert' => CERT_FILE,
'connection_timeout' => 20,
'cache_wsdl' => WSDL_CACHE_NONE,
'exceptions' => true,
'user_agent' => 'MySoapClient',
'trace' => true,
);

try
{
$client = new MySoapClient('http://some_ip/server.php?wsdl',
$options);

$message = '<my soap message />';

$result = $client->test($message);
print_r($result);
}
catch (Exception $e)
{
var_dump($e);
}

// this does NOT print the header
echo $client->__getLastRequest();

?>

I expected __getLastRequest() to print the ws-security header as well,
but it doesn't. When I echo $objWSSE->saveXML() I can see the header
and it looks nealy like the one I posted earlier. However the server
keeps denying my connection. I'm not totally sure whether my header is
sent at all. CERT_FILE and local_cert must be set to the CA cert I got
from the service provider, right? So that's not the certificate I
created myself!?

Kind regards,
Bernd

Rob Richards

unread,
Apr 6, 2009, 10:04:05 AM4/6/09
to xmlse...@googlegroups.com
Any modifications which are made in the __doRequest method are not
reflected within the __getLastRequest() call. This is something I would
like to fix in ext/soap, but for now to do debugging, just fo a
file_put_contents() of the saveXML output before returning from the
__doRequest method. Thats the only way to really see what is being sent.

Since your connection is HTTP, don't set the local_cert parameter in the
context.

The cert you should be using is the one you made (or the signed one if
you had it signed by an authority) . Basically all that you are doing
with it in the example above is adding your public key in the header so
that the service provider can pull it from the message and use it to
verify the signature. There might be more that the service you are using
offers because all having their cert would allow you to do is encrypt
data which only they could decrypt or verify any signatures they may
return to you.

Rob

Bernd

unread,
Apr 7, 2009, 4:11:19 AM4/7/09
to xmlseclibs
Good morning Rob,

All right, then I'll log $objWSSE->saveXML() for debug purposes and
remove local_cert. Encryption is done on the transport layer (HTTPS,
SSL), I think the certificate is used for identification and
authorisation only.

The header created by xmlseclibs nearly looks like the service
provider's example.

Minor differences I noticed:
- xmlseclibs does not name IDs (CertId-, #id-, KeyId-, STRId-)
- xmlseclibs does not set empty xmlns attributes
- mustUnderstand is set to 1 (I changed it to 0 manually)

The only major difference is in the KeyInfo node.

Expected:

<ds:KeyInfo Id="KeyId-XXXXXXX" xmlns="">
<wsse:SecurityTokenReference
wsu:Id="STRId-XXXXXXX"
xmlns=""
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/
oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Reference
URI="#CertId-XXXXXXX"
ValueType="http://docs.oasis-open.org/wss/2004/01/
oasis-200401-wss-x509-token-profile-1.0#X509v3"
xmlns=""/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>

Created with xmlseclibs:

<ds:KeyInfo>
<wsse:SecurityTokenReference>
<wsse:Reference URI="#pfxxxxxxxxxxxxxx"/>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>

Might the missing attributes cause a problem?

When I use the signed client certificate, the custom exception is
"Signature invalid". This may have two reasons, the webservice's
specification says: Message and hash do not match or an invalid
certificate was included in the request. I have then replaced the
signed certificate with the cacert for testing and I got:
"Unauthorized". This exception is thrown, when there is no valid login
associated with the certificate (obviously the signature itself was
correct this time?).

So perhaps the header I created still isn't valid for whatever reason.
Can I somehow verify the DigestValues and the SignatureValue for my
signed certificate?

Once again I'm looking forward to hearing from you. :-)

Many thanks,
Bernd

Rob Richards

unread,
Apr 9, 2009, 6:38:25 AM4/9/09
to xmlse...@googlegroups.com
The structure above looks fine. The extra Id tags are not required and
the extra namespace declarations are not needed since they aren't even
used. The only optional attribute that the server might require (though
I doubt its the problem is the ValueType on the Reference element - but
if it were I would expect your test cert usage to fail with the
Signature invalid error as well).

Have you compared your cert with the testing cert to make sure they are
both in the same format and look the same?
I would ask the service provider if they check the signature before or
after the credentials. Also if possible if they could just tell you why
the signature is failing on their end.

I usually verify the signature by running it through a different
validator (such as a test server written in .NET or Java); otherwise if
its a bug in the library you wont know since it was the one creating the
signature.

And you are positive that the private key you are using is the one
associated with your cert? I wonder about that because you didnt mention
using a different private key when using the testing cert.

Rob

Bernd

unread,
Apr 9, 2009, 7:42:41 AM4/9/09
to xmlseclibs
Hello Rob,

> The structure above looks fine. The extra Id tags are not required and
> the extra namespace declarations are not needed since they aren't even
> used. The only optional attribute that the server might require (though
> I doubt its the problem is the ValueType on the Reference element - but
> if it were I would expect your test cert usage to fail with the
> Signature invalid error as well).

I modified soap-wss.php to meet the needs, but though I added the
optional attributes to KeyInfo, my signature is beeing rejected. I'll
check whether they are really required, as soon as the authorisation
succeeds.

> Have you compared your cert with the testing cert to make sure they are
> both in the same format and look the same?

What testing cert? I just have my signed cert (the one I called
"client cert" earlier) and the service provider's cert (I used to call
it "ca cert"). The latter identifies the certificate authority, which
signed my cert. I used the ca cert for testing once, just to check
what happens. Sorry, if this confused you. Of cause that doesn't make
any sense, but however they rejected the ca cert with "unauthorized",
not with "signature invalid". But I'm not sure whether this is better
or worse (i.e. what do they check first?).

> I would ask the service provider if they check the signature before or
> after the credentials. Also if possible if they could just tell you why
> the signature is failing on their end.

I recently emailed them and they told me, my wsuCreated was three
minutes ahead of time. I'm having some server problems right now, so I
could not check on that yet. Maybe they're rejecting the message due
to an invalid timestamp. But I wonder why the ca cert-test didn't fail
then. I'll get back to you on that as soon as my server is back up
running. And I'll ask the service provider for their work order
(signature + credentials).

> And you are positive that the private key you are using is the one
> associated with your cert? I wonder about that because you didnt mention
> using a different private key when using the testing cert.

As I said above, I don't have any test cert. Looking on the certs more
closely, I noticed they have a different length. But I guess the
amount of characters does mean nothing, right?

Once again, thanks for responding. I really appreciate your help. Will
get back to you later this day.

Bernd

Bernd

unread,
Apr 14, 2009, 6:19:56 AM4/14/09
to xmlseclibs
Hi Rob,

adjusting the system clock didn't help. The timestamp is now correct,
but the message is still being rejected. The service provider adviced
me to change my ids, so they match their example, but that didn't help
either. Their logs say a "prefix could not be read". Even they seem to
be a little lost, as my request seems to be correct. They'll get back
to me by the end of this week.

The only difference I could make out is the order of the ds:Reference-
elements, but I think that's no problem causer, right? Or might that
mix up things? The ids match the timestamp's and soap-body's ids.

Bernd

Rob Richards

unread,
Apr 14, 2009, 8:29:31 AM4/14/09
to xmlse...@googlegroups.com, xmlse...@discardmail.com

The id names should not matter unless the provider's devs did some real
bad coding on their end. Order possibly might matter if the provider
requires some specific order (though I dont see any reason they would).

Can you send me the complete SOAP request as well as one of their
complete requests that works?
Who is the service provider if you dont mind me asking? I have run into
a few cases where the provider took some liberties with the XML-DSig
specs so may the problem here. At least they are helping you try to find
where the problem lies, though no idea why it would take them a week
when it could be done form their side in a few minutes.

Rob

Bernd

unread,
Apr 14, 2009, 11:41:08 AM4/14/09
to xmlseclibs
Hi Rob!

Sure, the pattern of the ids shouldn't matter. They just told me to
adjust them, to be sure this isn't the problem causer. I can provide
you with the sample SOAP request and my try, but I don't want to post
them here in public. May I directly email them to you at
rricha...@...tazone.org? The service provider is a rather big telco
and my contact person is on Easter vacation until next week. I think
that's basically why it'll take that long... :-)

Bernd

Rob Richards

unread,
Apr 14, 2009, 11:50:35 AM4/14/09
to xmlse...@googlegroups.com

Yea you can send me them to me directly. Ah that explains the timeframe.
Was a bit surprised when you said it would be a week :)

Rob

Bernd

unread,
Apr 15, 2009, 6:42:33 AM4/15/09
to xmlseclibs
OK, I emailed you last night.

Beside of my major problem, I found two little flaws in you code you
possibly want to check/think about:

1. In soap-wsse.php you have a function called addBinaryToken(). It's
last argument $isDSig is never used in the function.

2. To get a clean implementation of my id-patterns, I derived two new
classes from WSSESoap and XMLSecurityDSig. I think it's better for
maintenance to use inheritance than to modify your libs directly.
However I ran into some problems, because most of your class members +
some functions are declared private. So I changed the visibility of
soapDoc, SOAPXPath and locateSecurityHeader() to protected. I don't
know if this makes sense to you, but maybe it would make things easier
for extensions, if you would use protected instead of private at some
places!?

Bernd

Bernd

unread,
Apr 21, 2009, 9:07:21 AM4/21/09
to xmlseclibs
Hi, it's me again.

Seems like the service providers' employees are too busy to analyse a
student's problem more closely right now. :-( I recently modified the
wss header and added empty xmlns-attributes to each xml element (as in
their example) and changed the SOAP-ENV namespace to soapenv, but it
didn't help. Next would be swapping the two ds:Reference-nodes to fit
the given order. Any suggestions how I could do this most easily?

Furthermore I noticed that they have put "soapenv:encodingStyle" and
"xmlns:ns1" in the message body, more precisely added them to the
method they are calling remotely. PHP:SOAP moved these attributes to
the SOAP-ENV:Envelope in my code. Can I do anything about that?

Sorry for bothering you with that again...

Bernd

Bernd

unread,
Apr 30, 2009, 8:33:32 AM4/30/09
to xmlseclibs
Hi one again!

Are you still alive, Rob? ;-)

I found another flaw in xmlseclibs.php, around line 698 which is

return base64_encode(mhash(constant($alg), $data));

but should be

return base64_encode(mhash(constant('mhash_' . $alg),
$data));

accoring to the PHP manual on

http://php.net/manual/en/mhash.constants.php

Didn't solve my problems, but I came across this line while
debugging...

cu
Bernd

Rob Richards

unread,
Apr 30, 2009, 8:48:25 AM4/30/09
to xmlse...@googlegroups.com, xmlse...@discardmail.com
Hi Bernd,

Sorry about that. I am in charge of our OAuth services at work, so the
recent security issue robbed me of all my free time. Now that it has
settled down, I plan on digging back into your issue. I take it the
vendor hasn't been of much help?

The original mhash code should be correct. Can you confirm that line 697
for you is:
$alg = "MHASH_" . strtoupper($alg);

Rob

Rob Richards

unread,
May 5, 2009, 9:58:13 AM5/5/09
to xmlse...@googlegroups.com, xmlse...@discardmail.com

This is really going to require the provider to look at it and let you
know what's wrong. After going through the messages, the only thing I
could find (and I pray the provider didnt do something as stupid as
using a hard coded namespace prefix - I've seen it before though), is
that they are using soapenv as the prefix while PHP uses SOAP-ENV. Their
use of setting xmlns="" should not matter in the least because there are
no non-namespaced elements so setting a default namespace isn't doing
anything. Sorry I couldn't have been more of a help here.

Rob

Bernd

unread,
May 6, 2009, 8:33:48 AM5/6/09
to xmlseclibs
Hi Rob,

I have added empty xmlns-attributes to the nodes, replaced SOAP-ENV
with soapenv and changed the order of the ds:Reference-nodes, but
nothing helped. I did'n manage to move the "soapenv:encodingStyle" and
"xmlns:ns1" to the SOAP Body, but I don't believe this would change
anything. :-(

The service provider's devs are off duty till mid May, so they cannot
help me either right now. What about the digests, can they cause a
problem? Cuz these are the only elements I could not verify. Maybe
there are different ways to calculate them? Are there any tools that
can provide me with these digest, so I can check whether the ones
xmlseclibs creates are correct?

Bernd

Rob Richards

unread,
May 6, 2009, 10:28:06 AM5/6/09
to xmlse...@googlegroups.com, xmlse...@discardmail.com
When you modify the SOAP request, I assume you are doing this before the
signature is one correct?
If done post signature then the signature and digest will definitely be
incorrect because they would be performed on different data.

Rob

Bernd

unread,
May 7, 2009, 4:01:30 AM5/7/09
to xmlseclibs
addBinaryToken() and attachTokentoSig() are called after signSoapDoc
(), so the header is being modified after signature creation. I
slightly edited those two functions, but I'm not sure whether they
affect the signature. The signature is applied to the Timestamp- and
SOAP-Body-node only, am I correct? So modifying the SOAP request in
general does not necessarily break the signature, right?

But that might sure be a problem causer. Can I manually verify the
signature, e.g. by copying parts of the request is logged to a string
and calling base64_encode(sha1($str, true)) on it? This way I could
perhaps compare the signature from the header with the one that should
be there instead (if they differ). But I'm still unsure about what is
being signed by your script (just the content of a node or the whole
node including all xml tags and attributes....).

Bernd

Rob Richards

unread,
May 8, 2009, 6:57:12 AM5/8/09
to xmlse...@googlegroups.com
Modifying those shouldnt do anything since they arent included in the
signature. I was referring to when prefixes and attributes were changed.
If that is done POST signature it is bound to fail.

Based on your structure, the timestamp node (which includes all
attributes and children) and the SOAP body (including all attributes and
children) are included in the signature. The XML is canonicalized
(http://www.w3.org/TR/xml-exc-c14n/) so contains much more than just
text content. Based on the complexities, I doubt you would be able to
easily manaully verify this. Do you happen to have access to any other
toolsets (.NET or Java perhaps). You could then use that to do verification.

Rob


Bernd

unread,
May 11, 2009, 11:43:11 AM5/11/09
to xmlseclibs
Hi Rob,

I have access to Java, but admittedly I've never done any SOAP in Java
yet. Are there any build-in libs for SOAP and WSS?

Is the private key/certificate also included in the signature?
Otherwise maybe I could try to fake the service provider's example and
check, whether my code creates the same signature based on their data
(assuming that I hardcode their Timestamp-node)?

Bernd

Rob Richards

unread,
May 15, 2009, 6:58:24 AM5/15/09
to xmlse...@googlegroups.com
Bernd wrote:
> Hi Rob,
>
> I have access to Java, but admittedly I've never done any SOAP in Java
> yet. Are there any build-in libs for SOAP and WSS?
>
For Java you might want to look at WSS4J or IBM's Glassfish or the older
JWSDP.

> Is the private key/certificate also included in the signature?
> Otherwise maybe I could try to fake the service provider's example and
> check, whether my code creates the same signature based on their data
> (assuming that I hardcode their Timestamp-node)?
>
>

The private key is used for signing and is only required by the signer.
The public key, which is usually included with the document, is what is
used to verify the signature. In order to create the same signature, you
would need their private key they used for the example. I also don't
know if their example is a true example as they use xxx for for the
xmlData and version parameters. It's possible they sanitized those
values after signing.

Rob

Bernd

unread,
May 15, 2009, 9:49:44 AM5/15/09
to xmlseclibs
Hey Rob,

I don't want to count chickens before they hatch, but I think I solved
the auth problem! And as I already thought, it really was a trifle...

For debugging purposes I changed these lines

function __doRequest($request, $location, $saction, $version) {
$doc = new DOMDocument('1.0');
$doc->loadXML($request);

to

public function __doRequest($request, $location, $action, $version,
$one_way = 0) {
$dom = new DOMDocument('1.0');
$dom->formatOutput = true;
$dom->preserveWhiteSpace = false;
$dom->loadXML($request);

earlier. As I logged each soap request this seemed appropriate,
because the XML document was more readable that way. Obviously this
mixed up things on the service provider's side (probably a line break
problem, I guess). Anyway, today I got a positive SOAP response, so I
think removing the additional lines helped. Now I can finally dig into
their service more deeply.

Rob, thank you so much for for patience, a support far beyond your
library and constantly responding!

Kind regards,
Bernd
Reply all
Reply to author
Forward
0 new messages