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