xref: /onnv-gate/usr/src/common/openssl/crypto/pem/pem_lib.c (revision 2139:6243c3338933)
10Sstevel@tonic-gate /* crypto/pem/pem_lib.c */
20Sstevel@tonic-gate /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
30Sstevel@tonic-gate  * All rights reserved.
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * This package is an SSL implementation written
60Sstevel@tonic-gate  * by Eric Young (eay@cryptsoft.com).
70Sstevel@tonic-gate  * The implementation was written so as to conform with Netscapes SSL.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * This library is free for commercial and non-commercial use as long as
100Sstevel@tonic-gate  * the following conditions are aheared to.  The following conditions
110Sstevel@tonic-gate  * apply to all code found in this distribution, be it the RC4, RSA,
120Sstevel@tonic-gate  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
130Sstevel@tonic-gate  * included with this distribution is covered by the same copyright terms
140Sstevel@tonic-gate  * except that the holder is Tim Hudson (tjh@cryptsoft.com).
150Sstevel@tonic-gate  *
160Sstevel@tonic-gate  * Copyright remains Eric Young's, and as such any Copyright notices in
170Sstevel@tonic-gate  * the code are not to be removed.
180Sstevel@tonic-gate  * If this package is used in a product, Eric Young should be given attribution
190Sstevel@tonic-gate  * as the author of the parts of the library used.
200Sstevel@tonic-gate  * This can be in the form of a textual message at program startup or
210Sstevel@tonic-gate  * in documentation (online or textual) provided with the package.
220Sstevel@tonic-gate  *
230Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
240Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
250Sstevel@tonic-gate  * are met:
260Sstevel@tonic-gate  * 1. Redistributions of source code must retain the copyright
270Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
280Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
290Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
300Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
310Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
320Sstevel@tonic-gate  *    must display the following acknowledgement:
330Sstevel@tonic-gate  *    "This product includes cryptographic software written by
340Sstevel@tonic-gate  *     Eric Young (eay@cryptsoft.com)"
350Sstevel@tonic-gate  *    The word 'cryptographic' can be left out if the rouines from the library
360Sstevel@tonic-gate  *    being used are not cryptographic related :-).
370Sstevel@tonic-gate  * 4. If you include any Windows specific code (or a derivative thereof) from
380Sstevel@tonic-gate  *    the apps directory (application code) you must include an acknowledgement:
390Sstevel@tonic-gate  *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
420Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
430Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
440Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
450Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
460Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
470Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
480Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
490Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
500Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
510Sstevel@tonic-gate  * SUCH DAMAGE.
520Sstevel@tonic-gate  *
530Sstevel@tonic-gate  * The licence and distribution terms for any publically available version or
540Sstevel@tonic-gate  * derivative of this code cannot be changed.  i.e. this code cannot simply be
550Sstevel@tonic-gate  * copied and put under another distribution licence
560Sstevel@tonic-gate  * [including the GNU Public Licence.]
570Sstevel@tonic-gate  */
580Sstevel@tonic-gate 
590Sstevel@tonic-gate #include <stdio.h>
600Sstevel@tonic-gate #include "cryptlib.h"
610Sstevel@tonic-gate #include <openssl/buffer.h>
620Sstevel@tonic-gate #include <openssl/objects.h>
630Sstevel@tonic-gate #include <openssl/evp.h>
640Sstevel@tonic-gate #include <openssl/rand.h>
650Sstevel@tonic-gate #include <openssl/x509.h>
660Sstevel@tonic-gate #include <openssl/pem.h>
670Sstevel@tonic-gate #include <openssl/pkcs12.h>
680Sstevel@tonic-gate #ifndef OPENSSL_NO_DES
690Sstevel@tonic-gate #include <openssl/des.h>
700Sstevel@tonic-gate #endif
710Sstevel@tonic-gate 
720Sstevel@tonic-gate const char *PEM_version="PEM" OPENSSL_VERSION_PTEXT;
730Sstevel@tonic-gate 
740Sstevel@tonic-gate #define MIN_LENGTH	4
750Sstevel@tonic-gate 
76*2139Sjp161948 static int load_iv(char **fromp,unsigned char *to, int num);
770Sstevel@tonic-gate static int check_pem(const char *nm, const char *name);
780Sstevel@tonic-gate 
PEM_def_callback(char * buf,int num,int w,void * key)790Sstevel@tonic-gate int PEM_def_callback(char *buf, int num, int w, void *key)
800Sstevel@tonic-gate 	{
810Sstevel@tonic-gate #ifdef OPENSSL_NO_FP_API
820Sstevel@tonic-gate 	/* We should not ever call the default callback routine from
830Sstevel@tonic-gate 	 * windows. */
84*2139Sjp161948 	PEMerr(PEM_F_PEM_DEF_CALLBACK,ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
850Sstevel@tonic-gate 	return(-1);
860Sstevel@tonic-gate #else
870Sstevel@tonic-gate 	int i,j;
880Sstevel@tonic-gate 	const char *prompt;
890Sstevel@tonic-gate 	if(key) {
900Sstevel@tonic-gate 		i=strlen(key);
910Sstevel@tonic-gate 		i=(i > num)?num:i;
920Sstevel@tonic-gate 		memcpy(buf,key,i);
930Sstevel@tonic-gate 		return(i);
940Sstevel@tonic-gate 	}
950Sstevel@tonic-gate 
960Sstevel@tonic-gate 	prompt=EVP_get_pw_prompt();
970Sstevel@tonic-gate 	if (prompt == NULL)
980Sstevel@tonic-gate 		prompt="Enter PEM pass phrase:";
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	for (;;)
1010Sstevel@tonic-gate 		{
1020Sstevel@tonic-gate 		i=EVP_read_pw_string(buf,num,prompt,w);
1030Sstevel@tonic-gate 		if (i != 0)
1040Sstevel@tonic-gate 			{
105*2139Sjp161948 			PEMerr(PEM_F_PEM_DEF_CALLBACK,PEM_R_PROBLEMS_GETTING_PASSWORD);
1060Sstevel@tonic-gate 			memset(buf,0,(unsigned int)num);
1070Sstevel@tonic-gate 			return(-1);
1080Sstevel@tonic-gate 			}
1090Sstevel@tonic-gate 		j=strlen(buf);
1100Sstevel@tonic-gate 		if (j < MIN_LENGTH)
1110Sstevel@tonic-gate 			{
1120Sstevel@tonic-gate 			fprintf(stderr,"phrase is too short, needs to be at least %d chars\n",MIN_LENGTH);
1130Sstevel@tonic-gate 			}
1140Sstevel@tonic-gate 		else
1150Sstevel@tonic-gate 			break;
1160Sstevel@tonic-gate 		}
1170Sstevel@tonic-gate 	return(j);
1180Sstevel@tonic-gate #endif
1190Sstevel@tonic-gate 	}
1200Sstevel@tonic-gate 
PEM_proc_type(char * buf,int type)1210Sstevel@tonic-gate void PEM_proc_type(char *buf, int type)
1220Sstevel@tonic-gate 	{
1230Sstevel@tonic-gate 	const char *str;
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	if (type == PEM_TYPE_ENCRYPTED)
1260Sstevel@tonic-gate 		str="ENCRYPTED";
1270Sstevel@tonic-gate 	else if (type == PEM_TYPE_MIC_CLEAR)
1280Sstevel@tonic-gate 		str="MIC-CLEAR";
1290Sstevel@tonic-gate 	else if (type == PEM_TYPE_MIC_ONLY)
1300Sstevel@tonic-gate 		str="MIC-ONLY";
1310Sstevel@tonic-gate 	else
1320Sstevel@tonic-gate 		str="BAD-TYPE";
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	BUF_strlcat(buf,"Proc-Type: 4,",PEM_BUFSIZE);
1350Sstevel@tonic-gate 	BUF_strlcat(buf,str,PEM_BUFSIZE);
1360Sstevel@tonic-gate 	BUF_strlcat(buf,"\n",PEM_BUFSIZE);
1370Sstevel@tonic-gate 	}
1380Sstevel@tonic-gate 
PEM_dek_info(char * buf,const char * type,int len,char * str)1390Sstevel@tonic-gate void PEM_dek_info(char *buf, const char *type, int len, char *str)
1400Sstevel@tonic-gate 	{
1410Sstevel@tonic-gate 	static const unsigned char map[17]="0123456789ABCDEF";
1420Sstevel@tonic-gate 	long i;
1430Sstevel@tonic-gate 	int j;
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	BUF_strlcat(buf,"DEK-Info: ",PEM_BUFSIZE);
1460Sstevel@tonic-gate 	BUF_strlcat(buf,type,PEM_BUFSIZE);
1470Sstevel@tonic-gate 	BUF_strlcat(buf,",",PEM_BUFSIZE);
1480Sstevel@tonic-gate 	j=strlen(buf);
1490Sstevel@tonic-gate 	if (j + (len * 2) + 1 > PEM_BUFSIZE)
1500Sstevel@tonic-gate         	return;
1510Sstevel@tonic-gate 	for (i=0; i<len; i++)
1520Sstevel@tonic-gate 		{
1530Sstevel@tonic-gate 		buf[j+i*2]  =map[(str[i]>>4)&0x0f];
1540Sstevel@tonic-gate 		buf[j+i*2+1]=map[(str[i]   )&0x0f];
1550Sstevel@tonic-gate 		}
1560Sstevel@tonic-gate 	buf[j+i*2]='\n';
1570Sstevel@tonic-gate 	buf[j+i*2+1]='\0';
1580Sstevel@tonic-gate 	}
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate #ifndef OPENSSL_NO_FP_API
PEM_ASN1_read(d2i_of_void * d2i,const char * name,FILE * fp,void ** x,pem_password_cb * cb,void * u)161*2139Sjp161948 void *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x,
162*2139Sjp161948 		    pem_password_cb *cb, void *u)
1630Sstevel@tonic-gate 	{
1640Sstevel@tonic-gate         BIO *b;
165*2139Sjp161948         void *ret;
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate         if ((b=BIO_new(BIO_s_file())) == NULL)
1680Sstevel@tonic-gate 		{
1690Sstevel@tonic-gate 		PEMerr(PEM_F_PEM_ASN1_READ,ERR_R_BUF_LIB);
1700Sstevel@tonic-gate                 return(0);
1710Sstevel@tonic-gate 		}
1720Sstevel@tonic-gate         BIO_set_fp(b,fp,BIO_NOCLOSE);
1730Sstevel@tonic-gate         ret=PEM_ASN1_read_bio(d2i,name,b,x,cb,u);
1740Sstevel@tonic-gate         BIO_free(b);
1750Sstevel@tonic-gate         return(ret);
1760Sstevel@tonic-gate 	}
1770Sstevel@tonic-gate #endif
1780Sstevel@tonic-gate 
check_pem(const char * nm,const char * name)1790Sstevel@tonic-gate static int check_pem(const char *nm, const char *name)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate 	/* Normal matching nm and name */
1820Sstevel@tonic-gate 	if (!strcmp(nm,name)) return 1;
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate 	/* Make PEM_STRING_EVP_PKEY match any private key */
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	if(!strcmp(nm,PEM_STRING_PKCS8) &&
1870Sstevel@tonic-gate 		!strcmp(name,PEM_STRING_EVP_PKEY)) return 1;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	if(!strcmp(nm,PEM_STRING_PKCS8INF) &&
1900Sstevel@tonic-gate 		 !strcmp(name,PEM_STRING_EVP_PKEY)) return 1;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	if(!strcmp(nm,PEM_STRING_RSA) &&
1930Sstevel@tonic-gate 		!strcmp(name,PEM_STRING_EVP_PKEY)) return 1;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	if(!strcmp(nm,PEM_STRING_DSA) &&
1960Sstevel@tonic-gate 		 !strcmp(name,PEM_STRING_EVP_PKEY)) return 1;
1970Sstevel@tonic-gate 
198*2139Sjp161948  	if(!strcmp(nm,PEM_STRING_ECPRIVATEKEY) &&
199*2139Sjp161948  		 !strcmp(name,PEM_STRING_EVP_PKEY)) return 1;
2000Sstevel@tonic-gate 	/* Permit older strings */
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate 	if(!strcmp(nm,PEM_STRING_X509_OLD) &&
2030Sstevel@tonic-gate 		!strcmp(name,PEM_STRING_X509)) return 1;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	if(!strcmp(nm,PEM_STRING_X509_REQ_OLD) &&
2060Sstevel@tonic-gate 		!strcmp(name,PEM_STRING_X509_REQ)) return 1;
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	/* Allow normal certs to be read as trusted certs */
2090Sstevel@tonic-gate 	if(!strcmp(nm,PEM_STRING_X509) &&
2100Sstevel@tonic-gate 		!strcmp(name,PEM_STRING_X509_TRUSTED)) return 1;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	if(!strcmp(nm,PEM_STRING_X509_OLD) &&
2130Sstevel@tonic-gate 		!strcmp(name,PEM_STRING_X509_TRUSTED)) return 1;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate 	/* Some CAs use PKCS#7 with CERTIFICATE headers */
2160Sstevel@tonic-gate 	if(!strcmp(nm, PEM_STRING_X509) &&
2170Sstevel@tonic-gate 		!strcmp(name, PEM_STRING_PKCS7)) return 1;
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	return 0;
2200Sstevel@tonic-gate }
2210Sstevel@tonic-gate 
PEM_bytes_read_bio(unsigned char ** pdata,long * plen,char ** pnm,const char * name,BIO * bp,pem_password_cb * cb,void * u)2220Sstevel@tonic-gate int PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm, const char *name, BIO *bp,
2230Sstevel@tonic-gate 	     pem_password_cb *cb, void *u)
2240Sstevel@tonic-gate 	{
2250Sstevel@tonic-gate 	EVP_CIPHER_INFO cipher;
2260Sstevel@tonic-gate 	char *nm=NULL,*header=NULL;
2270Sstevel@tonic-gate 	unsigned char *data=NULL;
2280Sstevel@tonic-gate 	long len;
2290Sstevel@tonic-gate 	int ret = 0;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	for (;;)
2320Sstevel@tonic-gate 		{
2330Sstevel@tonic-gate 		if (!PEM_read_bio(bp,&nm,&header,&data,&len)) {
2340Sstevel@tonic-gate 			if(ERR_GET_REASON(ERR_peek_error()) ==
2350Sstevel@tonic-gate 				PEM_R_NO_START_LINE)
2360Sstevel@tonic-gate 				ERR_add_error_data(2, "Expecting: ", name);
2370Sstevel@tonic-gate 			return 0;
2380Sstevel@tonic-gate 		}
2390Sstevel@tonic-gate 		if(check_pem(nm, name)) break;
2400Sstevel@tonic-gate 		OPENSSL_free(nm);
2410Sstevel@tonic-gate 		OPENSSL_free(header);
2420Sstevel@tonic-gate 		OPENSSL_free(data);
2430Sstevel@tonic-gate 		}
2440Sstevel@tonic-gate 	if (!PEM_get_EVP_CIPHER_INFO(header,&cipher)) goto err;
2450Sstevel@tonic-gate 	if (!PEM_do_header(&cipher,data,&len,cb,u)) goto err;
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 	*pdata = data;
2480Sstevel@tonic-gate 	*plen = len;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	if (pnm)
2510Sstevel@tonic-gate 		*pnm = nm;
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	ret = 1;
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate err:
2560Sstevel@tonic-gate 	if (!ret || !pnm) OPENSSL_free(nm);
2570Sstevel@tonic-gate 	OPENSSL_free(header);
2580Sstevel@tonic-gate 	if (!ret) OPENSSL_free(data);
2590Sstevel@tonic-gate 	return ret;
2600Sstevel@tonic-gate 	}
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate #ifndef OPENSSL_NO_FP_API
PEM_ASN1_write(i2d_of_void * i2d,const char * name,FILE * fp,char * x,const EVP_CIPHER * enc,unsigned char * kstr,int klen,pem_password_cb * callback,void * u)263*2139Sjp161948 int PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp,
264*2139Sjp161948 		   char *x, const EVP_CIPHER *enc, unsigned char *kstr,
265*2139Sjp161948 		   int klen, pem_password_cb *callback, void *u)
2660Sstevel@tonic-gate         {
2670Sstevel@tonic-gate         BIO *b;
2680Sstevel@tonic-gate         int ret;
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate         if ((b=BIO_new(BIO_s_file())) == NULL)
2710Sstevel@tonic-gate 		{
2720Sstevel@tonic-gate 		PEMerr(PEM_F_PEM_ASN1_WRITE,ERR_R_BUF_LIB);
2730Sstevel@tonic-gate                 return(0);
2740Sstevel@tonic-gate 		}
2750Sstevel@tonic-gate         BIO_set_fp(b,fp,BIO_NOCLOSE);
2760Sstevel@tonic-gate         ret=PEM_ASN1_write_bio(i2d,name,b,x,enc,kstr,klen,callback,u);
2770Sstevel@tonic-gate         BIO_free(b);
2780Sstevel@tonic-gate         return(ret);
2790Sstevel@tonic-gate         }
2800Sstevel@tonic-gate #endif
2810Sstevel@tonic-gate 
PEM_ASN1_write_bio(i2d_of_void * i2d,const char * name,BIO * bp,char * x,const EVP_CIPHER * enc,unsigned char * kstr,int klen,pem_password_cb * callback,void * u)282*2139Sjp161948 int PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
283*2139Sjp161948 		       char *x, const EVP_CIPHER *enc, unsigned char *kstr,
284*2139Sjp161948 		       int klen, pem_password_cb *callback, void *u)
2850Sstevel@tonic-gate 	{
2860Sstevel@tonic-gate 	EVP_CIPHER_CTX ctx;
2870Sstevel@tonic-gate 	int dsize=0,i,j,ret=0;
2880Sstevel@tonic-gate 	unsigned char *p,*data=NULL;
2890Sstevel@tonic-gate 	const char *objstr=NULL;
2900Sstevel@tonic-gate 	char buf[PEM_BUFSIZE];
2910Sstevel@tonic-gate 	unsigned char key[EVP_MAX_KEY_LENGTH];
2920Sstevel@tonic-gate 	unsigned char iv[EVP_MAX_IV_LENGTH];
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	if (enc != NULL)
2950Sstevel@tonic-gate 		{
2960Sstevel@tonic-gate 		objstr=OBJ_nid2sn(EVP_CIPHER_nid(enc));
2970Sstevel@tonic-gate 		if (objstr == NULL)
2980Sstevel@tonic-gate 			{
2990Sstevel@tonic-gate 			PEMerr(PEM_F_PEM_ASN1_WRITE_BIO,PEM_R_UNSUPPORTED_CIPHER);
3000Sstevel@tonic-gate 			goto err;
3010Sstevel@tonic-gate 			}
3020Sstevel@tonic-gate 		}
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	if ((dsize=i2d(x,NULL)) < 0)
3050Sstevel@tonic-gate 		{
306*2139Sjp161948 		PEMerr(PEM_F_PEM_ASN1_WRITE_BIO,ERR_R_ASN1_LIB);
3070Sstevel@tonic-gate 		dsize=0;
3080Sstevel@tonic-gate 		goto err;
3090Sstevel@tonic-gate 		}
3100Sstevel@tonic-gate 	/* dzise + 8 bytes are needed */
3110Sstevel@tonic-gate 	/* actually it needs the cipher block size extra... */
3120Sstevel@tonic-gate 	data=(unsigned char *)OPENSSL_malloc((unsigned int)dsize+20);
3130Sstevel@tonic-gate 	if (data == NULL)
3140Sstevel@tonic-gate 		{
3150Sstevel@tonic-gate 		PEMerr(PEM_F_PEM_ASN1_WRITE_BIO,ERR_R_MALLOC_FAILURE);
3160Sstevel@tonic-gate 		goto err;
3170Sstevel@tonic-gate 		}
3180Sstevel@tonic-gate 	p=data;
3190Sstevel@tonic-gate 	i=i2d(x,&p);
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	if (enc != NULL)
3220Sstevel@tonic-gate 		{
3230Sstevel@tonic-gate 		if (kstr == NULL)
3240Sstevel@tonic-gate 			{
3250Sstevel@tonic-gate 			if (callback == NULL)
3260Sstevel@tonic-gate 				klen=PEM_def_callback(buf,PEM_BUFSIZE,1,u);
3270Sstevel@tonic-gate 			else
3280Sstevel@tonic-gate 				klen=(*callback)(buf,PEM_BUFSIZE,1,u);
3290Sstevel@tonic-gate 			if (klen <= 0)
3300Sstevel@tonic-gate 				{
3310Sstevel@tonic-gate 				PEMerr(PEM_F_PEM_ASN1_WRITE_BIO,PEM_R_READ_KEY);
3320Sstevel@tonic-gate 				goto err;
3330Sstevel@tonic-gate 				}
3340Sstevel@tonic-gate #ifdef CHARSET_EBCDIC
3350Sstevel@tonic-gate 			/* Convert the pass phrase from EBCDIC */
3360Sstevel@tonic-gate 			ebcdic2ascii(buf, buf, klen);
3370Sstevel@tonic-gate #endif
3380Sstevel@tonic-gate 			kstr=(unsigned char *)buf;
3390Sstevel@tonic-gate 			}
3400Sstevel@tonic-gate 		RAND_add(data,i,0);/* put in the RSA key. */
341*2139Sjp161948 		OPENSSL_assert(enc->iv_len <= (int)sizeof(iv));
3420Sstevel@tonic-gate 		if (RAND_pseudo_bytes(iv,enc->iv_len) < 0) /* Generate a salt */
3430Sstevel@tonic-gate 			goto err;
3440Sstevel@tonic-gate 		/* The 'iv' is used as the iv and as a salt.  It is
3450Sstevel@tonic-gate 		 * NOT taken from the BytesToKey function */
3460Sstevel@tonic-gate 		EVP_BytesToKey(enc,EVP_md5(),iv,kstr,klen,1,key,NULL);
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 		if (kstr == (unsigned char *)buf) OPENSSL_cleanse(buf,PEM_BUFSIZE);
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 		OPENSSL_assert(strlen(objstr)+23+2*enc->iv_len+13 <= sizeof buf);
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		buf[0]='\0';
3530Sstevel@tonic-gate 		PEM_proc_type(buf,PEM_TYPE_ENCRYPTED);
3540Sstevel@tonic-gate 		PEM_dek_info(buf,objstr,enc->iv_len,(char *)iv);
3550Sstevel@tonic-gate 		/* k=strlen(buf); */
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 		EVP_CIPHER_CTX_init(&ctx);
3580Sstevel@tonic-gate 		EVP_EncryptInit_ex(&ctx,enc,NULL,key,iv);
3590Sstevel@tonic-gate 		EVP_EncryptUpdate(&ctx,data,&j,data,i);
3600Sstevel@tonic-gate 		EVP_EncryptFinal_ex(&ctx,&(data[j]),&i);
3610Sstevel@tonic-gate 		EVP_CIPHER_CTX_cleanup(&ctx);
3620Sstevel@tonic-gate 		i+=j;
3630Sstevel@tonic-gate 		ret=1;
3640Sstevel@tonic-gate 		}
3650Sstevel@tonic-gate 	else
3660Sstevel@tonic-gate 		{
3670Sstevel@tonic-gate 		ret=1;
3680Sstevel@tonic-gate 		buf[0]='\0';
3690Sstevel@tonic-gate 		}
3700Sstevel@tonic-gate 	i=PEM_write_bio(bp,name,buf,data,i);
3710Sstevel@tonic-gate 	if (i <= 0) ret=0;
3720Sstevel@tonic-gate err:
3730Sstevel@tonic-gate 	OPENSSL_cleanse(key,sizeof(key));
3740Sstevel@tonic-gate 	OPENSSL_cleanse(iv,sizeof(iv));
3750Sstevel@tonic-gate 	OPENSSL_cleanse((char *)&ctx,sizeof(ctx));
3760Sstevel@tonic-gate 	OPENSSL_cleanse(buf,PEM_BUFSIZE);
3770Sstevel@tonic-gate 	if (data != NULL)
3780Sstevel@tonic-gate 		{
3790Sstevel@tonic-gate 		OPENSSL_cleanse(data,(unsigned int)dsize);
3800Sstevel@tonic-gate 		OPENSSL_free(data);
3810Sstevel@tonic-gate 		}
3820Sstevel@tonic-gate 	return(ret);
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 
PEM_do_header(EVP_CIPHER_INFO * cipher,unsigned char * data,long * plen,pem_password_cb * callback,void * u)3850Sstevel@tonic-gate int PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen,
3860Sstevel@tonic-gate 	     pem_password_cb *callback,void *u)
3870Sstevel@tonic-gate 	{
3880Sstevel@tonic-gate 	int i,j,o,klen;
3890Sstevel@tonic-gate 	long len;
3900Sstevel@tonic-gate 	EVP_CIPHER_CTX ctx;
3910Sstevel@tonic-gate 	unsigned char key[EVP_MAX_KEY_LENGTH];
3920Sstevel@tonic-gate 	char buf[PEM_BUFSIZE];
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	len= *plen;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	if (cipher->cipher == NULL) return(1);
3970Sstevel@tonic-gate 	if (callback == NULL)
3980Sstevel@tonic-gate 		klen=PEM_def_callback(buf,PEM_BUFSIZE,0,u);
3990Sstevel@tonic-gate 	else
4000Sstevel@tonic-gate 		klen=callback(buf,PEM_BUFSIZE,0,u);
4010Sstevel@tonic-gate 	if (klen <= 0)
4020Sstevel@tonic-gate 		{
4030Sstevel@tonic-gate 		PEMerr(PEM_F_PEM_DO_HEADER,PEM_R_BAD_PASSWORD_READ);
4040Sstevel@tonic-gate 		return(0);
4050Sstevel@tonic-gate 		}
4060Sstevel@tonic-gate #ifdef CHARSET_EBCDIC
4070Sstevel@tonic-gate 	/* Convert the pass phrase from EBCDIC */
4080Sstevel@tonic-gate 	ebcdic2ascii(buf, buf, klen);
4090Sstevel@tonic-gate #endif
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	EVP_BytesToKey(cipher->cipher,EVP_md5(),&(cipher->iv[0]),
4120Sstevel@tonic-gate 		(unsigned char *)buf,klen,1,key,NULL);
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	j=(int)len;
4150Sstevel@tonic-gate 	EVP_CIPHER_CTX_init(&ctx);
4160Sstevel@tonic-gate 	EVP_DecryptInit_ex(&ctx,cipher->cipher,NULL, key,&(cipher->iv[0]));
4170Sstevel@tonic-gate 	EVP_DecryptUpdate(&ctx,data,&i,data,j);
4180Sstevel@tonic-gate 	o=EVP_DecryptFinal_ex(&ctx,&(data[i]),&j);
4190Sstevel@tonic-gate 	EVP_CIPHER_CTX_cleanup(&ctx);
4200Sstevel@tonic-gate 	OPENSSL_cleanse((char *)buf,sizeof(buf));
4210Sstevel@tonic-gate 	OPENSSL_cleanse((char *)key,sizeof(key));
4220Sstevel@tonic-gate 	j+=i;
4230Sstevel@tonic-gate 	if (!o)
4240Sstevel@tonic-gate 		{
4250Sstevel@tonic-gate 		PEMerr(PEM_F_PEM_DO_HEADER,PEM_R_BAD_DECRYPT);
4260Sstevel@tonic-gate 		return(0);
4270Sstevel@tonic-gate 		}
4280Sstevel@tonic-gate 	*plen=j;
4290Sstevel@tonic-gate 	return(1);
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate 
PEM_get_EVP_CIPHER_INFO(char * header,EVP_CIPHER_INFO * cipher)4320Sstevel@tonic-gate int PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher)
4330Sstevel@tonic-gate 	{
4340Sstevel@tonic-gate 	int o;
4350Sstevel@tonic-gate 	const EVP_CIPHER *enc=NULL;
4360Sstevel@tonic-gate 	char *p,c;
437*2139Sjp161948 	char **header_pp = &header;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	cipher->cipher=NULL;
4400Sstevel@tonic-gate 	if ((header == NULL) || (*header == '\0') || (*header == '\n'))
4410Sstevel@tonic-gate 		return(1);
4420Sstevel@tonic-gate 	if (strncmp(header,"Proc-Type: ",11) != 0)
4430Sstevel@tonic-gate 		{ PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO,PEM_R_NOT_PROC_TYPE); return(0); }
4440Sstevel@tonic-gate 	header+=11;
4450Sstevel@tonic-gate 	if (*header != '4') return(0); header++;
4460Sstevel@tonic-gate 	if (*header != ',') return(0); header++;
4470Sstevel@tonic-gate 	if (strncmp(header,"ENCRYPTED",9) != 0)
4480Sstevel@tonic-gate 		{ PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO,PEM_R_NOT_ENCRYPTED); return(0); }
4490Sstevel@tonic-gate 	for (; (*header != '\n') && (*header != '\0'); header++)
4500Sstevel@tonic-gate 		;
4510Sstevel@tonic-gate 	if (*header == '\0')
4520Sstevel@tonic-gate 		{ PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO,PEM_R_SHORT_HEADER); return(0); }
4530Sstevel@tonic-gate 	header++;
4540Sstevel@tonic-gate 	if (strncmp(header,"DEK-Info: ",10) != 0)
4550Sstevel@tonic-gate 		{ PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO,PEM_R_NOT_DEK_INFO); return(0); }
4560Sstevel@tonic-gate 	header+=10;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	p=header;
4590Sstevel@tonic-gate 	for (;;)
4600Sstevel@tonic-gate 		{
4610Sstevel@tonic-gate 		c= *header;
4620Sstevel@tonic-gate #ifndef CHARSET_EBCDIC
4630Sstevel@tonic-gate 		if (!(	((c >= 'A') && (c <= 'Z')) || (c == '-') ||
4640Sstevel@tonic-gate 			((c >= '0') && (c <= '9'))))
4650Sstevel@tonic-gate 			break;
4660Sstevel@tonic-gate #else
4670Sstevel@tonic-gate 		if (!(	isupper(c) || (c == '-') ||
4680Sstevel@tonic-gate 			isdigit(c)))
4690Sstevel@tonic-gate 			break;
4700Sstevel@tonic-gate #endif
4710Sstevel@tonic-gate 		header++;
4720Sstevel@tonic-gate 		}
4730Sstevel@tonic-gate 	*header='\0';
4740Sstevel@tonic-gate 	o=OBJ_sn2nid(p);
4750Sstevel@tonic-gate 	cipher->cipher=enc=EVP_get_cipherbyname(p);
4760Sstevel@tonic-gate 	*header=c;
4770Sstevel@tonic-gate 	header++;
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	if (enc == NULL)
4800Sstevel@tonic-gate 		{
4810Sstevel@tonic-gate 		PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO,PEM_R_UNSUPPORTED_ENCRYPTION);
4820Sstevel@tonic-gate 		return(0);
4830Sstevel@tonic-gate 		}
484*2139Sjp161948 	if (!load_iv(header_pp,&(cipher->iv[0]),enc->iv_len))
485*2139Sjp161948 		return(0);
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	return(1);
4880Sstevel@tonic-gate 	}
4890Sstevel@tonic-gate 
load_iv(char ** fromp,unsigned char * to,int num)490*2139Sjp161948 static int load_iv(char **fromp, unsigned char *to, int num)
4910Sstevel@tonic-gate 	{
4920Sstevel@tonic-gate 	int v,i;
493*2139Sjp161948 	char *from;
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	from= *fromp;
4960Sstevel@tonic-gate 	for (i=0; i<num; i++) to[i]=0;
4970Sstevel@tonic-gate 	num*=2;
4980Sstevel@tonic-gate 	for (i=0; i<num; i++)
4990Sstevel@tonic-gate 		{
5000Sstevel@tonic-gate 		if ((*from >= '0') && (*from <= '9'))
5010Sstevel@tonic-gate 			v= *from-'0';
5020Sstevel@tonic-gate 		else if ((*from >= 'A') && (*from <= 'F'))
5030Sstevel@tonic-gate 			v= *from-'A'+10;
5040Sstevel@tonic-gate 		else if ((*from >= 'a') && (*from <= 'f'))
5050Sstevel@tonic-gate 			v= *from-'a'+10;
5060Sstevel@tonic-gate 		else
5070Sstevel@tonic-gate 			{
5080Sstevel@tonic-gate 			PEMerr(PEM_F_LOAD_IV,PEM_R_BAD_IV_CHARS);
5090Sstevel@tonic-gate 			return(0);
5100Sstevel@tonic-gate 			}
5110Sstevel@tonic-gate 		from++;
5120Sstevel@tonic-gate 		to[i/2]|=v<<(long)((!(i&1))*4);
5130Sstevel@tonic-gate 		}
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 	*fromp=from;
5160Sstevel@tonic-gate 	return(1);
5170Sstevel@tonic-gate 	}
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate #ifndef OPENSSL_NO_FP_API
PEM_write(FILE * fp,char * name,char * header,unsigned char * data,long len)5200Sstevel@tonic-gate int PEM_write(FILE *fp, char *name, char *header, unsigned char *data,
5210Sstevel@tonic-gate 	     long len)
5220Sstevel@tonic-gate         {
5230Sstevel@tonic-gate         BIO *b;
5240Sstevel@tonic-gate         int ret;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate         if ((b=BIO_new(BIO_s_file())) == NULL)
5270Sstevel@tonic-gate 		{
5280Sstevel@tonic-gate 		PEMerr(PEM_F_PEM_WRITE,ERR_R_BUF_LIB);
5290Sstevel@tonic-gate                 return(0);
5300Sstevel@tonic-gate 		}
5310Sstevel@tonic-gate         BIO_set_fp(b,fp,BIO_NOCLOSE);
5320Sstevel@tonic-gate         ret=PEM_write_bio(b, name, header, data,len);
5330Sstevel@tonic-gate         BIO_free(b);
5340Sstevel@tonic-gate         return(ret);
5350Sstevel@tonic-gate         }
5360Sstevel@tonic-gate #endif
5370Sstevel@tonic-gate 
PEM_write_bio(BIO * bp,const char * name,char * header,unsigned char * data,long len)5380Sstevel@tonic-gate int PEM_write_bio(BIO *bp, const char *name, char *header, unsigned char *data,
5390Sstevel@tonic-gate 	     long len)
5400Sstevel@tonic-gate 	{
5410Sstevel@tonic-gate 	int nlen,n,i,j,outl;
5420Sstevel@tonic-gate 	unsigned char *buf = NULL;
5430Sstevel@tonic-gate 	EVP_ENCODE_CTX ctx;
5440Sstevel@tonic-gate 	int reason=ERR_R_BUF_LIB;
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	EVP_EncodeInit(&ctx);
5470Sstevel@tonic-gate 	nlen=strlen(name);
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate 	if (	(BIO_write(bp,"-----BEGIN ",11) != 11) ||
5500Sstevel@tonic-gate 		(BIO_write(bp,name,nlen) != nlen) ||
5510Sstevel@tonic-gate 		(BIO_write(bp,"-----\n",6) != 6))
5520Sstevel@tonic-gate 		goto err;
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	i=strlen(header);
5550Sstevel@tonic-gate 	if (i > 0)
5560Sstevel@tonic-gate 		{
5570Sstevel@tonic-gate 		if (	(BIO_write(bp,header,i) != i) ||
5580Sstevel@tonic-gate 			(BIO_write(bp,"\n",1) != 1))
5590Sstevel@tonic-gate 			goto err;
5600Sstevel@tonic-gate 		}
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	buf = OPENSSL_malloc(PEM_BUFSIZE*8);
5630Sstevel@tonic-gate 	if (buf == NULL)
5640Sstevel@tonic-gate 		{
5650Sstevel@tonic-gate 		reason=ERR_R_MALLOC_FAILURE;
5660Sstevel@tonic-gate 		goto err;
5670Sstevel@tonic-gate 		}
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	i=j=0;
5700Sstevel@tonic-gate 	while (len > 0)
5710Sstevel@tonic-gate 		{
5720Sstevel@tonic-gate 		n=(int)((len>(PEM_BUFSIZE*5))?(PEM_BUFSIZE*5):len);
5730Sstevel@tonic-gate 		EVP_EncodeUpdate(&ctx,buf,&outl,&(data[j]),n);
5740Sstevel@tonic-gate 		if ((outl) && (BIO_write(bp,(char *)buf,outl) != outl))
5750Sstevel@tonic-gate 			goto err;
5760Sstevel@tonic-gate 		i+=outl;
5770Sstevel@tonic-gate 		len-=n;
5780Sstevel@tonic-gate 		j+=n;
5790Sstevel@tonic-gate 		}
5800Sstevel@tonic-gate 	EVP_EncodeFinal(&ctx,buf,&outl);
5810Sstevel@tonic-gate 	if ((outl > 0) && (BIO_write(bp,(char *)buf,outl) != outl)) goto err;
5820Sstevel@tonic-gate 	OPENSSL_free(buf);
5830Sstevel@tonic-gate 	buf = NULL;
5840Sstevel@tonic-gate 	if (	(BIO_write(bp,"-----END ",9) != 9) ||
5850Sstevel@tonic-gate 		(BIO_write(bp,name,nlen) != nlen) ||
5860Sstevel@tonic-gate 		(BIO_write(bp,"-----\n",6) != 6))
5870Sstevel@tonic-gate 		goto err;
5880Sstevel@tonic-gate 	return(i+outl);
5890Sstevel@tonic-gate err:
5900Sstevel@tonic-gate 	if (buf)
5910Sstevel@tonic-gate 		OPENSSL_free(buf);
5920Sstevel@tonic-gate 	PEMerr(PEM_F_PEM_WRITE_BIO,reason);
5930Sstevel@tonic-gate 	return(0);
5940Sstevel@tonic-gate 	}
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate #ifndef OPENSSL_NO_FP_API
PEM_read(FILE * fp,char ** name,char ** header,unsigned char ** data,long * len)5970Sstevel@tonic-gate int PEM_read(FILE *fp, char **name, char **header, unsigned char **data,
5980Sstevel@tonic-gate 	     long *len)
5990Sstevel@tonic-gate         {
6000Sstevel@tonic-gate         BIO *b;
6010Sstevel@tonic-gate         int ret;
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate         if ((b=BIO_new(BIO_s_file())) == NULL)
6040Sstevel@tonic-gate 		{
6050Sstevel@tonic-gate 		PEMerr(PEM_F_PEM_READ,ERR_R_BUF_LIB);
6060Sstevel@tonic-gate                 return(0);
6070Sstevel@tonic-gate 		}
6080Sstevel@tonic-gate         BIO_set_fp(b,fp,BIO_NOCLOSE);
6090Sstevel@tonic-gate         ret=PEM_read_bio(b, name, header, data,len);
6100Sstevel@tonic-gate         BIO_free(b);
6110Sstevel@tonic-gate         return(ret);
6120Sstevel@tonic-gate         }
6130Sstevel@tonic-gate #endif
6140Sstevel@tonic-gate 
PEM_read_bio(BIO * bp,char ** name,char ** header,unsigned char ** data,long * len)6150Sstevel@tonic-gate int PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,
6160Sstevel@tonic-gate 	     long *len)
6170Sstevel@tonic-gate 	{
6180Sstevel@tonic-gate 	EVP_ENCODE_CTX ctx;
6190Sstevel@tonic-gate 	int end=0,i,k,bl=0,hl=0,nohead=0;
6200Sstevel@tonic-gate 	char buf[256];
6210Sstevel@tonic-gate 	BUF_MEM *nameB;
6220Sstevel@tonic-gate 	BUF_MEM *headerB;
6230Sstevel@tonic-gate 	BUF_MEM *dataB,*tmpB;
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	nameB=BUF_MEM_new();
6260Sstevel@tonic-gate 	headerB=BUF_MEM_new();
6270Sstevel@tonic-gate 	dataB=BUF_MEM_new();
6280Sstevel@tonic-gate 	if ((nameB == NULL) || (headerB == NULL) || (dataB == NULL))
6290Sstevel@tonic-gate 		{
630*2139Sjp161948 		BUF_MEM_free(nameB);
631*2139Sjp161948 		BUF_MEM_free(headerB);
632*2139Sjp161948 		BUF_MEM_free(dataB);
6330Sstevel@tonic-gate 		PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE);
6340Sstevel@tonic-gate 		return(0);
6350Sstevel@tonic-gate 		}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	buf[254]='\0';
6380Sstevel@tonic-gate 	for (;;)
6390Sstevel@tonic-gate 		{
6400Sstevel@tonic-gate 		i=BIO_gets(bp,buf,254);
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 		if (i <= 0)
6430Sstevel@tonic-gate 			{
6440Sstevel@tonic-gate 			PEMerr(PEM_F_PEM_READ_BIO,PEM_R_NO_START_LINE);
6450Sstevel@tonic-gate 			goto err;
6460Sstevel@tonic-gate 			}
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 		while ((i >= 0) && (buf[i] <= ' ')) i--;
6490Sstevel@tonic-gate 		buf[++i]='\n'; buf[++i]='\0';
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 		if (strncmp(buf,"-----BEGIN ",11) == 0)
6520Sstevel@tonic-gate 			{
6530Sstevel@tonic-gate 			i=strlen(&(buf[11]));
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 			if (strncmp(&(buf[11+i-6]),"-----\n",6) != 0)
6560Sstevel@tonic-gate 				continue;
6570Sstevel@tonic-gate 			if (!BUF_MEM_grow(nameB,i+9))
6580Sstevel@tonic-gate 				{
6590Sstevel@tonic-gate 				PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE);
6600Sstevel@tonic-gate 				goto err;
6610Sstevel@tonic-gate 				}
6620Sstevel@tonic-gate 			memcpy(nameB->data,&(buf[11]),i-6);
6630Sstevel@tonic-gate 			nameB->data[i-6]='\0';
6640Sstevel@tonic-gate 			break;
6650Sstevel@tonic-gate 			}
6660Sstevel@tonic-gate 		}
6670Sstevel@tonic-gate 	hl=0;
6680Sstevel@tonic-gate 	if (!BUF_MEM_grow(headerB,256))
6690Sstevel@tonic-gate 		{ PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE); goto err; }
6700Sstevel@tonic-gate 	headerB->data[0]='\0';
6710Sstevel@tonic-gate 	for (;;)
6720Sstevel@tonic-gate 		{
6730Sstevel@tonic-gate 		i=BIO_gets(bp,buf,254);
6740Sstevel@tonic-gate 		if (i <= 0) break;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 		while ((i >= 0) && (buf[i] <= ' ')) i--;
6770Sstevel@tonic-gate 		buf[++i]='\n'; buf[++i]='\0';
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate 		if (buf[0] == '\n') break;
6800Sstevel@tonic-gate 		if (!BUF_MEM_grow(headerB,hl+i+9))
6810Sstevel@tonic-gate 			{ PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE); goto err; }
6820Sstevel@tonic-gate 		if (strncmp(buf,"-----END ",9) == 0)
6830Sstevel@tonic-gate 			{
6840Sstevel@tonic-gate 			nohead=1;
6850Sstevel@tonic-gate 			break;
6860Sstevel@tonic-gate 			}
6870Sstevel@tonic-gate 		memcpy(&(headerB->data[hl]),buf,i);
6880Sstevel@tonic-gate 		headerB->data[hl+i]='\0';
6890Sstevel@tonic-gate 		hl+=i;
6900Sstevel@tonic-gate 		}
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	bl=0;
6930Sstevel@tonic-gate 	if (!BUF_MEM_grow(dataB,1024))
6940Sstevel@tonic-gate 		{ PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE); goto err; }
6950Sstevel@tonic-gate 	dataB->data[0]='\0';
6960Sstevel@tonic-gate 	if (!nohead)
6970Sstevel@tonic-gate 		{
6980Sstevel@tonic-gate 		for (;;)
6990Sstevel@tonic-gate 			{
7000Sstevel@tonic-gate 			i=BIO_gets(bp,buf,254);
7010Sstevel@tonic-gate 			if (i <= 0) break;
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 			while ((i >= 0) && (buf[i] <= ' ')) i--;
7040Sstevel@tonic-gate 			buf[++i]='\n'; buf[++i]='\0';
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 			if (i != 65) end=1;
7070Sstevel@tonic-gate 			if (strncmp(buf,"-----END ",9) == 0)
7080Sstevel@tonic-gate 				break;
7090Sstevel@tonic-gate 			if (i > 65) break;
7100Sstevel@tonic-gate 			if (!BUF_MEM_grow_clean(dataB,i+bl+9))
7110Sstevel@tonic-gate 				{
7120Sstevel@tonic-gate 				PEMerr(PEM_F_PEM_READ_BIO,ERR_R_MALLOC_FAILURE);
7130Sstevel@tonic-gate 				goto err;
7140Sstevel@tonic-gate 				}
7150Sstevel@tonic-gate 			memcpy(&(dataB->data[bl]),buf,i);
7160Sstevel@tonic-gate 			dataB->data[bl+i]='\0';
7170Sstevel@tonic-gate 			bl+=i;
7180Sstevel@tonic-gate 			if (end)
7190Sstevel@tonic-gate 				{
7200Sstevel@tonic-gate 				buf[0]='\0';
7210Sstevel@tonic-gate 				i=BIO_gets(bp,buf,254);
7220Sstevel@tonic-gate 				if (i <= 0) break;
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 				while ((i >= 0) && (buf[i] <= ' ')) i--;
7250Sstevel@tonic-gate 				buf[++i]='\n'; buf[++i]='\0';
7260Sstevel@tonic-gate 
7270Sstevel@tonic-gate 				break;
7280Sstevel@tonic-gate 				}
7290Sstevel@tonic-gate 			}
7300Sstevel@tonic-gate 		}
7310Sstevel@tonic-gate 	else
7320Sstevel@tonic-gate 		{
7330Sstevel@tonic-gate 		tmpB=headerB;
7340Sstevel@tonic-gate 		headerB=dataB;
7350Sstevel@tonic-gate 		dataB=tmpB;
7360Sstevel@tonic-gate 		bl=hl;
7370Sstevel@tonic-gate 		}
7380Sstevel@tonic-gate 	i=strlen(nameB->data);
7390Sstevel@tonic-gate 	if (	(strncmp(buf,"-----END ",9) != 0) ||
7400Sstevel@tonic-gate 		(strncmp(nameB->data,&(buf[9]),i) != 0) ||
7410Sstevel@tonic-gate 		(strncmp(&(buf[9+i]),"-----\n",6) != 0))
7420Sstevel@tonic-gate 		{
7430Sstevel@tonic-gate 		PEMerr(PEM_F_PEM_READ_BIO,PEM_R_BAD_END_LINE);
7440Sstevel@tonic-gate 		goto err;
7450Sstevel@tonic-gate 		}
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	EVP_DecodeInit(&ctx);
7480Sstevel@tonic-gate 	i=EVP_DecodeUpdate(&ctx,
7490Sstevel@tonic-gate 		(unsigned char *)dataB->data,&bl,
7500Sstevel@tonic-gate 		(unsigned char *)dataB->data,bl);
7510Sstevel@tonic-gate 	if (i < 0)
7520Sstevel@tonic-gate 		{
7530Sstevel@tonic-gate 		PEMerr(PEM_F_PEM_READ_BIO,PEM_R_BAD_BASE64_DECODE);
7540Sstevel@tonic-gate 		goto err;
7550Sstevel@tonic-gate 		}
7560Sstevel@tonic-gate 	i=EVP_DecodeFinal(&ctx,(unsigned char *)&(dataB->data[bl]),&k);
7570Sstevel@tonic-gate 	if (i < 0)
7580Sstevel@tonic-gate 		{
7590Sstevel@tonic-gate 		PEMerr(PEM_F_PEM_READ_BIO,PEM_R_BAD_BASE64_DECODE);
7600Sstevel@tonic-gate 		goto err;
7610Sstevel@tonic-gate 		}
7620Sstevel@tonic-gate 	bl+=k;
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 	if (bl == 0) goto err;
7650Sstevel@tonic-gate 	*name=nameB->data;
7660Sstevel@tonic-gate 	*header=headerB->data;
7670Sstevel@tonic-gate 	*data=(unsigned char *)dataB->data;
7680Sstevel@tonic-gate 	*len=bl;
7690Sstevel@tonic-gate 	OPENSSL_free(nameB);
7700Sstevel@tonic-gate 	OPENSSL_free(headerB);
7710Sstevel@tonic-gate 	OPENSSL_free(dataB);
7720Sstevel@tonic-gate 	return(1);
7730Sstevel@tonic-gate err:
7740Sstevel@tonic-gate 	BUF_MEM_free(nameB);
7750Sstevel@tonic-gate 	BUF_MEM_free(headerB);
7760Sstevel@tonic-gate 	BUF_MEM_free(dataB);
7770Sstevel@tonic-gate 	return(0);
7780Sstevel@tonic-gate 	}
779