X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fpem%2Fpem_lib.c;h=7695699c739bf089259e77946a74314e0298a972;hp=5000f268b9be580046ebb9a3cc437ce289af45b1;hb=HEAD;hpb=d6d94d339756332bbabe2a1032ac511ae31b3fdc diff --git a/crypto/pem/pem_lib.c b/crypto/pem/pem_lib.c index 5000f268b9..9d8ad35ad3 100644 --- a/crypto/pem/pem_lib.c +++ b/crypto/pem/pem_lib.c @@ -1,14 +1,17 @@ /* - * Copyright 1995-2018 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html */ +/* We need to use some engine deprecated APIs */ +#define OPENSSL_SUPPRESS_DEPRECATED + #include -#include "internal/ctype.h" +#include "crypto/ctype.h" #include #include "internal/cryptlib.h" #include @@ -18,7 +21,7 @@ #include #include #include -#include "internal/asn1_int.h" +#include "crypto/asn1.h" #include #include @@ -26,7 +29,7 @@ static int load_iv(char **fromp, unsigned char *to, int num); static int check_pem(const char *nm, const char *name); -int pem_check_suffix(const char *pem_str, const char *suffix); +int ossl_pem_check_suffix(const char *pem_str, const char *suffix); int PEM_def_callback(char *buf, int num, int rwflag, void *userdata) { @@ -56,7 +59,7 @@ int PEM_def_callback(char *buf, int num, int rwflag, void *userdata) i = EVP_read_pw_string_min(buf, min_len, num, prompt, rwflag); if (i != 0) { - PEMerr(PEM_F_PEM_DEF_CALLBACK, PEM_R_PROBLEMS_GETTING_PASSWORD); + ERR_raise(ERR_LIB_PEM, PEM_R_PROBLEMS_GETTING_PASSWORD); memset(buf, 0, (unsigned int)num); return -1; } @@ -80,7 +83,7 @@ void PEM_proc_type(char *buf, int type) 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) +void PEM_dek_info(char *buf, const char *type, int len, const char *str) { long i; char *p = buf + strlen(buf); @@ -110,7 +113,7 @@ void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x, void *ret; if ((b = BIO_new(BIO_s_file())) == NULL) { - PEMerr(PEM_F_PEM_ASN1_READ, ERR_R_BUF_LIB); + ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); return 0; } BIO_set_fp(b, fp, BIO_NOCLOSE); @@ -135,7 +138,7 @@ static int check_pem(const char *nm, const char *name) return 1; if (strcmp(nm, PEM_STRING_PKCS8INF) == 0) return 1; - slen = pem_check_suffix(nm, "PRIVATE KEY"); + slen = ossl_pem_check_suffix(nm, "PRIVATE KEY"); if (slen > 0) { /* * NB: ENGINE implementations won't contain a deprecated old @@ -151,7 +154,7 @@ static int check_pem(const char *nm, const char *name) if (strcmp(name, PEM_STRING_PARAMETERS) == 0) { int slen; const EVP_PKEY_ASN1_METHOD *ameth; - slen = pem_check_suffix(nm, "PARAMETERS"); + slen = ossl_pem_check_suffix(nm, "PARAMETERS"); if (slen > 0) { ENGINE *e; ameth = EVP_PKEY_asn1_find_str(&e, nm, slen); @@ -215,18 +218,25 @@ static int check_pem(const char *nm, const char *name) return 0; } -static void pem_free(void *p, unsigned int flags, size_t num) +#define PEM_FREE(p, flags, num) \ + pem_free((p), (flags), (num), OPENSSL_FILE, OPENSSL_LINE) +static void pem_free(void *p, unsigned int flags, size_t num, + const char *file, int line) { if (flags & PEM_FLAG_SECURE) - OPENSSL_secure_clear_free(p, num); + CRYPTO_secure_clear_free(p, num, file, line); else - OPENSSL_free(p); + CRYPTO_free(p, file, line); } -static void *pem_malloc(int num, unsigned int flags) +#define PEM_MALLOC(num, flags) \ + pem_malloc((num), (flags), OPENSSL_FILE, OPENSSL_LINE) +static void *pem_malloc(int num, unsigned int flags, + const char *file, int line) { - return (flags & PEM_FLAG_SECURE) ? OPENSSL_secure_malloc(num) - : OPENSSL_malloc(num); + return (flags & PEM_FLAG_SECURE) ? CRYPTO_secure_malloc(num, file, line) + : CRYPTO_malloc(num, file, line); + } static int pem_bytes_read_bio_flags(unsigned char **pdata, long *plen, @@ -241,9 +251,9 @@ static int pem_bytes_read_bio_flags(unsigned char **pdata, long *plen, int ret = 0; do { - pem_free(nm, flags, 0); - pem_free(header, flags, 0); - pem_free(data, flags, len); + 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); @@ -265,10 +275,10 @@ static int pem_bytes_read_bio_flags(unsigned char **pdata, long *plen, err: if (!ret || pnm == NULL) - pem_free(nm, flags, 0); - pem_free(header, flags, 0); + PEM_FREE(nm, flags, 0); + PEM_FREE(header, flags, 0); if (!ret) - pem_free(data, flags, len); + PEM_FREE(data, flags, len); return ret; } @@ -288,14 +298,15 @@ int PEM_bytes_read_bio_secmem(unsigned char **pdata, long *plen, char **pnm, #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, - int klen, pem_password_cb *callback, void *u) + const void *x, const EVP_CIPHER *enc, + const unsigned char *kstr, int klen, + pem_password_cb *callback, void *u) { BIO *b; int ret; if ((b = BIO_new(BIO_s_file())) == NULL) { - PEMerr(PEM_F_PEM_ASN1_WRITE, ERR_R_BUF_LIB); + ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); return 0; } BIO_set_fp(b, fp, BIO_NOCLOSE); @@ -306,8 +317,9 @@ int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp, #endif int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, - void *x, const EVP_CIPHER *enc, unsigned char *kstr, - int klen, pem_password_cb *callback, void *u) + const void *x, const EVP_CIPHER *enc, + const unsigned char *kstr, int klen, + pem_password_cb *callback, void *u) { EVP_CIPHER_CTX *ctx = NULL; int dsize = 0, i = 0, j = 0, ret = 0; @@ -318,32 +330,30 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, unsigned char iv[EVP_MAX_IV_LENGTH]; if (enc != NULL) { - objstr = OBJ_nid2sn(EVP_CIPHER_nid(enc)); - if (objstr == NULL || EVP_CIPHER_iv_length(enc) == 0 - || EVP_CIPHER_iv_length(enc) > (int)sizeof(iv) + objstr = EVP_CIPHER_get0_name(enc); + if (objstr == NULL || EVP_CIPHER_get_iv_length(enc) == 0 + || EVP_CIPHER_get_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) + || strlen(objstr) + 23 + 2 * EVP_CIPHER_get_iv_length(enc) + 13 > sizeof(buf)) { - PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, PEM_R_UNSUPPORTED_CIPHER); + ERR_raise(ERR_LIB_PEM, PEM_R_UNSUPPORTED_CIPHER); goto err; } } - if ((dsize = i2d(x, NULL)) < 0) { - PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, ERR_R_ASN1_LIB); + if ((dsize = i2d(x, NULL)) <= 0) { + ERR_raise(ERR_LIB_PEM, ERR_R_ASN1_LIB); dsize = 0; goto err; } /* dsize + 8 bytes are needed */ /* actually it needs the cipher block size extra... */ data = OPENSSL_malloc((unsigned int)dsize + 20); - if (data == NULL) { - PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, ERR_R_MALLOC_FAILURE); + if (data == NULL) goto err; - } p = data; i = i2d(x, &p); @@ -354,7 +364,7 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, else klen = (*callback) (buf, PEM_BUFSIZE, 1, u); if (klen <= 0) { - PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, PEM_R_READ_KEY); + ERR_raise(ERR_LIB_PEM, PEM_R_READ_KEY); goto err; } #ifdef CHARSET_EBCDIC @@ -363,7 +373,8 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, #endif kstr = (unsigned char *)buf; } - if (RAND_bytes(iv, EVP_CIPHER_iv_length(enc)) <= 0) /* Generate a salt */ + /* Generate a salt */ + if (RAND_bytes(iv, EVP_CIPHER_get_iv_length(enc)) <= 0) goto err; /* * The 'iv' is used as the iv and as a salt. It is NOT taken from @@ -377,7 +388,7 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, buf[0] = '\0'; PEM_proc_type(buf, PEM_TYPE_ENCRYPTED); - PEM_dek_info(buf, objstr, EVP_CIPHER_iv_length(enc), (char *)iv); + PEM_dek_info(buf, objstr, EVP_CIPHER_get_iv_length(enc), (char *)iv); /* k=strlen(buf); */ ret = 1; @@ -419,7 +430,7 @@ int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen, #if LONG_MAX > INT_MAX /* Check that we did not truncate the length */ if (len > INT_MAX) { - PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_HEADER_TOO_LONG); + ERR_raise(ERR_LIB_PEM, PEM_R_HEADER_TOO_LONG); return 0; } #endif @@ -430,8 +441,8 @@ int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen, keylen = PEM_def_callback(buf, PEM_BUFSIZE, 0, u); else keylen = callback(buf, PEM_BUFSIZE, 0, u); - if (keylen <= 0) { - PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_BAD_PASSWORD_READ); + if (keylen < 0) { + ERR_raise(ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ); return 0; } #ifdef CHARSET_EBCDIC @@ -458,7 +469,7 @@ int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen, if (ok) *plen += ilen; else - PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_BAD_DECRYPT); + ERR_raise(ERR_LIB_PEM, PEM_R_BAD_DECRYPT); EVP_CIPHER_CTX_free(ctx); OPENSSL_cleanse((char *)buf, sizeof(buf)); @@ -478,24 +489,24 @@ int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen, * presumably we also parse rfc822-style headers for S/MIME, so a common * abstraction might well be more generally useful. */ +#define PROC_TYPE "Proc-Type:" +#define ENCRYPTED "ENCRYPTED" +#define DEK_INFO "DEK-Info:" int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher) { - static const char ProcType[] = "Proc-Type:"; - static const char ENCRYPTED[] = "ENCRYPTED"; - static const char DEKInfo[] = "DEK-Info:"; const EVP_CIPHER *enc = NULL; int ivlen; char *dekinfostart, c; cipher->cipher = NULL; + memset(cipher->iv, 0, sizeof(cipher->iv)); if ((header == NULL) || (*header == '\0') || (*header == '\n')) return 1; - if (strncmp(header, ProcType, sizeof(ProcType)-1) != 0) { - PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_NOT_PROC_TYPE); + if (!CHECK_AND_SKIP_PREFIX(header, PROC_TYPE)) { + ERR_raise(ERR_LIB_PEM, PEM_R_NOT_PROC_TYPE); return 0; } - header += sizeof(ProcType)-1; header += strspn(header, " \t"); if (*header++ != '4' || *header++ != ',') @@ -503,15 +514,14 @@ int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher) header += strspn(header, " \t"); /* We expect "ENCRYPTED" followed by optional white-space + line break */ - if (strncmp(header, ENCRYPTED, sizeof(ENCRYPTED)-1) != 0 || - strspn(header+sizeof(ENCRYPTED)-1, " \t\r\n") == 0) { - PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_NOT_ENCRYPTED); + if (!CHECK_AND_SKIP_PREFIX(header, ENCRYPTED) || + strspn(header, " \t\r\n") == 0) { + ERR_raise(ERR_LIB_PEM, PEM_R_NOT_ENCRYPTED); return 0; } - header += sizeof(ENCRYPTED)-1; header += strspn(header, " \t\r"); if (*header++ != '\n') { - PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_SHORT_HEADER); + ERR_raise(ERR_LIB_PEM, PEM_R_SHORT_HEADER); return 0; } @@ -519,11 +529,10 @@ int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher) * https://tools.ietf.org/html/rfc1421#section-4.6.1.3 * We expect "DEK-Info: algo[,hex-parameters]" */ - if (strncmp(header, DEKInfo, sizeof(DEKInfo)-1) != 0) { - PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_NOT_DEK_INFO); + if (!CHECK_AND_SKIP_PREFIX(header, DEK_INFO)) { + ERR_raise(ERR_LIB_PEM, PEM_R_NOT_DEK_INFO); return 0; } - header += sizeof(DEKInfo)-1; header += strspn(header, " \t"); /* @@ -539,19 +548,19 @@ int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher) header += strspn(header, " \t"); if (enc == NULL) { - PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_UNSUPPORTED_ENCRYPTION); + ERR_raise(ERR_LIB_PEM, PEM_R_UNSUPPORTED_ENCRYPTION); return 0; } - ivlen = EVP_CIPHER_iv_length(enc); + ivlen = EVP_CIPHER_get_iv_length(enc); if (ivlen > 0 && *header++ != ',') { - PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_MISSING_DEK_IV); + ERR_raise(ERR_LIB_PEM, PEM_R_MISSING_DEK_IV); return 0; } else if (ivlen == 0 && *header == ',') { - PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_UNEXPECTED_DEK_IV); + ERR_raise(ERR_LIB_PEM, PEM_R_UNEXPECTED_DEK_IV); return 0; } - if (!load_iv(&header, cipher->iv, EVP_CIPHER_iv_length(enc))) + if (!load_iv(&header, cipher->iv, EVP_CIPHER_get_iv_length(enc))) return 0; return 1; @@ -569,7 +578,7 @@ static int load_iv(char **fromp, unsigned char *to, int num) for (i = 0; i < num; i++) { v = OPENSSL_hexchar2int(*from); if (v < 0) { - PEMerr(PEM_F_LOAD_IV, PEM_R_BAD_IV_CHARS); + ERR_raise(ERR_LIB_PEM, PEM_R_BAD_IV_CHARS); return 0; } from++; @@ -588,7 +597,7 @@ int PEM_write(FILE *fp, const char *name, const char *header, int ret; if ((b = BIO_new(BIO_s_file())) == NULL) { - PEMerr(PEM_F_PEM_WRITE, ERR_R_BUF_LIB); + ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); return 0; } BIO_set_fp(b, fp, BIO_NOCLOSE); @@ -604,11 +613,11 @@ int PEM_write_bio(BIO *bp, const char *name, const char *header, int nlen, n, i, j, outl; unsigned char *buf = NULL; EVP_ENCODE_CTX *ctx = EVP_ENCODE_CTX_new(); - int reason = ERR_R_BUF_LIB; + int reason = 0; int retval = 0; if (ctx == NULL) { - reason = ERR_R_MALLOC_FAILURE; + reason = ERR_R_EVP_LIB; goto err; } @@ -617,44 +626,54 @@ int PEM_write_bio(BIO *bp, const char *name, const char *header, if ((BIO_write(bp, "-----BEGIN ", 11) != 11) || (BIO_write(bp, name, nlen) != nlen) || - (BIO_write(bp, "-----\n", 6) != 6)) + (BIO_write(bp, "-----\n", 6) != 6)) { + reason = ERR_R_BIO_LIB; goto err; + } - i = strlen(header); + i = header != NULL ? strlen(header) : 0; if (i > 0) { - if ((BIO_write(bp, header, i) != i) || (BIO_write(bp, "\n", 1) != 1)) + if ((BIO_write(bp, header, i) != i) || (BIO_write(bp, "\n", 1) != 1)) { + reason = ERR_R_BIO_LIB; goto err; + } } buf = OPENSSL_malloc(PEM_BUFSIZE * 8); - if (buf == NULL) { - reason = ERR_R_MALLOC_FAILURE; + if (buf == NULL) goto err; - } i = j = 0; while (len > 0) { n = (int)((len > (PEM_BUFSIZE * 5)) ? (PEM_BUFSIZE * 5) : len); - if (!EVP_EncodeUpdate(ctx, buf, &outl, &(data[j]), n)) + if (!EVP_EncodeUpdate(ctx, buf, &outl, &(data[j]), n)) { + reason = ERR_R_EVP_LIB; goto err; - if ((outl) && (BIO_write(bp, (char *)buf, outl) != outl)) + } + if ((outl) && (BIO_write(bp, (char *)buf, outl) != outl)) { + reason = ERR_R_BIO_LIB; goto err; + } i += outl; len -= n; j += n; } EVP_EncodeFinal(ctx, buf, &outl); - if ((outl > 0) && (BIO_write(bp, (char *)buf, outl) != outl)) + if ((outl > 0) && (BIO_write(bp, (char *)buf, outl) != outl)) { + reason = ERR_R_BIO_LIB; goto err; + } if ((BIO_write(bp, "-----END ", 9) != 9) || (BIO_write(bp, name, nlen) != nlen) || - (BIO_write(bp, "-----\n", 6) != 6)) + (BIO_write(bp, "-----\n", 6) != 6)) { + reason = ERR_R_BIO_LIB; goto err; + } retval = i + outl; err: - if (retval == 0) - PEMerr(PEM_F_PEM_WRITE_BIO, reason); + if (retval == 0 && reason != 0) + ERR_raise(ERR_LIB_PEM, reason); EVP_ENCODE_CTX_free(ctx); OPENSSL_clear_free(buf, PEM_BUFSIZE * 8); return retval; @@ -668,7 +687,7 @@ int PEM_read(FILE *fp, char **name, char **header, unsigned char **data, int ret; if ((b = BIO_new(BIO_s_file())) == NULL) { - PEMerr(PEM_F_PEM_READ, ERR_R_BUF_LIB); + ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); return 0; } BIO_set_fp(b, fp, BIO_NOCLOSE); @@ -679,9 +698,20 @@ int PEM_read(FILE *fp, char **name, char **header, unsigned char **data, #endif /* Some helpers for PEM_read_bio_ex(). */ -static int sanitize_line(char *linebuf, int len, unsigned int flags) +static int sanitize_line(char *linebuf, int len, unsigned int flags, int first_call) { int i; + if (first_call) { + /* Other BOMs imply unsupported multibyte encoding, + * so don't strip them and let the error raise */ + const unsigned char utf8_bom[3] = {0xEF, 0xBB, 0xBF}; + + if (len > 3 && memcmp(linebuf, utf8_bom, 3) == 0) { + memmove(linebuf, linebuf + 3, len - 3); + linebuf[len - 3] = 0; + len -= 3; + } + } if (flags & PEM_FLAG_EAY_COMPATIBLE) { /* Strip trailing whitespace */ @@ -715,55 +745,53 @@ static int sanitize_line(char *linebuf, int len, unsigned int flags) #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)) +#define BEGINSTR "-----BEGIN " +#define ENDSTR "-----END " +#define 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; + int first_call = 1; /* * 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); + linebuf = PEM_MALLOC(LINESIZE + 1, flags); + if (linebuf == NULL) return 0; - } do { len = BIO_gets(bp, linebuf, LINESIZE); if (len <= 0) { - PEMerr(PEM_F_GET_NAME, PEM_R_NO_START_LINE); + ERR_raise(ERR_LIB_PEM, PEM_R_NO_START_LINE); goto err; } /* Strip trailing garbage and standardize ending. */ - len = sanitize_line(linebuf, len, flags & ~PEM_FLAG_ONLY_B64); + len = sanitize_line(linebuf, len, flags & ~PEM_FLAG_ONLY_B64, first_call); + first_call = 0; /* Allow leading empty or non-matching lines. */ - } while (strncmp(linebuf, beginstr, BEGINLEN) != 0 + } while (!HAS_PREFIX(linebuf, BEGINSTR) || len < TAILLEN - || strncmp(linebuf + len - TAILLEN, tailstr, TAILLEN) != 0); + || !HAS_PREFIX(linebuf + len - TAILLEN, TAILSTR)); 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); + *name = PEM_MALLOC(len, flags); + if (*name == NULL) goto err; - } memcpy(*name, linebuf + BEGINLEN, len); ret = 1; err: - pem_free(linebuf, flags, LINESIZE + 1); + PEM_FREE(linebuf, flags, LINESIZE + 1); return ret; } @@ -790,7 +818,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, 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; @@ -798,47 +826,59 @@ static int get_header_and_data(BIO *bp, BIO **header, BIO **data, char *name, /* 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); + linebuf = PEM_MALLOC(LINESIZE + 1, flags); + if (linebuf == NULL) return 0; - } - for (line = 0; ; line++) { + while(1) { flags_mask = ~0u; len = BIO_gets(bp, linebuf, LINESIZE); if (len <= 0) { - PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_SHORT_HEADER); + ERR_raise(ERR_LIB_PEM, PEM_R_BAD_END_LINE); 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; } - if (!strncmp(linebuf, endstr, ENDLEN) || got_header == IN_HEADER) + if (HAS_PREFIX(linebuf, ENDSTR) || got_header == IN_HEADER) flags_mask &= ~PEM_FLAG_ONLY_B64; - len = sanitize_line(linebuf, len, flags & flags_mask); + len = sanitize_line(linebuf, len, flags & flags_mask, 0); /* 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. */ + ERR_raise(ERR_LIB_PEM, PEM_R_BAD_END_LINE); + goto err; + } + got_header = POST_HEADER; + tmp = *data; } - got_header = POST_HEADER; - tmp = *data; continue; } /* Check for end of stream (which means there is no header). */ - if (strncmp(linebuf, endstr, ENDLEN) == 0) { - p = linebuf + ENDLEN; + p = linebuf; + if (CHECK_AND_SKIP_PREFIX(p, ENDSTR)) { 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); + !HAS_PREFIX(p + namelen, TAILSTR)) { + ERR_raise(ERR_LIB_PEM, PEM_R_BAD_END_LINE); goto err; } if (got_header == MAYBE_HEADER) { @@ -848,7 +888,7 @@ static int get_header_and_data(BIO *bp, BIO **header, BIO **data, char *name, break; } else if (end) { /* Malformed input; short line not at end of data. */ - PEMerr(PEM_F_GET_HEADER_AND_DATA, PEM_R_BAD_END_LINE); + ERR_raise(ERR_LIB_PEM, PEM_R_BAD_END_LINE); goto err; } /* @@ -871,7 +911,7 @@ static int get_header_and_data(BIO *bp, BIO **header, BIO **data, char *name, ret = 1; err: - pem_free(linebuf, flags, LINESIZE + 1); + PEM_FREE(linebuf, flags, LINESIZE + 1); return ret; } @@ -879,30 +919,24 @@ err: * 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, or lines that are longer than 80 - * characters, are malformed input and will be rejected. + * 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(); + EVP_ENCODE_CTX *ctx = NULL; const BIO_METHOD *bmeth; BIO *headerB = NULL, *dataB = NULL; char *name = NULL; int len, taillen, headerlen, ret = 0; - BUF_MEM * buf_mem; - - if (ctx == NULL) { - PEMerr(PEM_F_PEM_READ_BIO_EX, ERR_R_MALLOC_FAILURE); - return 0; - } + BUF_MEM *buf_mem; *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); + ERR_raise(ERR_LIB_PEM, ERR_R_PASSED_INVALID_ARGUMENT); goto end; } bmeth = (flags & PEM_FLAG_SECURE) ? BIO_s_secmem() : BIO_s_mem(); @@ -910,7 +944,7 @@ int PEM_read_bio_ex(BIO *bp, char **name_out, char **header, headerB = BIO_new(bmeth); dataB = BIO_new(bmeth); if (headerB == NULL || dataB == NULL) { - PEMerr(PEM_F_PEM_READ_BIO_EX, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_PEM, ERR_R_BIO_LIB); goto end; } @@ -919,41 +953,54 @@ int PEM_read_bio_ex(BIO *bp, char **name_out, char **header, 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; + + /* There was no data in the PEM file */ + if (len == 0) + goto end; + + ctx = EVP_ENCODE_CTX_new(); + if (ctx == NULL) { + ERR_raise(ERR_LIB_PEM, ERR_R_EVP_LIB); + goto end; + } + + EVP_DecodeInit(ctx); 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); + ERR_raise(ERR_LIB_PEM, 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 = PEM_MALLOC(headerlen + 1, flags); + *data = PEM_MALLOC(len, flags); + if (*header == NULL || *data == NULL) + goto out_free; + if (headerlen != 0 && BIO_read(headerB, *header, headerlen) != headerlen) + goto out_free; (*header)[headerlen] = '\0'; - BIO_read(dataB, *data, len); + if (BIO_read(dataB, *data, len) != len) + goto out_free; *len_out = len; *name_out = name; name = NULL; ret = 1; + goto end; +out_free: + PEM_FREE(*header, flags, 0); + *header = NULL; + PEM_FREE(*data, flags, 0); + *data = NULL; end: EVP_ENCODE_CTX_free(ctx); - pem_free(name, flags, 0); + PEM_FREE(name, flags, 0); BIO_free(headerB); BIO_free(dataB); return ret; @@ -971,7 +1018,7 @@ int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data, * string "RSA". */ -int pem_check_suffix(const char *pem_str, const char *suffix) +int ossl_pem_check_suffix(const char *pem_str, const char *suffix) { int pem_len = strlen(pem_str); int suffix_len = strlen(suffix);