Skip to content

SCEP: add keep-alive / async SCEP session API#12

Open
Frauschi wants to merge 1 commit into
wolfSSL:mainfrom
Frauschi:scep_async
Open

SCEP: add keep-alive / async SCEP session API#12
Frauschi wants to merge 1 commit into
wolfSSL:mainfrom
Frauschi:scep_async

Conversation

@Frauschi

Copy link
Copy Markdown
Contributor

Summary

Adds a keep-alive / non-blocking SCEP (RFC 8894) client session, the SCEP counterpart to the existing EST session. This is the last piece needed for feature-equivalence with wolfSCEP: SCEP enrollment can now run several PKIOperation round trips over one connection, and drive them non-blocking through a caller-owned event loop (poll/epoll/kqueue).

No public API is changed or removed; this is purely additive plus an internal refactor shared with the EST path.

What's included

  • WolfCertScepSession with blocking and non-blocking opens, plus PKCSReq, RenewalReq and GetCertInitial in _ex (blocking) and _nb (WANT_READ/WANT_WRITE pumped) forms.
  • Internal refactor: do_scep_round_trip split into reusable scep_prepare (envelope + sign), scep_build_transport (POST vs base64 GET), and scep_finish (parse + verify + de-envelop). The one-shot and session paths share these; one-shot behavior is unchanged.
  • Shared origin builder: the scheme://host[:port] construction duplicated by the EST and SCEP session opens is factored into wolfcert_http_url_origin so the two cannot drift.
  • Docs and build wiring: ARCHITECTURE.md, EMBEDDED.md context, CLAUDE.md, plus CMake + autoconf registration of the new test.

New public API (wolfcert/scep.h)

Function Purpose
wolfcert_scep_session_open / _open_async Open a blocking / non-blocking session
wolfcert_scep_session_close Tear down; zeroizes any in-flight private-key copy
wolfcert_scep_session_fd Backing socket fd for poll/epoll/kqueue
wolfcert_scep_session_pkcs_req_ex / _nb Enroll (PKCSReq)
wolfcert_scep_session_renewal_req_ex / _nb Renew (RenewalReq)
wolfcert_scep_session_get_cert_initial_ex / _nb Poll a PENDING enrollment (GetCertInitial)

Design notes

  • Mirrors the EST session in structure (one round trip in flight at a time, _ex/_nb split, same non-blocking HTTP session layer). The crypto stays synchronous; only the HTTP POST/GET is pumped through the state machine. The transactionID, senderNonce, and finish-phase inputs (CA bundle, signer cert/key) are captured in the session so they survive across pumps.
  • No TLS requirement, unlike EST. SCEP authenticates at the pkiMessage layer (the CMS signature is bound to the CA/RA bundle and the recipientNonce echo is enforced), so a plaintext http:// endpoint is accepted. An https:// endpoint, however, now requires verify_server rather than silently running an unauthenticated handshake.

Hardening and correctness

  • RNG return codes checked in scep_prepare: a wc_InitRng_ex / wc_RNG_GenerateBlock failure now fails the round trip instead of building a pkiMessage over an uninitialized transactionID and anti-replay senderNonce. (Pre-existing behavior in the one-shot path; fixed for both, now that the code is shared.)
  • Session misuse guards, all returning WOLFCERT_ERR_BAD_ARG:
    • a mismatched _ex/_nb pairing against the session's open mode (this also makes an in-flight-buffer / private-key-copy leak unreachable),
    • starting a different operation while one is in flight,
    • resuming a poll with a different WolfCertScepResult* than the one captured at begin (guards against a silently-empty result or a dangling-pointer write).

Testing

tests/integration/test_scep_async_roundtrip.c drives the in-tree test server end to end:

Scenario Covers
A Async enrollment; blocking-session enrollment + blocking RenewalReq
B Async PENDING -> GetCertInitial poll (keep-alive)
C Async enrollment -> async RenewalReq (keep-alive)
D Misuse guards: _ex-on-async, _nb-on-blocking, in-flight op-type mismatch
E Blocking PENDING -> GetCertInitial poll (get_cert_initial_ex)
F Session forced onto the base64 GET transport

The async scenarios are pumped through a real poll(2) loop. All 25 project tests pass (including the 12 EST tests, which exercise the shared origin-builder refactor); build is warning-clean.

