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

OpenSSL PKI cleanup

* Added C++11 features such as move constructor and move
  assignment method.

* Since these classes are already object wrappers, it's
  redundant to manage them via RC.

* Use the "::" prefix to denote OpenSSL symbols from the
  top-level namespace.

Signed-off-by: James Yonan <james@openvpn.net>
This commit is contained in:
James Yonan 2019-05-23 23:52:02 -06:00 committed by Antonio Quartulli
parent d5eb77c53c
commit 95e761f3cc
No known key found for this signature in database
GPG Key ID: F4556C5945830E6D
7 changed files with 292 additions and 243 deletions

View File

@ -21,8 +21,7 @@
// Wrap an OpenSSL X509_CRL object
#ifndef OPENVPN_OPENSSL_PKI_CRL_H
#define OPENVPN_OPENSSL_PKI_CRL_H
#pragma once
#include <string>
#include <vector>
@ -32,16 +31,18 @@
#include <openvpn/common/size.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/rc.hpp>
#include <openvpn/openssl/util/error.hpp>
namespace openvpn {
namespace OpenSSLPKI {
class CRL : public RC<thread_unsafe_refcount>
class CRL
{
public:
CRL() : crl_(nullptr) {}
CRL()
: crl_(nullptr)
{
}
explicit CRL(const std::string& crl_txt)
: crl_(nullptr)
@ -50,27 +51,48 @@ namespace openvpn {
}
CRL(const CRL& other)
: crl_(nullptr)
: crl_(dup(other.crl_))
{
assign(other.crl_);
}
void operator=(const CRL& other)
CRL(CRL&& other) noexcept
: crl_(other.crl_)
{
assign(other.crl_);
other.crl_ = nullptr;
}
CRL& operator=(const CRL& other)
{
if (this != &other)
{
erase();
crl_ = dup(other.crl_);
}
return *this;
}
CRL& operator=(CRL&& other) noexcept
{
if (this != &other)
{
erase();
crl_ = other.crl_;
other.crl_ = nullptr;
}
return *this;
}
bool defined() const { return crl_ != nullptr; }
X509_CRL* obj() const { return crl_; }
::X509_CRL* obj() const { return 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());
BIO *bio = ::BIO_new_mem_buf(const_cast<char *>(crl_txt.c_str()), crl_txt.length());
if (!bio)
throw OpenSSLException();
X509_CRL *crl = PEM_read_bio_X509_CRL(bio, nullptr, nullptr, nullptr);
BIO_free(bio);
::X509_CRL *crl = ::PEM_read_bio_X509_CRL(bio, nullptr, nullptr, nullptr);
::BIO_free(bio);
if (!crl)
throw OpenSSLException("CRL::parse_pem");
@ -82,19 +104,19 @@ namespace openvpn {
{
if (crl_)
{
BIO *bio = BIO_new(BIO_s_mem());
const int ret = PEM_write_bio_X509_CRL(bio, crl_);
BIO *bio = ::BIO_new(BIO_s_mem());
const int ret = ::PEM_write_bio_X509_CRL(bio, crl_);
if (ret == 0)
{
BIO_free(bio);
::BIO_free(bio);
throw OpenSSLException("CRL::render_pem");
}
{
char *temp;
const int buf_len = BIO_get_mem_data(bio, &temp);
const int buf_len = ::BIO_get_mem_data(bio, &temp);
std::string ret = std::string(temp, buf_len);
BIO_free(bio);
::BIO_free(bio);
return ret;
}
}
@ -102,59 +124,46 @@ namespace openvpn {
return "";
}
void erase()
{
if (crl_)
{
X509_CRL_free(crl_);
crl_ = nullptr;
}
}
~CRL()
{
erase();
}
private:
void erase()
{
if (crl_)
::X509_CRL_free(crl_);
}
static X509_CRL *dup(const X509_CRL *crl)
{
if (crl)
{
return X509_CRL_dup(const_cast<X509_CRL *>(crl));
}
return ::X509_CRL_dup(const_cast<X509_CRL *>(crl));
else
return nullptr;
}
void assign(const X509_CRL *crl)
{
erase();
crl_ = dup(crl);
}
X509_CRL *crl_;
::X509_CRL *crl_;
};
typedef RCPtr<CRL> CRLPtr;
class CRLList : public std::vector<CRLPtr>
class CRLList : public std::vector<CRL>
{
public:
typedef CRL Item;
typedef CRLPtr ItemPtr;
typedef X509 CRL;
bool defined() const { return !empty(); }
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();
for (const auto &e : *this)
ret += e.render_pem();
return ret;
}
};
}
} // namespace openvpn
#endif // OPENVPN_OPENSSL_PKI_CRL_H
}

