Skip to content

Commit cafe7bf

Browse files
mcollinaaduh95
authored andcommitted
tls: fix SNICallback certificate selection
Signed-off-by: Matteo Collina <hello@matteocollina.com> PR-URL: #64700 Reviewed-By: Daniel Lemire <daniel@lemire.me> Reviewed-By: Tim Perry <pimterry@gmail.com>
1 parent 335c28c commit cafe7bf

2 files changed

Lines changed: 78 additions & 1 deletion

File tree

‎deps/ncrypto/ncrypto.cc‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4083,7 +4083,13 @@ bool SSLPointer::setSniContext(const SSLCtxPointer& ctx) const {
40834083
EVP_PKEY* pkey = SSL_CTX_get0_privatekey(ctx.get());
40844084
STACK_OF(X509) * chain;
40854085
int err = SSL_CTX_get0_chain_certs(ctx.get(), &chain);
4086-
if (err == 1) err = SSL_use_certificate(get(), x509);
4086+
if (err == 1) {
4087+
// SSL_use_certificate replaces only the certificate matching the key
4088+
// type. Clear all existing certificates so credentials from the default
4089+
// context cannot be selected for a different key type.
4090+
SSL_certs_clear(get());
4091+
err = SSL_use_certificate(get(), x509);
4092+
}
40874093
if (err == 1) err = SSL_use_PrivateKey(get(), pkey);
40884094
if (err == 1 && chain != nullptr) err = SSL_set1_chain(get(), chain);
40894095
return err == 1;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use strict';
2+
3+
constcommon=require('../common');
4+
if(!common.hasCrypto)
5+
common.skip('missing crypto');
6+
7+
constassert=require('assert');
8+
const{ X509Certificate }=require('crypto');
9+
consthttps=require('https');
10+
consttls=require('tls');
11+
constfixtures=require('../common/fixtures');
12+
13+
constdefaultCredentials={
14+
cert: fixtures.readKey('ca5-cert.pem'),
15+
key: fixtures.readKey('ca5-key.pem'),
16+
};
17+
constsniCredentials={
18+
cert: fixtures.readKey('agent1-cert.pem'),
19+
key: fixtures.readKey('agent1-key.pem'),
20+
};
21+
22+
constdefaultCertificate=newX509Certificate(defaultCredentials.cert);
23+
constsniCertificate=newX509Certificate(sniCredentials.cert);
24+
constsniContext=tls.createSecureContext(sniCredentials);
25+
26+
functionrequest(port,servername,expectedCertificate){
27+
returnnewPromise((resolve,reject)=>{
28+
constreq=https.get({
29+
host: '127.0.0.1',
30+
port,
31+
servername,
32+
rejectUnauthorized: false,
33+
agent: false,
34+
},common.mustCall((response)=>{
35+
try{
36+
constcertificate=response.socket.getPeerX509Certificate();
37+
assert.strictEqual(certificate.fingerprint256,
38+
expectedCertificate.fingerprint256);
39+
}catch(err){
40+
reject(err);
41+
return;
42+
}
43+
44+
response.resume();
45+
response.once('end',resolve);
46+
response.once('error',reject);
47+
}));
48+
req.once('error',reject);
49+
});
50+
}
51+
52+
constserver=https.createServer({
53+
cert: defaultCredentials.cert,
54+
key: defaultCredentials.key,
55+
SNICallback: common.mustCall((servername,callback)=>{
56+
assert.strictEqual(servername,'agent1.com');
57+
callback(null,sniContext);
58+
},1),
59+
},(_request,response)=>{
60+
response.end('ok');
61+
});
62+
63+
server.listen(0,common.mustCall(async()=>{
64+
try{
65+
const{ port }=server.address();
66+
awaitrequest(port,undefined,defaultCertificate);
67+
awaitrequest(port,'agent1.com',sniCertificate);
68+
}finally{
69+
server.close(common.mustCall());
70+
}
71+
}));

0 commit comments

Comments
 (0)