mirror of
https://github.com/savoirfairelinux/opendht.git
synced 2026-11-09 04:49:14 +00:00
Compare commits
2
Commits
1.8.2
...
cert_request
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d80aab9399 | ||
|
|
9b881d4e95 |
No files matched your search
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -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() {
|
||||
|
||||
|
||||
@@ -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
|
||||
Reference in new issue
Block a user