0
0
mirror of https://github.com/OpenVPN/openvpn3.git synced 2024-09-20 04:02:15 +02:00

PolarSSL support fully implemented (except for External PKI).

This commit is contained in:
James Yonan 2012-03-14 00:51:40 +00:00
parent 801bfae881
commit 1b0088ab2e
17 changed files with 1235 additions and 466 deletions

21
javacli/build-linux-polar Executable file
View File

@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -e
swig -c++ -java -I$OVPN3_DIR ovpncli.i
javac *.java
# -flto=4 -Wl,--no-as-needed \
gcc -O3 -fPIC -pthread \
-fno-strict-aliasing \
-Wall -Wno-sign-compare -Wno-unused-parameter \
-fwhole-program "-DSWIGEXPORT=__attribute__((externally_visible))" \
-DUSE_POLARSSL \
-I$OVPN3_DIR \
-I$BOOST_DIR \
-I$POLARSSL_DIR/include \
-I/usr/lib/jvm/java-7-openjdk-amd64/include \
-L$BOOST_DIR/stage/lib \
-L$POLARSSL_DIR/library \
ovpncli_wrap.cxx \
-o libovpncli.so \
-shared -Wl,-soname,libovpncli.so \
-lpolarssl \
-lboost_system -lboost_thread

View File

