Skip to content

Identify SSL support in upsd and libupsclient, add NIT tests for OpenSSL and Mozilla NSS#3330

Merged
jimklimov merged 46 commits intonetworkupstools:masterfrom
jimklimov:nit-ssl
Mar 7, 2026
Merged

Identify SSL support in upsd and libupsclient, add NIT tests for OpenSSL and Mozilla NSS#3330
jimklimov merged 46 commits intonetworkupstools:masterfrom
jimklimov:nit-ssl

Conversation

@jimklimov
Copy link
Copy Markdown
Member

Closes: #3328
Largely fulfills #1711 (for the C client tests, but not for other ecosystems like C++ and Python)

@jimklimov jimklimov added this to the 2.8.5 milestone Feb 26, 2026
@jimklimov jimklimov added this to NUT QA Feb 26, 2026
@jimklimov jimklimov added enhancement CI Entries related to continuous integration infrastructure (here CI = tools + scripts + recipes) SSL/NSS Issues and PRs about SSL, TLS and other crypto-related matters portability We want NUT to build and run everywhere possible labels Feb 26, 2026
@jimklimov
Copy link
Copy Markdown
Member Author

jimklimov commented Feb 26, 2026

  • upsmon with NSS (confirms server cert, but server not built to check client cert so not checking that):
Thu Feb 26 18:12:06 UTC 2026 [DEBUG] execcmd: running:   upsmon -FF
Network UPS Tools upsmon 2.8.4.1454.17-1471+g47eedafa1 (development iteration after 2.8.4)
UPS: dummy@localhost:12345 (monitoring only)
No POWERDOWNFLAG value was configured in /home/jim/nut/tests/NIT/tmp/etc/upsmon.conf!
POWERDOWNFLAG should be a path to file that is normally writeable for root user, and remains at least readable late in shutdown after all unmounting completes.
upsmon: initialized OS integration for sleep inhibitor
upsmon: initialized OS integration for sleep/wake monitoring
Connecting in SSL to 'localhost' and look at certificate called 'NIT data server'
Intend to authenticate server localhost : SUCCESS
SSL handshake done successfully with server localhost
Connected to NUT server localhost in SSL
SSL handshake done successfully with client 127.0.0.1
User dummy-admin-m@127.0.0.1 logged into UPS [dummy] (SSL)
UPS dummy@localhost:12345 on battery
Thu Feb 26 18:12:06 UTC 2026: /home/jim/nut/clients/upssched-cmd: THIS IS A SAMPLE SCRIPT, PLEASE TAILOR IT FOR YOUR DEPLOYMENT OF NUT!
Thu Feb 26 18:12:06 UTC 2026: UPSNAME='dummy@localhost:12345'   NOTIFYTYPE='ONBATT'     NOTIFYMSG=''    args=ONBATT-HANDLER
Thu Feb 26 18:12:08 UTC 2026 [DEBUG] [sandbox] UPSMON PID 359584 is alive after a short while
Thu Feb 26 18:12:05 UTC 2026 [DEBUG] execcmd: running:   upsc dummy@localhost:12345
Connecting in SSL to 'localhost' (no certificate name specified)
Do not intend to authenticate server localhost
SSL handshake done successfully with server localhost
Connected to NUT server localhost in SSL
Certificate verification is disabled
Thu Feb 26 18:12:06 UTC 2026 [INFO] [testcase_sandbox_start_drivers_after_upsd] Got output:
device.mfr: Dummy Manufacturer
...
  • nut-scanner with NSS:
================================
Thu Feb 26 18:08:55 UTC 2026 [INFO] [testcase_sandbox_nutscanner_list] Call libupsclient test suite: nut-scanner on localhost:35012
Thu Feb 26 18:08:55 UTC 2026 [INFO] [testcase_sandbox_nutscanner_list] Preparing LD_LIBRARY_PATH='/home/jim/nut/clients:/home/jim/nut/clients/.libs'
SSL handshake done successfully with client 127.0.0.1
Thu Feb 26 18:08:55 UTC 2026 [DEBUG] execcmd: asked for: /home/jim/nut/tools/nut-scanner/nut-scanner -m 127.0.0.1/32 -O -p 35012
Thu Feb 26 18:08:55 UTC 2026 [DEBUG] execcmd: running:   /home/jim/nut/tools/nut-scanner/nut-scanner -m 127.0.0.1/32 -O -p 35012
Scanning NUT bus (old libupsclient connect method).
Connecting in SSL to '127.0.0.1' (no certificate name specified)
Do not intend to authenticate server 127.0.0.1
SSL handshake done successfully with server 127.0.0.1
Connected to NUT server 127.0.0.1 in SSL
Certificate verification is disabled
Thu Feb 26 18:08:55 UTC 2026 [INFO] [testcase_sandbox_nutscanner_list] findings from nut-scanner:
[nutdev-nut1]
        driver = "dummy-ups"
        port = "dummy@127.0.0.1:35012"
