1
0
This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
TP-Link_Archer-XR500v/BBA1.5_platform/apps/public/mailx-12.5/openssl.c
2024-07-22 01:58:46 -03:00

878 lines
22 KiB
C
Executable File

/*
* Heirloom mailx - a mail user agent derived from Berkeley Mail.
*
* Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
*/
/*
* Copyright (c) 2002
* Gunnar Ritter. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Gunnar Ritter
* and his contributors.
* 4. Neither the name of Gunnar Ritter nor the names of his contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY GUNNAR RITTER AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL GUNNAR RITTER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
#ifdef DOSCCS
static char sccsid[] = "@(#)openssl.c 1.26 (gritter) 5/26/09";
#endif
#endif /* not lint */
#include "config.h"
#include <setjmp.h>
#include <termios.h>
#include <stdio.h>
static int verbose;
static int reset_tio;
static struct termios otio;
static sigjmp_buf ssljmp;
#include <openssl/crypto.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/x509v3.h>
#include <openssl/x509.h>
#include <openssl/pem.h>
#include <openssl/rand.h>
#include "rcv.h"
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif /* HAVE_ARPA_INET_H */
#include <dirent.h>
#include "extern.h"
/*
* Mail -- a mail program
*
* SSL functions
*/
/*
* OpenSSL client implementation according to: John Viega, Matt Messier,
* Pravir Chandra: Network Security with OpenSSL. Sebastopol, CA 2002.
*/
static int initialized;
static int rand_init;
static int message_number;
static int verify_error_found;
static void sslcatch(int s);
static int ssl_rand_init(void);
static void ssl_init(void);
static int ssl_verify_cb(int success, X509_STORE_CTX *store);
static const SSL_METHOD *ssl_select_method(const char *uhp);
static void ssl_load_verifications(struct sock *sp);
static void ssl_certificate(struct sock *sp, const char *uhp);
static enum okay ssl_check_host(const char *server, struct sock *sp);
static EVP_CIPHER *smime_cipher(const char *name);
static int ssl_password_cb(char *buf, int size, int rwflag, void *userdata);
static FILE *smime_sign_cert(const char *xname, const char *xname2, int warn);
#if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
static enum okay load_crl1(X509_STORE *store, const char *name);
#endif
static enum okay load_crls(X509_STORE *store, const char *vfile,
const char *vdir);
static void
sslcatch(int s)
{
if (reset_tio)
tcsetattr(0, TCSADRAIN, &otio);
siglongjmp(ssljmp, s);
}
static int
ssl_rand_init(void)
{
char *cp;
int state = 0;
if ((cp = value("ssl-rand-egd")) != NULL) {
cp = expand(cp);
if (RAND_egd(cp) == -1) {
DEBUG_ERROR( catgets(catd, CATSET, 245,
"entropy daemon at \"%s\" not available\n"),
cp);
} else
state = 1;
} else if ((cp = value("ssl-rand-file")) != NULL) {
cp = expand(cp);
if (RAND_load_file(cp, 1024) == -1) {
DEBUG_ERROR( catgets(catd, CATSET, 246,
"entropy file at \"%s\" not available\n"), cp);
} else {
struct stat st;
if (stat(cp, &st) == 0 && S_ISREG(st.st_mode) &&
access(cp, W_OK) == 0) {
if (RAND_write_file(cp) == -1) {
DEBUG_ERROR( catgets(catd, CATSET,
247,
"writing entropy data to \"%s\" failed\n"), cp);
}
}
state = 1;
}
}
return state;
}
static void
ssl_init(void)
{
verbose = value("verbose") != NULL;
if (initialized == 0) {
SSL_library_init();
initialized = 1;
}
if (rand_init == 0)
rand_init = ssl_rand_init();
}
static int
ssl_verify_cb(int success, X509_STORE_CTX *store)
{
if (success == 0) {
char data[256];
X509 *cert = X509_STORE_CTX_get_current_cert(store);
int depth = X509_STORE_CTX_get_error_depth(store);
int err = X509_STORE_CTX_get_error(store);
verify_error_found = 1;
if (message_number)
DEBUG_ERROR("Message %d: ", message_number);
DEBUG_ERROR( catgets(catd, CATSET, 229,
"Error with certificate at depth: %i\n"),
depth);
X509_NAME_oneline(X509_get_issuer_name(cert), data,
sizeof data);
DEBUG_ERROR( catgets(catd, CATSET, 230, " issuer = %s\n"),
data);
X509_NAME_oneline(X509_get_subject_name(cert), data,
sizeof data);
DEBUG_ERROR( catgets(catd, CATSET, 231, " subject = %s\n"),
data);
DEBUG_ERROR( catgets(catd, CATSET, 232, " err %i: %s\n"),
err, X509_verify_cert_error_string(err));
if (ssl_vrfy_decide() != OKAY)
return 0;
}
return 1;
}
static const SSL_METHOD *
ssl_select_method(const char *uhp)
{
const SSL_METHOD *method;
char *cp;
cp = ssl_method_string(uhp);
if (cp != NULL) {
/* lichao added: openssl in trunk does not support ssl2 */
/*if (equal(cp, "ssl2"))
method = SSLv2_client_method();
else */if (equal(cp, "ssl3"))
method = SSLv3_client_method();
else if (equal(cp, "tls1"))
method = TLSv1_client_method();
else {
DEBUG_ERROR( catgets(catd, CATSET, 244,
"Invalid SSL method \"%s\"\n"), cp);
method = SSLv23_client_method();
}
} else
method = SSLv23_client_method();
return method;
}
static void
ssl_load_verifications(struct sock *sp)
{
char *ca_dir, *ca_file;
X509_STORE *store;
if (ssl_vrfy_level == VRFY_IGNORE)
return;
if ((ca_dir = value("ssl-ca-dir")) != NULL)
ca_dir = expand(ca_dir);
if ((ca_file = value("ssl-ca-file")) != NULL)
ca_file = expand(ca_file);
if (ca_dir || ca_file) {
if (SSL_CTX_load_verify_locations(sp->s_ctx,
ca_file, ca_dir) != 1) {
DEBUG_ERROR( catgets(catd, CATSET, 233,
"Error loading"));
if (ca_dir) {
DEBUG_ERROR( catgets(catd, CATSET, 234,
" %s"), ca_dir);
if (ca_file)
DEBUG_ERROR( catgets(catd, CATSET,
235, " or"));
}
if (ca_file)
DEBUG_ERROR( catgets(catd, CATSET, 236,
" %s"), ca_file);
DEBUG_ERROR( catgets(catd, CATSET, 237, "\n"));
}
}
if (value("ssl-no-default-ca") == NULL) {
if (SSL_CTX_set_default_verify_paths(sp->s_ctx) != 1)
DEBUG_ERROR( catgets(catd, CATSET, 243,
"Error loading default CA locations\n"));
}
verify_error_found = 0;
message_number = 0;
SSL_CTX_set_verify(sp->s_ctx, SSL_VERIFY_PEER, ssl_verify_cb);
store = SSL_CTX_get_cert_store(sp->s_ctx);
load_crls(store, "ssl-crl-file", "ssl-crl-dir");
}
static void
ssl_certificate(struct sock *sp, const char *uhp)
{
char *certvar, *keyvar, *cert, *key;
certvar = ac_alloc(strlen(uhp) + 10);
strcpy(certvar, "ssl-cert-");
strcpy(&certvar[9], uhp);
if ((cert = value(certvar)) != NULL ||
(cert = value("ssl-cert")) != NULL) {
cert = expand(cert);
if (SSL_CTX_use_certificate_chain_file(sp->s_ctx, cert) == 1) {
keyvar = ac_alloc(strlen(uhp) + 9);
strcpy(keyvar, "ssl-key-");
if ((key = value(keyvar)) == NULL &&
(key = value("ssl-key")) == NULL)
key = cert;
else
key = expand(key);
if (SSL_CTX_use_PrivateKey_file(sp->s_ctx, key,
SSL_FILETYPE_PEM) != 1)
DEBUG_ERROR( catgets(catd, CATSET, 238,
"cannot load private key from file %s\n"),
key);
ac_free(keyvar);
} else
DEBUG_ERROR( catgets(catd, CATSET, 239,
"cannot load certificate from file %s\n"),
cert);
}
ac_free(certvar);
}
static enum okay
ssl_check_host(const char *server, struct sock *sp)
{
X509 *cert;
X509_NAME *subj;
char data[256];
#ifdef HAVE_STACK_OF
STACK_OF(GENERAL_NAME) *gens;
#else
/*GENERAL_NAMES*/STACK *gens;
#endif
GENERAL_NAME *gen;
int i;
if ((cert = SSL_get_peer_certificate(sp->s_ssl)) == NULL) {
DEBUG_ERROR( catgets(catd, CATSET, 248,
"no certificate from \"%s\"\n"), server);
return STOP;
}
gens = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
if (gens != NULL) {
for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
gen = sk_GENERAL_NAME_value(gens, i);
if (gen->type == GEN_DNS) {
if (verbose)
DEBUG_ERROR(
"Comparing DNS name: \"%s\"\n",
gen->d.ia5->data);
if (rfc2595_hostname_match(server,
(char *)gen->d.ia5->data)
== OKAY)
goto found;
}
}
}
if ((subj = X509_get_subject_name(cert)) != NULL &&
X509_NAME_get_text_by_NID(subj, NID_commonName,
data, sizeof data) > 0) {
data[sizeof data - 1] = 0;
if (verbose)
DEBUG_ERROR("Comparing common name: \"%s\"\n",
data);
if (rfc2595_hostname_match(server, data) == OKAY)
goto found;
}
X509_free(cert);
return STOP;
found: X509_free(cert);
return OKAY;
}
enum okay
ssl_open(const char *server, struct sock *sp, const char *uhp)
{
char *cp;
long options;
ssl_init();
ssl_set_vrfy_level(uhp);
if ((sp->s_ctx =
SSL_CTX_new((SSL_METHOD *)ssl_select_method(uhp))) == NULL) {
ssl_gen_err(catgets(catd, CATSET, 261, "SSL_CTX_new() failed"));
return STOP;
}
#ifdef SSL_MODE_AUTO_RETRY
/* available with OpenSSL 0.9.6 or later */
SSL_CTX_set_mode(sp->s_ctx, SSL_MODE_AUTO_RETRY);
#endif /* SSL_MODE_AUTO_RETRY */
options = SSL_OP_ALL;
if (value("ssl-v2-allow") == NULL)
options |= SSL_OP_NO_SSLv2;
SSL_CTX_set_options(sp->s_ctx, options);
ssl_load_verifications(sp);
ssl_certificate(sp, uhp);
if ((cp = value("ssl-cipher-list")) != NULL) {
if (SSL_CTX_set_cipher_list(sp->s_ctx, cp) != 1)
DEBUG_ERROR( catgets(catd, CATSET, 240,
"invalid ciphers: %s\n"), cp);
}
if ((sp->s_ssl = SSL_new(sp->s_ctx)) == NULL) {
ssl_gen_err(catgets(catd, CATSET, 262, "SSL_new() failed"));
return STOP;
}
SSL_set_fd(sp->s_ssl, sp->s_fd);
if (SSL_connect(sp->s_ssl) < 0) {
ssl_gen_err(catgets(catd, CATSET, 263,
"could not initiate SSL/TLS connection"));
return STOP;
}
if (ssl_vrfy_level != VRFY_IGNORE) {
if (ssl_check_host(server, sp) != OKAY) {
DEBUG_ERROR( catgets(catd, CATSET, 249,
"host certificate does not match \"%s\"\n"),
server);
if (ssl_vrfy_decide() != OKAY)
return STOP;
}
}
sp->s_use_ssl = 1;
return OKAY;
}
void
ssl_gen_err(const char *fmt, ...)
{
#if (DEBUG_LEVEL >= DEBUG_LEVEL_ERROR)
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
SSL_load_error_strings();
DEBUG_ERROR(": %s\n",
(ERR_error_string(ERR_get_error(), NULL)));
#endif
}
FILE *
smime_sign(FILE *ip, struct header *headp)
{
FILE *sp, *fp, *bp, *hp;
char *cp, *addr;
X509 *cert;
PKCS7 *pkcs7;
EVP_PKEY *pkey;
BIO *bb, *sb;
ssl_init();
if ((addr = myorigin(headp)) == NULL) {
DEBUG_ERROR("No \"from\" address for signing specified\n");
return NULL;
}
if ((fp = smime_sign_cert(addr, NULL, 1)) == NULL)
return NULL;
if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb, NULL))
== NULL) {
ssl_gen_err("Error reading private key from");
Fclose(fp);
return NULL;
}
rewind(fp);
if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
ssl_gen_err("Error reading signer certificate from");
Fclose(fp);
EVP_PKEY_free(pkey);
return NULL;
}
Fclose(fp);
if ((sp = Ftemp(&cp, "Rs", "w+", 0600, 1)) == NULL) {
perror("tempfile");
X509_free(cert);
EVP_PKEY_free(pkey);
return NULL;
}
unlink(cp);
Ftfree(&cp);
rewind(ip);
if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
Fclose(sp);
X509_free(cert);
EVP_PKEY_free(pkey);
return NULL;
}
if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
(sb = BIO_new_fp(sp, BIO_NOCLOSE)) == NULL) {
ssl_gen_err("Error creating BIO signing objects");
Fclose(sp);
X509_free(cert);
EVP_PKEY_free(pkey);
return NULL;
}
if ((pkcs7 = PKCS7_sign(cert, pkey, NULL, bb,
PKCS7_DETACHED)) == NULL) {
ssl_gen_err("Error creating the PKCS#7 signing object");
BIO_free(bb);
BIO_free(sb);
Fclose(sp);
X509_free(cert);
EVP_PKEY_free(pkey);
return NULL;
}
if (PEM_write_bio_PKCS7(sb, pkcs7) == 0) {
ssl_gen_err("Error writing signed S/MIME data");
BIO_free(bb);
BIO_free(sb);
Fclose(sp);
X509_free(cert);
EVP_PKEY_free(pkey);
return NULL;
}
BIO_free(bb);
BIO_free(sb);
X509_free(cert);
EVP_PKEY_free(pkey);
rewind(bp);
fflush(sp);
rewind(sp);
return smime_sign_assemble(hp, bp, sp);
}
static EVP_CIPHER *
smime_cipher(const char *name)
{
const EVP_CIPHER *cipher;
char *vn, *cp;
int vs;
vn = ac_alloc(vs = strlen(name) + 30);
snprintf(vn, vs, "smime-cipher-%s", name);
if ((cp = value(vn)) != NULL) {
if (strcmp(cp, "rc2-40") == 0)
cipher = EVP_rc2_40_cbc();
else if (strcmp(cp, "rc2-64") == 0)
cipher = EVP_rc2_64_cbc();
else if (strcmp(cp, "des") == 0)
cipher = EVP_des_cbc();
else if (strcmp(cp, "des-ede3") == 0)
cipher = EVP_des_ede3_cbc();
else {
DEBUG_ERROR("Invalid cipher \"%s\".\n", cp);
cipher = NULL;
}
} else
cipher = EVP_des_ede3_cbc();
ac_free(vn);
return (EVP_CIPHER *)cipher;
}
FILE *
smime_encrypt(FILE *ip, const char *certfile, const char *to)
{
FILE *yp, *fp, *bp, *hp;
char *cp;
X509 *cert;
PKCS7 *pkcs7;
BIO *bb, *yb;
#ifdef HAVE_STACK_OF
STACK_OF(X509) *certs;
#else
STACK *certs;
#endif
EVP_CIPHER *cipher;
certfile = expand((char *)certfile);
ssl_init();
if ((cipher = smime_cipher(to)) == NULL)
return NULL;
if ((fp = Fopen(certfile, "r")) == NULL) {
perror(certfile);
return NULL;
}
if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb, NULL)) == NULL) {
ssl_gen_err("Error reading encryption certificate from \"%s\"",
certfile);
Fclose(fp);
return NULL;
}
Fclose(fp);
certs = sk_X509_new_null();
sk_X509_push(certs, cert);
if ((yp = Ftemp(&cp, "Ry", "w+", 0600, 1)) == NULL) {
perror("tempfile");
return NULL;
}
unlink(cp);
Ftfree(&cp);
rewind(ip);
if (smime_split(ip, &hp, &bp, -1, 0) == STOP) {
Fclose(yp);
return NULL;
}
if ((bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL ||
(yb = BIO_new_fp(yp, BIO_NOCLOSE)) == NULL) {
ssl_gen_err("Error creating BIO encryption objects");
Fclose(yp);
return NULL;
}
if ((pkcs7 = PKCS7_encrypt(certs, bb, cipher, 0)) == NULL) {
ssl_gen_err("Error creating the PKCS#7 encryption object");
BIO_free(bb);
BIO_free(yb);
Fclose(yp);
return NULL;
}
if (PEM_write_bio_PKCS7(yb, pkcs7) == 0) {
ssl_gen_err("Error writing encrypted S/MIME data");
BIO_free(bb);
BIO_free(yb);
Fclose(yp);
return NULL;
}
BIO_free(bb);
BIO_free(yb);
Fclose(bp);
fflush(yp);
rewind(yp);
return smime_encrypt_assemble(hp, yp);
}
struct message *
smime_decrypt(struct message *m, const char *to, const char *cc, int signcall)
{
FILE *fp, *bp, *hp, *op;
char *cp;
X509 *cert = NULL;
PKCS7 *pkcs7;
EVP_PKEY *pkey = NULL;
BIO *bb, *pb, *ob;
long size = m->m_size;
FILE *yp;
if ((yp = setinput(&mb, m, NEED_BODY)) == NULL)
return NULL;
ssl_init();
if ((fp = smime_sign_cert(to, cc, 0)) != NULL) {
if ((pkey = PEM_read_PrivateKey(fp, NULL, ssl_password_cb,
NULL)) == NULL) {
ssl_gen_err("Error reading private key");
Fclose(fp);
return NULL;
}
rewind(fp);
if ((cert = PEM_read_X509(fp, NULL, ssl_password_cb,
NULL)) == NULL) {
ssl_gen_err("Error reading decryption certificate");
Fclose(fp);
EVP_PKEY_free(pkey);
return NULL;
}
Fclose(fp);
}
if ((op = Ftemp(&cp, "Rp", "w+", 0600, 1)) == NULL) {
perror("tempfile");
if (cert)
X509_free(cert);
if (pkey)
EVP_PKEY_free(pkey);
return NULL;
}
unlink(cp);
Ftfree(&cp);
if (smime_split(yp, &hp, &bp, size, 1) == STOP) {
Fclose(op);
if (cert)
X509_free(cert);
if (pkey)
EVP_PKEY_free(pkey);
return NULL;
}
if ((ob = BIO_new_fp(op, BIO_NOCLOSE)) == NULL ||
(bb = BIO_new_fp(bp, BIO_NOCLOSE)) == NULL) {
ssl_gen_err("Error creating BIO decryption objects");
Fclose(op);
if (cert)
X509_free(cert);
if (pkey)
EVP_PKEY_free(pkey);
return NULL;
}
if ((pkcs7 = SMIME_read_PKCS7(bb, &pb)) == NULL) {
ssl_gen_err("Error reading PKCS#7 object");
Fclose(op);
if (cert)
X509_free(cert);
if (pkey)
EVP_PKEY_free(pkey);
return NULL;
}
if (PKCS7_type_is_signed(pkcs7)) {
if (signcall) {
BIO_free(bb);
BIO_free(ob);
if (cert)
X509_free(cert);
if (pkey)
EVP_PKEY_free(pkey);
Fclose(op);
Fclose(bp);
Fclose(hp);
setinput(&mb, m, NEED_BODY);
return (struct message *)-1;
}
if (PKCS7_verify(pkcs7, NULL, NULL, NULL, ob,
PKCS7_NOVERIFY|PKCS7_NOSIGS) != 1)
goto err;
fseek(hp, 0L, SEEK_END);
fprintf(hp, "X-Encryption-Cipher: none\n");
fflush(hp);
rewind(hp);
} else if (pkey == NULL) {
DEBUG_ERROR("No appropriate private key found.\n");
goto err2;
} else if (cert == NULL) {
DEBUG_ERROR("No appropriate certificate found.\n");
goto err2;
} else if (PKCS7_decrypt(pkcs7, pkey, cert, ob, 0) != 1) {
err: ssl_gen_err("Error decrypting PKCS#7 object");
err2: BIO_free(bb);
BIO_free(ob);
Fclose(op);
Fclose(bp);
Fclose(hp);
if (cert)
X509_free(cert);
if (pkey)
EVP_PKEY_free(pkey);
return NULL;
}
BIO_free(bb);
BIO_free(ob);
if (cert)
X509_free(cert);
if (pkey)
EVP_PKEY_free(pkey);
fflush(op);
rewind(op);
Fclose(bp);
return smime_decrypt_assemble(m, hp, op);
}
/*ARGSUSED4*/
static int
ssl_password_cb(char *buf, int size, int rwflag, void *userdata)
{
sighandler_type saveint;
char *pass = NULL;
int len;
(void)&saveint;
(void)&pass;
saveint = safe_signal(SIGINT, SIG_IGN);
if (sigsetjmp(ssljmp, 1) == 0) {
if (saveint != SIG_IGN)
safe_signal(SIGINT, sslcatch);
pass = getpassword(&otio, &reset_tio, "PEM pass phrase:");
}
safe_signal(SIGINT, saveint);
if (pass == NULL)
return 0;
len = strlen(pass);
if (len > size)
len = size;
memcpy(buf, pass, len);
return len;
}
static FILE *
smime_sign_cert(const char *xname, const char *xname2, int warn)
{
char *vn, *cp;
int vs;
FILE *fp;
struct name *np;
const char *name = xname, *name2 = xname2;
loop: if (name) {
np = sextract(savestr(name), GTO|GSKIN);
while (np) {
/*
* This needs to be more intelligent since it will
* currently take the first name for which a private
* key is available regardless of whether it is the
* right one for the message.
*/
vn = ac_alloc(vs = strlen(np->n_name) + 30);
snprintf(vn, vs, "smime-sign-cert-%s", np->n_name);
if ((cp = value(vn)) != NULL)
goto open;
np = np->n_flink;
}
if (name2) {
name = name2;
name2 = NULL;
goto loop;
}
}
if ((cp = value("smime-sign-cert")) != NULL)
goto open;
if (warn) {
DEBUG_ERROR("Could not find a certificate for %s", xname);
if (xname2)
DEBUG_ERROR("or %s", xname2);
DEBUG_ERROR("%c", '\n');
}
return NULL;
open: cp = expand(cp);
if ((fp = Fopen(cp, "r")) == NULL) {
perror(cp);
return NULL;
}
return fp;
}
#if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
static enum okay
load_crl1(X509_STORE *store, const char *name)
{
X509_LOOKUP *lookup;
if (verbose)
DEBUG_PRINT("Loading CRL from \"%s\".\n", name);
if ((lookup = X509_STORE_add_lookup(store,
X509_LOOKUP_file())) == NULL) {
ssl_gen_err("Error creating X509 lookup object");
return STOP;
}
if (X509_load_crl_file(lookup, name, X509_FILETYPE_PEM) != 1) {
ssl_gen_err("Error loading CRL from \"%s\"", name);
return STOP;
}
return OKAY;
}
#endif /* new OpenSSL */
static enum okay
load_crls(X509_STORE *store, const char *vfile, const char *vdir)
{
char *crl_file, *crl_dir;
#if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
DIR *dirfd;
struct dirent *dp;
char *fn = NULL;
int fs = 0, ds, es;
#endif /* new OpenSSL */
if ((crl_file = value(vfile)) != NULL) {
#if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
crl_file = expand(crl_file);
if (load_crl1(store, crl_file) != OKAY)
return STOP;
#else /* old OpenSSL */
DEBUG_ERROR(
"This OpenSSL version is too old to use CRLs.\n");
return STOP;
#endif /* old OpenSSL */
}
if ((crl_dir = value(vdir)) != NULL) {
#if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
crl_dir = expand(crl_dir);
ds = strlen(crl_dir);
if ((dirfd = opendir(crl_dir)) == NULL) {
perror(crl_dir);
return STOP;
}
fn = smalloc(fs = ds + 20);
strcpy(fn, crl_dir);
fn[ds] = '/';
while ((dp = readdir(dirfd)) != NULL) {
if (dp->d_name[0] == '.' &&
(dp->d_name[1] == '\0' ||
(dp->d_name[1] == '.' &&
dp->d_name[2] == '\0')))
continue;
if (dp->d_name[0] == '.')
continue;
if (ds + (es = strlen(dp->d_name)) + 2 < fs)
fn = srealloc(fn, fs = ds + es + 20);
strcpy(&fn[ds+1], dp->d_name);
if (load_crl1(store, fn) != OKAY) {
closedir(dirfd);
free(fn);
return STOP;
}
}
closedir(dirfd);
free(fn);
#else /* old OpenSSL */
DEBUG_ERROR(
"This OpenSSL version is too old to use CRLs.\n");
return STOP;
#endif /* old OpenSSL */
}
#if defined (X509_V_FLAG_CRL_CHECK) && defined (X509_V_FLAG_CRL_CHECK_ALL)
if (crl_file || crl_dir)
X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK |
X509_V_FLAG_CRL_CHECK_ALL);
#endif /* old OpenSSL */
return OKAY;
}