summaryrefslogtreecommitdiff
path: root/pith
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2016-02-28 14:12:49 -0700
committerEduardo Chappa <chappa@washington.edu>2016-02-28 14:12:49 -0700
commit4bf825141cd564a2c5a23c55f79e04665c428641 (patch)
tree4fd033202e91d414985f4896fe63b0039adc2cf2 /pith
parentdc1062254da60a0f2bf8d52e861dbf4fb7b8cab9 (diff)
downloadalpine-4bf825141cd564a2c5a23c55f79e04665c428641.tar.xz
* Add the ability to change the private key and certificates used
to encrypt a password file in the SMIME setup configuration screen.
Diffstat (limited to 'pith')
-rw-r--r--pith/conftype.h51
-rw-r--r--pith/imap.c52
-rw-r--r--pith/imap.h4
-rw-r--r--pith/pine.hlp54
-rw-r--r--pith/smime.c261
-rw-r--r--pith/smime.h2
-rw-r--r--pith/smkeys.c90
-rw-r--r--pith/smkeys.h4
-rw-r--r--pith/state.h9
9 files changed, 426 insertions, 101 deletions
diff --git a/pith/conftype.h b/pith/conftype.h
index abae2b0d..3c9316fa 100644
--- a/pith/conftype.h
+++ b/pith/conftype.h
@@ -675,7 +675,7 @@ typedef enum {Main, Post, None} EditWhich;
typedef enum {Directory, Container, Keychain, Nada} SmimeHolderType;
-typedef enum {Public, Private, CACert} WhichCerts;
+typedef enum {Public, Private, CACert, Password} WhichCerts;
typedef struct certdata {
unsigned deleted:1; /* certificate is marked deleted */
@@ -721,7 +721,6 @@ typedef struct smime_stuff {
char *privatecontent;
CertList *privatecertlist;
CertList *backupprivatecertlist;
- void *backuppersonal_certs; /* this is type (PERSONAL_CERT *) */
void *personal_certs; /* this is type (PERSONAL_CERT *) */
SmimeHolderType catype;
@@ -732,25 +731,35 @@ typedef struct smime_stuff {
} SMIME_STUFF_S;
-#define BACKUPDATACERT(X) (((X) == Public ? ps_global->smime->backuppubliccertlist \
- : ((X) == Private ? ps_global->smime->backupprivatecertlist \
- : ps_global->smime->backupcacertlist)))
-
-#define DATACERT(X) (((X) == Public ? ps_global->smime->publiccertlist \
- : ((X) == Private ? ps_global->smime->privatecertlist \
- : ps_global->smime->cacertlist)))
-
-#define PATHCERTDIR(X) (((X) == Public ? ps_global->smime->publicpath \
- : ((X) == Private ? ps_global->smime->privatepath \
- : ((X) == CACert ? ps_global->smime->capath : NULL))))
-
-#define CONTENTCERTLIST(X) (((X) == Public ? ps_global->smime->publiccontent \
- : ((X) == Private ? ps_global->smime->privatecontent \
- : ((X) == CACert ? ps_global->smime->cacontent : NULL))))
-
-#define SMHOLDERTYPE(X) (((X) == Public ? ps_global->smime->publictype \
- : ((X) == Private ? ps_global->smime->privatetype \
- : ((X) == CACert ? ps_global->smime->catype : Nada))))
+#define BACKUPDATACERT(X) ((X) == Public ? ps_global->smime->backuppubliccertlist : \
+ (X) == Private ? ps_global->smime->backupprivatecertlist : \
+ (X) == CACert ? ps_global->smime->backupcacertlist : \
+ (X) == Password ? (CertList *) ps_global->backuppassword : \
+ NULL)
+
+#define DATACERT(X) ((X) == Public ? ps_global->smime->publiccertlist : \
+ (X) == Private ? ps_global->smime->privatecertlist : \
+ (X) == CACert ? ps_global->smime->cacertlist : \
+ (X) == Password ? (CertList *) ps_global->pwdcertlist : \
+ NULL)
+
+#define PATHCERTDIR(X) ((X) == Public ? ps_global->smime->publicpath : \
+ (X) == Private ? ps_global->smime->privatepath : \
+ (X) == CACert ? ps_global->smime->capath : \
+ (X) == Password ? ps_global->pwdcertdir : \
+ NULL)
+
+#define CONTENTCERTLIST(X) ((X) == Public ? ps_global->smime->publiccontent : \
+ (X) == Private ? ps_global->smime->privatecontent : \
+ (X) == CACert ? ps_global->smime->cacontent : \
+ (X) == Password ? ps_global->pwdcertcontent : \
+ NULL)
+
+#define SMHOLDERTYPE(X) ((X) == Public ? ps_global->smime->publictype : \
+ (X) == Private ? ps_global->smime->privatetype : \
+ (X) == CACert ? ps_global->smime->catype : \
+ (X) == Password ? Directory : \
+ Nada)
#define EXTCERT(X) (((X) == Public ? ".crt" \
: ((X) == Private ? ".key" \
diff --git a/pith/imap.c b/pith/imap.c
index da338712..e02f46ba 100644
--- a/pith/imap.c
+++ b/pith/imap.c
@@ -1109,3 +1109,55 @@ ps_get(size_t size)
return(block);
}
+
+#ifdef PASSFILE
+char *
+passfile_name(char *pinerc, char *path, size_t len)
+{
+ struct stat sbuf;
+ char *p = NULL;
+ int i, j;
+
+ if(!path || !((pinerc && pinerc[0]) || ps_global->passfile))
+ return(NULL);
+
+ if(ps_global->passfile)
+ strncpy(path, ps_global->passfile, len-1);
+ else{
+ if((p = last_cmpnt(pinerc)) && *(p-1) && *(p-1) != PASSFILE[0])
+ for(i = 0; pinerc < p && i < len; pinerc++, i++)
+ path[i] = *pinerc;
+ else
+ i = 0;
+
+ for(j = 0; (i < len) && (path[i] = PASSFILE[j]); i++, j++)
+ ;
+
+ }
+
+ path[len-1] = '\0';
+
+ dprint((9, "Looking for passfile \"%s\"\n",
+ path ? path : "?"));
+
+#if defined(DOS) || defined(OS2)
+ return((our_stat(path, &sbuf) == 0
+ && ((sbuf.st_mode & S_IFMT) == S_IFREG))
+ ? path : NULL);
+#else
+ /* First, make sure it's ours and not sym-linked */
+ if(our_lstat(path, &sbuf) == 0
+ && ((sbuf.st_mode & S_IFMT) == S_IFREG)
+ && sbuf.st_uid == getuid()){
+ /* if too liberal permissions, fix them */
+ if((sbuf.st_mode & 077) != 0)
+ if(our_chmod(path, sbuf.st_mode & ~077) != 0)
+ return(NULL);
+
+ return(path);
+ }
+ else
+ return(NULL);
+#endif
+}
+#endif /* PASSFILE */
diff --git a/pith/imap.h b/pith/imap.h
index 86a0b533..1b30e456 100644
--- a/pith/imap.h
+++ b/pith/imap.h
@@ -131,5 +131,9 @@ void imap_flush_passwd_cache(int);
void set_read_predicted(int);
void mm_login_work (NETMBX *mb,char *user,char *pwd,long trial,char *usethisprompt, char *altuserforcache);
+/* this is necessary to figure out the name of the password file of the application */
+#ifdef PASSFILE
+char *passfile_name(char *, char *, size_t);
+#endif /* PASSFILE */
#endif /* PITH_IMAP_INCLUDED */
diff --git a/pith/pine.hlp b/pith/pine.hlp
index de174d2b..2e0fd0c4 100644
--- a/pith/pine.hlp
+++ b/pith/pine.hlp
@@ -197,6 +197,10 @@ Additions include:
in lower case, as some SMTP servers, such as those of libero.it
reject messages if the boundary attribute is in uppercase.
+ <LI> Add the ability to change the private key and certificates used
+ to encrypt a password file in the SMIME setup configuration screen.
+ <A HREF="h_config_smime_password_file_certificates">Learn more</A>
+
<LI> SMIME: The ctrl-E command that gives information on the certificate
is only available for messages that have a signed or encrypted
part.
@@ -35422,6 +35426,56 @@ import a command to this collection.
&lt;End of help on this topic&gt;
</BODY>
</HTML>
+====== h_config_smime_password_file_certificates =====
+<HTML>
+<HEAD>
+<TITLE>S/MIME: Manage Password File Certificates</TITLE>
+</HEAD>
+<BODY>
+<H1>S/MIME: Manage Password File Certificates</H1>
+
+UNIX Alpine only.
+<P>
+This option allows you to manage the certificates that are used to
+encrypt and decrypt your password file. This is useful in case you
+want to change the certificates used to encrypt your password file.
+<P>
+In order to avoid unauthorized use of this option, you are asked to
+enter the password of the current private key used to encrypt your
+password file.
+<P>
+Once you have entered your password for the current key, you enter a
+screen where you can import your new key, and see the information on your
+current key.
+<P>
+To import a new key press &quot;RETURN&quot; and enter the location of
+the new key. You will be asked to enter the password of the new key. If
+this part of the process is successful, Alpine will search for the
+certificate that matches that key. If your key is named
+&quot;your_email@address.com.key&quot;, then Alpine will look for your
+certificate in the same directory in the file named
+&quot;your_email@address.com.crt&quot;, otherwise it will look for it
+as part of your key (that is, it will look to see if your certificate
+is in the file &quot;your_email@address.com.key&quot;), if all of this
+fails, Alpine will ask you to enter the location of the certificate
+that matches the key you unlocked. If a certificate is found, it will be
+used, and in this case, the password file will be read, decrypted with the
+old key and encrypted with the new key. Once this is done, the new key and
+certificates are saved, and the old keys are permanently deleted.
+<P>
+Alpine does not create a backup of your password file, or your old keys
+that will be replaced. If you need to keep old copies, you will have to do
+this operation outside Alpine.
+<UL>
+<LI><A HREF="h_mainhelp_smime">General S/MIME help</A>
+</UL><P>
+<P>
+<UL>
+<LI><A HREF="h_finding_help">Finding more information and requesting help</A>
+</UL><P>
+&lt;End of help on this topic&gt;
+</BODY>
+</HTML>
====== h_certificate_information =====
<HTML>
<HEAD>
diff --git a/pith/smime.c b/pith/smime.c
index 6f9efc7f..d32a97c9 100644
--- a/pith/smime.c
+++ b/pith/smime.c
@@ -42,6 +42,9 @@ static char rcsid[] = "$Id: smime.c 1176 2008-09-29 21:16:42Z hubert@u.washingto
#include "../pith/tempfile.h"
#include "../pith/readfile.h"
#include "../pith/remote.h"
+#ifdef PASSFILE
+#include "../pith/imap.h"
+#endif /* PASSFILE */
#include <openssl/buffer.h>
#include <openssl/x509v3.h>
@@ -70,10 +73,8 @@ static void setup_storage_locations(void);
static int copy_container_to_dir(WhichCerts which);
static int do_fiddle_smime_message(BODY *b, long msgno, char *section);
void setup_privatekey_storage(void);
-int smime_path(char *rpath, char *fpath, size_t len);
int smime_extract_and_save_cert(PKCS7 *p7, int check_cert);
int same_cert(X509 *, X509 *);
-CertList * certlist_from_personal_certs(PERSONAL_CERT *pc);
#ifdef PASSFILE
int load_key_and_cert(char *pathkeydir, char *pathcertdir, char **keyfile, char **certfile, EVP_PKEY **pkey, X509 **pcert);
#endif /* PASSFILE */
@@ -245,14 +246,18 @@ setup_pwdcert(void **pwdcert)
return;
}
+
+ if(ps_global->pwdcertdir == NULL) /* save the result of pwdcertdir */
+ ps_global->pwdcertdir = cpystr(pathdir);
+
if(certfile && keyfile){
pc = (PERSONAL_CERT *) fs_get(sizeof(PERSONAL_CERT));
memset((void *)pc, 0, sizeof(PERSONAL_CERT));
pc->name = keyfile;
pc->key = pkey;
pc->cert = pcert;
+ pc->cname = certfile;
*pwdcert = (void *) pc;
- fs_give((void **)&certfile);
was_here = 0;
return;
}
@@ -596,8 +601,10 @@ load_pkey_with_prompt(char *fpath, char *text, char *prompt, int *ret)
return pkey;
}
-
-
+/* This is a tool for conf_screen, The return value must be zero when
+ * nothing changed, so if there is a failure in the import return 0
+ * and return 1 when we succeeded
+ */
int
import_certificate(WhichCerts ctype)
{
@@ -607,18 +614,221 @@ import_certificate(WhichCerts ctype)
if(pith_smime_import_certificate == NULL){
q_status_message(SM_ORDER, 0, 2,
_("import of certificates not implemented yet!"));
- return -1;
+ return 0;
}
- smime_init();
-
r = (*pith_smime_import_certificate)(filename, full_filename, sizeof(filename) - 20);
+ if(r < 0)
+ return 0;
+
+ /* we are trying to import a new key for the password file. First we ask for the
+ * private key. Once this is loaded, we make a reasonable attempt to find the
+ * public key in the same directory as the key was loaded from. We do this by
+ * looking for a file with the correct public certificate name, then we look
+ * in the same private key, and if not, we ask the user for its location. If all
+ * of this works, we import the key and public to the password directory.
+ */
+ if(ctype == Password){
+ char PrivateKeyPath[MAXPATH+1], PublicCertPath[MAXPATH+1], s[MAXPATH+1];
+ char full_name_key[MAXPATH+1], full_name_cert[MAXPATH+1];
+ char *use_this_file;
+ char prompt[500];
+ EVP_PKEY *key = NULL;
+
+ rc = 1; /* assume success :) */
+ if(strlen(filename) > 4){
+ strncpy(s, filename, sizeof(s));
+ s[sizeof(s)-1] = '\0';
+ if(!strcmp(s + strlen(s) - strlen(EXTCERT(Private)), EXTCERT(Private)))
+ s[strlen(s) - strlen(EXTCERT(Private))] = '\0';
+ else
+ rc = 0;
+ } else rc = 0;
+
+ if(rc == 0){
+ q_status_message(SM_ORDER, 1, 3, _("Error in key name. Check file extension"));
+ return 0;
+ }
+
+ snprintf(prompt, sizeof(prompt), _("Enter passphrase for <%s>: "), filename);
+ prompt[sizeof(prompt)-1] = '\0';
+ if((key = load_pkey_with_prompt(full_filename, NULL, prompt, NULL)) != NULL){
+ BIO *ins = NULL;
+ X509 *cert = NULL;
+
+ strncpy(full_name_key, full_filename, sizeof(full_filename));
+ full_name_key[sizeof(full_name_key)-1] = '\0';
+
+ build_path(buf, PATHCERTDIR(ctype), s, sizeof(buf));
+
+ strncpy(PrivateKeyPath, buf, sizeof(PrivateKeyPath));
+ PrivateKeyPath[sizeof(PrivateKeyPath)-1] = '\0';
+ if(strlen(PrivateKeyPath) + 4 < sizeof(PrivateKeyPath)){
+ strncat(PrivateKeyPath, EXTCERT(Private), 4);
+ PrivateKeyPath[sizeof(PrivateKeyPath)-1] = '\0';
+ }
+
+ /* remove .key extension and replace it with .crt extension */
+ strncpy(full_name_cert, full_name_key, sizeof(full_name_key));
+ full_name_cert[sizeof(full_name_cert)-1] = '\0';
+ full_name_cert[strlen(full_name_cert) - strlen(EXTCERT(Private))] = '\0';
+ strncat(full_name_cert, EXTCERT(Public), 4);
+ full_name_cert[sizeof(full_name_cert)-1] = '\0';
+
+
+ /* set up path to location where we will save public cert */
+ strncpy(PublicCertPath, buf, sizeof(PublicCertPath));
+ PublicCertPath[sizeof(PublicCertPath)-1] = '\0';
+ if(strlen(PublicCertPath) + 4 < sizeof(PublicCertPath)){
+ strncat(PublicCertPath, EXTCERT(Public), 4);
+ PublicCertPath[sizeof(PublicCertPath)-1] = '\0';
+ }
+
+ /* attempt #1 to guess public cert name, use .crt extension */
+ if((ins = BIO_new_file(full_name_cert, "r")) != NULL){
+ if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL){
+ use_this_file = &full_name_cert[0];
+ }
+ }
+ else{
+ /* attempt #2 to guess public cert name: user the original key */
+ if((ins = BIO_new_file(full_name_key, "r")) != NULL){
+ if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL){
+ use_this_file = &full_name_key[0];
+ }
+ }
+ else {
+ int done = 0;
+ /* attempt #3, ask the user */
+ do {
+ r = (*pith_smime_import_certificate)(filename, use_this_file, sizeof(filename) - 20);
+ if(r < 0){
+ if(ins != NULL) BIO_free(ins);
+ if(cert != NULL) X509_free(cert);
+ return 0;
+ }
+ if((ins = BIO_new_file(use_this_file, "r")) != NULL){
+ if((cert = PEM_read_bio_X509(ins, NULL, NULL, NULL)) != NULL)
+ done++;
+ else
+ q_status_message(SM_ORDER, 1, 3, _("Error parsing certificate"));
+ }
+ else
+ q_status_message(SM_ORDER, 1, 3, _("Error reading certificate"));
+ } while (done == 0);
+ }
+ }
+ if(ins != NULL){
+ if(cert != NULL){ /* check that certificate matches key */
+ if(!X509_check_private_key(cert, key)){
+ rc = 0;
+ q_status_message(SM_ORDER, 1, 3, _("Certificate does not match key"));
+ }
+ else
+ rc = 1; /* Success! */
+ }
+ else
+ q_status_message(SM_ORDER, 1, 3, _("Error in certificate file (not a certificate?)"));
+ }
+ if(rc == 1){ /* if everything has been successful,
+ * copy the files to their final destination */
+ if(our_copy(PrivateKeyPath, full_filename) == 0){ /* <-- save the private key */
+ q_status_message(SM_ORDER, 1, 3, _("Private key saved"));
+ if(our_copy(PublicCertPath, use_this_file) == 0){
+ char tmp[MAILTMPLEN];
+ FILE *fp;
+
+ if(!passfile_name(ps_global->pinerc, tmp, sizeof(tmp))
+ || !(fp = our_fopen(tmp, "rb"))){
+ q_status_message(SM_ORDER, 1, 3, _("Error reading password file!"));
+ rc = 0;
+ }
+ else {
+ char tmp2[MAILTMPLEN];
+ int encrypted = 0;
+ char *text;
+ PERSONAL_CERT *pwdcert, *pc;
+
+ pwdcert = (PERSONAL_CERT *) ps_global->pwdcert;
+ if(pwdcert == NULL)
+ setup_pwdcert((void **)&pwdcert);
+
+ tmp2[0] = '\0';
+ fgets(tmp2, sizeof(tmp2), fp);
+ fclose(fp);
+ if(strcmp(tmp2, "-----BEGIN PKCS7-----\n")){
+ if(encrypt_file((char *)tmp, NULL, pwdcert))
+ encrypted++;
+ }
+ else
+ encrypted++;
+
+ if(encrypted){
+ text = decrypt_file((char *)tmp, NULL, pwdcert);
+ if(text != NULL){
+ pc = fs_get(sizeof(PERSONAL_CERT));
+ memset((void *)pc, 0, sizeof(PERSONAL_CERT));
+ filename[strlen(filename)-strlen(EXTCERT(Private))] = '\0';
+ pc->name = cpystr(filename);
+ snprintf(buf, sizeof(buf), "%s%s", filename, EXTCERT(Public));
+ buf[sizeof(buf)-1] = '\0';
+ pc->cname = cpystr(buf);
+ pc->key = key;
+ pc->cert = cert;
+
+ if(encrypt_file((char *)tmp, text, pc)){ /* we did it! */
+ build_path(buf, PATHCERTDIR(ctype), pwdcert->name, sizeof(buf));
+ strncat(buf, EXTCERT(Private), 4);
+ buf[sizeof(buf)-1] = '\0';
+ if(unlink(buf) < 0)
+ q_status_message(SM_ORDER, 1, 3, _("Failed to remove old key"));
+ build_path(buf, PATHCERTDIR(ctype), pwdcert->cname, sizeof(buf));
+ if(unlink(buf) < 0)
+ q_status_message(SM_ORDER, 1, 3, _("Failed to remove old certificate"));
+ free_personal_certs((PERSONAL_CERT **)&ps_global->pwdcert);
+ ps_global->pwdcert = pc;
+ rc = 1;
+ q_status_message(SM_ORDER, 1, 3, _("Password file reencrypted"));
+ } else {
+ q_status_message(SM_ORDER, 1, 3, _("Failed to reencrypt password file"));
+ rc = 0;
+ }
+ } else {
+ q_status_message(SM_ORDER, 1, 3, _("Error decrypting Password file"));
+ }
+ } else {
+ q_status_message(SM_ORDER, 1, 3, _("Password file not encrypted and coulr not encrypt"));
+ rc = 0;
+ }
+ }
+ }
+ else{
+ q_status_message(SM_ORDER, 1, 3, _("Error saving public certificate"));
+ if(our_unlink(PrivateKeyPath) < 0)
+ q_status_message(SM_ORDER, 1, 3, _("Error while cleaning private key"));
+ rc = 0;
+ }
+ }
+ else{
+ rc = 0;
+ q_status_message(SM_ORDER, 1, 3, _("Error saving private key"));
+ }
+ if(ins != NULL) BIO_free(ins);
+ if(rc == 0 && cert != NULL) X509_free(cert);
+ }
+ } else {
+ rc = 0;
+ q_status_message(SM_ORDER, 1, 3, _("Error unlocking private key"));
+ }
+
+ return rc;
+ }
+
+ smime_init();
ps_global->mangled_screen = 1;
- if(r < 0)
- return r;
- else if (ctype == Private){
+ if (ctype == Private){
char prompt[500], *s, *t;
EVP_PKEY *key = NULL;
@@ -651,7 +861,7 @@ import_certificate(WhichCerts ctype)
ps_global->smime->publiccertlist->data.renew = 1;
}
else
- q_status_message(SM_ORDER, 1, 3, _("Problem unlocking key (not a certificate and/or wrong password)"));
+ q_status_message(SM_ORDER, 1, 3, _("Problem unlocking key (not a certificate or wrong password)"));
} else if (ctype == CACert){
BIO *ins;
X509 *cert;
@@ -713,7 +923,7 @@ import_certificate(WhichCerts ctype)
}
}
if(DATACERT(ctype)) RENEWCERT(DATACERT(ctype)) = 1;
- return 0;
+ return 1;
}
/* itype: information type to add: 0 - public, 1 - private.
@@ -920,23 +1130,12 @@ certlist_from_personal_certs(PERSONAL_CERT *pc)
{
CertList *cl;
X509 *x;
- char buf[MAXPATH];
if(pc == NULL)
return NULL;
-
- cl = fs_get(sizeof(CertList));
- memset((void *)cl, 0, sizeof(CertList));
- cl->name = cpystr(pc->name);
- x = get_cert_for(pc->name, Public, 1);
- if(x){
- if(x->cert_info){
- cl->data.date_from = smime_get_date(x->cert_info->validity->notBefore);
- cl->data.date_to = smime_get_date(x->cert_info->validity->notAfter);
- get_fingerprint(x, EVP_md5(), buf, sizeof(buf), NULL);
- cl->data.md5 = cpystr(buf);
- cl->cn = smime_get_cn(x->cert_info->subject);
- }
+
+ if((x = get_cert_for(pc->name, Public, 1)) != NULL){
+ cl = smime_X509_to_cert_info(x, pc->name);
X509_free(x);
}
cl->next = certlist_from_personal_certs(pc->next);
@@ -3641,14 +3840,6 @@ free_smime_struct(SMIME_STUFF_S **smime)
(*smime)->personal_certs = NULL;
}
- if((*smime)->backuppersonal_certs){
- PERSONAL_CERT *pc;
-
- pc = (PERSONAL_CERT *) (*smime)->backuppersonal_certs;
- free_personal_certs(&pc);
- (*smime)->backuppersonal_certs = NULL;
- }
-
if((*smime)->privatecontent)
fs_give((void **) &(*smime)->privatecontent);
diff --git a/pith/smime.h b/pith/smime.h
index 636d8805..01e4cdc0 100644
--- a/pith/smime.h
+++ b/pith/smime.h
@@ -85,6 +85,8 @@ void *create_smime_sparep(SpareType stype, void *s);
SpareType get_smime_sparep_type(void *s);
void *get_smime_sparep_data(void *s);
STACK_OF(X509) *get_chain_for_cert(X509 *cert, int *error, int *level);
+CertList *certlist_from_personal_certs(PERSONAL_CERT *pc);
+int smime_path(char *rpath, char *fpath, size_t len);
#endif /* PITH_SMIME_INCLUDED */
#endif /* SMIME */
diff --git a/pith/smkeys.c b/pith/smkeys.c
index 18509622..415bc190 100644
--- a/pith/smkeys.c
+++ b/pith/smkeys.c
@@ -49,6 +49,30 @@ static char *emailstrclean(char *string);
static int mem_add_extra_cacerts(char *contents, X509_LOOKUP *lookup);
int compare_certs_by_name(const void *data1, const void *data2);
+
+CertList *
+smime_X509_to_cert_info(X509 *x, char *name)
+{
+ CertList *cert;
+ char buf[MAXPATH+1];
+
+ if(x == NULL) return NULL;
+
+ cert = fs_get(sizeof(CertList));
+ memset((void *)cert, 0, sizeof(CertList));
+ cert->x509_cert = x;
+ cert->name = name ? cpystr(name) : NULL;
+ if(x && x->cert_info){
+ cert->data.date_from = smime_get_date(x->cert_info->validity->notBefore);
+ cert->data.date_to = smime_get_date(x->cert_info->validity->notAfter);
+ cert->cn = smime_get_cn(x->cert_info->subject);
+ }
+ get_fingerprint(x, EVP_md5(), buf, sizeof(buf), NULL);
+ cert->data.md5 = cpystr(buf);
+
+ return cert;
+}
+
#define SMIME_BACKUP_DIR ".backup"
#define MAX_TRY_BACKUP 100
@@ -199,25 +223,11 @@ setup_certs_backup_by_type(WhichCerts ctype)
if((in = BIO_new_file(buf2, "r"))!=0){
x = PEM_read_bio_X509(in, NULL, NULL, NULL);
if(x && x->cert_info){ /* for now copy this information */
- X509_NAME_ENTRY *e;
-
- cert = fs_get(sizeof(CertList));
- memset((void *)cert, 0, sizeof(CertList));
- cert->x509_cert = x;
- cert->data.date_from = smime_get_date(x->cert_info->validity->notBefore);
- cert->data.date_to = smime_get_date(x->cert_info->validity->notAfter);
- get_fingerprint(x, EVP_md5(), buf, sizeof(buf), NULL);
- cert->data.md5 = cpystr(buf);
- cert->name = cpystr(df->d_name);
- cert->cn = smime_get_cn(x->cert_info->subject);
+ cert = smime_X509_to_cert_info(x, df->d_name);
/* we will use the cert->data.md5 variable to find a backup
certificate, not the name */
- if(data == NULL)
- data = cert;
- else{
- for (cl2 = data; cl2 && cl2->next; cl2 = cl2->next);
- cl2->next = cert;
- }
+ cert->next = data;
+ data = cert;
}
BIO_free(in);
}
@@ -872,6 +882,25 @@ get_cert_for(char *email, WhichCerts ctype, int tolower)
X509 *cert = NULL;
BIO *in;
+ if(ctype == Password){
+ build_path(certfilename, PATHCERTDIR(ctype), email, sizeof(certfilename));
+ strncat(certfilename, EXTCERT(Public), sizeof(certfilename)-1-strlen(certfilename));
+ certfilename[sizeof(certfilename)-1] = 0;
+
+ if((in = BIO_new_file(certfilename, "r"))!=0){
+
+ cert = PEM_read_bio_X509(in, NULL, NULL, NULL);
+
+ if(cert){
+ /* could check email addr in cert matches */
+ }
+
+ BIO_free(in);
+ }
+
+ return cert;
+ }
+
if(!ps_global->smime)
return cert;
@@ -1274,33 +1303,14 @@ certlist_to_file(char *filename, CertList *certlist)
void
add_to_end_of_certlist(CertList **cl, char *name, X509 *cert)
{
- CertList *new, *clp;
- char buf[MAILTMPLEN];
+ CertList *new;
if(!cl)
return;
- new = (CertList *) fs_get(sizeof(*new));
- memset((void *) new, 0, sizeof(*new));
- new->x509_cert = cert;
- new->name = name ? cpystr(name) : NULL;
- if(cert && cert->cert_info){
- new->data.date_from = smime_get_date(cert->cert_info->validity->notBefore);
- new->data.date_to = smime_get_date(cert->cert_info->validity->notAfter);
- get_fingerprint(cert, EVP_md5(), buf, sizeof(buf), NULL);
- new->data.md5 = cpystr(buf);
- new->cn = smime_get_cn(cert->cert_info->subject);
- }
-
- if(!*cl){
- *cl = new;
- }
- else{
- for(clp = (*cl); clp->next; clp = clp->next)
- ;
-
- clp->next = new;
- }
+ new = smime_X509_to_cert_info(cert, name);
+ new->next = *cl;
+ *cl = new;
}
diff --git a/pith/smkeys.h b/pith/smkeys.h
index 0a2b0065..8c23d905 100644
--- a/pith/smkeys.h
+++ b/pith/smkeys.h
@@ -38,7 +38,8 @@
typedef struct personal_cert {
X509 *cert;
EVP_PKEY *key;
- char *name;
+ char *name; /* name of key */
+ char *cname; /* name of cert */
char *keytext;
struct personal_cert *next;
} PERSONAL_CERT;
@@ -67,6 +68,7 @@ char *smime_get_date(ASN1_GENERALIZEDTIME *tm);
void resort_certificates(CertList **data, WhichCerts ctype);
int setup_certs_backup_by_type(WhichCerts ctype);
char *smime_get_cn(X509_NAME *);
+CertList *smime_X509_to_cert_info(X509 *, char *);
#endif /* PITH_SMKEYS_INCLUDED */
diff --git a/pith/state.h b/pith/state.h
index 481d8b41..52628cf0 100644
--- a/pith/state.h
+++ b/pith/state.h
@@ -272,9 +272,6 @@ struct pine {
#endif
#ifdef PASSFILE
*passfile,
-#ifdef SMIME
- *pwdcertdir,
-#endif /* SMIME inside PASSFILE */
#endif /* PASSFILE */
*pinerc, /* Location of user's pinerc */
*exceptions, /* Location of user's exceptions */
@@ -359,7 +356,11 @@ struct pine {
char *smimedir;
SMIME_STUFF_S *smime;
#ifdef PASSFILE
- void *pwdcert; /* this is of type PERSONAL_CERT */
+ char *pwdcertdir; /* path to location of certificates for password file */
+ char *pwdcertcontent; /* No comment yet */
+ void *pwdcert; /* this is of type PERSONAL_CERT */
+ void *backuppassword; /* this is of type CertList */
+ void *pwdcertlist; /* this is of type CertList */
#endif /* PASSFILE inside SMIME */
#endif /* SMIME */