Skip to content

Commit

Permalink
cherry-pick(#32007): fix(client-certificates): report error to the br…
Browse files Browse the repository at this point in the history
…owser if incorrect passphrase
  • Loading branch information
mxschmitt committed Aug 5, 2024
1 parent fca1fa0 commit ed9b4d9
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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') {
Expand Down Expand Up @@ -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);
});
});
}
Expand Down
2 changes: 2 additions & 0 deletions tests/assets/client-certificates/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Binary file not shown.
30 changes: 30 additions & 0 deletions tests/library/client-certificates.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down

0 comments on commit ed9b4d9

Please sign in to comment.