xref: /openbsd-src/lib/libcrypto/pem/pvkfmt.c (revision 76d5ca186bb8e52848aa4678170e8c331129c0d5)
1*76d5ca18Stb /* $OpenBSD: pvkfmt.c,v 1.28 2024/02/18 15:45:42 tb Exp $ */
2f1535dc8Sdjm /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL
3f1535dc8Sdjm  * project 2005.
4f1535dc8Sdjm  */
5f1535dc8Sdjm /* ====================================================================
6f1535dc8Sdjm  * Copyright (c) 2005 The OpenSSL Project.  All rights reserved.
7f1535dc8Sdjm  *
8f1535dc8Sdjm  * Redistribution and use in source and binary forms, with or without
9f1535dc8Sdjm  * modification, are permitted provided that the following conditions
10f1535dc8Sdjm  * are met:
11f1535dc8Sdjm  *
12f1535dc8Sdjm  * 1. Redistributions of source code must retain the above copyright
13f1535dc8Sdjm  *    notice, this list of conditions and the following disclaimer.
14f1535dc8Sdjm  *
15f1535dc8Sdjm  * 2. Redistributions in binary form must reproduce the above copyright
16f1535dc8Sdjm  *    notice, this list of conditions and the following disclaimer in
17f1535dc8Sdjm  *    the documentation and/or other materials provided with the
18f1535dc8Sdjm  *    distribution.
19f1535dc8Sdjm  *
20f1535dc8Sdjm  * 3. All advertising materials mentioning features or use of this
21f1535dc8Sdjm  *    software must display the following acknowledgment:
22f1535dc8Sdjm  *    "This product includes software developed by the OpenSSL Project
23f1535dc8Sdjm  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24f1535dc8Sdjm  *
25f1535dc8Sdjm  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26f1535dc8Sdjm  *    endorse or promote products derived from this software without
27f1535dc8Sdjm  *    prior written permission. For written permission, please contact
28f1535dc8Sdjm  *    licensing@OpenSSL.org.
29f1535dc8Sdjm  *
30f1535dc8Sdjm  * 5. Products derived from this software may not be called "OpenSSL"
31f1535dc8Sdjm  *    nor may "OpenSSL" appear in their names without prior written
32f1535dc8Sdjm  *    permission of the OpenSSL Project.
33f1535dc8Sdjm  *
34f1535dc8Sdjm  * 6. Redistributions of any form whatsoever must retain the following
35f1535dc8Sdjm  *    acknowledgment:
36f1535dc8Sdjm  *    "This product includes software developed by the OpenSSL Project
37f1535dc8Sdjm  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38f1535dc8Sdjm  *
39f1535dc8Sdjm  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40f1535dc8Sdjm  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41f1535dc8Sdjm  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42f1535dc8Sdjm  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43f1535dc8Sdjm  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44f1535dc8Sdjm  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45f1535dc8Sdjm  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46f1535dc8Sdjm  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47f1535dc8Sdjm  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48f1535dc8Sdjm  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49f1535dc8Sdjm  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50f1535dc8Sdjm  * OF THE POSSIBILITY OF SUCH DAMAGE.
51f1535dc8Sdjm  * ====================================================================
52f1535dc8Sdjm  *
53f1535dc8Sdjm  * This product includes cryptographic software written by Eric Young
54f1535dc8Sdjm  * (eay@cryptsoft.com).  This product includes software written by Tim
55f1535dc8Sdjm  * Hudson (tjh@cryptsoft.com).
56f1535dc8Sdjm  *
57f1535dc8Sdjm  */
58f1535dc8Sdjm 
59f1535dc8Sdjm /* Support for PVK format keys and related structures (such a PUBLICKEYBLOB
60f1535dc8Sdjm  * and PRIVATEKEYBLOB).
61f1535dc8Sdjm  */
62f1535dc8Sdjm 
63ef624301Sjsing #include <stdlib.h>
64a8913c44Sjsing #include <string.h>
65a8913c44Sjsing 
668cf4d6a6Sjsing #include <openssl/opensslconf.h>
678cf4d6a6Sjsing 
68b6ab114eSjsing #include <openssl/bn.h>
69b6ab114eSjsing #include <openssl/err.h>
70f1535dc8Sdjm #include <openssl/pem.h>
71b6ab114eSjsing 
72f1535dc8Sdjm #if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DSA)
73f1535dc8Sdjm #include <openssl/dsa.h>
74f1535dc8Sdjm #include <openssl/rsa.h>
75f1535dc8Sdjm 
76c9675a23Stb #include "bn_local.h"
77c9675a23Stb #include "dsa_local.h"
78c9675a23Stb #include "evp_local.h"
79c9675a23Stb #include "rsa_local.h"
803a88f7afSbeck 
81f1535dc8Sdjm /* Utility function: read a DWORD (4 byte unsigned integer) in little endian
82f1535dc8Sdjm  * format
83f1535dc8Sdjm  */
84f1535dc8Sdjm 
85a8b5ceceSjsing static unsigned int
read_ledword(const unsigned char ** in)86a8b5ceceSjsing read_ledword(const unsigned char **in)
87f1535dc8Sdjm {
88f1535dc8Sdjm 	const unsigned char *p = *in;
89f1535dc8Sdjm 	unsigned int ret;
90a8b5ceceSjsing 
91f1535dc8Sdjm 	ret = *p++;
92f1535dc8Sdjm 	ret |= (*p++ << 8);
93f1535dc8Sdjm 	ret |= (*p++ << 16);
94f1535dc8Sdjm 	ret |= (*p++ << 24);
95f1535dc8Sdjm 	*in = p;
96f1535dc8Sdjm 	return ret;
97f1535dc8Sdjm }
98f1535dc8Sdjm 
99f1535dc8Sdjm /* Read a BIGNUM in little endian format. The docs say that this should take up
100f1535dc8Sdjm  * bitlen/8 bytes.
101f1535dc8Sdjm  */
102f1535dc8Sdjm 
103a8b5ceceSjsing static int
read_lebn(const unsigned char ** in,unsigned int nbyte,BIGNUM ** r)104a8b5ceceSjsing read_lebn(const unsigned char **in, unsigned int nbyte, BIGNUM **r)
105f1535dc8Sdjm {
106f1535dc8Sdjm 	const unsigned char *p;
107f1535dc8Sdjm 	unsigned char *tmpbuf, *q;
108f1535dc8Sdjm 	unsigned int i;
109a8b5ceceSjsing 
110f1535dc8Sdjm 	p = *in + nbyte - 1;
1116f3a6cb1Sbeck 	tmpbuf = malloc(nbyte);
112f1535dc8Sdjm 	if (!tmpbuf)
113f1535dc8Sdjm 		return 0;
114f1535dc8Sdjm 	q = tmpbuf;
115f1535dc8Sdjm 	for (i = 0; i < nbyte; i++)
116f1535dc8Sdjm 		*q++ = *p--;
117f1535dc8Sdjm 	*r = BN_bin2bn(tmpbuf, nbyte, NULL);
1186f3a6cb1Sbeck 	free(tmpbuf);
119a8b5ceceSjsing 	if (*r) {
120f1535dc8Sdjm 		*in += nbyte;
121f1535dc8Sdjm 		return 1;
122a8b5ceceSjsing 	} else
123f1535dc8Sdjm 		return 0;
124f1535dc8Sdjm }
125f1535dc8Sdjm 
126f1535dc8Sdjm 
127f1535dc8Sdjm /* Convert private key blob to EVP_PKEY: RSA and DSA keys supported */
128f1535dc8Sdjm 
129f1535dc8Sdjm #define MS_PUBLICKEYBLOB	0x6
130f1535dc8Sdjm #define MS_PRIVATEKEYBLOB	0x7
131f1535dc8Sdjm #define MS_RSA1MAGIC		0x31415352L
132f1535dc8Sdjm #define MS_RSA2MAGIC		0x32415352L
133f1535dc8Sdjm #define MS_DSS1MAGIC		0x31535344L
134f1535dc8Sdjm #define MS_DSS2MAGIC		0x32535344L
135f1535dc8Sdjm 
136f1535dc8Sdjm #define MS_KEYALG_RSA_KEYX	0xa400
137f1535dc8Sdjm #define MS_KEYALG_DSS_SIGN	0x2200
138f1535dc8Sdjm 
139f1535dc8Sdjm #define MS_KEYTYPE_KEYX		0x1
140f1535dc8Sdjm #define MS_KEYTYPE_SIGN		0x2
141f1535dc8Sdjm 
142f1535dc8Sdjm /* The PVK file magic number: seems to spell out "bobsfile", who is Bob? */
143f1535dc8Sdjm #define MS_PVKMAGIC		0xb0b5f11eL
144f1535dc8Sdjm /* Salt length for PVK files */
145f1535dc8Sdjm #define PVK_SALTLEN		0x10
146f1535dc8Sdjm 
147f1535dc8Sdjm static EVP_PKEY *b2i_rsa(const unsigned char **in, unsigned int length,
148f1535dc8Sdjm     unsigned int bitlen, int ispub);
149f1535dc8Sdjm static EVP_PKEY *b2i_dss(const unsigned char **in, unsigned int length,
150f1535dc8Sdjm     unsigned int bitlen, int ispub);
151f1535dc8Sdjm 
152a8b5ceceSjsing static int
do_blob_header(const unsigned char ** in,unsigned int length,unsigned int * pmagic,unsigned int * pbitlen,int * pisdss,int * pispub)153a8b5ceceSjsing do_blob_header(const unsigned char **in, unsigned int length,
154a8b5ceceSjsing     unsigned int *pmagic, unsigned int *pbitlen, int *pisdss, int *pispub)
155f1535dc8Sdjm {
156f1535dc8Sdjm 	const unsigned char *p = *in;
157a8b5ceceSjsing 
158f1535dc8Sdjm 	if (length < 16)
159f1535dc8Sdjm 		return 0;
160f1535dc8Sdjm 	/* bType */
161a8b5ceceSjsing 	if (*p == MS_PUBLICKEYBLOB) {
162a8b5ceceSjsing 		if (*pispub == 0) {
1635067ae9fSbeck 			PEMerror(PEM_R_EXPECTING_PRIVATE_KEY_BLOB);
164f1535dc8Sdjm 			return 0;
165f1535dc8Sdjm 		}
166f1535dc8Sdjm 		*pispub = 1;
167a8b5ceceSjsing 	} else if (*p == MS_PRIVATEKEYBLOB) {
168a8b5ceceSjsing 		if (*pispub == 1) {
1695067ae9fSbeck 			PEMerror(PEM_R_EXPECTING_PUBLIC_KEY_BLOB);
170f1535dc8Sdjm 			return 0;
171f1535dc8Sdjm 		}
172f1535dc8Sdjm 		*pispub = 0;
173a8b5ceceSjsing 	} else
174f1535dc8Sdjm 		return 0;
175f1535dc8Sdjm 	p++;
176f1535dc8Sdjm 	/* Version */
177a8b5ceceSjsing 	if (*p++ != 0x2) {
1785067ae9fSbeck 		PEMerror(PEM_R_BAD_VERSION_NUMBER);
179f1535dc8Sdjm 		return 0;
180f1535dc8Sdjm 	}
181f1535dc8Sdjm 	/* Ignore reserved, aiKeyAlg */
182f1535dc8Sdjm 	p += 6;
183f1535dc8Sdjm 	*pmagic = read_ledword(&p);
184f1535dc8Sdjm 	*pbitlen = read_ledword(&p);
185cc6e7aeeSbeck 	if (*pbitlen > 65536) {
1865067ae9fSbeck 		PEMerror(PEM_R_INCONSISTENT_HEADER);
187cc6e7aeeSbeck 		return 0;
188cc6e7aeeSbeck 	}
189f1535dc8Sdjm 	*pisdss = 0;
190a8b5ceceSjsing 	switch (*pmagic) {
191f1535dc8Sdjm 
192f1535dc8Sdjm 	case MS_DSS1MAGIC:
193f1535dc8Sdjm 		*pisdss = 1;
194f1535dc8Sdjm 	case MS_RSA1MAGIC:
195a8b5ceceSjsing 		if (*pispub == 0) {
1965067ae9fSbeck 			PEMerror(PEM_R_EXPECTING_PRIVATE_KEY_BLOB);
197f1535dc8Sdjm 			return 0;
198f1535dc8Sdjm 		}
199f1535dc8Sdjm 		break;
200f1535dc8Sdjm 
201f1535dc8Sdjm 	case MS_DSS2MAGIC:
202f1535dc8Sdjm 		*pisdss = 1;
203f1535dc8Sdjm 	case MS_RSA2MAGIC:
204a8b5ceceSjsing 		if (*pispub == 1) {
2055067ae9fSbeck 			PEMerror(PEM_R_EXPECTING_PUBLIC_KEY_BLOB);
206f1535dc8Sdjm 			return 0;
207f1535dc8Sdjm 		}
208f1535dc8Sdjm 		break;
209f1535dc8Sdjm 
210f1535dc8Sdjm 	default:
2115067ae9fSbeck 		PEMerror(PEM_R_BAD_MAGIC_NUMBER);
212f1535dc8Sdjm 		return -1;
213f1535dc8Sdjm 	}
214f1535dc8Sdjm 	*in = p;
215f1535dc8Sdjm 	return 1;
216f1535dc8Sdjm }
217f1535dc8Sdjm 
218a8b5ceceSjsing static unsigned int
blob_length(unsigned bitlen,int isdss,int ispub)219a8b5ceceSjsing blob_length(unsigned bitlen, int isdss, int ispub)
220f1535dc8Sdjm {
221f1535dc8Sdjm 	unsigned int nbyte, hnbyte;
222a8b5ceceSjsing 
223f1535dc8Sdjm 	nbyte = (bitlen + 7) >> 3;
224f1535dc8Sdjm 	hnbyte = (bitlen + 15) >> 4;
225a8b5ceceSjsing 	if (isdss) {
226f1535dc8Sdjm 
227f1535dc8Sdjm 		/* Expected length: 20 for q + 3 components bitlen each + 24
228f1535dc8Sdjm 		 * for seed structure.
229f1535dc8Sdjm 		 */
230f1535dc8Sdjm 		if (ispub)
231f1535dc8Sdjm 			return 44 + 3 * nbyte;
232f1535dc8Sdjm 		/* Expected length: 20 for q, priv, 2 bitlen components + 24
233f1535dc8Sdjm 		 * for seed structure.
234f1535dc8Sdjm 		 */
235f1535dc8Sdjm 		else
236f1535dc8Sdjm 			return 64 + 2 * nbyte;
237a8b5ceceSjsing 	} else {
238f1535dc8Sdjm 		/* Expected length: 4 for 'e' + 'n' */
239f1535dc8Sdjm 		if (ispub)
240f1535dc8Sdjm 			return 4 + nbyte;
241f1535dc8Sdjm 		else
242f1535dc8Sdjm 		/* Expected length: 4 for 'e' and 7 other components.
243f1535dc8Sdjm 		 * 2 components are bitlen size, 5 are bitlen/2
244f1535dc8Sdjm 		 */
245f1535dc8Sdjm 				return 4 + 2*nbyte + 5*hnbyte;
246f1535dc8Sdjm 	}
247f1535dc8Sdjm 
248f1535dc8Sdjm }
249f1535dc8Sdjm 
250a8b5ceceSjsing static EVP_PKEY *
do_b2i(const unsigned char ** in,unsigned int length,int ispub)251a8b5ceceSjsing do_b2i(const unsigned char **in, unsigned int length, int ispub)
252f1535dc8Sdjm {
253f1535dc8Sdjm 	const unsigned char *p = *in;
254f1535dc8Sdjm 	unsigned int bitlen, magic;
255f1535dc8Sdjm 	int isdss;
256a8b5ceceSjsing 
257a8b5ceceSjsing 	if (do_blob_header(&p, length, &magic, &bitlen, &isdss, &ispub) <= 0) {
2585067ae9fSbeck 		PEMerror(PEM_R_KEYBLOB_HEADER_PARSE_ERROR);
259f1535dc8Sdjm 		return NULL;
260f1535dc8Sdjm 	}
261f1535dc8Sdjm 	length -= 16;
262a8b5ceceSjsing 	if (length < blob_length(bitlen, isdss, ispub)) {
2635067ae9fSbeck 		PEMerror(PEM_R_KEYBLOB_TOO_SHORT);
264f1535dc8Sdjm 		return NULL;
265f1535dc8Sdjm 	}
266f1535dc8Sdjm 	if (isdss)
267f1535dc8Sdjm 		return b2i_dss(&p, length, bitlen, ispub);
268f1535dc8Sdjm 	else
269f1535dc8Sdjm 		return b2i_rsa(&p, length, bitlen, ispub);
270f1535dc8Sdjm }
271f1535dc8Sdjm 
272a8b5ceceSjsing static EVP_PKEY *
do_b2i_bio(BIO * in,int ispub)273a8b5ceceSjsing do_b2i_bio(BIO *in, int ispub)
274f1535dc8Sdjm {
275f1535dc8Sdjm 	const unsigned char *p;
276f1535dc8Sdjm 	unsigned char hdr_buf[16], *buf = NULL;
277f1535dc8Sdjm 	unsigned int bitlen, magic, length;
278f1535dc8Sdjm 	int isdss;
279f1535dc8Sdjm 	EVP_PKEY *ret = NULL;
280a8b5ceceSjsing 
281a8b5ceceSjsing 	if (BIO_read(in, hdr_buf, 16) != 16) {
2825067ae9fSbeck 		PEMerror(PEM_R_KEYBLOB_TOO_SHORT);
283f1535dc8Sdjm 		return NULL;
284f1535dc8Sdjm 	}
285f1535dc8Sdjm 	p = hdr_buf;
286f1535dc8Sdjm 	if (do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) <= 0)
287f1535dc8Sdjm 		return NULL;
288f1535dc8Sdjm 
289f1535dc8Sdjm 	length = blob_length(bitlen, isdss, ispub);
2906f3a6cb1Sbeck 	buf = malloc(length);
291a8b5ceceSjsing 	if (!buf) {
2925067ae9fSbeck 		PEMerror(ERR_R_MALLOC_FAILURE);
293f1535dc8Sdjm 		goto err;
294f1535dc8Sdjm 	}
295f1535dc8Sdjm 	p = buf;
296a8b5ceceSjsing 	if (BIO_read(in, buf, length) != (int)length) {
2975067ae9fSbeck 		PEMerror(PEM_R_KEYBLOB_TOO_SHORT);
298f1535dc8Sdjm 		goto err;
299f1535dc8Sdjm 	}
300f1535dc8Sdjm 
301f1535dc8Sdjm 	if (isdss)
302f1535dc8Sdjm 		ret = b2i_dss(&p, length, bitlen, ispub);
303f1535dc8Sdjm 	else
304f1535dc8Sdjm 		ret = b2i_rsa(&p, length, bitlen, ispub);
305f1535dc8Sdjm 
306f1535dc8Sdjm  err:
3076f3a6cb1Sbeck 	free(buf);
308f1535dc8Sdjm 	return ret;
309f1535dc8Sdjm }
310f1535dc8Sdjm 
311a8b5ceceSjsing static EVP_PKEY *
b2i_dss(const unsigned char ** in,unsigned int length,unsigned int bitlen,int ispub)312a8b5ceceSjsing b2i_dss(const unsigned char **in, unsigned int length, unsigned int bitlen,
313a8b5ceceSjsing     int ispub)
314f1535dc8Sdjm {
315f1535dc8Sdjm 	const unsigned char *p = *in;
316f1535dc8Sdjm 	EVP_PKEY *ret = NULL;
317f1535dc8Sdjm 	DSA *dsa = NULL;
318f1535dc8Sdjm 	BN_CTX *ctx = NULL;
319f1535dc8Sdjm 	unsigned int nbyte;
320a8b5ceceSjsing 
321f1535dc8Sdjm 	nbyte = (bitlen + 7) >> 3;
322f1535dc8Sdjm 
323f1535dc8Sdjm 	dsa = DSA_new();
324f1535dc8Sdjm 	ret = EVP_PKEY_new();
325f1535dc8Sdjm 	if (!dsa || !ret)
326896b2b4fSinoguchi 		goto err;
327f1535dc8Sdjm 	if (!read_lebn(&p, nbyte, &dsa->p))
328896b2b4fSinoguchi 		goto err;
329f1535dc8Sdjm 	if (!read_lebn(&p, 20, &dsa->q))
330896b2b4fSinoguchi 		goto err;
331f1535dc8Sdjm 	if (!read_lebn(&p, nbyte, &dsa->g))
332896b2b4fSinoguchi 		goto err;
333a8b5ceceSjsing 	if (ispub) {
334f1535dc8Sdjm 		if (!read_lebn(&p, nbyte, &dsa->pub_key))
335896b2b4fSinoguchi 			goto err;
336a8b5ceceSjsing 	} else {
337f1535dc8Sdjm 		if (!read_lebn(&p, 20, &dsa->priv_key))
338896b2b4fSinoguchi 			goto err;
339f1535dc8Sdjm 		/* Calculate public key */
340f1535dc8Sdjm 		if (!(dsa->pub_key = BN_new()))
341896b2b4fSinoguchi 			goto err;
342f1535dc8Sdjm 		if (!(ctx = BN_CTX_new()))
343896b2b4fSinoguchi 			goto err;
3443a88f7afSbeck 		if (!BN_mod_exp_ct(dsa->pub_key, dsa->g,
345f1535dc8Sdjm 		    dsa->priv_key, dsa->p, ctx))
346896b2b4fSinoguchi 			goto err;
347f1535dc8Sdjm 		BN_CTX_free(ctx);
348f1535dc8Sdjm 	}
349f1535dc8Sdjm 
350f1535dc8Sdjm 	EVP_PKEY_set1_DSA(ret, dsa);
351f1535dc8Sdjm 	DSA_free(dsa);
352f1535dc8Sdjm 	*in = p;
353f1535dc8Sdjm 	return ret;
354f1535dc8Sdjm 
355896b2b4fSinoguchi  err:
3565067ae9fSbeck 	PEMerror(ERR_R_MALLOC_FAILURE);
357f1535dc8Sdjm 	DSA_free(dsa);
358f1535dc8Sdjm 	EVP_PKEY_free(ret);
359f1535dc8Sdjm 	BN_CTX_free(ctx);
360f1535dc8Sdjm 	return NULL;
361f1535dc8Sdjm }
362f1535dc8Sdjm 
363a8b5ceceSjsing static EVP_PKEY *
b2i_rsa(const unsigned char ** in,unsigned int length,unsigned int bitlen,int ispub)364a8b5ceceSjsing b2i_rsa(const unsigned char **in, unsigned int length, unsigned int bitlen,
365a8b5ceceSjsing     int ispub)
366f1535dc8Sdjm {
367f1535dc8Sdjm 	const unsigned char *p = *in;
368f1535dc8Sdjm 	EVP_PKEY *ret = NULL;
369f1535dc8Sdjm 	RSA *rsa = NULL;
370f1535dc8Sdjm 	unsigned int nbyte, hnbyte;
371a8b5ceceSjsing 
372f1535dc8Sdjm 	nbyte = (bitlen + 7) >> 3;
373f1535dc8Sdjm 	hnbyte = (bitlen + 15) >> 4;
374f1535dc8Sdjm 	rsa = RSA_new();
375f1535dc8Sdjm 	ret = EVP_PKEY_new();
376f1535dc8Sdjm 	if (!rsa || !ret)
377896b2b4fSinoguchi 		goto err;
378f1535dc8Sdjm 	rsa->e = BN_new();
379f1535dc8Sdjm 	if (!rsa->e)
380896b2b4fSinoguchi 		goto err;
381f1535dc8Sdjm 	if (!BN_set_word(rsa->e, read_ledword(&p)))
382896b2b4fSinoguchi 		goto err;
383f1535dc8Sdjm 	if (!read_lebn(&p, nbyte, &rsa->n))
384896b2b4fSinoguchi 		goto err;
385a8b5ceceSjsing 	if (!ispub) {
386f1535dc8Sdjm 		if (!read_lebn(&p, hnbyte, &rsa->p))
387896b2b4fSinoguchi 			goto err;
388f1535dc8Sdjm 		if (!read_lebn(&p, hnbyte, &rsa->q))
389896b2b4fSinoguchi 			goto err;
390f1535dc8Sdjm 		if (!read_lebn(&p, hnbyte, &rsa->dmp1))
391896b2b4fSinoguchi 			goto err;
392f1535dc8Sdjm 		if (!read_lebn(&p, hnbyte, &rsa->dmq1))
393896b2b4fSinoguchi 			goto err;
394f1535dc8Sdjm 		if (!read_lebn(&p, hnbyte, &rsa->iqmp))
395896b2b4fSinoguchi 			goto err;
396f1535dc8Sdjm 		if (!read_lebn(&p, nbyte, &rsa->d))
397896b2b4fSinoguchi 			goto err;
398f1535dc8Sdjm 	}
399f1535dc8Sdjm 
400f1535dc8Sdjm 	EVP_PKEY_set1_RSA(ret, rsa);
401f1535dc8Sdjm 	RSA_free(rsa);
402f1535dc8Sdjm 	*in = p;
403f1535dc8Sdjm 	return ret;
404a8b5ceceSjsing 
405896b2b4fSinoguchi  err:
4065067ae9fSbeck 	PEMerror(ERR_R_MALLOC_FAILURE);
407f1535dc8Sdjm 	RSA_free(rsa);
408f1535dc8Sdjm 	EVP_PKEY_free(ret);
409f1535dc8Sdjm 	return NULL;
410f1535dc8Sdjm }
411f1535dc8Sdjm 
412a8b5ceceSjsing EVP_PKEY *
b2i_PrivateKey(const unsigned char ** in,long length)413a8b5ceceSjsing b2i_PrivateKey(const unsigned char **in, long length)
414f1535dc8Sdjm {
415f1535dc8Sdjm 	return do_b2i(in, length, 0);
416f1535dc8Sdjm }
4174a925a6aSbeck LCRYPTO_ALIAS(b2i_PrivateKey);
418f1535dc8Sdjm 
419a8b5ceceSjsing EVP_PKEY *
b2i_PublicKey(const unsigned char ** in,long length)420a8b5ceceSjsing b2i_PublicKey(const unsigned char **in, long length)
421f1535dc8Sdjm {
422f1535dc8Sdjm 	return do_b2i(in, length, 1);
423f1535dc8Sdjm }
4244a925a6aSbeck LCRYPTO_ALIAS(b2i_PublicKey);
425f1535dc8Sdjm 
426a8b5ceceSjsing EVP_PKEY *
b2i_PrivateKey_bio(BIO * in)427a8b5ceceSjsing b2i_PrivateKey_bio(BIO *in)
428f1535dc8Sdjm {
429f1535dc8Sdjm 	return do_b2i_bio(in, 0);
430f1535dc8Sdjm }
4314a925a6aSbeck LCRYPTO_ALIAS(b2i_PrivateKey_bio);
432f1535dc8Sdjm 
433a8b5ceceSjsing EVP_PKEY *
b2i_PublicKey_bio(BIO * in)434a8b5ceceSjsing b2i_PublicKey_bio(BIO *in)
435f1535dc8Sdjm {
436f1535dc8Sdjm 	return do_b2i_bio(in, 1);
437f1535dc8Sdjm }
4384a925a6aSbeck LCRYPTO_ALIAS(b2i_PublicKey_bio);
439f1535dc8Sdjm 
440a8b5ceceSjsing static void
write_ledword(unsigned char ** out,unsigned int dw)441a8b5ceceSjsing write_ledword(unsigned char **out, unsigned int dw)
442f1535dc8Sdjm {
443f1535dc8Sdjm 	unsigned char *p = *out;
444a8b5ceceSjsing 
445f1535dc8Sdjm 	*p++ = dw & 0xff;
446f1535dc8Sdjm 	*p++ = (dw >> 8) & 0xff;
447f1535dc8Sdjm 	*p++ = (dw >> 16) & 0xff;
448f1535dc8Sdjm 	*p++ = (dw >> 24) & 0xff;
449f1535dc8Sdjm 	*out = p;
450f1535dc8Sdjm }
451f1535dc8Sdjm 
452a8b5ceceSjsing static void
write_lebn(unsigned char ** out,const BIGNUM * bn,int len)453a8b5ceceSjsing write_lebn(unsigned char **out, const BIGNUM *bn, int len)
454f1535dc8Sdjm {
455f1535dc8Sdjm 	int nb, i;
456f1535dc8Sdjm 	unsigned char *p = *out, *q, c;
457a8b5ceceSjsing 
458f1535dc8Sdjm 	nb = BN_num_bytes(bn);
459f1535dc8Sdjm 	BN_bn2bin(bn, p);
460f1535dc8Sdjm 	q = p + nb - 1;
461f1535dc8Sdjm 	/* In place byte order reversal */
462a8b5ceceSjsing 	for (i = 0; i < nb / 2; i++) {
463f1535dc8Sdjm 		c = *p;
464f1535dc8Sdjm 		*p++ = *q;
465f1535dc8Sdjm 		*q-- = c;
466f1535dc8Sdjm 	}
467f1535dc8Sdjm 	*out += nb;
468f1535dc8Sdjm 	/* Pad with zeroes if we have to */
469a8b5ceceSjsing 	if (len > 0) {
470f1535dc8Sdjm 		len -= nb;
471a8b5ceceSjsing 		if (len > 0) {
472f1535dc8Sdjm 			memset(*out, 0, len);
473f1535dc8Sdjm 			*out += len;
474f1535dc8Sdjm 		}
475f1535dc8Sdjm 	}
476f1535dc8Sdjm }
477f1535dc8Sdjm 
478f1535dc8Sdjm 
479f1535dc8Sdjm static int check_bitlen_rsa(RSA *rsa, int ispub, unsigned int *magic);
480f1535dc8Sdjm static int check_bitlen_dsa(DSA *dsa, int ispub, unsigned int *magic);
481f1535dc8Sdjm 
482f1535dc8Sdjm static void write_rsa(unsigned char **out, RSA *rsa, int ispub);
483f1535dc8Sdjm static void write_dsa(unsigned char **out, DSA *dsa, int ispub);
484f1535dc8Sdjm 
485a8b5ceceSjsing static int
do_i2b(unsigned char ** out,EVP_PKEY * pk,int ispub)486a8b5ceceSjsing do_i2b(unsigned char **out, EVP_PKEY *pk, int ispub)
487f1535dc8Sdjm {
488f1535dc8Sdjm 	unsigned char *p;
489f1535dc8Sdjm 	unsigned int bitlen, magic = 0, keyalg;
490f1535dc8Sdjm 	int outlen, noinc = 0;
491a8b5ceceSjsing 
492a8b5ceceSjsing 	if (pk->type == EVP_PKEY_DSA) {
493f1535dc8Sdjm 		bitlen = check_bitlen_dsa(pk->pkey.dsa, ispub, &magic);
494f1535dc8Sdjm 		keyalg = MS_KEYALG_DSS_SIGN;
495a8b5ceceSjsing 	} else if (pk->type == EVP_PKEY_RSA) {
496f1535dc8Sdjm 		bitlen = check_bitlen_rsa(pk->pkey.rsa, ispub, &magic);
497f1535dc8Sdjm 		keyalg = MS_KEYALG_RSA_KEYX;
498a8b5ceceSjsing 	} else
499f1535dc8Sdjm 		return -1;
500f1535dc8Sdjm 	if (bitlen == 0)
501f1535dc8Sdjm 		return -1;
502f1535dc8Sdjm 	outlen = 16 + blob_length(bitlen,
503f1535dc8Sdjm 	    keyalg == MS_KEYALG_DSS_SIGN ? 1 : 0, ispub);
504f1535dc8Sdjm 	if (out == NULL)
505f1535dc8Sdjm 		return outlen;
506f1535dc8Sdjm 	if (*out)
507f1535dc8Sdjm 		p = *out;
508a8b5ceceSjsing 	else {
5096f3a6cb1Sbeck 		p = malloc(outlen);
510f1535dc8Sdjm 		if (!p)
511f1535dc8Sdjm 			return -1;
512f1535dc8Sdjm 		*out = p;
513f1535dc8Sdjm 		noinc = 1;
514f1535dc8Sdjm 	}
515f1535dc8Sdjm 	if (ispub)
516f1535dc8Sdjm 		*p++ = MS_PUBLICKEYBLOB;
517f1535dc8Sdjm 	else
518f1535dc8Sdjm 		*p++ = MS_PRIVATEKEYBLOB;
519f1535dc8Sdjm 	*p++ = 0x2;
520f1535dc8Sdjm 	*p++ = 0;
521f1535dc8Sdjm 	*p++ = 0;
522f1535dc8Sdjm 	write_ledword(&p, keyalg);
523f1535dc8Sdjm 	write_ledword(&p, magic);
524f1535dc8Sdjm 	write_ledword(&p, bitlen);
525f1535dc8Sdjm 	if (keyalg == MS_KEYALG_DSS_SIGN)
526f1535dc8Sdjm 		write_dsa(&p, pk->pkey.dsa, ispub);
527f1535dc8Sdjm 	else
528f1535dc8Sdjm 		write_rsa(&p, pk->pkey.rsa, ispub);
529f1535dc8Sdjm 	if (!noinc)
530f1535dc8Sdjm 		*out += outlen;
531f1535dc8Sdjm 	return outlen;
532f1535dc8Sdjm }
533f1535dc8Sdjm 
534a8b5ceceSjsing static int
do_i2b_bio(BIO * out,EVP_PKEY * pk,int ispub)535a8b5ceceSjsing do_i2b_bio(BIO *out, EVP_PKEY *pk, int ispub)
536f1535dc8Sdjm {
537f1535dc8Sdjm 	unsigned char *tmp = NULL;
538f1535dc8Sdjm 	int outlen, wrlen;
539a8b5ceceSjsing 
540f1535dc8Sdjm 	outlen = do_i2b(&tmp, pk, ispub);
541f1535dc8Sdjm 	if (outlen < 0)
542f1535dc8Sdjm 		return -1;
543f1535dc8Sdjm 	wrlen = BIO_write(out, tmp, outlen);
5446f3a6cb1Sbeck 	free(tmp);
545f1535dc8Sdjm 	if (wrlen == outlen)
546f1535dc8Sdjm 		return outlen;
547f1535dc8Sdjm 	return -1;
548f1535dc8Sdjm }
549f1535dc8Sdjm 
550a8b5ceceSjsing static int
check_bitlen_dsa(DSA * dsa,int ispub,unsigned int * pmagic)551a8b5ceceSjsing check_bitlen_dsa(DSA *dsa, int ispub, unsigned int *pmagic)
552f1535dc8Sdjm {
553f1535dc8Sdjm 	int bitlen;
554a8b5ceceSjsing 
555f1535dc8Sdjm 	bitlen = BN_num_bits(dsa->p);
556a8b5ceceSjsing 	if ((bitlen & 7) || (BN_num_bits(dsa->q) != 160) ||
557a8b5ceceSjsing 	    (BN_num_bits(dsa->g) > bitlen))
558896b2b4fSinoguchi 		goto err;
559a8b5ceceSjsing 	if (ispub) {
560f1535dc8Sdjm 		if (BN_num_bits(dsa->pub_key) > bitlen)
561896b2b4fSinoguchi 			goto err;
562f1535dc8Sdjm 		*pmagic = MS_DSS1MAGIC;
563a8b5ceceSjsing 	} else {
564f1535dc8Sdjm 		if (BN_num_bits(dsa->priv_key) > 160)
565896b2b4fSinoguchi 			goto err;
566f1535dc8Sdjm 		*pmagic = MS_DSS2MAGIC;
567f1535dc8Sdjm 	}
568f1535dc8Sdjm 
569f1535dc8Sdjm 	return bitlen;
570a8b5ceceSjsing 
571896b2b4fSinoguchi  err:
5725067ae9fSbeck 	PEMerror(PEM_R_UNSUPPORTED_KEY_COMPONENTS);
573f1535dc8Sdjm 	return 0;
574f1535dc8Sdjm }
575f1535dc8Sdjm 
576a8b5ceceSjsing static int
check_bitlen_rsa(RSA * rsa,int ispub,unsigned int * pmagic)577a8b5ceceSjsing check_bitlen_rsa(RSA *rsa, int ispub, unsigned int *pmagic)
578f1535dc8Sdjm {
579f1535dc8Sdjm 	int nbyte, hnbyte, bitlen;
580a8b5ceceSjsing 
581f1535dc8Sdjm 	if (BN_num_bits(rsa->e) > 32)
582896b2b4fSinoguchi 		goto err;
583f1535dc8Sdjm 	bitlen = BN_num_bits(rsa->n);
584f1535dc8Sdjm 	nbyte = BN_num_bytes(rsa->n);
585f1535dc8Sdjm 	hnbyte = (BN_num_bits(rsa->n) + 15) >> 4;
586a8b5ceceSjsing 	if (ispub) {
587f1535dc8Sdjm 		*pmagic = MS_RSA1MAGIC;
588f1535dc8Sdjm 		return bitlen;
589a8b5ceceSjsing 	} else {
590f1535dc8Sdjm 		*pmagic = MS_RSA2MAGIC;
591f1535dc8Sdjm 		/* For private key each component must fit within nbyte or
592f1535dc8Sdjm 		 * hnbyte.
593f1535dc8Sdjm 		 */
594f1535dc8Sdjm 		if (BN_num_bytes(rsa->d) > nbyte)
595896b2b4fSinoguchi 			goto err;
596a8b5ceceSjsing 		if ((BN_num_bytes(rsa->iqmp) > hnbyte) ||
597a8b5ceceSjsing 		    (BN_num_bytes(rsa->p) > hnbyte) ||
598a8b5ceceSjsing 		    (BN_num_bytes(rsa->q) > hnbyte) ||
599a8b5ceceSjsing 		    (BN_num_bytes(rsa->dmp1) > hnbyte) ||
600a8b5ceceSjsing 		    (BN_num_bytes(rsa->dmq1) > hnbyte))
601896b2b4fSinoguchi 			goto err;
602f1535dc8Sdjm 	}
603f1535dc8Sdjm 	return bitlen;
604a8b5ceceSjsing 
605896b2b4fSinoguchi  err:
6065067ae9fSbeck 	PEMerror(PEM_R_UNSUPPORTED_KEY_COMPONENTS);
607f1535dc8Sdjm 	return 0;
608f1535dc8Sdjm }
609f1535dc8Sdjm 
610a8b5ceceSjsing static void
write_rsa(unsigned char ** out,RSA * rsa,int ispub)611a8b5ceceSjsing write_rsa(unsigned char **out, RSA *rsa, int ispub)
612f1535dc8Sdjm {
613f1535dc8Sdjm 	int nbyte, hnbyte;
614a8b5ceceSjsing 
615f1535dc8Sdjm 	nbyte = BN_num_bytes(rsa->n);
616f1535dc8Sdjm 	hnbyte = (BN_num_bits(rsa->n) + 15) >> 4;
617f1535dc8Sdjm 	write_lebn(out, rsa->e, 4);
618f1535dc8Sdjm 	write_lebn(out, rsa->n, -1);
619f1535dc8Sdjm 	if (ispub)
620f1535dc8Sdjm 		return;
621f1535dc8Sdjm 	write_lebn(out, rsa->p, hnbyte);
622f1535dc8Sdjm 	write_lebn(out, rsa->q, hnbyte);
623f1535dc8Sdjm 	write_lebn(out, rsa->dmp1, hnbyte);
624f1535dc8Sdjm 	write_lebn(out, rsa->dmq1, hnbyte);
625f1535dc8Sdjm 	write_lebn(out, rsa->iqmp, hnbyte);
626f1535dc8Sdjm 	write_lebn(out, rsa->d, nbyte);
627f1535dc8Sdjm }
628f1535dc8Sdjm 
629a8b5ceceSjsing static void
write_dsa(unsigned char ** out,DSA * dsa,int ispub)630a8b5ceceSjsing write_dsa(unsigned char **out, DSA *dsa, int ispub)
631f1535dc8Sdjm {
632f1535dc8Sdjm 	int nbyte;
633a8b5ceceSjsing 
634f1535dc8Sdjm 	nbyte = BN_num_bytes(dsa->p);
635f1535dc8Sdjm 	write_lebn(out, dsa->p, nbyte);
636f1535dc8Sdjm 	write_lebn(out, dsa->q, 20);
637f1535dc8Sdjm 	write_lebn(out, dsa->g, nbyte);
638f1535dc8Sdjm 	if (ispub)
639f1535dc8Sdjm 		write_lebn(out, dsa->pub_key, nbyte);
640f1535dc8Sdjm 	else
641f1535dc8Sdjm 		write_lebn(out, dsa->priv_key, 20);
642f1535dc8Sdjm 	/* Set "invalid" for seed structure values */
643f1535dc8Sdjm 	memset(*out, 0xff, 24);
644f1535dc8Sdjm 	*out += 24;
645f1535dc8Sdjm 	return;
646f1535dc8Sdjm }
647f1535dc8Sdjm 
648a8b5ceceSjsing int
i2b_PrivateKey_bio(BIO * out,EVP_PKEY * pk)649a8b5ceceSjsing i2b_PrivateKey_bio(BIO *out, EVP_PKEY *pk)
650f1535dc8Sdjm {
651f1535dc8Sdjm 	return do_i2b_bio(out, pk, 0);
652f1535dc8Sdjm }
6534a925a6aSbeck LCRYPTO_ALIAS(i2b_PrivateKey_bio);
654f1535dc8Sdjm 
655a8b5ceceSjsing int
i2b_PublicKey_bio(BIO * out,EVP_PKEY * pk)656a8b5ceceSjsing i2b_PublicKey_bio(BIO *out, EVP_PKEY *pk)
657f1535dc8Sdjm {
658f1535dc8Sdjm 	return do_i2b_bio(out, pk, 1);
659f1535dc8Sdjm }
6604a925a6aSbeck LCRYPTO_ALIAS(i2b_PublicKey_bio);
661f1535dc8Sdjm 
662f1535dc8Sdjm #ifndef OPENSSL_NO_RC4
663f1535dc8Sdjm 
664a8b5ceceSjsing static int
do_PVK_header(const unsigned char ** in,unsigned int length,int skip_magic,unsigned int * psaltlen,unsigned int * pkeylen)665a8b5ceceSjsing do_PVK_header(const unsigned char **in, unsigned int length, int skip_magic,
666f1535dc8Sdjm     unsigned int *psaltlen, unsigned int *pkeylen)
667f1535dc8Sdjm {
668f1535dc8Sdjm 	const unsigned char *p = *in;
6699a0dbe41Sdjm 	unsigned int pvk_magic, is_encrypted;
670a8b5ceceSjsing 
671a8b5ceceSjsing 	if (skip_magic) {
672a8b5ceceSjsing 		if (length < 20) {
6735067ae9fSbeck 			PEMerror(PEM_R_PVK_TOO_SHORT);
674f1535dc8Sdjm 			return 0;
675f1535dc8Sdjm 		}
676f1535dc8Sdjm 		length -= 20;
677a8b5ceceSjsing 	} else {
678a8b5ceceSjsing 		if (length < 24) {
6795067ae9fSbeck 			PEMerror(PEM_R_PVK_TOO_SHORT);
680f1535dc8Sdjm 			return 0;
681f1535dc8Sdjm 		}
682f1535dc8Sdjm 		length -= 24;
683f1535dc8Sdjm 		pvk_magic = read_ledword(&p);
684a8b5ceceSjsing 		if (pvk_magic != MS_PVKMAGIC) {
6855067ae9fSbeck 			PEMerror(PEM_R_BAD_MAGIC_NUMBER);
686f1535dc8Sdjm 			return 0;
687f1535dc8Sdjm 		}
688f1535dc8Sdjm 	}
689f1535dc8Sdjm 	/* Skip reserved */
690f1535dc8Sdjm 	p += 4;
6919a0dbe41Sdjm 	/*keytype = */read_ledword(&p);
692f1535dc8Sdjm 	is_encrypted = read_ledword(&p);
693f1535dc8Sdjm 	*psaltlen = read_ledword(&p);
694f1535dc8Sdjm 	*pkeylen = read_ledword(&p);
6954e5a679eSbeck 	if (*psaltlen > 65536 || *pkeylen > 65536) {
6965067ae9fSbeck 		PEMerror(PEM_R_ERROR_CONVERTING_PRIVATE_KEY);
6974e5a679eSbeck 		return 0;
6984e5a679eSbeck 	}
699f1535dc8Sdjm 
700a8b5ceceSjsing 	if (is_encrypted && !*psaltlen) {
7015067ae9fSbeck 		PEMerror(PEM_R_INCONSISTENT_HEADER);
702f1535dc8Sdjm 		return 0;
703f1535dc8Sdjm 	}
704f1535dc8Sdjm 
705f1535dc8Sdjm 	*in = p;
706f1535dc8Sdjm 	return 1;
707f1535dc8Sdjm }
708f1535dc8Sdjm 
709a8b5ceceSjsing static int
derive_pvk_key(unsigned char * key,const unsigned char * salt,unsigned int saltlen,const unsigned char * pass,int passlen)710a8b5ceceSjsing derive_pvk_key(unsigned char *key, const unsigned char *salt,
711a8b5ceceSjsing     unsigned int saltlen, const unsigned char *pass, int passlen)
712f1535dc8Sdjm {
713f1535dc8Sdjm 	EVP_MD_CTX mctx;
714ec07fdf1Sdjm 	int rv = 1;
715a8b5ceceSjsing 
716*76d5ca18Stb 	EVP_MD_CTX_legacy_clear(&mctx);
717a8b5ceceSjsing 	if (!EVP_DigestInit_ex(&mctx, EVP_sha1(), NULL) ||
718a8b5ceceSjsing 	    !EVP_DigestUpdate(&mctx, salt, saltlen) ||
719a8b5ceceSjsing 	    !EVP_DigestUpdate(&mctx, pass, passlen) ||
720a8b5ceceSjsing 	    !EVP_DigestFinal_ex(&mctx, key, NULL))
721ec07fdf1Sdjm 		rv = 0;
722ec07fdf1Sdjm 
723f1535dc8Sdjm 	EVP_MD_CTX_cleanup(&mctx);
724ec07fdf1Sdjm 	return rv;
725f1535dc8Sdjm }
726f1535dc8Sdjm 
727a8b5ceceSjsing static EVP_PKEY *
do_PVK_body(const unsigned char ** in,unsigned int saltlen,unsigned int keylen,pem_password_cb * cb,void * u)728a8b5ceceSjsing do_PVK_body(const unsigned char **in, unsigned int saltlen,
729a8b5ceceSjsing     unsigned int keylen, pem_password_cb *cb, void *u)
730f1535dc8Sdjm {
731f1535dc8Sdjm 	EVP_PKEY *ret = NULL;
732f1535dc8Sdjm 	const unsigned char *p = *in;
733f1535dc8Sdjm 	unsigned int magic;
734f1535dc8Sdjm 	unsigned char *enctmp = NULL, *q;
735896b2b4fSinoguchi 	EVP_CIPHER_CTX *cctx = NULL;
736e97f905bSmiod 
737896b2b4fSinoguchi 	if ((cctx = EVP_CIPHER_CTX_new()) == NULL) {
738896b2b4fSinoguchi 		PEMerror(ERR_R_MALLOC_FAILURE);
739896b2b4fSinoguchi 		goto err;
740896b2b4fSinoguchi 	}
741a8b5ceceSjsing 	if (saltlen) {
742f1535dc8Sdjm 		char psbuf[PEM_BUFSIZE];
743f1535dc8Sdjm 		unsigned char keybuf[20];
744f1535dc8Sdjm 		int enctmplen, inlen;
745e97f905bSmiod 
746f1535dc8Sdjm 		if (cb)
747f1535dc8Sdjm 			inlen = cb(psbuf, PEM_BUFSIZE, 0, u);
748f1535dc8Sdjm 		else
749f1535dc8Sdjm 			inlen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u);
750a8b5ceceSjsing 		if (inlen <= 0) {
7515067ae9fSbeck 			PEMerror(PEM_R_BAD_PASSWORD_READ);
752d5eebd0bSjsg 			goto err;
753f1535dc8Sdjm 		}
7546f3a6cb1Sbeck 		enctmp = malloc(keylen + 8);
755a8b5ceceSjsing 		if (!enctmp) {
7565067ae9fSbeck 			PEMerror(ERR_R_MALLOC_FAILURE);
757d5eebd0bSjsg 			goto err;
758f1535dc8Sdjm 		}
759e97f905bSmiod 		if (!derive_pvk_key(keybuf, p, saltlen, (unsigned char *)psbuf,
760e97f905bSmiod 		    inlen)) {
761d5eebd0bSjsg 			goto err;
76264b5e5f5Sjsg 		}
763f1535dc8Sdjm 		p += saltlen;
764f1535dc8Sdjm 		/* Copy BLOBHEADER across, decrypt rest */
765f1535dc8Sdjm 		memcpy(enctmp, p, 8);
766f1535dc8Sdjm 		p += 8;
767e97f905bSmiod 		if (keylen < 8) {
7685067ae9fSbeck 			PEMerror(PEM_R_PVK_TOO_SHORT);
769d5eebd0bSjsg 			goto err;
770e97f905bSmiod 		}
771f1535dc8Sdjm 		inlen = keylen - 8;
772f1535dc8Sdjm 		q = enctmp + 8;
773896b2b4fSinoguchi 		if (!EVP_DecryptInit_ex(cctx, EVP_rc4(), NULL, keybuf, NULL))
774ec07fdf1Sdjm 			goto err;
775896b2b4fSinoguchi 		if (!EVP_DecryptUpdate(cctx, q, &enctmplen, p, inlen))
776ec07fdf1Sdjm 			goto err;
777896b2b4fSinoguchi 		if (!EVP_DecryptFinal_ex(cctx, q + enctmplen, &enctmplen))
778ec07fdf1Sdjm 			goto err;
779f1535dc8Sdjm 		magic = read_ledword((const unsigned char **)&q);
780a8b5ceceSjsing 		if (magic != MS_RSA2MAGIC && magic != MS_DSS2MAGIC) {
781f1535dc8Sdjm 			q = enctmp + 8;
782f1535dc8Sdjm 			memset(keybuf + 5, 0, 11);
783896b2b4fSinoguchi 			if (!EVP_DecryptInit_ex(cctx, EVP_rc4(), NULL, keybuf,
784ec07fdf1Sdjm 			    NULL))
785ec07fdf1Sdjm 				goto err;
7860f777b12Sjsing 			explicit_bzero(keybuf, 20);
787896b2b4fSinoguchi 			if (!EVP_DecryptUpdate(cctx, q, &enctmplen, p, inlen))
788ec07fdf1Sdjm 				goto err;
789896b2b4fSinoguchi 			if (!EVP_DecryptFinal_ex(cctx, q + enctmplen,
790ec07fdf1Sdjm 			    &enctmplen))
791ec07fdf1Sdjm 				goto err;
792f1535dc8Sdjm 			magic = read_ledword((const unsigned char **)&q);
793a8b5ceceSjsing 			if (magic != MS_RSA2MAGIC && magic != MS_DSS2MAGIC) {
7945067ae9fSbeck 				PEMerror(PEM_R_BAD_DECRYPT);
795f1535dc8Sdjm 				goto err;
796f1535dc8Sdjm 			}
797a8b5ceceSjsing 		} else
7980f777b12Sjsing 			explicit_bzero(keybuf, 20);
799f1535dc8Sdjm 		p = enctmp;
800f1535dc8Sdjm 	}
801f1535dc8Sdjm 
802f1535dc8Sdjm 	ret = b2i_PrivateKey(&p, keylen);
803a8b5ceceSjsing 
804f1535dc8Sdjm  err:
805896b2b4fSinoguchi 	EVP_CIPHER_CTX_free(cctx);
806f1535dc8Sdjm 	if (enctmp && saltlen)
8076f3a6cb1Sbeck 		free(enctmp);
808f1535dc8Sdjm 	return ret;
809f1535dc8Sdjm }
810f1535dc8Sdjm 
811f1535dc8Sdjm 
812a8b5ceceSjsing EVP_PKEY *
b2i_PVK_bio(BIO * in,pem_password_cb * cb,void * u)813a8b5ceceSjsing b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u)
814f1535dc8Sdjm {
815f1535dc8Sdjm 	unsigned char pvk_hdr[24], *buf = NULL;
816f1535dc8Sdjm 	const unsigned char *p;
8174e5a679eSbeck 	size_t buflen;
818f1535dc8Sdjm 	EVP_PKEY *ret = NULL;
819f1535dc8Sdjm 	unsigned int saltlen, keylen;
820a8b5ceceSjsing 
821a8b5ceceSjsing 	if (BIO_read(in, pvk_hdr, 24) != 24) {
8225067ae9fSbeck 		PEMerror(PEM_R_PVK_DATA_TOO_SHORT);
823f1535dc8Sdjm 		return NULL;
824f1535dc8Sdjm 	}
825f1535dc8Sdjm 	p = pvk_hdr;
826f1535dc8Sdjm 
827f1535dc8Sdjm 	if (!do_PVK_header(&p, 24, 0, &saltlen, &keylen))
828f1535dc8Sdjm 		return 0;
8294e5a679eSbeck 	buflen = keylen + saltlen;
8306f3a6cb1Sbeck 	buf = malloc(buflen);
831a8b5ceceSjsing 	if (!buf) {
8325067ae9fSbeck 		PEMerror(ERR_R_MALLOC_FAILURE);
833f1535dc8Sdjm 		return 0;
834f1535dc8Sdjm 	}
835f1535dc8Sdjm 	p = buf;
836a8b5ceceSjsing 	if (BIO_read(in, buf, buflen) != buflen) {
8375067ae9fSbeck 		PEMerror(PEM_R_PVK_DATA_TOO_SHORT);
838f1535dc8Sdjm 		goto err;
839f1535dc8Sdjm 	}
840f1535dc8Sdjm 	ret = do_PVK_body(&p, saltlen, keylen, cb, u);
841f1535dc8Sdjm 
842f1535dc8Sdjm  err:
8437de8a684Sderaadt 	freezero(buf, buflen);
844f1535dc8Sdjm 	return ret;
845f1535dc8Sdjm }
8464a925a6aSbeck LCRYPTO_ALIAS(b2i_PVK_bio);
847f1535dc8Sdjm 
848a8b5ceceSjsing static int
i2b_PVK(unsigned char ** out,EVP_PKEY * pk,int enclevel,pem_password_cb * cb,void * u)849a8b5ceceSjsing i2b_PVK(unsigned char **out, EVP_PKEY*pk, int enclevel, pem_password_cb *cb,
850a8b5ceceSjsing     void *u)
851f1535dc8Sdjm {
8529a0dbe41Sdjm 	int outlen = 24, pklen;
8533278f4d9Sinoguchi 	unsigned char *p = NULL, *start = NULL, *salt = NULL;
854896b2b4fSinoguchi 	EVP_CIPHER_CTX *cctx = NULL;
855a8b5ceceSjsing 
856896b2b4fSinoguchi 	if ((cctx = EVP_CIPHER_CTX_new()) == NULL) {
857896b2b4fSinoguchi 		PEMerror(ERR_R_MALLOC_FAILURE);
858896b2b4fSinoguchi 		goto err;
859896b2b4fSinoguchi 	}
860896b2b4fSinoguchi 	if (enclevel != 0)
861f1535dc8Sdjm 		outlen += PVK_SALTLEN;
862f1535dc8Sdjm 	pklen = do_i2b(NULL, pk, 0);
863f1535dc8Sdjm 	if (pklen < 0)
864896b2b4fSinoguchi 		goto err;
865f1535dc8Sdjm 	outlen += pklen;
8663278f4d9Sinoguchi 	start = p = malloc(outlen);
867a8b5ceceSjsing 	if (!p) {
8685067ae9fSbeck 		PEMerror(ERR_R_MALLOC_FAILURE);
869896b2b4fSinoguchi 		goto err;
870f1535dc8Sdjm 	}
871f1535dc8Sdjm 
872f1535dc8Sdjm 	write_ledword(&p, MS_PVKMAGIC);
873f1535dc8Sdjm 	write_ledword(&p, 0);
874f1535dc8Sdjm 	if (pk->type == EVP_PKEY_DSA)
875f1535dc8Sdjm 		write_ledword(&p, MS_KEYTYPE_SIGN);
876f1535dc8Sdjm 	else
877f1535dc8Sdjm 		write_ledword(&p, MS_KEYTYPE_KEYX);
878f1535dc8Sdjm 	write_ledword(&p, enclevel ? 1 : 0);
879f1535dc8Sdjm 	write_ledword(&p, enclevel ? PVK_SALTLEN : 0);
880f1535dc8Sdjm 	write_ledword(&p, pklen);
881896b2b4fSinoguchi 	if (enclevel != 0) {
882ef624301Sjsing 		arc4random_buf(p, PVK_SALTLEN);
883f1535dc8Sdjm 		salt = p;
884f1535dc8Sdjm 		p += PVK_SALTLEN;
885f1535dc8Sdjm 	}
886f1535dc8Sdjm 	do_i2b(&p, pk, 0);
887896b2b4fSinoguchi 	if (enclevel != 0) {
888f1535dc8Sdjm 		char psbuf[PEM_BUFSIZE];
889f1535dc8Sdjm 		unsigned char keybuf[20];
890f1535dc8Sdjm 		int enctmplen, inlen;
891f1535dc8Sdjm 		if (cb)
892f1535dc8Sdjm 			inlen = cb(psbuf, PEM_BUFSIZE, 1, u);
893f1535dc8Sdjm 		else
894f1535dc8Sdjm 			inlen = PEM_def_callback(psbuf, PEM_BUFSIZE, 1, u);
895a8b5ceceSjsing 		if (inlen <= 0) {
8965067ae9fSbeck 			PEMerror(PEM_R_BAD_PASSWORD_READ);
897896b2b4fSinoguchi 			goto err;
898f1535dc8Sdjm 		}
899f1535dc8Sdjm 		if (!derive_pvk_key(keybuf, salt, PVK_SALTLEN,
900f1535dc8Sdjm 		    (unsigned char *)psbuf, inlen))
901896b2b4fSinoguchi 			goto err;
902f1535dc8Sdjm 		if (enclevel == 1)
903f1535dc8Sdjm 			memset(keybuf + 5, 0, 11);
904f1535dc8Sdjm 		p = salt + PVK_SALTLEN + 8;
905896b2b4fSinoguchi 		if (!EVP_EncryptInit_ex(cctx, EVP_rc4(), NULL, keybuf, NULL))
906896b2b4fSinoguchi 			goto err;
9070f777b12Sjsing 		explicit_bzero(keybuf, 20);
908896b2b4fSinoguchi 		if (!EVP_EncryptUpdate(cctx, p, &enctmplen, p, pklen - 8))
909896b2b4fSinoguchi 			goto err;
910896b2b4fSinoguchi 		if (!EVP_EncryptFinal_ex(cctx, p + enctmplen, &enctmplen))
911896b2b4fSinoguchi 			goto err;
912f1535dc8Sdjm 	}
913896b2b4fSinoguchi 	EVP_CIPHER_CTX_free(cctx);
9143278f4d9Sinoguchi 	*out = start;
915f1535dc8Sdjm 	return outlen;
916f1535dc8Sdjm 
917896b2b4fSinoguchi  err:
918896b2b4fSinoguchi 	EVP_CIPHER_CTX_free(cctx);
9193278f4d9Sinoguchi 	free(start);
920f1535dc8Sdjm 	return -1;
921f1535dc8Sdjm }
922f1535dc8Sdjm 
923a8b5ceceSjsing int
i2b_PVK_bio(BIO * out,EVP_PKEY * pk,int enclevel,pem_password_cb * cb,void * u)924a8b5ceceSjsing i2b_PVK_bio(BIO *out, EVP_PKEY *pk, int enclevel, pem_password_cb *cb, void *u)
925f1535dc8Sdjm {
926f1535dc8Sdjm 	unsigned char *tmp = NULL;
927f1535dc8Sdjm 	int outlen, wrlen;
928a8b5ceceSjsing 
929f1535dc8Sdjm 	outlen = i2b_PVK(&tmp, pk, enclevel, cb, u);
930f1535dc8Sdjm 	if (outlen < 0)
931f1535dc8Sdjm 		return -1;
932f1535dc8Sdjm 	wrlen = BIO_write(out, tmp, outlen);
9336f3a6cb1Sbeck 	free(tmp);
9343278f4d9Sinoguchi 	if (wrlen != outlen) {
9355067ae9fSbeck 		PEMerror(PEM_R_BIO_WRITE_FAILURE);
936f1535dc8Sdjm 		return -1;
937f1535dc8Sdjm 	}
9383278f4d9Sinoguchi 	return outlen;
9393278f4d9Sinoguchi }
9404a925a6aSbeck LCRYPTO_ALIAS(i2b_PVK_bio);
941f1535dc8Sdjm 
942f1535dc8Sdjm #endif
943f1535dc8Sdjm 
944f1535dc8Sdjm #endif
945