Add certificate loading APIs with content-based format detection - #1140
Add certificate loading APIs with content-based format detection#1140yosuke-wolfssl wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
Adds certificate-loading APIs that mirror wolfSSH_ReadKey_file() by detecting certificate format from content, while also tightening certificate algorithm identification and fixing an SSH public key parsing edge case.
Changes:
- Introduces
wolfSSH_ReadCert_{buffer,file}()andwolfSSH_CTX_{UseCert,AddRootCert}_file()(content-sniffed PEM/DER and OpenSSH cert-line support where enabled). - Refactors internal certificate identification to return the wire
x509v3-*algorithm (and reject unmappable certs). - Fixes
DoSshPubKey()handling for SSH public key lines that do not end with a trailing newline; adds API test coverage for new cert APIs and the newline edge case.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| wolfssh/ssh.h | Declares new public certificate read/file APIs and WS_CertFlavors. |
| wolfssh/internal.h | Exposes IdentifyCert() for internal callers under WOLFSSH_CERTS. |
| src/ssh.c | Implements new cert read APIs, adds cert form sniffing, refactors file reading helper, fixes DoSshPubKey() termination. |
| src/internal.c | Splits “identify key inside cert” vs “identify cert wire algo”; adjusts host certificate slot handling logic. |
| tests/api.c | Adds coverage for new cert APIs and validates no-trailing-newline SSH public key parsing. |
| keys/server-key-ed25519-cert.pem | Adds Ed25519 private key fixture used to generate the unmappable X.509 cert. |
| keys/server-cert-ed25519.pem | Adds Ed25519 X.509 cert fixture used to exercise unmappable x509v3-* rejection. |
| keys/renewcerts.sh | Extends renewal script to generate the new Ed25519 cert/key fixtures. |
| keys/include.am | Distributes new key/cert fixtures via Automake EXTRA_DIST. |
Suppressed comments (1)
src/internal.c:2364
- SetHostCertificate() always uses destIdx after the scan loop, but destIdx is guaranteed to equal ctx->privateKeyCount at that point. That means an existing certificate slot (certIdx) is never reused/replaced; instead a new entry is appended each time, leading to duplicate cert slots, leaked old certs, and eventual WS_CTX_KEY_COUNT_E once the key table fills.
Use certIdx when it was found (replace-in-place), and only use privateKeyCount as the insertion index when no existing cert slot exists.
}
if (destIdx >= WOLFSSH_MAX_PVT_KEYS) {
ret = WS_CTX_KEY_COUNT_E;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
a3593b5 to
4e61b9a
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #1140
Scan targets checked: wolfssh-bugs, wolfssh-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.
4e61b9a to
a9cb98a
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #1140
Scan targets checked: wolfssh-bugs, wolfssh-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.
a9cb98a to
26e1979
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #1140
Scan targets checked: wolfssh-bugs, wolfssh-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.
26e1979 to
1ce2f57
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #1140
Scan targets checked: wolfssh-bugs, wolfssh-src
No new issues found in the changed files. ✅
1ce2f57 to
c7200ca
Compare
Problem
wolfSSH has a single entry point for loading key files,
wolfSSH_ReadKey_file(), which sniffs the format from the file's content. Certificates had no equivalent:wolfSSH_CTX_UseCert_buffer()andwolfSSH_CTX_AddRootCert_buffer()are buffer-only and require the caller to already know PEM from DER. As a result five call sites acrossapps/andexamples/hand-roll file reading plus a blind try-PEM-then-retry-ASN1 dance, andapps/wolfsshd/wolfsshd.ccarries aTODOasking for exactly this helper.Fix (
src/ssh.c)New public API; the form is detected from the content, so there is no
formatargument.CERTIFICATE(header may follow an openssl text dump)flavor=WOLFSSH_CERT_FLAVOR_X509flavor=WOLFSSH_CERT_FLAVOR_X509*-cert-v01@openssh.comlineflavor=WOLFSSH_CERT_FLAVOR_OSSHoutTypeis the wire algorithm name derived from the certificate rather than a compile-time flag. An RFC 6187x509v3-*line is a public key carrying a chain, not a certificate, so it is declined here —wolfSSH_ReadKey_buffer()withWOLFSSH_FORMAT_SSHalready reads that form.Certificate identification is now consistent (
src/internal.c). The oldIdentifyCert()names the key inside a certificate, so it is renamedIdentifyCertKey(), and a newIdentifyCert()returns thex509v3-*wire algorithm, rejecting a key type that has no such name withWS_INVALID_ALGO_ID.SetHostCertificate()now takescertId, which letswolfSSH_ProcessBuffer()apply the same rule. PreviouslywolfSSH_CTX_UseCert_buffer()accepted such a certificate, stored it under a plain key id, and advertised an unusable host-key algorithm.This is the library half; converting the five existing call sites is a follow-up PR.
Tests (
tests/api.c)test_wolfSSH_ReadCert_buffer,_file,test_wolfSSH_CTX_UseCert_file,_AddRootCert_file, and an OpenSSH round-trip. Negative cases cover a truncated PEM, a bare DER header, a DER and a PEM private key, an SSH public key line, anx509v3-*line, and a certificate with nox509v3name — for whichkeys/server-cert-ed25519.{pem,der}is added, generated byrenewcerts.sh.Verification
make checkpasses with--enable-certs,--enable-ossh-certs, both, and neither.-Werroracross the CI configurations, including small-stack and Zephyr defines.x509v3-*name for the key type, the read and CTX paths now agree on rejecting the certificate.