[nutdev-nut2]
        driver = "dummy-ups"
        port = "UPS1@127.0.0.1:35012"
[nutdev-nut3]
        driver = "dummy-ups"
        port = "UPS2@127.0.0.1:35012"
Thu Feb 26 18:08:55 UTC 2026 [INFO] [testcase_sandbox_nutscanner_list] inspecting these findings from nut-scanner...
Thu Feb 26 18:08:55 UTC 2026 [INFO] [testcase_sandbox_nutscanner_list] PASSED: nut-scanner found all expected devices

@jimklimov
Copy link
Copy Markdown
Member Author

jimklimov commented Feb 26, 2026

  • upsmon (has proper SSL code) with OpenSSL does complain about something (TODO: investigate; UPDATE: CERTPATH location was not populated with hash-named symlinks to CA PEM files):
:; make check-NIT-sandbox-devel
...

Thu Feb 26 18:23:18 UTC 2026 [DEBUG] execcmd: running:   upsmon -FF
Network UPS Tools upsmon 2.8.4.1454.17-1471+g47eedafa1 (development iteration after 2.8.4)
UPS: dummy@localhost:12345 (monitoring only)
No POWERDOWNFLAG value was configured in /home/jim/nut/tests/NIT/tmp/etc/upsmon.conf!
POWERDOWNFLAG should be a path to file that is normally writeable for root user, and remains at least readable late in shutdown after all unmounting completes.
upsmon: initialized OS integration for sleep inhibitor
upsmon: initialized OS integration for sleep/wake monitoring
Unknown return value from SSL_accept: Success
ssl_error() ret=-1 SSL_ERROR 1
Can not connect to NUT server localhost in SSL, disconnect
UPS [dummy@localhost:12345]: connect failed: SSL error: error:0A000197:SSL routines::shutdown while in init
Communications with UPS dummy@localhost:12345 lost
Thu Feb 26 18:23:18 UTC 2026: /home/jim/nut/clients/upssched-cmd: THIS IS A SAMPLE SCRIPT, PLEASE TAILOR IT FOR YOUR DEPLOYMENT OF NUT!
Thu Feb 26 18:23:18 UTC 2026: UPSNAME='dummy@localhost:12345'   NOTIFYTYPE='COMMBAD'    NOTIFYMSG=''    args=COMMBAD-INFO
Thu Feb 26 18:23:20 UTC 2026 [DEBUG] [sandbox] UPSMON PID 402534 is alive after a short while
...
ssl_error() ret=-1 SSL_ERROR 1
Can not connect to NUT server localhost in SSL, disconnect
Unknown return value from SSL_accept: Success
UPS [dummy@localhost:12345]: connect failed: SSL error: error:0A000197:SSL routines::shutdown while in init
UPS dummy@localhost:12345 is unavailable
Thu Feb 26 18:23:23 UTC 2026: /home/jim/nut/clients/upssched-cmd: THIS IS A SAMPLE SCRIPT, PLEASE TAILOR IT FOR YOUR DEPLOYMENT OF NUT!
Thu Feb 26 18:23:23 UTC 2026: UPSNAME='dummy@localhost:12345'   NOTIFYTYPE='NOCOMM'     NOTIFYMSG=''    args=NOCOMM-HANDLER
ssl_error() ret=-1 SSL_ERROR 1
Unknown return value from SSL_accept: Success
Can not connect to NUT server localhost in SSL, disconnect
UPS [dummy@localhost:12345]: connect failed: SSL error: error:0A000197:SSL routines::shutdown while in init
... (Ctrl+S paused output and programs)
ssl_error() ret=-1 SSL_ERROR 1
Unknown return value from SSL_accept: Success
Can not connect to NUT server localhost in SSL, disconnect
Data for UPS [dummy] is stale - check driver
Data for UPS [UPS1] is stale - check driver
UPS [dummy@localhost:12345]: connect failed: SSL error: error:0A000197:SSL routines::shutdown while in init
Data for UPS [UPS2] is stale - check driver
UPS [dummy] data is no longer stale
UPS [UPS1] data is no longer stale
UPS [UPS2] data is no longer stale
...
Unknown return value from SSL_accept: Success
ssl_error() ret=-1 SSL_ERROR 1
Can not connect to NUT server localhost in SSL, disconnect
UPS [dummy@localhost:12345]: connect failed: SSL error: error:0A000197:SSL routines::shutdown while in init
ssl_error() ret=-1 SSL_ERROR 1
...
  • relevant part of upsmon.conf generated for the test:
# OpenSSL CERTPATH: Directory with PEM file(s), looked up by the
#  CA subject name hash value (which must include our NUT server).
#  Here we just use the path for PEM file that should be populated
#  by the generatecfg_upsd_add_SSL() method.
# We only support CERTPATH (to recognize servers), FORCESSL and
# CERTVERIFY in OpenSSL builds.
CERTPATH "/home/jim/nut/tests/NIT/tmp/etc/cert/upsmon"
# With OpenSSL this is the only way to configure these behaviors,
# no CERTHOST setting here so far:
FORCESSL 1
CERTVERIFY 1
  • relevant part of upsd.conf generated for the test:
# OpenSSL CERTFILE: PEM file with data server cert, possibly the
# intermediate and root CA's, and finally corresponding private key
CERTFILE "/home/jim/nut/tests/NIT/tmp/etc/cert/upsd/upsd.pem"
  • upsc with OpenSSL:
Thu Feb 26 18:21:26 UTC 2026 [INFO] [testcase_sandbox_start_drivers_after_upsd] Query driver state from UPSD by UPSC after driver startup
Connected to NUT server localhost in SSL
Certificate verification is disabled
Thu Feb 26 18:21:26 UTC 2026 [INFO] [testcase_sandbox_start_drivers_after_upsd] Got output:
device.mfr: Dummy Manufacturer
...
  • nut-scanner with OpenSSL:
================================
Thu Feb 26 18:21:33 UTC 2026 [INFO] [testcase_sandbox_nutscanner_list] Call libupsclient test suite: nut-scanner on localhost:34966
Thu Feb 26 18:21:33 UTC 2026 [INFO] [testcase_sandbox_nutscanner_list] Preparing LD_LIBRARY_PATH='/home/jim/nut/clients:/home/jim/nut/clients/.libs'
Scanning NUT bus (old libupsclient connect method).
Connected to NUT server 127.0.0.1 in SSL
Certificate verification is disabled
Thu Feb 26 18:21:33 UTC 2026 [INFO] [testcase_sandbox_nutscanner_list] findings from nut-scanner:
[nutdev-nut1]
        driver = "dummy-ups"
        port = "dummy@127.0.0.1:34966"
[nutdev-nut2]
        driver = "dummy-ups"
        port = "UPS1@127.0.0.1:34966"
[nutdev-nut3]
        driver = "dummy-ups"
        port = "UPS2@127.0.0.1:34966"
Thu Feb 26 18:21:33 UTC 2026 [INFO] [testcase_sandbox_nutscanner_list] inspecting these findings from nut-scanner...
Thu Feb 26 18:21:33 UTC 2026 [INFO] [testcase_sandbox_nutscanner_list] PASSED: nut-scanner found all expected devices

@AppVeyorBot
Copy link
Copy Markdown

jimklimov added a commit to jimklimov/nut that referenced this pull request Feb 26, 2026
jimklimov added a commit to jimklimov/nut that referenced this pull request Feb 26, 2026
…to handle numeric or specific string values, to match both ways of reading ambiguous documentation [networkupstools#3330]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
@jimklimov jimklimov moved this to In Progress in NUT QA Feb 26, 2026
jimklimov added a commit to jimklimov/nut that referenced this pull request Feb 27, 2026
jimklimov added a commit to jimklimov/nut that referenced this pull request Feb 27, 2026
…to handle numeric or specific string values, to match both ways of reading ambiguous documentation [networkupstools#3330]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
jimklimov added a commit to jimklimov/nut that referenced this pull request Feb 28, 2026
jimklimov added a commit to jimklimov/nut that referenced this pull request Feb 28, 2026
…to handle numeric or specific string values, to match both ways of reading ambiguous documentation [networkupstools#3330]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
jimklimov added a commit to jimklimov/nut that referenced this pull request Feb 28, 2026
…ver we change nut_debug_level [networkupstools#1711, networkupstools#2800, networkupstools#3330]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
jimklimov added a commit to jimklimov/nut that referenced this pull request Feb 28, 2026
…ibupsclient consumers to use upscli_set_debug_level() where available [networkupstools#1711, networkupstools#2800, networkupstools#3330]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
jimklimov added a commit to jimklimov/nut that referenced this pull request Feb 28, 2026
…ver we change nut_debug_level [networkupstools#1711, networkupstools#2800, networkupstools#3330]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
jimklimov added a commit to jimklimov/nut that referenced this pull request Feb 28, 2026
…ibupsclient consumers to use upscli_set_debug_level() where available [networkupstools#1711, networkupstools#2800, networkupstools#3330]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
@AppVeyorBot
Copy link
Copy Markdown

jimklimov added a commit to jimklimov/nut that referenced this pull request Mar 1, 2026
jimklimov added a commit to jimklimov/nut that referenced this pull request Mar 1, 2026
…to handle numeric or specific string values, to match both ways of reading ambiguous documentation [networkupstools#3330]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
jimklimov added a commit to jimklimov/nut that referenced this pull request Mar 1, 2026
…ver we change nut_debug_level [networkupstools#1711, networkupstools#2800, networkupstools#3330]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
…on actual code may be needed to rectify it after all [networkupstools#3331, networkupstools#1711]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
@AppVeyorBot
Copy link
Copy Markdown

@AppVeyorBot
Copy link
Copy Markdown

jimklimov added a commit to jimklimov/nut that referenced this pull request Mar 5, 2026
…file libupsclient.la exists and is not empty [networkupstools#3330]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
@AppVeyorBot
Copy link
Copy Markdown

…file libupsclient.la exists and is not empty [networkupstools#3330]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
…on.h [networkupstools#3328]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
@jimklimov jimklimov merged commit 7e9c6f3 into networkupstools:master Mar 7, 2026
22 of 23 checks passed
@jimklimov jimklimov deleted the nit-ssl branch March 7, 2026 12:19
jimklimov added a commit to jimklimov/nut that referenced this pull request Mar 8, 2026
…ng sockets [networkupstools#3331]

The TLS handshake functions `SSL_accept()` (server) and `SSL_connect()`
(client) require a retry loop when the underlying socket is in
non-blocking mode.  When either function returns '-1' with an error code
of `SSL_ERROR_WANT_READ` or `SSL_ERROR_WANT_WRITE`, it is signalling a
non-fatal "not done yet" condition: the handshake needs more I/O turns
to complete.  The correct response is to wait for the socket fd to
become ready in the indicated direction and then call the same function
again with the same SSL object (this is explicitly documented in OpenSSL
for every version since 0.9.x and the API contract has never changed).

Previously both call sites used a single-shot switch/case pattern that
treated these non-fatal WANT_READ/WANT_WRITE returns as fatal errors,
tearing down the connection immediately.

On Linux the loopback socket is fast enough that the handshake *nearly
always* completes in the first call, masking the bug.  On BSD (FreeBSD,
OpenBSD, NetBSD), macOS, and illumos-based systems (OmniOS, OpenIndiana)
the loopback socket behaves differently and WANT_READ/WANT_WRITE are
returned regularly, causing CI failures on all of those platforms
regardless of compiler, C standard dialect, or OpenSSL version used.

The fix is identical for all supported OpenSSL versions (0.9.x / 1.0.x /
1.1.x / 3.x): the `SSL_ERROR_WANT_*` codes and the required retry
semantics have been stable since the library's inception.

No NSS changes are needed: NSS uses `SSL_ForceHandshake()` which is
already blocking-by-design through NSPR.

Fixes issues (re-)discovered and/or confirmed by work on PR networkupstools#3330 for
issue networkupstools#1711

Tested-on: Linux (passes), macOS 12, FreeBSD 12, NetBSD 11, OpenBSD 6.5,
           OmniOS (amd64+i386), OpenIndiana (amd64+i386) - all compilers                    and C standard dialects in the CI matrix.
Co-authored-by: Claude Sonnet 4.6
Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
jimklimov added a commit to jimklimov/nut that referenced this pull request Mar 8, 2026
…ng sockets [networkupstools#3331]

The TLS handshake functions `SSL_accept()` (server) and `SSL_connect()`
(client) require a retry loop when the underlying socket is in
non-blocking mode.  When either function returns '-1' with an error code
of `SSL_ERROR_WANT_READ` or `SSL_ERROR_WANT_WRITE`, it is signalling a
non-fatal "not done yet" condition: the handshake needs more I/O turns
to complete.  The correct response is to wait for the socket fd to
become ready in the indicated direction and then call the same function
again with the same SSL object (this is explicitly documented in OpenSSL
for every version since 0.9.x and the API contract has never changed).

Previously both call sites used a single-shot switch/case pattern that
treated these non-fatal WANT_READ/WANT_WRITE returns as fatal errors,
tearing down the connection immediately.

On Linux the loopback socket is fast enough that the handshake *nearly
always* completes in the first call, masking the bug.  On BSD (FreeBSD,
OpenBSD, NetBSD), macOS, and illumos-based systems (OmniOS, OpenIndiana)
the loopback socket behaves differently and WANT_READ/WANT_WRITE are
returned regularly, causing CI failures on all of those platforms
regardless of compiler, C standard dialect, or OpenSSL version used.

The fix is identical for all supported OpenSSL versions (0.9.x / 1.0.x /
1.1.x / 3.x): the `SSL_ERROR_WANT_*` codes and the required retry
semantics have been stable since the library's inception.

No NSS changes are needed: NSS uses `SSL_ForceHandshake()` which is
already blocking-by-design through NSPR.

Fixes issues (re-)discovered and/or confirmed by work on PR networkupstools#3330 for
issue networkupstools#1711

Tested-on: Linux (passes), macOS 12, FreeBSD 12, NetBSD 11, OpenBSD 6.5,
           OmniOS (amd64+i386), OpenIndiana (amd64+i386) - all compilers                    and C standard dialects in the CI matrix.
Co-authored-by: Claude Sonnet 4.6
Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
jimklimov added a commit to jimklimov/nut that referenced this pull request Mar 8, 2026
…ng sockets [networkupstools#3331]

The TLS handshake functions `SSL_accept()` (server) and `SSL_connect()`
(client) require a retry loop when the underlying socket is in
non-blocking mode.  When either function returns '-1' with an error code
of `SSL_ERROR_WANT_READ` or `SSL_ERROR_WANT_WRITE`, it is signalling a
non-fatal "not done yet" condition: the handshake needs more I/O turns
to complete.  The correct response is to wait for the socket fd to
become ready in the indicated direction and then call the same function
again with the same SSL object (this is explicitly documented in OpenSSL
for every version since 0.9.x and the API contract has never changed).

Previously both call sites used a single-shot switch/case pattern that
treated these non-fatal WANT_READ/WANT_WRITE returns as fatal errors,
tearing down the connection immediately.

On Linux the loopback socket is fast enough that the handshake *nearly
always* completes in the first call, masking the bug.  On BSD (FreeBSD,
OpenBSD, NetBSD), macOS, and illumos-based systems (OmniOS, OpenIndiana)
the loopback socket behaves differently and WANT_READ/WANT_WRITE are
returned regularly, causing CI failures on all of those platforms
regardless of compiler, C standard dialect, or OpenSSL version used.

The fix is identical for all supported OpenSSL versions (0.9.x / 1.0.x /
1.1.x / 3.x): the `SSL_ERROR_WANT_*` codes and the required retry
semantics have been stable since the library's inception.

No NSS changes are needed: NSS uses `SSL_ForceHandshake()` which is
already blocking-by-design through NSPR.

Fixes issues (re-)discovered and/or confirmed by work on PR networkupstools#3330 for
issue networkupstools#1711

Tested-on: Linux (passes), macOS 12, FreeBSD 12, NetBSD 11, OpenBSD 6.5,
           OmniOS (amd64+i386), OpenIndiana (amd64+i386) - all compilers                    and C standard dialects in the CI matrix.
Co-authored-by: Claude Sonnet 4.6
Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
jimklimov added a commit that referenced this pull request Mar 12, 2026
…/NSS CA and server/client certs [#3330]

Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
@jimklimov jimklimov moved this from In Progress to Done in NUT QA Mar 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI Entries related to continuous integration infrastructure (here CI = tools + scripts + recipes) enhancement portability We want NUT to build and run everywhere possible SSL/NSS Issues and PRs about SSL, TLS and other crypto-related matters

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Track build info and SSL capabilities of libupsclient actually used by the clients, add SSL tests with NIT where possible

2 participants