summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorinoguchi <>2020-03-03 15:03:14 +0000
committerinoguchi <>2020-03-03 15:03:14 +0000
commitdad60cb9f024c77a6bb02993f7d77da011b245a1 (patch)
tree028ef43266c5a3cb73e903c4aba2786d8b8a9d0f
parent18cb47d15856a55b498c1011d26d7c72e8f90124 (diff)
downloadopenbsd-dad60cb9f024c77a6bb02993f7d77da011b245a1.tar.gz
openbsd-dad60cb9f024c77a6bb02993f7d77da011b245a1.tar.bz2
openbsd-dad60cb9f024c77a6bb02993f7d77da011b245a1.zip
Fix base64 processing of long lines
Fix the problem that long unbroken line of base64 text is not decoded. Referred to this OpenSSL commit and adapted to the codebase. 3cdd1e94b1d71f2ce3002738f9506da91fe2af45 Reported by john.a.passaro <at> gmail.com to the LibreSSL ML. ok tb@
-rw-r--r--src/lib/libcrypto/evp/encode.c165
1 files changed, 66 insertions, 99 deletions
diff --git a/src/lib/libcrypto/evp/encode.c b/src/lib/libcrypto/evp/encode.c
index ae107abb87..95dc79d70d 100644
--- a/src/lib/libcrypto/evp/encode.c
+++ b/src/lib/libcrypto/evp/encode.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: encode.c,v 1.26 2019/01/19 01:24:18 tb Exp $ */ 1/* $OpenBSD: encode.c,v 1.27 2020/03/03 15:03:14 inoguchi Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -92,6 +92,7 @@ abcdefghijklmnopqrstuvwxyz0123456789+/";
92#define B64_WS 0xE0 92#define B64_WS 0xE0
93#define B64_ERROR 0xFF 93#define B64_ERROR 0xFF
94#define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3) 94#define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3)
95#define B64_BASE64(a) !B64_NOT_BASE64(a)
95 96
96static const unsigned char data_ascii2bin[128] = { 97static const unsigned char data_ascii2bin[128] = {
97 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 98 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
@@ -231,151 +232,117 @@ EVP_EncodeBlock(unsigned char *t, const unsigned char *f, int dlen)
231void 232void
232EVP_DecodeInit(EVP_ENCODE_CTX *ctx) 233EVP_DecodeInit(EVP_ENCODE_CTX *ctx)
233{ 234{
234 ctx->length = 30;
235 ctx->num = 0; 235 ctx->num = 0;
236 ctx->length = 0;
236 ctx->line_num = 0; 237 ctx->line_num = 0;
237 ctx->expect_nl = 0; 238 ctx->expect_nl = 0;
238} 239}
239 240
240/* -1 for error
241 * 0 for last line
242 * 1 for full line
243 */
244int 241int
245EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, 242EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl,
246 const unsigned char *in, int inl) 243 const unsigned char *in, int inl)
247{ 244{
248 int seof = -1, eof = 0, rv = -1, ret = 0, i, v, tmp, n, ln, exp_nl; 245 int seof = 0, eof = 0, rv = -1, ret = 0, i, v, tmp, n, decoded_len;
249 unsigned char *d; 246 unsigned char *d;
250 247
251 n = ctx->num; 248 n = ctx->num;
252 d = ctx->enc_data; 249 d = ctx->enc_data;
253 ln = ctx->line_num;
254 exp_nl = ctx->expect_nl;
255 250
256 /* last line of input. */ 251 if (n > 0 && d[n - 1] == '=') {
257 if ((inl == 0) || ((n == 0) && (conv_ascii2bin(in[0]) == B64_EOF))) { 252 eof++;
253 if (n > 1 && d[n - 2] == '=')
254 eof++;
255 }
256
257 /* Legacy behaviour: an empty input chunk signals end of input. */
258 if (inl == 0) {
258 rv = 0; 259 rv = 0;
259 goto end; 260 goto end;
260 } 261 }
261 262
262 /* We parse the input data */
263 for (i = 0; i < inl; i++) { 263 for (i = 0; i < inl; i++) {
264 /* If the current line is > 80 characters, scream alot */ 264 tmp = *(in++);
265 if (ln >= 80) {
266 rv = -1;
267 goto end;
268 }
269
270 /* Get char and put it into the buffer */
271 tmp= *(in++);
272 v = conv_ascii2bin(tmp); 265 v = conv_ascii2bin(tmp);
273 /* only save the good data :-) */ 266 if (v == B64_ERROR) {
274 if (!B64_NOT_BASE64(v)) {
275 OPENSSL_assert(n < (int)sizeof(ctx->enc_data));
276 d[n++] = tmp;
277 ln++;
278 } else if (v == B64_ERROR) {
279 rv = -1;
280 goto end;
281 }
282
283 /* There should not be base64 data after padding. */
284 if (eof && tmp != '=' && tmp != '\r' && tmp != '\n' &&
285 v != B64_EOF) {
286 rv = -1; 267 rv = -1;
287 goto end; 268 goto end;
288 } 269 }
289 270
290 /* have we seen a '=' which is 'definitely' the last
291 * input line. seof will point to the character that
292 * holds it. and eof will hold how many characters to
293 * chop off. */
294 if (tmp == '=') { 271 if (tmp == '=') {
295 if (seof == -1)
296 seof = n;
297 eof++; 272 eof++;
273 } else if (eof > 0 && B64_BASE64(v)) {
274 /* More data after padding. */
275 rv = -1;
276 goto end;
298 } 277 }
299 278
300 /* There should be no more than two padding markers. */
301 if (eof > 2) { 279 if (eof > 2) {
302 rv = -1; 280 rv = -1;
303 goto end; 281 goto end;
304 } 282 }
305 283
306 if (v == B64_CR) { 284 if (v == B64_EOF) {
307 ln = 0; 285 seof = 1;
308 if (exp_nl) 286 goto tail;
309 continue;
310 } 287 }
311 288
312 /* eoln */ 289 /* Only save valid base64 characters. */
313 if (v == B64_EOLN) { 290 if (B64_BASE64(v)) {
314 ln = 0; 291 if (n >= 64) {
315 if (exp_nl) { 292 /*
316 exp_nl = 0; 293 * We increment n once per loop, and empty the
317 continue; 294 * buffer as soon as we reach 64 characters, so
295 * this can only happen if someone's manually
296 * messed with the ctx. Refuse to write any
297 * more data.
298 */
299 rv = -1;
300 goto end;
318 } 301 }
319 } 302 OPENSSL_assert(n < (int)sizeof(ctx->enc_data));
320 exp_nl = 0; 303 d[n++] = tmp;
321
322 /* If we are at the end of input and it looks like a
323 * line, process it. */
324 if (((i + 1) == inl) && (((n&3) == 0) || eof)) {
325 v = B64_EOF;
326 /* In case things were given us in really small
327 records (so two '=' were given in separate
328 updates), eof may contain the incorrect number
329 of ending bytes to skip, so let's redo the count */
330 eof = 0;
331 if (d[n-1] == '=')
332 eof++;
333 if (d[n-2] == '=')
334 eof++;
335 /* There will never be more than two '=' */
336 } 304 }
337 305
338 if ((v == B64_EOF && (n&3) == 0) || (n >= 64)) { 306 if (n == 64) {
339 /* This is needed to work correctly on 64 byte input 307 decoded_len = EVP_DecodeBlock(out, d, n);
340 * lines. We process the line and then need to 308 n = 0;
341 * accept the '\n' */ 309 if (decoded_len < 0 || eof > decoded_len) {
342 if ((v != B64_EOF) && (n >= 64)) 310 rv = -1;
343 exp_nl = 1;
344 if (n > 0) {
345 v = EVP_DecodeBlock(out, d, n);
346 n = 0;
347 if (v < 0) {
348 rv = 0;
349 goto end;
350 }
351 ret += (v - eof);
352 } else {
353 eof = 1;
354 v = 0;
355 }
356
357 /* This is the case where we have had a short
358 * but valid input line */
359 if ((v < ctx->length) && eof) {
360 rv = 0;
361 goto end; 311 goto end;
362 } else 312 }
363 ctx->length = v; 313 ret += decoded_len - eof;
314 out += decoded_len - eof;
315 }
316 }
364 317
365 if (seof >= 0) { 318 /*
366 rv = 0; 319 * Legacy behaviour: if the current line is a full base64-block (i.e.,
320 * has 0 mod 4 base64 characters), it is processed immediately. We keep
321 * this behaviour as applications may not be calling EVP_DecodeFinal
322 * properly.
323 */
324 tail:
325 if (n > 0) {
326 if ((n & 3) == 0) {
327 decoded_len = EVP_DecodeBlock(out, d, n);
328 n = 0;
329 if (decoded_len < 0 || eof > decoded_len) {
330 rv = -1;
367 goto end; 331 goto end;
368 } 332 }
369 out += v; 333 ret += (decoded_len - eof);
334 } else if (seof) {
335 /* EOF in the middle of a base64 block. */
336 rv = -1;
337 goto end;
370 } 338 }
371 } 339 }
372 rv = 1;
373 340
374end: 341 rv = seof || (n == 0 && eof) ? 0 : 1;
342 end:
343 /* Legacy behaviour. This should probably rather be zeroed on error. */
375 *outl = ret; 344 *outl = ret;
376 ctx->num = n; 345 ctx->num = n;
377 ctx->line_num = ln;
378 ctx->expect_nl = exp_nl;
379 return (rv); 346 return (rv);
380} 347}
381 348