#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/opensslconf.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/crypto.h>
#include <openssl/dsa.h>
#include <openssl/ec.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/pem.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include "err_local.h"
#include "evp_local.h"
X509_PKEY *
X509_PKEY_new(void)
{
X509_PKEY *x_pkey;
if ((x_pkey = calloc(1, sizeof(*x_pkey))) == NULL) {
ASN1error(ERR_R_MALLOC_FAILURE);
return NULL;
}
return x_pkey;
}
void
X509_PKEY_free(X509_PKEY *x_pkey)
{
if (x_pkey == NULL)
return;
EVP_PKEY_free(x_pkey->dec_pkey);
free(x_pkey);
}
X509_INFO *
X509_INFO_new(void)
{
X509_INFO *ret;
if ((ret = calloc(1, sizeof(X509_INFO))) == NULL) {
ASN1error(ERR_R_MALLOC_FAILURE);
return NULL;
}
ret->references = 1;
return ret;
}
LCRYPTO_ALIAS(X509_INFO_new);
void
X509_INFO_free(X509_INFO *x)
{
if (x == NULL)
return;
if (CRYPTO_add(&x->references, -1, CRYPTO_LOCK_X509_INFO) > 0)
return;
X509_free(x->x509);
X509_CRL_free(x->crl);
X509_PKEY_free(x->x_pkey);
free(x->enc_data);
free(x);
}
LCRYPTO_ALIAS(X509_INFO_free);
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;
}
LCRYPTO_ALIAS(PEM_X509_INFO_read_bio);