Merge pull request #361

Conversion fixes for util.h
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..5a3d736
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,76 @@
+name: CI
+
+on: [push, pull_request]
+
+jobs:
+  linux:
+    name: "${{ matrix.name }}"
+    runs-on: [ubuntu-20.04]
+
+    # We want to run on external PRs, but not on our own internal PRs as they'll be run
+    # by the push to the branch.
+    if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
+
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - name: "Linux / OpenSSL 1.1.0"
+            command: make -f misc/docker-ci.mk CMAKE_ARGS='-DOPENSSL_ROOT_DIR=-DOPENSSL_ROOT_DIR=/opt/openssl-1.1.0' CONTAINER_NAME='h2oserver/h2o-ci:ubuntu1604'
+          - name: "Linux / OpenSSL 1.1.1"
+            command: make -f misc/docker-ci.mk
+          - name: "Linux / OpenSSL 1.1.1 + ASan & UBSan"
+            command: make -f misc/docker-ci.mk CMAKE_ARGS='-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_FLAGS=-fsanitize=address,undefined -DCMAKE_CXX_FLAGS=-fsanitize=address,undefined' CHECK_ENVS='ASAN_OPTIONS=detect_leaks=0 UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1'
+
+    timeout-minutes: 10
+    steps:
+    - uses: actions/checkout@v2
+      with:
+        submodules: recursive
+    - name: Run with Docker
+      shell: 'script -q -e -c "bash -xe {0}"'
+      run: |
+        chmod -R ugo+w .
+        ${{ matrix.command }}
+  macos:
+    name: "${{ matrix.name }}"
+    runs-on: [macos-latest]
+    # We want to run on external PRs, but not on our own internal PRs as they'll be run
+    # by the push to the branch.
+    if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
+
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - name: "macOS / OpenSSL 3.x"
+            openssl: openssl@3
+          - name: "macOS / OpenSSL 1.1.x"
+            openssl: openssl@1.1
+          - name: "macOS / LibreSSL"
+            openssl: libressl
+
+    timeout-minutes: 20
+    steps:
+    - uses: actions/checkout@v2
+      with:
+        submodules: recursive
+
+    - name: Install Dependencies
+      env:
+        OPENSSL: ${{ matrix.openssl }}
+      run: |
+        brew install perl libfaketime ${OPENSSL}
+        perl -v
+        curl -sSfL https://cpanmin.us | perl - -v --notest Scope::Guard Test::TCP
+
+    - name: Build
+      env:
+        OPENSSL: ${{ matrix.openssl }}
+      run: |
+        set -xe
+        mkdir -p build
+        cd build
+        cmake .. -DOPENSSL_ROOT_DIR="$(brew --prefix ${OPENSSL})"
+        make all VERBOSE=1
+        make check
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 2a9d1c6..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,71 +0,0 @@
-language: c
-dist: xenial
-sudo: required
-
-matrix:
-  include:
-    - name: Linux (gcc)
-      os: linux
-      dist: focal
-      compiler: gcc
-      before_install: &bs_linux
-        - sudo apt-get install faketime libscope-guard-perl libtest-tcp-perl
-    - name: Linux (clang)
-      os: linux
-      dist: focal
-      compiler: clang
-      before_install: *bs_linux
-    - name: Linux (OpenSSL 1.1.0)
-      os: linux
-      before_install:
-        - sudo apt-get install faketime libscope-guard-perl libtest-tcp-perl
-        - curl https://www.openssl.org/source/old/1.1.0/openssl-1.1.0l.tar.gz | tar xzf -
-        - cd openssl-1.1.0l
-        - ./config --prefix=/usr/local/openssl-1.1.0
-        - make
-        - sudo make install
-        - cd ..
-      env:
-        - PKG_CONFIG_PATH=/usr/local/openssl-1.1.0/lib/pkgconfig
-    - name: Linux (OpenSSL 1.0.2)
-      os: linux
-      before_install:
-        - sudo apt-get install faketime libscope-guard-perl libtest-tcp-perl
-        - curl https://www.openssl.org/source/old/1.0.2/openssl-1.0.2u.tar.gz | tar xzf -
-        - cd openssl-1.0.2u
-        - ./config --prefix=/usr/local/openssl-1.0.2
-        - make
-        - sudo make install
-        - cd ..
-      env:
-        - PKG_CONFIG_PATH=/usr/local/openssl-1.0.2/lib/pkgconfig
-    - name: Linux (libressl 3.2)
-      os: linux
-      before_install:
-        - sudo apt-get install faketime libscope-guard-perl libtest-tcp-perl
-        - curl https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-3.2.5.tar.gz | tar xzf -
-        - cd libressl-3.2.5
-        - ./configure --prefix=/usr/local/libressl-3.2
-        - make
-        - sudo make install
-        - cd ..
-      env:
-        - PKG_CONFIG_PATH=/usr/local/libressl-3.2/lib/pkgconfig
-    - name: macOS (Xcode)
-      os: osx
-      addons: &addons_macos
-        homebrew:
-          packages:
-            - libfaketime
-            - openssl
-      env:
-        - CMAKE_OPTS=" -DOPENSSL_ROOT_DIR=/usr/local/opt/openssl/"
-      before_install: &bs_macos
-        - curl -L https://cpanmin.us | sudo perl - App::cpanminus
-        - sudo cpanm --notest Scope::Guard
-        - sudo cpanm --notest Test::TCP
-
-script:
-  - cmake ${CMAKE_OPTS} .
-  - make all
-  - make check
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d1d6c09..793d1be 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12)
 CMAKE_POLICY(SET CMP0003 NEW)
 
 PROJECT(picotls)
