Skip to content

Commit 341b8f7

Browse files
committed
crypto: initial LibreSSL support
1 parent 1824bbb commit 341b8f7

11 files changed

+108
-36
lines changed

lib/_tls_common.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ var crypto = null;
1010

1111
const binding = process.binding('crypto');
1212
const NativeSecureContext = binding.SecureContext;
13+
const isLibreSSL = process.versions.openssl &&
14+
/LibreSSL$/.test(process.versions.openssl);
15+
1316

1417
function SecureContext(secureProtocol, secureOptions, context) {
1518
if (!(this instanceof SecureContext)) {
@@ -138,7 +141,10 @@ exports.createSecureContext = function createSecureContext(options, context) {
138141
// freelist.)
139142
if (options.singleUse) {
140143
c.singleUse = true;
141-
c.context.setFreeListLength(0);
144+
if (!isLibreSSL) {
145+
c.context.setFreeListLength(0);
146+
} // else TODO check for possible leak
147+
// https://github.com/nodejs/node/issues/1522
142148
}
143149

144150
return c;

lib/_tls_wrap.js

+29-15
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ const Timer = process.binding('timer_wrap').Timer;
1616
const tls_wrap = process.binding('tls_wrap');
1717
const TCP = process.binding('tcp_wrap').TCP;
1818
const Pipe = process.binding('pipe_wrap').Pipe;
19+
const isLibreSSL = process.versions.openssl &&
20+
/LibreSSL$/.test(process.versions.openssl);
1921

2022
function onhandshakestart() {
2123
debug('onhandshakestart');
@@ -155,14 +157,20 @@ function onclienthello(hello) {
155157
if (err)
156158
return self.destroy(err);
157159

158-
self._handle.endParser();
160+
if (isLibreSSL) {
161+
oncertcb(hello, self, session && session.servername || hello.servername);
162+
} else {
163+
self._handle.endParser();
164+
}
159165
});
160166
}
161167

162168

163-
function oncertcb(info) {
164-
var self = this;
165-
var servername = info.servername;
169+
function oncertcb(info, self, servername) {
170+
if (!self)
171+
self = this;
172+
if (!servername)
173+
servername = info.servername;
166174

167175
loadSNI(self, servername, function(err, ctx) {
168176
if (err)
@@ -174,10 +182,14 @@ function oncertcb(info) {
174182
if (!self._handle)
175183
return self.destroy(new Error('Socket is closed'));
176184

177-
try {
178-
self._handle.certCbDone();
179-
} catch (e) {
180-
self.destroy(e);
185+
if (isLibreSSL) {
186+
self._handle.endParser();
187+
} else {
188+
try {
189+
self._handle.certCbDone();
190+
} catch (e) {
191+
self.destroy(e);
192+
}
181193
}
182194
});
183195
});
@@ -1072,13 +1084,15 @@ exports.connect = function(...args /* [port,] [host,] [options,] [cb] */) {
10721084
socket.on('secure', function() {
10731085
// Check the size of DHE parameter above minimum requirement
10741086
// specified in options.
1075-
var ekeyinfo = socket.getEphemeralKeyInfo();
1076-
if (ekeyinfo.type === 'DH' && ekeyinfo.size < options.minDHSize) {
1077-
var err = new Error('DH parameter size ' + ekeyinfo.size +
1078-
' is less than ' + options.minDHSize);
1079-
socket.emit('error', err);
1080-
socket.destroy();
1081-
return;
1087+
if (!isLibreSSL) {
1088+
var ekeyinfo = socket.getEphemeralKeyInfo();
1089+
if (ekeyinfo.type === 'DH' && ekeyinfo.size < options.minDHSize) {
1090+
var err = new Error('DH parameter size ' + ekeyinfo.size +
1091+
' is less than ' + options.minDHSize);
1092+
socket.emit('error', err);
1093+
socket.destroy();
1094+
return;
1095+
}
10821096
}
10831097

10841098
var verifyError = socket._handle.verifyError();

node.gyp

+1-1
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@
381381
'conditions': [
382382
# -force_load or --whole-archive are not applicable for
383383
# the static library
384-
[ 'node_target_type!="static_library"', {
384+
[ 'node_target_type!="static_library" and node_shared_openssl=="false"', {
385385
'xcode_settings': {
386386
'OTHER_LDFLAGS': [
387387
'-Wl,-force_load,<(PRODUCT_DIR)/<(OPENSSL_PRODUCT)',

src/node.cc

+7-4
Original file line numberDiff line numberDiff line change
@@ -3126,10 +3126,13 @@ void SetupProcessObject(Environment* env,
31263126
break;
31273127
}
31283128
}
3129-
READONLY_PROPERTY(
3130-
versions,
3131-
"openssl",
3132-
OneByteString(env->isolate(), &OPENSSL_VERSION_TEXT[i], j - i));
3129+
Local<String> sslversion =
3130+
OneByteString(env->isolate(), &OPENSSL_VERSION_TEXT[i], j - i);
3131+
# ifdef LIBRESSL_VERSION_NUMBER
3132+
sslversion = String::Concat(sslversion,
3133+
OneByteString(env->isolate(), "-LibreSSL"));
3134+
# endif
3135+
READONLY_PROPERTY(versions, "openssl", sslversion);
31333136
}
31343137
#endif
31353138

src/node_crypto.cc

+27-11
Original file line numberDiff line numberDiff line change
@@ -523,8 +523,12 @@ int SSL_CTX_use_certificate_chain(SSL_CTX* ctx,
523523
for (int i = 0; i < sk_X509_num(extra_certs); i++) {
524524
X509* ca = sk_X509_value(extra_certs, i);
525525

526+
#ifdef LIBRESSL_VERSION_NUMBER
527+
r = SSL_CTX_add_extra_chain_cert(ctx, ca);
528+
#else
526529
// NOTE: Increments reference count on `ca`
527530
r = SSL_CTX_add1_chain_cert(ctx, ca);
531+
#endif // LIBRESSL_VERSION_NUMBER
528532

529533
if (!r) {
530534
ret = 0;
@@ -680,7 +684,7 @@ void SecureContext::SetCert(const FunctionCallbackInfo<Value>& args) {
680684
}
681685

682686

683-
#if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
687+
#if (OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)) || defined(LIBRESSL_VERSION_NUMBER)
684688
// This section contains OpenSSL 1.1.0 functions reimplemented for OpenSSL
685689
// 1.0.2 so that the following code can be written without lots of #if lines.
686690

@@ -693,7 +697,7 @@ static int X509_up_ref(X509* cert) {
693697
CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509);
694698
return 1;
695699
}
696-
#endif // OPENSSL_VERSION_NUMBER < 0x10100000L && !OPENSSL_IS_BORINGSSL
700+
#endif // (OPENSSL_VERSION_NUMBER < 0x10100000L && !OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER)
697701

698702

699703
static X509_STORE* NewRootCertStore() {
@@ -1153,7 +1157,7 @@ void SecureContext::SetTicketKeys(const FunctionCallbackInfo<Value>& args) {
11531157

11541158

11551159
void SecureContext::SetFreeListLength(const FunctionCallbackInfo<Value>& args) {
1156-
#if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(OPENSSL_IS_BORINGSSL)
1160+
#if OPENSSL_VERSION_NUMBER < 0x10100000L && !defined(OPENSSL_IS_BORINGSSL) && !defined(LIBRESSL_VERSION_NUMBER)
11571161
// |freelist_max_len| was removed in OpenSSL 1.1.0. In that version OpenSSL
11581162
// mallocs and frees buffers directly, without the use of a freelist.
11591163
SecureContext* wrap;
@@ -1930,6 +1934,10 @@ void SSLWrap<Base>::RequestOCSP(
19301934
template <class Base>
19311935
void SSLWrap<Base>::GetEphemeralKeyInfo(
19321936
const v8::FunctionCallbackInfo<v8::Value>& args) {
1937+
#ifdef LIBRESSL_VERSION_NUMBER
1938+
Environment* env = Environment::GetCurrent(args);
1939+
env->ThrowError("getEphemeralKeyInfo() not supported when using LibreSSL");
1940+
#else
19331941
Base* w;
19341942
ASSIGN_OR_RETURN_UNWRAP(&w, args.Holder());
19351943
Environment* env = Environment::GetCurrent(args);
@@ -1968,7 +1976,8 @@ void SSLWrap<Base>::GetEphemeralKeyInfo(
19681976
EVP_PKEY_free(key);
19691977
}
19701978

1971-
return args.GetReturnValue().Set(info);
1979+
args.GetReturnValue().Set(info);
1980+
#endif // LIBRESSL_VERSION_NUMBER
19721981
}
19731982

19741983

@@ -2449,8 +2458,9 @@ void SSLWrap<Base>::CertCbDone(const FunctionCallbackInfo<Value>& args) {
24492458
w->sni_context_.Reset();
24502459
w->sni_context_.Reset(env->isolate(), ctx);
24512460

2452-
int rv;
2461+
int rv = 1;
24532462

2463+
#ifndef LIBRESSL_VERSION_NUMBER
24542464
// NOTE: reference count is not increased by this API methods
24552465
X509* x509 = SSL_CTX_get0_certificate(sc->ctx_);
24562466
EVP_PKEY* pkey = SSL_CTX_get0_privatekey(sc->ctx_);
@@ -2463,6 +2473,8 @@ void SSLWrap<Base>::CertCbDone(const FunctionCallbackInfo<Value>& args) {
24632473
rv = SSL_use_PrivateKey(w->ssl_, pkey);
24642474
if (rv && chain != nullptr)
24652475
rv = SSL_set1_chain(w->ssl_, chain);
2476+
#endif // LIBRESSL_VERSION_NUMBER
2477+
24662478
if (rv)
24672479
rv = w->SetCACerts(sc);
24682480
if (!rv) {
@@ -2526,9 +2538,11 @@ void SSLWrap<Base>::SetSNIContext(SecureContext* sc) {
25262538

25272539
template <class Base>
25282540
int SSLWrap<Base>::SetCACerts(SecureContext* sc) {
2541+
#ifndef LIBRESSL_VERSION_NUMBER
25292542
int err = SSL_set1_verify_cert_store(ssl_, SSL_CTX_get_cert_store(sc->ctx_));
25302543
if (err != 1)
25312544
return err;
2545+
#endif // LIBRESSL_VERSION_NUMBER
25322546

25332547
STACK_OF(X509_NAME)* list = SSL_dup_CA_list(
25342548
SSL_CTX_get_client_CA_list(sc->ctx_));
@@ -2841,7 +2855,7 @@ inline int VerifyCallback(int preverify_ok, X509_STORE_CTX* ctx) {
28412855
SSL* ssl = static_cast<SSL*>(
28422856
X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
28432857

2844-
if (SSL_is_server(ssl))
2858+
if (ssl->server)
28452859
return 1;
28462860

28472861
// Client needs to check if the server cert is listed in the
@@ -2924,7 +2938,9 @@ void Connection::New(const FunctionCallbackInfo<Value>& args) {
29242938

29252939
InitNPN(sc);
29262940

2941+
#ifndef LIBRESSL_VERSION_NUMBER
29272942
SSL_set_cert_cb(conn->ssl_, SSLWrap<Connection>::SSLCertCallback, conn);
2943+
#endif // LIBRESSL_VERSION_NUMBER
29282944

29292945
#ifdef SSL_CTRL_SET_TLSEXT_SERVERNAME_CB
29302946
if (is_server) {
@@ -5976,11 +5992,11 @@ void SetEngine(const FunctionCallbackInfo<Value>& args) {
59765992
#endif // !OPENSSL_NO_ENGINE
59775993

59785994
void GetFipsCrypto(const FunctionCallbackInfo<Value>& args) {
5979-
if (FIPS_mode()) {
5980-
args.GetReturnValue().Set(1);
5981-
} else {
5982-
args.GetReturnValue().Set(0);
5983-
}
5995+
#ifdef NODE_FIPS_MODE
5996+
args.GetReturnValue().Set(FIPS_mode());
5997+
#else
5998+
args.GetReturnValue().Set(0);
5999+
#endif
59846000
}
59856001

59866002
void SetFipsCrypto(const FunctionCallbackInfo<Value>& args) {

src/tls_wrap.cc

+2
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,9 @@ void TLSWrap::InitSSL() {
142142

143143
InitNPN(sc_);
144144

145+
#ifndef LIBRESSL_VERSION_NUMBER
145146
SSL_set_cert_cb(ssl_, SSLWrap<TLSWrap>::SSLCertCallback, this);
147+
#endif // LIBRESSL_VERSION_NUMBER
146148

147149
if (is_server()) {
148150
SSL_set_accept_state(ssl_);

test/parallel/test-crypto.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const assert = require('assert');
1010
const crypto = require('crypto');
1111
const fs = require('fs');
1212
const tls = require('tls');
13+
const isLibreSSL = /LibreSSL$/.test(process.versions.openssl);
1314

1415
crypto.DEFAULT_ENCODING = 'buffer';
1516

@@ -82,9 +83,11 @@ assert(tlsCiphers.every((value) => /^[^A-Z]+$/.test(value)));
8283
validateList(tlsCiphers);
8384

8485
// Assert that we have sha and sha1 but not SHA and SHA1.
86+
<<<<<<< 1824bbbff1341e253a891a804651b6338f8008e4
8587
assert.notStrictEqual(0, crypto.getHashes().length);
8688
assert(crypto.getHashes().includes('sha1'));
87-
assert(crypto.getHashes().includes('sha'));
89+
if (!isLibreSSL)
90+
assert(crypto.getHashes().includes('sha'));
8891
assert(!crypto.getHashes().includes('SHA1'));
8992
assert(!crypto.getHashes().includes('SHA'));
9093
assert(crypto.getHashes().includes('RSA-SHA1'));

test/parallel/test-tls-client-getephemeralkeyinfo.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@ if (!common.hasCrypto) {
66
common.skip('missing crypto');
77
process.exit();
88
}
9-
const tls = require('tls');
109

10+
var isLibreSSL = /LibreSSL$/.test(process.versions.openssl);
11+
if (isLibreSSL) {
12+
common.skip('LibreSSL does not support getEphemeralKeyInfo()');
13+
process.exit();
14+
}
15+
16+
const tls = require('tls');
1117
const fs = require('fs');
1218
const key = fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem');
1319
const cert = fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem');

test/parallel/test-tls-client-mindhsize.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,15 @@ if (!common.hasCrypto) {
66
common.skip('missing crypto');
77
process.exit();
88
}
9-
const tls = require('tls');
109

10+
const isLibreSSL = /LibreSSL$/.test(process.versions.openssl);
11+
12+
if (isLibreSSL) {
13+
common.skip('LibreSSL does not support DH key size limiting');
14+
process.exit();
15+
}
16+
17+
const tls = require('tls');
1118
const fs = require('fs');
1219
const key = fs.readFileSync(common.fixturesDir + '/keys/agent2-key.pem');
1320
const cert = fs.readFileSync(common.fixturesDir + '/keys/agent2-cert.pem');

test/parallel/test-tls-cnnic-whitelist.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ const assert = require('assert');
1010
const tls = require('tls');
1111
const fs = require('fs');
1212
const path = require('path');
13+
const finished = 0;
14+
const isLibreSSL = /LibreSSL$/.test(process.versions.openssl);
1315

1416
function filenamePEM(n) {
1517
return path.join(common.fixturesDir, 'keys', n + '.pem');
@@ -52,7 +54,8 @@ const testCases = [
5254
port: undefined,
5355
rejectUnauthorized: true
5456
},
55-
errorCode: 'UNABLE_TO_GET_ISSUER_CERT_LOCALLY'
57+
errorCode: isLibreSSL ? 'CERT_UNTRUSTED' :
58+
'UNABLE_TO_GET_ISSUER_CERT_LOCALLY'
5659
}
5760
];
5861

test/parallel/test-tls-empty-sni-context.js

+12
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/*eslint max-len: ["error", { "ignoreComments": true }]*/
2+
13
'use strict';
24

35
const common = require('../common');
@@ -7,6 +9,12 @@ if (!process.features.tls_sni) {
79
return;
810
}
911

12+
var isLibreSSL = /LibreSSL$/.test(process.versions.openssl);
13+
if (isLibreSSL) {
14+
common.skip('Test not yet supported with LibreSSL');
15+
process.exit();
16+
}
17+
1018
const assert = require('assert');
1119

1220
if (!common.hasCrypto) {
@@ -24,6 +32,8 @@ const options = {
2432
const server = tls.createServer(options, (c) => {
2533
common.fail('Should not be called');
2634
}).on('tlsClientError', common.mustCall((err, c) => {
35+
//TODO: LibreSSL gives:
36+
// 140735295963904:error:1408A0C1:SSL routines:SSL3_GET_CLIENT_HELLO:no shared cipher:s3_srvr.c:1038:
2737
assert(/SSL_use_certificate:passed a null parameter/i.test(err.message));
2838
server.close();
2939
})).listen(0, common.mustCall(() => {
@@ -34,6 +44,8 @@ const server = tls.createServer(options, (c) => {
3444
}, common.mustNotCall());
3545

3646
c.on('error', common.mustCall((err) => {
47+
//TODO: LibreSSL gives:
48+
// 140735295963904:error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure:s23_clnt.c:441:
3749
assert(/socket hang up/.test(err.message));
3850
}));
3951
}));

0 commit comments

Comments
 (0)