1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2005-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci/*
11e1051a39Sopenharmony_ci * Support for PVK format keys and related structures (such a PUBLICKEYBLOB
12e1051a39Sopenharmony_ci * and PRIVATEKEYBLOB).
13e1051a39Sopenharmony_ci */
14e1051a39Sopenharmony_ci
15e1051a39Sopenharmony_ci/*
16e1051a39Sopenharmony_ci * RSA and DSA low level APIs are deprecated for public use, but still ok for
17e1051a39Sopenharmony_ci * internal use.
18e1051a39Sopenharmony_ci */
19e1051a39Sopenharmony_ci#include "internal/deprecated.h"
20e1051a39Sopenharmony_ci
21e1051a39Sopenharmony_ci#include <openssl/pem.h>
22e1051a39Sopenharmony_ci#include <openssl/rand.h>
23e1051a39Sopenharmony_ci#include <openssl/bn.h>
24e1051a39Sopenharmony_ci#include <openssl/dsa.h>
25e1051a39Sopenharmony_ci#include <openssl/rsa.h>
26e1051a39Sopenharmony_ci#include "internal/cryptlib.h"
27e1051a39Sopenharmony_ci#include "crypto/pem.h"
28e1051a39Sopenharmony_ci#include "crypto/evp.h"
29e1051a39Sopenharmony_ci
30e1051a39Sopenharmony_ci/*
31e1051a39Sopenharmony_ci * Utility function: read a DWORD (4 byte unsigned integer) in little endian
32e1051a39Sopenharmony_ci * format
33e1051a39Sopenharmony_ci */
34e1051a39Sopenharmony_ci
35e1051a39Sopenharmony_cistatic unsigned int read_ledword(const unsigned char **in)
36e1051a39Sopenharmony_ci{
37e1051a39Sopenharmony_ci    const unsigned char *p = *in;
38e1051a39Sopenharmony_ci    unsigned int ret;
39e1051a39Sopenharmony_ci
40e1051a39Sopenharmony_ci    ret = (unsigned int)*p++;
41e1051a39Sopenharmony_ci    ret |= (unsigned int)*p++ << 8;
42e1051a39Sopenharmony_ci    ret |= (unsigned int)*p++ << 16;
43e1051a39Sopenharmony_ci    ret |= (unsigned int)*p++ << 24;
44e1051a39Sopenharmony_ci    *in = p;
45e1051a39Sopenharmony_ci    return ret;
46e1051a39Sopenharmony_ci}
47e1051a39Sopenharmony_ci
48e1051a39Sopenharmony_ci/*
49e1051a39Sopenharmony_ci * Read a BIGNUM in little endian format. The docs say that this should take
50e1051a39Sopenharmony_ci * up bitlen/8 bytes.
51e1051a39Sopenharmony_ci */
52e1051a39Sopenharmony_ci
53e1051a39Sopenharmony_cistatic int read_lebn(const unsigned char **in, unsigned int nbyte, BIGNUM **r)
54e1051a39Sopenharmony_ci{
55e1051a39Sopenharmony_ci    *r = BN_lebin2bn(*in, nbyte, NULL);
56e1051a39Sopenharmony_ci    if (*r == NULL)
57e1051a39Sopenharmony_ci        return 0;
58e1051a39Sopenharmony_ci    *in += nbyte;
59e1051a39Sopenharmony_ci    return 1;
60e1051a39Sopenharmony_ci}
61e1051a39Sopenharmony_ci
62e1051a39Sopenharmony_ci/*
63e1051a39Sopenharmony_ci * Create an EVP_PKEY from a type specific key.
64e1051a39Sopenharmony_ci * This takes ownership of |key|, as long as the |evp_type| is acceptable
65e1051a39Sopenharmony_ci * (EVP_PKEY_RSA or EVP_PKEY_DSA), even if the resulting EVP_PKEY wasn't
66e1051a39Sopenharmony_ci * created.
67e1051a39Sopenharmony_ci */
68e1051a39Sopenharmony_ci#define isdss_to_evp_type(isdss)                                \
69e1051a39Sopenharmony_ci    (isdss == 0 ? EVP_PKEY_RSA : isdss == 1 ? EVP_PKEY_DSA : EVP_PKEY_NONE)
70e1051a39Sopenharmony_cistatic EVP_PKEY *evp_pkey_new0_key(void *key, int evp_type)
71e1051a39Sopenharmony_ci{
72e1051a39Sopenharmony_ci    EVP_PKEY *pkey = NULL;
73e1051a39Sopenharmony_ci
74e1051a39Sopenharmony_ci    /*
75e1051a39Sopenharmony_ci     * It's assumed that if |key| is NULL, something went wrong elsewhere
76e1051a39Sopenharmony_ci     * and suitable errors are already reported.
77e1051a39Sopenharmony_ci     */
78e1051a39Sopenharmony_ci    if (key == NULL)
79e1051a39Sopenharmony_ci        return NULL;
80e1051a39Sopenharmony_ci
81e1051a39Sopenharmony_ci    if (!ossl_assert(evp_type == EVP_PKEY_RSA || evp_type == EVP_PKEY_DSA)) {
82e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, ERR_R_INTERNAL_ERROR);
83e1051a39Sopenharmony_ci        return NULL;
84e1051a39Sopenharmony_ci    }
85e1051a39Sopenharmony_ci
86e1051a39Sopenharmony_ci    if ((pkey = EVP_PKEY_new()) != NULL) {
87e1051a39Sopenharmony_ci        switch (evp_type) {
88e1051a39Sopenharmony_ci        case EVP_PKEY_RSA:
89e1051a39Sopenharmony_ci            if (EVP_PKEY_set1_RSA(pkey, key))
90e1051a39Sopenharmony_ci                break;
91e1051a39Sopenharmony_ci            EVP_PKEY_free(pkey);
92e1051a39Sopenharmony_ci            pkey = NULL;
93e1051a39Sopenharmony_ci            break;
94e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DSA
95e1051a39Sopenharmony_ci        case EVP_PKEY_DSA:
96e1051a39Sopenharmony_ci            if (EVP_PKEY_set1_DSA(pkey, key))
97e1051a39Sopenharmony_ci                break;
98e1051a39Sopenharmony_ci            EVP_PKEY_free(pkey);
99e1051a39Sopenharmony_ci            pkey = NULL;
100e1051a39Sopenharmony_ci            break;
101e1051a39Sopenharmony_ci#endif
102e1051a39Sopenharmony_ci        }
103e1051a39Sopenharmony_ci    }
104e1051a39Sopenharmony_ci
105e1051a39Sopenharmony_ci    switch (evp_type) {
106e1051a39Sopenharmony_ci    case EVP_PKEY_RSA:
107e1051a39Sopenharmony_ci        RSA_free(key);
108e1051a39Sopenharmony_ci        break;
109e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DSA
110e1051a39Sopenharmony_ci    case EVP_PKEY_DSA:
111e1051a39Sopenharmony_ci        DSA_free(key);
112e1051a39Sopenharmony_ci        break;
113e1051a39Sopenharmony_ci#endif
114e1051a39Sopenharmony_ci    }
115e1051a39Sopenharmony_ci
116e1051a39Sopenharmony_ci    if (pkey == NULL)
117e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE);
118e1051a39Sopenharmony_ci    return pkey;
119e1051a39Sopenharmony_ci}
120e1051a39Sopenharmony_ci
121e1051a39Sopenharmony_ci/* Convert private key blob to EVP_PKEY: RSA and DSA keys supported */
122e1051a39Sopenharmony_ci
123e1051a39Sopenharmony_ci# define MS_PUBLICKEYBLOB        0x6
124e1051a39Sopenharmony_ci# define MS_PRIVATEKEYBLOB       0x7
125e1051a39Sopenharmony_ci# define MS_RSA1MAGIC            0x31415352L
126e1051a39Sopenharmony_ci# define MS_RSA2MAGIC            0x32415352L
127e1051a39Sopenharmony_ci# define MS_DSS1MAGIC            0x31535344L
128e1051a39Sopenharmony_ci# define MS_DSS2MAGIC            0x32535344L
129e1051a39Sopenharmony_ci
130e1051a39Sopenharmony_ci# define MS_KEYALG_RSA_KEYX      0xa400
131e1051a39Sopenharmony_ci# define MS_KEYALG_DSS_SIGN      0x2200
132e1051a39Sopenharmony_ci
133e1051a39Sopenharmony_ci# define MS_KEYTYPE_KEYX         0x1
134e1051a39Sopenharmony_ci# define MS_KEYTYPE_SIGN         0x2
135e1051a39Sopenharmony_ci
136e1051a39Sopenharmony_ci/* The PVK file magic number: seems to spell out "bobsfile", who is Bob? */
137e1051a39Sopenharmony_ci# define MS_PVKMAGIC             0xb0b5f11eL
138e1051a39Sopenharmony_ci/* Salt length for PVK files */
139e1051a39Sopenharmony_ci# define PVK_SALTLEN             0x10
140e1051a39Sopenharmony_ci/* Maximum length in PVK header */
141e1051a39Sopenharmony_ci# define PVK_MAX_KEYLEN          102400
142e1051a39Sopenharmony_ci/* Maximum salt length */
143e1051a39Sopenharmony_ci# define PVK_MAX_SALTLEN         10240
144e1051a39Sopenharmony_ci
145e1051a39Sopenharmony_ci/*
146e1051a39Sopenharmony_ci * Read the MSBLOB header and get relevant data from it.
147e1051a39Sopenharmony_ci *
148e1051a39Sopenharmony_ci * |pisdss| and |pispub| have a double role, as they can be used for
149e1051a39Sopenharmony_ci * discovery as well as to check the the blob meets expectations.
150e1051a39Sopenharmony_ci * |*pisdss| is the indicator for whether the key is a DSA key or not.
151e1051a39Sopenharmony_ci * |*pispub| is the indicator for whether the key is public or not.
152e1051a39Sopenharmony_ci * In both cases, the following input values apply:
153e1051a39Sopenharmony_ci *
154e1051a39Sopenharmony_ci * 0    Expected to not be what the variable indicates.
155e1051a39Sopenharmony_ci * 1    Expected to be what the variable indicates.
156e1051a39Sopenharmony_ci * -1   No expectations, this function will assign 0 or 1 depending on
157e1051a39Sopenharmony_ci *      header data.
158e1051a39Sopenharmony_ci */
159e1051a39Sopenharmony_ciint ossl_do_blob_header(const unsigned char **in, unsigned int length,
160e1051a39Sopenharmony_ci                        unsigned int *pmagic, unsigned int *pbitlen,
161e1051a39Sopenharmony_ci                        int *pisdss, int *pispub)
162e1051a39Sopenharmony_ci{
163e1051a39Sopenharmony_ci    const unsigned char *p = *in;
164e1051a39Sopenharmony_ci
165e1051a39Sopenharmony_ci    if (length < 16)
166e1051a39Sopenharmony_ci        return 0;
167e1051a39Sopenharmony_ci    /* bType */
168e1051a39Sopenharmony_ci    switch (*p) {
169e1051a39Sopenharmony_ci    case MS_PUBLICKEYBLOB:
170e1051a39Sopenharmony_ci        if (*pispub == 0) {
171e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, PEM_R_EXPECTING_PRIVATE_KEY_BLOB);
172e1051a39Sopenharmony_ci            return 0;
173e1051a39Sopenharmony_ci        }
174e1051a39Sopenharmony_ci        *pispub = 1;
175e1051a39Sopenharmony_ci        break;
176e1051a39Sopenharmony_ci
177e1051a39Sopenharmony_ci    case MS_PRIVATEKEYBLOB:
178e1051a39Sopenharmony_ci        if (*pispub == 1) {
179e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, PEM_R_EXPECTING_PUBLIC_KEY_BLOB);
180e1051a39Sopenharmony_ci            return 0;
181e1051a39Sopenharmony_ci        }
182e1051a39Sopenharmony_ci        *pispub = 0;
183e1051a39Sopenharmony_ci        break;
184e1051a39Sopenharmony_ci
185e1051a39Sopenharmony_ci    default:
186e1051a39Sopenharmony_ci        return 0;
187e1051a39Sopenharmony_ci    }
188e1051a39Sopenharmony_ci    p++;
189e1051a39Sopenharmony_ci    /* Version */
190e1051a39Sopenharmony_ci    if (*p++ != 0x2) {
191e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_BAD_VERSION_NUMBER);
192e1051a39Sopenharmony_ci        return 0;
193e1051a39Sopenharmony_ci    }
194e1051a39Sopenharmony_ci    /* Ignore reserved, aiKeyAlg */
195e1051a39Sopenharmony_ci    p += 6;
196e1051a39Sopenharmony_ci    *pmagic = read_ledword(&p);
197e1051a39Sopenharmony_ci    *pbitlen = read_ledword(&p);
198e1051a39Sopenharmony_ci
199e1051a39Sopenharmony_ci    /* Consistency check for private vs public */
200e1051a39Sopenharmony_ci    switch (*pmagic) {
201e1051a39Sopenharmony_ci    case MS_DSS1MAGIC:
202e1051a39Sopenharmony_ci    case MS_RSA1MAGIC:
203e1051a39Sopenharmony_ci        if (*pispub == 0) {
204e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, PEM_R_EXPECTING_PRIVATE_KEY_BLOB);
205e1051a39Sopenharmony_ci            return 0;
206e1051a39Sopenharmony_ci        }
207e1051a39Sopenharmony_ci        break;
208e1051a39Sopenharmony_ci
209e1051a39Sopenharmony_ci    case MS_DSS2MAGIC:
210e1051a39Sopenharmony_ci    case MS_RSA2MAGIC:
211e1051a39Sopenharmony_ci        if (*pispub == 1) {
212e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, PEM_R_EXPECTING_PUBLIC_KEY_BLOB);
213e1051a39Sopenharmony_ci            return 0;
214e1051a39Sopenharmony_ci        }
215e1051a39Sopenharmony_ci        break;
216e1051a39Sopenharmony_ci
217e1051a39Sopenharmony_ci    default:
218e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_BAD_MAGIC_NUMBER);
219e1051a39Sopenharmony_ci        return -1;
220e1051a39Sopenharmony_ci    }
221e1051a39Sopenharmony_ci
222e1051a39Sopenharmony_ci    /* Check that we got the expected type */
223e1051a39Sopenharmony_ci    switch (*pmagic) {
224e1051a39Sopenharmony_ci    case MS_DSS1MAGIC:
225e1051a39Sopenharmony_ci    case MS_DSS2MAGIC:
226e1051a39Sopenharmony_ci        if (*pisdss == 0) {
227e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, PEM_R_EXPECTING_DSS_KEY_BLOB);
228e1051a39Sopenharmony_ci            return 0;
229e1051a39Sopenharmony_ci        }
230e1051a39Sopenharmony_ci        *pisdss = 1;
231e1051a39Sopenharmony_ci        break;
232e1051a39Sopenharmony_ci    case MS_RSA1MAGIC:
233e1051a39Sopenharmony_ci    case MS_RSA2MAGIC:
234e1051a39Sopenharmony_ci        if (*pisdss == 1) {
235e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, PEM_R_EXPECTING_RSA_KEY_BLOB);
236e1051a39Sopenharmony_ci            return 0;
237e1051a39Sopenharmony_ci        }
238e1051a39Sopenharmony_ci        *pisdss = 0;
239e1051a39Sopenharmony_ci        break;
240e1051a39Sopenharmony_ci
241e1051a39Sopenharmony_ci    default:
242e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_BAD_MAGIC_NUMBER);
243e1051a39Sopenharmony_ci        return -1;
244e1051a39Sopenharmony_ci    }
245e1051a39Sopenharmony_ci    *in = p;
246e1051a39Sopenharmony_ci    return 1;
247e1051a39Sopenharmony_ci}
248e1051a39Sopenharmony_ci
249e1051a39Sopenharmony_ciunsigned int ossl_blob_length(unsigned bitlen, int isdss, int ispub)
250e1051a39Sopenharmony_ci{
251e1051a39Sopenharmony_ci    unsigned int nbyte = (bitlen + 7) >> 3;
252e1051a39Sopenharmony_ci    unsigned int hnbyte = (bitlen + 15) >> 4;
253e1051a39Sopenharmony_ci
254e1051a39Sopenharmony_ci    if (isdss) {
255e1051a39Sopenharmony_ci
256e1051a39Sopenharmony_ci        /*
257e1051a39Sopenharmony_ci         * Expected length: 20 for q + 3 components bitlen each + 24 for seed
258e1051a39Sopenharmony_ci         * structure.
259e1051a39Sopenharmony_ci         */
260e1051a39Sopenharmony_ci        if (ispub)
261e1051a39Sopenharmony_ci            return 44 + 3 * nbyte;
262e1051a39Sopenharmony_ci        /*
263e1051a39Sopenharmony_ci         * Expected length: 20 for q, priv, 2 bitlen components + 24 for seed
264e1051a39Sopenharmony_ci         * structure.
265e1051a39Sopenharmony_ci         */
266e1051a39Sopenharmony_ci        else
267e1051a39Sopenharmony_ci            return 64 + 2 * nbyte;
268e1051a39Sopenharmony_ci    } else {
269e1051a39Sopenharmony_ci        /* Expected length: 4 for 'e' + 'n' */
270e1051a39Sopenharmony_ci        if (ispub)
271e1051a39Sopenharmony_ci            return 4 + nbyte;
272e1051a39Sopenharmony_ci        else
273e1051a39Sopenharmony_ci            /*
274e1051a39Sopenharmony_ci             * Expected length: 4 for 'e' and 7 other components. 2
275e1051a39Sopenharmony_ci             * components are bitlen size, 5 are bitlen/2
276e1051a39Sopenharmony_ci             */
277e1051a39Sopenharmony_ci            return 4 + 2 * nbyte + 5 * hnbyte;
278e1051a39Sopenharmony_ci    }
279e1051a39Sopenharmony_ci
280e1051a39Sopenharmony_ci}
281e1051a39Sopenharmony_ci
282e1051a39Sopenharmony_cistatic void *do_b2i_key(const unsigned char **in, unsigned int length,
283e1051a39Sopenharmony_ci                        int *isdss, int *ispub)
284e1051a39Sopenharmony_ci{
285e1051a39Sopenharmony_ci    const unsigned char *p = *in;
286e1051a39Sopenharmony_ci    unsigned int bitlen, magic;
287e1051a39Sopenharmony_ci    void *key = NULL;
288e1051a39Sopenharmony_ci
289e1051a39Sopenharmony_ci    if (ossl_do_blob_header(&p, length, &magic, &bitlen, isdss, ispub) <= 0) {
290e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_KEYBLOB_HEADER_PARSE_ERROR);
291e1051a39Sopenharmony_ci        return NULL;
292e1051a39Sopenharmony_ci    }
293e1051a39Sopenharmony_ci    length -= 16;
294e1051a39Sopenharmony_ci    if (length < ossl_blob_length(bitlen, *isdss, *ispub)) {
295e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT);
296e1051a39Sopenharmony_ci        return NULL;
297e1051a39Sopenharmony_ci    }
298e1051a39Sopenharmony_ci    if (!*isdss)
299e1051a39Sopenharmony_ci        key = ossl_b2i_RSA_after_header(&p, bitlen, *ispub);
300e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DSA
301e1051a39Sopenharmony_ci    else
302e1051a39Sopenharmony_ci        key = ossl_b2i_DSA_after_header(&p, bitlen, *ispub);
303e1051a39Sopenharmony_ci#endif
304e1051a39Sopenharmony_ci
305e1051a39Sopenharmony_ci    if (key == NULL) {
306e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
307e1051a39Sopenharmony_ci        return NULL;
308e1051a39Sopenharmony_ci    }
309e1051a39Sopenharmony_ci
310e1051a39Sopenharmony_ci    return key;
311e1051a39Sopenharmony_ci}
312e1051a39Sopenharmony_ci
313e1051a39Sopenharmony_ciEVP_PKEY *ossl_b2i(const unsigned char **in, unsigned int length, int *ispub)
314e1051a39Sopenharmony_ci{
315e1051a39Sopenharmony_ci    int isdss = -1;
316e1051a39Sopenharmony_ci    void *key = do_b2i_key(in, length, &isdss, ispub);
317e1051a39Sopenharmony_ci
318e1051a39Sopenharmony_ci    return evp_pkey_new0_key(key, isdss_to_evp_type(isdss));
319e1051a39Sopenharmony_ci}
320e1051a39Sopenharmony_ci
321e1051a39Sopenharmony_ciEVP_PKEY *ossl_b2i_bio(BIO *in, int *ispub)
322e1051a39Sopenharmony_ci{
323e1051a39Sopenharmony_ci    const unsigned char *p;
324e1051a39Sopenharmony_ci    unsigned char hdr_buf[16], *buf = NULL;
325e1051a39Sopenharmony_ci    unsigned int bitlen, magic, length;
326e1051a39Sopenharmony_ci    int isdss = -1;
327e1051a39Sopenharmony_ci    void *key = NULL;
328e1051a39Sopenharmony_ci    EVP_PKEY *pkey = NULL;
329e1051a39Sopenharmony_ci
330e1051a39Sopenharmony_ci    if (BIO_read(in, hdr_buf, 16) != 16) {
331e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT);
332e1051a39Sopenharmony_ci        return NULL;
333e1051a39Sopenharmony_ci    }
334e1051a39Sopenharmony_ci    p = hdr_buf;
335e1051a39Sopenharmony_ci    if (ossl_do_blob_header(&p, 16, &magic, &bitlen, &isdss, ispub) <= 0)
336e1051a39Sopenharmony_ci        return NULL;
337e1051a39Sopenharmony_ci
338e1051a39Sopenharmony_ci    length = ossl_blob_length(bitlen, isdss, *ispub);
339e1051a39Sopenharmony_ci    if (length > BLOB_MAX_LENGTH) {
340e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_HEADER_TOO_LONG);
341e1051a39Sopenharmony_ci        return NULL;
342e1051a39Sopenharmony_ci    }
343e1051a39Sopenharmony_ci    buf = OPENSSL_malloc(length);
344e1051a39Sopenharmony_ci    if (buf == NULL) {
345e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE);
346e1051a39Sopenharmony_ci        goto err;
347e1051a39Sopenharmony_ci    }
348e1051a39Sopenharmony_ci    p = buf;
349e1051a39Sopenharmony_ci    if (BIO_read(in, buf, length) != (int)length) {
350e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_KEYBLOB_TOO_SHORT);
351e1051a39Sopenharmony_ci        goto err;
352e1051a39Sopenharmony_ci    }
353e1051a39Sopenharmony_ci
354e1051a39Sopenharmony_ci    if (!isdss)
355e1051a39Sopenharmony_ci        key = ossl_b2i_RSA_after_header(&p, bitlen, *ispub);
356e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DSA
357e1051a39Sopenharmony_ci    else
358e1051a39Sopenharmony_ci        key = ossl_b2i_DSA_after_header(&p, bitlen, *ispub);
359e1051a39Sopenharmony_ci#endif
360e1051a39Sopenharmony_ci
361e1051a39Sopenharmony_ci    if (key == NULL) {
362e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_UNSUPPORTED_PUBLIC_KEY_TYPE);
363e1051a39Sopenharmony_ci        goto err;
364e1051a39Sopenharmony_ci    }
365e1051a39Sopenharmony_ci
366e1051a39Sopenharmony_ci    pkey = evp_pkey_new0_key(key, isdss_to_evp_type(isdss));
367e1051a39Sopenharmony_ci err:
368e1051a39Sopenharmony_ci    OPENSSL_free(buf);
369e1051a39Sopenharmony_ci    return pkey;
370e1051a39Sopenharmony_ci}
371e1051a39Sopenharmony_ci
372e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DSA
373e1051a39Sopenharmony_ciDSA *ossl_b2i_DSA_after_header(const unsigned char **in, unsigned int bitlen,
374e1051a39Sopenharmony_ci                               int ispub)
375e1051a39Sopenharmony_ci{
376e1051a39Sopenharmony_ci    const unsigned char *p = *in;
377e1051a39Sopenharmony_ci    DSA *dsa = NULL;
378e1051a39Sopenharmony_ci    BN_CTX *ctx = NULL;
379e1051a39Sopenharmony_ci    BIGNUM *pbn = NULL, *qbn = NULL, *gbn = NULL, *priv_key = NULL;
380e1051a39Sopenharmony_ci    BIGNUM *pub_key = NULL;
381e1051a39Sopenharmony_ci    unsigned int nbyte = (bitlen + 7) >> 3;
382e1051a39Sopenharmony_ci
383e1051a39Sopenharmony_ci    dsa = DSA_new();
384e1051a39Sopenharmony_ci    if (dsa == NULL)
385e1051a39Sopenharmony_ci        goto memerr;
386e1051a39Sopenharmony_ci    if (!read_lebn(&p, nbyte, &pbn))
387e1051a39Sopenharmony_ci        goto memerr;
388e1051a39Sopenharmony_ci
389e1051a39Sopenharmony_ci    if (!read_lebn(&p, 20, &qbn))
390e1051a39Sopenharmony_ci        goto memerr;
391e1051a39Sopenharmony_ci
392e1051a39Sopenharmony_ci    if (!read_lebn(&p, nbyte, &gbn))
393e1051a39Sopenharmony_ci        goto memerr;
394e1051a39Sopenharmony_ci
395e1051a39Sopenharmony_ci    if (ispub) {
396e1051a39Sopenharmony_ci        if (!read_lebn(&p, nbyte, &pub_key))
397e1051a39Sopenharmony_ci            goto memerr;
398e1051a39Sopenharmony_ci    } else {
399e1051a39Sopenharmony_ci        if (!read_lebn(&p, 20, &priv_key))
400e1051a39Sopenharmony_ci            goto memerr;
401e1051a39Sopenharmony_ci
402e1051a39Sopenharmony_ci        /* Set constant time flag before public key calculation */
403e1051a39Sopenharmony_ci        BN_set_flags(priv_key, BN_FLG_CONSTTIME);
404e1051a39Sopenharmony_ci
405e1051a39Sopenharmony_ci        /* Calculate public key */
406e1051a39Sopenharmony_ci        pub_key = BN_new();
407e1051a39Sopenharmony_ci        if (pub_key == NULL)
408e1051a39Sopenharmony_ci            goto memerr;
409e1051a39Sopenharmony_ci        if ((ctx = BN_CTX_new()) == NULL)
410e1051a39Sopenharmony_ci            goto memerr;
411e1051a39Sopenharmony_ci
412e1051a39Sopenharmony_ci        if (!BN_mod_exp(pub_key, gbn, priv_key, pbn, ctx))
413e1051a39Sopenharmony_ci            goto memerr;
414e1051a39Sopenharmony_ci
415e1051a39Sopenharmony_ci        BN_CTX_free(ctx);
416e1051a39Sopenharmony_ci        ctx = NULL;
417e1051a39Sopenharmony_ci    }
418e1051a39Sopenharmony_ci    if (!DSA_set0_pqg(dsa, pbn, qbn, gbn))
419e1051a39Sopenharmony_ci        goto memerr;
420e1051a39Sopenharmony_ci    pbn = qbn = gbn = NULL;
421e1051a39Sopenharmony_ci    if (!DSA_set0_key(dsa, pub_key, priv_key))
422e1051a39Sopenharmony_ci        goto memerr;
423e1051a39Sopenharmony_ci    pub_key = priv_key = NULL;
424e1051a39Sopenharmony_ci
425e1051a39Sopenharmony_ci    *in = p;
426e1051a39Sopenharmony_ci    return dsa;
427e1051a39Sopenharmony_ci
428e1051a39Sopenharmony_ci memerr:
429e1051a39Sopenharmony_ci    ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE);
430e1051a39Sopenharmony_ci    DSA_free(dsa);
431e1051a39Sopenharmony_ci    BN_free(pbn);
432e1051a39Sopenharmony_ci    BN_free(qbn);
433e1051a39Sopenharmony_ci    BN_free(gbn);
434e1051a39Sopenharmony_ci    BN_free(pub_key);
435e1051a39Sopenharmony_ci    BN_free(priv_key);
436e1051a39Sopenharmony_ci    BN_CTX_free(ctx);
437e1051a39Sopenharmony_ci    return NULL;
438e1051a39Sopenharmony_ci}
439e1051a39Sopenharmony_ci#endif
440e1051a39Sopenharmony_ci
441e1051a39Sopenharmony_ciRSA *ossl_b2i_RSA_after_header(const unsigned char **in, unsigned int bitlen,
442e1051a39Sopenharmony_ci                               int ispub)
443e1051a39Sopenharmony_ci{
444e1051a39Sopenharmony_ci    const unsigned char *pin = *in;
445e1051a39Sopenharmony_ci    BIGNUM *e = NULL, *n = NULL, *d = NULL;
446e1051a39Sopenharmony_ci    BIGNUM *p = NULL, *q = NULL, *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
447e1051a39Sopenharmony_ci    RSA *rsa = NULL;
448e1051a39Sopenharmony_ci    unsigned int nbyte = (bitlen + 7) >> 3;
449e1051a39Sopenharmony_ci    unsigned int hnbyte = (bitlen + 15) >> 4;
450e1051a39Sopenharmony_ci
451e1051a39Sopenharmony_ci    rsa = RSA_new();
452e1051a39Sopenharmony_ci    if (rsa == NULL)
453e1051a39Sopenharmony_ci        goto memerr;
454e1051a39Sopenharmony_ci    e = BN_new();
455e1051a39Sopenharmony_ci    if (e == NULL)
456e1051a39Sopenharmony_ci        goto memerr;
457e1051a39Sopenharmony_ci    if (!BN_set_word(e, read_ledword(&pin)))
458e1051a39Sopenharmony_ci        goto memerr;
459e1051a39Sopenharmony_ci    if (!read_lebn(&pin, nbyte, &n))
460e1051a39Sopenharmony_ci        goto memerr;
461e1051a39Sopenharmony_ci    if (!ispub) {
462e1051a39Sopenharmony_ci        if (!read_lebn(&pin, hnbyte, &p))
463e1051a39Sopenharmony_ci            goto memerr;
464e1051a39Sopenharmony_ci        if (!read_lebn(&pin, hnbyte, &q))
465e1051a39Sopenharmony_ci            goto memerr;
466e1051a39Sopenharmony_ci        if (!read_lebn(&pin, hnbyte, &dmp1))
467e1051a39Sopenharmony_ci            goto memerr;
468e1051a39Sopenharmony_ci        if (!read_lebn(&pin, hnbyte, &dmq1))
469e1051a39Sopenharmony_ci            goto memerr;
470e1051a39Sopenharmony_ci        if (!read_lebn(&pin, hnbyte, &iqmp))
471e1051a39Sopenharmony_ci            goto memerr;
472e1051a39Sopenharmony_ci        if (!read_lebn(&pin, nbyte, &d))
473e1051a39Sopenharmony_ci            goto memerr;
474e1051a39Sopenharmony_ci        if (!RSA_set0_factors(rsa, p, q))
475e1051a39Sopenharmony_ci            goto memerr;
476e1051a39Sopenharmony_ci        p = q = NULL;
477e1051a39Sopenharmony_ci        if (!RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp))
478e1051a39Sopenharmony_ci            goto memerr;
479e1051a39Sopenharmony_ci        dmp1 = dmq1 = iqmp = NULL;
480e1051a39Sopenharmony_ci    }
481e1051a39Sopenharmony_ci    if (!RSA_set0_key(rsa, n, e, d))
482e1051a39Sopenharmony_ci        goto memerr;
483e1051a39Sopenharmony_ci    n = e = d = NULL;
484e1051a39Sopenharmony_ci
485e1051a39Sopenharmony_ci    *in = pin;
486e1051a39Sopenharmony_ci    return rsa;
487e1051a39Sopenharmony_ci memerr:
488e1051a39Sopenharmony_ci    ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE);
489e1051a39Sopenharmony_ci    BN_free(e);
490e1051a39Sopenharmony_ci    BN_free(n);
491e1051a39Sopenharmony_ci    BN_free(p);
492e1051a39Sopenharmony_ci    BN_free(q);
493e1051a39Sopenharmony_ci    BN_free(dmp1);
494e1051a39Sopenharmony_ci    BN_free(dmq1);
495e1051a39Sopenharmony_ci    BN_free(iqmp);
496e1051a39Sopenharmony_ci    BN_free(d);
497e1051a39Sopenharmony_ci    RSA_free(rsa);
498e1051a39Sopenharmony_ci    return NULL;
499e1051a39Sopenharmony_ci}
500e1051a39Sopenharmony_ci
501e1051a39Sopenharmony_ciEVP_PKEY *b2i_PrivateKey(const unsigned char **in, long length)
502e1051a39Sopenharmony_ci{
503e1051a39Sopenharmony_ci    int ispub = 0;
504e1051a39Sopenharmony_ci
505e1051a39Sopenharmony_ci    return ossl_b2i(in, length, &ispub);
506e1051a39Sopenharmony_ci}
507e1051a39Sopenharmony_ci
508e1051a39Sopenharmony_ciEVP_PKEY *b2i_PublicKey(const unsigned char **in, long length)
509e1051a39Sopenharmony_ci{
510e1051a39Sopenharmony_ci    int ispub = 1;
511e1051a39Sopenharmony_ci
512e1051a39Sopenharmony_ci    return ossl_b2i(in, length, &ispub);
513e1051a39Sopenharmony_ci}
514e1051a39Sopenharmony_ci
515e1051a39Sopenharmony_ciEVP_PKEY *b2i_PrivateKey_bio(BIO *in)
516e1051a39Sopenharmony_ci{
517e1051a39Sopenharmony_ci    int ispub = 0;
518e1051a39Sopenharmony_ci
519e1051a39Sopenharmony_ci    return ossl_b2i_bio(in, &ispub);
520e1051a39Sopenharmony_ci}
521e1051a39Sopenharmony_ci
522e1051a39Sopenharmony_ciEVP_PKEY *b2i_PublicKey_bio(BIO *in)
523e1051a39Sopenharmony_ci{
524e1051a39Sopenharmony_ci    int ispub = 1;
525e1051a39Sopenharmony_ci
526e1051a39Sopenharmony_ci    return ossl_b2i_bio(in, &ispub);
527e1051a39Sopenharmony_ci}
528e1051a39Sopenharmony_ci
529e1051a39Sopenharmony_cistatic void write_ledword(unsigned char **out, unsigned int dw)
530e1051a39Sopenharmony_ci{
531e1051a39Sopenharmony_ci    unsigned char *p = *out;
532e1051a39Sopenharmony_ci
533e1051a39Sopenharmony_ci    *p++ = dw & 0xff;
534e1051a39Sopenharmony_ci    *p++ = (dw >> 8) & 0xff;
535e1051a39Sopenharmony_ci    *p++ = (dw >> 16) & 0xff;
536e1051a39Sopenharmony_ci    *p++ = (dw >> 24) & 0xff;
537e1051a39Sopenharmony_ci    *out = p;
538e1051a39Sopenharmony_ci}
539e1051a39Sopenharmony_ci
540e1051a39Sopenharmony_cistatic void write_lebn(unsigned char **out, const BIGNUM *bn, int len)
541e1051a39Sopenharmony_ci{
542e1051a39Sopenharmony_ci    BN_bn2lebinpad(bn, *out, len);
543e1051a39Sopenharmony_ci    *out += len;
544e1051a39Sopenharmony_ci}
545e1051a39Sopenharmony_ci
546e1051a39Sopenharmony_cistatic int check_bitlen_rsa(const RSA *rsa, int ispub, unsigned int *magic);
547e1051a39Sopenharmony_cistatic void write_rsa(unsigned char **out, const RSA *rsa, int ispub);
548e1051a39Sopenharmony_ci
549e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DSA
550e1051a39Sopenharmony_cistatic int check_bitlen_dsa(const DSA *dsa, int ispub, unsigned int *magic);
551e1051a39Sopenharmony_cistatic void write_dsa(unsigned char **out, const DSA *dsa, int ispub);
552e1051a39Sopenharmony_ci#endif
553e1051a39Sopenharmony_ci
554e1051a39Sopenharmony_cistatic int do_i2b(unsigned char **out, const EVP_PKEY *pk, int ispub)
555e1051a39Sopenharmony_ci{
556e1051a39Sopenharmony_ci    unsigned char *p;
557e1051a39Sopenharmony_ci    unsigned int bitlen = 0, magic = 0, keyalg = 0;
558e1051a39Sopenharmony_ci    int outlen = -1, noinc = 0;
559e1051a39Sopenharmony_ci
560e1051a39Sopenharmony_ci    if (EVP_PKEY_is_a(pk, "RSA")) {
561e1051a39Sopenharmony_ci        bitlen = check_bitlen_rsa(EVP_PKEY_get0_RSA(pk), ispub, &magic);
562e1051a39Sopenharmony_ci        keyalg = MS_KEYALG_RSA_KEYX;
563e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DSA
564e1051a39Sopenharmony_ci    } else if (EVP_PKEY_is_a(pk, "DSA")) {
565e1051a39Sopenharmony_ci        bitlen = check_bitlen_dsa(EVP_PKEY_get0_DSA(pk), ispub, &magic);
566e1051a39Sopenharmony_ci        keyalg = MS_KEYALG_DSS_SIGN;
567e1051a39Sopenharmony_ci#endif
568e1051a39Sopenharmony_ci    }
569e1051a39Sopenharmony_ci    if (bitlen == 0) {
570e1051a39Sopenharmony_ci        goto end;
571e1051a39Sopenharmony_ci    }
572e1051a39Sopenharmony_ci    outlen = 16
573e1051a39Sopenharmony_ci        + ossl_blob_length(bitlen, keyalg == MS_KEYALG_DSS_SIGN ? 1 : 0, ispub);
574e1051a39Sopenharmony_ci    if (out == NULL)
575e1051a39Sopenharmony_ci        goto end;
576e1051a39Sopenharmony_ci    if (*out)
577e1051a39Sopenharmony_ci        p = *out;
578e1051a39Sopenharmony_ci    else {
579e1051a39Sopenharmony_ci        if ((p = OPENSSL_malloc(outlen)) == NULL) {
580e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE);
581e1051a39Sopenharmony_ci            outlen = -1;
582e1051a39Sopenharmony_ci            goto end;
583e1051a39Sopenharmony_ci        }
584e1051a39Sopenharmony_ci        *out = p;
585e1051a39Sopenharmony_ci        noinc = 1;
586e1051a39Sopenharmony_ci    }
587e1051a39Sopenharmony_ci    if (ispub)
588e1051a39Sopenharmony_ci        *p++ = MS_PUBLICKEYBLOB;
589e1051a39Sopenharmony_ci    else
590e1051a39Sopenharmony_ci        *p++ = MS_PRIVATEKEYBLOB;
591e1051a39Sopenharmony_ci    *p++ = 0x2;
592e1051a39Sopenharmony_ci    *p++ = 0;
593e1051a39Sopenharmony_ci    *p++ = 0;
594e1051a39Sopenharmony_ci    write_ledword(&p, keyalg);
595e1051a39Sopenharmony_ci    write_ledword(&p, magic);
596e1051a39Sopenharmony_ci    write_ledword(&p, bitlen);
597e1051a39Sopenharmony_ci    if (keyalg == MS_KEYALG_RSA_KEYX)
598e1051a39Sopenharmony_ci        write_rsa(&p, EVP_PKEY_get0_RSA(pk), ispub);
599e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DSA
600e1051a39Sopenharmony_ci    else
601e1051a39Sopenharmony_ci        write_dsa(&p, EVP_PKEY_get0_DSA(pk), ispub);
602e1051a39Sopenharmony_ci#endif
603e1051a39Sopenharmony_ci    if (!noinc)
604e1051a39Sopenharmony_ci        *out += outlen;
605e1051a39Sopenharmony_ci end:
606e1051a39Sopenharmony_ci    return outlen;
607e1051a39Sopenharmony_ci}
608e1051a39Sopenharmony_ci
609e1051a39Sopenharmony_cistatic int do_i2b_bio(BIO *out, const EVP_PKEY *pk, int ispub)
610e1051a39Sopenharmony_ci{
611e1051a39Sopenharmony_ci    unsigned char *tmp = NULL;
612e1051a39Sopenharmony_ci    int outlen, wrlen;
613e1051a39Sopenharmony_ci
614e1051a39Sopenharmony_ci    outlen = do_i2b(&tmp, pk, ispub);
615e1051a39Sopenharmony_ci    if (outlen < 0)
616e1051a39Sopenharmony_ci        return -1;
617e1051a39Sopenharmony_ci    wrlen = BIO_write(out, tmp, outlen);
618e1051a39Sopenharmony_ci    OPENSSL_free(tmp);
619e1051a39Sopenharmony_ci    if (wrlen == outlen)
620e1051a39Sopenharmony_ci        return outlen;
621e1051a39Sopenharmony_ci    return -1;
622e1051a39Sopenharmony_ci}
623e1051a39Sopenharmony_ci
624e1051a39Sopenharmony_cistatic int check_bitlen_rsa(const RSA *rsa, int ispub, unsigned int *pmagic)
625e1051a39Sopenharmony_ci{
626e1051a39Sopenharmony_ci    int nbyte, hnbyte, bitlen;
627e1051a39Sopenharmony_ci    const BIGNUM *e;
628e1051a39Sopenharmony_ci
629e1051a39Sopenharmony_ci    RSA_get0_key(rsa, NULL, &e, NULL);
630e1051a39Sopenharmony_ci    if (BN_num_bits(e) > 32)
631e1051a39Sopenharmony_ci        goto badkey;
632e1051a39Sopenharmony_ci    bitlen = RSA_bits(rsa);
633e1051a39Sopenharmony_ci    nbyte = RSA_size(rsa);
634e1051a39Sopenharmony_ci    hnbyte = (bitlen + 15) >> 4;
635e1051a39Sopenharmony_ci    if (ispub) {
636e1051a39Sopenharmony_ci        *pmagic = MS_RSA1MAGIC;
637e1051a39Sopenharmony_ci        return bitlen;
638e1051a39Sopenharmony_ci    } else {
639e1051a39Sopenharmony_ci        const BIGNUM *d, *p, *q, *iqmp, *dmp1, *dmq1;
640e1051a39Sopenharmony_ci
641e1051a39Sopenharmony_ci        *pmagic = MS_RSA2MAGIC;
642e1051a39Sopenharmony_ci
643e1051a39Sopenharmony_ci        /*
644e1051a39Sopenharmony_ci         * For private key each component must fit within nbyte or hnbyte.
645e1051a39Sopenharmony_ci         */
646e1051a39Sopenharmony_ci        RSA_get0_key(rsa, NULL, NULL, &d);
647e1051a39Sopenharmony_ci        if (BN_num_bytes(d) > nbyte)
648e1051a39Sopenharmony_ci            goto badkey;
649e1051a39Sopenharmony_ci        RSA_get0_factors(rsa, &p, &q);
650e1051a39Sopenharmony_ci        RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
651e1051a39Sopenharmony_ci        if ((BN_num_bytes(iqmp) > hnbyte)
652e1051a39Sopenharmony_ci            || (BN_num_bytes(p) > hnbyte)
653e1051a39Sopenharmony_ci            || (BN_num_bytes(q) > hnbyte)
654e1051a39Sopenharmony_ci            || (BN_num_bytes(dmp1) > hnbyte)
655e1051a39Sopenharmony_ci            || (BN_num_bytes(dmq1) > hnbyte))
656e1051a39Sopenharmony_ci            goto badkey;
657e1051a39Sopenharmony_ci    }
658e1051a39Sopenharmony_ci    return bitlen;
659e1051a39Sopenharmony_ci badkey:
660e1051a39Sopenharmony_ci    ERR_raise(ERR_LIB_PEM, PEM_R_UNSUPPORTED_KEY_COMPONENTS);
661e1051a39Sopenharmony_ci    return 0;
662e1051a39Sopenharmony_ci}
663e1051a39Sopenharmony_ci
664e1051a39Sopenharmony_cistatic void write_rsa(unsigned char **out, const RSA *rsa, int ispub)
665e1051a39Sopenharmony_ci{
666e1051a39Sopenharmony_ci    int nbyte, hnbyte;
667e1051a39Sopenharmony_ci    const BIGNUM *n, *d, *e, *p, *q, *iqmp, *dmp1, *dmq1;
668e1051a39Sopenharmony_ci
669e1051a39Sopenharmony_ci    nbyte = RSA_size(rsa);
670e1051a39Sopenharmony_ci    hnbyte = (RSA_bits(rsa) + 15) >> 4;
671e1051a39Sopenharmony_ci    RSA_get0_key(rsa, &n, &e, &d);
672e1051a39Sopenharmony_ci    write_lebn(out, e, 4);
673e1051a39Sopenharmony_ci    write_lebn(out, n, nbyte);
674e1051a39Sopenharmony_ci    if (ispub)
675e1051a39Sopenharmony_ci        return;
676e1051a39Sopenharmony_ci    RSA_get0_factors(rsa, &p, &q);
677e1051a39Sopenharmony_ci    RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
678e1051a39Sopenharmony_ci    write_lebn(out, p, hnbyte);
679e1051a39Sopenharmony_ci    write_lebn(out, q, hnbyte);
680e1051a39Sopenharmony_ci    write_lebn(out, dmp1, hnbyte);
681e1051a39Sopenharmony_ci    write_lebn(out, dmq1, hnbyte);
682e1051a39Sopenharmony_ci    write_lebn(out, iqmp, hnbyte);
683e1051a39Sopenharmony_ci    write_lebn(out, d, nbyte);
684e1051a39Sopenharmony_ci}
685e1051a39Sopenharmony_ci
686e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DSA
687e1051a39Sopenharmony_cistatic int check_bitlen_dsa(const DSA *dsa, int ispub, unsigned int *pmagic)
688e1051a39Sopenharmony_ci{
689e1051a39Sopenharmony_ci    int bitlen;
690e1051a39Sopenharmony_ci    const BIGNUM *p = NULL, *q = NULL, *g = NULL;
691e1051a39Sopenharmony_ci    const BIGNUM *pub_key = NULL, *priv_key = NULL;
692e1051a39Sopenharmony_ci
693e1051a39Sopenharmony_ci    DSA_get0_pqg(dsa, &p, &q, &g);
694e1051a39Sopenharmony_ci    DSA_get0_key(dsa, &pub_key, &priv_key);
695e1051a39Sopenharmony_ci    bitlen = BN_num_bits(p);
696e1051a39Sopenharmony_ci    if ((bitlen & 7) || (BN_num_bits(q) != 160)
697e1051a39Sopenharmony_ci        || (BN_num_bits(g) > bitlen))
698e1051a39Sopenharmony_ci        goto badkey;
699e1051a39Sopenharmony_ci    if (ispub) {
700e1051a39Sopenharmony_ci        if (BN_num_bits(pub_key) > bitlen)
701e1051a39Sopenharmony_ci            goto badkey;
702e1051a39Sopenharmony_ci        *pmagic = MS_DSS1MAGIC;
703e1051a39Sopenharmony_ci    } else {
704e1051a39Sopenharmony_ci        if (BN_num_bits(priv_key) > 160)
705e1051a39Sopenharmony_ci            goto badkey;
706e1051a39Sopenharmony_ci        *pmagic = MS_DSS2MAGIC;
707e1051a39Sopenharmony_ci    }
708e1051a39Sopenharmony_ci
709e1051a39Sopenharmony_ci    return bitlen;
710e1051a39Sopenharmony_ci badkey:
711e1051a39Sopenharmony_ci    ERR_raise(ERR_LIB_PEM, PEM_R_UNSUPPORTED_KEY_COMPONENTS);
712e1051a39Sopenharmony_ci    return 0;
713e1051a39Sopenharmony_ci}
714e1051a39Sopenharmony_ci
715e1051a39Sopenharmony_cistatic void write_dsa(unsigned char **out, const DSA *dsa, int ispub)
716e1051a39Sopenharmony_ci{
717e1051a39Sopenharmony_ci    int nbyte;
718e1051a39Sopenharmony_ci    const BIGNUM *p = NULL, *q = NULL, *g = NULL;
719e1051a39Sopenharmony_ci    const BIGNUM *pub_key = NULL, *priv_key = NULL;
720e1051a39Sopenharmony_ci
721e1051a39Sopenharmony_ci    DSA_get0_pqg(dsa, &p, &q, &g);
722e1051a39Sopenharmony_ci    DSA_get0_key(dsa, &pub_key, &priv_key);
723e1051a39Sopenharmony_ci    nbyte = BN_num_bytes(p);
724e1051a39Sopenharmony_ci    write_lebn(out, p, nbyte);
725e1051a39Sopenharmony_ci    write_lebn(out, q, 20);
726e1051a39Sopenharmony_ci    write_lebn(out, g, nbyte);
727e1051a39Sopenharmony_ci    if (ispub)
728e1051a39Sopenharmony_ci        write_lebn(out, pub_key, nbyte);
729e1051a39Sopenharmony_ci    else
730e1051a39Sopenharmony_ci        write_lebn(out, priv_key, 20);
731e1051a39Sopenharmony_ci    /* Set "invalid" for seed structure values */
732e1051a39Sopenharmony_ci    memset(*out, 0xff, 24);
733e1051a39Sopenharmony_ci    *out += 24;
734e1051a39Sopenharmony_ci    return;
735e1051a39Sopenharmony_ci}
736e1051a39Sopenharmony_ci#endif
737e1051a39Sopenharmony_ci
738e1051a39Sopenharmony_ciint i2b_PrivateKey_bio(BIO *out, const EVP_PKEY *pk)
739e1051a39Sopenharmony_ci{
740e1051a39Sopenharmony_ci    return do_i2b_bio(out, pk, 0);
741e1051a39Sopenharmony_ci}
742e1051a39Sopenharmony_ci
743e1051a39Sopenharmony_ciint i2b_PublicKey_bio(BIO *out, const EVP_PKEY *pk)
744e1051a39Sopenharmony_ci{
745e1051a39Sopenharmony_ci    return do_i2b_bio(out, pk, 1);
746e1051a39Sopenharmony_ci}
747e1051a39Sopenharmony_ci
748e1051a39Sopenharmony_ciint ossl_do_PVK_header(const unsigned char **in, unsigned int length,
749e1051a39Sopenharmony_ci                       int skip_magic,
750e1051a39Sopenharmony_ci                       unsigned int *psaltlen, unsigned int *pkeylen)
751e1051a39Sopenharmony_ci{
752e1051a39Sopenharmony_ci    const unsigned char *p = *in;
753e1051a39Sopenharmony_ci    unsigned int pvk_magic, is_encrypted;
754e1051a39Sopenharmony_ci
755e1051a39Sopenharmony_ci    if (skip_magic) {
756e1051a39Sopenharmony_ci        if (length < 20) {
757e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, PEM_R_PVK_TOO_SHORT);
758e1051a39Sopenharmony_ci            return 0;
759e1051a39Sopenharmony_ci        }
760e1051a39Sopenharmony_ci    } else {
761e1051a39Sopenharmony_ci        if (length < 24) {
762e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, PEM_R_PVK_TOO_SHORT);
763e1051a39Sopenharmony_ci            return 0;
764e1051a39Sopenharmony_ci        }
765e1051a39Sopenharmony_ci        pvk_magic = read_ledword(&p);
766e1051a39Sopenharmony_ci        if (pvk_magic != MS_PVKMAGIC) {
767e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, PEM_R_BAD_MAGIC_NUMBER);
768e1051a39Sopenharmony_ci            return 0;
769e1051a39Sopenharmony_ci        }
770e1051a39Sopenharmony_ci    }
771e1051a39Sopenharmony_ci    /* Skip reserved */
772e1051a39Sopenharmony_ci    p += 4;
773e1051a39Sopenharmony_ci    /*
774e1051a39Sopenharmony_ci     * keytype =
775e1051a39Sopenharmony_ci     */ read_ledword(&p);
776e1051a39Sopenharmony_ci    is_encrypted = read_ledword(&p);
777e1051a39Sopenharmony_ci    *psaltlen = read_ledword(&p);
778e1051a39Sopenharmony_ci    *pkeylen = read_ledword(&p);
779e1051a39Sopenharmony_ci
780e1051a39Sopenharmony_ci    if (*pkeylen > PVK_MAX_KEYLEN || *psaltlen > PVK_MAX_SALTLEN)
781e1051a39Sopenharmony_ci        return 0;
782e1051a39Sopenharmony_ci
783e1051a39Sopenharmony_ci    if (is_encrypted && *psaltlen == 0) {
784e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_INCONSISTENT_HEADER);
785e1051a39Sopenharmony_ci        return 0;
786e1051a39Sopenharmony_ci    }
787e1051a39Sopenharmony_ci
788e1051a39Sopenharmony_ci    *in = p;
789e1051a39Sopenharmony_ci    return 1;
790e1051a39Sopenharmony_ci}
791e1051a39Sopenharmony_ci
792e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_RC4
793e1051a39Sopenharmony_cistatic int derive_pvk_key(unsigned char *key,
794e1051a39Sopenharmony_ci                          const unsigned char *salt, unsigned int saltlen,
795e1051a39Sopenharmony_ci                          const unsigned char *pass, int passlen,
796e1051a39Sopenharmony_ci                          OSSL_LIB_CTX *libctx, const char *propq)
797e1051a39Sopenharmony_ci{
798e1051a39Sopenharmony_ci    EVP_MD_CTX *mctx = EVP_MD_CTX_new();
799e1051a39Sopenharmony_ci    int rv = 0;
800e1051a39Sopenharmony_ci    EVP_MD *sha1 = NULL;
801e1051a39Sopenharmony_ci
802e1051a39Sopenharmony_ci    if ((sha1 = EVP_MD_fetch(libctx, SN_sha1, propq)) == NULL)
803e1051a39Sopenharmony_ci        goto err;
804e1051a39Sopenharmony_ci
805e1051a39Sopenharmony_ci    if (mctx == NULL
806e1051a39Sopenharmony_ci        || !EVP_DigestInit_ex(mctx, sha1, NULL)
807e1051a39Sopenharmony_ci        || !EVP_DigestUpdate(mctx, salt, saltlen)
808e1051a39Sopenharmony_ci        || !EVP_DigestUpdate(mctx, pass, passlen)
809e1051a39Sopenharmony_ci        || !EVP_DigestFinal_ex(mctx, key, NULL))
810e1051a39Sopenharmony_ci        goto err;
811e1051a39Sopenharmony_ci
812e1051a39Sopenharmony_ci    rv = 1;
813e1051a39Sopenharmony_cierr:
814e1051a39Sopenharmony_ci    EVP_MD_CTX_free(mctx);
815e1051a39Sopenharmony_ci    EVP_MD_free(sha1);
816e1051a39Sopenharmony_ci    return rv;
817e1051a39Sopenharmony_ci}
818e1051a39Sopenharmony_ci#endif
819e1051a39Sopenharmony_ci
820e1051a39Sopenharmony_cistatic void *do_PVK_body_key(const unsigned char **in,
821e1051a39Sopenharmony_ci                             unsigned int saltlen, unsigned int keylen,
822e1051a39Sopenharmony_ci                             pem_password_cb *cb, void *u,
823e1051a39Sopenharmony_ci                             int *isdss, int *ispub,
824e1051a39Sopenharmony_ci                             OSSL_LIB_CTX *libctx, const char *propq)
825e1051a39Sopenharmony_ci{
826e1051a39Sopenharmony_ci    const unsigned char *p = *in;
827e1051a39Sopenharmony_ci    unsigned char *enctmp = NULL;
828e1051a39Sopenharmony_ci    unsigned char keybuf[20];
829e1051a39Sopenharmony_ci    void *key = NULL;
830e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_RC4
831e1051a39Sopenharmony_ci    EVP_CIPHER *rc4 = NULL;
832e1051a39Sopenharmony_ci#endif
833e1051a39Sopenharmony_ci    EVP_CIPHER_CTX *cctx = EVP_CIPHER_CTX_new();
834e1051a39Sopenharmony_ci
835e1051a39Sopenharmony_ci    if (cctx == NULL) {
836e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE);
837e1051a39Sopenharmony_ci        goto err;
838e1051a39Sopenharmony_ci    }
839e1051a39Sopenharmony_ci
840e1051a39Sopenharmony_ci    if (saltlen) {
841e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_RC4
842e1051a39Sopenharmony_ci        unsigned int magic;
843e1051a39Sopenharmony_ci        char psbuf[PEM_BUFSIZE];
844e1051a39Sopenharmony_ci        int enctmplen, inlen;
845e1051a39Sopenharmony_ci        unsigned char *q;
846e1051a39Sopenharmony_ci
847e1051a39Sopenharmony_ci        if (cb)
848e1051a39Sopenharmony_ci            inlen = cb(psbuf, PEM_BUFSIZE, 0, u);
849e1051a39Sopenharmony_ci        else
850e1051a39Sopenharmony_ci            inlen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u);
851e1051a39Sopenharmony_ci        if (inlen < 0) {
852e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ);
853e1051a39Sopenharmony_ci            goto err;
854e1051a39Sopenharmony_ci        }
855e1051a39Sopenharmony_ci        enctmp = OPENSSL_malloc(keylen + 8);
856e1051a39Sopenharmony_ci        if (enctmp == NULL) {
857e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE);
858e1051a39Sopenharmony_ci            goto err;
859e1051a39Sopenharmony_ci        }
860e1051a39Sopenharmony_ci        if (!derive_pvk_key(keybuf, p, saltlen,
861e1051a39Sopenharmony_ci                            (unsigned char *)psbuf, inlen, libctx, propq))
862e1051a39Sopenharmony_ci            goto err;
863e1051a39Sopenharmony_ci        p += saltlen;
864e1051a39Sopenharmony_ci        /* Copy BLOBHEADER across, decrypt rest */
865e1051a39Sopenharmony_ci        memcpy(enctmp, p, 8);
866e1051a39Sopenharmony_ci        p += 8;
867e1051a39Sopenharmony_ci        if (keylen < 8) {
868e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, PEM_R_PVK_TOO_SHORT);
869e1051a39Sopenharmony_ci            goto err;
870e1051a39Sopenharmony_ci        }
871e1051a39Sopenharmony_ci        inlen = keylen - 8;
872e1051a39Sopenharmony_ci        q = enctmp + 8;
873e1051a39Sopenharmony_ci        if ((rc4 = EVP_CIPHER_fetch(libctx, "RC4", propq)) == NULL)
874e1051a39Sopenharmony_ci            goto err;
875e1051a39Sopenharmony_ci        if (!EVP_DecryptInit_ex(cctx, rc4, NULL, keybuf, NULL))
876e1051a39Sopenharmony_ci            goto err;
877e1051a39Sopenharmony_ci        if (!EVP_DecryptUpdate(cctx, q, &enctmplen, p, inlen))
878e1051a39Sopenharmony_ci            goto err;
879e1051a39Sopenharmony_ci        if (!EVP_DecryptFinal_ex(cctx, q + enctmplen, &enctmplen))
880e1051a39Sopenharmony_ci            goto err;
881e1051a39Sopenharmony_ci        magic = read_ledword((const unsigned char **)&q);
882e1051a39Sopenharmony_ci        if (magic != MS_RSA2MAGIC && magic != MS_DSS2MAGIC) {
883e1051a39Sopenharmony_ci            q = enctmp + 8;
884e1051a39Sopenharmony_ci            memset(keybuf + 5, 0, 11);
885e1051a39Sopenharmony_ci            if (!EVP_DecryptInit_ex(cctx, rc4, NULL, keybuf, NULL))
886e1051a39Sopenharmony_ci                goto err;
887e1051a39Sopenharmony_ci            if (!EVP_DecryptUpdate(cctx, q, &enctmplen, p, inlen))
888e1051a39Sopenharmony_ci                goto err;
889e1051a39Sopenharmony_ci            if (!EVP_DecryptFinal_ex(cctx, q + enctmplen, &enctmplen))
890e1051a39Sopenharmony_ci                goto err;
891e1051a39Sopenharmony_ci            magic = read_ledword((const unsigned char **)&q);
892e1051a39Sopenharmony_ci            if (magic != MS_RSA2MAGIC && magic != MS_DSS2MAGIC) {
893e1051a39Sopenharmony_ci                ERR_raise(ERR_LIB_PEM, PEM_R_BAD_DECRYPT);
894e1051a39Sopenharmony_ci                goto err;
895e1051a39Sopenharmony_ci            }
896e1051a39Sopenharmony_ci        }
897e1051a39Sopenharmony_ci        p = enctmp;
898e1051a39Sopenharmony_ci#else
899e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_UNSUPPORTED_CIPHER);
900e1051a39Sopenharmony_ci        goto err;
901e1051a39Sopenharmony_ci#endif
902e1051a39Sopenharmony_ci    }
903e1051a39Sopenharmony_ci
904e1051a39Sopenharmony_ci    key = do_b2i_key(&p, keylen, isdss, ispub);
905e1051a39Sopenharmony_ci err:
906e1051a39Sopenharmony_ci    EVP_CIPHER_CTX_free(cctx);
907e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_RC4
908e1051a39Sopenharmony_ci    EVP_CIPHER_free(rc4);
909e1051a39Sopenharmony_ci#endif
910e1051a39Sopenharmony_ci    if (enctmp != NULL) {
911e1051a39Sopenharmony_ci        OPENSSL_cleanse(keybuf, sizeof(keybuf));
912e1051a39Sopenharmony_ci        OPENSSL_free(enctmp);
913e1051a39Sopenharmony_ci    }
914e1051a39Sopenharmony_ci    return key;
915e1051a39Sopenharmony_ci}
916e1051a39Sopenharmony_ci
917e1051a39Sopenharmony_cistatic void *do_PVK_key_bio(BIO *in, pem_password_cb *cb, void *u,
918e1051a39Sopenharmony_ci                            int *isdss, int *ispub,
919e1051a39Sopenharmony_ci                            OSSL_LIB_CTX *libctx, const char *propq)
920e1051a39Sopenharmony_ci{
921e1051a39Sopenharmony_ci    unsigned char pvk_hdr[24], *buf = NULL;
922e1051a39Sopenharmony_ci    const unsigned char *p;
923e1051a39Sopenharmony_ci    int buflen;
924e1051a39Sopenharmony_ci    void *key = NULL;
925e1051a39Sopenharmony_ci    unsigned int saltlen, keylen;
926e1051a39Sopenharmony_ci
927e1051a39Sopenharmony_ci    if (BIO_read(in, pvk_hdr, 24) != 24) {
928e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_PVK_DATA_TOO_SHORT);
929e1051a39Sopenharmony_ci        return NULL;
930e1051a39Sopenharmony_ci    }
931e1051a39Sopenharmony_ci    p = pvk_hdr;
932e1051a39Sopenharmony_ci
933e1051a39Sopenharmony_ci    if (!ossl_do_PVK_header(&p, 24, 0, &saltlen, &keylen))
934e1051a39Sopenharmony_ci        return 0;
935e1051a39Sopenharmony_ci    buflen = (int)keylen + saltlen;
936e1051a39Sopenharmony_ci    buf = OPENSSL_malloc(buflen);
937e1051a39Sopenharmony_ci    if (buf == NULL) {
938e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE);
939e1051a39Sopenharmony_ci        return 0;
940e1051a39Sopenharmony_ci    }
941e1051a39Sopenharmony_ci    p = buf;
942e1051a39Sopenharmony_ci    if (BIO_read(in, buf, buflen) != buflen) {
943e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_PVK_DATA_TOO_SHORT);
944e1051a39Sopenharmony_ci        goto err;
945e1051a39Sopenharmony_ci    }
946e1051a39Sopenharmony_ci    key = do_PVK_body_key(&p, saltlen, keylen, cb, u, isdss, ispub, libctx, propq);
947e1051a39Sopenharmony_ci
948e1051a39Sopenharmony_ci err:
949e1051a39Sopenharmony_ci    OPENSSL_clear_free(buf, buflen);
950e1051a39Sopenharmony_ci    return key;
951e1051a39Sopenharmony_ci}
952e1051a39Sopenharmony_ci
953e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DSA
954e1051a39Sopenharmony_ciDSA *b2i_DSA_PVK_bio_ex(BIO *in, pem_password_cb *cb, void *u,
955e1051a39Sopenharmony_ci                        OSSL_LIB_CTX *libctx, const char *propq)
956e1051a39Sopenharmony_ci{
957e1051a39Sopenharmony_ci    int isdss = 1;
958e1051a39Sopenharmony_ci    int ispub = 0;               /* PVK keys are always private */
959e1051a39Sopenharmony_ci
960e1051a39Sopenharmony_ci    return do_PVK_key_bio(in, cb, u, &isdss, &ispub, libctx, propq);
961e1051a39Sopenharmony_ci}
962e1051a39Sopenharmony_ci
963e1051a39Sopenharmony_ciDSA *b2i_DSA_PVK_bio(BIO *in, pem_password_cb *cb, void *u)
964e1051a39Sopenharmony_ci{
965e1051a39Sopenharmony_ci    return b2i_DSA_PVK_bio_ex(in, cb, u, NULL, NULL);
966e1051a39Sopenharmony_ci}
967e1051a39Sopenharmony_ci#endif
968e1051a39Sopenharmony_ci
969e1051a39Sopenharmony_ciRSA *b2i_RSA_PVK_bio_ex(BIO *in, pem_password_cb *cb, void *u,
970e1051a39Sopenharmony_ci                        OSSL_LIB_CTX *libctx, const char *propq)
971e1051a39Sopenharmony_ci{
972e1051a39Sopenharmony_ci    int isdss = 0;
973e1051a39Sopenharmony_ci    int ispub = 0;               /* PVK keys are always private */
974e1051a39Sopenharmony_ci
975e1051a39Sopenharmony_ci    return do_PVK_key_bio(in, cb, u, &isdss, &ispub, libctx, propq);
976e1051a39Sopenharmony_ci}
977e1051a39Sopenharmony_ci
978e1051a39Sopenharmony_ciRSA *b2i_RSA_PVK_bio(BIO *in, pem_password_cb *cb, void *u)
979e1051a39Sopenharmony_ci{
980e1051a39Sopenharmony_ci    return b2i_RSA_PVK_bio_ex(in, cb, u, NULL, NULL);
981e1051a39Sopenharmony_ci}
982e1051a39Sopenharmony_ci
983e1051a39Sopenharmony_ciEVP_PKEY *b2i_PVK_bio_ex(BIO *in, pem_password_cb *cb, void *u,
984e1051a39Sopenharmony_ci                         OSSL_LIB_CTX *libctx, const char *propq)
985e1051a39Sopenharmony_ci{
986e1051a39Sopenharmony_ci    int isdss = -1;
987e1051a39Sopenharmony_ci    int ispub = -1;
988e1051a39Sopenharmony_ci    void *key = do_PVK_key_bio(in, cb, u, &isdss, &ispub, NULL, NULL);
989e1051a39Sopenharmony_ci
990e1051a39Sopenharmony_ci    return evp_pkey_new0_key(key, isdss_to_evp_type(isdss));
991e1051a39Sopenharmony_ci}
992e1051a39Sopenharmony_ci
993e1051a39Sopenharmony_ciEVP_PKEY *b2i_PVK_bio(BIO *in, pem_password_cb *cb, void *u)
994e1051a39Sopenharmony_ci{
995e1051a39Sopenharmony_ci    return b2i_PVK_bio_ex(in, cb, u, NULL, NULL);
996e1051a39Sopenharmony_ci}
997e1051a39Sopenharmony_ci
998e1051a39Sopenharmony_cistatic int i2b_PVK(unsigned char **out, const EVP_PKEY *pk, int enclevel,
999e1051a39Sopenharmony_ci                   pem_password_cb *cb, void *u, OSSL_LIB_CTX *libctx,
1000e1051a39Sopenharmony_ci                   const char *propq)
1001e1051a39Sopenharmony_ci{
1002e1051a39Sopenharmony_ci    int ret = -1;
1003e1051a39Sopenharmony_ci    int outlen = 24, pklen;
1004e1051a39Sopenharmony_ci    unsigned char *p = NULL, *start = NULL;
1005e1051a39Sopenharmony_ci    EVP_CIPHER_CTX *cctx = NULL;
1006e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_RC4
1007e1051a39Sopenharmony_ci    unsigned char *salt = NULL;
1008e1051a39Sopenharmony_ci    EVP_CIPHER *rc4 = NULL;
1009e1051a39Sopenharmony_ci#endif
1010e1051a39Sopenharmony_ci
1011e1051a39Sopenharmony_ci    if (enclevel)
1012e1051a39Sopenharmony_ci        outlen += PVK_SALTLEN;
1013e1051a39Sopenharmony_ci    pklen = do_i2b(NULL, pk, 0);
1014e1051a39Sopenharmony_ci    if (pklen < 0)
1015e1051a39Sopenharmony_ci        return -1;
1016e1051a39Sopenharmony_ci    outlen += pklen;
1017e1051a39Sopenharmony_ci    if (out == NULL)
1018e1051a39Sopenharmony_ci        return outlen;
1019e1051a39Sopenharmony_ci    if (*out != NULL) {
1020e1051a39Sopenharmony_ci        p = *out;
1021e1051a39Sopenharmony_ci    } else {
1022e1051a39Sopenharmony_ci        start = p = OPENSSL_malloc(outlen);
1023e1051a39Sopenharmony_ci        if (p == NULL) {
1024e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, ERR_R_MALLOC_FAILURE);
1025e1051a39Sopenharmony_ci            return -1;
1026e1051a39Sopenharmony_ci        }
1027e1051a39Sopenharmony_ci    }
1028e1051a39Sopenharmony_ci
1029e1051a39Sopenharmony_ci    cctx = EVP_CIPHER_CTX_new();
1030e1051a39Sopenharmony_ci    if (cctx == NULL)
1031e1051a39Sopenharmony_ci        goto error;
1032e1051a39Sopenharmony_ci
1033e1051a39Sopenharmony_ci    write_ledword(&p, MS_PVKMAGIC);
1034e1051a39Sopenharmony_ci    write_ledword(&p, 0);
1035e1051a39Sopenharmony_ci    if (EVP_PKEY_get_id(pk) == EVP_PKEY_RSA)
1036e1051a39Sopenharmony_ci        write_ledword(&p, MS_KEYTYPE_KEYX);
1037e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_DSA
1038e1051a39Sopenharmony_ci    else
1039e1051a39Sopenharmony_ci        write_ledword(&p, MS_KEYTYPE_SIGN);
1040e1051a39Sopenharmony_ci#endif
1041e1051a39Sopenharmony_ci    write_ledword(&p, enclevel ? 1 : 0);
1042e1051a39Sopenharmony_ci    write_ledword(&p, enclevel ? PVK_SALTLEN : 0);
1043e1051a39Sopenharmony_ci    write_ledword(&p, pklen);
1044e1051a39Sopenharmony_ci    if (enclevel) {
1045e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_RC4
1046e1051a39Sopenharmony_ci        if (RAND_bytes_ex(libctx, p, PVK_SALTLEN, 0) <= 0)
1047e1051a39Sopenharmony_ci            goto error;
1048e1051a39Sopenharmony_ci        salt = p;
1049e1051a39Sopenharmony_ci        p += PVK_SALTLEN;
1050e1051a39Sopenharmony_ci#endif
1051e1051a39Sopenharmony_ci    }
1052e1051a39Sopenharmony_ci    do_i2b(&p, pk, 0);
1053e1051a39Sopenharmony_ci    if (enclevel != 0) {
1054e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_RC4
1055e1051a39Sopenharmony_ci        char psbuf[PEM_BUFSIZE];
1056e1051a39Sopenharmony_ci        unsigned char keybuf[20];
1057e1051a39Sopenharmony_ci        int enctmplen, inlen;
1058e1051a39Sopenharmony_ci        if (cb)
1059e1051a39Sopenharmony_ci            inlen = cb(psbuf, PEM_BUFSIZE, 1, u);
1060e1051a39Sopenharmony_ci        else
1061e1051a39Sopenharmony_ci            inlen = PEM_def_callback(psbuf, PEM_BUFSIZE, 1, u);
1062e1051a39Sopenharmony_ci        if (inlen <= 0) {
1063e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ);
1064e1051a39Sopenharmony_ci            goto error;
1065e1051a39Sopenharmony_ci        }
1066e1051a39Sopenharmony_ci        if (!derive_pvk_key(keybuf, salt, PVK_SALTLEN,
1067e1051a39Sopenharmony_ci                            (unsigned char *)psbuf, inlen, libctx, propq))
1068e1051a39Sopenharmony_ci            goto error;
1069e1051a39Sopenharmony_ci        if ((rc4 = EVP_CIPHER_fetch(libctx, "RC4", propq)) == NULL)
1070e1051a39Sopenharmony_ci            goto error;
1071e1051a39Sopenharmony_ci        if (enclevel == 1)
1072e1051a39Sopenharmony_ci            memset(keybuf + 5, 0, 11);
1073e1051a39Sopenharmony_ci        p = salt + PVK_SALTLEN + 8;
1074e1051a39Sopenharmony_ci        if (!EVP_EncryptInit_ex(cctx, rc4, NULL, keybuf, NULL))
1075e1051a39Sopenharmony_ci            goto error;
1076e1051a39Sopenharmony_ci        OPENSSL_cleanse(keybuf, 20);
1077e1051a39Sopenharmony_ci        if (!EVP_EncryptUpdate(cctx, p, &enctmplen, p, pklen - 8))
1078e1051a39Sopenharmony_ci            goto error;
1079e1051a39Sopenharmony_ci        if (!EVP_EncryptFinal_ex(cctx, p + enctmplen, &enctmplen))
1080e1051a39Sopenharmony_ci            goto error;
1081e1051a39Sopenharmony_ci#else
1082e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_PEM, PEM_R_UNSUPPORTED_CIPHER);
1083e1051a39Sopenharmony_ci        goto error;
1084e1051a39Sopenharmony_ci#endif
1085e1051a39Sopenharmony_ci    }
1086e1051a39Sopenharmony_ci
1087e1051a39Sopenharmony_ci    if (*out == NULL)
1088e1051a39Sopenharmony_ci        *out = start;
1089e1051a39Sopenharmony_ci    ret = outlen;
1090e1051a39Sopenharmony_ci error:
1091e1051a39Sopenharmony_ci    EVP_CIPHER_CTX_free(cctx);
1092e1051a39Sopenharmony_ci#ifndef OPENSSL_NO_RC4
1093e1051a39Sopenharmony_ci    EVP_CIPHER_free(rc4);
1094e1051a39Sopenharmony_ci#endif
1095e1051a39Sopenharmony_ci    if (*out == NULL)
1096e1051a39Sopenharmony_ci        OPENSSL_free(start);
1097e1051a39Sopenharmony_ci
1098e1051a39Sopenharmony_ci    return ret;
1099e1051a39Sopenharmony_ci}
1100e1051a39Sopenharmony_ci
1101e1051a39Sopenharmony_ciint i2b_PVK_bio_ex(BIO *out, const EVP_PKEY *pk, int enclevel,
1102e1051a39Sopenharmony_ci                   pem_password_cb *cb, void *u, OSSL_LIB_CTX *libctx,
1103e1051a39Sopenharmony_ci                   const char *propq)
1104e1051a39Sopenharmony_ci{
1105e1051a39Sopenharmony_ci    unsigned char *tmp = NULL;
1106e1051a39Sopenharmony_ci    int outlen, wrlen;
1107e1051a39Sopenharmony_ci
1108e1051a39Sopenharmony_ci    outlen = i2b_PVK(&tmp, pk, enclevel, cb, u, libctx, propq);
1109e1051a39Sopenharmony_ci    if (outlen < 0)
1110e1051a39Sopenharmony_ci        return -1;
1111e1051a39Sopenharmony_ci    wrlen = BIO_write(out, tmp, outlen);
1112e1051a39Sopenharmony_ci    OPENSSL_free(tmp);
1113e1051a39Sopenharmony_ci    if (wrlen == outlen) {
1114e1051a39Sopenharmony_ci        return outlen;
1115e1051a39Sopenharmony_ci    }
1116e1051a39Sopenharmony_ci    ERR_raise(ERR_LIB_PEM, PEM_R_BIO_WRITE_FAILURE);
1117e1051a39Sopenharmony_ci    return -1;
1118e1051a39Sopenharmony_ci}
1119e1051a39Sopenharmony_ci
1120e1051a39Sopenharmony_ciint i2b_PVK_bio(BIO *out, const EVP_PKEY *pk, int enclevel,
1121e1051a39Sopenharmony_ci                pem_password_cb *cb, void *u)
1122e1051a39Sopenharmony_ci{
1123e1051a39Sopenharmony_ci    return i2b_PVK_bio_ex(out, pk, enclevel, cb, u, NULL, NULL);
1124e1051a39Sopenharmony_ci}
1125e1051a39Sopenharmony_ci
1126