1 /*
2 * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
3 *
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
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
8 */
9
10 #include <stdio.h>
11 #include <limits.h>
12 #include "internal/cryptlib.h"
13 #include <openssl/evp.h>
14 #include "crypto/evp.h"
15 #include "evp_local.h"
16
17 static unsigned char conv_ascii2bin(unsigned char a,
18 const unsigned char *table);
19 static int evp_encodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
20 const unsigned char *f, int dlen);
21 static int evp_decodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
22 const unsigned char *f, int n);
23
24 #ifndef CHARSET_EBCDIC
25 # define conv_bin2ascii(a, table) ((table)[(a)&0x3f])
26 #else
27 /*
28 * We assume that PEM encoded files are EBCDIC files (i.e., printable text
29 * files). Convert them here while decoding. When encoding, output is EBCDIC
30 * (text) format again. (No need for conversion in the conv_bin2ascii macro,
31 * as the underlying textstring data_bin2ascii[] is already EBCDIC)
32 */
33 # define conv_bin2ascii(a, table) ((table)[(a)&0x3f])
34 #endif
35
36 /*-
37 * 64 char lines
38 * pad input with 0
39 * left over chars are set to =
40 * 1 byte => xx==
41 * 2 bytes => xxx=
42 * 3 bytes => xxxx
43 */
44 #define BIN_PER_LINE (64/4*3)
45 #define CHUNKS_PER_LINE (64/4)
46 #define CHAR_PER_LINE (64+1)
47
48 static const unsigned char data_bin2ascii[65] =
49 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
50
51 /* SRP uses a different base64 alphabet */
52 static const unsigned char srpdata_bin2ascii[65] =
53 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./";
54
55
56 /*-
57 * 0xF0 is a EOLN
58 * 0xF1 is ignore but next needs to be 0xF0 (for \r\n processing).
59 * 0xF2 is EOF
60 * 0xE0 is ignore at start of line.
61 * 0xFF is error
62 */
63
64 #define B64_EOLN 0xF0
65 #define B64_CR 0xF1
66 #define B64_EOF 0xF2
67 #define B64_WS 0xE0
68 #define B64_ERROR 0xFF
69 #define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3)
70 #define B64_BASE64(a) (!B64_NOT_BASE64(a))
71
72 static const unsigned char data_ascii2bin[128] = {
73 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
74 0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
75 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
76 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
77 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
78 0xFF, 0xFF, 0xFF, 0x3E, 0xFF, 0xF2, 0xFF, 0x3F,
79 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
80 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
81 0xFF, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
82 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
83 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
84 0x17, 0x18, 0x19, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
85 0xFF, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
86 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
87 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30,
88 0x31, 0x32, 0x33, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
89 };
90
91 static const unsigned char srpdata_ascii2bin[128] = {
92 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
93 0xFF, 0xE0, 0xF0, 0xFF, 0xFF, 0xF1, 0xFF, 0xFF,
94 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
95 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
96 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
97 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF2, 0x3E, 0x3F,
98 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
99 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF,
100 0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
101 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
102 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20,
103 0x21, 0x22, 0x23, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
104 0xFF, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A,
105 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32,
106 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
107 0x3B, 0x3C, 0x3D, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
108 };
109
110 #ifndef CHARSET_EBCDIC
conv_ascii2bin(unsigned char a,const unsigned char * table)111 static unsigned char conv_ascii2bin(unsigned char a, const unsigned char *table)
112 {
113 if (a & 0x80)
114 return B64_ERROR;
115 return table[a];
116 }
117 #else
conv_ascii2bin(unsigned char a,const unsigned char * table)118 static unsigned char conv_ascii2bin(unsigned char a, const unsigned char *table)
119 {
120 a = os_toascii[a];
121 if (a & 0x80)
122 return B64_ERROR;
123 return table[a];
124 }
125 #endif
126
EVP_ENCODE_CTX_new(void)127 EVP_ENCODE_CTX *EVP_ENCODE_CTX_new(void)
128 {
129 return OPENSSL_zalloc(sizeof(EVP_ENCODE_CTX));
130 }
131
EVP_ENCODE_CTX_free(EVP_ENCODE_CTX * ctx)132 void EVP_ENCODE_CTX_free(EVP_ENCODE_CTX *ctx)
133 {
134 OPENSSL_free(ctx);
135 }
136
EVP_ENCODE_CTX_copy(EVP_ENCODE_CTX * dctx,const EVP_ENCODE_CTX * sctx)137 int EVP_ENCODE_CTX_copy(EVP_ENCODE_CTX *dctx, const EVP_ENCODE_CTX *sctx)
138 {
139 memcpy(dctx, sctx, sizeof(EVP_ENCODE_CTX));
140
141 return 1;
142 }
143
EVP_ENCODE_CTX_num(EVP_ENCODE_CTX * ctx)144 int EVP_ENCODE_CTX_num(EVP_ENCODE_CTX *ctx)
145 {
146 return ctx->num;
147 }
148
evp_encode_ctx_set_flags(EVP_ENCODE_CTX * ctx,unsigned int flags)149 void evp_encode_ctx_set_flags(EVP_ENCODE_CTX *ctx, unsigned int flags)
150 {
151 ctx->flags = flags;
152 }
153
EVP_EncodeInit(EVP_ENCODE_CTX * ctx)154 void EVP_EncodeInit(EVP_ENCODE_CTX *ctx)
155 {
156 ctx->length = 48;
157 ctx->num = 0;
158 ctx->line_num = 0;
159 ctx->flags = 0;
160 }
161
EVP_EncodeUpdate(EVP_ENCODE_CTX * ctx,unsigned char * out,int * outl,const unsigned char * in,int inl)162 int EVP_EncodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
163 const unsigned char *in, int inl)
164 {
165 int i, j;
166 size_t total = 0;
167
168 *outl = 0;
169 if (inl <= 0)
170 return 0;
171 OPENSSL_assert(ctx->length <= (int)sizeof(ctx->enc_data));
172 if (ctx->length - ctx->num > inl) {
173 memcpy(&(ctx->enc_data[ctx->num]), in, inl);
174 ctx->num += inl;
175 return 1;
176 }
177 if (ctx->num != 0) {
178 i = ctx->length - ctx->num;
179 memcpy(&(ctx->enc_data[ctx->num]), in, i);
180 in += i;
181 inl -= i;
182 j = evp_encodeblock_int(ctx, out, ctx->enc_data, ctx->length);
183 ctx->num = 0;
184 out += j;
185 total = j;
186 if ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0) {
187 *(out++) = '\n';
188 total++;
189 }
190 *out = '\0';
191 }
192 while (inl >= ctx->length && total <= INT_MAX) {
193 j = evp_encodeblock_int(ctx, out, in, ctx->length);
194 in += ctx->length;
195 inl -= ctx->length;
196 out += j;
197 total += j;
198 if ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0) {
199 *(out++) = '\n';
200 total++;
201 }
202 *out = '\0';
203 }
204 if (total > INT_MAX) {
205 /* Too much output data! */
206 *outl = 0;
207 return 0;
208 }
209 if (inl != 0)
210 memcpy(&(ctx->enc_data[0]), in, inl);
211 ctx->num = inl;
212 *outl = total;
213
214 return 1;
215 }
216
EVP_EncodeFinal(EVP_ENCODE_CTX * ctx,unsigned char * out,int * outl)217 void EVP_EncodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl)
218 {
219 unsigned int ret = 0;
220
221 if (ctx->num != 0) {
222 ret = evp_encodeblock_int(ctx, out, ctx->enc_data, ctx->num);
223 if ((ctx->flags & EVP_ENCODE_CTX_NO_NEWLINES) == 0)
224 out[ret++] = '\n';
225 out[ret] = '\0';
226 ctx->num = 0;
227 }
228 *outl = ret;
229 }
230
evp_encodeblock_int(EVP_ENCODE_CTX * ctx,unsigned char * t,const unsigned char * f,int dlen)231 static int evp_encodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
232 const unsigned char *f, int dlen)
233 {
234 int i, ret = 0;
235 unsigned long l;
236 const unsigned char *table;
237
238 if (ctx != NULL && (ctx->flags & EVP_ENCODE_CTX_USE_SRP_ALPHABET) != 0)
239 table = srpdata_bin2ascii;
240 else
241 table = data_bin2ascii;
242
243 for (i = dlen; i > 0; i -= 3) {
244 if (i >= 3) {
245 l = (((unsigned long)f[0]) << 16L) |
246 (((unsigned long)f[1]) << 8L) | f[2];
247 *(t++) = conv_bin2ascii(l >> 18L, table);
248 *(t++) = conv_bin2ascii(l >> 12L, table);
249 *(t++) = conv_bin2ascii(l >> 6L, table);
250 *(t++) = conv_bin2ascii(l, table);
251 } else {
252 l = ((unsigned long)f[0]) << 16L;
253 if (i == 2)
254 l |= ((unsigned long)f[1] << 8L);
255
256 *(t++) = conv_bin2ascii(l >> 18L, table);
257 *(t++) = conv_bin2ascii(l >> 12L, table);
258 *(t++) = (i == 1) ? '=' : conv_bin2ascii(l >> 6L, table);
259 *(t++) = '=';
260 }
261 ret += 4;
262 f += 3;
263 }
264
265 *t = '\0';
266 return ret;
267 }
268
EVP_EncodeBlock(unsigned char * t,const unsigned char * f,int dlen)269 int EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen)
270 {
271 return evp_encodeblock_int(NULL, t, f, dlen);
272 }
273
EVP_DecodeInit(EVP_ENCODE_CTX * ctx)274 void EVP_DecodeInit(EVP_ENCODE_CTX *ctx)
275 {
276 /* Only ctx->num and ctx->flags are used during decoding. */
277 ctx->num = 0;
278 ctx->length = 0;
279 ctx->line_num = 0;
280 ctx->flags = 0;
281 }
282
283 /*-
284 * -1 for error
285 * 0 for last line
286 * 1 for full line
287 *
288 * Note: even though EVP_DecodeUpdate attempts to detect and report end of
289 * content, the context doesn't currently remember it and will accept more data
290 * in the next call. Therefore, the caller is responsible for checking and
291 * rejecting a 0 return value in the middle of content.
292 *
293 * Note: even though EVP_DecodeUpdate has historically tried to detect end of
294 * content based on line length, this has never worked properly. Therefore,
295 * we now return 0 when one of the following is true:
296 * - Padding or B64_EOF was detected and the last block is complete.
297 * - Input has zero-length.
298 * -1 is returned if:
299 * - Invalid characters are detected.
300 * - There is extra trailing padding, or data after padding.
301 * - B64_EOF is detected after an incomplete base64 block.
302 */
EVP_DecodeUpdate(EVP_ENCODE_CTX * ctx,unsigned char * out,int * outl,const unsigned char * in,int inl)303 int EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
304 const unsigned char *in, int inl)
305 {
306 int seof = 0, eof = 0, rv = -1, ret = 0, i, v, tmp, n, decoded_len;
307 unsigned char *d;
308 const unsigned char *table;
309
310 n = ctx->num;
311 d = ctx->enc_data;
312
313 if (n > 0 && d[n - 1] == '=') {
314 eof++;
315 if (n > 1 && d[n - 2] == '=')
316 eof++;
317 }
318
319 /* Legacy behaviour: an empty input chunk signals end of input. */
320 if (inl == 0) {
321 rv = 0;
322 goto end;
323 }
324
325 if ((ctx->flags & EVP_ENCODE_CTX_USE_SRP_ALPHABET) != 0)
326 table = srpdata_ascii2bin;
327 else
328 table = data_ascii2bin;
329
330 for (i = 0; i < inl; i++) {
331 tmp = *(in++);
332 v = conv_ascii2bin(tmp, table);
333 if (v == B64_ERROR) {
334 rv = -1;
335 goto end;
336 }
337
338 if (tmp == '=') {
339 eof++;
340 } else if (eof > 0 && B64_BASE64(v)) {
341 /* More data after padding. */
342 rv = -1;
343 goto end;
344 }
345
346 if (eof > 2) {
347 rv = -1;
348 goto end;
349 }
350
351 if (v == B64_EOF) {
352 seof = 1;
353 goto tail;
354 }
355
356 /* Only save valid base64 characters. */
357 if (B64_BASE64(v)) {
358 if (n >= 64) {
359 /*
360 * We increment n once per loop, and empty the buffer as soon as
361 * we reach 64 characters, so this can only happen if someone's
362 * manually messed with the ctx. Refuse to write any more data.
363 */
364 rv = -1;
365 goto end;
366 }
367 OPENSSL_assert(n < (int)sizeof(ctx->enc_data));
368 d[n++] = tmp;
369 }
370
371 if (n == 64) {
372 decoded_len = evp_decodeblock_int(ctx, out, d, n);
373 n = 0;
374 if (decoded_len < 0 || eof > decoded_len) {
375 rv = -1;
376 goto end;
377 }
378 ret += decoded_len - eof;
379 out += decoded_len - eof;
380 }
381 }
382
383 /*
384 * Legacy behaviour: if the current line is a full base64-block (i.e., has
385 * 0 mod 4 base64 characters), it is processed immediately. We keep this
386 * behaviour as applications may not be calling EVP_DecodeFinal properly.
387 */
388 tail:
389 if (n > 0) {
390 if ((n & 3) == 0) {
391 decoded_len = evp_decodeblock_int(ctx, out, d, n);
392 n = 0;
393 if (decoded_len < 0 || eof > decoded_len) {
394 rv = -1;
395 goto end;
396 }
397 ret += (decoded_len - eof);
398 } else if (seof) {
399 /* EOF in the middle of a base64 block. */
400 rv = -1;
401 goto end;
402 }
403 }
404
405 rv = seof || (n == 0 && eof) ? 0 : 1;
406 end:
407 /* Legacy behaviour. This should probably rather be zeroed on error. */
408 *outl = ret;
409 ctx->num = n;
410 return rv;
411 }
412
evp_decodeblock_int(EVP_ENCODE_CTX * ctx,unsigned char * t,const unsigned char * f,int n)413 static int evp_decodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
414 const unsigned char *f, int n)
415 {
416 int i, ret = 0, a, b, c, d;
417 unsigned long l;
418 const unsigned char *table;
419
420 if (ctx != NULL && (ctx->flags & EVP_ENCODE_CTX_USE_SRP_ALPHABET) != 0)
421 table = srpdata_ascii2bin;
422 else
423 table = data_ascii2bin;
424
425 /* trim whitespace from the start of the line. */
426 while ((n > 0) && (conv_ascii2bin(*f, table) == B64_WS)) {
427 f++;
428 n--;
429 }
430
431 /*
432 * strip off stuff at the end of the line ascii2bin values B64_WS,
433 * B64_EOLN, B64_EOLN and B64_EOF
434 */
435 while ((n > 3) && (B64_NOT_BASE64(conv_ascii2bin(f[n - 1], table))))
436 n--;
437
438 if (n % 4 != 0)
439 return -1;
440
441 for (i = 0; i < n; i += 4) {
442 a = conv_ascii2bin(*(f++), table);
443 b = conv_ascii2bin(*(f++), table);
444 c = conv_ascii2bin(*(f++), table);
445 d = conv_ascii2bin(*(f++), table);
446 if ((a | b | c | d) & 0x80)
447 return -1;
448 l = ((((unsigned long)a) << 18L) |
449 (((unsigned long)b) << 12L) |
450 (((unsigned long)c) << 6L) | (((unsigned long)d)));
451 *(t++) = (unsigned char)(l >> 16L) & 0xff;
452 *(t++) = (unsigned char)(l >> 8L) & 0xff;
453 *(t++) = (unsigned char)(l) & 0xff;
454 ret += 3;
455 }
456 return ret;
457 }
458
EVP_DecodeBlock(unsigned char * t,const unsigned char * f,int n)459 int EVP_DecodeBlock(unsigned char *t, const unsigned char *f, int n)
460 {
461 return evp_decodeblock_int(NULL, t, f, n);
462 }
463
EVP_DecodeFinal(EVP_ENCODE_CTX * ctx,unsigned char * out,int * outl)464 int EVP_DecodeFinal(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl)
465 {
466 int i;
467
468 *outl = 0;
469 if (ctx->num != 0) {
470 i = evp_decodeblock_int(ctx, out, ctx->enc_data, ctx->num);
471 if (i < 0)
472 return -1;
473 ctx->num = 0;
474 *outl = i;
475 return 1;
476 } else
477 return 1;
478 }
479