Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to verify Paypal webhook signature in PHP?

I'm not very knowledgeable in SSL and certificates. I used the post "How to use hash_hmac() with "SHA256withRSA" on PHP?" to see if I can get webhooks with PayPal working.

The issue I am have is I am getting the following error after calling openssl_verify() and a return result of (0):

OpenSSL error openssl_verify error:04091068:rsa routines:INT_RSA_VERIFY:bad signature

I've tried to solve this, but documentation on errors and the functions around the web is minimal to none.

My current code looks like this:

 // get the header post to my php file by PayPal
 $headers = apache_request_headers();
 // get the body post to me php file by PayPal
 $body = @file_get_contents('php://input');
 $json = json_decode($body);

 // TransmissionId|TransmissionTimeStamp|WebhookId|CRC32 as per PayPal documentation
 $sigString = $headers['Paypal-Transmission-Id'].'|'.$headers['Paypal-Transmission-Time'].'|'.$json->id.'|'.crc32($body);

 // $headers['Paypal-Cert-Url'] contains the "-----BEGIN CERTIFICATE---MIIHmjCCBoKgAwIBAgIQDB8 ... -----END CERTIFICATE-----"
 $pubKey = openssl_pkey_get_public(file_get_contents($headers['Paypal-Cert-Url']));

 // and this is the call to verify that returns result (0)
 $verifyResult = openssl_verify($sigString, base64_decode($headers['Paypal-Transmission-Sig']), $pubKey, 'sha256WithRSAEncryption');

Only different from the reference code I used, is that I do not use openssl_pkey_get_details($pubKey) because I will get below error in addition to the existing signature error:

OpenSSL error openssl_verify error:0906D06C:PEM routines:PEM_read_bio:no start line OpenSSL error openssl_verify error:04091068:rsa routines:INT_RSA_VERIFY:bad signature

Also I've tried a variation by not using base64_decode() on the header but that would get the same return result (0) with error stating:

OpenSSL error openssl_verify error:04091077:rsa routines:INT_RSA_VERIFY:wrong signature length

What is wrong with the signature?

like image 224
Bob2u Avatar asked Nov 20 '22 15:11

Bob2u


2 Answers

You may want to use this piece of code:

$pubKey = openssl_pkey_get_public(file_get_contents($headers['PAYPAL-CERT-URL']));
$details = openssl_pkey_get_details($pubKey);

$verifyResult = openssl_verify($sigString, base64_decode($headers['PAYPAL-TRANSMISSION-SIG']), $details['key'], 'sha256WithRSAEncryption');

if ($verifyResult === 0) {
    throw new Exception('signature incorrect');
} elseif ($verifyResult === -1) {
    throw new Exception('error checking signature');
}
like image 112
VJ-PP Avatar answered Dec 04 '22 06:12

VJ-PP


The formula is <transmissionId>|<timeStamp>|<webhookId>|<crc32> not <transmissionId>|<timeStamp>|<eventId>|<crc32>. Also note that Webhook simulator events can't be verified.

like image 23
JUBEI Avatar answered Dec 04 '22 05:12

JUBEI