Skip to content

fix: private_encrypt/public_decrypt broken on OpenSSL 3.x#118

Merged
timlegge merged 3 commits intocpan-authors:mainfrom
toddr-bot:koan.toddr.bot/fix-private-encrypt-padding
Apr 7, 2026
Merged

fix: private_encrypt/public_decrypt broken on OpenSSL 3.x#118
timlegge merged 3 commits intocpan-authors:mainfrom
toddr-bot:koan.toddr.bot/fix-private-encrypt-padding

Conversation

@toddr-bot
Copy link
Copy Markdown
Contributor

@toddr-bot toddr-bot commented Mar 17, 2026

What

Fixes private_encrypt() and public_decrypt() being broken on OpenSSL 3.x with any padding except NO_PADDING.

Why

rsa_crypt() is shared by four operations: encrypt, decrypt, private_encrypt, and public_decrypt. On OpenSSL 3.x, it unconditionally forced OAEP padding for all non-NO_PADDING modes. But private_encrypt/public_decrypt use EVP_PKEY_sign/EVP_PKEY_verify_recover under the hood, where OAEP is not a valid padding mode. This caused an OpenSSL error ("illegal or unsupported padding mode") for any call to private_encrypt() or public_decrypt() with the default padding.

This is the same family of issues as #61 — the v0.35 Marvin attack mitigation broke signature-related operations. This fix complements #103 (which fixes sign()/verify()).

How

Replaced the unused int public parameter in rsa_crypt() with int is_encrypt to distinguish encryption from sign/verify_recover operations:

  • Encryption path (encrypt/decrypt): forces OAEP, rejects PSS (existing behavior)
  • Sign path (private_encrypt/public_decrypt): passes through the user's padding choice; rejects OAEP and PSS with clear error messages pointing to the correct API

Testing

  • 375 tests pass (364 existing + 10 new in t/private_encrypt.t)
  • Verified private_encrypt/public_decrypt roundtrip with NO_PADDING
  • Verified clear croak messages for OAEP and PSS on the sign path
  • Verified encrypt/decrypt behavior unchanged

🤖 Generated with Claude Code


Quality Report

Changes: 4 files changed, 131 insertions(+), 15 deletions(-)

Code scan: clean

Tests: passed (OK)

Branch hygiene: clean

Generated by Kōan post-mission quality pipeline

@atoomic
Copy link
Copy Markdown
Collaborator

atoomic commented Mar 17, 2026

view errors from smokers

t/private_encrypt.t ......... 
1..10
ok 1 - private_encrypt with no_padding succeeds
ok 2 - public_decrypt(private_encrypt(data)) round-trips with no_padding
ok 3 - private_encrypt with OAEP behavior on pre-3.x (skipped)
ok 4 - public_decrypt with OAEP behavior on pre-3.x (skipped)
ok 5 - private_encrypt with PSS behavior on pre-3.x (skipped)
ok 6 - public_decrypt with PSS behavior on pre-3.x (skipped)
ok 7 - encrypt with OAEP still works
ok 8 - decrypt with OAEP round-trips
not ok 9 - encrypt with PSS still croaks

#   Failed test 'encrypt with PSS still croaks'
#   at t/private_encrypt.t line 83.
#                   'RSA.xs:389: OpenSSL error: unknown padding type at t/private_encrypt.t line 82.
# '
#     doesn't match '(?^:RSA-PSS cannot be used for encryption)'
ok 10 - public key private_encrypt croaks
# Looks like you failed 1 test of 10.
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/10 subtests 

@toddr-bot rebase

Copy link
Copy Markdown
Member

@timlegge timlegge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assigning to myself . I need to look at this closer

@timlegge timlegge self-assigned this Mar 18, 2026
@toddr-bot toddr-bot force-pushed the koan.toddr.bot/fix-private-encrypt-padding branch from 2b34b88 to df8d955 Compare March 18, 2026 01:09
toddr-bot added a commit to toddr-bot/Crypt-OpenSSL-RSA that referenced this pull request Mar 18, 2026
@toddr-bot
Copy link
Copy Markdown
Contributor Author

