diff options
Diffstat (limited to 'src/network/ssl/qsslcertificate_openssl.cpp')
-rw-r--r-- | src/network/ssl/qsslcertificate_openssl.cpp | 88 |
1 files changed, 62 insertions, 26 deletions
diff --git a/src/network/ssl/qsslcertificate_openssl.cpp b/src/network/ssl/qsslcertificate_openssl.cpp index 5022b899aa..d1794d4dbd 100644 --- a/src/network/ssl/qsslcertificate_openssl.cpp +++ b/src/network/ssl/qsslcertificate_openssl.cpp @@ -44,6 +44,7 @@ #include "qsslkey_p.h" #include "qsslcertificateextension_p.h" +#include <QtCore/qscopeguard.h> #include <QtCore/qendian.h> #include <QtCore/qmutex.h> @@ -330,12 +331,11 @@ QSslKey QSslCertificate::publicKey() const */ static QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext) { - // Get the extension specific method object if available + Q_ASSERT(ext); + // Get the extension specific method object if available, // we cast away the const-ness here because some versions of openssl // don't use const for the parameters in the functions pointers stored // in the object. - Q_ASSERT(ext); - X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext)); if (!meth) { ASN1_OCTET_STRING *value = q_X509_EXTENSION_get_data(ext); @@ -345,18 +345,34 @@ static QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext) return result; } - //const unsigned char *data = ext->value->data; void *ext_internal = q_X509V3_EXT_d2i(ext); + if (!ext_internal) + return {}; + + const auto extCleaner = qScopeGuard([meth, ext_internal]{ + Q_ASSERT(ext_internal && meth); + + if (meth->it) + q_ASN1_item_free(static_cast<ASN1_VALUE *>(ext_internal), ASN1_ITEM_ptr(meth->it)); + else if (meth->ext_free) + meth->ext_free(ext_internal); + else + qCWarning(lcSsl, "No method to free an unknown extension, a potential memory leak?"); + }); // If this extension can be converted - if (meth->i2v && ext_internal) { + if (meth->i2v) { STACK_OF(CONF_VALUE) *val = meth->i2v(meth, ext_internal, nullptr); + const auto stackCleaner = qScopeGuard([val]{ + if (val) + q_OPENSSL_sk_pop_free((OPENSSL_STACK *)val, (void(*)(void*))q_X509V3_conf_free); + }); QVariantMap map; QVariantList list; bool isMap = false; - for (int j = 0; j < q_SKM_sk_num(CONF_VALUE, val); j++) { + for (int j = 0; j < q_SKM_sk_num(val); j++) { CONF_VALUE *nval = q_SKM_sk_value(CONF_VALUE, val, j); if (nval->name && nval->value) { isMap = true; @@ -372,10 +388,12 @@ static QVariant x509UnknownExtensionToValue(X509_EXTENSION *ext) return map; else return list; - } else if (meth->i2s && ext_internal) { - QVariant result(QString::fromUtf8(meth->i2s(meth, ext_internal))); + } else if (meth->i2s) { + const char *hexString = meth->i2s(meth, ext_internal); + QVariant result(hexString ? QString::fromUtf8(hexString) : QString{}); + q_OPENSSL_free((void *)hexString); return result; - } else if (meth->i2r && ext_internal) { + } else if (meth->i2r) { QByteArray result; BIO *bio = q_BIO_new(q_BIO_s_mem()); @@ -405,13 +423,36 @@ static QVariant x509ExtensionToValue(X509_EXTENSION *ext) ASN1_OBJECT *obj = q_X509_EXTENSION_get_object(ext); int nid = q_OBJ_obj2nid(obj); + // We cast away the const-ness here because some versions of openssl + // don't use const for the parameters in the functions pointers stored + // in the object. + X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext)); + + void *ext_internal = nullptr; // The value, returned by X509V3_EXT_d2i. + const auto extCleaner = qScopeGuard([meth, &ext_internal]() { + if (!meth || !ext_internal) + return; + + if (meth->it) + q_ASN1_item_free(static_cast<ASN1_VALUE *>(ext_internal), ASN1_ITEM_ptr(meth->it)); + else if (meth->ext_free) + meth->ext_free(ext_internal); + else + qWarning(lcSsl, "Cannot free an extension, a potential memory leak?"); + }); + + const char * hexString = nullptr; // The value returned by meth->i2s. + const auto hexStringCleaner = qScopeGuard([&hexString](){ + if (hexString) + q_OPENSSL_free((void*)hexString); + }); + switch (nid) { case NID_basic_constraints: { BASIC_CONSTRAINTS *basic = reinterpret_cast<BASIC_CONSTRAINTS *>(q_X509V3_EXT_d2i(ext)); if (!basic) - return QVariant(); - + return {}; QVariantMap result; result[QLatin1String("ca")] = basic->ca ? true : false; if (basic->pathlen) @@ -425,10 +466,9 @@ static QVariant x509ExtensionToValue(X509_EXTENSION *ext) { AUTHORITY_INFO_ACCESS *info = reinterpret_cast<AUTHORITY_INFO_ACCESS *>(q_X509V3_EXT_d2i(ext)); if (!info) - return QVariant(); - + return {}; QVariantMap result; - for (int i=0; i < q_SKM_sk_num(ACCESS_DESCRIPTION, info); i++) { + for (int i=0; i < q_SKM_sk_num(info); i++) { ACCESS_DESCRIPTION *ad = q_SKM_sk_value(ACCESS_DESCRIPTION, info, i); GENERAL_NAME *name = ad->location; @@ -448,29 +488,25 @@ static QVariant x509ExtensionToValue(X509_EXTENSION *ext) } } - q_OPENSSL_sk_pop_free((OPENSSL_STACK*)info, reinterpret_cast<void(*)(void *)>(q_OPENSSL_sk_free)); + q_AUTHORITY_INFO_ACCESS_free(info); return result; } break; case NID_subject_key_identifier: { - void *ext_internal = q_X509V3_EXT_d2i(ext); + ext_internal = q_X509V3_EXT_d2i(ext); if (!ext_internal) - return QVariant(); - // we cast away the const-ness here because some versions of openssl - // don't use const for the parameters in the functions pointers stored - // in the object. - X509V3_EXT_METHOD *meth = const_cast<X509V3_EXT_METHOD *>(q_X509V3_EXT_get(ext)); + return {}; - return QVariant(QString::fromUtf8(meth->i2s(meth, ext_internal))); + hexString = meth->i2s(meth, ext_internal); + return QVariant(QString::fromUtf8(hexString)); } break; - case NID_authority_key_identifier: + case NID_authority_key_identifier: { AUTHORITY_KEYID *auth_key = reinterpret_cast<AUTHORITY_KEYID *>(q_X509V3_EXT_d2i(ext)); if (!auth_key) - return QVariant(); - + return {}; QVariantMap result; // keyid @@ -493,7 +529,7 @@ static QVariant x509ExtensionToValue(X509_EXTENSION *ext) break; } - return QVariant(); + return {}; } QSslCertificateExtension QSslCertificatePrivate::convertExtension(X509_EXTENSION *ext) |