mirror of
https://github.com/Icinga/icinga2.git
synced 2025-04-08 17:05:25 +02:00
Merge pull request #9933 from Icinga/renew-the-ca-9890-214
ApiListener#Start(): auto-renew CA on its owner
This commit is contained in:
commit
5059d0f8b0
@ -714,7 +714,7 @@ String GetIcingaCADir()
|
|||||||
return Configuration::DataDir + "/ca";
|
return Configuration::DataDir + "/ca";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<X509> CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject)
|
std::shared_ptr<X509> CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject, bool ca)
|
||||||
{
|
{
|
||||||
char errbuf[256];
|
char errbuf[256];
|
||||||
|
|
||||||
@ -751,7 +751,7 @@ std::shared_ptr<X509> CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject)
|
|||||||
EVP_PKEY *privkey = EVP_PKEY_new();
|
EVP_PKEY *privkey = EVP_PKEY_new();
|
||||||
EVP_PKEY_assign_RSA(privkey, rsa);
|
EVP_PKEY_assign_RSA(privkey, rsa);
|
||||||
|
|
||||||
return CreateCert(pubkey, subject, X509_get_subject_name(cacert.get()), privkey, false);
|
return CreateCert(pubkey, subject, X509_get_subject_name(cacert.get()), privkey, ca);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<X509> CreateCertIcingaCA(const std::shared_ptr<X509>& cert)
|
std::shared_ptr<X509> CreateCertIcingaCA(const std::shared_ptr<X509>& cert)
|
||||||
@ -760,24 +760,37 @@ std::shared_ptr<X509> CreateCertIcingaCA(const std::shared_ptr<X509>& cert)
|
|||||||
return CreateCertIcingaCA(pkey.get(), X509_get_subject_name(cert.get()));
|
return CreateCertIcingaCA(pkey.get(), X509_get_subject_name(cert.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
bool CertExpiresWithin(X509* cert, int seconds)
|
||||||
|
{
|
||||||
|
time_t renewalStart = time(nullptr) + seconds;
|
||||||
|
|
||||||
|
return X509_cmp_time(X509_get_notAfter(cert), &renewalStart) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool IsCertUptodate(const std::shared_ptr<X509>& cert)
|
bool IsCertUptodate(const std::shared_ptr<X509>& cert)
|
||||||
{
|
{
|
||||||
time_t now;
|
if (CertExpiresWithin(cert.get(), RENEW_THRESHOLD)) {
|
||||||
time(&now);
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* auto-renew all certificates which were created before 2017 to force an update of the CA,
|
/* auto-renew all certificates which were created before 2017 to force an update of the CA,
|
||||||
* because Icinga versions older than 2.4 sometimes create certificates with an invalid
|
* because Icinga versions older than 2.4 sometimes create certificates with an invalid
|
||||||
* serial number. */
|
* serial number. */
|
||||||
time_t forceRenewalEnd = 1483228800; /* January 1st, 2017 */
|
time_t forceRenewalEnd = 1483228800; /* January 1st, 2017 */
|
||||||
time_t renewalStart = now + RENEW_THRESHOLD;
|
|
||||||
|
|
||||||
return X509_cmp_time(X509_get_notBefore(cert.get()), &forceRenewalEnd) != -1 && X509_cmp_time(X509_get_notAfter(cert.get()), &renewalStart) != -1;
|
return X509_cmp_time(X509_get_notBefore(cert.get()), &forceRenewalEnd) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
String CertificateToString(const std::shared_ptr<X509>& cert)
|
bool IsCaUptodate(X509* cert)
|
||||||
|
{
|
||||||
|
return !CertExpiresWithin(cert, LEAF_VALID_FOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
String CertificateToString(X509* cert)
|
||||||
{
|
{
|
||||||
BIO *mem = BIO_new(BIO_s_mem());
|
BIO *mem = BIO_new(BIO_s_mem());
|
||||||
PEM_write_bio_X509(mem, cert.get());
|
PEM_write_bio_X509(mem, cert);
|
||||||
|
|
||||||
char *data;
|
char *data;
|
||||||
long len = BIO_get_mem_data(mem, &data);
|
long len = BIO_get_mem_data(mem, &data);
|
||||||
|
@ -58,12 +58,18 @@ int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile =
|
|||||||
std::shared_ptr<X509> CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PKEY *cakey, bool ca);
|
std::shared_ptr<X509> CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PKEY *cakey, bool ca);
|
||||||
|
|
||||||
String GetIcingaCADir();
|
String GetIcingaCADir();
|
||||||
String CertificateToString(const std::shared_ptr<X509>& cert);
|
String CertificateToString(X509* cert);
|
||||||
|
|
||||||
|
inline String CertificateToString(const std::shared_ptr<X509>& cert)
|
||||||
|
{
|
||||||
|
return CertificateToString(cert.get());
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<X509> StringToCertificate(const String& cert);
|
std::shared_ptr<X509> StringToCertificate(const String& cert);
|
||||||
std::shared_ptr<X509> CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject);
|
std::shared_ptr<X509> CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject, bool ca = false);
|
||||||
std::shared_ptr<X509> CreateCertIcingaCA(const std::shared_ptr<X509>& cert);
|
std::shared_ptr<X509> CreateCertIcingaCA(const std::shared_ptr<X509>& cert);
|
||||||
bool IsCertUptodate(const std::shared_ptr<X509>& cert);
|
bool IsCertUptodate(const std::shared_ptr<X509>& cert);
|
||||||
|
bool IsCaUptodate(X509* cert);
|
||||||
|
|
||||||
String PBKDF2_SHA1(const String& password, const String& salt, int iterations);
|
String PBKDF2_SHA1(const String& password, const String& salt, int iterations);
|
||||||
String PBKDF2_SHA256(const String& password, const String& salt, int iterations);
|
String PBKDF2_SHA256(const String& password, const String& salt, int iterations);
|
||||||
|
@ -181,12 +181,12 @@ void ApiListener::OnConfigLoaded()
|
|||||||
UpdateSSLContext();
|
UpdateSSLContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<X509> ApiListener::RenewCert(const std::shared_ptr<X509>& cert)
|
std::shared_ptr<X509> ApiListener::RenewCert(const std::shared_ptr<X509>& cert, bool ca)
|
||||||
{
|
{
|
||||||
std::shared_ptr<EVP_PKEY> pubkey (X509_get_pubkey(cert.get()), EVP_PKEY_free);
|
std::shared_ptr<EVP_PKEY> pubkey (X509_get_pubkey(cert.get()), EVP_PKEY_free);
|
||||||
auto subject (X509_get_subject_name(cert.get()));
|
auto subject (X509_get_subject_name(cert.get()));
|
||||||
auto cacert (GetX509Certificate(GetDefaultCaPath()));
|
auto cacert (GetX509Certificate(GetDefaultCaPath()));
|
||||||
auto newcert (CreateCertIcingaCA(pubkey.get(), subject));
|
auto newcert (CreateCertIcingaCA(pubkey.get(), subject, ca));
|
||||||
|
|
||||||
/* verify that the new cert matches the CA we're using for the ApiListener;
|
/* verify that the new cert matches the CA we're using for the ApiListener;
|
||||||
* this ensures that the CA we have in /var/lib/icinga2/ca matches the one
|
* this ensures that the CA we have in /var/lib/icinga2/ca matches the one
|
||||||
@ -248,7 +248,12 @@ void ApiListener::Start(bool runtimeCreated)
|
|||||||
|
|
||||||
if (Utility::PathExists(GetIcingaCADir() + "/ca.key")) {
|
if (Utility::PathExists(GetIcingaCADir() + "/ca.key")) {
|
||||||
RenewOwnCert();
|
RenewOwnCert();
|
||||||
m_RenewOwnCertTimer->OnTimerExpired.connect([this](const Timer * const&) { RenewOwnCert(); });
|
RenewCA();
|
||||||
|
|
||||||
|
m_RenewOwnCertTimer->OnTimerExpired.connect([this](const Timer * const&) {
|
||||||
|
RenewOwnCert();
|
||||||
|
RenewCA();
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
m_RenewOwnCertTimer->OnTimerExpired.connect([this](const Timer * const&) {
|
m_RenewOwnCertTimer->OnTimerExpired.connect([this](const Timer * const&) {
|
||||||
JsonRpcConnection::SendCertificateRequest(nullptr, nullptr, String());
|
JsonRpcConnection::SendCertificateRequest(nullptr, nullptr, String());
|
||||||
@ -329,6 +334,31 @@ void ApiListener::RenewOwnCert()
|
|||||||
UpdateSSLContext();
|
UpdateSSLContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ApiListener::RenewCA()
|
||||||
|
{
|
||||||
|
auto certPath (GetCaDir() + "/ca.crt");
|
||||||
|
auto cert (GetX509Certificate(certPath));
|
||||||
|
|
||||||
|
if (IsCaUptodate(cert.get())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log(LogInformation, "ApiListener")
|
||||||
|
<< "Our CA will expire soon, but we own it. Renewing.";
|
||||||
|
|
||||||
|
cert = RenewCert(cert, true);
|
||||||
|
|
||||||
|
if (!cert) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto certStr (CertificateToString(cert));
|
||||||
|
|
||||||
|
AtomicFile::Write(GetDefaultCaPath(), 0644, certStr);
|
||||||
|
AtomicFile::Write(certPath, 0644, certStr);
|
||||||
|
UpdateSSLContext();
|
||||||
|
}
|
||||||
|
|
||||||
void ApiListener::Stop(bool runtimeDeleted)
|
void ApiListener::Stop(bool runtimeDeleted)
|
||||||
{
|
{
|
||||||
m_ApiPackageIntegrityTimer->Stop(true);
|
m_ApiPackageIntegrityTimer->Stop(true);
|
||||||
|
@ -91,7 +91,7 @@ public:
|
|||||||
static String GetCaDir();
|
static String GetCaDir();
|
||||||
static String GetCertificateRequestsDir();
|
static String GetCertificateRequestsDir();
|
||||||
|
|
||||||
std::shared_ptr<X509> RenewCert(const std::shared_ptr<X509>& cert);
|
std::shared_ptr<X509> RenewCert(const std::shared_ptr<X509>& cert, bool ca = false);
|
||||||
void UpdateSSLContext();
|
void UpdateSSLContext();
|
||||||
|
|
||||||
static ApiListener::Ptr GetInstance();
|
static ApiListener::Ptr GetInstance();
|
||||||
@ -227,6 +227,7 @@ private:
|
|||||||
void SyncLocalZoneDirs() const;
|
void SyncLocalZoneDirs() const;
|
||||||
void SyncLocalZoneDir(const Zone::Ptr& zone) const;
|
void SyncLocalZoneDir(const Zone::Ptr& zone) const;
|
||||||
void RenewOwnCert();
|
void RenewOwnCert();
|
||||||
|
void RenewCA();
|
||||||
|
|
||||||
void SendConfigUpdate(const JsonRpcConnection::Ptr& aclient);
|
void SendConfigUpdate(const JsonRpcConnection::Ptr& aclient);
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include <boost/thread/once.hpp>
|
#include <boost/thread/once.hpp>
|
||||||
#include <boost/regex.hpp>
|
#include <boost/regex.hpp>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <openssl/asn1.h>
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
|
|
||||||
@ -31,11 +32,11 @@ Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictiona
|
|||||||
std::shared_ptr<X509> cert;
|
std::shared_ptr<X509> cert;
|
||||||
|
|
||||||
Dictionary::Ptr result = new Dictionary();
|
Dictionary::Ptr result = new Dictionary();
|
||||||
|
auto& tlsConn (origin->FromClient->GetStream()->next_layer());
|
||||||
|
|
||||||
/* Use the presented client certificate if not provided. */
|
/* Use the presented client certificate if not provided. */
|
||||||
if (certText.IsEmpty()) {
|
if (certText.IsEmpty()) {
|
||||||
auto stream (origin->FromClient->GetStream());
|
cert = tlsConn.GetPeerCertificate();
|
||||||
cert = stream->next_layer().GetPeerCertificate();
|
|
||||||
} else {
|
} else {
|
||||||
cert = StringToCertificate(certText);
|
cert = StringToCertificate(certText);
|
||||||
}
|
}
|
||||||
@ -77,13 +78,54 @@ Value RequestCertificateHandler(const MessageOrigin::Ptr& origin, const Dictiona
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signedByCA) {
|
std::shared_ptr<X509> parsedRequestorCA;
|
||||||
if (IsCertUptodate(cert)) {
|
X509* requestorCA = nullptr;
|
||||||
|
|
||||||
|
if (signedByCA) {
|
||||||
|
bool uptodate = IsCertUptodate(cert);
|
||||||
|
|
||||||
|
if (uptodate) {
|
||||||
|
// Even if the leaf is up-to-date, the root may expire soon.
|
||||||
|
// In a regular setup where Icinga manages the PKI, there is only one CA.
|
||||||
|
// Icinga includes it in handshakes, let's see whether the peer needs a fresh one...
|
||||||
|
|
||||||
|
if (cn == origin->FromClient->GetIdentity()) {
|
||||||
|
auto chain (SSL_get_peer_cert_chain(tlsConn.native_handle()));
|
||||||
|
|
||||||
|
if (chain) {
|
||||||
|
auto len (sk_X509_num(chain));
|
||||||
|
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
auto link (sk_X509_value(chain, i));
|
||||||
|
|
||||||
|
if (!X509_NAME_cmp(X509_get_subject_name(link), X509_get_issuer_name(link))) {
|
||||||
|
requestorCA = link;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Value requestorCaStr;
|
||||||
|
|
||||||
|
if (params->Get("requestor_ca", &requestorCaStr)) {
|
||||||
|
parsedRequestorCA = StringToCertificate(requestorCaStr);
|
||||||
|
requestorCA = parsedRequestorCA.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestorCA && !IsCaUptodate(requestorCA)) {
|
||||||
|
int days;
|
||||||
|
|
||||||
|
if (ASN1_TIME_diff(&days, nullptr, X509_get_notAfter(requestorCA), X509_get_notAfter(cacert.get())) && days > 0) {
|
||||||
|
uptodate = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uptodate) {
|
||||||
Log(LogInformation, "JsonRpcConnection")
|
Log(LogInformation, "JsonRpcConnection")
|
||||||
<< "The certificate for CN '" << cn << "' is valid and uptodate. Skipping automated renewal.";
|
<< "The certificates for CN '" << cn << "' and its root CA are valid and uptodate. Skipping automated renewal.";
|
||||||
result->Set("status_code", 1);
|
result->Set("status_code", 1);
|
||||||
result->Set("error", "The certificate for CN '" + cn + "' is valid and uptodate. Skipping automated renewal.");
|
result->Set("error", "The certificates for CN '" + cn + "' and its root CA are valid and uptodate. Skipping automated renewal.");
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,6 +272,10 @@ delayed_request:
|
|||||||
{ "ticket", params->Get("ticket") }
|
{ "ticket", params->Get("ticket") }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (requestorCA) {
|
||||||
|
request->Set("requestor_ca", CertificateToString(requestorCA));
|
||||||
|
}
|
||||||
|
|
||||||
Utility::SaveJsonFile(requestPath, 0600, request);
|
Utility::SaveJsonFile(requestPath, 0600, request);
|
||||||
|
|
||||||
JsonRpcConnection::SendCertificateRequest(nullptr, origin, requestPath);
|
JsonRpcConnection::SendCertificateRequest(nullptr, origin, requestPath);
|
||||||
@ -291,8 +337,7 @@ void JsonRpcConnection::SendCertificateRequest(const JsonRpcConnection::Ptr& acl
|
|||||||
if (request->Contains("cert_response"))
|
if (request->Contains("cert_response"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
params->Set("cert_request", request->Get("cert_request"));
|
request->CopyTo(params);
|
||||||
params->Set("ticket", request->Get("ticket"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send the request to a) the connected client
|
/* Send the request to a) the connected client
|
||||||
|
@ -109,6 +109,11 @@ add_boost_test(base
|
|||||||
base_timer/invoke
|
base_timer/invoke
|
||||||
base_timer/scope
|
base_timer/scope
|
||||||
base_tlsutility/sha1
|
base_tlsutility/sha1
|
||||||
|
base_tlsutility/iscauptodate_ok
|
||||||
|
base_tlsutility/iscauptodate_expiring
|
||||||
|
base_tlsutility/iscertuptodate_ok
|
||||||
|
base_tlsutility/iscertuptodate_expiring
|
||||||
|
base_tlsutility/iscertuptodate_old
|
||||||
base_type/gettype
|
base_type/gettype
|
||||||
base_type/assign
|
base_type/assign
|
||||||
base_type/byname
|
base_type/byname
|
||||||
|
@ -2,11 +2,61 @@
|
|||||||
|
|
||||||
#include "base/tlsutility.hpp"
|
#include "base/tlsutility.hpp"
|
||||||
#include <BoostTestTargetConfig.h>
|
#include <BoostTestTargetConfig.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
#include <openssl/asn1.h>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/obj_mac.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/x509.h>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
|
static EVP_PKEY* GenKeypair()
|
||||||
|
{
|
||||||
|
InitializeOpenSSL();
|
||||||
|
|
||||||
|
auto e (BN_new());
|
||||||
|
BOOST_REQUIRE(e);
|
||||||
|
|
||||||
|
auto rsa (RSA_new());
|
||||||
|
BOOST_REQUIRE(rsa);
|
||||||
|
|
||||||
|
auto key (EVP_PKEY_new());
|
||||||
|
BOOST_REQUIRE(key);
|
||||||
|
|
||||||
|
BOOST_REQUIRE(BN_set_word(e, RSA_F4));
|
||||||
|
BOOST_REQUIRE(RSA_generate_key_ex(rsa, 4096, e, nullptr));
|
||||||
|
BOOST_REQUIRE(EVP_PKEY_assign_RSA(key, rsa));
|
||||||
|
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::shared_ptr<X509> MakeCert(const char* issuer, EVP_PKEY* signer, const char* subject, EVP_PKEY* pubkey, std::function<void(ASN1_TIME*, ASN1_TIME*)> setTimes)
|
||||||
|
{
|
||||||
|
auto cert (X509_new());
|
||||||
|
BOOST_REQUIRE(cert);
|
||||||
|
|
||||||
|
auto serial (BN_new());
|
||||||
|
BOOST_REQUIRE(serial);
|
||||||
|
|
||||||
|
BOOST_REQUIRE(X509_set_version(cert, 0x2));
|
||||||
|
BOOST_REQUIRE(BN_to_ASN1_INTEGER(serial, X509_get_serialNumber(cert)));
|
||||||
|
BOOST_REQUIRE(X509_NAME_add_entry_by_NID(X509_get_issuer_name(cert), NID_commonName, MBSTRING_ASC, (unsigned char*)issuer, -1, -1, 0));
|
||||||
|
setTimes(X509_get_notBefore(cert), X509_get_notAfter(cert));
|
||||||
|
BOOST_REQUIRE(X509_NAME_add_entry_by_NID(X509_get_subject_name(cert), NID_commonName, MBSTRING_ASC, (unsigned char*)subject, -1, -1, 0));
|
||||||
|
BOOST_REQUIRE(X509_set_pubkey(cert, pubkey));
|
||||||
|
BOOST_REQUIRE(X509_sign(cert, signer, EVP_sha256()));
|
||||||
|
|
||||||
|
return std::shared_ptr<X509>(cert, X509_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const long l_2016 = 1480000000; // Thu Nov 24 15:06:40 UTC 2016
|
||||||
|
static const long l_2017 = 1490000000; // Mon Mar 20 08:53:20 UTC 2017
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(base_tlsutility)
|
BOOST_AUTO_TEST_SUITE(base_tlsutility)
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(sha1)
|
BOOST_AUTO_TEST_CASE(sha1)
|
||||||
@ -35,4 +85,51 @@ BOOST_AUTO_TEST_CASE(sha1)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(iscauptodate_ok)
|
||||||
|
{
|
||||||
|
auto key (GenKeypair());
|
||||||
|
|
||||||
|
BOOST_CHECK(IsCaUptodate(MakeCert("Icinga CA", key, "Icinga CA", key, [](ASN1_TIME* notBefore, ASN1_TIME* notAfter) {
|
||||||
|
BOOST_REQUIRE(X509_gmtime_adj(notBefore, 0));
|
||||||
|
BOOST_REQUIRE(X509_gmtime_adj(notAfter, LEAF_VALID_FOR + 60 * 60));
|
||||||
|
}).get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(iscauptodate_expiring)
|
||||||
|
{
|
||||||
|
auto key (GenKeypair());
|
||||||
|
|
||||||
|
BOOST_CHECK(!IsCaUptodate(MakeCert("Icinga CA", key, "Icinga CA", key, [](ASN1_TIME* notBefore, ASN1_TIME* notAfter) {
|
||||||
|
BOOST_REQUIRE(X509_gmtime_adj(notBefore, 0));
|
||||||
|
BOOST_REQUIRE(X509_gmtime_adj(notAfter, LEAF_VALID_FOR - 60 * 60));
|
||||||
|
}).get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(iscertuptodate_ok)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(IsCertUptodate(MakeCert("Icinga CA", GenKeypair(), "example.com", GenKeypair(), [](ASN1_TIME* notBefore, ASN1_TIME* notAfter) {
|
||||||
|
time_t epoch = 0;
|
||||||
|
BOOST_REQUIRE(X509_time_adj(notBefore, l_2017, &epoch));
|
||||||
|
BOOST_REQUIRE(X509_gmtime_adj(notAfter, RENEW_THRESHOLD + 60 * 60));
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(iscertuptodate_expiring)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(!IsCertUptodate(MakeCert("Icinga CA", GenKeypair(), "example.com", GenKeypair(), [](ASN1_TIME* notBefore, ASN1_TIME* notAfter) {
|
||||||
|
time_t epoch = 0;
|
||||||
|
BOOST_REQUIRE(X509_time_adj(notBefore, l_2017, &epoch));
|
||||||
|
BOOST_REQUIRE(X509_gmtime_adj(notAfter, RENEW_THRESHOLD - 60 * 60));
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(iscertuptodate_old)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(!IsCertUptodate(MakeCert("Icinga CA", GenKeypair(), "example.com", GenKeypair(), [](ASN1_TIME* notBefore, ASN1_TIME* notAfter) {
|
||||||
|
time_t epoch = 0;
|
||||||
|
BOOST_REQUIRE(X509_time_adj(notBefore, l_2016, &epoch));
|
||||||
|
BOOST_REQUIRE(X509_gmtime_adj(notAfter, RENEW_THRESHOLD + 60 * 60));
|
||||||
|
})));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user