Skip to content

Add hw-rsa feature for hardware RSA offload#1

Open
abhay wants to merge 4 commits into
mainfrom
hw-rsa
Open

Add hw-rsa feature for hardware RSA offload#1
abhay wants to merge 4 commits into
mainfrom
hw-rsa

Conversation

@abhay

@abhay abhay commented Feb 15, 2026

Copy link
Copy Markdown

Add a hw-rsa Cargo feature that enables RSA signature verification during TLS handshakes via extern "Rust" callbacks instead of the software rsa crate. This allows embedded targets with hardware RSA accelerators (e.g., ESP32) to verify RSA signatures without pulling in the heavy ~60-120KB software RSA implementation.

Six extern callbacks cover all RSA signature schemes:

  • Certificate chain verification (PKCS#1 v1.5):
    • embedded_tls_verify_rsa_pkcs1v15_sha256
    • embedded_tls_verify_rsa_pkcs1v15_sha384
    • embedded_tls_verify_rsa_pkcs1v15_sha512
  • CertificateVerify signature verification (RSA-PSS):
    • embedded_tls_verify_rsa_pss_sha256
    • embedded_tls_verify_rsa_pss_sha384
    • embedded_tls_verify_rsa_pss_sha512

The firmware must provide these symbols at link time. Features rsa and hw-rsa are mutually exclusive (enforced via compile_error!).

Changes:

  • Cargo.toml: add hw-rsa feature, add heapless to der features (fixes existing upstream build bug), add rsa as dev-dependency for testing
  • lib.rs: add compile_error guard for rsa+hw-rsa mutual exclusion
  • config.rs: enable RSA signature schemes when hw-rsa is active
  • der_certificate.rs: gate RSA OID constants on hw-rsa too
  • pki.rs: add hw-rsa match arms with extern callback declarations
  • tests/rustpki_hw_rsa_test.rs: integration test providing software RSA as callback implementations, validates full dispatch path through a real TLS handshake

Add a `hw-rsa` Cargo feature that enables RSA signature verification
during TLS handshakes via extern "Rust" callbacks instead of the
software `rsa` crate. This allows embedded targets with hardware RSA
accelerators (e.g., ESP32) to verify RSA signatures without pulling
in the heavy ~60-120KB software RSA implementation.

Six extern callbacks cover all RSA signature schemes:
- Certificate chain verification (PKCS#1 v1.5):
  - embedded_tls_verify_rsa_pkcs1v15_sha256
  - embedded_tls_verify_rsa_pkcs1v15_sha384
  - embedded_tls_verify_rsa_pkcs1v15_sha512
- CertificateVerify signature verification (RSA-PSS):
  - embedded_tls_verify_rsa_pss_sha256
  - embedded_tls_verify_rsa_pss_sha384
  - embedded_tls_verify_rsa_pss_sha512

The firmware must provide these symbols at link time. Features `rsa`
and `hw-rsa` are mutually exclusive (enforced via compile_error!).

Changes:
- Cargo.toml: add hw-rsa feature, add heapless to der features (fixes
  existing upstream build bug), add rsa as dev-dependency for testing
- lib.rs: add compile_error guard for rsa+hw-rsa mutual exclusion
- config.rs: enable RSA signature schemes when hw-rsa is active
- der_certificate.rs: gate RSA OID constants on hw-rsa too
- pki.rs: add hw-rsa match arms with extern callback declarations
- tests/rustpki_hw_rsa_test.rs: integration test providing software
  RSA as callback implementations, validates full dispatch path
  through a real TLS handshake
@abhay abhay marked this pull request as ready for review February 15, 2026 11:43
Adds RSA_PKCS1_SHA1 (OID 1.2.840.113549.1.1.5) to the hw-rsa feature's
certificate verification dispatch. This enables proper verification of
certificates signed with sha1WithRSAEncryption (e.g. Go Daddy Class 2 CA)
without bypassing any validation steps.

Reverts the earlier trust anchor self-signature skip, which had three
security issues: it bypassed time validity checks, could accept rogue
self-signed certs from the server, and broke CN extraction for
self-signed leaf certs.
When enabled, NoClock::now() calls an extern "Rust" callback
(embedded_tls_system_clock_now) to get the current epoch seconds,
enabling TLS certificate time validation without modifying reqwless.
The rustpki backend only checked CommonName for hostname verification,
ignoring Subject Alternative Names. Modern certificates (including
wildcard certs from CAs like Cloudflare) rely on SANs — connections
to hosts like a.example.com failed because CN=example.com didn't match
and SANs were never consulted.

- New san_matches_hostname() streams through extensions DER inline,
  matching each dNSName against the hostname during parsing. Zero
  allocation, no limit on SAN count, early return on first match.
- Follows RFC 6125: SANs take precedence over CN when present.
  Wildcard matching (*.example.com) is case-insensitive, single-level.
- Fail-closed: malformed DER returns Err (rejected), not None
  (which would silently fall back to CN trust).
- Null byte injection in dNSName entries is rejected.
- verify_certificate() takes hostname and returns HostnameResult
  with tri-state: Ok(None) no SANs / Ok(Some) matched / Err bad DER.
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.

1 participant