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