Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,10 @@ wolfcert_cleanup();
`examples/enroll_scep.c` is the full flow.
- **Step by step:** `wolfcert_key_generate`, `wolfcert_csr_build`, then
`wolfcert_est_simple_enroll` (`examples/enroll_est.c`).
- **Pending approval:** the `_ex` variants report a status of PENDING; poll
again later (EST: re-POST after `retry_after_sec`; SCEP:
`wolfcert_scep_get_cert_initial`). The plain variants return
`WOLFCERT_ERR_PENDING`.
- **Pending approval:** the enroll calls report PENDING in their result's
status; poll again later (EST: re-POST after `retry_after_sec`; SCEP:
`wolfcert_scep_get_cert_initial`). `wolfcert_client_enroll` and
`wolfcert_client_reenroll` return `WOLFCERT_ERR_PENDING`.
- **Renewal:** `wolfcert_client_reenroll` (EST, authenticates with the
certificate being renewed) or `wolfcert_scep_renewal_req`.
- **Hardware keys:** `examples/enroll_cryptocb.c`.
Expand All @@ -184,8 +184,8 @@ wolfcert_cleanup();
|---|---|
| `wolfcert/wolfcert.h` | Umbrella header, `wolfcert_init` / `wolfcert_cleanup` |
| `wolfcert/client.h` | High-level `wolfcert_client_*` API |
| `wolfcert/est.h`, `wolfcert/scep.h` | Protocol one-shots, `_ex` PENDING variants, sessions, non-blocking `_nb` sessions |
| `wolfcert/types.h` | `WolfCertServerCfg`, `WolfCertKeyCfg`, `WolfCertCertMeta`, `WolfCertTransport`, `wolfcert_buffer_free` |
| `wolfcert/est.h`, `wolfcert/scep.h` | Protocol one-shots, sessions, non-blocking `_nb` sessions |
| `wolfcert/types.h` | `WolfCertServerCfg`, `WolfCertKeyCfg`, `WolfCertCertMeta`, `WolfCertEncoding` (PEM or DER output), `WolfCertTransport`, `wolfcert_buffer_free` |
| `wolfcert/keygen.h`, `wolfcert/csr.h` | Key generation, import / export, CSR building |
| `wolfcert/store.h` | `WolfCertStoreOps` storage vtable, POSIX and in-memory backends |
| `wolfcert/errors.h`, `wolfcert/status.h`, `wolfcert/log.h` | Error codes, last-error detail, log callback |
Expand All @@ -206,7 +206,7 @@ contract, alone or in a group comment.
| Network stack without BSD sockets (lwIP, NetX, FreeRTOS+TCP, wolfIP) | Fill `WolfCertServerCfg.transport` (`WolfCertTransport`); TLS records go through it too | `wolfcert/types.h`, `docs/EMBEDDED.md` section 7 |
| Persistence in flash / NVM | Implement `WolfCertStoreOps` (`read` / `write` / `remove`) | `wolfcert/store.h` |
| Keys in a TPM, HSM, PKCS#11 token or secure element | Register a backend with `wc_CryptoCb_RegisterDevice`, pass its id as `WolfCertKeyCfg.dev_id` | `docs/ARCHITECTURE.md` section 4.2, `examples/enroll_cryptocb.c` |
| Event loop / no blocking | `wolfcert_est_session_open_async` / `wolfcert_scep_session_open_async`, then the `_nb` calls until they stop returning `WOLFCERT_ERR_WANT_READ` / `_WANT_WRITE`; `*_session_fd` gives the descriptor to poll | `wolfcert/est.h`, `wolfcert/scep.h` |
| Event loop / no blocking | `wolfcert_est_session_open` / `wolfcert_scep_session_open`, then the `_nb` calls until they stop returning `WOLFCERT_ERR_WANT_READ` / `_WANT_WRITE`; `*_session_fd` gives the descriptor to poll | `wolfcert/est.h`, `wolfcert/scep.h` |
| Logging | `wolfcert_set_log_cb` (e.g. to a UART) | `wolfcert/log.h` |
| RAM budget | `max_response_bytes`, HTTP stack buffers, wolfSSL `Cert` / `CertName` sizing | `docs/EMBEDDED.md` |

