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:55:09 -0700 |
commit | 69296e264e58334620f541d09a4e381ee45542d4 (patch) | |
tree | 5e4c3e7041d4ef9d187ced3b74632c83e2b5699f /crypto | |
parent | 6b057f75074a9061147d7e64fc77db85e310db47 (diff) |
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)
(cherry picked from commit 0324ffc5d5d393111288eca2c9d67f2141ed65f5)
Diffstat (limited to 'crypto')
-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 64baf7108e..0d79f4aea0 100644 --- a/crypto/pem/pem_lib.c +++ b/crypto/pem/pem_lib.c @@ -791,7 +791,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; @@ -813,6 +813,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; @@ -823,13 +831,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; } |