From 1b2bc7b1e34e075dd1eb72d458a1c4859454ffa0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Blin?=
 <sebastien.blin@savoirfairelinux.com>
Date: Mon, 3 Jan 2022 16:10:01 -0500
Subject: [PATCH] crypto: add parameter to change Certificate's validity period

This allow to create certificate with a different validity than
10 years and be able to change the expiration of a certificate
---
 include/opendht/crypto.h | 10 ++++++++--
 src/crypto.cpp           | 34 ++++++++++++++++++++++++++++++----
 2 files changed, 38 insertions(+), 6 deletions(-)

diff --git a/include/opendht/crypto.h b/include/opendht/crypto.h
index c734b704..70b68f52 100644
--- a/include/opendht/crypto.h
+++ b/include/opendht/crypto.h
@@ -541,8 +541,8 @@ struct OPENDHT_PUBLIC Certificate {
     void addRevocationList(RevocationList&&);
     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);
+    static Certificate generate(const PrivateKey& key, const std::string& name = "dhtnode", const Identity& ca = {}, bool is_ca = false, int64_t validity = 0);
+    static Certificate generate(const CertificateRequest& request, const Identity& ca, int64_t validity = 0);
 
     gnutls_x509_crt_t getCopy() const {
         if (not cert)
@@ -592,6 +592,12 @@ struct OPENDHT_PUBLIC Certificate {
      */
     std::pair<std::string, Blob> generateOcspRequest(gnutls_x509_crt_t& issuer);
 
+    /**
+     * Change certificate's expiration
+     */
+    void setValidity(const Identity& ca, int64_t validity);
+    void setValidity(const PrivateKey& key, int64_t validity);
+
     gnutls_x509_crt_t cert {nullptr};
     std::shared_ptr<Certificate> issuer {};
     std::shared_ptr<OcspResponse> ocspResponse;
diff --git a/src/crypto.cpp b/src/crypto.cpp
index e5c7f83d..4dad2584 100644
--- a/src/crypto.cpp
+++ b/src/crypto.cpp
@@ -1163,14 +1163,14 @@ setRandomSerial(gnutls_x509_crt_t cert)
 }
 
 Certificate
-Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca)
+Certificate::generate(const PrivateKey& key, const std::string& name, const Identity& ca, bool is_ca, int64_t validity)
 {
     gnutls_x509_crt_t cert;
     if (not key.x509_key or gnutls_x509_crt_init(&cert) != GNUTLS_E_SUCCESS)
         return {};
     Certificate ret {cert};
 
-    setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
+    setValidityPeriod(cert, validity <= 0 ? 10 * 365 * 24 * 60 * 60 : validity);
     if (int err = gnutls_x509_crt_set_key(cert, key.x509_key)) {
         throw CryptoException(std::string("Error when setting certificate key ") + gnutls_strerror(err));
     }
@@ -1216,7 +1216,7 @@ Certificate::generate(const PrivateKey& key, const std::string& name, const Iden
 }
 
 Certificate
-Certificate::generate(const CertificateRequest& request, const Identity& ca)
+Certificate::generate(const CertificateRequest& request, const Identity& ca, int64_t validity)
 {
     gnutls_x509_crt_t cert;
     if (auto err = gnutls_x509_crt_init(&cert))
@@ -1229,7 +1229,7 @@ Certificate::generate(const CertificateRequest& request, const Identity& ca)
         throw CryptoException(std::string("Can't set certificate version: ") + gnutls_strerror(err));
     }
 
-    setValidityPeriod(cert, 10 * 365 * 24 * 60 * 60);
+    setValidityPeriod(cert, validity <= 0 ? 10 * 365 * 24 * 60 * 60 : validity);
     setRandomSerial(cert);
 
     if (auto err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) {
@@ -1240,6 +1240,32 @@ Certificate::generate(const CertificateRequest& request, const Identity& ca)
     return ret.getPacked();
 }
 
+void
+Certificate::setValidity(const Identity& ca, int64_t validity)
+{
+    setValidityPeriod(cert, validity);
+    setRandomSerial(cert);
+    if (ca.first && ca.second) {
+        if (not ca.second->isCA()) {
+            throw CryptoException("Signing certificate must be CA");
+        }
+        if (int err = gnutls_x509_crt_privkey_sign(cert, ca.second->cert, ca.first->key, ca.second->getPreferredDigest(), 0)) {
+            throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
+        }
+    }
+}
+
+void
+Certificate::setValidity(const PrivateKey& key, int64_t validity)
+{
+    setValidityPeriod(cert, validity);
+    setRandomSerial(cert);
+    const auto& pk = key.getPublicKey();
+    if (int err = gnutls_x509_crt_privkey_sign(cert, cert, key.key, pk.getPreferredDigest(), 0)) {
+        throw CryptoException(std::string("Error when signing certificate ") + gnutls_strerror(err));
+    }
+}
+
 std::vector<std::shared_ptr<RevocationList>>
 Certificate::getRevocationLists() const
 {
-- 
GitLab