@@ -7,10 +7,23 @@
 INCLUDE(cmake/dtrace-utils.cmake)
 
 CHECK_DTRACE(${PROJECT_SOURCE_DIR}/picotls-probes.d)
+IF ((CMAKE_SIZEOF_VOID_P EQUAL 8) AND
+    (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") OR
+     (CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64") OR
+     (CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64"))
+    SET(WITH_FUSION_DEFAULT "ON")
+ELSE ()
+    SET(WITH_FUSION_DEFAULT "OFF")
+ENDIF ()
+
 OPTION(WITH_DTRACE "use USDT (userspace Dtrace probes)" ${HAVE_DTRACE})
+OPTION(WITH_FUSION "build 'fusion' AES-GCM engine" ${WITH_FUSION_DEFAULT})
 IF (WITH_DTRACE)
     MESSAGE(STATUS "Enabling USDT support")
 ENDIF ()
+IF (WITH_FUSION)
+    MESSAGE(STATUS "Enabling 'fusion' AES-GCM engine")
+ENDIF ()
 
 SET(CMAKE_C_FLAGS "-std=c99 -Wall -O2 -g ${CC_WARNING_FLAGS} ${CMAKE_C_FLAGS}")
 INCLUDE_DIRECTORIES(
@@ -133,11 +146,7 @@
     MESSAGE(WARNING "Disabling OpenSSL support (requires 1.0.1 or newer)")
 ENDIF ()
 
-IF ((CMAKE_SIZEOF_VOID_P EQUAL 8) AND
-    (CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") OR
-     (CMAKE_SYSTEM_PROCESSOR STREQUAL "amd64") OR
-     (CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64"))
-    MESSAGE(STATUS " Enabling fusion support")
+IF (WITH_FUSION)
     ADD_LIBRARY(picotls-fusion lib/fusion.c)
     SET_TARGET_PROPERTIES(picotls-fusion PROPERTIES COMPILE_FLAGS "-mavx2 -maes -mpclmul")
     TARGET_LINK_LIBRARIES(picotls-fusion picotls-core)
@@ -151,13 +160,16 @@
         ADD_DEPENDENCIES(test-fusion.t generate-picotls-probes)
     ENDIF ()
     SET(TEST_EXES ${TEST_EXES} test-fusion.t)
-    
+
     LIST(APPEND PTLSBENCH_LIBS picotls-fusion)
 ENDIF ()
 
 ADD_EXECUTABLE(ptlsbench t/ptlsbench.c)
 SET_TARGET_PROPERTIES(ptlsbench PROPERTIES COMPILE_FLAGS "-DPTLS_MEMORY_DEBUG=1")
 TARGET_LINK_LIBRARIES(ptlsbench ${PTLSBENCH_LIBS})
+IF (NOT WITH_FUSION)
+    SET_TARGET_PROPERTIES(ptlsbench PROPERTIES EXCLUDE_FROM_ALL 1)
+ENDIF ()
 
 ADD_CUSTOM_TARGET(check env BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} prove --exec '' -v ${CMAKE_CURRENT_BINARY_DIR}/*.t t/*.t WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${TEST_EXES} cli)
 
diff --git a/README.md b/README.md
index d7c5dbc..c8e3ef8 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 picotls
 ===
 
-[![Build Status](https://travis-ci.org/h2o/picotls.svg?branch=master)](https://travis-ci.org/h2o/picotls)
+[![CI](https://github.com/h2o/picotls/actions/workflows/ci.yml/badge.svg)](https://github.com/h2o/picotls/actions/workflows/ci.yml)
 
 Picotls is a [TLS 1.3 (RFC 8446)](https://tools.ietf.org/html/rfc8446) protocol stack written in C, with the following features:
 * support for three crypto engines
diff --git a/deps/cifra/src/bitops.h b/deps/cifra/src/bitops.h
index f2ca308..a1c1e7d 100644
--- a/deps/cifra/src/bitops.h
+++ b/deps/cifra/src/bitops.h
@@ -55,19 +55,19 @@
 /** Read 4 bytes from buf, as a 32-bit big endian quantity. */
 static inline uint32_t read32_be(const uint8_t buf[4])
 {
-  return (buf[0] << 24) |
-         (buf[1] << 16) |
-         (buf[2] << 8) |
-         (buf[3]);
+  return ((uint32_t)buf[0] << 24) |
+         ((uint32_t)buf[1] << 16) |
+         ((uint32_t)buf[2] << 8) |
+         ((uint32_t)buf[3]);
 }
 
 /** Read 4 bytes from buf, as a 32-bit little endian quantity. */
 static inline uint32_t read32_le(const uint8_t buf[4])
 {
-  return (buf[3] << 24) |
-         (buf[2] << 16) |
-         (buf[1] << 8) |
-         (buf[0]);
+  return ((uint32_t)buf[3] << 24) |
+         ((uint32_t)buf[2] << 16) |
+         ((uint32_t)buf[1] << 8) |
+         ((uint32_t)buf[0]);
 }
 
 /** Read 8 bytes from buf, as a 64-bit big endian quantity. */
diff --git a/deps/cifra/src/curve25519.tweetnacl.c b/deps/cifra/src/curve25519.tweetnacl.c
index c98c107..f028f67 100644
--- a/deps/cifra/src/curve25519.tweetnacl.c
+++ b/deps/cifra/src/curve25519.tweetnacl.c
@@ -53,7 +53,7 @@
     o[i] += (1LL << 16);
     c = o[i] >> 16;
     o[(i + 1) * (i < 15)] += c - 1 + 37 * (c - 1) * (i == 15);
-    o[i] -= c << 16;
+    o[i] -= (int64_t)((uint64_t)c << 16);
   }
 }
 
@@ -78,7 +78,7 @@
   car25519(t);
   car25519(t);
   car25519(t);
-  
+
   for(j = 0; j < 2; j++)
   {
     m[0] = t[0] - 0xffed;
@@ -157,7 +157,7 @@
   int a;
   for (a = 0; a < 16; a++)
     c[a] = i[a];
-  
+
   for (a = 253; a >= 0; a--)
   {
     sqr(c, c);
@@ -182,7 +182,7 @@
     z[i] = n[i];
   z[31] = (n[31] & 127) | 64;
   z[0] &= 248;
-  
+
   unpack25519(x, p);
 
   for(i = 0; i < 16; i++)
diff --git a/deps/cifra/src/gf128.c b/deps/cifra/src/gf128.c
index f7ea834..d438d13 100644
--- a/deps/cifra/src/gf128.c
+++ b/deps/cifra/src/gf128.c
@@ -45,7 +45,7 @@
   inword = in[2];   out[2] = (inword << 1) | borrow;  borrow = inword >> 31;
   inword = in[1];   out[1] = (inword << 1) | borrow;  borrow = inword >> 31;
   inword = in[0];   out[0] = (inword << 1) | borrow;  borrow = inword >> 31;
-  
+
 #if CF_CACHE_SIDE_CHANNEL_PROTECTION
   out[3] ^= select_u8(borrow, table, 2);
 #else
@@ -66,9 +66,9 @@
   inword = in[3];   out[3] = (inword >> 1) | (borrow << 31);  borrow = inword & 1;
 
 #if CF_CACHE_SIDE_CHANNEL_PROTECTION
-  out[0] ^= select_u8(borrow, table, 2) << 24;
+  out[0] ^= (uint32_t)select_u8(borrow, table, 2) << 24;
 #else
-  out[0] ^= table[borrow] << 24;
+  out[0] ^= (uint32_t)table[borrow] << 24;
 #endif
 }
 
@@ -87,9 +87,9 @@
 #if CF_TIME_SIDE_CHANNEL_PROTECTION
   cf_gf128 zero = { 0 };
 #endif
- 
+
   /* Z_0 = 0^128
-   * V_0 = Y */ 
+   * V_0 = Y */
   cf_gf128 Z, V;
   memset(Z, 0, sizeof Z);
   memcpy(V, y, sizeof V);
diff --git a/include/picotls.h b/include/picotls.h
index ea5c15e..a25346a 100644
--- a/include/picotls.h
+++ b/include/picotls.h
@@ -168,6 +168,7 @@
 #define PTLS_ALERT_CERTIFICATE_UNKNOWN 46
 #define PTLS_ALERT_ILLEGAL_PARAMETER 47
 #define PTLS_ALERT_UNKNOWN_CA 48
+#define PTLS_ALERT_ACCESS_DENIED 49
 #define PTLS_ALERT_DECODE_ERROR 50
 #define PTLS_ALERT_DECRYPT_ERROR 51
 #define PTLS_ALERT_PROTOCOL_VERSION 70
@@ -946,6 +947,9 @@
 static uint8_t *ptls_encode_quicint(uint8_t *p, uint64_t v);
 #define PTLS_ENCODE_QUICINT_CAPACITY 8
 
+#define PTLS_QUICINT_MAX 4611686018427387903 // (1 << 62) - 1
+#define PTLS_QUICINT_LONGEST_STR "4611686018427387903"
+
 #define ptls_buffer_pushv(buf, src, len)                                                                                           \
     do {                                                                                                                           \
         if ((ret = ptls_buffer__do_pushv((buf), (src), (len))) != 0)                                                               \
diff --git a/lib/fusion.c b/lib/fusion.c
index d6562b4..e77e8ba 100644
--- a/lib/fusion.c
+++ b/lib/fusion.c
@@ -203,6 +203,13 @@
                                           0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
                                           0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; // latter 15 bytes map to zero
 
+#if defined(__clang__)
+#if __has_feature(address_sanitizer)
+__attribute__((no_sanitize("address")))
+#endif
+#elif __SANITIZE_ADDRESS__ /* gcc */
+__attribute__((no_sanitize_address))
+#endif
 static inline __m128i loadn(const void *p, size_t l)
 {
     __m128i v, mask = _mm_loadu_si128((__m128i *)(loadn_mask + 16 - l));
diff --git a/lib/openssl.c b/lib/openssl.c
index a1866b0..85327a2 100644
--- a/lib/openssl.c
+++ b/lib/openssl.c
@@ -1232,7 +1232,7 @@
 
     { /* setup verify params */
         X509_VERIFY_PARAM *params = X509_STORE_CTX_get0_param(verify_ctx);
-        X509_VERIFY_PARAM_set_purpose(params, is_server ? X509_PURPOSE_SSL_SERVER : X509_PURPOSE_SSL_CLIENT);
+        X509_VERIFY_PARAM_set_purpose(params, is_server ? X509_PURPOSE_SSL_CLIENT : X509_PURPOSE_SSL_SERVER);
         X509_VERIFY_PARAM_set_depth(params, 98); /* use the default of OpenSSL 1.0.2 and above; see `man SSL_CTX_set_verify` */
         /* when _acting_ as client, set the server name */
         if (!is_server) {
diff --git a/misc/docker-ci.mk b/misc/docker-ci.mk
new file mode 100644
index 0000000..4eb042a
--- /dev/null
+++ b/misc/docker-ci.mk
@@ -0,0 +1,24 @@
+CONTAINER_NAME=h2oserver/h2o-ci:ubuntu2004
+SRC_DIR=/picotls
+CI_MK=$(SRC_DIR)/misc/docker-ci.mk
+CMAKE_ARGS=
+CHECK_ENVS=
+DOCKER_RUN_OPTS=--privileged \
+	-v `pwd`:$(SRC_DIR) \
+	-it
+
+ALL:
+	docker run $(DOCKER_RUN_OPTS) $(CONTAINER_NAME) make -f $(CI_MK) _check CMAKE_ARGS='$(CMAKE_ARGS)' CHECK_ENVS='$(CHECK_ENVS)'
+
+_check:
+	uname -a
+	mkdir -p build
+	sudo mount -t tmpfs tmpfs build -o size=3G
+	sudo chown -R ci:ci build
+	sudo chmod 0755 build
+	$(MAKE) -f $(CI_MK) -C build _do-check CMAKE_ARGS='$(CMAKE_ARGS)' CHECK_ENVS='$(CHECK_ENVS)'
+
+_do-check:
+	cmake $(CMAKE_ARGS) "-H$(SRC_DIR)" -B.
+	$(MAKE) all VERBOSE=1
+	env $(CHECK_ENVS) $(MAKE) check
diff --git a/t/e2e.t b/t/e2e.t
index ada3109..bb92c6d 100755
--- a/t/e2e.t
+++ b/t/e2e.t
@@ -1,4 +1,4 @@
-#! /usr/bin/perl
+#! /usr/bin/env perl
 
 use strict;
 use warnings;
diff --git a/t/fusion.c b/t/fusion.c
index f9c61bb..4c79153 100644
--- a/t/fusion.c
+++ b/t/fusion.c
@@ -338,4 +338,4 @@
     subtest("generated-256-iv96", test_generated_aes256_iv96);
 
     return done_testing();
-}
\ No newline at end of file
+}
diff --git a/t/openssl.c b/t/openssl.c
index ff47eee..5669b81 100644
--- a/t/openssl.c
+++ b/t/openssl.c
@@ -25,9 +25,13 @@
 #include <assert.h>
 #include <stdio.h>
 #include <string.h>
+#include <openssl/opensslv.h>
 #include <openssl/bio.h>
 #include <openssl/pem.h>
 #include <openssl/engine.h>
+#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/provider.h>
+#endif
 #include "picotls.h"
 #include "picotls/minicrypto.h"
 #include "../deps/picotest/picotest.h"
@@ -65,23 +69,24 @@
 
 #define RSA_CERTIFICATE                                                                                                            \
     "-----BEGIN CERTIFICATE-----\n"                                                                                                \
-    "MIIDKzCCAhOgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9waWNv\n"                                                           \
-    "dGxzIHRlc3QgY2EwHhcNMTgwMjIzMDIzODEyWhcNMjgwMjIxMDIzODEyWjAbMRkw\n"                                                           \
+    "MIIDQjCCAiqgAwIBAgIBBTANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDEw9waWNv\n"                                                           \
+    "dGxzIHRlc3QgY2EwHhcNMjExMjEzMDY1MzQwWhcNMzExMjExMDY1MzQwWjAbMRkw\n"                                                           \
     "FwYDVQQDExB0ZXN0LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n"                                                           \
     "MIIBCgKCAQEA5soWzSG7iyawQlHM1yaX2dUAATUkhpbg2WPFOEem7E3zYzc6A/Z+\n"                                                           \
     "bViFlfEgL37cbDUb4pnOAHrrsjGgkyBYh5i9iCTVfCk+H6SOHZJORO1Tq8X9C7Wc\n"                                                           \
     "NcshpSdm2Pa8hmv9hsHbLSeoPNeg8NkTPwMVaMZ2GpdmiyAmhzSZ2H9mzNI7ntPW\n"                                                           \
     "/XCchVf+ax2yt9haZ+mQE2NPYwHDjqCtdGkP5ZXXnYhJSBzSEhxfGckIiKDyOxiN\n"                                                           \
     "kLFLvUdT4ERSFBjauP2cSI0XoOUsiBxJNwHH310AU8jZbveSTcXGYgEuu2MIuDo7\n"                                                           \
-    "Vhkq5+TCqXsIFNbjy0taOoPRvUbPsbqFlQIDAQABo3sweTAJBgNVHRMEAjAAMCwG\n"                                                           \
-    "CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNV\n"                                                           \
-    "HQ4EFgQUE1vXDjBT8j2etP4brfHQ9DeKnpgwHwYDVR0jBBgwFoAUv3nKl7JgeCCW\n"                                                           \
-    "qkZXnN+nsiP1JWMwDQYJKoZIhvcNAQELBQADggEBAKwARsxOCiGPXU1xhvs+pq9I\n"                                                           \
-    "63mLi4rfnssOGzGnnAfuEaxggpozf3fOSgfyTaDbACdRPTZEStjQ5HMCcHvY7CH0\n"                                                           \
-    "8EYA+lkmFbuXXL8uHby1JBTzbTGf8pkRUsuF/Ie0SLChoDgt8oF3mY5pyU4HUaAw\n"                                                           \
-    "Zp6HBpIRMdmbwGcwm25bl9MQYTrTX3dBfp3XPzfXbVwjJ7bsiTwAGq+dKwzwOQeM\n"                                                           \
-    "2ZMZt4BQBoevsNopPrqG0S6kGUmJOIax0t13bKwDj21+Hp/O90HTFVCtAaDxRC56\n"                                                           \
-    "k0O8Q62ZxzjGJ7Zw6K3azXlH/BYE+CajxTUF+FKRRkkWL1GrFVUsYd9KLDAVry0=\n"                                                           \
+    "Vhkq5+TCqXsIFNbjy0taOoPRvUbPsbqFlQIDAQABo4GRMIGOMAkGA1UdEwQCMAAw\n"                                                           \
+    "LAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0G\n"                                                           \
+    "A1UdDgQWBBQTW9cOMFPyPZ60/hut8dD0N4qemDAfBgNVHSMEGDAWgBS/ecqXsmB4\n"                                                           \
+    "IJaqRlec36eyI/UlYzATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0BAQsF\n"                                                           \
+    "AAOCAQEAYTglgIYqxhbmErQar8yFmRRJp93Zul+PnCuq1nkGPokJoytszoQtGBfw\n"                                                           \
+    "ftgcMyTH3TOR22XThQafi/qWj3gz//oicZ09AuDfk/GMweWPjPGSs2lNUCbC9FqW\n"                                                           \
+    "75JpYWsKqk8s0GwetZ710rX/65wJQAb4EcibMdWq98C/HUwQspXiXBXkEMDbMF5Q\n"                                                           \
+    "s41vyeASk03jff+ofvTZl33sPurltO2oyRtDfUKWFAMBS7Bk/h/d3ZIwmv7DjXVw\n"                                                           \
+    "ZKjxMZbXSmlgdngzBCBYZb5p+VkGXHqVjd07KhZd4nn5sqLy2i1COWB4OCb0xUHr\n"                                                           \
+    "QxHvmJiqQ57FTFDypV0sKZRLuY9ovQ==\n"                                                                                           \
     "-----END CERTIFICATE-----\n"
 
 static void test_bf(void)
@@ -299,6 +304,12 @@
     ENGINE_register_all_digests();
 #endif
 
+#if !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x30000000L
+    /* Explicitly load the legacy provider in addition to default, as we test Blowfish in one of the tests. */
+    OSSL_PROVIDER *legacy = OSSL_PROVIDER_load(NULL, "legacy");
+    OSSL_PROVIDER *dflt = OSSL_PROVIDER_load(NULL, "default");
+#endif
+
     subtest("bf", test_bf);
 
     subtest("key-exchange", test_key_exchanges);