1e1051a39Sopenharmony_ci/* 2e1051a39Sopenharmony_ci * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. 3e1051a39Sopenharmony_ci * 4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License"). You may not use 5e1051a39Sopenharmony_ci * this file except in compliance with the License. You can obtain a copy 6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at 7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html 8e1051a39Sopenharmony_ci */ 9e1051a39Sopenharmony_ci 10e1051a39Sopenharmony_ci#define OPENSSL_SUPPRESS_DEPRECATED /* for BIO_get_callback */ 11e1051a39Sopenharmony_ci 12e1051a39Sopenharmony_ci#include <stdio.h> 13e1051a39Sopenharmony_ci#include <errno.h> 14e1051a39Sopenharmony_ci#include "internal/cryptlib.h" 15e1051a39Sopenharmony_ci#include <openssl/buffer.h> 16e1051a39Sopenharmony_ci#include <openssl/evp.h> 17e1051a39Sopenharmony_ci#include "internal/bio.h" 18e1051a39Sopenharmony_ci 19e1051a39Sopenharmony_cistatic int enc_write(BIO *h, const char *buf, int num); 20e1051a39Sopenharmony_cistatic int enc_read(BIO *h, char *buf, int size); 21e1051a39Sopenharmony_cistatic long enc_ctrl(BIO *h, int cmd, long arg1, void *arg2); 22e1051a39Sopenharmony_cistatic int enc_new(BIO *h); 23e1051a39Sopenharmony_cistatic int enc_free(BIO *data); 24e1051a39Sopenharmony_cistatic long enc_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fps); 25e1051a39Sopenharmony_ci#define ENC_BLOCK_SIZE (1024*4) 26e1051a39Sopenharmony_ci#define ENC_MIN_CHUNK (256) 27e1051a39Sopenharmony_ci#define BUF_OFFSET (ENC_MIN_CHUNK + EVP_MAX_BLOCK_LENGTH) 28e1051a39Sopenharmony_ci 29e1051a39Sopenharmony_citypedef struct enc_struct { 30e1051a39Sopenharmony_ci int buf_len; 31e1051a39Sopenharmony_ci int buf_off; 32e1051a39Sopenharmony_ci int cont; /* <= 0 when finished */ 33e1051a39Sopenharmony_ci int finished; 34e1051a39Sopenharmony_ci int ok; /* bad decrypt */ 35e1051a39Sopenharmony_ci EVP_CIPHER_CTX *cipher; 36e1051a39Sopenharmony_ci unsigned char *read_start, *read_end; 37e1051a39Sopenharmony_ci /* 38e1051a39Sopenharmony_ci * buf is larger than ENC_BLOCK_SIZE because EVP_DecryptUpdate can return 39e1051a39Sopenharmony_ci * up to a block more data than is presented to it 40e1051a39Sopenharmony_ci */ 41e1051a39Sopenharmony_ci unsigned char buf[BUF_OFFSET + ENC_BLOCK_SIZE]; 42e1051a39Sopenharmony_ci} BIO_ENC_CTX; 43e1051a39Sopenharmony_ci 44e1051a39Sopenharmony_cistatic const BIO_METHOD methods_enc = { 45e1051a39Sopenharmony_ci BIO_TYPE_CIPHER, 46e1051a39Sopenharmony_ci "cipher", 47e1051a39Sopenharmony_ci bwrite_conv, 48e1051a39Sopenharmony_ci enc_write, 49e1051a39Sopenharmony_ci bread_conv, 50e1051a39Sopenharmony_ci enc_read, 51e1051a39Sopenharmony_ci NULL, /* enc_puts, */ 52e1051a39Sopenharmony_ci NULL, /* enc_gets, */ 53e1051a39Sopenharmony_ci enc_ctrl, 54e1051a39Sopenharmony_ci enc_new, 55e1051a39Sopenharmony_ci enc_free, 56e1051a39Sopenharmony_ci enc_callback_ctrl, 57e1051a39Sopenharmony_ci}; 58e1051a39Sopenharmony_ci 59e1051a39Sopenharmony_ciconst BIO_METHOD *BIO_f_cipher(void) 60e1051a39Sopenharmony_ci{ 61e1051a39Sopenharmony_ci return &methods_enc; 62e1051a39Sopenharmony_ci} 63e1051a39Sopenharmony_ci 64e1051a39Sopenharmony_cistatic int enc_new(BIO *bi) 65e1051a39Sopenharmony_ci{ 66e1051a39Sopenharmony_ci BIO_ENC_CTX *ctx; 67e1051a39Sopenharmony_ci 68e1051a39Sopenharmony_ci if ((ctx = OPENSSL_zalloc(sizeof(*ctx))) == NULL) { 69e1051a39Sopenharmony_ci ERR_raise(ERR_LIB_EVP, ERR_R_MALLOC_FAILURE); 70e1051a39Sopenharmony_ci return 0; 71e1051a39Sopenharmony_ci } 72e1051a39Sopenharmony_ci 73e1051a39Sopenharmony_ci ctx->cipher = EVP_CIPHER_CTX_new(); 74e1051a39Sopenharmony_ci if (ctx->cipher == NULL) { 75e1051a39Sopenharmony_ci OPENSSL_free(ctx); 76e1051a39Sopenharmony_ci return 0; 77e1051a39Sopenharmony_ci } 78e1051a39Sopenharmony_ci ctx->cont = 1; 79e1051a39Sopenharmony_ci ctx->ok = 1; 80e1051a39Sopenharmony_ci ctx->read_end = ctx->read_start = &(ctx->buf[BUF_OFFSET]); 81e1051a39Sopenharmony_ci BIO_set_data(bi, ctx); 82e1051a39Sopenharmony_ci BIO_set_init(bi, 1); 83e1051a39Sopenharmony_ci 84e1051a39Sopenharmony_ci return 1; 85e1051a39Sopenharmony_ci} 86e1051a39Sopenharmony_ci 87e1051a39Sopenharmony_cistatic int enc_free(BIO *a) 88e1051a39Sopenharmony_ci{ 89e1051a39Sopenharmony_ci BIO_ENC_CTX *b; 90e1051a39Sopenharmony_ci 91e1051a39Sopenharmony_ci if (a == NULL) 92e1051a39Sopenharmony_ci return 0; 93e1051a39Sopenharmony_ci 94e1051a39Sopenharmony_ci b = BIO_get_data(a); 95e1051a39Sopenharmony_ci if (b == NULL) 96e1051a39Sopenharmony_ci return 0; 97e1051a39Sopenharmony_ci 98e1051a39Sopenharmony_ci EVP_CIPHER_CTX_free(b->cipher); 99e1051a39Sopenharmony_ci OPENSSL_clear_free(b, sizeof(BIO_ENC_CTX)); 100e1051a39Sopenharmony_ci BIO_set_data(a, NULL); 101e1051a39Sopenharmony_ci BIO_set_init(a, 0); 102e1051a39Sopenharmony_ci 103e1051a39Sopenharmony_ci return 1; 104e1051a39Sopenharmony_ci} 105e1051a39Sopenharmony_ci 106e1051a39Sopenharmony_cistatic int enc_read(BIO *b, char *out, int outl) 107e1051a39Sopenharmony_ci{ 108e1051a39Sopenharmony_ci int ret = 0, i, blocksize; 109e1051a39Sopenharmony_ci BIO_ENC_CTX *ctx; 110e1051a39Sopenharmony_ci BIO *next; 111e1051a39Sopenharmony_ci 112e1051a39Sopenharmony_ci if (out == NULL) 113e1051a39Sopenharmony_ci return 0; 114e1051a39Sopenharmony_ci ctx = BIO_get_data(b); 115e1051a39Sopenharmony_ci 116e1051a39Sopenharmony_ci next = BIO_next(b); 117e1051a39Sopenharmony_ci if ((ctx == NULL) || (next == NULL)) 118e1051a39Sopenharmony_ci return 0; 119e1051a39Sopenharmony_ci 120e1051a39Sopenharmony_ci /* First check if there are bytes decoded/encoded */ 121e1051a39Sopenharmony_ci if (ctx->buf_len > 0) { 122e1051a39Sopenharmony_ci i = ctx->buf_len - ctx->buf_off; 123e1051a39Sopenharmony_ci if (i > outl) 124e1051a39Sopenharmony_ci i = outl; 125e1051a39Sopenharmony_ci memcpy(out, &(ctx->buf[ctx->buf_off]), i); 126e1051a39Sopenharmony_ci ret = i; 127e1051a39Sopenharmony_ci out += i; 128e1051a39Sopenharmony_ci outl -= i; 129e1051a39Sopenharmony_ci ctx->buf_off += i; 130e1051a39Sopenharmony_ci if (ctx->buf_len == ctx->buf_off) { 131e1051a39Sopenharmony_ci ctx->buf_len = 0; 132e1051a39Sopenharmony_ci ctx->buf_off = 0; 133e1051a39Sopenharmony_ci } 134e1051a39Sopenharmony_ci } 135e1051a39Sopenharmony_ci 136e1051a39Sopenharmony_ci blocksize = EVP_CIPHER_CTX_get_block_size(ctx->cipher); 137e1051a39Sopenharmony_ci if (blocksize == 1) 138e1051a39Sopenharmony_ci blocksize = 0; 139e1051a39Sopenharmony_ci 140e1051a39Sopenharmony_ci /* 141e1051a39Sopenharmony_ci * At this point, we have room of outl bytes and an empty buffer, so we 142e1051a39Sopenharmony_ci * should read in some more. 143e1051a39Sopenharmony_ci */ 144e1051a39Sopenharmony_ci 145e1051a39Sopenharmony_ci while (outl > 0) { 146e1051a39Sopenharmony_ci if (ctx->cont <= 0) 147e1051a39Sopenharmony_ci break; 148e1051a39Sopenharmony_ci 149e1051a39Sopenharmony_ci if (ctx->read_start == ctx->read_end) { /* time to read more data */ 150e1051a39Sopenharmony_ci ctx->read_end = ctx->read_start = &(ctx->buf[BUF_OFFSET]); 151e1051a39Sopenharmony_ci i = BIO_read(next, ctx->read_start, ENC_BLOCK_SIZE); 152e1051a39Sopenharmony_ci if (i > 0) 153e1051a39Sopenharmony_ci ctx->read_end += i; 154e1051a39Sopenharmony_ci } else { 155e1051a39Sopenharmony_ci i = ctx->read_end - ctx->read_start; 156e1051a39Sopenharmony_ci } 157e1051a39Sopenharmony_ci 158e1051a39Sopenharmony_ci if (i <= 0) { 159e1051a39Sopenharmony_ci /* Should be continue next time we are called? */ 160e1051a39Sopenharmony_ci if (!BIO_should_retry(next)) { 161e1051a39Sopenharmony_ci ctx->cont = i; 162e1051a39Sopenharmony_ci i = EVP_CipherFinal_ex(ctx->cipher, 163e1051a39Sopenharmony_ci ctx->buf, &(ctx->buf_len)); 164e1051a39Sopenharmony_ci ctx->ok = i; 165e1051a39Sopenharmony_ci ctx->buf_off = 0; 166e1051a39Sopenharmony_ci } else { 167e1051a39Sopenharmony_ci ret = (ret == 0) ? i : ret; 168e1051a39Sopenharmony_ci break; 169e1051a39Sopenharmony_ci } 170e1051a39Sopenharmony_ci } else { 171e1051a39Sopenharmony_ci if (outl > ENC_MIN_CHUNK) { 172e1051a39Sopenharmony_ci /* 173e1051a39Sopenharmony_ci * Depending on flags block cipher decrypt can write 174e1051a39Sopenharmony_ci * one extra block and then back off, i.e. output buffer 175e1051a39Sopenharmony_ci * has to accommodate extra block... 176e1051a39Sopenharmony_ci */ 177e1051a39Sopenharmony_ci int j = outl - blocksize, buf_len; 178e1051a39Sopenharmony_ci 179e1051a39Sopenharmony_ci if (!EVP_CipherUpdate(ctx->cipher, 180e1051a39Sopenharmony_ci (unsigned char *)out, &buf_len, 181e1051a39Sopenharmony_ci ctx->read_start, i > j ? j : i)) { 182e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 183e1051a39Sopenharmony_ci return 0; 184e1051a39Sopenharmony_ci } 185e1051a39Sopenharmony_ci ret += buf_len; 186e1051a39Sopenharmony_ci out += buf_len; 187e1051a39Sopenharmony_ci outl -= buf_len; 188e1051a39Sopenharmony_ci 189e1051a39Sopenharmony_ci if ((i -= j) <= 0) { 190e1051a39Sopenharmony_ci ctx->read_start = ctx->read_end; 191e1051a39Sopenharmony_ci continue; 192e1051a39Sopenharmony_ci } 193e1051a39Sopenharmony_ci ctx->read_start += j; 194e1051a39Sopenharmony_ci } 195e1051a39Sopenharmony_ci if (i > ENC_MIN_CHUNK) 196e1051a39Sopenharmony_ci i = ENC_MIN_CHUNK; 197e1051a39Sopenharmony_ci if (!EVP_CipherUpdate(ctx->cipher, 198e1051a39Sopenharmony_ci ctx->buf, &ctx->buf_len, 199e1051a39Sopenharmony_ci ctx->read_start, i)) { 200e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 201e1051a39Sopenharmony_ci ctx->ok = 0; 202e1051a39Sopenharmony_ci return 0; 203e1051a39Sopenharmony_ci } 204e1051a39Sopenharmony_ci ctx->read_start += i; 205e1051a39Sopenharmony_ci ctx->cont = 1; 206e1051a39Sopenharmony_ci /* 207e1051a39Sopenharmony_ci * Note: it is possible for EVP_CipherUpdate to decrypt zero 208e1051a39Sopenharmony_ci * bytes because this is or looks like the final block: if this 209e1051a39Sopenharmony_ci * happens we should retry and either read more data or decrypt 210e1051a39Sopenharmony_ci * the final block 211e1051a39Sopenharmony_ci */ 212e1051a39Sopenharmony_ci if (ctx->buf_len == 0) 213e1051a39Sopenharmony_ci continue; 214e1051a39Sopenharmony_ci } 215e1051a39Sopenharmony_ci 216e1051a39Sopenharmony_ci if (ctx->buf_len <= outl) 217e1051a39Sopenharmony_ci i = ctx->buf_len; 218e1051a39Sopenharmony_ci else 219e1051a39Sopenharmony_ci i = outl; 220e1051a39Sopenharmony_ci if (i <= 0) 221e1051a39Sopenharmony_ci break; 222e1051a39Sopenharmony_ci memcpy(out, ctx->buf, i); 223e1051a39Sopenharmony_ci ret += i; 224e1051a39Sopenharmony_ci ctx->buf_off = i; 225e1051a39Sopenharmony_ci outl -= i; 226e1051a39Sopenharmony_ci out += i; 227e1051a39Sopenharmony_ci } 228e1051a39Sopenharmony_ci 229e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 230e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 231e1051a39Sopenharmony_ci return ((ret == 0) ? ctx->cont : ret); 232e1051a39Sopenharmony_ci} 233e1051a39Sopenharmony_ci 234e1051a39Sopenharmony_cistatic int enc_write(BIO *b, const char *in, int inl) 235e1051a39Sopenharmony_ci{ 236e1051a39Sopenharmony_ci int ret = 0, n, i; 237e1051a39Sopenharmony_ci BIO_ENC_CTX *ctx; 238e1051a39Sopenharmony_ci BIO *next; 239e1051a39Sopenharmony_ci 240e1051a39Sopenharmony_ci ctx = BIO_get_data(b); 241e1051a39Sopenharmony_ci next = BIO_next(b); 242e1051a39Sopenharmony_ci if ((ctx == NULL) || (next == NULL)) 243e1051a39Sopenharmony_ci return 0; 244e1051a39Sopenharmony_ci 245e1051a39Sopenharmony_ci ret = inl; 246e1051a39Sopenharmony_ci 247e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 248e1051a39Sopenharmony_ci n = ctx->buf_len - ctx->buf_off; 249e1051a39Sopenharmony_ci while (n > 0) { 250e1051a39Sopenharmony_ci i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n); 251e1051a39Sopenharmony_ci if (i <= 0) { 252e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 253e1051a39Sopenharmony_ci return i; 254e1051a39Sopenharmony_ci } 255e1051a39Sopenharmony_ci ctx->buf_off += i; 256e1051a39Sopenharmony_ci n -= i; 257e1051a39Sopenharmony_ci } 258e1051a39Sopenharmony_ci /* at this point all pending data has been written */ 259e1051a39Sopenharmony_ci 260e1051a39Sopenharmony_ci if ((in == NULL) || (inl <= 0)) 261e1051a39Sopenharmony_ci return 0; 262e1051a39Sopenharmony_ci 263e1051a39Sopenharmony_ci ctx->buf_off = 0; 264e1051a39Sopenharmony_ci while (inl > 0) { 265e1051a39Sopenharmony_ci n = (inl > ENC_BLOCK_SIZE) ? ENC_BLOCK_SIZE : inl; 266e1051a39Sopenharmony_ci if (!EVP_CipherUpdate(ctx->cipher, 267e1051a39Sopenharmony_ci ctx->buf, &ctx->buf_len, 268e1051a39Sopenharmony_ci (const unsigned char *)in, n)) { 269e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 270e1051a39Sopenharmony_ci ctx->ok = 0; 271e1051a39Sopenharmony_ci return 0; 272e1051a39Sopenharmony_ci } 273e1051a39Sopenharmony_ci inl -= n; 274e1051a39Sopenharmony_ci in += n; 275e1051a39Sopenharmony_ci 276e1051a39Sopenharmony_ci ctx->buf_off = 0; 277e1051a39Sopenharmony_ci n = ctx->buf_len; 278e1051a39Sopenharmony_ci while (n > 0) { 279e1051a39Sopenharmony_ci i = BIO_write(next, &(ctx->buf[ctx->buf_off]), n); 280e1051a39Sopenharmony_ci if (i <= 0) { 281e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 282e1051a39Sopenharmony_ci return (ret == inl) ? i : ret - inl; 283e1051a39Sopenharmony_ci } 284e1051a39Sopenharmony_ci n -= i; 285e1051a39Sopenharmony_ci ctx->buf_off += i; 286e1051a39Sopenharmony_ci } 287e1051a39Sopenharmony_ci ctx->buf_len = 0; 288e1051a39Sopenharmony_ci ctx->buf_off = 0; 289e1051a39Sopenharmony_ci } 290e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 291e1051a39Sopenharmony_ci return ret; 292e1051a39Sopenharmony_ci} 293e1051a39Sopenharmony_ci 294e1051a39Sopenharmony_cistatic long enc_ctrl(BIO *b, int cmd, long num, void *ptr) 295e1051a39Sopenharmony_ci{ 296e1051a39Sopenharmony_ci BIO *dbio; 297e1051a39Sopenharmony_ci BIO_ENC_CTX *ctx, *dctx; 298e1051a39Sopenharmony_ci long ret = 1; 299e1051a39Sopenharmony_ci int i; 300e1051a39Sopenharmony_ci EVP_CIPHER_CTX **c_ctx; 301e1051a39Sopenharmony_ci BIO *next; 302e1051a39Sopenharmony_ci int pend; 303e1051a39Sopenharmony_ci 304e1051a39Sopenharmony_ci ctx = BIO_get_data(b); 305e1051a39Sopenharmony_ci next = BIO_next(b); 306e1051a39Sopenharmony_ci if (ctx == NULL) 307e1051a39Sopenharmony_ci return 0; 308e1051a39Sopenharmony_ci 309e1051a39Sopenharmony_ci switch (cmd) { 310e1051a39Sopenharmony_ci case BIO_CTRL_RESET: 311e1051a39Sopenharmony_ci ctx->ok = 1; 312e1051a39Sopenharmony_ci ctx->finished = 0; 313e1051a39Sopenharmony_ci if (!EVP_CipherInit_ex(ctx->cipher, NULL, NULL, NULL, NULL, 314e1051a39Sopenharmony_ci EVP_CIPHER_CTX_is_encrypting(ctx->cipher))) 315e1051a39Sopenharmony_ci return 0; 316e1051a39Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 317e1051a39Sopenharmony_ci break; 318e1051a39Sopenharmony_ci case BIO_CTRL_EOF: /* More to read */ 319e1051a39Sopenharmony_ci if (ctx->cont <= 0) 320e1051a39Sopenharmony_ci ret = 1; 321e1051a39Sopenharmony_ci else 322e1051a39Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 323e1051a39Sopenharmony_ci break; 324e1051a39Sopenharmony_ci case BIO_CTRL_WPENDING: 325e1051a39Sopenharmony_ci ret = ctx->buf_len - ctx->buf_off; 326e1051a39Sopenharmony_ci if (ret <= 0) 327e1051a39Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 328e1051a39Sopenharmony_ci break; 329e1051a39Sopenharmony_ci case BIO_CTRL_PENDING: /* More to read in buffer */ 330e1051a39Sopenharmony_ci ret = ctx->buf_len - ctx->buf_off; 331e1051a39Sopenharmony_ci if (ret <= 0) 332e1051a39Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 333e1051a39Sopenharmony_ci break; 334e1051a39Sopenharmony_ci case BIO_CTRL_FLUSH: 335e1051a39Sopenharmony_ci /* do a final write */ 336e1051a39Sopenharmony_ci again: 337e1051a39Sopenharmony_ci while (ctx->buf_len != ctx->buf_off) { 338e1051a39Sopenharmony_ci pend = ctx->buf_len - ctx->buf_off; 339e1051a39Sopenharmony_ci i = enc_write(b, NULL, 0); 340e1051a39Sopenharmony_ci /* 341e1051a39Sopenharmony_ci * i should never be > 0 here because we didn't ask to write any 342e1051a39Sopenharmony_ci * new data. We stop if we get an error or we failed to make any 343e1051a39Sopenharmony_ci * progress writing pending data. 344e1051a39Sopenharmony_ci */ 345e1051a39Sopenharmony_ci if (i < 0 || (ctx->buf_len - ctx->buf_off) == pend) 346e1051a39Sopenharmony_ci return i; 347e1051a39Sopenharmony_ci } 348e1051a39Sopenharmony_ci 349e1051a39Sopenharmony_ci if (!ctx->finished) { 350e1051a39Sopenharmony_ci ctx->finished = 1; 351e1051a39Sopenharmony_ci ctx->buf_off = 0; 352e1051a39Sopenharmony_ci ret = EVP_CipherFinal_ex(ctx->cipher, 353e1051a39Sopenharmony_ci (unsigned char *)ctx->buf, 354e1051a39Sopenharmony_ci &(ctx->buf_len)); 355e1051a39Sopenharmony_ci ctx->ok = (int)ret; 356e1051a39Sopenharmony_ci if (ret <= 0) 357e1051a39Sopenharmony_ci break; 358e1051a39Sopenharmony_ci 359e1051a39Sopenharmony_ci /* push out the bytes */ 360e1051a39Sopenharmony_ci goto again; 361e1051a39Sopenharmony_ci } 362e1051a39Sopenharmony_ci 363e1051a39Sopenharmony_ci /* Finally flush the underlying BIO */ 364e1051a39Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 365e1051a39Sopenharmony_ci break; 366e1051a39Sopenharmony_ci case BIO_C_GET_CIPHER_STATUS: 367e1051a39Sopenharmony_ci ret = (long)ctx->ok; 368e1051a39Sopenharmony_ci break; 369e1051a39Sopenharmony_ci case BIO_C_DO_STATE_MACHINE: 370e1051a39Sopenharmony_ci BIO_clear_retry_flags(b); 371e1051a39Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 372e1051a39Sopenharmony_ci BIO_copy_next_retry(b); 373e1051a39Sopenharmony_ci break; 374e1051a39Sopenharmony_ci case BIO_C_GET_CIPHER_CTX: 375e1051a39Sopenharmony_ci c_ctx = (EVP_CIPHER_CTX **)ptr; 376e1051a39Sopenharmony_ci *c_ctx = ctx->cipher; 377e1051a39Sopenharmony_ci BIO_set_init(b, 1); 378e1051a39Sopenharmony_ci break; 379e1051a39Sopenharmony_ci case BIO_CTRL_DUP: 380e1051a39Sopenharmony_ci dbio = (BIO *)ptr; 381e1051a39Sopenharmony_ci dctx = BIO_get_data(dbio); 382e1051a39Sopenharmony_ci dctx->cipher = EVP_CIPHER_CTX_new(); 383e1051a39Sopenharmony_ci if (dctx->cipher == NULL) 384e1051a39Sopenharmony_ci return 0; 385e1051a39Sopenharmony_ci ret = EVP_CIPHER_CTX_copy(dctx->cipher, ctx->cipher); 386e1051a39Sopenharmony_ci if (ret) 387e1051a39Sopenharmony_ci BIO_set_init(dbio, 1); 388e1051a39Sopenharmony_ci break; 389e1051a39Sopenharmony_ci default: 390e1051a39Sopenharmony_ci ret = BIO_ctrl(next, cmd, num, ptr); 391e1051a39Sopenharmony_ci break; 392e1051a39Sopenharmony_ci } 393e1051a39Sopenharmony_ci return ret; 394e1051a39Sopenharmony_ci} 395e1051a39Sopenharmony_ci 396e1051a39Sopenharmony_cistatic long enc_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) 397e1051a39Sopenharmony_ci{ 398e1051a39Sopenharmony_ci BIO *next = BIO_next(b); 399e1051a39Sopenharmony_ci 400e1051a39Sopenharmony_ci if (next == NULL) 401e1051a39Sopenharmony_ci return 0; 402e1051a39Sopenharmony_ci 403e1051a39Sopenharmony_ci return BIO_callback_ctrl(next, cmd, fp); 404e1051a39Sopenharmony_ci} 405e1051a39Sopenharmony_ci 406e1051a39Sopenharmony_ciint BIO_set_cipher(BIO *b, const EVP_CIPHER *c, const unsigned char *k, 407e1051a39Sopenharmony_ci const unsigned char *i, int e) 408e1051a39Sopenharmony_ci{ 409e1051a39Sopenharmony_ci BIO_ENC_CTX *ctx; 410e1051a39Sopenharmony_ci BIO_callback_fn_ex callback_ex; 411e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DEPRECATED_3_0 412e1051a39Sopenharmony_ci long (*callback) (struct bio_st *, int, const char *, int, long, long) = NULL; 413e1051a39Sopenharmony_ci#endif 414e1051a39Sopenharmony_ci 415e1051a39Sopenharmony_ci ctx = BIO_get_data(b); 416e1051a39Sopenharmony_ci if (ctx == NULL) 417e1051a39Sopenharmony_ci return 0; 418e1051a39Sopenharmony_ci 419e1051a39Sopenharmony_ci if ((callback_ex = BIO_get_callback_ex(b)) != NULL) { 420e1051a39Sopenharmony_ci if (callback_ex(b, BIO_CB_CTRL, (const char *)c, 0, BIO_CTRL_SET, 421e1051a39Sopenharmony_ci e, 1, NULL) <= 0) 422e1051a39Sopenharmony_ci return 0; 423e1051a39Sopenharmony_ci } 424e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DEPRECATED_3_0 425e1051a39Sopenharmony_ci else { 426e1051a39Sopenharmony_ci callback = BIO_get_callback(b); 427e1051a39Sopenharmony_ci 428e1051a39Sopenharmony_ci if ((callback != NULL) && 429e1051a39Sopenharmony_ci (callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 430e1051a39Sopenharmony_ci 0L) <= 0)) 431e1051a39Sopenharmony_ci return 0; 432e1051a39Sopenharmony_ci } 433e1051a39Sopenharmony_ci#endif 434e1051a39Sopenharmony_ci 435e1051a39Sopenharmony_ci BIO_set_init(b, 1); 436e1051a39Sopenharmony_ci 437e1051a39Sopenharmony_ci if (!EVP_CipherInit_ex(ctx->cipher, c, NULL, k, i, e)) 438e1051a39Sopenharmony_ci return 0; 439e1051a39Sopenharmony_ci 440e1051a39Sopenharmony_ci if (callback_ex != NULL) 441e1051a39Sopenharmony_ci return callback_ex(b, BIO_CB_CTRL | BIO_CB_RETURN, (const char *)c, 0, 442e1051a39Sopenharmony_ci BIO_CTRL_SET, e, 1, NULL); 443e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DEPRECATED_3_0 444e1051a39Sopenharmony_ci else if (callback != NULL) 445e1051a39Sopenharmony_ci return callback(b, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 1L); 446e1051a39Sopenharmony_ci#endif 447e1051a39Sopenharmony_ci return 1; 448e1051a39Sopenharmony_ci} 449