From e9554c597f7f33c6ebebaa47087b4db878a59913 Mon Sep 17 00:00:00 2001 From: Eduardo Chappa Date: Sun, 9 Mar 2014 14:26:50 -0600 Subject: * Forwarding messages with attachments of content-type multipart, failed when attempting to sign it, with and "Error writing pipe" error. * Using a .pinerc file outside the home directory made Alpine not find the .alpine-smime directory with certificates. * Configuration screen for S/MIME adds ability to manage certificates. (currently available to users who manage certificates in directories, not in containers, which will be available in the next alpha release.) --- pith/smime.c | 573 ++++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 471 insertions(+), 102 deletions(-) (limited to 'pith/smime.c') diff --git a/pith/smime.c b/pith/smime.c index 469a381e..e691ae68 100644 --- a/pith/smime.c +++ b/pith/smime.c @@ -45,20 +45,15 @@ static char rcsid[] = "$Id: smime.c 1176 2008-09-29 21:16:42Z hubert@u.washingto #include - -typedef enum {Public, Private, CACert} WhichCerts; - - /* internal prototypes */ static void forget_private_keys(void); static int app_RAND_load_file(const char *file); static void openssl_extra_randomness(void); static int app_RAND_write_file(const char *file); -static void smime_init(void); static const char *openssl_error_string(void); +static int load_private_key(PERSONAL_CERT *pcert); static void create_local_cache(char *h, char *base, BODY *b); static long rfc822_output_func(void *b, char *string); -static int load_private_key(PERSONAL_CERT *pcert); static void setup_pkcs7_body_for_signature(BODY *b, char *description, char *type, char *filename); static BIO *body_to_bio(BODY *body); @@ -73,10 +68,14 @@ static void free_smime_struct(SMIME_STUFF_S **smime); static void setup_storage_locations(void); static int copy_dir_to_container(WhichCerts which); static int copy_container_to_dir(WhichCerts which); - +int smime_path(char *rpath, char *fpath, size_t len); +int smime_extract_and_save_cert(PKCS7 *p7); +int same_cert(X509 *, X509 *); +CertList * certlist_from_personal_certs(PERSONAL_CERT *pc); int (*pith_opt_smime_get_passphrase)(void); - +int (*pith_smime_import_certificate)(char *, char *, size_t); +char *(*pith_enter_password)(char *prompt, char *, size_t); static X509_STORE *s_cert_store; @@ -85,6 +84,189 @@ static int seeded = 0; static int egdsocket = 0; +int +import_certificate(WhichCerts ctype) +{ + int r = 1; + char filename[MAXPATH+1], full_filename[MAXPATH+1], buf[MAXPATH+1]; + + if(pith_smime_import_certificate == NULL) + q_status_message(SM_ORDER, 0, 2, + _("import of certificates not implemented yet!")); + + smime_init(); + + r = (*pith_smime_import_certificate)(filename, full_filename, sizeof(filename) - 20); + if(r < 0){ + switch(r){ + default: + case -1: + cmd_cancelled("Import certificate"); + break; + + case -2: + q_status_message1(SM_ORDER, 0, 2, + _("Can't import certificate outside of %s"), + ps_global->VAR_OPER_DIR); + break; + } + } else if (ctype == Private){ + char prompt[500], *s, *t; + char pass[MAILTMPLEN+1]; + BIO *in; + EVP_PKEY *key = NULL; + PERSONAL_CERT *pc; + + if(!ps_global->smime->privatecertdata){ + ps_global->smime->privatecertdata = fs_get(sizeof(CertList)); + memset((void *)DATACERT(ctype), 0, sizeof(CertList)); + } + + if(!(in = BIO_new_file(full_filename, "r"))) + return -1; + + for(s = t = filename; (t = strstr(s, ".key")) != NULL; s = t + 1); + if(s) *(s-1) = 0; + + snprintf(prompt, sizeof(prompt), + _("Enter passphrase for <%s>: "), s ? s : filename); + + pass[0] = '\0'; + if(pith_enter_password) + (*pith_enter_password)(prompt, (char *)pass, sizeof(pass)); + + if((key = PEM_read_bio_PrivateKey(in, NULL, NULL, pass)) != NULL){ + if(SMHOLDERTYPE(ctype) == Directory){ + STORE_S *in_cert, *out_cert; + char c; + + build_path(buf, PATHCERTDIR(ctype), filename, sizeof(buf)); + if(strcmp(buf + strlen(buf) - 4, EXTCERT(ctype)) != 0 && strlen(buf) + 4 < sizeof(buf)) + strcat(buf, EXTCERT(ctype)); + + in_cert = so_get(FileStar, full_filename, READ_ACCESS | READ_FROM_LOCALE); + out_cert = so_get(FileStar, buf, WRITE_ACCESS | WRITE_TO_LOCALE); + + if(in_cert != NULL && out_cert != NULL){ + while(so_readc(&c, in_cert) > 0) + so_writec(c, out_cert); + q_status_message(SM_ORDER, 1, 3, _("Certificate saved")); + } + else + q_status_message(SM_ORDER, 1, 3, _("Error saving certificate")); + + so_give(&in_cert); + so_give(&out_cert); + } + if(ps_global->smime->publiccertdata) + ps_global->smime->publiccertdata->data.renew = 1; + } + else + q_status_message(SM_ORDER, 1, 3, _("Problem unlocking key (not a certificate and/or wrong password)")); + BIO_free(in); + } else if (ctype == CACert){ + BIO *ins; + X509 *cert; + + if((ins = BIO_new_file(full_filename, "r")) != NULL){ + if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL){ + if(SMHOLDERTYPE(ctype) == Directory){ + STORE_S *in_cert, *out_cert; + char c; + + build_path(buf, PATHCERTDIR(ctype), filename, sizeof(buf)); + if(strcmp(buf + strlen(buf) - 4, ".crt") != 0 && strlen(buf) + 4 < sizeof(buf)) + strcat(buf, EXTCERT(ctype)); + + in_cert = so_get(FileStar, full_filename, READ_ACCESS | READ_FROM_LOCALE); + out_cert = so_get(FileStar, buf, WRITE_ACCESS | WRITE_TO_LOCALE); + + if(in_cert != NULL && out_cert != NULL){ + while(so_readc(&c, in_cert) > 0) + so_writec(c, out_cert); + q_status_message(SM_ORDER, 1, 3, _("Certificate saved")); + } + else + q_status_message(SM_ORDER, 1, 3, _("Error saving certificate")); + + so_give(&in_cert); + so_give(&out_cert); + } + X509_free(cert); /* not needed anymore */ + } + else + q_status_message(SM_ORDER, 1, 3, _("Error in certificate file (not a certificate?)")); + BIO_free(ins); + } + renew_store(); + } else { /* ctype == Public. save certificate, but first validate that it is one */ + BIO *ins; + X509 *cert; + + if((ins = BIO_new_file(full_filename, "r")) != NULL){ + if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL){ + char **email = get_x509_subject_email(cert); + int i; + + for(i = 0; email[i] != NULL; i++){ + save_cert_for(email[i], cert, Public); + fs_give((void **)&email[i]); + } + fs_give((void **)email); + X509_free(cert); + if(ps_global->smime->publiccertdata) + ps_global->smime->publiccertdata->data.renew = 1; + } + else + q_status_message(SM_ORDER, 1, 3, _("Error in certificate file (not a certificate?)")); + BIO_free(ins); + } + } + if(DATACERT(ctype)) RENEWCERT(DATACERT(ctype)) = 1; + ps_global->mangled_screen = 1; + return 0; +} + +/* itype: information type to add: 0 - public, 1 - private. + * Memory freed by caller + */ +BIO * +print_private_key_information(char *email, int itype) +{ + BIO *out; + PERSONAL_CERT *pc; + + if(ps_global->smime == NULL + || ps_global->smime->personal_certs == NULL + || (itype != 0 && itype != 1)) + return NULL; + + for(pc = ps_global->smime->personal_certs; + pc != NULL && strcmp(pc->name, email) != 0; pc = pc->next); + if(pc->key == NULL + && !load_private_key(pc) + && ps_global->smime + && ps_global->smime->need_passphrase){ + if (*pith_opt_smime_get_passphrase) + (*pith_opt_smime_get_passphrase)(); + load_private_key(pc); + } + + if(pc->key == NULL) + return NULL; + + out = BIO_new(BIO_s_mem()); + if(itype == 0) /* 0 means public */ + EVP_PKEY_print_public(out, pc->key, 0, NULL); + else if (itype == 1) /* 1 means private */ + EVP_PKEY_print_private(out, pc->key, 0, NULL); + + if(F_OFF(F_REMEMBER_SMIME_PASSPHRASE,ps_global)) + forget_private_keys(); + + return out; +} + /* * Forget any cached private keys */ @@ -116,6 +298,41 @@ forget_private_keys(void) } } +/* modelled after signature_path in reply.c, but uses home dir instead of the + * directory where the .pinerc is located, since according to documentation, + * the .alpine-smime directories are subdirectories of the home directory + */ + +int smime_path(char *rpath, char *fpath, size_t len) +{ + *fpath = '\0'; + if(rpath && *rpath){ + size_t spl = strlen(rpath); + + *fpath = '\0'; + if(IS_REMOTE(rpath)){ + if(spl < len - 1) + strncpy(fpath, rpath, len-1); + fpath[len-1] = '\0'; + } + else if(is_absolute_path(rpath)){ + strncpy(fpath, rpath, len-1); + fpath[len-1] = '\0'; + fnexpand(fpath, len); + } + else if(ps_global->VAR_OPER_DIR){ + if(strlen(ps_global->VAR_OPER_DIR) + spl < len - 1) + build_path(fpath, ps_global->VAR_OPER_DIR, rpath, len); + } + else if(ps_global->home_dir){ + if(strlen(ps_global->home_dir) + spl < len - 1) + build_path(fpath, ps_global->home_dir, rpath, len); + } + } + return fpath && *fpath ? 1 : 0; +} + + /* * taken from openssl/apps/app_rand.c @@ -216,6 +433,66 @@ app_RAND_write_file(const char *file) return 1; } +CertList * +certlist_from_personal_certs(PERSONAL_CERT *pc) +{ + CertList *cl; + + if(pc == NULL) + return NULL; + + cl = fs_get(sizeof(CertList)); + memset((void *)cl, 0, sizeof(CertList)); + cl->name = cpystr(pc->name); + cl->next = certlist_from_personal_certs(pc->next); + + return cl; +} + + +void +renew_cert_data(CertList **data, WhichCerts ctype) +{ + smime_init(); + if(ctype == Private){ + if(data){ + PERSONAL_CERT *pc = (PERSONAL_CERT *)ps_global->smime->personal_certs; + if(*data) + free_certlist(data); + free_personal_certs(&pc); + ps_global->smime->personal_certs = (void *) get_personal_certs(ps_global->smime->privatepath); + *data = certlist_from_personal_certs((PERSONAL_CERT *)ps_global->smime->personal_certs); + if(data && *data) + RENEWCERT(*data) = 0; + ps_global->smime->privatecertdata = (CertList *) *data; + } + if(ps_global->smime->privatecertdata) + RENEWCERT(ps_global->smime->privatecertdata) = 0; + } else { + X509_LOOKUP *lookup = NULL; + X509_STORE *store = NULL; + + if((store = X509_STORE_new()) != NULL) + if ((lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file())) == NULL){ + X509_STORE_free(store); + store = NULL; + } + else{ + if(PATHCERTDIR(ctype)){ + free_certlist(data); + add_certs_in_dir(lookup, PATHCERTDIR(ctype), EXTCERT(ctype), data); + if(data && *data) + RENEWCERT(*data) = 0; + if(ctype == Public) + ps_global->smime->publiccertdata = *data; + else + ps_global->smime->cacertdata = *data; + } + } + } +} + + /* Installed as an atexit() handler to save the random data */ void @@ -226,9 +503,18 @@ smime_deinit(void) free_smime_struct(&ps_global->smime); } +/* we renew the store when it has changed */ +void renew_store(void) +{ + if(ps_global->smime->inited){ + if(s_cert_store != NULL) + X509_STORE_free(s_cert_store); + s_cert_store = get_ca_store(); + } +} /* Initialise openssl stuff if needed */ -static void +void smime_init(void) { if(F_OFF(F_DONT_DO_SMIME, ps_global) && !(ps_global->smime && ps_global->smime->inited)){ @@ -254,6 +540,73 @@ smime_init(void) } +/* validate a certificate. Return value : 0 for no error, -1 for error. + * In the latter case, set the openssl smime error in *error. + */ +int smime_validate_cert(X509 *cert, long *error) +{ + X509_STORE_CTX *csc; + + ERR_clear_error(); + *error = 0; + if((csc = X509_STORE_CTX_new()) != NULL){ + X509_STORE_set_flags(s_cert_store, 0); + if(X509_STORE_CTX_init(csc,s_cert_store,cert,NULL) + && X509_verify_cert(csc) <= 0) + *error = X509_STORE_CTX_get_error(csc); + X509_STORE_CTX_free(csc); + } + return *error ? -1 : 0; +} + +PERSONAL_CERT * +get_personal_certs(char *path) +{ + PERSONAL_CERT *result = NULL; + char buf2[MAXPATH]; + struct dirent *d; + DIR *dirp; + + ps_global->smime->privatepath = cpystr(path); + dirp = opendir(path); + if(dirp){ + while((d=readdir(dirp)) != NULL){ + X509 *cert; + size_t ll; + + if((ll=strlen(d->d_name)) && ll > 4 && !strcmp(d->d_name+ll-4, ".key")){ + + /* copy file name to temp buffer */ + strncpy(buf2, d->d_name, sizeof(buf2)-1); + buf2[sizeof(buf2)-1] = '\0'; + /* chop off ".key" trailier */ + buf2[strlen(buf2)-4] = 0; + /* Look for certificate */ + cert = get_cert_for(buf2, Public); + + if(cert){ + PERSONAL_CERT *pc; + + /* create a new PERSONAL_CERT, fill it in */ + + pc = (PERSONAL_CERT *) fs_get(sizeof(*pc)); + pc->cert = cert; + pc->name = cpystr(buf2); + + /* Try to load the key with an empty password */ + pc->key = load_key(pc, ""); + + pc->next = result; + result = pc; + } + } + } + closedir(dirp); + } + return result; +} + + static void setup_storage_locations(void) { @@ -275,7 +628,7 @@ setup_storage_locations(void) publiccertcontainer = 1; contents = NULL; path[0] = '\0'; - if(!signature_path(ps_global->VAR_PUBLICCERT_CONTAINER, path, MAXPATH)) + if(!smime_path(ps_global->VAR_PUBLICCERT_CONTAINER, path, MAXPATH)) publiccertcontainer = 0; if(publiccertcontainer && !IS_REMOTE(path) @@ -313,7 +666,7 @@ setup_storage_locations(void) ps_global->smime->publictype = Directory; path[0] = '\0'; - if(!(signature_path(ps_global->VAR_PUBLICCERT_DIR, path, MAXPATH) + if(!(smime_path(ps_global->VAR_PUBLICCERT_DIR, path, MAXPATH) && !IS_REMOTE(path))) ps_global->smime->publictype = Nada; else if(can_access(path, ACCESS_EXISTS)){ @@ -337,7 +690,7 @@ setup_storage_locations(void) privatekeycontainer = 1; contents = NULL; path[0] = '\0'; - if(!signature_path(ps_global->VAR_PRIVATEKEY_CONTAINER, path, MAXPATH)) + if(!smime_path(ps_global->VAR_PRIVATEKEY_CONTAINER, path, MAXPATH)) privatekeycontainer = 0; if(privatekeycontainer && !IS_REMOTE(path) @@ -377,7 +730,7 @@ setup_storage_locations(void) ps_global->smime->privatetype = Directory; path[0] = '\0'; - if(!(signature_path(ps_global->VAR_PRIVATEKEY_DIR, path, MAXPATH) + if(!(smime_path(ps_global->VAR_PRIVATEKEY_DIR, path, MAXPATH) && !IS_REMOTE(path))) ps_global->smime->privatetype = Nada; else if(can_access(path, ACCESS_EXISTS)){ @@ -387,52 +740,8 @@ setup_storage_locations(void) } } - if(ps_global->smime->privatetype == Directory){ - char buf2[MAXPATH]; - struct dirent *d; - DIR *dirp; - - ps_global->smime->privatepath = cpystr(path); - dirp = opendir(path); - if(dirp){ - - while((d=readdir(dirp)) != NULL){ - X509 *cert; - size_t ll; - - if((ll=strlen(d->d_name)) && ll > 4 && !strcmp(d->d_name+ll-4, ".key")){ - - /* copy file name to temp buffer */ - strncpy(buf2, d->d_name, sizeof(buf2)-1); - buf2[sizeof(buf2)-1] = '\0'; - /* chop off ".key" trailier */ - buf2[strlen(buf2)-4] = 0; - /* Look for certificate */ - cert = get_cert_for(buf2); - - if(cert){ - PERSONAL_CERT *pc; - - /* create a new PERSONAL_CERT, fill it in */ - - pc = (PERSONAL_CERT *) fs_get(sizeof(*pc)); - pc->cert = cert; - pc->name = cpystr(buf2); - - /* Try to load the key with an empty password */ - pc->key = load_key(pc, ""); - - pc->next = result; - result = pc; - } - } - } - - closedir(dirp); - } - } - - ps_global->smime->personal_certs = result; + if(ps_global->smime->privatetype == Directory) + ps_global->smime->personal_certs = get_personal_certs(path); } /* extra cacerts in a container */ @@ -441,7 +750,7 @@ setup_storage_locations(void) cacertcontainer = 1; contents = NULL; path[0] = '\0'; - if(!signature_path(ps_global->VAR_CACERT_CONTAINER, path, MAXPATH)) + if(!smime_path(ps_global->VAR_CACERT_CONTAINER, path, MAXPATH)) cacertcontainer = 0; if(cacertcontainer && !IS_REMOTE(path) @@ -474,7 +783,7 @@ setup_storage_locations(void) ps_global->smime->catype = Directory; path[0] = '\0'; - if(!(signature_path(ps_global->VAR_CACERT_DIR, path, MAXPATH) + if(!(smime_path(ps_global->VAR_CACERT_DIR, path, MAXPATH) && !IS_REMOTE(path))) ps_global->smime->catype = Nada; else if(can_access(path, ACCESS_EXISTS)){ @@ -598,7 +907,7 @@ copy_dir_to_container(WhichCerts which) * If there is a legit directory to read from set up the * container file to write to. */ - if(signature_path(configdir, srcpath, MAXPATH) && !IS_REMOTE(srcpath)){ + if(smime_path(configdir, srcpath, MAXPATH) && !IS_REMOTE(srcpath)){ if(IS_REMOTE(configpath)){ rd = rd_create_remote(RemImap, configpath, REMOTE_SMIME_SUBTYPE, @@ -829,7 +1138,7 @@ copy_container_to_dir(WhichCerts which) fs_give((void **) &ps_global->smime->publicpath); path[0] = '\0'; - if(!(signature_path(ps_global->VAR_PUBLICCERT_DIR, path, MAXPATH) + if(!(smime_path(ps_global->VAR_PUBLICCERT_DIR, path, MAXPATH) && !IS_REMOTE(path))){ q_status_message(SM_ORDER, 3, 3, _("Directory is not defined")); return -1; @@ -859,7 +1168,7 @@ copy_container_to_dir(WhichCerts which) fs_give((void **) &ps_global->smime->privatepath); path[0] = '\0'; - if(!(signature_path(ps_global->VAR_PRIVATEKEY_DIR, path, MAXPATH) + if(!(smime_path(ps_global->VAR_PRIVATEKEY_DIR, path, MAXPATH) && !IS_REMOTE(path))){ q_status_message(SM_ORDER, 3, 3, _("Directory is not defined")); return -1; @@ -889,7 +1198,7 @@ copy_container_to_dir(WhichCerts which) fs_give((void **) &ps_global->smime->capath); path[0] = '\0'; - if(!(signature_path(ps_global->VAR_CACERT_DIR, path, MAXPATH) + if(!(smime_path(ps_global->VAR_CACERT_DIR, path, MAXPATH) && !IS_REMOTE(path))){ q_status_message(SM_ORDER, 3, 3, _("Directory is not defined")); return -1; @@ -1342,7 +1651,7 @@ encrypt_file(char *fp, char *text) cipher = EVP_aes_256_cbc(); encerts = sk_X509_new_null(); - if((cert = get_cert_for(pcert->name)) != NULL) + if((cert = get_cert_for(pcert->name, Public)) != NULL) sk_X509_push(encerts, cert); else goto end; @@ -1414,7 +1723,7 @@ encrypt_outgoing_message(METAENV *header, BODY **bodyP) snprintf(buf, sizeof(buf), "%s@%s", a->mailbox, a->host); - cert = get_cert_for(buf); + cert = get_cert_for(buf, Public); if(cert) sk_X509_push(encerts,cert); else{ @@ -1545,6 +1854,88 @@ get_pkcs7_from_part(long msgno,const char *section) return p7; } +int same_cert(X509 *x, X509 *cert) +{ + char bufcert[256], bufx[256]; + int rv = 0; + + get_fingerprint(cert, EVP_md5(), bufcert, sizeof(bufcert)); + get_fingerprint(x, EVP_md5(), bufx, sizeof(bufx)); + if(strcmp(bufx, bufcert) == 0) + rv = 1; + + return rv; +} + + +/* extract and save certificates from a PKCS7 package. The ctype variable + * tells us if we want to extract it to a public/ or a ca/ directory. The + * later makes sense only for recoverable errors (errors that can be fixed + * by saving to the ca/ directory before we verify the signature). + * Return value: + * 0 - no errors (in public/) no need to try again, + * or validated self signed certificate (in ca/) + * 1 - self signed certificate was saved in public/, try again to validate it + * 2 - user was prompted about self-signed certificate, but certificate was not saved + * < 0 - certificate error is not recoverable, don't even think about it. + */ + +int smime_extract_and_save_cert(PKCS7 *p7) +{ + STACK_OF(X509) *signers; + X509 *x, *cert; + char **email; + int i, j, rv; + long error; + + if((signers = PKCS7_get0_signers(p7, NULL, 0)) == NULL) + return -1; + + rv = 0; /* assume no error */ + for(i = 0; i < sk_X509_num(signers); i++){ + if((x = sk_X509_value(signers,i)) == NULL) + continue; + + if((email = get_x509_subject_email(x)) != NULL){ + for(j = 0; email[j] != NULL; j++){ + if((cert = get_cert_for(email[j], Public)) == NULL || same_cert(x, cert) == 0) + save_cert_for(email[j], x, Public); + + if(smime_validate_cert(cert, &error) < 0){ + const char *error_string = X509_verify_cert_error_string(error); + dprint((1, "Certificate verify error code %lu for <%s>", error, email[j])); + switch(error){ + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + rv = 2; /* recoverable error */ + break; + default : rv = -1; /* not recoverable error */ + break; + } + sprintf(tmp_20k_buf, "%s <%s>: %s", _("Error in certificate for "), email[j], error_string); + q_status_message(SM_ORDER | SM_DING, 2, 2, tmp_20k_buf); +#if 0 + if(pith_opt_action_certificate_error) + switch((*pith_opt_action_certificate_error)(cert_error)){ + case 1 : save_cert_for(email[j], x, CACert); + renew_store(); + rv = 0; + break; + case 0 : + default : break; + } +#endif + } + X509_free(cert); + } + fs_give((void **) &email[i]); + } + fs_give((void **) email); + } + sk_X509_free(signers); + + return rv; +} /* * Try to verify a signature. @@ -1558,15 +1949,10 @@ static int do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent) { STACK_OF(X509) *otherCerts = NULL; - int result; + int result; const char *data; long err; -#if 0 - if (in) - dump_bio_to_file(in,"/tmp/verified-data"); -#endif - if(!s_cert_store){ if(!silent) q_status_message(SM_ORDER | SM_DING, 2, 2, _("Couldn't verify S/MIME signature: No CA Certs were loaded")); @@ -1574,6 +1960,8 @@ do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent) return -1; } + smime_extract_and_save_cert(p7); + result = PKCS7_verify(p7, otherCerts, s_cert_store, in, out, 0); if(result){ @@ -1593,34 +1981,6 @@ do_signature_verify(PKCS7 *p7, BIO *in, BIO *out, int silent) _("Couldn't verify S/MIME signature: %s"), (char*) openssl_error_string()); } - /* now try to extract the certificates of any signers */ - { - STACK_OF(X509) *signers; - int i; - - if((signers = PKCS7_get0_signers(p7, NULL, 0)) != NULL) - for(i=0; ikey) == NULL) goto end; - recip = get_cert_for(pcert->name); + recip = get_cert_for(pcert->name, Public); out = BIO_new(BIO_s_mem()); (void) BIO_reset(out); @@ -2383,6 +2743,15 @@ free_smime_struct(SMIME_STUFF_S **smime) if((*smime)->publiccertlist) free_certlist(&(*smime)->publiccertlist); + if((*smime)->publiccertdata) + free_certlist(&(*smime)->publiccertdata); + + if((*smime)->privatecertdata) + free_certlist(&(*smime)->privatecertdata); + + if((*smime)->cacertdata) + free_certlist(&(*smime)->cacertdata); + if((*smime)->publiccontent) fs_give((void **) &(*smime)->publiccontent); -- cgit v1.2.3-54-g00ecf