GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||
GeezerVison is showing github.com — tls: fix authorized state on no-cert TLS1.3 client cert resumption by pimterry · Pull Request #64677 · nodejs/node Conversation
Member
Previously if you used TLS 1.3 and the server requested a client cert, but the client didn't send one, and you used This doesn't match TLS 1.2 behaviour (which correctly preserves authorization state & errors across resumption). It's not inevitable and it wasn't intentional - this is an artifact of our internal logic for handling PSKs in TLS 1.3 inside ncrypto (here) that wasn't properly validated on this side. We now correctly report the authorization state and/or error from the original connection in all cases. This also adds a matrix test that fully checks the invariant over all combinations of TLS 1.2/1.3 + valid-cert/invalid-cert/no-cert: authorized state after resume should always match the initial state. Fixes #35317 - note there is some debate in there (cc @bnoordhuis) but I think there's confusion in some of the descriptions and it's actually just a clear bug. See also #64584 which was opened just now, to simply document the current state. This PR is either a fix for the current state (in which case we could close #64584) or a semver-major change (in which case we can keep the document PR for now, and merge this to clean that up to change the behaviour as a major bump). Opinions from @nodejs/crypto would be helpful. This is arguably a security fix but it has been directly described in public in that issue as intended behaviour for nearly 6 years. The scope is limited to
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page. All reactions
Collaborator
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
pimterry
force-pushed
the
fix-tls-1.3-client-cert-resume
branch
from
005f950 to
8ec1d60
Compare
Previously if you used TLS 1.3 and the server requested a client cert, but the client didn't send one, and you used rejectUnauthorized:false the resumed session would report authorized=true. This doesn't match TLS 1.2 behaviour or make any sense, and was purely an artifact of our internal logic for handling TLS 1.3 resumption details. We now correctly report the authorization state and/or error from the original connection in all cases, with a matrix test that fully checks the invariant: authorized state after resume should always match the initial state. Signed-off-by: Tim Perry <[email protected]>
pimterry
force-pushed
the
fix-tls-1.3-client-cert-resume
branch
from
8ec1d60 to
428a444
Compare
Member
Author
All reactions
Sorry, something went wrong. Uh oh!
There was an error while loading. Please reload this page.
|
There was an error while loading. Please reload this page.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@ ## main #64677 +/- ## ========================================== - Coverage 90.15% 90.13% -0.02% ========================================== Files 741 741 Lines 242207 242119 -88 Branches 45606 45598 -8 ========================================== - Hits 218354 218228 -126 - Misses 15350 15388 +38 Partials 8503 8503
🚀 New features to boost your workflow:
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@pimterry Did you mean to add |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thanks for the reminder @trivikr! Lost this somewhere, added to the queue. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Landed in c59cd6b |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Previously if you used TLS 1.3 and the server requested a client cert, but the client didn't send one, and you used rejectUnauthorized:false the resumed session would report authorized=true. This doesn't match TLS 1.2 behaviour or make any sense, and was purely an artifact of our internal logic for handling TLS 1.3 resumption details. We now correctly report the authorization state and/or error from the original connection in all cases, with a matrix test that fully checks the invariant: authorized state after resume should always match the initial state. Signed-off-by: Tim Perry <[email protected]> PR-URL: #64677 Reviewed-By: James M Snell <[email protected]>
Previously if you used TLS 1.3 and the server requested a client cert, but the client didn't send one, and you used rejectUnauthorized:false the resumed session would report authorized=true. This doesn't match TLS 1.2 behaviour or make any sense, and was purely an artifact of our internal logic for handling TLS 1.3 resumption details. We now correctly report the authorization state and/or error from the original connection in all cases, with a matrix test that fully checks the invariant: authorized state after resume should always match the initial state. Signed-off-by: Tim Perry <[email protected]> PR-URL: #64677 Reviewed-By: James M Snell <[email protected]>
Previously if you used TLS 1.3 and the server requested a client cert, but the client didn't send one, and you used rejectUnauthorized:false the resumed session would report authorized=true. This doesn't match TLS 1.2 behaviour or make any sense, and was purely an artifact of our internal logic for handling TLS 1.3 resumption details. We now correctly report the authorization state and/or error from the original connection in all cases, with a matrix test that fully checks the invariant: authorized state after resume should always match the initial state. Signed-off-by: Tim Perry <[email protected]> PR-URL: #64677 Reviewed-By: James M Snell <[email protected]>
|
FYI: This caused #65579 by tripping over the pre-existing yet unreported bug that |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
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 <[email protected]> PR-URL: #65602 Fixes: #65579 Refs: #64677 Reviewed-By: Filip Skokan <[email protected]> Reviewed-By: Tim Perry <[email protected]>
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 <[email protected]> PR-URL: #65602 Fixes: #65579 Refs: #64677 Reviewed-By: Filip Skokan <[email protected]> Reviewed-By: Tim Perry <[email protected]>
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 <[email protected]> PR-URL: #65602 Fixes: #65579 Refs: #64677 Reviewed-By: Filip Skokan <[email protected]> Reviewed-By: Tim Perry <[email protected]>
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 <[email protected]> PR-URL: #65602 Fixes: #65579 Refs: #64677 Reviewed-By: Filip Skokan <[email protected]> Reviewed-By: Tim Perry <[email protected]>
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 <[email protected]> PR-URL: #65602 Fixes: #65579 Refs: #64677 Reviewed-By: Filip Skokan <[email protected]> Reviewed-By: Tim Perry <[email protected]>
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
Reloading page bypasses TLS client authentication
There was an error while loading. Please reload this page.