Skip to content

Commit

Permalink
OpenSSLContext::Config: added set_cn_reject_handler() hook
Browse files Browse the repository at this point in the history
The set_cn_reject_handler() method allows users to specify
a hook for examining the leaf Common Name during SSL/TLS
handshakes, with the option to reject the handshake.

Signed-off-by: James Yonan <[email protected]>
  • Loading branch information
jamesyonan authored and Jenkins-dev committed Dec 30, 2024
1 parent 0571a11 commit 689f3ed
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 1 deletion.
5 changes: 5 additions & 0 deletions openvpn/mbedtls/ssl/sslctx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,11 @@ class MbedTLSContext : public SSLFactoryAPI
throw MbedTLSException("set_sni_name not implemented");
}

void set_cn_reject_handler(CommonNameReject *cn_reject_handler_arg) override
{
throw MbedTLSException("set_cn_reject_handler not implemented");
}

void set_private_key_password(const std::string &pwd) override
{
priv_key_pwd = pwd;
Expand Down
36 changes: 35 additions & 1 deletion openvpn/openssl/ssl/sslctx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,18 @@ class OpenSSLContext : public SSLFactoryAPI
sni_name = sni_name_arg;
}

/**
* Add a hook to allow inspection and possible rejection
* of leaf cert common names (server-side only).
*
* @param cn_reject_handler_arg CommonNameReject object
* that implements a custom reject() hook.
*/
void set_cn_reject_handler(CommonNameReject *cn_reject_handler_arg) override
{
cn_reject_handler = cn_reject_handler_arg;
}

void set_private_key_password(const std::string &pwd) override
{
pkey.set_private_key_password(pwd);
Expand Down Expand Up @@ -664,6 +676,7 @@ class OpenSSLContext : public SSLFactoryAPI
std::string external_pki_alias;
TLSSessionTicketBase *session_ticket_handler = nullptr; // server side only
SNI::HandlerBase *sni_handler = nullptr; // server side only
CommonNameReject *cn_reject_handler = nullptr;
Frame::Ptr frame;
unsigned int flags = 0; // defined in sslconsts.hpp
std::string sni_name; // client side only
Expand Down Expand Up @@ -1999,10 +2012,31 @@ class OpenSSLContext : public SSLFactoryAPI
preverify_ok = false;
}

// get the Common name
std::string cn = OpenSSLPKI::x509_get_field(current_cert, NID_commonName);

// early rejection of Common Name?
if (self->config->cn_reject_handler)
{
try
{
if (self->config->cn_reject_handler->reject(cn))
{
OVPN_LOG_INFO("VERIFY FAIL -- early rejection of leaf cert Common Name");
preverify_ok = false;
}
}
catch (const std::exception &e)
{
OVPN_LOG_INFO("VERIFY FAIL -- early rejection of leaf cert Common Name due to handler exception: " << e.what());
preverify_ok = false;
}
}

if (self_ssl->authcert)
{
// save the Common Name
self_ssl->authcert->cn = OpenSSLPKI::x509_get_field(current_cert, NID_commonName);
self_ssl->authcert->cn = std::move(cn); // NOTE: cn is consumed!

// save the leaf cert serial number
load_serial_number_into_authcert(*self_ssl->authcert, current_cert);
Expand Down
40 changes: 40 additions & 0 deletions openvpn/ssl/cn_reject_handler.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// OpenVPN -- An application to securely tunnel IP networks
// over a single port, with support for SSL/TLS-based
// session authentication and key exchange,
// packet encryption, packet authentication, and
// packet compression.
//
// Copyright (C) 2012- OpenVPN Inc.
//
// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
//

#pragma once

#include <string>
#include <memory>

namespace openvpn {

/**
* Abstract base class used to provide early rejection
* of specific Common Names during SSL/TLS handshake.
*/
class CommonNameReject
{
public:
typedef std::unique_ptr<CommonNameReject> UPtr;

/**
* Should a leaf certificate having Common Name cn
* be rejected during SSL/TLS handshake?
*
* @param cn Common Name
* @return true if certificate should be rejected.
*/
virtual bool reject(const std::string &cn) = 0;

virtual ~CommonNameReject() = default;
};

} // namespace openvpn
2 changes: 2 additions & 0 deletions openvpn/ssl/sslapi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <openvpn/ssl/tls_remote.hpp>
#include <openvpn/ssl/tls_cert_profile.hpp>
#include <openvpn/ssl/sess_ticket.hpp>
#include <openvpn/ssl/cn_reject_handler.hpp>
#include <openvpn/random/randapi.hpp>
#include "openvpn/log/logger.hpp"

Expand Down Expand Up @@ -146,6 +147,7 @@ class SSLConfigAPI : public RC<thread_unsafe_refcount>
virtual void set_sni_handler(SNI::HandlerBase *sni_handler) = 0; // server side
virtual void set_sni_name(const std::string &sni_name_arg) = 0; // client side
virtual void set_private_key_password(const std::string &pwd) = 0;
virtual void set_cn_reject_handler(CommonNameReject *cn_reject_handler_arg) = 0;
virtual void load_ca(const std::string &ca_txt, bool strict) = 0;
virtual void load_crl(const std::string &crl_txt) = 0;
virtual void load_cert(const std::string &cert_txt) = 0;
Expand Down

0 comments on commit 689f3ed

Please sign in to comment.