Integrated support for PVK files.
This commit is contained in:
		| @@ -18,10 +18,10 @@ APPS= | ||||
|  | ||||
| LIB=$(TOP)/libcrypto.a | ||||
| LIBSRC= pem_sign.c pem_seal.c pem_info.c pem_lib.c pem_all.c pem_err.c \ | ||||
| 	pem_x509.c pem_xaux.c pem_oth.c pem_pk8.c pem_pkey.c | ||||
| 	pem_x509.c pem_xaux.c pem_oth.c pem_pk8.c pem_pkey.c pvkfmt.c | ||||
|  | ||||
| LIBOBJ=	pem_sign.o pem_seal.o pem_info.o pem_lib.o pem_all.o pem_err.o \ | ||||
| 	pem_x509.o pem_xaux.o pem_oth.o pem_pk8.o pem_pkey.o | ||||
| 	pem_x509.o pem_xaux.o pem_oth.o pem_pk8.o pem_pkey.o pvkfmt.o | ||||
|  | ||||
| SRC= $(LIBSRC) | ||||
|  | ||||
|   | ||||
| @@ -677,6 +677,18 @@ int PEM_write_PKCS8PrivateKey(FILE *fp,EVP_PKEY *x,const EVP_CIPHER *enc, | ||||
| #endif /* SSLEAY_MACROS */ | ||||
|  | ||||
|  | ||||
| EVP_PKEY *b2i_PrivateKey(const unsigned char **in, long length); | ||||
| EVP_PKEY *b2i_PublicKey(const unsigned char **in, long length); | ||||
| EVP_PKEY *b2i_PrivateKey_bio(BIO *in); | ||||
| EVP_PKEY *b2i_PublicKey_bio(BIO *in); | ||||
| int i2b_PrivateKey_bio(BIO *out, EVP_PKEY *pk); | ||||
| int i2b_PublicKey_bio(BIO *out, EVP_PKEY *pk); | ||||
|  | ||||
| EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u); | ||||
| int i2b_PVK_bio(BIO *out, EVP_PKEY *pk, int enclevel, | ||||
| 		pem_password_cb *cb, void *u); | ||||
|  | ||||
|  | ||||
| /* BEGIN ERROR CODES */ | ||||
| /* The following lines are auto generated by the script mkerr.pl. Any changes | ||||
|  * made after this point may be overwritten when the script is next run. | ||||
| @@ -686,10 +698,22 @@ void ERR_load_PEM_strings(void); | ||||
| /* Error codes for the PEM functions. */ | ||||
|  | ||||
| /* Function codes. */ | ||||
| #define PEM_F_B2I_DSS					 127 | ||||
| #define PEM_F_B2I_PVK_BIO				 128 | ||||
| #define PEM_F_B2I_RSA					 129 | ||||
| #define PEM_F_CHECK_BITLEN_DSA				 130 | ||||
| #define PEM_F_CHECK_BITLEN_RSA				 131 | ||||
| #define PEM_F_D2I_PKCS8PRIVATEKEY_BIO			 120 | ||||
| #define PEM_F_D2I_PKCS8PRIVATEKEY_FP			 121 | ||||
| #define PEM_F_DO_B2I					 132 | ||||
| #define PEM_F_DO_B2I_BIO				 133 | ||||
| #define PEM_F_DO_BLOB_HEADER				 134 | ||||
| #define PEM_F_DO_PK8PKEY				 126 | ||||
| #define PEM_F_DO_PK8PKEY_FP				 125 | ||||
| #define PEM_F_DO_PVK_BODY				 135 | ||||
| #define PEM_F_DO_PVK_HEADER				 136 | ||||
| #define PEM_F_I2B_PVK					 137 | ||||
| #define PEM_F_I2B_PVK_BIO				 138 | ||||
| #define PEM_F_LOAD_IV					 101 | ||||
| #define PEM_F_PEM_ASN1_READ				 102 | ||||
| #define PEM_F_PEM_ASN1_READ_BIO				 103 | ||||
| @@ -718,18 +742,29 @@ void ERR_load_PEM_strings(void); | ||||
| #define PEM_R_BAD_DECRYPT				 101 | ||||
| #define PEM_R_BAD_END_LINE				 102 | ||||
| #define PEM_R_BAD_IV_CHARS				 103 | ||||
| #define PEM_R_BAD_MAGIC_NUMBER				 116 | ||||
| #define PEM_R_BAD_PASSWORD_READ				 104 | ||||
| #define PEM_R_BAD_VERSION_NUMBER			 117 | ||||
| #define PEM_R_BIO_WRITE_FAILURE				 118 | ||||
| #define PEM_R_ERROR_CONVERTING_PRIVATE_KEY		 115 | ||||
| #define PEM_R_EXPECTING_PRIVATE_KEY_BLOB		 119 | ||||
| #define PEM_R_EXPECTING_PUBLIC_KEY_BLOB			 120 | ||||
| #define PEM_R_INCONSISTENT_HEADER			 121 | ||||
| #define PEM_R_KEYBLOB_HEADER_PARSE_ERROR		 122 | ||||
| #define PEM_R_KEYBLOB_TOO_SHORT				 123 | ||||
| #define PEM_R_NOT_DEK_INFO				 105 | ||||
| #define PEM_R_NOT_ENCRYPTED				 106 | ||||
| #define PEM_R_NOT_PROC_TYPE				 107 | ||||
| #define PEM_R_NO_START_LINE				 108 | ||||
| #define PEM_R_PROBLEMS_GETTING_PASSWORD			 109 | ||||
| #define PEM_R_PUBLIC_KEY_NO_RSA				 110 | ||||
| #define PEM_R_PVK_DATA_TOO_SHORT			 124 | ||||
| #define PEM_R_PVK_TOO_SHORT				 125 | ||||
| #define PEM_R_READ_KEY					 111 | ||||
| #define PEM_R_SHORT_HEADER				 112 | ||||
| #define PEM_R_UNSUPPORTED_CIPHER			 113 | ||||
| #define PEM_R_UNSUPPORTED_ENCRYPTION			 114 | ||||
| #define PEM_R_UNSUPPORTED_KEY_COMPONENTS		 126 | ||||
|  | ||||
| #ifdef  __cplusplus | ||||
| } | ||||
|   | ||||
| @@ -70,10 +70,22 @@ | ||||
|  | ||||
| static ERR_STRING_DATA PEM_str_functs[]= | ||||
| 	{ | ||||
| {ERR_FUNC(PEM_F_B2I_DSS),	"B2I_DSS"}, | ||||
| {ERR_FUNC(PEM_F_B2I_PVK_BIO),	"B2I_PVK_BIO"}, | ||||
| {ERR_FUNC(PEM_F_B2I_RSA),	"B2I_RSA"}, | ||||
| {ERR_FUNC(PEM_F_CHECK_BITLEN_DSA),	"CHECK_BITLEN_DSA"}, | ||||
| {ERR_FUNC(PEM_F_CHECK_BITLEN_RSA),	"CHECK_BITLEN_RSA"}, | ||||
| {ERR_FUNC(PEM_F_D2I_PKCS8PRIVATEKEY_BIO),	"d2i_PKCS8PrivateKey_bio"}, | ||||
| {ERR_FUNC(PEM_F_D2I_PKCS8PRIVATEKEY_FP),	"d2i_PKCS8PrivateKey_fp"}, | ||||
| {ERR_FUNC(PEM_F_DO_B2I),	"DO_B2I"}, | ||||
| {ERR_FUNC(PEM_F_DO_B2I_BIO),	"DO_B2I_BIO"}, | ||||
| {ERR_FUNC(PEM_F_DO_BLOB_HEADER),	"DO_BLOB_HEADER"}, | ||||
| {ERR_FUNC(PEM_F_DO_PK8PKEY),	"DO_PK8PKEY"}, | ||||
| {ERR_FUNC(PEM_F_DO_PK8PKEY_FP),	"DO_PK8PKEY_FP"}, | ||||
| {ERR_FUNC(PEM_F_DO_PVK_BODY),	"DO_PVK_BODY"}, | ||||
| {ERR_FUNC(PEM_F_DO_PVK_HEADER),	"DO_PVK_HEADER"}, | ||||
| {ERR_FUNC(PEM_F_I2B_PVK),	"I2B_PVK"}, | ||||
| {ERR_FUNC(PEM_F_I2B_PVK_BIO),	"I2B_PVK_BIO"}, | ||||
| {ERR_FUNC(PEM_F_LOAD_IV),	"LOAD_IV"}, | ||||
| {ERR_FUNC(PEM_F_PEM_ASN1_READ),	"PEM_ASN1_read"}, | ||||
| {ERR_FUNC(PEM_F_PEM_ASN1_READ_BIO),	"PEM_ASN1_read_bio"}, | ||||
| @@ -105,18 +117,29 @@ static ERR_STRING_DATA PEM_str_reasons[]= | ||||
| {ERR_REASON(PEM_R_BAD_DECRYPT)           ,"bad decrypt"}, | ||||
| {ERR_REASON(PEM_R_BAD_END_LINE)          ,"bad end line"}, | ||||
| {ERR_REASON(PEM_R_BAD_IV_CHARS)          ,"bad iv chars"}, | ||||
| {ERR_REASON(PEM_R_BAD_MAGIC_NUMBER)      ,"bad magic number"}, | ||||
| {ERR_REASON(PEM_R_BAD_PASSWORD_READ)     ,"bad password read"}, | ||||
| {ERR_REASON(PEM_R_BAD_VERSION_NUMBER)    ,"bad version number"}, | ||||
| {ERR_REASON(PEM_R_BIO_WRITE_FAILURE)     ,"bio write failure"}, | ||||
| {ERR_REASON(PEM_R_ERROR_CONVERTING_PRIVATE_KEY),"error converting private key"}, | ||||
| {ERR_REASON(PEM_R_EXPECTING_PRIVATE_KEY_BLOB),"expecting private key blob"}, | ||||
| {ERR_REASON(PEM_R_EXPECTING_PUBLIC_KEY_BLOB),"expecting public key blob"}, | ||||
| {ERR_REASON(PEM_R_INCONSISTENT_HEADER)   ,"inconsistent header"}, | ||||
| {ERR_REASON(PEM_R_KEYBLOB_HEADER_PARSE_ERROR),"keyblob header parse error"}, | ||||
| {ERR_REASON(PEM_R_KEYBLOB_TOO_SHORT)     ,"keyblob too short"}, | ||||
| {ERR_REASON(PEM_R_NOT_DEK_INFO)          ,"not dek info"}, | ||||
| {ERR_REASON(PEM_R_NOT_ENCRYPTED)         ,"not encrypted"}, | ||||
| {ERR_REASON(PEM_R_NOT_PROC_TYPE)         ,"not proc type"}, | ||||
| {ERR_REASON(PEM_R_NO_START_LINE)         ,"no start line"}, | ||||
| {ERR_REASON(PEM_R_PROBLEMS_GETTING_PASSWORD),"problems getting password"}, | ||||
| {ERR_REASON(PEM_R_PUBLIC_KEY_NO_RSA)     ,"public key no rsa"}, | ||||
| {ERR_REASON(PEM_R_PVK_DATA_TOO_SHORT)    ,"pvk data too short"}, | ||||
| {ERR_REASON(PEM_R_PVK_TOO_SHORT)         ,"pvk too short"}, | ||||
| {ERR_REASON(PEM_R_READ_KEY)              ,"read key"}, | ||||
| {ERR_REASON(PEM_R_SHORT_HEADER)          ,"short header"}, | ||||
| {ERR_REASON(PEM_R_UNSUPPORTED_CIPHER)    ,"unsupported cipher"}, | ||||
| {ERR_REASON(PEM_R_UNSUPPORTED_ENCRYPTION),"unsupported encryption"}, | ||||
| {ERR_REASON(PEM_R_UNSUPPORTED_KEY_COMPONENTS),"unsupported key components"}, | ||||
| {0,NULL} | ||||
| 	}; | ||||
|  | ||||
|   | ||||
							
								
								
									
										930
									
								
								crypto/pem/pvkfmt.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										930
									
								
								crypto/pem/pvkfmt.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,930 @@ | ||||
