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