Validity of public keys is not checked
Description
The Verify
function does not check the validity of the public key passKey
. To be valid, a public key needs to
not be the point at infinity,
have coordinates satisfying , and
satisfy the equation modulo
p
.
The public key is only used after conversion to Jacobian coordinates in _preComputeJacobianPoints
with JPoint(passKey.pubKeyX, passKey.pubKeyY, 1)
, which is never the point at infinity. The _affineFromJacobian
function uses the convention that (0,0)
in affine coordinates represents the point at infinity. So for this special case, conversion as JPoint(passKey.pubKeyX, passKey.pubKeyY, 1)
would be incorrect. But given that the point at infinity is not a valid public key anyway, this is not an issue if instead the public key (0,0)
is rejected by recognizing that (0,0)
does not lie on the curve.
As x and y coordinates of passKey
always get reduced modulo p
in calculations, the missing check for property 2 means that Verify
will in effect check the signature for the public key with coordinates (x % p, y % p)
. This means that for some public keys (x,y)
, where or , there exists another pair (x', y')
--- for example, (x+p, y)
--- that can be used as a public key and for which signatures made for (x,y)
would also verify.
Finally, if the public key passed to Verify
does not lie on the curve, then results returned by Verify
do not have a meaningful interpretation.
Impact
Whether the possibility an attacker could generate two different keys for which the same signature is valid is a problem depends on how the caller uses public keys and signature verification.
This bug allows an attacker to generate public keys together with signatures that will be rejected by verification algorithms that validate the public key but will be accepted by Verify
. The impact on the security of projects making use of the Secp256r1 library for signature verification is highly dependent on how signatures are otherwise used. See section ref↗ for a discussion of this as well as the reason for our severity rating.
Recommendations
Ensure that (passKey.pubKeyX, passKey.pubKeyY)
is a valid public key for the secp256r1 curve. One option is to check this in the Verify
function. If this is instead ensured by callers to Verify
, then one could alternatively document that Verify
assumes validity of the public key and that the caller must ensure this.
Remediation
This issue has been acknowledged by Biconomy Labs, and fixes were implemented in the following commits: