From e567f92e643cc1a0c20016fe818dbe25cca93cb3 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sun, 17 May 2026 21:59:20 +0200 Subject: [PATCH] Removed unnecessary CA and certificate handlers This removes certificate and CA handlers not used by the openconnect client. This is a hardening measure to further reduce the attack surface of the worker process. Signed-off-by: Nikos Mavrogiannopoulos --- NEWS | 5 ++ src/worker-http-handlers.c | 154 ------------------------------------- src/worker-http.c | 4 - src/worker.h | 6 +- tests/meson.build | 2 +- tests/test-camouflage | 2 +- tests/test-get-cert | 92 ---------------------- tests/test-owasp-headers | 21 ----- 8 files changed, 8 insertions(+), 278 deletions(-) delete mode 100755 tests/test-get-cert diff --git a/NEWS b/NEWS index eaa766c3..ca879ccf 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,11 @@ body limit - Fix build issue on FreeBSD (#704) - Build against Nettle 4. +- Removed unnecessary for openconnect client handlers to reduce attack surface: + * /cert.pem + * /cert.cer + * /ca.pem + * /ca.cer * Version 1.4.2 (released 2026-04-16) diff --git a/src/worker-http-handlers.c b/src/worker-http-handlers.c index 494ca627..f825c023 100644 --- a/src/worker-http-handlers.c +++ b/src/worker-http-handlers.c @@ -90,160 +90,6 @@ static int send_data(worker_st *ws, unsigned int http_ver, return 0; } -int get_cert_handler(worker_st *ws, unsigned int http_ver) -{ - if (ws->conn_type != SOCK_TYPE_UNIX) { /* we have TLS */ - const gnutls_datum_t *certs; - gnutls_datum_t out = { NULL, 0 }; - int ret; - - oclog(ws, LOG_DEBUG, "requested server certificate"); - - certs = gnutls_certificate_get_ours(ws->session); - if (certs == NULL) { - return -1; - } - - ret = gnutls_pem_base64_encode_alloc("CERTIFICATE", &certs[0], - &out); - if (ret < 0) - return -1; - - ret = send_data(ws, http_ver, "application/x-pem-file", - (char *)out.data, out.size); - gnutls_free(out.data); - - return ret; - } else { - return -1; - } -} -int get_cert_der_handler(worker_st *ws, unsigned int http_ver) -{ - if (ws->conn_type != SOCK_TYPE_UNIX) { /* we have TLS */ - const gnutls_datum_t *certs; - - oclog(ws, LOG_DEBUG, "requested raw server certificate"); - - certs = gnutls_certificate_get_ours(ws->session); - if (certs == NULL) { - return -1; - } - - return send_data(ws, http_ver, "application/pkix-cert", - (char *)certs[0].data, certs[0].size); - } else { - return -1; - } -} - -static int ca_handler(worker_st *ws, unsigned int http_ver, unsigned int der) -{ - if (ws->conn_type != SOCK_TYPE_UNIX) { /* we have TLS */ - const gnutls_datum_t *certs; - gnutls_datum_t out = { NULL, 0 }, tmpca; - unsigned int i; - int ret; - gnutls_x509_crt_t issuer = NULL, crt = NULL; - - oclog(ws, LOG_DEBUG, "requested server CA"); - - certs = gnutls_certificate_get_ours(ws->session); - if (certs == NULL) { - oclog(ws, LOG_DEBUG, "could not obtain our cert"); - return -1; - } - - ret = gnutls_x509_crt_init(&crt); - if (ret < 0) { - oclog(ws, LOG_DEBUG, "could not initialize cert"); - return -1; - } - - ret = gnutls_x509_crt_import(crt, &certs[0], - GNUTLS_X509_FMT_DER); - if (ret < 0) { - ret = -1; - oclog(ws, LOG_DEBUG, "could not import our cert"); - goto cleanup; - } - - for (i = 0; i < 8; i++) { - ret = gnutls_certificate_get_crt_raw(WSCREDS(ws)->xcred, - i, 1, &tmpca); - if (ret < 0) { - goto cleanup; - } - - ret = gnutls_x509_crt_init(&issuer); - if (ret < 0) { - ret = -1; - oclog(ws, LOG_DEBUG, - "could not initialize issuer cert"); - goto cleanup; - } - - ret = gnutls_x509_crt_import(issuer, &tmpca, - GNUTLS_X509_FMT_DER); - if (ret < 0) { - ret = -1; - oclog(ws, LOG_DEBUG, - "could not import issuer cert"); - goto cleanup; - } - - ret = gnutls_x509_crt_check_issuer(crt, issuer); - if (ret != 0) { - ret = gnutls_x509_crt_export2( - issuer, - der ? GNUTLS_X509_FMT_DER : - GNUTLS_X509_FMT_PEM, - &out); - if (ret < 0) { - ret = -1; - oclog(ws, LOG_DEBUG, - "could not export issuer of cert"); - goto cleanup; - } - break; - } - - gnutls_x509_crt_deinit(issuer); - issuer = NULL; - } - - ret = send_data(ws, http_ver, "application/pkix-cert", - (char *)out.data, out.size); - -cleanup: - if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - oclog(ws, LOG_DEBUG, - "could not get CA; does the server cert list contain the CA certificate?"); - ret = -1; - } - - if (crt) - gnutls_x509_crt_deinit(crt); - if (issuer) - gnutls_x509_crt_deinit(issuer); - gnutls_free(out.data); - - return ret; - } else { - return -1; - } -} - -int get_ca_handler(worker_st *ws, unsigned int http_ver) -{ - return ca_handler(ws, http_ver, 0); -} - -int get_ca_der_handler(worker_st *ws, unsigned int http_ver) -{ - return ca_handler(ws, http_ver, 1); -} - #ifdef ANYCONNECT_CLIENT_COMPAT int get_config_handler(worker_st *ws, unsigned int http_ver) { diff --git a/src/worker-http.c b/src/worker-http.c index fee47cb3..ed08760e 100644 --- a/src/worker-http.c +++ b/src/worker-http.c @@ -61,10 +61,6 @@ static const struct known_urls_st known_urls[] = { LL("/", get_auth_handler, post_auth_handler), LL("/auth", get_auth_handler, post_auth_handler), LL("/VPN", get_auth_handler, post_auth_handler), - LL("/cert.pem", get_cert_handler, NULL), - LL("/cert.cer", get_cert_der_handler, NULL), - LL("/ca.pem", get_ca_handler, NULL), - LL("/ca.cer", get_ca_der_handler, NULL), #ifdef ANYCONNECT_CLIENT_COMPAT LL_DIR("/profiles", get_config_handler, NULL), LL("/VPNManifest.xml", get_string_handler, NULL), diff --git a/src/worker.h b/src/worker.h index ce42d45e..11f6a8a6 100644 --- a/src/worker.h +++ b/src/worker.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2016 Nikos Mavrogiannopoulos + * Copyright (C) 2013-2026 Nikos Mavrogiannopoulos * * Author: Nikos Mavrogiannopoulos * @@ -348,10 +348,6 @@ int auth_user_deinit(worker_st *ws); int get_auth_handler(worker_st *server, unsigned int http_ver); int post_auth_handler(worker_st *server, unsigned int http_ver); int post_kkdcp_handler(worker_st *server, unsigned int http_ver); -int get_cert_handler(worker_st *ws, unsigned int http_ver); -int get_cert_der_handler(worker_st *ws, unsigned int http_ver); -int get_ca_handler(worker_st *ws, unsigned int http_ver); -int get_ca_der_handler(worker_st *ws, unsigned int http_ver); int get_svc_handler(worker_st *ws, unsigned int http_ver); int post_svc_handler(worker_st *ws, unsigned int http_ver); diff --git a/tests/meson.build b/tests/meson.build index 778dafe5..84d6ca0a 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -116,7 +116,7 @@ if have_cwrap 'test-pass', 'test-pass-cert', 'test-pass-cert-rfc822name', 'test-cert', 'test-group-pass', 'test-pass-group-cert', 'test-pass-group-cert-no-pass', 'test-sighup', - 'test-enc-key', 'test-sighup-key-change', 'test-get-cert', + 'test-enc-key', 'test-sighup-key-change', 'test-san-cert', 'test-pass-opt-cert', 'test-cert-opt-pass', 'haproxy-auth', 'test-maintenance', 'resumption', diff --git a/tests/test-camouflage b/tests/test-camouflage index 0ceaff6a..c26eaa0a 100755 --- a/tests/test-camouflage +++ b/tests/test-camouflage @@ -75,7 +75,7 @@ else fi echo "Checking with CURL that server returns HTTP 200 for user authenticated GET" -http_result=$(curl --insecure https://localhost:${PORT}/cert.pem --output /dev/null --cookie "${HTTP_COOKIE}" --silent --write-out "%{http_code}") +http_result=$(curl --insecure https://localhost:${PORT}/svc --output /dev/null --cookie "${HTTP_COOKIE}" --silent --write-out "%{http_code}") if [ "${http_result}" != "200" ]; then fail ${PID} "Server returned ${http_result} instead of 200 for GET" fi diff --git a/tests/test-get-cert b/tests/test-get-cert deleted file mode 100755 index 1097a1e8..00000000 --- a/tests/test-get-cert +++ /dev/null @@ -1,92 +0,0 @@ -#!/bin/sh -# -# Copyright (C) 2013 Nikos Mavrogiannopoulos -# -# This file is part of ocserv. -# -# ocserv is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 2 of the License, or (at -# your option) any later version. -# -# ocserv is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GnuTLS; if not, write to the Free Software Foundation, -# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -SERV="${SERV:-../src/ocserv}" -srcdir=${srcdir:-.} -NO_NEED_ROOT=1 - -TMPFILE=getcert.$$.tmp -TMPFILE2=getcert2.$$.tmp - -. `dirname $0`/common.sh - -eval "${GETPORT}" - -echo "Testing ocserv certificate GET handlers... " - -update_config test-user-cert.config -launch_simple_sr_server -d 1 -f -c ${CONFIG} -PID=$! - -wait_server $PID - -echo -n "Connecting to GET PEM certificate... " -( LD_PRELOAD=libsocket_wrapper.so curl https://$ADDRESS:$PORT/cert.pem --insecure > $TMPFILE 2>/dev/null ) || - fail $PID "Could not get certificate!" - -cmp $TMPFILE "${srcdir}/certs/server-cert.pem" -if test $? != 0;then - fail $PID "failed, certs not match" -fi - -echo "ok" - -echo -n "Connecting to GET DER certificate... " -( LD_PRELOAD=libsocket_wrapper.so curl https://$ADDRESS:$PORT/cert.cer --insecure > $TMPFILE 2>/dev/null ) || - fail $PID "Could not get DER certificate!" - -certtool --inder -i <"$TMPFILE" >$TMPFILE2 -certtool -i <"${srcdir}/certs/server-cert.pem" >$TMPFILE -cmp "$TMPFILE" "$TMPFILE2" -if test $? != 0;then - fail $PID "failed, certs not match" -fi - -echo "ok" - -echo -n "Connecting to GET CA PEM certificate... " -( LD_PRELOAD=libsocket_wrapper.so curl https://$ADDRESS:$PORT/ca.pem --insecure > $TMPFILE 2>/dev/null ) || - fail $PID "Could not get certificate!" - -cmp $TMPFILE "${srcdir}/certs/ca.pem" -if test $? != 0;then - fail $PID "failed, certs not match" -fi - -echo "ok" - -echo -n "Connecting to GET CA DER certificate... " -( LD_PRELOAD=libsocket_wrapper.so curl https://$ADDRESS:$PORT/ca.cer --insecure > $TMPFILE 2>/dev/null ) || - fail $PID "Could not get DER certificate!" - -certtool --inder -i <"$TMPFILE" >$TMPFILE2 -certtool -i <"${srcdir}/certs/ca.pem" >$TMPFILE -cmp "$TMPFILE" "$TMPFILE2" -if test $? != 0;then - fail $PID "failed, certs not match" -fi - -echo "ok" - -cleanup - -rm -f "$TMPFILE" "$TMPFILE2" - -exit 0 diff --git a/tests/test-owasp-headers b/tests/test-owasp-headers index c2d6e844..a7624f71 100755 --- a/tests/test-owasp-headers +++ b/tests/test-owasp-headers @@ -111,27 +111,6 @@ results=$(LD_PRELOAD=libsocket_wrapper.so curl -I -X GET -s https://$ADDRESS:$PO CheckHeaders "$results" echo "ok" -echo -n "Testing /cert.pem ... " -results=$(LD_PRELOAD=libsocket_wrapper.so curl -I -X GET -s https://$ADDRESS:$PORT/cert.pem --insecure) -CheckHeaders "$results" -echo "ok" - -echo -n "Testing /cert.cer ... " -results=$(LD_PRELOAD=libsocket_wrapper.so curl -I -X GET -s https://$ADDRESS:$PORT/cert.cer --insecure) -CheckHeaders "$results" -echo "ok" - -echo -n "Testing /ca.pem ... " -results=$(LD_PRELOAD=libsocket_wrapper.so curl -I -X GET -s https://$ADDRESS:$PORT/ca.pem --insecure) -CheckHeaders "$results" -echo "ok" - -echo -n "Testing /ca.cer ... " -results=$(LD_PRELOAD=libsocket_wrapper.so curl -I -X GET -s https://$ADDRESS:$PORT/ca.cer --insecure) -CheckHeaders "$results" -echo "ok" - - cleanup exit 0