Skip to content

Commit d265329

Browse files
authored
Merge commit from fork
Fix for master
2 parents 56d9f38 + 4023128 commit d265329

File tree

4 files changed

+52
-10
lines changed

4 files changed

+52
-10
lines changed

lib/base/tlsutility.cpp

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -985,27 +985,47 @@ String BinaryToHex(const unsigned char* data, size_t length) {
985985

986986
bool VerifyCertificate(const std::shared_ptr<X509> &caCertificate, const std::shared_ptr<X509> &certificate, const String& crlFile)
987987
{
988-
X509_STORE *store = X509_STORE_new();
988+
return VerifyCertificate(caCertificate.get(), certificate.get(), crlFile);
989+
}
990+
991+
bool VerifyCertificate(X509* caCertificate, X509* certificate, const String& crlFile)
992+
{
993+
#if OPENSSL_VERSION_NUMBER < 0x10100000L
994+
/*
995+
* OpenSSL older than version 1.1.0 stored a valid flag in the struct behind X509* which leads to certain validation
996+
* steps to be skipped on subsequent verification operations. If a certificate is verified multiple times with a
997+
* different configuration, for example with different trust anchors, this can result in the certificate
998+
* incorrectly being treated as valid.
999+
*
1000+
* This issue is worked around by serializing and deserializing the certificate which creates a new struct instance
1001+
* with the valid flag cleared, hence performing the full validation.
1002+
*
1003+
* The flag in question was removed in OpenSSL 1.1.0, so this extra step isn't necessary for more recent versions:
1004+
* https://github.com/openssl/openssl/commit/0e76014e584ba78ef1d6ecb4572391ef61c4fb51
1005+
*/
1006+
std::shared_ptr<X509> copy = StringToCertificate(CertificateToString(certificate));
1007+
VERIFY(copy.get() != certificate);
1008+
certificate = copy.get();
1009+
#endif
1010+
1011+
std::unique_ptr<X509_STORE, decltype(&X509_STORE_free)> store{X509_STORE_new(), &X509_STORE_free};
9891012

9901013
if (!store)
9911014
return false;
9921015

993-
X509_STORE_add_cert(store, caCertificate.get());
1016+
X509_STORE_add_cert(store.get(), caCertificate);
9941017

9951018
if (!crlFile.IsEmpty()) {
996-
AddCRLToSSLContext(store, crlFile);
1019+
AddCRLToSSLContext(store.get(), crlFile);
9971020
}
9981021

999-
X509_STORE_CTX *csc = X509_STORE_CTX_new();
1000-
X509_STORE_CTX_init(csc, store, certificate.get(), nullptr);
1001-
1002-
int rc = X509_verify_cert(csc);
1022+
std::unique_ptr<X509_STORE_CTX, decltype(&X509_STORE_CTX_free)> csc{X509_STORE_CTX_new(), &X509_STORE_CTX_free};
1023+
X509_STORE_CTX_init(csc.get(), store.get(), certificate, nullptr);
10031024

1004-
X509_STORE_CTX_free(csc);
1005-
X509_STORE_free(store);
1025+
int rc = X509_verify_cert(csc.get());
10061026

10071027
if (rc == 0) {
1008-
int err = X509_STORE_CTX_get_error(csc);
1028+
int err = X509_STORE_CTX_get_error(csc.get());
10091029

10101030
BOOST_THROW_EXCEPTION(openssl_error()
10111031
<< boost::errinfo_api_function("X509_verify_cert")

lib/base/tlsutility.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ String RandomString(int length);
7979
String BinaryToHex(const unsigned char* data, size_t length);
8080

8181
bool VerifyCertificate(const std::shared_ptr<X509>& caCertificate, const std::shared_ptr<X509>& certificate, const String& crlFile);
82+
bool VerifyCertificate(X509* caCertificate, X509* certificate, const String& crlFile);
8283
bool IsCa(const std::shared_ptr<X509>& cacert);
8384
int GetCertificateVersion(const std::shared_ptr<X509>& cert);
8485
String GetSignatureAlgorithm(const std::shared_ptr<X509>& cert);

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ add_boost_test(base
178178
base_tlsutility/iscertuptodate_ok
179179
base_tlsutility/iscertuptodate_expiring
180180
base_tlsutility/iscertuptodate_old
181+
base_tlsutility/VerifyCertificate_revalidate
181182
base_utility/parse_version
182183
base_utility/compare_version
183184
base_utility/comparepasswords_works

test/base-tlsutility.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,24 @@ BOOST_AUTO_TEST_CASE(iscertuptodate_old)
132132
})));
133133
}
134134

135+
BOOST_AUTO_TEST_CASE(VerifyCertificate_revalidate)
136+
{
137+
X509_NAME *caSubject = X509_NAME_new();
138+
X509_NAME_add_entry_by_txt(caSubject, "CN", MBSTRING_ASC, (const unsigned char*)"Icinga CA", -1, -1, 0);
139+
140+
auto signingCaKey = GenKeypair();
141+
auto signingCaCert = CreateCert(signingCaKey, caSubject, caSubject, signingCaKey, true);
142+
143+
X509_NAME *leafSubject = X509_NAME_new();
144+
X509_NAME_add_entry_by_txt(leafSubject, "CN", MBSTRING_ASC, (const unsigned char*)"Leaf Certificate", -1, -1, 0);
145+
auto leafKey = GenKeypair();
146+
auto leafCert = CreateCert(leafKey, leafSubject, caSubject, signingCaKey, false);
147+
BOOST_CHECK(VerifyCertificate(signingCaCert, leafCert, ""));
148+
149+
// Create a second CA with a different key, the leaf certificate is supposed to fail validation against that CA.
150+
auto otherCaKey = GenKeypair();
151+
auto otherCaCert = CreateCert(otherCaKey, caSubject, caSubject, otherCaKey, true);
152+
BOOST_CHECK_THROW(VerifyCertificate(otherCaCert, leafCert, ""), openssl_error);
153+
}
154+
135155
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)