Skip to content

Commit

Permalink
Allow CA fingerprints in different formats (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoshMock authored Aug 21, 2024
1 parent bb0e264 commit db14394
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 4 deletions.
9 changes: 9 additions & 0 deletions src/connection/BaseConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,3 +236,12 @@ export function getIssuerCertificate (socket: TLSSocket): DetailedPeerCertificat
}
return certificate
}

export function isCaFingerprintMatch (cert1: string | null, cert2: string | null): boolean {
if (typeof cert1 === 'string' && typeof cert2 === 'string') {
const c1 = cert1.toLowerCase().replace(/:/g, '')
const c2 = cert2.toLowerCase().replace(/:/g, '')
return c1 === c2
}
return cert1 === cert2
}
5 changes: 3 additions & 2 deletions src/connection/HttpConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ import BaseConnection, {
ConnectionRequestOptionsAsStream,
ConnectionRequestResponse,
ConnectionRequestResponseAsStream,
getIssuerCertificate
getIssuerCertificate,
isCaFingerprintMatch
} from './BaseConnection'
import { kCaFingerprint } from '../symbols'
import { Readable as ReadableStream, pipeline } from 'stream'
Expand Down Expand Up @@ -256,7 +257,7 @@ export default class HttpConnection extends BaseConnection {

// Check if fingerprint matches
/* istanbul ignore else */
if (this[kCaFingerprint] !== issuerCertificate.fingerprint256) {
if (!isCaFingerprintMatch(this[kCaFingerprint], issuerCertificate.fingerprint256)) {
onError(new Error('Server certificate CA fingerprint does not match the value configured in caFingerprint'))
request.once('error', () => {}) // we need to catch the request aborted error
return request.destroy()
Expand Down
5 changes: 3 additions & 2 deletions src/connection/UndiciConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ import BaseConnection, {
ConnectionRequestOptionsAsStream,
ConnectionRequestResponse,
ConnectionRequestResponseAsStream,
getIssuerCertificate
getIssuerCertificate,
isCaFingerprintMatch
} from './BaseConnection'
import { Pool, buildConnector, Dispatcher } from 'undici'
import {
Expand Down Expand Up @@ -95,7 +96,7 @@ export default class Connection extends BaseConnection {

// Check if fingerprint matches
/* istanbul ignore else */
if (caFingerprint !== issuerCertificate.fingerprint256) {
if (!isCaFingerprintMatch(caFingerprint, issuerCertificate.fingerprint256)) {
socket.destroy()
return cb(new Error('Server certificate CA fingerprint does not match the value configured in caFingerprint'), null)
}
Expand Down
23 changes: 23 additions & 0 deletions test/unit/http-connection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1133,6 +1133,29 @@ test('Check server fingerprint (success)', async t => {
server.stop()
})

test('Check server fingerprint (different formats)', async t => {
t.plan(1)

function handler (req: http.IncomingMessage, res: http.ServerResponse) {
res.end('ok')
}

const [{ port, caFingerprint }, server] = await buildServer(handler, { secure: true })

let newCaFingerprint = caFingerprint.toLowerCase().replace(/:/g, '')

const connection = new HttpConnection({
url: new URL(`https://localhost:${port}`),
caFingerprint: newCaFingerprint,
})
const res = await connection.request({
path: '/hello',
method: 'GET'
}, options)
t.equal(res.body, 'ok')
server.stop()
})

test('Check server fingerprint (failure)', async t => {
t.plan(2)

Expand Down
23 changes: 23 additions & 0 deletions test/unit/undici-connection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -991,6 +991,29 @@ test('Check server fingerprint (success)', async t => {
server.stop()
})

test('Check server fingerprint (different formats)', async t => {
t.plan(1)

function handler (_req: http.IncomingMessage, res: http.ServerResponse) {
res.end('ok')
}

const [{ port, caFingerprint }, server] = await buildServer(handler, { secure: true })

let newCaFingerprint = caFingerprint.toLowerCase().replace(/:/g, '')

const connection = new UndiciConnection({
url: new URL(`https://localhost:${port}`),
caFingerprint: newCaFingerprint
})
const res = await connection.request({
path: '/hello',
method: 'GET'
}, options)
t.equal(res.body, 'ok')
server.stop()
})

test('Check server fingerprint (failure)', async t => {
t.plan(2)

Expand Down

0 comments on commit db14394

Please sign in to comment.