Use hash-based serial numbers for new certificates

fixes #12453
This commit is contained in:
Gunnar Beutner 2016-08-16 15:01:54 +02:00
parent ae38f160de
commit ec87b9e795
3 changed files with 38 additions and 27 deletions

View File

@ -318,7 +318,7 @@ boost::shared_ptr<X509> GetX509Certificate(const String& pemfile)
return boost::shared_ptr<X509>(cert, X509_free); 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]; 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 *subject = X509_NAME_new();
X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC, (unsigned char *)cn.CStr(), -1, -1, 0); 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); X509_NAME_free(subject);
@ -439,7 +439,7 @@ int MakeX509CSR(const String& cn, const String& keyfile, const String& csrfile,
return 1; 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 *cert = X509_new();
X509_set_version(cert, 2); 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_subject_name(cert, subject);
X509_set_issuer_name(cert, issuer); X509_set_issuer_name(cert, issuer);
int serial = 1; String id = Utility::NewUniqueID();
if (!serialfile.IsEmpty()) { char errbuf[120];
if (Utility::PathExists(serialfile)) { SHA_CTX context;
std::ifstream ifp; unsigned char digest[SHA_DIGEST_LENGTH];
ifp.open(serialfile.CStr());
ifp >> std::hex >> serial;
ifp.close();
if (ifp.fail()) if (!SHA1_Init(&context)) {
BOOST_THROW_EXCEPTION(std::runtime_error("Could not read serial file.")); 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; if (!SHA1_Update(&context, (unsigned char*)id.CStr(), id.GetLength())) {
ofp.open(serialfile.CStr()); Log(LogCritical, "SSL")
ofp << std::hex << std::setw(2) << std::setfill('0') << serial + 1; << "Error on SHA1 Update: " << ERR_peek_error() << ", \"" << ERR_error_string(ERR_peek_error(), errbuf) << "\"";
ofp.close(); BOOST_THROW_EXCEPTION(openssl_error()
<< boost::errinfo_api_function("SHA1_Update")
if (ofp.fail()) << errinfo_openssl_error(ERR_peek_error()));
BOOST_THROW_EXCEPTION(std::runtime_error("Could not update serial file."));
} }
ASN1_INTEGER_set(X509_get_serialNumber(cert), serial); 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()));
}
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_CTX ctx;
X509V3_set_ctx_nodb(&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 *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, cadir + "/serial.txt"); return CreateCert(pubkey, subject, X509_get_subject_name(cacert.get()), privkey, false);
} }
String CertificateToString(const boost::shared_ptr<X509>& cert) String CertificateToString(const boost::shared_ptr<X509>& cert)

View 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); 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); String I2_BASE_API GetCertificateCN(const boost::shared_ptr<X509>& certificate);
boost::shared_ptr<X509> I2_BASE_API GetX509Certificate(const String& pemfile); 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); 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, const String& serialfile = String()); 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 GetIcingaCADir(void);
String I2_BASE_API CertificateToString(const boost::shared_ptr<X509>& cert); 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); 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 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 SHA256(const String& s);
String I2_BASE_API RandomString(int length); String I2_BASE_API RandomString(int length);

View File

@ -49,7 +49,6 @@ int PkiUtility::NewCa(void)
String caDir = GetLocalCaPath(); String caDir = GetLocalCaPath();
String caCertFile = caDir + "/ca.crt"; String caCertFile = caDir + "/ca.crt";
String caKeyFile = caDir + "/ca.key"; String caKeyFile = caDir + "/ca.key";
String caSerialFile = caDir + "/serial.txt";
if (Utility::PathExists(caCertFile) && Utility::PathExists(caKeyFile)) { if (Utility::PathExists(caCertFile) && Utility::PathExists(caKeyFile)) {
Log(LogCritical, "cli") Log(LogCritical, "cli")
@ -59,7 +58,7 @@ int PkiUtility::NewCa(void)
Utility::MkDirP(caDir, 0700); Utility::MkDirP(caDir, 0700);
MakeX509CSR("Icinga CA", caKeyFile, String(), caCertFile, caSerialFile, true); MakeX509CSR("Icinga CA", caKeyFile, String(), caCertFile, true);
return 0; return 0;
} }