@ -91,6 +91,8 @@ namespace openvpn {
class SSL : public RC<thread_unsafe_refcount>
{
public:
typedef boost::intrusive_ptr<SSL> Ptr;
enum {
SHOULD_RETRY = -1
};
@ -211,7 +213,7 @@ namespace openvpn {
std::string ssl_handshake_details() const // fixme -- code me
{
return "[not implemented]";
return "[AppleSSL not implemented]";
}
~SSL()
@ -267,8 +269,6 @@ namespace openvpn {
bool overflow;
};
typedef boost::intrusive_ptr<SSL> SSLPtr;
explicit AppleSSLContext(const Config& config)
: config_(config)
{
@ -276,7 +276,7 @@ namespace openvpn {
OPENVPN_THROW(ssl_context_error, "AppleSSLContext: identity undefined");
}
SSLPtr ssl() const { return SSLPtr(new SSL(*this)); }
SSL::Ptr ssl() const { return SSL::Ptr(new SSL(*this)); }
const Mode& mode() const { return config_.mode; }
Config::Flags flags() const { return config_.flags; }

View File

@ -38,7 +38,7 @@
#ifdef USE_POLARSSL
#include <openvpn/polarssl/crypto/api.hpp>
//#include <openvpn/polarssl/ssl/sslctx.hpp> // fixme
#include <openvpn/polarssl/ssl/sslctx.hpp>
#include <openvpn/polarssl/util/rand.hpp>
#endif
@ -53,7 +53,7 @@ namespace openvpn {
#if defined(USE_POLARSSL)
typedef PolarSSLCryptoAPI ClientCryptoAPI;
typedef OpenSSLContext ClientSSLAPI; // fixme
typedef PolarSSLContext ClientSSLAPI;
typedef PolarSSLRandom RandomAPI;
#elif defined(USE_APPLE_SSL)
typedef AppleSSLCryptoAPI ClientCryptoAPI;
@ -117,6 +117,9 @@ namespace openvpn {
cc.frame = frame;
#ifdef OPENVPN_SSL_DEBUG
cc.enable_debug();
#endif
#if defined(USE_POLARSSL)
cc.rng = rng;
#endif
cc.load(opt);
if (!cc.mode.is_client())

View File

@ -13,124 +13,125 @@
#include <openvpn/openssl/util/error.hpp>
namespace openvpn {
namespace OpenSSLPKI {
class CRL : public RC<thread_unsafe_refcount>
{
public:
CRL() : crl_(NULL) {}
explicit CRL(const std::string& crl_txt)
: crl_(NULL)
class CRL : public RC<thread_unsafe_refcount>
{
parse_pem(crl_txt);
}
public:
CRL() : crl_(NULL) {}
CRL(const CRL& other)
: crl_(NULL)
{
assign(other.crl_);
}
explicit CRL(const std::string& crl_txt)
: crl_(NULL)
{
parse_pem(crl_txt);
}
void operator=(const CRL& other)
{
assign(other.crl_);
}
CRL(const CRL& other)
: crl_(NULL)
{
assign(other.crl_);
}
bool defined() const { return crl_ != NULL; }
X509_CRL* obj() const { return crl_; }
void operator=(const CRL& other)
{
assign(other.crl_);
}
void parse_pem(const std::string& crl_txt)
{
BIO *bio = BIO_new_mem_buf(const_cast<char *>(crl_txt.c_str()), crl_txt.length());
if (!bio)
throw OpenSSLException();
bool defined() const { return crl_ != NULL; }
X509_CRL* obj() const { return crl_; }
X509_CRL *crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!crl)
throw OpenSSLException("CRL::parse_pem");
void parse_pem(const std::string& crl_txt)
{
BIO *bio = BIO_new_mem_buf(const_cast<char *>(crl_txt.c_str()), crl_txt.length());
if (!bio)
throw OpenSSLException();
erase();
crl_ = crl;
}
X509_CRL *crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!crl)
throw OpenSSLException("CRL::parse_pem");
std::string render_pem() const
{
if (crl_)
{
BIO *bio = BIO_new(BIO_s_mem());
const int ret = PEM_write_bio_X509_CRL(bio, crl_);
if (ret == 0)
{
BIO_free(bio);
throw OpenSSLException("CRL::render_pem");
}
erase();
crl_ = crl;
}
std::string render_pem() const
{
if (crl_)
{
char *temp;
const int buf_len = BIO_get_mem_data(bio, &temp);
std::string ret = std::string(temp, buf_len);
BIO_free(bio);
return ret;
BIO *bio = BIO_new(BIO_s_mem());
const int ret = PEM_write_bio_X509_CRL(bio, crl_);
if (ret == 0)
{
BIO_free(bio);
throw OpenSSLException("CRL::render_pem");
}
{
char *temp;
const int buf_len = BIO_get_mem_data(bio, &temp);
std::string ret = std::string(temp, buf_len);
BIO_free(bio);
return ret;
}
}
}
else
return "";
}
else
return "";
}
void erase()
void erase()
{
if (crl_)
{
X509_CRL_free(crl_);
crl_ = NULL;
}
}
~CRL()
{
erase();
}
private:
static X509_CRL *dup(const X509_CRL *crl)
{
if (crl)
{
return X509_CRL_dup(const_cast<X509_CRL *>(crl));
}
else
return NULL;
}
void assign(const X509_CRL *crl)
{
erase();
crl_ = dup(crl);
}
X509_CRL *crl_;
};
typedef boost::intrusive_ptr<CRL> CRLPtr;
class CRLList : public std::vector<CRLPtr>
{
if (crl_)
{
X509_CRL_free(crl_);
crl_ = NULL;
}
}
public:
typedef CRL Item;
typedef CRLPtr ItemPtr;
~CRL()
{
erase();
}
private:
static X509_CRL *dup(const X509_CRL *crl)
{
if (crl)
{
return X509_CRL_dup(const_cast<X509_CRL *>(crl));
}
else
return NULL;
}
void assign(const X509_CRL *crl)
{
erase();
crl_ = dup(crl);
}
X509_CRL *crl_;
};
typedef boost::intrusive_ptr<CRL> CRLPtr;
class CRLList : public std::vector<CRLPtr>
{
public:
typedef CRL Item;
typedef CRLPtr ItemPtr;
bool defined() const { return !empty(); }
std::string render_pem() const
{
std::string ret;
for (const_iterator i = begin(); i != end(); i++)
ret += (*i)->render_pem();
return ret;
}
};
bool defined() const { return !empty(); }
std::string render_pem() const
{
std::string ret;
for (const_iterator i = begin(); i != end(); i++)
ret += (*i)->render_pem();
return ret;
}
};
}
} // namespace openvpn
#endif // OPENVPN_OPENSSL_PKI_CRL_H

View File

@ -17,107 +17,108 @@
#endif
namespace openvpn {
namespace OpenSSLPKI {
namespace DH_private {
// defined outside of DH class to avoid symbol collision in way
// that DHparams_dup macro is defined
inline ::DH *dup(const ::DH *dh)
{
if (dh)
return DHparams_dup(const_cast< ::DH * >(dh));
else
return NULL;
}
}
class DH
{
public:
DH() : dh_(NULL) {}
explicit DH(const std::string& dh_txt)
: dh_(NULL)
{
parse_pem(dh_txt);
namespace DH_private {
// defined outside of DH class to avoid symbol collision in way
// that DHparams_dup macro is defined
inline ::DH *dup(const ::DH *dh)
{
if (dh)
return DHparams_dup(const_cast< ::DH * >(dh));
else
return NULL;
}
}
DH(const DH& other)
: dh_(NULL)
class DH
{
assign(other.dh_);
}
public:
DH() : dh_(NULL) {}
void operator=(const DH& other)
{
assign(other.dh_);
}
explicit DH(const std::string& dh_txt)
: dh_(NULL)
{
parse_pem(dh_txt);
}
bool defined() const { return dh_ != NULL; }
::DH* obj() const { return dh_; }
DH(const DH& other)
: dh_(NULL)
{
assign(other.dh_);
}
void parse_pem(const std::string& dh_txt)
{
BIO *bio = BIO_new_mem_buf(const_cast<char *>(dh_txt.c_str()), dh_txt.length());
if (!bio)
throw OpenSSLException();
void operator=(const DH& other)
{
assign(other.dh_);
}
::DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!dh)
throw OpenSSLException("DH::parse_pem");
bool defined() const { return dh_ != NULL; }
::DH* obj() const { return dh_; }
erase();
dh_ = dh;
}
void parse_pem(const std::string& dh_txt)
{
BIO *bio = BIO_new_mem_buf(const_cast<char *>(dh_txt.c_str()), dh_txt.length());
if (!bio)
throw OpenSSLException();
std::string render_pem() const
{
if (dh_)
{
BIO *bio = BIO_new(BIO_s_mem());
const int ret = PEM_write_bio_DHparams(bio, dh_);
if (ret == 0)
{
BIO_free(bio);
throw OpenSSLException("DH::render_pem");
}
::DH *dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!dh)
throw OpenSSLException("DH::parse_pem");
erase();
dh_ = dh;
}
std::string render_pem() const
{
if (dh_)
{
char *temp;
const int buf_len = BIO_get_mem_data(bio, &temp);
std::string ret = std::string(temp, buf_len);
BIO_free(bio);
return ret;
BIO *bio = BIO_new(BIO_s_mem());
const int ret = PEM_write_bio_DHparams(bio, dh_);
if (ret == 0)
{
BIO_free(bio);
throw OpenSSLException("DH::render_pem");
}
{
char *temp;
const int buf_len = BIO_get_mem_data(bio, &temp);
std::string ret = std::string(temp, buf_len);
BIO_free(bio);
return ret;
}
}
}
else
return "";
}
else
return "";
}
void erase()
{
if (dh_)
{
DH_free(dh_);
dh_ = NULL;
}
}
void erase()
{
if (dh_)
{
DH_free(dh_);
dh_ = NULL;
}
}
~DH()
{
erase();
}
~DH()
{
erase();
}
private:
void assign(const ::DH *dh)
{
erase();
dh_ = DH_private::dup(dh);
}
::DH *dh_;
};
private:
void assign(const ::DH *dh)
{
erase();
dh_ = DH_private::dup(dh);
}
::DH *dh_;
};
}
} // namespace openvpn
#endif // OPENVPN_OPENSSL_PKI_DH_H

View File

