Compare commits

..
2 Commits
Author SHA1 Message Date
Adrien Béraud d80aab9399 pingpong: cleanup 2019-03-29 13:13:29 -04:00
Adrien Béraud 9b881d4e95 crypto: add initial certificate request support 2019-03-29 13:13:29 -04:00
5 changed files with 335 additions and 107 deletions

No files matched your search

+45 -8
View File
@@ -66,7 +66,7 @@ using Identity = std::pair<std::shared_ptr<PrivateKey>, std::shared_ptr<Certific
*/
struct OPENDHT_PUBLIC PublicKey
{
PublicKey() {}
PublicKey();
/**
* Takes ownership of an existing gnutls_pubkey.
@@ -115,7 +115,9 @@ struct OPENDHT_PUBLIC PublicKey
void msgpack_unpack(msgpack::object o);
gnutls_pubkey_t pk {};
gnutls_digest_algorithm_t getPreferredDigest() const;
gnutls_pubkey_t pk {nullptr};
private:
PublicKey(const PublicKey&) = delete;
PublicKey& operator=(const PublicKey&) = delete;
@@ -254,14 +256,48 @@ private:
RevocationList& operator=(const RevocationList&) = delete;
};
enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
class OPENDHT_PUBLIC CertificateRequest {
public:
CertificateRequest();
CertificateRequest(const uint8_t* data, size_t size);
CertificateRequest(const Blob& data) : CertificateRequest(data.data(), data.size()) {}
CertificateRequest(CertificateRequest&& o) noexcept : request(std::move(o.request)) {
o.request = nullptr;
}
CertificateRequest& operator=(CertificateRequest&& o) noexcept;
~CertificateRequest();
void setName(const std::string& name);
void setUID(const std::string& name);
void setAltName(NameType type, const std::string& name);
std::string getName() const;
std::string getUID() const;
void sign(const PrivateKey& key, const std::string& password = {});
bool verify() const;
Blob pack() const;
gnutls_x509_crq_t get() const { return request; }
private:
CertificateRequest(const CertificateRequest& o) = delete;
CertificateRequest& operator=(const CertificateRequest& o) = delete;
gnutls_x509_crq_t request {nullptr};
};
struct OPENDHT_PUBLIC Certificate {
Certificate() {}
Certificate() noexcept {}
/**
* Take ownership of existing gnutls structure
*/
Certificate(gnutls_x509_crt_t crt) : cert(crt) {}
Certificate(gnutls_x509_crt_t crt) noexcept : cert(crt) {}
Certificate(Certificate&& o) noexcept : cert(o.cert), issuer(std::move(o.issuer)) { o.cert = nullptr; };
@@ -392,8 +428,6 @@ struct OPENDHT_PUBLIC Certificate {
/** Read certificate issuer User ID (UID) */
std::string getIssuerUID() const;
enum class NameType { UNKNOWN = 0, RFC822, DNS, URI, IP };
/** Read certificate alternative names */
std::vector<std::pair<NameType, std::string>> getAltNames() const;
@@ -432,6 +466,7 @@ struct OPENDHT_PUBLIC Certificate {
void addRevocationList(std::shared_ptr<RevocationList>);
static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false);
static Certificate generate(const CertificateRequest& request, const Identity& ca);
gnutls_x509_crt_t getCopy() const {
if (not cert)
@@ -472,7 +507,9 @@ struct OPENDHT_PUBLIC Certificate {
return {crts, crls};
}
gnutls_x509_crt_t cert {};
gnutls_digest_algorithm_t getPreferredDigest() const;
gnutls_x509_crt_t cert {nullptr};
std::shared_ptr<Certificate> issuer {};
private:
Certificate(const Certificate&) = delete;
@@ -513,7 +550,7 @@ struct OPENDHT_PUBLIC TrustList
private:
TrustList(const TrustList& o) = delete;
TrustList& operator=(const TrustList& o) = delete;
gnutls_x509_trust_list_t trust;
gnutls_x509_trust_list_t trust {nullptr};
};
template <class T>
+1 -1
View File
@@ -27,7 +27,7 @@ ping_node.run()
pong_node = dht.DhtRunner()
pong_node.run()
#pong_node.enableLogging()
pong_node.ping(ping_node.getBound());
pong_node.ping(ping_node.getBound())
loc_ping = dht.InfoHash.get("toto99")
loc_pong = dht.InfoHash.get(str(loc_ping))
+256 -97
View File
@@ -40,31 +40,6 @@ static std::uniform_int_distribution<int> rand_byte{ 0, std::numeric_limits<uint
static std::uniform_int_distribution<uint8_t> rand_byte;
#endif
static gnutls_digest_algorithm_t get_dig_for_pub(gnutls_pubkey_t pubkey)
{
gnutls_digest_algorithm_t dig;
int result = gnutls_pubkey_get_preferred_hash_algorithm(pubkey, &dig, nullptr);
if (result < 0)
return GNUTLS_DIG_UNKNOWN;
return dig;
}
static gnutls_digest_algorithm_t get_dig(gnutls_x509_crt_t crt)
{
gnutls_pubkey_t pubkey;
gnutls_pubkey_init(&pubkey);
int result = gnutls_pubkey_import_x509(pubkey, crt, 0);
if (result < 0) {
gnutls_pubkey_deinit(pubkey);
return GNUTLS_DIG_UNKNOWN;
}
gnutls_digest_algorithm_t dig = get_dig_for_pub(pubkey);
gnutls_pubkey_deinit(pubkey);
return dig;
}
// support for GnuTLS < 3.4.
#if GNUTLS_VERSION_NUMBER < 0x030400
#define GNUTLS_PKCS_PKCS12_3DES GNUTLS_PKCS_USE_PKCS12_3DES
@@ -377,15 +352,19 @@ PrivateKey::serialize(const std::string& password) const
PublicKey
PrivateKey::getPublicKey() const
{
gnutls_pubkey_t pk;
gnutls_pubkey_init(&pk);
PublicKey pk_ret {pk};
if (gnutls_pubkey_import_privkey(pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0) != GNUTLS_E_SUCCESS)
return {};
return pk_ret;
PublicKey pk;
if (auto err = gnutls_pubkey_import_privkey(pk.pk, key, GNUTLS_KEY_KEY_CERT_SIGN | GNUTLS_KEY_CRL_SIGN, 0))
throw CryptoException(std::string("Can't retreive public key: ") + gnutls_strerror(err));
return pk;
}
PublicKey::PublicKey(const Blob& dat)
PublicKey::PublicKey()
{
if (auto err = gnutls_pubkey_init(&pk))
throw CryptoException(std::string("Can't initialize public key: ") + gnutls_strerror(err));
}
PublicKey::PublicKey(const Blob& dat) : PublicKey()
{
unpack(dat.data(), dat.size());
}
@@ -415,8 +394,7 @@ PublicKey::pack(Blob& b) const
throw CryptoException(std::string("Could not export public key: null key"));
std::vector<uint8_t> tmp(2048);
size_t sz = tmp.size();
int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, tmp.data(), &sz);
if (err != GNUTLS_E_SUCCESS)
if (int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_DER, tmp.data(), &sz))
throw CryptoException(std::string("Could not export public key: ") + gnutls_strerror(err));
tmp.resize(sz);
b.insert(b.end(), tmp.begin(), tmp.end());
@@ -425,9 +403,6 @@ PublicKey::pack(Blob& b) const
void
PublicKey::unpack(const uint8_t* data, size_t data_size)
{
if (pk)
gnutls_pubkey_deinit(pk);
gnutls_pubkey_init(&pk);
const gnutls_datum_t dat {(uint8_t*)data, (unsigned)data_size};
int err = gnutls_pubkey_import(pk, &dat, GNUTLS_X509_FMT_PEM);
if (err != GNUTLS_E_SUCCESS)
@@ -446,10 +421,9 @@ PublicKey::toString() const
int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_PEM, (void*)ret.data(), &sz);
if (err == GNUTLS_E_SHORT_MEMORY_BUFFER) {
ret.resize(sz);
int err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_PEM, (void*)ret.data(), &sz);
if (err != GNUTLS_E_SUCCESS)
throw CryptoException(std::string("Could not print public key: ") + gnutls_strerror(err));
} else if (err != GNUTLS_E_SUCCESS)
err = gnutls_pubkey_export(pk, GNUTLS_X509_FMT_PEM, (void*)ret.data(), &sz);
}
if (err != GNUTLS_E_SUCCESS)
throw CryptoException(std::string("Could not print public key: ") + gnutls_strerror(err));
return ret;
}
@@ -572,6 +546,179 @@ PublicKey::getLongId() const
#endif
}
gnutls_digest_algorithm_t
PublicKey::getPreferredDigest() const
{
gnutls_digest_algorithm_t dig;
int result = gnutls_pubkey_get_preferred_hash_algorithm(pk, &dig, nullptr);
if (result < 0)
return GNUTLS_DIG_UNKNOWN;
return dig;
}
// Certificate Request
static NameType
typeFromGnuTLS(gnutls_x509_subject_alt_name_t type)
{
switch(type) {
case GNUTLS_SAN_DNSNAME:
return NameType::DNS;
case GNUTLS_SAN_RFC822NAME:
return NameType::RFC822;
case GNUTLS_SAN_URI:
return NameType::URI;
case GNUTLS_SAN_IPADDRESS:
return NameType::IP;
default:
return NameType::UNKNOWN;
}
}
static gnutls_x509_subject_alt_name_t
GnuTLSFromType(NameType type)
{
switch(type) {
case NameType::DNS:
return GNUTLS_SAN_DNSNAME;
case NameType::RFC822:
return GNUTLS_SAN_RFC822NAME;
case NameType::URI:
return GNUTLS_SAN_URI;
case NameType::IP:
return GNUTLS_SAN_IPADDRESS;
default:
return (gnutls_x509_subject_alt_name_t)0;
}
}
static std::string
getDN(gnutls_x509_crq_t request, const char* oid)
{
std::string dn;
dn.resize(512);
size_t dn_sz = dn.size();
int ret = gnutls_x509_crq_get_dn_by_oid(request, oid, 0, 0, &(*dn.begin()), &dn_sz);
if (ret != GNUTLS_E_SUCCESS)
return {};
dn.resize(dn_sz);
return dn;
}
CertificateRequest::CertificateRequest()
{
if (auto err = gnutls_x509_crq_init(&request))
throw CryptoException(std::string("Can't initialize certificate request: ") + gnutls_strerror(err));
}
CertificateRequest::CertificateRequest(const uint8_t* data, size_t size) : CertificateRequest()
{
const gnutls_datum_t dat {(uint8_t*)data, (unsigned)size};
if (auto err = gnutls_x509_crq_import(request, &dat, GNUTLS_X509_FMT_PEM))
throw CryptoException(std::string("Can't import certificate request: ") + gnutls_strerror(err));
}
CertificateRequest::~CertificateRequest()
{
if (request) {
gnutls_x509_crq_deinit(request);
request = nullptr;
}
}
CertificateRequest&
CertificateRequest::operator=(CertificateRequest&& o) noexcept
{
if (request)
gnutls_x509_crq_deinit(request);
request = o.request;
o.request = nullptr;
return *this;
}
void
CertificateRequest::setAltName(NameType type, const std::string& name)
{
gnutls_x509_crq_set_subject_alt_name(request, GnuTLSFromType(type), name.data(), name.size(), 0);
}
void
CertificateRequest::setName(const std::string& name)
{
gnutls_x509_crq_set_dn_by_oid(request, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
}
std::string
CertificateRequest::getName() const
{
return getDN(request, GNUTLS_OID_X520_COMMON_NAME);
}
std::string
CertificateRequest::getUID() const
{
return getDN(request, GNUTLS_OID_LDAP_UID);
}
void
CertificateRequest::setUID(const std::string& uid)
{
gnutls_x509_crq_set_dn_by_oid(request, GNUTLS_OID_LDAP_UID, 0, uid.data(), uid.length());
}
void
CertificateRequest::sign(const PrivateKey& key, const std::string& password)
{
gnutls_x509_crq_set_version(request, 1);
if (not password.empty())
gnutls_x509_crq_set_challenge_password(request, password.c_str());
if (auto err = gnutls_x509_crq_set_key(request, key.x509_key))
throw CryptoException(std::string("Can't set certificate request key: ") + gnutls_strerror(err));
#if GNUTLS_VERSION_NUMBER < 0x030601
if (auto err = gnutls_x509_crq_privkey_sign(request, key.key, key.getPublicKey().getPreferredDigest(), 0))
throw CryptoException(std::string("Can't sign certificate request: ") + gnutls_strerror(err));
#else
if (auto err = gnutls_x509_crq_privkey_sign(request, key.key, GNUTLS_DIG_UNKNOWN, 0))
throw CryptoException(std::string("Can't sign certificate request: ") + gnutls_strerror(err));
#endif
}
bool
CertificateRequest::verify() const
{
return gnutls_x509_crq_verify(request, 0) >= 0;
}
Blob
CertificateRequest::pack() const
{
gnutls_datum_t dat {nullptr, 0};
if (auto err = gnutls_x509_crq_export2(request, GNUTLS_X509_FMT_PEM, &dat))
throw CryptoException(std::string("Can't export certificate request: ") + gnutls_strerror(err));
Blob ret(dat.data, dat.data + dat.size);
gnutls_free(dat.data);
return ret;
}
// Certificate
static std::string
getDN(gnutls_x509_crt_t cert, const char* oid, bool issuer = false)
{
std::string dn;
dn.resize(512);
size_t dn_sz = dn.size();
int ret = issuer
? gnutls_x509_crt_get_issuer_dn_by_oid(cert, oid, 0, 0, &(*dn.begin()), &dn_sz)
: gnutls_x509_crt_get_dn_by_oid( cert, oid, 0, 0, &(*dn.begin()), &dn_sz);
if (ret != GNUTLS_E_SUCCESS)
return {};
dn.resize(dn_sz);
return dn;
}
Certificate::Certificate(const Blob& certData)
{
unpack(certData.data(), certData.size());
@@ -656,11 +803,9 @@ Certificate::~Certificate()
PublicKey
Certificate::getPublicKey() const
{
gnutls_pubkey_t pk;
gnutls_pubkey_init(&pk);
PublicKey pk_ret(pk);
if (gnutls_pubkey_import_x509(pk, cert, 0) != GNUTLS_E_SUCCESS)
return {};
PublicKey pk_ret;
if (auto err = gnutls_pubkey_import_x509(pk_ret.pk, cert, 0))
throw CryptoException(std::string("Can't get certificate public key: ") + gnutls_strerror(err));
return pk_ret;
}
@@ -696,21 +841,6 @@ Certificate::getLongId() const
#endif
}
static std::string
getDN(gnutls_x509_crt_t cert, const char* oid, bool issuer = false)
{
std::string dn;
dn.resize(512);
size_t dn_sz = dn.size();
int ret = issuer
? gnutls_x509_crt_get_issuer_dn_by_oid(cert, oid, 0, 0, &(*dn.begin()), &dn_sz)
: gnutls_x509_crt_get_dn_by_oid( cert, oid, 0, 0, &(*dn.begin()), &dn_sz);
if (ret != GNUTLS_E_SUCCESS)
return {};
dn.resize(dn_sz);
return dn;
}
std::string
Certificate::getName() const
{
@@ -735,24 +865,7 @@ Certificate::getIssuerUID() const
return getDN(cert, GNUTLS_OID_LDAP_UID, true);
}
static Certificate::NameType
typeFromGnuTLS(gnutls_x509_subject_alt_name_t type)
{
switch(type) {
case GNUTLS_SAN_DNSNAME:
return Certificate::NameType::DNS;
case GNUTLS_SAN_RFC822NAME:
return Certificate::NameType::RFC822;
case GNUTLS_SAN_URI:
return Certificate::NameType::URI;
case GNUTLS_SAN_IPADDRESS:
return Certificate::NameType::IP;
default:
return Certificate::NameType::UNKNOWN;
}
}
std::vector<std::pair<Certificate::NameType, std::string>>
std::vector<std::pair<NameType, std::string>>
Certificate::getAltNames() const
{
std::vector<std::pair<NameType, std::string>> names;
@@ -867,6 +980,14 @@ Certificate::getExpiration() const
return std::chrono::system_clock::from_time_t(t);
}
gnutls_digest_algorithm_t
Certificate::getPreferredDigest() const
{
return getPublicKey().getPreferredDigest();
}
// PrivateKey
PrivateKey
PrivateKey::generate(unsigned key_length)
{
@@ -922,6 +1043,27 @@ generateEcIdentity(const std::string& name, const Identity& ca) {
return generateEcIdentity(name, ca, !ca.first || !ca.second);
}
void
setValidityPeriod(gnutls_x509_crt_t cert, int64_t validity)
{
int64_t now = time(nullptr);
/* 2038 bug: don't allow time wrap */
auto boundTime = [](int64_t t) -> time_t {
return std::min<int64_t>(t, std::numeric_limits<time_t>::max());
};
gnutls_x509_crt_set_activation_time(cert, boundTime(now));
gnutls_x509_crt_set_expiration_time(cert, boundTime(now + validity));
}
void
setRandomSerial(gnutls_x509_crt_t cert)
{
random_device rdev;
std::uniform_int_distribution<uint64_t> dist{};
uint64_t cert_serial = dist(rdev);
gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial));
}
Certificate
Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca)
{
@@ -930,13 +1072,7 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
return {};
Certificate ret {cert};
int64_t now = time(nullptr);
/* 2038 bug: don't allow time wrap */
auto boundTime = [](int64_t t) -> time_t {
return std::min<int64_t>(t, std::numeric_limits<time_t>::max());
};
gnutls_x509_crt_set_activation_time(cert, boundTime(now));
gnutls_x509_crt_set_expiration_time(cert, boundTime(now + (10 * 365 * 24 * 60 * 60)));
setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
if (gnutls_x509_crt_set_key(cert, key.x509_key) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when setting certificate key" << std::endl;
return {};
@@ -947,19 +1083,15 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
}
// TODO: compute the subject key using the recommended RFC method
auto pk_id = key.getPublicKey().getId();
auto pk = key.getPublicKey();
auto pk_id = pk.getId();
const std::string uid_str = pk_id.toString();
gnutls_x509_crt_set_subject_key_id(cert, &pk_id, sizeof(pk_id));
gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, name.data(), name.length());
gnutls_x509_crt_set_dn_by_oid(cert, GNUTLS_OID_LDAP_UID, 0, uid_str.data(), uid_str.length());
{
random_device rdev;
std::uniform_int_distribution<uint64_t> dist{};
uint64_t cert_serial = dist(rdev);
gnutls_x509_crt_set_serial(cert, &cert_serial, sizeof(cert_serial));
}
setRandomSerial(cert);
unsigned key_usage = 0;
if (is_ca) {
@@ -975,15 +1107,13 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
// Signing certificate must be CA.
return {};
}
//if (gnutls_x509_crt_sign2(cert, ca.second->cert, ca.first->x509_key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
if (gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
if (gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, pk.getPreferredDigest(), 0) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when signing certificate" << std::endl;
return {};
}
ret.issuer = ca.second;
} else {
//if (gnutls_x509_crt_sign2(cert, cert, key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
if (gnutls_x509_crt_privkey_sign(cert, cert, key.key, get_dig(cert), 0) != GNUTLS_E_SUCCESS) {
if (gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0) != GNUTLS_E_SUCCESS) {
std::cerr << "Error when signing certificate" << std::endl;
return {};
}
@@ -992,6 +1122,31 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
return ret.getPacked();
}
Certificate
Certificate::generate(const CertificateRequest& request, const Identity& ca)
{
gnutls_x509_crt_t cert;
if (auto err = gnutls_x509_crt_init(&cert))
throw CryptoException(std::string("Can't initialize certificate: ") + gnutls_strerror(err));
Certificate ret {cert};
if (auto err = gnutls_x509_crt_set_crq(cert, request.get()))
throw CryptoException(std::string("Can't initialize certificate: ") + gnutls_strerror(err));
if (auto err = gnutls_x509_crt_set_version(cert, 3)) {
throw CryptoException(std::string("Can't set certificate version: ") + gnutls_strerror(err));
}
setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
setRandomSerial(cert);
if (auto err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) {
throw CryptoException(std::string("Can't sign certificate: ") + gnutls_strerror(err));
}
ret.issuer = ca.second;
return ret.getPacked();
}
std::vector<std::shared_ptr<RevocationList>>
Certificate::getRevocationLists() const
{
@@ -1002,6 +1157,8 @@ Certificate::getRevocationLists() const
return ret;
}
// RevocationList
RevocationList::RevocationList()
{
gnutls_x509_crl_init(&crl);
@@ -1219,6 +1376,8 @@ RevocationList::toString() const
return ret;
}
// TrustList
TrustList::TrustList() {
gnutls_x509_trust_list_init(&trust, 0);
}
+28 -1
View File
@@ -54,7 +54,6 @@ CryptoTester::testCertificateRevocation()
auto device11 = dht::crypto::generateIdentity("dev11", account1);
auto device12 = dht::crypto::generateIdentity("dev12", account1);
dht::crypto::TrustList list;
list.add(*ca1.second);
auto v = list.verify(*account1.second);
@@ -83,6 +82,34 @@ CryptoTester::testCertificateRevocation()
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
}
void
CryptoTester::testCertificateRequest()
{
// Generate CA
auto ca = dht::crypto::generateIdentity("Test CA");
// Generate signed request
auto deviceKey = dht::crypto::PrivateKey::generate();
auto request = dht::crypto::CertificateRequest();
request.setName("Test Device");
request.sign(deviceKey);
// Export/import request
auto importedRequest = dht::crypto::CertificateRequest(request.pack());
CPPUNIT_ASSERT(importedRequest.verify());
// Generate/sign certificate from request
auto signedCert = dht::crypto::Certificate::generate(request, ca);
CPPUNIT_ASSERT_EQUAL(ca.second->getName(), signedCert.getIssuerName());
CPPUNIT_ASSERT_EQUAL(request.getName(), signedCert.getName());
// Check generated certificate
dht::crypto::TrustList list;
list.add(*ca.second);
auto v = list.verify(signedCert);
CPPUNIT_ASSERT_MESSAGE(v.toString(), v);
}
void
CryptoTester::tearDown() {
+5
View File
@@ -29,6 +29,7 @@ class CryptoTester : public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(CryptoTester);
CPPUNIT_TEST(testSignatureEncryption);
CPPUNIT_TEST(testCertificateRevocation);
CPPUNIT_TEST(testCertificateRequest);
CPPUNIT_TEST_SUITE_END();
public:
@@ -48,6 +49,10 @@ class CryptoTester : public CppUnit::TestFixture {
* Test certificate generation, validation and revocation
*/
void testCertificateRevocation();
/**
* Test certificate requests
*/
void testCertificateRequest();
};
} // namespace test