fix(client-certificates): report error to the browser if incorrect passphrase (#32007)

This commit is contained in:
Max Schmitt 2024-08-05 10:54:33 +02:00 committed by GitHub
parent dbc4bc84d6
commit 71e614dc5a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 66 additions and 23 deletions

View File

@ -142,34 +142,14 @@ class SocksProxyConnection {
dummyServer.emit('connection', this.internal);
dummyServer.on('secureConnection', internalTLS => {
debugLogger.log('client-certificates', `Browser->Proxy ${this.host}:${this.port} chooses ALPN ${internalTLS.alpnProtocol}`);
const tlsOptions: tls.ConnectionOptions = {
socket: this.target,
host: this.host,
port: this.port,
rejectUnauthorized: !this.socksProxy.ignoreHTTPSErrors,
ALPNProtocols: [internalTLS.alpnProtocol || 'http/1.1'],
...clientCertificatesToTLSOptions(this.socksProxy.clientCertificates, new URL(`https://${this.host}:${this.port}`).origin),
};
if (!net.isIP(this.host))
tlsOptions.servername = this.host;
const targetTLS = tls.connect(tlsOptions);
targetTLS.on('secureConnect', () => {
internalTLS.pipe(targetTLS);
targetTLS.pipe(internalTLS);
});
// Handle close and errors
let targetTLS: tls.TLSSocket | undefined = undefined;
const closeBothSockets = () => {
internalTLS.end();
targetTLS.end();
targetTLS?.end();
};
internalTLS.on('end', () => closeBothSockets());
targetTLS.on('end', () => closeBothSockets());
internalTLS.on('error', () => closeBothSockets());
targetTLS.on('error', error => {
const handleError = (error: Error) => {
debugLogger.log('client-certificates', `error when connecting to target: ${error.message}`);
const responseBody = 'Playwright client-certificate error: ' + error.message;
if (internalTLS?.alpnProtocol === 'h2') {
@ -204,7 +184,38 @@ class SocksProxyConnection {
].join('\r\n'));
closeBothSockets();
}
};
let secureContext: tls.SecureContext;
try {
secureContext = tls.createSecureContext(clientCertificatesToTLSOptions(this.socksProxy.clientCertificates, new URL(`https://${this.host}:${this.port}`).origin));
} catch (error) {
handleError(error);
return;
}
const tlsOptions: tls.ConnectionOptions = {
socket: this.target,
host: this.host,
port: this.port,
rejectUnauthorized: !this.socksProxy.ignoreHTTPSErrors,
ALPNProtocols: [internalTLS.alpnProtocol || 'http/1.1'],
servername: !net.isIP(this.host) ? this.host : undefined,
secureContext,
};
targetTLS = tls.connect(tlsOptions);
targetTLS.on('secureConnect', () => {
internalTLS.pipe(targetTLS);
targetTLS.pipe(internalTLS);
});
internalTLS.on('end', () => closeBothSockets());
targetTLS.on('end', () => closeBothSockets());
internalTLS.on('error', () => closeBothSockets());
targetTLS.on('error', handleError);
});
});
}

View File

@ -36,6 +36,8 @@ openssl x509 \
-out client/trusted/cert.pem \
-set_serial 01 \
-days 365
# create pfx
openssl pkcs12 -export -out client/trusted/cert.pfx -inkey client/trusted/key.pem -in client/trusted/cert.pem -passout pass:secure
```
## Self-signed certificate (invalid)

View File

@ -257,6 +257,36 @@ test.describe('browser', () => {
await page.close();
});
test('should pass with matching certificates in pfx format', async ({ browser, startCCServer, asset, browserName }) => {
const serverURL = await startCCServer({ useFakeLocalhost: browserName === 'webkit' && process.platform === 'darwin' });
const page = await browser.newPage({
ignoreHTTPSErrors: true,
clientCertificates: [{
origin: new URL(serverURL).origin,
pfxPath: asset('client-certificates/client/trusted/cert.pfx'),
passphrase: 'secure'
}],
});
await page.goto(serverURL);
await expect(page.getByTestId('message')).toHaveText('Hello Alice, your certificate was issued by localhost!');
await page.close();
});
test('should throw a http error if the pfx passphrase is incorect', async ({ browser, startCCServer, asset, browserName }) => {
const serverURL = await startCCServer({ useFakeLocalhost: browserName === 'webkit' && process.platform === 'darwin' });
const page = await browser.newPage({
ignoreHTTPSErrors: true,
clientCertificates: [{
origin: new URL(serverURL).origin,
pfxPath: asset('client-certificates/client/trusted/cert.pfx'),
passphrase: 'this-password-is-incorrect'
}],
});
await page.goto(serverURL);
await expect(page.getByText('Playwright client-certificate error: mac verify failure')).toBeVisible();
await page.close();
});
test('should pass with matching certificates on context APIRequestContext instance', async ({ browser, startCCServer, asset, browserName }) => {
const serverURL = await startCCServer({ host: '127.0.0.1' });
const baseOptions = {