diff options
author | inoguchi <> | 2020-03-03 15:03:14 +0000 |
---|---|---|
committer | inoguchi <> | 2020-03-03 15:03:14 +0000 |
commit | dad60cb9f024c77a6bb02993f7d77da011b245a1 (patch) | |
tree | 028ef43266c5a3cb73e903c4aba2786d8b8a9d0f | |
parent | 18cb47d15856a55b498c1011d26d7c72e8f90124 (diff) | |
download | openbsd-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.c | 165 |
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 | ||
96 | static const unsigned char data_ascii2bin[128] = { | 97 | static 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) | |||
231 | void | 232 | void |
232 | EVP_DecodeInit(EVP_ENCODE_CTX *ctx) | 233 | EVP_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 | */ | ||
244 | int | 241 | int |
245 | EVP_DecodeUpdate(EVP_ENCODE_CTX *ctx, unsigned char *out, int *outl, | 242 | EVP_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 | ||
374 | end: | 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 | ||