summaryrefslogtreecommitdiff
path: root/deps/openssl/openssl/crypto/pem/pem_lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'deps/openssl/openssl/crypto/pem/pem_lib.c')
-rw-r--r--deps/openssl/openssl/crypto/pem/pem_lib.c554
1 files changed, 345 insertions, 209 deletions
diff --git a/deps/openssl/openssl/crypto/pem/pem_lib.c b/deps/openssl/openssl/crypto/pem/pem_lib.c
index 6f06c5291f..4bb86463fa 100644
--- a/deps/openssl/openssl/crypto/pem/pem_lib.c
+++ b/deps/openssl/openssl/crypto/pem/pem_lib.c
@@ -8,7 +8,7 @@
*/
#include <stdio.h>
-#include <ctype.h>
+#include "internal/ctype.h"
#include <string.h>
#include "internal/cryptlib.h"
#include <openssl/buffer.h>
@@ -30,11 +30,8 @@ int pem_check_suffix(const char *pem_str, const char *suffix);
int PEM_def_callback(char *buf, int num, int rwflag, void *userdata)
{
- int i;
-#ifndef OPENSSL_NO_UI
- int min_len;
+ int i, min_len;
const char *prompt;
-#endif
/* We assume that the user passes a default password as userdata */
if (userdata) {
@@ -44,10 +41,6 @@ int PEM_def_callback(char *buf, int num, int rwflag, void *userdata)
return i;
}
-#ifdef OPENSSL_NO_UI
- PEMerr(PEM_F_PEM_DEF_CALLBACK, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
- return -1;
-#else
prompt = EVP_get_pw_prompt();
if (prompt == NULL)
prompt = "Enter PEM pass phrase:";
@@ -68,12 +61,12 @@ int PEM_def_callback(char *buf, int num, int rwflag, void *userdata)
return -1;
}
return strlen(buf);
-#endif
}
void PEM_proc_type(char *buf, int type)
{
const char *str;
+ char *p = buf + strlen(buf);
if (type == PEM_TYPE_ENCRYPTED)
str = "ENCRYPTED";
@@ -84,29 +77,29 @@ void PEM_proc_type(char *buf, int type)
else
str = "BAD-TYPE";
- OPENSSL_strlcat(buf, "Proc-Type: 4,", PEM_BUFSIZE);
- OPENSSL_strlcat(buf, str, PEM_BUFSIZE);
- OPENSSL_strlcat(buf, "\n", PEM_BUFSIZE);
+ BIO_snprintf(p, PEM_BUFSIZE - (size_t)(p - buf), "Proc-Type: 4,%s\n", str);
}
void PEM_dek_info(char *buf, const char *type, int len, char *str)
{
- static const unsigned char map[17] = "0123456789ABCDEF";
long i;
- int j;
-
- OPENSSL_strlcat(buf, "DEK-Info: ", PEM_BUFSIZE);
- OPENSSL_strlcat(buf, type, PEM_BUFSIZE);
- OPENSSL_strlcat(buf, ",", PEM_BUFSIZE);
- j = strlen(buf);
- if (j + (len * 2) + 1 > PEM_BUFSIZE)
- return;
- for (i = 0; i < len; i++) {
- buf[j + i * 2] = map[(str[i] >> 4) & 0x0f];
- buf[j + i * 2 + 1] = map[(str[i]) & 0x0f];
- }
- buf[j + i * 2] = '\n';
- buf[j + i * 2 + 1] = '\0';
+ char *p = buf + strlen(buf);
+ int j = PEM_BUFSIZE - (size_t)(p - buf), n;
+
+ n = BIO_snprintf(p, j, "DEK-Info: %s,", type);
+ if (n > 0) {
+ j -= n;
+ p += n;
+ for (i = 0; i < len; i++) {
+ n = BIO_snprintf(p, j, "%02X", 0xff & str[i]);
+ if (n <= 0)
+ return;
+ j -= n;
+ p += n;
+ }
+ if (j > 1)
+ strcpy(p, "\n");
+ }
}
#ifndef OPENSSL_NO_STDIO
@@ -118,12 +111,12 @@ void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x,
if ((b = BIO_new(BIO_s_file())) == NULL) {
PEMerr(PEM_F_PEM_ASN1_READ, ERR_R_BUF_LIB);
- return (0);
+ return 0;
}
BIO_set_fp(b, fp, BIO_NOCLOSE);
ret = PEM_ASN1_read_bio(d2i, name, b, x, cb, u);
BIO_free(b);
- return (ret);
+ return ret;
}
#endif
@@ -222,28 +215,41 @@ static int check_pem(const char *nm, const char *name)
return 0;
}
-int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
- const char *name, BIO *bp, pem_password_cb *cb,
- void *u)
+static void pem_free(void *p, unsigned int flags, size_t num)
+{
+ if (flags & PEM_FLAG_SECURE)
+ OPENSSL_secure_clear_free(p, num);
+ else
+ OPENSSL_free(p);
+}
+
+static void *pem_malloc(int num, unsigned int flags)
+{
+ return (flags & PEM_FLAG_SECURE) ? OPENSSL_secure_malloc(num)
+ : OPENSSL_malloc(num);
+}
+
+static int pem_bytes_read_bio_flags(unsigned char **pdata, long *plen,
+ char **pnm, const char *name, BIO *bp,
+ pem_password_cb *cb, void *u,
+ unsigned int flags)
{
EVP_CIPHER_INFO cipher;
char *nm = NULL, *header = NULL;
unsigned char *data = NULL;
- long len;
+ long len = 0;
int ret = 0;
- for (;;) {
- if (!PEM_read_bio(bp, &nm, &header, &data, &len)) {
+ do {
+ pem_free(nm, flags, 0);
+ pem_free(header, flags, 0);
+ pem_free(data, flags, len);
+ if (!PEM_read_bio_ex(bp, &nm, &header, &data, &len, flags)) {
if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE)
ERR_add_error_data(2, "Expecting: ", name);
return 0;
}
- if (check_pem(nm, name))
- break;
- OPENSSL_free(nm);
- OPENSSL_free(header);
- OPENSSL_free(data);
- }
+ } while (!check_pem(nm, name));
if (!PEM_get_EVP_CIPHER_INFO(header, &cipher))
goto err;
if (!PEM_do_header(&cipher, data, &len, cb, u))
@@ -252,20 +258,34 @@ int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
*pdata = data;
*plen = len;
- if (pnm)
+ if (pnm != NULL)
*pnm = nm;
ret = 1;
err:
- if (!ret || !pnm)
- OPENSSL_free(nm);
- OPENSSL_free(header);
+ if (!ret || pnm == NULL)
+ pem_free(nm, flags, 0);
+ pem_free(header, flags, 0);
if (!ret)
- OPENSSL_free(data);
+ pem_free(data, flags, len);
return ret;
}
+int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
+ const char *name, BIO *bp, pem_password_cb *cb,
+ void *u) {
+ return pem_bytes_read_bio_flags(pdata, plen, pnm, name, bp, cb, u,
+ PEM_FLAG_EAY_COMPATIBLE);
+}
+
+int PEM_bytes_read_bio_secmem(unsigned char **pdata, long *plen, char **pnm,
+ const char *name, BIO *bp, pem_password_cb *cb,
+ void *u) {
+ return pem_bytes_read_bio_flags(pdata, plen, pnm, name, bp, cb, u,
+ PEM_FLAG_SECURE | PEM_FLAG_EAY_COMPATIBLE);
+}
+
#ifndef OPENSSL_NO_STDIO
int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp,
void *x, const EVP_CIPHER *enc, unsigned char *kstr,
@@ -276,12 +296,12 @@ int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp,
if ((b = BIO_new(BIO_s_file())) == NULL) {
PEMerr(PEM_F_PEM_ASN1_WRITE, ERR_R_BUF_LIB);
- return (0);
+ return 0;
}
BIO_set_fp(b, fp, BIO_NOCLOSE);
ret = PEM_ASN1_write_bio(i2d, name, b, x, enc, kstr, klen, callback, u);
BIO_free(b);
- return (ret);
+ return ret;
}
#endif
@@ -299,7 +319,14 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
if (enc != NULL) {
objstr = OBJ_nid2sn(EVP_CIPHER_nid(enc));
- if (objstr == NULL || EVP_CIPHER_iv_length(enc) == 0) {
+ if (objstr == NULL || EVP_CIPHER_iv_length(enc) == 0
+ || EVP_CIPHER_iv_length(enc) > (int)sizeof(iv)
+ /*
+ * Check "Proc-Type: 4,Encrypted\nDEK-Info: objstr,hex-iv\n"
+ * fits into buf
+ */
+ || (strlen(objstr) + 23 + 2 * EVP_CIPHER_iv_length(enc) + 13)
+ > sizeof(buf)) {
PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, PEM_R_UNSUPPORTED_CIPHER);
goto err;
}
@@ -336,8 +363,6 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
#endif
kstr = (unsigned char *)buf;
}
- RAND_add(data, i, 0); /* put in the RSA key. */
- OPENSSL_assert(EVP_CIPHER_iv_length(enc) <= (int)sizeof(iv));
if (RAND_bytes(iv, EVP_CIPHER_iv_length(enc)) <= 0) /* Generate a salt */
goto err;
/*
@@ -350,9 +375,6 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
if (kstr == (unsigned char *)buf)
OPENSSL_cleanse(buf, PEM_BUFSIZE);
- OPENSSL_assert(strlen(objstr) + 23 + 2 * EVP_CIPHER_iv_length(enc) + 13
- <= sizeof(buf));
-
buf[0] = '\0';
PEM_proc_type(buf, PEM_TYPE_ENCRYPTED);
PEM_dek_info(buf, objstr, EVP_CIPHER_iv_length(enc), (char *)iv);
@@ -380,7 +402,7 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
EVP_CIPHER_CTX_free(ctx);
OPENSSL_cleanse(buf, PEM_BUFSIZE);
OPENSSL_clear_free(data, (unsigned int)dsize);
- return (ret);
+ return ret;
}
int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen,
@@ -549,14 +571,14 @@ static int load_iv(char **fromp, unsigned char *to, int num)
v = OPENSSL_hexchar2int(*from);
if (v < 0) {
PEMerr(PEM_F_LOAD_IV, PEM_R_BAD_IV_CHARS);
- return (0);
+ return 0;
}
from++;
to[i / 2] |= v << (long)((!(i & 1)) * 4);
}
*fromp = from;
- return (1);
+ return 1;
}
#ifndef OPENSSL_NO_STDIO
@@ -568,12 +590,12 @@ int PEM_write(FILE *fp, const char *name, const char *header,
if ((b = BIO_new(BIO_s_file())) == NULL) {
PEMerr(PEM_F_PEM_WRITE, ERR_R_BUF_LIB);
- return (0);
+ return 0;
}
BIO_set_fp(b, fp, BIO_NOCLOSE);
ret = PEM_write_bio(b, name, header, data, len);
BIO_free(b);
- return (ret);
+ return ret;
}
#endif
@@ -584,6 +606,7 @@ int PEM_write_bio(BIO *bp, const char *name, const char *header,
unsigned char *buf = NULL;
EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
int reason = ERR_R_BUF_LIB;
+ int retval = 0;
if (ctx == NULL) {
reason = ERR_R_MALLOC_FAILURE;
@@ -628,14 +651,14 @@ int PEM_write_bio(BIO *bp, const char *name, const char *header,
(BIO_write(bp, name, nlen) != nlen) ||
(BIO_write(bp, "-----\n", 6) != 6))
goto err;
- OPENSSL_clear_free(buf, PEM_BUFSIZE * 8);
- EVP_ENCODE_CTX_free(ctx);
- return (i + outl);
+ retval = i + outl;
+
err:
- OPENSSL_clear_free(buf, PEM_BUFSIZE * 8);
+ if (retval == 0)
+ PEMerr(PEM_F_PEM_WRITE_BIO, reason);
EVP_ENCODE_CTX_free(ctx);
- PEMerr(PEM_F_PEM_WRITE_BIO, reason);
- return (0);
+ OPENSSL_clear_free(buf, PEM_BUFSIZE * 8);
+ return retval;
}
#ifndef OPENSSL_NO_STDIO
@@ -647,186 +670,299 @@ int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,
if ((b = BIO_new(BIO_s_file())) == NULL) {
PEMerr(PEM_F_PEM_READ, ERR_R_BUF_LIB);
- return (0);
+ return 0;
}
BIO_set_fp(b, fp, BIO_NOCLOSE);
ret = PEM_read_bio(b, name, header, data, len);
BIO_free(b);
- return (ret);
+ return ret;
}
#endif
-int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,
- long *len)
+/* Some helpers for PEM_read_bio_ex(). */
+static int sanitize_line(char *linebuf, int len, unsigned int flags)
{
- EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
- int end = 0, i, k, bl = 0, hl = 0, nohead = 0;
- char buf[256];
- BUF_MEM *nameB;
- BUF_MEM *headerB;
- BUF_MEM *dataB, *tmpB;
+ int i;
- if (ctx == NULL) {
- PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
- return (0);
+ if (flags & PEM_FLAG_EAY_COMPATIBLE) {
+ /* Strip trailing whitespace */
+ while ((len >= 0) && (linebuf[len] <= ' '))
+ len--;
+ /* Go back to whitespace before applying uniform line ending. */
+ len++;
+ } else if (flags & PEM_FLAG_ONLY_B64) {
+ for (i = 0; i < len; ++i) {
+ if (!ossl_isbase64(linebuf[i]) || linebuf[i] == '\n'
+ || linebuf[i] == '\r')
+ break;
+ }
+ len = i;
+ } else {
+ /* EVP_DecodeBlock strips leading and trailing whitespace, so just strip
+ * control characters in-place and let everything through. */
+ for (i = 0; i < len; ++i) {
+ if (linebuf[i] == '\n' || linebuf[i] == '\r')
+ break;
+ if (ossl_iscntrl(linebuf[i]))
+ linebuf[i] = ' ';
+ }
+ len = i;
}
+ /* The caller allocated LINESIZE+1, so this is safe. */
+ linebuf[len++] = '\n';
+ linebuf[len] = '\0';
+ return len;
+}
- nameB = BUF_MEM_new();
- headerB = BUF_MEM_new();
- dataB = BUF_MEM_new();
- if ((nameB == NULL) || (headerB == NULL) || (dataB == NULL)) {
- goto err;
+#define LINESIZE 255
+/* Note trailing spaces for begin and end. */
+static const char beginstr[] = "-----BEGIN ";
+static const char endstr[] = "-----END ";
+static const char tailstr[] = "-----\n";
+#define BEGINLEN ((int)(sizeof(beginstr) - 1))
+#define ENDLEN ((int)(sizeof(endstr) - 1))
+#define TAILLEN ((int)(sizeof(tailstr) - 1))
+static int get_name(BIO *bp, char **name, unsigned int flags)
+{
+ char *linebuf;
+ int ret = 0;
+ int len;
+
+ /*
+ * Need to hold trailing NUL (accounted for by BIO_gets() and the newline
+ * that will be added by sanitize_line() (the extra '1').
+ */
+ linebuf = pem_malloc(LINESIZE + 1, flags);
+ if (linebuf == NULL) {
+ PEMerr(PEM_F_GET_NAME, ERR_R_MALLOC_FAILURE);
+ return 0;
}
- buf[254] = '\0';
- for (;;) {
- i = BIO_gets(bp, buf, 254);
+ do {
+ len = BIO_gets(bp, linebuf, LINESIZE);
- if (i <= 0) {
- PEMerr(PEM_F_PEM_READ_BIO, PEM_R_NO_START_LINE);
+ if (len <= 0) {
+ PEMerr(PEM_F_GET_NAME, PEM_R_NO_START_LINE);
goto err;
}
- while ((i >= 0) && (buf[i] <= ' '))
- i--;
- buf[++i] = '\n';
- buf[++i] = '\0';
+ /* Strip trailing garbage and standardize ending. */
+ len = sanitize_line(linebuf, len, flags & ~PEM_FLAG_ONLY_B64);
+
+ /* Allow leading empty or non-matching lines. */
+ } while (strncmp(linebuf, beginstr, BEGINLEN) != 0
+ || len < TAILLEN
+ || strncmp(linebuf + len - TAILLEN, tailstr, TAILLEN) != 0);
+ linebuf[len - TAILLEN] = '\0';
+ len = len - BEGINLEN - TAILLEN + 1;
+ *name = pem_malloc(len, flags);
+ if (*name == NULL) {
+ PEMerr(PEM_F_GET_NAME, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ memcpy(*name, linebuf + BEGINLEN, len);
+ ret = 1;
+
+err:
+ pem_free(linebuf, flags, LINESIZE + 1);
+ return ret;
+}
+
+/* Keep track of how much of a header we've seen. */
+enum header_status {
+ MAYBE_HEADER,
+ IN_HEADER,
+ POST_HEADER
+};
+
+/**
+ * Extract the optional PEM header, with details on the type of content and
+ * any encryption used on the contents, and the bulk of the data from the bio.
+ * The end of the header is marked by a blank line; if the end-of-input marker
+ * is reached prior to a blank line, there is no header.
+ *
+ * The header and data arguments are BIO** since we may have to swap them
+ * if there is no header, for efficiency.
+ *
+ * We need the name of the PEM-encoded type to verify the end string.
+ */
+static int get_header_and_data(BIO *bp, BIO **header, BIO **data, char *name,
+ unsigned int flags)
+{
+ BIO *tmp = *header;
+ char *linebuf, *p;
+ int len, line, ret = 0, end = 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;
+ size_t namelen;
+
+ /* Need to hold trailing NUL (accounted for by BIO_gets() and the newline
+ * that will be added by sanitize_line() (the extra '1'). */
+ linebuf = pem_malloc(LINESIZE + 1, flags);
+ if (linebuf == NULL) {
+ PEMerr(PEM_F_GET_HEADER_AND_DATA, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
- if (strncmp(buf, "-----BEGIN ", 11) == 0) {
- i = strlen(&(buf[11]));
+ for (line = 0; ; line++) {
+ flags_mask = ~0u;
+ len = BIO_gets(bp, linebuf, LINESIZE);
+ if (len <= 0) {
+ PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_SHORT_HEADER);
+ goto err;
+ }
- if (strncmp(&(buf[11 + i - 6]), "-----\n", 6) != 0)
- continue;
- if (!BUF_MEM_grow(nameB, i + 9)) {
- PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
+ if (got_header == MAYBE_HEADER) {
+ if (memchr(linebuf, ':', len) != NULL)
+ got_header = IN_HEADER;
+ }
+ if (!strncmp(linebuf, endstr, ENDLEN) || got_header == IN_HEADER)
+ flags_mask &= ~PEM_FLAG_ONLY_B64;
+ len = sanitize_line(linebuf, len, flags & flags_mask);
+
+ /* 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;
}
- memcpy(nameB->data, &(buf[11]), i - 6);
- nameB->data[i - 6] = '\0';
- break;
+ got_header = POST_HEADER;
+ tmp = *data;
+ continue;
}
- }
- hl = 0;
- if (!BUF_MEM_grow(headerB, 256)) {
- PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- headerB->data[0] = '\0';
- for (;;) {
- i = BIO_gets(bp, buf, 254);
- if (i <= 0)
- break;
- while ((i >= 0) && (buf[i] <= ' '))
- i--;
- buf[++i] = '\n';
- buf[++i] = '\0';
-
- if (buf[0] == '\n')
+ /* Check for end of stream (which means there is no header). */
+ if (strncmp(linebuf, endstr, ENDLEN) == 0) {
+ p = linebuf + ENDLEN;
+ namelen = strlen(name);
+ if (strncmp(p, name, namelen) != 0 ||
+ strncmp(p + namelen, tailstr, TAILLEN) != 0) {
+ PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_BAD_END_LINE);
+ goto err;
+ }
+ if (got_header == MAYBE_HEADER) {
+ *header = *data;
+ *data = tmp;
+ }
break;
- if (!BUF_MEM_grow(headerB, hl + i + 9)) {
- PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
+ } else if (end) {
+ /* Malformed input; short line not at end of data. */
+ PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_BAD_END_LINE);
goto err;
}
- if (strncmp(buf, "-----END ", 9) == 0) {
- nohead = 1;
- break;
+ /*
+ * Else, a line of text -- could be header or data; we don't
+ * know yet. Just pass it through.
+ */
+ if (BIO_puts(tmp, linebuf) < 0)
+ goto err;
+ /*
+ * Only encrypted files need the line length check applied.
+ */
+ if (got_header == POST_HEADER) {
+ /* 65 includes the trailing newline */
+ if (len > 65)
+ goto err;
+ if (len < 65)
+ end = 1;
}
- memcpy(&(headerB->data[hl]), buf, i);
- headerB->data[hl + i] = '\0';
- hl += i;
}
- bl = 0;
- if (!BUF_MEM_grow(dataB, 1024)) {
- PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- dataB->data[0] = '\0';
- if (!nohead) {
- for (;;) {
- i = BIO_gets(bp, buf, 254);
- if (i <= 0)
- break;
-
- while ((i >= 0) && (buf[i] <= ' '))
- i--;
- buf[++i] = '\n';
- buf[++i] = '\0';
+ ret = 1;
+err:
+ pem_free(linebuf, flags, LINESIZE + 1);
+ return ret;
+}
- if (i != 65)
- end = 1;
- if (strncmp(buf, "-----END ", 9) == 0)
- break;
- if (i > 65)
- break;
- if (!BUF_MEM_grow_clean(dataB, i + bl + 9)) {
- PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
- goto err;
- }
- memcpy(&(dataB->data[bl]), buf, i);
- dataB->data[bl + i] = '\0';
- bl += i;
- if (end) {
- buf[0] = '\0';
- i = BIO_gets(bp, buf, 254);
- if (i <= 0)
- break;
-
- while ((i >= 0) && (buf[i] <= ' '))
- i--;
- buf[++i] = '\n';
- buf[++i] = '\0';
+/**
+ * Read in PEM-formatted data from the given BIO.
+ *
+ * By nature of the PEM format, all content must be printable ASCII (except
+ * for line endings). Other characters are malformed input and will be rejected.
+ */
+int PEM_read_bio_ex(BIO *bp, char **name_out, char **header,
+ unsigned char **data, long *len_out, unsigned int flags)
+{
+ EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new();
+ const BIO_METHOD *bmeth;
+ BIO *headerB = NULL, *dataB = NULL;
+ char *name = NULL;
+ int len, taillen, headerlen, ret = 0;
+ BUF_MEM * buf_mem;
- break;
- }
- }
- } else {
- tmpB = headerB;
- headerB = dataB;
- dataB = tmpB;
- bl = hl;
- }
- i = strlen(nameB->data);
- if ((strncmp(buf, "-----END ", 9) != 0) ||
- (strncmp(nameB->data, &(buf[9]), i) != 0) ||
- (strncmp(&(buf[9 + i]), "-----\n", 6) != 0)) {
- PEMerr(PEM_F_PEM_READ_BIO, PEM_R_BAD_END_LINE);
- goto err;
+ if (ctx == NULL) {
+ PEMerr(PEM_F_PEM_READ_BIO_EX, ERR_R_MALLOC_FAILURE);
+ return 0;
}
- EVP_DecodeInit(ctx);
- i = EVP_DecodeUpdate(ctx,
- (unsigned char *)dataB->data, &bl,
- (unsigned char *)dataB->data, bl);
- if (i < 0) {
- PEMerr(PEM_F_PEM_READ_BIO, PEM_R_BAD_BASE64_DECODE);
- goto err;
+ *len_out = 0;
+ *name_out = *header = NULL;
+ *data = NULL;
+ if ((flags & PEM_FLAG_EAY_COMPATIBLE) && (flags & PEM_FLAG_ONLY_B64)) {
+ /* These two are mutually incompatible; bail out. */
+ PEMerr(PEM_F_PEM_READ_BIO_EX, ERR_R_PASSED_INVALID_ARGUMENT);
+ goto end;
}
- i = EVP_DecodeFinal(ctx, (unsigned char *)&(dataB->data[bl]), &k);
- if (i < 0) {
- PEMerr(PEM_F_PEM_READ_BIO, PEM_R_BAD_BASE64_DECODE);
- goto err;
+ bmeth = (flags & PEM_FLAG_SECURE) ? BIO_s_secmem() : BIO_s_mem();
+
+ headerB = BIO_new(bmeth);
+ dataB = BIO_new(bmeth);
+ if (headerB == NULL || dataB == NULL) {
+ PEMerr(PEM_F_PEM_READ_BIO_EX, ERR_R_MALLOC_FAILURE);
+ goto end;
}
- bl += k;
- if (bl == 0)
- goto err;
- *name = nameB->data;
- *header = headerB->data;
- *data = (unsigned char *)dataB->data;
- *len = bl;
- OPENSSL_free(nameB);
- OPENSSL_free(headerB);
- OPENSSL_free(dataB);
- EVP_ENCODE_CTX_free(ctx);
- return (1);
- err:
- BUF_MEM_free(nameB);
- BUF_MEM_free(headerB);
- BUF_MEM_free(dataB);
+ if (!get_name(bp, &name, flags))
+ goto end;
+ if (!get_header_and_data(bp, &headerB, &dataB, name, flags))
+ goto end;
+
+ EVP_DecodeInit(ctx);
+ BIO_get_mem_ptr(dataB, &buf_mem);
+ len = buf_mem->length;
+ if (EVP_DecodeUpdate(ctx, (unsigned char*)buf_mem->data, &len,
+ (unsigned char*)buf_mem->data, len) < 0
+ || EVP_DecodeFinal(ctx, (unsigned char*)&(buf_mem->data[len]),
+ &taillen) < 0) {
+ PEMerr(PEM_F_PEM_READ_BIO_EX, PEM_R_BAD_BASE64_DECODE);
+ goto end;
+ }
+ len += taillen;
+ buf_mem->length = len;
+
+ /* There was no data in the PEM file; avoid malloc(0). */
+ if (len == 0)
+ goto end;
+ headerlen = BIO_get_mem_data(headerB, NULL);
+ *header = pem_malloc(headerlen + 1, flags);
+ *data = pem_malloc(len, flags);
+ if (*header == NULL || *data == NULL) {
+ pem_free(*header, flags, 0);
+ pem_free(*data, flags, 0);
+ goto end;
+ }
+ BIO_read(headerB, *header, headerlen);
+ (*header)[headerlen] = '\0';
+ BIO_read(dataB, *data, len);
+ *len_out = len;
+ *name_out = name;
+ name = NULL;
+ ret = 1;
+
+end:
EVP_ENCODE_CTX_free(ctx);
- return (0);
+ pem_free(name, flags, 0);
+ BIO_free(headerB);
+ BIO_free(dataB);
+ return ret;
+}
+
+int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,
+ long *len)
+{
+ return PEM_read_bio_ex(bp, name, header, data, len, PEM_FLAG_EAY_COMPATIBLE);
}
/*