@ -11,112 +11,113 @@
#include <openvpn/openssl/util/error.hpp>
namespace openvpn {
namespace OpenSSLPKI {
class PKey
{
public:
PKey() : pkey_(NULL) {}
PKey(const std::string& pkey_txt, const std::string& title)
: pkey_(NULL)
class PKey
{
parse_pem(pkey_txt, title);
}
public:
PKey() : pkey_(NULL) {}
PKey(const PKey& other)
: pkey_(NULL)
{
assign(other.pkey_);
}
PKey(const std::string& pkey_txt, const std::string& title)
: pkey_(NULL)
{
parse_pem(pkey_txt, title);
}
void operator=(const PKey& other)
{
assign(other.pkey_);
}
PKey(const PKey& other)
: pkey_(NULL)
{
assign(other.pkey_);
}
bool defined() const { return pkey_ != NULL; }
EVP_PKEY* obj() const { return pkey_; }
void operator=(const PKey& other)
{
assign(other.pkey_);
}
void parse_pem(const std::string& pkey_txt, const std::string& title)
{
BIO *bio = BIO_new_mem_buf(const_cast<char *>(pkey_txt.c_str()), pkey_txt.length());
if (!bio)
throw OpenSSLException();
bool defined() const { return pkey_ != NULL; }
EVP_PKEY* obj() const { return pkey_; }
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!pkey)
throw OpenSSLException(std::string("PKey::parse_pem: error in ") + title + std::string(":"));
void parse_pem(const std::string& pkey_txt, const std::string& title)
{
BIO *bio = BIO_new_mem_buf(const_cast<char *>(pkey_txt.c_str()), pkey_txt.length());
if (!bio)
throw OpenSSLException();
erase();
pkey_ = pkey;
}
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!pkey)
throw OpenSSLException(std::string("PKey::parse_pem: error in ") + title + std::string(":"));
std::string render_pem() const
{
if (pkey_)
{
BIO *bio = BIO_new(BIO_s_mem());
const int ret = PEM_write_bio_PrivateKey(bio, pkey_, NULL, NULL, 0, NULL, NULL);
if (ret == 0)
{
BIO_free(bio);
throw OpenSSLException("PKey::render_pem");
}
erase();
pkey_ = pkey;
}
std::string render_pem() const
{
if (pkey_)
{
char *temp;
const int buf_len = BIO_get_mem_data(bio, &temp);
std::string ret = std::string(temp, buf_len);
BIO_free(bio);
return ret;
BIO *bio = BIO_new(BIO_s_mem());
const int ret = PEM_write_bio_PrivateKey(bio, pkey_, NULL, NULL, 0, NULL, NULL);
if (ret == 0)
{
BIO_free(bio);
throw OpenSSLException("PKey::render_pem");
}
{
char *temp;
const int buf_len = BIO_get_mem_data(bio, &temp);
std::string ret = std::string(temp, buf_len);
BIO_free(bio);
return ret;
}
}
}
else
return "";
}
else
return "";
}
void erase()
{
if (pkey_)
{
EVP_PKEY_free(pkey_);
pkey_ = NULL;
}
}
void erase()
{
if (pkey_)
{
EVP_PKEY_free(pkey_);
pkey_ = NULL;
}
}
~PKey()
{
erase();
}
~PKey()
{
erase();
}
private:
static EVP_PKEY *dup(const EVP_PKEY *pkey)
{
// No OpenSSL EVP_PKEY_dup method so we roll our own
if (pkey)
{
EVP_PKEY* pDupKey = EVP_PKEY_new();
RSA* pRSA = EVP_PKEY_get1_RSA(const_cast<EVP_PKEY *>(pkey));
RSA* pRSADupKey = RSAPrivateKey_dup(pRSA);
RSA_free(pRSA);
EVP_PKEY_set1_RSA(pDupKey, pRSADupKey);
RSA_free(pRSADupKey);
return pDupKey;
}
else
return NULL;
}
private:
static EVP_PKEY *dup(const EVP_PKEY *pkey)
{
// No OpenSSL EVP_PKEY_dup method so we roll our own
if (pkey)
{
EVP_PKEY* pDupKey = EVP_PKEY_new();
RSA* pRSA = EVP_PKEY_get1_RSA(const_cast<EVP_PKEY *>(pkey));
RSA* pRSADupKey = RSAPrivateKey_dup(pRSA);
RSA_free(pRSA);
EVP_PKEY_set1_RSA(pDupKey, pRSADupKey);
RSA_free(pRSADupKey);
return pDupKey;
}
else
return NULL;
}
void assign(const EVP_PKEY *pkey)
{
erase();
pkey_ = dup(pkey);
}
EVP_PKEY *pkey_;
};
void assign(const EVP_PKEY *pkey)
{
erase();
pkey_ = dup(pkey);
}
EVP_PKEY *pkey_;
};
}
} // namespace openvpn
#endif // OPENVPN_OPENSSL_PKI_PKEY_H

View File

