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:
parent
801bfae881
commit
1b0088ab2e
21
javacli/build-linux-polar
Executable file
21
javacli/build-linux-polar
Executable 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
|
@ -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; }
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
84
openvpn/polarssl/pki/rsactx.hpp
Normal file
84
openvpn/polarssl/pki/rsactx.hpp
Normal 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
|
91
openvpn/polarssl/pki/x509cert.hpp
Normal file
91
openvpn/polarssl/pki/x509cert.hpp
Normal 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
|
491
openvpn/polarssl/ssl/sslctx.hpp
Normal file
491
openvpn/polarssl/ssl/sslctx.hpp
Normal 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
|
54
openvpn/polarssl/util/error.hpp
Normal file
54
openvpn/polarssl/util/error.hpp
Normal 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
|
@ -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)
|
||||
{
|
||||
|
@ -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_;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user