diff --git a/CMakeLists.txt b/CMakeLists.txt index 6c9b1606..41806d14 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,9 @@ set(CMAKE_C_STANDARD_REQUIRED ON) # load CMake library modules include(FindOpenSSL) -include(FindCURL) +if(OPENSSL_VERSION VERSION_LESS "3.0.0") + include(FindCURL) +endif(OPENSSL_VERSION VERSION_LESS "3.0.0") include(FindZLIB) # load CMake project modules @@ -64,14 +66,14 @@ target_include_directories(osslsigncode PRIVATE ${OPENSSL_INCLUDE_DIR}) target_link_libraries(osslsigncode PRIVATE ${OPENSSL_LIBRARIES}) # set cURL includes/libraries -if(CURL_FOUND) +if(OPENSSL_VERSION VERSION_LESS "3.0.0" AND CURL_FOUND) target_compile_definitions(osslsigncode PRIVATE ENABLE_CURL=1) target_include_directories(osslsigncode PRIVATE ${CURL_INCLUDE_DIRS}) target_link_libraries(osslsigncode PRIVATE ${CURL_LIBRARIES}) message(STATUS "cURL support enabled") -else(CURL_FOUND) +else(OPENSSL_VERSION VERSION_LESS "3.0.0" AND CURL_FOUND) message(STATUS "cURL support disabled (library not found)") -endif(CURL_FOUND) +endif(OPENSSL_VERSION VERSION_LESS "3.0.0" AND CURL_FOUND) if(NOT ZLIB_FOUND) message(FATAL_ERROR "Zlib library not found") @@ -79,6 +81,11 @@ endif(NOT ZLIB_FOUND) target_include_directories(osslsigncode PRIVATE ${ZLIB_INCLUDE_DIR}) target_link_libraries(osslsigncode PRIVATE ${ZLIB_LIBRARIES}) +if(NOT UNIX) +# https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-shutdown +target_link_libraries(osslsigncode PRIVATE Ws2_32.lib) +endif(NOT UNIX) + # add paths to linker search and installed rpath set_target_properties(osslsigncode PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) diff --git a/INSTALL.W32.md b/INSTALL.W32.md index bf2a1968..303b4f2b 100644 --- a/INSTALL.W32.md +++ b/INSTALL.W32.md @@ -3,20 +3,19 @@ ### Building osslsigncode source with MSYS2 MinGW 64-bit and MSYS2 packages: 1) Download and install MSYS2 from https://msys2.github.io/ and follow installation instructions. - Once up and running install even mingw-w64-x86_64-gcc, mingw-w64-x86_64-curl. + Once up and running install mingw-w64-x86_64-gcc and mingw-w64-x86_64-openssl packages. ``` - pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-curl + pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-openssl ``` - mingw-w64-x86_64-openssl and mingw-w64-x86_64-zlib packages are installed with dependencies. + mingw-w64-x86_64-zlib package is installed with dependencies. 2) Run "MSYS2 MinGW 64-bit" and build 64-bit Windows executables. ``` cd osslsigncode-folder x86_64-w64-mingw32-gcc *.c -o osslsigncode.exe \ - -lcrypto -lssl -lcurl \ + -lcrypto -lssl -lws2_32 -lz \ -D 'PACKAGE_STRING="osslsigncode x.y"' \ - -D 'PACKAGE_BUGREPORT="Your.Email@example.com"' \ - -D ENABLE_CURL + -D 'PACKAGE_BUGREPORT="Your.Email@example.com"' ``` 3) Run "Command prompt" and include "c:\msys64\mingw64\bin" folder as part of the path. @@ -24,29 +23,19 @@ path=%path%;c:\msys64\mingw64\bin cd osslsigncode-folder osslsigncode.exe -v - osslsigncode 2.4, using: - OpenSSL 1.1.1g 21 Apr 2020 (Library: OpenSSL 1.1.1g 21 Apr 2020) - libcurl/7.70.0 OpenSSL/1.1.1g (Schannel) zlib/1.2.11 brotli/1.0.7 libidn2/2.3.0 - libpsl/0.21.0 (+libidn2/2.3.0) libssh2/1.9.0 nghttp2/1.40.0 + osslsigncode 2.8, using: + OpenSSL 3.2.0 23 Nov 2023 (Library: OpenSSL 3.2.0 23 Nov 2023) + Default -CAfile location: /etc/ssl/certs/ca-certificates.crt ``` -### Building OpenSSL, Curl and osslsigncode sources with MSYS2 MinGW 64-bit: +### Building OpenSSL and osslsigncode sources with MSYS2 MinGW 64-bit: 1) Download and install MSYS2 from https://msys2.github.io/ and follow installation instructions. Once up and running install even: perl make autoconf automake libtool pkg-config. ``` pacman -S perl make autoconf automake libtool pkg-config ``` - Make sure there are no curl, brotli, libpsl, libidn2 and nghttp2 packages installed: -``` - pacman -R mingw-w64-x86_64-curl \ - mingw-w64-x86_64-brotli \ - mingw-w64-x86_64-libpsl \ - mingw-w64-x86_64-libidn2 \ - mingw-w64-x86_64-nghttp2 -``` - Run "MSYS2 MinGW 64-bit" in the administrator mode. 2) Build and install OpenSSL. @@ -54,31 +43,15 @@ cd openssl-(version) ./config --prefix='C:/OpenSSL' --openssldir='C:/OpenSSL' make && make install -``` - 3) Build and install curl. -``` - cd curl-(version) - ./buildconf - ./configure --prefix='C:/curl' --with-ssl='C:/OpenSSL' \ - --disable-ftp --disable-tftp --disable-file --disable-dict \ - --disable-telnet --disable-imap --disable-smb --disable-smtp \ - --disable-gopher --disable-pop --disable-pop3 --disable-rtsp \ - --disable-ldap --disable-ldaps --disable-unix-sockets \ - --disable-pthreads --without-zstd --without-zlib - make && make install -``` 3) Build 64-bit Windows executables. ``` cd osslsigncode-folder x86_64-w64-mingw32-gcc *.c -o osslsigncode.exe \ - -L 'C:/OpenSSL/lib/' -lcrypto -lssl \ - -I 'C:/OpenSSL/include/' \ - -L 'C:/curl/lib' -lcurl \ - -I 'C:/curl/include' \ + -L "C:/OpenSSL/lib/" -lcrypto -lssl -lws2_32 -lz \ + -I "C:/OpenSSL/include/" \ -D 'PACKAGE_STRING="osslsigncode x.y"' \ - -D 'PACKAGE_BUGREPORT="Your.Email@example.com"' \ - -D ENABLE_CURL + -D 'PACKAGE_BUGREPORT="Your.Email@example.com"' ``` 4) Run "Command prompt" and copy required libraries. @@ -86,15 +59,14 @@ cd osslsigncode-folder copy C:\OpenSSL\bin\libssl-1_1-x64.dll copy C:\OpenSSL\bin\libcrypto-1_1-x64.dll - copy C:\curl\bin\libcurl-4.dll osslsigncode.exe -v - osslsigncode 2.4, using: - OpenSSL 1.1.1k 25 Mar 2021 (Library: OpenSSL 1.1.1k 25 Mar 2021) - libcurl/7.78.0 OpenSSL/1.1.1k + osslsigncode 2.8, using: + OpenSSL 3.2.0 23 Nov 2023 (Library: OpenSSL 3.2.0 23 Nov 2023) + Default -CAfile location: /etc/ssl/certs/ca-certificates.crt ``` -### Building OpenSSL, Curl and osslsigncode sources with Microsoft Visual Studio: +### Building OpenSSL and osslsigncode sources with Microsoft Visual Studio: 1) Install and integrate vcpkg: https://vcpkg.io/en/getting-started.html diff --git a/NEWS.md b/NEWS.md index 516bedf8..1a959517 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,6 +3,7 @@ ### 2.9 (unreleased) - added a 64 bit long pseudo-random NONCE in the TSA request +- used native HTTP client with OpenSSL 3.0 or later, removed libcurl dependency ### 2.8 (2024.03.03) diff --git a/osslsigncode.c b/osslsigncode.c index cc9a05b1..27e387bf 100644 --- a/osslsigncode.c +++ b/osslsigncode.c @@ -208,6 +208,7 @@ IMPLEMENT_ASN1_FUNCTIONS(MsCtlContent) /* Prototypes */ static ASN1_INTEGER *create_nonce(int bits); +static char *clrdp_url_get_x509(X509 *cert); static time_t time_t_get_asn1_time(const ASN1_TIME *s); static time_t time_t_get_si_time(PKCS7_SIGNER_INFO *si); static ASN1_UTCTIME *asn1_time_get_si_time(PKCS7_SIGNER_INFO *si); @@ -221,10 +222,10 @@ static int X509_attribute_chain_append_object(STACK_OF(X509_ATTRIBUTE) **unauth_ static STACK_OF(PKCS7) *signature_list_create(PKCS7 *p7); static int PKCS7_compare(const PKCS7 *const *a, const PKCS7 *const *b); static PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx); +static void print_cert(X509 *cert, int i); +static int x509_store_load_crlfile(X509_STORE *store, char *cafile, char *crlfile); -static int blob_has_nl = 0; - /* A timestamp request looks like this: @@ -523,8 +524,6 @@ static int attach_authenticode_response(PKCS7 *p7, PKCS7 *resp, int verbose) return 0; /* OK */ } -#ifdef ENABLE_CURL - static void print_proxy(char *proxy) { if (proxy) { @@ -545,6 +544,11 @@ static void print_proxy(char *proxy) } } +#if OPENSSL_VERSION_NUMBER<0x30000000L +#ifdef ENABLE_CURL + +static int blob_has_nl = 0; + /* * Callback for writing received data */ @@ -565,15 +569,15 @@ static size_t curl_write(void *ptr, size_t sz, size_t nmemb, void *stream) * Get data from HTTP server. * [out] http_code: HTTP status * [in] url: URL of the CRL distribution point or Time-Stamp Authority HTTP server - * [in] bout: timestamp request + * [in] req: timestamp request * [in] proxy: proxy to getting the timestamp through * [in] noverifypeer: do not verify the Time-Stamp Authority's SSL certificate * [in] verbose: additional output mode - * [in] content: CRL distribution point (0), RFC3161 TSA (1), Authenticode TSA (2) - * [returns] pointer to BIO with X509 Certificate Revocation List + * [in] rfc3161: Authenticode / RFC3161 Timestamp switch + * [returns] pointer to BIO with X509 Certificate Revocation List or timestamp response */ -static BIO *bio_get_http(long *http_code, char *url, BIO *bout, char *proxy, - int noverifypeer, int verbose, int content) +static BIO *bio_get_http_curl(long *http_code, char *url, BIO *req, char *proxy, + int noverifypeer, int verbose, int rfc3161) { CURL *curl; struct curl_slist *slist = NULL; @@ -621,24 +625,23 @@ static BIO *bio_get_http(long *http_code, char *url, BIO *bout, char *proxy, printf("CURL failure: %s %s\n", curl_easy_strerror(res), url); } } - if (content == 1) { - /* RFC3161 Timestamp */ - slist = curl_slist_append(slist, "Content-Type: application/timestamp-query"); - slist = curl_slist_append(slist, "Accept: application/timestamp-reply"); - } else if (content == 2) { - /* Authenticode Timestamp */ - slist = curl_slist_append(slist, "Content-Type: application/octet-stream"); - slist = curl_slist_append(slist, "Accept: application/octet-stream"); - } - if (content > 0) { - /* Timestamp */ + if (req) { /* POST */ + if (rfc3161) { + /* RFC3161 Timestamp */ + slist = curl_slist_append(slist, "Content-Type: application/timestamp-query"); + slist = curl_slist_append(slist, "Accept: application/timestamp-reply"); + } else { + /* Authenticode Timestamp */ + slist = curl_slist_append(slist, "Content-Type: application/octet-stream"); + slist = curl_slist_append(slist, "Accept: application/octet-stream"); + } slist = curl_slist_append(slist, "User-Agent: Transport"); slist = curl_slist_append(slist, "Cache-Control: no-cache"); res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist); if (res != CURLE_OK) { printf("CURL failure: %s %s\n", curl_easy_strerror(res), url); } - len = BIO_get_mem_data(bout, &p); + len = BIO_get_mem_data(req, &p); res = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len); if (res != CURLE_OK) { printf("CURL failure: %s %s\n", curl_easy_strerror(res), url); @@ -679,12 +682,285 @@ static BIO *bio_get_http(long *http_code, char *url, BIO *bout, char *proxy, } /* End a libcurl easy handle */ curl_easy_cleanup(curl); + if (req && !rfc3161) { + /* BASE64 encoded Authenticode Timestamp */ + BIO *b64 = BIO_new(BIO_f_base64()); + + if (!blob_has_nl) + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + bin = BIO_push(b64, bin); + } return bin; } #endif /* ENABLE_CURL */ +#else /* OPENSSL_VERSION_NUMBER<0x30000000L */ + +/* HTTP callback function that supports TLS connection also via HTTPS proxy */ +static BIO *http_tls_cb(BIO *bio, void *arg, int connect, int detail) +{ + HTTP_TLS_Info *info = (HTTP_TLS_Info *)arg; + SSL_CTX *ssl_ctx = info->ssl_ctx; + + if (ssl_ctx == NULL) { + /* not using TLS */ + return bio; + } + if (connect && detail) { + /* connecting with TLS */ + SSL *ssl; + BIO *sbio = NULL; + + if (info->use_proxy && !OSSL_HTTP_proxy_connect(bio, info->server, + info->port, NULL, NULL, info->timeout, NULL, NULL)) { + return NULL; + } + sbio = BIO_new(BIO_f_ssl()); + if (sbio == NULL) { + return NULL; + } + ssl = SSL_new(ssl_ctx); + if (ssl == NULL) { + BIO_free(sbio); + return NULL; + } + SSL_set_tlsext_host_name(ssl, info->server); + SSL_set_connect_state(ssl); + BIO_set_ssl(sbio, ssl, BIO_CLOSE); + bio = BIO_push(sbio, bio); + } + return bio; +} + +static int verify_callback(int ok, X509_STORE_CTX *ctx) +{ + if (!ok) { + int error = X509_STORE_CTX_get_error(ctx); + + print_cert(X509_STORE_CTX_get_current_cert(ctx), 0); + if (error == X509_V_ERR_UNABLE_TO_GET_CRL) { + char *url = clrdp_url_get_x509(X509_STORE_CTX_get_current_cert(ctx)); + + printf("\tWarning: Ignoring \'%s\' error for CRL validation\n", + X509_verify_cert_error_string(error)); + printf("\nUse the \"-HTTPS-CRLfile\" option to verify CRL\n"); + if (url) { + printf("HTTPS's CRL distribution point: %s\n", url); + OPENSSL_free(url); + } + return 1; + } else { + printf("\tError: %s\n", X509_verify_cert_error_string(error)); + } + } + return ok; +} + +/* + * Read data from socket BIO + * [in] s_bio: socket BIO + * [in] rctx: open connection context + * [in] use_ssl: HTTPS request switch + * [returns] memory BIO + */ +static BIO *socket_bio_read(BIO *s_bio, OSSL_HTTP_REQ_CTX *rctx, int use_ssl) +{ + int retry = 1, ok = 0, written = 0, resp_len = 0; + char *buf = OPENSSL_malloc(OSSL_HTTP_DEFAULT_MAX_RESP_LEN); + BIO *resp = BIO_new(BIO_s_mem()); + + if (rctx) { + resp_len = (int)OSSL_HTTP_REQ_CTX_get_resp_len(rctx); + } + if (resp_len == 0) { + if (use_ssl) + BIO_ssl_shutdown(s_bio); + else { + int fd = (int)BIO_get_fd(s_bio, NULL); + + if (fd >= 0) { +#ifdef WIN32 + (void)shutdown(fd, SD_SEND); +#else /* WIN32 */ + (void)shutdown(fd, SHUT_WR); +#endif /* WIN32 */ + } + } + } + ERR_clear_error(); + while (retry) { + int n; + + errno = 0; + n = BIO_read(s_bio, buf, OSSL_HTTP_DEFAULT_MAX_RESP_LEN); + if (n > 0) { + written += BIO_write(resp, buf, n); + } else if (BIO_eof(s_bio) == 1) { + ok = 1; + retry = 0; /* EOF */ + } else if (BIO_should_retry(s_bio)) { + } else { + unsigned long err = ERR_get_error(); + + if (err == 0) { + ok = 1; + retry = 0; /* use_ssl EOF */ + } else { + printf("\nHTTP failure: error %ld: %s\n", err, ERR_reason_error_string(err)); + retry = 0; /* FAILED */ + } + } + if (resp_len > 0 && resp_len == written) { + ok = 1; + retry = 0; /* all response has been read */ + } + } + OSSL_HTTP_close(rctx, ok); + OPENSSL_free(buf); + if (!ok) { + BIO_free_all(resp); + resp = NULL; + } + + return resp; +} + +/* + * pkcs7-signedData bytes found indicates DER form + * in otherwise BASE64 encoded + * '\n' newline character means BASE64 line with newline at the end + * in otherwise BIO_FLAGS_BASE64_NO_NL flag must me set + * [in, out] resp: memory BIO with Authenticode Timestamp data + * [returns] none + */ +static void check_authenticode_timestamp(BIO **resp) +{ + u_char *ptr = NULL; + const u_char pkcs7_signed[] = {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02}; + int i, len, pkcs7_signed_len, found = 0; + + len = (int)BIO_get_mem_data(*resp, &ptr); + if (len <= 0) { + return; + } + pkcs7_signed_len = (int)sizeof pkcs7_signed; + for (i = 0; i <= len - pkcs7_signed_len; i++) { + if (memcmp(ptr + i, pkcs7_signed, (size_t)pkcs7_signed_len) == 0) { + found = 1; + break; + } + } + if (!found) { + /* BASE64 encoded Authenticode Timestamp */ + BIO *b64 = BIO_new(BIO_f_base64()); + + if (!memchr(ptr, '\n', (size_t)len)) { + BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); + } else { + BIO *bio_mem = BIO_new_mem_buf(ptr, len); + BIO_push(b64, bio_mem); + } + *resp = BIO_push(b64, *resp); + } +} + +/* + * Get data from HTTP server. + * [in] url: URL of the CRL distribution point or Time-Stamp Authority HTTP server + * [in] req: timestamp request + * [in] proxy: proxy to getting the timestamp through + * [in] rfc3161: Authenticode / RFC3161 Timestamp switch + * [in] cafile: file contains concatenated CA certificates in PEM format + * [in] crlfile: file contains Certificate Revocation List (CRLs) + * [returns] pointer to BIO with X509 Certificate Revocation List or timestamp response + */ +static BIO *bio_get_http(char *url, BIO *req, char *proxy, int rfc3161, char *cafile, char *crlfile) +{ + BIO *tmp_bio = NULL, *s_bio = NULL, *resp = NULL; + OSSL_HTTP_REQ_CTX *rctx = NULL; + HTTP_TLS_Info info; + SSL_CTX *ssl_ctx = NULL; + char *server = NULL, *port = NULL, *path = NULL; + int timeout = -1; /* blocking mode, exactly one try, see BIO_do_connect_retry() */ + int keep_alive = 1; /* prefer */ + int use_ssl = 0; + + if (!url) { + return NULL; /* FAILED */ + } + print_proxy(proxy); + printf("Connecting to %s\n", url); + + if (!OSSL_HTTP_parse_url(url, &use_ssl, NULL, &server, &port, NULL, &path, NULL, NULL)) { + return NULL; /* FAILED */ + } + if (use_ssl) { + X509_STORE *store = NULL; + + ssl_ctx = SSL_CTX_new(TLS_client_method()); + if (cafile) { + printf("HTTPS-CAfile: %s\n", cafile); + if (crlfile) + printf("HTTPS-CRLfile: %s\n", crlfile); + store = SSL_CTX_get_cert_store(ssl_ctx); + if (x509_store_load_crlfile(store, cafile, crlfile)) + SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, verify_callback); + else + printf("Warning: HTTPS verification was skipped\n"); + } else { + printf("Warning: HTTPS verification was skipped\n"); + } + } + info.server = server; + info.port = port; + info.use_proxy = OSSL_HTTP_adapt_proxy(proxy, NULL, server, use_ssl) != NULL; + info.timeout = timeout; + info.ssl_ctx = ssl_ctx; + + if (!req) { /* GET */ + const char *expected_content_type = "application/pkix-crl"; + + s_bio = OSSL_HTTP_get(url, proxy, NULL, NULL, NULL, http_tls_cb, &info, 0, + NULL, expected_content_type, 0, 0, timeout); + } else { /* POST */ + const char *content_type = "application/timestamp-query"; /* RFC3161 Timestamp */ + const char *expected_content_type = "application/timestamp-reply"; + + if (!rfc3161) { + u_char *p = NULL; + long len = BIO_get_mem_data(req, &p); + + tmp_bio = BIO_new(BIO_s_mem()); + BIO_write(tmp_bio, p, (int)len); + req = BIO_push(tmp_bio, req); + content_type = "application/octet-stream"; /* Authenticode Timestamp */ + expected_content_type = "application/octet-stream"; + } + s_bio = OSSL_HTTP_transfer(&rctx, server, port, path, use_ssl, proxy, NULL, + NULL, NULL, http_tls_cb, &info, 0, NULL, content_type, req, + expected_content_type, 0, 0, timeout, keep_alive); + BIO_free(tmp_bio); + } + OPENSSL_free(server); + OPENSSL_free(port); + OPENSSL_free(path); + SSL_CTX_free(ssl_ctx); + + if (s_bio) { + resp = socket_bio_read(s_bio, rctx, use_ssl); + BIO_free_all(s_bio); + if (resp && req && !rfc3161) + check_authenticode_timestamp(&resp); + } else { + printf("\nHTTP failure: Failed to get data from %s\n", url); + } + + return resp; +} +#endif /* OPENSSL_VERSION_NUMBER<0x30000000L */ + /* - * Decode a curl response from BIO and write it into the PKCS7 structure + * Decode a HTTP response from BIO and write it into the PKCS7 structure * Add timestamp to the PKCS7 SignerInfo structure: * sig->d.sign->signer_info->unauth_attr * [in, out] p7: new PKCS#7 signature @@ -695,54 +971,58 @@ static BIO *bio_get_http(long *http_code, char *url, BIO *bout, char *proxy, */ static int add_timestamp(PKCS7 *p7, FILE_FORMAT_CTX *ctx, char *url, int rfc3161) { - BIO *bout, *bin; + BIO *req, *resp; int verbose = ctx->options->verbose || ctx->options->ntsurl == 1; int res = 1; long http_code = -1; /* Encode timestamp request */ if (rfc3161) { - bout = bio_encode_rfc3161_request(p7, ctx->options->md); + req = bio_encode_rfc3161_request(p7, ctx->options->md); } else { - bout = bio_encode_authenticode_request(p7); + req = bio_encode_authenticode_request(p7); } - if (!bout) { + if (!req) { return 1; /* FAILED */ } -#ifdef ENABLE_CURL +#if OPENSSL_VERSION_NUMBER<0x30000000L +#ifndef ENABLE_CURL + (void)url; + (void)rfc3161; + printf("Could NOT find CURL\n"); + BIO_free_all(req); + return NULL; /* FAILED */ +#else /* ENABLE_CURL */ if (rfc3161) { - bin = bio_get_http(&http_code, url, bout, ctx->options->proxy, + resp = bio_get_http_curl(&http_code, url, req, ctx->options->proxy, ctx->options->noverifypeer, verbose, 1); } else { - bin = bio_get_http(&http_code, url, bout, ctx->options->proxy, - ctx->options->noverifypeer, verbose, 2); + resp = bio_get_http_curl(&http_code, url, req, ctx->options->proxy, + ctx->options->noverifypeer, verbose, 0); } - BIO_free_all(bout); -#else /* ENABLE_CURL */ - /* TODO implement an HTTP session */ - printf("Could NOT find CURL\n"); - return 1; /* FAILED */ #endif /* ENABLE_CURL */ - - if (bin) { +#else /* OPENSSL_VERSION_NUMBER<0x30000000L */ + if (rfc3161) { + resp = bio_get_http(url, req, ctx->options->proxy, 1, + ctx->options->noverifypeer ? NULL : ctx->options->https_cafile, + ctx->options->noverifypeer ? NULL : ctx->options->https_crlfile); + } else { + resp = bio_get_http(url, req, ctx->options->proxy, 0, + ctx->options->noverifypeer ? NULL : ctx->options->https_cafile, + ctx->options->noverifypeer ? NULL : ctx->options->https_crlfile); + } +#endif /* OPENSSL_VERSION_NUMBER<0x30000000L */ + BIO_free_all(req); + if (resp != NULL) { if (rfc3161) { /* decode a RFC 3161 response from BIO */ - TS_RESP *response = d2i_TS_RESP_bio(bin, NULL); - BIO_free_all(bin); + TS_RESP *response = d2i_TS_RESP_bio(resp, NULL); res = attach_rfc3161_response(p7, response, verbose); TS_RESP_free(response); } else { /* decode an authenticode response from BIO */ - PKCS7 *response; - BIO *b64, *b64_bin; - - b64 = BIO_new(BIO_f_base64()); - if (!blob_has_nl) - BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL); - b64_bin = BIO_push(b64, bin); - response = d2i_PKCS7_bio(b64_bin, NULL); - BIO_free_all(b64_bin); + PKCS7 *response = d2i_PKCS7_bio(resp, NULL); res = attach_authenticode_response(p7, response, verbose); } @@ -751,11 +1031,11 @@ static int add_timestamp(PKCS7 *p7, FILE_FORMAT_CTX *ctx, char *url, int rfc3161 printf("Failed to convert timestamp reply from %s; " "HTTP status %ld\n", url, http_code); } else { - printf("Failed to convert timestamp reply from %s; " - "no HTTP status available", url); + printf("Failed to convert timestamp reply from %s\n", url); } ERR_print_errors_fp(stdout); } + BIO_free_all(resp); } return res; } @@ -1445,7 +1725,7 @@ static int trusted_cert(X509 *cert, int error) { return 0; /* FAILED */ } if (on_list(hex, fingerprints)) { - printf("\tWarning: Ignoring %s error for Windows certificate whitelist\n", + printf("\tWarning: Ignoring \'%s\' error for Windows certificate whitelist\n", X509_verify_cert_error_string(error)); OPENSSL_free(hex); return 1; /* trusted */ @@ -1468,7 +1748,7 @@ static int verify_ca_callback(int ok, X509_STORE_CTX *ctx) if (trusted_cert(current_cert, error)) { return 1; } else if (error == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) { - printf("\tError: Unable to get local CA certificate; %s\n", + printf("\tError: Certificate not found in local repository: %s\n", X509_verify_cert_error_string(error)); } else { printf("\tError: %s\n", X509_verify_cert_error_string(error)); @@ -1488,11 +1768,11 @@ static int verify_crl_callback(int ok, X509_STORE_CTX *ctx) if (trusted_cert(current_cert, error)) { return 1; } else if (error == X509_V_ERR_CERT_HAS_EXPIRED) { - printf("\tWarning: Ignoring %s error for CRL validation\n", + printf("\tWarning: Ignoring \'%s\' error for CRL validation\n", X509_verify_cert_error_string(error)); return 1; } else if (error == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) { - printf("\tError: Unable to get local CA certificate; %s\n", + printf("\tError: Certificate not found in local repository: %s\n", X509_verify_cert_error_string(error)); } else { @@ -1661,24 +1941,28 @@ static char *clrdp_url_get_x509(X509 *cert) /* * Get Certificate Revocation List from a CRL distribution point * and write it into the X509_CRL structure. - * [in] proxy: proxy to getting CRL through + * [in] ctx: structure holds input and output data * [in] url: URL of the CRL distribution point server * [returns] X509 Certificate Revocation List */ -static X509_CRL *x509_crl_get(char *proxy, char *url) +static X509_CRL *x509_crl_get(FILE_FORMAT_CTX *ctx, char *url) { X509_CRL *crl; BIO *bio = NULL; -#ifdef ENABLE_CURL - long http_code = -1; - bio = bio_get_http(&http_code, url, NULL, proxy, 0, 1, 0); -#else /* ENABLE_CURL */ - /* TODO implement an HTTP session */ - (void)proxy; +#if OPENSSL_VERSION_NUMBER<0x30000000L +#ifndef ENABLE_CURL printf("Could NOT find CURL\n"); return NULL; /* FAILED */ +#else /* ENABLE_CURL */ + long http_code = -1; + bio = bio_get_http_curl(&http_code, url, NULL, ctx->options->proxy, 0, 1, 0); #endif /* ENABLE_CURL */ +#else /* OPENSSL_VERSION_NUMBER<0x30000000L */ + bio = bio_get_http(url, NULL, ctx->options->proxy, 0, + ctx->options->noverifypeer ? NULL : ctx->options->https_cafile, + ctx->options->noverifypeer ? NULL : ctx->options->https_crlfile); +#endif /* OPENSSL_VERSION_NUMBER<0x30000000L */ if (!bio) { printf("Warning: Faild to get CRL from %s\n\n", url); return NULL; /* FAILED */ @@ -1879,7 +2163,7 @@ static int verify_timestamp(FILE_FORMAT_CTX *ctx, PKCS7 *p7, CMS_ContentInfo *ti printf("Ignored TSA's CRL distribution point: %s\n", url); } else { printf("TSA's CRL distribution point: %s\n", url); - crl = x509_crl_get(ctx->options->proxy, url); + crl = x509_crl_get(ctx, url); } OPENSSL_free(url); if (!crl && !ctx->options->tsa_crlfile) { @@ -2041,7 +2325,7 @@ static int verify_authenticode(FILE_FORMAT_CTX *ctx, PKCS7 *p7, time_t time, X50 printf("Ignored CRL distribution point: %s\n", url); } else { printf("CRL distribution point: %s\n", url); - crl = x509_crl_get(ctx->options->proxy, url); + crl = x509_crl_get(ctx, url); } OPENSSL_free(url); if (!crl && !ctx->options->crlfile) { @@ -2737,7 +3021,7 @@ static int verify_signature(FILE_FORMAT_CTX *ctx, PKCS7 *p7) time = INVALID_TIME; } else { int timeok = verify_timestamp(ctx, p7, timestamp, time); - printf("Timestamp Server Signature verification: %s\n", timeok ? "ok" : "failed"); + printf("\nTimestamp Server Signature verification: %s\n", timeok ? "ok" : "failed"); if (!timeok) { time = INVALID_TIME; } @@ -3035,8 +3319,10 @@ static void free_options(GLOBAL_OPTIONS *options) { /* If memory has not been allocated nothing is done */ OPENSSL_free(options->cafile); - OPENSSL_free(options->tsa_cafile); OPENSSL_free(options->crlfile); + OPENSSL_free(options->https_cafile); + OPENSSL_free(options->https_crlfile); + OPENSSL_free(options->tsa_cafile); OPENSSL_free(options->tsa_crlfile); /* If key is NULL nothing is done */ EVP_PKEY_free(options->pkey); @@ -3093,6 +3379,8 @@ static void usage(const char *argv0, const char *cmd) printf("%12s[ -ts [ -ts ... ] [ -p ] [ -noverifypeer ] ]\n", ""); printf("%12s[ -TSA-certs ] [ -TSA-key ]\n", ""); printf("%12s[ -TSA-time ]\n", ""); + printf("%12s[ -HTTPS-CAfile ]\n", ""); + printf("%12s[ -HTTPS-CRLfile ]\n", ""); printf("%12s[ -time ]\n", ""); printf("%12s[ -addUnauthenticatedBlob ]\n", ""); printf("%12s[ -nest ]\n", ""); @@ -3114,6 +3402,8 @@ static void usage(const char *argv0, const char *cmd) printf("%12s[ -ts [ -ts ... ] [ -p ] [ -noverifypeer ] ]\n", ""); printf("%12s[ -TSA-certs ] [ -TSA-key ]\n", ""); printf("%12s[ -TSA-time ]\n", ""); + printf("%12s[ -HTTPS-CAfile ]\n", ""); + printf("%12s[ -HTTPS-CRLfile ]\n", ""); printf("%12s[ -h {md5,sha1,sha2(56),sha384,sha512} ]\n", ""); printf("%12s[ -index ]\n", ""); printf("%12s[ -verbose ]\n", ""); @@ -3144,6 +3434,8 @@ static void usage(const char *argv0, const char *cmd) printf("%12s[ -c | -catalog ]\n", ""); printf("%12s[ -CAfile ]\n", ""); printf("%12s[ -CRLfile ]\n", ""); + printf("%12s[ -HTTPS-CAfile ]\n", ""); + printf("%12s[ -HTTPS-CRLfile ]\n", ""); printf("%12s[ -TSA-CAfile ]\n", ""); printf("%12s[ -TSA-CRLfile ]\n", ""); printf("%12s[ -p ]\n", ""); @@ -3181,6 +3473,7 @@ static void help_for(const char *argv0, const char *cmd) const char *cmds_certs[] = {"sign", NULL}; const char *cmds_comm[] = {"sign", NULL}; const char *cmds_CRLfile[] = {"attach-signature", "verify", NULL}; + const char *cmds_CRLfileHTTPS[] = {"add", "sign", "verify", NULL}; const char *cmds_CRLfileTSA[] = {"attach-signature", "verify", NULL}; const char *cmds_h[] = {"add", "attach-signature", "sign", "extract-data", NULL}; const char *cmds_i[] = {"sign", NULL}; @@ -3213,6 +3506,7 @@ static void help_for(const char *argv0, const char *cmd) const char *cmds_ignore_cdp[] = {"verify", NULL}; const char *cmds_t[] = {"add", "sign", NULL}; const char *cmds_ts[] = {"add", "sign", NULL}; + const char *cmds_CAfileHTTPS[] = {"add", "sign", "verify", NULL}; const char *cmds_CAfileTSA[] = {"attach-signature", "verify", NULL}; const char *cmds_certsTSA[] = {"add", "sign", NULL}; const char *cmds_keyTSA[] = {"add", "sign", NULL}; @@ -3364,6 +3658,10 @@ static void help_for(const char *argv0, const char *cmd) } if (on_list(cmd, cmds_time)) printf("%-24s= the unix-time to set the signing and/or verifying time\n", "-time"); + if (on_list(cmd, cmds_CAfileHTTPS)) + printf("%-24s= the file containing one or more HTTPS certificates in PEM format\n", "-HTTPS-CAfile"); + if (on_list(cmd, cmds_CRLfileHTTPS)) + printf("%-24s= the file containing one or more HTTPS CRLs in PEM format\n", "-HTTPS-CRLfile"); if (on_list(cmd, cmds_CAfileTSA)) printf("%-24s= the file containing one or more Time-Stamp Authority certificates in PEM format\n", "-TSA-CAfile"); if (on_list(cmd, cmds_CRLfileTSA)) @@ -3926,11 +4224,13 @@ static void print_version(void) printf("%s, using:\n", "osslsigncode custom build"); #endif /* PACKAGE_STRING */ printf("\t%s (Library: %s)\n", OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION)); +#if OPENSSL_VERSION_NUMBER<0x30000000L #ifdef ENABLE_CURL printf("\t%s\n", curl_version()); #else /* ENABLE_CURL */ printf("\t%s\n", "no libcurl available"); #endif /* ENABLE_CURL */ +#endif /* OPENSSL_VERSION_NUMBER<0x30000000L */ if (cafile) { printf("Default -CAfile location: %s\n", cafile); OPENSSL_free(cafile); @@ -4067,8 +4367,9 @@ static int main_configure(int argc, char **argv, GLOBAL_OPTIONS *options) if (cmd == CMD_HELP) { return 0; /* FAILED */ } - if (cmd == CMD_VERIFY || cmd == CMD_ATTACH) { + if (cmd == CMD_SIGN || cmd == CMD_VERIFY || cmd == CMD_ATTACH) { options->cafile = get_cafile(); + options->https_cafile = get_cafile(); options->tsa_cafile = get_cafile(); } for (argc--,argv++; argc >= 1; argc--,argv++) { @@ -4277,11 +4578,26 @@ static int main_configure(int argc, char **argv, GLOBAL_OPTIONS *options) return 0; /* FAILED */ } options->crlfile = OPENSSL_strdup(*++argv); + } else if ((cmd == CMD_SIGN || cmd == CMD_ADD || cmd == CMD_VERIFY) + && !strcmp(*argv, "-HTTPS-CAfile")) { + if (--argc < 1) { + usage(argv0, "all"); + return 0; /* FAILED */ + } + OPENSSL_free(options->https_cafile); + options->https_cafile = OPENSSL_strdup(*++argv); + } else if ((cmd == CMD_SIGN || cmd == CMD_ADD || cmd == CMD_VERIFY) + && !strcmp(*argv, "-HTTPS-CRLfile")) { + if (--argc < 1) { + usage(argv0, "all"); + return 0; /* FAILED */ + } + options->https_crlfile = OPENSSL_strdup(*++argv); } else if ((cmd == CMD_VERIFY || cmd == CMD_ATTACH) && (!strcmp(*argv, "-untrusted") || !strcmp(*argv, "-TSA-CAfile"))) { if (--argc < 1) { usage(argv0, "all"); return 0; /* FAILED */ - } + } OPENSSL_free(options->tsa_cafile); options->tsa_cafile = OPENSSL_strdup(*++argv); } else if ((cmd == CMD_VERIFY || cmd == CMD_ATTACH) && (!strcmp(*argv, "-CRLuntrusted") || !strcmp(*argv, "-TSA-CRLfile"))) { diff --git a/osslsigncode.h b/osslsigncode.h index 97ad12be..f5b5713b 100644 --- a/osslsigncode.h +++ b/osslsigncode.h @@ -14,6 +14,7 @@ #define NOCRYPT #define WIN32_LEAN_AND_MEAN #include +#include #endif /* HAVE_WINDOWS_H */ #ifdef HAVE_CONFIG_H @@ -32,6 +33,7 @@ #ifndef _WIN32 #include +#include #ifdef HAVE_SYS_MMAN_H #include #endif /* HAVE_SYS_MMAN_H */ @@ -63,6 +65,7 @@ #endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */ #include #include +#include #include #include #include /* X509_PURPOSE */ @@ -279,6 +282,8 @@ typedef struct { char *catalog; char *cafile; char *crlfile; + char *https_cafile; + char *https_crlfile; char *tsa_cafile; char *tsa_crlfile; char *leafhash; @@ -480,6 +485,14 @@ typedef struct { DECLARE_ASN1_FUNCTIONS(MsCtlContent) +typedef struct { + char *server; + const char *port; + int use_proxy; + int timeout; + SSL_CTX *ssl_ctx; +} HTTP_TLS_Info; + typedef struct file_format_st FILE_FORMAT; typedef struct script_ctx_st SCRIPT_CTX; diff --git a/tests/server_http.py b/tests/server_http.py index 963f6a91..084dc454 100644 --- a/tests/server_http.py +++ b/tests/server_http.py @@ -44,7 +44,7 @@ def do_GET(self): # pylint: disable=invalid-name try: url = urlparse(self.path) self.send_response(200) - self.send_header("Content-type", "application/crl") + self.send_header("Content-type", "application/pkix-crl") self.end_headers() resp_data = b'' # Read the file and send the contents diff --git a/tests/server_http.pyw b/tests/server_http.pyw index a1d006c4..df7c0175 100644 --- a/tests/server_http.pyw +++ b/tests/server_http.pyw @@ -41,7 +41,7 @@ class RequestHandler(SimpleHTTPRequestHandler): try: url = urlparse(self.path) self.send_response(200) - self.send_header("Content-type", "application/crl") + self.send_header("Content-type", "application/pkix-crl") self.end_headers() resp_data = b'' # Read the file and send the contents