View File

@ -21,8 +21,7 @@
// Wrap an OpenSSL DH object
#ifndef OPENVPN_OPENSSL_PKI_DH_H
#define OPENVPN_OPENSSL_PKI_DH_H
#pragma once
#include <string>
@ -57,7 +56,10 @@ namespace openvpn {
class DH
{
public:
DH() : dh_(nullptr) {}
DH()
: dh_(nullptr)
{
}
explicit DH(const std::string& dh_txt)
: dh_(nullptr)
@ -66,15 +68,34 @@ namespace openvpn {
}
DH(const DH& other)
: dh_(nullptr)
{
dup(other.dh_);
}
DH(DH&& other) noexcept
: dh_(other.dh_)
{
other.dh_ = nullptr;
}
void operator=(const DH& other)
{
erase();
dup(other.dh_);
if (this != &other)
{
erase();
dup(other.dh_);
}
}
DH& operator=(DH&& other) noexcept
{
if (this != &other)
{
erase();
dh_ = other.dh_;
other.dh_ = nullptr;
}
return *this;
}
bool defined() const { return dh_ != nullptr; }
@ -82,12 +103,12 @@ namespace openvpn {
void parse_pem(const std::string& dh_txt)
{
BIO *bio = BIO_new_mem_buf(const_cast<char *>(dh_txt.c_str()), dh_txt.length());
BIO *bio = ::BIO_new_mem_buf(const_cast<char *>(dh_txt.c_str()), dh_txt.length());
if (!bio)
throw OpenSSLException();
::DH *dh = PEM_read_bio_DHparams(bio, nullptr, nullptr, nullptr);
BIO_free(bio);
::DH *dh = ::PEM_read_bio_DHparams(bio, nullptr, nullptr, nullptr);
::BIO_free(bio);
if (!dh)
throw OpenSSLException("DH::parse_pem");
@ -99,19 +120,19 @@ namespace openvpn {
{
if (dh_)
{
BIO *bio = BIO_new(BIO_s_mem());
const int ret = PEM_write_bio_DHparams(bio, dh_);
BIO *bio = ::BIO_new(BIO_s_mem());
const int ret = ::PEM_write_bio_DHparams(bio, dh_);
if (ret == 0)
{
BIO_free(bio);
::BIO_free(bio);
throw OpenSSLException("DH::render_pem");
}
{
char *temp;
const int buf_len = BIO_get_mem_data(bio, &temp);
const int buf_len = ::BIO_get_mem_data(bio, &temp);
std::string ret = std::string(temp, buf_len);
BIO_free(bio);
::BIO_free(bio);
return ret;
}
}
@ -119,21 +140,18 @@ namespace openvpn {
return "";
}
void erase()
{
if (dh_)
{
DH_free(dh_);
dh_ = nullptr;
}
}
~DH()
{
erase();
}
private:
void erase()
{
if (dh_)
::DH_free(dh_);
}
void dup(const ::DH *dh)
{
dh_ = DH_private::dup(dh);
@ -142,7 +160,4 @@ namespace openvpn {
::DH *dh_;
};
}
} // namespace openvpn
#endif // OPENVPN_OPENSSL_PKI_DH_H
}

View File

@ -21,10 +21,10 @@
// Wrap an OpenSSL EVP_PKEY object
#ifndef OPENVPN_OPENSSL_PKI_PKEY_H
#define OPENVPN_OPENSSL_PKI_PKEY_H
#pragma once
#include <string>
#include <utility>
#include <openssl/ssl.h>
#include <openssl/bio.h>
@ -32,6 +32,7 @@
#include <openvpn/common/size.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/openssl/util/error.hpp>
#include <openvpn/pki/pktype.hpp>
namespace openvpn {
namespace OpenSSLPKI {
@ -39,7 +40,10 @@ namespace openvpn {
class PKey
{
public:
PKey() : pkey_(nullptr) {}
PKey()
: pkey_(nullptr)
{
}
PKey(const std::string& pkey_txt, const std::string& title)
: pkey_(nullptr)
@ -48,45 +52,69 @@ namespace openvpn {
}
PKey(const PKey& other)
: pkey_(nullptr)
: pkey_(dup(other.pkey_)),
priv_key_pwd(other.priv_key_pwd)
{
assign(other.pkey_);
}
void operator=(const PKey& other)
PKey(PKey&& other) noexcept
: pkey_(other.pkey_),
priv_key_pwd(std::move(other.priv_key_pwd))
{
assign(other.pkey_);
priv_key_pwd = other.priv_key_pwd;
other.pkey_ = nullptr;
}
PKey& operator=(const PKey& other)
{
if (this != &other)
{
erase();
pkey_ = dup(other.pkey_);
priv_key_pwd = other.priv_key_pwd;
}
return *this;
}
PKey& operator=(PKey&& other) noexcept
{
if (this != &other)
{
erase();
pkey_ = other.pkey_;
other.pkey_ = nullptr;
priv_key_pwd = std::move(other.priv_key_pwd);
}
return *this;
}
bool defined() const { return pkey_ != nullptr; }
EVP_PKEY* obj() const { return pkey_; }
::EVP_PKEY* obj() const { return pkey_; }
SSLConfigAPI::PKType key_type() const
PKType::Type key_type() const
{
switch (EVP_PKEY_id(pkey_))
switch (::EVP_PKEY_id(pkey_))
{
case EVP_PKEY_RSA:
case EVP_PKEY_RSA2:
return SSLConfigAPI::PK_RSA;
return PKType::PK_RSA;
case EVP_PKEY_EC:
return SSLConfigAPI::PK_EC;
return PKType::PK_EC;
case EVP_PKEY_DSA:
case EVP_PKEY_DSA1:
case EVP_PKEY_DSA2:
case EVP_PKEY_DSA3:
case EVP_PKEY_DSA4:
return SSLConfigAPI::PK_DSA;
return PKType::PK_DSA;
case EVP_PKEY_NONE:
return SSLConfigAPI::PK_NONE;
return PKType::PK_NONE;
default:
return SSLConfigAPI::PK_UNKNOWN;
return PKType::PK_UNKNOWN;
}
}
size_t key_length() const
{
int ret = i2d_PrivateKey(pkey_, NULL);
int ret = ::i2d_PrivateKey(pkey_, NULL);
if (ret < 0)
return 0;
@ -101,12 +129,12 @@ namespace openvpn {
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());
BIO *bio = ::BIO_new_mem_buf(const_cast<char *>(pkey_txt.c_str()), pkey_txt.length());
if (!bio)
throw OpenSSLException();
EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, nullptr, pem_password_callback, this);
BIO_free(bio);
::EVP_PKEY *pkey = ::PEM_read_bio_PrivateKey(bio, nullptr, pem_password_callback, this);
::BIO_free(bio);
if (!pkey)
throw OpenSSLException(std::string("PKey::parse_pem: error in ") + title + std::string(":"));
@ -118,19 +146,19 @@ namespace openvpn {
{
if (pkey_)
{
BIO *bio = BIO_new(BIO_s_mem());
const int ret = PEM_write_bio_PrivateKey(bio, pkey_, nullptr, nullptr, 0, nullptr, nullptr);
BIO *bio = ::BIO_new(BIO_s_mem());
const int ret = ::PEM_write_bio_PrivateKey(bio, pkey_, nullptr, nullptr, 0, nullptr, nullptr);
if (ret == 0)
{
BIO_free(bio);
::BIO_free(bio);
throw OpenSSLException("PKey::render_pem");
}
{
char *temp;
const int buf_len = BIO_get_mem_data(bio, &temp);
const int buf_len = ::BIO_get_mem_data(bio, &temp);
std::string ret = std::string(temp, buf_len);
BIO_free(bio);
::BIO_free(bio);
return ret;
}
}
@ -138,15 +166,6 @@ namespace openvpn {
return "";
}
void erase()
{
if (pkey_)
{
EVP_PKEY_free(pkey_);
pkey_ = nullptr;
}
}
~PKey()
{
erase();
@ -165,33 +184,31 @@ namespace openvpn {
return 0;
}
static EVP_PKEY *dup(const EVP_PKEY *pkey)
void erase()
{
if (pkey_)
::EVP_PKEY_free(pkey_);
}
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);
::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 nullptr;
}
void assign(const EVP_PKEY *pkey)
{
erase();
pkey_ = dup(pkey);
}
::EVP_PKEY *pkey_;
std::string priv_key_pwd;
EVP_PKEY *pkey_;
};
}
} // namespace openvpn
#endif // OPENVPN_OPENSSL_PKI_PKEY_H
}

View File

@ -21,8 +21,7 @@
// Wrap an OpenSSL X509 object
#ifndef OPENVPN_OPENSSL_PKI_X509_H
#define OPENVPN_OPENSSL_PKI_X509_H
#pragma once
#include <string>
#include <vector>
@ -32,92 +31,77 @@
#include <openvpn/common/size.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/rc.hpp>
#include <openvpn/openssl/util/error.hpp>
namespace openvpn {
namespace OpenSSLPKI {
class X509;
class X509Base
class X509
{
public:
X509Base() : x509_(nullptr) {}
explicit X509Base(::X509 *x509) : x509_(x509) {}
X509()
: x509_(nullptr)
{
}
X509(const std::string& cert_txt, const std::string& title)
: x509_(nullptr)
{
parse_pem(cert_txt, title);
}
explicit X509(::X509 *x509, const bool create=true)
{
if (create)
x509_ = x509;
else
x509_ = dup(x509);
}
X509(const X509& other)
: x509_(dup(other.x509_))
{
}
X509(X509&& other) noexcept
: x509_(other.x509_)
{
other.x509_ = nullptr;
}
X509& operator=(const X509& other)
{
if (this != &other)
{
erase();
x509_ = dup(other.x509_);
}
return *this;
}
X509& operator=(X509&& other) noexcept
{
if (this != &other)
{
erase();
x509_ = other.x509_;
other.x509_ = nullptr;
}
return *this;
}
bool defined() const { return x509_ != nullptr; }
::X509* obj() const { return x509_; }
::X509* obj_dup() const { return dup(x509_); }
std::string render_pem() const
{
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");
}
{
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 "";
}
private:
static ::X509 *dup(const ::X509 *x509)
{
if (x509)
return X509_dup(const_cast< ::X509 * >(x509));
else
return nullptr;
}
friend class X509;
::X509 *x509_;
};
class X509 : public X509Base, public RC<thread_unsafe_refcount>
{
public:
typedef RCPtr<X509> Ptr;
X509() {}
X509(const std::string& cert_txt, const std::string& title)
{
parse_pem(cert_txt, title);
}
X509(const X509& other)
{
dup(other.x509_);
}
void operator=(const X509& other)
{
erase();
dup(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());
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, nullptr, nullptr, nullptr);
BIO_free(bio);
::X509 *cert = ::PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
::BIO_free(bio);
if (!cert)
throw OpenSSLException(std::string("X509::parse_pem: error in ") + title + std::string(":"));
@ -125,13 +109,28 @@ namespace openvpn {
x509_ = cert;
}
void erase()
std::string render_pem() const
{
if (x509_)
{
X509_free(x509_);
x509_ = nullptr;
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 "";
}
~X509()
@ -140,29 +139,40 @@ namespace openvpn {
}
private:
void dup(const ::X509 *x509)
static ::X509 *dup(const ::X509 *x509)
{
x509_ = X509Base::dup(x509);
if (x509)
return ::X509_dup(const_cast< ::X509 * >(x509));
else
return nullptr;
}
void erase()
{
if (x509_)
::X509_free(x509_);
}
::X509 *x509_;
};
class X509List : public std::vector<X509::Ptr>
class X509List : public std::vector<X509>
{
public:
typedef X509 Item;
typedef X509::Ptr ItemPtr;
bool defined() const { return !empty(); }
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();
for (const auto &e : *this)
ret += e.render_pem();
return ret;
}
};
}
} // namespace openvpn
#endif // OPENVPN_OPENSSL_PKI_X509_H
}

View File

@ -21,12 +21,10 @@
// Wrap an OpenSSL X509Store object
#ifndef OPENVPN_OPENSSL_PKI_X509STORE_H
#define OPENVPN_OPENSSL_PKI_X509STORE_H
#pragma once
#include <openvpn/common/size.hpp>
#include <openvpn/common/exception.hpp>
#include <openvpn/common/rc.hpp>
#include <openvpn/pki/cclist.hpp>
#include <openvpn/openssl/util/error.hpp>
#include <openvpn/openssl/pki/x509.hpp>
@ -35,16 +33,17 @@
namespace openvpn {
namespace OpenSSLPKI {
class X509Store : public RC<thread_unsafe_refcount>
class X509Store
{
public:
OPENVPN_SIMPLE_EXCEPTION(x509_store_init_error);
OPENVPN_SIMPLE_EXCEPTION(x509_store_add_cert_error);
OPENVPN_SIMPLE_EXCEPTION(x509_store_add_crl_error);
OPENVPN_EXCEPTION(x509_store_error);
typedef CertCRLListTemplate<X509List, CRLList> CertCRLList;
X509Store() : x509_store_(nullptr) {}
X509Store()
: x509_store_(nullptr)
{
}
explicit X509Store(const CertCRLList& cc)
{
@ -52,10 +51,10 @@ namespace openvpn {
// Load cert list
{
for (X509List::const_iterator i = cc.certs.begin(); i != cc.certs.end(); ++i)
for (const auto &e : cc.certs)
{
if (!X509_STORE_add_cert(x509_store_, (*i)->obj()))
throw x509_store_add_cert_error();
if (!::X509_STORE_add_cert(x509_store_, e.obj()))
throw x509_store_error("X509_STORE_add_cert(");
}
}
@ -63,19 +62,22 @@ namespace openvpn {
{
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)
::X509_STORE_set_flags(x509_store_, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
for (const auto &e : cc.crls)
{
if (!X509_STORE_add_crl(x509_store_, (*i)->obj()))
throw x509_store_add_crl_error();
if (!::X509_STORE_add_crl(x509_store_, e.obj()))
throw x509_store_error("X509_STORE_add_crl");
}
}
}
}
X509_STORE* obj() const { return x509_store_; }
X509_STORE* obj() const
{
return x509_store_;
}
X509_STORE* move()
X509_STORE* release()
{
X509_STORE* ret = x509_store_;
x509_store_ = nullptr;
@ -85,20 +87,18 @@ namespace openvpn {
~X509Store()
{
if (x509_store_)
X509_STORE_free(x509_store_);
::X509_STORE_free(x509_store_);
}
private:
void init()
{
x509_store_ = X509_STORE_new();
x509_store_ = ::X509_STORE_new();
if (!x509_store_)
throw x509_store_init_error();
throw x509_store_error("X509_STORE_new");
}
X509_STORE* x509_store_;
::X509_STORE* x509_store_;
};
}
} // namespace openvpn
#endif // OPENVPN_OPENSSL_PKI_X509STORE_H
}

View File

@ -194,7 +194,7 @@ namespace openvpn {
std::vector<std::string> ret;
for (auto const& cert : extra_certs)
ret.push_back(cert->render_pem());
ret.push_back(cert.render_pem());
return ret;
}
@ -1262,9 +1262,9 @@ namespace openvpn {
// chain but shouldn't be included in the verify chain.
if (config->extra_certs.defined())
{
for (OpenSSLPKI::X509List::const_iterator i = config->extra_certs.begin(); i != config->extra_certs.end(); ++i)
for (const auto& e : config->extra_certs)
{
if (SSL_CTX_add_extra_chain_cert(ctx, (*i)->obj_dup()) != 1)
if (SSL_CTX_add_extra_chain_cert(ctx, e.obj_dup()) != 1)
throw OpenSSLException("OpenSSLContext: SSL_CTX_add_extra_chain_cert failed");
}
}
@ -1303,7 +1303,7 @@ namespace openvpn {
void update_trust(const CertCRLList& cc)
{
OpenSSLPKI::X509Store store(cc);
SSL_CTX_set_cert_store(ctx, store.move());
SSL_CTX_set_cert_store(ctx, store.release());
}
~OpenSSLContext()

View File

@ -35,7 +35,7 @@ namespace openvpn {
// Parse a concatenated list of certs and CRLs (PEM format).
// Abstracts CertList and CRLList, so can be used with any crypto lib.
// CertList and CRLList must define Item and ItemPtr types.
// CertList and CRLList must define Item type.
template <typename CertList, typename CRLList>
class CertCRLListTemplate
{
@ -109,8 +109,7 @@ namespace openvpn {
if (state == S_IN_CERT && line == cert_end)
{
try {
typename CertList::ItemPtr x509(new typename CertList::Item(item, title));
cert_list->push_back(x509);
cert_list->emplace_back(item, title);
}
catch (const std::exception& e)
{
@ -122,8 +121,7 @@ namespace openvpn {
if (state == S_IN_CRL && line == crl_end)
{
try {
typename CRLList::ItemPtr crl(new typename CRLList::Item(item));
crl_list->push_back(crl);
crl_list->emplace_back(item);
}
catch (const std::exception& e)
{