diff options
Diffstat (limited to 'Cryptlib/OpenSSL/crypto/pem/pem_lib.c')
-rw-r--r-- | Cryptlib/OpenSSL/crypto/pem/pem_lib.c | 434 |
1 files changed, 213 insertions, 221 deletions
diff --git a/Cryptlib/OpenSSL/crypto/pem/pem_lib.c b/Cryptlib/OpenSSL/crypto/pem/pem_lib.c index e25cc685..2792593c 100644 --- a/Cryptlib/OpenSSL/crypto/pem/pem_lib.c +++ b/Cryptlib/OpenSSL/crypto/pem/pem_lib.c @@ -1,64 +1,16 @@ -/* crypto/pem/pem_lib.c */ -/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) - * All rights reserved. - * - * This package is an SSL implementation written - * by Eric Young (eay@cryptsoft.com). - * The implementation was written so as to conform with Netscapes SSL. - * - * This library is free for commercial and non-commercial use as long as - * the following conditions are aheared to. The following conditions - * apply to all code found in this distribution, be it the RC4, RSA, - * lhash, DES, etc., code; not just the SSL code. The SSL documentation - * included with this distribution is covered by the same copyright terms - * except that the holder is Tim Hudson (tjh@cryptsoft.com). - * - * Copyright remains Eric Young's, and as such any Copyright notices in - * the code are not to be removed. - * If this package is used in a product, Eric Young should be given attribution - * as the author of the parts of the library used. - * This can be in the form of a textual message at program startup or - * in documentation (online or textual) provided with the package. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * "This product includes cryptographic software written by - * Eric Young (eay@cryptsoft.com)" - * The word 'cryptographic' can be left out if the rouines from the library - * being used are not cryptographic related :-). - * 4. If you include any Windows specific code (or a derivative thereof) from - * the apps directory (application code) you must include an acknowledgement: - * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" - * - * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. +/* + * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. * - * The licence and distribution terms for any publically available version or - * derivative of this code cannot be changed. i.e. this code cannot simply be - * copied and put under another distribution licence - * [including the GNU Public Licence.] + * Licensed under the OpenSSL license (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 */ #include <stdio.h> #include <ctype.h> -#include "cryptlib.h" +#include <string.h> +#include "internal/cryptlib.h" #include <openssl/buffer.h> #include <openssl/objects.h> #include <openssl/evp.h> @@ -66,15 +18,9 @@ #include <openssl/x509.h> #include <openssl/pem.h> #include <openssl/pkcs12.h> -#include "asn1_locl.h" -#ifndef OPENSSL_NO_DES -# include <openssl/des.h> -#endif -#ifndef OPENSSL_NO_ENGINE -# include <openssl/engine.h> -#endif - -const char PEM_version[] = "PEM" OPENSSL_VERSION_PTEXT; +#include "internal/asn1_int.h" +#include <openssl/des.h> +#include <openssl/engine.h> #define MIN_LENGTH 4 @@ -84,42 +30,50 @@ int pem_check_suffix(const char *pem_str, const char *suffix); int PEM_def_callback(char *buf, int num, int w, void *key) { -#if defined(OPENSSL_NO_FP_API) || defined(OPENSSL_NO_UI) - /* - * We should not ever call the default callback routine from windows. - */ - PEMerr(PEM_F_PEM_DEF_CALLBACK, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED); - return (-1); +#if defined(OPENSSL_NO_STDIO) || defined(OPENSSL_NO_UI) + int i; #else int i, j; const char *prompt; +#endif + if (key) { i = strlen(key); i = (i > num) ? num : i; memcpy(buf, key, i); - return (i); + return i; } +#if defined(OPENSSL_NO_STDIO) || defined(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:"; for (;;) { - i = EVP_read_pw_string_min(buf, MIN_LENGTH, num, prompt, w); + /* + * We assume that w == 0 means decryption, + * while w == 1 means encryption + */ + int min_len = w ? MIN_LENGTH : 0; + + i = EVP_read_pw_string_min(buf, min_len, num, prompt, w); if (i != 0) { PEMerr(PEM_F_PEM_DEF_CALLBACK, PEM_R_PROBLEMS_GETTING_PASSWORD); memset(buf, 0, (unsigned int)num); - return (-1); + return -1; } j = strlen(buf); - if (j < MIN_LENGTH) { + if (min_len && j < min_len) { fprintf(stderr, "phrase is too short, needs to be at least %d chars\n", - MIN_LENGTH); + min_len); } else break; } - return (j); + return j; #endif } @@ -136,9 +90,9 @@ void PEM_proc_type(char *buf, int type) else str = "BAD-TYPE"; - BUF_strlcat(buf, "Proc-Type: 4,", PEM_BUFSIZE); - BUF_strlcat(buf, str, PEM_BUFSIZE); - BUF_strlcat(buf, "\n", PEM_BUFSIZE); + OPENSSL_strlcat(buf, "Proc-Type: 4,", PEM_BUFSIZE); + OPENSSL_strlcat(buf, str, PEM_BUFSIZE); + OPENSSL_strlcat(buf, "\n", PEM_BUFSIZE); } void PEM_dek_info(char *buf, const char *type, int len, char *str) @@ -147,9 +101,9 @@ void PEM_dek_info(char *buf, const char *type, int len, char *str) long i; int j; - BUF_strlcat(buf, "DEK-Info: ", PEM_BUFSIZE); - BUF_strlcat(buf, type, PEM_BUFSIZE); - BUF_strlcat(buf, ",", PEM_BUFSIZE); + 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; @@ -161,7 +115,7 @@ void PEM_dek_info(char *buf, const char *type, int len, char *str) buf[j + i * 2 + 1] = '\0'; } -#ifndef OPENSSL_NO_FP_API +#ifndef OPENSSL_NO_STDIO void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x, pem_password_cb *cb, void *u) { @@ -182,22 +136,22 @@ void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x, static int check_pem(const char *nm, const char *name) { /* Normal matching nm and name */ - if (!strcmp(nm, name)) + if (strcmp(nm, name) == 0) return 1; /* Make PEM_STRING_EVP_PKEY match any private key */ - if (!strcmp(name, PEM_STRING_EVP_PKEY)) { + if (strcmp(name, PEM_STRING_EVP_PKEY) == 0) { int slen; const EVP_PKEY_ASN1_METHOD *ameth; - if (!strcmp(nm, PEM_STRING_PKCS8)) + if (strcmp(nm, PEM_STRING_PKCS8) == 0) return 1; - if (!strcmp(nm, PEM_STRING_PKCS8INF)) + if (strcmp(nm, PEM_STRING_PKCS8INF) == 0) return 1; slen = pem_check_suffix(nm, "PRIVATE KEY"); if (slen > 0) { /* - * NB: ENGINE implementations wont contain a deprecated old + * NB: ENGINE implementations won't contain a deprecated old * private key decode function so don't look for them. */ ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen); @@ -207,7 +161,7 @@ static int check_pem(const char *nm, const char *name) return 0; } - if (!strcmp(name, PEM_STRING_PARAMETERS)) { + if (strcmp(name, PEM_STRING_PARAMETERS) == 0) { int slen; const EVP_PKEY_ASN1_METHOD *ameth; slen = pem_check_suffix(nm, "PARAMETERS"); @@ -221,8 +175,7 @@ static int check_pem(const char *nm, const char *name) else r = 0; #ifndef OPENSSL_NO_ENGINE - if (e) - ENGINE_finish(e); + ENGINE_finish(e); #endif return r; } @@ -230,41 +183,45 @@ static int check_pem(const char *nm, const char *name) return 0; } /* If reading DH parameters handle X9.42 DH format too */ - if (!strcmp(nm, PEM_STRING_DHXPARAMS) && - !strcmp(name, PEM_STRING_DHPARAMS)) + if (strcmp(nm, PEM_STRING_DHXPARAMS) == 0 + && strcmp(name, PEM_STRING_DHPARAMS) == 0) return 1; /* Permit older strings */ - if (!strcmp(nm, PEM_STRING_X509_OLD) && !strcmp(name, PEM_STRING_X509)) + if (strcmp(nm, PEM_STRING_X509_OLD) == 0 + && strcmp(name, PEM_STRING_X509) == 0) return 1; - if (!strcmp(nm, PEM_STRING_X509_REQ_OLD) && - !strcmp(name, PEM_STRING_X509_REQ)) + if (strcmp(nm, PEM_STRING_X509_REQ_OLD) == 0 + && strcmp(name, PEM_STRING_X509_REQ) == 0) return 1; /* Allow normal certs to be read as trusted certs */ - if (!strcmp(nm, PEM_STRING_X509) && - !strcmp(name, PEM_STRING_X509_TRUSTED)) + if (strcmp(nm, PEM_STRING_X509) == 0 + && strcmp(name, PEM_STRING_X509_TRUSTED) == 0) return 1; - if (!strcmp(nm, PEM_STRING_X509_OLD) && - !strcmp(name, PEM_STRING_X509_TRUSTED)) + if (strcmp(nm, PEM_STRING_X509_OLD) == 0 + && strcmp(name, PEM_STRING_X509_TRUSTED) == 0) return 1; /* Some CAs use PKCS#7 with CERTIFICATE headers */ - if (!strcmp(nm, PEM_STRING_X509) && !strcmp(name, PEM_STRING_PKCS7)) + if (strcmp(nm, PEM_STRING_X509) == 0 + && strcmp(name, PEM_STRING_PKCS7) == 0) return 1; - if (!strcmp(nm, PEM_STRING_PKCS7_SIGNED) && - !strcmp(name, PEM_STRING_PKCS7)) + if (strcmp(nm, PEM_STRING_PKCS7_SIGNED) == 0 + && strcmp(name, PEM_STRING_PKCS7) == 0) return 1; #ifndef OPENSSL_NO_CMS - if (!strcmp(nm, PEM_STRING_X509) && !strcmp(name, PEM_STRING_CMS)) + if (strcmp(nm, PEM_STRING_X509) == 0 + && strcmp(name, PEM_STRING_CMS) == 0) return 1; /* Allow CMS to be read from PKCS#7 headers */ - if (!strcmp(nm, PEM_STRING_PKCS7) && !strcmp(name, PEM_STRING_CMS)) + if (strcmp(nm, PEM_STRING_PKCS7) == 0 + && strcmp(name, PEM_STRING_CMS) == 0) return 1; #endif @@ -315,7 +272,7 @@ int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, return ret; } -#ifndef OPENSSL_NO_FP_API +#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) @@ -338,8 +295,8 @@ 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) { - EVP_CIPHER_CTX ctx; - int dsize = 0, i, j, ret = 0; + EVP_CIPHER_CTX *ctx = NULL; + int dsize = 0, i = 0, j = 0, ret = 0; unsigned char *p, *data = NULL; const char *objstr = NULL; char buf[PEM_BUFSIZE]; @@ -361,7 +318,7 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, } /* dzise + 8 bytes are needed */ /* actually it needs the cipher block size extra... */ - data = (unsigned char *)OPENSSL_malloc((unsigned int)dsize + 20); + data = OPENSSL_malloc((unsigned int)dsize + 20); if (data == NULL) { PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, ERR_R_MALLOC_FAILURE); goto err; @@ -386,8 +343,8 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, kstr = (unsigned char *)buf; } RAND_add(data, i, 0); /* put in the RSA key. */ - OPENSSL_assert(enc->iv_len <= (int)sizeof(iv)); - if (RAND_pseudo_bytes(iv, enc->iv_len) < 0) /* Generate a salt */ + 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; /* * The 'iv' is used as the iv and as a salt. It is NOT taken from @@ -399,21 +356,20 @@ 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 * enc->iv_len + 13 <= - sizeof buf); + 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, enc->iv_len, (char *)iv); + PEM_dek_info(buf, objstr, EVP_CIPHER_iv_length(enc), (char *)iv); /* k=strlen(buf); */ - EVP_CIPHER_CTX_init(&ctx); ret = 1; - if (!EVP_EncryptInit_ex(&ctx, enc, NULL, key, iv) - || !EVP_EncryptUpdate(&ctx, data, &j, data, i) - || !EVP_EncryptFinal_ex(&ctx, &(data[j]), &i)) + if ((ctx = EVP_CIPHER_CTX_new()) == NULL + || !EVP_EncryptInit_ex(ctx, enc, NULL, key, iv) + || !EVP_EncryptUpdate(ctx, data, &j, data, i) + || !EVP_EncryptFinal_ex(ctx, &(data[j]), &i)) ret = 0; - EVP_CIPHER_CTX_cleanup(&ctx); if (ret == 0) goto err; i += j; @@ -427,127 +383,162 @@ int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp, err: OPENSSL_cleanse(key, sizeof(key)); OPENSSL_cleanse(iv, sizeof(iv)); - OPENSSL_cleanse((char *)&ctx, sizeof(ctx)); + EVP_CIPHER_CTX_free(ctx); OPENSSL_cleanse(buf, PEM_BUFSIZE); - if (data != NULL) { - OPENSSL_cleanse(data, (unsigned int)dsize); - OPENSSL_free(data); - } + OPENSSL_clear_free(data, (unsigned int)dsize); return (ret); } int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen, pem_password_cb *callback, void *u) { - int i = 0, j, o, klen; - long len; - EVP_CIPHER_CTX ctx; + int ok; + int keylen; + long len = *plen; + int ilen = (int) len; /* EVP_DecryptUpdate etc. take int lengths */ + EVP_CIPHER_CTX *ctx; unsigned char key[EVP_MAX_KEY_LENGTH]; char buf[PEM_BUFSIZE]; - len = *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); + return 0; + } +#endif if (cipher->cipher == NULL) - return (1); + return 1; if (callback == NULL) - klen = PEM_def_callback(buf, PEM_BUFSIZE, 0, u); + keylen = PEM_def_callback(buf, PEM_BUFSIZE, 0, u); else - klen = callback(buf, PEM_BUFSIZE, 0, u); - if (klen <= 0) { + keylen = callback(buf, PEM_BUFSIZE, 0, u); + if (keylen <= 0) { PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_BAD_PASSWORD_READ); - return (0); + return 0; } #ifdef CHARSET_EBCDIC /* Convert the pass phrase from EBCDIC */ - ebcdic2ascii(buf, buf, klen); + ebcdic2ascii(buf, buf, keylen); #endif if (!EVP_BytesToKey(cipher->cipher, EVP_md5(), &(cipher->iv[0]), - (unsigned char *)buf, klen, 1, key, NULL)) + (unsigned char *)buf, keylen, 1, key, NULL)) return 0; - j = (int)len; - EVP_CIPHER_CTX_init(&ctx); - o = EVP_DecryptInit_ex(&ctx, cipher->cipher, NULL, key, &(cipher->iv[0])); - if (o) - o = EVP_DecryptUpdate(&ctx, data, &i, data, j); - if (o) - o = EVP_DecryptFinal_ex(&ctx, &(data[i]), &j); - EVP_CIPHER_CTX_cleanup(&ctx); + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) + return 0; + + ok = EVP_DecryptInit_ex(ctx, cipher->cipher, NULL, key, &(cipher->iv[0])); + if (ok) + ok = EVP_DecryptUpdate(ctx, data, &ilen, data, ilen); + if (ok) { + /* Squirrel away the length of data decrypted so far. */ + *plen = ilen; + ok = EVP_DecryptFinal_ex(ctx, &(data[ilen]), &ilen); + } + if (ok) + *plen += ilen; + else + PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_BAD_DECRYPT); + + EVP_CIPHER_CTX_free(ctx); OPENSSL_cleanse((char *)buf, sizeof(buf)); OPENSSL_cleanse((char *)key, sizeof(key)); - if (o) - j += i; - else { - PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_BAD_DECRYPT); - return (0); - } - *plen = j; - return (1); + return ok; } +/* + * This implements a very limited PEM header parser that does not support the + * full grammar of rfc1421. In particular, folded headers are not supported, + * nor is additional whitespace. + * + * A robust implementation would make use of a library that turns the headers + * into a BIO from which one folded line is read at a time, and is then split + * into a header label and content. We would then parse the content of the + * headers we care about. This is overkill for just this limited use-case, but + * presumably we also parse rfc822-style headers for S/MIME, so a common + * abstraction might well be more generally useful. + */ 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; - char *p, c; - char **header_pp = &header; + int ivlen; + char *dekinfostart, c; cipher->cipher = NULL; if ((header == NULL) || (*header == '\0') || (*header == '\n')) - return (1); - if (strncmp(header, "Proc-Type: ", 11) != 0) { + return 1; + + if (strncmp(header, ProcType, sizeof(ProcType)-1) != 0) { PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_NOT_PROC_TYPE); - return (0); + return 0; } - header += 11; - if (*header != '4') - return (0); - header++; - if (*header != ',') - return (0); - header++; - if (strncmp(header, "ENCRYPTED", 9) != 0) { + header += sizeof(ProcType)-1; + header += strspn(header, " \t"); + + if (*header++ != '4' || *header++ != ',') + return 0; + 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); - return (0); + return 0; } - for (; (*header != '\n') && (*header != '\0'); header++) ; - if (*header == '\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); - return (0); + return 0; } - header++; - if (strncmp(header, "DEK-Info: ", 10) != 0) { + + /*- + * 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); - return (0); + return 0; } - header += 10; + header += sizeof(DEKInfo)-1; + header += strspn(header, " \t"); - p = header; - for (;;) { - c = *header; -#ifndef CHARSET_EBCDIC - if (!(((c >= 'A') && (c <= 'Z')) || (c == '-') || - ((c >= '0') && (c <= '9')))) - break; -#else - if (!(isupper(c) || (c == '-') || isdigit(c))) - break; -#endif - header++; - } + /* + * DEK-INFO is a comma-separated combination of algorithm name and optional + * parameters. + */ + dekinfostart = header; + header += strcspn(header, " \t,"); + c = *header; *header = '\0'; - cipher->cipher = enc = EVP_get_cipherbyname(p); + cipher->cipher = enc = EVP_get_cipherbyname(dekinfostart); *header = c; - header++; + header += strspn(header, " \t"); if (enc == NULL) { PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_UNSUPPORTED_ENCRYPTION); - return (0); + return 0; + } + ivlen = EVP_CIPHER_iv_length(enc); + if (ivlen > 0 && *header++ != ',') { + PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, 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); + return 0; } - if (!load_iv(header_pp, &(cipher->iv[0]), enc->iv_len)) - return (0); - return (1); + if (!load_iv(&header, cipher->iv, EVP_CIPHER_iv_length(enc))) + return 0; + + return 1; } static int load_iv(char **fromp, unsigned char *to, int num) @@ -560,13 +551,8 @@ static int load_iv(char **fromp, unsigned char *to, int num) to[i] = 0; num *= 2; for (i = 0; i < num; i++) { - if ((*from >= '0') && (*from <= '9')) - v = *from - '0'; - else if ((*from >= 'A') && (*from <= 'F')) - v = *from - 'A' + 10; - else if ((*from >= 'a') && (*from <= 'f')) - v = *from - 'a' + 10; - else { + v = OPENSSL_hexchar2int(*from); + if (v < 0) { PEMerr(PEM_F_LOAD_IV, PEM_R_BAD_IV_CHARS); return (0); } @@ -578,7 +564,7 @@ static int load_iv(char **fromp, unsigned char *to, int num) return (1); } -#ifndef OPENSSL_NO_FP_API +#ifndef OPENSSL_NO_STDIO int PEM_write(FILE *fp, const char *name, const char *header, const unsigned char *data, long len) { @@ -601,10 +587,15 @@ 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 *ctx = EVP_ENCODE_CTX_new(); int reason = ERR_R_BUF_LIB; - EVP_EncodeInit(&ctx); + if (ctx == NULL) { + reason = ERR_R_MALLOC_FAILURE; + goto err; + } + + EVP_EncodeInit(ctx); nlen = strlen(name); if ((BIO_write(bp, "-----BEGIN ", 11) != 11) || @@ -627,34 +618,32 @@ int PEM_write_bio(BIO *bp, const char *name, const char *header, i = j = 0; while (len > 0) { n = (int)((len > (PEM_BUFSIZE * 5)) ? (PEM_BUFSIZE * 5) : len); - EVP_EncodeUpdate(&ctx, buf, &outl, &(data[j]), n); + if (!EVP_EncodeUpdate(ctx, buf, &outl, &(data[j]), n)) + goto err; if ((outl) && (BIO_write(bp, (char *)buf, outl) != outl)) goto err; i += outl; len -= n; j += n; } - EVP_EncodeFinal(&ctx, buf, &outl); + EVP_EncodeFinal(ctx, buf, &outl); if ((outl > 0) && (BIO_write(bp, (char *)buf, outl) != outl)) goto err; - OPENSSL_cleanse(buf, PEM_BUFSIZE * 8); - OPENSSL_free(buf); - buf = NULL; if ((BIO_write(bp, "-----END ", 9) != 9) || (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); err: - if (buf) { - OPENSSL_cleanse(buf, PEM_BUFSIZE * 8); - OPENSSL_free(buf); - } + OPENSSL_clear_free(buf, PEM_BUFSIZE * 8); + EVP_ENCODE_CTX_free(ctx); PEMerr(PEM_F_PEM_WRITE_BIO, reason); return (0); } -#ifndef OPENSSL_NO_FP_API +#ifndef OPENSSL_NO_STDIO int PEM_read(FILE *fp, char **name, char **header, unsigned char **data, long *len) { @@ -675,22 +664,23 @@ int PEM_read(FILE *fp, char **name, char **header, unsigned char **data, int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data, long *len) { - EVP_ENCODE_CTX ctx; + 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; + if (ctx == NULL) { + PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE); + return (0); + } + nameB = BUF_MEM_new(); headerB = BUF_MEM_new(); dataB = BUF_MEM_new(); if ((nameB == NULL) || (headerB == NULL) || (dataB == NULL)) { - BUF_MEM_free(nameB); - BUF_MEM_free(headerB); - BUF_MEM_free(dataB); - PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE); - return (0); + goto err; } buf[254] = '\0'; @@ -810,15 +800,15 @@ int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data, goto err; } - EVP_DecodeInit(&ctx); - i = EVP_DecodeUpdate(&ctx, + 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; } - i = EVP_DecodeFinal(&ctx, (unsigned char *)&(dataB->data[bl]), &k); + 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; @@ -834,11 +824,13 @@ int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data, 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); + EVP_ENCODE_CTX_free(ctx); return (0); } |