@ -13,130 +13,131 @@
#include <openvpn/openssl/util/error.hpp>
namespace openvpn {
namespace OpenSSLPKI {
class X509Base
{
public:
X509Base() : x509_(NULL) {}
explicit X509Base(::X509 *x509) : x509_(x509) {}
bool defined() const { return x509_ != NULL; }
::X509* obj() const { return x509_; }
::X509* obj_dup() const { return dup(x509_); }
std::string render_pem() const
class X509Base
{
if (x509_)
{
BIO *bio = BIO_new(BIO_s_mem());
const int ret = PEM_write_bio_X509(bio, x509_);
if (ret == 0)
{
BIO_free(bio);
throw OpenSSLException("X509::render_pem");
}
public:
X509Base() : x509_(NULL) {}
explicit X509Base(::X509 *x509) : x509_(x509) {}
bool defined() const { return x509_ != NULL; }
::X509* obj() const { return x509_; }
::X509* obj_dup() const { return dup(x509_); }
std::string render_pem() const
{
if (x509_)
{
char *temp;
const int buf_len = BIO_get_mem_data(bio, &temp);
std::string ret = std::string(temp, buf_len);
BIO_free(bio);
return ret;
BIO *bio = BIO_new(BIO_s_mem());
const int ret = PEM_write_bio_X509(bio, x509_);
if (ret == 0)
{
BIO_free(bio);
throw OpenSSLException("X509::render_pem");
}
{
char *temp;
const int buf_len = BIO_get_mem_data(bio, &temp);
std::string ret = std::string(temp, buf_len);
BIO_free(bio);
return ret;
}
}
}
else
return "";
}
else
return "";
}
private:
static ::X509 *dup(const ::X509 *x509)
private:
static ::X509 *dup(const ::X509 *x509)
{
if (x509)
return X509_dup(const_cast< ::X509 * >(x509));
else
return NULL;
}
friend class X509;
::X509 *x509_;
};
class X509 : public X509Base, public RC<thread_unsafe_refcount>
{
if (x509)
return X509_dup(const_cast< ::X509 * >(x509));
else
return NULL;
}
public:
X509() {}
friend class X509;
::X509 *x509_;
};
X509(const std::string& cert_txt, const std::string& title)
{
parse_pem(cert_txt, title);
}
class X509 : public X509Base, public RC<thread_unsafe_refcount>
{
public:
X509() {}
X509(const X509& other)
{
assign(other.x509_);
}
X509(const std::string& cert_txt, const std::string& title)
void operator=(const X509& other)
{
assign(other.x509_);
}
void parse_pem(const std::string& cert_txt, const std::string& title)
{
BIO *bio = BIO_new_mem_buf(const_cast<char *>(cert_txt.c_str()), cert_txt.length());
if (!bio)
throw OpenSSLException();
::X509 *cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!cert)
throw OpenSSLException(std::string("X509::parse_pem: error in ") + title + std::string(":"));
erase();
x509_ = cert;
}
void erase()
{
if (x509_)
{
X509_free(x509_);
x509_ = NULL;
}
}
~X509()
{
erase();
}
private:
void assign(const ::X509 *x509)
{
erase();
x509_ = dup(x509);
}
};
typedef boost::intrusive_ptr<X509> X509Ptr;
class X509List : public std::vector<X509Ptr>
{
parse_pem(cert_txt, title);
}
public:
typedef X509 Item;
typedef X509Ptr ItemPtr;
X509(const X509& other)
{
assign(other.x509_);
}
void operator=(const X509& other)
{
assign(other.x509_);
}
void parse_pem(const std::string& cert_txt, const std::string& title)
{
BIO *bio = BIO_new_mem_buf(const_cast<char *>(cert_txt.c_str()), cert_txt.length());
if (!bio)
throw OpenSSLException();
::X509 *cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
BIO_free(bio);
if (!cert)
throw OpenSSLException(std::string("X509::parse_pem: error in ") + title + std::string(":"));
erase();
x509_ = cert;
}
void erase()
{
if (x509_)
{
X509_free(x509_);
x509_ = NULL;
}
}
~X509()
{
erase();
}
private:
void assign(const ::X509 *x509)
{
erase();
x509_ = dup(x509);
}
};
typedef boost::intrusive_ptr<X509> X509Ptr;
class X509List : public std::vector<X509Ptr>
{
public:
typedef X509 Item;
typedef X509Ptr ItemPtr;
bool defined() const { return !empty(); }
std::string render_pem() const
{
std::string ret;
for (const_iterator i = begin(); i != end(); i++)
ret += (*i)->render_pem();
return ret;
}
};
bool defined() const { return !empty(); }
std::string render_pem() const
{
std::string ret;
for (const_iterator i = begin(); i != end(); i++)
ret += (*i)->render_pem();
return ret;
}
};
}
} // namespace openvpn
#endif // OPENVPN_OPENSSL_PKI_X509_H

View File

