4.7.2
🔐 Security release — upgrade is recommended
This release fixes three security advisories. All released versions up to and including 4.7.1 are affected; there is no BC break, and no key an earlier release accepted is turned away.
composer require web-auth/cose-lib:^4.7.2| Advisory | Severity | Affected | Impact |
|---|---|---|---|
| GHSA-rh56-4rc8-hj58 | Medium | <= 4.7.1 |
RSA signature verification accepted trivially forged signatures under a key with public exponent e = 1 |
| GHSA-9v8c-2mgr-qvx3 | Medium | <= 4.7.1 |
CPU exhaustion through oversized attacker-supplied RSA keys |
| GHSA-h7p4-6f74-7w4g | Medium | >= 2.1.0, <= 4.7.1 |
Ed25519 private key recovery when EdDSA::sign() is given a public key that does not match the seed |
What changed
RSA public key validation — RsaKeyValidator::checkPublicParameters() now establishes the constraints of RFC 8017, section 3.1 (an odd, non-zero modulus and an odd public exponent with 3 <= e < n), and RS1/RS256/RS384/RS512 and PS256/PS384/PS512 apply it to every key they are given. verify() reports a key that fails them as an invalid signature; sign() throws.
RSA key size bounds — RsaKeyValidator::checkLengthBounds() bounds the modulus to 16384 bits (RFC 8230, section 6.1) and the public exponent to 256 bits (FIPS 186-5, appendix A.1.1), applied automatically before any arithmetic. The minimum modulus length remains the opt-in policy decision of check()/isValid(). Two new helpers come with it: RsaKeyValidator::exponentLength() and the MAXIMUM_EXPONENT_LENGTH constant.
RSA key export is linear — RsaKey::asPem() builds the DER from the octet strings of the key instead of routing every parameter through a decimal string and back. On a build with neither ext-gmp nor ext-bcmath — the stock php/php-fpm images — exporting a 16384 bit key went from about 107 s to 0.00 s. The PEM is byte for byte the one the previous encoder produced.
RSASSA-PSS verification uses OpenSSL for RSAVP1 — the public operation no longer depends on brick/math having an extension behind it. PS256::verify() against a 16384 bit key drops from roughly 200 s to 0.00 s without ext-gmp, and a legitimate 2048 bit key from 3.2 s to 0.00 s.
EdDSA signing derives the public key from the seed — EdDSA::sign() derives the key pair from d alone, as RFC 8032, section 5.1.5 requires, and only ever compares a stored x against it, refusing a mismatch. A caller-supplied public key can no longer reach the challenge k = SHA-512(R || A || M).
Note
ext-gmp or ext-bcmath is still recommended, but RSA verification no longer needs either to be cheap.
Release Notes for 4.7.2
4.7.x bugfix release (patch)
4.7.2
- Total issues resolved: 4
- Total pull requests resolved: 4
- Total contributors: 1
bug,compliance,security
- 180: fix(signature): make verify() total for every invalid signature outcome thanks to @Spomky
- 178: fix(rsa): make RSASSA-PSS follow RFC 8017 thanks to @Spomky
- 177: fix(ecdsa): encode and decode Ecdsa-Sig-Value strictly as DER thanks to @Spomky