summaryrefslogtreecommitdiffstats
path: root/crypto/evp
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/evp')
-rw-r--r--crypto/evp/bio_b64.c126
-rw-r--r--crypto/evp/encode.c2
2 files changed, 64 insertions, 64 deletions
diff --git a/crypto/evp/bio_b64.c b/crypto/evp/bio_b64.c
index 8700315a6b..4bf47c6f24 100644
--- a/crypto/evp/bio_b64.c
+++ b/crypto/evp/bio_b64.c
@@ -103,9 +103,17 @@ static int b64_free(BIO *a)
return 1;
}
+/*
+ * Unless `BIO_FLAGS_BASE64_NO_NL` is set, this BIO ignores leading lines that
+ * aren't exclusively composed of valid Base64 characters (followed by <CRLF>
+ * or <LF>). Once a valid Base64 line is found, `ctx->start` is set to 0 and
+ * lines are processed until EOF or the first line that contains invalid Base64
+ * characters. In a nod to PEM, lines that start with a '-' (hyphen) are
+ * treated as a soft EOF, rather than an error.
+ */
static int b64_read(BIO *b, char *out, int outl)
{
- int ret = 0, i, ii, j, k, x, n, num, ret_code = 0;
+ int ret = 0, i, ii, j, k, x, n, num, ret_code;
BIO_B64_CTX *ctx;
unsigned char *p, *q;
BIO *next;
@@ -128,7 +136,7 @@ static int b64_read(BIO *b, char *out, int outl)
EVP_DecodeInit(ctx->base64);
}
- /* First check if there are bytes decoded/encoded */
+ /* First check if there are buffered bytes already decoded */
if (ctx->buf_len > 0) {
OPENSSL_assert(ctx->buf_len >= ctx->buf_off);
i = ctx->buf_len - ctx->buf_off;
@@ -146,14 +154,17 @@ static int b64_read(BIO *b, char *out, int outl)
}
}
+ /* Restore any non-retriable error condition (ctx->cont < 0) */
+ ret_code = ctx->cont < 0 ? ctx->cont : 0;
+
/*
- * At this point, we have room of outl bytes and an empty buffer, so we
- * should read in some more.
+ * At this point, we have room of outl bytes and an either an empty buffer,
+ * or outl == 0, so we'll attempt to read in some more.
*/
-
- ret_code = 0;
while (outl > 0) {
- if (ctx->cont <= 0)
+ int again = ctx->cont;
+
+ if (again <= 0)
break;
i = BIO_read(next, &(ctx->tmp[ctx->tmp_len]),
@@ -164,18 +175,22 @@ static int b64_read(BIO *b, char *out, int outl)
/* Should we continue next time we are called? */
if (!BIO_should_retry(next)) {
- ctx->cont = i;
- /* If buffer empty break */
- if (ctx->tmp_len == 0)
- break;
- /* Fall through and process what we have */
- else
- i = 0;
+ /* Incomplete final Base64 chunk in the decoder is an error */
+ if (ctx->tmp_len == 0) {
+ if (EVP_DecodeFinal(ctx->base64, NULL, &num) < 0)
+ ret_code = -1;
+ EVP_DecodeInit(ctx->base64);
+ }
+ ctx->cont = ret_code;
}
- /* else we retry and add more data to buffer */
- else
+ if (ctx->tmp_len == 0)
break;
+ /* Fall through and process what we have */
+ i = 0;
+ /* But don't loop to top-up even if the buffer is not full! */
+ again = 0;
}
+
i += ctx->tmp_len;
ctx->tmp_len = i;
@@ -204,23 +219,23 @@ static int b64_read(BIO *b, char *out, int outl)
}
k = EVP_DecodeUpdate(ctx->base64, ctx->buf, &num, p, q - p);
- if (k <= 0 && num == 0 && ctx->start) {
- EVP_DecodeInit(ctx->base64);
- } else {
- if (p != ctx->tmp) {
- i -= p - ctx->tmp;
- for (x = 0; x < i; x++)
- ctx->tmp[x] = p[x];
- }
- EVP_DecodeInit(ctx->base64);
- ctx->start = 0;
- break;
+ EVP_DecodeInit(ctx->base64);
+ if (k <= 0 && num == 0) {
+ p = q;
+ continue;
+ }
+
+ ctx->start = 0;
+ if (p != ctx->tmp) {
+ i -= p - ctx->tmp;
+ for (x = 0; x < i; x++)
+ ctx->tmp[x] = p[x];
}
- p = q;
+ break;
}
/* we fell off the end without starting */
- if (j == i && num == 0) {
+ if (ctx->start) {
/*
* Is this is one long chunk?, if so, keep on reading until a
* new line.
@@ -231,18 +246,29 @@ static int b64_read(BIO *b, char *out, int outl)
ctx->tmp_nl = 1;
ctx->tmp_len = 0;
}
- } else if (p != q) { /* finished on a '\n' */
+ } else if (p != q) {
+ /* Retain partial line at end of buffer */
n = q - p;
for (ii = 0; ii < n; ii++)
ctx->tmp[ii] = p[ii];
ctx->tmp_len = n;
+ } else {
+ /* All we have is newline terminated non-start data */
+ ctx->tmp_len = 0;
}
- /* else finished on a '\n' */
- continue;
+ /*
+ * Try to read more if possible, otherwise we can't make
+ * progress unless the underlying BIO is retriable and may
+ * produce more data next time we're called.
+ */
+ if (again > 0)
+ continue;
+ else
+ break;
} else {
ctx->tmp_len = 0;
}
- } else if (i < B64_BLOCK_SIZE && ctx->cont > 0) {
+ } else if (i < B64_BLOCK_SIZE && again > 0) {
/*
* If buffer isn't full and we can retry then restart to read in
* more data.
@@ -250,35 +276,9 @@ static int b64_read(BIO *b, char *out, int outl)
continue;
}
- if ((BIO_get_flags(b) & BIO_FLAGS_BASE64_NO_NL) != 0) {
- int z, jj;
-
- jj = i & ~3; /* process per 4 */
- z = EVP_DecodeBlock(ctx->buf, ctx->tmp, jj);
- if (jj > 2) {
- if (ctx->tmp[jj - 1] == '=') {
- z--;
- if (ctx->tmp[jj - 2] == '=')
- z--;
- }
- }
- /*
- * z is now number of output bytes and jj is the number consumed
- */
- if (jj != i) {
- memmove(ctx->tmp, &ctx->tmp[jj], i - jj);
- ctx->tmp_len = i - jj;
- }
- ctx->buf_len = 0;
- if (z > 0) {
- ctx->buf_len = z;
- }
- i = z;
- } else {
- i = EVP_DecodeUpdate(ctx->base64, ctx->buf, &ctx->buf_len,
- ctx->tmp, i);
- ctx->tmp_len = 0;
- }
+ i = EVP_DecodeUpdate(ctx->base64, ctx->buf, &ctx->buf_len,
+ ctx->tmp, i);
+ ctx->tmp_len = 0;
/*
* If eof or an error was signalled, then the condition
* 'ctx->cont <= 0' will prevent b64_read() from reading
@@ -289,7 +289,7 @@ static int b64_read(BIO *b, char *out, int outl)
ctx->buf_off = 0;
if (i < 0) {
- ret_code = 0;
+ ret_code = ctx->start ? 0 : i;
ctx->buf_len = 0;
break;
}
diff --git a/crypto/evp/encode.c b/crypto/evp/encode.c
index 2c047fa039..f8b344766e 100644
--- a/crypto/evp/encode.c
+++ b/crypto/evp/encode.c
@@ -443,7 +443,7 @@ static int evp_decodeblock_int(EVP_ENCODE_CTX *ctx, unsigned char *t,
b = conv_ascii2bin(*(f++), table);
c = conv_ascii2bin(*(f++), table);
d = conv_ascii2bin(*(f++), table);
- if ((a & 0x80) || (b & 0x80) || (c & 0x80) || (d & 0x80))
+ if ((a | b | c | d) & 0x80)
return -1;
l = ((((unsigned long)a) << 18L) |
(((unsigned long)b) << 12L) |