rsa_crypt no longer needs public/private arguement#165
Conversation
Koan-Bot
left a comment
There was a problem hiding this comment.
Review — PR #165
Good refactor. The public parameter was only used for the public == is_encrypt length-check guard after 85fce04 removed its other use. Moving the check to the callers (encrypt, private_encrypt) makes rsa_crypt simpler and the call sites self-documenting. The equivalence is correct:
| Call | Old: public == is_encrypt |
New: explicit call |
|---|---|---|
| encrypt | 1==1 → check ✓ | check_max_message_length() called ✓ |
| decrypt | 0==1 → skip ✓ | not called ✓ |
| private_encrypt | 0==0 → check ✓ | check_max_message_length() called ✓ |
| public_decrypt | 1==0 → skip ✓ | not called ✓ |
Issues
1. C89 mixed declarations — will break on older compilers (blocking)
void check_max_message_length(rsaData* p_rsa, int from_length) {
int size;
/* comment */
size = EVP_PKEY_get_size(p_rsa->rsa); // ← this is a statement
int max_len = -1; // ← declaration after statement = C99
const char *pad_name = NULL; // ← sameMany Perl builds use C89 mode. All declarations must come before any statements:
void check_max_message_length(rsaData* p_rsa, int from_length) {
int size;
int max_len = -1;
const char *pad_name = NULL;
size = EVP_PKEY_get_size(p_rsa->rsa);
/* ... */2. SvCUR doesn't guarantee stringification (important)
check_max_message_length(p_rsa, SvCUR(p_plaintext));SvCUR() returns the string length of the SV's PV slot, but if the SV hasn't been stringified yet (e.g., it's an integer), SvCUR may return 0 or garbage. The original code used SvPV(p_from, from_length) inside rsa_crypt() which forces stringification.
Two options:
- Use
SvPV_nolen(p_plaintext)beforeSvCURto force stringification, or - Pass the length returned by
SvPV(but that would mean duplicating theSvPVcall)
In practice, Perl crypto data is almost always already a string, but the safety guarantee matters for an XS module.
3. from_length type should be STRLEN, not int
SvCUR returns STRLEN (which is size_t). The function parameter is int, which silently truncates on 64-bit. The original code had the same limitation (casting to (int) for the comparison), but since we're touching the signature anyway, STRLEN would be more correct.
Nits
- Commit message: "arguement" → "argument"
- The comment inside
check_max_message_length()about "Only applies to encryption direction" is now redundant — the function is only called from encrypt/private_encrypt, so it's self-documenting. Could simplify to just the overhead calculation comments.
Summary
The refactor is sound. Fix the C89 declarations and the SvCUR issue, and this is good to merge.
PR Review — rsa_crypt no longer needs public/private arguementSound refactor — the 🔴 Blocking1. C89 mixed declarations will break older Perl/compiler builds (`RSA.xs`, L392-397)The void check_max_message_length(rsaData* p_rsa, int from_length) {
int size;
int max_len = -1;
const char *pad_name = NULL;
size = EVP_PKEY_get_size(p_rsa->rsa);
...🟡 Important1. Function parameter type should be STRLEN, not int (`RSA.xs`, L392)
void check_max_message_length(rsaData* p_rsa, STRLEN from_length) {This also removes the need for the 2. SvCUR on potentially non-stringified SV (`RSA.xs`, L1139)
Safest fix: call check_max_message_length(p_rsa, sv_len(p_plaintext));
🟢 Suggestions1. Function should be declared static (`RSA.xs`, L392-415)
static void check_max_message_length(rsaData* p_rsa, int from_length) {2. Comment about encryption direction is now redundant (`RSA.xs`, L393-397)The block comment explaining this only applies to encrypt/private_encrypt is no longer needed — the function is only called from those two XS functions, making it self-documenting. Consider removing or shortening to just document the overhead constants. Checklist
SummarySound refactor — the Automated review by Kōan |
|
@Koan-Bot and @toddr-bot review the changes now. I still need to address a couple of issues but check the details of the oaep max length calculation |
Follow-up review — OAEP max length calculationThe formula However, the current implementation has a compilation-breaking issue on pre-3.x OpenSSL, plus a memory leak. 🔴 Blocking:
|
|
@Koan-Bot implement the get_digest_length() fix and fix the minor nit and the previous review items |
|
Draft PR submitted: #166 |
PR Review — rsa_crypt no longer needs public/private arguementThe refactor direction is sound — removing the 🔴 Blocking1. get_md_bynid() is 3.x-only — won't compile on pre-3.x OpenSSL (`RSA.xs`, L392-420)
Options:
2. EVP_MD memory leak from get_md_bynid() (`RSA.xs`, L404-406)
Fix: add 3. C89 mixed declarations will break older compilers (`RSA.xs`, L392-397)The void check_max_message_length(rsaData* p_rsa, int from_length) {
int size;
int max_len = -1;
const char *pad_name = NULL;
int digest_length = 0;
size = EVP_PKEY_get_size(p_rsa->rsa);
...🟡 Important1. Parameter type should be STRLEN, not int (`RSA.xs`, L392)
void check_max_message_length(rsaData* p_rsa, STRLEN from_length) {Then adjust the comparison: 2. SvCUR on potentially non-stringified SV is unsafe (`RSA.xs`, L1137)
Same issue at line 1183 ( 🟢 Suggestions1. Function should be declared static (`RSA.xs`, L392-420)
static void check_max_message_length(rsaData* p_rsa, STRLEN from_length) {2. Stale comment says SHA-1 but calculation uses SHA-256 (`t/error.t`, L89-90)Line 90 has Checklist
SummaryThe refactor direction is sound — removing the Automated review by Kōan |
The OAEP max length formula However, the implementation has two blocking issues with the digest length calculation:
Recommended fix: create a simple |
Note for the implementation: when creating the
|
|
❌ Permission denied. Only users with write access can trigger bot commands. |
|
@Koan-Bot @toddr-bot review |
PR Review — rsa_crypt no longer needs public/private arguementThe 🔴 Blocking1. OAEP overhead uses hashMode but OAEP always uses SHA-1 (`RSA.xs`, L392-415)The new This means
Either:
Option 1 is simpler and matches the pre-existing behavior. 2. C89 violation: declaration after statements in pre-3.x path (`RSA.xs`, L475-476)In the Fix: keep // At top of function:
int size;
// In #else block:
size = EVP_PKEY_get_size(p_rsa->rsa);Or use it only where needed: the 3.x path doesn't reference 🟡 Important1. MD5 digest length is wrong; OAEP overhead values are incorrect (`t/padding.t`, L120-127)MD5_DIGEST_LENGTH is 16, not 20. The comment "OpenSSL seems to require a minimum of 20" is masking the real issue: OAEP in this module always uses SHA-1 (digest length 20) regardless of the hash mode setting, so ALL entries should use 20 (or more precisely, the tests should use the fixed overhead of 42 as before). Since 2. OAEP max calculation assumes hashMode affects OAEP (`t/crypto.t`, L18-22)The new calculation The old 3. Same OAEP max miscalculation as crypto.t (`t/error.t`, L88-90)Same issue: This is a test regression: the old Checklist
SummaryThe Automated review by Kōan |
Reviewed. The previous review items (C89 declarations, |
The OAEP max length formula The test changes in To make hashMode actually control OAEP, you'd need to add |
|
❌ Permission denied. Only users with write access can trigger bot commands. |
|
@toddr-bot implement EVP_PKEY_CTX_set_rsa_oaep_md in a separate PR |
…ngth The `public` parameter in rsa_crypt() was only used to decide whether to run plaintext length pre-validation. This refactor: - Extracts pre-validation into a standalone check_max_message_length() static function, called directly from encrypt() and private_encrypt() - Removes the now-unnecessary `public` parameter from rsa_crypt() - Keeps OAEP overhead as the fixed SHA-1 value (size - 42) since this module never sets EVP_PKEY_CTX_set_rsa_oaep_md() — OpenSSL always uses SHA-1 for OAEP regardless of hashMode - Fixes C89 compliance: moves `int size` declaration to function top and assigns in the #else block to avoid declaration-after-statement Closes cpan-authors#165 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
c0de6ec to
abed6b3
Compare
|
@Koan-Bot @toddr-bot final review |
Final review — PR #165Previous review items are addressed: One blocking issue remains, plus one concern about the test changes. 🔴 BlockingC89 declaration-after-statement in pre-3.x path ( #else
int size = EVP_PKEY_get_size(p_rsa->rsa); /* ← C89 violation */
CHECK_NEW(to, size, UNSIGNED_CHAR);On pre-3.x builds, the compiler sees this declaration after the Fix: Add #if OPENSSL_VERSION_NUMBER < 0x30000000L
int size;
#endifThen change L476 to just (Note: the pre-existing C89 violations in the 3.x path — 🟡 Test deletion concernThe The runtime guard code is still present in this diff, but without tests it has no regression coverage. These tests are unrelated to the ✅ Verified correct
|
move the max message length check and call it from the correct functions to simplify rsa_crypt
… digests for OAEP
Post-merge review — KōanThe refactor is clean. Verified on macOS/OpenSSL 3.6.1 — builds and all tests pass. What's good
Minor observations (non-blocking, for future reference)
No blocking issues. 👍 🤖 Post-merge review by Kōan |
move the max message length check and call it from the correct functions to simplify rsa_crypt
Things were getting complicated in rsa_crypt so I pulled the message length check out to check_max_message_length() and it is not called only from encrypt and private_encrypt (sign) .
That simplifies rsa_crypt.
In addition, the reason for the public argument was eliminated in 85fce04
@Koan-Bot and @toddr-bot review