| /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL | ||||
|  * project 2005. | ||||
|  */ | ||||
| /* ==================================================================== | ||||
|  * Copyright (c) 2005 The OpenSSL Project.  All rights reserved. | ||||
|  * | ||||
|  * 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 above 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 acknowledgment: | ||||
|  *    "This product includes software developed by the OpenSSL Project | ||||
|  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" | ||||
|  * | ||||
|  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to | ||||
|  *    endorse or promote products derived from this software without | ||||
|  *    prior written permission. For written permission, please contact | ||||
|  *    licensing@OpenSSL.org. | ||||
|  * | ||||
|  * 5. Products derived from this software may not be called "OpenSSL" | ||||
|  *    nor may "OpenSSL" appear in their names without prior written | ||||
|  *    permission of the OpenSSL Project. | ||||
|  * | ||||
|  * 6. Redistributions of any form whatsoever must retain the following | ||||
|  *    acknowledgment: | ||||
|  *    "This product includes software developed by the OpenSSL Project | ||||
|  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY | ||||
|  * EXPRESSED 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 OpenSSL PROJECT OR | ||||
|  * ITS 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. | ||||
|  * ==================================================================== | ||||
|  * | ||||
|  * This product includes cryptographic software written by Eric Young | ||||
|  * (eay@cryptsoft.com).  This product includes software written by Tim | ||||
|  * Hudson (tjh@cryptsoft.com). | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| /* Support for PVK format keys and related structures (such a PUBLICKEYBLOB | ||||
|  * and PRIVATEKEYBLOB). | ||||
|  */ | ||||
|  | ||||
| #include "cryptlib.h" | ||||
| #include <openssl/pem.h> | ||||
| #include <openssl/rand.h> | ||||
|  | ||||
| /* Utility function: read a DWORD (4 byte unsigned integer) in little endian | ||||
|  * format | ||||
|  */ | ||||
|  | ||||
| static unsigned int read_ledword(const unsigned char **in) | ||||
| 	{ | ||||
| 	const unsigned char *p = *in; | ||||
| 	unsigned int ret; | ||||
| 	ret = *p++; | ||||
| 	ret |= (*p++ << 8); | ||||
| 	ret |= (*p++ << 16); | ||||
| 	ret |= (*p++ << 24); | ||||
| 	*in = p; | ||||
| 	return ret; | ||||
| 	} | ||||
|  | ||||
| /* Read a BIGNUM in little endian format. The docs say that this should take up  | ||||
|  * bitlen/8 bytes. | ||||
|  */ | ||||
|  | ||||
| static int read_lebn(const unsigned char **in, unsigned int nbyte, BIGNUM **r) | ||||
| 	{ | ||||
| 	const unsigned char *p; | ||||
| 	unsigned char *tmpbuf, *q; | ||||
| 	unsigned int i; | ||||
| 	p = *in + nbyte - 1; | ||||
| 	tmpbuf = OPENSSL_malloc(nbyte); | ||||
| 	if (!tmpbuf) | ||||
| 		return 0; | ||||
| 	q = tmpbuf; | ||||
| 	for (i = 0; i < nbyte; i++) | ||||
| 		*q++ = *p--; | ||||
| 	*r = BN_bin2bn(tmpbuf, nbyte, NULL); | ||||
| 	OPENSSL_free(tmpbuf); | ||||
| 	if (*r) | ||||
| 		{ | ||||
| 		*in += nbyte; | ||||
| 		return 1; | ||||
| 		} | ||||
| 	else | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| /* Convert private key blob to EVP_PKEY: RSA and DSA keys supported */ | ||||
|  | ||||
| #define MS_PUBLICKEYBLOB	0x6 | ||||
| #define MS_PRIVATEKEYBLOB	0x7 | ||||
| #define MS_RSA1MAGIC		0x31415352L | ||||
| #define MS_RSA2MAGIC		0x32415352L | ||||
| #define MS_DSS1MAGIC		0x31535344L | ||||
| #define MS_DSS2MAGIC		0x32535344L | ||||
|  | ||||
| #define MS_KEYALG_RSA_KEYX	0xa400 | ||||
| #define MS_KEYALG_DSS_SIGN	0x2200 | ||||
|  | ||||
| #define MS_KEYTYPE_KEYX		0x1 | ||||
| #define MS_KEYTYPE_SIGN		0x2 | ||||
|  | ||||
| /* The PVK file magic number: seems to spell out "bobsfile", who is Bob? */ | ||||
| #define MS_PVKMAGIC		0xb0b5f11eL | ||||
| /* Salt length for PVK files */ | ||||
| #define PVK_SALTLEN		0x10 | ||||
|  | ||||
| static EVP_PKEY *b2i_rsa(const unsigned char **in, unsigned int length, | ||||
| 						unsigned int bitlen, int ispub); | ||||
| static EVP_PKEY *b2i_dss(const unsigned char **in, unsigned int length, | ||||
| 						unsigned int bitlen, int ispub); | ||||
|  | ||||
| static int do_blob_header(const unsigned char **in, unsigned int length, | ||||
| 				unsigned int *pmagic, unsigned int *pbitlen, | ||||
| 				int *pisdss, int *pispub) | ||||
| 	{ | ||||
| 	const unsigned char *p = *in; | ||||
| 	if (length < 16) | ||||
| 		return 0; | ||||
| 	/* bType */ | ||||
| 	if (*p == MS_PUBLICKEYBLOB) | ||||
| 		{ | ||||
| 		if (*pispub == 0) | ||||
| 			{ | ||||
| 			PEMerr(PEM_F_DO_BLOB_HEADER, | ||||
| 					PEM_R_EXPECTING_PRIVATE_KEY_BLOB); | ||||
| 			return 0; | ||||
| 			} | ||||
| 		*pispub = 1; | ||||
| 		} | ||||
| 	else if (*p == MS_PRIVATEKEYBLOB) | ||||
| 		{ | ||||
| 		if (*pispub == 1) | ||||
| 			{ | ||||
| 			PEMerr(PEM_F_DO_BLOB_HEADER, | ||||
| 					PEM_R_EXPECTING_PUBLIC_KEY_BLOB); | ||||
| 			return 0; | ||||
| 			} | ||||
| 		*pispub = 0; | ||||
| 		} | ||||
| 	else | ||||
| 		return 0; | ||||
| 	p++; | ||||
| 	/* Version */ | ||||
| 	if (*p++ != 0x2) | ||||
| 		{ | ||||
| 		PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_BAD_VERSION_NUMBER); | ||||
| 		return 0; | ||||
| 		} | ||||
| 	/* Ignore reserved, aiKeyAlg */ | ||||
| 	p+= 6; | ||||
| 	*pmagic = read_ledword(&p); | ||||
| 	*pbitlen = read_ledword(&p); | ||||
| 	*pisdss = 0; | ||||
| 	switch (*pmagic) | ||||
| 		{ | ||||
|  | ||||
| 		case MS_DSS1MAGIC: | ||||
| 		*pisdss = 1; | ||||
| 		case MS_RSA1MAGIC: | ||||
| 		if (*pispub == 0) | ||||
| 			{ | ||||
| 			PEMerr(PEM_F_DO_BLOB_HEADER, | ||||
| 					PEM_R_EXPECTING_PRIVATE_KEY_BLOB); | ||||
| 			return 0; | ||||
| 			} | ||||
| 		break; | ||||
|  | ||||
| 		case MS_DSS2MAGIC: | ||||
| 		*pisdss = 1; | ||||
| 		case MS_RSA2MAGIC: | ||||
| 		if (*pispub == 1) | ||||
| 			{ | ||||
| 			PEMerr(PEM_F_DO_BLOB_HEADER, | ||||
| 					PEM_R_EXPECTING_PUBLIC_KEY_BLOB); | ||||
| 			return 0; | ||||
| 			} | ||||
| 		break; | ||||
|  | ||||
| 		default: | ||||
| 		PEMerr(PEM_F_DO_BLOB_HEADER, PEM_R_BAD_MAGIC_NUMBER); | ||||
| 		return -1; | ||||
| 		} | ||||
| 	*in = p; | ||||
| 	return 1; | ||||
| 	} | ||||
|  | ||||
| static unsigned int blob_length(unsigned bitlen, int isdss, int ispub) | ||||
| 	{ | ||||
| 	unsigned int nbyte, hnbyte; | ||||
| 	nbyte = (bitlen + 7) >> 3; | ||||
| 	hnbyte = (bitlen + 15) >> 4; | ||||
| 	if (isdss) | ||||
| 		{ | ||||
|  | ||||
| 		/* Expected length: 20 for q + 3 components bitlen each + 24 | ||||
| 		 * for seed structure. | ||||
| 		 */ | ||||
| 		if (ispub) | ||||
| 			return  44 + 3 * nbyte; | ||||
| 		/* Expected length: 20 for q, priv, 2 bitlen components + 24 | ||||
| 		 * for seed structure. | ||||
| 		 */ | ||||
| 		else | ||||
| 			return 64 + 2 * nbyte; | ||||
| 		} | ||||
| 	else | ||||
| 		{ | ||||
| 		/* Expected length: 4 for 'e' + 'n' */ | ||||
| 		if (ispub) | ||||
| 			return 4 + nbyte; | ||||
| 		else | ||||
| 		/* Expected length: 4 for 'e' and 7 other components. | ||||
| 		 * 2 components are bitlen size, 5 are bitlen/2 | ||||
| 		 */ | ||||
| 			return 4 + 2*nbyte + 5*hnbyte; | ||||
| 		} | ||||
|  | ||||
| 	} | ||||
|  | ||||
| static EVP_PKEY *do_b2i(const unsigned char **in, unsigned int length, | ||||
| 								int ispub) | ||||
| 	{ | ||||
| 	const unsigned char *p = *in; | ||||
| 	unsigned int bitlen, magic; | ||||
| 	int isdss; | ||||
| 	if (do_blob_header(&p, length, &magic, &bitlen, &isdss, &ispub) <= 0) | ||||
| 		{ | ||||
| 		PEMerr(PEM_F_DO_B2I, PEM_R_KEYBLOB_HEADER_PARSE_ERROR); | ||||
| 		return NULL; | ||||
| 		} | ||||
| 	length -= 16; | ||||
| 	if (length < blob_length(bitlen, isdss, ispub)) | ||||
| 		{ | ||||
| 		PEMerr(PEM_F_DO_B2I, PEM_R_KEYBLOB_TOO_SHORT); | ||||
| 		return NULL; | ||||
| 		} | ||||
| 	if (isdss) | ||||
| 		return b2i_dss(&p, length, bitlen, ispub); | ||||
| 	else | ||||
| 		return b2i_rsa(&p, length, bitlen, ispub); | ||||
| 	} | ||||
|  | ||||
| static EVP_PKEY *do_b2i_bio(BIO *in, int ispub) | ||||
| 	{ | ||||
| 	const unsigned char *p; | ||||
| 	unsigned char hdr_buf[16], *buf = NULL; | ||||
| 	unsigned int bitlen, magic, length; | ||||
| 	int isdss; | ||||
| 	EVP_PKEY *ret = NULL; | ||||
| 	if (BIO_read(in, hdr_buf, 16) != 16) | ||||
| 		{ | ||||
| 		PEMerr(PEM_F_DO_B2I_BIO, PEM_R_KEYBLOB_TOO_SHORT); | ||||
| 		return NULL; | ||||
| 		} | ||||
| 	p = hdr_buf; | ||||
| 	if (do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) <= 0) | ||||
| 		return NULL; | ||||
|  | ||||
| 	length = blob_length(bitlen, isdss, ispub); | ||||
| 	buf = OPENSSL_malloc(length); | ||||
| 	if (!buf) | ||||
| 		{ | ||||
| 		PEMerr(PEM_F_DO_B2I_BIO, ERR_R_MALLOC_FAILURE); | ||||
| 		goto err; | ||||
| 		} | ||||
| 	p = buf; | ||||
| 	if (BIO_read(in, buf, length) != (int)length) | ||||
| 		{ | ||||
| 		PEMerr(PEM_F_DO_B2I_BIO, PEM_R_KEYBLOB_TOO_SHORT); | ||||
| 		goto err; | ||||
| 		} | ||||
|  | ||||
| 	if (isdss) | ||||
| 		ret = b2i_dss(&p, length, bitlen, ispub); | ||||
| 	else | ||||
| 		ret = b2i_rsa(&p, length, bitlen, ispub); | ||||
|  | ||||
| 	err: | ||||
| 	if (buf) | ||||
| 		OPENSSL_free(buf); | ||||
| 	return ret; | ||||
| 	} | ||||
|  | ||||
| static EVP_PKEY *b2i_dss(const unsigned char **in, unsigned int length, | ||||
| 						unsigned int bitlen, int ispub) | ||||
| 	{ | ||||
| 	const unsigned char *p = *in; | ||||
| 	EVP_PKEY *ret = NULL; | ||||
| 	DSA *dsa = NULL; | ||||
| 	BN_CTX *ctx = NULL; | ||||
| 	unsigned int nbyte; | ||||
| 	nbyte = (bitlen + 7) >> 3; | ||||
|  | ||||
| 	dsa = DSA_new(); | ||||
| 	ret = EVP_PKEY_new(); | ||||
| 	if (!dsa || !ret) | ||||
| 		goto memerr; | ||||
| 	if (!read_lebn(&p, nbyte, &dsa->p)) | ||||
| 		goto memerr; | ||||
| 	if (!read_lebn(&p, 20, &dsa->q)) | ||||
| 		goto memerr; | ||||
| 	if (!read_lebn(&p, nbyte, &dsa->g)) | ||||
| 		goto memerr; | ||||
| 	if (ispub) | ||||
| 		{ | ||||
| 		if (!read_lebn(&p, nbyte, &dsa->pub_key)) | ||||
| 			goto memerr; | ||||
| 		} | ||||
| 	else | ||||
| 		{ | ||||
| 		if (!read_lebn(&p, 20, &dsa->priv_key)) | ||||
| 			goto memerr; | ||||
| 		/* Calculate public key */ | ||||
| 		if (!(dsa->pub_key = BN_new())) | ||||
| 			goto memerr; | ||||
| 		if (!(ctx = BN_CTX_new())) | ||||
| 			goto memerr; | ||||
| 			 | ||||
| 		if (!BN_mod_exp(dsa->pub_key, dsa->g, | ||||
| 						 dsa->priv_key, dsa->p, ctx)) | ||||
| 			 | ||||
| 			goto memerr; | ||||
| 		BN_CTX_free(ctx); | ||||
| 		} | ||||
|  | ||||
| 	EVP_PKEY_set1_DSA(ret, dsa); | ||||
| 	DSA_free(dsa); | ||||
| 	*in = p; | ||||
| 	return ret; | ||||
|  | ||||
| 	memerr: | ||||
| 	PEMerr(PEM_F_B2I_DSS, ERR_R_MALLOC_FAILURE); | ||||
| 	if (dsa) | ||||
| 		DSA_free(dsa); | ||||
| 	if (ret) | ||||
| 		EVP_PKEY_free(ret); | ||||
| 	if (ctx) | ||||
| 		BN_CTX_free(ctx); | ||||
| 	return NULL; | ||||
| 	} | ||||
|  | ||||
| static EVP_PKEY *b2i_rsa(const unsigned char **in, unsigned int length, | ||||
| 						unsigned int bitlen, int ispub) | ||||
| 		 | ||||
| 	{ | ||||
| 	const unsigned char *p = *in; | ||||
| 	EVP_PKEY *ret = NULL; | ||||
| 	RSA *rsa = NULL; | ||||
| 	unsigned int nbyte, hnbyte; | ||||
| 	nbyte = (bitlen + 7) >> 3; | ||||
| 	hnbyte = (bitlen + 15) >> 4; | ||||
| 	rsa = RSA_new(); | ||||
| 	ret = EVP_PKEY_new(); | ||||
| 	if (!rsa || !ret) | ||||
| 		goto memerr; | ||||
| 	rsa->e = BN_new(); | ||||
| 	if (!rsa->e) | ||||
| 		goto memerr; | ||||
| 	if (!BN_set_word(rsa->e, read_ledword(&p))) | ||||
| 		goto memerr; | ||||
| 	if (!read_lebn(&p, nbyte, &rsa->n)) | ||||
| 		goto memerr; | ||||
| 	if (!ispub) | ||||
| 		{ | ||||
| 		if (!read_lebn(&p, hnbyte, &rsa->p)) | ||||
| 			goto memerr; | ||||
| 		if (!read_lebn(&p, hnbyte, &rsa->q)) | ||||
| 			goto memerr; | ||||
| 		if (!read_lebn(&p, hnbyte, &rsa->dmp1)) | ||||
| 			goto memerr; | ||||
| 		if (!read_lebn(&p, hnbyte, &rsa->dmq1)) | ||||
| 			goto memerr; | ||||
| 		if (!read_lebn(&p, hnbyte, &rsa->iqmp)) | ||||
| 			goto memerr; | ||||
| 		if (!read_lebn(&p, nbyte, &rsa->d)) | ||||
| 			goto memerr; | ||||
| 		} | ||||
|  | ||||
| 	EVP_PKEY_set1_RSA(ret, rsa); | ||||
| 	RSA_free(rsa); | ||||
| 	*in = p; | ||||
| 	return ret; | ||||
| 	memerr: | ||||
| 	PEMerr(PEM_F_B2I_RSA, ERR_R_MALLOC_FAILURE); | ||||
| 	if (rsa) | ||||
| 		RSA_free(rsa); | ||||
| 	if (ret) | ||||
| 		EVP_PKEY_free(ret); | ||||
| 	return NULL; | ||||
| 	} | ||||
|  | ||||
| EVP_PKEY *b2i_PrivateKey(const unsigned char **in, long length) | ||||
| 	{ | ||||
| 	return do_b2i(in, length, 0); | ||||
| 	} | ||||
|  | ||||
| EVP_PKEY *b2i_PublicKey(const unsigned char **in, long length) | ||||
| 	{ | ||||
| 	return do_b2i(in, length, 1); | ||||
| 	} | ||||
|  | ||||
|  | ||||
| EVP_PKEY *b2i_PrivateKey_bio(BIO *in) | ||||
| 	{ | ||||
| 	return do_b2i_bio(in, 0); | ||||
| 	} | ||||
|  | ||||
| EVP_PKEY *b2i_PublicKey_bio(BIO *in) | ||||
| 	{ | ||||
| 	return do_b2i_bio(in, 1); | ||||
| 	} | ||||
|  | ||||
| static void write_ledword(unsigned char **out, unsigned int dw) | ||||
| 	{ | ||||
| 	unsigned char *p = *out; | ||||
| 	*p++ = dw & 0xff; | ||||
| 	*p++ = (dw>>8) & 0xff; | ||||
| 	*p++ = (dw>>16) & 0xff; | ||||
| 	*p++ = (dw>>24) & 0xff; | ||||
| 	*out = p; | ||||
| 	} | ||||
|  | ||||
| static void write_lebn(unsigned char **out, const BIGNUM *bn, int len) | ||||
| 	{ | ||||
| 	int nb, i; | ||||
| 	unsigned char *p = *out, *q, c; | ||||
| 	nb = BN_num_bytes(bn); | ||||
| 	BN_bn2bin(bn, p); | ||||
| 	q = p + nb - 1; | ||||
| 	/* In place byte order reversal */ | ||||
| 	for (i = 0; i < nb/2; i++) | ||||
| 		{ | ||||
| 		c = *p; | ||||
| 		*p++ = *q; | ||||
| 		*q-- = c; | ||||
| 		} | ||||
| 	*out += nb; | ||||
| 	/* Pad with zeroes if we have to */ | ||||
| 	if (len > 0) | ||||
| 		{ | ||||
| 		len -= nb; | ||||
| 		if (len > 0) | ||||
| 			{ | ||||
| 			memset(*out, 0, len); | ||||
| 			*out += len; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|  | ||||
| static int check_bitlen_rsa(RSA *rsa, int ispub, unsigned int *magic); | ||||
| static int check_bitlen_dsa(DSA *dsa, int ispub, unsigned int *magic); | ||||
|  | ||||
| static void write_rsa(unsigned char **out, RSA *rsa, int ispub); | ||||
| static void write_dsa(unsigned char **out, DSA *dsa, int ispub); | ||||
| 	 | ||||
| static int do_i2b(unsigned char **out, EVP_PKEY *pk, int ispub) | ||||
| 	{ | ||||
| 	unsigned char *p; | ||||
| 	unsigned int bitlen, magic, keyalg; | ||||
| 	int outlen, noinc = 0; | ||||
| 	if (pk->type == EVP_PKEY_DSA) | ||||
| 		{ | ||||
| 		bitlen = check_bitlen_dsa(pk->pkey.dsa, ispub, &magic); | ||||
| 		keyalg = MS_KEYALG_DSS_SIGN; | ||||
| 		} | ||||
| 	else if (pk->type == EVP_PKEY_RSA) | ||||
| 		{ | ||||
| 		bitlen = check_bitlen_rsa(pk->pkey.rsa, ispub, &magic); | ||||
| 		keyalg = MS_KEYALG_RSA_KEYX; | ||||
| 		} | ||||
| 	else | ||||
| 		return -1; | ||||
| 	if (bitlen == 0) | ||||
| 		return -1; | ||||
| 	outlen = 16 + blob_length(bitlen, | ||||
| 			keyalg == MS_KEYALG_DSS_SIGN ? 1 : 0, ispub); | ||||
| 	if (out == NULL) | ||||
| 		return outlen; | ||||
| 	if (*out) | ||||
| 		p = *out; | ||||
| 	else | ||||
| 		{ | ||||
| 		p = OPENSSL_malloc(outlen); | ||||
| 		if (!p) | ||||
| 			return -1; | ||||
| 		*out = p; | ||||
| 		noinc = 1; | ||||
| 		} | ||||
| 	if (ispub) | ||||
| 		*p++ = MS_PUBLICKEYBLOB; | ||||
| 	else | ||||
| 		*p++ = MS_PRIVATEKEYBLOB; | ||||
| 	*p++ = 0x2; | ||||
| 	*p++ = 0; | ||||
| 	*p++ = 0; | ||||
| 	write_ledword(&p, keyalg); | ||||
| 	write_ledword(&p, magic); | ||||
| 	write_ledword(&p, bitlen); | ||||
| 	if (keyalg == MS_KEYALG_DSS_SIGN) | ||||
| 		write_dsa(&p, pk->pkey.dsa, ispub); | ||||
| 	else | ||||
| 		write_rsa(&p, pk->pkey.rsa, ispub); | ||||
| 	if (!noinc) | ||||
| 		*out += outlen; | ||||
| 	return outlen; | ||||
| 	} | ||||
|  | ||||
| static int do_i2b_bio(BIO *out, EVP_PKEY *pk, int ispub) | ||||
| 	{ | ||||
| 	unsigned char *tmp = NULL; | ||||
| 	int outlen, wrlen; | ||||
| 	outlen = do_i2b(&tmp, pk, ispub); | ||||
| 	if (outlen < 0) | ||||
| 		return -1; | ||||
| 	wrlen = BIO_write(out, tmp, outlen); | ||||
| 	OPENSSL_free(tmp); | ||||
| 	if (wrlen == outlen) | ||||
| 		return outlen; | ||||
| 	return -1; | ||||
| 	} | ||||
|  | ||||
| static int check_bitlen_dsa(DSA *dsa, int ispub, unsigned int *pmagic) | ||||
| 	{ | ||||
| 	int bitlen; | ||||
| 	bitlen = BN_num_bits(dsa->p); | ||||
| 	if ((bitlen & 7) || (BN_num_bits(dsa->q) != 160) | ||||
| 		|| (BN_num_bits(dsa->g) > bitlen)) | ||||
| 		goto badkey; | ||||
| 	if (ispub) | ||||
| 		{ | ||||
| 		if (BN_num_bits(dsa->pub_key) > bitlen) | ||||
| 			goto badkey; | ||||
| 		*pmagic = MS_DSS1MAGIC; | ||||
| 		} | ||||
| 	else | ||||
| 		{ | ||||
| 		if (BN_num_bits(dsa->priv_key) > 160) | ||||
| 			goto badkey; | ||||
| 		*pmagic = MS_DSS2MAGIC; | ||||
| 		} | ||||
| 	 | ||||
| 	return bitlen; | ||||
| 	badkey: | ||||
| 	PEMerr(PEM_F_CHECK_BITLEN_DSA, PEM_R_UNSUPPORTED_KEY_COMPONENTS); | ||||
| 	return 0; | ||||
| 	} | ||||
|  | ||||
| static int check_bitlen_rsa(RSA *rsa, int ispub, unsigned int *pmagic) | ||||
| 	{ | ||||
| 	int nbyte, hnbyte, bitlen; | ||||
| 	if (BN_num_bits(rsa->e) > 32) | ||||
| 		goto badkey; | ||||
| 	bitlen = BN_num_bits(rsa->n); | ||||
| 	nbyte = BN_num_bytes(rsa->n); | ||||
| 	hnbyte = (BN_num_bits(rsa->n) + 15) >> 4; | ||||
| 	if (ispub) | ||||
| 		{ | ||||
| 		*pmagic = MS_RSA1MAGIC; | ||||
| 		return bitlen; | ||||
| 		} | ||||
| 	else | ||||
| 	{ | ||||
| 		*pmagic = MS_RSA2MAGIC; | ||||
| 		/* For private key each component must fit within nbyte or | ||||
| 		 * hnbyte. | ||||
| 		 */ | ||||
| 		if (BN_num_bytes(rsa->d) > nbyte) | ||||
| 			goto badkey; | ||||
| 		if ((BN_num_bytes(rsa->iqmp) > hnbyte) | ||||
| 			|| (BN_num_bytes(rsa->p) > hnbyte) | ||||
| 			|| (BN_num_bytes(rsa->q) > hnbyte) | ||||
| 			|| (BN_num_bytes(rsa->dmp1) > hnbyte) | ||||
| 			|| (BN_num_bytes(rsa->dmq1) > hnbyte)) | ||||
| 			goto badkey; | ||||
| 	} | ||||
| 	return bitlen; | ||||
| 	badkey: | ||||
| 	PEMerr(PEM_F_CHECK_BITLEN_RSA, PEM_R_UNSUPPORTED_KEY_COMPONENTS); | ||||
| 	return 0; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| static void write_rsa(unsigned char **out, RSA *rsa, int ispub) | ||||
| 	{ | ||||
| 	int nbyte, hnbyte; | ||||
| 	nbyte = BN_num_bytes(rsa->n); | ||||
| 	hnbyte = (BN_num_bits(rsa->n) + 15) >> 4; | ||||
| 	write_lebn(out, rsa->e, 4); | ||||
| 	write_lebn(out, rsa->n, -1); | ||||
| 	if (ispub) | ||||
| 		return; | ||||
| 	write_lebn(out, rsa->p, hnbyte); | ||||
| 	write_lebn(out, rsa->q, hnbyte); | ||||
| 	write_lebn(out, rsa->dmp1, hnbyte); | ||||
| 	write_lebn(out, rsa->dmq1, hnbyte); | ||||
| 	write_lebn(out, rsa->iqmp, hnbyte); | ||||
| 	write_lebn(out, rsa->d, nbyte); | ||||
| 	} | ||||
|  | ||||
| 	 | ||||
| static void write_dsa(unsigned char **out, DSA *dsa, int ispub) | ||||
| 	{ | ||||
| 	int nbyte; | ||||
| 	nbyte = BN_num_bytes(dsa->p); | ||||
| 	write_lebn(out, dsa->p, nbyte); | ||||
| 	write_lebn(out, dsa->q, 20); | ||||
| 	write_lebn(out, dsa->g, nbyte); | ||||
| 	if (ispub) | ||||
| 		write_lebn(out, dsa->pub_key, nbyte); | ||||
| 	else | ||||
| 		write_lebn(out, dsa->priv_key, 20); | ||||
| 	/* Set "invalid" for seed structure values */ | ||||
| 	memset(*out, 0xff, 24); | ||||
| 	*out += 24; | ||||
| 	return; | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| int i2b_PrivateKey_bio(BIO *out, EVP_PKEY *pk) | ||||
| 	{ | ||||
| 	return do_i2b_bio(out, pk, 0); | ||||
| 	} | ||||
|  | ||||
| int i2b_PublicKey_bio(BIO *out, EVP_PKEY *pk) | ||||
| 	{ | ||||
| 	return do_i2b_bio(out, pk, 1); | ||||
| 	} | ||||
|  | ||||
| static int do_PVK_header(const unsigned char **in, unsigned int length, | ||||
| 		int skip_magic, | ||||
| 	       	unsigned int *psaltlen, unsigned int *pkeylen) | ||||
| 		 | ||||
| 	{ | ||||
| 	const unsigned char *p = *in; | ||||
| 	unsigned int pvk_magic, keytype, is_encrypted; | ||||
| 	if (skip_magic) | ||||
| 		{ | ||||
| 		if (length < 20) | ||||
| 			{ | ||||
| 			PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT); | ||||
| 			return 0; | ||||
| 			} | ||||
| 		length -= 20; | ||||
| 		} | ||||
| 	else | ||||
| 		{ | ||||
| 		if (length < 24) | ||||
| 			{ | ||||
| 			PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_PVK_TOO_SHORT); | ||||
| 			return 0; | ||||
| 			} | ||||
| 		length -= 24; | ||||
| 		pvk_magic = read_ledword(&p); | ||||
| 		if (pvk_magic != MS_PVKMAGIC) | ||||
| 			{ | ||||
| 			PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_BAD_MAGIC_NUMBER); | ||||
| 			return 0; | ||||
| 			} | ||||
| 		} | ||||
| 	/* Skip reserved */ | ||||
| 	p += 4; | ||||
| 	keytype = read_ledword(&p); | ||||
| 	is_encrypted = read_ledword(&p); | ||||
| 	*psaltlen = read_ledword(&p); | ||||
| 	*pkeylen = read_ledword(&p); | ||||
|  | ||||
| 	if (is_encrypted && !*psaltlen) | ||||
| 		{ | ||||
| 		PEMerr(PEM_F_DO_PVK_HEADER, PEM_R_INCONSISTENT_HEADER); | ||||
| 		return 0; | ||||
| 		} | ||||
|  | ||||
| 	*in = p; | ||||
| 	return 1; | ||||
| 	} | ||||
|  | ||||
| static int derive_pvk_key(unsigned char *key,  | ||||
| 			const unsigned char *salt, unsigned int saltlen, | ||||
| 			const unsigned char *pass, int passlen) | ||||
| 	{ | ||||
| 	EVP_MD_CTX mctx; | ||||
| 	EVP_MD_CTX_init(&mctx); | ||||
| 	EVP_DigestInit_ex(&mctx, EVP_sha1(), NULL); | ||||
| 	EVP_DigestUpdate(&mctx, salt, saltlen); | ||||
| 	EVP_DigestUpdate(&mctx, pass, passlen); | ||||
| 	EVP_DigestFinal_ex(&mctx, key, NULL); | ||||
| 	EVP_MD_CTX_cleanup(&mctx); | ||||
| 	return 1; | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| static EVP_PKEY *do_PVK_body(const unsigned char **in, | ||||
| 		unsigned int saltlen, unsigned int keylen, | ||||
| 		pem_password_cb *cb, void *u) | ||||
| 	{ | ||||
| 	EVP_PKEY *ret = NULL; | ||||
| 	const unsigned char *p = *in; | ||||
| 	unsigned int magic; | ||||
| 	unsigned char *enctmp = NULL, *q; | ||||
| 	if (saltlen) | ||||
| 		{ | ||||
| 		char psbuf[PEM_BUFSIZE]; | ||||
| 		unsigned char keybuf[20]; | ||||
| 		EVP_CIPHER_CTX cctx; | ||||
| 		int enctmplen, inlen; | ||||
| 		if (cb) | ||||
| 			inlen=cb(psbuf,PEM_BUFSIZE,0,u); | ||||
| 		else | ||||
| 			inlen=PEM_def_callback(psbuf,PEM_BUFSIZE,0,u); | ||||
| 		if (inlen <= 0) | ||||
| 			{ | ||||
| 			PEMerr(PEM_F_DO_PVK_BODY,PEM_R_BAD_PASSWORD_READ); | ||||
| 			return NULL; | ||||
| 			} | ||||
| 		enctmp = OPENSSL_malloc(keylen + 8); | ||||
| 		if (!enctmp) | ||||
| 			{ | ||||
| 			PEMerr(PEM_F_DO_PVK_BODY, ERR_R_MALLOC_FAILURE); | ||||
| 			return NULL; | ||||
| 			} | ||||
| 		if (!derive_pvk_key(keybuf, p, saltlen, psbuf, inlen)) | ||||
| 			return NULL; | ||||
| 		p += saltlen; | ||||
| 		/* Copy BLOBHEADER across, decrypt rest */ | ||||
| 		memcpy(enctmp, p, 8); | ||||
| 		p += 8; | ||||
| 		inlen = keylen - 8; | ||||
| 		q = enctmp + 8; | ||||
| 		EVP_CIPHER_CTX_init(&cctx); | ||||
| 		EVP_DecryptInit_ex(&cctx, EVP_rc4(), NULL, keybuf, NULL); | ||||
| 		EVP_DecryptUpdate(&cctx, q, &enctmplen, p, inlen); | ||||
| 		EVP_DecryptFinal_ex(&cctx, q + enctmplen, &enctmplen); | ||||
| 		magic = read_ledword((const unsigned char **)&q); | ||||
| 		if (magic != MS_RSA2MAGIC && magic != MS_DSS2MAGIC) | ||||
| 			{ | ||||
| 			q = enctmp + 8; | ||||
| 			memset(keybuf + 5, 0, 11); | ||||
| 			EVP_DecryptInit_ex(&cctx, EVP_rc4(), NULL, keybuf, | ||||
| 								NULL); | ||||
| 			OPENSSL_cleanse(keybuf, 20); | ||||
| 			EVP_DecryptUpdate(&cctx, q, &enctmplen, p, inlen); | ||||
| 			EVP_DecryptFinal_ex(&cctx, q + enctmplen, | ||||
| 								&enctmplen); | ||||
| 			magic = read_ledword((const unsigned char **)&q); | ||||
| 			if (magic != MS_RSA2MAGIC && magic != MS_DSS2MAGIC) | ||||
| 				{ | ||||
| 				EVP_CIPHER_CTX_cleanup(&cctx); | ||||
| 				PEMerr(PEM_F_DO_PVK_BODY, PEM_R_BAD_DECRYPT); | ||||
| 				goto err; | ||||
| 				} | ||||
| 			} | ||||
| 		else | ||||
| 			OPENSSL_cleanse(keybuf, 20); | ||||
| 		EVP_CIPHER_CTX_cleanup(&cctx); | ||||
| 		p = enctmp; | ||||
| 		} | ||||
|  | ||||
| 	ret = b2i_PrivateKey(&p, keylen); | ||||
| 	err: | ||||
| 	if (enctmp && saltlen) | ||||
| 		OPENSSL_free(enctmp); | ||||
| 	return ret; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| EVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u) | ||||
| 	{ | ||||
| 	unsigned char pvk_hdr[24], *buf = NULL; | ||||
| 	const unsigned char *p; | ||||
| 	int buflen; | ||||
| 	EVP_PKEY *ret = NULL; | ||||
| 	unsigned int saltlen, keylen; | ||||
| 	if (BIO_read(in, pvk_hdr, 24) != 24) | ||||
| 		{ | ||||
| 		PEMerr(PEM_F_B2I_PVK_BIO, PEM_R_PVK_DATA_TOO_SHORT); | ||||
| 		return NULL; | ||||
| 		} | ||||
| 	p = pvk_hdr; | ||||
|  | ||||
| 	if (!do_PVK_header(&p, 24, 0, &saltlen, &keylen)) | ||||
| 		return 0; | ||||
| 	buflen = (int) keylen + saltlen; | ||||
| 	buf = OPENSSL_malloc(buflen); | ||||
| 	if (!buf) | ||||
| 		{ | ||||
| 		PEMerr(PEM_F_B2I_PVK_BIO, ERR_R_MALLOC_FAILURE); | ||||
| 		return 0; | ||||
| 		} | ||||
| 	p = buf; | ||||
| 	if (BIO_read(in, buf, buflen) != buflen) | ||||
| 		{ | ||||
| 		PEMerr(PEM_F_B2I_PVK_BIO, PEM_R_PVK_DATA_TOO_SHORT); | ||||
| 		goto err; | ||||
| 		} | ||||
| 	ret = do_PVK_body(&p, saltlen, keylen, cb, u); | ||||
|  | ||||
| 	err: | ||||
| 	if (buf) | ||||
| 		{ | ||||
| 		OPENSSL_cleanse(buf, buflen); | ||||
| 		OPENSSL_free(buf); | ||||
| 		} | ||||
| 	return ret; | ||||
| 	} | ||||
|  | ||||
| 	 | ||||
| 	 | ||||
| static int i2b_PVK(unsigned char **out, EVP_PKEY*pk, int enclevel, | ||||
| 		pem_password_cb *cb, void *u) | ||||
| 	{ | ||||
| 	int outlen = 24, noinc, pklen; | ||||
| 	unsigned char *p, *salt = NULL; | ||||
| 	if (enclevel) | ||||
| 		outlen += PVK_SALTLEN; | ||||
| 	pklen = do_i2b(NULL, pk, 0); | ||||
| 	if (pklen < 0) | ||||
| 		return -1; | ||||
| 	outlen += pklen; | ||||
| 	if (!out) | ||||
| 		return outlen; | ||||
| 	if (*out) | ||||
| 		{ | ||||
| 		p = *out; | ||||
| 		noinc = 0; | ||||
| 		} | ||||
| 	else | ||||
| 		{ | ||||
| 		p = OPENSSL_malloc(outlen); | ||||
| 		if (!p) | ||||
| 			{ | ||||
| 			PEMerr(PEM_F_I2B_PVK,ERR_R_MALLOC_FAILURE); | ||||
| 			return -1; | ||||
| 			} | ||||
| 		*out = p; | ||||
| 		noinc = 1; | ||||
| 		} | ||||
|  | ||||
| 	write_ledword(&p, MS_PVKMAGIC); | ||||
| 	write_ledword(&p, 0); | ||||
| 	if (pk->type == EVP_PKEY_DSA) | ||||
| 		write_ledword(&p, MS_KEYTYPE_SIGN); | ||||
| 	else | ||||
| 		write_ledword(&p, MS_KEYTYPE_KEYX); | ||||
| 	write_ledword(&p, enclevel ? 1 : 0); | ||||
| 	write_ledword(&p, enclevel ? PVK_SALTLEN: 0); | ||||
| 	write_ledword(&p, pklen); | ||||
| 	if (enclevel) | ||||
| 		{ | ||||
| 		if (RAND_bytes(p, PVK_SALTLEN) <= 0) | ||||
| 			goto error; | ||||
| 		salt = p; | ||||
| 		p += PVK_SALTLEN; | ||||
| 		} | ||||
| 	do_i2b(&p, pk, 0); | ||||
| 	if (enclevel == 0) | ||||
| 		return outlen; | ||||
| 	else | ||||
| 		{ | ||||
| 		char psbuf[PEM_BUFSIZE]; | ||||
| 		unsigned char keybuf[20]; | ||||
| 		EVP_CIPHER_CTX cctx; | ||||
| 		int enctmplen, inlen; | ||||
| 		if (cb) | ||||
| 			inlen=cb(psbuf,PEM_BUFSIZE,1,u); | ||||
| 		else | ||||
| 			inlen=PEM_def_callback(psbuf,PEM_BUFSIZE,1,u); | ||||
| 		if (inlen <= 0) | ||||
| 			{ | ||||
| 			PEMerr(PEM_F_I2B_PVK,PEM_R_BAD_PASSWORD_READ); | ||||
| 			goto error; | ||||
| 			} | ||||
| 		if (!derive_pvk_key(keybuf, salt, PVK_SALTLEN, psbuf, inlen)) | ||||
| 			goto error; | ||||
| 		if (enclevel == 1) | ||||
| 			memset(keybuf + 5, 0, 11); | ||||
| 		p = salt + PVK_SALTLEN + 8; | ||||
| 		EVP_CIPHER_CTX_init(&cctx); | ||||
| 		EVP_EncryptInit_ex(&cctx, EVP_rc4(), NULL, keybuf, NULL); | ||||
| 		OPENSSL_cleanse(keybuf, 20); | ||||
| 		EVP_DecryptUpdate(&cctx, p, &enctmplen, p, pklen - 8); | ||||
| 		EVP_DecryptFinal_ex(&cctx, p + enctmplen, &enctmplen); | ||||
| 		EVP_CIPHER_CTX_cleanup(&cctx); | ||||
| 		} | ||||
| 	return outlen; | ||||
|  | ||||
| 	error: | ||||
| 	return -1; | ||||
| 	} | ||||
|  | ||||
| int i2b_PVK_bio(BIO *out, EVP_PKEY *pk, int enclevel, | ||||
| 		pem_password_cb *cb, void *u) | ||||
| 	{ | ||||
| 	unsigned char *tmp = NULL; | ||||
| 	int outlen, wrlen; | ||||
| 	outlen = i2b_PVK(&tmp, pk, enclevel, cb, u); | ||||
| 	if (outlen < 0) | ||||
| 		return -1; | ||||
| 	wrlen = BIO_write(out, tmp, outlen); | ||||
| 	OPENSSL_free(tmp); | ||||
| 	if (wrlen == outlen) | ||||
| 		{ | ||||
| 		PEMerr(PEM_F_I2B_PVK_BIO, PEM_R_BIO_WRITE_FAILURE); | ||||
| 		return outlen; | ||||
| 		} | ||||
| 	return -1; | ||||
| 	} | ||||
		Reference in New Issue
	
	Block a user
	 Dr. Stephen Henson
					Dr. Stephen Henson