Skip to content

NULL Pointer Dereference in Certificate Verification #2255

@dqp10515

Description

@dqp10515

During our fault injection testing of cpp-httplib's OpenSSL API usage, we found that cpp-httplib demonstrates stability overall. We only identified two potential issues where improper handling of OpenSSL API edge cases could lead to crashes.

In the SSL client certificate verification code, the return value of sk_GENERAL_NAME_value() is dereferenced without a NULL check, which can cause a crash.
Location: httplib.h, lines 11308-11309

Crash Scenario:

According to OpenSSL source code (crypto/stack/stack.c), sk_GENERAL_NAME_value (which calls OPENSSL_sk_value) returns NULL in the following scenarios:

1. Boundary Check Failureif (st == NULL || i < 0 || i >= st->num)    return NULL;

2. NULL Element in Stackreturn (void *)st->data[i];  // Returns NULL if st->data[i] is NULL

This can occur when:

a. Certificate Parsing Errors: Malformed certificates may have partially parsed SAN entries
b. Memory Allocation Failures: OpenSSL may fail to allocate memory during certificate parsing
c. ASN.1 Decoding Errors: Invalid ASN.1 encoding can result in NULL entries
d. Memory Corruption: Buffer overflows or other memory errors can corrupt stack data

3. Maliciously Crafted Certificates

An attacker could intentionally craft certificates with malformed SAN extensions:

a. Declaring N SAN entries but with NULL data for some entries
b. ASN.1 length fields inconsistent with actual data
c. Corrupted nested structures

Reproduction:

When sk_GENERAL_NAME_value returns NULL, run cpp-httplib/example/server and cpp-httplib/example/client with ASAN.

Asan report:

../httplib.h:11309:16: runtime error: member access within null pointer of type 'struct GENERAL_NAME_st'
AddressSanitizer:DEADLYSIGNAL
=================================================================
==1367783==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x557cee6ae38b bp 0x7ffd91922ea0 sp 0x7ffd91922da0 T0)
==1367783==The signal is caused by a READ memory access.
==1367783==Hint: address points to the zero page.
    #0 0x557cee6ae38a in httplib::SSLClient::verify_host_with_subject_alt_name(x509_st*) const ../httplib.h:11309
    #1 0x557cee6add95 in httplib::SSLClient::verify_host(x509_st*) const ../httplib.h:11274
    #2 0x557cee6abac9 in httplib::SSLClient::initialize_ssl(httplib::ClientImpl::Socket&, httplib::Error&)::{lambda(ssl_st*)#1}::operator()(ssl_st*) const ../httplib.h:11178
    #3 0x557cee6fddb4 in ssl_st* httplib::detail::ssl_new<httplib::SSLClient::initialize_ssl(httplib::ClientImpl::Socket&, httplib::Error&)::{lambda(ssl_st*)#1}, httplib::SSLClient::initialize_ssl(httplib::ClientImpl::Socket&, httplib::Error&)::{lambda(ssl_st*)#2}>(int, ssl_ctx_st*, std::mutex&, httplib::SSLClient::initialize_ssl(httplib::ClientImpl::Socket&, httplib::Error&)::{lambda(ssl_st*)#1}, httplib::SSLClient::initialize_ssl(httplib::ClientImpl::Socket&, httplib::Error&)::{lambda(ssl_st*)#2}) ../httplib.h:10481
    #4 0x557cee6ac62e in httplib::SSLClient::initialize_ssl(httplib::ClientImpl::Socket&, httplib::Error&) ../httplib.h:11123
    #5 0x557cee67b36b in httplib::ClientImpl::send_(httplib::Request&, httplib::Response&, httplib::Error&) ../httplib.h:8782
    #6 0x557cee677970 in httplib::ClientImpl::send(httplib::Request&, httplib::Response&, httplib::Error&) ../httplib.h:8722
    #7 0x557cee67ffbf in httplib::ClientImpl::send_(httplib::Request&&) ../httplib.h:8848
    #8 0x557cee696465 in httplib::ClientImpl::Get(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::unordered_multimap<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, httplib::detail::case_ignore::hash, httplib::detail::case_ignore::equal_to, std::allocator<std::pair<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&, std::function<bool (unsigned long, unsigned long)>) ../httplib.h:9630
    #9 0x557cee695de1 in httplib::ClientImpl::Get(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::function<bool (unsigned long, unsigned long)>) ../httplib.h:9607
    #10 0x557cee5fde01 in main cpp-httplib/example/client.cc:26
    #11 0x7f78332730b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #12 0x557cee5fd60d in _start (cpp-httplib/example/client+0x3ea60d)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV ../httplib.h:11309 in httplib::SSLClient::verify_host_with_subject_alt_name(x509_st*) const
==1367783==ABORTING

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions