diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 165f435c69542418b66368eb5452ff65acc319be..c125b0684f79bb8297d84b8a53d8acec9c321c2a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ permissions: jobs: check_update: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - name: install unifdef run: | @@ -42,7 +42,7 @@ jobs: run: git diff --exit-code check_docs: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: config @@ -62,7 +62,7 @@ jobs: # We are not as strict with libraries, but rather adapt to what's # expected to be available in a certain version of each platform. check-ansi: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: config @@ -71,7 +71,7 @@ jobs: run: make -s -j4 basic_gcc: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -91,7 +91,7 @@ jobs: run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} basic_clang: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -127,7 +127,7 @@ jobs: run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} minimal: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -144,7 +144,7 @@ jobs: run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} no-deprecated: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -160,11 +160,8 @@ jobs: - name: make test run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} - no-shared: - strategy: - matrix: - os: [ ubuntu-latest, macos-latest ] - runs-on: ${{matrix.os}} + no-shared-ubuntu: + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -174,12 +171,32 @@ jobs: - name: make run: make -s -j4 - name: get cpu info - run: ./util/opensslwrap.sh version -c + run: | + cat /proc/cpuinfo + ./util/opensslwrap.sh version -c + - name: make test + run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} + + no-shared-macos: + runs-on: macos-latest + if: github.server_url == 'https://github.com' + 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 --strict-warnings no-shared no-fips && perl configdata.pm --dump + - name: make + run: make -s -j4 + - name: get cpu info + run: | + sysctl machdep.cpu + ./util/opensslwrap.sh version -c - name: make test run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} non-caching: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -196,7 +213,7 @@ jobs: run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} OPENSSL_TEST_RAND_ORDER=0 TESTS="-test_fuzz* -test_ssl_* -test_sslapi -test_evp -test_cmp_http -test_verify -test_cms -test_store -test_enc -[01][0-9]" address_ub_sanitizer: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -213,7 +230,7 @@ jobs: run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} OPENSSL_TEST_RAND_ORDER=0 fuzz_tests: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -230,7 +247,7 @@ jobs: run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} OPENSSL_TEST_RAND_ORDER=0 TESTS="test_fuzz*" memory_sanitizer: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -248,7 +265,7 @@ jobs: run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} OPENSSL_TEST_RAND_ORDER=0 threads_sanitizer: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -265,7 +282,7 @@ jobs: run: make V=1 TESTS="test_threads test_internal_provider test_provfetch test_provider test_pbe test_evp_kdf test_pkcs12 test_store test_evp test_quic*" test HARNESS_JOBS=${HARNESS_JOBS:-4} enable_non-default_options: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -284,7 +301,7 @@ jobs: run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} full_featured: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -309,7 +326,7 @@ jobs: run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} no-legacy: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -326,7 +343,7 @@ jobs: run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} legacy: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -347,11 +364,8 @@ jobs: # build tree # - That building, testing and installing works with a read-only source # tree - out-of-readonly-source-and-install: - strategy: - matrix: - os: [ubuntu-latest, macos-latest ] - runs-on: ${{matrix.os}} + out-of-readonly-source-and-install-ubuntu: + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 with: @@ -374,7 +388,45 @@ jobs: run: make -s -j4 working-directory: ./build - name: get cpu info - run: ./util/opensslwrap.sh version -c + run: | + cat /proc/cpuinfo + ./util/opensslwrap.sh version -c + working-directory: ./build + - name: make test + run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} + working-directory: ./build + - name: make install + run: make install + working-directory: ./build + + out-of-readonly-source-and-install-macos: + runs-on: macos-latest + if: github.server_url == 'https://github.com' + steps: + - uses: actions/checkout@v4 + with: + path: ./source + - name: checkout fuzz/corpora submodule + run: git submodule update --init --depth 1 fuzz/corpora + working-directory: ./source + - name: make source read-only + run: chmod -R a-w ./source + - name: create build and install directories + run: | + mkdir ./build + mkdir ./install + - name: config + run: | + ../source/config --banner=Configured enable-fips enable-quic enable-acvp-tests --strict-warnings --prefix=$(cd ../install; pwd) + perl configdata.pm --dump + working-directory: ./build + - name: make + run: make -s -j4 + working-directory: ./build + - name: get cpu info + run: | + sysctl machdep.cpu + ./util/opensslwrap.sh version -c working-directory: ./build - name: make test run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} @@ -384,7 +436,7 @@ jobs: working-directory: ./build external-tests: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 with: @@ -417,7 +469,7 @@ jobs: run: make test TESTS="test_external_oqsprovider" external-test-pyca: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} strategy: matrix: RUST: @@ -433,7 +485,7 @@ jobs: - name: make run: make -s -j4 - name: Setup Python - uses: actions/setup-python@v4.7.1 + uses: actions/setup-python@v5.0.0 with: python-version: ${{ matrix.PYTHON }} - uses: actions-rs/toolchain@v1 @@ -450,7 +502,7 @@ jobs: run: make test TESTS="test_external_pyca" VERBOSE=1 external-test-cf-quiche: - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/cross-compiles.yml b/.github/workflows/cross-compiles.yml index 21683b731dffd3d61907df5af201d604c1a92080..c3dd90cab9a0af7885df03e1e6f241404cdb0c63 100644 --- a/.github/workflows/cross-compiles.yml +++ b/.github/workflows/cross-compiles.yml @@ -148,7 +148,7 @@ jobs: tests: none } ] - runs-on: ubuntu-latest + runs-on: ${{ github.server_url == 'https://github.com' && 'ubuntu-latest' || 'ubuntu-22.04-self-hosted' }} steps: - name: install package repository if: matrix.platform.ppa != '' diff --git a/.github/workflows/fips-checksums.yml b/.github/workflows/fips-checksums.yml index 9b0bec2a78f1335eb0b743737c6f0afb5fcb2c5a..bbf135fd77ac9f7d3a5b08bdd4839d6e0f223530 100644 --- a/.github/workflows/fips-checksums.yml +++ b/.github/workflows/fips-checksums.yml @@ -69,7 +69,7 @@ jobs: - name: save PR number run: echo ${{ github.event.number }} > ./artifact/pr_num - name: save artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: fips_checksum path: artifact/ @@ -113,7 +113,7 @@ jobs: - name: save PR number run: echo ${{ github.event.number }} > ./artifact/pr_num - name: save artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: abidiff path: artifact/ diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8ff02cee2757eb128df60965f04a1a2cb7c2ca5f..e167416be561b6adfb713a40ed74b3dea5d66348 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -26,7 +26,7 @@ jobs: fuzz-seconds: 600 dry-run: false - name: Upload Crash - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: artifacts diff --git a/.github/workflows/provider-compatibility.yml b/.github/workflows/provider-compatibility.yml index 8fc125cbd83e5c07330b9f44f442d19ab70a79d9..afb2782690bc93bc48241282957b66a3bc4860c9 100644 --- a/.github/workflows/provider-compatibility.yml +++ b/.github/workflows/provider-compatibility.yml @@ -93,7 +93,7 @@ jobs: -providers working-directory: ${{ matrix.release.dir }} - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: ${{ matrix.release.tgz }} path: ${{ matrix.release.tgz }} @@ -169,7 +169,7 @@ jobs: run: make test HARNESS_JOBS=${HARNESS_JOBS:-4} working-directory: ${{ matrix.branch.dir }} - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: name: ${{ matrix.branch.tgz }} path: ${{ matrix.branch.tgz }} @@ -201,7 +201,7 @@ jobs: fi continue-on-error: true - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 if: steps.early_exit.outcome == 'success' with: name: ${{ matrix.tree_a }}.tar.gz @@ -209,7 +209,7 @@ jobs: if: steps.early_exit.outcome == 'success' run: tar xzf "${{ matrix.tree_a }}.tar.gz" - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 if: steps.early_exit.outcome == 'success' with: name: ${{ matrix.tree_b }}.tar.gz diff --git a/.github/workflows/run-checker-daily.yml b/.github/workflows/run-checker-daily.yml index 157746f39ff57d910167633e010beccee66e725b..eda5005f68f9e577be377d83a0f40833a10cad54 100644 --- a/.github/workflows/run-checker-daily.yml +++ b/.github/workflows/run-checker-daily.yml @@ -130,7 +130,8 @@ jobs: no-zlib, enable-zlib-dynamic, no-zlib-dynamic, - -DOPENSSL_NO_BUILTIN_OVERFLOW_CHECKING + -DOPENSSL_NO_BUILTIN_OVERFLOW_CHECKING, + -DSSL3_ALIGN_PAYLOAD=4 ] runs-on: ubuntu-latest steps: diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 0d0f24c299b8b24edfca37f8d079b2949d549f10..792190bb083817a1cc698f5cb7bf42c647f30fe4 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -25,7 +25,7 @@ jobs: config: enable-fips - arch: win32 config: --strict-warnings no-fips - runs-on: ${{matrix.os}} + runs-on: ${{ github.server_url == 'https://github.com' && matrix.os || format('{0}-self-hosted', matrix.os) }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -77,7 +77,7 @@ jobs: os: - windows-2019 - windows-2022 - runs-on: ${{matrix.os}} + runs-on: ${{ github.server_url == 'https://github.com' && matrix.os || format('{0}-self-hosted', matrix.os) }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -114,7 +114,7 @@ jobs: os: - windows-2019 - windows-2022 - runs-on: ${{matrix.os}} + runs-on: ${{ github.server_url == 'https://github.com' && matrix.os || format('{0}-self-hosted', matrix.os) }} steps: - uses: actions/checkout@v4 - name: checkout fuzz/corpora submodule @@ -159,7 +159,7 @@ jobs: # are we really learning sth new from win32? So let's save some CO2 for now disabling this # - arch: win32 # config: -DCMAKE_C_COMPILER=gcc --strict-warnings no-fips - runs-on: ${{matrix.os}} + runs-on: ${{ github.server_url == 'https://github.com' && matrix.os || format('{0}-self-hosted', matrix.os) }} env: CYGWIN_NOWINPATH: 1 SHELLOPTS: igncr diff --git a/CHANGES.md b/CHANGES.md index 93365619fa8f8f3f3f379fbeb31e03d732a50aae..271af0389418e0ad8a35fb1417f3435d67a65929 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -28,11 +28,25 @@ OpenSSL 3.3 ### Changes between 3.2 and 3.3 [xx XXX xxxx] + * The activate configuration setting for providers in openssl.cnf has been + updated to require a value of [1|yes|true|on] (in lower or UPPER case) to + activate the provider. Conversely a setting [0|no|false|off] will prevent + provider activation. All other values, or the omission of a value for this + setting will result in an error. + + *Neil Horman* + * In `openssl speed`, changed the default hash function used with `hmac` from `md5` to `sha256`. *James Muir* + * Added several new features of CMPv3 defined in RFC 9480 and RFC 9483: + - `certProfile` request message header and respective `-profile` CLI option + - support for delayed delivery of all types of response messages + + *David von Oheimb* + * The build of exporters (such as `.pc` files for pkg-config) cleaned up to be less hard coded in the build file templates, and to allow easier addition of more exporters. With that, an exporter for CMake is also diff --git a/Configurations/10-main.conf b/Configurations/10-main.conf index d1a15a1152747b4197d8cd7ff00bd4a30e60eaaa..7fb0fda8666694a5aab8ed720431444725766455 100644 --- a/Configurations/10-main.conf +++ b/Configurations/10-main.conf @@ -821,12 +821,13 @@ my %targets = ( asm_arch => 'riscv32', }, - # loongarch64 below refers to contemporary LOONGARCH Architecture + # loongarch64 below refers to contemporary LoongArch Architecture # specifications, "linux64-loongarch64" => { inherit_from => [ "linux-generic64"], perlasm_scheme => "linux64", asm_arch => 'loongarch64', + lib_cppflags => add("-DL_ENDIAN"), }, #### IA-32 targets... diff --git a/apps/cmp.c b/apps/cmp.c index dd5a69af7c35b1593756461fc847a2d7eadb3740..e0b03c3cb594b4a99ee6155f0b5983663ad27829 100644 --- a/apps/cmp.c +++ b/apps/cmp.c @@ -112,6 +112,7 @@ static int opt_cmd = -1; static char *opt_geninfo = NULL; static char *opt_infotype_s = NULL; static int opt_infotype = NID_undef; +static char *opt_profile = NULL; /* certificate enrollment */ static char *opt_newkey = NULL; @@ -210,7 +211,7 @@ typedef enum OPTION_choice { OPT_COMMON, OPT_CONFIG, OPT_SECTION, OPT_VERBOSITY, - OPT_CMD, OPT_INFOTYPE, OPT_GENINFO, + OPT_CMD, OPT_INFOTYPE, OPT_PROFILE, OPT_GENINFO, OPT_NEWKEY, OPT_NEWKEYPASS, OPT_SUBJECT, OPT_DAYS, OPT_REQEXTS, @@ -291,10 +292,12 @@ const OPTIONS cmp_options[] = { "InfoType name for requesting specific info in genm, with specific support"}, {OPT_MORE_STR, 0, 0, "for 'caCerts' and 'rootCaCert'"}, + {"profile", OPT_PROFILE, 's', + "Certificate profile name to place in generalInfo field of request PKIHeader"}, {"geninfo", OPT_GENINFO, 's', - "generalInfo integer values to place in request PKIHeader with given OID"}, + "Comma-separated list of OID and value to place in generalInfo PKIHeader"}, {OPT_MORE_STR, 0, 0, - "specified in the form :int:, e.g. \"1.2.3.4:int:56789\""}, + "of form :int: or :str:, e.g. \'1.2.3.4:int:56789, id-kp:str:name'"}, OPT_SECTION("Certificate enrollment"), {"newkey", OPT_NEWKEY, 's', @@ -587,7 +590,7 @@ typedef union { static varref cmp_vars[] = { /* must be in same order as enumerated above! */ {&opt_config}, {&opt_section}, {(char **)&opt_verbosity}, - {&opt_cmd_s}, {&opt_infotype_s}, {&opt_geninfo}, + {&opt_cmd_s}, {&opt_infotype_s}, {&opt_profile}, {&opt_geninfo}, {&opt_newkey}, {&opt_newkeypass}, {&opt_subject}, {(char **)&opt_days}, {&opt_reqexts}, @@ -1791,9 +1794,11 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) char *next = next_item(opt_policy_oids); if ((policy = OBJ_txt2obj(opt_policy_oids, 1)) == 0) { - CMP_err1("unknown policy OID '%s'", opt_policy_oids); + CMP_err1("Invalid -policy_oids arg '%s'", opt_policy_oids); return 0; } + if (OBJ_obj2nid(policy) == NID_undef) + CMP_warn1("Unknown -policy_oids arg: %.40s", opt_policy_oids); if ((pinfo = POLICYINFO_new()) == NULL) { ASN1_OBJECT_free(policy); @@ -1837,64 +1842,127 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) return 0; } -static int handle_opt_geninfo(OSSL_CMP_CTX *ctx) +static int add_certProfile(OSSL_CMP_CTX *ctx, const char *name) { - long value; - ASN1_OBJECT *type; - ASN1_INTEGER *aint; - ASN1_TYPE *val; - OSSL_CMP_ITAV *itav; - char *endstr; - char *valptr = strchr(opt_geninfo, ':'); + OSSL_CMP_ITAV *itav = NULL; + STACK_OF(ASN1_UTF8STRING) *sk; + ASN1_UTF8STRING *utf8string; - if (valptr == NULL) { - CMP_err("missing ':' in -geninfo option"); + if (ctx == NULL || name == NULL) return 0; - } - valptr[0] = '\0'; - valptr++; - if (!CHECK_AND_SKIP_CASE_PREFIX(valptr, "int:")) { - CMP_err("missing 'int:' in -geninfo option"); + if ((sk = sk_ASN1_UTF8STRING_new_reserve(NULL, 1)) == NULL) return 0; - } + if ((utf8string = ASN1_UTF8STRING_new()) == NULL) + goto err; + if (!ASN1_STRING_set(utf8string, name, (int)strlen(name))) { + ASN1_STRING_free(utf8string); + goto err; + } + /* Due to sk_ASN1_UTF8STRING_new_reserve(NULL, 1), this surely succeeds: */ + (void)sk_ASN1_UTF8STRING_push(sk, utf8string); + if ((itav = OSSL_CMP_ITAV_new0_certProfile(sk)) == NULL) + goto err; + if (OSSL_CMP_CTX_push0_geninfo_ITAV(ctx, itav)) + return 1; + OSSL_CMP_ITAV_free(itav); + return 0; - value = strtol(valptr, &endstr, 10); - if (endstr == valptr || *endstr != '\0') { - CMP_err("cannot parse int in -geninfo option"); - return 0; - } + err: + sk_ASN1_UTF8STRING_pop_free(sk, ASN1_UTF8STRING_free); + return 0; +} - type = OBJ_txt2obj(opt_geninfo, 1); - if (type == NULL) { - CMP_err("cannot parse OID in -geninfo option"); - return 0; - } +static int handle_opt_geninfo(OSSL_CMP_CTX *ctx) +{ + ASN1_OBJECT *obj = NULL; + ASN1_TYPE *type = NULL; + long value; + ASN1_INTEGER *aint = NULL; + ASN1_UTF8STRING *text = NULL; + OSSL_CMP_ITAV *itav; + char *ptr = opt_geninfo, *oid, *end; + + do { + while (isspace(_UC(*ptr))) + ptr++; + oid = ptr; + if ((ptr = strchr(oid, ':')) == NULL) { + CMP_err1("Missing ':' in -geninfo arg %.40s", oid); + return 0; + } + *ptr++ = '\0'; + if ((obj = OBJ_txt2obj(oid, 0)) == NULL) { + CMP_err1("Invalid OID in -geninfo arg %.40s", oid); + return 0; + } + if (OBJ_obj2nid(obj) == NID_undef) + CMP_warn1("Unknown OID in -geninfo arg: %.40s", oid); + if ((type = ASN1_TYPE_new()) == NULL) + goto oom; - if ((aint = ASN1_INTEGER_new()) == NULL) - goto oom; + if (CHECK_AND_SKIP_CASE_PREFIX(ptr, "int:")) { + value = strtol(ptr, &end, 10); + if (end == ptr) { + CMP_err1("Cannot parse int in -geninfo arg %.40s", ptr); + goto err; + } + ptr = end; + if (*ptr != '\0') { + if (*ptr != ',') { + CMP_err1("Missing ',' or end of -geninfo arg after int at %.40s", + ptr); + goto err; + } + ptr++; + } - val = ASN1_TYPE_new(); - if (!ASN1_INTEGER_set(aint, value) || val == NULL) { - ASN1_INTEGER_free(aint); - goto oom; - } - ASN1_TYPE_set(val, V_ASN1_INTEGER, aint); - itav = OSSL_CMP_ITAV_create(type, val); - if (itav == NULL) { - ASN1_TYPE_free(val); - goto oom; - } + if ((aint = ASN1_INTEGER_new()) == NULL + || !ASN1_INTEGER_set(aint, value)) + goto oom; + ASN1_TYPE_set(type, V_ASN1_INTEGER, aint); + aint = NULL; + + } else if (CHECK_AND_SKIP_CASE_PREFIX(ptr, "str:")) { + end = strchr(ptr, ','); + if (end == NULL) + end = ptr + strlen(ptr); + else + *end++ = '\0'; + if ((text = ASN1_UTF8STRING_new()) == NULL + || !ASN1_STRING_set(text, ptr, -1)) + goto oom; + ptr = end; + ASN1_TYPE_set(type, V_ASN1_UTF8STRING, text); + text = NULL; - if (!OSSL_CMP_CTX_push0_geninfo_ITAV(ctx, itav)) { - OSSL_CMP_ITAV_free(itav); - return 0; - } + } else { + CMP_err1("Missing 'int:' or 'str:' in -geninfo arg %.40s", ptr); + goto err; + } + + if ((itav = OSSL_CMP_ITAV_create(obj, type)) == NULL) { + CMP_err("Unable to create 'OSSL_CMP_ITAV' structure"); + goto err; + } + obj = NULL; + type = NULL; + + if (!OSSL_CMP_CTX_push0_geninfo_ITAV(ctx, itav)) { + CMP_err("Failed to add ITAV for geninfo of the PKI message header"); + OSSL_CMP_ITAV_free(itav); + return 0; + } + } while (*ptr != '\0'); return 1; oom: - ASN1_OBJECT_free(type); CMP_err("out of memory"); + err: + ASN1_OBJECT_free(obj); + ASN1_TYPE_free(type); + ASN1_INTEGER_free(aint); + ASN1_UTF8STRING_free(text); return 0; } @@ -2078,6 +2146,8 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) if (opt_geninfo != NULL && !handle_opt_geninfo(ctx)) goto err; + if (opt_profile != NULL && !add_certProfile(ctx, opt_profile)) + goto err; /* not printing earlier, to minimize confusion in case setup fails before */ if (opt_rspin != NULL) @@ -2603,6 +2673,9 @@ static int get_opts(int argc, char **argv) case OPT_INFOTYPE: opt_infotype_s = opt_str(); break; + case OPT_PROFILE: + opt_profile = opt_str(); + break; case OPT_GENINFO: opt_geninfo = opt_str(); break; @@ -3108,6 +3181,10 @@ int cmp_main(int argc, char **argv) } (void)BIO_flush(bio_err); /* prevent interference with opt_help() */ + cmp_ctx = OSSL_CMP_CTX_new(app_get0_libctx(), app_get0_propq()); + if (cmp_ctx == NULL) + goto err; + ret = get_opts(argc, argv); if (ret <= 0) goto err; @@ -3128,9 +3205,6 @@ int cmp_main(int argc, char **argv) } } - cmp_ctx = OSSL_CMP_CTX_new(app_get0_libctx(), app_get0_propq()); - if (cmp_ctx == NULL) - goto err; OSSL_CMP_CTX_set_log_verbosity(cmp_ctx, opt_verbosity); if (!OSSL_CMP_CTX_set_log_cb(cmp_ctx, print_to_bio_out)) { CMP_err1("cannot set up error reporting and logging for %s", prog); diff --git a/apps/lib/cmp_mock_srv.c b/apps/lib/cmp_mock_srv.c index a0450446c1ca631cbe25d8879374a1dfb91ea441..5fed3a9fd07a190baab70ed86dc0024c67e38615 100644 --- a/apps/lib/cmp_mock_srv.c +++ b/apps/lib/cmp_mock_srv.c @@ -27,7 +27,7 @@ typedef struct X509 *oldWithNew; /* to return in oldWithNew of rootKeyUpdate */ OSSL_CMP_PKISI *statusOut; /* status for ip/cp/kup/rp msg unless polling */ int sendError; /* send error response on given request type */ - OSSL_CMP_MSG *certReq; /* ir/cr/p10cr/kur remembered while polling */ + OSSL_CMP_MSG *req; /* original request message during polling */ int pollCount; /* number of polls before actual cert response */ int curr_pollCount; /* number of polls so far for current request */ int checkAfterTime; /* time the client should wait between polling */ @@ -43,7 +43,7 @@ static void mock_srv_ctx_free(mock_srv_ctx *ctx) X509_free(ctx->certOut); OSSL_STACK_OF_X509_free(ctx->chainOut); OSSL_STACK_OF_X509_free(ctx->caPubsOut); - OSSL_CMP_MSG_free(ctx->certReq); + OSSL_CMP_MSG_free(ctx->req); OPENSSL_free(ctx); } @@ -183,6 +183,38 @@ int ossl_cmp_mock_srv_set_checkAfterTime(OSSL_CMP_SRV_CTX *srv_ctx, int sec) return 1; } +/* determine whether to delay response to (non-polling) request */ +static int delayed_delivery(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *req) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + int req_type = OSSL_CMP_MSG_get_bodytype(req); + + if (ctx == NULL || req == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return -1; + } + + /* + * For ir/cr/p10cr/kur delayed delivery is handled separately in + * process_cert_request + */ + if (req_type == OSSL_CMP_IR + || req_type == OSSL_CMP_CR + || req_type == OSSL_CMP_P10CR + || req_type == OSSL_CMP_KUR + /* Client may use error to abort the ongoing polling */ + || req_type == OSSL_CMP_ERROR) + return 0; + + if (ctx->pollCount > 0 && ctx->curr_pollCount == 0) { + /* start polling */ + if ((ctx->req = OSSL_CMP_MSG_dup(req)) == NULL) + return -1; + return 1; + } + return 0; +} + /* check for matching reference cert components, as far as given */ static int refcert_cmp(const X509 *refcert, const X509_NAME *issuer, const ASN1_INTEGER *serial) @@ -198,6 +230,23 @@ static int refcert_cmp(const X509 *refcert, && (ref_serial == NULL || ASN1_INTEGER_cmp(serial, ref_serial) == 0); } +/* reset the state that belongs to a transaction */ +static int clean_transaction(OSSL_CMP_SRV_CTX *srv_ctx, + ossl_unused const ASN1_OCTET_STRING *id) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + + ctx->curr_pollCount = 0; + OSSL_CMP_MSG_free(ctx->req); + ctx->req = NULL; + return 1; +} + static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *cert_req, ossl_unused int certReqId, @@ -228,12 +277,7 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, if (ctx->pollCount > 0 && ctx->curr_pollCount == 0) { /* start polling */ - if (ctx->certReq != NULL) { - /* already in polling mode */ - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - return NULL; - } - if ((ctx->certReq = OSSL_CMP_MSG_dup(cert_req)) == NULL) + if ((ctx->req = OSSL_CMP_MSG_dup(cert_req)) == NULL) return NULL; return OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_waiting, 0, NULL); } @@ -241,6 +285,42 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, /* give final response after polling */ ctx->curr_pollCount = 0; + /* accept cert profile for cr messages only with the configured name */ + if (OSSL_CMP_MSG_get_bodytype(cert_req) == OSSL_CMP_CR) { + STACK_OF(OSSL_CMP_ITAV) *itavs = + OSSL_CMP_HDR_get0_geninfo_ITAVs(OSSL_CMP_MSG_get0_header(cert_req)); + int i; + + for (i = 0; i < sk_OSSL_CMP_ITAV_num(itavs); i++) { + OSSL_CMP_ITAV *itav = sk_OSSL_CMP_ITAV_value(itavs, i); + ASN1_OBJECT *obj = OSSL_CMP_ITAV_get0_type(itav); + STACK_OF(ASN1_UTF8STRING) *strs; + ASN1_UTF8STRING *str; + const char *data; + + if (OBJ_obj2nid(obj) == NID_id_it_certProfile) { + if (!OSSL_CMP_ITAV_get0_certProfile(itav, &strs)) + return NULL; + if (sk_ASN1_UTF8STRING_num(strs) < 1) { + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_CERTPROFILE); + return NULL; + } + str = sk_ASN1_UTF8STRING_value(strs, 0); + if (str == NULL + || (data = + (const char *)ASN1_STRING_get0_data(str)) == NULL) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return NULL; + } + if (strcmp(data, "profile1") != 0) { + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_CERTPROFILE); + return NULL; + } + break; + } + } + } + /* accept cert update request only for the reference cert, if given */ if (bodytype == OSSL_CMP_KUR && crm != NULL /* thus not p10cr */ && ctx->refCert != NULL) { @@ -442,38 +522,38 @@ static int process_certConf(OSSL_CMP_SRV_CTX *srv_ctx, return 1; } +/* return 0 on failure, 1 on success, setting *req or otherwise *check_after */ static int process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *pollReq, ossl_unused int certReqId, - OSSL_CMP_MSG **certReq, int64_t *check_after) + OSSL_CMP_MSG **req, int64_t *check_after) { mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + if (req != NULL) + *req = NULL; if (ctx == NULL || pollReq == NULL - || certReq == NULL || check_after == NULL) { + || req == NULL || check_after == NULL) { ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); return 0; } + if (ctx->sendError == 1 || ctx->sendError == OSSL_CMP_MSG_get_bodytype(pollReq)) { - *certReq = NULL; ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE); return 0; } - if (ctx->certReq == NULL) { - /* not currently in polling mode */ - *certReq = NULL; - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + if (ctx->req == NULL) { /* not currently in polling mode */ + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_POLLREQ); return 0; } if (++ctx->curr_pollCount >= ctx->pollCount) { /* end polling */ - *certReq = ctx->certReq; - ctx->certReq = NULL; + *req = ctx->req; + ctx->req = NULL; *check_after = 0; } else { - *certReq = NULL; *check_after = ctx->checkAfterTime; } return 1; @@ -487,7 +567,9 @@ OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(OSSL_LIB_CTX *libctx, const char *propq) if (srv_ctx != NULL && ctx != NULL && OSSL_CMP_SRV_CTX_init(srv_ctx, ctx, process_cert_request, process_rr, process_genm, process_error, - process_certConf, process_pollReq)) + process_certConf, process_pollReq) + && OSSL_CMP_SRV_CTX_init_trans(srv_ctx, + delayed_delivery, clean_transaction)) return srv_ctx; mock_srv_ctx_free(ctx); diff --git a/crypto/chacha/asm/chacha-loongarch64.pl b/crypto/chacha/asm/chacha-loongarch64.pl index ea9cc7ecce237bfe92534e8a5deaf45816180d4a..9eed5860de9a710ba92d876117c0778b0ace0f13 100644 --- a/crypto/chacha/asm/chacha-loongarch64.pl +++ b/crypto/chacha/asm/chacha-loongarch64.pl @@ -17,6 +17,14 @@ my ($a0,$a1,$a2,$a3,$a4,$a5,$a6,$a7)=map("\$r$_",(4..11)); my ($t0,$t1,$t2,$t3,$t4,$t5,$t6,$t7,$t8,$x)=map("\$r$_",(12..21)); my ($s0,$s1,$s2,$s3,$s4,$s5,$s6,$s7,$s8)=map("\$r$_",(23..31)); +# The saved floating-point registers in the LP64D ABI. In LoongArch +# with vector extension, the low 64 bits of a vector register alias with +# the corresponding FPR. So we must save and restore the corresponding +# FPR if we'll write into a vector register. The ABI only requires +# saving and restoring the FPR (i.e. 64 bits of the corresponding vector +# register), not the entire vector register. +my ($fs0,$fs1,$fs2,$fs3,$fs4,$fs5,$fs6,$fs7)=map("\$f$_",(24..31)); + # Here is the 128-bit vector register layout for LSX extension. my ($vr0,$vr1,$vr2,$vr3,$vr4,$vr5,$vr6,$vr7,$vr8,$vr9,$vr10, $vr11,$vr12,$vr13,$vr14,$vr15,$vr16,$vr17,$vr18,$vr19, @@ -66,13 +74,25 @@ ChaCha20_ctr32: la.pcrel $t0,OPENSSL_loongarch_hwcap_P ld.w $t0,$t0,0 + bleu $len,$t3,.LChaCha20_1x # goto 1x when len <= 64 + + andi $t0,$t0,LOONGARCH_HWCAP_LASX | LOONGARCH_HWCAP_LSX + beqz $t0,.LChaCha20_1x + + addi.d $sp,$sp,-64 + fst.d $fs0,$sp,0 + fst.d $fs1,$sp,8 + fst.d $fs2,$sp,16 + fst.d $fs3,$sp,24 + fst.d $fs4,$sp,32 + fst.d $fs5,$sp,40 + fst.d $fs6,$sp,48 + fst.d $fs7,$sp,56 + andi $t1,$t0,LOONGARCH_HWCAP_LASX bnez $t1,.LChaCha20_8x - andi $t2,$t0,LOONGARCH_HWCAP_LSX - bnez $t2,.LChaCha20_4x - - b .LChaCha20_1x + b .LChaCha20_4x EOF @@ -442,8 +462,6 @@ $code .= <infoType = OBJ_nid2obj(NID_id_it_certProfile); + itav->infoValue.certProfile = certProfile; + return itav; +} + +int OSSL_CMP_ITAV_get0_certProfile(const OSSL_CMP_ITAV *itav, + STACK_OF(ASN1_UTF8STRING) **out) +{ + if (itav == NULL || out == NULL) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + if (OBJ_obj2nid(itav->infoType) != NID_id_it_certProfile) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + *out = itav->infoValue.certProfile; + return 1; +} + OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_caCerts(const STACK_OF(X509) *caCerts) { OSSL_CMP_ITAV *itav = OSSL_CMP_ITAV_new(); @@ -327,7 +353,7 @@ int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a) } static int ossl_cmp_msg_cb(int operation, ASN1_VALUE **pval, - const ASN1_ITEM *it, void *exarg) + ossl_unused const ASN1_ITEM *it, void *exarg) { OSSL_CMP_MSG *msg = (OSSL_CMP_MSG *)*pval; @@ -417,14 +443,9 @@ ASN1_ITEM_TEMPLATE_END(OSSL_CMP_PKISTATUS) ASN1_SEQUENCE(OSSL_CMP_PKISI) = { ASN1_SIMPLE(OSSL_CMP_PKISI, status, OSSL_CMP_PKISTATUS), - /* - * CMP_PKIFREETEXT is effectively a sequence of ASN1_UTF8STRING - * so it is used directly - */ + /* OSSL_CMP_PKIFREETEXT is a ASN1_UTF8STRING sequence, so used directly */ ASN1_SEQUENCE_OF_OPT(OSSL_CMP_PKISI, statusString, ASN1_UTF8STRING), - /* - * OSSL_CMP_PKIFAILUREINFO is effectively ASN1_BIT_STRING so used directly - */ + /* OSSL_CMP_PKIFAILUREINFO is effectively ASN1_BIT_STRING, used directly */ ASN1_OPT(OSSL_CMP_PKISI, failInfo, ASN1_BIT_STRING) } ASN1_SEQUENCE_END(OSSL_CMP_PKISI) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_PKISI) @@ -541,10 +562,7 @@ ASN1_SEQUENCE(OSSL_CMP_PKIHEADER) = { ASN1_EXP_OPT(OSSL_CMP_PKIHEADER, transactionID, ASN1_OCTET_STRING, 4), ASN1_EXP_OPT(OSSL_CMP_PKIHEADER, senderNonce, ASN1_OCTET_STRING, 5), ASN1_EXP_OPT(OSSL_CMP_PKIHEADER, recipNonce, ASN1_OCTET_STRING, 6), - /* - * OSSL_CMP_PKIFREETEXT is effectively a sequence of ASN1_UTF8STRING - * so it is used directly - */ + /* OSSL_CMP_PKIFREETEXT is a ASN1_UTF8STRING sequence, so used directly */ ASN1_EXP_SEQUENCE_OF_OPT(OSSL_CMP_PKIHEADER, freeText, ASN1_UTF8STRING, 7), ASN1_EXP_SEQUENCE_OF_OPT(OSSL_CMP_PKIHEADER, generalInfo, OSSL_CMP_ITAV, 8) diff --git a/crypto/cmp/cmp_client.c b/crypto/cmp/cmp_client.c index b5b0557b0d046fab248102e5f621bf9b9cc29986..91876ee948e631d10d0681510ea10cf2070cdc9b 100644 --- a/crypto/cmp/cmp_client.c +++ b/crypto/cmp/cmp_client.c @@ -113,6 +113,23 @@ static int save_statusInfo(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si) return 1; } +static int is_crep_with_waiting(const OSSL_CMP_MSG *resp, int rid) +{ + OSSL_CMP_CERTREPMESSAGE *crepmsg; + OSSL_CMP_CERTRESPONSE *crep; + int bt = OSSL_CMP_MSG_get_bodytype(resp); + + if (!IS_CREP(bt)) + return 0; + + crepmsg = resp->body->value.ip; /* same for cp and kup */ + crep = ossl_cmp_certrepmessage_get0_certresponse(crepmsg, rid); + + return (crep != NULL + && ossl_cmp_pkisi_get_status(crep->status) + == OSSL_CMP_PKISTATUS_waiting); +} + /*- * Perform the generic aspects of sending a request and receiving a response. * Returns 1 on success and provides the received PKIMESSAGE in *rep. @@ -180,7 +197,8 @@ static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req, * Still we use this preliminary value already for a progress report because * the following msg verification may also produce log entries and may fail. */ - ossl_cmp_log1(INFO, ctx, "received %s", ossl_cmp_bodytype_to_string(bt)); + ossl_cmp_log2(INFO, ctx, "received %s%s", ossl_cmp_bodytype_to_string(bt), + ossl_cmp_is_error_with_waiting(*rep) ? " (waiting)" : ""); /* copy received extraCerts to ctx->extraCertsIn so they can be retrieved */ if (bt != OSSL_CMP_PKIBODY_POLLREP && bt != OSSL_CMP_PKIBODY_PKICONF @@ -191,9 +209,17 @@ static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req, expected_type)) return 0; + /* + * rep can have the expected response type, which during polling is pollRep. + * When polling, also any other non-error response (the final response) + * is fine here. When not yet polling, delayed delivery may be initiated + * by the server returning an error message with 'waiting' status (or a + * response message of expected type ip/cp/kup with 'waiting' status). + */ if (bt == expected_type - /* as an answer to polling, there could be IP/CP/KUP: */ - || (IS_CREP(bt) && expected_type == OSSL_CMP_PKIBODY_POLLREP)) + || (expected_type == OSSL_CMP_PKIBODY_POLLREP + ? bt != OSSL_CMP_PKIBODY_ERROR + : ossl_cmp_is_error_with_waiting(*rep))) return 1; /* received message type is not one of the expected ones (e.g., error) */ @@ -235,7 +261,7 @@ static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req, /*- * When a 'waiting' PKIStatus has been received, this function is used to - * poll, which should yield a pollRep or finally a CertRepMessage in ip/cp/kup. + * poll, which should yield a pollRep or the final response. * On receiving a pollRep, which includes a checkAfter value, it return this * value if sleep == 0, else it sleeps as long as indicated and retries. * @@ -246,7 +272,8 @@ static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req, * Returns -1 on receiving pollRep if sleep == 0, setting the checkAfter value. * Returns 1 on success and provides the received PKIMESSAGE in *rep. * In this case the caller is responsible for freeing *rep. - * Returns 0 on error (which includes the case that timeout has been reached). + * Returns 0 on error (which includes the cases that timeout has been reached + * or a response with 'waiting' status has been received). */ static int poll_for_response(OSSL_CMP_CTX *ctx, int sleep, int rid, OSSL_CMP_MSG **rep, int *checkAfter) @@ -312,7 +339,7 @@ static int poll_for_response(OSSL_CMP_CTX *ctx, int sleep, int rid, str, check_after); if (ctx->total_timeout != 0) { /* timeout is not infinite */ - const int exp = 5; /* expected max time per msg round trip */ + const int exp = OSSL_CMP_EXPECTED_RESP_TIME; int64_t time_left = (int64_t)(ctx->end_time - exp - time(NULL)); if (time_left <= 0) { @@ -335,9 +362,19 @@ static int poll_for_response(OSSL_CMP_CTX *ctx, int sleep, int rid, *checkAfter = (int)check_after; return -1; /* exits the loop */ } + } else if (is_crep_with_waiting(prep, rid) + || ossl_cmp_is_error_with_waiting(prep)) { + /* received status must not be 'waiting' */ + (void)ossl_cmp_exchange_error(ctx, OSSL_CMP_PKISTATUS_rejection, + OSSL_CMP_CTX_FAILINFO_badRequest, + "polling already started", + 0 /* errorCode */, NULL); + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKISTATUS); + goto err; } else { - ossl_cmp_info(ctx, "received ip/cp/kup after polling"); - /* any other body type has been rejected by send_receive_check() */ + ossl_cmp_info(ctx, "received final response after polling"); + if (!ossl_cmp_ctx_set1_first_senderNonce(ctx, NULL)) + return 0; break; } } @@ -349,11 +386,63 @@ static int poll_for_response(OSSL_CMP_CTX *ctx, int sleep, int rid, return 1; err: + (void)ossl_cmp_ctx_set1_first_senderNonce(ctx, NULL); OSSL_CMP_MSG_free(preq); OSSL_CMP_MSG_free(prep); return 0; } +static int save_senderNonce_if_waiting(OSSL_CMP_CTX *ctx, + const OSSL_CMP_MSG *rep, int rid) +{ + /* + * Lightweight CMP Profile section 4.4 states: the senderNonce of the + * preceding request message because this value will be needed for checking + * the recipNonce of the final response to be received after polling. + */ + if ((is_crep_with_waiting(rep, rid) + || ossl_cmp_is_error_with_waiting(rep)) + && !ossl_cmp_ctx_set1_first_senderNonce(ctx, ctx->senderNonce)) + return 0; + + return 1; +} + +/* + * Send request and get response possibly with polling initiated by error msg. + * Polling for ip/cp/kup/ with 'waiting' status is handled by cert_response(). + */ +static int send_receive_also_delayed(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req, + OSSL_CMP_MSG **rep, int expected_type) +{ + + if (!send_receive_check(ctx, req, rep, expected_type)) + return 0; + + if (ossl_cmp_is_error_with_waiting(*rep)) { + if (!save_senderNonce_if_waiting(ctx, *rep, OSSL_CMP_CERTREQID_NONE)) + return 0; + /* not modifying ctx->status during certConf and error exchanges */ + if (expected_type != OSSL_CMP_PKIBODY_PKICONF + && !save_statusInfo(ctx, (*rep)->body->value.error->pKIStatusInfo)) + return 0; + + OSSL_CMP_MSG_free(*rep); + *rep = NULL; + + if (poll_for_response(ctx, 1 /* can sleep */, OSSL_CMP_CERTREQID_NONE, + rep, NULL /* checkAfter */) <= 0) { + ERR_raise(ERR_LIB_CMP, CMP_R_POLLING_FAILED); + return 0; + } + } + if (OSSL_CMP_MSG_get_bodytype(*rep) != expected_type) { + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + return 0; + } + + return 1; +} /* * Send certConf for IR, CR or KUR sequences and check response, * not modifying ctx->status during the certConf exchange @@ -370,7 +459,8 @@ int ossl_cmp_exchange_certConf(OSSL_CMP_CTX *ctx, int certReqId, if (certConf == NULL) goto err; - res = send_receive_check(ctx, certConf, &PKIconf, OSSL_CMP_PKIBODY_PKICONF); + res = send_receive_also_delayed(ctx, certConf, &PKIconf, + OSSL_CMP_PKIBODY_PKICONF); err: OSSL_CMP_MSG_free(certConf); @@ -394,7 +484,8 @@ int ossl_cmp_exchange_error(OSSL_CMP_CTX *ctx, int status, int fail_info, if ((error = ossl_cmp_error_new(ctx, si, errorCode, details, 0)) == NULL) goto err; - res = send_receive_check(ctx, error, &PKIconf, OSSL_CMP_PKIBODY_PKICONF); + res = send_receive_also_delayed(ctx, error, + &PKIconf, OSSL_CMP_PKIBODY_PKICONF); err: OSSL_CMP_MSG_free(error); @@ -515,7 +606,7 @@ int OSSL_CMP_certConf_cb(OSSL_CMP_CTX *ctx, X509 *cert, int fail_info, if (X509_verify_cert(csc) <= 0) goto err; - if (!ossl_x509_add_certs_new(&chain, X509_STORE_CTX_get0_chain(csc), + if (!ossl_x509_add_certs_new(&chain, X509_STORE_CTX_get0_chain(csc), X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP | X509_ADD_FLAG_NO_SS)) { sk_X509_free(chain); @@ -564,48 +655,78 @@ static int cert_response(OSSL_CMP_CTX *ctx, int sleep, int rid, EVP_PKEY *rkey = ossl_cmp_ctx_get0_newPubkey(ctx); int fail_info = 0; /* no failure */ const char *txt = NULL; - OSSL_CMP_CERTREPMESSAGE *crepmsg; - OSSL_CMP_CERTRESPONSE *crep; + OSSL_CMP_CERTREPMESSAGE *crepmsg = NULL; + OSSL_CMP_CERTRESPONSE *crep = NULL; OSSL_CMP_certConf_cb_t cb; X509 *cert; char *subj = NULL; int ret = 1; + int rcvd_type; + OSSL_CMP_PKISI *si; if (!ossl_assert(ctx != NULL)) return 0; retry: - crepmsg = (*resp)->body->value.ip; /* same for cp and kup */ - if (sk_OSSL_CMP_CERTRESPONSE_num(crepmsg->response) > 1) { - ERR_raise(ERR_LIB_CMP, CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED); - return 0; - } - crep = ossl_cmp_certrepmessage_get0_certresponse(crepmsg, rid); - if (crep == NULL) - return 0; - if (!save_statusInfo(ctx, crep->status)) - return 0; - if (rid == OSSL_CMP_CERTREQID_NONE) { /* used for OSSL_CMP_PKIBODY_P10CR */ - rid = ossl_cmp_asn1_get_int(crep->certReqId); - if (rid < OSSL_CMP_CERTREQID_NONE) { - ERR_raise(ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID); + rcvd_type = OSSL_CMP_MSG_get_bodytype(*resp); + if (IS_CREP(rcvd_type)) { + crepmsg = (*resp)->body->value.ip; /* same for cp and kup */ + if (sk_OSSL_CMP_CERTRESPONSE_num(crepmsg->response) > 1) { + ERR_raise(ERR_LIB_CMP, CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED); return 0; } + crep = ossl_cmp_certrepmessage_get0_certresponse(crepmsg, rid); + if (crep == NULL) + return 0; + si = crep->status; + + if (rid == OSSL_CMP_CERTREQID_NONE) { + /* for OSSL_CMP_PKIBODY_P10CR learn CertReqId from response */ + rid = ossl_cmp_asn1_get_int(crep->certReqId); + if (rid < OSSL_CMP_CERTREQID_NONE) { + ERR_raise(ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID); + return 0; + } + } + } else if (rcvd_type == OSSL_CMP_PKIBODY_ERROR) { + si = (*resp)->body->value.error->pKIStatusInfo; + } else { + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + return 0; } - if (ossl_cmp_pkisi_get_status(crep->status) == OSSL_CMP_PKISTATUS_waiting) { + if (!save_statusInfo(ctx, si)) + return 0; + + if (ossl_cmp_pkisi_get_status(si) == OSSL_CMP_PKISTATUS_waiting) { + /* + * Here we allow both and error message with waiting indication + * as well as a certificate response with waiting indication, where + * its flavor (ip, cp, or kup) may not strictly match ir/cr/p10cr/kur. + */ OSSL_CMP_MSG_free(*resp); *resp = NULL; if ((ret = poll_for_response(ctx, sleep, rid, resp, checkAfter)) != 0) { if (ret == -1) /* at this point implies sleep == 0 */ return ret; /* waiting */ - goto retry; /* got ip/cp/kup, which may still indicate 'waiting' */ + goto retry; /* got some response other than pollRep */ } else { ERR_raise(ERR_LIB_CMP, CMP_R_POLLING_FAILED); return 0; } } + /* at this point, we have received ip/cp/kup/error without waiting */ + if (rcvd_type == OSSL_CMP_PKIBODY_ERROR) { + ERR_raise(ERR_LIB_CMP, CMP_R_RECEIVED_ERROR); + return 0; + } + /* here we are strict on the flavor of ip/cp/kup: must match request */ + if (rcvd_type != expected_type) { + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + return 0; + } + cert = get1_cert_status(ctx, (*resp)->body->type, crep); if (cert == NULL) { ERR_add_error_data(1, "; cannot extract certificate from response"); @@ -618,7 +739,7 @@ static int cert_response(OSSL_CMP_CTX *ctx, int sleep, int rid, * if the CMP server returned certificates in the caPubs field, copy them * to the context so that they can be retrieved if necessary */ - if (crepmsg->caPubs != NULL + if (crepmsg != NULL && crepmsg->caPubs != NULL && !ossl_cmp_ctx_set1_caPubs(ctx, crepmsg->caPubs)) return 0; @@ -709,6 +830,9 @@ int OSSL_CMP_try_certreq(OSSL_CMP_CTX *ctx, int req_type, if (ctx->status != OSSL_CMP_PKISTATUS_waiting) { /* not polling already */ if (!initial_certreq(ctx, req_type, crm, &rep, rep_type)) goto err; + + if (!save_senderNonce_if_waiting(ctx, rep, rid)) + return 0; } else { if (req_type < 0) return ossl_cmp_exchange_error(ctx, OSSL_CMP_PKISTATUS_rejection, @@ -750,6 +874,9 @@ X509 *OSSL_CMP_exec_certreq(OSSL_CMP_CTX *ctx, int req_type, if (!initial_certreq(ctx, req_type, crm, &rep, rep_type)) goto err; + if (!save_senderNonce_if_waiting(ctx, rep, rid)) + return 0; + if (cert_response(ctx, 1 /* sleep */, rid, &rep, NULL, req_type, rep_type) <= 0) goto err; @@ -787,7 +914,7 @@ int OSSL_CMP_exec_RR_ses(OSSL_CMP_CTX *ctx) goto end; ctx->status = OSSL_CMP_PKISTATUS_trans; - if (!send_receive_check(ctx, rr, &rp, OSSL_CMP_PKIBODY_RP)) + if (!send_receive_also_delayed(ctx, rr, &rp, OSSL_CMP_PKIBODY_RP)) goto end; rrep = rp->body->value.rp; @@ -908,7 +1035,7 @@ STACK_OF(OSSL_CMP_ITAV) *OSSL_CMP_exec_GENM_ses(OSSL_CMP_CTX *ctx) goto err; ctx->status = OSSL_CMP_PKISTATUS_trans; - if (!send_receive_check(ctx, genm, &genp, OSSL_CMP_PKIBODY_GENP)) + if (!send_receive_also_delayed(ctx, genm, &genp, OSSL_CMP_PKIBODY_GENP)) goto err; ctx->status = OSSL_CMP_PKISTATUS_accepted; diff --git a/crypto/cmp/cmp_ctx.c b/crypto/cmp/cmp_ctx.c index 947d2ceb8fde8b255ce0e119aac585715c0bff9a..cc62ae4e4e8fb0070dfcbf2304443d57d31b829f 100644 --- a/crypto/cmp/cmp_ctx.c +++ b/crypto/cmp/cmp_ctx.c @@ -183,6 +183,7 @@ int OSSL_CMP_CTX_reinit(OSSL_CMP_CTX *ctx) && ossl_cmp_ctx_set1_caPubs(ctx, NULL) && ossl_cmp_ctx_set1_extraCertsIn(ctx, NULL) && ossl_cmp_ctx_set1_validatedSrvCert(ctx, NULL) + && ossl_cmp_ctx_set1_first_senderNonce(ctx, NULL) && OSSL_CMP_CTX_set1_transactionID(ctx, NULL) && OSSL_CMP_CTX_set1_senderNonce(ctx, NULL) && ossl_cmp_ctx_set1_recipNonce(ctx, NULL); @@ -226,6 +227,7 @@ void OSSL_CMP_CTX_free(OSSL_CMP_CTX *ctx) ASN1_OCTET_STRING_free(ctx->transactionID); ASN1_OCTET_STRING_free(ctx->senderNonce); ASN1_OCTET_STRING_free(ctx->recipNonce); + ASN1_OCTET_STRING_free(ctx->first_senderNonce); OSSL_CMP_ITAVs_free(ctx->geninfo_ITAVs); OSSL_STACK_OF_X509_free(ctx->extraCertsOut); @@ -534,6 +536,8 @@ int OSSL_CMP_CTX_reset_geninfo_ITAVs(OSSL_CMP_CTX *ctx) return 1; } +DEFINE_OSSL_CMP_CTX_get0(geninfo_ITAVs, STACK_OF(OSSL_CMP_ITAV)) + /* Add an itav for the body of outgoing general messages */ int OSSL_CMP_CTX_push0_genm_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav) { @@ -812,6 +816,9 @@ DEFINE_set1_ASN1_OCTET_STRING(ossl_cmp_ctx, recipNonce) /* Stores the given nonce as the last senderNonce sent out */ DEFINE_set1_ASN1_OCTET_STRING(OSSL_CMP_CTX, senderNonce) +/* store the first req sender nonce for verifying delayed delivery */ +DEFINE_set1_ASN1_OCTET_STRING(ossl_cmp_ctx, first_senderNonce) + /* Set the proxy server to use for HTTP(S) connections */ DEFINE_OSSL_CMP_CTX_set1(proxy, char) diff --git a/crypto/cmp/cmp_err.c b/crypto/cmp/cmp_err.c index 3853e52605969a23e4a64f87d422104a9f83cf84..6c2588d4d48abfec6021a61ed8b653df74552234 100644 --- a/crypto/cmp/cmp_err.c +++ b/crypto/cmp/cmp_err.c @@ -76,6 +76,7 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { "error validating protection"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_VALIDATING_SIGNATURE), "error validating signature"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_EXPECTED_POLLREQ), "expected pollreq"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILED_BUILDING_OWN_CHAIN), "failed building own chain"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILED_EXTRACTING_PUBKEY), @@ -144,9 +145,12 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { "transactionid unmatched"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_TRANSFER_ERROR), "transfer error"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNCLEAN_CTX), "unclean ctx"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_CERTPROFILE), + "unexpected certprofile"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKIBODY), "unexpected pkibody"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKISTATUS), "unexpected pkistatus"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_POLLREQ), "unexpected pollreq"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PVNO), "unexpected pvno"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNKNOWN_ALGORITHM_ID), "unknown algorithm id"}, @@ -156,6 +160,8 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { "unsupported algorithm"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_KEY_TYPE), "unsupported key type"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_PKIBODY), + "unsupported pkibody"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC), "unsupported protection alg dhbasedmac"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_VALUE_TOO_LARGE), "value too large"}, diff --git a/crypto/cmp/cmp_hdr.c b/crypto/cmp/cmp_hdr.c index 5fabf1aa3349106dfafe7c068f7f52a31f1e5f5e..4358b38873f357579bf6267601f07463adbf288d 100644 --- a/crypto/cmp/cmp_hdr.c +++ b/crypto/cmp/cmp_hdr.c @@ -72,6 +72,16 @@ ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr) return hdr->recipNonce; } +STACK_OF(OSSL_CMP_ITAV) + *OSSL_CMP_HDR_get0_geninfo_ITAVs(const OSSL_CMP_PKIHEADER *hdr) +{ + if (hdr == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return NULL; + } + return hdr->generalInfo; +} + /* a NULL-DN as an empty sequence of RDNs */ int ossl_cmp_general_name_is_NULL_DN(GENERAL_NAME *name) { diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h index 29aa84cd2a09e69afe0790ab9947cc0712bb899a..175cc2575ccc52e47af4dd6e0ff9dcf2ca94fb6e 100644 --- a/crypto/cmp/cmp_local.h +++ b/crypto/cmp/cmp_local.h @@ -95,6 +95,7 @@ struct ossl_cmp_ctx_st { ASN1_OCTET_STRING *transactionID; /* the current transaction ID */ ASN1_OCTET_STRING *senderNonce; /* last nonce sent */ ASN1_OCTET_STRING *recipNonce; /* last nonce received */ + ASN1_OCTET_STRING *first_senderNonce; /* sender nonce when starting to poll */ ASN1_UTF8STRING *freeText; /* optional string to include each msg */ STACK_OF(OSSL_CMP_ITAV) *geninfo_ITAVs; int implicitConfirm; /* set implicitConfirm in IR/KUR/CR messages */ @@ -254,6 +255,8 @@ struct ossl_cmp_itav_st { OSSL_CMP_MSGS *origPKIMessage; /* NID_id_it_suppLangTags - Supported Language Tags */ STACK_OF(ASN1_UTF8STRING) *suppLangTagsValue; + /* NID_id_it_certProfile - Certificate Profile */ + STACK_OF(ASN1_UTF8STRING) *certProfile; /* NID_id_it_caCerts - CA Certificates */ STACK_OF(X509) *caCerts; /* NID_id_it_rootCaCert - Root CA Certificate */ @@ -821,6 +824,8 @@ int ossl_cmp_ctx_set1_extraCertsIn(OSSL_CMP_CTX *ctx, int ossl_cmp_ctx_set1_recipNonce(OSSL_CMP_CTX *ctx, const ASN1_OCTET_STRING *nonce); EVP_PKEY *ossl_cmp_ctx_get0_newPubkey(const OSSL_CMP_CTX *ctx); +int ossl_cmp_ctx_set1_first_senderNonce(OSSL_CMP_CTX *ctx, + const ASN1_OCTET_STRING *nonce); /* from cmp_status.c */ int ossl_cmp_pkisi_get_status(const OSSL_CMP_PKISI *si); @@ -937,6 +942,7 @@ ossl_cmp_certrepmessage_get0_certresponse(const OSSL_CMP_CERTREPMESSAGE *crm, X509 *ossl_cmp_certresponse_get1_cert(const OSSL_CMP_CTX *ctx, const OSSL_CMP_CERTRESPONSE *crep); OSSL_CMP_MSG *ossl_cmp_msg_load(const char *file); +int ossl_cmp_is_error_with_waiting(const OSSL_CMP_MSG *msg); /* from cmp_protect.c */ int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg); @@ -956,6 +962,8 @@ int ossl_cmp_verify_popo(const OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, int accept_RAVerified); /* from cmp_client.c */ +/* expected max time per msg round trip, used for last try during polling: */ +# define OSSL_CMP_EXPECTED_RESP_TIME 2 int ossl_cmp_exchange_certConf(OSSL_CMP_CTX *ctx, int certReqId, int fail_info, const char *txt); int ossl_cmp_exchange_error(OSSL_CMP_CTX *ctx, int status, int fail_info, diff --git a/crypto/cmp/cmp_msg.c b/crypto/cmp/cmp_msg.c index e00afc809e2b8abec480c0b9cc67f0e50cccc6de..a7e22d874ade5604983ab2b566cbc7e23cda2890 100644 --- a/crypto/cmp/cmp_msg.c +++ b/crypto/cmp/cmp_msg.c @@ -984,8 +984,7 @@ static int suitable_rid(const ASN1_INTEGER *certReqId, int rid) return 1; trid = ossl_cmp_asn1_get_int(certReqId); - - if (trid == OSSL_CMP_CERTREQID_NONE) { + if (trid <= OSSL_CMP_CERTREQID_INVALID) { ERR_raise(ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID); return 0; } @@ -1200,3 +1199,13 @@ int i2d_OSSL_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg) { return ASN1_i2d_bio_of(OSSL_CMP_MSG, i2d_OSSL_CMP_MSG, bio, msg); } + +int ossl_cmp_is_error_with_waiting(const OSSL_CMP_MSG *msg) +{ + if (!ossl_assert(msg != NULL)) + return 0; + + return (OSSL_CMP_MSG_get_bodytype(msg) == OSSL_CMP_PKIBODY_ERROR + && ossl_cmp_pkisi_get_status(msg->body->value.error->pKIStatusInfo) + == OSSL_CMP_PKISTATUS_waiting); +} diff --git a/crypto/cmp/cmp_server.c b/crypto/cmp/cmp_server.c index 06ef8fbb613ef5490eeac53c525f8855c85355e2..4e2ca099662c170a993028f49f7bea8e4ccc1a50 100644 --- a/crypto/cmp/cmp_server.c +++ b/crypto/cmp/cmp_server.c @@ -22,9 +22,10 @@ /* the context for the generic CMP server */ struct ossl_cmp_srv_ctx_st { - void *custom_ctx; /* pointer to application-specific server context */ - OSSL_CMP_CTX *ctx; /* Client CMP context, reusing transactionID etc. */ - int certReqId; /* id of last ir/cr/kur, OSSL_CMP_CERTREQID_NONE for p10cr */ + OSSL_CMP_CTX *ctx; /* CMP client context reused for transactionID etc. */ + void *custom_ctx; /* application-specific server context */ + int certReqId; /* of ir/cr/kur, OSSL_CMP_CERTREQID_NONE for p10cr */ + int polling; /* current tranaction is in polling mode */ OSSL_CMP_SRV_cert_request_cb_t process_cert_request; OSSL_CMP_SRV_rr_cb_t process_rr; @@ -32,6 +33,8 @@ struct ossl_cmp_srv_ctx_st OSSL_CMP_SRV_error_cb_t process_error; OSSL_CMP_SRV_certConf_cb_t process_certConf; OSSL_CMP_SRV_pollReq_cb_t process_pollReq; + OSSL_CMP_SRV_delayed_delivery_cb_t delayed_delivery; + OSSL_CMP_SRV_clean_transaction_cb_t clean_transaction; int sendUnprotectedErrors; /* Send error and rejection msgs unprotected */ int acceptUnprotected; /* Accept requests with no/invalid prot. */ @@ -59,6 +62,7 @@ OSSL_CMP_SRV_CTX *OSSL_CMP_SRV_CTX_new(OSSL_LIB_CTX *libctx, const char *propq) if ((ctx->ctx = OSSL_CMP_CTX_new(libctx, propq)) == NULL) goto err; ctx->certReqId = OSSL_CMP_CERTREQID_INVALID; + ctx->polling = 0; /* all other elements are initialized to 0 or NULL, respectively */ return ctx; @@ -89,6 +93,19 @@ int OSSL_CMP_SRV_CTX_init(OSSL_CMP_SRV_CTX *srv_ctx, void *custom_ctx, return 1; } +int OSSL_CMP_SRV_CTX_init_trans(OSSL_CMP_SRV_CTX *srv_ctx, + OSSL_CMP_SRV_delayed_delivery_cb_t delay, + OSSL_CMP_SRV_clean_transaction_cb_t clean) +{ + if (srv_ctx == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + srv_ctx->delayed_delivery = delay; + srv_ctx->clean_transaction = clean; + return 1; +} + OSSL_CMP_CTX *OSSL_CMP_SRV_CTX_get0_cmp_ctx(const OSSL_CMP_SRV_CTX *srv_ctx) { if (srv_ctx == NULL) { @@ -149,6 +166,46 @@ int OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(OSSL_CMP_SRV_CTX *srv_ctx, return 1; } +/* return error msg with waiting status if polling is initiated, else NULL */ +static OSSL_CMP_MSG *delayed_delivery(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req) +{ + int ret; + unsigned long err; + int status = OSSL_CMP_PKISTATUS_waiting, + fail_info = 0, errorCode = 0; + const char *txt = NULL, *details = NULL; + OSSL_CMP_PKISI *si; + OSSL_CMP_MSG *msg; + + if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL + && srv_ctx->delayed_delivery != NULL)) + return NULL; + + ret = srv_ctx->delayed_delivery(srv_ctx, req); + if (ret == 0) + return NULL; + if (ret == 1) { + srv_ctx->polling = 1; + } else { + status = OSSL_CMP_PKISTATUS_rejection; + fail_info = 1 << OSSL_CMP_PKIFAILUREINFO_systemFailure; + txt = "server application error"; + err = ERR_peek_error(); + errorCode = ERR_GET_REASON(err); + details = ERR_reason_error_string(err); + } + + si = OSSL_CMP_STATUSINFO_new(status, fail_info, txt); + if (si == NULL) + return NULL; + + msg = ossl_cmp_error_new(srv_ctx->ctx, si, errorCode, details, + srv_ctx->sendUnprotectedErrors); + OSSL_CMP_PKISI_free(si); + return msg; +} + /* * Processes an ir/cr/p10cr/kur and returns a certification response. * Only handles the first certification request contained in req @@ -195,15 +252,14 @@ static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, ERR_raise(ERR_LIB_CMP, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED); return NULL; } - - if ((crm = sk_OSSL_CRMF_MSG_value(reqs, OSSL_CMP_CERTREQID)) == NULL) { + if ((crm = sk_OSSL_CRMF_MSG_value(reqs, 0)) == NULL) { ERR_raise(ERR_LIB_CMP, CMP_R_CERTREQMSG_NOT_FOUND); return NULL; } certReqId = OSSL_CRMF_MSG_get_certReqId(crm); - if (certReqId != OSSL_CMP_CERTREQID) { + if (certReqId != OSSL_CMP_CERTREQID) { /* so far, only possible value */ ERR_raise(ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID); - return 0; + return NULL; } } srv_ctx->certReqId = certReqId; @@ -222,6 +278,8 @@ static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, &certOut, &chainOut, &caPubs); if (si == NULL) goto err; + if (ossl_cmp_pkisi_get_status(si) == OSSL_CMP_PKISTATUS_waiting) + srv_ctx->polling = 1; /* set OSSL_CMP_OPT_IMPLICIT_CONFIRM if and only if transaction ends */ if (!OSSL_CMP_CTX_set_option(srv_ctx->ctx, OSSL_CMP_OPT_IMPLICIT_CONFIRM, @@ -265,9 +323,8 @@ static OSSL_CMP_MSG *process_rr(OSSL_CMP_SRV_CTX *srv_ctx, ERR_raise(ERR_LIB_CMP, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED); return NULL; } - - if ((details = sk_OSSL_CMP_REVDETAILS_value(req->body->value.rr, - OSSL_CMP_REVREQSID)) == NULL) { + details = sk_OSSL_CMP_REVDETAILS_value(req->body->value.rr, 0); + if (details == NULL) { ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE); return NULL; } @@ -356,7 +413,7 @@ static OSSL_CMP_MSG *process_certConf(OSSL_CMP_SRV_CTX *srv_ctx, } else { if (num > 1) ossl_cmp_warn(ctx, "All CertStatus but the first will be ignored"); - status = sk_OSSL_CMP_CERTSTATUS_value(ccc, OSSL_CMP_CERTREQID); + status = sk_OSSL_CMP_CERTSTATUS_value(ccc, 0); } if (status != NULL) { @@ -387,38 +444,96 @@ static OSSL_CMP_MSG *process_certConf(OSSL_CMP_SRV_CTX *srv_ctx, return msg; } +/* pollReq is handled separately, to avoid recursive call */ +static OSSL_CMP_MSG *process_non_polling_request(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req) +{ + OSSL_CMP_MSG *rsp = NULL; + + if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL + && req->body != NULL)) + return NULL; + + switch (OSSL_CMP_MSG_get_bodytype(req)) { + case OSSL_CMP_PKIBODY_IR: + case OSSL_CMP_PKIBODY_CR: + case OSSL_CMP_PKIBODY_P10CR: + case OSSL_CMP_PKIBODY_KUR: + if (srv_ctx->process_cert_request == NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); + else + rsp = process_cert_request(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_RR: + if (srv_ctx->process_rr == NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); + else + rsp = process_rr(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_GENM: + if (srv_ctx->process_genm == NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); + else + rsp = process_genm(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_ERROR: + if (srv_ctx->process_error == NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); + else + rsp = process_error(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_CERTCONF: + if (srv_ctx->process_certConf == NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); + else + rsp = process_certConf(srv_ctx, req); + break; + + case OSSL_CMP_PKIBODY_POLLREQ: + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + break; + default: + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); + break; + } + + return rsp; +} + static OSSL_CMP_MSG *process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *req) { OSSL_CMP_POLLREQCONTENT *prc; OSSL_CMP_POLLREQ *pr; int certReqId; - OSSL_CMP_MSG *certReq; + OSSL_CMP_MSG *orig_req; int64_t check_after = 0; OSSL_CMP_MSG *msg = NULL; if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL)) return NULL; + if (!srv_ctx->polling) { + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + return NULL; + } + prc = req->body->value.pollReq; if (sk_OSSL_CMP_POLLREQ_num(prc) != 1) { ERR_raise(ERR_LIB_CMP, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED); return NULL; } - pr = sk_OSSL_CMP_POLLREQ_value(prc, OSSL_CMP_CERTREQID); + pr = sk_OSSL_CMP_POLLREQ_value(prc, 0); certReqId = ossl_cmp_asn1_get_int(pr->certReqId); - if (certReqId != srv_ctx->certReqId) { - ERR_raise(ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID); - return NULL; - } if (!srv_ctx->process_pollReq(srv_ctx, req, certReqId, - &certReq, &check_after)) + &orig_req, &check_after)) return NULL; - if (certReq != NULL) { - msg = process_cert_request(srv_ctx, certReq); - OSSL_CMP_MSG_free(certReq); + if (orig_req != NULL) { + srv_ctx->polling = 0; + msg = process_non_polling_request(srv_ctx, orig_req); + OSSL_CMP_MSG_free(orig_req); } else { if ((msg = ossl_cmp_pollRep_new(srv_ctx->ctx, certReqId, check_after)) == NULL) @@ -488,6 +603,12 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, if (!OSSL_CMP_CTX_set1_recipient(ctx, hdr->sender->d.directoryName)) goto err; + if (srv_ctx->polling && req_type != OSSL_CMP_PKIBODY_POLLREQ + && req_type != OSSL_CMP_PKIBODY_ERROR) { + ERR_raise(ERR_LIB_CMP, CMP_R_EXPECTED_POLLREQ); + goto err; + } + switch (req_type) { case OSSL_CMP_PKIBODY_IR: case OSSL_CMP_PKIBODY_CR: @@ -509,6 +630,13 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, if (!OSSL_CMP_CTX_set1_transactionID(ctx, NULL) || !OSSL_CMP_CTX_set1_senderNonce(ctx, NULL)) goto err; + + if (srv_ctx->clean_transaction != NULL + && !srv_ctx->clean_transaction(srv_ctx, NULL)) { + ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE); + goto err; + } + break; default: /* transactionID should be already initialized */ @@ -528,50 +656,17 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, if (!req_verified) goto err; - switch (req_type) { - case OSSL_CMP_PKIBODY_IR: - case OSSL_CMP_PKIBODY_CR: - case OSSL_CMP_PKIBODY_P10CR: - case OSSL_CMP_PKIBODY_KUR: - if (srv_ctx->process_cert_request == NULL) - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - else - rsp = process_cert_request(srv_ctx, req); - break; - case OSSL_CMP_PKIBODY_RR: - if (srv_ctx->process_rr == NULL) - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - else - rsp = process_rr(srv_ctx, req); - break; - case OSSL_CMP_PKIBODY_GENM: - if (srv_ctx->process_genm == NULL) - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - else - rsp = process_genm(srv_ctx, req); - break; - case OSSL_CMP_PKIBODY_ERROR: - if (srv_ctx->process_error == NULL) - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - else - rsp = process_error(srv_ctx, req); - break; - case OSSL_CMP_PKIBODY_CERTCONF: - if (srv_ctx->process_certConf == NULL) - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - else - rsp = process_certConf(srv_ctx, req); - break; - case OSSL_CMP_PKIBODY_POLLREQ: + if (req_type == OSSL_CMP_PKIBODY_POLLREQ) { if (srv_ctx->process_pollReq == NULL) - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); else rsp = process_pollReq(srv_ctx, req); - break; - default: - /* Other request message types are not supported */ - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - break; + } else { + if (srv_ctx->delayed_delivery != NULL + && (rsp = delayed_delivery(srv_ctx, req)) != NULL) { + goto err; + } + rsp = process_non_polling_request(srv_ctx, req); } err: @@ -627,12 +722,19 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, break; /* fall through */ + case OSSL_CMP_PKIBODY_ERROR: + if (rsp != NULL && ossl_cmp_is_error_with_waiting(rsp)) + break; + /* fall through */ + case OSSL_CMP_PKIBODY_RP: case OSSL_CMP_PKIBODY_PKICONF: case OSSL_CMP_PKIBODY_GENP: - case OSSL_CMP_PKIBODY_ERROR: /* Other terminating response message types are not supported */ + srv_ctx->certReqId = OSSL_CMP_CERTREQID_INVALID; /* Prepare for next transaction, ignoring any errors here: */ + if (srv_ctx->clean_transaction != NULL) + (void)srv_ctx->clean_transaction(srv_ctx, ctx->transactionID); (void)OSSL_CMP_CTX_set1_transactionID(ctx, NULL); (void)OSSL_CMP_CTX_set1_senderNonce(ctx, NULL); ctx->status = OSSL_CMP_PKISTATUS_unspecified; /* transaction closed */ diff --git a/crypto/cmp/cmp_vfy.c b/crypto/cmp/cmp_vfy.c index 1869fae696357bb1aab7860416461d1b152b9c2a..5944b43526d08eebc687791b89f64988b5b53f4d 100644 --- a/crypto/cmp/cmp_vfy.c +++ b/crypto/cmp/cmp_vfy.c @@ -786,10 +786,26 @@ int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, CMP_R_TRANSACTIONID_UNMATCHED)) return 0; + /* + * enable clearing irrelevant errors + * in attempts to validate recipient nonce in case of delayed delivery. + */ + (void)ERR_set_mark(); /* compare received nonce with the one we sent */ if (!check_transactionID_or_nonce(ctx->senderNonce, hdr->recipNonce, - CMP_R_RECIPNONCE_UNMATCHED)) - return 0; + CMP_R_RECIPNONCE_UNMATCHED)) { + /* check if we are polling and received final response */ + if (ctx->first_senderNonce == NULL + || OSSL_CMP_MSG_get_bodytype(msg) == OSSL_CMP_PKIBODY_POLLREP + /* compare received nonce with our sender nonce at poll start */ + || !check_transactionID_or_nonce(ctx->first_senderNonce, + hdr->recipNonce, + CMP_R_RECIPNONCE_UNMATCHED)) { + (void)ERR_clear_last_mark(); + return 0; + } + } + (void)ERR_pop_to_mark(); /* if not yet present, learn transactionID */ if (ctx->transactionID == NULL diff --git a/crypto/conf/conf_err.c b/crypto/conf/conf_err.c index 68ee90b97055e77a2f7f2b2cdf4999703170c5b6..9f1309c507c5bd36f4149c17c1c77efbf81068fe 100644 --- a/crypto/conf/conf_err.c +++ b/crypto/conf/conf_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2021 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 @@ -41,6 +41,8 @@ static const ERR_STRING_DATA CONF_str_reasons[] = { "openssl conf references missing section"}, {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_RECURSIVE_DIRECTORY_INCLUDE), "recursive directory include"}, + {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_RECURSIVE_SECTION_REFERENCE), + "recursive section reference"}, {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_RELATIVE_PATH), "relative path"}, {ERR_PACK(ERR_LIB_CONF, 0, CONF_R_SSL_COMMAND_SECTION_EMPTY), "ssl command section empty"}, diff --git a/crypto/ec/asm/ecp_sm2p256-armv8.pl b/crypto/ec/asm/ecp_sm2p256-armv8.pl index 50950865e43402bd9db9ad9cfb286d88c248c660..62fadc0454afe43ab49a496c9bc35b60a5ddb77d 100644 --- a/crypto/ec/asm/ecp_sm2p256-armv8.pl +++ b/crypto/ec/asm/ecp_sm2p256-armv8.pl @@ -28,44 +28,44 @@ my ($t4,$t5,$t6,$t7,$t8)=map("x$_",(15..19)); sub bn_mod_add() { my $mod = shift; $code.=<<___; - # Load inputs + // Load inputs ldp $s0,$s1,[x1] ldp $s2,$s3,[x1,#16] ldp $s4,$s5,[x2] ldp $s6,$s7,[x2,#16] - # Addition + // Addition adds $s0,$s0,$s4 adcs $s1,$s1,$s5 adcs $s2,$s2,$s6 adcs $s3,$s3,$s7 adc $t4,xzr,xzr - # Load polynomial + // Load polynomial adr x2,$mod ldp $s4,$s5,[x2] ldp $s6,$s7,[x2,#16] - # Backup Addition + // Backup Addition mov $t0,$s0 mov $t1,$s1 mov $t2,$s2 mov $t3,$s3 - # Sub polynomial + // Sub polynomial subs $t0,$t0,$s4 sbcs $t1,$t1,$s5 sbcs $t2,$t2,$s6 sbcs $t3,$t3,$s7 sbcs $t4,$t4,xzr - # Select based on carry + // Select based on carry csel $s0,$s0,$t0,cc csel $s1,$s1,$t1,cc csel $s2,$s2,$t2,cc csel $s3,$s3,$t3,cc - # Store results + // Store results stp $s0,$s1,[x0] stp $s2,$s3,[x0,#16] ___ @@ -74,44 +74,44 @@ ___ sub bn_mod_sub() { my $mod = shift; $code.=<<___; - # Load inputs + // Load inputs ldp $s0,$s1,[x1] ldp $s2,$s3,[x1,#16] ldp $s4,$s5,[x2] ldp $s6,$s7,[x2,#16] - # Subtraction + // Subtraction subs $s0,$s0,$s4 sbcs $s1,$s1,$s5 sbcs $s2,$s2,$s6 sbcs $s3,$s3,$s7 sbc $t4,xzr,xzr - # Load polynomial + // Load polynomial adr x2,$mod ldp $s4,$s5,[x2] ldp $s6,$s7,[x2,#16] - # Backup subtraction + // Backup subtraction mov $t0,$s0 mov $t1,$s1 mov $t2,$s2 mov $t3,$s3 - # Add polynomial + // Add polynomial adds $t0,$t0,$s4 adcs $t1,$t1,$s5 adcs $t2,$t2,$s6 adcs $t3,$t3,$s7 tst $t4,$t4 - # Select based on carry + // Select based on carry csel $s0,$s0,$t0,eq csel $s1,$s1,$t1,eq csel $s2,$s2,$t2,eq csel $s3,$s3,$t3,eq - # Store results + // Store results stp $s0,$s1,[x0] stp $s2,$s3,[x0,#16] ___ @@ -120,38 +120,38 @@ ___ sub bn_mod_div_by_2() { my $mod = shift; $code.=<<___; - # Load inputs + // Load inputs ldp $s0,$s1,[x1] ldp $s2,$s3,[x1,#16] - # Save the least significant bit + // Save the least significant bit mov $t0,$s0 - # Right shift 1 + // Right shift 1 extr $s0,$s1,$s0,#1 extr $s1,$s2,$s1,#1 extr $s2,$s3,$s2,#1 lsr $s3,$s3,#1 - # Load mod + // Load mod adr x2,$mod ldp $s4,$s5,[x2] ldp $s6,$s7,[x2,#16] - # Parity check + // Parity check tst $t0,#1 csel $s4,xzr,$s4,eq csel $s5,xzr,$s5,eq csel $s6,xzr,$s6,eq csel $s7,xzr,$s7,eq - # Add + // Add adds $s0,$s0,$s4 adcs $s1,$s1,$s5 adcs $s2,$s2,$s6 adc $s3,$s3,$s7 - # Store results + // Store results stp $s0,$s1,[x0] stp $s2,$s3,[x0,#16] ___ @@ -183,17 +183,17 @@ $code.=<<___; .align 5 bn_rshift1: AARCH64_VALID_CALL_TARGET - # Load inputs + // Load inputs ldp $s0,$s1,[x0] ldp $s2,$s3,[x0,#16] - # Right shift + // Right shift extr $s0,$s1,$s0,#1 extr $s1,$s2,$s1,#1 extr $s2,$s3,$s2,#1 lsr $s3,$s3,#1 - # Store results + // Store results stp $s0,$s1,[x0] stp $s2,$s3,[x0,#16] @@ -206,19 +206,19 @@ bn_rshift1: .align 5 bn_sub: AARCH64_VALID_CALL_TARGET - # Load inputs + // Load inputs ldp $s0,$s1,[x1] ldp $s2,$s3,[x1,#16] ldp $s4,$s5,[x2] ldp $s6,$s7,[x2,#16] - # Subtraction + // Subtraction subs $s0,$s0,$s4 sbcs $s1,$s1,$s5 sbcs $s2,$s2,$s6 sbc $s3,$s3,$s7 - # Store results + // Store results stp $s0,$s1,[x0] stp $s2,$s3,[x0,#16] @@ -255,11 +255,11 @@ $code.=<<___; .align 5 ecp_sm2p256_mul_by_3: AARCH64_VALID_CALL_TARGET - # Load inputs + // Load inputs ldp $s0,$s1,[x1] ldp $s2,$s3,[x1,#16] - # 2*a + // 2*a adds $s0,$s0,$s0 adcs $s1,$s1,$s1 adcs $s2,$s2,$s2 @@ -271,7 +271,7 @@ ecp_sm2p256_mul_by_3: mov $t2,$s2 mov $t3,$s3 - # Sub polynomial + // Sub polynomial adr x2,.Lpoly ldp $s4,$s5,[x2] ldp $s6,$s7,[x2,#16] @@ -287,7 +287,7 @@ ecp_sm2p256_mul_by_3: csel $s3,$s3,$t3,cs eor $t4,$t4,$t4 - # 3*a + // 3*a ldp $s4,$s5,[x1] ldp $s6,$s7,[x1,#16] adds $s0,$s0,$s4 @@ -301,7 +301,7 @@ ecp_sm2p256_mul_by_3: mov $t2,$s2 mov $t3,$s3 - # Sub polynomial + // Sub polynomial adr x2,.Lpoly ldp $s4,$s5,[x2] ldp $s6,$s7,[x2,#16] @@ -316,7 +316,7 @@ ecp_sm2p256_mul_by_3: csel $s2,$s2,$t2,cs csel $s3,$s3,$t3,cs - # Store results + // Store results stp $s0,$s1,[x0] stp $s2,$s3,[x0,#16] @@ -360,45 +360,45 @@ $code.=<<___; .size ecp_sm2p256_sub_mod_ord,.-ecp_sm2p256_sub_mod_ord .macro RDC - # a = | s7 | ... | s0 |, where si are 64-bit quantities - # = |a15|a14| ... |a1|a0|, where ai are 32-bit quantities - # | s7 | s6 | s5 | s4 | - # | a15 | a14 | a13 | a12 | a11 | a10 | a9 | a8 | - # | s3 | s2 | s1 | s0 | - # | a7 | a6 | a5 | a4 | a3 | a2 | a1 | a0 | - # ================================================= - # | a8 | a11 | a10 | a9 | a8 | 0 | s4 | (+) - # | a9 | a15 | s6 | a11 | 0 | a10 | a9 | (+) - # | a10 | 0 | a14 | a13 | a12 | 0 | s5 | (+) - # | a11 | 0 | s7 | a13 | 0 | a12 | a11 | (+) - # | a12 | 0 | s7 | a13 | 0 | s6 | (+) - # | a12 | 0 | 0 | a15 | a14 | 0 | a14 | a13 | (+) - # | a13 | 0 | 0 | 0 | a15 | 0 | a14 | a13 | (+) - # | a13 | 0 | 0 | 0 | 0 | 0 | s7 | (+) - # | a14 | 0 | 0 | 0 | 0 | 0 | s7 | (+) - # | a14 | 0 | 0 | 0 | 0 | 0 | 0 | a15 | (+) - # | a15 | 0 | 0 | 0 | 0 | 0 | 0 | a15 | (+) - # | a15 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | (+) - # | s7 | 0 | 0 | 0 | 0 | 0 | 0 | (+) - # | 0 | 0 | 0 | 0 | 0 | a8 | 0 | 0 | (-) - # | 0 | 0 | 0 | 0 | 0 | a9 | 0 | 0 | (-) - # | 0 | 0 | 0 | 0 | 0 | a13 | 0 | 0 | (-) - # | 0 | 0 | 0 | 0 | 0 | a14 | 0 | 0 | (-) - # | U[7]| U[6]| U[5]| U[4]| U[3]| U[2]| U[1]| U[0]| - # | V[3] | V[2] | V[1] | V[0] | - - # 1. 64-bit addition - # t2=s6+s7+s7 + // a = | s7 | ... | s0 |, where si are 64-bit quantities + // = |a15|a14| ... |a1|a0|, where ai are 32-bit quantities + // | s7 | s6 | s5 | s4 | + // | a15 | a14 | a13 | a12 | a11 | a10 | a9 | a8 | + // | s3 | s2 | s1 | s0 | + // | a7 | a6 | a5 | a4 | a3 | a2 | a1 | a0 | + // ================================================= + // | a8 | a11 | a10 | a9 | a8 | 0 | s4 | (+) + // | a9 | a15 | s6 | a11 | 0 | a10 | a9 | (+) + // | a10 | 0 | a14 | a13 | a12 | 0 | s5 | (+) + // | a11 | 0 | s7 | a13 | 0 | a12 | a11 | (+) + // | a12 | 0 | s7 | a13 | 0 | s6 | (+) + // | a12 | 0 | 0 | a15 | a14 | 0 | a14 | a13 | (+) + // | a13 | 0 | 0 | 0 | a15 | 0 | a14 | a13 | (+) + // | a13 | 0 | 0 | 0 | 0 | 0 | s7 | (+) + // | a14 | 0 | 0 | 0 | 0 | 0 | s7 | (+) + // | a14 | 0 | 0 | 0 | 0 | 0 | 0 | a15 | (+) + // | a15 | 0 | 0 | 0 | 0 | 0 | 0 | a15 | (+) + // | a15 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | (+) + // | s7 | 0 | 0 | 0 | 0 | 0 | 0 | (+) + // | 0 | 0 | 0 | 0 | 0 | a8 | 0 | 0 | (-) + // | 0 | 0 | 0 | 0 | 0 | a9 | 0 | 0 | (-) + // | 0 | 0 | 0 | 0 | 0 | a13 | 0 | 0 | (-) + // | 0 | 0 | 0 | 0 | 0 | a14 | 0 | 0 | (-) + // | U[7]| U[6]| U[5]| U[4]| U[3]| U[2]| U[1]| U[0]| + // | V[3] | V[2] | V[1] | V[0] | + + // 1. 64-bit addition + // t2=s6+s7+s7 adds $t2,$s6,$s7 adcs $t1,xzr,xzr adds $t2,$t2,$s7 adcs $t1,$t1,xzr - # t3=s4+s5+t2 + // t3=s4+s5+t2 adds $t3,$s4,$t2 adcs $t4,$t1,xzr adds $t3,$t3,$s5 adcs $t4,$t4,xzr - # sum + // sum adds $s0,$s0,$t3 adcs $s1,$s1,$t4 adcs $s2,$s2,$t2 @@ -410,7 +410,7 @@ $code.=<<___; stp $s0,$s1,[sp,#32] stp $s2,$s3,[sp,#48] - # 2. 64-bit to 32-bit spread + // 2. 64-bit to 32-bit spread mov $t1,#0xffffffff mov $s0,$s4 mov $s1,$s5 @@ -425,7 +425,7 @@ $code.=<<___; lsr $s6,$s6,#32 // a13 lsr $s7,$s7,#32 // a15 - # 3. 32-bit addition + // 3. 32-bit addition add $t1,$a14,$a12 // t1 <- a12 + a14 add $t2,$a15,$a13 // t2 <- a13 + a15 add $t3,$a8,$a9 // t3 <- a8 + a9 @@ -446,53 +446,53 @@ $code.=<<___; add $a11,$a11,$t2 // a11 <- a9 + a11 + 2*(a13 + a15) add $t1,$t1,$t4 // t1 <- a10 + a12 + 2*a14 - # U[0] s5 a9 + a11 + 2*(a13 + a15) - # U[1] t1 a10 + a12 + 2*a14 - # U[2] -t3 a8 + a9 + a13 + a14 - # U[3] s2 a8 + a11 + a12 + 2*a13 + a14 + a15 - # U[4] s4 a9 + a13 + a15 - # U[5] t4 a10 + a14 - # U[6] s7 a11 + a15 - # U[7] s1 a8 + a9 + a10 + a11 + 2*(a12 + a13 + a14 + a15) + // U[0] s5 a9 + a11 + 2*(a13 + a15) + // U[1] t1 a10 + a12 + 2*a14 + // U[2] -t3 a8 + a9 + a13 + a14 + // U[3] s2 a8 + a11 + a12 + 2*a13 + a14 + a15 + // U[4] s4 a9 + a13 + a15 + // U[5] t4 a10 + a14 + // U[6] s7 a11 + a15 + // U[7] s1 a8 + a9 + a10 + a11 + 2*(a12 + a13 + a14 + a15) - # 4. 32-bit to 64-bit + // 4. 32-bit to 64-bit lsl $s0,$t1,#32 extr $t1,$s2,$t1,#32 extr $s2,$t4,$s2,#32 extr $t4,$s1,$t4,#32 lsr $s1,$s1,#32 - # 5. 64-bit addition + // 5. 64-bit addition adds $s5,$s5,$s0 adcs $t1,$t1,xzr adcs $s4,$s4,$s2 adcs $s7,$s7,$t4 adcs $t0,$t0,$s1 - # V[0] s5 - # V[1] t1 - # V[2] s4 - # V[3] s7 - # carry t0 - # sub t3 + // V[0] s5 + // V[1] t1 + // V[2] s4 + // V[3] s7 + // carry t0 + // sub t3 - # 5. Process s0-s3 + // 5. Process s0-s3 ldp $s0,$s1,[sp,#32] ldp $s2,$s3,[sp,#48] - # add with V0-V3 + // add with V0-V3 adds $s0,$s0,$s5 adcs $s1,$s1,$t1 adcs $s2,$s2,$s4 adcs $s3,$s3,$s7 adcs $t0,$t0,xzr - # sub with t3 + // sub with t3 subs $s1,$s1,$t3 sbcs $s2,$s2,xzr sbcs $s3,$s3,xzr sbcs $t0,$t0,xzr - # 6. MOD - # First Mod + // 6. MOD + // First Mod lsl $t1,$t0,#32 subs $t2,$t1,$t0 @@ -501,8 +501,8 @@ $code.=<<___; adcs $s2,$s2,xzr adcs $s3,$s3,$t1 - # Last Mod - # return y - p if y > p else y + // Last Mod + // return y - p if y > p else y mov $s4,$s0 mov $s5,$s1 mov $s6,$s2 @@ -533,44 +533,44 @@ $code.=<<___; .align 5 ecp_sm2p256_mul: AARCH64_SIGN_LINK_REGISTER - # Store scalar registers + // Store scalar registers stp x29,x30,[sp,#-80]! add x29,sp,#0 stp x16,x17,[sp,#16] stp x18,x19,[sp,#64] - # Load inputs + // Load inputs ldp $s0,$s1,[x1] ldp $s2,$s3,[x1,#16] ldp $s4,$s5,[x2] ldp $s6,$s7,[x2,#16] -### multiplication ### - # ======================== - # s3 s2 s1 s0 - # * s7 s6 s5 s4 - # ------------------------ - # + s0 s0 s0 s0 - # * * * * - # s7 s6 s5 s4 - # s1 s1 s1 s1 - # * * * * - # s7 s6 s5 s4 - # s2 s2 s2 s2 - # * * * * - # s7 s6 s5 s4 - # s3 s3 s3 s3 - # * * * * - # s7 s6 s5 s4 - # ------------------------ - # s7 s6 s5 s4 s3 s2 s1 s0 - # ======================== - -### s0*s4 ### +// ### multiplication ### + // ======================== + // s3 s2 s1 s0 + // * s7 s6 s5 s4 + // ------------------------ + // + s0 s0 s0 s0 + // * * * * + // s7 s6 s5 s4 + // s1 s1 s1 s1 + // * * * * + // s7 s6 s5 s4 + // s2 s2 s2 s2 + // * * * * + // s7 s6 s5 s4 + // s3 s3 s3 s3 + // * * * * + // s7 s6 s5 s4 + // ------------------------ + // s7 s6 s5 s4 s3 s2 s1 s0 + // ======================== + +// ### s0*s4 ### mul $t5,$s0,$s4 umulh $t2,$s0,$s4 -### s1*s4 + s0*s5 ### +// ### s1*s4 + s0*s5 ### mul $t0,$s1,$s4 umulh $t1,$s1,$s4 adds $t2,$t2,$t0 @@ -582,7 +582,7 @@ ecp_sm2p256_mul: adcs $t3,$t3,$t1 adcs $t4,xzr,xzr -### s2*s4 + s1*s5 + s0*s6 ### +// ### s2*s4 + s1*s5 + s0*s6 ### mul $t0,$s2,$s4 umulh $t1,$s2,$s4 adds $t3,$t3,$t0 @@ -600,7 +600,7 @@ ecp_sm2p256_mul: adcs $t4,$t4,$t1 adcs $t6,$t6,xzr -### s3*s4 + s2*s5 + s1*s6 + s0*s7 ### +// ### s3*s4 + s2*s5 + s1*s6 + s0*s7 ### mul $t0,$s3,$s4 umulh $t1,$s3,$s4 adds $t4,$t4,$t0 @@ -625,7 +625,7 @@ ecp_sm2p256_mul: adcs $t6,$t6,$t1 adcs $t7,$t7,xzr -### s3*s5 + s2*s6 + s1*s7 ### +// ### s3*s5 + s2*s6 + s1*s7 ### mul $t0,$s3,$s5 umulh $t1,$s3,$s5 adds $t6,$t6,$t0 @@ -644,7 +644,7 @@ ecp_sm2p256_mul: adcs $t7,$t7,$t1 adcs $t8,$t8,xzr -### s3*s6 + s2*s7 ### +// ### s3*s6 + s2*s7 ### mul $t0,$s3,$s6 umulh $t1,$s3,$s6 adds $t7,$t7,$t0 @@ -657,7 +657,7 @@ ecp_sm2p256_mul: adcs $t8,$t8,$t1 adcs $t6,$t6,xzr -### s3*s7 ### +// ### s3*s7 ### mul $t0,$s3,$s7 umulh $t1,$s3,$s7 adds $s6,$t8,$t0 @@ -668,15 +668,15 @@ ecp_sm2p256_mul: mov $s2,$t3 mov $s3,$t4 - # result of mul: s7 s6 s5 s4 s3 s2 s1 s0 + // result of mul: s7 s6 s5 s4 s3 s2 s1 s0 -### Reduction ### +// ### Reduction ### RDC stp $s0,$s1,[x0] stp $s2,$s3,[x0,#16] - # Restore scalar registers + // Restore scalar registers ldp x16,x17,[sp,#16] ldp x18,x19,[sp,#64] ldp x29,x30,[sp],#80 @@ -692,48 +692,48 @@ ecp_sm2p256_mul: ecp_sm2p256_sqr: AARCH64_SIGN_LINK_REGISTER - # Store scalar registers + // Store scalar registers stp x29,x30,[sp,#-80]! add x29,sp,#0 stp x16,x17,[sp,#16] stp x18,x19,[sp,#64] - # Load inputs + // Load inputs ldp $s4,$s5,[x1] ldp $s6,$s7,[x1,#16] -### square ### - # ======================== - # s7 s6 s5 s4 - # * s7 s6 s5 s4 - # ------------------------ - # + s4 s4 s4 s4 - # * * * * - # s7 s6 s5 s4 - # s5 s5 s5 s5 - # * * * * - # s7 s6 s5 s4 - # s6 s6 s6 s6 - # * * * * - # s7 s6 s5 s4 - # s7 s7 s7 s7 - # * * * * - # s7 s6 s5 s4 - # ------------------------ - # s7 s6 s5 s4 s3 s2 s1 s0 - # ======================== - -### s4*s5 ### +// ### square ### + // ======================== + // s7 s6 s5 s4 + // * s7 s6 s5 s4 + // ------------------------ + // + s4 s4 s4 s4 + // * * * * + // s7 s6 s5 s4 + // s5 s5 s5 s5 + // * * * * + // s7 s6 s5 s4 + // s6 s6 s6 s6 + // * * * * + // s7 s6 s5 s4 + // s7 s7 s7 s7 + // * * * * + // s7 s6 s5 s4 + // ------------------------ + // s7 s6 s5 s4 s3 s2 s1 s0 + // ======================== + +// ### s4*s5 ### mul $s1,$s4,$s5 umulh $s2,$s4,$s5 -### s4*s6 ### +// ### s4*s6 ### mul $t0,$s6,$s4 umulh $s3,$s6,$s4 adds $s2,$s2,$t0 adcs $s3,$s3,xzr -### s4*s7 + s5*s6 ### +// ### s4*s7 + s5*s6 ### mul $t0,$s7,$s4 umulh $t1,$s7,$s4 adds $s3,$s3,$t0 @@ -745,19 +745,19 @@ ecp_sm2p256_sqr: adcs $s0,$s0,$t1 adcs $t2,xzr,xzr -### s5*s7 ### +// ### s5*s7 ### mul $t0,$s7,$s5 umulh $t1,$s7,$s5 adds $s0,$s0,$t0 adcs $t2,$t2,$t1 -### s6*s7 ### +// ### s6*s7 ### mul $t0,$s7,$s6 umulh $t1,$s7,$s6 adds $t2,$t2,$t0 adcs $t3,$t1,xzr -### 2*(t3,t2,s0,s3,s2,s1) ### +// ### 2*(t3,t2,s0,s3,s2,s1) ### adds $s1,$s1,$s1 adcs $s2,$s2,$s2 adcs $s3,$s3,$s3 @@ -766,19 +766,19 @@ ecp_sm2p256_sqr: adcs $t3,$t3,$t3 adcs $t4,xzr,xzr -### s4*s4 ### +// ### s4*s4 ### mul $t5,$s4,$s4 umulh $t6,$s4,$s4 -### s5*s5 ### +// ### s5*s5 ### mul $s4,$s5,$s5 umulh $s5,$s5,$s5 -### s6*s6 ### +// ### s6*s6 ### mul $t0,$s6,$s6 umulh $t1,$s6,$s6 -### s7*s7 ### +// ### s7*s7 ### mul $t7,$s7,$s7 umulh $t8,$s7,$s7 @@ -796,15 +796,15 @@ ecp_sm2p256_sqr: mov $s6,$t3 mov $s7,$t4 - # result of mul: s7 s6 s5 s4 s3 s2 s1 s0 + // result of mul: s7 s6 s5 s4 s3 s2 s1 s0 -### Reduction ### +// ### Reduction ### RDC stp $s0,$s1,[x0] stp $s2,$s3,[x0,#16] - # Restore scalar registers + // Restore scalar registers ldp x16,x17,[sp,#16] ldp x18,x19,[sp,#64] ldp x29,x30,[sp],#80 diff --git a/crypto/ec/ecp_sm2p256.c b/crypto/ec/ecp_sm2p256.c index 6ec42455299b31772c53f07e923a510f57a9cc7b..7668b61378b629fd0ae17ccb317cd943a6376a17 100644 --- a/crypto/ec/ecp_sm2p256.c +++ b/crypto/ec/ecp_sm2p256.c @@ -40,28 +40,28 @@ typedef struct { #if !defined(OPENSSL_NO_SM2_PRECOMP) /* Coordinates of G, for which we have precomputed tables */ -static const BN_ULONG def_xG[P256_LIMBS] ALIGN32 = { +ALIGN32 static const BN_ULONG def_xG[P256_LIMBS] = { 0x715a4589334c74c7, 0x8fe30bbff2660be1, 0x5f9904466a39c994, 0x32c4ae2c1f198119 }; -static const BN_ULONG def_yG[P256_LIMBS] ALIGN32 = { +ALIGN32 static const BN_ULONG def_yG[P256_LIMBS] = { 0x02df32e52139f0a0, 0xd0a9877cc62a4740, 0x59bdcee36b692153, 0xbc3736a2f4f6779c, }; #endif /* p and order for SM2 according to GB/T 32918.5-2017 */ -static const BN_ULONG def_p[P256_LIMBS] ALIGN32 = { +ALIGN32 static const BN_ULONG def_p[P256_LIMBS] = { 0xffffffffffffffff, 0xffffffff00000000, 0xffffffffffffffff, 0xfffffffeffffffff }; -static const BN_ULONG def_ord[P256_LIMBS] ALIGN32 = { +ALIGN32 static const BN_ULONG def_ord[P256_LIMBS] = { 0x53bbf40939d54123, 0x7203df6b21c6052b, 0xffffffffffffffff, 0xfffffffeffffffff }; -static const BN_ULONG ONE[P256_LIMBS] ALIGN32 = {1, 0, 0, 0}; +ALIGN32 static const BN_ULONG ONE[P256_LIMBS] = {1, 0, 0, 0}; /* Functions implemented in assembly */ /* @@ -139,10 +139,10 @@ static ossl_inline int is_greater(const BN_ULONG *a, const BN_ULONG *b) /* Binary algorithm for inversion in Fp */ #define BN_MOD_INV(out, in, mod_div, mod_sub, mod) \ do { \ - BN_ULONG u[4] ALIGN32; \ - BN_ULONG v[4] ALIGN32; \ - BN_ULONG x1[4] ALIGN32 = {1, 0, 0, 0}; \ - BN_ULONG x2[4] ALIGN32 = {0}; \ + ALIGN32 BN_ULONG u[4]; \ + ALIGN32 BN_ULONG v[4]; \ + ALIGN32 BN_ULONG x1[4] = {1, 0, 0, 0}; \ + ALIGN32 BN_ULONG x2[4] = {0}; \ \ if (is_zeros(in)) \ return; \ @@ -188,9 +188,9 @@ static ossl_inline void ecp_sm2p256_mod_ord_inverse(BN_ULONG* out, static void ecp_sm2p256_point_double(P256_POINT *R, const P256_POINT *P) { unsigned int i; - BN_ULONG tmp0[P256_LIMBS] ALIGN32; - BN_ULONG tmp1[P256_LIMBS] ALIGN32; - BN_ULONG tmp2[P256_LIMBS] ALIGN32; + ALIGN32 BN_ULONG tmp0[P256_LIMBS]; + ALIGN32 BN_ULONG tmp1[P256_LIMBS]; + ALIGN32 BN_ULONG tmp2[P256_LIMBS]; /* zero-check P->Z */ if (is_zeros(P->Z)) { @@ -225,10 +225,10 @@ static void ecp_sm2p256_point_add_affine(P256_POINT *R, const P256_POINT *P, const P256_POINT_AFFINE *Q) { unsigned int i; - BN_ULONG tmp0[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG tmp1[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG tmp2[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG tmp3[P256_LIMBS] ALIGN32 = {0}; + ALIGN32 BN_ULONG tmp0[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG tmp1[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG tmp2[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG tmp3[P256_LIMBS] = {0}; /* zero-check P->Z */ if (is_zeros(P->Z)) { @@ -288,9 +288,9 @@ static void ecp_sm2p256_point_add(P256_POINT *R, const P256_POINT *P, const P256_POINT *Q) { unsigned int i; - BN_ULONG tmp0[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG tmp1[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG tmp2[P256_LIMBS] ALIGN32 = {0}; + ALIGN32 BN_ULONG tmp0[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG tmp1[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG tmp2[P256_LIMBS] = {0}; /* zero-check P | Q ->Z */ if (is_zeros(P->Z)) { @@ -382,7 +382,7 @@ static void ecp_sm2p256_point_P_mul_by_scalar(P256_POINT *R, const BN_ULONG *k, { int i, init = 0; unsigned int index, mask = 0x0f; - P256_POINT precomputed[16] ALIGN64; + ALIGN64 P256_POINT precomputed[16]; memset(R, 0, sizeof(P256_POINT)); @@ -427,8 +427,8 @@ static void ecp_sm2p256_point_P_mul_by_scalar(P256_POINT *R, const BN_ULONG *k, static void ecp_sm2p256_point_get_affine(P256_POINT_AFFINE *R, const P256_POINT *P) { - BN_ULONG z_inv3[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG z_inv2[P256_LIMBS] ALIGN32 = {0}; + ALIGN32 BN_ULONG z_inv3[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG z_inv2[P256_LIMBS] = {0}; if (is_one(P->Z)) { memcpy(R->X, P->X, 32); @@ -461,13 +461,13 @@ static int ecp_sm2p256_get_affine(const EC_GROUP *group, const EC_POINT *point, BIGNUM *x, BIGNUM *y, BN_CTX *ctx) { - BN_ULONG z_inv2[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG z_inv3[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG x_aff[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG y_aff[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG point_x[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG point_y[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG point_z[P256_LIMBS] ALIGN32 = {0}; + ALIGN32 BN_ULONG z_inv2[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG z_inv3[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG x_aff[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG y_aff[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG point_x[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG point_y[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG point_z[P256_LIMBS] = {0}; if (EC_POINT_is_at_infinity(group, point)) { ECerr(ERR_LIB_EC, EC_R_POINT_AT_INFINITY); @@ -510,7 +510,7 @@ static int ecp_sm2p256_windowed_mul(const EC_GROUP *group, unsigned int i; int ret = 0; const BIGNUM **scalars = NULL; - BN_ULONG k[P256_LIMBS] ALIGN32 = {0}; + ALIGN32 BN_ULONG k[P256_LIMBS] = {0}; P256_POINT kP; ALIGN32 union { P256_POINT p; @@ -572,7 +572,7 @@ static int ecp_sm2p256_points_mul(const EC_GROUP *group, { int ret = 0, p_is_infinity = 0; const EC_POINT *generator = NULL; - BN_ULONG k[P256_LIMBS] ALIGN32 = {0}; + ALIGN32 BN_ULONG k[P256_LIMBS] = {0}; ALIGN32 union { P256_POINT p; P256_POINT_AFFINE a; @@ -646,9 +646,9 @@ err: static int ecp_sm2p256_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { - BN_ULONG a_fe[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG b_fe[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG r_fe[P256_LIMBS] ALIGN32 = {0}; + ALIGN32 BN_ULONG a_fe[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG b_fe[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG r_fe[P256_LIMBS] = {0}; if (a == NULL || b == NULL || r == NULL) return 0; @@ -670,8 +670,8 @@ static int ecp_sm2p256_field_mul(const EC_GROUP *group, BIGNUM *r, static int ecp_sm2p256_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) { - BN_ULONG a_fe[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG r_fe[P256_LIMBS] ALIGN32 = {0}; + ALIGN32 BN_ULONG a_fe[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG r_fe[P256_LIMBS] = {0}; if (a == NULL || r == NULL) return 0; @@ -693,8 +693,8 @@ static int ecp_sm2p256_inv_mod_ord(const EC_GROUP *group, BIGNUM *r, const BIGNUM *x, BN_CTX *ctx) { int ret = 0; - BN_ULONG t[P256_LIMBS] ALIGN32 = {0}; - BN_ULONG out[P256_LIMBS] ALIGN32 = {0}; + ALIGN32 BN_ULONG t[P256_LIMBS] = {0}; + ALIGN32 BN_ULONG out[P256_LIMBS] = {0}; if (bn_wexpand(r, P256_LIMBS) == NULL) { ECerr(ERR_LIB_EC, ERR_R_BN_LIB); diff --git a/crypto/err/err_mark.c b/crypto/err/err_mark.c index 82dc4764c498b0d403dd35b6bf2e3008dd67a499..cb01a1f4f699a5d18f920caec29552805e9a0cc7 100644 --- a/crypto/err/err_mark.c +++ b/crypto/err/err_mark.c @@ -26,6 +26,19 @@ int ERR_set_mark(void) return 1; } +int ERR_pop(void) +{ + ERR_STATE *es; + + es = ossl_err_get_state_int(); + if (es == NULL || es->bottom == es->top) + return 0; + + err_clear(es, es->top, 0); + es->top = es->top > 0 ? es->top - 1 : ERR_NUM_ERRORS - 1; + return 1; +} + int ERR_pop_to_mark(void) { ERR_STATE *es; diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 5f60bd52d2d46613e620010b4b166987fe188863..fd6b128a2a5365c0021466b42490c2e5b408436a 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -227,6 +227,7 @@ CMP_R_ERROR_SETTING_CERTHASH:128:error setting certhash CMP_R_ERROR_UNEXPECTED_CERTCONF:160:error unexpected certconf CMP_R_ERROR_VALIDATING_PROTECTION:140:error validating protection CMP_R_ERROR_VALIDATING_SIGNATURE:171:error validating signature +CMP_R_EXPECTED_POLLREQ:104:expected pollreq CMP_R_FAILED_BUILDING_OWN_CHAIN:164:failed building own chain CMP_R_FAILED_EXTRACTING_PUBKEY:141:failed extracting pubkey CMP_R_FAILURE_OBTAINING_RANDOM:110:failure obtaining random @@ -272,14 +273,17 @@ CMP_R_TOTAL_TIMEOUT:184:total timeout CMP_R_TRANSACTIONID_UNMATCHED:152:transactionid unmatched CMP_R_TRANSFER_ERROR:159:transfer error CMP_R_UNCLEAN_CTX:191:unclean ctx +CMP_R_UNEXPECTED_CERTPROFILE:196:unexpected certprofile CMP_R_UNEXPECTED_PKIBODY:133:unexpected pkibody CMP_R_UNEXPECTED_PKISTATUS:185:unexpected pkistatus +CMP_R_UNEXPECTED_POLLREQ:105:unexpected pollreq CMP_R_UNEXPECTED_PVNO:153:unexpected pvno CMP_R_UNKNOWN_ALGORITHM_ID:134:unknown algorithm id CMP_R_UNKNOWN_CERT_TYPE:135:unknown cert type CMP_R_UNKNOWN_PKISTATUS:186:unknown pkistatus CMP_R_UNSUPPORTED_ALGORITHM:136:unsupported algorithm CMP_R_UNSUPPORTED_KEY_TYPE:137:unsupported key type +CMP_R_UNSUPPORTED_PKIBODY:101:unsupported pkibody CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC:154:\ unsupported protection alg dhbasedmac CMP_R_VALUE_TOO_LARGE:175:value too large @@ -424,6 +428,7 @@ CONF_R_NUMBER_TOO_LARGE:121:number too large CONF_R_OPENSSL_CONF_REFERENCES_MISSING_SECTION:124:\ openssl conf references missing section CONF_R_RECURSIVE_DIRECTORY_INCLUDE:111:recursive directory include +CONF_R_RECURSIVE_SECTION_REFERENCE:126:recursive section reference CONF_R_RELATIVE_PATH:125:relative path CONF_R_SSL_COMMAND_SECTION_EMPTY:117:ssl command section empty CONF_R_SSL_COMMAND_SECTION_NOT_FOUND:118:ssl command section not found diff --git a/crypto/loongarch64cpuid.pl b/crypto/loongarch64cpuid.pl index d16a8e98f2251d53ce6d35e806e33d5ba6e01785..8a84caca923b679911c7c23370ec7123da844483 100644 --- a/crypto/loongarch64cpuid.pl +++ b/crypto/loongarch64cpuid.pl @@ -101,8 +101,8 @@ $code.=<<___; .globl OPENSSL_rdtsc .type OPENSSL_rdtsc,\@function OPENSSL_rdtsc: - move $a0,$zero - jr $ra + rdtimel.w $a0,$zero + jr $ra ___ } diff --git a/crypto/provider_conf.c b/crypto/provider_conf.c index 288ade6b4de25bce61d438669c734ad65e4e5071..a4a5c5122b6d27db31a05e6dcb535a1489afbac0 100644 --- a/crypto/provider_conf.c +++ b/crypto/provider_conf.c @@ -64,13 +64,22 @@ static const char *skip_dot(const char *name) return name; } -static int provider_conf_params(OSSL_PROVIDER *prov, - OSSL_PROVIDER_INFO *provinfo, - const char *name, const char *value, - const CONF *cnf) +/* + * Parse the provider params section + * Returns: + * 1 for success + * 0 for non-fatal errors + * < 0 for fatal errors + */ +static int provider_conf_params_internal(OSSL_PROVIDER *prov, + OSSL_PROVIDER_INFO *provinfo, + const char *name, const char *value, + const CONF *cnf, + STACK_OF(OPENSSL_CSTRING) *visited) { STACK_OF(CONF_VALUE) *sect; int ok = 1; + int rc = 0; sect = NCONF_get_section(cnf, value); if (sect != NULL) { @@ -80,6 +89,25 @@ static int provider_conf_params(OSSL_PROVIDER *prov, OSSL_TRACE1(CONF, "Provider params: start section %s\n", value); + /* + * Check to see if the provided section value has already + * been visited. If it has, then we have a recursive lookup + * in the configuration which isn't valid. As such we should error + * out + */ + for (i = 0; i < sk_OPENSSL_CSTRING_num(visited); i++) { + if (sk_OPENSSL_CSTRING_value(visited, i) == value) { + ERR_raise(ERR_LIB_CONF, CONF_R_RECURSIVE_SECTION_REFERENCE); + return -1; + } + } + + /* + * We've not visited this node yet, so record it on the stack + */ + if (!sk_OPENSSL_CSTRING_push(visited, value)) + return -1; + if (name != NULL) { OPENSSL_strlcpy(buffer, name, sizeof(buffer)); OPENSSL_strlcat(buffer, ".", sizeof(buffer)); @@ -89,14 +117,20 @@ static int provider_conf_params(OSSL_PROVIDER *prov, for (i = 0; i < sk_CONF_VALUE_num(sect); i++) { CONF_VALUE *sectconf = sk_CONF_VALUE_value(sect, i); - if (buffer_len + strlen(sectconf->name) >= sizeof(buffer)) - return 0; + if (buffer_len + strlen(sectconf->name) >= sizeof(buffer)) { + sk_OPENSSL_CSTRING_pop(visited); + return -1; + } buffer[buffer_len] = '\0'; OPENSSL_strlcat(buffer, sectconf->name, sizeof(buffer)); - if (!provider_conf_params(prov, provinfo, buffer, sectconf->value, - cnf)) - return 0; + rc = provider_conf_params_internal(prov, provinfo, buffer, + sectconf->value, cnf, visited); + if (rc < 0) { + sk_OPENSSL_CSTRING_pop(visited); + return rc; + } } + sk_OPENSSL_CSTRING_pop(visited); OSSL_TRACE1(CONF, "Provider params: finish section %s\n", value); } else { @@ -110,6 +144,33 @@ static int provider_conf_params(OSSL_PROVIDER *prov, return ok; } +/* + * recursively parse the provider configuration section + * of the config file. + * Returns + * 1 on success + * 0 on non-fatal error + * < 0 on fatal errors + */ +static int provider_conf_params(OSSL_PROVIDER *prov, + OSSL_PROVIDER_INFO *provinfo, + const char *name, const char *value, + const CONF *cnf) +{ + int rc; + STACK_OF(OPENSSL_CSTRING) *visited = sk_OPENSSL_CSTRING_new_null(); + + if (visited == NULL) + return -1; + + rc = provider_conf_params_internal(prov, provinfo, name, + value, cnf, visited); + + sk_OPENSSL_CSTRING_free(visited); + + return rc; +} + static int prov_already_activated(const char *name, STACK_OF(OSSL_PROVIDER) *activated) { @@ -130,6 +191,13 @@ static int prov_already_activated(const char *name, return 0; } +/* + * Attempt to activate a provider + * Returns: + * 1 on successful activation + * 0 on failed activation for non-fatal error + * < 0 on failed activation for fatal errors + */ static int provider_conf_activate(OSSL_LIB_CTX *libctx, const char *name, const char *value, const char *path, int soft, const CONF *cnf) @@ -141,7 +209,7 @@ static int provider_conf_activate(OSSL_LIB_CTX *libctx, const char *name, if (pcgbl == NULL || !CRYPTO_THREAD_write_lock(pcgbl->lock)) { ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); - return 0; + return -1; } if (!prov_already_activated(name, pcgbl->activated_providers)) { /* @@ -154,7 +222,7 @@ static int provider_conf_activate(OSSL_LIB_CTX *libctx, const char *name, if (!ossl_provider_disable_fallback_loading(libctx)) { CRYPTO_THREAD_unlock(pcgbl->lock); ERR_raise(ERR_LIB_CRYPTO, ERR_R_INTERNAL_ERROR); - return 0; + return -1; } prov = ossl_provider_find(libctx, name, 1); if (prov == NULL) @@ -163,7 +231,7 @@ static int provider_conf_activate(OSSL_LIB_CTX *libctx, const char *name, CRYPTO_THREAD_unlock(pcgbl->lock); if (soft) ERR_clear_error(); - return 0; + return (soft == 0) ? -1 : 0; } if (path != NULL) @@ -171,7 +239,7 @@ static int provider_conf_activate(OSSL_LIB_CTX *libctx, const char *name, ok = provider_conf_params(prov, NULL, NULL, value, cnf); - if (ok) { + if (ok == 1) { if (!ossl_provider_activate(prov, 1, 0)) { ok = 0; } else if (!ossl_provider_add_to_store(prov, &actual, 0)) { @@ -195,7 +263,8 @@ static int provider_conf_activate(OSSL_LIB_CTX *libctx, const char *name, } } } - if (!ok) + + if (ok <= 0) ossl_provider_free(prov); } CRYPTO_THREAD_unlock(pcgbl->lock); @@ -212,6 +281,7 @@ static int provider_conf_load(OSSL_LIB_CTX *libctx, const char *name, const char *path = NULL; long activate = 0; int ok = 0; + int added = 0; name = skip_dot(name); OSSL_TRACE1(CONF, "Configuring provider %s\n", name); @@ -236,15 +306,43 @@ static int provider_conf_load(OSSL_LIB_CTX *libctx, const char *name, /* First handle some special pseudo confs */ /* Override provider name to use */ - if (strcmp(confname, "identity") == 0) + if (strcmp(confname, "identity") == 0) { name = confvalue; - else if (strcmp(confname, "soft_load") == 0) + } else if (strcmp(confname, "soft_load") == 0) { soft = 1; /* Load a dynamic PROVIDER */ - else if (strcmp(confname, "module") == 0) + } else if (strcmp(confname, "module") == 0) { path = confvalue; - else if (strcmp(confname, "activate") == 0) - activate = 1; + } else if (strcmp(confname, "activate") == 0) { + if (confvalue == NULL) { + ERR_raise_data(ERR_LIB_CRYPTO, CRYPTO_R_PROVIDER_SECTION_ERROR, + "section=%s activate set to unrecognized value", + value); + return 0; + } + if ((strcmp(confvalue, "1") == 0) + || (strcmp(confvalue, "yes") == 0) + || (strcmp(confvalue, "YES") == 0) + || (strcmp(confvalue, "true") == 0) + || (strcmp(confvalue, "TRUE") == 0) + || (strcmp(confvalue, "on") == 0) + || (strcmp(confvalue, "ON") == 0)) { + activate = 1; + } else if ((strcmp(confvalue, "0") == 0) + || (strcmp(confvalue, "no") == 0) + || (strcmp(confvalue, "NO") == 0) + || (strcmp(confvalue, "false") == 0) + || (strcmp(confvalue, "FALSE") == 0) + || (strcmp(confvalue, "off") == 0) + || (strcmp(confvalue, "OFF") == 0)) { + activate = 0; + } else { + ERR_raise_data(ERR_LIB_CRYPTO, CRYPTO_R_PROVIDER_SECTION_ERROR, + "section=%s activate set to unrecognized value", + value); + return 0; + } + } } if (activate) { @@ -266,19 +364,23 @@ static int provider_conf_load(OSSL_LIB_CTX *libctx, const char *name, } if (ok) ok = provider_conf_params(NULL, &entry, NULL, value, cnf); - if (ok && (entry.path != NULL || entry.parameters != NULL)) + if (ok >= 1 && (entry.path != NULL || entry.parameters != NULL)) { ok = ossl_provider_info_add_to_store(libctx, &entry); - if (!ok || (entry.path == NULL && entry.parameters == NULL)) { - ossl_provider_info_clear(&entry); + added = 1; } - + if (added == 0) + ossl_provider_info_clear(&entry); } /* - * Even if ok is 0, we still return success. Failure to load a provider is - * not fatal. We want to continue to load the rest of the config file. + * Provider activation returns a tristate: + * 1 for successful activation + * 0 for non-fatal activation failure + * < 0 for fatal activation failure + * We return success (1) for activation, (1) for non-fatal activation + * failure, and (0) for fatal activation failure */ - return 1; + return ok >= 0; } static int provider_conf_init(CONF_IMODULE *md, const CONF *cnf) @@ -301,7 +403,7 @@ static int provider_conf_init(CONF_IMODULE *md, const CONF *cnf) for (i = 0; i < sk_CONF_VALUE_num(elist); i++) { cval = sk_CONF_VALUE_value(elist, i); if (!provider_conf_load(NCONF_get0_libctx((CONF *)cnf), - cval->name, cval->value, cnf)) + cval->name, cval->value, cnf)) return 0; } diff --git a/crypto/x509/v3_addr.c b/crypto/x509/v3_addr.c index b990d54048e6b387a88076d91d710c87f008a784..da9604cf963a3f138a9c4190681ce6f24b4d4c8d 100644 --- a/crypto/x509/v3_addr.c +++ b/crypto/x509/v3_addr.c @@ -300,6 +300,8 @@ static int IPAddressOrRange_cmp(const IPAddressOrRange *a, return -1; prefixlen_a = length * 8; break; + default: + return -1; } switch (b->type) { @@ -313,6 +315,8 @@ static int IPAddressOrRange_cmp(const IPAddressOrRange *a, return -1; prefixlen_b = length * 8; break; + default: + return -1; } if ((r = memcmp(addr_a, addr_b, length)) != 0) diff --git a/doc/designs/quic-design/glossary.md b/doc/designs/quic-design/glossary.md index a70cfd1ade1019424889752f58ba380848ac666d..3993c6f8453ba0a7c066718729e67f3b9c8d806b 100644 --- a/doc/designs/quic-design/glossary.md +++ b/doc/designs/quic-design/glossary.md @@ -25,8 +25,7 @@ limits on transmissions accordingly. the CFQ strategy for frame in flight management. For details, see FIFM design document. -**Channel:** Core QUIC connection handling object and connection state machine -implementation. This is fused tightly with the RXDP. +**Channel:** See `QUIC_CHANNEL`. **CID:** Connection ID. @@ -55,6 +54,8 @@ dispatches calls to libssl public APIs to the APL. **EL:** Encryption level. See RFC 9000. +**Engine:** See `QUIC_ENGINE`. + **FC:** Flow control. Comprises TXFC and RXFC. **FIFD:** Frame-in-flight dispatcher. Ties together the CFQ and TXPIM to handle @@ -134,6 +135,8 @@ Initial packets. It is only used temporarily. **PN:** Packet number. Most QUIC packet types have a packet number (PN); see RFC 9000. +**Port:** See `QUIC_PORT`. + **PTO:** Probe timeout. See RFC 9000. **QC:** See `QUIC_CONNECTION`. @@ -167,8 +170,24 @@ wrapping libssl TLS code to implement the QUIC-specific aspects of QUIC TLS. **QTX:** QUIC Record Layer TX. Encrypts and sends packets in datagrams. +**QUIC_CHANNEL:** Internal object in the QUIC core implementation corresponding +to a QUIC connection. Ties together other components and provides connection +handling and state machine implementation. Belongs to a `QUIC_PORT` representing +a UDP socket/BIO, which in turn belongs to a `QUIC_ENGINE`. Owns some number of +`QUIC_STREAM` instances. The `QUIC_CHANNEL` code is fused tightly with the RXDP. + **QUIC_CONNECTION:** QUIC connection. This is the object representing a QUIC -connection in the APL. +connection in the APL. It internally corresponds to a `QUIC_CHANNEL` object in +the QUIC core implementation. + +**QUIC_ENGINE:** Internal object in the QUIC core implementation constituting +the top-level object of a QUIC event and I/O processing domain. Owns zero or +more `QUIC_PORT` instances, each of which owns zero or more `QUIC_CHANNEL` +objects representing QUIC connections. + +**QUIC_PORT:** Internal object in the QUIC core implementation corresponding to +a listening port/network BIO. Has zero or more child `QUIC_CHANNEL` objects +associated with it and belongs to a `QUIC_ENGINE`. **QUIC_STREAM**: Internal object tracking a QUIC stream. Unlike an XSO this is not part of the APL. An XSO wraps a QUIC_STREAM once that stream is exposed as diff --git a/doc/man1/openssl-cmp.pod.in b/doc/man1/openssl-cmp.pod.in index 051c749d08e617e879651bb79274838c15b18735..21e4bd95b72db3b43b408e68c93d871caf9c363b 100644 --- a/doc/man1/openssl-cmp.pod.in +++ b/doc/man1/openssl-cmp.pod.in @@ -17,7 +17,8 @@ Generic message options: [B<-cmd> I] [B<-infotype> I] -[B<-geninfo> I] +[B<-profile> I] +[B<-geninfo> I] Certificate enrollment options: @@ -246,10 +247,18 @@ Set InfoType name to use for requesting specific info in B, e.g., C. So far, there is specific support for C and C. -=item B<-geninfo> I +=item B<-profile> I -generalInfo integer values to place in request PKIHeader with given OID, -e.g., C<1.2.3.4:int:56789>. +Name of a certificate profile to place in +the PKIHeader generalInfo field of request messages. + +=item B<-geninfo> I + +A comma-separated list of InfoTypeAndValue to place in +the generalInfo field of the PKIHeader of requests messages. +Each InfoTypeAndValue gives an OID and an integer or string value +of the form I:int:I or I:str:I, +e.g., C<'1.2.3.4:int:56789, id-kp:str:name'>. =back @@ -1272,7 +1281,7 @@ In order to update the enrolled certificate one may call openssl cmp -section insta,kur -using with MAC-based protection with PBM or +using MAC-based protection with PBM or openssl cmp -section insta,kur,signature @@ -1390,7 +1399,9 @@ L, L, L The B application was added in OpenSSL 3.0. -The B<-engine option> was deprecated in OpenSSL 3.0. +The B<-engine> option was deprecated in OpenSSL 3.0. + +The B<-profile> option was added in OpenSSL 3.3. =head1 COPYRIGHT diff --git a/doc/man3/ERR_set_mark.pod b/doc/man3/ERR_set_mark.pod index b2c0f7de0a18fac6cee19025c88614eea4f58e71..070a7f6e2938f16ce07246cdfc74e39f5cb420a1 100644 --- a/doc/man3/ERR_set_mark.pod +++ b/doc/man3/ERR_set_mark.pod @@ -2,8 +2,8 @@ =head1 NAME -ERR_set_mark, ERR_clear_last_mark, ERR_pop_to_mark, ERR_count_to_mark - set -mark, clear mark and pop errors until mark +ERR_set_mark, ERR_clear_last_mark, ERR_pop_to_mark, ERR_count_to_mark, ERR_pop - +set mark, clear mark, pop errors until mark and pop last error =head1 SYNOPSIS @@ -13,6 +13,7 @@ mark, clear mark and pop errors until mark int ERR_pop_to_mark(void); int ERR_clear_last_mark(void); int ERR_count_to_mark(void); + int ERR_pop(void); =head1 DESCRIPTION @@ -28,6 +29,9 @@ ERR_count_to_mark() returns the number of entries on the error stack above the most recently marked entry, not including that entry. If there is no mark in the error stack, the number of entries in the error stack is returned. +ERR_pop() unconditionally pops a single error entry from the top of the error +stack (which is the entry obtainable via L). + =head1 RETURN VALUES ERR_set_mark() returns 0 if the error stack is empty, otherwise 1. @@ -38,6 +42,12 @@ error stack, which implies that the stack became empty, otherwise 1. ERR_count_to_mark() returns the number of error stack entries found above the most recent mark, if any, or the total number of error stack entries. +ERR_pop() returns 1 if an error was popped or 0 if the error stack was empty. + +=head1 HISTORY + +ERR_pop() was added in OpenSSL 3.3. + =head1 COPYRIGHT Copyright 2003-2023 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man3/OSSL_CMP_CTX_new.pod b/doc/man3/OSSL_CMP_CTX_new.pod index 810997017176b32b9a408dadcf185a9b0adec5bc..d038f2f61c62fc488afb56f2b6abec20e09e5b31 100644 --- a/doc/man3/OSSL_CMP_CTX_new.pod +++ b/doc/man3/OSSL_CMP_CTX_new.pod @@ -39,6 +39,7 @@ OSSL_CMP_CTX_set1_secretValue, OSSL_CMP_CTX_set1_recipient, OSSL_CMP_CTX_push0_geninfo_ITAV, OSSL_CMP_CTX_reset_geninfo_ITAVs, +OSSL_CMP_CTX_get0_geninfo_ITAVs, OSSL_CMP_CTX_set1_extraCertsOut, OSSL_CMP_CTX_set0_newPkey, OSSL_CMP_CTX_get0_newPkey, @@ -127,6 +128,8 @@ OSSL_CMP_CTX_set1_senderNonce int OSSL_CMP_CTX_set1_recipient(OSSL_CMP_CTX *ctx, const X509_NAME *name); int OSSL_CMP_CTX_push0_geninfo_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav); int OSSL_CMP_CTX_reset_geninfo_ITAVs(OSSL_CMP_CTX *ctx); + STACK_OF(OSSL_CMP_ITAV) + *OSSL_CMP_CTX_get0_geninfo_ITAVs(const OSSL_CMP_CTX *ctx); int OSSL_CMP_CTX_set1_extraCertsOut(OSSL_CMP_CTX *ctx, STACK_OF(X509) *extraCertsOut); @@ -540,12 +543,16 @@ the issuer of the CMP signer certificate, as far as any of those is present, else the NULL-DN as last resort. OSSL_CMP_CTX_push0_geninfo_ITAV() adds I to the stack in the I to be -added to the GeneralInfo field of the CMP PKIMessage header of a request +added to the generalInfo field of the CMP PKIMessage header of a request message sent with this context. OSSL_CMP_CTX_reset_geninfo_ITAVs() clears any ITAVs that were added by OSSL_CMP_CTX_push0_geninfo_ITAV(). +OSSL_CMP_CTX_get0_geninfo_ITAVs() returns the list of ITAVs set in I +for inclusion in the generalInfo field of the CMP PKIMessage header of requests +or NULL if not set. + OSSL_CMP_CTX_set1_extraCertsOut() sets the stack of extraCerts that will be sent to remote. @@ -737,6 +744,7 @@ OSSL_CMP_CTX_get_http_cb_arg(), OSSL_CMP_CTX_get_transfer_cb_arg(), OSSL_CMP_CTX_get0_trusted(), OSSL_CMP_CTX_get0_untrusted(), +OSSL_CMP_CTX_get0_geninfo_ITAVs(), OSSL_CMP_CTX_get0_newPkey(), OSSL_CMP_CTX_get_certConf_cb_arg(), OSSL_CMP_CTX_get0_statusString(), @@ -841,10 +849,11 @@ in OpenSSL 3.2. OSSL_CMP_CTX_reset_geninfo_ITAVs() was added in OpenSSL 3.0.8. +OSSL_CMP_CTX_set1_serialNumber(), OSSL_CMP_CTX_get0_libctx(), OSSL_CMP_CTX_get0_propq(), and OSSL_CMP_CTX_get0_validatedSrvCert() were added in OpenSSL 3.2. -OSSL_CMP_CTX_set1_serialNumber() was added in OpenSSL 3.2. +OSSL_CMP_CTX_get0_geninfo_ITAVs() was added in OpenSSL 3.3. =head1 COPYRIGHT diff --git a/doc/man3/OSSL_CMP_HDR_get0_transactionID.pod b/doc/man3/OSSL_CMP_HDR_get0_transactionID.pod index 36bdf1917f39950e4fd57a5cfea9d4749ba81b96..6e79e9a0e3c399c2851b1ed971a5c98d209c9ff5 100644 --- a/doc/man3/OSSL_CMP_HDR_get0_transactionID.pod +++ b/doc/man3/OSSL_CMP_HDR_get0_transactionID.pod @@ -3,7 +3,8 @@ =head1 NAME OSSL_CMP_HDR_get0_transactionID, -OSSL_CMP_HDR_get0_recipNonce +OSSL_CMP_HDR_get0_recipNonce, +OSSL_CMP_HDR_get0_geninfo_ITAVs - functions manipulating CMP message headers =head1 SYNOPSIS @@ -14,6 +15,8 @@ OSSL_CMP_HDR_get0_recipNonce OSSL_CMP_PKIHEADER *hdr); ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr); + STACK_OF(OSSL_CMP_ITAV) + *OSSL_CMP_HDR_get0_geninfo_ITAVs(const OSSL_CMP_PKIHEADER *hdr); =head1 DESCRIPTION @@ -22,6 +25,9 @@ PKIHeader. OSSL_CMP_HDR_get0_recipNonce returns the recipient nonce of the given PKIHeader. +OSSL_CMP_HDR_get0_geninfo_ITAVs() returns the list of ITAVs +in the generalInfo field of the given PKIHeader. + =head1 NOTES CMP is defined in RFC 4210. @@ -35,6 +41,8 @@ or NULL if the respective entry does not exist and on error. The OpenSSL CMP support was added in OpenSSL 3.0. +OSSL_CMP_HDR_get0_geninfo_ITAVs() was added in OpenSSL 3.3. + =head1 COPYRIGHT Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man3/OSSL_CMP_ITAV_set0.pod b/doc/man3/OSSL_CMP_ITAV_set0.pod index 5dd9bcb266fb847df4b27834ab843a2cdc26b16f..13d7868a6debd56e2641abb15bc9a4edb6afbb53 100644 --- a/doc/man3/OSSL_CMP_ITAV_set0.pod +++ b/doc/man3/OSSL_CMP_ITAV_set0.pod @@ -6,7 +6,9 @@ OSSL_CMP_ITAV_create, OSSL_CMP_ITAV_set0, OSSL_CMP_ITAV_get0_type, OSSL_CMP_ITAV_get0_value, -OSSL_CMP_ITAV_push0_stack_item +OSSL_CMP_ITAV_push0_stack_item, +OSSL_CMP_ITAV_new0_certProfile, +OSSL_CMP_ITAV_get0_certProfile - OSSL_CMP_ITAV utility functions =head1 SYNOPSIS @@ -20,6 +22,10 @@ OSSL_CMP_ITAV_push0_stack_item ASN1_TYPE *OSSL_CMP_ITAV_get0_value(const OSSL_CMP_ITAV *itav); int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **itav_sk_p, OSSL_CMP_ITAV *itav); + OSSL_CMP_ITAV + *OSSL_CMP_ITAV_new0_certProfile(STACK_OF(ASN1_UTF8STRING) *certProfile); + int OSSL_CMP_ITAV_get0_certProfile(const OSSL_CMP_ITAV *itav, + STACK_OF(ASN1_UTF8STRING) **out); =head1 DESCRIPTION @@ -43,21 +49,37 @@ the I as generic B pointer. OSSL_CMP_ITAV_push0_stack_item() pushes I to the stack pointed to by I<*itav_sk_p>. It creates a new stack if I<*itav_sk_p> points to NULL. +OSSL_CMP_ITAV_new0_certProfile() creates a new B structure +of type B that includes the optionally given list of profile names. +On success, ownership of the list is with the new B structure. + +OSSL_CMP_ITAV_get0_certProfile() on success assigns to I<*out> +an internal pointer to the +list of certificate profile names contained in the infoValue field of I. +The pointer may be NULL if no profile name is included. +It is an error if the infoType of I is not B. + =head1 NOTES -CMP is defined in RFC 4210 (and CRMF in RFC 4211). +CMP is defined in RFC 4210 and RFC 9480 (and CRMF in RFC 4211). + +OIDs to use as types in B can be found at +L. +The respective OpenSSL NIDs, such as B, +are defined in the F<< >> header file. =head1 RETURN VALUES -OSSL_CMP_ITAV_create() returns a pointer to the ITAV structure on success, -or NULL on error. +OSSL_CMP_ITAV_create() and OSSL_CMP_ITAV_new0_certProfile() +return a pointer to an ITAV structure on success, or NULL on error. OSSL_CMP_ITAV_set0() does not return a value. OSSL_CMP_ITAV_get0_type() and OSSL_CMP_ITAV_get0_value() return the respective pointer or NULL if their input is NULL. -OSSL_CMP_ITAV_push0_stack_item() returns 1 on success, 0 on error. +OSSL_CMP_ITAV_push0_stack_item() and OSSL_CMP_ITAV_get0_certProfile() +return 1 on success, 0 on error. =head1 EXAMPLES @@ -96,6 +118,9 @@ L, L, L The OpenSSL CMP support was added in OpenSSL 3.0. +OSSL_CMP_ITAV_new0_certProfile() and OSSL_CMP_ITAV_get0_certProfile() +were added in OpenSSL 3.3. + =head1 COPYRIGHT Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man3/OSSL_CMP_SRV_CTX_new.pod b/doc/man3/OSSL_CMP_SRV_CTX_new.pod index d7f1a2e4dba7ba4f8b32aed90307dd65053e5e1e..66d722c291ea4a72ac73edf506ef674a20d04945 100644 --- a/doc/man3/OSSL_CMP_SRV_CTX_new.pod +++ b/doc/man3/OSSL_CMP_SRV_CTX_new.pod @@ -13,6 +13,9 @@ OSSL_CMP_SRV_genm_cb_t, OSSL_CMP_SRV_error_cb_t, OSSL_CMP_SRV_pollReq_cb_t, OSSL_CMP_SRV_CTX_init, +OSSL_CMP_SRV_delayed_delivery_cb_t, +OSSL_CMP_SRV_clean_transaction_cb_t, +OSSL_CMP_SRV_CTX_init_trans, OSSL_CMP_SRV_CTX_get0_cmp_ctx, OSSL_CMP_SRV_CTX_get0_custom_ctx, OSSL_CMP_SRV_CTX_set_send_unprotected_errors, @@ -71,6 +74,13 @@ OSSL_CMP_SRV_CTX_set_grant_implicit_confirm OSSL_CMP_SRV_error_cb_t process_error, OSSL_CMP_SRV_certConf_cb_t process_certConf, OSSL_CMP_SRV_pollReq_cb_t process_pollReq); + typedef int (*OSSL_CMP_SRV_delayed_delivery_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req); + typedef int (*OSSL_CMP_SRV_clean_transaction_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const ASN1_OCTET_STRING *id); + int OSSL_CMP_SRV_CTX_init_trans(OSSL_CMP_SRV_CTX *srv_ctx, + OSSL_CMP_SRV_delayed_delivery_cb_t delay, + OSSL_CMP_SRV_clean_transaction_cb_t clean); OSSL_CMP_CTX *OSSL_CMP_SRV_CTX_get0_cmp_ctx(const OSSL_CMP_SRV_CTX *srv_ctx); void *OSSL_CMP_SRV_CTX_get0_custom_ctx(const OSSL_CMP_SRV_CTX *srv_ctx); @@ -113,6 +123,20 @@ All arguments except I may be NULL. If a callback for some message type is not given this means that the respective type of CMP message is not supported by the server. +OSSL_CMP_SRV_CTX_init_trans() sets in I the optional callback +functions for initiating delayed delivery and cleaning up a transaction. +If the function is NULL then delivery of responses is never delayed. +Otherwise I takes a custom server context and a request message as input. +It must return 1 if delivery of the respecive response shall be delayed, +0 if not, and -1 on error. +If the function is NULL then no specific cleanup is performed. +Otherwise I takes a custom server context and a transaction ID pointer +as input, where the pointer is NULL in case a new transaction is being started +and otherwise provides the ID of the transaction being terminated. +The function should reset the respective portions of the state +and free related memory. +It must return 1 on success and 0 on error. + OSSL_CMP_SRV_CTX_get0_cmp_ctx() returns the B from the I. OSSL_CMP_SRV_CTX_get0_custom_ctx() returns the custom server context from @@ -156,6 +180,10 @@ All other functions return 1 on success, 0 on error. The OpenSSL CMP support was added in OpenSSL 3.0. +OSSL_CMP_SRV_CTX_init_trans() +supporting delayed delivery of all types of response messages +was added in OpenSSL 3.3. + =head1 COPYRIGHT Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man3/OSSL_CMP_exec_certreq.pod b/doc/man3/OSSL_CMP_exec_certreq.pod index 38aa4abc834b6e30dfa9fc2ba2c89e0c2b31367d..54632ce93697bc49f43f7989eaa1cc8fa380d2d9 100644 --- a/doc/man3/OSSL_CMP_exec_certreq.pod +++ b/doc/man3/OSSL_CMP_exec_certreq.pod @@ -78,8 +78,8 @@ Typically I is NULL, then the template ingredients are taken from I and need to be filled in using L, L, L, etc. For P10CR, L needs to be used instead. -The enrollment session may be blocked by sleeping until the addressed -CA (or an intermediate PKI component) can fully process and answer the request. +The enrollment session may be blocked (with polling and sleeping in between) +until the server side can fully process and ultimately answer the request. OSSL_CMP_try_certreq() is an alternative to the above functions that is more flexible regarding what to do after receiving a checkAfter value. @@ -118,11 +118,15 @@ We take "accepted" and "grantedWithMods" as clear success and handle typically return them as an indication that the certificate was already revoked. "rejection" is a clear error. The values "waiting" and "keyUpdateWarning" make no sense for revocation and thus are treated as an error as well. +The revocation session may be blocked (with polling and sleeping in between) +until the server can fully process and ultimately answer the request. OSSL_CMP_exec_GENM_ses() sends a genm general message containing the sequence of infoType and infoValue pairs (InfoTypeAndValue; short: B) optionally provided in the I using L. -On success it records in I the status B +The message exchange may be blocked (with polling and sleeping in between) +until the server can fully process and ultimately answer the request. +On success the function records in I status B and returns the list of Bs received in a genp response message. This can be used, for instance, with infoType C to obtain the set of signature @@ -216,6 +220,9 @@ The OpenSSL CMP support was added in OpenSSL 3.0. OSSL_CMP_get1_caCerts() and OSSL_CMP_get1_rootCaKeyUpdate() were added in OpenSSL 3.2. +Support for delayed delivery of all types of response messages +was added in OpenSSL 3.3. + =head1 COPYRIGHT Copyright 2007-2023 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man5/config.pod b/doc/man5/config.pod index 8d312c661fa099372c7a50004e4fd98d3efe216f..96eaa6ffd392715072b9ea87a76457cf46c6d335 100644 --- a/doc/man5/config.pod +++ b/doc/man5/config.pod @@ -265,8 +265,11 @@ Specifies the pathname of the module (typically a shared library) to load. =item B -If present, the module is activated. The value assigned to this name is not -significant. +If present and set to one of the values yes, on, true or 1, then the associated +provider will be activated. Conversely, setting this value to no, off, false, or +0 will prevent the provider from being activated. Settings can be given in lower +or uppercase. Setting activate to any other setting, or omitting a setting +value will result in an error. =back diff --git a/fuzz/cmp.c b/fuzz/cmp.c index 490c4211f8e29d13ea53788018306a6f3e2ba5ab..16d2fade225d5554d23455cdeb928d556cb3789b 100644 --- a/fuzz/cmp.c +++ b/fuzz/cmp.c @@ -155,6 +155,18 @@ static int process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx, return 0; } +static int clean_transaction(ossl_unused OSSL_CMP_SRV_CTX *srv_ctx, + ossl_unused const ASN1_OCTET_STRING *id) +{ + return 1; +} + +static int delayed_delivery(ossl_unused OSSL_CMP_SRV_CTX *srv_ctx, + ossl_unused const OSSL_CMP_MSG *req) +{ + return 0; +} + int FuzzerTestOneInput(const uint8_t *buf, size_t len) { OSSL_CMP_MSG *msg; @@ -183,7 +195,9 @@ int FuzzerTestOneInput(const uint8_t *buf, size_t len) print_noop) && OSSL_CMP_SRV_CTX_init(srv_ctx, NULL, process_cert_request, process_rr, process_genm, process_error, - process_certConf, process_pollReq)) + process_certConf, process_pollReq) + && OSSL_CMP_SRV_CTX_init_trans(srv_ctx, delayed_delivery, + clean_transaction)) OSSL_CMP_MSG_free(OSSL_CMP_SRV_process_request(srv_ctx, msg)); OSSL_CMP_CTX_free(client_ctx); diff --git a/include/crypto/conferr.h b/include/crypto/conferr.h index cb367e4f32a04d6a3c2d42fed9b939e283faca67..fc9645127d12d44d37739635a15f0c3a76518cfe 100644 --- a/include/crypto/conferr.h +++ b/include/crypto/conferr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-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 diff --git a/include/internal/list.h b/include/internal/list.h index fdd356c407d1c5966002767aac69d5a58d83fd72..902047641f7bb381ba8406db6c54c2c2a4b78ca6 100644 --- a/include/internal/list.h +++ b/include/internal/list.h @@ -20,6 +20,34 @@ # define OSSL_LIST_DBG(x) x; # endif +# define LIST_FOREACH_FROM(p, name, init) \ + for ((p) = (init); \ + (p) != NULL; \ + (p) = ossl_list_##name##_next(p)) +# define LIST_FOREACH(p, name, l) \ + LIST_FOREACH_FROM(p, name, ossl_list_##name##_head(l)) + +# define LIST_FOREACH_REV_FROM(p, name, init) \ + for ((p) = (init); \ + (p) != NULL; \ + (p) = ossl_list_##name##_prev(p)) +# define LIST_FOREACH_REV(p, name, l) \ + LIST_FOREACH_FROM(p, name, ossl_list_##name##_tail(l)) + +# define LIST_FOREACH_DELSAFE_FROM(p, pn, name, init) \ + for ((p) = (init); \ + (p) != NULL && (((pn) = ossl_list_##name##_next(p)), 1); \ + (p) = (pn)) +#define LIST_FOREACH_DELSAFE(p, pn, name, l) \ + LIST_FOREACH_DELSAFE_FROM(p, pn, name, ossl_list_##name##_head(l)) + +# define LIST_FOREACH_REV_DELSAFE_FROM(p, pn, name, init) \ + for ((p) = (init); \ + (p) != NULL && (((pn) = ossl_list_##name##_prev(p)), 1); \ + (p) = (pn)) +# define LIST_FOREACH_REV_DELSAFE(p, pn, name, l) \ + LIST_FOREACH_REV_DELSAFE_FROM(p, pn, name, ossl_list_##name##_tail(l)) + /* Define a list structure */ # define OSSL_LIST(name) OSSL_LIST_ ## name @@ -30,12 +58,14 @@ OSSL_LIST_DBG(struct ossl_list_st_ ## name *list) \ } ossl_list_ ## name -# define DEFINE_LIST_OF(name, type) \ +# define DECLARE_LIST_OF(name, type) \ typedef struct ossl_list_st_ ## name OSSL_LIST(name); \ struct ossl_list_st_ ## name { \ type *alpha, *omega; \ size_t num_elems; \ - }; \ + } \ + +# define DEFINE_LIST_OF_IMPL(name, type) \ static ossl_unused ossl_inline void \ ossl_list_##name##_init(OSSL_LIST(name) *list) \ { \ @@ -166,4 +196,8 @@ } \ struct ossl_list_st_ ## name +# define DEFINE_LIST_OF(name, type) \ + DECLARE_LIST_OF(name, type); \ + DEFINE_LIST_OF_IMPL(name, type) + #endif diff --git a/include/internal/quic_ackm.h b/include/internal/quic_ackm.h index 03fc6088678454f66303ce3ace1cf0cb2a1569b6..69b862d9c55a7b89b0e84f0f66621001d7740632 100644 --- a/include/internal/quic_ackm.h +++ b/include/internal/quic_ackm.h @@ -13,13 +13,12 @@ # include "internal/quic_cc.h" # include "internal/quic_types.h" # include "internal/quic_wire.h" +# include "internal/quic_predef.h" # include "internal/time.h" # include "internal/list.h" # ifndef OPENSSL_NO_QUIC -typedef struct ossl_ackm_st OSSL_ACKM; - OSSL_ACKM *ossl_ackm_new(OSSL_TIME (*now)(void *arg), void *now_arg, OSSL_STATM *statm, diff --git a/include/internal/quic_cc.h b/include/internal/quic_cc.h index 60c710b0bdaae2ee449ecb862140ebbed890dbf1..dbd439dd0cf50acc95df65138c979e0c30e7412d 100644 --- a/include/internal/quic_cc.h +++ b/include/internal/quic_cc.h @@ -11,11 +11,10 @@ #include "openssl/params.h" #include "internal/time.h" +#include "internal/quic_predef.h" # ifndef OPENSSL_NO_QUIC -typedef struct ossl_cc_data_st OSSL_CC_DATA; - typedef struct ossl_cc_ack_info_st { /* The time the packet being acknowledged was originally sent. */ OSSL_TIME tx_time; @@ -80,7 +79,7 @@ typedef struct ossl_cc_ecn_info_st { */ #define OSSL_CC_LOST_FLAG_PERSISTENT_CONGESTION (1U << 0) -typedef struct ossl_cc_method_st { +struct ossl_cc_method_st { /* * Instantiation. */ @@ -209,7 +208,7 @@ typedef struct ossl_cc_method_st { */ int (*on_ecn)(OSSL_CC_DATA *ccdata, const OSSL_CC_ECN_INFO *info); -} OSSL_CC_METHOD; +}; extern const OSSL_CC_METHOD ossl_cc_dummy_method; extern const OSSL_CC_METHOD ossl_cc_newreno_method; diff --git a/include/internal/quic_cfq.h b/include/internal/quic_cfq.h index 22c436dc0746a2739928d500243946fa7e71645a..56ebcb930ed61a967fbd2a77b018a09444ba2750 100644 --- a/include/internal/quic_cfq.h +++ b/include/internal/quic_cfq.h @@ -12,6 +12,7 @@ # include # include "internal/quic_types.h" +# include "internal/quic_predef.h" # ifndef OPENSSL_NO_QUIC @@ -63,7 +64,6 @@ int ossl_quic_cfq_item_is_unreliable(const QUIC_CFQ_ITEM *item); * QUIC Control Frame Queue * ======================== */ -typedef struct quic_cfq_st QUIC_CFQ; QUIC_CFQ *ossl_quic_cfq_new(void); void ossl_quic_cfq_free(QUIC_CFQ *cfq); diff --git a/include/internal/quic_channel.h b/include/internal/quic_channel.h index f46db0637e91c6a34745f56b6822cd164035c7c5..b6b3e28352012db84e85d4c490b32d249264bc51 100644 --- a/include/internal/quic_channel.h +++ b/include/internal/quic_channel.h @@ -12,9 +12,9 @@ # include # include "internal/quic_types.h" -# include "internal/quic_stream_map.h" -# include "internal/quic_reactor.h" -# include "internal/quic_statm.h" +# include "internal/quic_record_tx.h" +# include "internal/quic_wire.h" +# include "internal/quic_predef.h" # include "internal/time.h" # include "internal/thread.h" @@ -106,34 +106,20 @@ # define QUIC_CHANNEL_STATE_TERMINATED 4 typedef struct quic_channel_args_st { - OSSL_LIB_CTX *libctx; - const char *propq; - int is_server; - SSL *tls; - /* - * This must be a mutex the lifetime of which will exceed that of the - * channel. The instantiator of the channel is responsible for providing a - * mutex as this makes it easier to handle instantiation and teardown of - * channels in situations potentially requiring locking. - * - * Note that this is a MUTEX not a RWLOCK as it needs to be an OS mutex for - * compatibility with an OS's condition variable wait API, whereas RWLOCK - * may, depending on the build configuration, be implemented using an OS's - * mutex primitive or using its RW mutex primitive. + * The QUIC_PORT which the channel is to belong to. The lifetime of the + * QUIC_PORT must exceed that of the created channel. */ - CRYPTO_MUTEX *mutex; + QUIC_PORT *port; + /* LCIDM to register LCIDs with. */ + QUIC_LCIDM *lcidm; + /* SRTM to register SRTs with. */ + QUIC_SRTM *srtm; - /* - * Optional function pointer to use to retrieve the current time. If NULL, - * ossl_time_now() is used. - */ - OSSL_TIME (*now_cb)(void *arg); - void *now_cb_arg; + int is_server; + SSL *tls; } QUIC_CHANNEL_ARGS; -typedef struct quic_channel_st QUIC_CHANNEL; - /* Represents the cause for a connection's termination. */ typedef struct quic_terminate_cause_st { /* @@ -176,10 +162,11 @@ typedef struct quic_terminate_cause_st { unsigned int remote : 1; } QUIC_TERMINATE_CAUSE; - /* * Create a new QUIC channel using the given arguments. The argument structure * does not need to remain allocated. Returns NULL on failure. + * + * Only QUIC_PORT should use this function. */ QUIC_CHANNEL *ossl_quic_channel_new(const QUIC_CHANNEL_ARGS *args); @@ -276,6 +263,23 @@ void ossl_quic_channel_on_remote_conn_close(QUIC_CHANNEL *ch, void ossl_quic_channel_on_new_conn_id(QUIC_CHANNEL *ch, OSSL_QUIC_FRAME_NEW_CONN_ID *f); +/* Temporarily exposed during QUIC_PORT transition. */ +int ossl_quic_channel_on_new_conn(QUIC_CHANNEL *ch, const BIO_ADDR *peer, + const QUIC_CONN_ID *peer_scid, + const QUIC_CONN_ID *peer_dcid); + +/* For use by QUIC_PORT. You should not need to call this directly. */ +void ossl_quic_channel_subtick(QUIC_CHANNEL *ch, QUIC_TICK_RESULT *r, + uint32_t flags); + +/* For use by QUIC_PORT only. */ +void ossl_quic_channel_raise_net_error(QUIC_CHANNEL *ch); + +/* For use by QUIC_PORT only. */ +void ossl_quic_channel_on_stateless_reset(QUIC_CHANNEL *ch); + +void ossl_quic_channel_inject(QUIC_CHANNEL *ch, QUIC_URXE *e); + /* * Queries and Accessors * ===================== @@ -297,18 +301,6 @@ OSSL_STATM *ossl_quic_channel_get_statm(QUIC_CHANNEL *ch); int ossl_quic_channel_get_peer_addr(QUIC_CHANNEL *ch, BIO_ADDR *peer_addr); int ossl_quic_channel_set_peer_addr(QUIC_CHANNEL *ch, const BIO_ADDR *peer_addr); -/* Gets/sets the underlying network read and write BIOs. */ -BIO *ossl_quic_channel_get_net_rbio(QUIC_CHANNEL *ch); -BIO *ossl_quic_channel_get_net_wbio(QUIC_CHANNEL *ch); -int ossl_quic_channel_set_net_rbio(QUIC_CHANNEL *ch, BIO *net_rbio); -int ossl_quic_channel_set_net_wbio(QUIC_CHANNEL *ch, BIO *net_wbio); - -/* - * Re-poll the network BIOs already set to determine if their support - * for polling has changed. - */ -int ossl_quic_channel_update_poll_descriptors(QUIC_CHANNEL *ch); - /* * Returns an existing stream by stream ID. Returns NULL if the stream does not * exist. @@ -326,6 +318,8 @@ int ossl_quic_channel_is_active(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_handshake_complete(const QUIC_CHANNEL *ch); int ossl_quic_channel_is_handshake_confirmed(const QUIC_CHANNEL *ch); +QUIC_PORT *ossl_quic_channel_get0_port(QUIC_CHANNEL *ch); +QUIC_ENGINE *ossl_quic_channel_get0_engine(QUIC_CHANNEL *ch); QUIC_DEMUX *ossl_quic_channel_get0_demux(QUIC_CHANNEL *ch); SSL *ossl_quic_channel_get0_ssl(QUIC_CHANNEL *ch); @@ -404,9 +398,6 @@ int ossl_quic_channel_has_pending(const QUIC_CHANNEL *ch); /* Force transmission of an ACK-eliciting packet. */ int ossl_quic_channel_ping(QUIC_CHANNEL *ch); -/* For testing use. While enabled, ticking is not performed. */ -void ossl_quic_channel_set_inhibit_tick(QUIC_CHANNEL *ch, int inhibit); - /* * These queries exist for diagnostic purposes only. They may roll over. * Do not rely on them for non-testing purposes. diff --git a/include/internal/quic_demux.h b/include/internal/quic_demux.h index 444249e728881df336be539403548024bc1f5203..bc0ad9563600b7834f31b67323ced653e3ece06a 100644 --- a/include/internal/quic_demux.h +++ b/include/internal/quic_demux.h @@ -12,6 +12,7 @@ # include # include "internal/quic_types.h" +# include "internal/quic_predef.h" # include "internal/bio_addr.h" # include "internal/time.h" # include "internal/list.h" @@ -23,20 +24,19 @@ * ============ * * The QUIC connection demuxer is the entity responsible for receiving datagrams - * from the network via a datagram BIO. It parses packet headers to determine - * each packet's destination connection ID (DCID) and hands off processing of - * the packet to the correct QUIC Record Layer (QRL)'s RX side (known as the - * QRX). - * - * A QRX is instantiated per QUIC connection and contains the cryptographic - * resources needed to decrypt QUIC packets for that connection. Received - * datagrams are passed from the demuxer to the QRX via a callback registered - * for a specific DCID by the QRX; thus the demuxer has no specific knowledge of - * the QRX and is not coupled to it. - * - * A connection may have multiple connection IDs associated with it; a QRX - * handles this simply by registering multiple connection IDs with the demuxer - * via multiple register calls. + * from the network via a datagram BIO. It parses the headers of the first + * packet in the datagram to determine that packet's DCID and hands off + * processing of the entire datagram to a single callback function which can + * decide how to handle and route the datagram, for example by looking up + * a QRX instance and injecting the URXE into that QRX. + * + * A QRX will typically be instantiated per QUIC connection and contains the + * cryptographic resources needed to decrypt QUIC packets for that connection. + * However, it is up to the callback function to handle routing, for example by + * consulting a LCIDM instance. Thus the demuxer has no specific knowledge of + * any QRX and is not coupled to it. All CID knowledge is also externalised into + * a LCIDM or other CID state tracking object, without the DEMUX being coupled + * to any particular DCID resolution mechanism. * * URX Queue * --------- @@ -83,8 +83,6 @@ * same allocation. */ -typedef struct quic_urxe_st QUIC_URXE; - /* Maximum number of packets we allow to exist in one datagram. */ #define QUIC_MAX_PKT_PER_URXE (sizeof(uint64_t) * 8) @@ -159,9 +157,6 @@ void ossl_quic_urxe_remove(QUIC_URXE_LIST *l, QUIC_URXE *e); void ossl_quic_urxe_insert_head(QUIC_URXE_LIST *l, QUIC_URXE *e); void ossl_quic_urxe_insert_tail(QUIC_URXE_LIST *l, QUIC_URXE *e); -/* Opaque type representing a demuxer. */ -typedef struct quic_demux_st QUIC_DEMUX; - /* * Called when a datagram is received for a given connection ID. * @@ -169,6 +164,9 @@ typedef struct quic_demux_st QUIC_DEMUX; * to mutate this buffer; once the demuxer calls this callback, it will never * read the buffer again. * + * If a DCID was identified for the datagram, dcid is non-NULL; otherwise + * it is NULL. + * * The callee must arrange for ossl_quic_demux_release_urxe or * ossl_quic_demux_reinject_urxe to be called on the URXE at some point in the * future (this need not be before the callback returns). @@ -176,15 +174,8 @@ typedef struct quic_demux_st QUIC_DEMUX; * At the time the callback is made, the URXE will not be in any queue, * therefore the callee can use the prev and next fields as it wishes. */ -typedef void (ossl_quic_demux_cb_fn)(QUIC_URXE *e, void *arg); - -/* - * Called when a datagram is received. - * Returns 1 if the datagram ends with a stateless reset token and - * 0 if not. - */ -typedef int (ossl_quic_stateless_reset_cb_fn)(const unsigned char *data, - size_t data_len, void *arg); +typedef void (ossl_quic_demux_cb_fn)(QUIC_URXE *e, void *arg, + const QUIC_CONN_ID *dcid); /* * Creates a new demuxer. The given BIO is used to receive datagrams from the @@ -220,50 +211,6 @@ void ossl_quic_demux_set_bio(QUIC_DEMUX *demux, BIO *net_bio); */ int ossl_quic_demux_set_mtu(QUIC_DEMUX *demux, unsigned int mtu); -/* - * Register a datagram handler callback for a connection ID. - * - * ossl_quic_demux_pump will call the specified function if it receives a datagram - * the first packet of which has the specified destination connection ID. - * - * It is assumed all packets in a datagram have the same destination connection - * ID (as QUIC mandates this), but it is the user's responsibility to check for - * this and reject subsequent packets in a datagram that violate this rule. - * - * dst_conn_id is a destination connection ID; it is copied and need not remain - * valid after this function returns. - * - * cb_arg is passed to cb when it is called. For information on the callback, - * see its typedef above. - * - * Only one handler can be set for a given connection ID. If a handler is - * already set for the given connection ID, returns 0. - * - * Returns 1 on success or 0 on failure. - */ -int ossl_quic_demux_register(QUIC_DEMUX *demux, - const QUIC_CONN_ID *dst_conn_id, - ossl_quic_demux_cb_fn *cb, - void *cb_arg); - -/* - * Unregisters any datagram handler callback set for the given connection ID. - * Fails if no handler is registered for the given connection ID. - * - * Returns 1 on success or 0 on failure. - */ -int ossl_quic_demux_unregister(QUIC_DEMUX *demux, - const QUIC_CONN_ID *dst_conn_id); - -/* - * Unregisters any datagram handler callback from all connection IDs it is used - * for. cb and cb_arg must both match the values passed to - * ossl_quic_demux_register. - */ -void ossl_quic_demux_unregister_by_cb(QUIC_DEMUX *demux, - ossl_quic_demux_cb_fn *cb, - void *cb_arg); - /* * Set the default packet handler. This is used for incoming packets which don't * match a registered DCID. This is only needed for servers. If a default packet @@ -278,18 +225,6 @@ void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux, ossl_quic_demux_cb_fn *cb, void *cb_arg); -/* - * Sets a callback for stateless reset processing. - * - * If set, this callback is called for datagrams for which we cannot identify - * a CID. This function should return 1 if there is a stateless reset token - * present and 0 if not. If there is a token present, the connection should - * also be reset. - */ -void ossl_quic_demux_set_stateless_reset_handler( - QUIC_DEMUX *demux, - ossl_quic_stateless_reset_cb_fn *cb, void *cb_arg); - /* * Releases a URXE back to the demuxer. No reference must be made to the URXE or * its buffer after calling this function. The URXE must not be in any queue; @@ -335,7 +270,6 @@ void ossl_quic_demux_reinject_urxe(QUIC_DEMUX *demux, #define QUIC_DEMUX_PUMP_RES_OK 1 #define QUIC_DEMUX_PUMP_RES_TRANSIENT_FAIL (-1) #define QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL (-2) -#define QUIC_DEMUX_PUMP_RES_STATELESS_RESET (-3) int ossl_quic_demux_pump(QUIC_DEMUX *demux); diff --git a/include/internal/quic_engine.h b/include/internal/quic_engine.h new file mode 100644 index 0000000000000000000000000000000000000000..5d06d076b934a7ecd836326fe6f87af3aa0f3152 --- /dev/null +++ b/include/internal/quic_engine.h @@ -0,0 +1,84 @@ +/* + * 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_QUIC_ENGINE_H +# define OSSL_QUIC_ENGINE_H + +# include + +# include "internal/quic_predef.h" +# include "internal/quic_port.h" +# include "internal/thread_arch.h" + +# ifndef OPENSSL_NO_QUIC + +/* + * QUIC Engine + * =========== + * + * A QUIC Engine (QUIC_ENGINE) represents an event processing domain for the + * purposes of QUIC and contains zero or more subsidiary QUIC_PORT instances + * (each of which currently represents a UDP socket), each of which in turn + * contains zero or more subsidiary QUIC_CHANNEL instances, each of which + * represents a single QUIC connection. All QUIC_PORT instances must belong + * to a QUIC_ENGINE. + * + * TODO(QUIC SERVER): Currently a QUIC_PORT belongs to a single QUIC_CHANNEL. + * This will cease to be the case once connection migration and/or multipath is + * implemented, so in future a channel might be associated with multiple ports. + * + * A QUIC engine is the root object in a QUIC event domain, and is responsible + * for managing event processing for all QUIC ports and channels (e.g. timeouts, + * clock management, the QUIC_REACTOR instance, etc.). + */ +typedef struct quic_engine_args_st { + OSSL_LIB_CTX *libctx; + const char *propq; + + /* + * This must be a mutex the lifetime of which will exceed that of the engine + * and all ports and channels. The instantiator of the engine is responsible + * for providing a mutex as this makes it easier to handle instantiation and + * teardown of channels in situations potentially requiring locking. + * + * Note that this is a MUTEX not a RWLOCK as it needs to be an OS mutex for + * compatibility with an OS's condition variable wait API, whereas RWLOCK + * may, depending on the build configuration, be implemented using an OS's + * mutex primitive or using its RW mutex primitive. + */ + CRYPTO_MUTEX *mutex; + + OSSL_TIME (*now_cb)(void *arg); + void *now_cb_arg; +} QUIC_ENGINE_ARGS; + +QUIC_ENGINE *ossl_quic_engine_new(const QUIC_ENGINE_ARGS *args); + +void ossl_quic_engine_free(QUIC_ENGINE *qeng); + +/* + * Create a port which is a child of the engine. args->engine shall be NULL. + */ +QUIC_PORT *ossl_quic_engine_create_port(QUIC_ENGINE *qeng, + const QUIC_PORT_ARGS *args); + +/* Gets the mutex used by the engine. */ +CRYPTO_MUTEX *ossl_quic_engine_get0_mutex(QUIC_ENGINE *qeng); + +/* Gets the current time. */ +OSSL_TIME ossl_quic_engine_get_time(QUIC_ENGINE *qeng); + +/* For testing use. While enabled, ticking is not performed. */ +void ossl_quic_engine_set_inhibit_tick(QUIC_ENGINE *qeng, int inhibit); + +/* Gets the reactor which can be used to tick/poll on the port. */ +QUIC_REACTOR *ossl_quic_engine_get0_reactor(QUIC_ENGINE *qeng); + +# endif + +#endif diff --git a/include/internal/quic_lcidm.h b/include/internal/quic_lcidm.h index 9b11429814895f97d855d05f4864e5ac44fba2ff..4911e042302ba9d363d4255c900cbef17894b2b5 100644 --- a/include/internal/quic_lcidm.h +++ b/include/internal/quic_lcidm.h @@ -15,6 +15,7 @@ # include "internal/time.h" # include "internal/quic_types.h" # include "internal/quic_wire.h" +# include "internal/quic_predef.h" # ifndef OPENSSL_NO_QUIC @@ -95,7 +96,6 @@ * An ODCID has no sequence number associated with it. It is the only CID to * lack one. */ -typedef struct quic_lcidm_st QUIC_LCIDM; /* * Creates a new LCIDM. lcid_len is the length to use for LCIDs in bytes, which diff --git a/include/internal/quic_port.h b/include/internal/quic_port.h new file mode 100644 index 0000000000000000000000000000000000000000..bcb578c3f8d21efbd5f03e1b60f9650fa41ff946 --- /dev/null +++ b/include/internal/quic_port.h @@ -0,0 +1,142 @@ +/* + * 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_QUIC_PORT_H +# define OSSL_QUIC_PORT_H + +# include +# include "internal/quic_types.h" +# include "internal/quic_reactor.h" +# include "internal/quic_demux.h" +# include "internal/quic_predef.h" +# include "internal/thread_arch.h" + +# ifndef OPENSSL_NO_QUIC + +/* + * QUIC Port + * ========= + * + * A QUIC Port (QUIC_PORT) represents a single UDP network socket and contains + * zero or more subsidiary QUIC_CHANNEL instances, each of which represents a + * single QUIC connection. All QUIC_CHANNEL instances must belong to a + * QUIC_PORT. + * + * A QUIC port is responsible for managing a set of channels which all use the + * same UDP socket, and (in future) for automatically creating new channels when + * incoming connections are received. + * + * In order to retain compatibility with QUIC_TSERVER, it also supports a point + * of legacy compatibility where a caller can create an incoming (server role) + * channel and that channel will be automatically be bound to the next incoming + * connection. In the future this will go away once QUIC_TSERVER is removed. + * + * All QUIC_PORT instances are created by a QUIC_ENGINE. + */ +typedef struct quic_port_args_st { + /* The engine which the QUIC port is to be a child of. */ + QUIC_ENGINE *engine; + + /* + * This SSL_CTX will be used when constructing the handshake layer object + * inside newly created channels. + */ + SSL_CTX *channel_ctx; + + /* + * If 1, this port is to be used for multiple connections, so + * non-zero-length CIDs should be used. If 0, this port will only be used + * for a single connection, so a zero-length local CID can be used. + */ + int is_multi_conn; +} QUIC_PORT_ARGS; + +/* Only QUIC_ENGINE should use this function. */ +QUIC_PORT *ossl_quic_port_new(const QUIC_PORT_ARGS *args); + +void ossl_quic_port_free(QUIC_PORT *port); + +/* + * Operations + * ========== + */ + +/* Create an outgoing channel using this port. */ +QUIC_CHANNEL *ossl_quic_port_create_outgoing(QUIC_PORT *port, SSL *tls); + +/* + * Create an incoming channel using this port. + * + * TODO(QUIC SERVER): temporary TSERVER use only - will be removed. + */ +QUIC_CHANNEL *ossl_quic_port_create_incoming(QUIC_PORT *port, SSL *tls); + +/* + * Queries and Accessors + * ===================== + */ + +/* Gets/sets the underlying network read and write BIO. */ +BIO *ossl_quic_port_get_net_rbio(QUIC_PORT *port); +BIO *ossl_quic_port_get_net_wbio(QUIC_PORT *port); +int ossl_quic_port_set_net_rbio(QUIC_PORT *port, BIO *net_rbio); +int ossl_quic_port_set_net_wbio(QUIC_PORT *port, BIO *net_wbio); + +/* + * Re-poll the network BIOs already set to determine if their support + * for polling has changed. + */ +int ossl_quic_port_update_poll_descriptors(QUIC_PORT *port); + +/* Gets the engine which this port is a child of. */ +QUIC_ENGINE *ossl_quic_port_get0_engine(QUIC_PORT *port); + +/* Gets the reactor which can be used to tick/poll on the port. */ +QUIC_REACTOR *ossl_quic_port_get0_reactor(QUIC_PORT *port); + +/* Gets the demuxer belonging to the port. */ +QUIC_DEMUX *ossl_quic_port_get0_demux(QUIC_PORT *port); + +/* Gets the mutex used by the port. */ +CRYPTO_MUTEX *ossl_quic_port_get0_mutex(QUIC_PORT *port); + +/* Gets the current time. */ +OSSL_TIME ossl_quic_port_get_time(QUIC_PORT *port); + +int ossl_quic_port_get_rx_short_dcid_len(const QUIC_PORT *port); +int ossl_quic_port_get_tx_init_dcid_len(const QUIC_PORT *port); + +/* Returns 1 if the port is running/healthy, 0 if it has failed. */ +int ossl_quic_port_is_running(const QUIC_PORT *port); + +/* + * Restores port-level error to the error stack. To be called only if + * the port is no longer running. + */ +void ossl_quic_port_restore_err_state(const QUIC_PORT *port); + +/* For use by QUIC_ENGINE. You should not need to call this directly. */ +void ossl_quic_port_subtick(QUIC_PORT *port, QUIC_TICK_RESULT *r, + uint32_t flags); + +/* + * Events + * ====== + */ + +/* + * Called if a permanent network error occurs. Terminates all channels + * immediately. triggering_ch is an optional argument designating + * a channel which encountered the network error. + */ +void ossl_quic_port_raise_net_error(QUIC_PORT *port, + QUIC_CHANNEL *triggering_ch); + +# endif + +#endif diff --git a/include/internal/quic_predef.h b/include/internal/quic_predef.h new file mode 100644 index 0000000000000000000000000000000000000000..7c7567b9c52e56c10872ebd18df7912cf9e59844 --- /dev/null +++ b/include/internal/quic_predef.h @@ -0,0 +1,43 @@ +/* + * 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_QUIC_PREDEF_H +# define OSSL_QUIC_PREDEF_H + +# ifndef OPENSSL_NO_QUIC + +typedef struct quic_port_st QUIC_PORT; +typedef struct quic_channel_st QUIC_CHANNEL; +typedef struct quic_tls_st QUIC_TLS; +typedef struct quic_txpim_st QUIC_TXPIM; +typedef struct quic_fifd_st QUIC_FIFD; +typedef struct quic_cfq_st QUIC_CFQ; +typedef struct ossl_quic_tx_packetiser_st OSSL_QUIC_TX_PACKETISER; +typedef struct ossl_ackm_st OSSL_ACKM; +typedef struct quic_srt_elem_st QUIC_SRT_ELEM; +typedef struct ossl_cc_data_st OSSL_CC_DATA; +typedef struct ossl_cc_method_st OSSL_CC_METHOD; +typedef struct quic_stream_map_st QUIC_STREAM_MAP; +typedef struct quic_stream_st QUIC_STREAM; +typedef struct quic_sstream_st QUIC_SSTREAM; +typedef struct quic_rstream_st QUIC_RSTREAM; +typedef struct quic_reactor_st QUIC_REACTOR; +typedef struct ossl_statm_st OSSL_STATM; +typedef struct quic_demux_st QUIC_DEMUX; +typedef struct ossl_qrx_pkt_st OSSL_QRX_PKT; +typedef struct ossl_qtx_pkt_st OSSL_QTX_PKT; +typedef struct quic_tick_result_st QUIC_TICK_RESULT; +typedef struct quic_srtm_st QUIC_SRTM; +typedef struct quic_lcidm_st QUIC_LCIDM; +typedef struct quic_urxe_st QUIC_URXE; +typedef struct quic_engine_st QUIC_ENGINE; + +# endif + +#endif diff --git a/include/internal/quic_reactor.h b/include/internal/quic_reactor.h index 57bb551e27a222871758e09ebba4d2e74bd142e2..10d54ee15649dd7d340d927aeec65d557c2ae2ec 100644 --- a/include/internal/quic_reactor.h +++ b/include/internal/quic_reactor.h @@ -11,6 +11,7 @@ # include "internal/time.h" # include "internal/sockets.h" +# include "internal/quic_predef.h" # include # ifndef OPENSSL_NO_QUIC @@ -67,13 +68,22 @@ * adaptation layer on top of our internal asynchronous I/O API as exposed by * the reactor interface. */ -typedef struct quic_tick_result_st { +struct quic_tick_result_st { char net_read_desired; char net_write_desired; OSSL_TIME tick_deadline; -} QUIC_TICK_RESULT; - -typedef struct quic_reactor_st { +}; + +static ossl_inline ossl_unused void +ossl_quic_tick_result_merge_into(QUIC_TICK_RESULT *r, + const QUIC_TICK_RESULT *src) +{ + r->net_read_desired = r->net_read_desired || src->net_read_desired; + r->net_write_desired = r->net_write_desired || src->net_write_desired; + r->tick_deadline = ossl_time_min(r->tick_deadline, src->tick_deadline); +} + +struct quic_reactor_st { /* * BIO poll descriptors which can be polled. poll_r is a poll descriptor * which becomes readable when the QUIC state machine can potentially do @@ -101,7 +111,7 @@ typedef struct quic_reactor_st { */ unsigned int can_poll_r : 1; unsigned int can_poll_w : 1; -} QUIC_REACTOR; +}; void ossl_quic_reactor_init(QUIC_REACTOR *rtor, void (*tick_cb)(QUIC_TICK_RESULT *res, void *arg, diff --git a/include/internal/quic_record_rx.h b/include/internal/quic_record_rx.h index e26fd35600d665ed6364fdd17e122e5fc7a5f556..24c2bbc8aec5498062f0664cf0852ada2e875adc 100644 --- a/include/internal/quic_record_rx.h +++ b/include/internal/quic_record_rx.h @@ -13,6 +13,7 @@ # include # include "internal/quic_wire_pkt.h" # include "internal/quic_types.h" +# include "internal/quic_predef.h" # include "internal/quic_record_util.h" # include "internal/quic_demux.h" @@ -28,7 +29,7 @@ typedef struct ossl_qrx_args_st { OSSL_LIB_CTX *libctx; const char *propq; - /* Demux to receive datagrams from. */ + /* Demux which owns the URXEs passed to us. */ QUIC_DEMUX *demux; /* Length of connection IDs used in short-header packets in bytes. */ @@ -66,34 +67,6 @@ void ossl_qrx_set_msg_callback(OSSL_QRX *qrx, ossl_msg_cb msg_callback, void ossl_qrx_set_msg_callback_arg(OSSL_QRX *qrx, void *msg_callback_arg); -/* - * DCID Management - * =============== - */ - -/* - * Adds a given DCID to the QRX. The QRX will register the DCID with the demuxer - * so that incoming packets with that DCID are passed to the given QRX. Multiple - * DCIDs may be associated with a QRX at any one time. You will need to add at - * least one DCID after instantiating the QRX. A zero-length DCID is a valid - * input to this function. This function fails if the DCID is already - * registered. - * - * Returns 1 on success or 0 on error. - */ -int ossl_qrx_add_dst_conn_id(OSSL_QRX *qrx, - const QUIC_CONN_ID *dst_conn_id); - -/* - * Remove a DCID previously registered with ossl_qrx_add_dst_conn_id. The DCID - * is unregistered from the demuxer. Fails if the DCID is not registered with - * the demuxer. - * - * Returns 1 on success or 0 on error. - */ -int ossl_qrx_remove_dst_conn_id(OSSL_QRX *qrx, - const QUIC_CONN_ID *dst_conn_id); - /* * Secret Management * ================= @@ -206,7 +179,7 @@ int ossl_qrx_discard_enc_level(OSSL_QRX *qrx, uint32_t enc_level); */ /* Information about a received packet. */ -typedef struct ossl_qrx_pkt_st { +struct ossl_qrx_pkt_st { /* * Points to a logical representation of the decoded QUIC packet header. The * data and len fields point to the decrypted QUIC payload (i.e., to a @@ -252,7 +225,7 @@ typedef struct ossl_qrx_pkt_st { * packets. */ uint64_t key_epoch; -} OSSL_QRX_PKT; +}; /* * Tries to read a new decrypted packet from the QRX. diff --git a/include/internal/quic_record_tx.h b/include/internal/quic_record_tx.h index f3b798fea06ce5414c9c8dc0efa58dd86e42266b..068899832610bfa72479d334af348e051132e61a 100644 --- a/include/internal/quic_record_tx.h +++ b/include/internal/quic_record_tx.h @@ -13,6 +13,7 @@ # include # include "internal/quic_wire_pkt.h" # include "internal/quic_types.h" +# include "internal/quic_predef.h" # include "internal/quic_record_util.h" # ifndef OPENSSL_NO_QUIC @@ -148,7 +149,7 @@ uint32_t ossl_qrl_get_suite_cipher_tag_len(uint32_t suite_id); * ------------------- */ -typedef struct ossl_qtx_pkt_st { +struct ossl_qtx_pkt_st { /* Logical packet header to be serialized. */ QUIC_PKT_HDR *hdr; @@ -176,7 +177,7 @@ typedef struct ossl_qtx_pkt_st { /* Packet flags. Zero or more OSSL_QTX_PKT_FLAG_* values. */ uint32_t flags; -} OSSL_QTX_PKT; +}; /* * More packets will be written which should be coalesced into a single diff --git a/include/internal/quic_srtm.h b/include/internal/quic_srtm.h index 9a2c18fdf33a02afbace48b411bcd466ba536751..830c3992757a0eca18d8cdf6dec6c66bc56d36b5 100644 --- a/include/internal/quic_srtm.h +++ b/include/internal/quic_srtm.h @@ -15,6 +15,7 @@ # include "internal/time.h" # include "internal/quic_types.h" # include "internal/quic_wire.h" +# include "internal/quic_predef.h" # ifndef OPENSSL_NO_QUIC @@ -53,7 +54,6 @@ * The opaque pointer may be used for any purpose but is intended to represent a * connection identity and must therefore be consistent (usefully comparable). */ -typedef struct quic_srtm_st QUIC_SRTM; /* Creates a new empty SRTM instance. */ QUIC_SRTM *ossl_quic_srtm_new(OSSL_LIB_CTX *libctx, const char *propq); diff --git a/include/internal/quic_statm.h b/include/internal/quic_statm.h index 5b33551b06cabb99378548a575557efa7ed88abf..2fca69b0d181b9a61fb2320bf8421049f5c3abfe 100644 --- a/include/internal/quic_statm.h +++ b/include/internal/quic_statm.h @@ -12,13 +12,14 @@ # include # include "internal/time.h" +# include "internal/quic_predef.h" # ifndef OPENSSL_NO_QUIC -typedef struct ossl_statm_st { +struct ossl_statm_st { OSSL_TIME smoothed_rtt, latest_rtt, min_rtt, rtt_variance; char have_first_sample; -} OSSL_STATM; +}; typedef struct ossl_rtt_info_st { /* As defined in RFC 9002. */ diff --git a/include/internal/quic_stream.h b/include/internal/quic_stream.h index 0da8febd5a8c8ac8f72770bbb5785b10857810de..d446dadc5047736d4bb40503054c7fba4902a1dd 100644 --- a/include/internal/quic_stream.h +++ b/include/internal/quic_stream.h @@ -14,6 +14,7 @@ #include "internal/e_os.h" #include "internal/time.h" #include "internal/quic_types.h" +#include "internal/quic_predef.h" #include "internal/quic_wire.h" #include "internal/quic_record_tx.h" #include "internal/quic_record_rx.h" @@ -51,7 +52,6 @@ * datagrams. The terms 'send' and 'receive' are used when referring to the * stream abstraction. Applications send; we transmit. */ -typedef struct quic_sstream_st QUIC_SSTREAM; /* * Instantiates a new QUIC_SSTREAM. init_buf_size specifies the initial size of @@ -312,7 +312,6 @@ void ossl_quic_sstream_set_cleanse(QUIC_SSTREAM *qss, int cleanse); * (i.e., for a unidirectional receiving stream or for the receiving component * of a bidirectional stream). */ -typedef struct quic_rstream_st QUIC_RSTREAM; /* * Create a new instance of QUIC_RSTREAM with pointers to the flow diff --git a/include/internal/quic_stream_map.h b/include/internal/quic_stream_map.h index ae7490619bb165670f1f5419f3e59b7d371999bf..9d860f6d1f46181fdf2f145858c9d0118076fe87 100644 --- a/include/internal/quic_stream_map.h +++ b/include/internal/quic_stream_map.h @@ -15,6 +15,7 @@ # include "internal/time.h" # include "internal/common.h" # include "internal/quic_types.h" +# include "internal/quic_predef.h" # include "internal/quic_stream.h" # include "internal/quic_fc.h" # include @@ -27,7 +28,6 @@ * * Logical QUIC stream composing all relevant send and receive components. */ -typedef struct quic_stream_st QUIC_STREAM; typedef struct quic_stream_list_node_st QUIC_STREAM_LIST_NODE; @@ -514,7 +514,7 @@ static ossl_inline ossl_unused int ossl_quic_stream_recv_get_final_size(const QU * - allows iteration over the active streams only. * */ -typedef struct quic_stream_map_st { +struct quic_stream_map_st { LHASH_OF(QUIC_STREAM) *map; QUIC_STREAM_LIST_NODE active_list; QUIC_STREAM_LIST_NODE accept_list; @@ -527,7 +527,7 @@ typedef struct quic_stream_map_st { QUIC_RXFC *max_streams_bidi_rxfc; QUIC_RXFC *max_streams_uni_rxfc; int is_server; -} QUIC_STREAM_MAP; +}; /* * get_stream_limit is a callback which is called to retrieve the current stream diff --git a/include/internal/quic_tls.h b/include/internal/quic_tls.h index 0e4a9d339b74f8519b7c2971fa4b570a1a37c1c3..f9f007a76cc475ee8a29f6a0b7e42fcf5b7b170f 100644 --- a/include/internal/quic_tls.h +++ b/include/internal/quic_tls.h @@ -12,9 +12,9 @@ # include # include "internal/quic_stream.h" +# include "internal/quic_predef.h" - -typedef struct quic_tls_st QUIC_TLS; +# ifndef OPENSSL_NO_QUIC typedef struct quic_tls_args_st { /* @@ -103,4 +103,6 @@ int ossl_quic_tls_get_error(QUIC_TLS *qtls, int ossl_quic_tls_is_cert_request(QUIC_TLS *qtls); int ossl_quic_tls_has_bad_max_early_data(QUIC_TLS *qtls); +# endif + #endif diff --git a/include/internal/quic_txp.h b/include/internal/quic_txp.h index ae508f2393bd41bc63fd388ed3fd1deff020d706..7c00c4141939acbee8500f332dc0fd274a46d1a8 100644 --- a/include/internal/quic_txp.h +++ b/include/internal/quic_txp.h @@ -12,6 +12,7 @@ # include # include "internal/quic_types.h" +# include "internal/quic_predef.h" # include "internal/quic_record_tx.h" # include "internal/quic_cfq.h" # include "internal/quic_txpim.h" @@ -59,8 +60,6 @@ typedef struct ossl_quic_tx_packetiser_args_st { } OSSL_QUIC_TX_PACKETISER_ARGS; -typedef struct ossl_quic_tx_packetiser_st OSSL_QUIC_TX_PACKETISER; - OSSL_QUIC_TX_PACKETISER *ossl_quic_tx_packetiser_new(const OSSL_QUIC_TX_PACKETISER_ARGS *args); typedef void (ossl_quic_initial_token_free_fn)(const unsigned char *buf, diff --git a/include/internal/quic_txpim.h b/include/internal/quic_txpim.h index ed6e3875c47b2def02a9c81ba3648a337f36377b..efe1ca6302a99810995a223afeb69cd7da39a429 100644 --- a/include/internal/quic_txpim.h +++ b/include/internal/quic_txpim.h @@ -12,6 +12,7 @@ # include # include "internal/quic_types.h" +# include "internal/quic_predef.h" # include "internal/quic_cfq.h" # include "internal/quic_ackm.h" @@ -21,8 +22,6 @@ * QUIC Transmitted Packet Information Manager * =========================================== */ -typedef struct quic_txpim_st QUIC_TXPIM; -typedef struct quic_fifd_st QUIC_FIFD; typedef struct quic_txpim_pkt_st { /* ACKM-specific data. Caller should fill this. */ diff --git a/include/internal/quic_types.h b/include/internal/quic_types.h index 1d3816a20987226ead56dc573a9a2d25df255507..fa1ac81ca1e6a8c52444247e169560c9e6bf59a2 100644 --- a/include/internal/quic_types.h +++ b/include/internal/quic_types.h @@ -87,6 +87,13 @@ static ossl_unused ossl_inline int ossl_quic_conn_id_eq(const QUIC_CONN_ID *a, return memcmp(a->id, b->id, a->id_len) == 0; } +/* + * Generates a random CID of the given length. libctx may be NULL. + * Returns 1 on success or 0 on failure. + */ +int ossl_quic_gen_rand_conn_id(OSSL_LIB_CTX *libctx, size_t len, + QUIC_CONN_ID *cid); + # define QUIC_MIN_INITIAL_DGRAM_LEN 1200 # define QUIC_DEFAULT_ACK_DELAY_EXP 3 diff --git a/include/openssl/cmp.h.in b/include/openssl/cmp.h.in index 5bd8beb57a14dbe1d743343586b63c581b9dd7b7..d53d74a6e1d999253299930fbd1bccc683dee9dc 100644 --- a/include/openssl/cmp.h.in +++ b/include/openssl/cmp.h.in @@ -261,6 +261,10 @@ int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **itav_sk_p, OSSL_CMP_ITAV *itav); void OSSL_CMP_ITAV_free(OSSL_CMP_ITAV *itav); +OSSL_CMP_ITAV *OSSL_CMP_ITAV_new0_certProfile(STACK_OF(ASN1_UTF8STRING) + *certProfile); +int OSSL_CMP_ITAV_get0_certProfile(const OSSL_CMP_ITAV *itav, + STACK_OF(ASN1_UTF8STRING) **out); OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_caCerts(const STACK_OF(X509) *caCerts); int OSSL_CMP_ITAV_get0_caCerts(const OSSL_CMP_ITAV *itav, STACK_OF(X509) **out); @@ -351,6 +355,8 @@ int OSSL_CMP_CTX_set1_secretValue(OSSL_CMP_CTX *ctx, int OSSL_CMP_CTX_set1_recipient(OSSL_CMP_CTX *ctx, const X509_NAME *name); int OSSL_CMP_CTX_push0_geninfo_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav); int OSSL_CMP_CTX_reset_geninfo_ITAVs(OSSL_CMP_CTX *ctx); +STACK_OF(OSSL_CMP_ITAV) + *OSSL_CMP_CTX_get0_geninfo_ITAVs(const OSSL_CMP_CTX *ctx); int OSSL_CMP_CTX_set1_extraCertsOut(OSSL_CMP_CTX *ctx, STACK_OF(X509) *extraCertsOut); /* certificate template: */ @@ -403,6 +409,8 @@ OSSL_CMP_STATUSINFO_new(int status, int fail_info, const char *text); ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const OSSL_CMP_PKIHEADER *hdr); ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr); +STACK_OF(OSSL_CMP_ITAV) + *OSSL_CMP_HDR_get0_geninfo_ITAVs(const OSSL_CMP_PKIHEADER *hdr); /* from cmp_msg.c */ OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg); @@ -468,6 +476,13 @@ int OSSL_CMP_SRV_CTX_init(OSSL_CMP_SRV_CTX *srv_ctx, void *custom_ctx, OSSL_CMP_SRV_error_cb_t process_error, OSSL_CMP_SRV_certConf_cb_t process_certConf, OSSL_CMP_SRV_pollReq_cb_t process_pollReq); +typedef int (*OSSL_CMP_SRV_delayed_delivery_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req); +typedef int (*OSSL_CMP_SRV_clean_transaction_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const ASN1_OCTET_STRING *id); +int OSSL_CMP_SRV_CTX_init_trans(OSSL_CMP_SRV_CTX *srv_ctx, + OSSL_CMP_SRV_delayed_delivery_cb_t delay, + OSSL_CMP_SRV_clean_transaction_cb_t clean); OSSL_CMP_CTX *OSSL_CMP_SRV_CTX_get0_cmp_ctx(const OSSL_CMP_SRV_CTX *srv_ctx); void *OSSL_CMP_SRV_CTX_get0_custom_ctx(const OSSL_CMP_SRV_CTX *srv_ctx); int OSSL_CMP_SRV_CTX_set_send_unprotected_errors(OSSL_CMP_SRV_CTX *srv_ctx, @@ -484,6 +499,8 @@ X509 *OSSL_CMP_exec_certreq(OSSL_CMP_CTX *ctx, int req_type, # define OSSL_CMP_CR 2 # define OSSL_CMP_P10CR 4 # define OSSL_CMP_KUR 7 +# define OSSL_CMP_GENM 21 +# define OSSL_CMP_ERROR 23 # define OSSL_CMP_exec_IR_ses(ctx) \ OSSL_CMP_exec_certreq(ctx, OSSL_CMP_IR, NULL) # define OSSL_CMP_exec_CR_ses(ctx) \ diff --git a/include/openssl/cmperr.h b/include/openssl/cmperr.h index 57a6effbe3fc2db148abe0c9bec7ddeb79e27dc3..c6ca3d10d35617315ea24b421f1844924ac68ae8 100644 --- a/include/openssl/cmperr.h +++ b/include/openssl/cmperr.h @@ -55,6 +55,7 @@ # define CMP_R_ERROR_UNEXPECTED_CERTCONF 160 # define CMP_R_ERROR_VALIDATING_PROTECTION 140 # define CMP_R_ERROR_VALIDATING_SIGNATURE 171 +# define CMP_R_EXPECTED_POLLREQ 104 # define CMP_R_FAILED_BUILDING_OWN_CHAIN 164 # define CMP_R_FAILED_EXTRACTING_PUBKEY 141 # define CMP_R_FAILURE_OBTAINING_RANDOM 110 @@ -98,14 +99,17 @@ # define CMP_R_TRANSACTIONID_UNMATCHED 152 # define CMP_R_TRANSFER_ERROR 159 # define CMP_R_UNCLEAN_CTX 191 +# define CMP_R_UNEXPECTED_CERTPROFILE 196 # define CMP_R_UNEXPECTED_PKIBODY 133 # define CMP_R_UNEXPECTED_PKISTATUS 185 +# define CMP_R_UNEXPECTED_POLLREQ 105 # define CMP_R_UNEXPECTED_PVNO 153 # define CMP_R_UNKNOWN_ALGORITHM_ID 134 # define CMP_R_UNKNOWN_CERT_TYPE 135 # define CMP_R_UNKNOWN_PKISTATUS 186 # define CMP_R_UNSUPPORTED_ALGORITHM 136 # define CMP_R_UNSUPPORTED_KEY_TYPE 137 +# define CMP_R_UNSUPPORTED_PKIBODY 101 # define CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC 154 # define CMP_R_VALUE_TOO_LARGE 175 # define CMP_R_VALUE_TOO_SMALL 177 diff --git a/include/openssl/conferr.h b/include/openssl/conferr.h index 496e2e1efd66a45bc7715e9856bb87a2db805b8d..a8798e792412bac701497177d0e5457f0c96339b 100644 --- a/include/openssl/conferr.h +++ b/include/openssl/conferr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2021 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 @@ -38,6 +38,7 @@ # define CONF_R_NUMBER_TOO_LARGE 121 # define CONF_R_OPENSSL_CONF_REFERENCES_MISSING_SECTION 124 # define CONF_R_RECURSIVE_DIRECTORY_INCLUDE 111 +# define CONF_R_RECURSIVE_SECTION_REFERENCE 126 # define CONF_R_RELATIVE_PATH 125 # define CONF_R_SSL_COMMAND_SECTION_EMPTY 117 # define CONF_R_SSL_COMMAND_SECTION_NOT_FOUND 118 diff --git a/include/openssl/err.h.in b/include/openssl/err.h.in index 1ef09de02e02ecc4738e810cc6d414b557138d9b..9143704c098e2218e69f1e34191da0e39d476736 100644 --- a/include/openssl/err.h.in +++ b/include/openssl/err.h.in @@ -486,6 +486,7 @@ int ERR_set_mark(void); int ERR_pop_to_mark(void); int ERR_clear_last_mark(void); int ERR_count_to_mark(void); +int ERR_pop(void); ERR_STATE *OSSL_ERR_STATE_new(void); void OSSL_ERR_STATE_save(ERR_STATE *es); diff --git a/ssl/quic/build.info b/ssl/quic/build.info index e8016dae91fdb60f38c7d59d988e62ad634d9704..9927d344d8eb7a9f2db53632d985a3e708140f67 100644 --- a/ssl/quic/build.info +++ b/ssl/quic/build.info @@ -9,10 +9,11 @@ SOURCE[$LIBSSL]=quic_cfq.c quic_txpim.c quic_fifd.c quic_txp.c SOURCE[$LIBSSL]=quic_stream_map.c SOURCE[$LIBSSL]=quic_sf_list.c quic_rstream.c quic_sstream.c SOURCE[$LIBSSL]=quic_reactor.c -SOURCE[$LIBSSL]=quic_channel.c +SOURCE[$LIBSSL]=quic_channel.c quic_port.c quic_engine.c SOURCE[$LIBSSL]=quic_tserver.c SOURCE[$LIBSSL]=quic_tls.c SOURCE[$LIBSSL]=quic_thread_assist.c SOURCE[$LIBSSL]=quic_trace.c SOURCE[$LIBSSL]=quic_srtm.c quic_srt_gen.c SOURCE[$LIBSSL]=quic_lcidm.c +SOURCE[$LIBSSL]=quic_types.c diff --git a/ssl/quic/quic_channel.c b/ssl/quic/quic_channel.c index d3b7947fb462587200512c9463a16599eb40ec76..b5f019f40ed5218b7d66eebf0b4eef6ef903d22e 100644 --- a/ssl/quic/quic_channel.c +++ b/ssl/quic/quic_channel.c @@ -12,8 +12,12 @@ #include "internal/quic_channel.h" #include "internal/quic_error.h" #include "internal/quic_rx_depack.h" +#include "internal/quic_lcidm.h" +#include "internal/quic_srtm.h" #include "../ssl_local.h" #include "quic_channel_local.h" +#include "quic_port_local.h" +#include "quic_engine_local.h" /* * NOTE: While this channel implementation currently has basic server support, @@ -25,7 +29,6 @@ * TODO(QUIC SERVER): Implement retry logic */ -#define INIT_DCID_LEN 8 #define INIT_CRYPTO_RECV_BUF_LEN 16384 #define INIT_CRYPTO_SEND_BUF_LEN 16384 #define INIT_APP_BUF_LEN 8192 @@ -45,11 +48,11 @@ */ #define DEFAULT_MAX_ACK_DELAY QUIC_DEFAULT_MAX_ACK_DELAY +DEFINE_LIST_OF_IMPL(ch, QUIC_CHANNEL); + static void ch_save_err_state(QUIC_CHANNEL *ch); -static void ch_rx_pre(QUIC_CHANNEL *ch); static int ch_rx(QUIC_CHANNEL *ch, int channel_only); static int ch_tx(QUIC_CHANNEL *ch); -static void ch_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags); static int ch_tick_tls(QUIC_CHANNEL *ch, int channel_only); static void ch_rx_handle_packet(QUIC_CHANNEL *ch, int channel_only); static OSSL_TIME ch_determine_next_tick_deadline(QUIC_CHANNEL *ch); @@ -89,17 +92,10 @@ static int ch_discard_el(QUIC_CHANNEL *ch, static void ch_on_idle_timeout(QUIC_CHANNEL *ch); static void ch_update_idle(QUIC_CHANNEL *ch); static void ch_update_ping_deadline(QUIC_CHANNEL *ch); -static void ch_stateless_reset(QUIC_CHANNEL *ch); -static void ch_raise_net_error(QUIC_CHANNEL *ch); static void ch_on_terminating_timeout(QUIC_CHANNEL *ch); static void ch_start_terminating(QUIC_CHANNEL *ch, const QUIC_TERMINATE_CAUSE *tcause, int force_immediate); -static int ch_stateless_reset_token_handler(const unsigned char *data, size_t datalen, void *arg); -static void ch_default_packet_handler(QUIC_URXE *e, void *arg); -static int ch_server_on_new_conn(QUIC_CHANNEL *ch, const BIO_ADDR *peer, - const QUIC_CONN_ID *peer_scid, - const QUIC_CONN_ID *peer_dcid); static void ch_on_txp_ack_tx(const OSSL_QUIC_FRAME_ACK *ack, uint32_t pn_space, void *arg); static void ch_rx_handle_version_neg(QUIC_CHANNEL *ch, OSSL_QRX_PKT *pkt); @@ -107,152 +103,6 @@ static void ch_raise_version_neg_failure(QUIC_CHANNEL *ch); DEFINE_LHASH_OF_EX(QUIC_SRT_ELEM); -static int gen_rand_conn_id(OSSL_LIB_CTX *libctx, size_t len, QUIC_CONN_ID *cid) -{ - if (len > QUIC_MAX_CONN_ID_LEN) - return 0; - - cid->id_len = (unsigned char)len; - - if (RAND_bytes_ex(libctx, cid->id, len, len * 8) != 1) { - ERR_raise(ERR_LIB_SSL, ERR_R_RAND_LIB); - cid->id_len = 0; - return 0; - } - - return 1; -} - -static unsigned long chan_reset_token_hash(const QUIC_SRT_ELEM *a) -{ - unsigned long h; - - assert(sizeof(h) <= sizeof(a->token)); - memcpy(&h, &a->token, sizeof(h)); - return h; -} - -static int chan_reset_token_cmp(const QUIC_SRT_ELEM *a, const QUIC_SRT_ELEM *b) -{ - /* RFC 9000 s. 10.3.1: - * When comparing a datagram to stateless reset token values, - * endpoints MUST perform the comparison without leaking - * information about the value of the token. For example, - * performing this comparison in constant time protects the - * value of individual stateless reset tokens from information - * leakage through timing side channels. - * - * TODO(QUIC FUTURE): make this a memcmp when obfuscation is done and update - * comment above. - */ - return CRYPTO_memcmp(&a->token, &b->token, sizeof(a->token)); -} - -static int reset_token_obfuscate(QUIC_SRT_ELEM *out, const unsigned char *in) -{ - /* - * TODO(QUIC FUTURE): update this to AES encrypt the token in ECB mode with a - * random (per channel) key. - */ - memcpy(&out->token, in, sizeof(out->token)); - return 1; -} - -/* - * Add a stateless reset token to the channel - */ -static int chan_add_reset_token(QUIC_CHANNEL *ch, const unsigned char *new, - uint64_t seq_num) -{ - QUIC_SRT_ELEM *srte; - int err; - - /* Add to list by sequence number (always the tail) */ - if ((srte = OPENSSL_malloc(sizeof(*srte))) == NULL) - return 0; - - ossl_list_stateless_reset_tokens_init_elem(srte); - ossl_list_stateless_reset_tokens_insert_tail(&ch->srt_list_seq, srte); - reset_token_obfuscate(srte, new); - srte->seq_num = seq_num; - - lh_QUIC_SRT_ELEM_insert(ch->srt_hash_tok, srte); - err = lh_QUIC_SRT_ELEM_error(ch->srt_hash_tok); - if (err > 0) { - ossl_list_stateless_reset_tokens_remove(&ch->srt_list_seq, srte); - OPENSSL_free(srte); - return 0; - } - return 1; -} - -/* - * Remove a stateless reset token from the channel - * If the token isn't known, we just ignore the remove request which is safe. - */ -static void chan_remove_reset_token(QUIC_CHANNEL *ch, uint64_t seq_num) -{ - QUIC_SRT_ELEM *srte; - - /* - * Because the list is ordered and we only ever remove CIDs in order, - * this loop should never iterate, but safer to provide the option. - */ - for (srte = ossl_list_stateless_reset_tokens_head(&ch->srt_list_seq); - srte != NULL; - srte = ossl_list_stateless_reset_tokens_next(srte)) { - if (srte->seq_num > seq_num) - return; - if (srte->seq_num == seq_num) { - ossl_list_stateless_reset_tokens_remove(&ch->srt_list_seq, srte); - (void)lh_QUIC_SRT_ELEM_delete(ch->srt_hash_tok, srte); - OPENSSL_free(srte); - return; - } - } -} - -/* - * This is called by the demux whenever a new datagram arrives - * - * TODO(QUIC FUTURE): optimise this to only be called for unparsable packets - */ -static int ch_stateless_reset_token_handler(const unsigned char *data, - size_t datalen, void *arg) -{ - QUIC_SRT_ELEM srte; - QUIC_CHANNEL *ch = (QUIC_CHANNEL *)arg; - - /* - * Perform some fast and cheap checks for a packet not being a stateless - * reset token. RFC 9000 s. 10.3 specifies this layout for stateless - * reset packets: - * - * Stateless Reset { - * Fixed Bits (2) = 1, - * Unpredictable Bits (38..), - * Stateless Reset Token (128), - * } - * - * It also specifies: - * However, endpoints MUST treat any packet ending in a valid - * stateless reset token as a Stateless Reset, as other QUIC - * versions might allow the use of a long header. - * - * We can rapidly check for the minimum length and that the first pair - * of bits in the first byte are 01 or 11. - * - * The function returns 1 if it is a stateless reset packet, 0 if it isn't - * and -1 if an error was encountered. - */ - if (datalen < QUIC_STATELESS_RESET_TOKEN_LEN + 5 || (0100 & *data) != 0100) - return 0; - memset(&srte, 0, sizeof(srte)); - if (!reset_token_obfuscate(&srte, data + datalen - sizeof(srte.token))) - return -1; - return lh_QUIC_SRT_ELEM_retrieve(ch->srt_hash_tok, &srte) != NULL; -} - /* * QUIC Channel Initialization and Teardown * ======================================== @@ -272,21 +122,23 @@ static int ch_init(QUIC_CHANNEL *ch) OSSL_QRX_ARGS qrx_args = {0}; QUIC_TLS_ARGS tls_args = {0}; uint32_t pn_space; - size_t rx_short_cid_len = ch->is_server ? INIT_DCID_LEN : 0; + size_t rx_short_dcid_len; + size_t tx_init_dcid_len; - ossl_list_stateless_reset_tokens_init(&ch->srt_list_seq); - ch->srt_hash_tok = lh_QUIC_SRT_ELEM_new(&chan_reset_token_hash, - &chan_reset_token_cmp); - if (ch->srt_hash_tok == NULL) + if (ch->port == NULL || ch->lcidm == NULL || ch->srtm == NULL) goto err; + rx_short_dcid_len = ossl_quic_port_get_rx_short_dcid_len(ch->port); + tx_init_dcid_len = ossl_quic_port_get_tx_init_dcid_len(ch->port); + /* For clients, generate our initial DCID. */ if (!ch->is_server - && !gen_rand_conn_id(ch->libctx, INIT_DCID_LEN, &ch->init_dcid)) + && !ossl_quic_gen_rand_conn_id(ch->port->engine->libctx, tx_init_dcid_len, + &ch->init_dcid)) goto err; /* We plug in a network write BIO to the QTX later when we get one. */ - qtx_args.libctx = ch->libctx; + qtx_args.libctx = ch->port->engine->libctx; qtx_args.mdpl = QUIC_MIN_INITIAL_DGRAM_LEN; ch->rx_max_udp_payload_size = qtx_args.mdpl; @@ -358,6 +210,10 @@ static int ch_init(QUIC_CHANNEL *ch) ch->have_qsm = 1; + if (!ch->is_server + && !ossl_quic_lcidm_generate_initial(ch->lcidm, ch, &txp_args.cur_scid)) + goto err; + /* We use a zero-length SCID. */ txp_args.cur_dcid = ch->init_dcid; txp_args.ack_delay_exponent = 3; @@ -389,31 +245,9 @@ static int ch_init(QUIC_CHANNEL *ch) ossl_quic_tx_packetiser_set_ack_tx_cb(ch->txp, ch_on_txp_ack_tx, ch); - if ((ch->demux = ossl_quic_demux_new(/*BIO=*/NULL, - /*Short CID Len=*/rx_short_cid_len, - get_time, ch)) == NULL) - goto err; - - /* - * Setup a handler to detect stateless reset tokens. - */ - ossl_quic_demux_set_stateless_reset_handler(ch->demux, - &ch_stateless_reset_token_handler, - ch); - - /* - * If we are a server, setup our handler for packets not corresponding to - * any known DCID on our end. This is for handling clients establishing new - * connections. - */ - if (ch->is_server) - ossl_quic_demux_set_default_handler(ch->demux, - ch_default_packet_handler, - ch); - - qrx_args.libctx = ch->libctx; - qrx_args.demux = ch->demux; - qrx_args.short_conn_id_len = rx_short_cid_len; + qrx_args.libctx = ch->port->engine->libctx; + qrx_args.demux = ch->port->demux; + qrx_args.short_conn_id_len = rx_short_dcid_len; qrx_args.max_deferred = 32; if ((ch->qrx = ossl_qrx_new(&qrx_args)) == NULL) @@ -429,9 +263,6 @@ static int ch_init(QUIC_CHANNEL *ch) ch)) goto err; - if (!ch->is_server && !ossl_qrx_add_dst_conn_id(ch->qrx, &txp_args.cur_scid)) - goto err; - for (pn_space = QUIC_PN_SPACE_INITIAL; pn_space < QUIC_PN_SPACE_NUM; ++pn_space) { ch->crypto_recv[pn_space] = ossl_quic_rstream_new(NULL, NULL, 0); if (ch->crypto_recv[pn_space] == NULL) @@ -480,8 +311,8 @@ static int ch_init(QUIC_CHANNEL *ch) goto err; ch_update_idle(ch); - ossl_quic_reactor_init(&ch->rtor, ch_tick, ch, - ch_determine_next_tick_deadline(ch)); + ossl_list_ch_insert_tail(&ch->port->channel_list, ch); + ch->on_port_list = 1; return 1; err: @@ -491,7 +322,6 @@ err: static void ch_cleanup(QUIC_CHANNEL *ch) { - QUIC_SRT_ELEM *srte, *srte_next; uint32_t pn_space; if (ch->ackm != NULL) @@ -500,6 +330,8 @@ static void ch_cleanup(QUIC_CHANNEL *ch) ++pn_space) ossl_ackm_on_pkt_space_discarded(ch->ackm, pn_space); + ossl_quic_lcidm_cull(ch->lcidm, ch); + ossl_quic_srtm_cull(ch->srtm, ch); ossl_quic_tx_packetiser_free(ch->txp); ossl_quic_txpim_free(ch->txpim); ossl_quic_cfq_free(ch->cfq); @@ -523,22 +355,15 @@ static void ch_cleanup(QUIC_CHANNEL *ch) ossl_quic_tls_free(ch->qtls); ossl_qrx_free(ch->qrx); - ossl_quic_demux_free(ch->demux); OPENSSL_free(ch->local_transport_params); OPENSSL_free((char *)ch->terminate_cause.reason); OSSL_ERR_STATE_free(ch->err_state); OPENSSL_free(ch->ack_range_scratch); - /* Free the stateless reset tokens */ - for (srte = ossl_list_stateless_reset_tokens_head(&ch->srt_list_seq); - srte != NULL; - srte = srte_next) { - srte_next = ossl_list_stateless_reset_tokens_next(srte); - ossl_list_stateless_reset_tokens_remove(&ch->srt_list_seq, srte); - (void)lh_QUIC_SRT_ELEM_delete(ch->srt_hash_tok, srte); - OPENSSL_free(srte); + if (ch->on_port_list) { + ossl_list_ch_remove(&ch->port->channel_list, ch); + ch->on_port_list = 0; } - lh_QUIC_SRT_ELEM_free(ch->srt_hash_tok); } QUIC_CHANNEL *ossl_quic_channel_new(const QUIC_CHANNEL_ARGS *args) @@ -548,13 +373,11 @@ QUIC_CHANNEL *ossl_quic_channel_new(const QUIC_CHANNEL_ARGS *args) if ((ch = OPENSSL_zalloc(sizeof(*ch))) == NULL) return NULL; - ch->libctx = args->libctx; - ch->propq = args->propq; + ch->port = args->port; ch->is_server = args->is_server; ch->tls = args->tls; - ch->mutex = args->mutex; - ch->now_cb = args->now_cb; - ch->now_cb_arg = args->now_cb_arg; + ch->lcidm = args->lcidm; + ch->srtm = args->srtm; if (!ch_init(ch)) { OPENSSL_free(ch); @@ -613,7 +436,7 @@ int ossl_quic_channel_set_peer_addr(QUIC_CHANNEL *ch, const BIO_ADDR *peer_addr) QUIC_REACTOR *ossl_quic_channel_get_reactor(QUIC_CHANNEL *ch) { - return &ch->rtor; + return ossl_quic_port_get0_reactor(ch->port); } QUIC_STREAM_MAP *ossl_quic_channel_get_qsm(QUIC_CHANNEL *ch) @@ -682,17 +505,27 @@ int ossl_quic_channel_is_handshake_confirmed(const QUIC_CHANNEL *ch) QUIC_DEMUX *ossl_quic_channel_get0_demux(QUIC_CHANNEL *ch) { - return ch->demux; + return ch->port->demux; +} + +QUIC_PORT *ossl_quic_channel_get0_port(QUIC_CHANNEL *ch) +{ + return ch->port; +} + +QUIC_ENGINE *ossl_quic_channel_get0_engine(QUIC_CHANNEL *ch) +{ + return ossl_quic_port_get0_engine(ch->port); } CRYPTO_MUTEX *ossl_quic_channel_get_mutex(QUIC_CHANNEL *ch) { - return ch->mutex; + return ossl_quic_port_get0_mutex(ch->port); } int ossl_quic_channel_has_pending(const QUIC_CHANNEL *ch) { - return ossl_quic_demux_has_pending(ch->demux) + return ossl_quic_demux_has_pending(ch->port->demux) || ossl_qrx_processed_read_pending(ch->qrx); } @@ -706,10 +539,7 @@ static OSSL_TIME get_time(void *arg) { QUIC_CHANNEL *ch = arg; - if (ch->now_cb == NULL) - return ossl_time_now(); - - return ch->now_cb(ch->now_cb_arg); + return ossl_quic_port_get_time(ch->port); } /* Used by QSM. */ @@ -1603,7 +1433,8 @@ static int ch_on_transport_params(const unsigned char *params, reason = TP_REASON_MALFORMED("STATELESS_RESET_TOKEN"); goto malformed; } - if (!chan_add_reset_token(ch, body, ch->cur_remote_seq_num)) { + if (!ossl_quic_srtm_add(ch->srtm, ch, ch->cur_remote_seq_num, + (const QUIC_STATELESS_RESET_TOKEN *)body)) { reason = TP_REASON_INTERNAL_ERROR("STATELESS_RESET_TOKEN"); goto malformed; } @@ -1849,20 +1680,20 @@ err: * at least everything network I/O related. Best effort - not allowed to fail * "loudly". */ -static void ch_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags) +void ossl_quic_channel_subtick(QUIC_CHANNEL *ch, QUIC_TICK_RESULT *res, + uint32_t flags) { OSSL_TIME now, deadline; - QUIC_CHANNEL *ch = arg; int channel_only = (flags & QUIC_REACTOR_TICK_FLAG_CHANNEL_ONLY) != 0; /* * When we tick the QUIC connection, we do everything we need to do - * periodically. In order, we: + * periodically. Network I/O handling will already have been performed + * as necessary by the QUIC port. Thus, in order, we: * - * - handle any incoming data from the network; - * - handle any timer events which are due to fire (ACKM, etc.) - * - write any data to the network due to be sent, to the extent - * possible; + * - handle any packets the DEMUX has queued up for us; + * - handle any timer events which are due to fire (ACKM, etc.); + * - generate any packets which need to be sent; * - determine the time at which we should next be ticked. */ @@ -1890,13 +1721,10 @@ static void ch_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags) } } - if (!ch->inhibit_tick) { + if (!ch->port->engine->inhibit_tick) { /* Handle RXKU timeouts. */ ch_rxku_tick(ch); - /* Handle any incoming data from network. */ - ch_rx_pre(ch); - do { /* Process queued incoming packets. */ ch->did_tls_tick = 0; @@ -1933,7 +1761,7 @@ static void ch_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags) * Idle timeout differs from normal protocol violation because we do * not send a CONN_CLOSE frame; go straight to TERMINATED. */ - if (!ch->inhibit_tick) + if (!ch->port->engine->inhibit_tick) ch_on_idle_timeout(ch); res->net_read_desired = 0; @@ -1942,7 +1770,7 @@ static void ch_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags) return; } - if (!ch->inhibit_tick) { + if (!ch->port->engine->inhibit_tick) { deadline = ossl_ackm_get_loss_detection_deadline(ch->ackm); if (!ossl_time_is_zero(deadline) && ossl_time_compare(now, deadline) >= 0) @@ -1964,7 +1792,7 @@ static void ch_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags) ch_update_ping_deadline(ch); } - /* Write any data to the network due to be sent. */ + /* Queue any data to be sent for transmission. */ ch_tx(ch); /* Do stream GC. */ @@ -1975,14 +1803,13 @@ static void ch_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags) res->tick_deadline = ch_determine_next_tick_deadline(ch); /* - * Always process network input unless we are now terminated. - * Although we had not terminated at the beginning of this tick, network - * errors in ch_rx_pre() or ch_tx() may have caused us to transition to the - * Terminated state. + * Always process network input unless we are now terminated. Although we + * had not terminated at the beginning of this tick, network errors in + * ch_tx() may have caused us to transition to the Terminated state. */ res->net_read_desired = !ossl_quic_channel_is_terminated(ch); - /* We want to write to the network if we have any in our queue. */ + /* We want to write to the network if we have any data in our TX queue. */ res->net_write_desired = (!ossl_quic_channel_is_terminated(ch) && ossl_qtx_get_queue_len_datagrams(ch->qtx) > 0); @@ -2010,32 +1837,6 @@ static int ch_tick_tls(QUIC_CHANNEL *ch, int channel_only) return 1; } -/* Process incoming datagrams, if any. */ -static void ch_rx_pre(QUIC_CHANNEL *ch) -{ - int ret; - - if (!ch->is_server && !ch->have_sent_any_pkt) - return; - - /* - * Get DEMUX to BIO_recvmmsg from the network and queue incoming datagrams - * to the appropriate QRX instance. - */ - ret = ossl_quic_demux_pump(ch->demux); - if (ret == QUIC_DEMUX_PUMP_RES_STATELESS_RESET) - ch_stateless_reset(ch); - else if (ret == QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL) - /* - * We don't care about transient failure, but permanent failure means we - * should tear down the connection as though a protocol violation - * occurred. Skip straight to the Terminating state as there is no point - * trying to send CONNECTION_CLOSE frames if the network BIO is not - * operating correctly. - */ - ch_raise_net_error(ch); -} - /* Check incoming forged packet limit and terminate connection if needed. */ static void ch_rx_check_forged_pkt_limit(QUIC_CHANNEL *ch) { @@ -2270,8 +2071,8 @@ static void ch_rx_handle_packet(QUIC_CHANNEL *ch, int channel_only) * than allow the QRX to emit a potentially malformed packet to the * upper layers. However, special casing this will do for now. */ - if (!ossl_quic_validate_retry_integrity_tag(ch->libctx, - ch->propq, + if (!ossl_quic_validate_retry_integrity_tag(ch->port->engine->libctx, + ch->port->engine->propq, ch->qrx_pkt->hdr, &ch->init_dcid)) /* Malformed retry packet, ignore. */ @@ -2413,87 +2214,6 @@ static void ch_raise_version_neg_failure(QUIC_CHANNEL *ch) ch_start_terminating(ch, &tcause, 1); } -/* - * This is called by the demux when we get a packet not destined for any known - * DCID. - */ -static void ch_default_packet_handler(QUIC_URXE *e, void *arg) -{ - QUIC_CHANNEL *ch = arg; - PACKET pkt; - QUIC_PKT_HDR hdr; - - if (!ossl_assert(ch->is_server)) - goto undesirable; - - /* - * We only support one connection to our server currently, so if we already - * started one, ignore any new connection attempts. - */ - if (ch->state != QUIC_CHANNEL_STATE_IDLE) - goto undesirable; - - /* - * We have got a packet for an unknown DCID. This might be an attempt to - * open a new connection. - */ - if (e->data_len < QUIC_MIN_INITIAL_DGRAM_LEN) - goto undesirable; - - if (!PACKET_buf_init(&pkt, ossl_quic_urxe_data(e), e->data_len)) - goto err; - - /* - * We set short_conn_id_len to SIZE_MAX here which will cause the decode - * operation to fail if we get a 1-RTT packet. This is fine since we only - * care about Initial packets. - */ - if (!ossl_quic_wire_decode_pkt_hdr(&pkt, SIZE_MAX, 1, 0, &hdr, NULL)) - goto undesirable; - - switch (hdr.version) { - case QUIC_VERSION_1: - break; - - case QUIC_VERSION_NONE: - default: - /* Unknown version or proactive version negotiation request, bail. */ - /* TODO(QUIC SERVER): Handle version negotiation on server side */ - goto undesirable; - } - - /* - * We only care about Initial packets which might be trying to establish a - * connection. - */ - if (hdr.type != QUIC_PKT_TYPE_INITIAL) - goto undesirable; - - /* - * Assume this is a valid attempt to initiate a connection. - * - * We do not register the DCID in the initial packet we received and that - * DCID is not actually used again, thus after provisioning the correct - * Initial keys derived from it (which is done in the call below) we pass - * the received packet directly to the QRX so that it can process it as a - * one-time thing, instead of going through the usual DEMUX DCID-based - * routing. - */ - if (!ch_server_on_new_conn(ch, &e->peer, - &hdr.src_conn_id, - &hdr.dst_conn_id)) - goto err; - - ossl_qrx_inject_urxe(ch->qrx, e); - return; - -err: - ossl_quic_channel_raise_protocol_error(ch, QUIC_ERR_INTERNAL_ERROR, 0, - "internal error"); -undesirable: - ossl_quic_demux_release_urxe(ch->demux, e); -} - /* Try to generate packets and if possible, flush them to the network. */ static int ch_tx(QUIC_CHANNEL *ch) { @@ -2544,6 +2264,7 @@ static int ch_tx(QUIC_CHANNEL *ch) res = ossl_quic_tx_packetiser_generate(ch->txp, &status); if (status.sent_pkt > 0) { ch->have_sent_any_pkt = 1; /* Packet(s) were sent */ + ch->port->have_sent_any_pkt = 1; /* * RFC 9000 s. 10.1. 'An endpoint also restarts its idle timer when @@ -2599,7 +2320,7 @@ static int ch_tx(QUIC_CHANNEL *ch) case QTX_FLUSH_NET_RES_PERMANENT_FAIL: default: /* Permanent underlying network BIO, start terminating. */ - ch_raise_net_error(ch); + ossl_quic_port_raise_net_error(ch->port, ch); break; } @@ -2657,98 +2378,6 @@ static OSSL_TIME ch_determine_next_tick_deadline(QUIC_CHANNEL *ch) return deadline; } -/* - * QUIC Channel: Network BIO Configuration - * ======================================= - */ - -/* Determines whether we can support a given poll descriptor. */ -static int validate_poll_descriptor(const BIO_POLL_DESCRIPTOR *d) -{ - if (d->type == BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD && d->value.fd < 0) { - ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT); - return 0; - } - - return 1; -} - -BIO *ossl_quic_channel_get_net_rbio(QUIC_CHANNEL *ch) -{ - return ch->net_rbio; -} - -BIO *ossl_quic_channel_get_net_wbio(QUIC_CHANNEL *ch) -{ - return ch->net_wbio; -} - -static int ch_update_poll_desc(QUIC_CHANNEL *ch, BIO *net_bio, int for_write) -{ - BIO_POLL_DESCRIPTOR d = {0}; - - if (net_bio == NULL - || (!for_write && !BIO_get_rpoll_descriptor(net_bio, &d)) - || (for_write && !BIO_get_wpoll_descriptor(net_bio, &d))) - /* Non-pollable BIO */ - d.type = BIO_POLL_DESCRIPTOR_TYPE_NONE; - - if (!validate_poll_descriptor(&d)) - return 0; - - if (for_write) - ossl_quic_reactor_set_poll_w(&ch->rtor, &d); - else - ossl_quic_reactor_set_poll_r(&ch->rtor, &d); - - return 1; -} - -int ossl_quic_channel_update_poll_descriptors(QUIC_CHANNEL *ch) -{ - int ok = 1; - - if (!ch_update_poll_desc(ch, ch->net_rbio, /*for_write=*/0)) - ok = 0; - - if (!ch_update_poll_desc(ch, ch->net_wbio, /*for_write=*/1)) - ok = 0; - - return ok; -} - -/* - * QUIC_CHANNEL does not ref any BIO it is provided with, nor is any ref - * transferred to it. The caller (i.e., QUIC_CONNECTION) is responsible for - * ensuring the BIO lasts until the channel is freed or the BIO is switched out - * for another BIO by a subsequent successful call to this function. - */ -int ossl_quic_channel_set_net_rbio(QUIC_CHANNEL *ch, BIO *net_rbio) -{ - if (ch->net_rbio == net_rbio) - return 1; - - if (!ch_update_poll_desc(ch, net_rbio, /*for_write=*/0)) - return 0; - - ossl_quic_demux_set_bio(ch->demux, net_rbio); - ch->net_rbio = net_rbio; - return 1; -} - -int ossl_quic_channel_set_net_wbio(QUIC_CHANNEL *ch, BIO *net_wbio) -{ - if (ch->net_wbio == net_wbio) - return 1; - - if (!ch_update_poll_desc(ch, net_wbio, /*for_write=*/1)) - return 0; - - ossl_qtx_set_bio(ch->qtx, net_wbio); - ch->net_wbio = net_wbio; - return 1; -} - /* * QUIC Channel: Lifecycle Events * ============================== @@ -2771,8 +2400,8 @@ int ossl_quic_channel_start(QUIC_CHANNEL *ch) return 0; /* Plug in secrets for the Initial EL. */ - if (!ossl_quic_provide_initial_secret(ch->libctx, - ch->propq, + if (!ossl_quic_provide_initial_secret(ch->port->engine->libctx, + ch->port->engine->propq, &ch->init_dcid, ch->is_server, ch->qrx, ch->qtx)) @@ -2786,7 +2415,7 @@ int ossl_quic_channel_start(QUIC_CHANNEL *ch) if (!ch_tick_tls(ch, /*channel_only=*/0)) return 0; - ossl_quic_reactor_tick(&ch->rtor, 0); /* best effort */ + ossl_quic_reactor_tick(ossl_quic_port_get0_reactor(ch->port), 0); /* best effort */ return 1; } @@ -2871,8 +2500,8 @@ static int ch_retry(QUIC_CHANNEL *ch, * Plug in new secrets for the Initial EL. This is the only time we change * the secrets for an EL after we already provisioned it. */ - if (!ossl_quic_provide_initial_secret(ch->libctx, - ch->propq, + if (!ossl_quic_provide_initial_secret(ch->port->engine->libctx, + ch->port->engine->propq, &ch->retry_scid, /*is_server=*/0, ch->qrx, ch->qtx)) @@ -3133,7 +2762,7 @@ static int ch_enqueue_retire_conn_id(QUIC_CHANNEL *ch, uint64_t seq_num) WPACKET wpkt; size_t l; - chan_remove_reset_token(ch, seq_num); + ossl_quic_srtm_remove(ch->srtm, ch, seq_num); if ((buf_mem = BUF_MEM_new()) == NULL) goto err; @@ -3238,8 +2867,8 @@ void ossl_quic_channel_on_new_conn_id(QUIC_CHANNEL *ch, if (new_remote_seq_num > ch->cur_remote_seq_num) { /* Add new stateless reset token */ - if (!chan_add_reset_token(ch, f->stateless_reset.token, - new_remote_seq_num)) { + if (!ossl_quic_srtm_add(ch->srtm, ch, new_remote_seq_num, + &f->stateless_reset)) { ossl_quic_channel_raise_protocol_error( ch, QUIC_ERR_CONNECTION_ID_LIMIT_ERROR, OSSL_QUIC_FRAME_TYPE_NEW_CONN_ID, @@ -3290,25 +2919,32 @@ static void ch_save_err_state(QUIC_CHANNEL *ch) OSSL_ERR_STATE_save(ch->err_state); } -static void ch_stateless_reset(QUIC_CHANNEL *ch) +void ossl_quic_channel_inject(QUIC_CHANNEL *ch, QUIC_URXE *e) +{ + ossl_qrx_inject_urxe(ch->qrx, e); +} + +void ossl_quic_channel_on_stateless_reset(QUIC_CHANNEL *ch) { QUIC_TERMINATE_CAUSE tcause = {0}; - tcause.error_code = QUIC_ERR_NO_ERROR; - ch_start_terminating(ch, &tcause, 1); + tcause.error_code = QUIC_ERR_NO_ERROR; + tcause.remote = 1; + ch_start_terminating(ch, &tcause, 0); } -static void ch_raise_net_error(QUIC_CHANNEL *ch) +void ossl_quic_channel_raise_net_error(QUIC_CHANNEL *ch) { QUIC_TERMINATE_CAUSE tcause = {0}; - ch->net_error = 1; + if (ch->net_error) + return; - ERR_raise_data(ERR_LIB_SSL, SSL_R_QUIC_NETWORK_ERROR, - "connection terminated due to network error"); - ch_save_err_state(ch); + ch->net_error = 1; tcause.error_code = QUIC_ERR_INTERNAL_ERROR; + tcause.reason = "network BIO I/O error"; + tcause.reason_len = strlen(tcause.reason); /* * Skip Terminating state and go directly to Terminated, no point trying to @@ -3327,7 +2963,10 @@ void ossl_quic_channel_restore_err_state(QUIC_CHANNEL *ch) if (ch == NULL) return; - OSSL_ERR_STATE_restore(ch->err_state); + if (!ossl_quic_port_is_running(ch->port)) + ossl_quic_port_restore_err_state(ch->port); + else + OSSL_ERR_STATE_restore(ch->err_state); } void ossl_quic_channel_raise_protocol_error_loc(QUIC_CHANNEL *ch, @@ -3487,16 +3126,15 @@ static void ch_on_idle_timeout(QUIC_CHANNEL *ch) } /* Called when we, as a server, get a new incoming connection. */ -static int ch_server_on_new_conn(QUIC_CHANNEL *ch, const BIO_ADDR *peer, - const QUIC_CONN_ID *peer_scid, - const QUIC_CONN_ID *peer_dcid) +int ossl_quic_channel_on_new_conn(QUIC_CHANNEL *ch, const BIO_ADDR *peer, + const QUIC_CONN_ID *peer_scid, + const QUIC_CONN_ID *peer_dcid) { if (!ossl_assert(ch->state == QUIC_CHANNEL_STATE_IDLE && ch->is_server)) return 0; - /* Generate a SCID we will use for the connection. */ - if (!gen_rand_conn_id(ch->libctx, INIT_DCID_LEN, - &ch->cur_local_cid)) + /* Generate an Initial LCID we will use for the connection. */ + if (!ossl_quic_lcidm_generate_initial(ch->lcidm, ch, &ch->cur_local_cid)) return 0; /* Note our newly learnt peer address and CIDs. */ @@ -3516,15 +3154,15 @@ static int ch_server_on_new_conn(QUIC_CHANNEL *ch, const BIO_ADDR *peer, return 0; /* Plug in secrets for the Initial EL. */ - if (!ossl_quic_provide_initial_secret(ch->libctx, - ch->propq, + if (!ossl_quic_provide_initial_secret(ch->port->engine->libctx, + ch->port->engine->propq, &ch->init_dcid, /*is_server=*/1, ch->qrx, ch->qtx)) return 0; - /* Register our local CID in the DEMUX. */ - if (!ossl_qrx_add_dst_conn_id(ch->qrx, &ch->cur_local_cid)) + /* Register the peer ODCID in the LCIDM. */ + if (!ossl_quic_lcidm_enrol_odcid(ch->lcidm, ch, &ch->init_dcid)) return 0; /* Change state. */ @@ -3718,15 +3356,16 @@ void ossl_quic_channel_reject_stream(QUIC_CHANNEL *ch, QUIC_STREAM *qs) int ossl_quic_channel_replace_local_cid(QUIC_CHANNEL *ch, const QUIC_CONN_ID *conn_id) { - /* Remove the current local CID from the DEMUX. */ - if (!ossl_qrx_remove_dst_conn_id(ch->qrx, &ch->cur_local_cid)) + /* Remove the current LCID from the LCIDM. */ + if (!ossl_quic_lcidm_debug_remove(ch->lcidm, &ch->cur_local_cid)) return 0; ch->cur_local_cid = *conn_id; /* Set in the TXP, used only for long header packets. */ if (!ossl_quic_tx_packetiser_set_cur_scid(ch->txp, &ch->cur_local_cid)) return 0; - /* Register our new local CID in the DEMUX. */ - if (!ossl_qrx_add_dst_conn_id(ch->qrx, &ch->cur_local_cid)) + /* Add the new LCID to the LCIDM. */ + if (!ossl_quic_lcidm_debug_add(ch->lcidm, ch, &ch->cur_local_cid, + 100)) return 0; return 1; } @@ -3787,11 +3426,6 @@ int ossl_quic_channel_ping(QUIC_CHANNEL *ch) return 1; } -void ossl_quic_channel_set_inhibit_tick(QUIC_CHANNEL *ch, int inhibit) -{ - ch->inhibit_tick = (inhibit != 0); -} - uint16_t ossl_quic_channel_get_diag_num_rx_ack(QUIC_CHANNEL *ch) { return ch->diag_num_rx_ack; diff --git a/ssl/quic/quic_channel_local.h b/ssl/quic/quic_channel_local.h index f0ac74242087ab683cdf86c7f14016e4e5370d85..cd9fe276a5806ae2284a5ef5e4ee10578940ebb2 100644 --- a/ssl/quic/quic_channel_local.h +++ b/ssl/quic/quic_channel_local.h @@ -7,17 +7,9 @@ # include # include "internal/list.h" - - -typedef struct quic_srt_elem_st QUIC_SRT_ELEM; - -struct quic_srt_elem_st { - OSSL_LIST_MEMBER(stateless_reset_tokens, QUIC_SRT_ELEM); - QUIC_STATELESS_RESET_TOKEN token; - uint64_t seq_num; -}; - -DEFINE_LIST_OF(stateless_reset_tokens, QUIC_SRT_ELEM); +# include "internal/quic_predef.h" +# include "internal/quic_fc.h" +# include "internal/quic_stream_map.h" /* * QUIC Channel Structure @@ -36,22 +28,13 @@ DEFINE_LIST_OF(stateless_reset_tokens, QUIC_SRT_ELEM); * Other components should not include this header. */ struct quic_channel_st { - OSSL_LIB_CTX *libctx; - const char *propq; + QUIC_PORT *port; /* - * Master synchronisation mutex used for thread assisted mode - * synchronisation. We don't own this; the instantiator of the channel - * passes it to us and is responsible for freeing it after channel - * destruction. + * QUIC_PORT keeps the channels which belong to it on a list for bookkeeping + * purposes. */ - CRYPTO_MUTEX *mutex; - - /* - * Callback used to get the current time. - */ - OSSL_TIME (*now_cb)(void *arg); - void *now_cb_arg; + OSSL_LIST_MEMBER(ch, struct quic_channel_st); /* * The associated TLS 1.3 connection data. Used to provide the handshake @@ -61,21 +44,20 @@ struct quic_channel_st { QUIC_TLS *qtls; SSL *tls; + /* Port LCIDM we use to register LCIDs. */ + QUIC_LCIDM *lcidm; + /* SRTM we register SRTs with. */ + QUIC_SRTM *srtm; + /* * The transport parameter block we will send or have sent. * Freed after sending or when connection is freed. */ unsigned char *local_transport_params; - /* Asynchronous I/O reactor. */ - QUIC_REACTOR rtor; - /* Our current L4 peer address, if any. */ BIO_ADDR cur_peer_addr; - /* Network-side read and write BIOs. */ - BIO *net_rbio, *net_wbio; - /* * Subcomponents of the connection. All of these components are instantiated * and owned by us. @@ -96,14 +78,7 @@ struct quic_channel_st { const OSSL_CC_METHOD *cc_method; OSSL_ACKM *ackm; - /* - * RX demuxer. We register incoming DCIDs with this. Since we currently only - * support client operation and use one L4 port per connection, we own the - * demuxer and register a single zero-length DCID with it. - */ - QUIC_DEMUX *demux; - - /* Record layers in the TX and RX directions, plus the RX demuxer. */ + /* Record layers in the TX and RX directions. */ OSSL_QTX *qtx; OSSL_QRX *qrx; @@ -143,14 +118,6 @@ struct quic_channel_st { /* * The DCID we currently use to talk to the peer and its sequence num. - * - * TODO(QUIC FUTURE) consider removing the second two, both are contained in - * srt_list_seq (defined below). - * - * cur_remote_seq_num is same as the sequence number in the last element. - * cur_retire_prior_to corresponds to the sequence number in first element. - * - * Leaving them here avoids null checking etc */ QUIC_CONN_ID cur_remote_dcid; uint64_t cur_remote_seq_num; @@ -159,12 +126,6 @@ struct quic_channel_st { /* Server only: The DCID we currently expect the peer to use to talk to us. */ QUIC_CONN_ID cur_local_cid; - /* Hash of stateless reset tokens keyed on the token */ - LHASH_OF(QUIC_SRT_ELEM) *srt_hash_tok; - - /* List of the stateless reset tokens ordered by sequence number */ - OSSL_LIST(stateless_reset_tokens) srt_list_seq; - /* Transport parameter values we send to our peer. */ uint64_t tx_init_max_stream_data_bidi_local; uint64_t tx_init_max_stream_data_bidi_remote; @@ -458,12 +419,12 @@ struct quic_channel_st { */ unsigned int protocol_error : 1; - /* Inhibit tick for testing purposes? */ - unsigned int inhibit_tick : 1; - /* Are we using addressed mode? */ unsigned int addressed_mode : 1; + /* Are we on the QUIC_PORT linked list of channels? */ + unsigned int on_port_list : 1; + /* Saved error stack in case permanent error was encountered */ ERR_STATE *err_state; diff --git a/ssl/quic/quic_demux.c b/ssl/quic/quic_demux.c index 88135fe5b9e444a2b9b8aa590d17f5ce6be37b86..b3e03a0bcab6ee03c17e8cdc0e399191ed263b9d 100644 --- a/ssl/quic/quic_demux.c +++ b/ssl/quic/quic_demux.c @@ -21,37 +21,6 @@ #define DEMUX_DEFAULT_MTU 1500 -/* Structure used to track a given connection ID. */ -typedef struct quic_demux_conn_st QUIC_DEMUX_CONN; - -struct quic_demux_conn_st { - QUIC_DEMUX_CONN *next; /* used when unregistering only */ - QUIC_CONN_ID dst_conn_id; - ossl_quic_demux_cb_fn *cb; - void *cb_arg; -}; - -DEFINE_LHASH_OF_EX(QUIC_DEMUX_CONN); - -static unsigned long demux_conn_hash(const QUIC_DEMUX_CONN *conn) -{ - size_t i; - unsigned long v = 0; - - assert(conn->dst_conn_id.id_len <= QUIC_MAX_CONN_ID_LEN); - - for (i = 0; i < conn->dst_conn_id.id_len; ++i) - v ^= ((unsigned long)conn->dst_conn_id.id[i]) - << ((i * 8) % (sizeof(unsigned long) * 8)); - - return v; -} - -static int demux_conn_cmp(const QUIC_DEMUX_CONN *a, const QUIC_DEMUX_CONN *b) -{ - return !ossl_quic_conn_id_eq(&a->dst_conn_id, &b->dst_conn_id); -} - struct quic_demux_st { /* The underlying transport BIO with datagram semantics. */ BIO *net_bio; @@ -73,17 +42,10 @@ struct quic_demux_st { OSSL_TIME (*now)(void *arg); void *now_arg; - /* Hashtable mapping connection IDs to QUIC_DEMUX_CONN structures. */ - LHASH_OF(QUIC_DEMUX_CONN) *conns_by_id; - /* The default packet handler, if any. */ ossl_quic_demux_cb_fn *default_cb; void *default_cb_arg; - /* The stateless reset token checker handler, if any. */ - ossl_quic_stateless_reset_cb_fn *reset_token_cb; - void *reset_token_cb_arg; - /* * List of URXEs which are not currently in use (i.e., not filled with * unconsumed data). These are moved to the pending list as they are filled. @@ -121,13 +83,6 @@ QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio, demux->now = now; demux->now_arg = now_arg; - demux->conns_by_id - = lh_QUIC_DEMUX_CONN_new(demux_conn_hash, demux_conn_cmp); - if (demux->conns_by_id == NULL) { - OPENSSL_free(demux); - return NULL; - } - if (net_bio != NULL && BIO_dgram_get_local_addr_cap(net_bio) && BIO_dgram_set_local_addr_enable(net_bio, 1)) @@ -136,11 +91,6 @@ QUIC_DEMUX *ossl_quic_demux_new(BIO *net_bio, return demux; } -static void demux_free_conn_it(QUIC_DEMUX_CONN *conn, void *arg) -{ - OPENSSL_free(conn); -} - static void demux_free_urxl(QUIC_URXE_LIST *l) { QUIC_URXE *e, *enext; @@ -157,10 +107,6 @@ void ossl_quic_demux_free(QUIC_DEMUX *demux) if (demux == NULL) return; - /* Free all connection structures. */ - lh_QUIC_DEMUX_CONN_doall_arg(demux->conns_by_id, demux_free_conn_it, NULL); - lh_QUIC_DEMUX_CONN_free(demux->conns_by_id); - /* Free all URXEs we are holding. */ demux_free_urxl(&demux->urx_free); demux_free_urxl(&demux->urx_pending); @@ -195,104 +141,6 @@ int ossl_quic_demux_set_mtu(QUIC_DEMUX *demux, unsigned int mtu) return 1; } -static QUIC_DEMUX_CONN *demux_get_by_conn_id(QUIC_DEMUX *demux, - const QUIC_CONN_ID *dst_conn_id) -{ - QUIC_DEMUX_CONN key; - - if (dst_conn_id->id_len > QUIC_MAX_CONN_ID_LEN) - return NULL; - - key.dst_conn_id = *dst_conn_id; - return lh_QUIC_DEMUX_CONN_retrieve(demux->conns_by_id, &key); -} - -int ossl_quic_demux_register(QUIC_DEMUX *demux, - const QUIC_CONN_ID *dst_conn_id, - ossl_quic_demux_cb_fn *cb, void *cb_arg) -{ - QUIC_DEMUX_CONN *conn; - - if (dst_conn_id == NULL - || dst_conn_id->id_len > QUIC_MAX_CONN_ID_LEN - || cb == NULL) - return 0; - - /* Ensure not already registered. */ - if (demux_get_by_conn_id(demux, dst_conn_id) != NULL) - /* Handler already registered with this connection ID. */ - return 0; - - conn = OPENSSL_zalloc(sizeof(QUIC_DEMUX_CONN)); - if (conn == NULL) - return 0; - - conn->dst_conn_id = *dst_conn_id; - conn->cb = cb; - conn->cb_arg = cb_arg; - - lh_QUIC_DEMUX_CONN_insert(demux->conns_by_id, conn); - return 1; -} - -static void demux_unregister(QUIC_DEMUX *demux, - QUIC_DEMUX_CONN *conn) -{ - lh_QUIC_DEMUX_CONN_delete(demux->conns_by_id, conn); - OPENSSL_free(conn); -} - -int ossl_quic_demux_unregister(QUIC_DEMUX *demux, - const QUIC_CONN_ID *dst_conn_id) -{ - QUIC_DEMUX_CONN *conn; - - if (dst_conn_id == NULL - || dst_conn_id->id_len > QUIC_MAX_CONN_ID_LEN) - return 0; - - conn = demux_get_by_conn_id(demux, dst_conn_id); - if (conn == NULL) - return 0; - - demux_unregister(demux, conn); - return 1; -} - -struct unreg_arg { - ossl_quic_demux_cb_fn *cb; - void *cb_arg; - QUIC_DEMUX_CONN *head; -}; - -static void demux_unregister_by_cb(QUIC_DEMUX_CONN *conn, void *arg_) -{ - struct unreg_arg *arg = arg_; - - if (conn->cb == arg->cb && conn->cb_arg == arg->cb_arg) { - conn->next = arg->head; - arg->head = conn; - } -} - -void ossl_quic_demux_unregister_by_cb(QUIC_DEMUX *demux, - ossl_quic_demux_cb_fn *cb, - void *cb_arg) -{ - QUIC_DEMUX_CONN *conn, *cnext; - struct unreg_arg arg = {0}; - arg.cb = cb; - arg.cb_arg = cb_arg; - - lh_QUIC_DEMUX_CONN_doall_arg(demux->conns_by_id, - demux_unregister_by_cb, &arg); - - for (conn = arg.head; conn != NULL; conn = cnext) { - cnext = conn->next; - demux_unregister(demux, conn); - } -} - void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux, ossl_quic_demux_cb_fn *cb, void *cb_arg) @@ -301,14 +149,6 @@ void ossl_quic_demux_set_default_handler(QUIC_DEMUX *demux, demux->default_cb_arg = cb_arg; } -void ossl_quic_demux_set_stateless_reset_handler( - QUIC_DEMUX *demux, - ossl_quic_stateless_reset_cb_fn *cb, void *cb_arg) -{ - demux->reset_token_cb = cb; - demux->reset_token_cb_arg = cb_arg; -} - static QUIC_URXE *demux_alloc_urxe(size_t alloc_len) { QUIC_URXE *e; @@ -480,29 +320,14 @@ static int demux_identify_conn_id(QUIC_DEMUX *demux, dst_conn_id); } -/* Identify the connection structure corresponding to a given URXE. */ -static QUIC_DEMUX_CONN *demux_identify_conn(QUIC_DEMUX *demux, QUIC_URXE *e) -{ - QUIC_CONN_ID dst_conn_id; - - if (!demux_identify_conn_id(demux, e, &dst_conn_id)) - /* - * Datagram is so badly malformed we can't get the DCID from the first - * packet in it, so just give up. - */ - return NULL; - - return demux_get_by_conn_id(demux, &dst_conn_id); -} - /* * Process a single pending URXE. - * Returning 1 on success, 0 on failure and -1 on stateless reset. + * Returning 1 on success, 0 on failure. */ static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e) { - QUIC_DEMUX_CONN *conn; - int r; + QUIC_CONN_ID dst_conn_id; + int dst_conn_id_ok = 0; /* The next URXE we process should be at the head of the pending list. */ if (!ossl_assert(e == ossl_list_urxe_head(&demux->urx_pending))) @@ -510,57 +335,25 @@ static int demux_process_pending_urxe(QUIC_DEMUX *demux, QUIC_URXE *e) assert(e->demux_state == URXE_DEMUX_STATE_PENDING); - /* - * Check if the packet ends with a stateless reset token and if it does - * skip it after dropping the connection. - * - * RFC 9000 s. 10.3.1 Detecting a Stateless Reset - * If the last 16 bytes of the datagram are identical in value to - * a stateless reset token, the endpoint MUST enter the draining - * period and not send any further packets on this connection. - * - * Returning a failure here causes the connection to enter the terminating - * state which achieves the desired outcome. - * - * TODO(QUIC FUTURE): only try to match unparsable packets - */ - if (demux->reset_token_cb != NULL) { - r = demux->reset_token_cb(ossl_quic_urxe_data(e), e->data_len, - demux->reset_token_cb_arg); - if (r > 0) /* Received a stateless reset */ - return -1; - if (r < 0) /* Error during stateless reset detection */ - return 0; - } + /* Determine the DCID of the first packet in the datagram. */ + dst_conn_id_ok = demux_identify_conn_id(demux, e, &dst_conn_id); - conn = demux_identify_conn(demux, e); - if (conn == NULL) { + ossl_list_urxe_remove(&demux->urx_pending, e); + if (demux->default_cb != NULL) { /* - * We could not identify a connection. If we have a default packet - * handler, pass it to the handler. Otherwise, we will never be able to - * process this datagram, so get rid of it. + * Pass to default handler for routing. The URXE now belongs to the + * callback. */ - ossl_list_urxe_remove(&demux->urx_pending, e); - if (demux->default_cb != NULL) { - /* Pass to default handler. */ - e->demux_state = URXE_DEMUX_STATE_ISSUED; - demux->default_cb(e, demux->default_cb_arg); - } else { - /* Discard. */ - ossl_list_urxe_insert_tail(&demux->urx_free, e); - e->demux_state = URXE_DEMUX_STATE_FREE; - } - return 1; /* keep processing pending URXEs */ + e->demux_state = URXE_DEMUX_STATE_ISSUED; + demux->default_cb(e, demux->default_cb_arg, + dst_conn_id_ok ? &dst_conn_id : NULL); + } else { + /* Discard. */ + ossl_list_urxe_insert_tail(&demux->urx_free, e); + e->demux_state = URXE_DEMUX_STATE_FREE; } - /* - * Remove from list and invoke callback. The URXE now belongs to the - * callback. (QUIC_DEMUX_CONN never has non-NULL cb.) - */ - ossl_list_urxe_remove(&demux->urx_pending, e); - e->demux_state = URXE_DEMUX_STATE_ISSUED; - conn->cb(e, conn->cb_arg); - return 1; + return 1; /* keep processing pending URXEs */ } /* Process pending URXEs to generate callbacks. */ @@ -600,8 +393,7 @@ int ossl_quic_demux_pump(QUIC_DEMUX *demux) } if ((ret = demux_process_pending_urxl(demux)) <= 0) - return ret == 0 ? QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL - : QUIC_DEMUX_PUMP_RES_STATELESS_RESET; + return QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL; return QUIC_DEMUX_PUMP_RES_OK; } diff --git a/ssl/quic/quic_engine.c b/ssl/quic/quic_engine.c new file mode 100644 index 0000000000000000000000000000000000000000..3bcb5d6810d34eb41f5d781714e414f9ed5fed9a --- /dev/null +++ b/ssl/quic/quic_engine.c @@ -0,0 +1,140 @@ +/* + * 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 "internal/quic_engine.h" +#include "internal/quic_port.h" +#include "quic_engine_local.h" +#include "quic_port_local.h" +#include "../ssl_local.h" + +/* + * QUIC Engine + * =========== + */ +static int qeng_init(QUIC_ENGINE *qeng); +static void qeng_cleanup(QUIC_ENGINE *qeng); +static void qeng_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags); + +DEFINE_LIST_OF_IMPL(port, QUIC_PORT); + +QUIC_ENGINE *ossl_quic_engine_new(const QUIC_ENGINE_ARGS *args) +{ + QUIC_ENGINE *qeng; + + if ((qeng = OPENSSL_zalloc(sizeof(QUIC_ENGINE))) == NULL) + return NULL; + + qeng->libctx = args->libctx; + qeng->propq = args->propq; + qeng->mutex = args->mutex; + qeng->now_cb = args->now_cb; + qeng->now_cb_arg = args->now_cb_arg; + + if (!qeng_init(qeng)) { + OPENSSL_free(qeng); + return NULL; + } + + return qeng; +} + +void ossl_quic_engine_free(QUIC_ENGINE *qeng) +{ + if (qeng == NULL) + return; + + qeng_cleanup(qeng); + OPENSSL_free(qeng); +} + +static int qeng_init(QUIC_ENGINE *qeng) +{ + ossl_quic_reactor_init(&qeng->rtor, qeng_tick, qeng, ossl_time_zero()); + return 1; +} + +static void qeng_cleanup(QUIC_ENGINE *qeng) +{ + assert(ossl_list_port_num(&qeng->port_list) == 0); +} + +QUIC_REACTOR *ossl_quic_engine_get0_reactor(QUIC_ENGINE *qeng) +{ + return &qeng->rtor; +} + +CRYPTO_MUTEX *ossl_quic_engine_get0_mutex(QUIC_ENGINE *qeng) +{ + return qeng->mutex; +} + +OSSL_TIME ossl_quic_engine_get_time(QUIC_ENGINE *qeng) +{ + if (qeng->now_cb == NULL) + return ossl_time_now(); + + return qeng->now_cb(qeng->now_cb_arg); +} + +void ossl_quic_engine_set_inhibit_tick(QUIC_ENGINE *qeng, int inhibit) +{ + qeng->inhibit_tick = (inhibit != 0); +} + +/* + * QUIC Engine: Child Object Lifecycle Management + * ============================================== + */ + +QUIC_PORT *ossl_quic_engine_create_port(QUIC_ENGINE *qeng, + const QUIC_PORT_ARGS *args) +{ + QUIC_PORT_ARGS largs = *args; + + if (ossl_list_port_num(&qeng->port_list) > 0) + /* TODO(QUIC MULTIPORT): We currently support only one port. */ + return NULL; + + if (largs.engine != NULL) + return NULL; + + largs.engine = qeng; + return ossl_quic_port_new(&largs); +} + +/* + * QUIC Engine: Ticker-Mutator + * ========================== + */ + +/* + * The central ticker function called by the reactor. This does everything, or + * at least everything network I/O related. Best effort - not allowed to fail + * "loudly". + */ +static void qeng_tick(QUIC_TICK_RESULT *res, void *arg, uint32_t flags) +{ + QUIC_ENGINE *qeng = arg; + QUIC_PORT *port; + + res->net_read_desired = 0; + res->net_write_desired = 0; + res->tick_deadline = ossl_time_infinite(); + + if (qeng->inhibit_tick) + return; + + /* Iterate through all ports and service them. */ + LIST_FOREACH(port, port, &qeng->port_list) { + QUIC_TICK_RESULT subr = {0}; + + ossl_quic_port_subtick(port, &subr, flags); + ossl_quic_tick_result_merge_into(res, &subr); + } +} diff --git a/ssl/quic/quic_engine_local.h b/ssl/quic/quic_engine_local.h new file mode 100644 index 0000000000000000000000000000000000000000..280fd31dd7c14bf5e0ed6f1aaabeff2b1e83abd5 --- /dev/null +++ b/ssl/quic/quic_engine_local.h @@ -0,0 +1,59 @@ +/* + * 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_QUIC_ENGINE_LOCAL_H +# define OSSL_QUIC_ENGINE_LOCAL_H + +# include "internal/quic_engine.h" +# include "internal/quic_reactor.h" + +# ifndef OPENSSL_NO_QUIC + +/* + * QUIC Engine Structure + * ===================== + * + * QUIC engine internals. It is intended that only the QUIC_ENGINE, QUIC_PORT + * and QUIC_CHANNEL implementations be allowed to access this structure + * directly. + * + * Other components should not include this header. + */ +DECLARE_LIST_OF(port, QUIC_PORT); + +struct quic_engine_st { + /* All objects in a QUIC event domain share the same (libctx, propq). */ + OSSL_LIB_CTX *libctx; + const char *propq; + + /* + * Master synchronisation mutex for the entire QUIC event domain. Used for + * thread assisted mode synchronisation. We don't own this; the instantiator + * of the engine passes it to us and is responsible for freeing it after + * engine destruction. + */ + CRYPTO_MUTEX *mutex; + + /* Callback used to get the current time. */ + OSSL_TIME (*now_cb)(void *arg); + void *now_cb_arg; + + /* Asynchronous I/O reactor. */ + QUIC_REACTOR rtor; + + /* List of all child ports. */ + OSSL_LIST(port) port_list; + + /* Inhibit tick for testing purposes? */ + unsigned int inhibit_tick : 1; +}; + +# endif + +#endif diff --git a/ssl/quic/quic_impl.c b/ssl/quic/quic_impl.c index 399d1d2afd15e468b8c6044db6e056aca7be3d58..5306d6bd40a27bebb68efd2dca0302000ac2c192 100644 --- a/ssl/quic/quic_impl.c +++ b/ssl/quic/quic_impl.c @@ -15,6 +15,8 @@ #include "internal/quic_tls.h" #include "internal/quic_rx_depack.h" #include "internal/quic_error.h" +#include "internal/quic_engine.h" +#include "internal/quic_port.h" #include "internal/time.h" typedef struct qctx_st QCTX; @@ -63,7 +65,7 @@ static int block_until_pred(QUIC_CONNECTION *qc, * Any attempt to block auto-disables tick inhibition as otherwise we will * hang around forever. */ - ossl_quic_channel_set_inhibit_tick(qc->ch, 0); + ossl_quic_engine_set_inhibit_tick(qc->engine, 0); rtor = ossl_quic_channel_get_reactor(qc->ch); return ossl_quic_reactor_block_until_pred(rtor, pred, pred_arg, flags, @@ -543,6 +545,8 @@ void ossl_quic_free(SSL *s) #endif ossl_quic_channel_free(ctx.qc->ch); + ossl_quic_port_free(ctx.qc->port); + ossl_quic_engine_free(ctx.qc->engine); BIO_free_all(ctx.qc->net_rbio); BIO_free_all(ctx.qc->net_wbio); @@ -854,7 +858,7 @@ static int qc_can_support_blocking_cached(QUIC_CONNECTION *qc) static void qc_update_can_support_blocking(QUIC_CONNECTION *qc) { - ossl_quic_channel_update_poll_descriptors(qc->ch); /* best effort */ + ossl_quic_port_update_poll_descriptors(qc->port); /* best effort */ } static void qc_update_blocking_mode(QUIC_CONNECTION *qc) @@ -872,7 +876,7 @@ void ossl_quic_conn_set0_net_rbio(SSL *s, BIO *net_rbio) if (ctx.qc->net_rbio == net_rbio) return; - if (!ossl_quic_channel_set_net_rbio(ctx.qc->ch, net_rbio)) + if (!ossl_quic_port_set_net_rbio(ctx.qc->port, net_rbio)) return; BIO_free_all(ctx.qc->net_rbio); @@ -899,7 +903,7 @@ void ossl_quic_conn_set0_net_wbio(SSL *s, BIO *net_wbio) if (ctx.qc->net_wbio == net_wbio) return; - if (!ossl_quic_channel_set_net_wbio(ctx.qc->ch, net_wbio)) + if (!ossl_quic_port_set_net_wbio(ctx.qc->port, net_wbio)) return; BIO_free_all(ctx.qc->net_wbio); @@ -1476,8 +1480,8 @@ static int configure_channel(QUIC_CONNECTION *qc) { assert(qc->ch != NULL); - if (!ossl_quic_channel_set_net_rbio(qc->ch, qc->net_rbio) - || !ossl_quic_channel_set_net_wbio(qc->ch, qc->net_wbio) + if (!ossl_quic_port_set_net_rbio(qc->port, qc->net_rbio) + || !ossl_quic_port_set_net_wbio(qc->port, qc->net_wbio) || !ossl_quic_channel_set_peer_addr(qc->ch, &qc->init_peer_addr)) return 0; @@ -1487,19 +1491,33 @@ static int configure_channel(QUIC_CONNECTION *qc) QUIC_NEEDS_LOCK static int create_channel(QUIC_CONNECTION *qc) { - QUIC_CHANNEL_ARGS args = {0}; + QUIC_ENGINE_ARGS engine_args = {0}; + QUIC_PORT_ARGS port_args = {0}; - args.libctx = qc->ssl.ctx->libctx; - args.propq = qc->ssl.ctx->propq; - args.is_server = qc->as_server; - args.tls = qc->tls; - args.mutex = qc->mutex; - args.now_cb = get_time_cb; - args.now_cb_arg = qc; + engine_args.libctx = qc->ssl.ctx->libctx; + engine_args.propq = qc->ssl.ctx->propq; + engine_args.mutex = qc->mutex; + engine_args.now_cb = get_time_cb; + engine_args.now_cb_arg = qc; + qc->engine = ossl_quic_engine_new(&engine_args); + if (qc->engine == NULL) { + QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_INTERNAL_ERROR, NULL); + return 0; + } + + port_args.channel_ctx = qc->ssl.ctx; + qc->port = ossl_quic_engine_create_port(qc->engine, &port_args); + if (qc->port == NULL) { + QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_INTERNAL_ERROR, NULL); + ossl_quic_engine_free(qc->engine); + return 0; + } - qc->ch = ossl_quic_channel_new(&args); + qc->ch = ossl_quic_port_create_outgoing(qc->port, qc->tls); if (qc->ch == NULL) { QUIC_RAISE_NON_NORMAL_ERROR(NULL, ERR_R_INTERNAL_ERROR, NULL); + ossl_quic_port_free(qc->port); + ossl_quic_engine_free(qc->engine); return 0; } diff --git a/ssl/quic/quic_lcidm.c b/ssl/quic/quic_lcidm.c index a3315164c7cb03adc6ed56d2d4cb4f42066dfa8e..e5948b95e90c238bc54f4a268654a981d4c42f84 100644 --- a/ssl/quic/quic_lcidm.c +++ b/ssl/quic/quic_lcidm.c @@ -287,26 +287,6 @@ size_t ossl_quic_lcidm_get_num_active_lcid(const QUIC_LCIDM *lcidm, return conn->num_active_lcid; } -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - -static int gen_rand_conn_id(OSSL_LIB_CTX *libctx, size_t len, QUIC_CONN_ID *cid) -{ - if (len > QUIC_MAX_CONN_ID_LEN) - return 0; - - cid->id_len = (unsigned char)len; - - if (RAND_bytes_ex(libctx, cid->id, len, len * 8) != 1) { - ERR_raise(ERR_LIB_SSL, ERR_R_RAND_LIB); - cid->id_len = 0; - return 0; - } - - return 1; -} - -#endif - static int lcidm_generate_cid(QUIC_LCIDM *lcidm, QUIC_CONN_ID *cid) { @@ -322,7 +302,7 @@ static int lcidm_generate_cid(QUIC_LCIDM *lcidm, return 1; #else - return gen_rand_conn_id(lcidm->libctx, lcidm->lcid_len, cid); + return ossl_quic_gen_rand_conn_id(lcidm->libctx, lcidm->lcid_len, cid); #endif } diff --git a/ssl/quic/quic_local.h b/ssl/quic/quic_local.h index 928ae4c6bf3f90c2889c9ed41a438f9aafefb738..ca95f46f5260b1c0af9227d45288901a90421339 100644 --- a/ssl/quic/quic_local.h +++ b/ssl/quic/quic_local.h @@ -118,6 +118,12 @@ struct quic_conn_st { SSL *tls; + /* The QUIC engine representing the QUIC event domain. */ + QUIC_ENGINE *engine; + + /* The QUIC port representing the QUIC listener and socket. */ + QUIC_PORT *port; + /* * The QUIC channel providing the core QUIC connection implementation. Note * that this is not instantiated until we actually start trying to do the diff --git a/ssl/quic/quic_port.c b/ssl/quic/quic_port.c new file mode 100644 index 0000000000000000000000000000000000000000..46ca22cc3b1850ecf75f52f765f2432e8c12eb0f --- /dev/null +++ b/ssl/quic/quic_port.c @@ -0,0 +1,610 @@ +/* + * 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 "internal/quic_port.h" +#include "internal/quic_channel.h" +#include "internal/quic_lcidm.h" +#include "internal/quic_srtm.h" +#include "quic_port_local.h" +#include "quic_channel_local.h" +#include "quic_engine_local.h" +#include "../ssl_local.h" + +/* + * QUIC Port Structure + * =================== + */ +#define INIT_DCID_LEN 8 + +static int port_init(QUIC_PORT *port); +static void port_cleanup(QUIC_PORT *port); +static OSSL_TIME get_time(void *arg); +static void port_default_packet_handler(QUIC_URXE *e, void *arg, + const QUIC_CONN_ID *dcid); +static void port_rx_pre(QUIC_PORT *port); + +DEFINE_LIST_OF_IMPL(ch, QUIC_CHANNEL); +DEFINE_LIST_OF_IMPL(port, QUIC_PORT); + +QUIC_PORT *ossl_quic_port_new(const QUIC_PORT_ARGS *args) +{ + QUIC_PORT *port; + + if ((port = OPENSSL_zalloc(sizeof(QUIC_PORT))) == NULL) + return NULL; + + port->engine = args->engine; + port->channel_ctx = args->channel_ctx; + port->is_multi_conn = args->is_multi_conn; + + if (!port_init(port)) { + OPENSSL_free(port); + return NULL; + } + + return port; +} + +void ossl_quic_port_free(QUIC_PORT *port) +{ + if (port == NULL) + return; + + port_cleanup(port); + OPENSSL_free(port); +} + +static int port_init(QUIC_PORT *port) +{ + size_t rx_short_dcid_len = (port->is_multi_conn ? INIT_DCID_LEN : 0); + + if (port->engine == NULL || port->channel_ctx == NULL) + goto err; + + if ((port->err_state = OSSL_ERR_STATE_new()) == NULL) + goto err; + + if ((port->demux = ossl_quic_demux_new(/*BIO=*/NULL, + /*Short CID Len=*/rx_short_dcid_len, + get_time, port)) == NULL) + goto err; + + ossl_quic_demux_set_default_handler(port->demux, + port_default_packet_handler, + port); + + if ((port->srtm = ossl_quic_srtm_new(port->engine->libctx, + port->engine->propq)) == NULL) + goto err; + + if ((port->lcidm = ossl_quic_lcidm_new(port->engine->libctx, + rx_short_dcid_len)) == NULL) + goto err; + + port->rx_short_dcid_len = (unsigned char)rx_short_dcid_len; + port->tx_init_dcid_len = INIT_DCID_LEN; + port->state = QUIC_PORT_STATE_RUNNING; + + ossl_list_port_insert_tail(&port->engine->port_list, port); + port->on_engine_list = 1; + return 1; + +err: + port_cleanup(port); + return 0; +} + +static void port_cleanup(QUIC_PORT *port) +{ + assert(ossl_list_ch_num(&port->channel_list) == 0); + + ossl_quic_demux_free(port->demux); + port->demux = NULL; + + ossl_quic_srtm_free(port->srtm); + port->srtm = NULL; + + ossl_quic_lcidm_free(port->lcidm); + port->lcidm = NULL; + + OSSL_ERR_STATE_free(port->err_state); + port->err_state = NULL; + + if (port->on_engine_list) { + ossl_list_port_remove(&port->engine->port_list, port); + port->on_engine_list = 0; + } +} + +static void port_transition_failed(QUIC_PORT *port) +{ + if (port->state == QUIC_PORT_STATE_FAILED) + return; + + port->state = QUIC_PORT_STATE_FAILED; +} + +int ossl_quic_port_is_running(const QUIC_PORT *port) +{ + return port->state == QUIC_PORT_STATE_RUNNING; +} + +QUIC_ENGINE *ossl_quic_port_get0_engine(QUIC_PORT *port) +{ + return port->engine; +} + +QUIC_REACTOR *ossl_quic_port_get0_reactor(QUIC_PORT *port) +{ + return ossl_quic_engine_get0_reactor(port->engine); +} + +QUIC_DEMUX *ossl_quic_port_get0_demux(QUIC_PORT *port) +{ + return port->demux; +} + +CRYPTO_MUTEX *ossl_quic_port_get0_mutex(QUIC_PORT *port) +{ + return ossl_quic_engine_get0_mutex(port->engine); +} + +OSSL_TIME ossl_quic_port_get_time(QUIC_PORT *port) +{ + return ossl_quic_engine_get_time(port->engine); +} + +static OSSL_TIME get_time(void *port) +{ + return ossl_quic_port_get_time((QUIC_PORT *)port); +} + +int ossl_quic_port_get_rx_short_dcid_len(const QUIC_PORT *port) +{ + return port->rx_short_dcid_len; +} + +int ossl_quic_port_get_tx_init_dcid_len(const QUIC_PORT *port) +{ + return port->tx_init_dcid_len; +} + +/* + * QUIC Port: Network BIO Configuration + * ==================================== + */ + +/* Determines whether we can support a given poll descriptor. */ +static int validate_poll_descriptor(const BIO_POLL_DESCRIPTOR *d) +{ + if (d->type == BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD && d->value.fd < 0) { + ERR_raise(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + + return 1; +} + +BIO *ossl_quic_port_get_net_rbio(QUIC_PORT *port) +{ + return port->net_rbio; +} + +BIO *ossl_quic_port_get_net_wbio(QUIC_PORT *port) +{ + return port->net_wbio; +} + +static int port_update_poll_desc(QUIC_PORT *port, BIO *net_bio, int for_write) +{ + BIO_POLL_DESCRIPTOR d = {0}; + + if (net_bio == NULL + || (!for_write && !BIO_get_rpoll_descriptor(net_bio, &d)) + || (for_write && !BIO_get_wpoll_descriptor(net_bio, &d))) + /* Non-pollable BIO */ + d.type = BIO_POLL_DESCRIPTOR_TYPE_NONE; + + if (!validate_poll_descriptor(&d)) + return 0; + + /* + * TODO(QUIC MULTIPORT): We currently only support one port per + * engine/domain. This is necessitated because QUIC_REACTOR only supports a + * single pollable currently. In the future, once complete polling + * infrastructure has been implemented, this limitation can be removed. + * + * For now, just update the descriptor on the the engine's reactor as we are + * guaranteed to be the only port under it. + */ + if (for_write) + ossl_quic_reactor_set_poll_w(&port->engine->rtor, &d); + else + ossl_quic_reactor_set_poll_r(&port->engine->rtor, &d); + + return 1; +} + +int ossl_quic_port_update_poll_descriptors(QUIC_PORT *port) +{ + int ok = 1; + + if (!port_update_poll_desc(port, port->net_rbio, /*for_write=*/0)) + ok = 0; + + if (!port_update_poll_desc(port, port->net_wbio, /*for_write=*/1)) + ok = 0; + + return ok; +} + +/* + * QUIC_PORT does not ref any BIO it is provided with, nor is any ref + * transferred to it. The caller (e.g., QUIC_CONNECTION) is responsible for + * ensuring the BIO lasts until the channel is freed or the BIO is switched out + * for another BIO by a subsequent successful call to this function. + */ +int ossl_quic_port_set_net_rbio(QUIC_PORT *port, BIO *net_rbio) +{ + if (port->net_rbio == net_rbio) + return 1; + + if (!port_update_poll_desc(port, net_rbio, /*for_write=*/0)) + return 0; + + ossl_quic_demux_set_bio(port->demux, net_rbio); + port->net_rbio = net_rbio; + return 1; +} + +int ossl_quic_port_set_net_wbio(QUIC_PORT *port, BIO *net_wbio) +{ + QUIC_CHANNEL *ch; + + if (port->net_wbio == net_wbio) + return 1; + + if (!port_update_poll_desc(port, net_wbio, /*for_write=*/1)) + return 0; + + LIST_FOREACH(ch, ch, &port->channel_list) + ossl_qtx_set_bio(ch->qtx, net_wbio); + + port->net_wbio = net_wbio; + return 1; +} + +/* + * QUIC Port: Channel Lifecycle + * ============================ + */ + +static SSL *port_new_handshake_layer(QUIC_PORT *port) +{ + SSL *tls = NULL; + SSL_CONNECTION *tls_conn = NULL; + + tls = ossl_ssl_connection_new_int(port->channel_ctx, TLS_method()); + if (tls == NULL || (tls_conn = SSL_CONNECTION_FROM_SSL(tls)) == NULL) + return NULL; + + /* Override the user_ssl of the inner connection. */ + tls_conn->s3.flags |= TLS1_FLAGS_QUIC; + + /* Restrict options derived from the SSL_CTX. */ + tls_conn->options &= OSSL_QUIC_PERMITTED_OPTIONS_CONN; + tls_conn->pha_enabled = 0; + return tls; +} + +static QUIC_CHANNEL *port_make_channel(QUIC_PORT *port, SSL *tls, int is_server) +{ + QUIC_CHANNEL_ARGS args = {0}; + QUIC_CHANNEL *ch; + + args.port = port; + args.is_server = is_server; + args.tls = (tls != NULL ? tls : port_new_handshake_layer(port)); + args.lcidm = port->lcidm; + args.srtm = port->srtm; + if (args.tls == NULL) + return NULL; + + ch = ossl_quic_channel_new(&args); + if (ch == NULL) { + if (tls == NULL) + SSL_free(args.tls); + + return NULL; + } + + return ch; +} + +QUIC_CHANNEL *ossl_quic_port_create_outgoing(QUIC_PORT *port, SSL *tls) +{ + return port_make_channel(port, tls, /*is_server=*/0); +} + +QUIC_CHANNEL *ossl_quic_port_create_incoming(QUIC_PORT *port, SSL *tls) +{ + QUIC_CHANNEL *ch; + + assert(port->tserver_ch == NULL); + + ch = port_make_channel(port, tls, /*is_server=*/1); + port->tserver_ch = ch; + port->is_server = 1; + return ch; +} + +/* + * QUIC Port: Ticker-Mutator + * ========================= + */ + +/* + * Tick function for this port. This does everything related to network I/O for + * this port's network BIOs, and services child channels. + */ +void ossl_quic_port_subtick(QUIC_PORT *port, QUIC_TICK_RESULT *res, + uint32_t flags) +{ + QUIC_CHANNEL *ch; + + res->net_read_desired = 0; + res->net_write_desired = 0; + res->tick_deadline = ossl_time_infinite(); + + if (!port->engine->inhibit_tick) { + /* Handle any incoming data from network. */ + if (ossl_quic_port_is_running(port)) + port_rx_pre(port); + + /* Iterate through all channels and service them. */ + LIST_FOREACH(ch, ch, &port->channel_list) { + QUIC_TICK_RESULT subr = {0}; + + ossl_quic_channel_subtick(ch, &subr, flags); + ossl_quic_tick_result_merge_into(res, &subr); + } + } +} + +/* Process incoming datagrams, if any. */ +static void port_rx_pre(QUIC_PORT *port) +{ + int ret; + + /* + * Originally, this check (don't RX before we have sent anything if we are + * not a server, because there can't be anything) was just intended as a + * minor optimisation. However, it is actually required on Windows, and + * removing this check will cause Windows to break. + * + * The reason is that under Win32, recvfrom() does not work on a UDP socket + * which has not had bind() called (???). However, calling sendto() will + * automatically bind an unbound UDP socket. Therefore, if we call a Winsock + * recv-type function before calling a Winsock send-type function, that call + * will fail with WSAEINVAL, which we will regard as a permanent network + * error. + * + * Therefore, this check is essential as we do not require our API users to + * bind a socket first when using the API in client mode. + */ + if (!port->is_server && !port->have_sent_any_pkt) + return; + + /* + * Get DEMUX to BIO_recvmmsg from the network and queue incoming datagrams + * to the appropriate QRX instances. + */ + ret = ossl_quic_demux_pump(port->demux); + if (ret == QUIC_DEMUX_PUMP_RES_PERMANENT_FAIL) + /* + * We don't care about transient failure, but permanent failure means we + * should tear down the port. All connections skip straight to the + * Terminated state as there is no point trying to send CONNECTION_CLOSE + * frames if the network BIO is not operating correctly. + */ + ossl_quic_port_raise_net_error(port, NULL); +} + +/* + * Handles an incoming connection request and potentially decides to make a + * connection from it. If a new connection is made, the new channel is written + * to *new_ch. + */ +static void port_on_new_conn(QUIC_PORT *port, const BIO_ADDR *peer, + const QUIC_CONN_ID *scid, + const QUIC_CONN_ID *dcid, + QUIC_CHANNEL **new_ch) +{ + if (port->tserver_ch != NULL) { + /* Specially assign to existing channel */ + if (!ossl_quic_channel_on_new_conn(port->tserver_ch, peer, scid, dcid)) + return; + + *new_ch = port->tserver_ch; + port->tserver_ch = NULL; + return; + } +} + +static int port_try_handle_stateless_reset(QUIC_PORT *port, const QUIC_URXE *e) +{ + size_t i; + const unsigned char *data = ossl_quic_urxe_data(e); + void *opaque = NULL; + + /* + * Perform some fast and cheap checks for a packet not being a stateless + * reset token. RFC 9000 s. 10.3 specifies this layout for stateless + * reset packets: + * + * Stateless Reset { + * Fixed Bits (2) = 1, + * Unpredictable Bits (38..), + * Stateless Reset Token (128), + * } + * + * It also specifies: + * However, endpoints MUST treat any packet ending in a valid + * stateless reset token as a Stateless Reset, as other QUIC + * versions might allow the use of a long header. + * + * We can rapidly check for the minimum length and that the first pair + * of bits in the first byte are 01 or 11. + * + * The function returns 1 if it is a stateless reset packet, 0 if it isn't + * and -1 if an error was encountered. + */ + if (e->data_len < QUIC_STATELESS_RESET_TOKEN_LEN + 5 + || (0100 & *data) != 0100) + return 0; + + for (i = 0;; ++i) { + if (!ossl_quic_srtm_lookup(port->srtm, + (QUIC_STATELESS_RESET_TOKEN *)(data + e->data_len + - sizeof(QUIC_STATELESS_RESET_TOKEN)), + i, &opaque, NULL)) + break; + + assert(opaque != NULL); + ossl_quic_channel_on_stateless_reset((QUIC_CHANNEL *)opaque); + } + + return i > 0; +} + +/* + * This is called by the demux when we get a packet not destined for any known + * DCID. + */ +static void port_default_packet_handler(QUIC_URXE *e, void *arg, + const QUIC_CONN_ID *dcid) +{ + QUIC_PORT *port = arg; + PACKET pkt; + QUIC_PKT_HDR hdr; + QUIC_CHANNEL *ch = NULL, *new_ch = NULL; + + /* Don't handle anything if we are no longer running. */ + if (!ossl_quic_port_is_running(port)) + goto undesirable; + + if (dcid != NULL + && ossl_quic_lcidm_lookup(port->lcidm, dcid, NULL, + (void **)&ch)) { + assert(ch != NULL); + ossl_quic_channel_inject(ch, e); + return; + } + + if (port_try_handle_stateless_reset(port, e)) + goto undesirable; + + /* + * If we have an incoming packet which doesn't match any existing connection + * we assume this is an attempt to make a new connection. Currently we + * require our caller to have precreated a latent 'incoming' channel via + * TSERVER which then gets turned into the new connection. + * + * TODO(QUIC SERVER): In the future we will construct channels dynamically + * in this case. + */ + if (port->tserver_ch == NULL) + goto undesirable; + + /* + * We have got a packet for an unknown DCID. This might be an attempt to + * open a new connection. + */ + if (e->data_len < QUIC_MIN_INITIAL_DGRAM_LEN) + goto undesirable; + + if (!PACKET_buf_init(&pkt, ossl_quic_urxe_data(e), e->data_len)) + goto undesirable; + + /* + * We set short_conn_id_len to SIZE_MAX here which will cause the decode + * operation to fail if we get a 1-RTT packet. This is fine since we only + * care about Initial packets. + */ + if (!ossl_quic_wire_decode_pkt_hdr(&pkt, SIZE_MAX, 1, 0, &hdr, NULL)) + goto undesirable; + + switch (hdr.version) { + case QUIC_VERSION_1: + break; + + case QUIC_VERSION_NONE: + default: + /* Unknown version or proactive version negotiation request, bail. */ + /* TODO(QUIC SERVER): Handle version negotiation on server side */ + goto undesirable; + } + + /* + * We only care about Initial packets which might be trying to establish a + * connection. + */ + if (hdr.type != QUIC_PKT_TYPE_INITIAL) + goto undesirable; + + /* + * Try to process this as a valid attempt to initiate a connection. + * + * The channel will do all the LCID registration needed, but as an + * optimization inject this packet directly into the channel's QRX for + * processing without going through the DEMUX again. + */ + port_on_new_conn(port, &e->peer, &hdr.src_conn_id, &hdr.dst_conn_id, + &new_ch); + if (new_ch != NULL) + ossl_qrx_inject_urxe(new_ch->qrx, e); + + return; + +undesirable: + ossl_quic_demux_release_urxe(port->demux, e); +} + +void ossl_quic_port_raise_net_error(QUIC_PORT *port, + QUIC_CHANNEL *triggering_ch) +{ + QUIC_CHANNEL *ch; + + if (!ossl_quic_port_is_running(port)) + return; + + /* + * Immediately capture any triggering error on the error stack, with a + * cover error. + */ + ERR_raise_data(ERR_LIB_SSL, SSL_R_QUIC_NETWORK_ERROR, + "port failed due to network BIO I/O error"); + OSSL_ERR_STATE_save(port->err_state); + + port_transition_failed(port); + + /* Give the triggering channel (if any) the first notification. */ + if (triggering_ch != NULL) + ossl_quic_channel_raise_net_error(triggering_ch); + + LIST_FOREACH(ch, ch, &port->channel_list) + if (ch != triggering_ch) + ossl_quic_channel_raise_net_error(ch); +} + +void ossl_quic_port_restore_err_state(const QUIC_PORT *port) +{ + ERR_clear_error(); + OSSL_ERR_STATE_restore(port->err_state); +} diff --git a/ssl/quic/quic_port_local.h b/ssl/quic/quic_port_local.h new file mode 100644 index 0000000000000000000000000000000000000000..b5e1206368c905de9a45a07126fced7519e8d2fe --- /dev/null +++ b/ssl/quic/quic_port_local.h @@ -0,0 +1,100 @@ +/* + * 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_QUIC_PORT_LOCAL_H +# define OSSL_QUIC_PORT_LOCAL_H + +# include "internal/quic_port.h" +# include "internal/quic_reactor.h" +# include "internal/list.h" + +# ifndef OPENSSL_NO_QUIC + +/* + * QUIC Port Structure + * =================== + * + * QUIC port internals. It is intended that only the QUIC_PORT and QUIC_CHANNEL + * implementation be allowed to access this structure directly. + * + * Other components should not include this header. + */ +DECLARE_LIST_OF(ch, QUIC_CHANNEL); + +/* A port is always in one of the following states: */ +enum { + /* Initial and steady state. */ + QUIC_PORT_STATE_RUNNING, + + /* + * Terminal state indicating port is no longer functioning. There are no + * transitions out of this state. May be triggered by e.g. a permanent + * network BIO error. + */ + QUIC_PORT_STATE_FAILED +}; + +struct quic_port_st { + /* The engine which this port is a child of. */ + QUIC_ENGINE *engine; + + /* + * QUIC_ENGINE keeps the ports which belong to it on a list for bookkeeping + * purposes. + */ + OSSL_LIST_MEMBER(port, QUIC_PORT); + + /* Used to create handshake layer objects inside newly created channels. */ + SSL_CTX *channel_ctx; + + /* Network-side read and write BIOs. */ + BIO *net_rbio, *net_wbio; + + /* RX demuxer. We register incoming DCIDs with this. */ + QUIC_DEMUX *demux; + + /* List of all child channels. */ + OSSL_LIST(ch) channel_list; + + /* Special TSERVER channel. To be removed in the future. */ + QUIC_CHANNEL *tserver_ch; + + /* LCIDM used for incoming packet routing by DCID. */ + QUIC_LCIDM *lcidm; + + /* SRTM used for incoming packet routing by SRT. */ + QUIC_SRTM *srtm; + + /* Port-level permanent errors (causing failure state) are stored here. */ + ERR_STATE *err_state; + + /* DCID length used for incoming short header packets. */ + unsigned char rx_short_dcid_len; + /* For clients, CID length used for outgoing Initial packets. */ + unsigned char tx_init_dcid_len; + + /* Port state (QUIC_PORT_STATE_*). */ + unsigned int state : 1; + + /* Is this port created to support multiple connections? */ + unsigned int is_multi_conn : 1; + + /* Has this port sent any packet of any kind yet? */ + unsigned int have_sent_any_pkt : 1; + + /* Does this port allow incoming connections? */ + unsigned int is_server : 1; + + /* Are we on the QUIC_ENGINE linked list of ports? */ + unsigned int on_engine_list : 1; +}; + +# endif + +#endif diff --git a/ssl/quic/quic_record_rx.c b/ssl/quic/quic_record_rx.c index 4d0493baff6e8e640a9c2602da8ca6efc2e93e7e..97dadd3dbe3419313b956435365bba08b9de0eae 100644 --- a/ssl/quic/quic_record_rx.c +++ b/ssl/quic/quic_record_rx.c @@ -167,19 +167,17 @@ struct ossl_qrx_st { SSL *msg_callback_ssl; }; -static void qrx_on_rx(QUIC_URXE *urxe, void *arg); - OSSL_QRX *ossl_qrx_new(const OSSL_QRX_ARGS *args) { OSSL_QRX *qrx; size_t i; if (args->demux == NULL || args->max_deferred == 0) - return 0; + return NULL; qrx = OPENSSL_zalloc(sizeof(OSSL_QRX)); if (qrx == NULL) - return 0; + return NULL; for (i = 0; i < OSSL_NELEM(qrx->largest_pn); ++i) qrx->largest_pn[i] = args->init_largest_pn[i]; @@ -222,9 +220,6 @@ void ossl_qrx_free(OSSL_QRX *qrx) if (qrx == NULL) return; - /* Unregister from the RX DEMUX. */ - ossl_quic_demux_unregister_by_cb(qrx->demux, qrx_on_rx, qrx); - /* Free RXE queue data. */ qrx_cleanup_rxl(&qrx->rx_free); qrx_cleanup_rxl(&qrx->rx_pending); @@ -252,28 +247,6 @@ void ossl_qrx_inject_urxe(OSSL_QRX *qrx, QUIC_URXE *urxe) qrx->msg_callback_arg); } -static void qrx_on_rx(QUIC_URXE *urxe, void *arg) -{ - OSSL_QRX *qrx = arg; - - ossl_qrx_inject_urxe(qrx, urxe); -} - -int ossl_qrx_add_dst_conn_id(OSSL_QRX *qrx, - const QUIC_CONN_ID *dst_conn_id) -{ - return ossl_quic_demux_register(qrx->demux, - dst_conn_id, - qrx_on_rx, - qrx); -} - -int ossl_qrx_remove_dst_conn_id(OSSL_QRX *qrx, - const QUIC_CONN_ID *dst_conn_id) -{ - return ossl_quic_demux_unregister(qrx->demux, dst_conn_id); -} - static void qrx_requeue_deferred(OSSL_QRX *qrx) { QUIC_URXE *e; diff --git a/ssl/quic/quic_tserver.c b/ssl/quic/quic_tserver.c index 130733821cf3d9c37d655049a98c2d7be2052a3f..159669ef8f819ab1115a09df798b33b83784a61c 100644 --- a/ssl/quic/quic_tserver.c +++ b/ssl/quic/quic_tserver.c @@ -10,6 +10,8 @@ #include "internal/quic_tserver.h" #include "internal/quic_channel.h" #include "internal/quic_statm.h" +#include "internal/quic_port.h" +#include "internal/quic_engine.h" #include "internal/common.h" #include "internal/time.h" #include "quic_local.h" @@ -25,8 +27,11 @@ struct quic_tserver_st { SSL *ssl; /* - * The QUIC channel providing the core QUIC connection implementation. + * The QUIC engine, port and channel providing the core QUIC connection + * implementation. */ + QUIC_ENGINE *engine; + QUIC_PORT *port; QUIC_CHANNEL *ch; /* The mutex we give to the QUIC channel. */ @@ -75,7 +80,8 @@ QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args, const char *certfile, const char *keyfile) { QUIC_TSERVER *srv = NULL; - QUIC_CHANNEL_ARGS ch_args = {0}; + QUIC_ENGINE_ARGS engine_args = {0}; + QUIC_PORT_ARGS port_args = {0}; QUIC_CONNECTION *qc = NULL; if (args->net_rbio == NULL || args->net_wbio == NULL) @@ -113,19 +119,26 @@ QUIC_TSERVER *ossl_quic_tserver_new(const QUIC_TSERVER_ARGS *args, if (srv->tls == NULL) goto err; - ch_args.libctx = srv->args.libctx; - ch_args.propq = srv->args.propq; - ch_args.tls = srv->tls; - ch_args.mutex = srv->mutex; - ch_args.is_server = 1; - ch_args.now_cb = srv->args.now_cb; - ch_args.now_cb_arg = srv->args.now_cb_arg; + engine_args.libctx = srv->args.libctx; + engine_args.propq = srv->args.propq; + engine_args.mutex = srv->mutex; + engine_args.now_cb = srv->args.now_cb; + engine_args.now_cb_arg = srv->args.now_cb_arg; - if ((srv->ch = ossl_quic_channel_new(&ch_args)) == NULL) + if ((srv->engine = ossl_quic_engine_new(&engine_args)) == NULL) goto err; - if (!ossl_quic_channel_set_net_rbio(srv->ch, srv->args.net_rbio) - || !ossl_quic_channel_set_net_wbio(srv->ch, srv->args.net_wbio)) + port_args.channel_ctx = srv->ctx; + port_args.is_multi_conn = 1; + + if ((srv->port = ossl_quic_engine_create_port(srv->engine, &port_args)) == NULL) + goto err; + + if ((srv->ch = ossl_quic_port_create_incoming(srv->port, srv->tls)) == NULL) + goto err; + + if (!ossl_quic_port_set_net_rbio(srv->port, srv->args.net_rbio) + || !ossl_quic_port_set_net_wbio(srv->port, srv->args.net_wbio)) goto err; qc = OPENSSL_zalloc(sizeof(*qc)); @@ -143,6 +156,8 @@ err: SSL_CTX_free(srv->ctx); SSL_free(srv->tls); ossl_quic_channel_free(srv->ch); + ossl_quic_port_free(srv->port); + ossl_quic_engine_free(srv->engine); #if defined(OPENSSL_THREADS) ossl_crypto_mutex_free(&srv->mutex); #endif @@ -159,6 +174,8 @@ void ossl_quic_tserver_free(QUIC_TSERVER *srv) return; ossl_quic_channel_free(srv->ch); + ossl_quic_port_free(srv->port); + ossl_quic_engine_free(srv->engine); BIO_free_all(srv->args.net_rbio); BIO_free_all(srv->args.net_wbio); OPENSSL_free(srv->ssl); diff --git a/ssl/quic/quic_types.c b/ssl/quic/quic_types.c new file mode 100644 index 0000000000000000000000000000000000000000..4ff3ae6580b5196eb3d313e3b56f3a8e5ec3d361 --- /dev/null +++ b/ssl/quic/quic_types.c @@ -0,0 +1,29 @@ +/* + * 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 "internal/quic_types.h" +#include +#include + +int ossl_quic_gen_rand_conn_id(OSSL_LIB_CTX *libctx, size_t len, + QUIC_CONN_ID *cid) +{ + if (len > QUIC_MAX_CONN_ID_LEN) + return 0; + + cid->id_len = (unsigned char)len; + + if (RAND_bytes_ex(libctx, cid->id, len, len * 8) != 1) { + ERR_raise(ERR_LIB_SSL, ERR_R_RAND_LIB); + cid->id_len = 0; + return 0; + } + + return 1; +} diff --git a/ssl/record/methods/tls_common.c b/ssl/record/methods/tls_common.c index 423777c18dd40fa13671c6718958a352783c38fb..7da423e24300e62a2b2931f5e0a4d0324a856f37 100644 --- a/ssl/record/methods/tls_common.c +++ b/ssl/record/methods/tls_common.c @@ -147,6 +147,7 @@ int tls_setup_write_buffer(OSSL_RECORD_LAYER *rl, size_t numwpipes, TLS_BUFFER *wb; size_t currpipe; size_t defltlen = 0; + size_t contenttypelen = 0; if (firstlen == 0 || (numwpipes > 1 && nextlen == 0)) { if (rl->isdtls) @@ -154,21 +155,26 @@ int tls_setup_write_buffer(OSSL_RECORD_LAYER *rl, size_t numwpipes, else headerlen = SSL3_RT_HEADER_LENGTH; + /* TLSv1.3 adds an extra content type byte after payload data */ + if (rl->version == TLS1_3_VERSION) + contenttypelen = 1; + #if defined(SSL3_ALIGN_PAYLOAD) && SSL3_ALIGN_PAYLOAD != 0 align = SSL3_ALIGN_PAYLOAD - 1; #endif - defltlen = rl->max_frag_len + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD - + headerlen + align + rl->eivlen; + defltlen = align + headerlen + rl->eivlen + rl->max_frag_len + + contenttypelen + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD; #ifndef OPENSSL_NO_COMP if (tls_allow_compression(rl)) defltlen += SSL3_RT_MAX_COMPRESSED_OVERHEAD; #endif /* * We don't need to add eivlen here since empty fragments only occur - * when we don't have an explicit IV + * when we don't have an explicit IV. The contenttype byte will also + * always be 0 in these protocol versions */ - if (!(rl->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS)) + if ((rl->options & SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) == 0) defltlen += headerlen + align + SSL3_RT_SEND_MAX_ENCRYPTED_OVERHEAD; } diff --git a/ssl/ssl_conf.c b/ssl/ssl_conf.c index b361719a5a5a37803fc871129dbc2c507e2a1a1a..49e682247929b41f2cdda4a2dc7c7dfe00fd758d 100644 --- a/ssl/ssl_conf.c +++ b/ssl/ssl_conf.c @@ -902,9 +902,12 @@ static int ctrl_switch_option(SSL_CONF_CTX *cctx, const ssl_conf_cmd_tbl *cmd) /* Find index of command in table */ size_t idx = cmd - ssl_conf_cmds; const ssl_switch_tbl *scmd; + /* Sanity check index */ - if (idx >= OSSL_NELEM(ssl_cmd_switches)) + if (idx >= OSSL_NELEM(ssl_cmd_switches)) { + ERR_raise(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR); return 0; + } /* Obtain switches entry with same index */ scmd = ssl_cmd_switches + idx; ssl_set_option(cctx, scmd->name_flags, scmd->option_value, 1); @@ -920,28 +923,33 @@ int SSL_CONF_cmd(SSL_CONF_CTX *cctx, const char *cmd, const char *value) } if (!ssl_conf_cmd_skip_prefix(cctx, &cmd)) - return -2; + goto unknown_cmd; runcmd = ssl_conf_cmd_lookup(cctx, cmd); if (runcmd) { - int rv; + int rv = -3; + if (runcmd->value_type == SSL_CONF_TYPE_NONE) { return ctrl_switch_option(cctx, runcmd); } if (value == NULL) - return -3; + goto bad_value; rv = runcmd->cmd(cctx, value); if (rv > 0) return 2; - if (rv == -2) - return -2; + if (rv != -2) + rv = 0; + + bad_value: if (cctx->flags & SSL_CONF_FLAG_SHOW_ERRORS) ERR_raise_data(ERR_LIB_SSL, SSL_R_BAD_VALUE, - "cmd=%s, value=%s", cmd, value); - return 0; + "cmd=%s, value=%s", cmd, + value != NULL ? value : ""); + return rv; } + unknown_cmd: if (cctx->flags & SSL_CONF_FLAG_SHOW_ERRORS) ERR_raise_data(ERR_LIB_SSL, SSL_R_UNKNOWN_CMD_NAME, "cmd=%s", cmd); diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 0150589feae9b55e8aff2fcd903065337fbd6af4..cf59d2dfa57268a8ee62304a69c10f760ce5cfb2 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -6023,6 +6023,7 @@ uint64_t SSL_set_options(SSL *s, uint64_t op) /* Ignore return value */ sc->rlayer.rrlmethod->set_options(sc->rlayer.rrl, options); + sc->rlayer.wrlmethod->set_options(sc->rlayer.wrl, options); return sc->options; } @@ -6035,6 +6036,7 @@ uint64_t SSL_CTX_clear_options(SSL_CTX *ctx, uint64_t op) uint64_t SSL_clear_options(SSL *s, uint64_t op) { SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s); + OSSL_PARAM options[2], *opts = options; #ifndef OPENSSL_NO_QUIC if (IS_QUIC(s)) @@ -6044,7 +6046,17 @@ uint64_t SSL_clear_options(SSL *s, uint64_t op) if (sc == NULL) return 0; - return sc->options &= ~op; + sc->options &= ~op; + + *opts++ = OSSL_PARAM_construct_uint64(OSSL_LIBSSL_RECORD_LAYER_PARAM_OPTIONS, + &sc->options); + *opts = OSSL_PARAM_construct_end(); + + /* Ignore return value */ + sc->rlayer.rrlmethod->set_options(sc->rlayer.rrl, options); + sc->rlayer.wrlmethod->set_options(sc->rlayer.wrl, options); + + return sc->options; } STACK_OF(X509) *SSL_get0_verified_chain(const SSL *s) diff --git a/ssl/ssl_mcnf.c b/ssl/ssl_mcnf.c index c2366e41e365db7cb4529e8395f41c8a78dd780a..8bccce84d465dbef6b1fb74859d747fb755ec367 100644 --- a/ssl/ssl_mcnf.c +++ b/ssl/ssl_mcnf.c @@ -24,7 +24,7 @@ static int ssl_do_config(SSL *s, SSL_CTX *ctx, const char *name, int system) { SSL_CONF_CTX *cctx = NULL; size_t i, idx, cmd_count; - int rv = 0; + int err = 1; unsigned int flags; const SSL_METHOD *meth; const SSL_CONF_CMD *cmds; @@ -66,24 +66,22 @@ static int ssl_do_config(SSL *s, SSL_CTX *ctx, const char *name, int system) flags |= SSL_CONF_FLAG_CLIENT; SSL_CONF_CTX_set_flags(cctx, flags); prev_libctx = OSSL_LIB_CTX_set0_default(libctx); + err = 0; for (i = 0; i < cmd_count; i++) { char *cmdstr, *arg; + int rv; conf_ssl_get_cmd(cmds, i, &cmdstr, &arg); rv = SSL_CONF_cmd(cctx, cmdstr, arg); - if (rv <= 0) { - int errcode = rv == -2 ? SSL_R_UNKNOWN_COMMAND : SSL_R_BAD_VALUE; - - ERR_raise_data(ERR_LIB_SSL, errcode, - "section=%s, cmd=%s, arg=%s", name, cmdstr, arg); - goto err; - } + if (rv <= 0) + ++err; } - rv = SSL_CONF_CTX_finish(cctx); + if (!SSL_CONF_CTX_finish(cctx)) + ++err; err: OSSL_LIB_CTX_set0_default(prev_libctx); SSL_CONF_CTX_free(cctx); - return rv <= 0 ? 0 : 1; + return err == 0; } int SSL_config(SSL *s, const char *name) diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 853af8c0aa9f93a43839b6fc6558537b9daa62bd..da77c16e6b288bdf58beb10939a4fe09e22d3206 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -1734,18 +1734,9 @@ static int tls_early_post_process_client_hello(SSL_CONNECTION *s) /* SSLv3/TLS */ s->client_version = clienthello->legacy_version; } - /* - * Do SSL/TLS version negotiation if applicable. For DTLS we just check - * versions are potentially compatible. Version negotiation comes later. - */ - if (!SSL_CONNECTION_IS_DTLS(s)) { - protverr = ssl_choose_server_version(s, clienthello, &dgrd); - } else if (ssl->method->version != DTLS_ANY_VERSION && - DTLS_VERSION_LT((int)clienthello->legacy_version, s->version)) { - protverr = SSL_R_VERSION_TOO_LOW; - } else { - protverr = 0; - } + + /* Choose the server SSL/TLS/DTLS version. */ + protverr = ssl_choose_server_version(s, clienthello, &dgrd); if (protverr) { if (SSL_IS_FIRST_HANDSHAKE(s)) { @@ -1783,14 +1774,6 @@ static int tls_early_post_process_client_hello(SSL_CONNECTION *s) } s->d1->cookie_verified = 1; } - if (ssl->method->version == DTLS_ANY_VERSION) { - protverr = ssl_choose_server_version(s, clienthello, &dgrd); - if (protverr != 0) { - s->version = s->client_version; - SSLfatal(s, SSL_AD_PROTOCOL_VERSION, protverr); - goto err; - } - } } s->hit = 0; diff --git a/test/README.md b/test/README.md index fe25bd8b4ecbf13c874114a94d6ff20386f17edb..746a0156ceeaef65637a5b9a794798581a4bb90f 100644 --- a/test/README.md +++ b/test/README.md @@ -42,7 +42,7 @@ the make variable TESTS to specify them, like this: $ make TESTS='test_rsa test_dsa' test # Unix $ mms/macro="TESTS=test_rsa test_dsa" test ! OpenVMS - $ nmake TESTS='test_rsa test_dsa' test # Windows + $ nmake TESTS="test_rsa test_dsa" test # Windows And of course, you can combine (Unix examples shown): diff --git a/test/build.info b/test/build.info index af43407611de7149415945badd6b48c4809a9fcf..88620b86b329438897f817772f586585135d703a 100644 --- a/test/build.info +++ b/test/build.info @@ -60,10 +60,10 @@ IF[{- !$disabled{tests} -}] context_internal_test aesgcmtest params_test evp_pkey_dparams_test \ keymgmt_internal_test hexstr_test provider_status_test defltfips_test \ bio_readbuffer_test user_property_test pkcs7_test upcallstest \ - provfetchtest prov_config_test rand_test ca_internals_test \ - bio_tfo_test membio_test bio_dgram_test list_test fips_version_test \ - x509_test hpke_test pairwise_fail_test nodefltctxtest \ - evp_xof_test x509_load_cert_file_test + provfetchtest prov_config_test rand_test \ + ca_internals_test bio_tfo_test membio_test bio_dgram_test list_test \ + fips_version_test x509_test hpke_test pairwise_fail_test \ + nodefltctxtest evp_xof_test x509_load_cert_file_test IF[{- !$disabled{'rpk'} -}] PROGRAMS{noinst}=rpktest diff --git a/test/cmp_client_test.c b/test/cmp_client_test.c index 44c369bc907f61e783cfa5515217168d451889ef..208e0a176733a405a3e397752cc397fd24965ab5 100644 --- a/test/cmp_client_test.c +++ b/test/cmp_client_test.c @@ -184,7 +184,7 @@ static int test_exec_RR_ses_receive_error(void) static int test_exec_IR_ses(void) { SETUP_TEST_FIXTURE(CMP_SES_TEST_FIXTURE, set_up); - fixture->req_type = OSSL_CMP_IR; + fixture->req_type = OSSL_CMP_PKIBODY_IR; fixture->expected = OSSL_CMP_PKISTATUS_accepted; fixture->caPubs = sk_X509_new_null(); sk_X509_push(fixture->caPubs, server_cert); @@ -194,42 +194,51 @@ static int test_exec_IR_ses(void) return result; } -static int test_exec_IR_ses_poll(int check_after, int poll_count, - int total_timeout, int expect) +static int test_exec_REQ_ses_poll(int req_type, int check_after, + int poll_count, int total_timeout, + int expect) { SETUP_TEST_FIXTURE(CMP_SES_TEST_FIXTURE, set_up); - fixture->req_type = OSSL_CMP_IR; + fixture->req_type = req_type; fixture->expected = expect; ossl_cmp_mock_srv_set_checkAfterTime(fixture->srv_ctx, check_after); ossl_cmp_mock_srv_set_pollCount(fixture->srv_ctx, poll_count); OSSL_CMP_CTX_set_option(fixture->cmp_ctx, OSSL_CMP_OPT_TOTAL_TIMEOUT, total_timeout); - EXECUTE_TEST(execute_exec_certrequest_ses_test, tear_down); + + if (req_type == OSSL_CMP_PKIBODY_IR) { + EXECUTE_TEST(execute_exec_certrequest_ses_test, tear_down); + } else if (req_type == OSSL_CMP_PKIBODY_GENM) { + EXECUTE_TEST(execute_exec_GENM_ses_test, tear_down); + } return result; } static int checkAfter = 1; static int test_exec_IR_ses_poll_ok(void) { - return test_exec_IR_ses_poll(checkAfter, 2, 0, OSSL_CMP_PKISTATUS_accepted); + return test_exec_REQ_ses_poll(OSSL_CMP_PKIBODY_IR, checkAfter, 2, 0, + OSSL_CMP_PKISTATUS_accepted); } static int test_exec_IR_ses_poll_no_timeout(void) { - return test_exec_IR_ses_poll(checkAfter, 1 /* pollCount */, checkAfter + 1, - OSSL_CMP_PKISTATUS_accepted); + return test_exec_REQ_ses_poll(OSSL_CMP_PKIBODY_IR, checkAfter, + 2 /* pollCount */, checkAfter + 4, + OSSL_CMP_PKISTATUS_accepted); } static int test_exec_IR_ses_poll_total_timeout(void) { - return test_exec_IR_ses_poll(checkAfter + 1, 2 /* pollCount */, checkAfter, - OSSL_CMP_PKISTATUS_waiting); + return !test_exec_REQ_ses_poll(OSSL_CMP_PKIBODY_IR, checkAfter + 1, + 3 /* pollCount */, checkAfter + 6, + OSSL_CMP_PKISTATUS_waiting); } static int test_exec_CR_ses(int implicit_confirm, int granted, int reject) { SETUP_TEST_FIXTURE(CMP_SES_TEST_FIXTURE, set_up); - fixture->req_type = OSSL_CMP_CR; + fixture->req_type = OSSL_CMP_PKIBODY_CR; OSSL_CMP_CTX_set_option(fixture->cmp_ctx, OSSL_CMP_OPT_IMPLICIT_CONFIRM, implicit_confirm); OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(fixture->srv_ctx, granted); @@ -256,7 +265,7 @@ static int test_exec_CR_ses_implicit_confirm(void) static int test_exec_KUR_ses(int transfer_error, int pubkey, int raverified) { SETUP_TEST_FIXTURE(CMP_SES_TEST_FIXTURE, set_up); - fixture->req_type = OSSL_CMP_KUR; + fixture->req_type = OSSL_CMP_PKIBODY_KUR; /* ctx->oldCert has already been set */ if (transfer_error) @@ -324,7 +333,7 @@ static int test_exec_P10CR_ses(int reject) X509_REQ *csr = NULL; SETUP_TEST_FIXTURE(CMP_SES_TEST_FIXTURE, set_up); - fixture->req_type = OSSL_CMP_P10CR; + fixture->req_type = OSSL_CMP_PKIBODY_P10CR; fixture->expected = reject ? OSSL_CMP_PKISTATUS_rejection : OSSL_CMP_PKISTATUS_accepted; ctx = fixture->cmp_ctx; @@ -354,8 +363,8 @@ static int execute_try_certreq_poll_test(CMP_SES_TEST_FIXTURE *fixture) { OSSL_CMP_CTX *ctx = fixture->cmp_ctx; int check_after; - const int CHECK_AFTER = 5; - const int TYPE = OSSL_CMP_KUR; + const int CHECK_AFTER = 0; + const int TYPE = OSSL_CMP_PKIBODY_KUR; ossl_cmp_mock_srv_set_pollCount(fixture->srv_ctx, 3); ossl_cmp_mock_srv_set_checkAfterTime(fixture->srv_ctx, CHECK_AFTER); @@ -384,7 +393,7 @@ static int execute_try_certreq_poll_abort_test(CMP_SES_TEST_FIXTURE *fixture) OSSL_CMP_CTX *ctx = fixture->cmp_ctx; int check_after; const int CHECK_AFTER = 99; - const int TYPE = OSSL_CMP_CR; + const int TYPE = OSSL_CMP_PKIBODY_CR; ossl_cmp_mock_srv_set_pollCount(fixture->srv_ctx, 3); ossl_cmp_mock_srv_set_checkAfterTime(fixture->srv_ctx, CHECK_AFTER); @@ -404,6 +413,26 @@ static int test_try_certreq_poll_abort(void) return result; } +static int test_exec_GENM_ses_poll_ok(void) +{ + return test_exec_REQ_ses_poll(OSSL_CMP_PKIBODY_GENM, checkAfter, 2, 0, + OSSL_CMP_PKISTATUS_accepted); +} + +static int test_exec_GENM_ses_poll_no_timeout(void) +{ + return test_exec_REQ_ses_poll(OSSL_CMP_PKIBODY_GENM, checkAfter, + 1 /* pollCount */, checkAfter + 1, + OSSL_CMP_PKISTATUS_accepted); +} + +static int test_exec_GENM_ses_poll_total_timeout(void) +{ + return test_exec_REQ_ses_poll(OSSL_CMP_PKIBODY_GENM, checkAfter + 1, + 3 /* pollCount */, checkAfter + 2, + OSSL_CMP_PKISTATUS_waiting); +} + static int test_exec_GENM_ses(int transfer_error, int total_timeout, int expect) { SETUP_TEST_FIXTURE(CMP_SES_TEST_FIXTURE, set_up); @@ -539,6 +568,9 @@ int setup_tests(void) ADD_TEST(test_exec_GENM_ses_ok); ADD_TEST(test_exec_GENM_ses_transfer_error); ADD_TEST(test_exec_GENM_ses_total_timeout); + ADD_TEST(test_exec_GENM_ses_poll_ok); + ADD_TEST(test_exec_GENM_ses_poll_no_timeout); + ADD_TEST(test_exec_GENM_ses_poll_total_timeout); ADD_TEST(test_exchange_certConf); ADD_TEST(test_exchange_error); return 1; diff --git a/test/cmp_server_test.c b/test/cmp_server_test.c index e270bb924baddcd1861ad7986dbf573f23c39c8b..5e778ab656e6b12d511d2ab9032b4b269711a0a6 100644 --- a/test/cmp_server_test.c +++ b/test/cmp_server_test.c @@ -76,6 +76,7 @@ static int execute_test_handle_request(CMP_SRV_TEST_FIXTURE *fixture) if (!TEST_true(OSSL_CMP_SRV_CTX_init(ctx, dummy_custom_ctx, process_cert_request, NULL, NULL, NULL, NULL, NULL)) + || !TEST_true(OSSL_CMP_SRV_CTX_init_trans(ctx, NULL, NULL)) || !TEST_ptr(custom_ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(ctx)) || !TEST_int_eq(strcmp(custom_ctx, dummy_custom_ctx), 0)) goto end; diff --git a/test/default-and-fips.cnf b/test/default-and-fips.cnf index 2ca6487fd2fdda2bb5a69d5588749502d94414b7..71af0a385abba3e137cac18238ab0574a72943f8 100644 --- a/test/default-and-fips.cnf +++ b/test/default-and-fips.cnf @@ -13,4 +13,4 @@ default = default_sect fips = fips_sect [default_sect] -activate = 1 +activate = yes diff --git a/test/default.cnf b/test/default.cnf index f29d0e92bae8e8c75496ab6e2240e1b3d22b8eed..21c7e070a9e0048f7ba57b9c2bd5985fa869c4f8 100644 --- a/test/default.cnf +++ b/test/default.cnf @@ -8,6 +8,10 @@ providers = provider_sect [provider_sect] default = default_sect +legacy = legacy_sect [default_sect] -activate = 1 +activate = true + +[legacy_sect] +activate = false diff --git a/test/evp_fetch_prov_test.c b/test/evp_fetch_prov_test.c index 19e780d8566673bdafe4c0380549fc04da0afbb9..876d6ccc0a3d9c2ddf04f5ed341a101635cc842c 100644 --- a/test/evp_fetch_prov_test.c +++ b/test/evp_fetch_prov_test.c @@ -121,6 +121,27 @@ static void unload_providers(OSSL_LIB_CTX **libctx, OSSL_PROVIDER *prov[]) } } +static int test_legacy_provider_unloaded(void) +{ + OSSL_LIB_CTX *ctx = NULL; + int rc = 0; + + ctx = OSSL_LIB_CTX_new(); + if (!TEST_ptr(ctx)) + goto err; + + if (!TEST_true(OSSL_LIB_CTX_load_config(ctx, config_file))) + goto err; + + if (!TEST_int_eq(OSSL_PROVIDER_available(ctx, "legacy"), 0)) + goto err; + + rc = 1; +err: + OSSL_LIB_CTX_free(ctx); + return rc; +} + static X509_ALGOR *make_algor(int nid) { X509_ALGOR *algor; @@ -379,6 +400,7 @@ int setup_tests(void) return 0; } } + ADD_TEST(test_legacy_provider_unloaded); if (strcmp(alg, "digest") == 0) { ADD_TEST(test_implicit_EVP_MD_fetch); ADD_TEST(test_explicit_EVP_MD_fetch_by_name); diff --git a/test/evp_test.c b/test/evp_test.c index cef7b1b9e83bcf7dc7082314528d7a94012609b7..ecc7f7fe209c2f28c8f0b605fd6a68edb1e73780 100644 --- a/test/evp_test.c +++ b/test/evp_test.c @@ -1514,7 +1514,7 @@ static int mac_test_run_mac(EVP_TEST *t) EVP_MAC_CTX *ctx = NULL; unsigned char *got = NULL; size_t got_len = 0, size = 0; - size_t size_before_init, size_after_init, size_val = 0; + size_t size_before_init = 0, size_after_init, size_val = 0; int i, block_size = -1, output_size = -1; OSSL_PARAM params[21], sizes[3], *psizes = sizes; size_t params_n = 0; @@ -1622,7 +1622,8 @@ static int mac_test_run_mac(EVP_TEST *t) t->err = "MAC_CREATE_ERROR"; goto err; } - size_before_init = EVP_MAC_CTX_get_mac_size(ctx); + if (fips_provider_version_gt(libctx, 3, 2, 0)) + size_before_init = EVP_MAC_CTX_get_mac_size(ctx); if (!EVP_MAC_init(ctx, expected->key, expected->key_len, params)) { t->err = "MAC_INIT_ERROR"; goto err; diff --git a/test/prov_config_test.c b/test/prov_config_test.c index 4b04211fa47ef32b9e5d5548b00be21bc742b99f..b44ec78d8d24b4e068642a80c82f89e94bb86cc3 100644 --- a/test/prov_config_test.c +++ b/test/prov_config_test.c @@ -8,9 +8,11 @@ */ #include +#include #include "testutil.h" static char *configfile = NULL; +static char *recurseconfigfile = NULL; /* * Test to make sure there are no leaks or failures from loading the config @@ -44,6 +46,30 @@ static int test_double_config(void) return testresult; } +static int test_recursive_config(void) +{ + OSSL_LIB_CTX *ctx = OSSL_LIB_CTX_new(); + int testresult = 0; + unsigned long err; + + if (!TEST_ptr(recurseconfigfile)) + goto err; + + if (!TEST_ptr(ctx)) + goto err; + + if (!TEST_false(OSSL_LIB_CTX_load_config(ctx, recurseconfigfile))) + goto err; + + err = ERR_peek_error(); + /* We expect to get a recursion error here */ + if (ERR_GET_REASON(err) == CONF_R_RECURSIVE_SECTION_REFERENCE) + testresult = 1; + err: + OSSL_LIB_CTX_free(ctx); + return testresult; +} + OPT_TEST_DECLARE_USAGE("configfile\n") int setup_tests(void) @@ -56,6 +82,10 @@ int setup_tests(void) if (!TEST_ptr(configfile = test_get_argument(0))) return 0; + if (!TEST_ptr(recurseconfigfile = test_get_argument(1))) + return 0; + + ADD_TEST(test_recursive_config); ADD_TEST(test_double_config); return 1; } diff --git a/test/quic_multistream_test.c b/test/quic_multistream_test.c index 22a753ad673b309b5fd6daea2e7d809481597759..9e53d147a680f5b78ebc8ee611602b1b45c9c001 100644 --- a/test/quic_multistream_test.c +++ b/test/quic_multistream_test.c @@ -13,6 +13,8 @@ #include "internal/quic_tserver.h" #include "internal/quic_ssl.h" #include "internal/quic_error.h" +#include "internal/quic_stream_map.h" +#include "internal/quic_engine.h" #include "testutil.h" #include "helpers/quictestlib.h" #if defined(OPENSSL_THREADS) @@ -180,6 +182,7 @@ struct script_op { #define OPK_C_SKIP_IF_UNBOUND 48 #define OPK_S_SET_INJECT_DATAGRAM 49 #define OPK_S_SHUTDOWN 50 +#define OPK_POP_ERR 51 #define EXPECT_CONN_CLOSE_APP (1U << 0) #define EXPECT_CONN_CLOSE_REMOTE (1U << 1) @@ -318,6 +321,8 @@ struct script_op { {OPK_S_SET_INJECT_DATAGRAM, NULL, 0, NULL, NULL, 0, NULL, NULL, (f)}, #define OP_S_SHUTDOWN(error_code) \ {OPK_S_SHUTDOWN, NULL, (error_code)}, +#define OP_POP_ERR() \ + {OPK_POP_ERR}, static OSSL_TIME get_time(void *arg) { @@ -1108,6 +1113,7 @@ static int run_script_worker(struct helper *h, const struct script_op *script, case OPK_C_EXPECT_SSL_ERR: case OPK_EXPECT_ERR_REASON: case OPK_EXPECT_ERR_LIB: + case OPK_POP_ERR: case OPK_SLEEP: break; @@ -1593,7 +1599,7 @@ static int run_script_worker(struct helper *h, const struct script_op *script, QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn); SSL_SHUTDOWN_EX_ARGS args = {0}; - ossl_quic_channel_set_inhibit_tick(ch, 0); + ossl_quic_engine_set_inhibit_tick(ossl_quic_channel_get0_engine(ch), 0); if (!TEST_ptr(c_tgt)) goto out; @@ -1852,18 +1858,22 @@ static int run_script_worker(struct helper *h, const struct script_op *script, case OPK_EXPECT_ERR_REASON: { - if (!TEST_size_t_eq((size_t)ERR_GET_REASON(ERR_get_error()), op->arg1)) + if (!TEST_size_t_eq((size_t)ERR_GET_REASON(ERR_peek_last_error()), op->arg1)) goto out; } break; case OPK_EXPECT_ERR_LIB: { - if (!TEST_size_t_eq((size_t)ERR_GET_LIB(ERR_get_error()), op->arg1)) + if (!TEST_size_t_eq((size_t)ERR_GET_LIB(ERR_peek_last_error()), op->arg1)) goto out; } break; + case OPK_POP_ERR: + ERR_pop(); + break; + case OPK_SLEEP: { OSSL_sleep(op->arg2); @@ -1917,7 +1927,8 @@ static int run_script_worker(struct helper *h, const struct script_op *script, { QUIC_CHANNEL *ch = ossl_quic_conn_get_channel(h->c_conn); - ossl_quic_channel_set_inhibit_tick(ch, op->arg1); + ossl_quic_engine_set_inhibit_tick(ossl_quic_channel_get0_engine(ch), + op->arg1); } break; @@ -2712,8 +2723,14 @@ static const struct script_op script_20_child[] = { OP_C_READ_FAIL_WAIT (a) OP_C_EXPECT_SSL_ERR (a, SSL_ERROR_SYSCALL) - OP_EXPECT_ERR_LIB (ERR_LIB_SYS) + + OP_EXPECT_ERR_LIB (ERR_LIB_SSL) + OP_EXPECT_ERR_REASON (SSL_R_PROTOCOL_IS_SHUTDOWN) + + OP_POP_ERR () + OP_EXPECT_ERR_LIB (ERR_LIB_SSL) OP_EXPECT_ERR_REASON (SSL_R_QUIC_NETWORK_ERROR) + OP_C_FREE_STREAM (a) OP_END diff --git a/test/quic_record_test.c b/test/quic_record_test.c index 5966b937301288179c06eb41cb3bc209b0d9be85..3c6eb19f82bb5c9db27c7f2033c38371183a1545 100644 --- a/test/quic_record_test.c +++ b/test/quic_record_test.c @@ -21,7 +21,7 @@ static const QUIC_CONN_ID empty_conn_id = {0, {0}}; #define RX_TEST_OP_END 0 /* end of script */ #define RX_TEST_OP_SET_SCID_LEN 1 /* change SCID length */ #define RX_TEST_OP_SET_INIT_LARGEST_PN 2 /* set initial largest PN */ -#define RX_TEST_OP_ADD_RX_DCID 3 /* register an RX DCID */ +#define RX_TEST_OP_SET_RX_DCID 3 /* register an RX DCID */ #define RX_TEST_OP_INJECT 4 /* inject a datagram into demux */ #define RX_TEST_OP_PROVIDE_SECRET 5 /* provide RX secret */ #define RX_TEST_OP_PROVIDE_SECRET_INITIAL 6 /* provide RX secret for initial */ @@ -54,8 +54,8 @@ struct rx_test_op { { RX_TEST_OP_SET_SCID_LEN, 0, NULL, 0, NULL, (scid_len), 0, 0, NULL, NULL }, #define RX_OP_SET_INIT_LARGEST_PN(largest_pn) \ { RX_TEST_OP_SET_INIT_LARGEST_PN, 0, NULL, 0, NULL, 0, 0, (largest_pn), NULL, NULL }, -#define RX_OP_ADD_RX_DCID(dcid) \ - { RX_TEST_OP_ADD_RX_DCID, 0, NULL, 0, NULL, 0, 0, 0, &(dcid), NULL }, +#define RX_OP_SET_RX_DCID(dcid) \ + { RX_TEST_OP_SET_RX_DCID, 0, NULL, 0, NULL, 0, 0, 0, &(dcid), NULL }, #define RX_OP_INJECT(dgram) \ { RX_TEST_OP_INJECT, 0, (dgram), sizeof(dgram), NULL, 0, 0, 0, NULL }, #define RX_OP_PROVIDE_SECRET(el, suite, key) \ @@ -138,7 +138,7 @@ static const QUIC_PKT_HDR rx_script_1_expect_hdr = { static const struct rx_test_op rx_script_1[] = { RX_OP_SET_SCID_LEN(2) RX_OP_SET_INIT_LARGEST_PN(0) - RX_OP_ADD_RX_DCID(empty_conn_id) + RX_OP_SET_RX_DCID(empty_conn_id) RX_OP_PROVIDE_SECRET_INITIAL(rx_script_1_dcid) RX_OP_INJECT_CHECK(1) RX_OP_CHECK_NO_PKT() @@ -173,7 +173,7 @@ static const QUIC_PKT_HDR rx_script_2_expect_hdr = { static const struct rx_test_op rx_script_2[] = { RX_OP_ALLOW_1RTT() RX_OP_SET_INIT_LARGEST_PN(654360560) - RX_OP_ADD_RX_DCID(empty_conn_id) + RX_OP_SET_RX_DCID(empty_conn_id) RX_OP_PROVIDE_SECRET(QUIC_ENC_LEVEL_1RTT, QRL_SUITE_CHACHA20POLY1305, rx_script_2_secret) RX_OP_INJECT_CHECK(2) @@ -218,7 +218,7 @@ static const unsigned char rx_script_3_body[] = { }; static const struct rx_test_op rx_script_3[] = { - RX_OP_ADD_RX_DCID(empty_conn_id) + RX_OP_SET_RX_DCID(empty_conn_id) /* * This is a version negotiation packet, so doesn't have any frames. * However, the depacketizer still handles this sort of packet, so @@ -279,7 +279,7 @@ static const unsigned char rx_script_4_body[] = { }; static const struct rx_test_op rx_script_4[] = { - RX_OP_ADD_RX_DCID(empty_conn_id) + RX_OP_SET_RX_DCID(empty_conn_id) RX_OP_INJECT_CHECK(4) RX_OP_CHECK_NO_PKT() RX_OP_END @@ -592,7 +592,7 @@ static const unsigned char rx_script_5c_body[] = { static const struct rx_test_op rx_script_5[] = { RX_OP_ALLOW_1RTT() - RX_OP_ADD_RX_DCID(empty_conn_id) + RX_OP_SET_RX_DCID(empty_conn_id) RX_OP_PROVIDE_SECRET_INITIAL(rx_script_5_c2s_init_dcid) RX_OP_INJECT_N(5) RX_OP_CHECK_PKT_N(5a) @@ -629,7 +629,7 @@ static const struct rx_test_op rx_script_5[] = { /* Recreate QRL, test reading packets received before key */ RX_OP_SET_SCID_LEN(0) - RX_OP_ADD_RX_DCID(empty_conn_id) + RX_OP_SET_RX_DCID(empty_conn_id) RX_OP_INJECT_N(5) RX_OP_CHECK_NO_PKT() RX_OP_PROVIDE_SECRET_INITIAL(rx_script_5_c2s_init_dcid) @@ -961,7 +961,7 @@ static const unsigned char rx_script_6c_body[] = { static const struct rx_test_op rx_script_6[] = { RX_OP_ALLOW_1RTT() - RX_OP_ADD_RX_DCID(empty_conn_id) + RX_OP_SET_RX_DCID(empty_conn_id) RX_OP_PROVIDE_SECRET_INITIAL(rx_script_6_c2s_init_dcid) RX_OP_INJECT_N(6) RX_OP_CHECK_PKT_N(6a) @@ -998,7 +998,7 @@ static const struct rx_test_op rx_script_6[] = { /* Recreate QRL, test reading packets received before key */ RX_OP_SET_SCID_LEN(0) - RX_OP_ADD_RX_DCID(empty_conn_id) + RX_OP_SET_RX_DCID(empty_conn_id) RX_OP_INJECT_N(6) RX_OP_CHECK_NO_PKT() RX_OP_PROVIDE_SECRET_INITIAL(rx_script_6_c2s_init_dcid) @@ -1324,7 +1324,7 @@ static const unsigned char rx_script_7c_body[] = { static const struct rx_test_op rx_script_7[] = { RX_OP_ALLOW_1RTT() - RX_OP_ADD_RX_DCID(empty_conn_id) + RX_OP_SET_RX_DCID(empty_conn_id) RX_OP_PROVIDE_SECRET_INITIAL(rx_script_7_c2s_init_dcid) RX_OP_INJECT_N(7) RX_OP_CHECK_PKT_N(7a) @@ -1361,7 +1361,7 @@ static const struct rx_test_op rx_script_7[] = { /* Recreate QRL, test reading packets received before key */ RX_OP_SET_SCID_LEN(0) - RX_OP_ADD_RX_DCID(empty_conn_id) + RX_OP_SET_RX_DCID(empty_conn_id) RX_OP_INJECT_N(7) RX_OP_CHECK_NO_PKT() RX_OP_PROVIDE_SECRET_INITIAL(rx_script_7_c2s_init_dcid) @@ -1583,7 +1583,7 @@ static const unsigned char rx_script_8f_body[] = { static const struct rx_test_op rx_script_8[] = { RX_OP_ALLOW_1RTT() - RX_OP_ADD_RX_DCID(empty_conn_id) + RX_OP_SET_RX_DCID(empty_conn_id) /* Inject before we get the keys */ RX_OP_INJECT_N(8a) /* Nothing yet */ @@ -1676,7 +1676,7 @@ static const struct rx_test_op rx_script_8[] = { /* 9. 1-RTT Deferral Test */ static const struct rx_test_op rx_script_9[] = { - RX_OP_ADD_RX_DCID(empty_conn_id) + RX_OP_SET_RX_DCID(empty_conn_id) RX_OP_PROVIDE_SECRET_INITIAL(rx_script_5_c2s_init_dcid) RX_OP_INJECT_N(5) @@ -1723,6 +1723,8 @@ struct rx_state { SSL_CTX *quic_ssl_ctx; QUIC_CONNECTION *quic_conn; + QUIC_CONN_ID rx_dcid; + int allow_1rtt; }; @@ -1760,6 +1762,17 @@ static OSSL_TIME fake_time(void *arg) return expected_time(++time_counter); } +static void demux_default_handler(QUIC_URXE *e, void *arg, + const QUIC_CONN_ID *dcid) +{ + struct rx_state *s = arg; + + if (dcid == NULL || !ossl_quic_conn_id_eq(dcid, &s->rx_dcid)) + return; + + ossl_qrx_inject_urxe(s->qrx, e); +} + static int rx_state_ensure(struct rx_state *s) { if (s->demux == NULL @@ -1777,6 +1790,8 @@ static int rx_state_ensure(struct rx_state *s) && !TEST_ptr(s->qrx = ossl_qrx_new(&s->args))) return 0; + ossl_quic_demux_set_default_handler(s->demux, demux_default_handler, s); + if (s->allow_1rtt) ossl_qrx_allow_1rtt_processing(s->qrx); @@ -1803,11 +1818,10 @@ static int rx_run_script(const struct rx_test_op *script) for (i = 0; i < QUIC_PN_SPACE_NUM; ++i) s.args.init_largest_pn[i] = op->largest_pn; break; - case RX_TEST_OP_ADD_RX_DCID: + case RX_TEST_OP_SET_RX_DCID: if (!TEST_true(rx_state_ensure(&s))) goto err; - if (!TEST_true(ossl_qrx_add_dst_conn_id(s.qrx, op->dcid))) - goto err; + s.rx_dcid = *op->dcid; break; case RX_TEST_OP_PROVIDE_SECRET: if (!TEST_true(rx_state_ensure(&s))) diff --git a/test/quic_txp_test.c b/test/quic_txp_test.c index 423d28ddcbb4747b0f00b397340262a5e8ed8177..f234fb683ac9199d4d3c449ae849a838d5357b62 100644 --- a/test/quic_txp_test.c +++ b/test/quic_txp_test.c @@ -108,6 +108,17 @@ static void helper_cleanup(struct helper *h) BIO_free(h->bio2); } +static void demux_default_handler(QUIC_URXE *e, void *arg, + const QUIC_CONN_ID *dcid) +{ + struct helper *h = arg; + + if (dcid == NULL || !ossl_quic_conn_id_eq(dcid, &dcid_1)) + return; + + ossl_qrx_inject_urxe(h->qrx, e); +} + static int helper_init(struct helper *h) { int rc = 0; @@ -204,6 +215,8 @@ static int helper_init(struct helper *h) fake_now, NULL))) goto err; + ossl_quic_demux_set_default_handler(h->demux, demux_default_handler, h); + h->qrx_args.demux = h->demux; h->qrx_args.short_conn_id_len = 8; h->qrx_args.max_deferred = 32; @@ -211,9 +224,6 @@ static int helper_init(struct helper *h) if (!TEST_ptr(h->qrx = ossl_qrx_new(&h->qrx_args))) goto err; - if (!TEST_true(ossl_qrx_add_dst_conn_id(h->qrx, &dcid_1))) - goto err; - ossl_qrx_allow_1rtt_processing(h->qrx); rc = 1; diff --git a/test/recipes/30-test_prov_config.t b/test/recipes/30-test_prov_config.t index f97a26dbe9543c6e760d3782f96c00dc83b6337b..7f6350fd84e1161eb1b5135d08d49c0dc180333d 100644 --- a/test/recipes/30-test_prov_config.t +++ b/test/recipes/30-test_prov_config.t @@ -22,11 +22,14 @@ my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0); plan tests => 2; -ok(run(test(["prov_config_test", srctop_file("test", "default.cnf")])), +ok(run(test(["prov_config_test", srctop_file("test", "default.cnf"), + srctop_file("test", "recursive.cnf")])), "running prov_config_test default.cnf"); + SKIP: { skip "Skipping FIPS test in this build", 1 if $no_fips; - ok(run(test(["prov_config_test", srctop_file("test", "fips.cnf")])), + ok(run(test(["prov_config_test", srctop_file("test", "fips.cnf"), + srctop_file("test", "recursive.cnf")])), "running prov_config_test fips.cnf"); } diff --git a/test/recipes/80-test_cmp_http_data/test_commands.csv b/test/recipes/80-test_cmp_http_data/test_commands.csv index 5ab2ca3fd7a61696b1b235e81f1e9dbe3a49ef59..425385fe69125134c2de42cbd7e2282c1096ee60 100644 --- a/test/recipes/80-test_cmp_http_data/test_commands.csv +++ b/test/recipes/80-test_cmp_http_data/test_commands.csv @@ -77,12 +77,25 @@ expected,description, -section,val, -cmd,val,val2, -cacertsout,val,val2, -infoty 0,genm rootCaCert newwithold missig arg , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew.pem, -oldwithnew, _RESULT_DIR/test.oldwithnew.pem, -newwithold,, 1,genm rootCaCert newwithnew newwithold , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew3.pem, -newwithold, _RESULT_DIR/test.newwithold2.pem ,,,,,,,,,,,,,,,,,,,,,, -1,geninfo, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.2.3:int:987,BLANK,,BLANK, -0,geninfo missing argument, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,,,,, -0,geninfo bad syntax: leading '.', -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,.1.2.3:int:987,BLANK,,BLANK, -0,geninfo bad syntax: missing ':', -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.2.3:int987,,,, -0,geninfo bad syntax: double ':', -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.2.3:int::987,,,, +1,profile, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,profile1,BLANK,,BLANK, +0,profile wrong value, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,profile2,BLANK,,BLANK, +0,profile missing argument, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,,,,, +0,profile extra argument, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,profile1,profile2,,, +,,,,,,,,,,,,,,,,,,, +1,geninfo int, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.3:int:987 +1,geninfo str, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,id-kp:str:name +1,geninfo empty str, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,id-kp:str: +1,geninfo str and int, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo, 'id-kp:str:name, 1.3:int:987' +0,geninfo missing argument, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,,,,, +0,geninfo bad OID num syntax, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,.1.2.3:int:987 +0,geninfo invalid OID number string, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.333:int:987 +1,geninfo unknown OID number string, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.33:int:987 +0,geninfo bad OID name: trailing '_', -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,id-kp_:int:987 0,geninfo bad syntax: missing ':int', -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.2.3,,,, +0,geninfo bad type tag, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.2.3:xyz:987,,,, +0,geninfo bad syntax: missing ':', -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.2.3:int987,,,, +0,geninfo bad int syntax: double ':', -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.2.3:int::987,,,, +0,geninfo bad int syntax: extra char, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.2.3:int:987@,,,, ,,,,,,,,,,,,,,,,,,, 1,reqout ir+certConf rspout ip+pkiConf, -section,, -cmd,ir,,-reqout,_RESULT_DIR/ir.der _RESULT_DIR/certConf.der,,-rspout,_RESULT_DIR/ip.der _RESULT_DIR/pkiConf.der,,BLANK,,BLANK, 1,reqout cr rspout cp, -section,, -cmd,cr,,-reqout,_RESULT_DIR/cr.der,,-rspout,_RESULT_DIR/cp.der,,BLANK,,BLANK, diff --git a/test/recipes/80-test_cms.t b/test/recipes/80-test_cms.t index 0e1ebc50cd90485828917e25f92b2efb17a4a477..6a9792128be15fea9c483916ff87c0a3ed80a9bb 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 => 22; +plan tests => 23; ok(run(test(["pkcs7_test"])), "test pkcs7"); @@ -222,13 +222,15 @@ my @smime_pkcs7_tests = ( \&final_compare ], - [ "enveloped content test streaming S/MIME format, DES, 3 recipients, key only used", + [ "enveloped content test streaming S/MIME format, DES, 3 recipients, cert and key files used", [ "{cmd1}", @defaultprov, "-encrypt", "-in", $smcont, "-stream", "-out", "{output}.cms", $smrsa1, catfile($smdir, "smrsa2.pem"), - catfile($smdir, "smrsa3.pem") ], - [ "{cmd2}", @defaultprov, "-decrypt", "-inkey", catfile($smdir, "smrsa3.pem"), + catfile($smdir, "smrsa3-cert.pem") ], + [ "{cmd2}", @defaultprov, "-decrypt", + "-recip", catfile($smdir, "smrsa3-cert.pem"), + "-inkey", catfile($smdir, "smrsa3-key.pem"), "-in", "{output}.cms", "-out", "{output}.txt" ], \&final_compare ], @@ -1165,3 +1167,51 @@ with({ exit_checker => sub { return shift == 3; } }, ])), "Check for failure when cipher does not have an assigned OID (issue#22225)"); }); + +# Test encrypt to three recipients, and decrypt using key-only; +# i.e. do not follow the recommended practice of providing the +# recipient cert in the decrypt op. +# +# Use RSAES-OAEP for key-transport, not RSAES-PKCS-v1_5. +# +# Because the cert is not provided during decrypt, all RSA ciphertexts +# are decrypted in turn, and when/if there is a valid decryption, it +# is assumed the correct content-key has been recovered. +# +# That process may fail with RSAES-PKCS-v1_5 b/c there is a +# non-negligible chance that decrypting a random input using +# RSAES-PKCS-v1_5 can result in a valid plaintext (so two content-keys +# could be recovered and the wrong one might be used). +# +# See https://github.com/openssl/project/issues/380 +subtest "encrypt to three recipients with RSA-OAEP, key only decrypt" => sub { + plan tests => 3; + + my $pt = srctop_file("test", "smcont.txt"); + my $ct = "smtst.cms"; + my $ptpt = "smtst.txt"; + + ok(run(app(['openssl', 'cms', + @defaultprov, + '-encrypt', '-aes128', + '-in', $pt, + '-out', $ct, + '-stream', + '-recip', catfile($smdir, "smrsa1.pem"), + '-keyopt', 'rsa_padding_mode:oaep', + '-recip', catfile($smdir, "smrsa2.pem"), + '-keyopt', 'rsa_padding_mode:oaep', + '-recip', catfile($smdir, "smrsa3-cert.pem"), + '-keyopt', 'rsa_padding_mode:oaep', + ])), + "encrypt to three recipients with RSA-OAEP (avoid openssl/project issue#380)"); + ok(run(app(['openssl', 'cms', + @defaultprov, + '-decrypt', '-aes128', + '-in', $ct, + '-out', $ptpt, + '-inkey', catfile($smdir, "smrsa3-key.pem"), + ])), + "decrypt with key only"); + is(compare($pt, $ptpt), 0, "compare original message with decrypted ciphertext"); +}; diff --git a/test/recursive.cnf b/test/recursive.cnf new file mode 100644 index 0000000000000000000000000000000000000000..505733ae45658d416623fd35683e76087f4c057c --- /dev/null +++ b/test/recursive.cnf @@ -0,0 +1,8 @@ +openssl_conf = openssl_init +config_diagnostics = yes + +[openssl_init] +providers = provider_sect + +[provider_sect] + = provider_sect diff --git a/test/run_tests.pl b/test/run_tests.pl index 90fba194b11bec4e82dcff9420fe54701b39cc66..89d7fafb72566f3cdbe8fe2557726526b2017939 100644 --- a/test/run_tests.pl +++ b/test/run_tests.pl @@ -175,6 +175,7 @@ $eres = eval { my $failure_verbosity = $openssl_args{failure_verbosity}; my @plans = (); # initial level, no plan yet my $output_buffer = ""; + my $in_indirect = 0; # We rely heavily on perl closures to make failure verbosity work # We need to do so, because there's no way to safely pass extra @@ -211,7 +212,28 @@ $eres = eval { $output_buffer = ""; # ignore comments etc. until plan } elsif ($is_test) { # result of a test pop @plans if @plans && --($plans[-1]) <= 0; - print $output_buffer if !$is_ok; + if ($output_buffer =~ /.*Indirect leak of.*/ == 1) { + my @asan_array = split("\n", $output_buffer); + foreach (@asan_array) { + if ($_ =~ /.*Indirect leak of.*/ == 1) { + if ($in_indirect != 1) { + print "::group::Indirect Leaks\n"; + } + $in_indirect = 1; + } + print "$_\n"; + if ($_ =~ /.*Indirect leak of.*/ != 1) { + if ($_ =~ /^ #.*/ == 0) { + if ($in_indirect != 0) { + print "\n::endgroup::\n"; + } + $in_indirect = 0; + } + } + } + } else { + print $output_buffer if !$is_ok; + } print "\n".$self->as_string if !$is_ok || $failure_verbosity == 2; print "\n# ------------------------------------------------------------------------------" if !$is_ok; diff --git a/test/smime-certs/mksmime-certs.sh b/test/smime-certs/mksmime-certs.sh index ab7e22a136e2867891c0ee8b6291bc9d89362dce..0edf1d789e3f48ce78cdc2656ad05401c2f850e4 100644 --- a/test/smime-certs/mksmime-certs.sh +++ b/test/smime-certs/mksmime-certs.sh @@ -30,6 +30,9 @@ gen smrsa2.pem "/CN=Test SMIME EE RSA #2" usr_rsa_cert >>smrsa2.pem cp ../certs/ee-key-4096.pem smrsa3.pem gen smrsa3.pem "/CN=Test SMIME EE RSA #3" usr_rsa_cert >>smrsa3.pem +$OPENSSL x509 -in smrsa3.pem > smrsa3-cert.pem +$OPENSSL pkey -in smrsa3.pem > smrsa3-key.pem + # Create DSA certificates with respective extensions cp ../certs/server-dsa-key.pem smdsa1.pem diff --git a/test/smime-certs/smrsa3-cert.pem b/test/smime-certs/smrsa3-cert.pem new file mode 100644 index 0000000000000000000000000000000000000000..70004acb86988e15ca51448d1e61f1a659487bf1 --- /dev/null +++ b/test/smime-certs/smrsa3-cert.pem @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDeTCCAmGgAwIBAgIUIDyc//j/LoNDesZTGbPBoVarv4EwDQYJKoZIhvcNAQEL +BQAwRDELMAkGA1UEBhMCVUsxFjAUBgNVBAoMDU9wZW5TU0wgR3JvdXAxHTAbBgNV +BAMMFFRlc3QgUy9NSU1FIFJTQSBSb290MCAXDTIyMDYwMjE1MzMxM1oYDzIxMjIw +NTA5MTUzMzEzWjBFMQswCQYDVQQGEwJVSzEWMBQGA1UECgwNT3BlblNTTCBHcm91 +cDEeMBwGA1UEAwwVVGVzdCBTL01JTUUgRUUgUlNBICMzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA+QP7d56K4/9eu7aChtWILYNxvqWeDcJeWvX5Z5vC +XUjFuUxBD9U0rw1SBLgFYu8aqAJ+oXsqaGjJARifgKEqPUe7pnYYatr55lhTbHR+ +qA88p1V4sclEaPNWKzd7J/V3eeYr04kqWV5XYhAq9k9AWLzsNIePe2z7OoGPS6oK +wRzWFRd5RYXTpmFr/tqknbYvtYFd7duKb9QqytgHV+RKXXeY0fnjZ7frLmaqDwtI +U3DY7MyS3Hw2BVx72vQXBNA364HGEpqEgVOdzI7et0wpSumaFXDye714xUR53L7N +f3fp3PQXS/RbBiNXs7KUsHCR6nsdsIKO+sg66gxOLNt6zwIDAQABo2AwXjAMBgNV +HRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIF4DAdBgNVHQ4EFgQUN9pGq/UFS3o50rTi +V+AYgAk+3R4wHwYDVR0jBBgwFoAUFcETIWviVV+nah1XINbP86lzZFkwDQYJKoZI +hvcNAQELBQADggEBAGcOh380/6aJqMpYBssuf2CB3DX/hGKdvEF7fF8iNSfl5HHq +112kHl3MhbL9Th/safJq9sLDJqjXRNdVCUJJbU4YI2P2gsi04paC0qxWxMLtzQLd +CE7ki2xH94Fuu/dThbpzZBABROO1RrdI24GDGt9t4Gf0WVkobmT/zNlwGppKTIB2 +iV/Ug30iKr/C49UzwUIa+XXXujkjPTmGSnrKwVQNxQh81rb+iTL7GEnNuqDsatHW +ZyLS2SaVdG5tMqDkITPMDGjehUzJcAbVc8Bv4m8Ukuov3uDj2Doc6MxlvrVkV0AE +BcSCb/bWQJJ/X4LQZlx9cMk4NINxV9UeFPZOefg= +-----END CERTIFICATE----- diff --git a/test/smime-certs/smrsa3-key.pem b/test/smime-certs/smrsa3-key.pem new file mode 100644 index 0000000000000000000000000000000000000000..216d70b61b74c2038afd5fbbf612e7cf54956fec --- /dev/null +++ b/test/smime-certs/smrsa3-key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQD5A/t3norj/167 +toKG1Ygtg3G+pZ4Nwl5a9flnm8JdSMW5TEEP1TSvDVIEuAVi7xqoAn6heypoaMkB +GJ+AoSo9R7umdhhq2vnmWFNsdH6oDzynVXixyURo81YrN3sn9Xd55ivTiSpZXldi +ECr2T0BYvOw0h497bPs6gY9LqgrBHNYVF3lFhdOmYWv+2qSdti+1gV3t24pv1CrK +2AdX5Epdd5jR+eNnt+suZqoPC0hTcNjszJLcfDYFXHva9BcE0DfrgcYSmoSBU53M +jt63TClK6ZoVcPJ7vXjFRHncvs1/d+nc9BdL9FsGI1ezspSwcJHqex2wgo76yDrq +DE4s23rPAgMBAAECggEAEDi+VWD5VUpjD5zWOoPQiRDGBJBhtMAKkl6okxEmXvWb +Xz3STFnjHgA1JFHW3bRU9BHI9k8vSHmnlnkfKb3V/ZX5IHNcKCHb/x9NBak+QLVQ +0zLtfE9vxiTC0B/oac+MPaiD4hYFQ81pFwK6VS0Poi8ZCBJtOkRqfUvsyV8zZrgh +/6cs4mwOVyZPFRgF9eWXYv7PJz8pNRizhII0iv9H/r2I3DzsZLPCg7c29mP+I/SG +A7Pl82UXjtOc0KurGY2M5VheZjxJT/k/FLMkWY2GS5n6dfcyzsVSKb25HoeuvQsI +vs1mKs+Onbobdc17hCcKVJzbi3DwXs5XDhrEzfHccQKBgQD88uBxVCRV31PsCN6I +pKxQDGgz+1BqPqe7KMRiZI7HgDUK0eCM3/oG089/jsBtJcSxnScLSVNBjQ+xGiFi +YCD4icQoJSzpqJyR6gDq5lTHASAe+9LWRW771MrtyACQWNXowYEyu8AjekrZkCUS +wIKVpw57oWykzIoS7ixZsJ8gxwKBgQD8BPWqJEsLiQvOlS5E/g88eV1KTpxm9Xs+ +BbwsDXZ7m4Iw5lYaUu5CwBB/2jkGGRl8Q/EfAdUT7gXv3t6x5b1qMXaIczmRGYto +NuI3AH2MPxAa7lg5TgBgie1r7PKwyPMfG3CtDx6n8W5sexgJpbIy5u7E+U6d8s1o +c7EcsefduQKBgCkHJAx9v18GWFBip+W2ABUDzisQSlzRSNd8p03mTZpiWzgkDq4K +7j0JQhDIkMGjbKH6gYi9Hfn17WOmf1+7g92MSvrP/NbxeGPadsejEIEu14zu/6Wt +oXDLdRbYZ+8B2cBlEpWuCl42yck8Lic6fnPTou++oSah3otvglYR5d2lAoGACd8L +3FE1m0sP6lSPjmZBJIZAcDOqDqJY5HIHD9arKGZL8CxlfPx4lqa9PrTGfQWoqORk +YmmI9hHhq6aYJHGyPKGZWfjhbVyJyFg1/h+Hy2GA+P0S+ZOjkiR050BNtTz5wOMr +Q6wO8FcVkywzIdWaqEHBYne9a5RiFVBKxKv3QAkCgYBxmCBKajFkMVb4Uc55WqJs +Add0mctGgmZ1l5vq81eWe3wjM8wgfJgaD3Q3gwx2ABUX/R+OsVWSh4o5ZR86sYoz +TviknBHF8GeDLjpT49+04fEaz336J2JOptF9zIpz7ZK1nrOEjzaZGtumReVjUP7X +fNcb5iDYqZRzD8ixBbLxUw== +-----END PRIVATE KEY----- diff --git a/test/sslapitest.c b/test/sslapitest.c index efea1a6495444efdbe43dd685c202a7793636e98..e2c4563fd3fd40c001e3d24e8195a4bdb8245efa 100644 --- a/test/sslapitest.c +++ b/test/sslapitest.c @@ -6335,6 +6335,7 @@ static int test_export_key_mat(int tst) const unsigned char context[] = "context"; const unsigned char *emptycontext = NULL; unsigned char longcontext[1280]; + int test_longcontext = fips_provider_version_ge(libctx, 3, 3, 0); unsigned char ckeymat1[80], ckeymat2[80], ckeymat3[80], ckeymat4[80]; unsigned char skeymat1[80], skeymat2[80], skeymat3[80], skeymat4[80]; size_t labellen; @@ -6429,12 +6430,14 @@ static int test_export_key_mat(int tst) sizeof(ckeymat3), label, labellen, NULL, 0, 0), 1) - || !TEST_int_eq(SSL_export_keying_material(clientssl, ckeymat4, - sizeof(ckeymat4), label, - labellen, - longcontext, - sizeof(longcontext), 1), - 1) + || (test_longcontext + && !TEST_int_eq(SSL_export_keying_material(clientssl, + ckeymat4, + sizeof(ckeymat4), label, + labellen, + longcontext, + sizeof(longcontext), 1), + 1)) || !TEST_int_eq(SSL_export_keying_material(serverssl, skeymat1, sizeof(skeymat1), label, labellen, @@ -6450,12 +6453,13 @@ static int test_export_key_mat(int tst) sizeof(skeymat3), label, labellen, NULL, 0, 0), 1) - || !TEST_int_eq(SSL_export_keying_material(serverssl, skeymat4, - sizeof(skeymat4), label, - labellen, - longcontext, - sizeof(longcontext), 1), - 1) + || (test_longcontext + && !TEST_int_eq(SSL_export_keying_material(serverssl, skeymat4, + sizeof(skeymat4), label, + labellen, + longcontext, + sizeof(longcontext), 1), + 1)) /* * Check that both sides created the same key material with the * same context. @@ -6478,8 +6482,9 @@ static int test_export_key_mat(int tst) * Check that both sides created the same key material with a * long context. */ - || !TEST_mem_eq(ckeymat4, sizeof(ckeymat4), skeymat4, - sizeof(skeymat4)) + || (test_longcontext + && !TEST_mem_eq(ckeymat4, sizeof(ckeymat4), skeymat4, + sizeof(skeymat4))) /* Different contexts should produce different results */ || !TEST_mem_ne(ckeymat1, sizeof(ckeymat1), ckeymat2, sizeof(ckeymat2))) diff --git a/test/sysdefault.cnf b/test/sysdefault.cnf index 20712b5bda40cd7878927ccbf74b54206f10a418..1c8915074a7829c671f1986481fdbc2bda24f899 100644 --- a/test/sysdefault.cnf +++ b/test/sysdefault.cnf @@ -18,5 +18,6 @@ new-sig-oid = 1.1.1.1.1.1.1.1.1.1.1.1.1.1 system_default = ssl_default_sect [ssl_default_sect] +SignatureAlgorithms = RSA+SHA256:nonex MaxProtocol = TLSv1.2 MinProtocol = TLSv1.2 diff --git a/util/libcrypto.num b/util/libcrypto.num index c9941a383be0d13cd0e6599c9a78975c856d5710..9d92ca67cada87ce10f72ba2d2f85a147dfc25d5 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5536,4 +5536,10 @@ X509_STORE_CTX_set_get_crl 5663 3_2_0 EXIST::FUNCTION: X509_STORE_CTX_set_current_reasons 5664 3_2_0 EXIST::FUNCTION: OSSL_STORE_delete 5665 3_2_0 EXIST::FUNCTION: BIO_ADDR_copy 5666 3_2_0 EXIST::FUNCTION:SOCK +OSSL_CMP_CTX_get0_geninfo_ITAVs ? 3_3_0 EXIST::FUNCTION:CMP +OSSL_CMP_HDR_get0_geninfo_ITAVs ? 3_3_0 EXIST::FUNCTION:CMP +OSSL_CMP_ITAV_new0_certProfile ? 3_3_0 EXIST::FUNCTION:CMP +OSSL_CMP_ITAV_get0_certProfile ? 3_3_0 EXIST::FUNCTION:CMP +OSSL_CMP_SRV_CTX_init_trans ? 3_3_0 EXIST::FUNCTION:CMP EVP_DigestSqueeze ? 3_3_0 EXIST::FUNCTION: +ERR_pop ? 3_3_0 EXIST::FUNCTION: diff --git a/util/other.syms b/util/other.syms index fa7a59d6a8835788a5c6cc8744c6370b8ea13a00..bf7eb8b22e96a18512456983bedfd4b767c3d7e1 100644 --- a/util/other.syms +++ b/util/other.syms @@ -461,6 +461,8 @@ OSSL_CMP_SRV_certConf_cb_t datatype OSSL_CMP_SRV_genm_cb_t datatype OSSL_CMP_SRV_error_cb_t datatype OSSL_CMP_SRV_pollReq_cb_t datatype +OSSL_CMP_SRV_delayed_delivery_cb_t datatype +OSSL_CMP_SRV_clean_transaction_cb_t datatype OSSL_CORE_MAKE_FUNC define OSSL_PARAM_TYPE define OSSL_PARAM_octet_ptr define diff --git a/util/quicserver.c b/util/quicserver.c index b5c15806a34bba6a3d596ddde09fc11fb1f55c93..d752340882ca5f3923407703e9d657d28e52ca2f 100644 --- a/util/quicserver.c +++ b/util/quicserver.c @@ -19,6 +19,7 @@ #include "internal/e_os.h" #include "internal/sockets.h" #include "internal/quic_tserver.h" +#include "internal/quic_stream_map.h" #include "internal/time.h" static BIO *bio_err = NULL;