155714Skris/* crypto/pem/pem_lib.c */
255714Skris/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
355714Skris * All rights reserved.
455714Skris *
555714Skris * This package is an SSL implementation written
655714Skris * by Eric Young (eay@cryptsoft.com).
755714Skris * The implementation was written so as to conform with Netscapes SSL.
8296465Sdelphij *
955714Skris * This library is free for commercial and non-commercial use as long as
1055714Skris * the following conditions are aheared to.  The following conditions
1155714Skris * apply to all code found in this distribution, be it the RC4, RSA,
1255714Skris * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
1355714Skris * included with this distribution is covered by the same copyright terms
1455714Skris * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15296465Sdelphij *
1655714Skris * Copyright remains Eric Young's, and as such any Copyright notices in
1755714Skris * the code are not to be removed.
1855714Skris * If this package is used in a product, Eric Young should be given attribution
1955714Skris * as the author of the parts of the library used.
2055714Skris * This can be in the form of a textual message at program startup or
2155714Skris * in documentation (online or textual) provided with the package.
22296465Sdelphij *
2355714Skris * Redistribution and use in source and binary forms, with or without
2455714Skris * modification, are permitted provided that the following conditions
2555714Skris * are met:
2655714Skris * 1. Redistributions of source code must retain the copyright
2755714Skris *    notice, this list of conditions and the following disclaimer.
2855714Skris * 2. Redistributions in binary form must reproduce the above copyright
2955714Skris *    notice, this list of conditions and the following disclaimer in the
3055714Skris *    documentation and/or other materials provided with the distribution.
3155714Skris * 3. All advertising materials mentioning features or use of this software
3255714Skris *    must display the following acknowledgement:
3355714Skris *    "This product includes cryptographic software written by
3455714Skris *     Eric Young (eay@cryptsoft.com)"
3555714Skris *    The word 'cryptographic' can be left out if the rouines from the library
3655714Skris *    being used are not cryptographic related :-).
37296465Sdelphij * 4. If you include any Windows specific code (or a derivative thereof) from
3855714Skris *    the apps directory (application code) you must include an acknowledgement:
3955714Skris *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40296465Sdelphij *
4155714Skris * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
4255714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4355714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
4455714Skris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
4555714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
4655714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
4755714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4855714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
4955714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5055714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5155714Skris * SUCH DAMAGE.
52296465Sdelphij *
5355714Skris * The licence and distribution terms for any publically available version or
5455714Skris * derivative of this code cannot be changed.  i.e. this code cannot simply be
5555714Skris * copied and put under another distribution licence
5655714Skris * [including the GNU Public Licence.]
5755714Skris */
5855714Skris
5955714Skris#include <stdio.h>
6055714Skris#include "cryptlib.h"
6155714Skris#include <openssl/buffer.h>
6255714Skris#include <openssl/objects.h>
6355714Skris#include <openssl/evp.h>
6455714Skris#include <openssl/rand.h>
6555714Skris#include <openssl/x509.h>
6655714Skris#include <openssl/pem.h>
6755714Skris#include <openssl/pkcs12.h>
68109998Smarkm#ifndef OPENSSL_NO_DES
69296465Sdelphij# include <openssl/des.h>
7055714Skris#endif
7155714Skris
72296465Sdelphijconst char PEM_version[] = "PEM" OPENSSL_VERSION_PTEXT;
7355714Skris
74296465Sdelphij#define MIN_LENGTH      4
7555714Skris
76296465Sdelphijstatic int load_iv(char **fromp, unsigned char *to, int num);
7759191Skrisstatic int check_pem(const char *nm, const char *name);
7855714Skris
79109998Smarkmint PEM_def_callback(char *buf, int num, int w, void *key)
80296465Sdelphij{
81109998Smarkm#ifdef OPENSSL_NO_FP_API
82296465Sdelphij    /*
83296465Sdelphij     * We should not ever call the default callback routine from windows.
84296465Sdelphij     */
85296465Sdelphij    PEMerr(PEM_F_PEM_DEF_CALLBACK, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
86296465Sdelphij    return (-1);
8755714Skris#else
88296465Sdelphij    int i, j;
89296465Sdelphij    const char *prompt;
90296465Sdelphij    if (key) {
91296465Sdelphij        i = strlen(key);
92296465Sdelphij        i = (i > num) ? num : i;
93296465Sdelphij        memcpy(buf, key, i);
94296465Sdelphij        return (i);
95296465Sdelphij    }
9655714Skris
97296465Sdelphij    prompt = EVP_get_pw_prompt();
98296465Sdelphij    if (prompt == NULL)
99296465Sdelphij        prompt = "Enter PEM pass phrase:";
10055714Skris
101296465Sdelphij    for (;;) {
102296465Sdelphij        i = EVP_read_pw_string(buf, num, prompt, w);
103296465Sdelphij        if (i != 0) {
104296465Sdelphij            PEMerr(PEM_F_PEM_DEF_CALLBACK, PEM_R_PROBLEMS_GETTING_PASSWORD);
105296465Sdelphij            memset(buf, 0, (unsigned int)num);
106296465Sdelphij            return (-1);
107296465Sdelphij        }
108296465Sdelphij        j = strlen(buf);
109296465Sdelphij        if (j < MIN_LENGTH) {
110296465Sdelphij            fprintf(stderr,
111296465Sdelphij                    "phrase is too short, needs to be at least %d chars\n",
112296465Sdelphij                    MIN_LENGTH);
113296465Sdelphij        } else
114296465Sdelphij            break;
115296465Sdelphij    }
116296465Sdelphij    return (j);
11755714Skris#endif
118296465Sdelphij}
11955714Skris
12055714Skrisvoid PEM_proc_type(char *buf, int type)
121296465Sdelphij{
122296465Sdelphij    const char *str;
12355714Skris
124296465Sdelphij    if (type == PEM_TYPE_ENCRYPTED)
125296465Sdelphij        str = "ENCRYPTED";
126296465Sdelphij    else if (type == PEM_TYPE_MIC_CLEAR)
127296465Sdelphij        str = "MIC-CLEAR";
128296465Sdelphij    else if (type == PEM_TYPE_MIC_ONLY)
129296465Sdelphij        str = "MIC-ONLY";
130296465Sdelphij    else
131296465Sdelphij        str = "BAD-TYPE";
13255714Skris
133296465Sdelphij    BUF_strlcat(buf, "Proc-Type: 4,", PEM_BUFSIZE);
134296465Sdelphij    BUF_strlcat(buf, str, PEM_BUFSIZE);
135296465Sdelphij    BUF_strlcat(buf, "\n", PEM_BUFSIZE);
136296465Sdelphij}
137296465Sdelphij
13855714Skrisvoid PEM_dek_info(char *buf, const char *type, int len, char *str)
139296465Sdelphij{
140296465Sdelphij    static const unsigned char map[17] = "0123456789ABCDEF";
141296465Sdelphij    long i;
142296465Sdelphij    int j;
14355714Skris
144296465Sdelphij    BUF_strlcat(buf, "DEK-Info: ", PEM_BUFSIZE);
145296465Sdelphij    BUF_strlcat(buf, type, PEM_BUFSIZE);
146296465Sdelphij    BUF_strlcat(buf, ",", PEM_BUFSIZE);
147296465Sdelphij    j = strlen(buf);
148296465Sdelphij    if (j + (len * 2) + 1 > PEM_BUFSIZE)
149296465Sdelphij        return;
150296465Sdelphij    for (i = 0; i < len; i++) {
151296465Sdelphij        buf[j + i * 2] = map[(str[i] >> 4) & 0x0f];
152296465Sdelphij        buf[j + i * 2 + 1] = map[(str[i]) & 0x0f];
153296465Sdelphij    }
154296465Sdelphij    buf[j + i * 2] = '\n';
155296465Sdelphij    buf[j + i * 2 + 1] = '\0';
156296465Sdelphij}
15755714Skris
158109998Smarkm#ifndef OPENSSL_NO_FP_API
159160814Ssimonvoid *PEM_ASN1_read(d2i_of_void *d2i, const char *name, FILE *fp, void **x,
160296465Sdelphij                    pem_password_cb *cb, void *u)
161296465Sdelphij{
162296465Sdelphij    BIO *b;
163296465Sdelphij    void *ret;
16455714Skris
165296465Sdelphij    if ((b = BIO_new(BIO_s_file())) == NULL) {
166296465Sdelphij        PEMerr(PEM_F_PEM_ASN1_READ, ERR_R_BUF_LIB);
167296465Sdelphij        return (0);
168296465Sdelphij    }
169296465Sdelphij    BIO_set_fp(b, fp, BIO_NOCLOSE);
170296465Sdelphij    ret = PEM_ASN1_read_bio(d2i, name, b, x, cb, u);
171296465Sdelphij    BIO_free(b);
172296465Sdelphij    return (ret);
173296465Sdelphij}
17455714Skris#endif
17555714Skris
17659191Skrisstatic int check_pem(const char *nm, const char *name)
17759191Skris{
178296465Sdelphij    /* Normal matching nm and name */
179296465Sdelphij    if (!strcmp(nm, name))
180296465Sdelphij        return 1;
18159191Skris
182296465Sdelphij    /* Make PEM_STRING_EVP_PKEY match any private key */
18359191Skris
184296465Sdelphij    if (!strcmp(nm, PEM_STRING_PKCS8) && !strcmp(name, PEM_STRING_EVP_PKEY))
185296465Sdelphij        return 1;
18659191Skris
187296465Sdelphij    if (!strcmp(nm, PEM_STRING_PKCS8INF) &&
188296465Sdelphij        !strcmp(name, PEM_STRING_EVP_PKEY))
189296465Sdelphij        return 1;
19059191Skris
191296465Sdelphij    if (!strcmp(nm, PEM_STRING_RSA) && !strcmp(name, PEM_STRING_EVP_PKEY))
192296465Sdelphij        return 1;
19359191Skris
194296465Sdelphij    if (!strcmp(nm, PEM_STRING_DSA) && !strcmp(name, PEM_STRING_EVP_PKEY))
195296465Sdelphij        return 1;
19659191Skris
197296465Sdelphij    if (!strcmp(nm, PEM_STRING_ECPRIVATEKEY) &&
198296465Sdelphij        !strcmp(name, PEM_STRING_EVP_PKEY))
199296465Sdelphij        return 1;
200296465Sdelphij    /* Permit older strings */
20159191Skris
202296465Sdelphij    if (!strcmp(nm, PEM_STRING_X509_OLD) && !strcmp(name, PEM_STRING_X509))
203296465Sdelphij        return 1;
20459191Skris
205296465Sdelphij    if (!strcmp(nm, PEM_STRING_X509_REQ_OLD) &&
206296465Sdelphij        !strcmp(name, PEM_STRING_X509_REQ))
207296465Sdelphij        return 1;
20859191Skris
209296465Sdelphij    /* Allow normal certs to be read as trusted certs */
210296465Sdelphij    if (!strcmp(nm, PEM_STRING_X509) &&
211296465Sdelphij        !strcmp(name, PEM_STRING_X509_TRUSTED))
212296465Sdelphij        return 1;
21359191Skris
214296465Sdelphij    if (!strcmp(nm, PEM_STRING_X509_OLD) &&
215296465Sdelphij        !strcmp(name, PEM_STRING_X509_TRUSTED))
216296465Sdelphij        return 1;
21759191Skris
218296465Sdelphij    /* Some CAs use PKCS#7 with CERTIFICATE headers */
219296465Sdelphij    if (!strcmp(nm, PEM_STRING_X509) && !strcmp(name, PEM_STRING_PKCS7))
220296465Sdelphij        return 1;
22159191Skris
222296465Sdelphij    if (!strcmp(nm, PEM_STRING_PKCS7_SIGNED) &&
223296465Sdelphij        !strcmp(name, PEM_STRING_PKCS7))
224296465Sdelphij        return 1;
225194206Ssimon
226296465Sdelphij    return 0;
22759191Skris}
22859191Skris
229296465Sdelphijint PEM_bytes_read_bio(unsigned char **pdata, long *plen, char **pnm,
230296465Sdelphij                       const char *name, BIO *bp, pem_password_cb *cb,
231296465Sdelphij                       void *u)
232296465Sdelphij{
233296465Sdelphij    EVP_CIPHER_INFO cipher;
234296465Sdelphij    char *nm = NULL, *header = NULL;
235296465Sdelphij    unsigned char *data = NULL;
236296465Sdelphij    long len;
237296465Sdelphij    int ret = 0;
23855714Skris
239296465Sdelphij    for (;;) {
240296465Sdelphij        if (!PEM_read_bio(bp, &nm, &header, &data, &len)) {
241296465Sdelphij            if (ERR_GET_REASON(ERR_peek_error()) == PEM_R_NO_START_LINE)
242296465Sdelphij                ERR_add_error_data(2, "Expecting: ", name);
243296465Sdelphij            return 0;
244296465Sdelphij        }
245296465Sdelphij        if (check_pem(nm, name))
246296465Sdelphij            break;
247296465Sdelphij        OPENSSL_free(nm);
248296465Sdelphij        OPENSSL_free(header);
249296465Sdelphij        OPENSSL_free(data);
250296465Sdelphij    }
251296465Sdelphij    if (!PEM_get_EVP_CIPHER_INFO(header, &cipher))
252296465Sdelphij        goto err;
253296465Sdelphij    if (!PEM_do_header(&cipher, data, &len, cb, u))
254296465Sdelphij        goto err;
255109998Smarkm
256296465Sdelphij    *pdata = data;
257296465Sdelphij    *plen = len;
258109998Smarkm
259296465Sdelphij    if (pnm)
260296465Sdelphij        *pnm = nm;
261109998Smarkm
262296465Sdelphij    ret = 1;
263109998Smarkm
264296465Sdelphij err:
265296465Sdelphij    if (!ret || !pnm)
266296465Sdelphij        OPENSSL_free(nm);
267296465Sdelphij    OPENSSL_free(header);
268296465Sdelphij    if (!ret)
269296465Sdelphij        OPENSSL_free(data);
270296465Sdelphij    return ret;
271296465Sdelphij}
27255714Skris
273109998Smarkm#ifndef OPENSSL_NO_FP_API
274160814Ssimonint PEM_ASN1_write(i2d_of_void *i2d, const char *name, FILE *fp,
275296465Sdelphij                   char *x, const EVP_CIPHER *enc, unsigned char *kstr,
276296465Sdelphij                   int klen, pem_password_cb *callback, void *u)
277296465Sdelphij{
278296465Sdelphij    BIO *b;
279296465Sdelphij    int ret;
28055714Skris
281296465Sdelphij    if ((b = BIO_new(BIO_s_file())) == NULL) {
282296465Sdelphij        PEMerr(PEM_F_PEM_ASN1_WRITE, ERR_R_BUF_LIB);
283296465Sdelphij        return (0);
284296465Sdelphij    }
285296465Sdelphij    BIO_set_fp(b, fp, BIO_NOCLOSE);
286296465Sdelphij    ret = PEM_ASN1_write_bio(i2d, name, b, x, enc, kstr, klen, callback, u);
287296465Sdelphij    BIO_free(b);
288296465Sdelphij    return (ret);
289296465Sdelphij}
29055714Skris#endif
29155714Skris
292160814Ssimonint PEM_ASN1_write_bio(i2d_of_void *i2d, const char *name, BIO *bp,
293296465Sdelphij                       char *x, const EVP_CIPHER *enc, unsigned char *kstr,
294296465Sdelphij                       int klen, pem_password_cb *callback, void *u)
295296465Sdelphij{
296296465Sdelphij    EVP_CIPHER_CTX ctx;
297296465Sdelphij    int dsize = 0, i, j, ret = 0;
298296465Sdelphij    unsigned char *p, *data = NULL;
299296465Sdelphij    const char *objstr = NULL;
300296465Sdelphij    char buf[PEM_BUFSIZE];
301296465Sdelphij    unsigned char key[EVP_MAX_KEY_LENGTH];
302296465Sdelphij    unsigned char iv[EVP_MAX_IV_LENGTH];
30355714Skris
304296465Sdelphij    if (enc != NULL) {
305296465Sdelphij        objstr = OBJ_nid2sn(EVP_CIPHER_nid(enc));
306296465Sdelphij        if (objstr == NULL) {
307296465Sdelphij            PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, PEM_R_UNSUPPORTED_CIPHER);
308296465Sdelphij            goto err;
309296465Sdelphij        }
310296465Sdelphij    }
31155714Skris
312296465Sdelphij    if ((dsize = i2d(x, NULL)) < 0) {
313296465Sdelphij        PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, ERR_R_ASN1_LIB);
314296465Sdelphij        dsize = 0;
315296465Sdelphij        goto err;
316296465Sdelphij    }
317296465Sdelphij    /* dzise + 8 bytes are needed */
318296465Sdelphij    /* actually it needs the cipher block size extra... */
319296465Sdelphij    data = (unsigned char *)OPENSSL_malloc((unsigned int)dsize + 20);
320296465Sdelphij    if (data == NULL) {
321296465Sdelphij        PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, ERR_R_MALLOC_FAILURE);
322296465Sdelphij        goto err;
323296465Sdelphij    }
324296465Sdelphij    p = data;
325296465Sdelphij    i = i2d(x, &p);
326296465Sdelphij
327296465Sdelphij    if (enc != NULL) {
328296465Sdelphij        if (kstr == NULL) {
329296465Sdelphij            if (callback == NULL)
330296465Sdelphij                klen = PEM_def_callback(buf, PEM_BUFSIZE, 1, u);
331296465Sdelphij            else
332296465Sdelphij                klen = (*callback) (buf, PEM_BUFSIZE, 1, u);
333296465Sdelphij            if (klen <= 0) {
334296465Sdelphij                PEMerr(PEM_F_PEM_ASN1_WRITE_BIO, PEM_R_READ_KEY);
335296465Sdelphij                goto err;
336296465Sdelphij            }
33755714Skris#ifdef CHARSET_EBCDIC
338296465Sdelphij            /* Convert the pass phrase from EBCDIC */
339296465Sdelphij            ebcdic2ascii(buf, buf, klen);
34055714Skris#endif
341296465Sdelphij            kstr = (unsigned char *)buf;
342296465Sdelphij        }
343296465Sdelphij        RAND_add(data, i, 0);   /* put in the RSA key. */
344296465Sdelphij        OPENSSL_assert(enc->iv_len <= (int)sizeof(iv));
345296465Sdelphij        if (RAND_pseudo_bytes(iv, enc->iv_len) < 0) /* Generate a salt */
346296465Sdelphij            goto err;
347296465Sdelphij        /*
348296465Sdelphij         * The 'iv' is used as the iv and as a salt.  It is NOT taken from
349296465Sdelphij         * the BytesToKey function
350296465Sdelphij         */
351296465Sdelphij        EVP_BytesToKey(enc, EVP_md5(), iv, kstr, klen, 1, key, NULL);
35255714Skris
353296465Sdelphij        if (kstr == (unsigned char *)buf)
354296465Sdelphij            OPENSSL_cleanse(buf, PEM_BUFSIZE);
35555714Skris
356296465Sdelphij        OPENSSL_assert(strlen(objstr) + 23 + 2 * enc->iv_len + 13 <=
357296465Sdelphij                       sizeof buf);
358109998Smarkm
359296465Sdelphij        buf[0] = '\0';
360296465Sdelphij        PEM_proc_type(buf, PEM_TYPE_ENCRYPTED);
361296465Sdelphij        PEM_dek_info(buf, objstr, enc->iv_len, (char *)iv);
362296465Sdelphij        /* k=strlen(buf); */
363109998Smarkm
364296465Sdelphij        EVP_CIPHER_CTX_init(&ctx);
365296465Sdelphij        EVP_EncryptInit_ex(&ctx, enc, NULL, key, iv);
366296465Sdelphij        EVP_EncryptUpdate(&ctx, data, &j, data, i);
367296465Sdelphij        EVP_EncryptFinal_ex(&ctx, &(data[j]), &i);
368296465Sdelphij        EVP_CIPHER_CTX_cleanup(&ctx);
369296465Sdelphij        i += j;
370296465Sdelphij        ret = 1;
371296465Sdelphij    } else {
372296465Sdelphij        ret = 1;
373296465Sdelphij        buf[0] = '\0';
374296465Sdelphij    }
375296465Sdelphij    i = PEM_write_bio(bp, name, buf, data, i);
376296465Sdelphij    if (i <= 0)
377296465Sdelphij        ret = 0;
378296465Sdelphij err:
379296465Sdelphij    OPENSSL_cleanse(key, sizeof(key));
380296465Sdelphij    OPENSSL_cleanse(iv, sizeof(iv));
381296465Sdelphij    OPENSSL_cleanse((char *)&ctx, sizeof(ctx));
382296465Sdelphij    OPENSSL_cleanse(buf, PEM_BUFSIZE);
383296465Sdelphij    if (data != NULL) {
384296465Sdelphij        OPENSSL_cleanse(data, (unsigned int)dsize);
385296465Sdelphij        OPENSSL_free(data);
386296465Sdelphij    }
387296465Sdelphij    return (ret);
388296465Sdelphij}
38955714Skris
39055714Skrisint PEM_do_header(EVP_CIPHER_INFO *cipher, unsigned char *data, long *plen,
391296465Sdelphij                  pem_password_cb *callback, void *u)
392296465Sdelphij{
393296465Sdelphij    int i, j, o, klen;
394296465Sdelphij    long len;
395296465Sdelphij    EVP_CIPHER_CTX ctx;
396296465Sdelphij    unsigned char key[EVP_MAX_KEY_LENGTH];
397296465Sdelphij    char buf[PEM_BUFSIZE];
39855714Skris
399296465Sdelphij    len = *plen;
40055714Skris
401296465Sdelphij    if (cipher->cipher == NULL)
402296465Sdelphij        return (1);
403296465Sdelphij    if (callback == NULL)
404296465Sdelphij        klen = PEM_def_callback(buf, PEM_BUFSIZE, 0, u);
405296465Sdelphij    else
406296465Sdelphij        klen = callback(buf, PEM_BUFSIZE, 0, u);
407296465Sdelphij    if (klen <= 0) {
408296465Sdelphij        PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_BAD_PASSWORD_READ);
409296465Sdelphij        return (0);
410296465Sdelphij    }
41155714Skris#ifdef CHARSET_EBCDIC
412296465Sdelphij    /* Convert the pass phrase from EBCDIC */
413296465Sdelphij    ebcdic2ascii(buf, buf, klen);
41455714Skris#endif
41555714Skris
416296465Sdelphij    EVP_BytesToKey(cipher->cipher, EVP_md5(), &(cipher->iv[0]),
417296465Sdelphij                   (unsigned char *)buf, klen, 1, key, NULL);
41855714Skris
419296465Sdelphij    j = (int)len;
420296465Sdelphij    EVP_CIPHER_CTX_init(&ctx);
421296465Sdelphij    EVP_DecryptInit_ex(&ctx, cipher->cipher, NULL, key, &(cipher->iv[0]));
422296465Sdelphij    EVP_DecryptUpdate(&ctx, data, &i, data, j);
423296465Sdelphij    o = EVP_DecryptFinal_ex(&ctx, &(data[i]), &j);
424296465Sdelphij    EVP_CIPHER_CTX_cleanup(&ctx);
425296465Sdelphij    OPENSSL_cleanse((char *)buf, sizeof(buf));
426296465Sdelphij    OPENSSL_cleanse((char *)key, sizeof(key));
427296465Sdelphij    j += i;
428296465Sdelphij    if (!o) {
429296465Sdelphij        PEMerr(PEM_F_PEM_DO_HEADER, PEM_R_BAD_DECRYPT);
430296465Sdelphij        return (0);
431296465Sdelphij    }
432296465Sdelphij    *plen = j;
433296465Sdelphij    return (1);
434296465Sdelphij}
43555714Skris
43655714Skrisint PEM_get_EVP_CIPHER_INFO(char *header, EVP_CIPHER_INFO *cipher)
437296465Sdelphij{
438296465Sdelphij    const EVP_CIPHER *enc = NULL;
439296465Sdelphij    char *p, c;
440296465Sdelphij    char **header_pp = &header;
44155714Skris
442296465Sdelphij    cipher->cipher = NULL;
443296465Sdelphij    if ((header == NULL) || (*header == '\0') || (*header == '\n'))
444296465Sdelphij        return (1);
445296465Sdelphij    if (strncmp(header, "Proc-Type: ", 11) != 0) {
446296465Sdelphij        PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_NOT_PROC_TYPE);
447296465Sdelphij        return (0);
448296465Sdelphij    }
449296465Sdelphij    header += 11;
450296465Sdelphij    if (*header != '4')
451296465Sdelphij        return (0);
452296465Sdelphij    header++;
453296465Sdelphij    if (*header != ',')
454296465Sdelphij        return (0);
455296465Sdelphij    header++;
456296465Sdelphij    if (strncmp(header, "ENCRYPTED", 9) != 0) {
457296465Sdelphij        PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_NOT_ENCRYPTED);
458296465Sdelphij        return (0);
459296465Sdelphij    }
460296465Sdelphij    for (; (*header != '\n') && (*header != '\0'); header++) ;
461296465Sdelphij    if (*header == '\0') {
462296465Sdelphij        PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_SHORT_HEADER);
463296465Sdelphij        return (0);
464296465Sdelphij    }
465296465Sdelphij    header++;
466296465Sdelphij    if (strncmp(header, "DEK-Info: ", 10) != 0) {
467296465Sdelphij        PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_NOT_DEK_INFO);
468296465Sdelphij        return (0);
469296465Sdelphij    }
470296465Sdelphij    header += 10;
47155714Skris
472296465Sdelphij    p = header;
473296465Sdelphij    for (;;) {
474296465Sdelphij        c = *header;
47555714Skris#ifndef CHARSET_EBCDIC
476296465Sdelphij        if (!(((c >= 'A') && (c <= 'Z')) || (c == '-') ||
477296465Sdelphij              ((c >= '0') && (c <= '9'))))
478296465Sdelphij            break;
47955714Skris#else
480296465Sdelphij        if (!(isupper(c) || (c == '-') || isdigit(c)))
481296465Sdelphij            break;
48255714Skris#endif
483296465Sdelphij        header++;
484296465Sdelphij    }
485296465Sdelphij    *header = '\0';
486296465Sdelphij    cipher->cipher = enc = EVP_get_cipherbyname(p);
487296465Sdelphij    *header = c;
488296465Sdelphij    header++;
48955714Skris
490296465Sdelphij    if (enc == NULL) {
491296465Sdelphij        PEMerr(PEM_F_PEM_GET_EVP_CIPHER_INFO, PEM_R_UNSUPPORTED_ENCRYPTION);
492296465Sdelphij        return (0);
493296465Sdelphij    }
494296465Sdelphij    if (!load_iv(header_pp, &(cipher->iv[0]), enc->iv_len))
495296465Sdelphij        return (0);
49655714Skris
497296465Sdelphij    return (1);
498296465Sdelphij}
49955714Skris
500160814Ssimonstatic int load_iv(char **fromp, unsigned char *to, int num)
501296465Sdelphij{
502296465Sdelphij    int v, i;
503296465Sdelphij    char *from;
50455714Skris
505296465Sdelphij    from = *fromp;
506296465Sdelphij    for (i = 0; i < num; i++)
507296465Sdelphij        to[i] = 0;
508296465Sdelphij    num *= 2;
509296465Sdelphij    for (i = 0; i < num; i++) {
510296465Sdelphij        if ((*from >= '0') && (*from <= '9'))
511296465Sdelphij            v = *from - '0';
512296465Sdelphij        else if ((*from >= 'A') && (*from <= 'F'))
513296465Sdelphij            v = *from - 'A' + 10;
514296465Sdelphij        else if ((*from >= 'a') && (*from <= 'f'))
515296465Sdelphij            v = *from - 'a' + 10;
516296465Sdelphij        else {
517296465Sdelphij            PEMerr(PEM_F_LOAD_IV, PEM_R_BAD_IV_CHARS);
518296465Sdelphij            return (0);
519296465Sdelphij        }
520296465Sdelphij        from++;
521296465Sdelphij        to[i / 2] |= v << (long)((!(i & 1)) * 4);
522296465Sdelphij    }
52355714Skris
524296465Sdelphij    *fromp = from;
525296465Sdelphij    return (1);
526296465Sdelphij}
52755714Skris
528109998Smarkm#ifndef OPENSSL_NO_FP_API
52955714Skrisint PEM_write(FILE *fp, char *name, char *header, unsigned char *data,
530296465Sdelphij              long len)
531296465Sdelphij{
532296465Sdelphij    BIO *b;
533296465Sdelphij    int ret;
53455714Skris
535296465Sdelphij    if ((b = BIO_new(BIO_s_file())) == NULL) {
536296465Sdelphij        PEMerr(PEM_F_PEM_WRITE, ERR_R_BUF_LIB);
537296465Sdelphij        return (0);
538296465Sdelphij    }
539296465Sdelphij    BIO_set_fp(b, fp, BIO_NOCLOSE);
540296465Sdelphij    ret = PEM_write_bio(b, name, header, data, len);
541296465Sdelphij    BIO_free(b);
542296465Sdelphij    return (ret);
543296465Sdelphij}
54455714Skris#endif
54555714Skris
546296465Sdelphijint PEM_write_bio(BIO *bp, const char *name, char *header,
547296465Sdelphij                  unsigned char *data, long len)
548296465Sdelphij{
549296465Sdelphij    int nlen, n, i, j, outl;
550296465Sdelphij    unsigned char *buf = NULL;
551296465Sdelphij    EVP_ENCODE_CTX ctx;
552296465Sdelphij    int reason = ERR_R_BUF_LIB;
55355714Skris
554296465Sdelphij    EVP_EncodeInit(&ctx);
555296465Sdelphij    nlen = strlen(name);
55655714Skris
557296465Sdelphij    if ((BIO_write(bp, "-----BEGIN ", 11) != 11) ||
558296465Sdelphij        (BIO_write(bp, name, nlen) != nlen) ||
559296465Sdelphij        (BIO_write(bp, "-----\n", 6) != 6))
560296465Sdelphij        goto err;
56155714Skris
562296465Sdelphij    i = strlen(header);
563296465Sdelphij    if (i > 0) {
564296465Sdelphij        if ((BIO_write(bp, header, i) != i) || (BIO_write(bp, "\n", 1) != 1))
565296465Sdelphij            goto err;
566296465Sdelphij    }
56755714Skris
568296465Sdelphij    buf = OPENSSL_malloc(PEM_BUFSIZE * 8);
569296465Sdelphij    if (buf == NULL) {
570296465Sdelphij        reason = ERR_R_MALLOC_FAILURE;
571296465Sdelphij        goto err;
572296465Sdelphij    }
573296465Sdelphij
574296465Sdelphij    i = j = 0;
575296465Sdelphij    while (len > 0) {
576296465Sdelphij        n = (int)((len > (PEM_BUFSIZE * 5)) ? (PEM_BUFSIZE * 5) : len);
577296465Sdelphij        EVP_EncodeUpdate(&ctx, buf, &outl, &(data[j]), n);
578296465Sdelphij        if ((outl) && (BIO_write(bp, (char *)buf, outl) != outl))
579296465Sdelphij            goto err;
580296465Sdelphij        i += outl;
581296465Sdelphij        len -= n;
582296465Sdelphij        j += n;
583296465Sdelphij    }
584296465Sdelphij    EVP_EncodeFinal(&ctx, buf, &outl);
585296465Sdelphij    if ((outl > 0) && (BIO_write(bp, (char *)buf, outl) != outl))
586296465Sdelphij        goto err;
587296465Sdelphij    OPENSSL_cleanse(buf, PEM_BUFSIZE * 8);
588296465Sdelphij    OPENSSL_free(buf);
589296465Sdelphij    buf = NULL;
590296465Sdelphij    if ((BIO_write(bp, "-----END ", 9) != 9) ||
591296465Sdelphij        (BIO_write(bp, name, nlen) != nlen) ||
592296465Sdelphij        (BIO_write(bp, "-----\n", 6) != 6))
593296465Sdelphij        goto err;
594296465Sdelphij    return (i + outl);
595296465Sdelphij err:
596296465Sdelphij    if (buf) {
597296465Sdelphij        OPENSSL_cleanse(buf, PEM_BUFSIZE * 8);
598296465Sdelphij        OPENSSL_free(buf);
599296465Sdelphij    }
600296465Sdelphij    PEMerr(PEM_F_PEM_WRITE_BIO, reason);
601296465Sdelphij    return (0);
602296465Sdelphij}
603296465Sdelphij
604109998Smarkm#ifndef OPENSSL_NO_FP_API
60555714Skrisint PEM_read(FILE *fp, char **name, char **header, unsigned char **data,
606296465Sdelphij             long *len)
607296465Sdelphij{
608296465Sdelphij    BIO *b;
609296465Sdelphij    int ret;
61055714Skris
611296465Sdelphij    if ((b = BIO_new(BIO_s_file())) == NULL) {
612296465Sdelphij        PEMerr(PEM_F_PEM_READ, ERR_R_BUF_LIB);
613296465Sdelphij        return (0);
614296465Sdelphij    }
615296465Sdelphij    BIO_set_fp(b, fp, BIO_NOCLOSE);
616296465Sdelphij    ret = PEM_read_bio(b, name, header, data, len);
617296465Sdelphij    BIO_free(b);
618296465Sdelphij    return (ret);
619296465Sdelphij}
62055714Skris#endif
62155714Skris
62255714Skrisint PEM_read_bio(BIO *bp, char **name, char **header, unsigned char **data,
623296465Sdelphij                 long *len)
624296465Sdelphij{
625296465Sdelphij    EVP_ENCODE_CTX ctx;
626296465Sdelphij    int end = 0, i, k, bl = 0, hl = 0, nohead = 0;
627296465Sdelphij    char buf[256];
628296465Sdelphij    BUF_MEM *nameB;
629296465Sdelphij    BUF_MEM *headerB;
630296465Sdelphij    BUF_MEM *dataB, *tmpB;
63155714Skris
632296465Sdelphij    nameB = BUF_MEM_new();
633296465Sdelphij    headerB = BUF_MEM_new();
634296465Sdelphij    dataB = BUF_MEM_new();
635296465Sdelphij    if ((nameB == NULL) || (headerB == NULL) || (dataB == NULL)) {
636296465Sdelphij        BUF_MEM_free(nameB);
637296465Sdelphij        BUF_MEM_free(headerB);
638296465Sdelphij        BUF_MEM_free(dataB);
639296465Sdelphij        PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
640296465Sdelphij        return (0);
641296465Sdelphij    }
64255714Skris
643296465Sdelphij    buf[254] = '\0';
644296465Sdelphij    for (;;) {
645296465Sdelphij        i = BIO_gets(bp, buf, 254);
64655714Skris
647296465Sdelphij        if (i <= 0) {
648296465Sdelphij            PEMerr(PEM_F_PEM_READ_BIO, PEM_R_NO_START_LINE);
649296465Sdelphij            goto err;
650296465Sdelphij        }
65155714Skris
652296465Sdelphij        while ((i >= 0) && (buf[i] <= ' '))
653296465Sdelphij            i--;
654296465Sdelphij        buf[++i] = '\n';
655296465Sdelphij        buf[++i] = '\0';
65655714Skris
657296465Sdelphij        if (strncmp(buf, "-----BEGIN ", 11) == 0) {
658296465Sdelphij            i = strlen(&(buf[11]));
65955714Skris
660296465Sdelphij            if (strncmp(&(buf[11 + i - 6]), "-----\n", 6) != 0)
661296465Sdelphij                continue;
662296465Sdelphij            if (!BUF_MEM_grow(nameB, i + 9)) {
663296465Sdelphij                PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
664296465Sdelphij                goto err;
665296465Sdelphij            }
666296465Sdelphij            memcpy(nameB->data, &(buf[11]), i - 6);
667296465Sdelphij            nameB->data[i - 6] = '\0';
668296465Sdelphij            break;
669296465Sdelphij        }
670296465Sdelphij    }
671296465Sdelphij    hl = 0;
672296465Sdelphij    if (!BUF_MEM_grow(headerB, 256)) {
673296465Sdelphij        PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
674296465Sdelphij        goto err;
675296465Sdelphij    }
676296465Sdelphij    headerB->data[0] = '\0';
677296465Sdelphij    for (;;) {
678296465Sdelphij        i = BIO_gets(bp, buf, 254);
679296465Sdelphij        if (i <= 0)
680296465Sdelphij            break;
68155714Skris
682296465Sdelphij        while ((i >= 0) && (buf[i] <= ' '))
683296465Sdelphij            i--;
684296465Sdelphij        buf[++i] = '\n';
685296465Sdelphij        buf[++i] = '\0';
68655714Skris
687296465Sdelphij        if (buf[0] == '\n')
688296465Sdelphij            break;
689296465Sdelphij        if (!BUF_MEM_grow(headerB, hl + i + 9)) {
690296465Sdelphij            PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
691296465Sdelphij            goto err;
692296465Sdelphij        }
693296465Sdelphij        if (strncmp(buf, "-----END ", 9) == 0) {
694296465Sdelphij            nohead = 1;
695296465Sdelphij            break;
696296465Sdelphij        }
697296465Sdelphij        memcpy(&(headerB->data[hl]), buf, i);
698296465Sdelphij        headerB->data[hl + i] = '\0';
699296465Sdelphij        hl += i;
700296465Sdelphij    }
70155714Skris
702296465Sdelphij    bl = 0;
703296465Sdelphij    if (!BUF_MEM_grow(dataB, 1024)) {
704296465Sdelphij        PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
705296465Sdelphij        goto err;
706296465Sdelphij    }
707296465Sdelphij    dataB->data[0] = '\0';
708296465Sdelphij    if (!nohead) {
709296465Sdelphij        for (;;) {
710296465Sdelphij            i = BIO_gets(bp, buf, 254);
711296465Sdelphij            if (i <= 0)
712296465Sdelphij                break;
71355714Skris
714296465Sdelphij            while ((i >= 0) && (buf[i] <= ' '))
715296465Sdelphij                i--;
716296465Sdelphij            buf[++i] = '\n';
717296465Sdelphij            buf[++i] = '\0';
71855714Skris
719296465Sdelphij            if (i != 65)
720296465Sdelphij                end = 1;
721296465Sdelphij            if (strncmp(buf, "-----END ", 9) == 0)
722296465Sdelphij                break;
723296465Sdelphij            if (i > 65)
724296465Sdelphij                break;
725296465Sdelphij            if (!BUF_MEM_grow_clean(dataB, i + bl + 9)) {
726296465Sdelphij                PEMerr(PEM_F_PEM_READ_BIO, ERR_R_MALLOC_FAILURE);
727296465Sdelphij                goto err;
728296465Sdelphij            }
729296465Sdelphij            memcpy(&(dataB->data[bl]), buf, i);
730296465Sdelphij            dataB->data[bl + i] = '\0';
731296465Sdelphij            bl += i;
732296465Sdelphij            if (end) {
733296465Sdelphij                buf[0] = '\0';
734296465Sdelphij                i = BIO_gets(bp, buf, 254);
735296465Sdelphij                if (i <= 0)
736296465Sdelphij                    break;
73755714Skris
738296465Sdelphij                while ((i >= 0) && (buf[i] <= ' '))
739296465Sdelphij                    i--;
740296465Sdelphij                buf[++i] = '\n';
741296465Sdelphij                buf[++i] = '\0';
74255714Skris
743296465Sdelphij                break;
744296465Sdelphij            }
745296465Sdelphij        }
746296465Sdelphij    } else {
747296465Sdelphij        tmpB = headerB;
748296465Sdelphij        headerB = dataB;
749296465Sdelphij        dataB = tmpB;
750296465Sdelphij        bl = hl;
751296465Sdelphij    }
752296465Sdelphij    i = strlen(nameB->data);
753296465Sdelphij    if ((strncmp(buf, "-----END ", 9) != 0) ||
754296465Sdelphij        (strncmp(nameB->data, &(buf[9]), i) != 0) ||
755296465Sdelphij        (strncmp(&(buf[9 + i]), "-----\n", 6) != 0)) {
756296465Sdelphij        PEMerr(PEM_F_PEM_READ_BIO, PEM_R_BAD_END_LINE);
757296465Sdelphij        goto err;
758296465Sdelphij    }
75955714Skris
760296465Sdelphij    EVP_DecodeInit(&ctx);
761296465Sdelphij    i = EVP_DecodeUpdate(&ctx,
762296465Sdelphij                         (unsigned char *)dataB->data, &bl,
763296465Sdelphij                         (unsigned char *)dataB->data, bl);
764296465Sdelphij    if (i < 0) {
765296465Sdelphij        PEMerr(PEM_F_PEM_READ_BIO, PEM_R_BAD_BASE64_DECODE);
766296465Sdelphij        goto err;
767296465Sdelphij    }
768296465Sdelphij    i = EVP_DecodeFinal(&ctx, (unsigned char *)&(dataB->data[bl]), &k);
769296465Sdelphij    if (i < 0) {
770296465Sdelphij        PEMerr(PEM_F_PEM_READ_BIO, PEM_R_BAD_BASE64_DECODE);
771296465Sdelphij        goto err;
772296465Sdelphij    }
773296465Sdelphij    bl += k;
774296465Sdelphij
775296465Sdelphij    if (bl == 0)
776296465Sdelphij        goto err;
777296465Sdelphij    *name = nameB->data;
778296465Sdelphij    *header = headerB->data;
779296465Sdelphij    *data = (unsigned char *)dataB->data;
780296465Sdelphij    *len = bl;
781296465Sdelphij    OPENSSL_free(nameB);
782296465Sdelphij    OPENSSL_free(headerB);
783296465Sdelphij    OPENSSL_free(dataB);
784296465Sdelphij    return (1);
785296465Sdelphij err:
786296465Sdelphij    BUF_MEM_free(nameB);
787296465Sdelphij    BUF_MEM_free(headerB);
788296465Sdelphij    BUF_MEM_free(dataB);
789296465Sdelphij    return (0);
790296465Sdelphij}
791