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
8 changes: 5 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -165,18 +165,20 @@ check_c_source_compiles("
extern char wc_SetDNSEntry(void);
extern char wc_SetAltNamesFromList(void);
extern char SetLength(void);
extern char GetASNTag(void);
extern char GetLength(void);
int main(void)
{
return FreeAltNames() + wc_SetDNSEntry() + wc_SetAltNamesFromList() +
SetLength();
SetLength() + GetASNTag() + GetLength();
}
" _have_asn_helpers)
unset(CMAKE_REQUIRED_LIBRARIES)
if(NOT _have_asn_helpers)
message(FATAL_ERROR
"wolfSSL does not export its ASN helpers (wc_SetDNSEntry, "
"wc_SetAltNamesFromList, FreeAltNames, SetLength). Rebuild wolfSSL "
"with CPPFLAGS=\"-DWOLFSSL_PUBLIC_ASN\".")
"wc_SetAltNamesFromList, FreeAltNames, SetLength, GetASNTag, "
"GetLength). Rebuild wolfSSL with CPPFLAGS=\"-DWOLFSSL_PUBLIC_ASN\".")
endif()

# Features that default-on in wolfSSL and that wolfCert depends on
Expand Down
52 changes: 27 additions & 25 deletions cli/wolfcert_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,10 @@ static void print_usage(FILE* out)
"reenroll options:\n"
" --cert FILE Current certificate (PEM)\n"
" --key FILE Current private key (PEM)\n"
" plus the enroll options above to describe the renewed cert.\n"
" --out-cert FILE Write renewed certificate (PEM;\n"
" default stdout)\n"
" The renewed cert keeps --cert's subject and SAN (RFC 7030\n"
" section 4.2.2), so --subject and --san-* are rejected.\n"
" --cert/--key also authenticate the TLS connection, so\n"
" --client-cert/--client-key are rejected.\n"
"\n"
Expand Down Expand Up @@ -1455,7 +1458,8 @@ static int cmd_reenroll(int argc, char** argv)
uint8_t* cert_pem = NULL;
uint8_t* key_pem = NULL;
WolfCertKey* current_key = NULL;
WolfCertBuffer csr = { 0 };
WolfCertKey* new_key = NULL;
WolfCertCertMeta meta = { 0 };
WolfCertBuffer issued = { 0 };
WolfCertProtocol p = 0;
size_t cert_len = 0, key_len = 0;
Expand Down Expand Up @@ -1485,8 +1489,16 @@ static int cmd_reenroll(int argc, char** argv)
}

if (ret == 0 &&
(opts.subject == NULL || opts.cert_file == NULL || opts.key_file == NULL)) {
fprintf(stderr, "reenroll: --subject, --cert, --key required\n");
(opts.subject != NULL || opts.san_dns_len != 0 ||
opts.san_ip_len != 0 || opts.san_uri_len != 0 ||
opts.san_email_len != 0)) {
fprintf(stderr, "reenroll: --subject/--san-* are not used; the renewed "
"cert keeps --cert's subject and SAN\n");
ret = 1;
}

if (ret == 0 && (opts.cert_file == NULL || opts.key_file == NULL)) {
fprintf(stderr, "reenroll: --cert, --key required\n");
ret = 1;
}

Expand All @@ -1505,20 +1517,6 @@ static int cmd_reenroll(int argc, char** argv)
ret = 2;
}

if (ret == 0) {
WolfCertCertMeta meta = { .subject_dn = opts.subject,
.san_dns = opts.san_dns, .san_dns_len = opts.san_dns_len,
.san_ip = opts.san_ip, .san_ip_len = opts.san_ip_len,
.san_uri = opts.san_uri, .san_uri_len = opts.san_uri_len,
.san_email = opts.san_email, .san_email_len = opts.san_email_len,
.challenge_password = opts.challenge };
rc = wolfcert_csr_build(current_key, &meta, &csr);
if (rc != WOLFCERT_OK) {
fprintf(stderr, "reenroll csr: %s\n", wolfcert_strerror(rc));
ret = 2;
}
}

WolfCertServerCfg srv = { .protocol = p, .server_url = opts.url };

if (ret == 0) {
Expand All @@ -1529,14 +1527,17 @@ static int cmd_reenroll(int argc, char** argv)
}

