#include <stdio.h>
#include <string.h>
#include <openssl/opensslconf.h>
#include <openssl/buffer.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/pem.h>
#include <openssl/x509.h>
#ifndef OPENSSL_NO_DSA
#include <openssl/dsa.h>
#endif
#ifndef OPENSSL_NO_RSA
#include <openssl/rsa.h>
#endif
#include "evp_locl.h"
STACK_OF(X509_INFO) *
PEM_X509_INFO_read(FILE *fp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb,
void *u)
{
BIO *b;
STACK_OF(X509_INFO) *ret;
if ((b = BIO_new(BIO_s_file())) == NULL) {
PEMerror(ERR_R_BUF_LIB);
return (0);
}
BIO_set_fp(b, fp, BIO_NOCLOSE);
ret = PEM_X509_INFO_read_bio(b, sk, cb, u);
BIO_free(b);
return (ret);
}
STACK_OF(X509_INFO) *
PEM_X509_INFO_read_bio(BIO *bp, STACK_OF(X509_INFO) *sk, pem_password_cb *cb,
void *u)
{
X509_INFO *xi = NULL;
char *name = NULL, *header = NULL;
void *pp;
unsigned char *data = NULL;
const unsigned char *p;
long len;
int ok = 0;
int num_in, ptype, raw;
STACK_OF(X509_INFO) *ret = sk;
d2i_of_void *d2i = NULL;
if (ret == NULL) {
if ((ret = sk_X509_INFO_new_null()) == NULL) {
PEMerror(ERR_R_MALLOC_FAILURE);
return NULL;
}
}
num_in = sk_X509_INFO_num(ret);
if ((xi = X509_INFO_new()) == NULL)
goto err;
for (;;) {
raw = 0;
ptype = 0;
if (!PEM_read_bio(bp, &name, &header, &data, &len)) {
if (ERR_GET_REASON(ERR_peek_last_error()) ==
PEM_R_NO_START_LINE) {
ERR_clear_error();
break;
}
goto err;
}
if ((strcmp(name, PEM_STRING_X509) == 0) ||
(strcmp(name, PEM_STRING_X509_OLD) == 0)) {
d2i = (D2I_OF(void))d2i_X509;
if (xi->x509 != NULL) {
if (!sk_X509_INFO_push(ret, xi))
goto err;
if ((xi = X509_INFO_new()) == NULL)
goto err;
}
pp = &(xi->x509);
} else if ((strcmp(name, PEM_STRING_X509_TRUSTED) == 0)) {
d2i = (D2I_OF(void))d2i_X509_AUX;
if (xi->x509 != NULL) {
if (!sk_X509_INFO_push(ret, xi))
goto err;
if ((xi = X509_INFO_new()) == NULL)
goto err;
}
pp = &(xi->x509);
} else if (strcmp(name, PEM_STRING_X509_CRL) == 0) {
d2i = (D2I_OF(void))d2i_X509_CRL;
if (xi->crl != NULL) {
if (!sk_X509_INFO_push(ret, xi))
goto err;
if ((xi = X509_INFO_new()) == NULL)
goto err;
}
pp = &(xi->crl);
} else
#ifndef OPENSSL_NO_RSA
if (strcmp(name, PEM_STRING_RSA) == 0) {
d2i = (D2I_OF(void))d2i_RSAPrivateKey;
if (xi->x_pkey != NULL) {
if (!sk_X509_INFO_push(ret, xi))
goto err;
if ((xi = X509_INFO_new()) == NULL)
goto err;
}
xi->enc_data = NULL;
xi->enc_len = 0;
xi->x_pkey = X509_PKEY_new();
if (xi->x_pkey == NULL)
goto err;
ptype = EVP_PKEY_RSA;
pp = &xi->x_pkey->dec_pkey;
if (strlen(header) > 10)
raw = 1;
} else
#endif
#ifndef OPENSSL_NO_DSA
if (strcmp(name, PEM_STRING_DSA) == 0) {
d2i = (D2I_OF(void))d2i_DSAPrivateKey;
if (xi->x_pkey != NULL) {
if (!sk_X509_INFO_push(ret, xi))
goto err;
if ((xi = X509_INFO_new()) == NULL)
goto err;
}
xi->enc_data = NULL;
xi->enc_len = 0;
xi->x_pkey = X509_PKEY_new();
if (xi->x_pkey == NULL)
goto err;
ptype = EVP_PKEY_DSA;
pp = &xi->x_pkey->dec_pkey;
if (strlen(header) > 10)
raw = 1;
} else
#endif
#ifndef OPENSSL_NO_EC
if (strcmp(name, PEM_STRING_ECPRIVATEKEY) == 0) {
d2i = (D2I_OF(void))d2i_ECPrivateKey;
if (xi->x_pkey != NULL) {
if (!sk_X509_INFO_push(ret, xi))
goto err;
if ((xi = X509_INFO_new()) == NULL)
goto err;
}
xi->enc_data = NULL;
xi->enc_len = 0;
xi->x_pkey = X509_PKEY_new();
if (xi->x_pkey == NULL)
goto err;
ptype = EVP_PKEY_EC;
pp = &xi->x_pkey->dec_pkey;
if (strlen(header) > 10)
raw = 1;
} else
#endif
{
d2i = NULL;
pp = NULL;
}
if (d2i != NULL) {
if (!raw) {
EVP_CIPHER_INFO cipher;
if (!PEM_get_EVP_CIPHER_INFO(header, &cipher))
goto err;
if (!PEM_do_header(&cipher, data, &len, cb, u))
goto err;
p = data;
if (ptype) {
if (!d2i_PrivateKey(ptype, pp, &p,
len)) {
PEMerror(ERR_R_ASN1_LIB);
goto err;
}
} else if (d2i(pp, &p, len) == NULL) {
PEMerror(ERR_R_ASN1_LIB);
goto err;
}
} else {
if (!PEM_get_EVP_CIPHER_INFO(header,
&xi->enc_cipher))
goto err;
xi->enc_data = (char *)data;
xi->enc_len = (int)len;
data = NULL;
}
} else {
}
free(name);
free(header);
free(data);
name = NULL;
header = NULL;
data = NULL;
}
if ((xi->x509 != NULL) || (xi->crl != NULL) ||
(xi->x_pkey != NULL) || (xi->enc_data != NULL)) {
if (!sk_X509_INFO_push(ret, xi))
goto err;
xi = NULL;
}
ok = 1;
err:
if (!ok) {
while (sk_X509_INFO_num(ret) > num_in)
X509_INFO_free(sk_X509_INFO_pop(ret));
if (ret != sk)
sk_X509_INFO_free(ret);
ret = NULL;
}
X509_INFO_free(xi);
free(name);
free(header);
free(data);
return ret;
}
int
PEM_X509_INFO_write_bio(BIO *bp, X509_INFO *xi, EVP_CIPHER *enc,
unsigned char *kstr, int klen, pem_password_cb *cb, void *u)
{
EVP_CIPHER_CTX ctx;
int i, ret = 0;
unsigned char *data = NULL;
const char *objstr = NULL;
char buf[PEM_BUFSIZE];
unsigned char *iv = NULL;
if (enc != NULL) {
objstr = OBJ_nid2sn(EVP_CIPHER_nid(enc));
if (objstr == NULL) {
PEMerror(PEM_R_UNSUPPORTED_CIPHER);
goto err;
}
}
if (xi->x_pkey != NULL) {
if ((xi->enc_data != NULL) && (xi->enc_len > 0) ) {
if (enc == NULL) {
PEMerror(PEM_R_CIPHER_IS_NULL);
goto err;
}
iv = xi->enc_cipher.iv;
data = (unsigned char *)xi->enc_data;
i = xi->enc_len;
objstr = OBJ_nid2sn(
EVP_CIPHER_nid(xi->enc_cipher.cipher));
if (objstr == NULL) {
PEMerror(PEM_R_UNSUPPORTED_CIPHER);
goto err;
}
if (strlen(objstr) + 23 + 2 * enc->iv_len + 13 >
sizeof buf) {
PEMerror(ASN1_R_BUFFER_TOO_SMALL);
goto err;
}
buf[0] = '\0';
PEM_proc_type(buf, PEM_TYPE_ENCRYPTED);
PEM_dek_info(buf, objstr, enc->iv_len, (char *)iv);
i = PEM_write_bio(bp, PEM_STRING_RSA, buf, data, i);
if (i <= 0)
goto err;
} else {
#ifndef OPENSSL_NO_RSA
if (PEM_write_bio_RSAPrivateKey(bp,
xi->x_pkey->dec_pkey->pkey.rsa,
enc, kstr, klen, cb, u) <= 0)
goto err;
#endif
}
}
if ((xi->x509 != NULL) && (PEM_write_bio_X509(bp, xi->x509) <= 0))
goto err;
ret = 1;
err:
explicit_bzero((char *)&ctx, sizeof(ctx));
explicit_bzero(buf, PEM_BUFSIZE);
return (ret);
}