diff options
author | Maximilian Blenk <Maximilian.Blenk@bmw.de> | 2020-04-07 19:33:39 +0200 |
---|---|---|
committer | Benjamin Kaduk <kaduk@mit.edu> | 2020-05-08 13:27:47 -0700 |
commit | 0324ffc5d5d393111288eca2c9d67f2141ed65f5 (patch) | |
tree | c8aa4d097d3abed98a9c21faf809f77debff58f8 /crypto/pem/pem_lib.c | |
parent | 257e9d03b028402089c9f98f3acb25ba668c09af (diff) | |
download | openssl-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.c | 28 |
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; } |