Skip to content

Commit 99c80e3

Browse files
committed
quic: update the guard to check openssl version
Since we need to be able to use the openssl adapter provided by the ngtcp2 library, and because that adapter does not include any compile guards to ensure that OpenSSL 3.5 is being used and that the APIs are actually available, we need to add a compile time check for the openssl version in order to conditionally include the adapter to avoid build errors when using a shared openssl library that is not OpenSSL 3.5. Signed-off-by: James M Snell <[email protected]> PR-URL: #59249 Reviewed-By: Matteo Collina <[email protected]>
1 parent ebfc28a commit 99c80e3

File tree

3 files changed

+92
-10
lines changed

3 files changed

+92
-10
lines changed

configure.py

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,65 @@ def get_gas_version(cc):
12051205
warn(f'Could not recognize `gas`: {gas_ret}')
12061206
return '0.0'
12071207

1208+
def get_openssl_version():
1209+
"""Parse OpenSSL version from opensslv.h header file.
1210+
1211+
Returns the version as a number matching OPENSSL_VERSION_NUMBER format:
1212+
0xMNN00PPSL where M=major, NN=minor, PP=patch, S=status(0xf=release,0x0=pre), L=0
1213+
"""
1214+
1215+
try:
1216+
# Use the C compiler to extract preprocessor macros from opensslv.h
1217+
args = ['-E', '-dM', '-include', 'openssl/opensslv.h', '-']
1218+
if not options.shared_openssl:
1219+
args = ['-I', 'deps/openssl/openssl/include'] + args
1220+
elif options.shared_openssl_includes:
1221+
args = ['-I', options.shared_openssl_includes] + args
1222+
1223+
proc = subprocess.Popen(
1224+
shlex.split(CC) + args,
1225+
stdin=subprocess.PIPE,
1226+
stdout=subprocess.PIPE,
1227+
stderr=subprocess.PIPE
1228+
)
1229+
with proc:
1230+
proc.stdin.write(b'\n')
1231+
out = to_utf8(proc.communicate()[0])
1232+
1233+
if proc.returncode != 0:
1234+
warn('Failed to extract OpenSSL version from opensslv.h header')
1235+
return 0
1236+
1237+
# Parse the macro definitions
1238+
macros = {}
1239+
for line in out.split('\n'):
1240+
if line.startswith('#define OPENSSL_VERSION_'):
1241+
parts = line.split()
1242+
if len(parts) >= 3:
1243+
macro_name = parts[1]
1244+
macro_value = parts[2]
1245+
macros[macro_name] = macro_value
1246+
1247+
# Extract version components
1248+
major = int(macros.get('OPENSSL_VERSION_MAJOR', '0'))
1249+
minor = int(macros.get('OPENSSL_VERSION_MINOR', '0'))
1250+
patch = int(macros.get('OPENSSL_VERSION_PATCH', '0'))
1251+
1252+
# Check if it's a pre-release (has non-empty PRE_RELEASE string)
1253+
pre_release = macros.get('OPENSSL_VERSION_PRE_RELEASE', '""').strip('"')
1254+
status = 0x0 if pre_release else 0xf
1255+
# Construct version number: 0xMNN00PPSL
1256+
version_number = ((major << 28) |
1257+
(minor << 20) |
1258+
(patch << 4) |
1259+
status)
1260+
1261+
return version_number
1262+
1263+
except (OSError, ValueError, subprocess.SubprocessError) as e:
1264+
warn(f'Failed to determine OpenSSL version from header: {e}')
1265+
return 0
1266+
12081267
# Note: Apple clang self-reports as clang 4.2.0 and gcc 4.2.1. It passes
12091268
# the version check more by accident than anything else but a more rigorous
12101269
# check involves checking the build number against an allowlist. I'm not
@@ -1828,6 +1887,8 @@ def without_ssl_error(option):
18281887
if options.quic:
18291888
o['defines'] += ['NODE_OPENSSL_HAS_QUIC']
18301889

1890+
o['variables']['openssl_version'] = get_openssl_version()
1891+
18311892
configure_library('openssl', o)
18321893

18331894
def configure_sqlite(o):

deps/ngtcp2/ngtcp2.gyp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,36 @@
129129
'HAVE_NETINET_IN_H',
130130
],
131131
}],
132+
# TODO: Support OpenSSL 3.5 shared library builds.
133+
# The complexity here is that we need to use the ngtcp2 ossl
134+
# adapter, which does not include any conditional checks to
135+
# see if the version of OpenSSL used has the necessary QUIC
136+
# APIs, so we need to ensure that we conditionally enable use
137+
# of the adapter only when we know that the OpenSSL version we
138+
# are compiling against has the necessary APIs. We can do that
139+
# by checkig the OpenSSL version number but, currently, the
140+
# code that does so checks only the VERSION.dat file that is
141+
# bundled with the openssl dependency. We'll need to update
142+
# that to support the shared library case, where the version
143+
# of the shared library needs to be determined.
144+
#
145+
# TODO: Support Boringssl here also. ngtcp2 provides an adapter
146+
# for Boringssl. If we can detect that boringssl is being used
147+
# here then we can use that adapter and also set the
148+
# QUIC_NGTCP2_USE_BORINGSSL define (the guard in quic/guard.h
149+
# would need to be updated to check for this define).
150+
['node_shared_openssl=="false" and openssl_version >= 0x3050001f', {
151+
'sources': [
152+
'<@(ngtcp2_sources_ossl)',
153+
],
154+
'direct_dependent_settings': {
155+
'defines': [
156+
# Tells us that we are using the OpenSSL 3.5 adapter
157+
# that is provided by ngtcp2.
158+
'QUIC_NGTCP2_USE_OPENSSL_3_5',
159+
],
160+
},
161+
}]
132162
],
133163
'direct_dependent_settings': {
134164
'defines': [
@@ -143,7 +173,6 @@
143173
},
144174
'sources': [
145175
'<@(ngtcp2_sources)',
146-
'<@(ngtcp2_sources_ossl)',
147176
]
148177
},
149178
{

src/quic/guard.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
#pragma once
22

3-
#if HAVE_OPENSSL
4-
#include <openssl/opensslv.h>
5-
// QUIC is only available in Openssl 3.5.x and later. It was not introduced in
6-
// Node.js until 3.5.1... prior to that we will not compile any of the QUIC
7-
// related code.
8-
#if OPENSSL_VERSION_NUMBER < 0x30500010 || OPENSSL_IS_BORINGSSL
9-
#define OPENSSL_NO_QUIC = 1
10-
#endif
11-
#else
3+
#ifndef QUIC_NGTCP2_USE_OPENSSL_3_5
124
#define OPENSSL_NO_QUIC = 1
135
#endif

0 commit comments

Comments
 (0)