@Frauschi Frauschi self-assigned this Jul 21, 2026

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #12

Scan targets checked: wolfcert-bugs, wolfcert-src

Findings: 2
2 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread tests/integration/test_scep_async_roundtrip.c Outdated
Comment thread tests/integration/test_scep_async_roundtrip.c Outdated
Comment thread tests/integration/test_scep_async_roundtrip.c Outdated
Comment thread tests/integration/test_scep_async_roundtrip.c Outdated

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #12

Scan targets checked: wolfcert-bugs
Failed targets: wolfcert-src

Findings: 3
3 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread src/scep/scep_client.c
Comment thread tests/integration/test_scep_async_roundtrip.c Outdated
Comment thread tests/integration/test_scep_async_roundtrip.c Outdated
Comment thread src/scep/scep_client.c
Comment thread tests/integration/test_scep_async_roundtrip.c Outdated
Comment thread tests/integration/test_scep_async_roundtrip.c Outdated

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #12

Scan targets checked: wolfcert-bugs, wolfcert-src

Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread tests/integration/test_scep_async_roundtrip.c
Comment thread tests/integration/test_scep_async_roundtrip.c

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #12

Scan targets checked: wolfcert-bugs, wolfcert-src

Findings: 3
3 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread tests/integration/test_scep_async_roundtrip.c
Comment thread src/scep/scep_client.c
Comment thread tests/integration/test_scep_async_roundtrip.c Outdated
Add WolfCertScepSession with blocking (wolfcert_scep_session_open) and
non-blocking (wolfcert_scep_session_open_async) opens, plus session
PKCSReq, RenewalReq and GetCertInitial in _ex (blocking) and _nb
(WANT_READ/WANT_WRITE pumped) forms, with wolfcert_scep_session_fd and
wolfcert_scep_session_close. The session reuses the same non-blocking
HTTP session layer as EST. Unlike EST it does not require TLS, since
SCEP authenticates at the pkiMessage layer, so a plaintext http://
endpoint is accepted.

do_scep_round_trip is refactored into reusable scep_prepare (envelope +
sign, producing the transactionID and senderNonce) and scep_finish
(parse + verify + de-envelop) phases, with the POST/GET transport
decision factored into scep_build_transport. The one-shot and session
paths share these; existing entry-point behavior is unchanged.

An async round trip builds the message once, pumps only the HTTP POST/GET
through the session state machine, then parses the CertRep on completion;
the crypto stays synchronous. The txid, senderNonce and finish-phase
inputs (CA bundle, signer cert/key) are captured in the session so they
survive across pumps.

scep_prepare now checks the wc_InitRng_ex / wc_RNG_GenerateBlock return
codes and fails the round trip on error, rather than building a
pkiMessage over an uninitialized transactionID and anti-replay
senderNonce. The session records which PKIOperation occupies its single
in-flight slot and rejects an async _nb resume that names a different
operation or passes a different WolfCertScepResult* out than the one
captured at begin; it also records whether it was opened blocking or
async so a mismatched _ex/_nb call is rejected with WOLFCERT_ERR_BAD_ARG
instead of overwriting (and leaking) the in-flight buffers - including
the zeroized private-key copy - or blocking on a non-blocking socket.
Like the one-shot path a plaintext http:// session is accepted, but an
https:// session now requires verify_server rather than silently running
an unauthenticated TLS handshake. The scheme://host[:port] origin builder
shared by the EST and SCEP session opens is factored into
wolfcert_http_url_origin so the two cannot drift.

Tests: test_scep_async_roundtrip drives a direct async enrollment; a
blocking-session enrollment followed by a blocking RenewalReq; an async
PENDING -> GetCertInitial poll and its blocking mirror
(GetCertInitial_ex); an async enrollment followed by an async RenewalReq;
and a session forced onto the base64 GET transport. It also exercises the
session misuse guards: an _ex call on an async session, an _nb call on a
blocking session, and starting a second operation while one is in flight.
The async scenarios are pumped through a real poll(2) loop. Registered in
both CMake and autoconf. ARCHITECTURE.md, EMBEDDED context and CLAUDE.md
notes updated.
@Frauschi Frauschi assigned wolfSSL-Bot and philljj and unassigned Frauschi Jul 22, 2026
@Frauschi
Frauschi requested a review from philljj July 22, 2026 11:09
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.

4 participants