-
Notifications
You must be signed in to change notification settings - Fork 98
Description
Hello,
as most of our sensitive network services are secured via mutual TLS nowadays, I'd like to see that option in NCPA as well, if possible. Should it already be there and I've overlooked it, please point me to the documentation.
The following is the working code for one of my https api daemons. It is set to TLS v1.3 only. ssl_cert and ssl_key are the normal server TLS certificate and its private key. ssl_ca is the CA used for verifying the client certificate. If ssl_mtls is set, a client certificate is strictly required.
As is noted in the comments, enforcing TLS v1.3 works differently from <= TLS v1.2.
if args.ssl_key or args.ssl_cert or args.ssl_ca:
if not args.ssl_key or not args.ssl_cert or not args.ssl_ca:
print('Error: One or more of ssl_key, ssl_cert, ssl_ca, is missing')
sys.exit(1)
import ssl
# CLIENT_AUTH is correct, as it is for a server socket that needs to authenticate a client.
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.minimum_version = ssl.TLSVersion.TLSv1_3
context.maximum_version = ssl.TLSVersion.TLSv1_3
if args.ssl_mtls:
context.verify_mode = ssl.CERT_REQUIRED
# Only for TLS v1.2: context.set_ciphers(ssl_cipher), doesn't work with TLS v1.3.
#
# TODO: Available with python 3.15:
#
# get_sigalgs(): Return a list of available TLS signature algorithm names used by servers to complete the TLS handshake or clients requesting certificate-based authentication.
# >>> ssl.get_sigalgs(): ['ecdsa_secp256r1_sha256', 'ecdsa_secp384r1_sha384', ...]
#
# SSLContext.set_client_sigalgs
# SSLContext.set_server_sigalgs
# SSLContext.set_ciphersuites(ciphersuites, /): Set the allowed ciphers for sockets created with this context when connecting using TLS 1.3. The *ciphersuites* argument should
# be a colon-separate string of TLS 1.3 cipher names.
# SSLContext.set_groups(groups, /): Set the groups allowed for key agreement for sockets created with this context. It should be a string in the `OpenSSL group list format
# https://docs.openssl.org/master/man3/SSL_CTX_set1_groups_list/ .
#
# https://github.com/python/cpython/blob/main/Doc/library/ssl.rst
#
context.load_cert_chain(args.ssl_cert, keyfile=args.ssl_key)
context.load_verify_locations(cafile=args.ssl_ca)
httpd.socket = context.wrap_socket(httpd.socket,
server_side=True,
do_handshake_on_connect=False
)
This is the curl command to connect to it using the client cert and key for mTLS as well as the CA for verification of the server certificate (the CA that signs the client certificates can be a separate one from the one that signs the server certificates):
curl -s \
-H "Accept: application/json" \
--cert "$cert" \
--key "$key" \
--cacert "$ca" \
https://host:port/state
What remains is modifying the ncpa client to support providing the certificate + key + ca. The ca is of interest to me so I can do CA-pinning instead of relying on the OS/python trust store.