Skip to content

Commit

Permalink
Converted SSL_API from static to dynamic polymorphism
Browse files Browse the repository at this point in the history
(using SSLFactoryAPI and SSLAPI as base classes).
  • Loading branch information
jamesyonan committed Oct 16, 2014
1 parent 8b71fa9 commit 12e3f20
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 91 deletions.
49 changes: 34 additions & 15 deletions openvpn/applecrypto/ssl/sslctx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,20 @@
#include <Security/SecImportExport.h>
#include <Security/SecItem.h>
#include <Security/SecureTransport.h>
#include <Security/SecKey.h>

#include <openvpn/common/types.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/rc.hpp>
#include <openvpn/common/mode.hpp>
#include <openvpn/buffer/buffer.hpp>
#include <openvpn/frame/frame.hpp>
#include <openvpn/frame/memq_stream.hpp>
#include <openvpn/pki/epkibase.hpp>
#include <openvpn/applecrypto/cf/cfsec.hpp>
#include <openvpn/applecrypto/cf/error.hpp>
#include <openvpn/ssl/tlsver.hpp>
#include <openvpn/ssl/sslconsts.hpp>
#include <openvpn/ssl/sslapi.hpp>

// An SSL Context is essentially a configuration that can be used
// to generate an arbitrary number of actual SSL connections objects.
Expand All @@ -60,7 +62,7 @@ namespace openvpn {

// Represents an SSL configuration that can be used
// to instantiate actual SSL sessions.
class AppleSSLContext : public RC<thread_unsafe_refcount>
class AppleSSLContext : public SSLFactoryAPI
{
public:
OPENVPN_EXCEPTION(ssl_context_error);
Expand All @@ -76,12 +78,14 @@ namespace openvpn {
struct Config
{
Config() : ssl_debug_level(0),
flags(0) {}
flags(0),
tls_version_min(TLSVersion::UNDEF) {}

Mode mode;
int ssl_debug_level;
unsigned int flags; // defined in sslconsts.hpp
CF::Array identity; // as returned by load_identity
TLSVersion::Type tls_version_min; // minimum TLS version that we will negotiate (fixme -- not implemented)
Frame::Ptr frame;

void load_identity(const std::string& subject_match)
Expand All @@ -98,7 +102,7 @@ namespace openvpn {

// identity
{
const std::string& subject_match = opt.get("identity", 1);
const std::string& subject_match = opt.get("identity", 1, 256);
load_identity(subject_match);
}
}
Expand All @@ -110,19 +114,19 @@ namespace openvpn {

// Represents an actual SSL session.
// Normally instantiated by AppleSSLContext::ssl().
class SSL : public RC<thread_unsafe_refcount>
class SSL : public SSLAPI
{
friend class AppleSSLContext;

public:
typedef boost::intrusive_ptr<SSL> Ptr;

void start_handshake()
virtual void start_handshake()
{
SSLHandshake(ssl);
}

ssize_t write_cleartext_unbuffered(const void *data, const size_t size)
virtual ssize_t write_cleartext_unbuffered(const void *data, const size_t size)
{
size_t actual = 0;
const OSStatus status = SSLWrite(ssl, data, size, &actual);
Expand All @@ -137,7 +141,7 @@ namespace openvpn {
return actual;
}

ssize_t read_cleartext(void *data, const size_t capacity)
virtual ssize_t read_cleartext(void *data, const size_t capacity)
{
if (!overflow)
{
Expand All @@ -157,29 +161,31 @@ namespace openvpn {
throw ssl_ciphertext_in_overflow();
}

bool read_cleartext_ready() const {
virtual bool read_cleartext_ready() const
{
// fixme: need to detect data buffered at SSL layer
return !ct_in.empty();
}

void write_ciphertext(const BufferPtr& buf)
virtual void write_ciphertext(const BufferPtr& buf)
{
if (ct_in.size() < MAX_CIPHERTEXT_IN)
ct_in.write_buf(buf);
else
overflow = true;
}

bool read_ciphertext_ready() const {
virtual bool read_ciphertext_ready() const
{
return !ct_out.empty();
}

BufferPtr read_ciphertext()
virtual BufferPtr read_ciphertext()
{
return ct_out.read_buf();
}

std::string ssl_handshake_details() const // fixme -- code me
virtual std::string ssl_handshake_details() const // fixme -- code me
{
return "[AppleSSL not implemented]";
}
Expand Down Expand Up @@ -321,9 +327,22 @@ namespace openvpn {
OPENVPN_THROW(ssl_context_error, "AppleSSLContext: identity undefined");
}

SSL::Ptr ssl() const { return SSL::Ptr(new SSL(*this)); }
// create a new SSL instance
virtual SSLAPI::Ptr ssl()
{
return SSL::Ptr(new SSL(*this));
}

const Mode& mode() const { return config_.mode; }
// like ssl() above but verify hostname against cert CommonName and/or SubjectAltName
virtual SSLAPI::Ptr ssl(const std::string& hostname)
{
OPENVPN_THROW(ssl_context_error, "AppleSSLContext: ssl session with CommonName and/or SubjectAltName verification not implemented");
}

virtual const Mode& mode() const
{
return config_.mode;
}

private:
const Frame::Ptr& frame() const { return config_.frame; }
Expand Down
4 changes: 2 additions & 2 deletions openvpn/client/cliconnect.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@
// The top level object in an OpenVPN client connection.
// 2. class ClientProto::Session<ClientCryptoAPI, ClientSSLAPI> --
// The OpenVPN client protocol object.
// 3. ProtoContext<CRYPTO_API, SSL_API> --
// 3. ProtoContext<CRYPTO_API> --
// The core OpenVPN protocol implementation that is common to both
// client and server.
// 4. ProtoStackBase<SSLContext, Packet> --
// 4. ProtoStackBase<Packet> --
// The lowest-level class that implements the basic functionality of
// tunneling a protocol over a reliable or unreliable transport
// layer, but isn't specific to OpenVPN per-se.
Expand Down
4 changes: 2 additions & 2 deletions openvpn/client/cliopt.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ namespace openvpn {
public:
typedef boost::intrusive_ptr<ClientOptions> Ptr;

typedef ClientProto::Session<SSLLib::CryptoAPI, SSLLib::SSLAPI> Client;
typedef ClientProto::Session<SSLLib::CryptoAPI> Client;

struct Config {
Config()
Expand Down Expand Up @@ -171,7 +171,7 @@ namespace openvpn {
cp.reset(new Client::ProtoConfig());
cp->load(opt, *proto_context_options, config.default_key_direction);
cp->set_xmit_creds(!autologin || pcc.hasEmbeddedPassword());
cp->ssl_ctx.reset(new SSLLib::SSLAPI(cc));
cp->ssl_factory.reset(new SSLLib::SSLAPI(cc));
cp->cc_factory.reset(new CryptoContextCHMFactory<SSLLib::CryptoAPI>());
cp->gui_version = config.gui_version;
cp->frame = frame;
Expand Down
10 changes: 5 additions & 5 deletions openvpn/client/cliproto.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

// This is a middle-layer object in the OpenVPN client protocol stack.
// It is above the general OpenVPN protocol implementation in
// ProtoContext<CRYPTO_API, SSL_API> but below the top
// ProtoContext<CRYPTO_API> but below the top
// level object in a client connect (ClientConnect). See ClientConnect for
// a fuller description of the full client stack.
//
Expand All @@ -33,7 +33,7 @@
// 1. handles creation of transport-layer handler via TransportClientFactory
// 2. handles creation of tun-layer handler via TunClientFactory
// 3. handles sending PUSH_REQUEST to server and processing reply of server-pushed options
// 4. manages the underlying OpenVPN protocol object (ProtoContext<CRYPTO_API, SSL_API>)
// 4. manages the underlying OpenVPN protocol object (ProtoContext<CRYPTO_API>)
// 5. handles timers on behalf of the underlying OpenVPN protocol object
// 6. acts as an exception dispatcher for errors occuring in any of the underlying layers

Expand Down Expand Up @@ -74,13 +74,13 @@ namespace openvpn {
virtual void client_proto_connected() {}
};

template <typename CRYPTO_API, typename SSL_API>
class Session : ProtoContext<CRYPTO_API, SSL_API>,
template <typename CRYPTO_API>
class Session : ProtoContext<CRYPTO_API>,
TransportClientParent,
TunClientParent,
public RC<thread_unsafe_refcount>
{
typedef ProtoContext<CRYPTO_API, SSL_API> Base;
typedef ProtoContext<CRYPTO_API> Base;
typedef typename Base::PacketType PacketType;

using Base::now;
Expand Down
41 changes: 28 additions & 13 deletions openvpn/openssl/ssl/sslctx.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@

#include <openvpn/common/types.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/rc.hpp>
#include <openvpn/common/mode.hpp>
#include <openvpn/common/options.hpp>
#include <openvpn/common/scoped_ptr.hpp>
Expand All @@ -49,6 +48,7 @@
#include <openvpn/ssl/tlsver.hpp>
#include <openvpn/ssl/tls_remote.hpp>
#include <openvpn/ssl/sslconsts.hpp>
#include <openvpn/ssl/sslapi.hpp>
#include <openvpn/openssl/util/error.hpp>
#include <openvpn/openssl/pki/x509.hpp>
#include <openvpn/openssl/pki/crl.hpp>
Expand All @@ -68,7 +68,7 @@ namespace openvpn {

// Represents an SSL configuration that can be used
// to instantiate actual SSL sessions.
class OpenSSLContext : public RC<thread_unsafe_refcount>
class OpenSSLContext : public SSLFactoryAPI
{
public:
OPENVPN_EXCEPTION(ssl_context_error);
Expand Down Expand Up @@ -221,19 +221,19 @@ namespace openvpn {

// Represents an actual SSL session.
// Normally instantiated by OpenSSLContext::ssl().
class SSL : public RC<thread_unsafe_refcount>
class SSL : public SSLAPI
{
friend class OpenSSLContext;

public:
typedef boost::intrusive_ptr<SSL> Ptr;

void start_handshake()
virtual void start_handshake()
{
SSL_do_handshake(ssl);
}

ssize_t write_cleartext_unbuffered(const void *data, const size_t size)
virtual ssize_t write_cleartext_unbuffered(const void *data, const size_t size)
{
const int status = BIO_write(ssl_bio, data, size);
if (status < 0)
Expand All @@ -247,7 +247,7 @@ namespace openvpn {
return status;
}

ssize_t read_cleartext(void *data, const size_t capacity)
virtual ssize_t read_cleartext(void *data, const size_t capacity)
{
if (!overflow)
{
Expand All @@ -266,12 +266,13 @@ namespace openvpn {
throw ssl_ciphertext_in_overflow();
}

bool read_cleartext_ready() const {
virtual bool read_cleartext_ready() const
{
// fixme: need to detect data buffered at SSL layer
return !bmq_stream::memq_from_bio(ct_in)->empty();
}

void write_ciphertext(const BufferPtr& buf)
virtual void write_ciphertext(const BufferPtr& buf)
{
bmq_stream::MemQ* in = bmq_stream::memq_from_bio(ct_in);
if (in->size() < MAX_CIPHERTEXT_IN)
Expand All @@ -280,16 +281,17 @@ namespace openvpn {
overflow = true;
}

bool read_ciphertext_ready() const {
virtual bool read_ciphertext_ready() const
{
return !bmq_stream::memq_from_bio(ct_out)->empty();
}

BufferPtr read_ciphertext()
virtual BufferPtr read_ciphertext()
{
return bmq_stream::memq_from_bio(ct_out)->read_buf();
}

std::string ssl_handshake_details() const
virtual std::string ssl_handshake_details() const
{
return ssl_handshake_details(ssl);
}
Expand Down Expand Up @@ -680,7 +682,17 @@ namespace openvpn {
}
}

SSL::Ptr ssl() const { return SSL::Ptr(new SSL(*this)); }
// create a new SSL instance
virtual SSLAPI::Ptr ssl()
{
return SSL::Ptr(new SSL(*this));
}

// like ssl() above but verify hostname against cert CommonName and/or SubjectAltName
virtual SSLAPI::Ptr ssl(const std::string& hostname)
{
throw OpenSSLException("OpenSSLContext: ssl session with CommonName and/or SubjectAltName verification not implemented");
}

void update_trust(const CertCRLList& cc)
{
Expand All @@ -693,7 +705,10 @@ namespace openvpn {
erase();
}

const Mode& mode() const { return config.mode; }
virtual const Mode& mode() const
{
return config.mode;
}

private:
// ns-cert-type verification
Expand Down
Loading

0 comments on commit 12e3f20

Please sign in to comment.