1/* $OpenBSD: bio_enc.c,v 1.33 2024/04/12 11:10:34 tb Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved.
4 *
5 * This package is an SSL implementation written
6 * by Eric Young (eay@cryptsoft.com).
7 * The implementation was written so as to conform with Netscapes SSL.
8 *
9 * This library is free for commercial and non-commercial use as long as
10 * the following conditions are aheared to.  The following conditions
11 * apply to all code found in this distribution, be it the RC4, RSA,
12 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13 * included with this distribution is covered by the same copyright terms
14 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15 *
16 * Copyright remains Eric Young's, and as such any Copyright notices in
17 * the code are not to be removed.
18 * If this package is used in a product, Eric Young should be given attribution
19 * as the author of the parts of the library used.
20 * This can be in the form of a textual message at program startup or
21 * in documentation (online or textual) provided with the package.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the copyright
27 *    notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 *    notice, this list of conditions and the following disclaimer in the
30 *    documentation and/or other materials provided with the distribution.
31 * 3. All advertising materials mentioning features or use of this software
32 *    must display the following acknowledgement:
33 *    "This product includes cryptographic software written by
34 *     Eric Young (eay@cryptsoft.com)"
35 *    The word 'cryptographic' can be left out if the rouines from the library
36 *    being used are not cryptographic related :-).
37 * 4. If you include any Windows specific code (or a derivative thereof) from
38 *    the apps directory (application code) you must include an acknowledgement:
39 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40 *
41 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 * SUCH DAMAGE.
52 *
53 * The licence and distribution terms for any publically available version or
54 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55 * copied and put under another distribution licence
56 * [including the GNU Public Licence.]
57 */
58
59#include <errno.h>
60#include <stdio.h>
61#include <stdlib.h>
62#include <string.h>
63
64#include <openssl/buffer.h>
65#include <openssl/evp.h>
66
67#include "bio_local.h"
68#include "evp_local.h"
69
70static int enc_write(BIO *h, const char *buf, int num);
71static int enc_read(BIO *h, char *buf, int size);
72/*static int enc_puts(BIO *h, const char *str); */
73/*static int enc_gets(BIO *h, char *str, int size); */
74static long enc_ctrl(BIO *h, int cmd, long arg1, void *arg2);
75static int enc_new(BIO *h);
76static int enc_free(BIO *data);
77static long enc_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fps);
78#define ENC_BLOCK_SIZE	(1024*4)
79#define BUF_OFFSET	(EVP_MAX_BLOCK_LENGTH*2)
80
81typedef struct enc_struct {
82	int buf_len;
83	int buf_off;
84	int cont;		/* <= 0 when finished */
85	int finished;
86	int ok;			/* bad decrypt */
87	EVP_CIPHER_CTX *cipher_ctx;
88	/* buf is larger than ENC_BLOCK_SIZE because EVP_DecryptUpdate
89	 * can return up to a block more data than is presented to it
90	 */
91	char buf[ENC_BLOCK_SIZE + BUF_OFFSET + 2];
92} BIO_ENC_CTX;
93
94static const BIO_METHOD methods_enc = {
95	.type = BIO_TYPE_CIPHER,
96	.name = "cipher",
97	.bwrite = enc_write,
98	.bread = enc_read,
99	.ctrl = enc_ctrl,
100	.create = enc_new,
101	.destroy = enc_free,
102	.callback_ctrl = enc_callback_ctrl
103};
104
105const BIO_METHOD *
106BIO_f_cipher(void)
107{
108	return &methods_enc;
109}
110LCRYPTO_ALIAS(BIO_f_cipher);
111
112static void
113bio_enc_ctx_free(BIO_ENC_CTX *ctx)
114{
115	if (ctx == NULL)
116		return;
117
118	EVP_CIPHER_CTX_free(ctx->cipher_ctx);
119	freezero(ctx, sizeof(*ctx));
120}
121
122static int
123enc_new(BIO *bio)
124{
125	BIO_ENC_CTX *ctx;
126	int ret = 0;
127
128	if ((ctx = calloc(1, sizeof(BIO_ENC_CTX))) == NULL)
129		goto err;
130	if ((ctx->cipher_ctx = EVP_CIPHER_CTX_new()) == NULL)
131		goto err;
132
133	ctx->cont = 1;
134	ctx->ok = 1;
135
136	bio->ptr = ctx;
137	ctx = NULL;
138
139	ret = 1;
140
141 err:
142	bio_enc_ctx_free(ctx);
143
144	return ret;
145}
146
147static int
148enc_free(BIO *bio)
149{
150	if (bio == NULL)
151		return 0;
152
153	bio_enc_ctx_free(bio->ptr);
154	explicit_bzero(bio, sizeof(*bio));
155
156	return 1;
157}
158
159static int
160enc_read(BIO *bio, char *out, int outl)
161{
162	BIO_ENC_CTX *ctx;
163	int ret = 0, i;
164
165	if (out == NULL)
166		return 0;
167	ctx = bio->ptr;
168
169	if (ctx == NULL || bio->next_bio == NULL)
170		return 0;
171
172	/* First check if there are bytes decoded/encoded */
173	if (ctx->buf_len > 0) {
174		i = ctx->buf_len - ctx->buf_off;
175		if (i > outl)
176			i = outl;
177		memcpy(out, &(ctx->buf[ctx->buf_off]), i);
178		ret = i;
179		out += i;
180		outl -= i;
181		ctx->buf_off += i;
182		if (ctx->buf_len == ctx->buf_off) {
183			ctx->buf_len = 0;
184			ctx->buf_off = 0;
185		}
186	}
187
188	/* At this point, we have room of outl bytes and an empty
189	 * buffer, so we should read in some more. */
190
191	while (outl > 0) {
192		if (ctx->cont <= 0)
193			break;
194
195		/* read in at IV offset, read the EVP_Cipher
196		 * documentation about why */
197		i = BIO_read(bio->next_bio, &ctx->buf[BUF_OFFSET],
198		    ENC_BLOCK_SIZE);
199
200		if (i <= 0) {
201			/* Should be continue next time we are called? */
202			if (!BIO_should_retry(bio->next_bio)) {
203				ctx->cont = i;
204				i = EVP_CipherFinal_ex(ctx->cipher_ctx,
205				    (unsigned char *)ctx->buf,
206				    &(ctx->buf_len));
207				ctx->ok = i;
208				ctx->buf_off = 0;
209			} else {
210				ret = (ret == 0) ? i : ret;
211				break;
212			}
213		} else {
214			EVP_CipherUpdate(ctx->cipher_ctx,
215			    (unsigned char *)ctx->buf, &ctx->buf_len,
216			    (unsigned char *)&ctx->buf[BUF_OFFSET], i);
217			ctx->cont = 1;
218			/* Note: it is possible for EVP_CipherUpdate to
219			 * decrypt zero bytes because this is or looks like
220			 * the final block: if this happens we should retry
221			 * and either read more data or decrypt the final
222			 * block
223			 */
224			if (ctx->buf_len == 0)
225				continue;
226		}
227
228		if (ctx->buf_len <= outl)
229			i = ctx->buf_len;
230		else
231			i = outl;
232		if (i <= 0)
233			break;
234		memcpy(out, ctx->buf, i);
235		ret += i;
236		ctx->buf_off = i;
237		outl -= i;
238		out += i;
239	}
240
241	BIO_clear_retry_flags(bio);
242	BIO_copy_next_retry(bio);
243	return ret == 0 ? ctx->cont : ret;
244}
245
246static int
247enc_write(BIO *bio, const char *in, int inl)
248{
249	BIO_ENC_CTX *ctx;
250	int ret = 0, n, i;
251
252	ctx = bio->ptr;
253	ret = inl;
254
255	BIO_clear_retry_flags(bio);
256	n = ctx->buf_len - ctx->buf_off;
257	while (n > 0) {
258		i = BIO_write(bio->next_bio, &(ctx->buf[ctx->buf_off]), n);
259		if (i <= 0) {
260			BIO_copy_next_retry(bio);
261			return i;
262		}
263		ctx->buf_off += i;
264		n -= i;
265	}
266	/* at this point all pending data has been written */
267
268	if (in == NULL || inl <= 0)
269		return 0;
270
271	ctx->buf_off = 0;
272	while (inl > 0) {
273		n = inl > ENC_BLOCK_SIZE ? ENC_BLOCK_SIZE : inl;
274		EVP_CipherUpdate(ctx->cipher_ctx,
275		    (unsigned char *)ctx->buf, &ctx->buf_len,
276		    (unsigned char *)in, n);
277		inl -= n;
278		in += n;
279
280		ctx->buf_off = 0;
281		n = ctx->buf_len;
282		while (n > 0) {
283			i = BIO_write(bio->next_bio, &ctx->buf[ctx->buf_off], n);
284			if (i <= 0) {
285				BIO_copy_next_retry(bio);
286				return ret == inl ? i : ret - inl;
287			}
288			n -= i;
289			ctx->buf_off += i;
290		}
291		ctx->buf_len = 0;
292		ctx->buf_off = 0;
293	}
294	BIO_copy_next_retry(bio);
295
296	return ret;
297}
298
299static long
300enc_ctrl(BIO *bio, int cmd, long num, void *ptr)
301{
302	BIO *dbio;
303	BIO_ENC_CTX *ctx, *dctx;
304	EVP_CIPHER_CTX **c_ctx;
305	int i;
306	long ret = 1;
307
308	ctx = bio->ptr;
309
310	switch (cmd) {
311	case BIO_CTRL_RESET:
312		ctx->ok = 1;
313		ctx->finished = 0;
314		EVP_CipherInit_ex(ctx->cipher_ctx, NULL, NULL, NULL, NULL,
315		    ctx->cipher_ctx->encrypt);
316		ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
317		break;
318	case BIO_CTRL_EOF:	/* More to read */
319		if (ctx->cont <= 0)
320			ret = 1;
321		else
322			ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
323		break;
324	case BIO_CTRL_WPENDING:
325		ret = ctx->buf_len - ctx->buf_off;
326		if (ret <= 0)
327			ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
328		break;
329	case BIO_CTRL_PENDING: /* More to read in buffer */
330		ret = ctx->buf_len - ctx->buf_off;
331		if (ret <= 0)
332			ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
333		break;
334	case BIO_CTRL_FLUSH:
335		/* do a final write */
336 again:
337		while (ctx->buf_len != ctx->buf_off) {
338			i = enc_write(bio, NULL, 0);
339			if (i < 0)
340				return i;
341		}
342
343		if (!ctx->finished) {
344			ctx->finished = 1;
345			ctx->buf_off = 0;
346			ret = EVP_CipherFinal_ex(ctx->cipher_ctx,
347			    (unsigned char *)ctx->buf,
348			    &ctx->buf_len);
349			ctx->ok = (int)ret;
350			if (ret <= 0)
351				break;
352
353			/* push out the bytes */
354			goto again;
355		}
356
357		/* Finally flush the underlying BIO */
358		ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
359		break;
360	case BIO_C_GET_CIPHER_STATUS:
361		ret = (long)ctx->ok;
362		break;
363	case BIO_C_DO_STATE_MACHINE:
364		BIO_clear_retry_flags(bio);
365		ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
366		BIO_copy_next_retry(bio);
367		break;
368	case BIO_C_GET_CIPHER_CTX:
369		c_ctx = ptr;
370		*c_ctx = ctx->cipher_ctx;
371		bio->init = 1;
372		break;
373	case BIO_CTRL_DUP:
374		dbio = ptr;
375		dctx = dbio->ptr;
376		ret = EVP_CIPHER_CTX_copy(dctx->cipher_ctx, ctx->cipher_ctx);
377		if (ret)
378			dbio->init = 1;
379		break;
380	default:
381		ret = BIO_ctrl(bio->next_bio, cmd, num, ptr);
382		break;
383	}
384
385	return ret;
386}
387
388static long
389enc_callback_ctrl(BIO *bio, int cmd, BIO_info_cb *fp)
390{
391	long ret = 1;
392
393	if (bio->next_bio == NULL)
394		return 0;
395
396	switch (cmd) {
397	default:
398		ret = BIO_callback_ctrl(bio->next_bio, cmd, fp);
399		break;
400	}
401
402	return ret;
403}
404
405int
406BIO_set_cipher(BIO *bio, const EVP_CIPHER *c, const unsigned char *k,
407    const unsigned char *i, int e)
408{
409	BIO_ENC_CTX *ctx;
410	long (*cb)(BIO *, int, const char *, int, long, long);
411
412	if (bio == NULL)
413		return 0;
414
415	if ((ctx = BIO_get_data(bio)) == NULL)
416		return 0;
417
418	if ((cb = BIO_get_callback(bio)) != NULL) {
419		if (cb(bio, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 0L) <= 0)
420			return 0;
421	}
422
423	BIO_set_init(bio, 1);
424
425	if (!EVP_CipherInit_ex(ctx->cipher_ctx, c, NULL, k, i, e))
426		return 0;
427
428	if (cb != NULL)
429		return cb(bio, BIO_CB_CTRL, (const char *)c, BIO_CTRL_SET, e, 1L);
430
431	return 1;
432}
433LCRYPTO_ALIAS(BIO_set_cipher);
434