Skip to content

Add RFC8773(bis) cert_with_extern_psk support#10085

Merged
dgarske merged 1 commit intowolfSSL:masterfrom
Frauschi:rfc8773bis-cert-with-extern-psk
Apr 17, 2026
Merged

Add RFC8773(bis) cert_with_extern_psk support#10085
dgarske merged 1 commit intowolfSSL:masterfrom
Frauschi:rfc8773bis-cert-with-extern-psk

Conversation

@Frauschi
Copy link
Copy Markdown
Contributor

Implement RFC 8773(bis) cert_with_extern_psk for TLS 1.3.

Includes unit tests for API and handshake behavior as well as tests in the testsuite using extended examples.

Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #10085

Scan targets checked: src, src-bugs, src-compliance
Findings: 3

Medium (2)

DoPreSharedKeys returns fatal error instead of skipping session ticket identity when cert_with_extern_psk is offered

File: src/tls13.c:6193-6198
Function: DoPreSharedKeys
Category: Logic errors

When the server processes PSK identities in DoPreSharedKeys, it iterates through all client-offered identities trying each as a session ticket first, then as an external PSK via FindPsk. The new code returns PSK_KEY_ERROR immediately when a session ticket identity matches and certWithExternOffered is true. This terminates the entire function, preventing the server from trying subsequent identities in the list. A legitimate client could offer a session ticket identity (for resumption with servers that don't support cert_with_extern_psk) followed by an external PSK identity (for cert_with_extern_psk). The fatal return prevents the server from ever reaching the external PSK identity, causing a handshake failure that could be avoided by simply skipping the ticket identity.

#if defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && defined(HAVE_SESSION_TICKET)
            if (certWithExternOffered) {
                WOLFSSL_ERROR_VERBOSE(PSK_KEY_ERROR);
                return PSK_KEY_ERROR;
            }
#endif

Recommendation: Replace return PSK_KEY_ERROR with continue so that the server skips the session ticket identity and proceeds to try the next identity in the list, which may be a valid external PSK identity suitable for cert_with_extern_psk.


DoPreSharedKeys fatally rejects session ticket match when cert_with_extern_psk is offered, violating RFC 8773bis fallback behavior

File: src/tls13.c:6196-6200
Function: DoPreSharedKeys
Category: Session resumption violations

When the client offers the tls_cert_with_extern_psk extension and also includes a session ticket identity in pre_shared_key, the server returns PSK_KEY_ERROR if the session ticket successfully decrypts. This is a hard return, not a continue, so it aborts the entire PSK identity search loop — even if a valid external PSK identity appears later in the list.

RFC 8773bis Section 3 explicitly permits the server to select a resumption PSK when the client offers cert_with_extern_psk: "If the client includes the 'tls_cert_with_extern_psk' extension in the ClientHello, and the server selects a resumption PSK, the server MUST NOT echo the extension." The spec allows normal ticket resumption as a fallback — the server simply omits the extension from ServerHello.

The current code prevents two valid scenarios:

  1. A client offering both a session ticket and an external PSK identity (ticket listed first) — the server should skip the ticket and try the external PSK, or fall back to normal resumption.
  2. A client offering cert_with_extern_psk with only a session ticket that matches — the server should fall back to normal ticket resumption without echoing the extension.
#if defined(WOLFSSL_CERT_WITH_EXTERN_PSK) && defined(HAVE_SESSION_TICKET)
            if (certWithExternOffered) {
                WOLFSSL_ERROR_VERBOSE(PSK_KEY_ERROR);
                return PSK_KEY_ERROR;
            }
#endif

            /* SERVER: using secret in session ticket for peer auth. */
            ssl->options.peerAuthGood = 1;

Recommendation: Replace return PSK_KEY_ERROR with continue so the server skips the session ticket identity and continues searching for an external PSK identity. If no external PSK matches after the loop completes, the server can fall back to normal behavior (either retry with the ticket without echoing cert_with_extern_psk, or proceed without PSK).


Low (1)

TLSX_Cert_With_Extern_Psk_Parse overwrites actual error code with MEMORY_E

File: src/tls.c:12389-12390
Function: TLSX_Cert_With_Extern_Psk_Parse
Category: Incorrect error handling

In the client_hello handler of TLSX_Cert_With_Extern_Psk_Parse, the return value of TLSX_Cert_With_Extern_Psk_Use(ssl) is checked for non-zero but then hardcoded MEMORY_E is returned instead of the actual error code. TLSX_Cert_With_Extern_Psk_Use internally calls TLSX_Push, which may return various error codes. The actual error is lost and replaced with MEMORY_E, making debugging harder and potentially reporting the wrong error to the caller.

if (msgType == client_hello) {
        if (!ssl->options.certWithExternPsk)
            return 0;
        if (TLSX_Cert_With_Extern_Psk_Use(ssl) != 0)
            return MEMORY_E;

Recommendation: Propagate the actual error code: int ret = TLSX_Cert_With_Extern_Psk_Use(ssl); if (ret != 0) return ret;


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

@Frauschi Frauschi force-pushed the rfc8773bis-cert-with-extern-psk branch from 2ee0302 to 7a7ba81 Compare March 26, 2026 21:29
@Frauschi
Copy link
Copy Markdown
Contributor Author

@wolfSSL-Fenrir-bot Findings 1 and 2 identify a real bug,
but the recommended fix (continue instead of return) would be a spec
violation.

RFC 8773bis §5.1 (draft-ietf-tls-8773bis-13) is unambiguous:

▎ "All of the listed PSKs MUST be external PSKs. If a resumption PSK is
listed along with the tls_cert_with_extern_psk extension, the server
MUST abort the handshake with an illegal_parameter alert."

There is no "skip and continue" option — the presence of any resumption
PSK identity alongside tls_cert_with_extern_psk is a protocol
violation requiring a hard abort. Changing to continue would allow the
server to accept an external PSK identity from a list that also
contained a forbidden resumption PSK, violating the spec. The return
PSK_KEY_ERROR is correct because PSK_KEY_ERROR maps to
illegal_parameter in TranslateErrorToAlert (src/internal.c).

The actual bug was that the check fired too late: only after
DoClientTicketCheck succeeded. If a ticket successfully decrypted
(WOLFSSL_TICKET_RET_OK) but then failed DoClientTicketCheck (e.g.
cipher suite mismatch, expired), the early continue at the
check-failure path bypassed the certWithExternOffered guard entirely. A
client could therefore offer cert_with_extern_psk alongside a
resumption PSK identity that happened to fail the suite/expiry check,
and the server would proceed to evaluate subsequent external PSK
identities without aborting — a spec violation.

The fix moves the certWithExternOffered abort to fire immediately upon
successful ticket decryption, before DoClientTicketCheck and
DoClientTicketFinalize. This ensures any recognized session ticket
identity triggers the mandatory abort regardless of further validity
checks. The sess_free_cb cleanup is included in the early-exit path,
and the move also avoids DoClientTicketFinalize polluting ssl->session
with ticket state that will never be used.

Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #10085

Scan targets checked: src, src-bugs, src-compliance

No new issues found in the changed files. ✅

@Frauschi
Copy link
Copy Markdown
Contributor Author

Jenkins retest this please

@Frauschi Frauschi force-pushed the rfc8773bis-cert-with-extern-psk branch from 7a7ba81 to 9976db0 Compare March 27, 2026 08:40
@Frauschi Frauschi added the Not For This Release Not for release 5.9.1 label Mar 27, 2026
@dgarske dgarske removed the Not For This Release Not for release 5.9.1 label Apr 8, 2026
@Frauschi Frauschi force-pushed the rfc8773bis-cert-with-extern-psk branch from 9976db0 to 615ac8d Compare April 9, 2026 08:56
dgarske

This comment was marked as duplicate.

dgarske

This comment was marked as duplicate.

dgarske

This comment was marked as duplicate.

dgarske

This comment was marked as duplicate.

Copy link
Copy Markdown
Member

@dgarske dgarske left a comment

Choose a reason for hiding this comment

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

🐺 Skoll Code Review

Overall recommendation: REQUEST_CHANGES
Findings: 7 total — 5 posted, 2 skipped

Posted findings

  • [High] Early return in DoPreSharedKeys skips ForceZero cleanup of sensitive key materialsrc/tls13.c:6247
  • [Medium] FindPsk sets peerAuthGood=1 on server without considering certWithExternPsksrc/tls13.c:4316
  • [Medium] No negative test for client receiving resumption ticket with cert_with_extern_psktests/api/test_tls13.c:951-1059
  • [Medium] test_tls13_cert_with_extern_psk_handshake may silently skip cert verificationtests/api/test_tls13.c:970-975
  • [Medium] Early data extension validation runs only when WOLFSSL_EARLY_DATA is definedsrc/tls.c:17903-17907
Skipped findings
  • [Low] Preprocessor indent inconsistency in server.c cert_with_extern_psk block
  • [Info] WOLFSSL_ENTER missing from new API functions

Review generated by Skoll via openclaw

Comment thread src/tls13.c Outdated
Comment thread src/tls13.c
Comment thread tests/api/test_tls13.c
Comment thread tests/api/test_tls13.c Outdated
Comment thread src/tls.c
@Frauschi Frauschi force-pushed the rfc8773bis-cert-with-extern-psk branch 2 times, most recently from d6d9f9a to 11729ec Compare April 10, 2026 14:45
Copy link
Copy Markdown

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

Choose a reason for hiding this comment

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

Fenrir Automated Review — PR #10085

Scan targets checked: wolfssl-bugs, wolfssl-compliance, wolfssl-consttime, wolfssl-defaults, wolfssl-mutation, wolfssl-proptest, wolfssl-src, wolfssl-zeroize

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 src/tls.c
@Frauschi Frauschi force-pushed the rfc8773bis-cert-with-extern-psk branch from 11729ec to 28a3078 Compare April 10, 2026 15:48
@Frauschi
Copy link
Copy Markdown
Contributor Author

Jenkins retest this please

@Frauschi Frauschi removed their assignment Apr 10, 2026
@Frauschi Frauschi requested a review from dgarske April 10, 2026 18:44
dgarske
dgarske previously approved these changes Apr 10, 2026
Copy link
Copy Markdown
Member

@dgarske dgarske left a comment

Choose a reason for hiding this comment

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

@SparkiDev can you also take a quick look at this?

@dgarske dgarske requested a review from SparkiDev April 10, 2026 21:30
Comment thread src/tls.c Outdated
Comment thread src/tls.c Outdated
Comment thread src/tls.c Outdated
@Frauschi Frauschi requested a review from SparkiDev April 13, 2026 18:15
SparkiDev
SparkiDev previously approved these changes Apr 13, 2026
Copy link
Copy Markdown
Member

@dgarske dgarske left a comment

Choose a reason for hiding this comment

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

🐺 Skoll Code Review

Overall recommendation: APPROVE
Findings: 5 total — 3 posted, 3 skipped

Posted findings

  • [Low] Preprocessor guard mismatch between variable declarations and usage in TLSX_Parsesrc/tls.c:17143-17147 vs 17879-17880
  • [Medium] Server certWithExternPsk flag not cleared when PSK matching fails without WOLFSSL_PSK_ID_PROTECTIONsrc/tls13.c:6605-6624
  • [Medium] Early data acceptance not guarded against cert_with_extern_psk in CheckPreSharedKeyssrc/tls13.c:6498-6558
Skipped findings
  • [Medium] DoPreSharedKeys strict abort on ticket PSK with cert_with_extern_psk
  • [Low] Inconsistent preprocessor indentation in server.c cert_with_extern_psk block
  • [Low] Preprocessor guard mismatch between variable declarations and usage in TLSX_Parse

Review generated by Skoll via openclaw

Comment thread src/tls13.c
Comment thread src/tls13.c
@dgarske dgarske assigned Frauschi and unassigned wolfSSL-Bot Apr 14, 2026
@Frauschi Frauschi force-pushed the rfc8773bis-cert-with-extern-psk branch from 5acd914 to e35767e Compare April 14, 2026 18:05
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 15, 2026

MemBrowse Memory Report

No memory changes detected for:

@Frauschi
Copy link
Copy Markdown
Contributor Author

Jenkins retest this please

@Frauschi Frauschi force-pushed the rfc8773bis-cert-with-extern-psk branch 2 times, most recently from 0369947 to c6ec94a Compare April 15, 2026 13:26
@Frauschi Frauschi assigned wolfSSL-Bot and unassigned Frauschi Apr 15, 2026
@Frauschi Frauschi requested review from SparkiDev and dgarske April 15, 2026 15:40
@Frauschi
Copy link
Copy Markdown
Contributor Author

Fixed the issues from @dgarske and also incorporated some fixes Skoll found on my side.

dgarske
dgarske previously approved these changes Apr 15, 2026
@Frauschi
Copy link
Copy Markdown
Contributor Author

Jenkins retest this please

@Frauschi Frauschi removed their assignment Apr 16, 2026
SparkiDev
SparkiDev previously approved these changes Apr 16, 2026
Implement RFC8773bis (draft-ietf-tls-8773bis-13)
cert_with_extern_psk for TLS 1.3, including protocol checks
and API support.

Includes unit tests for API and handshake behavior as well
as tests in the testsuite using extended examples.
@Frauschi
Copy link
Copy Markdown
Contributor Author

Rebased to master and fixed merge conflicts. No other changes.

@dgarske dgarske merged commit c4c71ee into wolfSSL:master Apr 17, 2026
448 checks passed
@Frauschi Frauschi deleted the rfc8773bis-cert-with-extern-psk branch April 17, 2026 18:29
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.

5 participants