Commit 6f73fe1c68 for openssl.org

commit 6f73fe1c688dc3e4c3815e8f33e5b672abeb28d3
Author: Tomas Mraz <tomas@openssl.org>
Date:   Thu Dec 18 17:07:44 2025 +0100

    Remove BIO_f_reliable() as it is broken

    It was broken since the OpenSSL 3.0 release and
    nobody complained. Apparently nobody is using it.
    It would be practically impossible to reimplement
    it with the provided EVP_MDs in backwards-compatible
    manner.

    Fixes #29413

    Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
    Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
    Reviewed-by: Neil Horman <nhorman@openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/29445)

diff --git a/CHANGES.md b/CHANGES.md
index 0e5a3c813f..3bf218a50a 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -101,6 +101,11 @@ OpenSSL 4.0

    *Milan Broz*, *Neil Horman*, *Norbert Pocs*

+ * BIO_f_reliable() implementation was removed without replacement.
+   It was broken since 3.0 release without any complaints.
+
+   *Tomáš Mráz*
+
  * Added SNMP KDF (EVP_KDF_SNMPKDF) to EVP_KDF

    *Barry Fussell and Helen Zhang*
diff --git a/crypto/evp/bio_ok.c b/crypto/evp/bio_ok.c
deleted file mode 100644
index 9b48c3c745..0000000000
--- a/crypto/evp/bio_ok.c
+++ /dev/null
@@ -1,606 +0,0 @@
-/*
- * Copyright 1995-2025 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
- */
-
-/*-
-        From: Arne Ansper
-
-        Why BIO_f_reliable?
-
-        I wrote function which took BIO* as argument, read data from it
-        and processed it. Then I wanted to store the input file in
-        encrypted form. OK I pushed BIO_f_cipher to the BIO stack
-        and everything was OK. BUT if user types wrong password
-        BIO_f_cipher outputs only garbage and my function crashes. Yes
-        I can and I should fix my function, but BIO_f_cipher is
-        easy way to add encryption support to many existing applications
-        and it's hard to debug and fix them all.
-
-        So I wanted another BIO which would catch the incorrect passwords and
-        file damages which cause garbage on BIO_f_cipher's output.
-
-        The easy way is to push the BIO_f_md and save the checksum at
-        the end of the file. However there are several problems with this
-        approach:
-
-        1) you must somehow separate checksum from actual data.
-        2) you need lot's of memory when reading the file, because you
-        must read to the end of the file and verify the checksum before
-        letting the application to read the data.
-
-        BIO_f_reliable tries to solve both problems, so that you can
-        read and write arbitrary long streams using only fixed amount
-        of memory.
-
-        BIO_f_reliable splits data stream into blocks. Each block is prefixed
-        with its length and suffixed with its digest. So you need only
-        several Kbytes of memory to buffer single block before verifying
-        its digest.
-
-        BIO_f_reliable goes further and adds several important capabilities:
-
-        1) the digest of the block is computed over the whole stream
-        -- so nobody can rearrange the blocks or remove or replace them.
-
-        2) to detect invalid passwords right at the start BIO_f_reliable
-        adds special prefix to the stream. In order to avoid known plain-text
-        attacks this prefix is generated as follows:
-
-                *) digest is initialized with random seed instead of
-                standardized one.
-                *) same seed is written to output
-                *) well-known text is then hashed and the output
-                of the digest is also written to output.
-
-        reader can now read the seed from stream, hash the same string
-        and then compare the digest output.
-
-        Bad things: BIO_f_reliable knows what's going on in EVP_Digest. I
-        initially wrote and tested this code on x86 machine and wrote the
-        digests out in machine-dependent order :( There are people using
-        this code and I cannot change this easily without making existing
-        data files unreadable.
-
-*/
-
-#include <stdio.h>
-#include <errno.h>
-#include <assert.h>
-#include "internal/cryptlib.h"
-#include <openssl/buffer.h>
-#include "internal/bio.h"
-#include <openssl/evp.h>
-#include <openssl/rand.h>
-#include "internal/endian.h"
-#include "internal/numbers.h" /* includes SIZE_MAX */
-#include "crypto/evp.h"
-
-static int ok_write(BIO *h, const char *buf, int num);
-static int ok_read(BIO *h, char *buf, int size);
-static long ok_ctrl(BIO *h, int cmd, long arg1, void *arg2);
-static int ok_new(BIO *h);
-static int ok_free(BIO *data);
-static long ok_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp);
-
-static __owur int sig_out(BIO *b);
-static __owur int sig_in(BIO *b);
-static __owur int block_out(BIO *b);
-static __owur int block_in(BIO *b);
-#define OK_BLOCK_SIZE (1024 * 4)
-#define OK_BLOCK_BLOCK 4
-#define IOBS (OK_BLOCK_SIZE + OK_BLOCK_BLOCK + 3 * EVP_MAX_MD_SIZE)
-#define WELLKNOWN "The quick brown fox jumped over the lazy dog's back."
-
-typedef struct ok_struct {
-    size_t buf_len;
-    size_t buf_off;
-    size_t buf_len_save;
-    size_t buf_off_save;
-    int cont; /* <= 0 when finished */
-    int finished;
-    EVP_MD_CTX *md;
-    int blockout; /* output block is ready */
-    int sigio; /* must process signature */
-    unsigned char buf[IOBS];
-} BIO_OK_CTX;
-
-static const BIO_METHOD methods_ok = {
-    BIO_TYPE_CIPHER,
-    "reliable",
-    bwrite_conv,
-    ok_write,
-    bread_conv,
-    ok_read,
-    NULL, /* ok_puts, */
-    NULL, /* ok_gets, */
-    ok_ctrl,
-    ok_new,
-    ok_free,
-    ok_callback_ctrl,
-};
-
-const BIO_METHOD *BIO_f_reliable(void)
-{
-    return &methods_ok;
-}
-
-static int ok_new(BIO *bi)
-{
-    BIO_OK_CTX *ctx;
-
-    if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL)
-        return 0;
-
-    ctx->cont = 1;
-    ctx->sigio = 1;
-    ctx->md = EVP_MD_CTX_new();
-    if (ctx->md == NULL) {
-        OPENSSL_free(ctx);
-        return 0;
-    }
-    BIO_set_init(bi, 0);
-    BIO_set_data(bi, ctx);
-
-    return 1;
-}
-
-static int ok_free(BIO *a)
-{
-    BIO_OK_CTX *ctx;
-
-    if (a == NULL)
-        return 0;
-
-    ctx = BIO_get_data(a);
-
-    EVP_MD_CTX_free(ctx->md);
-    OPENSSL_clear_free(ctx, sizeof(BIO_OK_CTX));
-    BIO_set_data(a, NULL);
-    BIO_set_init(a, 0);
-
-    return 1;
-}
-
-static int ok_read(BIO *b, char *out, int outl)
-{
-    int ret = 0, i, n;
-    BIO_OK_CTX *ctx;
-    BIO *next;
-
-    if (out == NULL)
-        return 0;
-
-    ctx = BIO_get_data(b);
-    next = BIO_next(b);
-
-    if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
-        return 0;
-
-    while (outl > 0) {
-
-        /* copy clean bytes to output buffer */
-        if (ctx->blockout) {
-            i = (int)(ctx->buf_len - ctx->buf_off);
-            if (i > outl)
-                i = outl;
-            memcpy(out, &(ctx->buf[ctx->buf_off]), i);
-            ret += i;
-            out += i;
-            outl -= i;
-            ctx->buf_off += i;
-
-            /* all clean bytes are out */
-            if (ctx->buf_len == ctx->buf_off) {
-                ctx->buf_off = 0;
-
-                /*
-                 * copy start of the next block into proper place
-                 */
-                if (ctx->buf_len_save > ctx->buf_off_save) {
-                    ctx->buf_len = ctx->buf_len_save - ctx->buf_off_save;
-                    memmove(ctx->buf, &(ctx->buf[ctx->buf_off_save]),
-                        ctx->buf_len);
-                } else {
-                    ctx->buf_len = 0;
-                }
-                ctx->blockout = 0;
-            }
-        }
-
-        /* output buffer full -- cancel */
-        if (outl == 0)
-            break;
-
-        /* no clean bytes in buffer -- fill it */
-        n = (int)(IOBS - ctx->buf_len);
-        i = BIO_read(next, &(ctx->buf[ctx->buf_len]), n);
-
-        if (i <= 0)
-            break; /* nothing new */
-
-        ctx->buf_len += i;
-
-        /* no signature yet -- check if we got one */
-        if (ctx->sigio == 1) {
-            if (!sig_in(b)) {
-                BIO_clear_retry_flags(b);
-                return 0;
-            }
-        }
-
-        /* signature ok -- check if we got block */
-        if (ctx->sigio == 0) {
-            if (!block_in(b)) {
-                BIO_clear_retry_flags(b);
-                return 0;
-            }
-        }
-
-        /* invalid block -- cancel */
-        if (ctx->cont <= 0)
-            break;
-    }
-
-    BIO_clear_retry_flags(b);
-    BIO_copy_next_retry(b);
-    return ret;
-}
-
-static int ok_write(BIO *b, const char *in, int inl)
-{
-    int ret = 0, n, i;
-    BIO_OK_CTX *ctx;
-    BIO *next;
-
-    if (inl <= 0)
-        return inl;
-
-    ctx = BIO_get_data(b);
-    next = BIO_next(b);
-    ret = inl;
-
-    if ((ctx == NULL) || (next == NULL) || (BIO_get_init(b) == 0))
-        return 0;
-
-    if (ctx->sigio && !sig_out(b))
-        return 0;
-
-    do {
-        BIO_clear_retry_flags(b);
-        n = (int)(ctx->buf_len - ctx->buf_off);
-        while (ctx->blockout && n > 0) {
-            i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n);
-            if (i <= 0) {
-                BIO_copy_next_retry(b);
-                if (!BIO_should_retry(b))
-                    ctx->cont = 0;
-                return i;
-            }
-            ctx->buf_off += i;
-            n -= i;
-        }
-
-        /* at this point all pending data has been written */
-        ctx->blockout = 0;
-        if (ctx->buf_len == ctx->buf_off) {
-            ctx->buf_len = OK_BLOCK_BLOCK;
-            ctx->buf_off = 0;
-        }
-
-        if ((in == NULL) || (inl <= 0))
-            return 0;
-
-        n = (inl + ctx->buf_len > OK_BLOCK_SIZE + OK_BLOCK_BLOCK) ? (int)(OK_BLOCK_SIZE + OK_BLOCK_BLOCK - ctx->buf_len) : inl;
-
-        memcpy(&ctx->buf[ctx->buf_len], in, n);
-        ctx->buf_len += n;
-        inl -= n;
-        in += n;
-
-        if (ctx->buf_len >= OK_BLOCK_SIZE + OK_BLOCK_BLOCK) {
-            if (!block_out(b)) {
-                BIO_clear_retry_flags(b);
-                return 0;
-            }
-        }
-    } while (inl > 0);
-
-    BIO_clear_retry_flags(b);
-    BIO_copy_next_retry(b);
-    return ret;
-}
-
-static long ok_ctrl(BIO *b, int cmd, long num, void *ptr)
-{
-    BIO_OK_CTX *ctx;
-    EVP_MD *md;
-    const EVP_MD **ppmd;
-    long ret = 1;
-    int i;
-    BIO *next;
-
-    ctx = BIO_get_data(b);
-    next = BIO_next(b);
-
-    switch (cmd) {
-    case BIO_CTRL_RESET:
-        ctx->buf_len = 0;
-        ctx->buf_off = 0;
-        ctx->buf_len_save = 0;
-        ctx->buf_off_save = 0;
-        ctx->cont = 1;
-        ctx->finished = 0;
-        ctx->blockout = 0;
-        ctx->sigio = 1;
-        ret = BIO_ctrl(next, cmd, num, ptr);
-        break;
-    case BIO_CTRL_EOF: /* More to read */
-        if (ctx->cont <= 0)
-            ret = 1;
-        else
-            ret = BIO_ctrl(next, cmd, num, ptr);
-        break;
-    case BIO_CTRL_PENDING: /* More to read in buffer */
-    case BIO_CTRL_WPENDING: /* More to read in buffer */
-        ret = ctx->blockout ? (long)(ctx->buf_len - ctx->buf_off) : 0;
-        if (ret <= 0)
-            ret = BIO_ctrl(next, cmd, num, ptr);
-        break;
-    case BIO_CTRL_FLUSH:
-        /* do a final write */
-        if (ctx->blockout == 0)
-            if (!block_out(b))
-                return 0;
-
-        while (ctx->blockout) {
-            i = ok_write(b, NULL, 0);
-            if (i < 0) {
-                ret = i;
-                break;
-            }
-        }
-
-        ctx->finished = 1;
-        ctx->buf_off = ctx->buf_len = 0;
-        ctx->cont = (int)ret;
-
-        /* Finally flush the underlying BIO */
-        ret = BIO_ctrl(next, cmd, num, ptr);
-        BIO_copy_next_retry(b);
-        break;
-    case BIO_C_DO_STATE_MACHINE:
-        BIO_clear_retry_flags(b);
-        ret = BIO_ctrl(next, cmd, num, ptr);
-        BIO_copy_next_retry(b);
-        break;
-    case BIO_CTRL_INFO:
-        ret = (long)ctx->cont;
-        break;
-    case BIO_C_SET_MD:
-        md = ptr;
-        if (!EVP_DigestInit_ex(ctx->md, md, NULL))
-            return 0;
-        BIO_set_init(b, 1);
-        break;
-    case BIO_C_GET_MD:
-        if (BIO_get_init(b)) {
-            ppmd = ptr;
-            *ppmd = EVP_MD_CTX_get0_md(ctx->md);
-        } else
-            ret = 0;
-        break;
-    default:
-        ret = BIO_ctrl(next, cmd, num, ptr);
-        break;
-    }
-    return ret;
-}
-
-static long ok_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp)
-{
-    BIO *next;
-
-    next = BIO_next(b);
-
-    if (next == NULL)
-        return 0;
-
-    return BIO_callback_ctrl(next, cmd, fp);
-}
-
-static void longswap(void *_ptr, size_t len)
-{
-    DECLARE_IS_ENDIAN;
-
-    if (IS_LITTLE_ENDIAN) {
-        size_t i;
-        unsigned char *p = _ptr, c;
-
-        for (i = 0; i < len; i += 4) {
-            c = p[0], p[0] = p[3], p[3] = c;
-            c = p[1], p[1] = p[2], p[2] = c;
-        }
-    }
-}
-
-static int sig_out(BIO *b)
-{
-    BIO_OK_CTX *ctx;
-    EVP_MD_CTX *md;
-    const EVP_MD *digest;
-    int md_size;
-    void *md_data;
-
-    ctx = BIO_get_data(b);
-    md = ctx->md;
-    digest = EVP_MD_CTX_get0_md(md);
-    md_size = EVP_MD_get_size(digest);
-    md_data = EVP_MD_CTX_get0_md_data(md);
-
-    if (md_size <= 0)
-        goto berr;
-    if (ctx->buf_len + 2 * md_size > OK_BLOCK_SIZE)
-        return 1;
-
-    if (!EVP_DigestInit_ex(md, digest, NULL))
-        goto berr;
-    /*
-     * FIXME: there's absolutely no guarantee this makes any sense at all,
-     * particularly now EVP_MD_CTX has been restructured.
-     */
-    if (RAND_bytes(md_data, md_size) <= 0)
-        goto berr;
-    memcpy(&(ctx->buf[ctx->buf_len]), md_data, md_size);
-    longswap(&(ctx->buf[ctx->buf_len]), md_size);
-    ctx->buf_len += md_size;
-
-    if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
-        goto berr;
-    if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
-        goto berr;
-    ctx->buf_len += md_size;
-    ctx->blockout = 1;
-    ctx->sigio = 0;
-    return 1;
-berr:
-    BIO_clear_retry_flags(b);
-    return 0;
-}
-
-static int sig_in(BIO *b)
-{
-    BIO_OK_CTX *ctx;
-    EVP_MD_CTX *md;
-    unsigned char tmp[EVP_MAX_MD_SIZE];
-    int ret = 0;
-    const EVP_MD *digest;
-    int md_size;
-    void *md_data;
-
-    ctx = BIO_get_data(b);
-    if ((md = ctx->md) == NULL)
-        goto berr;
-    digest = EVP_MD_CTX_get0_md(md);
-    if ((md_size = EVP_MD_get_size(digest)) <= 0)
-        goto berr;
-    md_data = EVP_MD_CTX_get0_md_data(md);
-
-    if ((int)(ctx->buf_len - ctx->buf_off) < 2 * md_size)
-        return 1;
-
-    if (!EVP_DigestInit_ex(md, digest, NULL))
-        goto berr;
-    memcpy(md_data, &(ctx->buf[ctx->buf_off]), md_size);
-    longswap(md_data, md_size);
-    ctx->buf_off += md_size;
-
-    if (!EVP_DigestUpdate(md, WELLKNOWN, strlen(WELLKNOWN)))
-        goto berr;
-    if (!EVP_DigestFinal_ex(md, tmp, NULL))
-        goto berr;
-    ret = memcmp(&(ctx->buf[ctx->buf_off]), tmp, md_size) == 0;
-    ctx->buf_off += md_size;
-    if (ret == 1) {
-        ctx->sigio = 0;
-        if (ctx->buf_len != ctx->buf_off) {
-            memmove(ctx->buf, &(ctx->buf[ctx->buf_off]),
-                ctx->buf_len - ctx->buf_off);
-        }
-        ctx->buf_len -= ctx->buf_off;
-        ctx->buf_off = 0;
-    } else {
-        ctx->cont = 0;
-    }
-    return 1;
-berr:
-    BIO_clear_retry_flags(b);
-    return 0;
-}
-
-static int block_out(BIO *b)
-{
-    BIO_OK_CTX *ctx;
-    EVP_MD_CTX *md;
-    unsigned long tl;
-    const EVP_MD *digest;
-    int md_size;
-
-    ctx = BIO_get_data(b);
-    md = ctx->md;
-    digest = EVP_MD_CTX_get0_md(md);
-    md_size = EVP_MD_get_size(digest);
-    if (md_size <= 0)
-        goto berr;
-
-    tl = (unsigned long)(ctx->buf_len - OK_BLOCK_BLOCK);
-    ctx->buf[0] = (unsigned char)(tl >> 24);
-    ctx->buf[1] = (unsigned char)(tl >> 16);
-    ctx->buf[2] = (unsigned char)(tl >> 8);
-    ctx->buf[3] = (unsigned char)(tl);
-    if (!EVP_DigestUpdate(md,
-            (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
-        goto berr;
-    if (!EVP_DigestFinal_ex(md, &(ctx->buf[ctx->buf_len]), NULL))
-        goto berr;
-    ctx->buf_len += md_size;
-    ctx->blockout = 1;
-    return 1;
-berr:
-    BIO_clear_retry_flags(b);
-    return 0;
-}
-
-static int block_in(BIO *b)
-{
-    BIO_OK_CTX *ctx;
-    EVP_MD_CTX *md;
-    size_t tl = 0;
-    unsigned char tmp[EVP_MAX_MD_SIZE];
-    int md_size;
-
-    ctx = BIO_get_data(b);
-    md = ctx->md;
-    md_size = EVP_MD_get_size(EVP_MD_CTX_get0_md(md));
-    if (md_size <= 0)
-        goto berr;
-
-    assert(sizeof(tl) >= OK_BLOCK_BLOCK); /* always true */
-    tl = ((size_t)ctx->buf[0] << 24)
-        | ((size_t)ctx->buf[1] << 16)
-        | ((size_t)ctx->buf[2] << 8)
-        | ((size_t)ctx->buf[3]);
-
-    if (tl > OK_BLOCK_SIZE)
-        goto berr;
-
-    if (tl > SIZE_MAX - OK_BLOCK_BLOCK - (size_t)md_size)
-        goto berr;
-
-    if (ctx->buf_len < tl + OK_BLOCK_BLOCK + (size_t)md_size)
-        return 1;
-
-    if (!EVP_DigestUpdate(md,
-            (unsigned char *)&(ctx->buf[OK_BLOCK_BLOCK]), tl))
-        goto berr;
-    if (!EVP_DigestFinal_ex(md, tmp, NULL))
-        goto berr;
-    if (memcmp(&(ctx->buf[tl + OK_BLOCK_BLOCK]), tmp, (size_t)md_size) == 0) {
-        /* there might be parts from next block lurking around ! */
-        ctx->buf_off_save = tl + OK_BLOCK_BLOCK + md_size;
-        ctx->buf_len_save = ctx->buf_len;
-        ctx->buf_off = OK_BLOCK_BLOCK;
-        ctx->buf_len = tl + OK_BLOCK_BLOCK;
-        ctx->blockout = 1;
-    } else {
-        ctx->cont = 0;
-    }
-    return 1;
-berr:
-    BIO_clear_retry_flags(b);
-    return 0;
-}
diff --git a/crypto/evp/build.info b/crypto/evp/build.info
index 1cbf6e8920..45945afcab 100644
--- a/crypto/evp/build.info
+++ b/crypto/evp/build.info
@@ -13,7 +13,7 @@ SOURCE[../../libcrypto]=$COMMON\
         e_xcbc_d.c e_rc2.c e_cast.c e_rc5.c m_null.c \
         p_seal.c p_sign.c p_verify.c p_legacy.c \
         bio_md.c bio_b64.c bio_enc.c evp_err.c e_null.c \
-        c_allc.c c_alld.c bio_ok.c \
+        c_allc.c c_alld.c \
         evp_pkey.c evp_pbe.c p5_crpt.c p5_crpt2.c pbe_scrypt.c \
         e_aes_cbc_hmac_sha1.c e_aes_cbc_hmac_sha256.c e_rc4_hmac_md5.c \
         e_chacha20_poly1305.c \
diff --git a/doc/man7/ossl-removed-api.pod b/doc/man7/ossl-removed-api.pod
index d086b68011..3189bdfeec 100644
--- a/doc/man7/ossl-removed-api.pod
+++ b/doc/man7/ossl-removed-api.pod
@@ -93,6 +93,7 @@ EVP_PKEY_meth_get_check,
 EVP_PKEY_meth_get_public_check,
 EVP_PKEY_meth_get_param_check,
 EVP_PKEY_meth_get_digest_custom,
+BIO_f_reliable,
 ossl-removed-api - API that has been removed from OpenSSL

 =head1 SYNOPSIS
@@ -304,6 +305,8 @@ This includes consulting the L<ossl-guide-migration(7)> documentation.

 =item EVP_PKEY_meth_get_digest_custom (Deprecated in 3.0.0) - consult L<ossl-guide-migration(7)>

+=item BIO_f_reliable (Broken since 3.0.0) - removed without replacement
+
 =back

 =head1 SEE ALSO
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index b00c2044c0..d2a5736ad2 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -848,7 +848,6 @@ int EVP_CIPHER_CTX_get_algor(EVP_CIPHER_CTX *ctx, X509_ALGOR **alg);
 const BIO_METHOD *BIO_f_md(void);
 const BIO_METHOD *BIO_f_base64(void);
 const BIO_METHOD *BIO_f_cipher(void);
-const BIO_METHOD *BIO_f_reliable(void);
 __owur int BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k,
     const unsigned char *i, int enc);

diff --git a/util/libcrypto.num b/util/libcrypto.num
index c1b1367028..78d5fa5114 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -1001,7 +1001,6 @@ EVP_CIPHER_CTX_get_algor                ?	4_0_0	EXIST::FUNCTION:
 BIO_f_md                                ?	4_0_0	EXIST::FUNCTION:
 BIO_f_base64                            ?	4_0_0	EXIST::FUNCTION:
 BIO_f_cipher                            ?	4_0_0	EXIST::FUNCTION:
-BIO_f_reliable                          ?	4_0_0	EXIST::FUNCTION:
 BIO_set_cipher                          ?	4_0_0	EXIST::FUNCTION:
 EVP_md_null                             ?	4_0_0	EXIST::FUNCTION:
 EVP_md2                                 ?	4_0_0	EXIST::FUNCTION:MD2
diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt
index 7c997abb56..49765d4f7e 100644
--- a/util/missingcrypto.txt
+++ b/util/missingcrypto.txt
@@ -186,7 +186,6 @@ BIO_dup_chain(3)
 BIO_f_asn1(3)
 BIO_f_linebuffer(3)
 BIO_f_nbio_test(3)
-BIO_f_reliable(3)
 BIO_fd_non_fatal_error(3)
 BIO_fd_should_retry(3)
 BIO_get_accept_socket(3)