@@ -985,27 +985,47 @@ String BinaryToHex(const unsigned char* data, size_t length) {
985
985
986
986
bool VerifyCertificate (const std::shared_ptr<X509> &caCertificate, const std::shared_ptr<X509> &certificate, const String& crlFile)
987
987
{
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};
989
1012
990
1013
if (!store)
991
1014
return false ;
992
1015
993
- X509_STORE_add_cert (store, caCertificate .get ());
1016
+ X509_STORE_add_cert (store.get (), caCertificate );
994
1017
995
1018
if (!crlFile.IsEmpty ()) {
996
- AddCRLToSSLContext (store, crlFile);
1019
+ AddCRLToSSLContext (store. get () , crlFile);
997
1020
}
998
1021
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 );
1003
1024
1004
- X509_STORE_CTX_free (csc);
1005
- X509_STORE_free (store);
1025
+ int rc = X509_verify_cert (csc.get ());
1006
1026
1007
1027
if (rc == 0 ) {
1008
- int err = X509_STORE_CTX_get_error (csc);
1028
+ int err = X509_STORE_CTX_get_error (csc. get () );
1009
1029
1010
1030
BOOST_THROW_EXCEPTION (openssl_error ()
1011
1031
<< boost::errinfo_api_function (" X509_verify_cert" )
0 commit comments