Expand Down Expand Up @@ -249,7 +249,8 @@ contract, alone or in a group comment.
- **The HTTPS transport needs TLS 1.2 or newer**, or TLS 1.3 when wolfSSL
is built with `WOLFSSL_NO_TLS12`. A server limited to older versions
fails the handshake.
- **Non-blocking mode still blocks for DNS and the initial TCP connect.**
- **Session open still blocks for DNS and the initial TCP connect**, even
when every later call is `_nb`.
- **The test server is for development and interop only**, not a production
CA.
- **SCEP over plain HTTP is downgradable:** an attacker who strips `AES` from
Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,12 +213,12 @@ All `WolfCertBuffer` outputs remember which heap they came from, so the same
- **SCEP operations:** `GetCACaps`, `GetCACert`, `GetNextCACert`, `PKCSReq`,
`RenewalReq`, `GetCert`, plus `pkiStatus=PENDING` + `GetCertInitial` polling.
- **Transport:** HTTP/1.1 over wolfSSL TLS 1.3/1.2 (trust anchors, SNI,
mutual TLS), keep-alive sessions, TLS 1.3 post-handshake auth, and an
optional non-blocking mode for `poll`/`epoll`/`kqueue` event loops. Every
byte goes through the `WolfCertTransport` vtable, TLS records included, so
a non-BSD-sockets stack (FreeRTOS+TCP, NetX, lwIP, wolfIP) needs one small
glue file and no wolfCert change; the POSIX transport is the default
instance and can be compiled out.
mutual TLS), keep-alive sessions that take blocking or non-blocking (`_nb`)
calls for `poll`/`epoll`/`kqueue` event loops, and TLS 1.3 post-handshake
auth. Every byte goes through the `WolfCertTransport` vtable, TLS records
included, so a non-BSD-sockets stack (FreeRTOS+TCP, NetX, lwIP, wolfIP)
needs one small glue file and no wolfCert change; the POSIX transport is the
default instance and can be compiled out.
- **Storage:** file-based cert/key store with atomic writes and 0600 key-file
mode; pluggable via the `WolfCertStoreOps` vtable.
- **Test servers + CLIs** for Linux/macOS (`wolfcert-server`,
Expand Down
61 changes: 32 additions & 29 deletions cli/wolfcert_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1220,7 +1220,7 @@ static int scep_resolve_ca(const WolfCertServerCfg* srv, const CaPin* pin,
const char* who, int pick_ra, ScepCaSet* cs)
{
WolfCertBuffer der = { 0 };
int rc = wolfcert_scep_get_ca_cert_enc(srv, WOLFCERT_ENCODING_DER, &der);
int rc = wolfcert_scep_get_ca_cert(srv, WOLFCERT_ENCODING_DER, &der);

memset(cs, 0, sizeof(*cs));
if (rc == WOLFCERT_OK)
Expand Down Expand Up @@ -1275,14 +1275,14 @@ static int scep_enroll(const Opts* opts, const WolfCertServerCfg* srv,
renew_srv.proto_opts.scep.renewal_msg_type =
WOLFCERT_SCEP_RENEWAL_MSG_PKCS_REQ;
}
rc = wolfcert_scep_renewal_req_ex(&renew_srv, &caps, cas.ra,
rc = wolfcert_scep_renewal_req(&renew_srv, &caps, cas.ra,
cas.ra_len, cas.bundle, cas.bundle_len, renew_cert->buffer,
renew_cert->length, key, csr->data, csr->len, &scep_result);
}
else if (rc == WOLFCERT_OK) {
rc = wolfcert_scep_pkcs_req_ex(srv, &caps, cas.ra, cas.ra_len,
cas.bundle, cas.bundle_len, key,
csr->data, csr->len, &scep_result);
rc = wolfcert_scep_pkcs_req(srv, &caps, cas.ra, cas.ra_len,
cas.bundle, cas.bundle_len, key,
csr->data, csr->len, &scep_result);
}

/* GetCertInitial polling while PENDING (RFC 8894 section 3.3.3). */
Expand Down Expand Up @@ -1380,13 +1380,13 @@ static int cmd_getcacerts(int argc, char** argv)
if (ret == 0) {
if (p == WOLFCERT_PROTO_EST) {
#ifdef WOLFCERT_HAVE_EST
rc = wolfcert_est_get_cacerts(&srv, &pem);
rc = wolfcert_est_get_cacerts(&srv, WOLFCERT_ENCODING_PEM, &pem);
#endif
}
else {
#ifdef WOLFCERT_HAVE_SCEP
rc = wolfcert_scep_get_ca_cert_enc(&srv, WOLFCERT_ENCODING_DER,
&der);
rc = wolfcert_scep_get_ca_cert(&srv, WOLFCERT_ENCODING_DER,
&der);
#endif
}

Expand Down Expand Up @@ -1566,24 +1566,26 @@ static int cmd_enroll(int argc, char** argv)

if (ret == 0 && p == WOLFCERT_PROTO_EST) {
#ifdef WOLFCERT_HAVE_EST
WolfCertEstResult est_result = { 0 };
if (opts.pha) {
/* TLS 1.3 post-handshake auth on one kept-alive session. */
srv.proto_opts.est.allow_post_handshake_auth = 1;
WolfCertEstSession* es = NULL;
rc = wolfcert_est_session_open(&srv, &es);
if (rc == WOLFCERT_OK) {
WolfCertBuffer ca_pem = { 0 };
rc = wolfcert_est_session_get_cacerts(es, &ca_pem);
rc = wolfcert_est_session_get_cacerts(es, WOLFCERT_ENCODING_PEM,
&ca_pem);
wolfcert_buffer_free(&ca_pem);
if (rc == WOLFCERT_OK)
rc = wolfcert_est_session_simple_enroll(es, csr.data, csr.len, &issued);
rc = wolfcert_est_session_simple_enroll(es, csr.data, csr.len,
&est_result);
wolfcert_est_session_close(es);
}
}
else {
/* _ex reports 202 Accepted (RFC 7030 section 4.2.3) as PENDING. */
WolfCertEstResult est_result = { 0 };
rc = wolfcert_est_simple_enroll_ex(&srv, csr.data, csr.len, &est_result);
/* 202 Accepted (RFC 7030 section 4.2.3) comes back as PENDING. */
rc = wolfcert_est_simple_enroll(&srv, csr.data, csr.len, &est_result);
int attempts = 0;
while (rc == WOLFCERT_OK &&
est_result.status == WOLFCERT_EST_STATUS_PENDING &&
Expand All @@ -1599,26 +1601,26 @@ static int cmd_enroll(int argc, char** argv)

nanosleep(&ts, NULL);
wolfcert_est_result_free(&est_result);
rc = wolfcert_est_simple_enroll_ex(&srv, csr.data, csr.len, &est_result);
rc = wolfcert_est_simple_enroll(&srv, csr.data, csr.len, &est_result);
attempts++;
}
}

if (rc == WOLFCERT_OK) {
if (est_result.status == WOLFCERT_EST_STATUS_SUCCESS) {
issued = est_result.cert_pem;
est_result.cert_pem.data = NULL;
est_result.cert_pem.len = 0;
}
else if (est_result.status == WOLFCERT_EST_STATUS_PENDING) {
rc = WOLFCERT_ERR_PENDING;
}
else {
rc = WOLFCERT_ERR_PROTOCOL;
}
if (rc == WOLFCERT_OK) {
if (est_result.status == WOLFCERT_EST_STATUS_SUCCESS) {
issued = est_result.cert_pem;
est_result.cert_pem.data = NULL;
est_result.cert_pem.len = 0;
}
else if (est_result.status == WOLFCERT_EST_STATUS_PENDING) {
rc = WOLFCERT_ERR_PENDING;
}
else {
rc = WOLFCERT_ERR_PROTOCOL;
}

wolfcert_est_result_free(&est_result);
}

wolfcert_est_result_free(&est_result);
#endif
}
else if (ret == 0) {
Expand Down Expand Up @@ -2112,7 +2114,8 @@ static int cmd_getnextca(int argc, char** argv)
}

if (ret == 0) {
rc = wolfcert_scep_get_next_ca_cert(&srv, current, current_len, &pem);
rc = wolfcert_scep_get_next_ca_cert(&srv, WOLFCERT_ENCODING_PEM,
current, current_len, &pem);
if (rc != WOLFCERT_OK) {
fprintf(stderr, "getnextca: %s\n", wolfcert_strerror(rc));
if (pin.ca.len > 0 && rc == WOLFCERT_ERR_AUTH) {
Expand Down
Loading
Loading