@ -10,71 +10,72 @@
#include <openvpn/openssl/pki/crl.hpp>
namespace openvpn {
namespace OpenSSLPKI {
class X509Store : public RC<thread_unsafe_refcount>
{
public:
OPENVPN_SIMPLE_EXCEPTION(x509_store_init_error);
OPENVPN_SIMPLE_EXCEPTION(x509_store_add_cert_error);
OPENVPN_SIMPLE_EXCEPTION(x509_store_add_crl_error);
typedef CertCRLListTemplate<X509List, CRLList> CertCRLList;
X509Store() : x509_store_(NULL) {}
explicit X509Store(const CertCRLList& cc)
class X509Store : public RC<thread_unsafe_refcount>
{
init();
public:
OPENVPN_SIMPLE_EXCEPTION(x509_store_init_error);
OPENVPN_SIMPLE_EXCEPTION(x509_store_add_cert_error);
OPENVPN_SIMPLE_EXCEPTION(x509_store_add_crl_error);
// Load cert list
typedef CertCRLListTemplate<X509List, CRLList> CertCRLList;
X509Store() : x509_store_(NULL) {}
explicit X509Store(const CertCRLList& cc)
{
for (X509List::const_iterator i = cc.certs.begin(); i != cc.certs.end(); i++)
{
if (!X509_STORE_add_cert(x509_store_, (*i)->obj()))
throw x509_store_add_cert_error();
}
init();
// Load cert list
{
for (X509List::const_iterator i = cc.certs.begin(); i != cc.certs.end(); i++)
{
if (!X509_STORE_add_cert(x509_store_, (*i)->obj()))
throw x509_store_add_cert_error();
}
}
// Load CRL list
{
if (cc.crls.defined())
{
X509_STORE_set_flags(x509_store_, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
for (CRLList::const_iterator i = cc.crls.begin(); i != cc.crls.end(); i++)
{
if (!X509_STORE_add_crl(x509_store_, (*i)->obj()))
throw x509_store_add_crl_error();
}
}
}
}
// Load CRL list
X509_STORE* obj() const { return x509_store_; }
X509_STORE* move()
{
if (cc.crls.defined())
{
X509_STORE_set_flags(x509_store_, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
for (CRLList::const_iterator i = cc.crls.begin(); i != cc.crls.end(); i++)
{
if (!X509_STORE_add_crl(x509_store_, (*i)->obj()))
throw x509_store_add_crl_error();
}
}
X509_STORE* ret = x509_store_;
x509_store_ = NULL;
return ret;
}
}
X509_STORE* obj() const { return x509_store_; }
~X509Store()
{
if (x509_store_)
X509_STORE_free(x509_store_);
}
X509_STORE* move()
{
X509_STORE* ret = x509_store_;
x509_store_ = NULL;
return ret;
}
~X509Store()
{
if (x509_store_)
X509_STORE_free(x509_store_);
}
private:
void init()
{
x509_store_ = X509_STORE_new();
if (!x509_store_)
throw x509_store_init_error();
}
X509_STORE* x509_store_;
};
private:
void init()
{
x509_store_ = X509_STORE_new();
if (!x509_store_)
throw x509_store_init_error();
}
X509_STORE* x509_store_;
};
}
} // namespace openvpn
#endif // OPENVPN_OPENSSL_PKI_X509STORE_H

View File

@ -1,6 +1,7 @@
#ifndef OPENVPN_OPENSSL_SSL_SSLCTX_H
#define OPENVPN_OPENSSL_SSL_SSLCTX_H
#include <string>
#include <cstring>
#include <sstream>
@ -44,7 +45,7 @@ namespace openvpn {
OPENVPN_EXCEPTION(ssl_ciphertext_in_overflow);
typedef boost::intrusive_ptr<OpenSSLContext> Ptr;
typedef CertCRLListTemplate<X509List, CRLList> CertCRLList;
typedef CertCRLListTemplate<OpenSSLPKI::X509List, OpenSSLPKI::CRLList> CertCRLList;
enum {
MAX_CIPHERTEXT_IN = 64
@ -68,10 +69,10 @@ namespace openvpn {
Mode mode;
CertCRLList ca;
X509 cert;
X509List extra_certs;
PKey pkey;
DH dh; // only needed in server mode
OpenSSLPKI::X509 cert;
OpenSSLPKI::X509List extra_certs;
OpenSSLPKI::PKey pkey;
OpenSSLPKI::DH dh; // only needed in server mode
ExternalPKIBase* external_pki;
Frame::Ptr frame;
Flags flags;
@ -183,6 +184,8 @@ namespace openvpn {
class SSL : public RC<thread_unsafe_refcount>
{
public:
typedef boost::intrusive_ptr<SSL> Ptr;
enum {
SHOULD_RETRY = -1
};
@ -522,8 +525,6 @@ namespace openvpn {
/////// start of main class implementation
typedef boost::intrusive_ptr<SSL> SSLPtr;
explicit OpenSSLContext(const Config& config)
: ctx_(NULL), epki_(NULL)
{
@ -586,7 +587,7 @@ namespace openvpn {
// chain but shouldn't be included in the verify chain.
if (config.extra_certs.defined())
{
for (X509List::const_iterator i = config.extra_certs.begin(); i != config.extra_certs.end(); i++)
for (OpenSSLPKI::X509List::const_iterator i = config.extra_certs.begin(); i != config.extra_certs.end(); i++)
{
if (SSL_CTX_add_extra_chain_cert(ctx_, (*i)->obj_dup()) != 1)
throw OpenSSLException("OpenSSLContext: SSL_CTX_add_extra_chain_cert failed");
@ -620,11 +621,11 @@ namespace openvpn {
}
}
SSLPtr ssl() const { return SSLPtr(new SSL(*this)); }
SSL::Ptr ssl() const { return SSL::Ptr(new SSL(*this)); }
void update_trust(const CertCRLList& cc)
{
X509Store store(cc);
OpenSSLPKI::X509Store store(cc);
SSL_CTX_set_cert_store(ctx_, store.move());
}
@ -710,8 +711,6 @@ namespace openvpn {
ExternalPKIImpl* epki_;
};
typedef OpenSSLContext::Ptr OpenSSLContextPtr;
}
} // namespace openvpn
#endif // OPENVPN_OPENSSL_SSL_SSLCTX_H
#endif

View File

@ -0,0 +1,84 @@
#ifndef OPENVPN_POLARSSL_PKI_RSACTX_H
#define OPENVPN_POLARSSL_PKI_RSACTX_H
#include <string>
#include <sstream>
#include <cstring>
#include <polarssl/x509.h>
#include <openvpn/common/types.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/rc.hpp>
#include <openvpn/polarssl/util/error.hpp>
namespace openvpn {
namespace PolarSSLPKI {
class RSAContext : public RC<thread_unsafe_refcount>
{
public:
typedef boost::intrusive_ptr<RSAContext> Ptr;
RSAContext() : ctx(NULL) {}
RSAContext(const std::string& key_txt, const std::string& title)
: ctx(NULL)
{
try {
parse(key_txt, title);
}
catch (...)
{
dealloc();
throw;
}
}
void parse(const std::string& key_txt, const std::string& title)
{
alloc();
const int status = x509parse_key(ctx,
(const unsigned char *)key_txt.c_str(),
key_txt.length(),
NULL, 0);
if (status < 0)
throw PolarSSLException("error parsing " + title + " private key", status);
}
rsa_context* get() const
{
return ctx;
}
~RSAContext()
{
dealloc();
}
private:
void alloc()
{
if (!ctx)
{
ctx = new rsa_context;
std::memset(ctx, 0, sizeof(rsa_context));
}
}
void dealloc()
{
if (ctx)
{
rsa_free(ctx);
delete ctx;
ctx = NULL;
}
}
rsa_context *ctx;
};
}
}
#endif

View File

@ -0,0 +1,91 @@
#ifndef OPENVPN_POLARSSL_PKI_X509CERT_H
#define OPENVPN_POLARSSL_PKI_X509CERT_H
#include <string>
#include <sstream>
#include <cstring>
#include <polarssl/x509.h>
#include <openvpn/common/types.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/rc.hpp>
#include <openvpn/polarssl/util/error.hpp>
namespace openvpn {
namespace PolarSSLPKI {
class X509Cert : public RC<thread_unsafe_refcount>
{
public:
typedef boost::intrusive_ptr<X509Cert> Ptr;
X509Cert() : chain(NULL) {}
X509Cert(const std::string& cert_txt, const std::string& title)
: chain(NULL)
{
try {
parse(cert_txt, title);
}
catch (...)
{
dealloc();
throw;
}
}
void parse(const std::string& cert_txt, const std::string& title)
{
alloc();
const int status = x509parse_crt(chain,
(const unsigned char *)cert_txt.c_str(),
cert_txt.length());
if (status < 0)
{
throw PolarSSLException("error parsing " + title + " certificate", status);
}
if (status > 0)
{
std::ostringstream os;
os << status << " certificate(s) in " << title << " bundle failed to parse";
throw PolarSSLException(os.str());
}
}
x509_cert* get() const
{
return chain;
}
~X509Cert()
{
dealloc();
}
private:
void alloc()
{
if (!chain)
{
chain = new x509_cert;
std::memset(chain, 0, sizeof(x509_cert));
}
}
void dealloc()
{
if (chain)
{
x509_free(chain);
delete chain;
chain = NULL;
}
}
x509_cert *chain;
};
}
}
#endif

View File

@ -0,0 +1,491 @@
#ifndef OPENVPN_POLARSSL_SSL_SSLCTX_H
#define OPENVPN_POLARSSL_SSL_SSLCTX_H
#include <string>
#include <cstring>
#include <sstream>
#include <polarssl/ssl.h>
#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>
#include <openvpn/common/base64.hpp>
#include <openvpn/frame/frame.hpp>
#include <openvpn/frame/memq_stream.hpp>
#include <openvpn/buffer/buffer.hpp>
#include <openvpn/pki/cclist.hpp>
#include <openvpn/pki/epkibase.hpp>
#include <openvpn/polarssl/pki/x509cert.hpp>
#include <openvpn/polarssl/pki/rsactx.hpp>
#include <openvpn/polarssl/util/rand.hpp>
#include <openvpn/polarssl/util/error.hpp>
// An SSL Context is essentially a configuration that can be used
// to generate an arbitrary number of actual SSL connections objects.
// PolarSSLContext is an SSL Context implementation that uses the
// PolarSSL library as a backend.
namespace openvpn {
namespace polarssl_ctx_private {
static const int default_ciphersuites[] = // CONST GLOBAL
{
SSL_EDH_RSA_AES_256_SHA,
SSL_EDH_RSA_AES_128_SHA,
0
};
};
// Represents an SSL configuration that can be used
// to instantiate actual SSL sessions.
class PolarSSLContext : public RC<thread_unsafe_refcount>
{
public:
typedef boost::intrusive_ptr<PolarSSLContext> Ptr;
OPENVPN_SIMPLE_EXCEPTION(ssl_ciphertext_in_overflow);
enum {
MAX_CIPHERTEXT_IN = 64
};
// The data needed to construct a PolarSSLContext.
struct Config
{
enum {
DEBUG = 1<<0,
};
typedef unsigned int Flags;
enum CertType {
CERT_TYPE_NONE,
CERT_TYPE_NS_CLIENT,
CERT_TYPE_NS_SERVER
};
Config() : external_pki(NULL),
flags(0),
cert_type(CERT_TYPE_NONE) {}
Mode mode;
PolarSSLPKI::X509Cert::Ptr crt_chain; // local cert chain (including client cert + extra certs)
PolarSSLPKI::X509Cert::Ptr ca_chain; // CA chain for remote verification
PolarSSLPKI::RSAContext::Ptr priv_key; // private key
ExternalPKIBase* external_pki;
Frame::Ptr frame;
Flags flags;
CertType cert_type;
PolarSSLRandom::Ptr rng; // random data source
void enable_debug()
{
flags |= DEBUG;
}
// if this callback is defined, no private key needs to be loaded
void set_external_pki_callback(ExternalPKIBase* external_pki_arg)
{
external_pki = external_pki_arg;
}
void load_ca(const std::string& ca_txt)
{
PolarSSLPKI::X509Cert::Ptr c = new PolarSSLPKI::X509Cert();
c->parse(ca_txt, "ca");
ca_chain = c;
}
void load_cert(const std::string& cert_txt)
{
PolarSSLPKI::X509Cert::Ptr c = new PolarSSLPKI::X509Cert();
c->parse(cert_txt, "cert");
crt_chain = c;
}
void load_cert(const std::string& cert_txt, const std::string& extra_certs_txt)
{
PolarSSLPKI::X509Cert::Ptr c = new PolarSSLPKI::X509Cert();
c->parse(cert_txt, "cert");
if (!extra_certs_txt.empty())
c->parse(extra_certs_txt, "extra-certs");
crt_chain = c;
}
void load_private_key(const std::string& key_txt)
{
PolarSSLPKI::RSAContext::Ptr p = new PolarSSLPKI::RSAContext();
p->parse(key_txt, "private key");
priv_key = p;
}
#if 0 // fixme -- implement PolarSSL DH
void load_dh(const std::string& dh_txt)
{
}
#endif
void load(const OptionList& opt)
{
// client/server
mode = opt.exists("client") ? Mode(Mode::CLIENT) : Mode(Mode::SERVER);
// ca
{
const std::string& ca_txt = opt.get("ca", 1);
load_ca(ca_txt);
}
// cert/extra-certs
{
const std::string& cert_txt = opt.get("cert", 1);
const std::string& ec_txt = opt.get_optional("extra-certs", 1);
load_cert(cert_txt, ec_txt);
}
// private key
if (!external_pki)
{
const std::string& key_txt = opt.get("key", 1);
load_private_key(key_txt);
}
#if 0 // fixme -- implement PolarSSL DH
// DH
if (mode.is_server())
{
const std::string& dh_txt = opt.get("dh", 1);
load_dh(dh_txt);
}
#endif
// ns-cert-type
{
const Option* o = opt.get_ptr("ns-cert-type");
if (o)
{
const std::string& ct = o->get_optional(1);
if (ct == "server")
cert_type = CERT_TYPE_NS_SERVER;
else if (ct == "client")
cert_type = CERT_TYPE_NS_CLIENT;
else
throw option_error("ns-cert-type must be 'client' or 'server'");
}
}
// unsupported cert type checkers
{
if (opt.get_ptr("remote-cert-tls"))
throw option_error("remote-cert-tls not supported");
if (opt.get_ptr("remote-cert-ku"))
throw option_error("remote-cert-ku not supported");
if (opt.get_ptr("remote-cert-eku"))
throw option_error("remote-cert-eku not supported");
}
}
};
// Represents an actual SSL session.
// Normally instantiated by PolarSSLContext::ssl().
class SSL : public RC<thread_unsafe_refcount>
{
// read/write callback errors
enum {
// assumes that PolarSSL user-defined errors may start at -0x8000
CT_WOULD_BLOCK = -0x8000,
CT_INTERNAL_ERROR = -0x8001
};
public:
typedef boost::intrusive_ptr<SSL> Ptr;
// special return value from read functions -- indicates
// that no cleartext data is available now (until more
// ciphertext is pushed into the SSL engine)
enum {
SHOULD_RETRY = -1
};
SSL(const PolarSSLContext* ctx)
{
clear();
try {
const Config& c = ctx->config;
int status;
// init SSL object
ssl = new ssl_context;
std::memset(ssl, 0, sizeof(ssl));
status = ssl_init(ssl);
if (status < 0)
throw PolarSSLException("error in ssl_init", status);
// set client/server mode
if (c.mode.is_server())
ssl_set_endpoint(ssl, SSL_IS_SERVER);
else if (c.mode.is_client())
ssl_set_endpoint(ssl, SSL_IS_CLIENT);
else
throw PolarSSLException("unknown client/server mode");
// peer must present a valid certificate
ssl_set_authmode(ssl, SSL_VERIFY_REQUIRED);
// set verify callback
ssl_set_verify(ssl, verify_callback, (void *)ctx);
// allocate session object, but don't support SSL-level session resume
sess = new ssl_session;
std::memset(sess, 0, sizeof(sess));
ssl_set_session(ssl, 0, 0, sess);
// set list of allowed ciphersuites
ssl_set_ciphersuites(ssl, (int *)polarssl_ctx_private::default_ciphersuites); // fixme -- fix PolarSSL to not require cast
// set CA chain
if (c.ca_chain)
ssl_set_ca_chain(ssl, c.ca_chain->get(), NULL, NULL);
else
throw PolarSSLException("CA chain not defined");
// set our own certificate, supporting chain (i.e. extra-certs), and private key
if (c.crt_chain && c.priv_key)
ssl_set_own_cert(ssl, c.crt_chain->get(), c.priv_key->get());
else
throw PolarSSLException("cert and/or private key is undefined");
// fixme -- set pkcs11
// fixme -- set DH
// configure ciphertext buffers
ct_in.set_frame(c.frame);
ct_out.set_frame(c.frame);
// set BIO
ssl_set_bio(ssl, ct_read_func, this, ct_write_func, this);
// set RNG
if (c.rng)
{
rng = c.rng;
ssl_set_rng(ssl, rng_callback, this);
}
else
throw PolarSSLException("RNG not defined");
}
catch (...)
{
erase();
throw;
}
}
void start_handshake()
{
ssl_handshake(ssl);
}
ssize_t write_cleartext_unbuffered(const void *data, const size_t size)
{
const int status = ssl_write(ssl, (const unsigned char*)data, size);
if (status < 0)
{
if (status == CT_WOULD_BLOCK)
return SHOULD_RETRY;
else if (status == CT_INTERNAL_ERROR)
throw PolarSSLException("SSL write: internal error");
else
throw PolarSSLException("SSL write error", status);
}
else
return status;
}
ssize_t read_cleartext(void *data, const size_t capacity)
{
if (!overflow)
{
const int status = ssl_read(ssl, (unsigned char*)data, capacity);
if (status < 0)
{
if (status == CT_WOULD_BLOCK)
return SHOULD_RETRY;
else if (status == CT_INTERNAL_ERROR)
throw PolarSSLException("SSL read: internal error");
else
throw PolarSSLException("SSL read error", status);
}
else
return status;
}
else
throw ssl_ciphertext_in_overflow();
}
bool write_ciphertext_ready() const {
return !ct_in.empty();
}
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 {
return !ct_out.empty();
}
BufferPtr read_ciphertext()
{
return ct_out.read_buf();
}
std::string ssl_handshake_details() const
{
return ssl_get_version(ssl) + std::string("/") + ssl_get_ciphersuite(ssl);
}
~SSL()
{
erase();
}
private:
// cleartext read callback
static int ct_read_func(void *arg, unsigned char *data, size_t length)
{
try {
SSL *self = (SSL *)arg;
const size_t actual = self->ct_in.read(data, length);
return actual > 0 ? actual : CT_WOULD_BLOCK;
}
catch (...)
{
return CT_INTERNAL_ERROR;
}
}
// cleartext write callback
static int ct_write_func(void *arg, const unsigned char *data, size_t length)
{
try {
SSL *self = (SSL *)arg;
self->ct_out.write(data, length);
return length;
}
catch (...)
{
return CT_INTERNAL_ERROR;
}
}
// RNG callback -- return random data to PolarSSL
static int rng_callback(void *arg, unsigned char *data, size_t len)
{
SSL *self = (SSL *)arg;
return self->rng->rand_bytes_noexcept(data, len);
}
void clear()
{
ssl = NULL;
sess = NULL;
overflow = false;
}
void erase()
{
if (ssl)
{
ssl_free(ssl);
delete ssl;
}
if (sess)
delete sess;
clear();
}
ssl_context *ssl; // underlying SSL connection object
ssl_session *sess; // SSL session (tied to ssl object above)
PolarSSLRandom::Ptr rng; // random data source
bool overflow;
MemQStream ct_in; // write ciphertext to here
MemQStream ct_out; // read ciphertext from here
};
// begin main class
explicit PolarSSLContext(const Config& config_arg)
{
config = config_arg;
}
SSL::Ptr ssl() const { return SSL::Ptr(new SSL(this)); }
const Mode& mode() const { return config.mode; }
~PolarSSLContext()
{
erase();
}
private:
bool verify_ns_cert_type(const x509_cert *cert) const
{
if (config.cert_type == Config::CERT_TYPE_NS_SERVER)
return bool(cert->ns_cert_type & NS_CERT_TYPE_SSL_SERVER);
else if (config.cert_type == Config::CERT_TYPE_NS_CLIENT)
return bool(cert->ns_cert_type & NS_CERT_TYPE_SSL_CLIENT);
else
return true;
}
static int verify_callback(void *arg, x509_cert *cert, int depth, int preverify_ok)
{
PolarSSLContext *self = (PolarSSLContext *)arg;
OPENVPN_LOG_SSL("VERIFY "
<< (preverify_ok ? "OK" : "FAIL")
<< ": depth=" << depth
<< std::endl << cert_info(cert));
// verify ns-cert-type
if (depth == 0 && !self->verify_ns_cert_type(cert))
{
OPENVPN_LOG("VERIFY FAIL -- bad ns-cert-type in leaf certificate");
preverify_ok = false;
}
return preverify_ok ? 0 : POLARSSL_ERR_SSL_PEER_VERIFY_FAILED;
}
static std::string cert_info(const x509_cert *cert, const char *prefix = NULL)
{
char buf[512];
const int size = x509parse_cert_info(buf, sizeof(buf), prefix ? prefix : "", cert);
if (size >= 0)
return buf;
else
return "error rendering cert";
}
void erase()
{
}
Config config;
};
} // namespace openvpn
#endif

View File

@ -0,0 +1,54 @@
#ifndef OPENVPN_POLARSSL_UTIL_ERROR_H
#define OPENVPN_POLARSSL_UTIL_ERROR_H
#include <string>
#include <polarssl/error.h>
#include <openvpn/common/exception.hpp>
namespace openvpn {
// string exception class
class PolarSSLException : public std::exception
{
public:
PolarSSLException()
{
errnum = 0;
errtxt = "PolarSSL";
}
explicit PolarSSLException(const std::string& error_text)
{
errnum = 0;
errtxt = "PolarSSL: " + error_text;
}
explicit PolarSSLException(const std::string& error_text, const int polarssl_errnum)
{
errnum = polarssl_errnum;
errtxt = "PolarSSL: " + error_text + " : " + polarssl_errtext(polarssl_errnum);
}
virtual const char* what() const throw() { return errtxt.c_str(); }
std::string what_str() const { return errtxt; }
int get_errnum() const { return errnum; }
virtual ~PolarSSLException() throw() {}
static std::string polarssl_errtext(int errnum)
{
char buf[256];
error_strerror(errnum, buf, sizeof(buf));
return buf;
}
private:
std::string errtxt;
int errnum;
};
}
#endif

View File

@ -31,6 +31,11 @@ namespace openvpn {
throw rand_error_polarssl("CTR_DRBG rand_bytes");
}
int rand_bytes_noexcept(unsigned char *buf, const size_t size)
{
return ctr_drbg_random(&ctx, buf, size);
}
private:
static int entropy_poll(void *data, unsigned char *output, size_t len)
{

View File

@ -382,7 +382,7 @@ namespace openvpn {
}
private:
typename SSLContext::SSLPtr ssl_;
typename SSLContext::SSL::Ptr ssl_;
Frame::Ptr frame_;
int up_stack_reentry_level;
bool invalidated_;

View File

@ -11,6 +11,7 @@ if [ -z "$1" ]; then
echo " PGEN=1 -- generate data for profile-guided optimization"
echo " PUSE=1 -- use data from previous run of PGEN=1 build"
echo " PSSL=1 -- include PolarSSL"
echo " NOSSL=1 -- don't include OpenSSL (non-mac)"
echo " OSSL=1 -- include OpenSSL on Mac"
echo " SSL_BOTH=1 -- include OpenSSL and Apple SSL on Mac"
echo " NOTHREADS=1 -- disable threads"
@ -60,10 +61,12 @@ if [ "$PLATFORM" = "mac" ]; then
# -framework CoreServices
LIBS="$LIBS -framework CoreFoundation"
else
CPPFLAGS="$CPPFLAGS -DUSE_OPENSSL"
LIBS="$LIBS -lssl -lcrypto"
if [ "$NOSSL" != "1" ]; then
CPPFLAGS="$CPPFLAGS -DUSE_OPENSSL"
LIBS="$LIBS -lssl -lcrypto"
fi
fi
if [ "$OPENSSL_DIR" ]; then
if [ "$OPENSSL_DIR" ] && [ "$NOSSL" != "1" ]; then
CPPFLAGS="$CPPFLAGS -I$OPENSSL_DIR/include"
LIBDIRS="$LIBDIRS -L$OPENSSL_DIR/lib"
fi

View File

@ -53,6 +53,16 @@
#include <openvpn/openssl/ssl/sslctx.hpp>
#include <openvpn/openssl/util/rand.hpp>
// kludge to work around symbol conflict between OpenSSL and PolarSSL
#undef KU_DIGITAL_SIGNATURE
#undef KU_NON_REPUDIATION
#undef KU_KEY_ENCIPHERMENT
#undef KU_DATA_ENCIPHERMENT
#undef KU_KEY_AGREEMENT
#undef KU_KEY_CERT_SIGN
#undef KU_CRL_SIGN
#undef SSL_VERIFY_NONE
#ifdef USE_APPLE_SSL
#include <openvpn/applecrypto/crypto/api.hpp>
#include <openvpn/applecrypto/ssl/sslctx.hpp>
@ -61,7 +71,7 @@
#ifdef USE_POLARSSL
#include <openvpn/polarssl/crypto/api.hpp>
//#include <openvpn/polarssl/ssl/sslctx.hpp>
#include <openvpn/polarssl/ssl/sslctx.hpp>
#include <openvpn/polarssl/util/rand.hpp>
#endif
@ -79,7 +89,7 @@ typedef OpenSSLRandom ServerRandomAPI;
// client SSL implementation can be OpenSSL, Apple SSL, or PolarSSL
#if defined(USE_POLARSSL)
typedef PolarSSLCryptoAPI ClientCryptoAPI;
typedef OpenSSLContext ClientSSLAPI; // fixme
typedef PolarSSLContext ClientSSLAPI;
typedef PolarSSLRandom ClientRandomAPI;
#elif defined(USE_APPLE_SSL)
typedef AppleSSLCryptoAPI ClientCryptoAPI;
@ -628,6 +638,9 @@ void test(const int thread_num)
#ifdef VERBOSE
cc.enable_debug();
#endif
#if defined(USE_POLARSSL)
cc.rng = rng_cli;
#endif
// client stats
MySessionStats::Ptr cli_stats(new MySessionStats);