if (ret == 0) {
#ifdef WOLFCERT_HAVE_EST
rc = wolfcert_est_simple_reenroll(&srv, cert_pem, cert_len, current_key,
csr.data, csr.len, &issued);
#else
rc = WOLFCERT_ERR_UNSUPPORTED;
#endif
meta.challenge_password = opts.challenge;
rc = wolfcert_client_reenroll(NULL, &srv, cert_pem, cert_len,
current_key, NULL, &meta, &new_key,
&issued);
if (rc != WOLFCERT_OK) {
fprintf(stderr, "reenroll: %s\n", wolfcert_strerror(rc));
const char* m = wolfcert_last_error_message();
if (m && *m) {
fprintf(stderr, "reenroll: detail (wolfssl_err=%d): %s\n",
wolfcert_last_wolfssl_err(), m);
}
ret = 2;
}
}
Expand All @@ -1553,8 +1554,9 @@ static int cmd_reenroll(int argc, char** argv)
}
}

wolfcert_buffer_free(&csr);
wolfcert_buffer_free(&issued);
if (new_key != NULL)
wolfcert_key_free(new_key);
if (current_key != NULL)
wolfcert_key_free(current_key);
free(cert_pem);
Expand Down
10 changes: 6 additions & 4 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -233,14 +233,16 @@ AC_LINK_IFELSE(
[[extern char FreeAltNames(void);
extern char wc_SetDNSEntry(void);
extern char wc_SetAltNamesFromList(void);
extern char SetLength(void);]],
extern char SetLength(void);
extern char GetASNTag(void);
extern char GetLength(void);]],
[[return FreeAltNames() + wc_SetDNSEntry() + wc_SetAltNamesFromList() +
SetLength();]])],
SetLength() + GetASNTag() + GetLength();]])],
[AC_MSG_RESULT([yes])],
[AC_MSG_RESULT([no])
AC_MSG_ERROR([wolfSSL does not export its ASN helpers (wc_SetDNSEntry,
wc_SetAltNamesFromList, FreeAltNames, SetLength). Rebuild wolfSSL with
CPPFLAGS="-DWOLFSSL_PUBLIC_ASN".])])
wc_SetAltNamesFromList, FreeAltNames, SetLength, GetASNTag, GetLength).
Rebuild wolfSSL with CPPFLAGS="-DWOLFSSL_PUBLIC_ASN".])])
LIBS="$save_LIBS"

# wolfSSL default-on features that wolfCert requires unconditionally: AES,
Expand Down
10 changes: 7 additions & 3 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,11 @@ The layering rules that matter to an integrator:
can include it without caring whether EST or SCEP is present.
- **`wolfcert_client_*` is the high-level orchestrator.**
`wolfcert_client_enroll` / `_reenroll` route to EST or SCEP based on
`WolfCertServerCfg.protocol`. Callers that want finer control reach directly
into the `wolfcert_est_*` / `wolfcert_scep_*` primitives.
`WolfCertServerCfg.protocol`. `_reenroll` copies the Subject and SAN of the
certificate being renewed into its CSR byte for byte (RFC 7030 section
4.2.2) and refuses a `WolfCertCertMeta` that sets either. Callers that want
finer control reach directly into the `wolfcert_est_*` / `wolfcert_scep_*`
primitives.
- **Protocol modules depend on subsystems, never the reverse**, and the test
server lives below the public API — an embedder can hand it an
already-accepted socket via `wolfcert_server_serve_fd()` instead of using
Expand Down Expand Up @@ -614,7 +617,8 @@ time `#error`s. See [`EMBEDDED.md`](EMBEDDED.md#configuring-wolfcert-without-its
`WOLFSSL_BASE64_ENCODE`, `WOLFSSL_ALT_NAMES`, `WOLFSSL_CERT_NAME_ALL`. A
`NO_RSA` build hard-fails unless SCEP is disabled. CMake and autoconf also
link-probe the `WOLFSSL_ASN_API` helpers wolfCert calls (`wc_SetDNSEntry`,
`wc_SetAltNamesFromList`, `FreeAltNames`, `SetLength`); a shared libwolfssl
`wc_SetAltNamesFromList`, `FreeAltNames`, `SetLength`, `GetASNTag`,
`GetLength`); a shared libwolfssl
exports them only under one of `WOLFSSL_PUBLIC_ASN` / `OPENSSL_EXTRA` /
`OPENSSL_EXTRA_X509_SMALL` / `WOLFSSL_TEST_CERT`, a static one always links
them. `check_config.h` cannot test a link, so a header-only build that misses
Expand Down
11 changes: 7 additions & 4 deletions docs/EMBEDDED.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ miscompile.
| Consumer | Where it lives | Default size | Dominated by |
|----------|----------------|--------------|--------------|
| wolfSSL `Cert` (CSR / cert build) | **heap** (`wc_CertNew`) | ~20+ KB | `altNames[16384]` |
| wolfSSL `DecodedCert` (cert parse) | **stack**, transient | several KB | parse scratch |
| wolfSSL `DecodedCert` (cert parse) | **stack** or **heap**, transient | several KB | parse scratch |
| HTTP request handling | **stack** (EST + client); **heap** (SCEP server) | 2-3 KB stack | request read buffer |

