Skip to content
Snippets Groups Projects

Several OCSP improvements

Merged Ander Juaristi requested to merge aj-check-ocsp-at-end into master

This MR solves two major pain points on the OpenSSL backend. We move on-line OCSP verification out of the openssl_revocation_check_fn callback, and we take into account stapled responses sent by the server and avoid sending OCSP requests for those (#578).

We are doing OCSP verification in the openssl_revocation_check_fn callback. This callback is not the best place to check OCSP because the peer's X.509 cert stack that we get there is incomplete, and cannot be fully trusted. Hence, we move OCSP checking to the end of the wget_ssl_open function, just after the TLS handshake has successfully completed. At that point we do have the full, verified, cert stack (can be obtained with SSL_get0_verified_chain).

In addition, the fact that the on-line OCSP checks for the certificates were being carried out after the handshake completed caused that any stapled OCSP response sent by the server was not taking into account (all certificates were being OCSP-checked regardless of there was a stapled response for any of them or not). This was also happening before, when we used the openssl_revocation_check_fn callback, because it was always called after the OCSP verification callback. Hence, we create a vector and store all the stapled OCSP responses we receive, and then, during on-line OCSP verification, we check if a stapled response exists for each certificate before contacting OCSP servers.

Approver's checklist:

  • The author has submitted the FSF Copyright Assignment and is listed in AUTHORS
  • There is a test suite reasonably covering new functionality or modifications
  • Function naming, parameters, return values, types, etc., are consistent with existing code
  • This feature/change has adequate documentation added (if appropriate)
  • No obvious mistakes / misspelling in the code
Edited by Tim Rühsen

Merge request reports

Loading
Loading

Activity

Filter activity
  • Approvals
  • Assignees & reviewers
  • Comments (from bots)
  • Comments (from users)
  • Commits & branches
  • Edits
  • Labels
  • Lock status
  • Mentions
  • Merge request status
  • Tracking
  • Tim Rühsen
  • Tim Rühsen
  • Thanks Ander ! I just reviewed the code (overall LGTM) and would build/test when the comments are addressed.

  • Ander Juaristi added 2 commits

    added 2 commits

    Compare with previous version

  • Ander Juaristi resolved all threads

    resolved all threads

  • @rockdaboot Would you please review again?

  • Ander Juaristi added 13 commits

    added 13 commits

    Compare with previous version

  • @juaristi Code looks good, but could you fix the (gcc) warnings ?

    ssl_openssl.c:584:21: warning: function declaration isn't a prototype [-Wstrict-prototypes]
      584 | static wget_vector *ocsp_create_stapled_response_vector()
          |                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    ssl_openssl.c: In function 'ocsp_create_stapled_response_vector':
    ssl_openssl.c:584:21: warning: old-style function definition [-Wold-style-definition]
    ssl_openssl.c: In function 'ocsp_lookup_in_cache':
    ssl_openssl.c:639:31: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
      639 |                 *cache_origin = "stapled";
          |                               ^
    ssl_openssl.c:653:39: warning: assignment discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
      653 |                         *cache_origin = "cached";
  • clang-15 is even more picky, but we can care about this later:

    ssl_openssl.c:530:28: warning: 'ossl_check_const_X509_sk_type' was marked unused but was used [-Wused-but-marked-unused]
            unsigned cert_list_size = sk_X509_num(certs);
                                      ^
    /usr/include/openssl/x509.h:76:40: note: expanded from macro 'sk_X509_num'
    #define sk_X509_num(sk) OPENSSL_sk_num(ossl_check_const_X509_sk_type(sk))
                                           ^
    ssl_openssl.c:533:10: warning: 'ossl_check_const_X509_sk_type' was marked unused but was used [-Wused-but-marked-unused]
                    cert = sk_X509_value(certs, i);
                           ^
    /usr/include/openssl/x509.h:77:58: note: expanded from macro 'sk_X509_value'
    #define sk_X509_value(sk, idx) ((X509 *)OPENSSL_sk_value(ossl_check_const_X509_sk_type(sk), (idx)))
                                                             ^
    ssl_openssl.c:584:56: warning: a function declaration without a prototype is deprecated in all versions of C [-Wstrict-prototypes]
    static wget_vector *ocsp_create_stapled_response_vector()
                                                           ^
                                                            void
    ssl_openssl.c:1063:19: warning: 'ossl_check_const_OPENSSL_STRING_sk_type' was marked unused but was used [-Wused-but-marked-unused]
            if (str_stack && sk_OPENSSL_STRING_num(str_stack) > 0) {
                             ^
    /usr/include/openssl/safestack.h:206:50: note: expanded from macro 'sk_OPENSSL_STRING_num'
    #define sk_OPENSSL_STRING_num(sk) OPENSSL_sk_num(ossl_check_const_OPENSSL_STRING_sk_type(sk))
                                                     ^
    ssl_openssl.c:1064:27: warning: 'ossl_check_const_OPENSSL_STRING_sk_type' was marked unused but was used [-Wused-but-marked-unused]
                    char *uri = wget_strdup(sk_OPENSSL_STRING_value(str_stack, 0));
                                            ^
    /usr/include/openssl/safestack.h:207:68: note: expanded from macro 'sk_OPENSSL_STRING_value'
    #define sk_OPENSSL_STRING_value(sk, idx) ((char *)OPENSSL_sk_value(ossl_check_const_OPENSSL_STRING_sk_type(sk), (idx)))
                                                                       ^
    ssl_openssl.c:1134:29: warning: 'ossl_check_const_X509_sk_type' was marked unused but was used [-Wused-but-marked-unused]
            unsigned cert_chain_size = sk_X509_num(certs), next = starting_idx;
                                       ^
    /usr/include/openssl/x509.h:76:40: note: expanded from macro 'sk_X509_num'
    #define sk_X509_num(sk) OPENSSL_sk_num(ossl_check_const_X509_sk_type(sk))
                                           ^
    ssl_openssl.c:1138:15: warning: 'ossl_check_const_X509_sk_type' was marked unused but was used [-Wused-but-marked-unused]
                    candidate = sk_X509_value(certs, next);
                                ^
    /usr/include/openssl/x509.h:77:58: note: expanded from macro 'sk_X509_value'
    #define sk_X509_value(sk, idx) ((X509 *)OPENSSL_sk_value(ossl_check_const_X509_sk_type(sk), (idx)))
                                                             ^
    ssl_openssl.c:1156:28: warning: 'ossl_check_const_X509_sk_type' was marked unused but was used [-Wused-but-marked-unused]
            unsigned cert_list_size = sk_X509_num(certs);
                                      ^
    /usr/include/openssl/x509.h:76:40: note: expanded from macro 'sk_X509_num'
    #define sk_X509_num(sk) OPENSSL_sk_num(ossl_check_const_X509_sk_type(sk))
                                           ^
    ssl_openssl.c:1159:10: warning: 'ossl_check_const_X509_sk_type' was marked unused but was used [-Wused-but-marked-unused]
                    cert = sk_X509_value(certs, i);
                           ^
    /usr/include/openssl/x509.h:77:58: note: expanded from macro 'sk_X509_value'
    #define sk_X509_value(sk, idx) ((X509 *)OPENSSL_sk_value(ossl_check_const_X509_sk_type(sk), (idx)))
                                                             ^
    ssl_openssl.c:1199:11: warning: variable 'fingerprint' may be uninitialized when used here [-Wconditional-uninitialized]
                                    xfree(fingerprint);
                                          ^~~~~~~~~~~
    ./private.h:48:27: note: expanded from macro 'xfree'
    #define xfree(a) do { if (a) { wget_free((void *)(a)); a=NULL; } } while (0)
                              ^
    ssl_openssl.c:1153:15: note: initialize the variable 'fingerprint' to silence this warning
                    *fingerprint,
                                ^
                                 = NULL
    ssl_openssl.c:1281:28: warning: 'ossl_check_const_X509_sk_type' was marked unused but was used [-Wused-but-marked-unused]
            vflags->cert_chain_size = sk_X509_num(certs);
                                      ^
    /usr/include/openssl/x509.h:76:40: note: expanded from macro 'sk_X509_num'
    #define sk_X509_num(sk) OPENSSL_sk_num(ossl_check_const_X509_sk_type(sk))
                                           ^
    ssl_openssl.c:1293:2: warning: 'ossl_check_X509_sk_type' was marked unused but was used [-Wused-but-marked-unused]
            sk_X509_pop_free(certs, X509_free);
            ^
    /usr/include/openssl/x509.h:90:60: note: expanded from macro 'sk_X509_pop_free'
    #define sk_X509_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_X509_sk_type(sk),ossl_check_X509_freefunc_type(freefunc))
                                                               ^
    ssl_openssl.c:1293:2: warning: 'ossl_check_X509_freefunc_type' was marked unused but was used [-Wused-but-marked-unused]
    /usr/include/openssl/x509.h:90:88: note: expanded from macro 'sk_X509_pop_free'
    #define sk_X509_pop_free(sk, freefunc) OPENSSL_sk_pop_free(ossl_check_X509_sk_type(sk),ossl_check_X509_freefunc_type(freefunc))
                                                                                           ^
    ssl_openssl.c:1732:13: warning: 'ERR_GET_REASON' was marked unused but was used [-Wused-but-marked-unused]
                    retval = (ERR_GET_REASON(ERR_peek_last_error()) == SSL_R_CERTIFICATE_VERIFY_FAILED ?
                              ^
  • HTTPS checks are failing, reproducible with

    make='make -j$(nproc)'
    ./configure --with-ssl=openssl
    make clean
    make
    make check-valgrind

    e.g. from tests/test-ocsp-server.log:

    ==73655== Invalid read of size 1
    ==73655==    at 0x4849794: strlen (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==73655==    by 0x48672C4: copy_string (buffer_printf.c:65)
    ==73655==    by 0x48677D3: wget_buffer_vprintf_append (buffer_printf.c:455)
    ==73655==    by 0x4867963: wget_buffer_vprintf (buffer_printf.c:522)
    ==73655==    by 0x48768D2: logger_vprintf_func (logger.c:46)
    ==73655==    by 0x487681B: wget_debug_printf (log.c:105)
    ==73655==    by 0x488151D: ssl_set_alpn_selected_protocol (ssl_openssl.c:1539)
    ==73655==    by 0x4881E5D: wget_ssl_open (ssl_openssl.c:1772)
    ==73655==    by 0x4878358: wget_tcp_connect (net.c:761)
    ==73655==    by 0x4871DD8: wget_http_open (http.c:657)
    ==73655==    by 0x119370: try_connection (wget.c:1555)
    ==73655==    by 0x1195BA: establish_connection (wget.c:1626)
    ==73655==  Address 0x6b1e5d8 is 0 bytes after a block of size 8 alloc'd
    ==73655==    at 0x48437B4: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==73655==    by 0x4DC46B0: ??? (in /usr/lib/x86_64-linux-gnu/libssl.so.3)
    ==73655==    by 0x4DC03DF: ??? (in /usr/lib/x86_64-linux-gnu/libssl.so.3)
    ==73655==    by 0x4DD27CE: ??? (in /usr/lib/x86_64-linux-gnu/libssl.so.3)
    ==73655==    by 0x4DCADB1: ??? (in /usr/lib/x86_64-linux-gnu/libssl.so.3)
    ==73655==    by 0x4881D8D: wget_ssl_open (ssl_openssl.c:1714)
    ==73655==    by 0x4878358: wget_tcp_connect (net.c:761)
    ==73655==    by 0x4871DD8: wget_http_open (http.c:657)
    ==73655==    by 0x119370: try_connection (wget.c:1555)
    ==73655==    by 0x1195BA: establish_connection (wget.c:1626)
    ==73655==    by 0x121FE8: downloader_thread (wget.c:2311)
    ==73655==    by 0x4A7B849: start_thread (pthread_create.c:442)

    Not sure if this is due to your changes, but it stems from openssl code.

  • Hm, we need a new CI runner with OpenSSL and valgrind.

  • Fixed the bug (the above stacktrace) that was triggered by our openssl code: !514 (merged).

    Please rebase when the !514 (merged) got merged.

    The GH issue is something else.

    Edited by Tim Rühsen
    • Resolved by Ander Juaristi

      I assume that the vflags should be per-connection data. But it is used as global data:

      store = SSL_CTX_get_cert_store(_ctx);
      X509_STORE_set_ex_data(store, store_userdata_idx, (void *) vflags)

      What are your thoughts ?

      I am fine with opening another issue and get this MR merged independently.

      Edited by Tim Rühsen
  • Ander Juaristi added 14 commits

    added 14 commits

    Compare with previous version

  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Loading
  • Please register or sign in to reply
    Loading