From: tb Date: Fri, 29 Dec 2023 05:57:24 +0000 (+0000) Subject: Use more consistent naming for some files in evp X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=1cc76114d489046325db16299f875e8175c74330;p=openbsd Use more consistent naming for some files in evp EVP_Digest{Init,Update,Final}() move from digest.c to evp_digest.c which will become the home of all things related to EVP_MD{,_CTX} handling. EVP_Cipher{Init,Update,Final}() move from evp_enc.c to evp_cipher.c which will become the home of all things related to EVP_CIPHER{,_CTX} handling. EVP_Encode{Init,Update,Final}() move from encode.c to evp_encode.c which already is the home of EVP_ENCODE_CTX_{new,free}(). discussed with jsing --- diff --git a/lib/libcrypto/Makefile b/lib/libcrypto/Makefile index 6329d309e78..d9b3e180f09 100644 --- a/lib/libcrypto/Makefile +++ b/lib/libcrypto/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.159 2023/12/20 13:52:17 tb Exp $ +# $OpenBSD: Makefile,v 1.160 2023/12/29 05:57:24 tb Exp $ LIB= crypto LIBREBUILD=y @@ -350,7 +350,6 @@ SRCS+= bio_enc.c SRCS+= bio_md.c SRCS+= c_all.c SRCS+= cipher_method_lib.c -SRCS+= digest.c SRCS+= e_aes.c SRCS+= e_aes_cbc_hmac_sha1.c SRCS+= e_bf.c @@ -368,9 +367,10 @@ SRCS+= e_rc4.c SRCS+= e_rc4_hmac_md5.c SRCS+= e_sm4.c SRCS+= e_xcbc_d.c -SRCS+= encode.c SRCS+= evp_aead.c -SRCS+= evp_enc.c +SRCS+= evp_cipher.c +SRCS+= evp_digest.c +SRCS+= evp_encode.c SRCS+= evp_err.c SRCS+= evp_key.c SRCS+= evp_lib.c diff --git a/lib/libcrypto/evp/digest.c b/lib/libcrypto/evp/digest.c deleted file mode 100644 index 56decc231c2..00000000000 --- a/lib/libcrypto/evp/digest.c +++ /dev/null @@ -1,369 +0,0 @@ -/* $OpenBSD: digest.c,v 1.41 2023/12/24 22:17:05 tb Exp $ */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ -/* ==================================================================== - * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * 3. All advertising materials mentioning features or use of this - * software must display the following acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR - * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). - * - */ - -#include -#include - -#include - -#include -#include -#include - -#include "evp_local.h" - -int -EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type) -{ - EVP_MD_CTX_init(ctx); - return EVP_DigestInit_ex(ctx, type, NULL); -} - -int -EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) -{ - EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); - - if (ctx->digest != type) { - if (ctx->digest && ctx->digest->ctx_size && ctx->md_data && - !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) { - freezero(ctx->md_data, ctx->digest->ctx_size); - ctx->md_data = NULL; - } - ctx->digest = type; - if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) { - ctx->update = type->update; - ctx->md_data = calloc(1, type->ctx_size); - if (ctx->md_data == NULL) { - EVP_PKEY_CTX_free(ctx->pctx); - ctx->pctx = NULL; - EVPerror(ERR_R_MALLOC_FAILURE); - return 0; - } - } - } - if (ctx->pctx) { - int r; - r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG, - EVP_PKEY_CTRL_DIGESTINIT, 0, ctx); - if (r <= 0 && (r != -2)) - return 0; - } - if (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) - return 1; - return ctx->digest->init(ctx); -} - -int -EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t count) -{ - return ctx->update(ctx, data, count); -} - -/* The caller can assume that this removes any secret data from the context */ -int -EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size) -{ - int ret; - - ret = EVP_DigestFinal_ex(ctx, md, size); - EVP_MD_CTX_cleanup(ctx); - return ret; -} - -/* The caller can assume that this removes any secret data from the context */ -int -EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size) -{ - int ret; - - if ((size_t)ctx->digest->md_size > EVP_MAX_MD_SIZE) { - EVPerror(EVP_R_TOO_LARGE); - return 0; - } - ret = ctx->digest->final(ctx, md); - if (size != NULL) - *size = ctx->digest->md_size; - if (ctx->digest->cleanup) { - ctx->digest->cleanup(ctx); - EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); - } - memset(ctx->md_data, 0, ctx->digest->ctx_size); - return ret; -} - -int -EVP_Digest(const void *data, size_t count, - unsigned char *md, unsigned int *size, const EVP_MD *type, ENGINE *impl) -{ - EVP_MD_CTX ctx; - int ret; - - EVP_MD_CTX_init(&ctx); - EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_ONESHOT); - ret = EVP_DigestInit_ex(&ctx, type, NULL) && - EVP_DigestUpdate(&ctx, data, count) && - EVP_DigestFinal_ex(&ctx, md, size); - EVP_MD_CTX_cleanup(&ctx); - - return ret; -} - -int -EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in) -{ - EVP_MD_CTX_init(out); - return EVP_MD_CTX_copy_ex(out, in); -} - -int -EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) -{ - unsigned char *tmp_buf; - - if ((in == NULL) || (in->digest == NULL)) { - EVPerror(EVP_R_INPUT_NOT_INITIALIZED); - return 0; - } - - if (out->digest == in->digest) { - tmp_buf = out->md_data; - EVP_MD_CTX_set_flags(out, EVP_MD_CTX_FLAG_REUSE); - } else - tmp_buf = NULL; - EVP_MD_CTX_cleanup(out); - memcpy(out, in, sizeof *out); - out->md_data = NULL; - out->pctx = NULL; - - /* - * Because of the EVP_PKEY_CTX_dup() below, EVP_MD_CTX_cleanup() needs - * to free out->pctx in all cases (even if this flag is set on in). - */ - EVP_MD_CTX_clear_flags(out, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX); - - if (in->md_data && out->digest->ctx_size) { - if (tmp_buf) { - out->md_data = tmp_buf; - } else { - out->md_data = calloc(1, out->digest->ctx_size); - if (out->md_data == NULL) { - EVPerror(ERR_R_MALLOC_FAILURE); - return 0; - } - } - memcpy(out->md_data, in->md_data, out->digest->ctx_size); - } - - out->update = in->update; - - if (in->pctx) { - out->pctx = EVP_PKEY_CTX_dup(in->pctx); - if (!out->pctx) { - EVP_MD_CTX_cleanup(out); - return 0; - } - } - - if (out->digest->copy) - return out->digest->copy(out, in); - - return 1; -} - -EVP_MD_CTX * -EVP_MD_CTX_new(void) -{ - return calloc(1, sizeof(EVP_MD_CTX)); -} - -void -EVP_MD_CTX_free(EVP_MD_CTX *ctx) -{ - if (ctx == NULL) - return; - - EVP_MD_CTX_cleanup(ctx); - - free(ctx); -} - -void -EVP_MD_CTX_init(EVP_MD_CTX *ctx) -{ - memset(ctx, 0, sizeof(*ctx)); -} - -int -EVP_MD_CTX_reset(EVP_MD_CTX *ctx) -{ - return EVP_MD_CTX_cleanup(ctx); -} - -EVP_MD_CTX * -EVP_MD_CTX_create(void) -{ - return EVP_MD_CTX_new(); -} - -void -EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) -{ - EVP_MD_CTX_free(ctx); -} - -/* This call frees resources associated with the context */ -int -EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) -{ - /* - * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, - * because sometimes only copies of the context are ever finalised. - */ - if (ctx->digest && ctx->digest->cleanup && - !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED)) - ctx->digest->cleanup(ctx); - if (ctx->digest && ctx->digest->ctx_size && ctx->md_data && - !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) - freezero(ctx->md_data, ctx->digest->ctx_size); - /* - * If EVP_MD_CTX_FLAG_KEEP_PKEY_CTX is set, EVP_MD_CTX_set_pkey() was - * called and its strange API contract implies we don't own ctx->pctx. - */ - if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX)) - EVP_PKEY_CTX_free(ctx->pctx); - memset(ctx, 0, sizeof(*ctx)); - - return 1; -} - -int -EVP_MD_CTX_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr) -{ - int ret; - - if (!ctx->digest) { - EVPerror(EVP_R_NO_CIPHER_SET); - return 0; - } - - if (!ctx->digest->md_ctrl) { - EVPerror(EVP_R_CTRL_NOT_IMPLEMENTED); - return 0; - } - - ret = ctx->digest->md_ctrl(ctx, type, arg, ptr); - if (ret == -1) { - EVPerror(EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED); - return 0; - } - return ret; -} diff --git a/lib/libcrypto/evp/encode.c b/lib/libcrypto/evp/encode.c deleted file mode 100644 index c62a1dea8fc..00000000000 --- a/lib/libcrypto/evp/encode.c +++ /dev/null @@ -1,414 +0,0 @@ -/* $OpenBSD: encode.c,v 1.32 2023/07/07 19:37:53 beck Exp $ */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#include -#include -#include - -#include - -#include "evp_local.h" - -static unsigned char conv_ascii2bin(unsigned char a); -#define conv_bin2ascii(a) (data_bin2ascii[(a)&0x3f]) - -/* 64 char lines - * pad input with 0 - * left over chars are set to = - * 1 byte => xx== - * 2 bytes => xxx= - * 3 bytes => xxxx - */ -#define BIN_PER_LINE (64/4*3) -#define CHUNKS_PER_LINE (64/4) -#define CHAR_PER_LINE (64+1) - -static const unsigned char data_bin2ascii[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\ -abcdefghijklmnopqrstuvwxyz0123456789+/"; - -/* 0xF0 is a EOLN - * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing). - * 0xF2 is EOF - * 0xE0 is ignore at start of line. - * 0xFF is error - */ - -#define B64_EOLN 0xF0 -#define B64_CR 0xF1 -#define B64_EOF 0xF2 -#define B64_WS 0xE0 -#define B64_ERROR 0xFF -#define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3) -#define B64_BASE64(a) !B64_NOT_BASE64(a) - -static const unsigned char data_ascii2bin[128] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, - 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, - 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, - 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, - 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, - 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -}; - -static unsigned char -conv_ascii2bin(unsigned char a) -{ - if (a & 0x80) - return B64_ERROR; - return data_ascii2bin[a]; -} - -EVP_ENCODE_CTX * -EVP_ENCODE_CTX_new(void) -{ - return calloc(1, sizeof(EVP_ENCODE_CTX)); -} - -void -EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx) -{ - free(ctx); -} - -void -EVP_EncodeInit(EVP_ENCODE_CTX *ctx) -{ - ctx->length = 48; - ctx->num = 0; - ctx->line_num = 0; -} - -int -EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, - const unsigned char *in, int inl) -{ - int i, j; - size_t total = 0; - - *outl = 0; - if (inl <= 0) - return 0; - OPENSSL_assert(ctx->length <= (int)sizeof(ctx->enc_data)); - if (ctx->length - ctx->num > inl) { - memcpy(&(ctx->enc_data[ctx->num]), in, inl); - ctx->num += inl; - return 1; - } - if (ctx->num != 0) { - i = ctx->length - ctx->num; - memcpy(&(ctx->enc_data[ctx->num]), in, i); - in += i; - inl -= i; - j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length); - ctx->num = 0; - out += j; - *(out++) = '\n'; - *out = '\0'; - total = j + 1; - } - while (inl >= ctx->length && total <= INT_MAX) { - j = EVP_EncodeBlock(out, in, ctx->length); - in += ctx->length; - inl -= ctx->length; - out += j; - *(out++) = '\n'; - *out = '\0'; - total += j + 1; - } - if (total > INT_MAX) { - /* Too much output data! */ - *outl = 0; - return 0; - } - if (inl != 0) - memcpy(&(ctx->enc_data[0]), in, inl); - ctx->num = inl; - *outl = total; - - return 1; -} - -void -EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl) -{ - unsigned int ret = 0; - - if (ctx->num != 0) { - ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num); - out[ret++] = '\n'; - out[ret] = '\0'; - ctx->num = 0; - } - *outl = ret; -} - -int -EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen) -{ - int i, ret = 0; - unsigned long l; - - for (i = dlen; i > 0; i -= 3) { - if (i >= 3) { - l = (((unsigned long)f[0]) << 16L) | - (((unsigned long)f[1]) << 8L) | f[2]; - *(t++) = conv_bin2ascii(l >> 18L); - *(t++) = conv_bin2ascii(l >> 12L); - *(t++) = conv_bin2ascii(l >> 6L); - *(t++) = conv_bin2ascii(l ); - } else { - l = ((unsigned long)f[0]) << 16L; - if (i == 2) - l |= ((unsigned long)f[1] << 8L); - - *(t++) = conv_bin2ascii(l >> 18L); - *(t++) = conv_bin2ascii(l >> 12L); - *(t++) = (i == 1) ? '=' : conv_bin2ascii(l >> 6L); - *(t++) = '='; - } - ret += 4; - f += 3; - } - - *t = '\0'; - return (ret); -} - -void -EVP_DecodeInit(EVP_ENCODE_CTX *ctx) -{ - ctx->num = 0; - ctx->length = 0; - ctx->line_num = 0; - ctx->expect_nl = 0; -} - -int -EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, - const unsigned char *in, int inl) -{ - int seof = 0, eof = 0, rv = -1, ret = 0, i, v, tmp, n, decoded_len; - unsigned char *d; - - n = ctx->num; - d = ctx->enc_data; - - if (n > 0 && d[n - 1] == '=') { - eof++; - if (n > 1 && d[n - 2] == '=') - eof++; - } - - /* Legacy behaviour: an empty input chunk signals end of input. */ - if (inl == 0) { - rv = 0; - goto end; - } - - for (i = 0; i < inl; i++) { - tmp = *(in++); - v = conv_ascii2bin(tmp); - if (v == B64_ERROR) { - rv = -1; - goto end; - } - - if (tmp == '=') { - eof++; - } else if (eof > 0 && B64_BASE64(v)) { - /* More data after padding. */ - rv = -1; - goto end; - } - - if (eof > 2) { - rv = -1; - goto end; - } - - if (v == B64_EOF) { - seof = 1; - goto tail; - } - - /* Only save valid base64 characters. */ - if (B64_BASE64(v)) { - if (n >= 64) { - /* - * We increment n once per loop, and empty the - * buffer as soon as we reach 64 characters, so - * this can only happen if someone's manually - * messed with the ctx. Refuse to write any - * more data. - */ - rv = -1; - goto end; - } - OPENSSL_assert(n < (int)sizeof(ctx->enc_data)); - d[n++] = tmp; - } - - if (n == 64) { - decoded_len = EVP_DecodeBlock(out, d, n); - n = 0; - if (decoded_len < 0 || eof > decoded_len) { - rv = -1; - goto end; - } - ret += decoded_len - eof; - out += decoded_len - eof; - } - } - - /* - * Legacy behaviour: if the current line is a full base64-block (i.e., - * has 0 mod 4 base64 characters), it is processed immediately. We keep - * this behaviour as applications may not be calling EVP_DecodeFinal - * properly. - */ - tail: - if (n > 0) { - if ((n & 3) == 0) { - decoded_len = EVP_DecodeBlock(out, d, n); - n = 0; - if (decoded_len < 0 || eof > decoded_len) { - rv = -1; - goto end; - } - ret += (decoded_len - eof); - } else if (seof) { - /* EOF in the middle of a base64 block. */ - rv = -1; - goto end; - } - } - - rv = seof || (n == 0 && eof) ? 0 : 1; - end: - /* Legacy behaviour. This should probably rather be zeroed on error. */ - *outl = ret; - ctx->num = n; - return (rv); -} - -int -EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n) -{ - int i, ret = 0, a, b, c, d; - unsigned long l; - - /* trim white space from the start of the line. */ - while ((conv_ascii2bin(*f) == B64_WS) && (n > 0)) { - f++; - n--; - } - - /* strip off stuff at the end of the line - * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */ - while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n - 1])))) - n--; - - if (n % 4 != 0) - return (-1); - - for (i = 0; i < n; i += 4) { - a = conv_ascii2bin(*(f++)); - b = conv_ascii2bin(*(f++)); - c = conv_ascii2bin(*(f++)); - d = conv_ascii2bin(*(f++)); - if ((a & 0x80) || (b & 0x80) || - (c & 0x80) || (d & 0x80)) - return (-1); - l = ((((unsigned long)a) << 18L) | - (((unsigned long)b) << 12L) | - (((unsigned long)c) << 6L) | - (((unsigned long)d))); - *(t++) = (unsigned char)(l >> 16L) & 0xff; - *(t++) = (unsigned char)(l >> 8L) & 0xff; - *(t++) = (unsigned char)(l) & 0xff; - ret += 3; - } - return (ret); -} - -int -EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl) -{ - int i; - - *outl = 0; - if (ctx->num != 0) { - i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num); - if (i < 0) - return (-1); - ctx->num = 0; - *outl = i; - return (1); - } else - return (1); -} diff --git a/lib/libcrypto/evp/evp_cipher.c b/lib/libcrypto/evp/evp_cipher.c new file mode 100644 index 00000000000..3b38e18bf3c --- /dev/null +++ b/lib/libcrypto/evp/evp_cipher.c @@ -0,0 +1,687 @@ +/* $OpenBSD: evp_cipher.c,v 1.1 2023/12/29 05:57:24 tb Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include +#include +#include +#include + +#include + +#include +#include + +#include "evp_local.h" + +int +EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const unsigned char *key, const unsigned char *iv, int enc) +{ + return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc); +} + +int +EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *engine, + const unsigned char *key, const unsigned char *iv, int enc) +{ + if (enc == -1) + enc = ctx->encrypt; + if (enc != 0) + enc = 1; + ctx->encrypt = enc; + + if (cipher == NULL && ctx->cipher == NULL) { + EVPerror(EVP_R_NO_CIPHER_SET); + return 0; + } + + /* + * Set up cipher and context. Allocate cipher data and initialize ctx. + * On ctx reuse only retain encryption direction and key wrap flag. + */ + if (cipher != NULL) { + unsigned long flags = ctx->flags; + + EVP_CIPHER_CTX_cleanup(ctx); + ctx->encrypt = enc; + ctx->flags = flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW; + + ctx->cipher = cipher; + ctx->key_len = cipher->key_len; + + if (ctx->cipher->ctx_size != 0) { + ctx->cipher_data = calloc(1, ctx->cipher->ctx_size); + if (ctx->cipher_data == NULL) { + EVPerror(ERR_R_MALLOC_FAILURE); + return 0; + } + } + + if ((ctx->cipher->flags & EVP_CIPH_CTRL_INIT) != 0) { + if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) { + EVPerror(EVP_R_INITIALIZATION_ERROR); + return 0; + } + } + } + + /* Block sizes must be a power of 2 due to the use of block_mask. */ + if (ctx->cipher->block_size != 1 && + ctx->cipher->block_size != 8 && + ctx->cipher->block_size != 16) { + EVPerror(EVP_R_BAD_BLOCK_LENGTH); + return 0; + } + + if ((ctx->flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW) == 0 && + EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_WRAP_MODE) { + EVPerror(EVP_R_WRAP_MODE_NOT_ALLOWED); + return 0; + } + + if ((EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_CUSTOM_IV) == 0) { + int iv_len; + + switch (EVP_CIPHER_CTX_mode(ctx)) { + + case EVP_CIPH_STREAM_CIPHER: + case EVP_CIPH_ECB_MODE: + break; + + case EVP_CIPH_CFB_MODE: + case EVP_CIPH_OFB_MODE: + + ctx->num = 0; + /* fall-through */ + + case EVP_CIPH_CBC_MODE: + iv_len = EVP_CIPHER_CTX_iv_length(ctx); + if (iv_len < 0 || iv_len > sizeof(ctx->oiv)) { + EVPerror(EVP_R_IV_TOO_LARGE); + return 0; + } + if (iv != NULL) + memcpy(ctx->oiv, iv, iv_len); + memcpy(ctx->iv, ctx->oiv, iv_len); + break; + + case EVP_CIPH_CTR_MODE: + ctx->num = 0; + iv_len = EVP_CIPHER_CTX_iv_length(ctx); + if (iv_len < 0 || iv_len > sizeof(ctx->iv)) { + EVPerror(EVP_R_IV_TOO_LARGE); + return 0; + } + /* Don't reuse IV for CTR mode */ + if (iv != NULL) + memcpy(ctx->iv, iv, iv_len); + break; + + default: + return 0; + break; + } + } + + if (key != NULL || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT) != 0) { + if (!ctx->cipher->init(ctx, key, iv, enc)) + return 0; + } + + ctx->partial_len = 0; + ctx->final_used = 0; + + return 1; +} + +int +EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len, + const unsigned char *in, int in_len) +{ + if (ctx->encrypt) + return EVP_EncryptUpdate(ctx, out, out_len, in, in_len); + + return EVP_DecryptUpdate(ctx, out, out_len, in, in_len); +} + +int +EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) +{ + if (ctx->encrypt) + return EVP_EncryptFinal_ex(ctx, out, out_len); + + return EVP_DecryptFinal_ex(ctx, out, out_len); +} + +int +EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) +{ + if (ctx->encrypt) + return EVP_EncryptFinal_ex(ctx, out, out_len); + + return EVP_DecryptFinal_ex(ctx, out, out_len); +} + +int +EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const unsigned char *key, const unsigned char *iv) +{ + return EVP_CipherInit(ctx, cipher, key, iv, 1); +} + +int +EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *engine, + const unsigned char *key, const unsigned char *iv) +{ + return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 1); +} + +/* + * EVP_Cipher() is an implementation detail of EVP_Cipher{Update,Final}(). + * Behavior depends on EVP_CIPH_FLAG_CUSTOM_CIPHER being set on ctx->cipher. + * + * If the flag is set, do_cipher() operates in update mode if in != NULL and + * in final mode if in == NULL. It returns the number of bytes written to out + * (which may be 0) or -1 on error. + * + * If the flag is not set, do_cipher() assumes properly aligned data and that + * padding is handled correctly by the caller. Most do_cipher() methods will + * silently produce garbage and succeed. Returns 1 on success, 0 on error. + */ +int +EVP_Cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, + unsigned int in_len) +{ + return ctx->cipher->do_cipher(ctx, out, in, in_len); +} + +static int +evp_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len, + const unsigned char *in, int in_len) +{ + int len; + + *out_len = 0; + + if (in_len < 0) + return 0; + + if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0) { + if ((len = ctx->cipher->do_cipher(ctx, out, in, in_len)) < 0) + return 0; + + *out_len = len; + return 1; + } + + if (!ctx->cipher->do_cipher(ctx, out, in, in_len)) + return 0; + + *out_len = in_len; + + return 1; +} + +int +EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len, + const unsigned char *in, int in_len) +{ + const int block_size = ctx->cipher->block_size; + const int block_mask = block_size - 1; + int partial_len = ctx->partial_len; + int len = 0, total_len = 0; + + *out_len = 0; + + if ((block_size & block_mask) != 0) + return 0; + + if (in_len < 0) + return 0; + + if (in_len == 0 && EVP_CIPHER_mode(ctx->cipher) != EVP_CIPH_CCM_MODE) + return 1; + + if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0) + return evp_cipher(ctx, out, out_len, in, in_len); + + if (partial_len == 0 && (in_len & block_mask) == 0) + return evp_cipher(ctx, out, out_len, in, in_len); + + if (partial_len < 0 || partial_len >= block_size || + block_size > sizeof(ctx->buf)) { + EVPerror(EVP_R_BAD_BLOCK_LENGTH); + return 0; + } + + if (partial_len > 0) { + int partial_needed; + + if ((partial_needed = block_size - partial_len) > in_len) { + memcpy(&ctx->buf[partial_len], in, in_len); + ctx->partial_len += in_len; + return 1; + } + + /* + * Once the first partial_needed bytes from in are processed, + * the number of multiples of block_size of data remaining is + * (in_len - partial_needed) & ~block_mask. Ensure that this + * plus the block processed from ctx->buf doesn't overflow. + */ + if (((in_len - partial_needed) & ~block_mask) > INT_MAX - block_size) { + EVPerror(EVP_R_TOO_LARGE); + return 0; + } + memcpy(&ctx->buf[partial_len], in, partial_needed); + + len = 0; + if (!evp_cipher(ctx, out, &len, ctx->buf, block_size)) + return 0; + total_len = len; + + in_len -= partial_needed; + in += partial_needed; + out += len; + } + + partial_len = in_len & block_mask; + if ((in_len -= partial_len) > 0) { + if (INT_MAX - in_len < total_len) + return 0; + len = 0; + if (!evp_cipher(ctx, out, &len, in, in_len)) + return 0; + if (INT_MAX - len < total_len) + return 0; + total_len += len; + } + + if ((ctx->partial_len = partial_len) > 0) + memcpy(ctx->buf, &in[in_len], partial_len); + + *out_len = total_len; + + return 1; +} + +int +EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) +{ + return EVP_EncryptFinal_ex(ctx, out, out_len); +} + +int +EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) +{ + const int block_size = ctx->cipher->block_size; + int partial_len = ctx->partial_len; + int pad; + + *out_len = 0; + + if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0) + return evp_cipher(ctx, out, out_len, NULL, 0); + + if (partial_len < 0 || partial_len >= block_size || + block_size > sizeof(ctx->buf)) { + EVPerror(EVP_R_BAD_BLOCK_LENGTH); + return 0; + } + if (block_size == 1) + return 1; + + if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) { + if (partial_len != 0) { + EVPerror(EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH); + return 0; + } + return 1; + } + + pad = block_size - partial_len; + memset(&ctx->buf[partial_len], pad, pad); + + return evp_cipher(ctx, out, out_len, ctx->buf, block_size); +} + +int +EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, + const unsigned char *key, const unsigned char *iv) +{ + return EVP_CipherInit(ctx, cipher, key, iv, 0); +} + +int +EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *engine, + const unsigned char *key, const unsigned char *iv) +{ + return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 0); +} + +int +EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len, + const unsigned char *in, int in_len) +{ + const int block_size = ctx->cipher->block_size; + const int block_mask = block_size - 1; + int len = 0, total_len = 0; + + *out_len = 0; + + if ((block_size & block_mask) != 0) + return 0; + + if (in_len < 0) + return 0; + + if (in_len == 0 && EVP_CIPHER_mode(ctx->cipher) != EVP_CIPH_CCM_MODE) + return 1; + + if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0) + return evp_cipher(ctx, out, out_len, in, in_len); + + if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) + return EVP_EncryptUpdate(ctx, out, out_len, in, in_len); + + if (block_size > sizeof(ctx->final)) { + EVPerror(EVP_R_BAD_BLOCK_LENGTH); + return 0; + } + + if (ctx->final_used) { + /* + * final_used is only set if partial_len is 0. Therefore the + * output from EVP_EncryptUpdate() is in_len & ~block_mask. + * Ensure (in_len & ~block_mask) + block_size doesn't overflow. + */ + if ((in_len & ~block_mask) > INT_MAX - block_size) { + EVPerror(EVP_R_TOO_LARGE); + return 0; + } + memcpy(out, ctx->final, block_size); + out += block_size; + total_len = block_size; + } + + ctx->final_used = 0; + + len = 0; + if (!EVP_EncryptUpdate(ctx, out, &len, in, in_len)) + return 0; + + /* Keep copy of last block if a multiple of block_size was decrypted. */ + if (block_size > 1 && ctx->partial_len == 0) { + if (len < block_size) + return 0; + len -= block_size; + memcpy(ctx->final, &out[len], block_size); + ctx->final_used = 1; + } + + if (len > INT_MAX - total_len) + return 0; + total_len += len; + + *out_len = total_len; + + return 1; +} + +int +EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) +{ + return EVP_DecryptFinal_ex(ctx, out, out_len); +} + +int +EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) +{ + const int block_size = ctx->cipher->block_size; + int partial_len = ctx->partial_len; + int i, pad, plain_len; + + *out_len = 0; + + if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0) + return evp_cipher(ctx, out, out_len, NULL, 0); + + if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) { + if (partial_len != 0) { + EVPerror(EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH); + return 0; + } + return 1; + } + + if (block_size == 1) + return 1; + + if (partial_len != 0 || !ctx->final_used) { + EVPerror(EVP_R_WRONG_FINAL_BLOCK_LENGTH); + return 0; + } + + if (block_size > sizeof(ctx->final)) { + EVPerror(EVP_R_BAD_BLOCK_LENGTH); + return 0; + } + + pad = ctx->final[block_size - 1]; + if (pad <= 0 || pad > block_size) { + EVPerror(EVP_R_BAD_DECRYPT); + return 0; + } + plain_len = block_size - pad; + for (i = plain_len; i < block_size; i++) { + if (ctx->final[i] != pad) { + EVPerror(EVP_R_BAD_DECRYPT); + return 0; + } + } + + memcpy(out, ctx->final, plain_len); + *out_len = plain_len; + + return 1; +} + +EVP_CIPHER_CTX * +EVP_CIPHER_CTX_new(void) +{ + return calloc(1, sizeof(EVP_CIPHER_CTX)); +} + +void +EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) +{ + if (ctx == NULL) + return; + + EVP_CIPHER_CTX_cleanup(ctx); + + free(ctx); +} + +void +EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx) +{ + memset(ctx, 0, sizeof(EVP_CIPHER_CTX)); +} + +int +EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *a) +{ + return EVP_CIPHER_CTX_cleanup(a); +} + +int +EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c) +{ + if (c->cipher != NULL) { + /* XXX - Avoid leaks, so ignore return value of cleanup()... */ + if (c->cipher->cleanup != NULL) + c->cipher->cleanup(c); + if (c->cipher_data != NULL) + explicit_bzero(c->cipher_data, c->cipher->ctx_size); + } + + /* XXX - store size of cipher_data so we can always freezero(). */ + free(c->cipher_data); + + explicit_bzero(c, sizeof(EVP_CIPHER_CTX)); + + return 1; +} + +int +EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen) +{ + if (c->cipher->flags & EVP_CIPH_CUSTOM_KEY_LENGTH) + return EVP_CIPHER_CTX_ctrl(c, EVP_CTRL_SET_KEY_LENGTH, + keylen, NULL); + if (c->key_len == keylen) + return 1; + if (keylen > 0 && (c->cipher->flags & EVP_CIPH_VARIABLE_LENGTH)) { + c->key_len = keylen; + return 1; + } + EVPerror(EVP_R_INVALID_KEY_LENGTH); + return 0; +} + +int +EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad) +{ + if (pad) + ctx->flags &= ~EVP_CIPH_NO_PADDING; + else + ctx->flags |= EVP_CIPH_NO_PADDING; + return 1; +} + +int +EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) +{ + int ret; + + if (!ctx->cipher) { + EVPerror(EVP_R_NO_CIPHER_SET); + return 0; + } + + if (!ctx->cipher->ctrl) { + EVPerror(EVP_R_CTRL_NOT_IMPLEMENTED); + return 0; + } + + ret = ctx->cipher->ctrl(ctx, type, arg, ptr); + if (ret == -1) { + EVPerror(EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED); + return 0; + } + return ret; +} + +int +EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key) +{ + if (ctx->cipher->flags & EVP_CIPH_RAND_KEY) + return EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_RAND_KEY, 0, key); + arc4random_buf(key, ctx->key_len); + return 1; +} + +int +EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) +{ + if (in == NULL || in->cipher == NULL) { + EVPerror(EVP_R_INPUT_NOT_INITIALIZED); + return 0; + } + + EVP_CIPHER_CTX_cleanup(out); + memcpy(out, in, sizeof *out); + + if (in->cipher_data && in->cipher->ctx_size) { + out->cipher_data = calloc(1, in->cipher->ctx_size); + if (out->cipher_data == NULL) { + EVPerror(ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size); + } + + if (in->cipher->flags & EVP_CIPH_CUSTOM_COPY) { + if (!in->cipher->ctrl((EVP_CIPHER_CTX *)in, EVP_CTRL_COPY, + 0, out)) { + /* + * If the custom copy control failed, assume that there + * may still be pointers copied in the cipher_data that + * we do not own. This may result in a leak from a bad + * custom copy control, but that's preferable to a + * double free... + */ + freezero(out->cipher_data, in->cipher->ctx_size); + out->cipher_data = NULL; + return 0; + } + } + + return 1; +} diff --git a/lib/libcrypto/evp/evp_digest.c b/lib/libcrypto/evp/evp_digest.c new file mode 100644 index 00000000000..deb282e4ecc --- /dev/null +++ b/lib/libcrypto/evp/evp_digest.c @@ -0,0 +1,369 @@ +/* $OpenBSD: evp_digest.c,v 1.1 2023/12/29 05:57:24 tb Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ +/* ==================================================================== + * Copyright (c) 1998-2001 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + +#include +#include + +#include + +#include +#include +#include + +#include "evp_local.h" + +int +EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type) +{ + EVP_MD_CTX_init(ctx); + return EVP_DigestInit_ex(ctx, type, NULL); +} + +int +EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl) +{ + EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); + + if (ctx->digest != type) { + if (ctx->digest && ctx->digest->ctx_size && ctx->md_data && + !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) { + freezero(ctx->md_data, ctx->digest->ctx_size); + ctx->md_data = NULL; + } + ctx->digest = type; + if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) { + ctx->update = type->update; + ctx->md_data = calloc(1, type->ctx_size); + if (ctx->md_data == NULL) { + EVP_PKEY_CTX_free(ctx->pctx); + ctx->pctx = NULL; + EVPerror(ERR_R_MALLOC_FAILURE); + return 0; + } + } + } + if (ctx->pctx) { + int r; + r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG, + EVP_PKEY_CTRL_DIGESTINIT, 0, ctx); + if (r <= 0 && (r != -2)) + return 0; + } + if (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) + return 1; + return ctx->digest->init(ctx); +} + +int +EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t count) +{ + return ctx->update(ctx, data, count); +} + +/* The caller can assume that this removes any secret data from the context */ +int +EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size) +{ + int ret; + + ret = EVP_DigestFinal_ex(ctx, md, size); + EVP_MD_CTX_cleanup(ctx); + return ret; +} + +/* The caller can assume that this removes any secret data from the context */ +int +EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size) +{ + int ret; + + if ((size_t)ctx->digest->md_size > EVP_MAX_MD_SIZE) { + EVPerror(EVP_R_TOO_LARGE); + return 0; + } + ret = ctx->digest->final(ctx, md); + if (size != NULL) + *size = ctx->digest->md_size; + if (ctx->digest->cleanup) { + ctx->digest->cleanup(ctx); + EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_CLEANED); + } + memset(ctx->md_data, 0, ctx->digest->ctx_size); + return ret; +} + +int +EVP_Digest(const void *data, size_t count, + unsigned char *md, unsigned int *size, const EVP_MD *type, ENGINE *impl) +{ + EVP_MD_CTX ctx; + int ret; + + EVP_MD_CTX_init(&ctx); + EVP_MD_CTX_set_flags(&ctx, EVP_MD_CTX_FLAG_ONESHOT); + ret = EVP_DigestInit_ex(&ctx, type, NULL) && + EVP_DigestUpdate(&ctx, data, count) && + EVP_DigestFinal_ex(&ctx, md, size); + EVP_MD_CTX_cleanup(&ctx); + + return ret; +} + +int +EVP_MD_CTX_copy(EVP_MD_CTX *out, const EVP_MD_CTX *in) +{ + EVP_MD_CTX_init(out); + return EVP_MD_CTX_copy_ex(out, in); +} + +int +EVP_MD_CTX_copy_ex(EVP_MD_CTX *out, const EVP_MD_CTX *in) +{ + unsigned char *tmp_buf; + + if ((in == NULL) || (in->digest == NULL)) { + EVPerror(EVP_R_INPUT_NOT_INITIALIZED); + return 0; + } + + if (out->digest == in->digest) { + tmp_buf = out->md_data; + EVP_MD_CTX_set_flags(out, EVP_MD_CTX_FLAG_REUSE); + } else + tmp_buf = NULL; + EVP_MD_CTX_cleanup(out); + memcpy(out, in, sizeof *out); + out->md_data = NULL; + out->pctx = NULL; + + /* + * Because of the EVP_PKEY_CTX_dup() below, EVP_MD_CTX_cleanup() needs + * to free out->pctx in all cases (even if this flag is set on in). + */ + EVP_MD_CTX_clear_flags(out, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX); + + if (in->md_data && out->digest->ctx_size) { + if (tmp_buf) { + out->md_data = tmp_buf; + } else { + out->md_data = calloc(1, out->digest->ctx_size); + if (out->md_data == NULL) { + EVPerror(ERR_R_MALLOC_FAILURE); + return 0; + } + } + memcpy(out->md_data, in->md_data, out->digest->ctx_size); + } + + out->update = in->update; + + if (in->pctx) { + out->pctx = EVP_PKEY_CTX_dup(in->pctx); + if (!out->pctx) { + EVP_MD_CTX_cleanup(out); + return 0; + } + } + + if (out->digest->copy) + return out->digest->copy(out, in); + + return 1; +} + +EVP_MD_CTX * +EVP_MD_CTX_new(void) +{ + return calloc(1, sizeof(EVP_MD_CTX)); +} + +void +EVP_MD_CTX_free(EVP_MD_CTX *ctx) +{ + if (ctx == NULL) + return; + + EVP_MD_CTX_cleanup(ctx); + + free(ctx); +} + +void +EVP_MD_CTX_init(EVP_MD_CTX *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); +} + +int +EVP_MD_CTX_reset(EVP_MD_CTX *ctx) +{ + return EVP_MD_CTX_cleanup(ctx); +} + +EVP_MD_CTX * +EVP_MD_CTX_create(void) +{ + return EVP_MD_CTX_new(); +} + +void +EVP_MD_CTX_destroy(EVP_MD_CTX *ctx) +{ + EVP_MD_CTX_free(ctx); +} + +/* This call frees resources associated with the context */ +int +EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) +{ + /* + * Don't assume ctx->md_data was cleaned in EVP_Digest_Final, + * because sometimes only copies of the context are ever finalised. + */ + if (ctx->digest && ctx->digest->cleanup && + !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_CLEANED)) + ctx->digest->cleanup(ctx); + if (ctx->digest && ctx->digest->ctx_size && ctx->md_data && + !EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_REUSE)) + freezero(ctx->md_data, ctx->digest->ctx_size); + /* + * If EVP_MD_CTX_FLAG_KEEP_PKEY_CTX is set, EVP_MD_CTX_set_pkey() was + * called and its strange API contract implies we don't own ctx->pctx. + */ + if (!EVP_MD_CTX_test_flags(ctx, EVP_MD_CTX_FLAG_KEEP_PKEY_CTX)) + EVP_PKEY_CTX_free(ctx->pctx); + memset(ctx, 0, sizeof(*ctx)); + + return 1; +} + +int +EVP_MD_CTX_ctrl(EVP_MD_CTX *ctx, int type, int arg, void *ptr) +{ + int ret; + + if (!ctx->digest) { + EVPerror(EVP_R_NO_CIPHER_SET); + return 0; + } + + if (!ctx->digest->md_ctrl) { + EVPerror(EVP_R_CTRL_NOT_IMPLEMENTED); + return 0; + } + + ret = ctx->digest->md_ctrl(ctx, type, arg, ptr); + if (ret == -1) { + EVPerror(EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED); + return 0; + } + return ret; +} diff --git a/lib/libcrypto/evp/evp_enc.c b/lib/libcrypto/evp/evp_enc.c deleted file mode 100644 index 3eef53c2d69..00000000000 --- a/lib/libcrypto/evp/evp_enc.c +++ /dev/null @@ -1,687 +0,0 @@ -/* $OpenBSD: evp_enc.c,v 1.81 2023/12/26 09:04:30 tb Exp $ */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] - */ - -#include -#include -#include -#include - -#include - -#include -#include - -#include "evp_local.h" - -int -EVP_CipherInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, - const unsigned char *key, const unsigned char *iv, int enc) -{ - return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, enc); -} - -int -EVP_CipherInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *engine, - const unsigned char *key, const unsigned char *iv, int enc) -{ - if (enc == -1) - enc = ctx->encrypt; - if (enc != 0) - enc = 1; - ctx->encrypt = enc; - - if (cipher == NULL && ctx->cipher == NULL) { - EVPerror(EVP_R_NO_CIPHER_SET); - return 0; - } - - /* - * Set up cipher and context. Allocate cipher data and initialize ctx. - * On ctx reuse only retain encryption direction and key wrap flag. - */ - if (cipher != NULL) { - unsigned long flags = ctx->flags; - - EVP_CIPHER_CTX_cleanup(ctx); - ctx->encrypt = enc; - ctx->flags = flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW; - - ctx->cipher = cipher; - ctx->key_len = cipher->key_len; - - if (ctx->cipher->ctx_size != 0) { - ctx->cipher_data = calloc(1, ctx->cipher->ctx_size); - if (ctx->cipher_data == NULL) { - EVPerror(ERR_R_MALLOC_FAILURE); - return 0; - } - } - - if ((ctx->cipher->flags & EVP_CIPH_CTRL_INIT) != 0) { - if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_INIT, 0, NULL)) { - EVPerror(EVP_R_INITIALIZATION_ERROR); - return 0; - } - } - } - - /* Block sizes must be a power of 2 due to the use of block_mask. */ - if (ctx->cipher->block_size != 1 && - ctx->cipher->block_size != 8 && - ctx->cipher->block_size != 16) { - EVPerror(EVP_R_BAD_BLOCK_LENGTH); - return 0; - } - - if ((ctx->flags & EVP_CIPHER_CTX_FLAG_WRAP_ALLOW) == 0 && - EVP_CIPHER_CTX_mode(ctx) == EVP_CIPH_WRAP_MODE) { - EVPerror(EVP_R_WRAP_MODE_NOT_ALLOWED); - return 0; - } - - if ((EVP_CIPHER_CTX_flags(ctx) & EVP_CIPH_CUSTOM_IV) == 0) { - int iv_len; - - switch (EVP_CIPHER_CTX_mode(ctx)) { - - case EVP_CIPH_STREAM_CIPHER: - case EVP_CIPH_ECB_MODE: - break; - - case EVP_CIPH_CFB_MODE: - case EVP_CIPH_OFB_MODE: - - ctx->num = 0; - /* fall-through */ - - case EVP_CIPH_CBC_MODE: - iv_len = EVP_CIPHER_CTX_iv_length(ctx); - if (iv_len < 0 || iv_len > sizeof(ctx->oiv)) { - EVPerror(EVP_R_IV_TOO_LARGE); - return 0; - } - if (iv != NULL) - memcpy(ctx->oiv, iv, iv_len); - memcpy(ctx->iv, ctx->oiv, iv_len); - break; - - case EVP_CIPH_CTR_MODE: - ctx->num = 0; - iv_len = EVP_CIPHER_CTX_iv_length(ctx); - if (iv_len < 0 || iv_len > sizeof(ctx->iv)) { - EVPerror(EVP_R_IV_TOO_LARGE); - return 0; - } - /* Don't reuse IV for CTR mode */ - if (iv != NULL) - memcpy(ctx->iv, iv, iv_len); - break; - - default: - return 0; - break; - } - } - - if (key != NULL || (ctx->cipher->flags & EVP_CIPH_ALWAYS_CALL_INIT) != 0) { - if (!ctx->cipher->init(ctx, key, iv, enc)) - return 0; - } - - ctx->partial_len = 0; - ctx->final_used = 0; - - return 1; -} - -int -EVP_CipherUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len, - const unsigned char *in, int in_len) -{ - if (ctx->encrypt) - return EVP_EncryptUpdate(ctx, out, out_len, in, in_len); - - return EVP_DecryptUpdate(ctx, out, out_len, in, in_len); -} - -int -EVP_CipherFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) -{ - if (ctx->encrypt) - return EVP_EncryptFinal_ex(ctx, out, out_len); - - return EVP_DecryptFinal_ex(ctx, out, out_len); -} - -int -EVP_CipherFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) -{ - if (ctx->encrypt) - return EVP_EncryptFinal_ex(ctx, out, out_len); - - return EVP_DecryptFinal_ex(ctx, out, out_len); -} - -int -EVP_EncryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, - const unsigned char *key, const unsigned char *iv) -{ - return EVP_CipherInit(ctx, cipher, key, iv, 1); -} - -int -EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *engine, - const unsigned char *key, const unsigned char *iv) -{ - return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 1); -} - -/* - * EVP_Cipher() is an implementation detail of EVP_Cipher{Update,Final}(). - * Behavior depends on EVP_CIPH_FLAG_CUSTOM_CIPHER being set on ctx->cipher. - * - * If the flag is set, do_cipher() operates in update mode if in != NULL and - * in final mode if in == NULL. It returns the number of bytes written to out - * (which may be 0) or -1 on error. - * - * If the flag is not set, do_cipher() assumes properly aligned data and that - * padding is handled correctly by the caller. Most do_cipher() methods will - * silently produce garbage and succeed. Returns 1 on success, 0 on error. - */ -int -EVP_Cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, const unsigned char *in, - unsigned int in_len) -{ - return ctx->cipher->do_cipher(ctx, out, in, in_len); -} - -static int -evp_cipher(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len, - const unsigned char *in, int in_len) -{ - int len; - - *out_len = 0; - - if (in_len < 0) - return 0; - - if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0) { - if ((len = ctx->cipher->do_cipher(ctx, out, in, in_len)) < 0) - return 0; - - *out_len = len; - return 1; - } - - if (!ctx->cipher->do_cipher(ctx, out, in, in_len)) - return 0; - - *out_len = in_len; - - return 1; -} - -int -EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len, - const unsigned char *in, int in_len) -{ - const int block_size = ctx->cipher->block_size; - const int block_mask = block_size - 1; - int partial_len = ctx->partial_len; - int len = 0, total_len = 0; - - *out_len = 0; - - if ((block_size & block_mask) != 0) - return 0; - - if (in_len < 0) - return 0; - - if (in_len == 0 && EVP_CIPHER_mode(ctx->cipher) != EVP_CIPH_CCM_MODE) - return 1; - - if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0) - return evp_cipher(ctx, out, out_len, in, in_len); - - if (partial_len == 0 && (in_len & block_mask) == 0) - return evp_cipher(ctx, out, out_len, in, in_len); - - if (partial_len < 0 || partial_len >= block_size || - block_size > sizeof(ctx->buf)) { - EVPerror(EVP_R_BAD_BLOCK_LENGTH); - return 0; - } - - if (partial_len > 0) { - int partial_needed; - - if ((partial_needed = block_size - partial_len) > in_len) { - memcpy(&ctx->buf[partial_len], in, in_len); - ctx->partial_len += in_len; - return 1; - } - - /* - * Once the first partial_needed bytes from in are processed, - * the number of multiples of block_size of data remaining is - * (in_len - partial_needed) & ~block_mask. Ensure that this - * plus the block processed from ctx->buf doesn't overflow. - */ - if (((in_len - partial_needed) & ~block_mask) > INT_MAX - block_size) { - EVPerror(EVP_R_TOO_LARGE); - return 0; - } - memcpy(&ctx->buf[partial_len], in, partial_needed); - - len = 0; - if (!evp_cipher(ctx, out, &len, ctx->buf, block_size)) - return 0; - total_len = len; - - in_len -= partial_needed; - in += partial_needed; - out += len; - } - - partial_len = in_len & block_mask; - if ((in_len -= partial_len) > 0) { - if (INT_MAX - in_len < total_len) - return 0; - len = 0; - if (!evp_cipher(ctx, out, &len, in, in_len)) - return 0; - if (INT_MAX - len < total_len) - return 0; - total_len += len; - } - - if ((ctx->partial_len = partial_len) > 0) - memcpy(ctx->buf, &in[in_len], partial_len); - - *out_len = total_len; - - return 1; -} - -int -EVP_EncryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) -{ - return EVP_EncryptFinal_ex(ctx, out, out_len); -} - -int -EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) -{ - const int block_size = ctx->cipher->block_size; - int partial_len = ctx->partial_len; - int pad; - - *out_len = 0; - - if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0) - return evp_cipher(ctx, out, out_len, NULL, 0); - - if (partial_len < 0 || partial_len >= block_size || - block_size > sizeof(ctx->buf)) { - EVPerror(EVP_R_BAD_BLOCK_LENGTH); - return 0; - } - if (block_size == 1) - return 1; - - if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) { - if (partial_len != 0) { - EVPerror(EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH); - return 0; - } - return 1; - } - - pad = block_size - partial_len; - memset(&ctx->buf[partial_len], pad, pad); - - return evp_cipher(ctx, out, out_len, ctx->buf, block_size); -} - -int -EVP_DecryptInit(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, - const unsigned char *key, const unsigned char *iv) -{ - return EVP_CipherInit(ctx, cipher, key, iv, 0); -} - -int -EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, ENGINE *engine, - const unsigned char *key, const unsigned char *iv) -{ - return EVP_CipherInit_ex(ctx, cipher, NULL, key, iv, 0); -} - -int -EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len, - const unsigned char *in, int in_len) -{ - const int block_size = ctx->cipher->block_size; - const int block_mask = block_size - 1; - int len = 0, total_len = 0; - - *out_len = 0; - - if ((block_size & block_mask) != 0) - return 0; - - if (in_len < 0) - return 0; - - if (in_len == 0 && EVP_CIPHER_mode(ctx->cipher) != EVP_CIPH_CCM_MODE) - return 1; - - if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0) - return evp_cipher(ctx, out, out_len, in, in_len); - - if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) - return EVP_EncryptUpdate(ctx, out, out_len, in, in_len); - - if (block_size > sizeof(ctx->final)) { - EVPerror(EVP_R_BAD_BLOCK_LENGTH); - return 0; - } - - if (ctx->final_used) { - /* - * final_used is only set if partial_len is 0. Therefore the - * output from EVP_EncryptUpdate() is in_len & ~block_mask. - * Ensure (in_len & ~block_mask) + block_size doesn't overflow. - */ - if ((in_len & ~block_mask) > INT_MAX - block_size) { - EVPerror(EVP_R_TOO_LARGE); - return 0; - } - memcpy(out, ctx->final, block_size); - out += block_size; - total_len = block_size; - } - - ctx->final_used = 0; - - len = 0; - if (!EVP_EncryptUpdate(ctx, out, &len, in, in_len)) - return 0; - - /* Keep copy of last block if a multiple of block_size was decrypted. */ - if (block_size > 1 && ctx->partial_len == 0) { - if (len < block_size) - return 0; - len -= block_size; - memcpy(ctx->final, &out[len], block_size); - ctx->final_used = 1; - } - - if (len > INT_MAX - total_len) - return 0; - total_len += len; - - *out_len = total_len; - - return 1; -} - -int -EVP_DecryptFinal(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) -{ - return EVP_DecryptFinal_ex(ctx, out, out_len); -} - -int -EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, int *out_len) -{ - const int block_size = ctx->cipher->block_size; - int partial_len = ctx->partial_len; - int i, pad, plain_len; - - *out_len = 0; - - if ((ctx->cipher->flags & EVP_CIPH_FLAG_CUSTOM_CIPHER) != 0) - return evp_cipher(ctx, out, out_len, NULL, 0); - - if ((ctx->flags & EVP_CIPH_NO_PADDING) != 0) { - if (partial_len != 0) { - EVPerror(EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH); - return 0; - } - return 1; - } - - if (block_size == 1) - return 1; - - if (partial_len != 0 || !ctx->final_used) { - EVPerror(EVP_R_WRONG_FINAL_BLOCK_LENGTH); - return 0; - } - - if (block_size > sizeof(ctx->final)) { - EVPerror(EVP_R_BAD_BLOCK_LENGTH); - return 0; - } - - pad = ctx->final[block_size - 1]; - if (pad <= 0 || pad > block_size) { - EVPerror(EVP_R_BAD_DECRYPT); - return 0; - } - plain_len = block_size - pad; - for (i = plain_len; i < block_size; i++) { - if (ctx->final[i] != pad) { - EVPerror(EVP_R_BAD_DECRYPT); - return 0; - } - } - - memcpy(out, ctx->final, plain_len); - *out_len = plain_len; - - return 1; -} - -EVP_CIPHER_CTX * -EVP_CIPHER_CTX_new(void) -{ - return calloc(1, sizeof(EVP_CIPHER_CTX)); -} - -void -EVP_CIPHER_CTX_free(EVP_CIPHER_CTX *ctx) -{ - if (ctx == NULL) - return; - - EVP_CIPHER_CTX_cleanup(ctx); - - free(ctx); -} - -void -EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx) -{ - memset(ctx, 0, sizeof(EVP_CIPHER_CTX)); -} - -int -EVP_CIPHER_CTX_reset(EVP_CIPHER_CTX *a) -{ - return EVP_CIPHER_CTX_cleanup(a); -} - -int -EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *c) -{ - if (c->cipher != NULL) { - /* XXX - Avoid leaks, so ignore return value of cleanup()... */ - if (c->cipher->cleanup != NULL) - c->cipher->cleanup(c); - if (c->cipher_data != NULL) - explicit_bzero(c->cipher_data, c->cipher->ctx_size); - } - - /* XXX - store size of cipher_data so we can always freezero(). */ - free(c->cipher_data); - - explicit_bzero(c, sizeof(EVP_CIPHER_CTX)); - - return 1; -} - -int -EVP_CIPHER_CTX_set_key_length(EVP_CIPHER_CTX *c, int keylen) -{ - if (c->cipher->flags & EVP_CIPH_CUSTOM_KEY_LENGTH) - return EVP_CIPHER_CTX_ctrl(c, EVP_CTRL_SET_KEY_LENGTH, - keylen, NULL); - if (c->key_len == keylen) - return 1; - if (keylen > 0 && (c->cipher->flags & EVP_CIPH_VARIABLE_LENGTH)) { - c->key_len = keylen; - return 1; - } - EVPerror(EVP_R_INVALID_KEY_LENGTH); - return 0; -} - -int -EVP_CIPHER_CTX_set_padding(EVP_CIPHER_CTX *ctx, int pad) -{ - if (pad) - ctx->flags &= ~EVP_CIPH_NO_PADDING; - else - ctx->flags |= EVP_CIPH_NO_PADDING; - return 1; -} - -int -EVP_CIPHER_CTX_ctrl(EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr) -{ - int ret; - - if (!ctx->cipher) { - EVPerror(EVP_R_NO_CIPHER_SET); - return 0; - } - - if (!ctx->cipher->ctrl) { - EVPerror(EVP_R_CTRL_NOT_IMPLEMENTED); - return 0; - } - - ret = ctx->cipher->ctrl(ctx, type, arg, ptr); - if (ret == -1) { - EVPerror(EVP_R_CTRL_OPERATION_NOT_IMPLEMENTED); - return 0; - } - return ret; -} - -int -EVP_CIPHER_CTX_rand_key(EVP_CIPHER_CTX *ctx, unsigned char *key) -{ - if (ctx->cipher->flags & EVP_CIPH_RAND_KEY) - return EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_RAND_KEY, 0, key); - arc4random_buf(key, ctx->key_len); - return 1; -} - -int -EVP_CIPHER_CTX_copy(EVP_CIPHER_CTX *out, const EVP_CIPHER_CTX *in) -{ - if (in == NULL || in->cipher == NULL) { - EVPerror(EVP_R_INPUT_NOT_INITIALIZED); - return 0; - } - - EVP_CIPHER_CTX_cleanup(out); - memcpy(out, in, sizeof *out); - - if (in->cipher_data && in->cipher->ctx_size) { - out->cipher_data = calloc(1, in->cipher->ctx_size); - if (out->cipher_data == NULL) { - EVPerror(ERR_R_MALLOC_FAILURE); - return 0; - } - memcpy(out->cipher_data, in->cipher_data, in->cipher->ctx_size); - } - - if (in->cipher->flags & EVP_CIPH_CUSTOM_COPY) { - if (!in->cipher->ctrl((EVP_CIPHER_CTX *)in, EVP_CTRL_COPY, - 0, out)) { - /* - * If the custom copy control failed, assume that there - * may still be pointers copied in the cipher_data that - * we do not own. This may result in a leak from a bad - * custom copy control, but that's preferable to a - * double free... - */ - freezero(out->cipher_data, in->cipher->ctx_size); - out->cipher_data = NULL; - return 0; - } - } - - return 1; -} diff --git a/lib/libcrypto/evp/evp_encode.c b/lib/libcrypto/evp/evp_encode.c new file mode 100644 index 00000000000..9387328f5ea --- /dev/null +++ b/lib/libcrypto/evp/evp_encode.c @@ -0,0 +1,414 @@ +/* $OpenBSD: evp_encode.c,v 1.1 2023/12/29 05:57:24 tb Exp $ */ +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + +#include +#include +#include + +#include + +#include "evp_local.h" + +static unsigned char conv_ascii2bin(unsigned char a); +#define conv_bin2ascii(a) (data_bin2ascii[(a)&0x3f]) + +/* 64 char lines + * pad input with 0 + * left over chars are set to = + * 1 byte => xx== + * 2 bytes => xxx= + * 3 bytes => xxxx + */ +#define BIN_PER_LINE (64/4*3) +#define CHUNKS_PER_LINE (64/4) +#define CHAR_PER_LINE (64+1) + +static const unsigned char data_bin2ascii[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\ +abcdefghijklmnopqrstuvwxyz0123456789+/"; + +/* 0xF0 is a EOLN + * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing). + * 0xF2 is EOF + * 0xE0 is ignore at start of line. + * 0xFF is error + */ + +#define B64_EOLN 0xF0 +#define B64_CR 0xF1 +#define B64_EOF 0xF2 +#define B64_WS 0xE0 +#define B64_ERROR 0xFF +#define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3) +#define B64_BASE64(a) !B64_NOT_BASE64(a) + +static const unsigned char data_ascii2bin[128] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, + 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, + 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, + 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static unsigned char +conv_ascii2bin(unsigned char a) +{ + if (a & 0x80) + return B64_ERROR; + return data_ascii2bin[a]; +} + +EVP_ENCODE_CTX * +EVP_ENCODE_CTX_new(void) +{ + return calloc(1, sizeof(EVP_ENCODE_CTX)); +} + +void +EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx) +{ + free(ctx); +} + +void +EVP_EncodeInit(EVP_ENCODE_CTX *ctx) +{ + ctx->length = 48; + ctx->num = 0; + ctx->line_num = 0; +} + +int +EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, + const unsigned char *in, int inl) +{ + int i, j; + size_t total = 0; + + *outl = 0; + if (inl <= 0) + return 0; + OPENSSL_assert(ctx->length <= (int)sizeof(ctx->enc_data)); + if (ctx->length - ctx->num > inl) { + memcpy(&(ctx->enc_data[ctx->num]), in, inl); + ctx->num += inl; + return 1; + } + if (ctx->num != 0) { + i = ctx->length - ctx->num; + memcpy(&(ctx->enc_data[ctx->num]), in, i); + in += i; + inl -= i; + j = EVP_EncodeBlock(out, ctx->enc_data, ctx->length); + ctx->num = 0; + out += j; + *(out++) = '\n'; + *out = '\0'; + total = j + 1; + } + while (inl >= ctx->length && total <= INT_MAX) { + j = EVP_EncodeBlock(out, in, ctx->length); + in += ctx->length; + inl -= ctx->length; + out += j; + *(out++) = '\n'; + *out = '\0'; + total += j + 1; + } + if (total > INT_MAX) { + /* Too much output data! */ + *outl = 0; + return 0; + } + if (inl != 0) + memcpy(&(ctx->enc_data[0]), in, inl); + ctx->num = inl; + *outl = total; + + return 1; +} + +void +EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl) +{ + unsigned int ret = 0; + + if (ctx->num != 0) { + ret = EVP_EncodeBlock(out, ctx->enc_data, ctx->num); + out[ret++] = '\n'; + out[ret] = '\0'; + ctx->num = 0; + } + *outl = ret; +} + +int +EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen) +{ + int i, ret = 0; + unsigned long l; + + for (i = dlen; i > 0; i -= 3) { + if (i >= 3) { + l = (((unsigned long)f[0]) << 16L) | + (((unsigned long)f[1]) << 8L) | f[2]; + *(t++) = conv_bin2ascii(l >> 18L); + *(t++) = conv_bin2ascii(l >> 12L); + *(t++) = conv_bin2ascii(l >> 6L); + *(t++) = conv_bin2ascii(l ); + } else { + l = ((unsigned long)f[0]) << 16L; + if (i == 2) + l |= ((unsigned long)f[1] << 8L); + + *(t++) = conv_bin2ascii(l >> 18L); + *(t++) = conv_bin2ascii(l >> 12L); + *(t++) = (i == 1) ? '=' : conv_bin2ascii(l >> 6L); + *(t++) = '='; + } + ret += 4; + f += 3; + } + + *t = '\0'; + return (ret); +} + +void +EVP_DecodeInit(EVP_ENCODE_CTX *ctx) +{ + ctx->num = 0; + ctx->length = 0; + ctx->line_num = 0; + ctx->expect_nl = 0; +} + +int +EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, + const unsigned char *in, int inl) +{ + int seof = 0, eof = 0, rv = -1, ret = 0, i, v, tmp, n, decoded_len; + unsigned char *d; + + n = ctx->num; + d = ctx->enc_data; + + if (n > 0 && d[n - 1] == '=') { + eof++; + if (n > 1 && d[n - 2] == '=') + eof++; + } + + /* Legacy behaviour: an empty input chunk signals end of input. */ + if (inl == 0) { + rv = 0; + goto end; + } + + for (i = 0; i < inl; i++) { + tmp = *(in++); + v = conv_ascii2bin(tmp); + if (v == B64_ERROR) { + rv = -1; + goto end; + } + + if (tmp == '=') { + eof++; + } else if (eof > 0 && B64_BASE64(v)) { + /* More data after padding. */ + rv = -1; + goto end; + } + + if (eof > 2) { + rv = -1; + goto end; + } + + if (v == B64_EOF) { + seof = 1; + goto tail; + } + + /* Only save valid base64 characters. */ + if (B64_BASE64(v)) { + if (n >= 64) { + /* + * We increment n once per loop, and empty the + * buffer as soon as we reach 64 characters, so + * this can only happen if someone's manually + * messed with the ctx. Refuse to write any + * more data. + */ + rv = -1; + goto end; + } + OPENSSL_assert(n < (int)sizeof(ctx->enc_data)); + d[n++] = tmp; + } + + if (n == 64) { + decoded_len = EVP_DecodeBlock(out, d, n); + n = 0; + if (decoded_len < 0 || eof > decoded_len) { + rv = -1; + goto end; + } + ret += decoded_len - eof; + out += decoded_len - eof; + } + } + + /* + * Legacy behaviour: if the current line is a full base64-block (i.e., + * has 0 mod 4 base64 characters), it is processed immediately. We keep + * this behaviour as applications may not be calling EVP_DecodeFinal + * properly. + */ + tail: + if (n > 0) { + if ((n & 3) == 0) { + decoded_len = EVP_DecodeBlock(out, d, n); + n = 0; + if (decoded_len < 0 || eof > decoded_len) { + rv = -1; + goto end; + } + ret += (decoded_len - eof); + } else if (seof) { + /* EOF in the middle of a base64 block. */ + rv = -1; + goto end; + } + } + + rv = seof || (n == 0 && eof) ? 0 : 1; + end: + /* Legacy behaviour. This should probably rather be zeroed on error. */ + *outl = ret; + ctx->num = n; + return (rv); +} + +int +EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n) +{ + int i, ret = 0, a, b, c, d; + unsigned long l; + + /* trim white space from the start of the line. */ + while ((conv_ascii2bin(*f) == B64_WS) && (n > 0)) { + f++; + n--; + } + + /* strip off stuff at the end of the line + * ascii2bin values B64_WS, B64_EOLN, B64_EOLN and B64_EOF */ + while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n - 1])))) + n--; + + if (n % 4 != 0) + return (-1); + + for (i = 0; i < n; i += 4) { + a = conv_ascii2bin(*(f++)); + b = conv_ascii2bin(*(f++)); + c = conv_ascii2bin(*(f++)); + d = conv_ascii2bin(*(f++)); + if ((a & 0x80) || (b & 0x80) || + (c & 0x80) || (d & 0x80)) + return (-1); + l = ((((unsigned long)a) << 18L) | + (((unsigned long)b) << 12L) | + (((unsigned long)c) << 6L) | + (((unsigned long)d))); + *(t++) = (unsigned char)(l >> 16L) & 0xff; + *(t++) = (unsigned char)(l >> 8L) & 0xff; + *(t++) = (unsigned char)(l) & 0xff; + ret += 3; + } + return (ret); +} + +int +EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl) +{ + int i; + + *outl = 0; + if (ctx->num != 0) { + i = EVP_DecodeBlock(out, ctx->enc_data, ctx->num); + if (i < 0) + return (-1); + ctx->num = 0; + *outl = i; + return (1); + } else + return (1); +}