The good news: wolfCert never stack-allocates a `Cert`. Every CSR/cert
Expand All @@ -120,12 +120,12 @@ the bulk of the size (defaults from `wolfssl/wolfcrypt/asn_public.h`):
| Macro | Default | Effect |
|-------|---------|--------|
| `WC_CTC_MAX_ALT_SIZE` | `16384` | size of `Cert.altNames[]` - the encoded SAN extension. **Single largest contributor.** |
| `WC_CTC_NAME_SIZE` | `64` | size of every `CertName` string field (CN, O, OU, ...). `CertName` carries ~19 such fields under the `WOLFSSL_CERT_NAME_ALL` + `WOLFSSL_CERT_EXT` config wolfCert requires, ×2 for issuer+subject, plus raw copies. |
| `WC_CTC_NAME_SIZE` | `64` | size of every `CertName` string field (CN, O, OU, ...). `CertName` carries ~23 such fields under the `WOLFSSL_CERT_NAME_ALL` + `WOLFSSL_CERT_EXT` config wolfCert requires, ×2 for issuer+subject, plus raw copies. |

These are **wolfSSL** settings, not wolfCert ones - set them when you build
wolfSSL (via `user_settings.h` or `CPPFLAGS`), and wolfCert picks up
whatever wolfSSL provides. For example, to drop a `Cert` from ~20 KB to
~3 KB:
~5 KB:

```c
/* user_settings.h, when building wolfSSL */
Expand All @@ -142,7 +142,10 @@ Trade-offs:
`WOLFCERT_ERR_BAD_ARG` rather than truncating it - both when a client
builds a CSR (`assign_rdn()` in `src/csr.c`) and when the test server
issues from one (`wolfcert_copy_csr_subject()` in `src/ca_issue.c`) - so
shrinking this caps how long a CN you can request.
shrinking this caps how long a CN you can request. A renewal instead
copies the certificate's subject whole, so there the limit is the total
encoded name, `sizeof(CertName)` (about 800 bytes at 32), and a longer one
fails with `WOLFCERT_ERR_UNSUPPORTED`.
- Disabling `WOLFSSL_CERT_NAME_ALL` and/or `WOLFSSL_CERT_EXT` in wolfSSL
removes the less-common `CertName` fields entirely - but wolfCert's
build requires both (see `CLAUDE.md` / `CMakeLists.txt`), so prefer
Expand Down
6 changes: 2 additions & 4 deletions src/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,6 @@ int wolfcert_client_reenroll(WolfCertClient* client, const WolfCertServerCfg* sr
WolfCertKey** out_key, WolfCertBuffer* out_cert_pem)
{
(void)client;
#ifndef WOLFCERT_HAVE_EST
(void)current_cert_len; /* only the EST reenroll path reads it */
#endif
if (srv == NULL || current_cert == NULL || current_key == NULL ||
meta == NULL || out_key == NULL || out_cert_pem == NULL)
return WOLFCERT_ERR_BAD_ARG;
Expand All @@ -246,7 +243,8 @@ int wolfcert_client_reenroll(WolfCertClient* client, const WolfCertServerCfg* sr
const WolfCertKey* signing_key = nk ? nk : current_key;

WolfCertBuffer csr = { 0 };
rc = wolfcert_csr_build(signing_key, meta, &csr);
rc = wolfcert_csr_build_ex(signing_key, meta, current_cert,
current_cert_len, &csr);
if (rc != WOLFCERT_OK) {
if (nk)
wolfcert_key_free(nk);
Expand Down
Loading
Loading