-
Notifications
You must be signed in to change notification settings - Fork 308
Description
Please confirm the following:
- I have read the README entirely
- I have verified in the issues that my problem hasn't already been resolved
Setup
Please provide the following details, the more info you can provide the
better.
- Operating System: Windows
- PHP Version: 7.4.8
- web-push-php Version: 6.0.2
Please check that you have installed and enabled these PHP extensions :
- gmp
- mbstring
- curl
- openssl -
Problem
When Encryption::createLocalKeyObjectUsingPurePhpMethod()
and Utils::serializePublicKeyFromJWK()
is used to create $localPublicKey
then this will result in a key (with binary size) slightly larger than the expected 65 bytes.
Thus, Encryption::createContext()
will throw with "Invalid server public key length".
Expected
$localPublicKey
should have binary size of 65 bytes exactly.
Features Used
- VAPID Support
- Sending with Payload
Example / Reproduce Case
Should be reproducable with official example, when openssl is not correctly configured.
Other
Of course, the best fix is to configure openssl correctly. However, Encryption::createLocalKeyObjectUsingPurePhpMethod()
exists and thus should provide correct results.
Unfortunately, I am not an expert on elliptical curves, GMP, JWT and so on. But I have a guess: the error could be in the calls to BigInteger::toBytes()
. By default it prepends a signed bit and represents the number in two's-complement. I think this sign-bit is responsible for enlarging key length.
Current:
new JWK([
'kty' => 'EC',
'crv' => 'P-256',
'x' => Base64Url::encode(self::addNullPadding($publicKey->getPoint()->getX()->toBytes())),
'y' => Base64Url::encode(self::addNullPadding($publicKey->getPoint()->getY()->toBytes())),
'd' => Base64Url::encode(self::addNullPadding($privateKey->getSecret()->toBytes())),
])
Suggested fix:
new JWK([
'kty' => 'EC',
'crv' => 'P-256',
'x' => Base64Url::encode(self::addNullPadding($publicKey->getPoint()->getX()->toBytes(false))),
'y' => Base64Url::encode(self::addNullPadding($publicKey->getPoint()->getY()->toBytes(false))),
'd' => Base64Url::encode(self::addNullPadding($privateKey->getSecret()->toBytes(false))),
])
With this change naiively applied, the key lengths will be exactly 65 bytes, as expected.
However, I don't know if this "fix" is technically correct. As x
and y
are coordinates, maybe just d
should be handled as unsigned?