Skip to content

tls: read the peer certificate chain without consuming it - #65602

Open
tgies wants to merge 1 commit into
nodejs:mainfrom
tgies:tls-peer-cert-chain
Open

tls: read the peer certificate chain without consuming it#65602
tgies wants to merge 1 commit into
nodejs:mainfrom
tgies:tls-peer-cert-chain

Conversation

@tgies

@tgies tgies commented Aug 27, 2026

Copy link
Copy Markdown

Server-side getPeerCertificate(true) stopped returning the client certificate's issuer chain in v26.8.0. issuerCertificate became undefined.

The root cause actually predates this regression; X509Certificate::GetPeerCert() walked the stack from SSL_get_peer_cert_chain() with sk_X509_delete(), so the first read destroyed the chain for every later read. #64677 added an internal call to getPeerX509Certificate() in onServerSocketSecure() to detect presence of a certificate, so now the mutating read happens every time.

This changes getPeerX509Certificate() to read the chain non-destructively, copying issuers with X509_dup, and replaces the presence check with a hasPeerCertificate() binding.

Fixes: #65579
Refs: #64677

X509Certificate::GetPeerCert() built the certificate objects by deleting
entries from the stack returned by SSL_get_peer_cert_chain(), which is
owned by the SSL session. The first read emptied it, so any later read
by getPeerCertificate() or getPeerX509Certificate(), on either peer, saw
a truncated chain or nothing. Copy each issuer with X509_dup instead and
leave the session's stack untouched.

onServerSocketSecure() only called getPeerX509Certificate() to check
whether a peer certificate was present, building the whole chain on every
server handshake; that is what first exposed the destructive read. Use a
lightweight hasPeerCertificate() binding for the presence check.

Signed-off-by: Tony Gies <tgies@tgies.net>
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/crypto
  • @nodejs/net

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run. labels Aug 27, 2026
@tgies

tgies commented Aug 27, 2026

Copy link
Copy Markdown
Author

BTW, the argument for adding the hasPeerCertificate() binding even after making getPeerX509Certificate() nondestructive is mainly that it's expensive and unnecessary to call getPeerX509Certificate() here anyway. That builds the whole cert chain and the JS X509Certificate wrapper objects on every handshake just so we can test != null.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs related to general changes in the lib or src directory. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tls: server getPeerCertificate(true) drops the peer certificate chain since v26.8.0 (regressed by #64677)

2 participants