summaryrefslogtreecommitdiff
path: root/crypto/pem/pem_lib.c
diff options
context:
space:
mode:
authorMaximilian Blenk <Maximilian.Blenk@bmw.de>2020-04-07 19:33:39 +0200
committerBenjamin Kaduk <kaduk@mit.edu>2020-05-08 13:27:47 -0700
commit0324ffc5d5d393111288eca2c9d67f2141ed65f5 (patch)
treec8aa4d097d3abed98a9c21faf809f77debff58f8 /crypto/pem/pem_lib.c
parent257e9d03b028402089c9f98f3acb25ba668c09af (diff)
downloadopenssl-new-0324ffc5d5d393111288eca2c9d67f2141ed65f5.tar.gz
Fix PEM certificate loading that sometimes fails
As described in https://github.com/openssl/openssl/issues/9187, the loading of PEM certificates sometimes fails if a line of base64 content has the length of a multiple of 254. The problem is in get_header_and_data(). When such a line with a length of 254 (or a multiple) has been read, the next read will only read a newline. Due to this get_header_and_data() expects to be in the header not in the data area. This commit fixes that by checking if lines have been read completely or only partially. In case of a previous partial read, a newline will be ignored. Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com> Reviewed-by: Tomas Mraz <tmraz@fedoraproject.org> Reviewed-by: Ben Kaduk <kaduk@mit.edu> (Merged from https://github.com/openssl/openssl/pull/11741)
Diffstat (limited to 'crypto/pem/pem_lib.c')
-rw-r--r--crypto/pem/pem_lib.c28
1 files changed, 21 insertions, 7 deletions
diff --git a/crypto/pem/pem_lib.c b/crypto/pem/pem_lib.c
index e059328aee..f5ed70d6b4 100644
--- a/crypto/pem/pem_lib.c
+++ b/crypto/pem/pem_lib.c
@@ -806,7 +806,7 @@ static int get_header_and_data(BIO *bp, BIO **header, BIO **data, char *name,
{
BIO *tmp = *header;
char *linebuf, *p;
- int len, line, ret = 0, end = 0;
+ int len, line, ret = 0, end = 0, prev_partial_line_read = 0, partial_line_read = 0;
/* 0 if not seen (yet), 1 if reading header, 2 if finished header */
enum header_status got_header = MAYBE_HEADER;
unsigned int flags_mask;
@@ -828,6 +828,14 @@ static int get_header_and_data(BIO *bp, BIO **header, BIO **data, char *name,
goto err;
}
+ /*
+ * Check if line has been read completely or if only part of the line
+ * has been read. Keep the previous value to ignore newlines that
+ * appear due to reading a line up until the char before the newline.
+ */
+ prev_partial_line_read = partial_line_read;
+ partial_line_read = len == LINESIZE-1 && linebuf[LINESIZE-2] != '\n';
+
if (got_header == MAYBE_HEADER) {
if (memchr(linebuf, ':', len) != NULL)
got_header = IN_HEADER;
@@ -838,13 +846,19 @@ static int get_header_and_data(BIO *bp, BIO **header, BIO **data, char *name,
/* Check for end of header. */
if (linebuf[0] == '\n') {
- if (got_header == POST_HEADER) {
- /* Another blank line is an error. */
- PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_BAD_END_LINE);
- goto err;
+ /*
+ * If previous line has been read only partially this newline is a
+ * regular newline at the end of a line and not an empty line.
+ */
+ if (!prev_partial_line_read) {
+ if (got_header == POST_HEADER) {
+ /* Another blank line is an error. */
+ PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_BAD_END_LINE);
+ goto err;
+ }
+ got_header = POST_HEADER;
+ tmp = *data;
}
- got_header = POST_HEADER;
- tmp = *data;
continue;
}