Skip to content

Commit 82ac83c

Browse files
authored
fix: check for signal abort in tls during cert generation (#3203)
Ensure we don't miss abort events. Also removes abort listener from signal which can cause leaks if the signal is long-lived.
1 parent 8ad44f7 commit 82ac83c

File tree

2 files changed

+24
-13
lines changed

2 files changed

+24
-13
lines changed

packages/connection-encrypter-tls/src/tls.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export class TLS implements ConnectionEncrypter {
9898
}
9999

100100
const opts: TLSSocketOptions = {
101-
...await generateCertificate(this.components.privateKey),
101+
...await generateCertificate(this.components.privateKey, options),
102102
isServer,
103103
// require TLS 1.3 or later
104104
minVersion: 'TLSv1.3',
@@ -147,17 +147,19 @@ export class TLS implements ConnectionEncrypter {
147147
})
148148
}
149149

150-
return new Promise<SecuredConnection<Stream>>((resolve, reject) => {
151-
options?.signal?.addEventListener('abort', () => {
152-
this.metrics[isServer ? 'server' : 'client'].events?.increment({
153-
abort: true
154-
})
155-
this.metrics[isServer ? 'server' : 'client'].errors?.increment({
156-
encrypt_abort: true
157-
})
158-
socket.emit('error', new HandshakeTimeoutError())
150+
const onAbort = (): void => {
151+
this.metrics[isServer ? 'server' : 'client'].events?.increment({
152+
abort: true
153+
})
154+
this.metrics[isServer ? 'server' : 'client'].errors?.increment({
155+
encrypt_abort: true
159156
})
157+
socket.emit('error', new HandshakeTimeoutError())
158+
}
159+
160+
options?.signal?.addEventListener('abort', onAbort)
160161

162+
return new Promise<SecuredConnection<Stream>>((resolve, reject) => {
161163
const verifyRemote = (): void => {
162164
const remote = socket.getPeerCertificate()
163165

@@ -234,6 +236,9 @@ export class TLS implements ConnectionEncrypter {
234236
})
235237
})
236238
})
239+
.finally(() => {
240+
options?.signal?.removeEventListener('abort', onAbort)
241+
})
237242
}
238243
}
239244

packages/connection-encrypter-tls/src/utils.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
1313
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
1414
import { InvalidCertificateError } from './errors.js'
1515
import { KeyType, PublicKey } from './pb/index.js'
16-
import type { PeerId, PublicKey as Libp2pPublicKey, Logger, PrivateKey } from '@libp2p/interface'
16+
import type { PeerId, PublicKey as Libp2pPublicKey, Logger, PrivateKey, AbortOptions } from '@libp2p/interface'
1717
import type { Pushable } from 'it-queueless-pushable'
1818
import type { Duplex, Source } from 'it-stream-types'
1919
import type { Uint8ArrayList } from 'uint8arraylist'
@@ -91,7 +91,7 @@ export async function verifyPeerCertificate (rawCertificate: Uint8Array, expecte
9191
return remotePeerId
9292
}
9393

94-
export async function generateCertificate (privateKey: PrivateKey): Promise<{ cert: string, key: string }> {
94+
export async function generateCertificate (privateKey: PrivateKey, options?: AbortOptions): Promise<{ cert: string, key: string }> {
9595
const now = Date.now()
9696

9797
const alg = {
@@ -101,9 +101,13 @@ export async function generateCertificate (privateKey: PrivateKey): Promise<{ ce
101101
}
102102

103103
const keys = await crypto.subtle.generateKey(alg, true, ['sign'])
104+
options?.signal?.throwIfAborted()
105+
104106
const certPublicKeySpki = await crypto.subtle.exportKey('spki', keys.publicKey)
107+
options?.signal?.throwIfAborted()
108+
105109
const dataToSign = encodeSignatureData(certPublicKeySpki)
106-
const sig = await privateKey.sign(dataToSign)
110+
const sig = await privateKey.sign(dataToSign, options)
107111
const notAfter = new Date(now + CERT_VALIDITY_PERIOD_TO)
108112
// workaround for https://github.com/PeculiarVentures/x509/issues/73
109113
notAfter.setMilliseconds(0)
@@ -133,8 +137,10 @@ export async function generateCertificate (privateKey: PrivateKey): Promise<{ ce
133137
}).toBER())
134138
]
135139
})
140+
options?.signal?.throwIfAborted()
136141

137142
const certPrivateKeyPkcs8 = await crypto.subtle.exportKey('pkcs8', keys.privateKey)
143+
options?.signal?.throwIfAborted()
138144

139145
return {
140146
cert: selfCert.toString(),

0 commit comments

Comments
 (0)