]> granicus.if.org Git - icinga2/commitdiff
Use hash-based serial numbers for new certificates
authorGunnar Beutner <gunnar.beutner@netways.de>
Tue, 16 Aug 2016 13:01:54 +0000 (15:01 +0200)
committerGunnar Beutner <gunnar.beutner@netways.de>
Tue, 16 Aug 2016 13:03:01 +0000 (15:03 +0200)
fixes #12453

lib/base/tlsutility.cpp
lib/base/tlsutility.hpp
lib/cli/pkiutility.cpp

index fc31d3990076f3b58b63e81d477edb8d7aed0bf2..409a1dcc52f327d87f2a544844c72204c40773d8 100644 (file)
@@ -318,7 +318,7 @@ boost::shared_ptr<X509> GetX509Certificate(const String& pemfile)
        return boost::shared_ptr<X509>(cert, X509_free);
 }
 
-int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile, const String& certfile, const String& serialfile, bool ca)
+int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile, const String& certfile, bool ca)
 {
        char errbuf[120];
 
@@ -362,7 +362,7 @@ int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile,
                X509_NAME *subject = X509_NAME_new();
                X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (unsigned char *)cn.CStr(), -1, -1, 0);
 
-               boost::shared_ptr<X509> cert = CreateCert(key, subject, subject, key, ca, serialfile);
+               boost::shared_ptr<X509> cert = CreateCert(key, subject, subject, key, ca);
 
                X509_NAME_free(subject);
 
@@ -439,7 +439,7 @@ int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile,
        return 1;
 }
 
-boost::shared_ptr<X509> CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PKEY *cakey, bool ca, const String& serialfile)
+boost::shared_ptr<X509> CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PKEY *cakey, bool ca)
 {
        X509 *cert = X509_new();
        X509_set_version(cert, 2);
@@ -450,29 +450,40 @@ boost::shared_ptr<X509> CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NA
        X509_set_subject_name(cert, subject);
        X509_set_issuer_name(cert, issuer);
 
-       int serial = 1;
+       String id = Utility::NewUniqueID();
 
-       if (!serialfile.IsEmpty()) {
-               if (Utility::PathExists(serialfile)) {
-                       std::ifstream ifp;
-                       ifp.open(serialfile.CStr());
-                       ifp >> std::hex >> serial;
-                       ifp.close();
+       char errbuf[120];
+       SHA_CTX context;
+       unsigned char digest[SHA_DIGEST_LENGTH];
 
-                       if (ifp.fail())
-                               BOOST_THROW_EXCEPTION(std::runtime_error("Could not read serial file."));
-               }
+       if (!SHA1_Init(&context)) {
+               Log(LogCritical, "SSL")
+                   << "Error on SHA1 Init: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
+               BOOST_THROW_EXCEPTION(openssl_error()
+                   << boost::errinfo_api_function("SHA1_Init")
+                   << errinfo_openssl_error(ERR_peek_error()));
+       }
 
-               std::ofstream ofp;
-               ofp.open(serialfile.CStr());
-               ofp << std::hex << std::setw(2) << std::setfill('0') << serial + 1;
-               ofp.close();
+       if (!SHA1_Update(&context, (unsigned char*)id.CStr(), id.GetLength())) {
+               Log(LogCritical, "SSL")
+                   << "Error on SHA1 Update: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
+               BOOST_THROW_EXCEPTION(openssl_error()
+                   << boost::errinfo_api_function("SHA1_Update")
+                   << errinfo_openssl_error(ERR_peek_error()));
+       }
 
-               if (ofp.fail())
-                       BOOST_THROW_EXCEPTION(std::runtime_error("Could not update serial file."));
+       if (!SHA1_Final(digest, &context)) {
+               Log(LogCritical, "SSL")
+                   << "Error on SHA1 Final: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
+               BOOST_THROW_EXCEPTION(openssl_error()
+                   << boost::errinfo_api_function("SHA1_Final")
+                   << errinfo_openssl_error(ERR_peek_error()));
        }
 
-       ASN1_INTEGER_set(X509_get_serialNumber(cert), serial);
+       BIGNUM *bn = BN_new();
+       BN_bin2bn(digest, sizeof(digest), bn);
+       BN_to_ASN1_INTEGER(bn, X509_get_serialNumber(cert));
+       BN_free(bn);
 
        X509V3_CTX ctx;
        X509V3_set_ctx_nodb(&ctx);
@@ -548,7 +559,7 @@ boost::shared_ptr<X509> CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject)
        EVP_PKEY *privkey = EVP_PKEY_new();
        EVP_PKEY_assign_RSA(privkey, rsa);
 
-       return CreateCert(pubkey, subject, X509_get_subject_name(cacert.get()), privkey, false, cadir + "/serial.txt");
+       return CreateCert(pubkey, subject, X509_get_subject_name(cacert.get()), privkey, false);
 }
 
 String CertificateToString(const boost::shared_ptr<X509>& cert)
index aef59af44c1904dfad0445dd165b2210cda6db75..3c37b072c33ec74864632aa8dc399e1368c9df09 100644 (file)
@@ -44,12 +44,13 @@ void I2_BASE_API SetCipherListToSSLContext(const boost::shared_ptr<SSL_CTX>& con
 void I2_BASE_API SetTlsProtocolminToSSLContext(const boost::shared_ptr<SSL_CTX>& context, const String& tlsProtocolmin);
 String I2_BASE_API GetCertificateCN(const boost::shared_ptr<X509>& certificate);
 boost::shared_ptr<X509> I2_BASE_API GetX509Certificate(const String& pemfile);
-int I2_BASE_API MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile = String(), const String& certfile = String(), const String& serialFile = String(), bool ca = false);
-boost::shared_ptr<X509> I2_BASE_API CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PKEY *cakey, bool ca, const String& serialfile = String());
+int I2_BASE_API MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile = String(), const String& certfile = String(), bool ca = false);
+boost::shared_ptr<X509> I2_BASE_API CreateCert(EVP_PKEY *pubkey, X509_NAME *subject, X509_NAME *issuer, EVP_PKEY *cakey, bool ca);
 String I2_BASE_API GetIcingaCADir(void);
 String I2_BASE_API CertificateToString(const boost::shared_ptr<X509>& cert);
 boost::shared_ptr<X509> I2_BASE_API CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject);
 String I2_BASE_API PBKDF2_SHA1(const String& password, const String& salt, int iterations);
+String I2_BASE_API SHA1(const String& s);
 String I2_BASE_API SHA256(const String& s);
 String I2_BASE_API RandomString(int length);
 
index fd2487066cc1c97fbbb969ff1716362c0c758a9d..8fe8d67f36a28399ebe919783cef985a8286b461 100644 (file)
@@ -49,7 +49,6 @@ int PkiUtility::NewCa(void)
        String caDir = GetLocalCaPath();
        String caCertFile = caDir + "/ca.crt";
        String caKeyFile = caDir + "/ca.key";
-       String caSerialFile = caDir + "/serial.txt";
 
        if (Utility::PathExists(caCertFile) && Utility::PathExists(caKeyFile)) {
                Log(LogCritical, "cli")
@@ -59,7 +58,7 @@ int PkiUtility::NewCa(void)
 
        Utility::MkDirP(caDir, 0700);
 
-       MakeX509CSR("Icinga CA", caKeyFile, String(), caCertFile, caSerialFile, true);
+       MakeX509CSR("Icinga CA", caKeyFile, String(), caCertFile, true);
 
        return 0;
 }