Skip to content

Commit 4d777de

Browse files
mscdexaduh95
authored andcommitted
tls: add setKeyCert() to tls.Socket
PR-URL: #53636 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Tim Perry <pimterry@gmail.com>
1 parent c590828 commit 4d777de

5 files changed

Lines changed: 110 additions & 0 deletions

File tree

‎doc/api/tls.md‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,6 +1574,20 @@ When running as the server, the socket will be destroyed with an error after
15741574
For TLSv1.3, renegotiation cannot be initiated, it is not supported by the
15751575
protocol.
15761576

1577+
### `tlsSocket.setKeyCert(context)`
1578+
1579+
<!-- YAML
1580+
added: REPLACEME
1581+
-->
1582+
1583+
*`context` {Object|tls.SecureContext} An object containing at least `key` and
1584+
`cert` properties from the [`tls.createSecureContext()`][]`options`, or a
1585+
TLS context object created with [`tls.createSecureContext()`][] itself.
1586+
1587+
The `tlsSocket.setKeyCert()` method sets the private key and certificate to use
1588+
for the socket. This is mainly useful if you wish to select a server certificate
1589+
from a TLS server's `ALPNCallback`.
1590+
15771591
### `tlsSocket.setMaxSendFragment(size)`
15781592

15791593
<!-- YAML

‎lib/_tls_wrap.js‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,17 @@ TLSSocket.prototype.getX509Certificate = function() {
11441144
returncert ? newInternalX509Certificate(cert) : undefined;
11451145
};
11461146

1147+
TLSSocket.prototype.setKeyCert=function(context){
1148+
if(this._handle){
1149+
letsecureContext;
1150+
if(contextinstanceofcommon.SecureContext)
1151+
secureContext=context;
1152+
else
1153+
secureContext=tls.createSecureContext(context);
1154+
this._handle.setKeyCert(secureContext.context);
1155+
}
1156+
};
1157+
11471158
// Proxy TLSSocket handle methods
11481159
functionmakeSocketMethodProxy(name){
11491160
returnfunctionsocketMethodProxy(...args){

‎src/crypto/crypto_tls.cc‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,6 +1595,33 @@ void TLSWrap::SetALPNProtocols(const FunctionCallbackInfo<Value>& args) {
15951595
}
15961596
}
15971597

1598+
voidTLSWrap::SetKeyCert(const FunctionCallbackInfo<Value>& args) {
1599+
TLSWrap* w;
1600+
ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
1601+
Environment* env = w->env();
1602+
1603+
if (w->is_client()) return;
1604+
1605+
if (args.Length() < 1 || !args[0]->IsObject())
1606+
return env->ThrowTypeError("Must give a SecureContext as first argument");
1607+
1608+
Local<Value> ctx = args[0];
1609+
if (UNLIKELY(ctx.IsEmpty())) return;
1610+
1611+
Local<FunctionTemplate> cons = env->secure_context_constructor_template();
1612+
if (cons->HasInstance(ctx)) {
1613+
SecureContext* sc = Unwrap<SecureContext>(ctx.As<Object>());
1614+
CHECK_NOT_NULL(sc);
1615+
if (!UseSNIContext(w->ssl_, BaseObjectPtr<SecureContext>(sc)) ||
1616+
!w->SetCACerts(sc)) {
1617+
unsignedlong err = ERR_get_error(); // NOLINT(runtime/int)
1618+
returnThrowCryptoError(env, err, "SetKeyCert");
1619+
}
1620+
} else {
1621+
return env->ThrowTypeError("Must give a SecureContext as first argument");
1622+
}
1623+
}
1624+
15981625
voidTLSWrap::GetPeerCertificate(const FunctionCallbackInfo<Value>& args) {
15991626
TLSWrap* w;
16001627
ASSIGN_OR_RETURN_UNWRAP(&w, args.This());
@@ -2130,6 +2157,7 @@ void TLSWrap::Initialize(
21302157
SetProtoMethod(isolate, t, "renegotiate", Renegotiate);
21312158
SetProtoMethod(isolate, t, "requestOCSP", RequestOCSP);
21322159
SetProtoMethod(isolate, t, "setALPNProtocols", SetALPNProtocols);
2160+
SetProtoMethod(isolate, t, "setKeyCert", SetKeyCert);
21332161
SetProtoMethod(isolate, t, "setOCSPResponse", SetOCSPResponse);
21342162
SetProtoMethod(isolate, t, "setServername", SetServername);
21352163
SetProtoMethod(isolate, t, "setSession", SetSession);

‎src/crypto/crypto_tls.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ class TLSWrap : public AsyncWrap,
213213
staticvoidRenegotiate(const v8::FunctionCallbackInfo<v8::Value>& args);
214214
staticvoidRequestOCSP(const v8::FunctionCallbackInfo<v8::Value>& args);
215215
staticvoidSetALPNProtocols(const v8::FunctionCallbackInfo<v8::Value>& args);
216+
staticvoidSetKeyCert(const v8::FunctionCallbackInfo<v8::Value>& args);
216217
staticvoidSetOCSPResponse(const v8::FunctionCallbackInfo<v8::Value>& args);
217218
staticvoidSetServername(const v8::FunctionCallbackInfo<v8::Value>& args);
218219
staticvoidSetSession(const v8::FunctionCallbackInfo<v8::Value>& args);
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
'use strict';
2+
constcommon=require('../common');
3+
4+
if(!common.hasCrypto)
5+
common.skip('missing crypto');
6+
7+
constassert=require('assert');
8+
const{ X509Certificate }=require('crypto');
9+
consttls=require('tls');
10+
constfixtures=require('../common/fixtures');
11+
12+
constaltKeyCert={
13+
key: fixtures.readKey('agent2-key.pem'),
14+
cert: fixtures.readKey('agent2-cert.pem'),
15+
minVersion: 'TLSv1.2',
16+
};
17+
18+
constaltKeyCertVals=[
19+
altKeyCert,
20+
tls.createSecureContext(altKeyCert),
21+
];
22+
23+
(functionnext(){
24+
if(!altKeyCertVals.length)
25+
return;
26+
constaltKeyCertVal=altKeyCertVals.shift();
27+
constoptions={
28+
key: fixtures.readKey('agent1-key.pem'),
29+
cert: fixtures.readKey('agent1-cert.pem'),
30+
minVersion: 'TLSv1.3',
31+
ALPNCallback: common.mustCall(function({ servername, protocols }){
32+
this.setKeyCert(altKeyCertVal);
33+
assert.deepStrictEqual(protocols,['acme-tls/1']);
34+
returnprotocols[0];
35+
}),
36+
};
37+
38+
tls.createServer(options,(s)=>s.end()).listen(0,function(){
39+
this.on('connection',common.mustCall((socket)=>this.close()));
40+
41+
tls.connect({
42+
port: this.address().port,
43+
rejectUnauthorized: false,
44+
ALPNProtocols: ['acme-tls/1'],
45+
},common.mustCall(function(){
46+
assert.strictEqual(this.getProtocol(),'TLSv1.3');
47+
constaltCert=newX509Certificate(altKeyCert.cert);
48+
assert.strictEqual(
49+
this.getPeerX509Certificate().raw.equals(altCert.raw),
50+
true
51+
);
52+
this.end();
53+
next();
54+
}));
55+
});
56+
})();

0 commit comments

Comments
 (0)