Rebase: fix: private_encrypt/public_decrypt broken on OpenSSL 3.x

Branch koan.toddr.bot/fix-private-encrypt-padding rebased onto main and force-pushed.

Diff: 4 files changed, 135 insertions(+), 18 deletions(-)

Review feedback was analyzed and applied.

Actions

  • Resolved merge conflicts (1 round(s))
  • Rebased koan.toddr.bot/fix-private-encrypt-padding onto upstream/main
  • Applied review feedback
  • Force-pushed koan.toddr.bot/fix-private-encrypt-padding to origin
  • CI passed

CI

CI passed.


Automated by Kōan

@atoomic atoomic marked this pull request as ready for review March 18, 2026 04:35
@atoomic
Copy link
Copy Markdown
Collaborator

atoomic commented Mar 21, 2026

@toddr-bot rebase

toddr-bot added a commit to toddr-bot/Crypt-OpenSSL-RSA that referenced this pull request Mar 21, 2026
toddr-bot added a commit to toddr-bot/Crypt-OpenSSL-RSA that referenced this pull request Mar 21, 2026
- **Moved PSS-for-encrypt guard before `#if OPENSSL_VERSION_NUMBER >= 0x30000000L`** so it fires on all OpenSSL versions, not just 3.x. On pre-3.x smokers, `encrypt()` with PSS was falling through to the legacy RSA code path which produced a generic "unknown padding type" error instead of the friendly croak message. This matches how the Marvin attack (PKCS#1 v1.5) guard is already placed before the ifdef.
- **Simplified test 9 in `t/private_encrypt.t`** to use `like()` unconditionally instead of branching on OpenSSL version, since the PSS croak now fires on all versions.
@toddr-bot toddr-bot force-pushed the koan.toddr.bot/fix-private-encrypt-padding branch from df8d955 to 4fa560a Compare March 21, 2026 02:43
@toddr-bot
Copy link
Copy Markdown
Contributor Author

Rebase: fix: private_encrypt/public_decrypt broken on OpenSSL 3.x

Branch koan.toddr.bot/fix-private-encrypt-padding rebased onto main and force-pushed.

Diff: 4 files changed, 127 insertions(+), 16 deletions(-)

Review feedback was analyzed and applied.

Changes

  • Moved PSS-for-encrypt guard before #if OPENSSL_VERSION_NUMBER >= 0x30000000L so it fires on all OpenSSL versions, not just 3.x. On pre-3.x smokers, encrypt() with PSS was falling through to the legacy RSA code path which produced a generic "unknown padding type" error instead of the friendly croak message. This matches how the Marvin attack (PKCS#1 v1.5) guard is already placed before the ifdef.
  • Simplified test 9 in t/private_encrypt.t to use like() unconditionally instead of branching on OpenSSL version, since the PSS croak now fires on all versions.

Actions

  • Resolved merge conflicts (1 round(s))
  • Rebased koan.toddr.bot/fix-private-encrypt-padding onto upstream/main
  • Applied review feedback
  • Force-pushed koan.toddr.bot/fix-private-encrypt-padding to origin
  • CI passed

CI

CI passed.


Automated by Kōan

@timlegge
Copy link
Copy Markdown
Member

@toddr-bot rebase this

toddr-bot added a commit to toddr-bot/Crypt-OpenSSL-RSA that referenced this pull request Mar 25, 2026
toddr-bot added a commit to toddr-bot/Crypt-OpenSSL-RSA that referenced this pull request Mar 25, 2026
- **Moved PSS-for-encrypt guard before `#if OPENSSL_VERSION_NUMBER >= 0x30000000L`** so it fires on all OpenSSL versions, not just 3.x. On pre-3.x smokers, `encrypt()` with PSS was falling through to the legacy RSA code path which produced a generic "unknown padding type" error instead of the friendly croak message. This matches how the Marvin attack (PKCS#1 v1.5) guard is already placed before the ifdef.
- **Simplified test 9 in `t/private_encrypt.t`** to use `like()` unconditionally instead of branching on OpenSSL version, since the PSS croak now fires on all versions.
@toddr-bot toddr-bot force-pushed the koan.toddr.bot/fix-private-encrypt-padding branch from 4fa560a to 642c7d5 Compare March 25, 2026 00:38
@toddr-bot
Copy link
Copy Markdown
Contributor Author

Rebase: fix: private_encrypt/public_decrypt broken on OpenSSL 3.x

Branch koan.toddr.bot/fix-private-encrypt-padding rebased onto main and force-pushed.

Diff: 4 files changed, 127 insertions(+), 16 deletions(-)

Review feedback was analyzed and applied.

Actions

  • Resolved merge conflicts (1 round(s))
  • Rebased koan.toddr.bot/fix-private-encrypt-padding onto upstream/main
  • Force-pushed koan.toddr.bot/fix-private-encrypt-padding to origin
  • CI passed

CI

CI passed.


Automated by Kōan

@timlegge
Copy link
Copy Markdown
Member

timlegge commented Apr 6, 2026

@toddr-bot rebase from main

toddr-bot and others added 3 commits April 6, 2026 16:20
On OpenSSL 3.x, rsa_crypt() is shared by encrypt/decrypt (which use
EVP_PKEY_encrypt/decrypt) and private_encrypt/public_decrypt (which use
EVP_PKEY_sign/verify_recover). The code unconditionally forced OAEP
padding for all non-NO_PADDING modes, but OAEP is only valid for
encryption — not for sign/verify_recover operations. This meant
private_encrypt() and public_decrypt() were broken with any padding
except NO_PADDING.

The fix replaces the unused `int public` parameter with `int is_encrypt`
to distinguish the two operation types:
- Encryption path (encrypt/decrypt): forces OAEP, rejects PSS
- Sign path (private_encrypt/public_decrypt): passes through PKCS1
  and NO_PADDING; rejects OAEP and PSS with clear error messages

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- **Moved PSS-for-encrypt guard before `#if OPENSSL_VERSION_NUMBER >= 0x30000000L`** so it fires on all OpenSSL versions, not just 3.x. On pre-3.x smokers, `encrypt()` with PSS was falling through to the legacy RSA code path which produced a generic "unknown padding type" error instead of the friendly croak message. This matches how the Marvin attack (PKCS#1 v1.5) guard is already placed before the ifdef.
- **Simplified test 9 in `t/private_encrypt.t`** to use `like()` unconditionally instead of branching on OpenSSL version, since the PSS croak now fires on all versions.
@toddr-bot
Copy link
Copy Markdown
Contributor Author

Rebase: fix: private_encrypt/public_decrypt broken on OpenSSL 3.x

Branch koan.toddr.bot/fix-private-encrypt-padding rebased onto main and force-pushed.

Diff: 4 files changed, 122 insertions(+), 11 deletions(-)

Review feedback was analyzed and applied.

Actions

  • Already-solved check: skipped (Claude call failed)
  • Resolved merge conflicts (1 round(s))
  • Rebased koan.toddr.bot/fix-private-encrypt-padding onto upstream/main
  • Force-pushed koan.toddr.bot/fix-private-encrypt-padding to origin
  • CI check enqueued (async)

CI

CI will be checked asynchronously.


Automated by Kōan

@toddr-bot toddr-bot force-pushed the koan.toddr.bot/fix-private-encrypt-padding branch from 642c7d5 to 141a216 Compare April 6, 2026 16:21
Copy link
Copy Markdown
Member

@timlegge timlegge left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good

@timlegge timlegge merged commit 5ddfb9f into cpan-authors:main Apr 7, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants