cherry-pick(#32007): fix(client-certificates): report error to the browser if incorrect passphrase
This commit is contained in:
parent
fca1fa0b95
commit
ed9b4d9b9a
|
|
@ -142,34 +142,14 @@ class SocksProxyConnection {
|
||||||
dummyServer.emit('connection', this.internal);
|
dummyServer.emit('connection', this.internal);
|
||||||
dummyServer.on('secureConnection', internalTLS => {
|
dummyServer.on('secureConnection', internalTLS => {
|
||||||
debugLogger.log('client-certificates', `Browser->Proxy ${this.host}:${this.port} chooses ALPN ${internalTLS.alpnProtocol}`);
|
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', () => {
|
let targetTLS: tls.TLSSocket | undefined = undefined;
|
||||||
internalTLS.pipe(targetTLS);
|
|
||||||
targetTLS.pipe(internalTLS);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle close and errors
|
|
||||||
const closeBothSockets = () => {
|
const closeBothSockets = () => {
|
||||||
internalTLS.end();
|
internalTLS.end();
|
||||||
targetTLS.end();
|
targetTLS?.end();
|
||||||
};
|
};
|
||||||
|
|
||||||
internalTLS.on('end', () => closeBothSockets());
|
const handleError = (error: Error) => {
|
||||||
targetTLS.on('end', () => closeBothSockets());
|
|
||||||
|
|
||||||
internalTLS.on('error', () => closeBothSockets());
|
|
||||||
targetTLS.on('error', error => {
|
|
||||||
debugLogger.log('client-certificates', `error when connecting to target: ${error.message}`);
|
debugLogger.log('client-certificates', `error when connecting to target: ${error.message}`);
|
||||||
const responseBody = 'Playwright client-certificate error: ' + error.message;
|
const responseBody = 'Playwright client-certificate error: ' + error.message;
|
||||||
if (internalTLS?.alpnProtocol === 'h2') {
|
if (internalTLS?.alpnProtocol === 'h2') {
|
||||||
|
|
@ -204,7 +184,38 @@ class SocksProxyConnection {
|
||||||
].join('\r\n'));
|
].join('\r\n'));
|
||||||
closeBothSockets();
|
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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,8 @@ openssl x509 \
|
||||||
-out client/trusted/cert.pem \
|
-out client/trusted/cert.pem \
|
||||||
-set_serial 01 \
|
-set_serial 01 \
|
||||||
-days 365
|
-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)
|
## Self-signed certificate (invalid)
|
||||||
|
|
|
||||||
BIN
tests/assets/client-certificates/client/trusted/cert.pfx
Normal file
BIN
tests/assets/client-certificates/client/trusted/cert.pfx
Normal file
Binary file not shown.
|
|
@ -257,6 +257,36 @@ test.describe('browser', () => {
|
||||||
await page.close();
|
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 }) => {
|
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 serverURL = await startCCServer({ host: '127.0.0.1' });
|
||||||
const baseOptions = {
|
const baseOptions = {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue