Skip to content

Commit 41e14d2

Browse files
authored
Skip fingerprint check when TLS session is being reused (#197)
1 parent c2848e7 commit 41e14d2

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

src/connection/UndiciConnection.ts

+9
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,15 @@ export default class Connection extends BaseConnection {
9898
return cb(new Error('Invalid or malformed certificate'), null)
9999
}
100100

101+
// Certificate will be empty if a session is reused. In this case, getPeerCertificate
102+
// will return an empty object, causing a fingeprint check to fail. But, if the session
103+
// is being reused, it means this socket's peer certificate fingerprint has already been
104+
// checked, so we can skip it and assume the connection is secure.
105+
// See https://github.com/nodejs/node/issues/3940#issuecomment-166696776
106+
if (Object.keys(issuerCertificate).length === 0 && socket.isSessionReused()) {
107+
return cb(null, socket)
108+
}
109+
101110
// Check if fingerprint matches
102111
/* istanbul ignore else */
103112
if (!isCaFingerprintMatch(caFingerprint, issuerCertificate.fingerprint256)) {

test/unit/undici-connection.test.ts

+33
Original file line numberDiff line numberDiff line change
@@ -1073,6 +1073,39 @@ test('Check server fingerprint (failure)', async t => {
10731073
server.stop()
10741074
})
10751075

1076+
test('Multiple requests to same connection should skip fingerprint check when session is reused', async t => {
1077+
// fingerprint matching can, and must, be skipped when a TLS session is being reused
1078+
// see https://nodejs.org/api/tls.html#session-resumption
1079+
// this tests that subsequent requests sent to the same connection will not fail due to
1080+
// a fingerprint match test failing.
1081+
const runs = 4
1082+
t.plan(runs)
1083+
1084+
function handler (_req: http.IncomingMessage, res: http.ServerResponse) {
1085+
res.end('ok')
1086+
}
1087+
1088+
const [{ port, caFingerprint }, server] = await buildServer(handler, { secure: true })
1089+
const connection = new UndiciConnection({
1090+
url: new URL(`https://localhost:${port}`),
1091+
caFingerprint,
1092+
})
1093+
1094+
for (let i = 0; i < runs; i++) {
1095+
try {
1096+
const res = await connection.request({
1097+
path: `/hello-${i}`,
1098+
method: 'GET'
1099+
}, options)
1100+
t.equal(res.body, 'ok')
1101+
} catch {
1102+
t.fail('This should never be reached')
1103+
}
1104+
}
1105+
1106+
server.stop()
1107+
})
1108+
10761109
test('Should show local/remote socket addres in case of ECONNRESET', async t => {
10771110
t.plan(2)
10781111

0 commit comments

Comments
 (0)