diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c994d4f968485610af0a2a159c4e779521ac377..815f7c61b5a657604eac69705bb5d1b84b1aa0db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -183,7 +183,7 @@ jobs: - name: checkout fuzz/corpora submodule run: git submodule update --init --depth 1 fuzz/corpora - name: config - run: ./config --banner=Configured --debug enable-asan enable-ubsan enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-fips -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION && perl configdata.pm --dump + run: ./config --banner=Configured --debug enable-asan enable-ubsan enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-fips && perl configdata.pm --dump - name: make run: make -s -j4 - name: get cpu info @@ -193,6 +193,23 @@ jobs: - name: make test run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} OPENSSL_TEST_RAND_ORDER=0 + fuzz_tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: checkout fuzz/corpora submodule + run: git submodule update --init --depth 1 fuzz/corpora + - name: config + run: ./config --banner=Configured --debug -DPEDANTIC -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION enable-asan enable-ubsan enable-rc5 enable-md2 enable-ec_nistp_64_gcc_128 enable-weak-ssl-ciphers enable-ssl3 enable-ssl3-method enable-nextprotoneg && perl configdata.pm --dump + - name: make + run: make -s -j4 + - name: get cpu info + run: | + cat /proc/cpuinfo + ./util/opensslwrap.sh version -c + - name: make test + run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} OPENSSL_TEST_RAND_ORDER=0 TESTS="test_fuzz*" + memory_sanitizer: runs-on: ubuntu-latest steps: @@ -345,7 +362,7 @@ jobs: - name: checkout fuzz/corpora submodule run: git submodule update --init --depth 1 fuzz/corpora - name: config - run: ./config --banner=Configured --debug enable-asan enable-ubsan enable-comp enable-brotli -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -DPEDANTIC && perl configdata.pm --dump + run: ./config --banner=Configured --debug enable-asan enable-ubsan enable-comp enable-brotli -DPEDANTIC && perl configdata.pm --dump - name: make run: make -s -j4 - name: get cpu info @@ -367,7 +384,7 @@ jobs: - name: checkout fuzz/corpora submodule run: git submodule update --init --depth 1 fuzz/corpora - name: config - run: ./config --banner=Configured --debug enable-asan enable-ubsan enable-comp enable-zstd -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -DPEDANTIC && perl configdata.pm --dump + run: ./config --banner=Configured --debug enable-asan enable-ubsan enable-comp enable-zstd -DPEDANTIC && perl configdata.pm --dump - name: make run: make -s -j4 - name: get cpu info diff --git a/.github/workflows/fuzz-checker.yml b/.github/workflows/fuzz-checker.yml index 766a4a1326ecb29d4964eaccb0d44c3c3f0ea648..f476b525cff9fdc573137f237d670b092592ac31 100644 --- a/.github/workflows/fuzz-checker.yml +++ b/.github/workflows/fuzz-checker.yml @@ -23,6 +23,7 @@ jobs: config: enable-fuzz-afl no-module, install: afl++-clang, cc: afl-clang-fast + tests: - }, { name: libFuzzer, config: enable-fuzz-libfuzzer enable-asan enable-ubsan, diff --git a/.github/workflows/run-checker-daily.yml b/.github/workflows/run-checker-daily.yml index fdd07294a4a147515083275a1f25ad2767fae3f5..0dbbac285f17c68a8f34d9d8b2d98ea37ae9c846 100644 --- a/.github/workflows/run-checker-daily.yml +++ b/.github/workflows/run-checker-daily.yml @@ -147,6 +147,6 @@ jobs: - name: get cpu info run: | cat /proc/cpuinfo - ./util/opensslwrap.sh version -c + if [ -x apps/openssl ] ; then ./util/opensslwrap.sh version -c ; fi - name: make test run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 11d1b03abda52299fc8125b086a692b94726531d..05330f02d831340d7f1e6c517f816d7fe3d8c26a 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -26,7 +26,7 @@ jobs: --post-data "token=${{ secrets.COVERITY_TOKEN }}&project=openssl%2Fopenssl" \ --progress=dot:giga -O coverity_tool.tgz - name: config - run: CC=gcc ./config --banner=Configured --debug enable-fips enable-rc5 enable-md2 enable-ssl3 enable-nextprotoneg enable-ssl3-method enable-weak-ssl-ciphers enable-zlib enable-ec_nistp_64_gcc_128 no-shared enable-buildtest-c++ enable-external-tests -DPEDANTIC -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + run: CC=gcc ./config --banner=Configured --debug enable-fips enable-rc5 enable-md2 enable-ssl3 enable-nextprotoneg enable-ssl3-method enable-weak-ssl-ciphers enable-zlib enable-ec_nistp_64_gcc_128 no-shared enable-buildtest-c++ enable-external-tests -DPEDANTIC - name: config dump run: ./configdata.pm --dump - name: tool install diff --git a/CHANGES.md b/CHANGES.md index ef801c2f7362b8c6a7b341dbf83f62e8c860f4a3..15b5aa0542fc770882b0e590548576870c285b26 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -470,7 +470,15 @@ OpenSSL 3.2 OpenSSL 3.1 ----------- -### Changes between 3.1.2 and 3.1.3 [xx XXX xxxx] +### Changes between 3.1.3 and 3.1.4 [xx XXX xxxx] + +* Fix incorrect key and IV resizing issues when calling EVP_EncryptInit_ex2(), + EVP_DecryptInit_ex2() or EVP_CipherInit_ex2() with OSSL_PARAM parameters + that alter the key or IV length ([CVE-2023-5363]). + + *Paul Dale* + +### Changes between 3.1.2 and 3.1.3 [19 Sep 2023] * Fix POLY1305 MAC implementation corrupting XMM registers on Windows. @@ -20288,6 +20296,7 @@ ndif +[CVE-2023-5363]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-5363 [CVE-2023-4807]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-4807 [CVE-2023-3817]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-3817 [CVE-2023-3446]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-3446 diff --git a/NEWS.md b/NEWS.md index d0312961dfdc8b81b0cde836de8864b8ccf96a04..141f9dcc66cfd2d9c164b35a51700bf675c11ab2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -52,7 +52,12 @@ OpenSSL 3.2 OpenSSL 3.1 ----------- -### Major changes between OpenSSL 3.1.2 and OpenSSL 3.1.3 [under development] +### Major changes between OpenSSL 3.1.3 and OpenSSL 3.1.4 [under development] + + * Mitigate incorrect resize handling for symmetric cipher keys and IVs. + ([CVE-2023-5363]) + +### Major changes between OpenSSL 3.1.2 and OpenSSL 3.1.3 [19 Sep 2023] * Fix POLY1305 MAC implementation corrupting XMM registers on Windows ([CVE-2023-4807]) @@ -1502,6 +1507,7 @@ OpenSSL 0.9.x +[CVE-2023-5363]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-5363 [CVE-2023-4807]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-4807 [CVE-2023-3817]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-3817 [CVE-2023-3446]: https://www.openssl.org/news/vulnerabilities.html#CVE-2023-3446 diff --git a/README-QUIC.md b/README-QUIC.md new file mode 100644 index 0000000000000000000000000000000000000000..02708eda2c28d58a384d0e5990d5f89b862e3b16 --- /dev/null +++ b/README-QUIC.md @@ -0,0 +1,98 @@ +Using OpenSSL with QUIC +======================= + +From OpenSSL 3.2, OpenSSL features support for making QUIC connections as a +client. + +Users interested in using the new QUIC functionality are encouraged to look at +some of the following resources: + +- The [openssl-quic(7) manual page], which provides a basic reference overview + of QUIC functionality and how use of QUIC differs from use of TLS with regard + to our API; +- The new [OpenSSL Guide], which provides introductory guides + on the use of TLS, QUIC, and other OpenSSL functionality. See the + [ossl-guide-introduction(7) manual page][OpenSSL Guide] for the index. +- The [Demo-Driven Design (DDD)][DDD] demos, which demonstrate the use of QUIC + using simple examples. These can be [found in the source tree under + `doc/designs/ddd`]. +- The [demo found in `demos/http3`], which provides an HTTP/3 client example + using the nghttp3 HTTP/3 library. + +FAQ +--- + +### Why would I want to use QUIC, and what functionality does QUIC offer relative to TLS or DTLS? + +QUIC is a state-of-the-art secure transport protocol carried over UDP. It can +serve many of the use cases of TLS as well as those of DTLS. QUIC delivers +a number of advantages: + +- It supports multiple streams of communication, allowing application protocols + built on QUIC to create arbitrarily many bytestreams for communication between + a client and server. This allows an application protocol to avoid head-of-line + blocking and allows an application to open additional logical streams without + any round trip penalty, unlike opening an additional TCP connection. + +- Since QUIC is the basis of HTTP/3, support for QUIC also enables applications + to use HTTP/3 using a suitable third-party library. + +- Future versions of OpenSSL will offer support for 0-RTT connection + initiation, allowing a connection to be initiated to a server and application + data to be transmitted without any waiting time. This is similar to TLS 1.3's + 0-RTT functionality but also avoids the round trip needed to open a TCP + socket; thus, it is similar to a combination of TLS 1.3 0-RTT and TCP Fast + Open. + +- Future versions of OpenSSL will offer support for connection + migration, allowing connections to seamlessly survive IP address changes. + +- Future versions of OpenSSL will offer support for the QUIC + datagram extension, allowing support for both TLS and DTLS-style use cases on + a single connection. + +- Because most QUIC implementations, including OpenSSL's implementation, are + implemented as an application library rather than by an operating system, an + application can gain the benefit of QUIC without needing to wait for an OS + update to be deployed. Future evolutions and enhancements to the QUIC protocol + can be delivered as quickly as an application can be updated without + dependency on an OS update cadence. + +- Because QUIC is UDP-based, it is possible to multiplex a QUIC connection + on the same UDP socket as some other UDP-based protocols, such as RTP. + +For more background information on OpenSSL's QUIC implementation, see the +[openssl-quic(7) manual page]. + +### How can I use HTTP/3 with OpenSSL? + +There are many HTTP/3 implementations in C available. The use of one such HTTP/3 +library with OpenSSL QUIC is demonstrated via the [demo found in `demos/http3`]. + +### How can I use OpenSSL QUIC in my own application for a different protocol? + +The [OpenSSL Guide] provides introductory examples for how to make use of +OpenSSL QUIC. + +The [openssl-quic(7) manual page] and the [Demo-Driven Design (DDD)][DDD] demos +may also be helpful to illustrate the changes needed if you are trying to adapt +an existing application. + +### How can I test QUIC using `openssl s_client`? + +There is basic support for single-stream QUIC using `openssl s_client`: + +```shell +$ openssl s_client -quic -alpn ossltest -connect www.example.com:12345 +``` + +This connects to a QUIC server using the specified ALPN protocol name and opens +a single bidirectional stream. Data can be passed via stdin/stdout as usual. +This allows test usage of QUIC using simple TCP/TLS-like usage. + +[openssl-quic(7) manual page]: https://www.openssl.org/docs/manmaster/man7/openssl-quic.html +[OpenSSL guide]: https://www.openssl.org/docs/manmaster/man7/ossl-guide-introduction.html +[DDD]: https://github.com/openssl/openssl/tree/master/doc/designs/ddd +[found in the source tree under `doc/designs/ddd`]: ./doc/designs/ddd/ +[demo found in `demos/http3`]: ./demos/http3/ +[openssl-quic-background(7) manual page]: https://www.openssl.org/docs/manmaster/man7/openssl-quic-background.html diff --git a/apps/lib/apps.c b/apps/lib/apps.c index 6b2a4b86ce670313ba2b0fac17f9accb9489e341..47d994b9c2f35a7bec5dcfdee144a6849589be5c 100644 --- a/apps/lib/apps.c +++ b/apps/lib/apps.c @@ -1003,10 +1003,16 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, ctx = OSSL_STORE_open_ex(uri, libctx, propq, get_ui_method(), &uidata, params, NULL, NULL); } - if (ctx == NULL) + if (ctx == NULL) { + if (!quiet) + BIO_printf(bio_err, "Could not open file or uri for loading"); goto end; - if (expect > 0 && !OSSL_STORE_expect(ctx, expect)) + } + if (expect > 0 && !OSSL_STORE_expect(ctx, expect)) { + if (!quiet) + BIO_printf(bio_err, "Internal error trying to load"); goto end; + } failed = NULL; while ((ppkey != NULL || ppubkey != NULL || pparams != NULL @@ -1100,8 +1106,6 @@ int load_key_certs_crls(const char *uri, int format, int maybe_stdin, failed = FAIL_NAME; if (failed != NULL && !quiet) BIO_printf(bio_err, "Could not find"); - } else if (!quiet) { - BIO_printf(bio_err, "Could not read"); } if (failed != NULL && !quiet) { unsigned long err = ERR_peek_last_error(); diff --git a/apps/openssl-vms.cnf b/apps/openssl-vms.cnf index d6d5f58db6e54e7ac6ae5ec69d39f258c10f9767..8203d9ea0cf1bbe35d0a7a006e9508f4bd7c4619 100644 --- a/apps/openssl-vms.cnf +++ b/apps/openssl-vms.cnf @@ -388,10 +388,3 @@ oldcert = $insta::certout # insta.cert.pem # Certificate revocation cmd = rr oldcert = $insta::certout # insta.cert.pem - -[pkcs12] -certBagAttr = cb_attr - -# Uncomment this if you need Java compatible PKCS12 files -[cb_attr] -#jdkTrustedKeyUsage = anyExtendedKeyUsage diff --git a/apps/openssl.cnf b/apps/openssl.cnf index 0d564d3ba581306505270a0e142a11df3fd58919..2833b6f30bc6b51718c08a1dbe8341b39abd57d1 100644 --- a/apps/openssl.cnf +++ b/apps/openssl.cnf @@ -388,10 +388,3 @@ oldcert = $insta::certout # insta.cert.pem # Certificate revocation cmd = rr oldcert = $insta::certout # insta.cert.pem - -[pkcs12] -certBagAttr = cb_attr - -# Uncomment this if you need Java compatible PKCS12 files -[cb_attr] -#jdkTrustedKeyUsage = anyExtendedKeyUsage diff --git a/apps/pkcs12.c b/apps/pkcs12.c index 8e8c771819a345272600f49d18bf8a302b299c5a..1fa0abd3d4c61015bbf053e90ecddde0317d5258 100644 --- a/apps/pkcs12.c +++ b/apps/pkcs12.c @@ -71,7 +71,7 @@ typedef enum OPTION_choice { OPT_NAME, OPT_CSP, OPT_CANAME, OPT_IN, OPT_OUT, OPT_PASSIN, OPT_PASSOUT, OPT_PASSWORD, OPT_CAPATH, OPT_CAFILE, OPT_CASTORE, OPT_NOCAPATH, OPT_NOCAFILE, OPT_NOCASTORE, OPT_ENGINE, - OPT_R_ENUM, OPT_PROV_ENUM, + OPT_R_ENUM, OPT_PROV_ENUM, OPT_JDKTRUST, #ifndef OPENSSL_NO_DES OPT_LEGACY_ALG #endif @@ -154,6 +154,7 @@ const OPTIONS pkcs12_options[] = { {"maciter", OPT_MACITER, '-', "Unused, kept for backwards compatibility"}, {"macsaltlen", OPT_MACSALTLEN, 'p', "Specify the salt len for MAC"}, {"nomac", OPT_NOMAC, '-', "Don't generate MAC"}, + {"jdktrust", OPT_JDKTRUST, 's', "Mark certificate in PKCS#12 store as trusted for JDK compatibility"}, {NULL} }; @@ -165,6 +166,7 @@ int pkcs12_main(int argc, char **argv) char *name = NULL, *csp_name = NULL; char pass[PASSWD_BUF_SIZE] = "", macpass[PASSWD_BUF_SIZE] = ""; int export_pkcs12 = 0, options = 0, chain = 0, twopass = 0, keytype = 0; + char *jdktrust = NULL; #ifndef OPENSSL_NO_DES int use_legacy = 0; #endif @@ -222,6 +224,11 @@ int pkcs12_main(int argc, char **argv) case OPT_NOOUT: options |= (NOKEYS | NOCERTS); break; + case OPT_JDKTRUST: + jdktrust = opt_arg(); + /* Adding jdk trust implies nokeys */ + options |= NOKEYS; + break; case OPT_INFO: options |= INFO; break; @@ -530,9 +537,6 @@ int pkcs12_main(int argc, char **argv) int i; CONF *conf = NULL; ASN1_OBJECT *obj = NULL; - STACK_OF(CONF_VALUE) *cb_sk = NULL; - const char *cb_attr = NULL; - const CONF_VALUE *val = NULL; if ((options & (NOCERTS | NOKEYS)) == (NOCERTS | NOKEYS)) { BIO_printf(bio_err, "Nothing to export due to -noout or -nocerts and -nokeys\n"); @@ -682,20 +686,9 @@ int pkcs12_main(int argc, char **argv) goto export_end; if (!app_load_modules(conf)) goto export_end; - /* Find the cert bag section */ - cb_attr = app_conf_try_string(conf, "pkcs12", "certBagAttr"); - if (cb_attr != NULL) { - if ((cb_sk = NCONF_get_section(conf, cb_attr)) != NULL) { - for (i = 0; i < sk_CONF_VALUE_num(cb_sk); i++) { - val = sk_CONF_VALUE_value(cb_sk, i); - if (strcmp(val->name, "jdkTrustedKeyUsage") == 0) { - obj = OBJ_txt2obj(val->value, 0); - break; - } - } - } else { - ERR_clear_error(); - } + + if (jdktrust != NULL) { + obj = OBJ_txt2obj(jdktrust, 0); } p12 = PKCS12_create_ex2(cpass, name, key, ee_cert, certs, diff --git a/crypto/asn1/asn1_gen.c b/crypto/asn1/asn1_gen.c index 2b27624d8ae8562df081cadef4e896440a0b1189..6f73449cf405c836e627e54e91a234e51128946c 100644 --- a/crypto/asn1/asn1_gen.c +++ b/crypto/asn1/asn1_gen.c @@ -7,9 +7,10 @@ * https://www.openssl.org/source/license.html */ -#include "internal/cryptlib.h" #include #include +#include "internal/cryptlib.h" +#include "crypto/asn1.h" #define ASN1_GEN_FLAG 0x10000 #define ASN1_GEN_FLAG_IMP (ASN1_GEN_FLAG|1) diff --git a/crypto/cms/cms_enc.c b/crypto/cms/cms_enc.c index c9a5cfc69bbfbec07acabf2a0bcc71ef4a16f0e7..ea8f07e1affc655a4ead339a08145b1e6bc5fabf 100644 --- a/crypto/cms/cms_enc.c +++ b/crypto/cms/cms_enc.c @@ -15,6 +15,7 @@ #include #include #include "crypto/evp.h" +#include "crypto/asn1.h" #include "cms_local.h" /* CMS EncryptedData Utilities */ @@ -81,7 +82,7 @@ BIO *ossl_cms_EncryptedContent_init_bio(CMS_EncryptedContentInfo *ec, if (enc) { calg->algorithm = OBJ_nid2obj(EVP_CIPHER_CTX_get_type(ctx)); - if (calg->algorithm == NULL) { + if (calg->algorithm == NULL || calg->algorithm->nid == NID_undef) { ERR_raise(ERR_LIB_CMS, CMS_R_UNSUPPORTED_CONTENT_ENCRYPTION_ALGORITHM); goto err; } diff --git a/crypto/cms/cms_err.c b/crypto/cms/cms_err.c index 40f79eefa931bab244430044454620b9805864fa..40aeb7088cad03c3f48f096747c5a182d98a0473 100644 --- a/crypto/cms/cms_err.c +++ b/crypto/cms/cms_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -156,6 +156,8 @@ static const ERR_STRING_DATA CMS_str_reasons[] = { "unsupported recipientinfo type"}, {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_RECIPIENT_TYPE), "unsupported recipient type"}, + {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_SIGNATURE_ALGORITHM), + "unsupported signature algorithm"}, {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNSUPPORTED_TYPE), "unsupported type"}, {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNWRAP_ERROR), "unwrap error"}, {ERR_PACK(ERR_LIB_CMS, 0, CMS_R_UNWRAP_FAILURE), "unwrap failure"}, diff --git a/crypto/cms/cms_sd.c b/crypto/cms/cms_sd.c index c32e95f10dda1155902c126d929f0ac5e49cc512..43a404da14890ba93e00425a5665f5f8c853812e 100644 --- a/crypto/cms/cms_sd.c +++ b/crypto/cms/cms_sd.c @@ -386,11 +386,15 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, if (md == NULL) { int def_nid; - if (EVP_PKEY_get_default_digest_nid(pk, &def_nid) <= 0) + if (EVP_PKEY_get_default_digest_nid(pk, &def_nid) <= 0) { + ERR_raise_data(ERR_LIB_CMS, CMS_R_NO_DEFAULT_DIGEST, + "pkey nid=%d", EVP_PKEY_get_id(pk)); goto err; + } md = EVP_get_digestbynid(def_nid); if (md == NULL) { - ERR_raise(ERR_LIB_CMS, CMS_R_NO_DEFAULT_DIGEST); + ERR_raise_data(ERR_LIB_CMS, CMS_R_NO_DEFAULT_DIGEST, + "default md nid=%d", def_nid); goto err; } } @@ -422,8 +426,11 @@ CMS_SignerInfo *CMS_add1_signer(CMS_ContentInfo *cms, } } - if (!(flags & CMS_KEY_PARAM) && !cms_sd_asn1_ctrl(si, 0)) + if (!(flags & CMS_KEY_PARAM) && !cms_sd_asn1_ctrl(si, 0)) { + ERR_raise_data(ERR_LIB_CMS, CMS_R_UNSUPPORTED_SIGNATURE_ALGORITHM, + "pkey nid=%d", EVP_PKEY_get_id(pk)); goto err; + } if (!(flags & CMS_NOATTR)) { /* * Initialize signed attributes structure so other attributes diff --git a/crypto/conf/conf_lib.c b/crypto/conf/conf_lib.c index 05e7bf19cc7b35202753119e15bf917ba3b573bf..99e9f8c987b3471b4e6470425846b96dc4be8f49 100644 --- a/crypto/conf/conf_lib.c +++ b/crypto/conf/conf_lib.c @@ -421,6 +421,12 @@ OPENSSL_INIT_SETTINGS *OPENSSL_INIT_new(void) #ifndef OPENSSL_NO_STDIO +/* + * If CRYPTO_set_mem_functions is called after this, then + * memory allocation and deallocation in this function can + * become disjointed. Avoid this by always using standard + * strdup & free instead of OPENSSL_strdup & OPENSSL_free. + */ int OPENSSL_INIT_set_config_filename(OPENSSL_INIT_SETTINGS *settings, const char *filename) { @@ -444,6 +450,12 @@ void OPENSSL_INIT_set_config_file_flags(OPENSSL_INIT_SETTINGS *settings, settings->flags = flags; } +/* + * If CRYPTO_set_mem_functions is called after this, then + * memory allocation and deallocation in this function can + * become disjointed. Avoid this by always using standard + * strdup & free instead of OPENSSL_strdup & OPENSSL_free. + */ int OPENSSL_INIT_set_config_appname(OPENSSL_INIT_SETTINGS *settings, const char *appname) { diff --git a/crypto/err/err.c b/crypto/err/err.c index 7b7f309951554ca586273966a236253883b3da51..b95182d7029a2433081deaa1cd650e761534e070 100644 --- a/crypto/err/err.c +++ b/crypto/err/err.c @@ -834,7 +834,8 @@ void ERR_add_error_vdata(int num, va_list args) * If err_data is allocated already, reuse the space. * Otherwise, allocate a small new buffer. */ - if ((es->err_data_flags[i] & flags) == flags) { + if ((es->err_data_flags[i] & flags) == flags + && ossl_assert(es->err_data[i] != NULL)) { str = es->err_data[i]; size = es->err_data_size[i]; diff --git a/crypto/err/err_save.c b/crypto/err/err_save.c index 3ca059adc336b0dbf9cf61f80ab95bd086b8b629..1994c26ceef0c15cee128b3a63e09be55fb3fbce 100644 --- a/crypto/err/err_save.c +++ b/crypto/err/err_save.c @@ -85,16 +85,18 @@ void OSSL_ERR_STATE_save_to_mark(ERR_STATE *es) es->err_line[i] = thread_es->err_line[j]; es->err_func[i] = thread_es->err_func[j]; - thread_es->err_flags[j] = 0; - thread_es->err_buffer[j] = 0; - thread_es->err_data[j] = NULL; - thread_es->err_data_size[j] = 0; - thread_es->err_file[j] = NULL; - thread_es->err_line[j] = 0; - thread_es->err_func[j] = NULL; + thread_es->err_flags[j] = 0; + thread_es->err_buffer[j] = 0; + thread_es->err_data[j] = NULL; + thread_es->err_data_size[j] = 0; + thread_es->err_data_flags[j] = 0; + thread_es->err_file[j] = NULL; + thread_es->err_line[j] = 0; + thread_es->err_func[j] = NULL; } if (i > 0) { + thread_es->top = top; /* If we moved anything, es's stack always starts at [0]. */ es->top = i - 1; es->bottom = ERR_NUM_ERRORS - 1; diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 6952560d86610d7380537875cfce6ffd13bf6a99..1211b500c3befc6f3c4c5ff446719944f4d473f8 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -387,6 +387,7 @@ CMS_R_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM:179:\ CMS_R_UNSUPPORTED_LABEL_SOURCE:193:unsupported label source CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE:155:unsupported recipientinfo type CMS_R_UNSUPPORTED_RECIPIENT_TYPE:154:unsupported recipient type +CMS_R_UNSUPPORTED_SIGNATURE_ALGORITHM:195:unsupported signature algorithm CMS_R_UNSUPPORTED_TYPE:156:unsupported type CMS_R_UNWRAP_ERROR:157:unwrap error CMS_R_UNWRAP_FAILURE:180:unwrap failure diff --git a/crypto/evp/evp_enc.c b/crypto/evp/evp_enc.c index e1d3eeef641f8f489836670b9f1d58dbcca02f98..e9faf3105728e559fe6470bbd3fc4ae6911beb17 100644 --- a/crypto/evp/evp_enc.c +++ b/crypto/evp/evp_enc.c @@ -233,6 +233,42 @@ static int evp_cipher_init_internal(EVP_CIPHER_CTX *ctx, return 0; } +#ifndef FIPS_MODULE + /* + * Fix for CVE-2023-5363 + * Passing in a size as part of the init call takes effect late + * so, force such to occur before the initialisation. + * + * The FIPS provider's internal library context is used in a manner + * such that this is not an issue. + */ + if (params != NULL) { + OSSL_PARAM param_lens[3] = { OSSL_PARAM_END, OSSL_PARAM_END, + OSSL_PARAM_END }; + OSSL_PARAM *q = param_lens; + const OSSL_PARAM *p; + + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_KEYLEN); + if (p != NULL) + memcpy(q++, p, sizeof(*q)); + + /* + * Note that OSSL_CIPHER_PARAM_AEAD_IVLEN is a synomym for + * OSSL_CIPHER_PARAM_IVLEN so both are covered here. + */ + p = OSSL_PARAM_locate_const(params, OSSL_CIPHER_PARAM_IVLEN); + if (p != NULL) + memcpy(q++, p, sizeof(*q)); + + if (q != param_lens) { + if (!EVP_CIPHER_CTX_set_params(ctx, param_lens)) { + ERR_raise(ERR_LIB_EVP, EVP_R_INVALID_LENGTH); + return 0; + } + } + } +#endif + if (enc) { if (ctx->cipher->einit == NULL) { ERR_raise(ERR_LIB_EVP, EVP_R_INITIALIZATION_ERROR); diff --git a/crypto/evp/evp_rand.c b/crypto/evp/evp_rand.c index ecfc876cda8617b23914c97ac360b1ad12b2d66e..50334042a9cca11c445aba13568343817432ffac 100644 --- a/crypto/evp/evp_rand.c +++ b/crypto/evp/evp_rand.c @@ -46,6 +46,8 @@ struct evp_rand_st { OSSL_FUNC_rand_get_ctx_params_fn *get_ctx_params; OSSL_FUNC_rand_set_ctx_params_fn *set_ctx_params; OSSL_FUNC_rand_verify_zeroization_fn *verify_zeroization; + OSSL_FUNC_rand_get_seed_fn *get_seed; + OSSL_FUNC_rand_clear_seed_fn *clear_seed; } /* EVP_RAND */ ; static int evp_rand_up_ref(void *vrand) @@ -236,6 +238,16 @@ static void *evp_rand_from_algorithm(int name_id, fnzeroizecnt++; #endif break; + case OSSL_FUNC_RAND_GET_SEED: + if (rand->get_seed != NULL) + break; + rand->get_seed = OSSL_FUNC_rand_get_seed(fns); + break; + case OSSL_FUNC_RAND_CLEAR_SEED: + if (rand->clear_seed != NULL) + break; + rand->clear_seed = OSSL_FUNC_rand_clear_seed(fns); + break; } } /* @@ -680,3 +692,59 @@ int EVP_RAND_verify_zeroization(EVP_RAND_CTX *ctx) evp_rand_unlock(ctx); return res; } + +int evp_rand_can_seed(EVP_RAND_CTX *ctx) +{ + return ctx->meth->get_seed != NULL; +} + +static size_t evp_rand_get_seed_locked(EVP_RAND_CTX *ctx, + unsigned char **buffer, + int entropy, + size_t min_len, size_t max_len, + int prediction_resistance, + const unsigned char *adin, + size_t adin_len) +{ + if (ctx->meth->get_seed != NULL) + return ctx->meth->get_seed(ctx->algctx, buffer, + entropy, min_len, max_len, + prediction_resistance, + adin, adin_len); + return 0; +} + +size_t evp_rand_get_seed(EVP_RAND_CTX *ctx, + unsigned char **buffer, + int entropy, size_t min_len, size_t max_len, + int prediction_resistance, + const unsigned char *adin, size_t adin_len) +{ + int res; + + if (!evp_rand_lock(ctx)) + return 0; + res = evp_rand_get_seed_locked(ctx, + buffer, + entropy, min_len, max_len, + prediction_resistance, + adin, adin_len); + evp_rand_unlock(ctx); + return res; +} + +static void evp_rand_clear_seed_locked(EVP_RAND_CTX *ctx, + unsigned char *buffer, size_t b_len) +{ + if (ctx->meth->clear_seed != NULL) + ctx->meth->clear_seed(ctx->algctx, buffer, b_len); +} + +void evp_rand_clear_seed(EVP_RAND_CTX *ctx, + unsigned char *buffer, size_t b_len) +{ + if (!evp_rand_lock(ctx)) + return; + evp_rand_clear_seed_locked(ctx, buffer, b_len); + evp_rand_unlock(ctx); +} diff --git a/crypto/evp/legacy_sha.c b/crypto/evp/legacy_sha.c index 3859286eeb2046e6532919a19fdba3e5174715d5..0c2afc29007597e947785c60e50ac2984948a46c 100644 --- a/crypto/evp/legacy_sha.c +++ b/crypto/evp/legacy_sha.c @@ -71,7 +71,11 @@ static int sha1_int_ctrl(EVP_MD_CTX *ctx, int cmd, int p1, void *p2) static int shake_ctrl(EVP_MD_CTX *evp_ctx, int cmd, int p1, void *p2) { - KECCAK1600_CTX *ctx = evp_ctx->md_data; + KECCAK1600_CTX *ctx; + + if (evp_ctx == NULL) + return 0; + ctx = evp_ctx->md_data; switch (cmd) { case EVP_MD_CTRL_XOF_LEN: diff --git a/crypto/objects/obj_dat.c b/crypto/objects/obj_dat.c index 2c1a288167e4e013f1914cb5ccfe8d5dd4fb8500..b0e1032ec2cf859caa026fb0b2fa8a71ca29d304 100644 --- a/crypto/objects/obj_dat.c +++ b/crypto/objects/obj_dat.c @@ -221,25 +221,45 @@ void ossl_obj_cleanup_int(void) objs_free_locks(); } -int OBJ_new_nid(int num) +/* + * Requires that the ossl_obj_lock be held + * if TSAN_REQUIRES_LOCKING defined + */ +static int obj_new_nid_unlocked(int num) { static TSAN_QUALIFIER int new_nid = NUM_NID; #ifdef TSAN_REQUIRES_LOCKING int i; - if (!CRYPTO_THREAD_write_lock(ossl_obj_nid_lock)) { - ERR_raise(ERR_LIB_OBJ, ERR_R_UNABLE_TO_GET_WRITE_LOCK); - return NID_undef; - } i = new_nid; new_nid += num; - CRYPTO_THREAD_unlock(ossl_obj_nid_lock); + return i; #else return tsan_add(&new_nid, num); #endif } +int OBJ_new_nid(int num) +{ +#ifdef TSAN_REQUIRES_LOCKING + int i; + + if (!ossl_obj_write_lock(1)) { + ERR_raise(ERR_LIB_OBJ, ERR_R_UNABLE_TO_GET_WRITE_LOCK); + return NID_undef; + } + + i = obj_new_nid_unlocked(num); + + ossl_obj_unlock(1); + + return i; +#else + return obj_new_nid_unlocked(num); +#endif +} + static int ossl_obj_add_object(const ASN1_OBJECT *obj, int lock) { ASN1_OBJECT *o = NULL; @@ -677,13 +697,14 @@ const void *OBJ_bsearch_ex_(const void *key, const void *base, int num, if (p == NULL) { const char *base_ = base; int l, h, i = 0, c = 0; + char *p1; for (i = 0; i < num; ++i) { - p = &(base_[i * size]); - c = (*cmp) (key, p); + p1 = &(base_[i * size]); + c = (*cmp) (key, p1); if (c == 0 || (c < 0 && (flags & OBJ_BSEARCH_VALUE_ON_NOMATCH))) - return p; + return p1; } } #endif @@ -784,7 +805,8 @@ int OBJ_create(const char *oid, const char *sn, const char *ln) goto err; } - tmpoid->nid = OBJ_new_nid(1); + tmpoid->nid = obj_new_nid_unlocked(1); + if (tmpoid->nid == NID_undef) goto err; diff --git a/crypto/param_build_set.c b/crypto/param_build_set.c index e26ce15500da3e3a1a35ae81c03e025029d590d6..f205d101936a6c44b31bac8a521a289ebfdafaea 100644 --- a/crypto/param_build_set.c +++ b/crypto/param_build_set.c @@ -101,21 +101,22 @@ int ossl_param_build_set_multi_key_bn(OSSL_PARAM_BLD *bld, OSSL_PARAM *params, { int i, sz = sk_BIGNUM_const_num(stk); OSSL_PARAM *p; - + const BIGNUM *bn; if (bld != NULL) { for (i = 0; i < sz && names[i] != NULL; ++i) { - if (!OSSL_PARAM_BLD_push_BN(bld, names[i], - sk_BIGNUM_const_value(stk, i))) + bn = sk_BIGNUM_const_value(stk, i); + if (bn != NULL && !OSSL_PARAM_BLD_push_BN(bld, names[i], bn)) return 0; } return 1; } for (i = 0; i < sz && names[i] != NULL; ++i) { + bn = sk_BIGNUM_const_value(stk, i); p = OSSL_PARAM_locate(params, names[i]); - if (p != NULL) { - if (!OSSL_PARAM_set_BN(p, sk_BIGNUM_const_value(stk, i))) + if (p != NULL && bn != NULL) { + if (!OSSL_PARAM_set_BN(p, bn)) return 0; } } diff --git a/crypto/provider_core.c b/crypto/provider_core.c index 266934937cb892aa7d3b39541056e4d81bb58b60..838bcd161c810ee809730cddfda0bbd2cdea20d8 100644 --- a/crypto/provider_core.c +++ b/crypto/provider_core.c @@ -1930,12 +1930,14 @@ OSSL_FUNC_BIO_free_fn ossl_core_bio_free; OSSL_FUNC_BIO_vprintf_fn ossl_core_bio_vprintf; OSSL_FUNC_BIO_vsnprintf_fn BIO_vsnprintf; static OSSL_FUNC_self_test_cb_fn core_self_test_get_callback; -static OSSL_FUNC_get_user_entropy_fn rand_get_user_entropy; static OSSL_FUNC_get_entropy_fn rand_get_entropy; +static OSSL_FUNC_get_user_entropy_fn rand_get_user_entropy; static OSSL_FUNC_cleanup_entropy_fn rand_cleanup_entropy; -static OSSL_FUNC_get_user_nonce_fn rand_get_user_nonce; +static OSSL_FUNC_cleanup_user_entropy_fn rand_cleanup_user_entropy; static OSSL_FUNC_get_nonce_fn rand_get_nonce; +static OSSL_FUNC_get_user_nonce_fn rand_get_user_nonce; static OSSL_FUNC_cleanup_nonce_fn rand_cleanup_nonce; +static OSSL_FUNC_cleanup_user_nonce_fn rand_cleanup_user_nonce; #endif OSSL_FUNC_CRYPTO_malloc_fn CRYPTO_malloc; OSSL_FUNC_CRYPTO_zalloc_fn CRYPTO_zalloc; @@ -2119,6 +2121,13 @@ static void rand_cleanup_entropy(const OSSL_CORE_HANDLE *handle, buf, len); } +static void rand_cleanup_user_entropy(const OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len) +{ + ossl_rand_cleanup_user_entropy((OSSL_LIB_CTX *)core_get_libctx(handle), + buf, len); +} + static size_t rand_get_nonce(const OSSL_CORE_HANDLE *handle, unsigned char **pout, size_t min_len, size_t max_len, @@ -2144,6 +2153,13 @@ static void rand_cleanup_nonce(const OSSL_CORE_HANDLE *handle, buf, len); } +static void rand_cleanup_user_nonce(const OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len) +{ + ossl_rand_cleanup_user_nonce((OSSL_LIB_CTX *)core_get_libctx(handle), + buf, len); +} + static const char *core_provider_get0_name(const OSSL_CORE_HANDLE *prov) { return OSSL_PROVIDER_get0_name((const OSSL_PROVIDER *)prov); @@ -2238,11 +2254,13 @@ static const OSSL_DISPATCH core_dispatch_[] = { { OSSL_FUNC_BIO_VSNPRINTF, (void (*)(void))BIO_vsnprintf }, { OSSL_FUNC_SELF_TEST_CB, (void (*)(void))core_self_test_get_callback }, { OSSL_FUNC_GET_ENTROPY, (void (*)(void))rand_get_entropy }, + { OSSL_FUNC_GET_USER_ENTROPY, (void (*)(void))rand_get_user_entropy }, { OSSL_FUNC_CLEANUP_ENTROPY, (void (*)(void))rand_cleanup_entropy }, + { OSSL_FUNC_CLEANUP_USER_ENTROPY, (void (*)(void))rand_cleanup_user_entropy }, { OSSL_FUNC_GET_NONCE, (void (*)(void))rand_get_nonce }, - { OSSL_FUNC_CLEANUP_NONCE, (void (*)(void))rand_cleanup_nonce }, - { OSSL_FUNC_GET_USER_ENTROPY, (void (*)(void))rand_get_user_entropy }, { OSSL_FUNC_GET_USER_NONCE, (void (*)(void))rand_get_user_nonce }, + { OSSL_FUNC_CLEANUP_NONCE, (void (*)(void))rand_cleanup_nonce }, + { OSSL_FUNC_CLEANUP_USER_NONCE, (void (*)(void))rand_cleanup_user_nonce }, #endif { OSSL_FUNC_CRYPTO_MALLOC, (void (*)(void))CRYPTO_malloc }, { OSSL_FUNC_CRYPTO_ZALLOC, (void (*)(void))CRYPTO_zalloc }, diff --git a/crypto/rand/prov_seed.c b/crypto/rand/prov_seed.c index af35e0247595a7df70a6fa6f610e638bcb120942..2985c7f2d81130b0f0b0bd8909083d8473c04e6a 100644 --- a/crypto/rand/prov_seed.c +++ b/crypto/rand/prov_seed.c @@ -8,6 +8,7 @@ */ #include "rand_local.h" +#include "crypto/evp.h" #include "crypto/rand.h" #include "crypto/rand_pool.h" #include "internal/core.h" @@ -44,31 +45,13 @@ size_t ossl_rand_get_user_entropy(OSSL_LIB_CTX *ctx, unsigned char **pout, int entropy, size_t min_len, size_t max_len) { - unsigned char *buf; EVP_RAND_CTX *rng = ossl_rand_get0_seed_noncreating(ctx); - size_t ret; - if (rng == NULL) + if (rng != NULL && evp_rand_can_seed(rng)) + return evp_rand_get_seed(rng, pout, entropy, min_len, max_len, + 0, NULL, 0); + else return ossl_rand_get_entropy(ctx, pout, entropy, min_len, max_len); - - /* Determine how many bytes to generate */ - ret = entropy > 0 ? (size_t)(7 + entropy) / 8 : min_len; - if (ret < min_len) - ret = min_len; - else if (ret > max_len) - ret = max_len; - - /* Allocate the return buffer */ - if ((buf = OPENSSL_secure_malloc(ret)) == NULL) - return 0; - - /* Fill the buffer */ - if (!EVP_RAND_generate(rng, buf, ret, entropy, 0, NULL, 0)) { - OPENSSL_free(buf); - return 0; - } - *pout = buf; - return ret; } void ossl_rand_cleanup_entropy(ossl_unused OSSL_LIB_CTX *ctx, @@ -77,6 +60,17 @@ void ossl_rand_cleanup_entropy(ossl_unused OSSL_LIB_CTX *ctx, OPENSSL_secure_clear_free(buf, len); } +void ossl_rand_cleanup_user_entropy(OSSL_LIB_CTX *ctx, + unsigned char *buf, size_t len) +{ + EVP_RAND_CTX *rng = ossl_rand_get0_seed_noncreating(ctx); + + if (rng != NULL && evp_rand_can_seed(rng)) + evp_rand_clear_seed(rng, buf, len); + else + OPENSSL_secure_clear_free(buf, len); +} + size_t ossl_rand_get_nonce(ossl_unused OSSL_LIB_CTX *ctx, unsigned char **pout, size_t min_len, ossl_unused size_t max_len, @@ -130,3 +124,9 @@ void ossl_rand_cleanup_nonce(ossl_unused OSSL_LIB_CTX *ctx, { OPENSSL_clear_free(buf, len); } + +void ossl_rand_cleanup_user_nonce(ossl_unused OSSL_LIB_CTX *ctx, + unsigned char *buf, size_t len) +{ + OPENSSL_clear_free(buf, len); +} diff --git a/crypto/rand/rand_pool.c b/crypto/rand/rand_pool.c index 8dc230b540f619420c6ecf13bc8d420a26cdd641..8d77b77fd21dbc1c86e13ed67f5aa9e87699d510 100644 --- a/crypto/rand/rand_pool.c +++ b/crypto/rand/rand_pool.c @@ -249,7 +249,11 @@ size_t ossl_rand_pool_bytes_needed(RAND_POOL *pool, unsigned int entropy_factor) if (bytes_needed > pool->max_len - pool->len) { /* not enough space left */ - ERR_raise(ERR_LIB_RAND, RAND_R_RANDOM_POOL_OVERFLOW); + ERR_raise_data(ERR_LIB_RAND, RAND_R_RANDOM_POOL_OVERFLOW, + "entropy_factor=%u, entropy_needed=%zu, bytes_needed=%zu," + "pool->max_len=%zu, pool->len=%zu", + entropy_factor, entropy_needed, bytes_needed, + pool->max_len, pool->len); return 0; } diff --git a/crypto/rsa/rsa_backend.c b/crypto/rsa/rsa_backend.c index c416d4bf61310150681fa911019ba1a3fb582990..7b2efa88620fadae9feadcbce106c5636eb269db 100644 --- a/crypto/rsa/rsa_backend.c +++ b/crypto/rsa/rsa_backend.c @@ -141,18 +141,6 @@ int ossl_rsa_todata(RSA *rsa, OSSL_PARAM_BLD *bld, OSSL_PARAM params[], /* Check private key data integrity */ if (include_private && rsa_d != NULL) { - int numprimes = sk_BIGNUM_const_num(factors); - int numexps = sk_BIGNUM_const_num(exps); - int numcoeffs = sk_BIGNUM_const_num(coeffs); - - /* - * It's permissible to have zero primes, i.e. no CRT params. - * Otherwise, there must be at least two, as many exponents, - * and one coefficient less. - */ - if (numprimes != 0 - && (numprimes < 2 || numexps < 2 || numcoeffs < 1)) - goto err; if (!ossl_param_build_set_bn(bld, params, OSSL_PKEY_PARAM_RSA_D, rsa_d) diff --git a/crypto/rsa/rsa_lib.c b/crypto/rsa/rsa_lib.c index f1be43351292bfa7df9710235ab039e54f4dab7e..9548054da7bd7d743bae08256eac2b6f32193aaf 100644 --- a/crypto/rsa/rsa_lib.c +++ b/crypto/rsa/rsa_lib.c @@ -757,18 +757,22 @@ int ossl_rsa_set0_all_params(RSA *r, const STACK_OF(BIGNUM) *primes, return 0; pnum = sk_BIGNUM_num(primes); - if (pnum < 2 - || pnum != sk_BIGNUM_num(exps) - || pnum != sk_BIGNUM_num(coeffs) + 1) + if (pnum < 2) return 0; if (!RSA_set0_factors(r, sk_BIGNUM_value(primes, 0), - sk_BIGNUM_value(primes, 1)) - || !RSA_set0_crt_params(r, sk_BIGNUM_value(exps, 0), - sk_BIGNUM_value(exps, 1), - sk_BIGNUM_value(coeffs, 0))) + sk_BIGNUM_value(primes, 1))) return 0; + if (pnum == sk_BIGNUM_num(exps) + && pnum == sk_BIGNUM_num(coeffs) + 1) { + + if (!RSA_set0_crt_params(r, sk_BIGNUM_value(exps, 0), + sk_BIGNUM_value(exps, 1), + sk_BIGNUM_value(coeffs, 0))) + return 0; + } + #ifndef FIPS_MODULE old_infos = r->prime_infos; #endif @@ -1086,6 +1090,12 @@ int EVP_PKEY_CTX_get_rsa_mgf1_md(EVP_PKEY_CTX *ctx, const EVP_MD **md) int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, void *label, int llen) { OSSL_PARAM rsa_params[2], *p = rsa_params; + const char *empty = ""; + /* + * Needed as we swap label with empty if it is NULL, and label is + * freed at the end of this function. + */ + void *plabel = label; int ret; if (ctx == NULL || !EVP_PKEY_CTX_IS_ASYM_CIPHER_OP(ctx)) { @@ -1098,9 +1108,13 @@ int EVP_PKEY_CTX_set0_rsa_oaep_label(EVP_PKEY_CTX *ctx, void *label, int llen) if (!EVP_PKEY_CTX_is_a(ctx, "RSA")) return -1; + /* Accept NULL for backward compatibility */ + if (label == NULL && llen == 0) + plabel = (void *)empty; + /* Cast away the const. This is read only so should be safe */ *p++ = OSSL_PARAM_construct_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, - (void *)label, (size_t)llen); + (void *)plabel, (size_t)llen); *p++ = OSSL_PARAM_construct_end(); ret = evp_pkey_ctx_set_params_strict(ctx, rsa_params); diff --git a/crypto/x509/v3_addr.c b/crypto/x509/v3_addr.c index f4c8de2d160b9e2e79dfd34b1be53466d834a2a5..b990d54048e6b387a88076d91d710c87f008a784 100644 --- a/crypto/x509/v3_addr.c +++ b/crypto/x509/v3_addr.c @@ -16,12 +16,13 @@ #include #include -#include "internal/cryptlib.h" #include #include #include #include #include +#include "internal/cryptlib.h" +#include "crypto/asn1.h" #include "crypto/x509.h" #include "ext_dat.h" #include "x509_local.h" diff --git a/demos/http3/Makefile b/demos/http3/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..89bac3743e1ef0ffaf693989d41acf6fbe6ac819 --- /dev/null +++ b/demos/http3/Makefile @@ -0,0 +1,14 @@ +CFLAGS = -I../../include -g -Wall +LDFLAGS = -L../.. +LDLIBS = -lcrypto -lssl -lnghttp3 + +all: ossl-nghttp3-demo + +clean: + $(RM) -f ossl-nghttp3-demo *.o + +ossl-nghttp3-demo: ossl-nghttp3-demo.o ossl-nghttp3.o + $(CC) $(CFLAGS) -o "$@" $^ $(LDFLAGS) $(LDLIBS) + +%.o: %.c + $(CC) $(CFLAGS) -c -o "$@" "$<" diff --git a/demos/http3/README.md b/demos/http3/README.md new file mode 100644 index 0000000000000000000000000000000000000000..e087aba1e182e534e886797f471928219d645293 --- /dev/null +++ b/demos/http3/README.md @@ -0,0 +1,38 @@ +HTTP/3 Demo using OpenSSL QUIC and nghttp3 +========================================== + +This is a simple demo of how to use HTTP/3 with OpenSSL QUIC using the HTTP/3 +library “[nghttp3](https://github.com/ngtcp2/nghttp3)”. + +The demo is structured into two parts: + +- an adaptation layer which binds nghttp3 to OpenSSL's QUIC implementation + (`ossl-nghttp3.c`); +- a simple application which makes an HTTP/3 request using this adaptation + layer (`ossl-nghttp3-demo.c`). + +The Makefile in this directory can be used to build the demo on \*nix-style +systems. You will need to have the `nghttp3` library available. + +Running the Demo +---------------- + +Depending on your system configuration it may be necessary to set the +`SSL_CERT_FILE` or `SSL_CERT_DIR` environment variables to a location where +trusted root CA certificates can be found. + +After building by running `make`, run `./ossl-nghttp3-demo` with a hostname and +port as the sole argument: + +```shell +$ make +$ ./ossl-nghttp3-demo www.google.com:443 +``` + +The demo produces the HTTP response headers in textual form as output followed +by the response body. + +See Also +-------- + +- [nghttp3](https://github.com/ngtcp2/nghttp3) diff --git a/demos/http3/ossl-nghttp3-demo.c b/demos/http3/ossl-nghttp3-demo.c new file mode 100644 index 0000000000000000000000000000000000000000..b1cbd1abf9d250b88aab218d1515547f11501c62 --- /dev/null +++ b/demos/http3/ossl-nghttp3-demo.c @@ -0,0 +1,150 @@ +/* + * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#include "ossl-nghttp3.h" +#include + +static int done; + +static void make_nv(nghttp3_nv *nv, const char *name, const char *value) +{ + nv->name = (uint8_t *)name; + nv->value = (uint8_t *)value; + nv->namelen = strlen(name); + nv->valuelen = strlen(value); + nv->flags = NGHTTP3_NV_FLAG_NONE; +} + +static int on_recv_header(nghttp3_conn *h3conn, int64_t stream_id, + int32_t token, + nghttp3_rcbuf *name, nghttp3_rcbuf *value, + uint8_t flags, + void *conn_user_data, + void *stream_user_data) +{ + nghttp3_vec vname, vvalue; + + /* Received a single HTTP header. */ + vname = nghttp3_rcbuf_get_buf(name); + vvalue = nghttp3_rcbuf_get_buf(value); + + fwrite(vname.base, vname.len, 1, stderr); + fprintf(stderr, ": "); + fwrite(vvalue.base, vvalue.len, 1, stderr); + fprintf(stderr, "\n"); + + return 0; +} + +static int on_end_headers(nghttp3_conn *h3conn, int64_t stream_id, + int fin, + void *conn_user_data, void *stream_user_data) +{ + fprintf(stderr, "\n"); + return 0; +} + +static int on_recv_data(nghttp3_conn *h3conn, int64_t stream_id, + const uint8_t *data, size_t datalen, + void *conn_user_data, void *stream_user_data) +{ + ssize_t wr; + + /* HTTP response body data - write it to stdout. */ + while (datalen > 0) { + wr = fwrite(data, 1, datalen, stdout); + if (wr < 0) + return 1; + + data += wr; + datalen -= wr; + } + + return 0; +} + +static int on_end_stream(nghttp3_conn *h3conn, int64_t stream_id, + void *conn_user_data, void *stream_user_data) +{ + /* HTTP transaction is done - set done flag so that we stop looping. */ + done = 1; + return 0; +} + +int main(int argc, char **argv) +{ + int ret = 1; + SSL_CTX *ctx = NULL; + OSSL_DEMO_H3_CONN *conn = NULL; + nghttp3_nv nva[16]; + nghttp3_callbacks callbacks = {0}; + size_t num_nv = 0; + const char *addr; + + /* Check arguments. */ + if (argc < 2) { + fprintf(stderr, "usage: %s \n", argv[0]); + goto err; + } + + addr = argv[1]; + + /* Setup SSL_CTX. */ + if ((ctx = SSL_CTX_new(OSSL_QUIC_client_method())) == NULL) + goto err; + + SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL); + + if (SSL_CTX_set_default_verify_paths(ctx) == 0) + goto err; + + /* Setup callbacks. */ + callbacks.recv_header = on_recv_header; + callbacks.end_headers = on_end_headers; + callbacks.recv_data = on_recv_data; + callbacks.end_stream = on_end_stream; + + /* Create connection. */ + if ((conn = OSSL_DEMO_H3_CONN_new_for_addr(ctx, addr, &callbacks, + NULL, NULL)) == NULL) { + ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL, + "cannot create HTTP/3 connection"); + goto err; + } + + /* Build HTTP headers. */ + make_nv(&nva[num_nv++], ":method", "GET"); + make_nv(&nva[num_nv++], ":scheme", "https"); + make_nv(&nva[num_nv++], ":authority", addr); + make_nv(&nva[num_nv++], ":path", "/"); + make_nv(&nva[num_nv++], "user-agent", "OpenSSL-Demo/nghttp3"); + + /* Submit request. */ + if (!OSSL_DEMO_H3_CONN_submit_request(conn, nva, num_nv, NULL, NULL)) { + ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL, + "cannot submit HTTP/3 request"); + goto err; + } + + /* Wait for request to complete. */ + while (!done) + if (!OSSL_DEMO_H3_CONN_handle_events(conn)) { + ERR_raise_data(ERR_LIB_USER, ERR_R_OPERATION_FAIL, + "cannot handle events"); + goto err; + } + + ret = 0; +err: + if (ret != 0) + ERR_print_errors_fp(stderr); + + OSSL_DEMO_H3_CONN_free(conn); + SSL_CTX_free(ctx); + return ret; +} diff --git a/demos/http3/ossl-nghttp3.c b/demos/http3/ossl-nghttp3.c new file mode 100644 index 0000000000000000000000000000000000000000..2b2259f34fb16884a54d0291bf9e2113eb3d016f --- /dev/null +++ b/demos/http3/ossl-nghttp3.c @@ -0,0 +1,741 @@ +/* + * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#include "ossl-nghttp3.h" +#include +#include + +#define ARRAY_LEN(x) (sizeof(x)/sizeof((x)[0])) + +enum { + OSSL_DEMO_H3_STREAM_TYPE_CTRL_SEND, + OSSL_DEMO_H3_STREAM_TYPE_QPACK_ENC_SEND, + OSSL_DEMO_H3_STREAM_TYPE_QPACK_DEC_SEND, + OSSL_DEMO_H3_STREAM_TYPE_REQ, +}; + +#define BUF_SIZE 4096 + +struct ossl_demo_h3_stream_st { + uint64_t id; /* QUIC stream ID */ + SSL *s; /* QUIC stream SSL object */ + int done_recv_fin; /* Received FIN */ + void *user_data; + + uint8_t buf[BUF_SIZE]; + size_t buf_cur, buf_total; +}; + +DEFINE_LHASH_OF_EX(OSSL_DEMO_H3_STREAM); + +static void h3_stream_free(OSSL_DEMO_H3_STREAM *s) +{ + if (s == NULL) + return; + + SSL_free(s->s); + OPENSSL_free(s); +} + +static unsigned long h3_stream_hash(const OSSL_DEMO_H3_STREAM *s) +{ + return (unsigned long)s->id; +} + +static int h3_stream_eq(const OSSL_DEMO_H3_STREAM *a, const OSSL_DEMO_H3_STREAM *b) +{ + if (a->id < b->id) return -1; + if (a->id > b->id) return 1; + return 0; +} + +void *OSSL_DEMO_H3_STREAM_get_user_data(const OSSL_DEMO_H3_STREAM *s) +{ + return s->user_data; +} + +struct ossl_demo_h3_conn_st { + /* QUIC connection SSL object */ + SSL *qconn; + /* BIO wrapping QCSO */ + BIO *qconn_bio; + /* HTTP/3 connection object */ + nghttp3_conn *h3conn; + /* map of stream IDs to OSSL_DEMO_H3_STREAMs */ + LHASH_OF(OSSL_DEMO_H3_STREAM) *streams; + /* opaque user data pointer */ + void *user_data; + + int pump_res; + size_t consumed_app_data; + + /* Forwarding callbacks */ + nghttp3_recv_data recv_data_cb; + nghttp3_stream_close stream_close_cb; + nghttp3_stop_sending stop_sending_cb; + nghttp3_reset_stream reset_stream_cb; + nghttp3_deferred_consume deferred_consume_cb; +}; + +void OSSL_DEMO_H3_CONN_free(OSSL_DEMO_H3_CONN *conn) +{ + if (conn == NULL) + return; + + lh_OSSL_DEMO_H3_STREAM_doall(conn->streams, h3_stream_free); + + nghttp3_conn_del(conn->h3conn); + BIO_free_all(conn->qconn_bio); + lh_OSSL_DEMO_H3_STREAM_free(conn->streams); + OPENSSL_free(conn); +} + +static OSSL_DEMO_H3_STREAM *h3_conn_create_stream(OSSL_DEMO_H3_CONN *conn, int type) +{ + OSSL_DEMO_H3_STREAM *s; + uint64_t flags = SSL_STREAM_FLAG_ADVANCE; + + if ((s = OPENSSL_zalloc(sizeof(OSSL_DEMO_H3_STREAM))) == NULL) + return NULL; + + if (type != OSSL_DEMO_H3_STREAM_TYPE_REQ) + flags |= SSL_STREAM_FLAG_UNI; + + if ((s->s = SSL_new_stream(conn->qconn, flags)) == NULL) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "could not create QUIC stream object"); + goto err; + } + + s->id = SSL_get_stream_id(s->s); + lh_OSSL_DEMO_H3_STREAM_insert(conn->streams, s); + return s; + +err: + OPENSSL_free(s); + return NULL; +} + +static OSSL_DEMO_H3_STREAM *h3_conn_accept_stream(OSSL_DEMO_H3_CONN *conn, SSL *qstream) +{ + OSSL_DEMO_H3_STREAM *s; + + if ((s = OPENSSL_zalloc(sizeof(OSSL_DEMO_H3_STREAM))) == NULL) + return NULL; + + s->id = SSL_get_stream_id(qstream); + s->s = qstream; + lh_OSSL_DEMO_H3_STREAM_insert(conn->streams, s); + return s; +} + +static void h3_conn_remove_stream(OSSL_DEMO_H3_CONN *conn, OSSL_DEMO_H3_STREAM *s) +{ + if (s == NULL) + return; + + lh_OSSL_DEMO_H3_STREAM_delete(conn->streams, s); + h3_stream_free(s); +} + +static int h3_conn_recv_data(nghttp3_conn *h3conn, int64_t stream_id, + const uint8_t *data, size_t datalen, + void *conn_user_data, void *stream_user_data) +{ + OSSL_DEMO_H3_CONN *conn = conn_user_data; + + conn->consumed_app_data += datalen; + if (conn->recv_data_cb == NULL) + return 0; + + return conn->recv_data_cb(h3conn, stream_id, data, datalen, + conn_user_data, stream_user_data); +} + +static int h3_conn_stream_close(nghttp3_conn *h3conn, int64_t stream_id, + uint64_t app_error_code, + void *conn_user_data, void *stream_user_data) +{ + int ret = 0; + OSSL_DEMO_H3_CONN *conn = conn_user_data; + OSSL_DEMO_H3_STREAM *stream = stream_user_data; + + if (conn->stream_close_cb != NULL) + ret = conn->stream_close_cb(h3conn, stream_id, app_error_code, + conn_user_data, stream_user_data); + + h3_conn_remove_stream(conn, stream); + return ret; +} + +static int h3_conn_stop_sending(nghttp3_conn *h3conn, int64_t stream_id, + uint64_t app_error_code, + void *conn_user_data, void *stream_user_data) +{ + int ret = 0; + OSSL_DEMO_H3_CONN *conn = conn_user_data; + OSSL_DEMO_H3_STREAM *stream = stream_user_data; + + if (conn->stop_sending_cb != NULL) + ret = conn->stop_sending_cb(h3conn, stream_id, app_error_code, + conn_user_data, stream_user_data); + + SSL_free(stream->s); + stream->s = NULL; + return ret; +} + +static int h3_conn_reset_stream(nghttp3_conn *h3conn, int64_t stream_id, + uint64_t app_error_code, + void *conn_user_data, void *stream_user_data) +{ + int ret = 0; + OSSL_DEMO_H3_CONN *conn = conn_user_data; + OSSL_DEMO_H3_STREAM *stream = stream_user_data; + SSL_STREAM_RESET_ARGS args = {0}; + + if (conn->reset_stream_cb != NULL) + ret = conn->reset_stream_cb(h3conn, stream_id, app_error_code, + conn_user_data, stream_user_data); + + if (stream->s != NULL) { + args.quic_error_code = app_error_code; + + if (!SSL_stream_reset(stream->s, &args, sizeof(args))) + return 1; + } + + return ret; +} + +static int h3_conn_deferred_consume(nghttp3_conn *h3conn, int64_t stream_id, + size_t consumed, + void *conn_user_data, void *stream_user_data) +{ + int ret = 0; + OSSL_DEMO_H3_CONN *conn = conn_user_data; + + if (conn->deferred_consume_cb != NULL) + ret = conn->deferred_consume_cb(h3conn, stream_id, consumed, + conn_user_data, stream_user_data); + + conn->consumed_app_data += consumed; + return ret; +} + +OSSL_DEMO_H3_CONN *OSSL_DEMO_H3_CONN_new_for_conn(BIO *qconn_bio, + const nghttp3_callbacks *callbacks, + const nghttp3_settings *settings, + void *user_data) +{ + int ec; + OSSL_DEMO_H3_CONN *conn; + OSSL_DEMO_H3_STREAM *s_ctl_send = NULL; + OSSL_DEMO_H3_STREAM *s_qpenc_send = NULL; + OSSL_DEMO_H3_STREAM *s_qpdec_send = NULL; + nghttp3_settings dsettings = {0}; + nghttp3_callbacks intl_callbacks = {0}; + static const unsigned char alpn[] = {2, 'h', '3'}; + + if (qconn_bio == NULL) { + ERR_raise_data(ERR_LIB_USER, ERR_R_PASSED_NULL_PARAMETER, + "QUIC connection BIO must be provided"); + return NULL; + } + + if ((conn = OPENSSL_zalloc(sizeof(OSSL_DEMO_H3_CONN))) == NULL) + return NULL; + + conn->qconn_bio = qconn_bio; + conn->user_data = user_data; + + if (BIO_get_ssl(qconn_bio, &conn->qconn) == 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_PASSED_INVALID_ARGUMENT, + "BIO must be an SSL BIO"); + goto err; + } + + /* Create the map of stream IDs to OSSL_DEMO_H3_STREAM structures. */ + if ((conn->streams = lh_OSSL_DEMO_H3_STREAM_new(h3_stream_hash, h3_stream_eq)) == NULL) + goto err; + + /* + * If the application has not started connecting yet, helpfully + * auto-configure ALPN. If the application wants to initiate the connection + * itself, it must take care of this itself. + */ + if (SSL_in_before(conn->qconn)) + if (SSL_set_alpn_protos(conn->qconn, alpn, sizeof(alpn))) { + /* SSL_set_alpn_protos returns 1 on failure */ + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "failed to configure ALPN"); + goto err; + } + + /* + * We use the QUIC stack in non-blocking mode so that we can react to + * incoming data on different streams, and e.g. incoming streams initiated + * by a server, as and when events occur. + */ + BIO_set_nbio(conn->qconn_bio, 1); + + /* + * Disable default stream mode and create all streams explicitly. Each QUIC + * stream will be represented by its own QUIC stream SSL object (QSSO). This + * also automatically enables us to accept incoming streams (see + * SSL_set_incoming_stream_policy(3)). + */ + if (!SSL_set_default_stream_mode(conn->qconn, SSL_DEFAULT_STREAM_MODE_NONE)) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "failed to configure default stream mode"); + goto err; + } + + /* + * HTTP/3 requires a couple of unidirectional management streams: a control + * stream and some QPACK state management streams for each side of a + * connection. These are the instances on our side (with us sending); the + * server will also create its own equivalent unidirectional streams on its + * side, which we handle subsequently as they come in (see SSL_accept_stream + * in the event handling code below). + */ + if ((s_ctl_send + = h3_conn_create_stream(conn, OSSL_DEMO_H3_STREAM_TYPE_CTRL_SEND)) == NULL) + goto err; + + if ((s_qpenc_send + = h3_conn_create_stream(conn, OSSL_DEMO_H3_STREAM_TYPE_QPACK_ENC_SEND)) == NULL) + goto err; + + if ((s_qpdec_send + = h3_conn_create_stream(conn, OSSL_DEMO_H3_STREAM_TYPE_QPACK_DEC_SEND)) == NULL) + goto err; + + if (settings == NULL) { + nghttp3_settings_default(&dsettings); + settings = &dsettings; + } + + if (callbacks != NULL) + intl_callbacks = *callbacks; + + /* + * We need to do some of our own processing when many of these events occur, + * so we note the original callback functions and forward appropriately. + */ + conn->recv_data_cb = intl_callbacks.recv_data; + conn->stream_close_cb = intl_callbacks.stream_close; + conn->stop_sending_cb = intl_callbacks.stop_sending; + conn->reset_stream_cb = intl_callbacks.reset_stream; + conn->deferred_consume_cb = intl_callbacks.deferred_consume; + + intl_callbacks.recv_data = h3_conn_recv_data; + intl_callbacks.stream_close = h3_conn_stream_close; + intl_callbacks.stop_sending = h3_conn_stop_sending; + intl_callbacks.reset_stream = h3_conn_reset_stream; + intl_callbacks.deferred_consume = h3_conn_deferred_consume; + + /* Create the HTTP/3 client state. */ + ec = nghttp3_conn_client_new(&conn->h3conn, &intl_callbacks, settings, + NULL, conn); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "cannot create nghttp3 connection: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + /* + * Tell the HTTP/3 stack which stream IDs are used for our outgoing control + * and QPACK streams. Note that we don't have to tell the HTTP/3 stack what + * IDs are used for incoming streams as this is inferred automatically from + * the stream type byte which starts every incoming unidirectional stream, + * so it will autodetect the correct stream IDs for the incoming control and + * QPACK streams initiated by the server. + */ + ec = nghttp3_conn_bind_control_stream(conn->h3conn, s_ctl_send->id); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "cannot bind nghttp3 control stream: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + ec = nghttp3_conn_bind_qpack_streams(conn->h3conn, + s_qpenc_send->id, + s_qpdec_send->id); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "cannot bind nghttp3 QPACK streams: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + return conn; + +err: + nghttp3_conn_del(conn->h3conn); + h3_stream_free(s_ctl_send); + h3_stream_free(s_qpenc_send); + h3_stream_free(s_qpdec_send); + lh_OSSL_DEMO_H3_STREAM_free(conn->streams); + OPENSSL_free(conn); + return NULL; +} + +OSSL_DEMO_H3_CONN *OSSL_DEMO_H3_CONN_new_for_addr(SSL_CTX *ctx, const char *addr, + const nghttp3_callbacks *callbacks, + const nghttp3_settings *settings, + void *user_data) +{ + BIO *qconn_bio = NULL; + SSL *qconn = NULL; + OSSL_DEMO_H3_CONN *conn = NULL; + const char *bare_hostname; + + /* QUIC connection setup */ + if ((qconn_bio = BIO_new_ssl_connect(ctx)) == NULL) + goto err; + + /* Pass the 'hostname:port' string into the ssl_connect BIO. */ + if (BIO_set_conn_hostname(qconn_bio, addr) == 0) + goto err; + + /* + * Get the 'bare' hostname out of the ssl_connect BIO. This is the hostname + * without the port. + */ + bare_hostname = BIO_get_conn_hostname(qconn_bio); + if (bare_hostname == NULL) + goto err; + + if (BIO_get_ssl(qconn_bio, &qconn) == 0) + goto err; + + /* Set the hostname we will validate the X.509 certificate against. */ + if (SSL_set1_host(qconn, bare_hostname) <= 0) + goto err; + + /* Configure SNI */ + if (!SSL_set_tlsext_host_name(qconn, bare_hostname)) + goto err; + + conn = OSSL_DEMO_H3_CONN_new_for_conn(qconn_bio, callbacks, + settings, user_data); + if (conn == NULL) + goto err; + + return conn; + +err: + BIO_free_all(qconn_bio); + return NULL; +} + +int OSSL_DEMO_H3_CONN_connect(OSSL_DEMO_H3_CONN *conn) +{ + return SSL_connect(OSSL_DEMO_H3_CONN_get0_connection(conn)); +} + +void *OSSL_DEMO_H3_CONN_get_user_data(const OSSL_DEMO_H3_CONN *conn) +{ + return conn->user_data; +} + +SSL *OSSL_DEMO_H3_CONN_get0_connection(const OSSL_DEMO_H3_CONN *conn) +{ + return conn->qconn; +} + +/* Pumps received data to the HTTP/3 stack for a single stream. */ +static void h3_conn_pump_stream(OSSL_DEMO_H3_STREAM *s, void *conn_) +{ + int ec; + OSSL_DEMO_H3_CONN *conn = conn_; + size_t num_bytes, consumed; + uint64_t aec; + + if (!conn->pump_res) + /* + * Handling of a previous stream in the iteration over all streams + * failed, so just do nothing. + */ + return; + + for (;;) { + if (s->s == NULL /* If we already did STOP_SENDING, ignore this stream. */ + /* If this is a write-only stream, there is no read data to check. */ + || SSL_get_stream_read_state(s->s) == SSL_STREAM_STATE_WRONG_DIR + /* + * If we already got a FIN for this stream, there is nothing more to + * do for it. + */ + || s->done_recv_fin) + break; + + /* + * Pump data from OpenSSL QUIC to the HTTP/3 stack by calling SSL_peek + * to get received data and passing it to nghttp3 using + * nghttp3_conn_read_stream. Note that this function is confusingly + * named and inputs data to the HTTP/3 stack. + */ + if (s->buf_cur == s->buf_total) { + /* Need more data. */ + ec = SSL_read_ex(s->s, s->buf, sizeof(s->buf), &num_bytes); + if (ec <= 0) { + num_bytes = 0; + if (SSL_get_error(s->s, ec) == SSL_ERROR_ZERO_RETURN) { + /* Stream concluded normally. Pass FIN to HTTP/3 stack. */ + ec = nghttp3_conn_read_stream(conn->h3conn, s->id, NULL, 0, + /*fin=*/1); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "cannot pass FIN to nghttp3: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + s->done_recv_fin = 1; + } else if (SSL_get_stream_read_state(s->s) + == SSL_STREAM_STATE_RESET_REMOTE) { + /* Stream was reset by peer. */ + if (!SSL_get_stream_read_error_code(s->s, &aec)) + goto err; + + ec = nghttp3_conn_close_stream(conn->h3conn, s->id, aec); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "cannot mark stream as reset: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + s->done_recv_fin = 1; + } else { + /* Other error. */ + goto err; + } + } + + s->buf_cur = 0; + s->buf_total = num_bytes; + } + + if (s->buf_cur == s->buf_total) + break; + + /* + * This function is confusingly named as it is is named from nghttp3's + * 'perspective'; it is used to pass data *into* the HTTP/3 stack which + * has been received from the network. + */ + assert(conn->consumed_app_data == 0); + ec = nghttp3_conn_read_stream(conn->h3conn, s->id, s->buf + s->buf_cur, + s->buf_total - s->buf_cur, /*fin=*/0); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "nghttp3 failed to process incoming data: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + /* + * read_stream reports the data it consumes from us in two different + * ways; the non-application data is returned as a number of bytes 'ec' + * above, but the number of bytes of application data has to be recorded + * by our callback. We sum the two to determine the total number of + * bytes which nghttp3 consumed. + */ + consumed = ec + conn->consumed_app_data; + assert(consumed <= s->buf_total - s->buf_cur); + s->buf_cur += consumed; + conn->consumed_app_data = 0; + } + + return; +err: + conn->pump_res = 0; +} + +int OSSL_DEMO_H3_CONN_handle_events(OSSL_DEMO_H3_CONN *conn) +{ + int ec, fin; + size_t i, num_vecs, written, total_written, total_len; + int64_t stream_id; + nghttp3_vec vecs[8] = {0}; + OSSL_DEMO_H3_STREAM key, *s; + SSL *snew; + + if (conn == NULL) + return 0; + + /* + * We handle events by doing three things: + * + * 1. Handle new incoming streams + * 2. Pump outgoing data from the HTTP/3 stack to the QUIC engine + * 3. Pump incoming data from the QUIC engine to the HTTP/3 stack + */ + + /* 1. Check for new incoming streams */ + for (;;) { + if ((snew = SSL_accept_stream(conn->qconn, SSL_ACCEPT_STREAM_NO_BLOCK)) == NULL) + break; + + /* + * Each new incoming stream gets wrapped into an OSSL_DEMO_H3_STREAM object and + * added into our stream ID map. + */ + if (h3_conn_accept_stream(conn, snew) == NULL) { + SSL_free(snew); + return 0; + } + } + + /* 2. Pump outgoing data from HTTP/3 engine to QUIC. */ + for (;;) { + /* + * Get a number of send vectors from the HTTP/3 engine. + * + * Note that this function is confusingly named as it is named from + * nghttp3's 'perspective': this outputs pointers to data which nghttp3 + * wants to *write* to the network. + */ + ec = nghttp3_conn_writev_stream(conn->h3conn, &stream_id, &fin, + vecs, ARRAY_LEN(vecs)); + if (ec < 0) + return 0; + if (ec == 0) + break; + + /* For each of the vectors returned, pass it to OpenSSL QUIC. */ + key.id = stream_id; + if ((s = lh_OSSL_DEMO_H3_STREAM_retrieve(conn->streams, &key)) == NULL) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "no stream for ID %zd", stream_id); + return 0; + } + + num_vecs = ec; + total_len = nghttp3_vec_len(vecs, num_vecs); + total_written = 0; + for (i = 0; i < num_vecs; ++i) { + if (vecs[i].len == 0) + continue; + + if (s->s == NULL) { + /* Already did STOP_SENDING and threw away stream, ignore */ + written = vecs[i].len; + } else if (!SSL_write_ex(s->s, vecs[i].base, vecs[i].len, &written)) { + if (SSL_get_error(s->s, 0) == SSL_ERROR_WANT_WRITE) { + /* + * We have filled our send buffer so tell nghttp3 to stop + * generating more data; we have to do this explicitly. + */ + written = 0; + nghttp3_conn_block_stream(conn->h3conn, stream_id); + } else { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "writing HTTP/3 data to network failed"); + return 0; + } + } else { + /* + * Tell nghttp3 it can resume generating more data in case we + * previously called block_stream. + */ + nghttp3_conn_unblock_stream(conn->h3conn, stream_id); + } + + total_written += written; + if (written > 0) { + /* + * Tell nghttp3 we have consumed the data it output when we + * called writev_stream, otherwise subsequent calls to + * writev_stream will output the same data. + */ + ec = nghttp3_conn_add_write_offset(conn->h3conn, stream_id, written); + if (ec < 0) + return 0; + + /* + * Tell nghttp3 it can free the buffered data because we will + * not need it again. In our case we can always do this right + * away because we copy the data into our QUIC send buffers + * rather than simply storing a reference to it. + */ + ec = nghttp3_conn_add_ack_offset(conn->h3conn, stream_id, written); + if (ec < 0) + return 0; + } + } + + if (fin && total_written == total_len) { + /* + * We have written all the data so mark the stream as concluded + * (FIN). + */ + SSL_stream_conclude(s->s, 0); + + if (total_len == 0) { + /* + * As a special case, if nghttp3 requested to write a + * zero-length stream with a FIN, we have to tell it we did this + * by calling add_write_offset(0). + */ + ec = nghttp3_conn_add_write_offset(conn->h3conn, stream_id, 0); + if (ec < 0) + return 0; + } + } + } + + /* 3. Pump incoming data from QUIC to HTTP/3 engine. */ + conn->pump_res = 1; /* cleared in below call if an error occurs */ + lh_OSSL_DEMO_H3_STREAM_doall_arg(conn->streams, h3_conn_pump_stream, conn); + if (!conn->pump_res) + return 0; + + return 1; +} + +int OSSL_DEMO_H3_CONN_submit_request(OSSL_DEMO_H3_CONN *conn, + const nghttp3_nv *nva, size_t nvlen, + const nghttp3_data_reader *dr, + void *user_data) +{ + int ec; + OSSL_DEMO_H3_STREAM *s_req = NULL; + + if (conn == NULL) { + ERR_raise_data(ERR_LIB_USER, ERR_R_PASSED_NULL_PARAMETER, + "connection must be specified"); + return 0; + } + + /* Each HTTP/3 request is represented by a stream. */ + if ((s_req = h3_conn_create_stream(conn, OSSL_DEMO_H3_STREAM_TYPE_REQ)) == NULL) + goto err; + + s_req->user_data = user_data; + + ec = nghttp3_conn_submit_request(conn->h3conn, s_req->id, nva, nvlen, + dr, s_req); + if (ec < 0) { + ERR_raise_data(ERR_LIB_USER, ERR_R_INTERNAL_ERROR, + "cannot submit HTTP/3 request: %s (%d)", + nghttp3_strerror(ec), ec); + goto err; + } + + return 1; + +err: + h3_conn_remove_stream(conn, s_req); + return 0; +} diff --git a/demos/http3/ossl-nghttp3.h b/demos/http3/ossl-nghttp3.h new file mode 100644 index 0000000000000000000000000000000000000000..7926d866b121aae4f49cb9d936984c1d4aac59d3 --- /dev/null +++ b/demos/http3/ossl-nghttp3.h @@ -0,0 +1,111 @@ +/* + * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#ifndef OSSL_NGHTTP3_H +# define OSSL_NGHTTP3_H + +# include +# include +# include + +/* + * ossl-nghttp3: Demo binding of nghttp3 to OpenSSL QUIC + * ===================================================== + * + * This is a simple library which provides an example binding of the nghttp3 + * HTTP/3 library to OpenSSL's QUIC API. + */ + +/* Represents an HTTP/3 connection to a server. */ +typedef struct ossl_demo_h3_conn_st OSSL_DEMO_H3_CONN; + +/* Represents an HTTP/3 request, control or QPACK stream. */ +typedef struct ossl_demo_h3_stream_st OSSL_DEMO_H3_STREAM; + +/* + * Creates a HTTP/3 connection using the given QUIC client connection BIO. The + * BIO must be able to provide an SSL object pointer using BIO_get_ssl. Takes + * ownership of the reference. If the QUIC connection SSL object has not already + * been connected, HTTP/3 ALPN is set automatically. If it has already been + * connected, HTTP/3 ALPN ("h3") must have been configured and no streams must + * have been created yet. + * + * If settings is NULL, use default settings only. Settings unsupported by + * this QUIC binding are ignored. + * + * user_data is an application-provided opaque value which can be retrieved + * using OSSL_DEMO_H3_CONN_get_user_data. Note that the user data value passed + * to the callback functions specified in callbacks is a pointer to the + * OSSL_DEMO_H3_CONN, not user_data. + * + * Returns NULL on failure. + */ +OSSL_DEMO_H3_CONN *OSSL_DEMO_H3_CONN_new_for_conn(BIO *qconn_bio, + const nghttp3_callbacks *callbacks, + const nghttp3_settings *settings, + void *user_data); + +/* + * Works identically to OSSL_DEMO_H3_CONN_new_for_conn except that it manages + * the creation of a QUIC connection SSL object automatically using an address + * string. addr should be a string such as "www.example.com:443". The created + * underlying QUIC connection SSL object is owned by the OSSL_DEMO_H3_CONN and + * can be subsequently retrieved using OSSL_DEMO_H3_CONN_get0_connection. + * + * Returns NULL on failure. ctx must be a SSL_CTX using a QUIC client + * SSL_METHOD. + */ +OSSL_DEMO_H3_CONN *OSSL_DEMO_H3_CONN_new_for_addr(SSL_CTX *ctx, + const char *addr, + const nghttp3_callbacks *callbacks, + const nghttp3_settings *settings, + void *user_data); + +/* Equivalent to SSL_connect(OSSL_DEMO_H3_CONN_get0_connection(conn)). */ +int OSSL_DEMO_H3_CONN_connect(OSSL_DEMO_H3_CONN *conn); + +/* + * Free the OSSL_DEMO_H3_CONN and any underlying QUIC connection SSL object and + * associated streams. + */ +void OSSL_DEMO_H3_CONN_free(OSSL_DEMO_H3_CONN *conn); + +/* + * Returns the user data value which was specified in + * OSSL_DEMO_H3_CONN_new_for_conn. + */ +void *OSSL_DEMO_H3_CONN_get_user_data(const OSSL_DEMO_H3_CONN *conn); + +/* Returns the underlying QUIC connection SSL object. */ +SSL *OSSL_DEMO_H3_CONN_get0_connection(const OSSL_DEMO_H3_CONN *conn); + +/* + * Handle any pending events on a given HTTP/3 connection. Returns 0 on error. + */ +int OSSL_DEMO_H3_CONN_handle_events(OSSL_DEMO_H3_CONN *conn); + +/* + * Submits a new HTTP/3 request on the given connection. Returns 0 on error. + * + * This works analogously to nghttp3_conn_submit_request(). The stream user data + * pointer passed to the callbacks is a OSSL_DEMO_H3_STREAM object pointer; to + * retrieve the stream user data pointer passed to this function, use + * OSSL_DEMO_H3_STREAM_get_user_data. + */ +int OSSL_DEMO_H3_CONN_submit_request(OSSL_DEMO_H3_CONN *conn, + const nghttp3_nv *hdr, size_t hdrlen, + const nghttp3_data_reader *dr, + void *stream_user_data); + +/* + * Returns the user data value which was specified in + * OSSL_DEMO_H3_CONN_submit_request. + */ +void *OSSL_DEMO_H3_STREAM_get_user_data(const OSSL_DEMO_H3_STREAM *stream); + +#endif diff --git a/doc/internal/man3/ossl_rand_get_entropy.pod b/doc/internal/man3/ossl_rand_get_entropy.pod index 5c7a076336df0ded05dc6527672331b3aac29036..be39369f2b700bf8e69dc8e88ef02a89e70c06d8 100644 --- a/doc/internal/man3/ossl_rand_get_entropy.pod +++ b/doc/internal/man3/ossl_rand_get_entropy.pod @@ -2,8 +2,10 @@ =head1 NAME -ossl_rand_get_entropy, ossl_rand_get_user_entropy, ossl_rand_cleanup_entropy, -ossl_rand_get_nonce, ossl_rand_get_user_nonce, ossl_rand_cleanup_nonce +ossl_rand_get_entropy, ossl_rand_get_user_entropy, +ossl_rand_cleanup_entropy, ossl_rand_cleanup_user_entropy, +ossl_rand_get_nonce, ossl_rand_get_user_nonce, +ossl_rand_cleanup_nonce, ossl_rand_cleanup_user_nonce - get seed material from the operating system =head1 SYNOPSIS @@ -18,6 +20,8 @@ ossl_rand_get_nonce, ossl_rand_get_user_nonce, ossl_rand_cleanup_nonce size_t min_len, size_t max_len); void ossl_rand_cleanup_entropy(OSSL_CORE_HANDLE *handle, unsigned char *buf, size_t len); + void ossl_rand_cleanup_user_entropy(OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len); size_t ossl_rand_get_nonce(OSSL_CORE_HANDLE *handle, unsigned char **pout, size_t min_len, size_t max_len, const void *salt, size_t salt_len); @@ -26,6 +30,8 @@ ossl_rand_get_nonce, ossl_rand_get_user_nonce, ossl_rand_cleanup_nonce const void *salt, size_t salt_len); void ossl_rand_cleanup_nonce(OSSL_CORE_HANDLE *handle, unsigned char *buf, size_t len); + void ossl_rand_cleanup_user_nonce(OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len); =head1 DESCRIPTION @@ -41,8 +47,12 @@ DRBG seed source. By default this is the operating system but it can be changed by calling L. ossl_rand_cleanup_entropy() cleanses and frees any storage allocated by -ossl_rand_get_entropy() or ossl_rand_get_user_entropy(). The entropy -buffer is pointed to by I and is of length I bytes. +ossl_rand_get_entropy(). The entropy buffer is pointed to by I +and is of length I bytes. + +ossl_rand_cleanup_user_entropy() cleanses and frees any storage allocated by +ossl_rand_get_user_entropy(). The entropy buffer is pointed to by I +and is of length I bytes. ossl_rand_get_nonce() retrieves a nonce using the passed I parameter of length I and operating system specific information. @@ -76,8 +86,9 @@ of bytes in I<*pout> or 0 on error. =head1 HISTORY -The functions ossl_rand_get_user_entropy() and ossl_rand_get_user_nonce() -were added in OpenSSL 3.0.12, 3.1.4 and 3.2.0. +The functions ossl_rand_get_user_entropy(), ossl_rand_get_user_nonce(), +ossl_rand_cleanup_user_entropy(), and ossl_rand_cleanup_user_nonce() +were added in OpenSSL 3.1.4 and 3.2.0. The remaining functions described here were all added in OpenSSL 3.0. diff --git a/doc/man1/openssl-pkcs12.pod.in b/doc/man1/openssl-pkcs12.pod.in index 144650f742f5f060fe97e8290d0ddf2a68ba6b63..665b22bb644ac5f0ad9bf54fc65b20a1542e86bb 100644 --- a/doc/man1/openssl-pkcs12.pod.in +++ b/doc/man1/openssl-pkcs12.pod.in @@ -68,6 +68,7 @@ PKCS#12 output (export) options: [B<-maciter>] [B<-macsaltlen>] [B<-nomac>] +[B<-jdktrust> I] =head1 DESCRIPTION @@ -381,6 +382,15 @@ Do not attempt to provide the MAC integrity. This can be useful with the FIPS provider as the PKCS12 MAC requires PKCS12KDF which is not an approved FIPS algorithm and cannot be supported by the FIPS provider. +=item B<-jdktrust> + +Export pkcs12 file in a format compatible with Java keystore usage. This option +accepts a string parameter indicating the trust oid name to be granted to the +certificate it is associated with. Currently only "anyExtendedKeyUsage" is +defined. Note that, as Java keystores do not accept PKCS12 files with both +trusted certificates and keypairs, use of this option implies the setting of the +B<-nokeys> option + =back =head1 NOTES diff --git a/doc/man3/CMS_add1_signer.pod b/doc/man3/CMS_add1_signer.pod index 800085b7b86a9b5bcc8484aa0f23e042b80c845b..11afecb9050ee3c993883a514c641674f5eb77ce 100644 --- a/doc/man3/CMS_add1_signer.pod +++ b/doc/man3/CMS_add1_signer.pod @@ -31,8 +31,8 @@ Unless the B flag is set the returned CMS_ContentInfo structure is not complete and must be finalized either by streaming (if applicable) or a call to CMS_final(). -The CMS_SignerInfo_sign() function will explicitly sign a CMS_SignerInfo -structure, its main use is when B and B flags +The CMS_SignerInfo_sign() function explicitly signs a CMS_SignerInfo +structure, its main use is when the B and B flags are both set. =head1 NOTES @@ -90,6 +90,8 @@ before it is finalized. CMS_add1_signer() returns an internal pointer to the CMS_SignerInfo structure just added or NULL if an error occurs. +CMS_SignerInfo_sign() returns 1 on success, 0 on failure. + =head1 SEE ALSO L, L, diff --git a/doc/man3/EVP_aes_128_gcm.pod b/doc/man3/EVP_aes_128_gcm.pod index 067f17e8fc183df413a0aabb11dead4ff7f0f1b9..485705ea7889073dd706fa69be170e53ac6cdc7d 100644 --- a/doc/man3/EVP_aes_128_gcm.pod +++ b/doc/man3/EVP_aes_128_gcm.pod @@ -167,7 +167,7 @@ the XTS "tweak" value. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_aria_128_gcm.pod b/doc/man3/EVP_aria_128_gcm.pod index 92913652630d52d0c027de90dbfe28778a9e3b8a..91aa75ec387172ef6efe2e7ee3041d7b162bf42d 100644 --- a/doc/man3/EVP_aria_128_gcm.pod +++ b/doc/man3/EVP_aria_128_gcm.pod @@ -96,7 +96,7 @@ correctly, see the L section for details. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_bf_cbc.pod b/doc/man3/EVP_bf_cbc.pod index 4df98f4bdf47ec1dfb29e1514f9dd1bd7fadcd96..11a909207ac954ae7b765487ab89c9eb7ab7efc0 100644 --- a/doc/man3/EVP_bf_cbc.pod +++ b/doc/man3/EVP_bf_cbc.pod @@ -41,7 +41,7 @@ Blowfish encryption algorithm in CBC, CFB, ECB and OFB modes respectively. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_blake2b512.pod b/doc/man3/EVP_blake2b512.pod index 98e1899f6a935d0540e5ca3a13efe73d8e4b9a05..55bd9f3bce77dbee4470826718c9900d6ebce937 100644 --- a/doc/man3/EVP_blake2b512.pod +++ b/doc/man3/EVP_blake2b512.pod @@ -35,7 +35,7 @@ The BLAKE2b algorithm that produces a 512-bit output from a given input. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. While the BLAKE2b and BLAKE2s algorithms supports a variable length digest, diff --git a/doc/man3/EVP_camellia_128_ecb.pod b/doc/man3/EVP_camellia_128_ecb.pod index a6b597156a77a9ebf8a456e6710e9be518bac6c8..cb6e12e2122b760e436f18ce3ff53105b425f05c 100644 --- a/doc/man3/EVP_camellia_128_ecb.pod +++ b/doc/man3/EVP_camellia_128_ecb.pod @@ -79,7 +79,7 @@ Camellia for 128, 192 and 256 bit keys in the following modes: CBC, CFB with Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_cast5_cbc.pod b/doc/man3/EVP_cast5_cbc.pod index 85ff2ad014888f4eca7cbd0eb31626c4525abd56..7fef0598151d85f8f1c62b012061f0d1ca2a1d19 100644 --- a/doc/man3/EVP_cast5_cbc.pod +++ b/doc/man3/EVP_cast5_cbc.pod @@ -41,7 +41,7 @@ CAST encryption algorithm in CBC, ECB, CFB and OFB modes respectively. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_chacha20.pod b/doc/man3/EVP_chacha20.pod index 683faa326e145309277cd0e9ec051f86087867f4..7e80c8de40c9ecf583c35a303944732d3587c0f2 100644 --- a/doc/man3/EVP_chacha20.pod +++ b/doc/man3/EVP_chacha20.pod @@ -44,7 +44,7 @@ L section for more information. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. L diff --git a/doc/man3/EVP_des_cbc.pod b/doc/man3/EVP_des_cbc.pod index 501216cd6d77b3c22fd63cdb63ea6de693fe97d3..442be8993a29f78846f0422777776b1acc61aab2 100644 --- a/doc/man3/EVP_des_cbc.pod +++ b/doc/man3/EVP_des_cbc.pod @@ -89,7 +89,7 @@ Triple-DES key wrap according to RFC 3217 Section 3. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_desx_cbc.pod b/doc/man3/EVP_desx_cbc.pod index fae827192ee995e7a3c76e12c05cb010af42ff40..c22c0de47900c8805975a0ca4110a55ed5b80476 100644 --- a/doc/man3/EVP_desx_cbc.pod +++ b/doc/man3/EVP_desx_cbc.pod @@ -31,7 +31,7 @@ implementation. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_idea_cbc.pod b/doc/man3/EVP_idea_cbc.pod index 5a9adaedc4462c2db84f2b107fd4cfb5149e368b..a36aae0bc999e3170f2ea97b805c049937c7677b 100644 --- a/doc/man3/EVP_idea_cbc.pod +++ b/doc/man3/EVP_idea_cbc.pod @@ -39,7 +39,7 @@ The IDEA encryption algorithm in CBC, CFB, ECB and OFB modes respectively. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_md2.pod b/doc/man3/EVP_md2.pod index 0b473887e01b97bdb72d1fc22f6b5f0336a45601..a6f3a010deb5aa08e8029b163bd5d52a246626ea 100644 --- a/doc/man3/EVP_md2.pod +++ b/doc/man3/EVP_md2.pod @@ -28,7 +28,7 @@ The MD2 algorithm which produces a 128-bit output from a given input. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_md4.pod b/doc/man3/EVP_md4.pod index baaff9e4eaa2ac720b387473b96d91439855d3dd..a4e1a7d0a6e910ef080c20a712d75eb91ac2cf73 100644 --- a/doc/man3/EVP_md4.pod +++ b/doc/man3/EVP_md4.pod @@ -29,7 +29,7 @@ The MD4 algorithm which produces a 128-bit output from a given input. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_md5.pod b/doc/man3/EVP_md5.pod index 752fdd1f6c37b35b1e2e96366f0c8bcf747320d2..42370fb3d0a3299b30b87a2713513f286cf607c3 100644 --- a/doc/man3/EVP_md5.pod +++ b/doc/man3/EVP_md5.pod @@ -40,7 +40,7 @@ WARNING: this algorithm is not intended for non-SSL usage. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L or L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_mdc2.pod b/doc/man3/EVP_mdc2.pod index e9de6f3c560a61bf1919425734dc640ba5616967..3681bd06a63cd96dddddf75ddbd45710923cf2cf 100644 --- a/doc/man3/EVP_mdc2.pod +++ b/doc/man3/EVP_mdc2.pod @@ -30,7 +30,7 @@ The MDC-2DES algorithm of using MDC-2 with the DES block cipher. It produces a Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_rc2_cbc.pod b/doc/man3/EVP_rc2_cbc.pod index bf4a13ba45c19c11fc669bfd99280caacf51844a..17f6f4b3e254da3cc469e4aa5576355e47589e26 100644 --- a/doc/man3/EVP_rc2_cbc.pod +++ b/doc/man3/EVP_rc2_cbc.pod @@ -55,7 +55,7 @@ functions to set the key length and effective key length. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_rc4.pod b/doc/man3/EVP_rc4.pod index f22e88a652147747adb0a7209429a4fe532f0f4f..0311ef278ca12d69d3d86a6f1885656665c1ff27 100644 --- a/doc/man3/EVP_rc4.pod +++ b/doc/man3/EVP_rc4.pod @@ -47,7 +47,7 @@ interface. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_rc5_32_12_16_cbc.pod b/doc/man3/EVP_rc5_32_12_16_cbc.pod index c177b1845196f2bcb68886a62ae42a4deaa168c2..69fc2f2cc656b975e596ee413df31c550ad1b3d7 100644 --- a/doc/man3/EVP_rc5_32_12_16_cbc.pod +++ b/doc/man3/EVP_rc5_32_12_16_cbc.pod @@ -60,7 +60,7 @@ is an int. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_ripemd160.pod b/doc/man3/EVP_ripemd160.pod index 6ad2d3e0186968236ad0604cef608a446de9a23d..5b96fd09f85037938968ec9d0d1f80d0a4f94887 100644 --- a/doc/man3/EVP_ripemd160.pod +++ b/doc/man3/EVP_ripemd160.pod @@ -29,7 +29,7 @@ The RIPEMD-160 algorithm which produces a 160-bit output from a given input. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_seed_cbc.pod b/doc/man3/EVP_seed_cbc.pod index 010607e5740590b70fff5063ab51f5a9364e3f71..2c821d07c3993a12d0e3078732d22daa511465db 100644 --- a/doc/man3/EVP_seed_cbc.pod +++ b/doc/man3/EVP_seed_cbc.pod @@ -41,7 +41,7 @@ The SEED encryption algorithm in CBC, CFB, ECB and OFB modes respectively. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_sha1.pod b/doc/man3/EVP_sha1.pod index 264ddd1addb717f02d6e8684508608e64022430b..6fc8f07b066a6f8dfd02614249e661e3ce8e8233 100644 --- a/doc/man3/EVP_sha1.pod +++ b/doc/man3/EVP_sha1.pod @@ -29,7 +29,7 @@ The SHA-1 algorithm which produces a 160-bit output from a given input. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_sha224.pod b/doc/man3/EVP_sha224.pod index 7a50cf9b6c3f15ece50209e004eadc409ea1186a..be09e49ee39325dd462a331b3e29fb596ba1d76a 100644 --- a/doc/man3/EVP_sha224.pod +++ b/doc/man3/EVP_sha224.pod @@ -49,7 +49,7 @@ their outputs are of the same size. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with Linstead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_sha3_224.pod b/doc/man3/EVP_sha3_224.pod index 5bb9ae1b89e55015705f14cbe3a0961e3653fe73..93c0d0b9fb1e0f8e2bbb6515be9f53ccbc517c95 100644 --- a/doc/man3/EVP_sha3_224.pod +++ b/doc/man3/EVP_sha3_224.pod @@ -54,7 +54,7 @@ B provides that of 256 bits. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L or L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_sm3.pod b/doc/man3/EVP_sm3.pod index 4e8112dc0afee2b8548757e0040d18271e238db6..65be55e88dba8d207f2c0944b04927f60a8b39ef 100644 --- a/doc/man3/EVP_sm3.pod +++ b/doc/man3/EVP_sm3.pod @@ -28,7 +28,7 @@ The SM3 hash function. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_sm4_cbc.pod b/doc/man3/EVP_sm4_cbc.pod index b67ade549968c5a4df082fb5835ea6412863f109..48be7a31ad756d01752e8d4554f802184ff89416 100644 --- a/doc/man3/EVP_sm4_cbc.pod +++ b/doc/man3/EVP_sm4_cbc.pod @@ -45,7 +45,7 @@ respectively. Developers should be aware of the negative performance implications of calling these functions multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/EVP_whirlpool.pod b/doc/man3/EVP_whirlpool.pod index a9826e290a4279c1b7cac8716b72271312105b01..c5d465b16f0c3cc7727479b39c3cd4761713e3da 100644 --- a/doc/man3/EVP_whirlpool.pod +++ b/doc/man3/EVP_whirlpool.pod @@ -30,7 +30,7 @@ input. Developers should be aware of the negative performance implications of calling this function multiple times and should consider using -L instead. +L with L instead. See L for further information. =head1 RETURN VALUES diff --git a/doc/man3/OSSL_ERR_STATE_save.pod b/doc/man3/OSSL_ERR_STATE_save.pod index 05c738fc552a33e6a188547a4ba6bc8225e799cc..93c4b8f4736049d0651eae959ad99a570d26130d 100644 --- a/doc/man3/OSSL_ERR_STATE_save.pod +++ b/doc/man3/OSSL_ERR_STATE_save.pod @@ -70,6 +70,10 @@ missing the auxiliary error data. L, L, L +=head1 HISTORY + +All of these functions were added in OpenSSL 3.2. + =head1 COPYRIGHT Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man3/SSL_CTX_set_quiet_shutdown.pod b/doc/man3/SSL_CTX_set_quiet_shutdown.pod index b7c2a32069174c2cff439b1cd54fb2959b3c1331..4894e2f5d25f9a31b7b47c2c2f9c75d0d9031aa6 100644 --- a/doc/man3/SSL_CTX_set_quiet_shutdown.pod +++ b/doc/man3/SSL_CTX_set_quiet_shutdown.pod @@ -2,7 +2,8 @@ =head1 NAME -SSL_CTX_set_quiet_shutdown, SSL_CTX_get_quiet_shutdown, SSL_set_quiet_shutdown, SSL_get_quiet_shutdown - manipulate shutdown behaviour +SSL_CTX_set_quiet_shutdown, SSL_CTX_get_quiet_shutdown, SSL_set_quiet_shutdown, +SSL_get_quiet_shutdown - manipulate shutdown behaviour =head1 SYNOPSIS @@ -54,7 +55,7 @@ The default is normal shutdown behaviour as described by the TLS standard. SSL_CTX_set_quiet_shutdown() and SSL_set_quiet_shutdown() do not return diagnostic information. -SSL_CTX_get_quiet_shutdown() and SSL_get_quiet_shutdown return the current +SSL_CTX_get_quiet_shutdown() and SSL_get_quiet_shutdown() return the current setting. =head1 SEE ALSO diff --git a/doc/man3/SSL_set_shutdown.pod b/doc/man3/SSL_set_shutdown.pod index c3b613a247d1e68ab864a3febc01864a799f1181..9a7eb463a8275823b3d9ad26db50a8387d0e4225 100644 --- a/doc/man3/SSL_set_shutdown.pod +++ b/doc/man3/SSL_set_shutdown.pod @@ -57,13 +57,21 @@ If a close_notify was received, SSL_RECEIVED_SHUTDOWN will be set, for setting SSL_SENT_SHUTDOWN the application must however still call L or SSL_set_shutdown() itself. -These functions are not supported for QUIC SSL objects. +SSL_set_shutdown() is not supported for QUIC SSL objects. =head1 RETURN VALUES SSL_set_shutdown() does not return diagnostic information. -SSL_get_shutdown() returns the current setting. +SSL_get_shutdown() returns the current shutdown state as set or based +on the actual connection state. + +SSL_get_shutdown() returns 0 if called on a QUIC stream SSL object. If it +is called on a QUIC connection SSL object, it returns a value with +SSL_SENT_SHUTDOWN set if CONNECTION_CLOSE has been sent to the peer and +it returns a value with SSL_RECEIVED_SHUTDOWN set if CONNECTION_CLOSE +has been received from the peer or the QUIC connection is fully terminated +for other reasons. =head1 SEE ALSO diff --git a/doc/man7/provider-base.pod b/doc/man7/provider-base.pod index eb9e8d35758ffd6650eb345bcf2fb63c2878190e..5dcbbed221be2e40265deb8881fbb76076bdb22b 100644 --- a/doc/man7/provider-base.pod +++ b/doc/man7/provider-base.pod @@ -81,6 +81,8 @@ provider-base size_t min_len, size_t max_len); void cleanup_entropy(const OSSL_CORE_HANDLE *handle, unsigned char *buf, size_t len); + void cleanup_user_entropy(const OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len); size_t get_nonce(const OSSL_CORE_HANDLE *handle, unsigned char **pout, size_t min_len, size_t max_len, const void *salt, size_t salt_len); @@ -89,6 +91,8 @@ provider-base const void *salt, size_t salt_len); void cleanup_nonce(const OSSL_CORE_HANDLE *handle, unsigned char *buf, size_t len); + void cleanup_user_nonce(const OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len); /* Functions for querying the providers in the application library context */ int provider_register_child_cb(const OSSL_CORE_HANDLE *handle, @@ -179,9 +183,11 @@ provider): ossl_rand_get_entropy OSSL_FUNC_GET_ENTROPY ossl_rand_get_user_entropy OSSL_FUNC_GET_USER_ENTROPY ossl_rand_cleanup_entropy OSSL_FUNC_CLEANUP_ENTROPY + ossl_rand_cleanup_user_entropy OSSL_FUNC_CLEANUP_USER_ENTROPY ossl_rand_get_nonce OSSL_FUNC_GET_NONCE ossl_rand_get_user_nonce OSSL_FUNC_GET_USER_NONCE ossl_rand_cleanup_nonce OSSL_FUNC_CLEANUP_NONCE + ossl_rand_cleanup_user_nonce OSSL_FUNC_CLEANUP_USER_NONCE provider_register_child_cb OSSL_FUNC_PROVIDER_REGISTER_CHILD_CB provider_deregister_child_cb OSSL_FUNC_PROVIDER_DEREGISTER_CHILD_CB provider_name OSSL_FUNC_PROVIDER_NAME @@ -315,9 +321,12 @@ attempt to gather seed material via the seed source specified by a call to L or via L. cleanup_entropy() is used to clean up and free the buffer returned by -get_entropy() or get_user_entropy(). The entropy pointer returned by -get_entropy() or get_user_entropy() is passed in B and its length -in B. +get_entropy(). The entropy pointer returned by get_entropy() +is passed in B and its length in B. + +cleanup_user_entropy() is used to clean up and free the buffer returned by +get_user_entropy(). The entropy pointer returned by get_user_entropy() +is passed in B and its length in B. get_nonce() retrieves a nonce using the passed I parameter of length I and operating system specific information. @@ -331,10 +340,13 @@ get_user_nonce() is the same as get_nonce() except that it will attempt to gather seed material via the seed source specified by a call to L or via L. -cleanup_nonce() is used to clean up and free the buffer returned -by get_nonce() or get_user_nonce(). The nonce pointer returned by -get_nonce() or get_user_nonce() is passed in B and its length -in B. +cleanup_nonce() is used to clean up and free the buffer returned by +get_nonce(). The nonce pointer returned by get_nonce() +is passed in B and its length in B. + +cleanup_user_nonce() is used to clean up and free the buffer returned by +get_user_nonce(). The nonce pointer returned by get_user_nonce() +is passed in B and its length in B. provider_register_child_cb() registers callbacks for being informed about the loading and unloading of providers in the application's library context. diff --git a/fuzz/README.md b/fuzz/README.md index 6cc7811ad003eac90743b39453e974c8159b54e2..795606fec2c439ac09504d37e4adbb1d2cc0f800 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -32,6 +32,34 @@ to the `libFuzzer` library file while configuring; this is represented as enable-ssl3 enable-ssl3-method enable-nextprotoneg \ --debug +Clang uses the gcc libstdc++ library so this must also be installed. You can +check which version of gcc clang is using like this: + + $ clang --verbose + Ubuntu clang version 14.0.0-1ubuntu1.1 + Target: x86_64-pc-linux-gnu + Thread model: posix + InstalledDir: /usr/bin + Found candidate GCC installation: /usr/bin/../lib/gcc/i686-linux-gnu/12 + Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/10 + Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/11 + Found candidate GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/12 + Selected GCC installation: /usr/bin/../lib/gcc/x86_64-linux-gnu/12 + Candidate multilib: .;@m64 + Selected multilib: .;@m64 + +So, in the above example clang is using gcc version 12. Ensure that the selected +gcc version has the relevant libstdc++ files installed: + + $ ls /usr/lib/gcc/x86_64-linux-gnu/12 | grep stdc++ + libstdc++.a + libstdc++fs.a + libstdc++.so + +On Ubuntu for gcc-12 this requires the libstdc++-12-dev package installed. + + $ sudo apt-get install libstdc++-12-dev + Compile: sudo apt-get install make diff --git a/fuzz/build.info b/fuzz/build.info index 7efc52ef8516bbb8dd7fc35c04994729a3d104e2..de7cadc79e535f2c3957c283c42f94eb91d79e83 100644 --- a/fuzz/build.info +++ b/fuzz/build.info @@ -29,6 +29,10 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] PROGRAMS{noinst}=x509 ENDIF + IF[{- !$disabled{"quic"} -}] + PROGRAMS{noinst}=quic-client + ENDIF + SOURCE[asn1]=asn1.c driver.c fuzz_rand.c INCLUDE[asn1]=../include {- $ex_inc -} DEPEND[asn1]=../libcrypto ../libssl {- $ex_lib -} @@ -89,6 +93,10 @@ IF[{- !$disabled{"fuzz-afl"} || !$disabled{"fuzz-libfuzzer"} -}] INCLUDE[v3name]=../include {- $ex_inc -} DEPEND[v3name]=../libcrypto.a {- $ex_lib -} + SOURCE[quic-client]=quic-client.c driver.c fuzz_rand.c + INCLUDE[quic-client]=../include {- $ex_inc -} + DEPEND[quic-client]=../libcrypto.a ../libssl.a {- $ex_lib -} + SOURCE[server]=server.c driver.c fuzz_rand.c INCLUDE[server]=../include {- $ex_inc -} DEPEND[server]=../libcrypto ../libssl {- $ex_lib -} @@ -119,6 +127,10 @@ IF[{- !$disabled{tests} -}] PROGRAMS{noinst}=x509-test ENDIF + IF[{- !$disabled{"quic"} -}] + PROGRAMS{noinst}=quic-client-test + ENDIF + SOURCE[asn1-test]=asn1.c test-corpus.c fuzz_rand.c INCLUDE[asn1-test]=../include DEPEND[asn1-test]=../libcrypto ../libssl @@ -180,6 +192,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[v3name-test]=../include DEPEND[v3name-test]=../libcrypto.a + SOURCE[quic-client-test]=quic-client.c test-corpus.c fuzz_rand.c + INCLUDE[quic-client-test]=../include + DEPEND[quic-client-test]=../libcrypto.a ../libssl.a + SOURCE[server-test]=server.c test-corpus.c fuzz_rand.c INCLUDE[server-test]=../include DEPEND[server-test]=../libcrypto ../libssl diff --git a/fuzz/corpora b/fuzz/corpora index 7bdc71fa62c88173b8f818dd1646ac59b0eadebe..21c4851c48af74287cb82e567163c4d0a666ad87 160000 --- a/fuzz/corpora +++ b/fuzz/corpora @@ -1 +1 @@ -Subproject commit 7bdc71fa62c88173b8f818dd1646ac59b0eadebe +Subproject commit 21c4851c48af74287cb82e567163c4d0a666ad87 diff --git a/fuzz/quic-client.c b/fuzz/quic-client.c new file mode 100644 index 0000000000000000000000000000000000000000..2dc2b3c9b2c88b7a97e8e056152eba18812474fc --- /dev/null +++ b/fuzz/quic-client.c @@ -0,0 +1,176 @@ +/* + * Copyright 2016-2022 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * https://www.openssl.org/source/license.html + * or in the file LICENSE in the source distribution. + */ + +#include +#include +#include +#include "fuzzer.h" +#include "internal/sockets.h" +#include "internal/time.h" +#include "internal/quic_ssl.h" + +/* unused, to avoid warning. */ +static int idx; + +static OSSL_TIME fake_now; + +static OSSL_TIME fake_now_cb(void *arg) +{ + return fake_now; +} + +int FuzzerInitialize(int *argc, char ***argv) +{ + STACK_OF(SSL_COMP) *comp_methods; + + FuzzerSetRand(); + OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS | OPENSSL_INIT_ASYNC, NULL); + OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL); + ERR_clear_error(); + CRYPTO_free_ex_index(0, -1); + idx = SSL_get_ex_data_X509_STORE_CTX_idx(); + comp_methods = SSL_COMP_get_compression_methods(); + if (comp_methods != NULL) + sk_SSL_COMP_sort(comp_methods); + + return 1; +} + +int FuzzerTestOneInput(const uint8_t *buf, size_t len) +{ + SSL *client = NULL; + BIO *in; + BIO *out; + SSL_CTX *ctx; + BIO_ADDR *peer_addr = NULL; + struct in_addr ina = {0}; + struct timeval tv; + + if (len == 0) + return 0; + + /* This only fuzzes the initial flow from the client so far. */ + ctx = SSL_CTX_new(OSSL_QUIC_client_method()); + if (ctx == NULL) + goto end; + + client = SSL_new(ctx); + if (client == NULL) + goto end; + + fake_now = ossl_ms2time(1); + if (!ossl_quic_conn_set_override_now_cb(client, fake_now_cb, NULL)) + goto end; + + peer_addr = BIO_ADDR_new(); + if (peer_addr == NULL) + goto end; + + ina.s_addr = htonl(0x7f000001UL); + + if (!BIO_ADDR_rawmake(peer_addr, AF_INET, &ina, sizeof(ina), htons(4433))) + goto end; + + SSL_set_tlsext_host_name(client, "localhost"); + in = BIO_new(BIO_s_dgram_mem()); + if (in == NULL) + goto end; + out = BIO_new(BIO_s_dgram_mem()); + if (out == NULL) { + BIO_free(in); + goto end; + } + if (!BIO_dgram_set_caps(out, BIO_DGRAM_CAP_HANDLES_DST_ADDR)) { + BIO_free(in); + BIO_free(out); + goto end; + } + SSL_set_bio(client, in, out); + if (SSL_set_alpn_protos(client, (const unsigned char *)"\x08ossltest", 9) != 0) + goto end; + if (SSL_set1_initial_peer_addr(client, peer_addr) != 1) + goto end; + SSL_set_connect_state(client); + + for (;;) { + size_t size; + uint64_t nxtpktms = 0; + OSSL_TIME nxtpkt = ossl_time_zero(), nxttimeout; + int isinf, ret; + + if (len >= 2) { + nxtpktms = buf[0] + (buf[1] << 8); + nxtpkt = ossl_time_add(fake_now, ossl_ms2time(nxtpktms)); + len -= 2; + buf += 2; + } + + for (;;) { + if ((ret = SSL_do_handshake(client)) == 1) { + /* + * Keep reading application data until there are no more + * datagrams to inject or a fatal error occurs + */ + uint8_t tmp[1024]; + + ret = SSL_read(client, tmp, sizeof(tmp)); + } + if (ret <= 0) { + switch (SSL_get_error(client, ret)) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + break; + default: + goto end; + } + } + + if (!SSL_get_event_timeout(client, &tv, &isinf)) + goto end; + + if (isinf) { + fake_now = nxtpkt; + break; + } else { + nxttimeout = ossl_time_add(fake_now, + ossl_time_from_timeval(tv)); + if (len > 3 && ossl_time_compare(nxttimeout, nxtpkt) >= 0) { + fake_now = nxtpkt; + break; + } + fake_now = nxttimeout; + } + } + + if (len <= 3) + break; + + size = buf[0] + (buf[1] << 8); + if (size > len - 2) + break; + + if (size > 0) + BIO_write(in, buf+2, size); + len -= size + 2; + buf += size + 2; + } + end: + SSL_free(client); + ERR_clear_error(); + SSL_CTX_free(ctx); + BIO_ADDR_free(peer_addr); + + return 0; +} + +void FuzzerCleanup(void) +{ + FuzzerClearRand(); +} diff --git a/include/crypto/evp.h b/include/crypto/evp.h index 473b95514a0ada8d307236f81f2b25051962be1d..34cea2f9f4a0c564e27aea11f789d5c86f7d2d23 100644 --- a/include/crypto/evp.h +++ b/include/crypto/evp.h @@ -953,6 +953,14 @@ int evp_keymgmt_get_number(const EVP_KEYMGMT *keymgmt); int evp_mac_get_number(const EVP_MAC *mac); int evp_md_get_number(const EVP_MD *md); int evp_rand_get_number(const EVP_RAND *rand); +int evp_rand_can_seed(EVP_RAND_CTX *ctx); +size_t evp_rand_get_seed(EVP_RAND_CTX *ctx, + unsigned char **buffer, + int entropy, size_t min_len, size_t max_len, + int prediction_resistance, + const unsigned char *adin, size_t adin_len); +void evp_rand_clear_seed(EVP_RAND_CTX *ctx, + unsigned char *buffer, size_t b_len); int evp_signature_get_number(const EVP_SIGNATURE *signature); int evp_pkey_decrypt_alloc(EVP_PKEY_CTX *ctx, unsigned char **outp, diff --git a/include/crypto/rand.h b/include/crypto/rand.h index 5841cccaa66e9faa557da2fbcbed760d102a973b..215b3b7af34f56e9a64f0e9f1cccb4041a4db699 100644 --- a/include/crypto/rand.h +++ b/include/crypto/rand.h @@ -116,6 +116,8 @@ size_t ossl_rand_get_user_entropy(OSSL_LIB_CTX *ctx, size_t min_len, size_t max_len); void ossl_rand_cleanup_entropy(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t len); +void ossl_rand_cleanup_user_entropy(OSSL_LIB_CTX *ctx, + unsigned char *buf, size_t len); size_t ossl_rand_get_nonce(OSSL_LIB_CTX *ctx, unsigned char **pout, size_t min_len, size_t max_len, const void *salt, size_t salt_len); @@ -124,6 +126,8 @@ size_t ossl_rand_get_user_nonce(OSSL_LIB_CTX *ctx, unsigned char **pout, const void *salt, size_t salt_len); void ossl_rand_cleanup_nonce(OSSL_LIB_CTX *ctx, unsigned char *buf, size_t len); +void ossl_rand_cleanup_user_nonce(OSSL_LIB_CTX *ctx, + unsigned char *buf, size_t len); /* * Get seeding material from the operating system sources. diff --git a/include/internal/cryptlib.h b/include/internal/cryptlib.h index 843a720b8f149b2eab9cbc4d78027366039e7efb..64851fd8ed340c13dc90cc931c310cf0c56ecb74 100644 --- a/include/internal/cryptlib.h +++ b/include/internal/cryptlib.h @@ -19,7 +19,6 @@ # endif # include "internal/common.h" -# include "crypto/asn1.h" # include # include diff --git a/include/internal/quic_channel.h b/include/internal/quic_channel.h index 0841001c23da97aed31a512c09132e3d05aa5e6a..f46db0637e91c6a34745f56b6822cd164035c7c5 100644 --- a/include/internal/quic_channel.h +++ b/include/internal/quic_channel.h @@ -320,6 +320,7 @@ QUIC_STREAM *ossl_quic_channel_get_stream_by_id(QUIC_CHANNEL *ch, int ossl_quic_channel_is_term_any(const QUIC_CHANNEL *ch); const QUIC_TERMINATE_CAUSE * ossl_quic_channel_get_terminate_cause(const QUIC_CHANNEL *ch); +int ossl_quic_channel_is_closing(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_terminated(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_active(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_handshake_complete(const QUIC_CHANNEL *ch); diff --git a/include/internal/quic_ssl.h b/include/internal/quic_ssl.h index 66cea1bfe12ce5962fa59e26ed187522726d4f6f..52d4527c811021e172d3af247181cc834ffc5a02 100644 --- a/include/internal/quic_ssl.h +++ b/include/internal/quic_ssl.h @@ -125,6 +125,7 @@ void ossl_quic_conn_force_assist_thread_wake(SSL *s); QUIC_CHANNEL *ossl_quic_conn_get_channel(SSL *s); int ossl_quic_has_pending(const SSL *s); +int ossl_quic_get_shutdown(const SSL *s); # endif diff --git a/include/internal/quic_txp.h b/include/internal/quic_txp.h index 64efedc27f385e8b754f04bc6987aba8ed227d6c..ae508f2393bd41bc63fd388ed3fd1deff020d706 100644 --- a/include/internal/quic_txp.h +++ b/include/internal/quic_txp.h @@ -112,13 +112,15 @@ OSSL_TIME ossl_quic_tx_packetiser_get_deadline(OSSL_QUIC_TX_PACKETISER *txp); /* * Set the token used in Initial packets. The callback is called when the buffer * is no longer needed; for example, when the TXP is freed or when this function - * is called again with a new buffer. + * is called again with a new buffer. Fails returning 0 if the token is too big + * to ever be reasonably encapsulated in an outgoing packet based on our current + * understanding of our PMTU. */ -void ossl_quic_tx_packetiser_set_initial_token(OSSL_QUIC_TX_PACKETISER *txp, - const unsigned char *token, - size_t token_len, - ossl_quic_initial_token_free_fn *free_cb, - void *free_cb_arg); +int ossl_quic_tx_packetiser_set_initial_token(OSSL_QUIC_TX_PACKETISER *txp, + const unsigned char *token, + size_t token_len, + ossl_quic_initial_token_free_fn *free_cb, + void *free_cb_arg); /* Change the DCID the TXP uses to send outgoing packets. */ int ossl_quic_tx_packetiser_set_cur_dcid(OSSL_QUIC_TX_PACKETISER *txp, diff --git a/include/internal/time.h b/include/internal/time.h index 9bc5e545129cb47151462a9b583337d3533238fe..14d724abf5aad774bf17fdd9e7334acddd3a897f 100644 --- a/include/internal/time.h +++ b/include/internal/time.h @@ -45,6 +45,13 @@ typedef struct { #define ossl_us2time(us) ossl_ticks2time((us) * OSSL_TIME_US) #define ossl_time2us(t) (ossl_time2ticks(t) / OSSL_TIME_US) +/* + * Arithmetic operations on times. + * These operations are saturating, in that an overflow or underflow returns + * the largest or smallest value respectively. + */ +OSSL_SAFE_MATH_UNSIGNED(time, uint64_t) + /* Convert a tick count into a time */ static ossl_unused ossl_inline OSSL_TIME ossl_ticks2time(uint64_t ticks) @@ -84,6 +91,15 @@ static ossl_unused ossl_inline struct timeval ossl_time_to_timeval(OSSL_TIME t) { struct timeval tv; + int err = 0; + + /* + * Round up any nano secs which struct timeval doesn't support. Ensures that + * we never return a zero time if the input time is non zero + */ + t.t = safe_add_time(t.t, OSSL_TIME_US - 1, &err); + if (err) + t = ossl_time_infinite(); #ifdef _WIN32 tv.tv_sec = (long int)(t.t / OSSL_TIME_SECOND); @@ -151,13 +167,6 @@ int ossl_time_is_infinite(OSSL_TIME t) return ossl_time_compare(t, ossl_time_infinite()) == 0; } -/* - * Arithmetic operations on times. - * These operations are saturating, in that an overflow or underflow returns - * the largest or smallest value respectively. - */ -OSSL_SAFE_MATH_UNSIGNED(time, uint64_t) - static ossl_unused ossl_inline OSSL_TIME ossl_time_add(OSSL_TIME a, OSSL_TIME b) { diff --git a/include/openssl/cmserr.h b/include/openssl/cmserr.h index 9066cab6a7a57f7f66252e8fd0ad280b3afb0057..887035b1bf7d55ffe0b38935b849a83c6443c8e1 100644 --- a/include/openssl/cmserr.h +++ b/include/openssl/cmserr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -114,6 +114,7 @@ # define CMS_R_UNSUPPORTED_LABEL_SOURCE 193 # define CMS_R_UNSUPPORTED_RECIPIENTINFO_TYPE 155 # define CMS_R_UNSUPPORTED_RECIPIENT_TYPE 154 +# define CMS_R_UNSUPPORTED_SIGNATURE_ALGORITHM 195 # define CMS_R_UNSUPPORTED_TYPE 156 # define CMS_R_UNWRAP_ERROR 157 # define CMS_R_UNWRAP_FAILURE 180 diff --git a/include/openssl/core_dispatch.h b/include/openssl/core_dispatch.h index 6c952f18aac00fa038d48b4c95c95c489575ea72..9b03f20c3b7da4fe8939fd8b48af472453c4b45d 100644 --- a/include/openssl/core_dispatch.h +++ b/include/openssl/core_dispatch.h @@ -177,6 +177,8 @@ OSSL_CORE_MAKE_FUNC(int, BIO_ctrl, (OSSL_CORE_BIO *bio, int cmd, long num, void *ptr)) /* New seeding functions prototypes with the 101-104 series */ +#define OSSL_FUNC_CLEANUP_USER_ENTROPY 96 +#define OSSL_FUNC_CLEANUP_USER_NONCE 97 #define OSSL_FUNC_GET_USER_ENTROPY 98 #define OSSL_FUNC_GET_USER_NONCE 99 @@ -197,6 +199,8 @@ OSSL_CORE_MAKE_FUNC(size_t, get_user_entropy, (const OSSL_CORE_HANDLE *handle, size_t min_len, size_t max_len)) OSSL_CORE_MAKE_FUNC(void, cleanup_entropy, (const OSSL_CORE_HANDLE *handle, unsigned char *buf, size_t len)) +OSSL_CORE_MAKE_FUNC(void, cleanup_user_entropy, (const OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len)) OSSL_CORE_MAKE_FUNC(size_t, get_nonce, (const OSSL_CORE_HANDLE *handle, unsigned char **pout, size_t min_len, size_t max_len, const void *salt, @@ -207,6 +211,8 @@ OSSL_CORE_MAKE_FUNC(size_t, get_user_nonce, (const OSSL_CORE_HANDLE *handle, size_t salt_len)) OSSL_CORE_MAKE_FUNC(void, cleanup_nonce, (const OSSL_CORE_HANDLE *handle, unsigned char *buf, size_t len)) +OSSL_CORE_MAKE_FUNC(void, cleanup_user_nonce, (const OSSL_CORE_HANDLE *handle, + unsigned char *buf, size_t len)) /* Functions to access the core's providers */ #define OSSL_FUNC_PROVIDER_REGISTER_CHILD_CB 105 diff --git a/include/openssl/pkcs7.h.in b/include/openssl/pkcs7.h.in index 127d6afea8870900d8f97dfdc05efe3662673966..57e45dc2fb6d2ccfcbd5881559f79d7904642018 100644 --- a/include/openssl/pkcs7.h.in +++ b/include/openssl/pkcs7.h.in @@ -60,8 +60,8 @@ typedef struct pkcs7_signer_info_st { PKCS7_ISSUER_AND_SERIAL *issuer_and_serial; X509_ALGOR *digest_alg; STACK_OF(X509_ATTRIBUTE) *auth_attr; /* [ 0 ] */ - X509_ALGOR *digest_enc_alg; - ASN1_OCTET_STRING *enc_digest; + X509_ALGOR *digest_enc_alg; /* confusing name, actually used for signing */ + ASN1_OCTET_STRING *enc_digest; /* confusing name, actually signature */ STACK_OF(X509_ATTRIBUTE) *unauth_attr; /* [ 1 ] */ /* The private key to sign with */ EVP_PKEY *pkey; diff --git a/providers/common/provider_seeding.c b/providers/common/provider_seeding.c index c7b2ea6da62a30848ca16ca123cc1734ff15b055..544344f30a996473f374660b7f3be5818654fe00 100644 --- a/providers/common/provider_seeding.c +++ b/providers/common/provider_seeding.c @@ -14,9 +14,11 @@ static OSSL_FUNC_get_entropy_fn *c_get_entropy = NULL; static OSSL_FUNC_get_user_entropy_fn *c_get_user_entropy = NULL; static OSSL_FUNC_cleanup_entropy_fn *c_cleanup_entropy = NULL; +static OSSL_FUNC_cleanup_user_entropy_fn *c_cleanup_user_entropy = NULL; static OSSL_FUNC_get_nonce_fn *c_get_nonce = NULL; static OSSL_FUNC_get_user_nonce_fn *c_get_user_nonce = NULL; static OSSL_FUNC_cleanup_nonce_fn *c_cleanup_nonce = NULL; +static OSSL_FUNC_cleanup_user_nonce_fn *c_cleanup_user_nonce = NULL; #ifdef FIPS_MODULE /* @@ -56,6 +58,9 @@ int ossl_prov_seeding_from_dispatch(const OSSL_DISPATCH *fns) case OSSL_FUNC_CLEANUP_ENTROPY: set_func(c_cleanup_entropy, OSSL_FUNC_cleanup_entropy(fns)); break; + case OSSL_FUNC_CLEANUP_USER_ENTROPY: + set_func(c_cleanup_user_entropy, OSSL_FUNC_cleanup_user_entropy(fns)); + break; case OSSL_FUNC_GET_NONCE: set_func(c_get_nonce, OSSL_FUNC_get_nonce(fns)); break; @@ -65,6 +70,9 @@ int ossl_prov_seeding_from_dispatch(const OSSL_DISPATCH *fns) case OSSL_FUNC_CLEANUP_NONCE: set_func(c_cleanup_nonce, OSSL_FUNC_cleanup_nonce(fns)); break; + case OSSL_FUNC_CLEANUP_USER_NONCE: + set_func(c_cleanup_user_nonce, OSSL_FUNC_cleanup_user_nonce(fns)); + break; } #undef set_func } @@ -86,8 +94,12 @@ size_t ossl_prov_get_entropy(PROV_CTX *prov_ctx, unsigned char **pout, void ossl_prov_cleanup_entropy(PROV_CTX *prov_ctx, unsigned char *buf, size_t len) { - if (c_cleanup_entropy != NULL) - c_cleanup_entropy(CORE_HANDLE(prov_ctx), buf, len); + const OSSL_CORE_HANDLE *handle = CORE_HANDLE(prov_ctx); + + if (c_cleanup_user_entropy != NULL) + c_cleanup_user_entropy(handle, buf, len); + else if (c_cleanup_entropy != NULL) + c_cleanup_entropy(handle, buf, len); } size_t ossl_prov_get_nonce(PROV_CTX *prov_ctx, unsigned char **pout, @@ -105,6 +117,10 @@ size_t ossl_prov_get_nonce(PROV_CTX *prov_ctx, unsigned char **pout, void ossl_prov_cleanup_nonce(PROV_CTX *prov_ctx, unsigned char *buf, size_t len) { - if (c_cleanup_nonce != NULL) - c_cleanup_nonce(CORE_HANDLE(prov_ctx), buf, len); + const OSSL_CORE_HANDLE *handle = CORE_HANDLE(prov_ctx); + + if (c_cleanup_user_nonce != NULL) + c_cleanup_user_nonce(handle, buf, len); + else if (c_cleanup_nonce != NULL) + c_cleanup_nonce(handle, buf, len); } diff --git a/providers/implementations/ciphers/cipher_aes_gcm_hw_vaes_avx512.inc b/providers/implementations/ciphers/cipher_aes_gcm_hw_vaes_avx512.inc index ef18677979a6f99428843960d0ce261d373bf9e0..c892c0754e8d52dda620ac274e3d5a6827225290 100644 --- a/providers/implementations/ciphers/cipher_aes_gcm_hw_vaes_avx512.inc +++ b/providers/implementations/ciphers/cipher_aes_gcm_hw_vaes_avx512.inc @@ -48,7 +48,6 @@ static int vaes_gcm_setkey(PROV_GCM_CTX *ctx, const unsigned char *key, PROV_AES_GCM_CTX *actx = (PROV_AES_GCM_CTX *)ctx; AES_KEY *ks = &actx->ks.ks; - ctx->ks = ks; aesni_set_encrypt_key(key, keylen * 8, ks); memset(gcmctx, 0, sizeof(*gcmctx)); gcmctx->key = ks; @@ -77,7 +76,7 @@ static int vaes_gcm_setiv(PROV_GCM_CTX *ctx, const unsigned char *iv, if (ivlen > (U64(1) << 61)) return 0; - ossl_aes_gcm_setiv_avx512(ctx->ks, gcmctx, iv, ivlen); + ossl_aes_gcm_setiv_avx512(gcmctx->key, gcmctx, iv, ivlen); return 1; } @@ -162,9 +161,9 @@ static int vaes_gcm_cipherupdate(PROV_GCM_CTX *ctx, const unsigned char *in, } if (ctx->enc) - ossl_aes_gcm_encrypt_avx512(ctx->ks, gcmctx, &gcmctx->mres, in, len, out); + ossl_aes_gcm_encrypt_avx512(gcmctx->key, gcmctx, &gcmctx->mres, in, len, out); else - ossl_aes_gcm_decrypt_avx512(ctx->ks, gcmctx, &gcmctx->mres, in, len, out); + ossl_aes_gcm_decrypt_avx512(gcmctx->key, gcmctx, &gcmctx->mres, in, len, out); return 1; } diff --git a/providers/implementations/ciphers/cipher_sm4_gcm_hw.c b/providers/implementations/ciphers/cipher_sm4_gcm_hw.c index 432e3589ed86dbf88fbd34242bb92c5970306761..630d8a3218e8fef3ee9affe777ae92bd54c80ef2 100644 --- a/providers/implementations/ciphers/cipher_sm4_gcm_hw.c +++ b/providers/implementations/ciphers/cipher_sm4_gcm_hw.c @@ -15,7 +15,6 @@ #include "crypto/sm4_platform.h" # define SM4_GCM_HW_SET_KEY_CTR_FN(ks, fn_set_enc_key, fn_block, fn_ctr) \ - ctx->ks = ks; \ fn_set_enc_key(key, ks); \ CRYPTO_gcm128_init(&ctx->gcm, ks, (block128_f)fn_block); \ ctx->ctr = (ctr128_f)fn_ctr; \ diff --git a/providers/implementations/include/prov/ciphercommon_gcm.h b/providers/implementations/include/prov/ciphercommon_gcm.h index 3aacf91c8b5d05fa22c96e8ef269e553eca449cb..ee0b23b92785da99e6bbdfc27ceb3581316ddbeb 100644 --- a/providers/implementations/include/prov/ciphercommon_gcm.h +++ b/providers/implementations/include/prov/ciphercommon_gcm.h @@ -79,7 +79,6 @@ typedef struct prov_gcm_ctx_st { const PROV_GCM_HW *hw; /* hardware specific methods */ GCM128_CONTEXT gcm; ctr128_f ctr; - const void *ks; } PROV_GCM_CTX; PROV_CIPHER_FUNC(int, GCM_setkey, (PROV_GCM_CTX *ctx, const unsigned char *key, @@ -126,7 +125,6 @@ int ossl_gcm_cipher_update(PROV_GCM_CTX *ctx, const unsigned char *in, size_t len, unsigned char *out); # define GCM_HW_SET_KEY_CTR_FN(ks, fn_set_enc_key, fn_block, fn_ctr) \ - ctx->ks = ks; \ fn_set_enc_key(key, keylen * 8, ks); \ CRYPTO_gcm128_init(&ctx->gcm, ks, (block128_f)fn_block); \ ctx->ctr = (ctr128_f)fn_ctr; \ diff --git a/providers/implementations/rands/seed_src.c b/providers/implementations/rands/seed_src.c index e57c9c4d4160f7204bd3f2ae5ab2aebd0f626e59..e8f7ec9efcff0b3a482dcdbf14b379746c8284d8 100644 --- a/providers/implementations/rands/seed_src.c +++ b/providers/implementations/rands/seed_src.c @@ -177,33 +177,32 @@ static size_t seed_get_seed(void *vseed, unsigned char **pout, int prediction_resistance, const unsigned char *adin, size_t adin_len) { - size_t bytes_needed; - unsigned char *p; - - /* - * Figure out how many bytes we need. - * This assumes that the seed sources provide eight bits of entropy - * per byte. For lower quality sources, the formula will need to be - * different. - */ - bytes_needed = entropy >= 0 ? (entropy + 7) / 8 : 0; - if (bytes_needed < min_len) - bytes_needed = min_len; - if (bytes_needed > max_len) { - ERR_raise(ERR_LIB_PROV, PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK); + size_t ret = 0; + size_t entropy_available = 0; + size_t i; + RAND_POOL *pool; + + pool = ossl_rand_pool_new(entropy, 1, min_len, max_len); + if (pool == NULL) { + ERR_raise(ERR_LIB_PROV, ERR_R_RAND_LIB); return 0; } - p = OPENSSL_secure_malloc(bytes_needed); - if (p == NULL) - return 0; - if (seed_src_generate(vseed, p, bytes_needed, 0, prediction_resistance, - adin, adin_len) != 0) { - *pout = p; - return bytes_needed; + /* Get entropy by polling system entropy sources. */ + entropy_available = ossl_pool_acquire_entropy(pool); + + if (entropy_available > 0) { + ret = ossl_rand_pool_length(pool); + *pout = ossl_rand_pool_detach(pool); + + /* xor the additional data into the output */ + for (i = 0 ; i < adin_len ; ++i) + (*pout)[i % ret] ^= adin[i]; + } else { + ERR_raise(ERR_LIB_PROV, PROV_R_ENTROPY_SOURCE_STRENGTH_TOO_WEAK); } - OPENSSL_secure_clear_free(p, bytes_needed); - return 0; + ossl_rand_pool_free(pool); + return ret; } static void seed_clear_seed(ossl_unused void *vdrbg, diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index 3da0caa4ea63b9cdf4cb3fa4c239b65569e2cdbc..ef6ad1508720e1c5cdb0904aa86586cad6e41bcf 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -635,7 +635,7 @@ int ossl_quic_channel_is_active(const QUIC_CHANNEL *ch) return ch != NULL && ch->state == QUIC_CHANNEL_STATE_ACTIVE; } -static int ossl_quic_channel_is_closing(const QUIC_CHANNEL *ch) +int ossl_quic_channel_is_closing(const QUIC_CHANNEL *ch) { return ch->state == QUIC_CHANNEL_STATE_TERMINATING_CLOSING; } @@ -1311,11 +1311,13 @@ static int ch_on_transport_params(const unsigned char *params, goto malformed; } +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION /* Must match our initial DCID. */ if (!ossl_quic_conn_id_eq(&ch->init_dcid, &cid)) { reason = TP_REASON_EXPECTED_VALUE("ORIG_DCID"); goto malformed; } +#endif got_orig_dcid = 1; break; @@ -2220,6 +2222,14 @@ static void ch_rx_handle_packet(QUIC_CHANNEL *ch) */ return; + /* + * RFC 9000 s 17.2.5.2: After the client has received and processed an + * Initial or Retry packet from the server, it MUST discard any + * subsequent Retry packets that it receives. + */ + if (ch->have_received_enc_pkt) + return; + if (ch->qrx_pkt->hdr->len <= QUIC_RETRY_INTEGRITY_TAG_LEN) /* Packets with zero-length Retry Tokens are invalid. */ return; @@ -2294,7 +2304,7 @@ static void ch_rx_handle_packet(QUIC_CHANNEL *ch) * non-zero Token Length field MUST either discard the packet or * generate a connection error of type PROTOCOL_VIOLATION. * - * TODO(QUIC): consider the implications of RFC 9000 s. 10.2.3 + * TODO(QUIC FUTURE): consider the implications of RFC 9000 s. 10.2.3 * Immediate Close during the Handshake: * However, at the cost of reducing feedback about * errors for legitimate peers, some forms of denial of @@ -2590,6 +2600,13 @@ static OSSL_TIME ch_determine_next_tick_deadline(QUIC_CHANNEL *ch) ossl_quic_enc_level_to_pn_space(i))); } } + + /* + * When do we need to send an ACK-eliciting packet to reset the idle + * deadline timer for the peer? + */ + if (!ossl_time_is_infinite(ch->ping_deadline)) + deadline = ossl_time_min(deadline, ch->ping_deadline); } /* Apply TXP wakeup deadline. */ @@ -2604,14 +2621,6 @@ static OSSL_TIME ch_determine_next_tick_deadline(QUIC_CHANNEL *ch) deadline = ossl_time_min(deadline, ch->idle_deadline); - /* - * When do we need to send an ACK-eliciting packet to reset the idle - * deadline timer for the peer? - */ - if (!ossl_time_is_infinite(ch->ping_deadline)) - deadline = ossl_time_min(deadline, - ch->ping_deadline); - /* When does the RXKU process complete? */ if (ch->rxku_in_progress) deadline = ossl_time_min(deadline, ch->rxku_update_end_deadline); @@ -2809,8 +2818,18 @@ static int ch_retry(QUIC_CHANNEL *ch, if ((buf = OPENSSL_memdup(retry_token, retry_token_len)) == NULL) return 0; - ossl_quic_tx_packetiser_set_initial_token(ch->txp, buf, retry_token_len, - free_token, NULL); + if (!ossl_quic_tx_packetiser_set_initial_token(ch->txp, buf, + retry_token_len, + free_token, NULL)) { + /* + * This may fail if the token we receive is too big for us to ever be + * able to transmit in an outgoing Initial packet. + */ + ossl_quic_channel_raise_protocol_error(ch, QUIC_ERR_INVALID_TOKEN, 0, + "received oversize token"); + OPENSSL_free(buf); + return 0; + } ch->retry_scid = *retry_scid; ch->doing_retry = 1; diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index 29a283dca0b27707fc91bb9ffce1af047c8e65e4..bdf5d5fea882dea4cce5f73a741b8bf89352c8f1 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -3571,6 +3571,27 @@ const SSL_CIPHER *ossl_quic_get_cipher(unsigned int u) return NULL; } +/* + * SSL_get_shutdown() + * ------------------ + */ +int ossl_quic_get_shutdown(const SSL *s) +{ + QCTX ctx; + int shut = 0; + + if (!expect_quic_conn_only(s, &ctx)) + return 0; + + if (ossl_quic_channel_is_term_any(ctx.qc->ch)) { + shut |= SSL_SENT_SHUTDOWN; + if (!ossl_quic_channel_is_closing(ctx.qc->ch)) + shut |= SSL_RECEIVED_SHUTDOWN; + } + + return shut; +} + /* * Internal Testing APIs * ===================== diff --git a/ssl/quic/quic_record_rx.c b/ssl/quic/quic_record_rx.c index 31c1f8fffdf5b635f1a501cd810be086c199f6d0..4d0493baff6e8e640a9c2602da8ca6efc2e93e7e 100644 --- a/ssl/quic/quic_record_rx.c +++ b/ssl/quic/quic_record_rx.c @@ -280,7 +280,7 @@ static void qrx_requeue_deferred(OSSL_QRX *qrx) while ((e = ossl_list_urxe_head(&qrx->urx_deferred)) != NULL) { ossl_list_urxe_remove(&qrx->urx_deferred, e); - ossl_list_urxe_insert_head(&qrx->urx_pending, e); + ossl_list_urxe_insert_tail(&qrx->urx_pending, e); } } @@ -757,12 +757,25 @@ static int qrx_decrypt_pkt_body(OSSL_QRX *qrx, unsigned char *dst, if (EVP_CipherUpdate(cctx, dst, &l, src, src_len - el->tag_len) != 1) return 0; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* + * Throw away what we just decrypted and just use the ciphertext instead + * (which should be unencrypted) + */ + memcpy(dst, src, l); + + /* Pretend to authenticate the tag but ignore it */ + if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) { + /* We don't care */ + } +#else /* Ensure authentication succeeded. */ if (EVP_CipherFinal_ex(cctx, NULL, &l2) != 1) { /* Authentication failed, increment failed auth counter. */ ++qrx->forged_pkt_count; return 0; } +#endif *dec_len = l; return 1; @@ -926,10 +939,19 @@ static int qrx_process_pkt(OSSL_QRX *qrx, QUIC_URXE *urxe, * * Relocate token buffer and fix pointer. */ - if (rxe->hdr.type == QUIC_PKT_TYPE_INITIAL - && !qrx_relocate_buffer(qrx, &rxe, &i, &rxe->hdr.token, - rxe->hdr.token_len)) - goto malformed; + if (rxe->hdr.type == QUIC_PKT_TYPE_INITIAL) { + const unsigned char *token = rxe->hdr.token; + + /* + * This may change the value of rxe and change the value of the token + * pointer as well. So we must make a temporary copy of the pointer to + * the token, and then copy it back into the new location of the rxe + */ + if (!qrx_relocate_buffer(qrx, &rxe, &i, &token, rxe->hdr.token_len)) + goto malformed; + + rxe->hdr.token = token; + } /* Now remove header protection. */ *pkt = orig_pkt; diff --git a/ssl/quic/quic_record_tx.c b/ssl/quic/quic_record_tx.c index d450470366db33234411eea1f734164d5b9d8cc1..4f86c68e1773b558dd5ce4eb4d8c4ee0e76f4fd8 100644 --- a/ssl/quic/quic_record_tx.c +++ b/ssl/quic/quic_record_tx.c @@ -543,6 +543,11 @@ static int qtx_encrypt_into_txe(OSSL_QTX *qtx, struct iovec_cur *cur, TXE *txe, return 0; } +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Ignore what we just encrypted and overwrite it with the plaintext */ + memcpy(txe_data(txe) + txe->data_len, src, l); +#endif + assert(l > 0 && src_len == (size_t)l); txe->data_len += src_len; } diff --git a/ssl/quic/quic_tls.c b/ssl/quic/quic_tls.c index a1bcedbfb071642a7a9cf2050f09b7cc2c8b03fa..af4af56c77b4adfb59c9445ed95199979c59cc38 100644 --- a/ssl/quic/quic_tls.c +++ b/ssl/quic/quic_tls.c @@ -85,6 +85,7 @@ struct ossl_record_layer_st { }; static int quic_set1_bio(OSSL_RECORD_LAYER *rl, BIO *bio); +static int quic_free(OSSL_RECORD_LAYER *r); static int quic_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, @@ -189,7 +190,7 @@ quic_new_record_layer(OSSL_LIB_CTX *libctx, const char *propq, int vers, return 1; err: *retrl = NULL; - OPENSSL_free(rl); + quic_free(rl); return 0; } diff --git a/ssl/quic/quic_tserver.c b/ssl/quic/quic_tserver.c index 3630577e707b918affe75a4c9a3a2edbd998808c..3fc51b4a778aa1202a58a44106b60f73888e3bd7 100644 --- a/ssl/quic/quic_tserver.c +++ b/ssl/quic/quic_tserver.c @@ -508,7 +508,7 @@ int ossl_quic_tserver_shutdown(QUIC_TSERVER *srv, uint64_t app_error_code) { ossl_quic_channel_local_close(srv->ch, app_error_code, NULL); - /* TODO(QUIC): !SSL_SHUTDOWN_FLAG_NO_STREAM_FLUSH */ + /* TODO(QUIC SERVER): !SSL_SHUTDOWN_FLAG_NO_STREAM_FLUSH */ if (ossl_quic_channel_is_terminated(srv->ch)) return 1; diff --git a/ssl/quic/quic_txp.c b/ssl/quic/quic_txp.c index 0f1e9b8f25618bde8ddf31cead956293d0211bb1..1045e79e0fc05471bd43fd4c13f2d41e6169f3e3 100644 --- a/ssl/quic/quic_txp.c +++ b/ssl/quic/quic_txp.c @@ -510,12 +510,63 @@ void ossl_quic_tx_packetiser_free(OSSL_QUIC_TX_PACKETISER *txp) OPENSSL_free(txp); } -void ossl_quic_tx_packetiser_set_initial_token(OSSL_QUIC_TX_PACKETISER *txp, - const unsigned char *token, - size_t token_len, - ossl_quic_initial_token_free_fn *free_cb, - void *free_cb_arg) +/* + * Determine if an Initial packet token length is reasonable based on the + * current MDPL, returning 1 if it is OK. + * + * The real PMTU to the peer could differ from our (pessimistic) understanding + * of the PMTU, therefore it is possible we could receive an Initial token from + * a server in a Retry packet which is bigger than the MDPL. In this case it is + * impossible for us ever to make forward progress and we need to error out + * and fail the connection attempt. + * + * The specific boundary condition is complex: for example, after the size of + * the Initial token, there are the Initial packet header overheads and then + * encryption/AEAD tag overheads. After that, the minimum room for frame data in + * order to guarantee forward progress must be guaranteed. For example, a crypto + * stream needs to always be able to serialize at least one byte in a CRYPTO + * frame in order to make forward progress. Because the offset field of a CRYPTO + * frame uses a variable-length integer, the number of bytes needed to ensure + * this also varies. + * + * Rather than trying to get this boundary condition check actually right, + * require a reasonable amount of slack to avoid pathological behaviours. (After + * all, transmitting a CRYPTO stream one byte at a time is probably not + * desirable anyway.) + * + * We choose 160 bytes as the required margin, which is double the rough + * estimation of the minimum we would require to guarantee forward progress + * under worst case packet overheads. + */ +#define TXP_REQUIRED_TOKEN_MARGIN 160 + +static int txp_check_token_len(size_t token_len, size_t mdpl) +{ + if (token_len == 0) + return 1; + + if (token_len >= mdpl) + return 0; + + if (TXP_REQUIRED_TOKEN_MARGIN >= mdpl) + /* (should not be possible because MDPL must be at least 1200) */ + return 0; + + if (token_len > mdpl - TXP_REQUIRED_TOKEN_MARGIN) + return 0; + + return 1; +} + +int ossl_quic_tx_packetiser_set_initial_token(OSSL_QUIC_TX_PACKETISER *txp, + const unsigned char *token, + size_t token_len, + ossl_quic_initial_token_free_fn *free_cb, + void *free_cb_arg) { + if (!txp_check_token_len(token_len, txp_get_mdpl(txp))) + return 0; + if (txp->initial_token != NULL && txp->initial_token_free_cb != NULL) txp->initial_token_free_cb(txp->initial_token, txp->initial_token_len, txp->initial_token_free_cb_arg); @@ -524,6 +575,7 @@ void ossl_quic_tx_packetiser_set_initial_token(OSSL_QUIC_TX_PACKETISER *txp, txp->initial_token_len = token_len; txp->initial_token_free_cb = free_cb; txp->initial_token_free_cb_arg = free_cb_arg; + return 1; } int ossl_quic_tx_packetiser_set_cur_dcid(OSSL_QUIC_TX_PACKETISER *txp, diff --git a/ssl/quic/quic_wire_pkt.c b/ssl/quic/quic_wire_pkt.c index 136c40e7ad8539e25f47d4c1ccd76add9282588f..acb926ad38a045ac3961ebb4ff01161afeb8c300 100644 --- a/ssl/quic/quic_wire_pkt.c +++ b/ssl/quic/quic_wire_pkt.c @@ -115,6 +115,11 @@ static int hdr_generate_mask(QUIC_HDR_PROTECTOR *hpr, return 0; } +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* No matter what we did above we use the same mask in fuzzing mode */ + memset(mask, 0, 5); +#endif + return 1; } diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c index 260d163a50d932c694ce7006b5884abb3856b8da..845eff9848e5b84525d32715a3ce56b9467bee01 100644 --- a/ssl/record/rec_layer_s3.c +++ b/ssl/record/rec_layer_s3.c @@ -294,8 +294,10 @@ int ssl3_write_bytes(SSL *ssl, uint8_t type, const void *buf_, size_t len, /* Retry needed */ i = HANDLE_RLAYER_WRITE_RETURN(s, s->rlayer.wrlmethod->retry_write_records(s->rlayer.wrl)); - if (i <= 0) + if (i <= 0) { + s->rlayer.wnum = tot; return i; + } tot += s->rlayer.wpend_tot; s->rlayer.wpend_tot = 0; } /* else no retry required */ @@ -321,6 +323,7 @@ int ssl3_write_bytes(SSL *ssl, uint8_t type, const void *buf_, size_t len, i = ssl->method->ssl_dispatch_alert(ssl); if (i <= 0) { /* SSLfatal() already called if appropriate */ + s->rlayer.wnum = tot; return i; } /* if it went, fall through and send more stuff */ diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index f15fe126a22f54b2d85e186592a1450757a2ce40..bd9160b7561b2e9076f4e0e5fe93655a37ac5425 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -5142,7 +5142,7 @@ void SSL_set_quiet_shutdown(SSL *s, int mode) { SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s); - /* TODO(QUIC): Currently not supported for QUIC. */ + /* Not supported with QUIC */ if (sc == NULL) return; @@ -5153,7 +5153,7 @@ int SSL_get_quiet_shutdown(const SSL *s) { const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s); - /* TODO(QUIC): Currently not supported for QUIC. */ + /* Not supported with QUIC */ if (sc == NULL) return 0; @@ -5164,7 +5164,7 @@ void SSL_set_shutdown(SSL *s, int mode) { SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL_ONLY(s); - /* TODO(QUIC): Do we want this for QUIC? */ + /* Not supported with QUIC */ if (sc == NULL) return; @@ -5175,7 +5175,12 @@ int SSL_get_shutdown(const SSL *s) { const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_CONST_SSL_ONLY(s); - /* TODO(QUIC): Do we want this for QUIC? */ +#ifndef OPENSSL_NO_QUIC + /* QUIC: Just indicate whether the connection was shutdown cleanly. */ + if (IS_QUIC(s)) + return ossl_quic_get_shutdown(s); +#endif + if (sc == NULL) return 0; diff --git a/ssl/statem/statem_lib.c b/ssl/statem/statem_lib.c index d979b6d5fc437714b93abc1e75f79f4cfdcc1742..5693a1269df2c7f1f40220684cf32145f02f8ebf 100644 --- a/ssl/statem/statem_lib.c +++ b/ssl/statem/statem_lib.c @@ -575,6 +575,11 @@ MSG_PROCESS_RETURN tls_process_cert_verify(SSL_CONNECTION *s, PACKET *pkt) } } else { j = EVP_DigestVerify(mctx, data, len, hdata, hdatalen); +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + /* Ignore bad signatures when fuzzing */ + if (SSL_IS_QUIC_HANDSHAKE(s)) + j = 1; +#endif if (j <= 0) { SSLfatal(s, SSL_AD_DECRYPT_ERROR, SSL_R_BAD_SIGNATURE); goto err; diff --git a/test/build.info b/test/build.info index 73f8de1f7a125b96eba58b2a4ca3382bc987d7af..cd8254164a0ac3c69daf12772d26ea25b8848987 100644 --- a/test/build.info +++ b/test/build.info @@ -34,7 +34,7 @@ IF[{- !$disabled{tests} -}] confdump \ versions \ aborttest test_test pkcs12_format_test pkcs12_api_test \ - sanitytest rsa_complex exdatatest bntest \ + sanitytest time_test rsa_complex exdatatest bntest \ ecstresstest gmdifftest pbelutest \ destest mdc2test sha_test \ exptest pbetest localetest evp_pkey_ctx_new_from_name \ @@ -97,6 +97,10 @@ IF[{- !$disabled{tests} -}] INCLUDE[sanitytest]=../include ../apps/include DEPEND[sanitytest]=../libcrypto.a libtestutil.a + SOURCE[time_test]=time_test.c + INCLUDE[time_test]=../include ../apps/include + DEPEND[time_test]=../libcrypto.a libtestutil.a + SOURCE[rand_test]=rand_test.c INCLUDE[rand_test]=../include ../apps/include DEPEND[rand_test]=../libcrypto libtestutil.a diff --git a/test/errtest.c b/test/errtest.c index dbf07f8a72cd8342432d9d2b5964887be954f3e1..2a66b483fec95d8ae55f1c553f6cecfd808be256 100644 --- a/test/errtest.c +++ b/test/errtest.c @@ -334,7 +334,12 @@ static int test_clear_error(void) return res; } -static int test_save_restore(void) +/* + * Test saving and restoring error state. + * Test 0: Save using OSSL_ERR_STATE_save() + * Test 1: Save using OSSL_ERR_STATE_save_to_mark() + */ +static int test_save_restore(int idx) { ERR_STATE *es; int res = 0, i, flags = -1; @@ -350,15 +355,25 @@ static int test_save_restore(void) if (!TEST_ulong_gt(mallocfail, 0)) goto err; + if (idx == 1 && !TEST_int_eq(ERR_set_mark(), 1)) + goto err; + ERR_raise_data(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR, testdata); interr = ERR_peek_last_error(); if (!TEST_ulong_ne(mallocfail, ERR_peek_last_error())) goto err; - OSSL_ERR_STATE_save(es); + if (idx == 0) { + OSSL_ERR_STATE_save(es); - if (!TEST_ulong_eq(ERR_peek_last_error(), 0)) - goto err; + if (!TEST_ulong_eq(ERR_peek_last_error(), 0)) + goto err; + } else { + OSSL_ERR_STATE_save_to_mark(es); + + if (!TEST_ulong_ne(ERR_peek_last_error(), 0)) + goto err; + } for (i = 0; i < 2; i++) { OSSL_ERR_STATE_restore(es); @@ -374,10 +389,12 @@ static int test_save_restore(void) OSSL_ERR_STATE_restore(es); /* verify them all */ - if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL, - &data, &flags), mallocfail) - || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED)) - goto err; + if (idx == 0 || i == 0) { + if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL, + &data, &flags), mallocfail) + || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED)) + goto err; + } if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL, &data, &flags), interr) @@ -385,10 +402,12 @@ static int test_save_restore(void) || !TEST_int_eq(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED)) goto err; - if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL, - &data, &flags), mallocfail) - || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED)) - goto err; + if (idx == 0) { + if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL, + &data, &flags), mallocfail) + || !TEST_int_ne(flags, ERR_TXT_STRING | ERR_TXT_MALLOCED)) + goto err; + } if (!TEST_ulong_eq(ERR_get_error_all(NULL, NULL, NULL, &data, &flags), interr) @@ -415,7 +434,7 @@ int setup_tests(void) ADD_TEST(test_print_error_format); #endif ADD_TEST(test_marks); - ADD_TEST(test_save_restore); + ADD_ALL_TESTS(test_save_restore, 2); ADD_TEST(test_clear_error); return 1; } diff --git a/test/evp_extra_test.c b/test/evp_extra_test.c index a0724981de34e55f15145ae896e5f7b0a14333ef..0ece891159488aba16f956ebcd9100a7a5cc3d0e 100644 --- a/test/evp_extra_test.c +++ b/test/evp_extra_test.c @@ -3046,6 +3046,36 @@ static int test_RSA_OAEP_set_get_params(void) return ret; } +/* https://github.com/openssl/openssl/issues/21288 */ +static int test_RSA_OAEP_set_null_label(void) +{ + int ret = 0; + EVP_PKEY *key = NULL; + EVP_PKEY_CTX *key_ctx = NULL; + + if (!TEST_ptr(key = load_example_rsa_key()) + || !TEST_ptr(key_ctx = EVP_PKEY_CTX_new_from_pkey(testctx, key, NULL)) + || !TEST_true(EVP_PKEY_encrypt_init(key_ctx))) + goto err; + + if (!TEST_true(EVP_PKEY_CTX_set_rsa_padding(key_ctx, RSA_PKCS1_OAEP_PADDING))) + goto err; + + if (!TEST_true(EVP_PKEY_CTX_set0_rsa_oaep_label(key_ctx, OPENSSL_strdup("foo"), 0))) + goto err; + + if (!TEST_true(EVP_PKEY_CTX_set0_rsa_oaep_label(key_ctx, NULL, 0))) + goto err; + + ret = 1; + + err: + EVP_PKEY_free(key); + EVP_PKEY_CTX_free(key_ctx); + + return ret; +} + #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) static int test_decrypt_null_chunks(void) { @@ -5021,6 +5051,253 @@ end: return testresult; } +static int aes_gcm_encrypt(const unsigned char *gcm_key, size_t gcm_key_s, + const unsigned char *gcm_iv, size_t gcm_ivlen, + const unsigned char *gcm_pt, size_t gcm_pt_s, + const unsigned char *gcm_aad, size_t gcm_aad_s, + const unsigned char *gcm_ct, size_t gcm_ct_s, + const unsigned char *gcm_tag, size_t gcm_tag_s) +{ + int ret = 0; + EVP_CIPHER_CTX *ctx; + EVP_CIPHER *cipher = NULL; + int outlen, tmplen; + unsigned char outbuf[1024]; + unsigned char outtag[16]; + OSSL_PARAM params[2] = { + OSSL_PARAM_END, OSSL_PARAM_END + }; + + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_ptr(cipher = EVP_CIPHER_fetch(testctx, "AES-256-GCM", ""))) + goto err; + + params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, + &gcm_ivlen); + + if (!TEST_true(EVP_EncryptInit_ex2(ctx, cipher, gcm_key, gcm_iv, params)) + || (gcm_aad != NULL + && !TEST_true(EVP_EncryptUpdate(ctx, NULL, &outlen, + gcm_aad, gcm_aad_s))) + || !TEST_true(EVP_EncryptUpdate(ctx, outbuf, &outlen, + gcm_pt, gcm_pt_s)) + || !TEST_true(EVP_EncryptFinal_ex(ctx, outbuf, &tmplen))) + goto err; + + params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, + outtag, sizeof(outtag)); + + if (!TEST_true(EVP_CIPHER_CTX_get_params(ctx, params)) + || !TEST_mem_eq(outbuf, outlen, gcm_ct, gcm_ct_s) + || !TEST_mem_eq(outtag, gcm_tag_s, gcm_tag, gcm_tag_s)) + goto err; + + ret = 1; +err: + EVP_CIPHER_free(cipher); + EVP_CIPHER_CTX_free(ctx); + + return ret; +} + +static int aes_gcm_decrypt(const unsigned char *gcm_key, size_t gcm_key_s, + const unsigned char *gcm_iv, size_t gcm_ivlen, + const unsigned char *gcm_pt, size_t gcm_pt_s, + const unsigned char *gcm_aad, size_t gcm_aad_s, + const unsigned char *gcm_ct, size_t gcm_ct_s, + const unsigned char *gcm_tag, size_t gcm_tag_s) +{ + int ret = 0; + EVP_CIPHER_CTX *ctx; + EVP_CIPHER *cipher = NULL; + int outlen; + unsigned char outbuf[1024]; + OSSL_PARAM params[2] = { + OSSL_PARAM_END, OSSL_PARAM_END + }; + + if ((ctx = EVP_CIPHER_CTX_new()) == NULL) + goto err; + + if ((cipher = EVP_CIPHER_fetch(testctx, "AES-256-GCM", "")) == NULL) + goto err; + + params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_AEAD_IVLEN, + &gcm_ivlen); + + if (!TEST_true(EVP_DecryptInit_ex2(ctx, cipher, gcm_key, gcm_iv, params)) + || (gcm_aad != NULL + && !TEST_true(EVP_DecryptUpdate(ctx, NULL, &outlen, + gcm_aad, gcm_aad_s))) + || !TEST_true(EVP_DecryptUpdate(ctx, outbuf, &outlen, + gcm_ct, gcm_ct_s)) + || !TEST_mem_eq(outbuf, outlen, gcm_pt, gcm_pt_s)) + goto err; + + params[0] = OSSL_PARAM_construct_octet_string(OSSL_CIPHER_PARAM_AEAD_TAG, + (void*)gcm_tag, gcm_tag_s); + + if (!TEST_true(EVP_CIPHER_CTX_set_params(ctx, params)) + ||!TEST_true(EVP_DecryptFinal_ex(ctx, outbuf, &outlen))) + goto err; + + ret = 1; +err: + EVP_CIPHER_free(cipher); + EVP_CIPHER_CTX_free(ctx); + + return ret; +} + +static int test_aes_gcm_ivlen_change_cve_2023_5363(void) +{ + /* AES-GCM test data obtained from NIST public test vectors */ + static const unsigned char gcm_key[] = { + 0xd0, 0xc2, 0x67, 0xc1, 0x9f, 0x30, 0xd8, 0x0b, 0x89, 0x14, 0xbb, 0xbf, + 0xb7, 0x2f, 0x73, 0xb8, 0xd3, 0xcd, 0x5f, 0x6a, 0x78, 0x70, 0x15, 0x84, + 0x8a, 0x7b, 0x30, 0xe3, 0x8f, 0x16, 0xf1, 0x8b, + }; + static const unsigned char gcm_iv[] = { + 0xb6, 0xdc, 0xda, 0x95, 0xac, 0x99, 0x77, 0x76, 0x25, 0xae, 0x87, 0xf8, + 0xa3, 0xa9, 0xdd, 0x64, 0xd7, 0x9b, 0xbd, 0x5f, 0x4a, 0x0e, 0x54, 0xca, + 0x1a, 0x9f, 0xa2, 0xe3, 0xf4, 0x5f, 0x5f, 0xc2, 0xce, 0xa7, 0xb6, 0x14, + 0x12, 0x6f, 0xf0, 0xaf, 0xfd, 0x3e, 0x17, 0x35, 0x6e, 0xa0, 0x16, 0x09, + 0xdd, 0xa1, 0x3f, 0xd8, 0xdd, 0xf3, 0xdf, 0x4f, 0xcb, 0x18, 0x49, 0xb8, + 0xb3, 0x69, 0x2c, 0x5d, 0x4f, 0xad, 0x30, 0x91, 0x08, 0xbc, 0xbe, 0x24, + 0x01, 0x0f, 0xbe, 0x9c, 0xfb, 0x4f, 0x5d, 0x19, 0x7f, 0x4c, 0x53, 0xb0, + 0x95, 0x90, 0xac, 0x7b, 0x1f, 0x7b, 0xa0, 0x99, 0xe1, 0xf3, 0x48, 0x54, + 0xd0, 0xfc, 0xa9, 0xcc, 0x91, 0xf8, 0x1f, 0x9b, 0x6c, 0x9a, 0xe0, 0xdc, + 0x63, 0xea, 0x7d, 0x2a, 0x4a, 0x7d, 0xa5, 0xed, 0x68, 0x57, 0x27, 0x6b, + 0x68, 0xe0, 0xf2, 0xb8, 0x51, 0x50, 0x8d, 0x3d, + }; + static const unsigned char gcm_pt[] = { + 0xb8, 0xb6, 0x88, 0x36, 0x44, 0xe2, 0x34, 0xdf, 0x24, 0x32, 0x91, 0x07, + 0x4f, 0xe3, 0x6f, 0x81, + }; + static const unsigned char gcm_ct[] = { + 0xff, 0x4f, 0xb3, 0xf3, 0xf9, 0xa2, 0x51, 0xd4, 0x82, 0xc2, 0xbe, 0xf3, + 0xe2, 0xd0, 0xec, 0xed, + }; + static const unsigned char gcm_tag[] = { + 0xbd, 0x06, 0x38, 0x09, 0xf7, 0xe1, 0xc4, 0x72, 0x0e, 0xf2, 0xea, 0x63, + 0xdb, 0x99, 0x6c, 0x21, + }; + + return aes_gcm_encrypt(gcm_key, sizeof(gcm_key), gcm_iv, sizeof(gcm_iv), + gcm_pt, sizeof(gcm_pt), NULL, 0, + gcm_ct, sizeof(gcm_ct), gcm_tag, sizeof(gcm_tag)) + && aes_gcm_decrypt(gcm_key, sizeof(gcm_key), gcm_iv, sizeof(gcm_iv), + gcm_pt, sizeof(gcm_pt), NULL, 0, + gcm_ct, sizeof(gcm_ct), gcm_tag, sizeof(gcm_tag)); +} + +#ifndef OPENSSL_NO_RC4 +static int rc4_encrypt(const unsigned char *rc4_key, size_t rc4_key_s, + const unsigned char *rc4_pt, size_t rc4_pt_s, + const unsigned char *rc4_ct, size_t rc4_ct_s) +{ + int ret = 0; + EVP_CIPHER_CTX *ctx; + EVP_CIPHER *cipher = NULL; + int outlen, tmplen; + unsigned char outbuf[1024]; + OSSL_PARAM params[2] = { + OSSL_PARAM_END, OSSL_PARAM_END + }; + + if (!TEST_ptr(ctx = EVP_CIPHER_CTX_new()) + || !TEST_ptr(cipher = EVP_CIPHER_fetch(testctx, "RC4", ""))) + goto err; + + params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, + &rc4_key_s); + + if (!TEST_true(EVP_EncryptInit_ex2(ctx, cipher, rc4_key, NULL, params)) + || !TEST_true(EVP_EncryptUpdate(ctx, outbuf, &outlen, + rc4_pt, rc4_pt_s)) + || !TEST_true(EVP_EncryptFinal_ex(ctx, outbuf, &tmplen))) + goto err; + + if (!TEST_mem_eq(outbuf, outlen, rc4_ct, rc4_ct_s)) + goto err; + + ret = 1; +err: + EVP_CIPHER_free(cipher); + EVP_CIPHER_CTX_free(ctx); + + return ret; +} + +static int rc4_decrypt(const unsigned char *rc4_key, size_t rc4_key_s, + const unsigned char *rc4_pt, size_t rc4_pt_s, + const unsigned char *rc4_ct, size_t rc4_ct_s) +{ + int ret = 0; + EVP_CIPHER_CTX *ctx; + EVP_CIPHER *cipher = NULL; + int outlen; + unsigned char outbuf[1024]; + OSSL_PARAM params[2] = { + OSSL_PARAM_END, OSSL_PARAM_END + }; + + if ((ctx = EVP_CIPHER_CTX_new()) == NULL) + goto err; + + if ((cipher = EVP_CIPHER_fetch(testctx, "RC4", "")) == NULL) + goto err; + + params[0] = OSSL_PARAM_construct_size_t(OSSL_CIPHER_PARAM_KEYLEN, + &rc4_key_s); + + if (!TEST_true(EVP_DecryptInit_ex2(ctx, cipher, rc4_key, NULL, params)) + || !TEST_true(EVP_DecryptUpdate(ctx, outbuf, &outlen, + rc4_ct, rc4_ct_s)) + || !TEST_mem_eq(outbuf, outlen, rc4_pt, rc4_pt_s)) + goto err; + + ret = 1; +err: + EVP_CIPHER_free(cipher); + EVP_CIPHER_CTX_free(ctx); + + return ret; +} + +static int test_aes_rc4_keylen_change_cve_2023_5363(void) +{ + /* RC4 test data obtained from RFC 6229 */ + static const struct { + unsigned char key[5]; + unsigned char padding[11]; + } rc4_key = { + { /* Five bytes of key material */ + 0x83, 0x32, 0x22, 0x77, 0x2a, + }, + { /* Random padding to 16 bytes */ + 0x80, 0xad, 0x97, 0xbd, 0xc9, 0x73, 0xdf, 0x8a, 0xaa, 0x32, 0x91 + } + }; + static const unsigned char rc4_pt[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + static const unsigned char rc4_ct[] = { + 0x80, 0xad, 0x97, 0xbd, 0xc9, 0x73, 0xdf, 0x8a, + 0x2e, 0x87, 0x9e, 0x92, 0xa4, 0x97, 0xef, 0xda + }; + + if (lgcyprov == NULL) + return TEST_skip("Test requires legacy provider to be loaded"); + + return rc4_encrypt(rc4_key.key, sizeof(rc4_key.key), + rc4_pt, sizeof(rc4_pt), rc4_ct, sizeof(rc4_ct)) + && rc4_decrypt(rc4_key.key, sizeof(rc4_key.key), + rc4_pt, sizeof(rc4_pt), rc4_ct, sizeof(rc4_ct)); +} +#endif + int setup_tests(void) { OPTION_CHOICE o; @@ -5101,6 +5378,7 @@ int setup_tests(void) #endif ADD_TEST(test_RSA_get_set_params); ADD_TEST(test_RSA_OAEP_set_get_params); + ADD_TEST(test_RSA_OAEP_set_null_label); #if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305) ADD_TEST(test_decrypt_null_chunks); #endif @@ -5168,6 +5446,12 @@ int setup_tests(void) ADD_TEST(test_sign_continuation); + /* Test cases for CVE-2023-5363 */ + ADD_TEST(test_aes_gcm_ivlen_change_cve_2023_5363); +#ifndef OPENSSL_NO_RC4 + ADD_TEST(test_aes_rc4_keylen_change_cve_2023_5363); +#endif + return 1; } diff --git a/test/helpers/ssltestlib.c b/test/helpers/ssltestlib.c index 3ae3e7d4eaf47ee1996a9e5c6ef435b811e08161..ddc6bb7b64ab508d1e726267d5466bf2cfaea2fd 100644 --- a/test/helpers/ssltestlib.c +++ b/test/helpers/ssltestlib.c @@ -29,13 +29,15 @@ static int tls_dump_gets(BIO *bp, char *buf, int size); static int tls_dump_puts(BIO *bp, const char *str); /* Choose a sufficiently large type likely to be unused for this custom BIO */ -#define BIO_TYPE_TLS_DUMP_FILTER (0x80 | BIO_TYPE_FILTER) +#define BIO_TYPE_TLS_DUMP_FILTER (0x80 | BIO_TYPE_FILTER) #define BIO_TYPE_MEMPACKET_TEST 0x81 #define BIO_TYPE_ALWAYS_RETRY 0x82 +#define BIO_TYPE_MAYBE_RETRY (0x83 | BIO_TYPE_FILTER) static BIO_METHOD *method_tls_dump = NULL; static BIO_METHOD *meth_mem = NULL; static BIO_METHOD *meth_always_retry = NULL; +static BIO_METHOD *meth_maybe_retry = NULL; static int retry_err = -1; /* Note: Not thread safe! */ @@ -804,6 +806,100 @@ static int always_retry_puts(BIO *bio, const char *str) return retry_err; } +struct maybe_retry_data_st { + unsigned int retrycnt; +}; + +static int maybe_retry_new(BIO *bi); +static int maybe_retry_free(BIO *a); +static int maybe_retry_write(BIO *b, const char *in, int inl); +static long maybe_retry_ctrl(BIO *b, int cmd, long num, void *ptr); + +const BIO_METHOD *bio_s_maybe_retry(void) +{ + if (meth_maybe_retry == NULL) { + if (!TEST_ptr(meth_maybe_retry = BIO_meth_new(BIO_TYPE_MAYBE_RETRY, + "Maybe Retry")) + || !TEST_true(BIO_meth_set_write(meth_maybe_retry, + maybe_retry_write)) + || !TEST_true(BIO_meth_set_ctrl(meth_maybe_retry, + maybe_retry_ctrl)) + || !TEST_true(BIO_meth_set_create(meth_maybe_retry, + maybe_retry_new)) + || !TEST_true(BIO_meth_set_destroy(meth_maybe_retry, + maybe_retry_free))) + return NULL; + } + return meth_maybe_retry; +} + +void bio_s_maybe_retry_free(void) +{ + BIO_meth_free(meth_maybe_retry); +} + +static int maybe_retry_new(BIO *bio) +{ + struct maybe_retry_data_st *data = OPENSSL_zalloc(sizeof(*data)); + + if (data == NULL) + return 0; + + BIO_set_data(bio, data); + BIO_set_init(bio, 1); + return 1; +} + +static int maybe_retry_free(BIO *bio) +{ + struct maybe_retry_data_st *data = BIO_get_data(bio); + + OPENSSL_free(data); + BIO_set_data(bio, NULL); + BIO_set_init(bio, 0); + return 1; +} + +static int maybe_retry_write(BIO *bio, const char *in, int inl) +{ + struct maybe_retry_data_st *data = BIO_get_data(bio); + + if (data == NULL) + return -1; + + if (data->retrycnt == 0) { + BIO_set_retry_write(bio); + return -1; + } + data->retrycnt--; + + return BIO_write(BIO_next(bio), in, inl); +} + +static long maybe_retry_ctrl(BIO *bio, int cmd, long num, void *ptr) +{ + struct maybe_retry_data_st *data = BIO_get_data(bio); + + if (data == NULL) + return 0; + + switch (cmd) { + case MAYBE_RETRY_CTRL_SET_RETRY_AFTER_CNT: + data->retrycnt = num; + return 1; + + case BIO_CTRL_FLUSH: + if (data->retrycnt == 0) { + BIO_set_retry_write(bio); + return -1; + } + data->retrycnt--; + /* fall through */ + default: + return BIO_ctrl(BIO_next(bio), cmd, num, ptr); + } +} + int create_ssl_ctx_pair(OSSL_LIB_CTX *libctx, const SSL_METHOD *sm, const SSL_METHOD *cm, int min_proto_version, int max_proto_version, SSL_CTX **sctx, SSL_CTX **cctx, diff --git a/test/helpers/ssltestlib.h b/test/helpers/ssltestlib.h index c513769ddd956027957dd7022af260a84e6e47ba..eb54b04f2c662112837832c579ecb7505c668ee4 100644 --- a/test/helpers/ssltestlib.h +++ b/test/helpers/ssltestlib.h @@ -44,6 +44,15 @@ const BIO_METHOD *bio_s_always_retry(void); void bio_s_always_retry_free(void); void set_always_retry_err_val(int err); +/* + * Maybe retry BIO ctrls. We make them large enough to not clash with standard + * BIO ctrl codes. + */ +#define MAYBE_RETRY_CTRL_SET_RETRY_AFTER_CNT (1 << 15) + +const BIO_METHOD *bio_s_maybe_retry(void); +void bio_s_maybe_retry_free(void); + /* Packet types - value 0 is reserved */ #define INJECT_PACKET 1 #define INJECT_PACKET_IGNORE_REC_SEQ 2 diff --git a/test/quic_multistream_test.c b/test/quic_multistream_test.c index e4663ece172f7564b68fdaf3781df9d578fae278..36be2dc80c02b57cf808a94ac795c77b0c78a1a7 100644 --- a/test/quic_multistream_test.c +++ b/test/quic_multistream_test.c @@ -4902,6 +4902,7 @@ static const struct script_op script_76[] = { OP_END }; +/* 77. Ensure default stream popping operates correctly */ static const struct script_op script_77[] = { OP_C_SET_ALPN ("ossltest") OP_C_CONNECT_WAIT () @@ -4922,6 +4923,66 @@ static const struct script_op script_77[] = { OP_END }; +/* 78. Post-connection session ticket handling */ +static size_t new_session_count; + +static int on_new_session(SSL *s, SSL_SESSION *sess) +{ + ++new_session_count; + return 0; /* do not ref session, we aren't keeping it */ +} + +static int setup_session(struct helper *h, struct helper_local *hl) +{ + SSL_CTX_set_session_cache_mode(h->c_ctx, SSL_SESS_CACHE_BOTH); + SSL_CTX_sess_set_new_cb(h->c_ctx, on_new_session); + return 1; +} + +static int trigger_late_session_ticket(struct helper *h, struct helper_local *hl) +{ + new_session_count = 0; + + if (!TEST_true(ossl_quic_tserver_new_ticket(ACQUIRE_S()))) + return 0; + + return 1; +} + +static int check_got_session_ticket(struct helper *h, struct helper_local *hl) +{ + if (!TEST_size_t_gt(new_session_count, 0)) + return 0; + + return 1; +} + +static const struct script_op script_78[] = { + OP_C_SET_ALPN ("ossltest") + OP_CHECK (setup_session, 0) + OP_C_CONNECT_WAIT () + + OP_C_SET_DEFAULT_STREAM_MODE(SSL_DEFAULT_STREAM_MODE_NONE) + + OP_C_NEW_STREAM_BIDI (a, C_BIDI_ID(0)) + OP_C_WRITE (a, "apple", 5) + + OP_S_BIND_STREAM_ID (a, C_BIDI_ID(0)) + OP_S_READ_EXPECT (a, "apple", 5) + + OP_S_WRITE (a, "orange", 6) + OP_C_READ_EXPECT (a, "orange", 6) + + OP_CHECK (trigger_late_session_ticket, 0) + + OP_S_WRITE (a, "Strawberry", 10) + OP_C_READ_EXPECT (a, "Strawberry", 10) + + OP_CHECK (check_got_session_ticket, 0) + + OP_END +}; + static const struct script_op *const scripts[] = { script_1, script_2, @@ -4999,7 +5060,8 @@ static const struct script_op *const scripts[] = { script_74, script_75, script_76, - script_77 + script_77, + script_78 }; static int test_script(int idx) diff --git a/test/quic_txp_test.c b/test/quic_txp_test.c index 4682483acc3d10bbc56c3fc8358371d8dbab830d..423d28ddcbb4747b0f00b397340262a5e8ed8177 100644 --- a/test/quic_txp_test.c +++ b/test/quic_txp_test.c @@ -1198,6 +1198,54 @@ static const struct script_op script_17[] = { OP_END }; +/* 18. Big Token Rejection */ +static const unsigned char big_token[1950]; + +static int try_big_token(struct helper *h) +{ + size_t i; + + /* Ensure big token is rejected */ + if (!TEST_false(ossl_quic_tx_packetiser_set_initial_token(h->txp, + big_token, + sizeof(big_token), + NULL, + NULL))) + return 0; + + /* + * Keep trying until we find an acceptable size, then make sure + * that works for generation + */ + for (i = sizeof(big_token) - 1;; --i) { + if (!TEST_size_t_gt(i, 0)) + return 0; + + if (ossl_quic_tx_packetiser_set_initial_token(h->txp, big_token, i, + NULL, NULL)) + break; + } + + return 1; +} + +static const struct script_op script_18[] = { + OP_PROVIDE_SECRET(QUIC_ENC_LEVEL_INITIAL, QRL_SUITE_AES128GCM, secret_1) + OP_TXP_GENERATE_NONE() + OP_CHECK(try_big_token) + OP_TXP_GENERATE_NONE() + OP_CRYPTO_SEND(QUIC_PN_SPACE_INITIAL, crypto_1) + OP_TXP_GENERATE() + OP_RX_PKT() + OP_EXPECT_DGRAM_LEN(1200, 1200) + OP_NEXT_FRAME() + OP_EXPECT_FRAME(OSSL_QUIC_FRAME_TYPE_CRYPTO) + OP_EXPECT_NO_FRAME() + OP_RX_PKT_NONE() + OP_TXP_GENERATE_NONE() + OP_END +}; + static const struct script_op *const scripts[] = { script_1, script_2, @@ -1215,7 +1263,8 @@ static const struct script_op *const scripts[] = { script_14, script_15, script_16, - script_17 + script_17, + script_18 }; static void skip_padding(struct helper *h) diff --git a/test/quicapitest.c b/test/quicapitest.c index 81c8c215bd43a9666754f0228a0efe39d60148b9..37d7803005cb93aecea7f55ab0c30c6487c9501c 100644 --- a/test/quicapitest.c +++ b/test/quicapitest.c @@ -1335,6 +1335,52 @@ static int test_alpn(int idx) return testresult; } +/* + * Test SSL_get_shutdown() behavior. + */ +static int test_get_shutdown(void) +{ + SSL_CTX *cctx = SSL_CTX_new_ex(libctx, NULL, OSSL_QUIC_client_method()); + SSL *clientquic = NULL; + QUIC_TSERVER *qtserv = NULL; + int testresult = 0; + + if (!TEST_ptr(cctx) + || !TEST_true(qtest_create_quic_objects(libctx, cctx, NULL, cert, + privkey, + QTEST_FLAG_FAKE_TIME, + &qtserv, &clientquic, + NULL, NULL)) + || !TEST_true(qtest_create_quic_connection(qtserv, clientquic))) + goto err; + + if (!TEST_int_eq(SSL_get_shutdown(clientquic), 0)) + goto err; + + if (!TEST_int_eq(SSL_shutdown(clientquic), 0)) + goto err; + + if (!TEST_int_eq(SSL_get_shutdown(clientquic), SSL_SENT_SHUTDOWN)) + goto err; + + do { + ossl_quic_tserver_tick(qtserv); + qtest_add_time(100); + } while (SSL_shutdown(clientquic) == 0); + + if (!TEST_int_eq(SSL_get_shutdown(clientquic), + SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN)) + goto err; + + testresult = 1; + err: + ossl_quic_tserver_free(qtserv); + SSL_free(clientquic); + SSL_CTX_free(cctx); + + return testresult; +} + #define MAX_LOOPS 2000 /* @@ -1586,6 +1632,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_client_auth, 2); ADD_ALL_TESTS(test_alpn, 2); ADD_ALL_TESTS(test_noisy_dgram, 2); + ADD_TEST(test_get_shutdown); return 1; err: diff --git a/test/recipes/02-test_time.t b/test/recipes/02-test_time.t new file mode 100644 index 0000000000000000000000000000000000000000..c4534034fcfdadea6784a0f7cd8c79d1b6f59dd6 --- /dev/null +++ b/test/recipes/02-test_time.t @@ -0,0 +1,12 @@ +#! /usr/bin/env perl +# Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + + +use OpenSSL::Test::Simple; + +simple_test("test_time", "time_test"); diff --git a/test/recipes/70-test_quic_record.t b/test/recipes/70-test_quic_record.t index 3fd782000c34a0c056c200398e4c8ce2d2d6e6c7..52acaa8aed624c03c00716fb46b9ce2a1e702d71 100644 --- a/test/recipes/70-test_quic_record.t +++ b/test/recipes/70-test_quic_record.t @@ -14,6 +14,9 @@ setup("test_quic_record"); plan skip_all => "QUIC protocol is not supported by this OpenSSL build" if disabled('quic'); +plan skip_all => "These tests are not supported in a fuzz build" + if config('options') =~ /-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION|enable-fuzz-afl/; + plan tests => 1; ok(run(test(["quic_record_test"]))); diff --git a/test/recipes/75-test_quicapi.t b/test/recipes/75-test_quicapi.t index bd411f221c8d68d882f6336745f23e9519d9bc6e..e1ce5eabb291b9abf51a472f0efd715c4b38b0d4 100644 --- a/test/recipes/75-test_quicapi.t +++ b/test/recipes/75-test_quicapi.t @@ -22,6 +22,9 @@ my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0); plan skip_all => "QUIC protocol is not supported by this OpenSSL build" if disabled('quic'); +plan skip_all => "These tests are not supported in a fuzz build" + if config('options') =~ /-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION|enable-fuzz-afl/; + plan tests => ($no_fips ? 0 : 1) # quicapitest with fips + 1; # quicapitest with default provider diff --git a/test/recipes/75-test_quicapi_data/ssltraceref-zlib.txt b/test/recipes/75-test_quicapi_data/ssltraceref-zlib.txt index e8bdee624fbcc4154ddcc89bb206cae0b25406d4..68d3fd86ecf4c49bf3a4791dcd195242cd16a918 100644 --- a/test/recipes/75-test_quicapi_data/ssltraceref-zlib.txt +++ b/test/recipes/75-test_quicapi_data/ssltraceref-zlib.txt @@ -127,21 +127,21 @@ Received Packet Version: 0x00000001 Destination Conn Id: Source Conn Id: 0x???????????????? - Payload length: 213 - Packet Number: 0x00000001 + Payload length: 1042 + Packet Number: 0x00000000 Received Packet Packet Type: Handshake Version: 0x00000001 Destination Conn Id: Source Conn Id: 0x???????????????? - Payload length: 1042 - Packet Number: 0x00000000 -Received Frame: Crypto - Offset: 1022 - Len: 192 + Payload length: 213 + Packet Number: 0x00000001 Received Frame: Crypto Offset: 0 Len: 1022 +Received Frame: Crypto + Offset: 1022 + Len: 192 Received TLS Record Header: Version = TLS 1.2 (0x303) diff --git a/test/recipes/75-test_quicapi_data/ssltraceref.txt b/test/recipes/75-test_quicapi_data/ssltraceref.txt index 6b64d0652e9b1f90ca9c3b9194be6e1b9822e9d5..6a6828ec01eba3c43f6d56ef0fe0b0ddfc5582a5 100644 --- a/test/recipes/75-test_quicapi_data/ssltraceref.txt +++ b/test/recipes/75-test_quicapi_data/ssltraceref.txt @@ -125,21 +125,21 @@ Received Packet Version: 0x00000001 Destination Conn Id: Source Conn Id: 0x???????????????? - Payload length: 213 - Packet Number: 0x00000001 + Payload length: 1042 + Packet Number: 0x00000000 Received Packet Packet Type: Handshake Version: 0x00000001 Destination Conn Id: Source Conn Id: 0x???????????????? - Payload length: 1042 - Packet Number: 0x00000000 -Received Frame: Crypto - Offset: 1022 - Len: 192 + Payload length: 213 + Packet Number: 0x00000001 Received Frame: Crypto Offset: 0 Len: 1022 +Received Frame: Crypto + Offset: 1022 + Len: 192 Received TLS Record Header: Version = TLS 1.2 (0x303) diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t index 385791610577e1a9a315769a034a25e4cf1996bb..0e1ebc50cd90485828917e25f92b2efb17a4a477 100644 --- a/test/recipes/80-test_cms.t +++ b/test/recipes/80-test_cms.t @@ -50,7 +50,7 @@ my ($no_des, $no_dh, $no_dsa, $no_ec, $no_ec2m, $no_rc2, $no_zlib) $no_rc2 = 1 if disabled("legacy"); -plan tests => 21; +plan tests => 22; ok(run(test(["pkcs7_test"])), "test pkcs7"); @@ -1154,3 +1154,14 @@ with({ exit_checker => sub { return shift == 3; } }, "issue#21986"); } }); + +# Test for problem reported in #22225 +with({ exit_checker => sub { return shift == 3; } }, + sub { + ok(run(app(['openssl', 'cms', '-encrypt', + '-in', srctop_file("test", "smcont.txt"), + '-aes-256-ctr', '-recip', + catfile($smdir, "smec1.pem"), + ])), + "Check for failure when cipher does not have an assigned OID (issue#22225)"); + }); diff --git a/test/recipes/80-test_pkcs12.t b/test/recipes/80-test_pkcs12.t index 06a90ec24b328bfcd2ad6540731ca148a96f4451..307942710f17445effc1d01e76edb24eb15b5bf2 100644 --- a/test/recipes/80-test_pkcs12.t +++ b/test/recipes/80-test_pkcs12.t @@ -172,9 +172,8 @@ ok(grep(/Trusted key usage (Oracle)/, @pkcs12info) == 0, # Test with Oracle Trusted Key Usage specified in openssl.cnf { - $ENV{OPENSSL_CONF} = srctop_file("test", "recipes", "80-test_pkcs12_data", "jdk_trusted.cnf"); ok(run(app(["openssl", "pkcs12", "-export", "-out", $outfile7, - "-in", srctop_file(@path, "ee-cert.pem"), + "-jdktrust", "anyExtendedKeyUsage", "-in", srctop_file(@path, "ee-cert.pem"), "-nokeys", "-passout", "pass:", "-certpbe", "NONE"])), "test nokeys single cert"); diff --git a/test/recipes/80-test_pkcs12_data/jdk_trusted.cnf b/test/recipes/80-test_pkcs12_data/jdk_trusted.cnf deleted file mode 100644 index 57d11fccf2ab018617f940eb26a79f031200bbbe..0000000000000000000000000000000000000000 --- a/test/recipes/80-test_pkcs12_data/jdk_trusted.cnf +++ /dev/null @@ -1,8 +0,0 @@ -# -[pkcs12] -certBagAttr = cb_attr - -# Uncomment this if you need Java compatible PKCS12 files -[cb_attr] -jdkTrustedKeyUsage = anyExtendedKeyUsage - diff --git a/test/recipes/90-test_quicfaults.t b/test/recipes/90-test_quicfaults.t index 7fa039a37060445523b07dd016520dc5aa07a407..710fdad86924dfd6f33f7b87763b43a55c75b587 100644 --- a/test/recipes/90-test_quicfaults.t +++ b/test/recipes/90-test_quicfaults.t @@ -20,6 +20,9 @@ use lib bldtop_dir('.'); plan skip_all => "QUIC protocol is not supported by this OpenSSL build" if disabled('quic'); +plan skip_all => "These tests are not supported in a fuzz build" + if config('options') =~ /-DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION|enable-fuzz-afl/; + plan tests => 2; ok(run(test(["quicfaultstest", srctop_dir("test", "certs")])), diff --git a/test/recipes/99-test_fuzz_quic_client.t b/test/recipes/99-test_fuzz_quic_client.t new file mode 100644 index 0000000000000000000000000000000000000000..a22d0d0c3221aa9353ff1e5acadceefd4b842247 --- /dev/null +++ b/test/recipes/99-test_fuzz_quic_client.t @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +# Copyright 2016-2020 The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the Apache License 2.0 (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html + +use strict; +use warnings; + +use OpenSSL::Test qw/:DEFAULT srctop_file/; +use OpenSSL::Test::Utils; + +my $fuzzer = "quic-client"; +setup("test_fuzz_${fuzzer}"); + +plan skip_all => "This test requires quic support" + if disabled("quic"); + +plan tests => 2; # one more due to below require_ok(...) + +require_ok(srctop_file('test','recipes','fuzz.pl')); + +fuzz_ok($fuzzer); diff --git a/test/rsa_test.c b/test/rsa_test.c index fe2087465f63a915b5a49195684cf3244b4d6e3e..2d9f6aa3a3f877124782ba1a11ab0faa4fe79377 100644 --- a/test/rsa_test.c +++ b/test/rsa_test.c @@ -391,6 +391,121 @@ err: return r; } +static int test_EVP_rsa_legacy_key(void) +{ + int ret; + size_t buflen = 384; + size_t msglen = 64; + unsigned char sigbuf[384]; + unsigned char msgbuf[64]; + BIGNUM *p; + BIGNUM *q; + BIGNUM *n; + BIGNUM *d; + BIGNUM *e; + RSA *rsa; + const EVP_MD *md; + EVP_MD_CTX *ctx = NULL; + EVP_PKEY *pkey = NULL; + + unsigned char n_data[] = { + 0x00, 0xc7, 0x28, 0x7a, 0x28, 0x91, 0x51, 0xa5, 0xe8, 0x3c, 0x45, 0xcf, + 0x1d, 0xa9, 0x69, 0x7a, 0x0d, 0xdb, 0xdd, 0x8f, 0xe2, 0xde, 0x85, 0xdd, + 0x85, 0x6d, 0x8f, 0x78, 0x20, 0xd6, 0xe, 0xe5, 0x06, 0xcb, 0x9c, 0xd6, + 0xd3, 0xca, 0xef, 0x1d, 0x80, 0xd3, 0x18, 0x23, 0x91, 0x5c, 0xe5, 0xc8, + 0x44, 0x37, 0x56, 0x1b, 0x68, 0x7f, 0x08, 0xa3, 0x1c, 0xf6, 0xe8, 0x11, + 0x38, 0x0f, 0x2e, 0xad, 0xb1, 0x89, 0x8b, 0x08, 0xe8, 0x35, 0xaf, 0x3b, + 0xfe, 0x37, 0x8d, 0x21, 0xd5, 0x3f, 0x1f, 0x4b, 0x01, 0x30, 0xd8, 0xd0, + 0x24, 0xf7, 0xab, 0x57, 0xad, 0xac, 0xbc, 0x53, 0x6d, 0x84, 0x8e, 0xa1, + 0xb2, 0x5b, 0x8e, 0xe7, 0xb3, 0xac, 0xfc, 0x60, 0x22, 0x10, 0x1e, 0x99, + 0xfa, 0xa0, 0x60, 0x00, 0x69, 0x5f, 0x8e, 0xca, 0x6d, 0x9c, 0xee, 0x5e, + 0x84, 0x4e, 0x53, 0x83, 0x42, 0x76, 0x4d, 0xb8, 0xc1, 0xeb, 0x4e, 0x3d, + 0xc3, 0xce, 0xac, 0x79, 0xbb, 0x29, 0x5d, 0x92, 0x33, 0x6e, 0xcf, 0x8f, + 0x5a, 0xf0, 0xb3, 0xb5, 0xdc, 0xd5, 0xa3, 0xaf, 0x40, 0x4b, 0x0f, 0x05, + 0xac, 0x46, 0x53, 0x2d, 0x5f, 0x20, 0x96, 0x42, 0xa8, 0x47, 0x61, 0x54, + 0x05, 0x2c, 0x8a, 0x26, 0x5d, 0x92, 0x1d, 0x01, 0x2a, 0x27, 0x8a, 0xfc, + 0x64, 0x24, 0x5c, 0x34, 0xde, 0x92, 0xc6, 0x82, 0xea, 0x4d, 0xe2, 0x52, + 0xe5, 0xad, 0x62, 0x00, 0xc6, 0xc8, 0xe9, 0x0c, 0x22, 0xf0, 0x9e, 0xbe, + 0xdc, 0x51, 0x58, 0xad, 0x3b, 0xba, 0x2e, 0x45, 0x65, 0xcc, 0x5b, 0x55, + 0x46, 0x67, 0x18, 0x4a, 0x80, 0x67, 0x5b, 0x84, 0x7f, 0x13, 0x37, 0x45, + 0xd8, 0x03, 0xc6, 0x22, 0xc3, 0x4a, 0x46, 0x6b, 0xde, 0x50, 0xbf, 0x16, + 0x0a, 0x23, 0x0b, 0xaa, 0x50, 0x54, 0xf6, 0x20, 0x83, 0x74, 0x33, 0x97, + 0x2e, 0xf2, 0x8e, 0x7e, 0x13 }; + + unsigned char e_data[] = { 0x01, 0x00, 0x01 }; + + unsigned char d_data[] = { + 0x09, 0x2d, 0xcb, 0xe7, 0x87, 0xbf, 0x10, 0x1a, 0xf2, 0x80, 0x33, 0x2a, + 0x06, 0x4f, 0x56, 0xb1, 0x41, 0xd3, 0x65, 0xd8, 0xca, 0x71, 0xb8, 0x02, + 0x78, 0xc8, 0xb6, 0x7c, 0x28, 0xf4, 0x6c, 0xe8, 0xd1, 0xc4, 0x92, 0x40, + 0x23, 0xa7, 0xbe, 0x9f, 0xdb, 0xda, 0xce, 0x74, 0xda, 0x27, 0xbb, 0x01, + 0xad, 0xdd, 0x39, 0x99, 0x28, 0xd5, 0xb0, 0x92, 0xda, 0xac, 0x5a, 0x72, + 0xcf, 0x7c, 0x52, 0xc4, 0x0e, 0x77, 0x4a, 0x7b, 0x4d, 0x52, 0x1c, 0xbd, + 0x3c, 0x39, 0x34, 0x78, 0x7c, 0x16, 0xc8, 0xa1, 0xae, 0xeb, 0x27, 0x38, + 0xb4, 0xf3, 0x80, 0x30, 0x80, 0x78, 0x13, 0x8e, 0x46, 0x20, 0x3e, 0xc2, + 0x96, 0x26, 0xb1, 0x76, 0x1e, 0x00, 0x69, 0xbb, 0xd8, 0x2b, 0x58, 0xe4, + 0x6c, 0xb4, 0xd0, 0x00, 0x0b, 0x47, 0xec, 0xfb, 0x7d, 0x52, 0x9d, 0x27, + 0x92, 0xe6, 0x95, 0x73, 0xa0, 0x39, 0x37, 0xcd, 0x1f, 0x60, 0x13, 0x1c, + 0x87, 0x9d, 0xa7, 0x91, 0x90, 0xf9, 0x36, 0xc5, 0xfa, 0x3f, 0xf9, 0x7f, + 0x50, 0xf8, 0xb3, 0x54, 0x65, 0xff, 0x6f, 0xa6, 0x22, 0xcc, 0x4a, 0x1e, + 0x49, 0x3f, 0x07, 0xc6, 0xf2, 0x65, 0x73, 0x13, 0x1b, 0x2d, 0xb6, 0x15, + 0xff, 0xcd, 0x9a, 0x1c, 0xea, 0xef, 0x58, 0x56, 0x91, 0x2d, 0x47, 0x81, + 0x56, 0x0d, 0xc3, 0xb0, 0x47, 0x58, 0x8d, 0x05, 0x7d, 0x5b, 0xc0, 0x22, + 0xa4, 0xf0, 0x2e, 0x70, 0x36, 0x01, 0x89, 0xa1, 0x71, 0xed, 0x76, 0xe9, + 0x8d, 0xf5, 0x49, 0xaf, 0x11, 0xbe, 0xe4, 0xd4, 0x48, 0x92, 0xb6, 0x5b, + 0xc2, 0x04, 0xd4, 0x0c, 0x5c, 0x8b, 0xe3, 0xfa, 0x29, 0x63, 0x86, 0xb4, + 0x10, 0xad, 0x32, 0x07, 0x85, 0xe2, 0x43, 0x76, 0x16, 0x90, 0xab, 0xdf, + 0xb3, 0x36, 0x0a, 0xc4, 0x49, 0x7b, 0x95, 0x48, 0x50, 0x72, 0x8f, 0x7d, + 0xf4, 0xfa, 0x60, 0xc1 }; + + unsigned char p_data[] = { + 0x00, 0xed, 0xf7, 0xa7, 0x00, 0x5a, 0xbb, 0xd1, 0x52, 0x65, 0x9b, 0xec, + 0xfe, 0x27, 0x8b, 0xe2, 0xbe, 0x40, 0x8c, 0x2f, 0x6f, 0xb4, 0x26, 0xb2, + 0xbe, 0x45, 0x4b, 0x3b, 0x5a, 0xaa, 0xc6, 0xaa, 0xfa, 0xc1, 0x3a, 0xa9, + 0xa1, 0xba, 0xb7, 0x86, 0x1a, 0x98, 0x15, 0x5f, 0x5c, 0x1c, 0x57, 0x78, + 0x78, 0x6a, 0x13, 0xc2, 0x40, 0x7d, 0x07, 0x87, 0x47, 0xc6, 0x96, 0xd5, + 0x92, 0xc9, 0x65, 0x2c, 0xfe, 0xbb, 0xe0, 0xd6, 0x76, 0x25, 0x5a, 0xa3, + 0xdf, 0x97, 0x4b, 0x64, 0xfd, 0x3b, 0x2b, 0xbc, 0xfb, 0x80, 0xad, 0x3b, + 0x7d, 0x1f, 0x48, 0x56, 0x27, 0xf7, 0x2f, 0x8e, 0x92, 0x07, 0xa8, 0x9f, + 0xbc, 0x5a, 0xce, 0xfa, 0xd5, 0x67, 0xad, 0xf4, 0xbf, 0xe0, 0xc9, 0x3e, + 0x8e, 0xb5, 0x90, 0x58, 0x54, 0x92, 0x9f, 0xda, 0x36, 0xc0, 0x0d, 0x57, + 0xfe, 0x6c, 0x23, 0x63, 0x8b, 0xd1, 0x1e, 0x4f, 0xd3 }; + + unsigned char q_data[] = { + 0x00, 0xd6, 0x3f, 0xf5, 0xee, 0xff, 0x4d, 0x7d, 0x8c, 0x1a, 0x85, 0x5d, + 0x3c, 0x4f, 0x9d, 0xdf, 0xc7, 0x68, 0x27, 0x7f, 0xe4, 0x4f, 0x4f, 0xd7, + 0xa2, 0x3b, 0xcd, 0x4a, 0x34, 0xd8, 0x55, 0x4a, 0x3e, 0x8e, 0xb3, 0xa8, + 0xe9, 0x8a, 0xc5, 0x94, 0xd1, 0x09, 0x32, 0x4b, 0x79, 0x8d, 0x7b, 0x03, + 0x0b, 0x5d, 0xca, 0x91, 0x41, 0xbc, 0x82, 0xc3, 0x89, 0x67, 0x4d, 0x03, + 0x68, 0x03, 0x2d, 0x0e, 0x4e, 0x97, 0x6c, 0xf6, 0x3e, 0x1f, 0xf4, 0x50, + 0x06, 0x5d, 0x05, 0x22, 0xf2, 0xf8, 0xf2, 0xde, 0xad, 0x2e, 0x9d, 0xc3, + 0x97, 0x1b, 0xc3, 0x75, 0xe7, 0x86, 0xde, 0xc5, 0x11, 0x89, 0xed, 0x6a, + 0x13, 0x14, 0x23, 0x4b, 0x98, 0x81, 0xf7, 0xd4, 0x1c, 0xee, 0x30, 0x92, + 0x85, 0x20, 0x4f, 0x35, 0x02, 0xfa, 0xda, 0x14, 0x77, 0xfa, 0x08, 0x34, + 0x60, 0xc7, 0x93, 0x72, 0xdc, 0xc4, 0x18, 0x70, 0xc1 }; + + memset(msgbuf, 0xef, 64); + + ret = (TEST_ptr((p = BN_bin2bn(p_data, sizeof(p_data), NULL))) + && TEST_ptr((q = BN_bin2bn(q_data, sizeof(q_data), NULL))) + && TEST_ptr((n = BN_bin2bn(n_data, sizeof(n_data), NULL))) + && TEST_ptr((d = BN_bin2bn(d_data, sizeof(d_data), NULL))) + && TEST_ptr((e = BN_bin2bn(e_data, sizeof(e_data), NULL))) + && TEST_ptr((rsa = RSA_new())) + && TEST_ptr((md = EVP_sha256())) + && TEST_ptr((ctx = EVP_MD_CTX_new())) + && TEST_ptr((pkey = EVP_PKEY_new())) + && TEST_true(RSA_set0_factors(rsa, p, q)) + && TEST_true(RSA_set0_key(rsa, n, e, d)) + && TEST_true(EVP_PKEY_assign_RSA(pkey, rsa)) + && TEST_true(EVP_DigestSignInit(ctx, NULL, md, NULL, pkey)) + && TEST_true(EVP_DigestSign(ctx, sigbuf, &buflen, msgbuf, msglen))); + + EVP_MD_CTX_free(ctx); + EVP_PKEY_free(pkey); + return ret; +} + static RSA *load_key(int priv) { RSA *rsa = NULL; @@ -600,5 +715,6 @@ int setup_tests(void) ADD_ALL_TESTS(test_rsa_oaep, 3); ADD_ALL_TESTS(test_rsa_security_bit, OSSL_NELEM(rsa_security_bits_cases)); ADD_TEST(test_rsa_saos); + ADD_TEST(test_EVP_rsa_legacy_key); return 1; } diff --git a/test/sslapitest.c b/test/sslapitest.c index 9539b4cf3a658ac477b418fbe479974b30580cc5..2fbe76f97980368e2f510fb102dc32595ed15c84 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -11138,6 +11138,102 @@ end: return testresult; } +/* + * Test that receiving retries when writing application data works as expected + */ +static int test_data_retry(void) +{ + SSL_CTX *cctx = NULL, *sctx = NULL; + SSL *clientssl = NULL, *serverssl = NULL; + int testresult = 0; + unsigned char inbuf[1200], outbuf[1200]; + size_t i; + BIO *tmp = NULL; + BIO *bretry = BIO_new(bio_s_maybe_retry()); + size_t written, readbytes, totread = 0; + + if (!TEST_ptr(bretry)) + goto end; + + for (i = 0; i < sizeof(inbuf); i++) + inbuf[i] = i; + memset(outbuf, 0, sizeof(outbuf)); + + if (!TEST_true(create_ssl_ctx_pair(libctx, TLS_server_method(), + TLS_client_method(), 0, 0, &sctx, &cctx, + cert, privkey))) + goto end; + + if (!TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, NULL, + NULL))) + goto end; + + if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) + goto end; + + /* Smallest possible max send fragment is 512 */ + if (!TEST_true(SSL_set_max_send_fragment(clientssl, 512))) + goto end; + + tmp = SSL_get_wbio(clientssl); + if (!TEST_ptr(tmp)) + goto end; + if (!TEST_true(BIO_up_ref(tmp))) + goto end; + BIO_push(bretry, tmp); + tmp = NULL; + SSL_set0_wbio(clientssl, bretry); + if (!BIO_up_ref(bretry)) { + bretry = NULL; + goto end; + } + + for (i = 0; i < 3; i++) { + /* We expect this call to make no progress and indicate retry */ + if (!TEST_false(SSL_write_ex(clientssl, inbuf, sizeof(inbuf), &written))) + goto end; + if (!TEST_int_eq(SSL_get_error(clientssl, 0), SSL_ERROR_WANT_WRITE)) + goto end; + + /* Allow one write to progess, but the next one to signal retry */ + if (!TEST_true(BIO_ctrl(bretry, MAYBE_RETRY_CTRL_SET_RETRY_AFTER_CNT, 1, + NULL))) + goto end; + + if (i == 2) + break; + + /* + * This call will hopefully make progress but will still indicate retry + * because there is more data than will fit into a single record. + */ + if (!TEST_false(SSL_write_ex(clientssl, inbuf, sizeof(inbuf), &written))) + goto end; + if (!TEST_int_eq(SSL_get_error(clientssl, 0), SSL_ERROR_WANT_WRITE)) + goto end; + } + + /* The final call should write the last chunk of data and succeed */ + if (!TEST_true(SSL_write_ex(clientssl, inbuf, sizeof(inbuf), &written))) + goto end; + /* Read all the data available */ + while (SSL_read_ex(serverssl, outbuf + totread, sizeof(outbuf) - totread, + &readbytes)) + totread += readbytes; + if (!TEST_mem_eq(inbuf, sizeof(inbuf), outbuf, totread)) + goto end; + + testresult = 1; +end: + SSL_free(serverssl); + SSL_free(clientssl); + SSL_CTX_free(sctx); + SSL_CTX_free(cctx); + BIO_free_all(bretry); + BIO_free(tmp); + return testresult; +} + OPT_TEST_DECLARE_USAGE("certfile privkeyfile srpvfile tmpfile provider config dhfile\n") int setup_tests(void) @@ -11444,6 +11540,7 @@ int setup_tests(void) ADD_ALL_TESTS(test_version, 6); ADD_TEST(test_rstate_string); ADD_ALL_TESTS(test_handshake_retry, 16); + ADD_TEST(test_data_retry); return 1; err: @@ -11473,6 +11570,7 @@ void cleanup_tests(void) OPENSSL_free(privkey8192); bio_s_mempacket_test_free(); bio_s_always_retry_free(); + bio_s_maybe_retry_free(); OSSL_PROVIDER_unload(defctxnull); OSSL_LIB_CTX_free(libctx); } diff --git a/test/time_test.c b/test/time_test.c new file mode 100644 index 0000000000000000000000000000000000000000..62f911f61cbc1b1d2b73e4e3af0b284ec1da003e --- /dev/null +++ b/test/time_test.c @@ -0,0 +1,79 @@ +/* + * Copyright 2023 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the Apache License 2.0 (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include "testutil.h" +#include "internal/time.h" + +static int test_time_to_timeval(void) +{ + OSSL_TIME a; + struct timeval tv; + + a = ossl_time_zero(); + + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 0) || !TEST_long_eq(tv.tv_usec, 0)) + return 0; + + /* Test that zero round trips */ + if (!TEST_true(ossl_time_is_zero(ossl_time_from_timeval(tv)))) + return 0; + + /* We should round up nano secs to the next usec */ + a = ossl_ticks2time(1); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 0) || !TEST_long_eq(tv.tv_usec, 1)) + return 0; + a = ossl_ticks2time(999); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 0) || !TEST_long_eq(tv.tv_usec, 1)) + return 0; + a = ossl_ticks2time(1000); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 0) || !TEST_long_eq(tv.tv_usec, 1)) + return 0; + a = ossl_ticks2time(1001); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 0) || !TEST_long_eq(tv.tv_usec, 2)) + return 0; + a = ossl_ticks2time(999000); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 0) || !TEST_long_eq(tv.tv_usec, 999)) + return 0; + a = ossl_ticks2time(999999001); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 1) || !TEST_long_eq(tv.tv_usec, 0)) + return 0; + a = ossl_ticks2time(999999999); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 1) || !TEST_long_eq(tv.tv_usec, 0)) + return 0; + a = ossl_ticks2time(1000000000); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 1) || !TEST_long_eq(tv.tv_usec, 0)) + return 0; + a = ossl_ticks2time(1000000001); + tv = ossl_time_to_timeval(a); + if (!TEST_long_eq(tv.tv_sec, 1) || !TEST_long_eq(tv.tv_usec, 1)) + return 0; + + /* + * Note that we don't currently support infinity round tripping. Instead + * callers need to explicitly test for infinity. + */ + + return 1; +} + +int setup_tests(void) +{ + ADD_TEST(test_time_to_timeval); + + return 1; +} diff --git a/util/markdownlint.rb b/util/markdownlint.rb index 3833a252ef3c3ccf3e215febae453f4348d4a121..2179f15999b5bc1fa99ff9f04157a2452f12274d 100644 --- a/util/markdownlint.rb +++ b/util/markdownlint.rb @@ -8,12 +8,14 @@ rule 'MD003', :style => :setext_with_atx # Code blocks may be fenced or indented, both are OK... # but they must be consistent throughout each file. rule 'MD046', :style => :consistent -# Not possible to line-break tables. -rule 'MD013', :tables => false # Bug in mdl, https://github.com/markdownlint/markdownlint/issues/313 exclude_rule 'MD007' +# Not possible to line-break tables (:tables => false) +# Not possible to line-break headers (currently cannot be selectively exempted) +exclude_rule 'MD013' + exclude_rule 'MD004' # Unordered list style TODO(fix?) exclude_rule 'MD005' # Inconsistent indentation for list items at the same level exclude_rule 'MD006' # Consider starting bulleted lists at the beginning of the line