RFC 2246 PRF function in PHP

297 Views Asked by At

I've been looking all over for an implementation of the PRF function from RFC 2246. I've found three. One here, one from the openSSL library, and one from wpa_supplicant. They all return different results. So my first question is: is there sample PRF input and sample PRF output somewhere?

That function is part of connecting to a .NET web service (protected with WS-Security) from PHP.

What I've found so far is this. My client sends a request for a token first with a username/password and a nonce -- that's an RST. The server, in its RSTR, responds with another nonce and a security token. The next request from my client should come with a signature whose key is derived from the two nonces and a "master secret". That derived key is computed according to RFC 2246. And that's why I need a reliable implementation of it.

Even if I have a reliable implementation of it, what would constitute the parameters to that function in the context of WS-Security? The PRF function should take three parameters, i.e.:

secret, label, seed.

I've read here, that the label Microsoft uses is "WS-SecureConversationWS-SecureConversation", but that article was written in 2006... Now, what would be the secret? Is it the original password? The security token? A combination of those? Finally, what would be the seed? I have two nonce's -- do I concatenate them, OR them, XOR them?

I'm seriously stuck. Any help greatly appreciated.

1

There are 1 best solutions below

0
On

I fought with this for two days, but I was ultimately successful. This is my PHP psha1 function, which is based on a C# method found at a reply to "signing SOAP message request via ADFS". Take your RST and RSTR, base64_decode each and pass them to this function as the $clientSecret and $serverSecret respectively. The token response should come with a KeySize element, which you can pass in as $sizeBits if it's not equal to 256.

function psha1($clientSecret, $serverSecret, $sizeBits = 256)
{
    $sizeBytes = $sizeBits / 8;

    $hmacKey = $clientSecret;
    $hashSize = 160; // HMAC_SHA1 length is always 160
    $bufferSize = $hashSize / 8 + strlen($serverSecret);
    $i = 0;

    $b1 = $serverSecret;
    $b2 = "";
    $temp = null;
    $psha = array();

    while ($i < $sizeBytes) {
        $b1 = hash_hmac('SHA1', $b1, $hmacKey, true);
        $b2 = $b1 . $serverSecret;
        $temp = hash_hmac('SHA1', $b2, $hmacKey, true);

        for ($j = 0; $j < strlen($temp); $j++) {
            if ($i < $sizeBytes) {
                $psha[$i] = $temp[$j];
                $i++;
            } else {
                break;
            }
        }
    }

    return implode("", $psha);
}