fix: check EVP_PKEY_get_bn_param() return values in _get_key_parameters()#159
Conversation
|
@Koan-Bot Review this fails. EVP_PKEY_get_bn_param returns 1 on success and 0 on an error. an error could simply be that the parameter is not included in the key. In openssl < 3 EVP_PKEY_get_bn_param does not fail the test. In openssl 3+ we would need to allow 0 as a valid response and set the value to undef. It probably should not croak but return an undef |
PR Review — fix: check EVP_PKEY_get_bn_param() return values in _get_key_parameters()The PR correctly identifies a real gap (unchecked return values on 3.x), but the fix is too aggressive: croaking on missing private components changes the established Perl-level API contract where public keys return undef for private components. As timlegge noted, 🔴 Blocking1. Croaking on missing params contradicts pre-3.x behavior (`RSA.xs`, L877-912)timlegge's review is correct. On pre-3.x paths ( The current approach of croaking when Even for n and e, consider whether croaking is the right behavior — the pre-3.x paths don't croak either (they'd just push NULL through 🟡 Important1. _is_private() called 6 times redundantly on 3.x (`RSA.xs`, L883)Each int is_priv = _is_private(p_rsa);and reuse 2. Cascading cleanup lines are fragile and unmaintainable (`RSA.xs`, L895-908)Each successive error path adds one more However, this is moot if you adopt the simpler approach of not croaking (see critical comment). 3. OpenSSL error queue not drained on skipped public-key failures (`RSA.xs`, L883)When 🟢 Suggestions1. Tests are good but don't cover the error path (`t/get_key_parameters.t`, L1-46)The tests verify the happy paths (private key returns 8 defined values, public key returns 2 defined + 6 undef). Consider adding a test that exercises the error path — e.g., a corrupted or minimal key where n/e extraction might fail — to validate whatever error handling strategy is adopted. Also consider testing with Checklist
SummaryThe PR correctly identifies a real gap (unchecked return values on 3.x), but the fix is too aggressive: croaking on missing private components changes the established Perl-level API contract where public keys return undef for private components. As timlegge noted, Automated review by Kōan |
|
Agree with this assessment. The pre-3.x paths ( On 3.x,
The current |
|
@Koan-Bot lets keep the contracted API and return the undef for any parameter that cannot be retrieved - that is, do not croak |
EVP_PKEY_get_bn_param() pushes errors onto the OpenSSL error queue when a parameter is absent (e.g. private components on a public key). These stale errors could leak into the next croakSsl() call from an unrelated operation. Add ERR_clear_error() after the parameter extraction calls. The API contract is preserved: missing parameters return undef (via cor_bn2sv(NULL)), matching the pre-3.x behavior exactly. Add t/get_key_parameters.t to codify this contract: private keys return 8 defined values, public keys return n/e defined + 6 undef. Addresses review feedback on PR cpan-authors#159. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@Koan-Bot rebase |
…rs() On the OpenSSL 3.x path, the eight EVP_PKEY_get_bn_param() calls had their return values discarded. A failure left the BIGNUM* NULL so cor_bn2sv(NULL) silently returned &PL_sv_undef, making a broken or truncated key look like a public key. - n and e are mandatory for every RSA key: croak (via croakSsl) if either call fails, freeing any already-allocated BIGNUMs first. - d, p, q, dmp1, dmq1, iqmp are absent for public keys (return 0, leave pointer NULL), so only croak when the call returns an error and the key is marked private. Add t/get_key_parameters.t to verify: private key returns all eight params defined; public key returns n/e defined and private components as undef; neither case croaks. Fixes cpan-authors#155 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* (`RSA.xs`, d/p/q/dmp1/dmq1/iqmp): `EVP_PKEY_get_bn_param()` returning 0 for absent parameters is expected behavior for public keys, not an error. The return values are now intentionally ignored — NULL pointers flow through `cor_bn2sv()` as `undef`, matching the pre-3.x behavior where `RSA_get0_key`/`RSA_get0_factors`/`RSA_get0_crt_params` simply set NULL for missing fields. - **Removed cascading inline cleanup and redundant `_is_private()` calls**: The fragile per-line cleanup chains and 6 redundant `_is_private()` calls (each performing an extra `EVP_PKEY_get_bn_param` round-trip) are eliminated. - **Added `ERR_clear_error()` after private component fetches**: Failed `EVP_PKEY_get_bn_param()` calls on public keys may push errors onto the OpenSSL error queue; draining it prevents stale errors from leaking into subsequent operations. - **Kept n/e mandatory checks**: `n` and `e` are present in every valid RSA key, so the croak-on-failure check is retained for these two parameters only.
Rebase: fix: check EVP_PKEY_get_bn_param() return values in _get_key_parameters()Branch Diff: 2 files changed, 59 insertions(+), 2 deletions(-) Review feedback was analyzed and applied. Changes
Actions
CICI will be checked asynchronously. Automated by Kōan |
f70e835 to
b4ec4ff
Compare
EVP_PKEY_get_bn_param() pushes errors onto the OpenSSL error queue when a parameter is absent (e.g. private components on a public key). These stale errors could leak into the next croakSsl() call from an unrelated operation. Add ERR_clear_error() after the parameter extraction calls. The API contract is preserved: missing parameters return undef (via cor_bn2sv(NULL)), matching the pre-3.x behavior exactly. Add t/get_key_parameters.t to codify this contract: private keys return 8 defined values, public keys return n/e defined + 6 undef. Addresses review feedback on PR cpan-authors#159. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
On the OpenSSL 3.x path,
_get_key_parameters()silently discarded the return values of all eightEVP_PKEY_get_bn_param()calls. A failure left theBIGNUM*pointer NULL, causingcor_bn2sv(NULL)to return&PL_sv_undef— making a broken or truncated key indistinguishable from a valid public key to callers ofget_key_parameters().Fixes #155
Changes
croakSsl()if eitherEVP_PKEY_get_bn_param()call fails, freeing any already-allocated BIGNUMs before the longjmp._is_private()— a NULL result is legitimate for a public key.Test plan
t/get_key_parameters.t(10 tests):undef, no croakGenerated by Kōan /fix
Quality Report
Changes: 2 files changed, 79 insertions(+), 8 deletions(-)
Code scan: clean
Tests: passed (OK)
Branch hygiene: clean
Generated by Kōan post-mission quality pipeline