From 0ef0caf0d77164aa615fffa8aff4e82a3a540f0f Mon Sep 17 00:00:00 2001 From: Eduardo Chappa Date: Wed, 22 Nov 2017 11:29:40 -0700 Subject: [PATCH] * Add "remove password" command to the management screen for the password file encryption key. This allows users to use their password file without entering a master password. --- alpine/keymenu.c | 19 ++++++++- alpine/keymenu.h | 3 +- alpine/smime.c | 120 +++++++++++++++++++++++++++++++++++++++++++++---------- pith/pine.hlp | 42 +++++++++++++++---- pith/state.h | 1 + 5 files changed, 154 insertions(+), 31 deletions(-) diff --git a/alpine/keymenu.c b/alpine/keymenu.c index 326bc23..3452e5b 100644 --- a/alpine/keymenu.c +++ b/alpine/keymenu.c @@ -2710,10 +2710,10 @@ INST_KEY_MENU(config_smime_manage_certs_work_keymenu, config_smime_manage_certs_ struct key config_smime_view_cert[] = {HELP_MENU, - OTHER_MENU, + NULL_MENU, EXIT_SETUP_MENU, {"V", "[" N_("View Info") "]", {MC_CHOICE,3,{'v',ctrl('M'),ctrl('J')}}, KS_NONE}, - NULL_MENU, + {"D", N_("Delete pwd"), {MC_DELETE,1,{'d'}},KS_NONE}, NULL_MENU, NULL_MENU, NULL_MENU, @@ -2723,6 +2723,21 @@ struct key config_smime_view_cert[] = NULL_MENU}; INST_KEY_MENU(config_smime_manage_view_cert_keymenu, config_smime_view_cert); +struct key config_smime_view_cert_no_delete[] = + {HELP_MENU, + NULL_MENU, + EXIT_SETUP_MENU, + {"V", "[" N_("View Info") "]", {MC_CHOICE,3,{'v',ctrl('M'),ctrl('J')}}, KS_NONE}, + NULL_MENU, + NULL_MENU, + NULL_MENU, + NULL_MENU, + NULL_MENU, + NULL_MENU, + NULL_MENU, + NULL_MENU}; +INST_KEY_MENU(config_smime_manage_view_cert_keymenu_no_delete, config_smime_view_cert_no_delete); + struct key smime_certificate_info_keys[] = {HELP_MENU, OTHER_MENU, diff --git a/alpine/keymenu.h b/alpine/keymenu.h index 047e992..061a58d 100644 --- a/alpine/keymenu.h +++ b/alpine/keymenu.h @@ -666,7 +666,8 @@ extern struct key_menu cancel_keymenu, config_smime_manage_password_file_menu_keymenu, smime_certificate_info_keymenu, config_smime_add_new_key_keymenu, - config_smime_manage_view_cert_keymenu; + config_smime_manage_view_cert_keymenu, + config_smime_manage_view_cert_keymenu_no_delete; extern struct key rev_msg_keys[]; diff --git a/alpine/smime.c b/alpine/smime.c index 4300038..2fe22a3 100644 --- a/alpine/smime.c +++ b/alpine/smime.c @@ -38,6 +38,7 @@ static char rcsid[] = "$Id: smime.c 1074 2008-06-04 00:08:43Z hubert@u.washingto #include "../pith/tempfile.h" #include "radio.h" #include "keymenu.h" +#include "mailcmd.h" #include "mailview.h" #include "conftype.h" #include "confscroll.h" @@ -1286,18 +1287,21 @@ manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags) pathdir, MASTERNAME); filename[sizeof(filename)-1] = '\0'; rv = import_certificate(ctype, pc, filename); - if(rv == 1 && our_stat(pathdir, &sbuf) == 0){ - if(unlink(filename) < 0) - q_status_message1(SM_ORDER, 0, 2, + if(rv == 1){ + ps->keyemptypwd = 0; + if(our_stat(pathdir, &sbuf) == 0){ + if(unlink(filename) < 0) + q_status_message1(SM_ORDER, 0, 2, _("Could not remove private key %s.key"), MASTERNAME); - filename[strlen(filename)-4] = '\0'; - strcat(filename, ".crt"); - if(unlink(filename) < 0) - q_status_message1(SM_ORDER, 0, 2, + filename[strlen(filename)-4] = '\0'; + strcat(filename, ".crt"); + if(unlink(filename) < 0) + q_status_message1(SM_ORDER, 0, 2, _("Could not remove public certificate %s.crt"), MASTERNAME); - if(rmdir(pathdir) < 0) - q_status_message1(SM_ORDER, 0, 2, + if(rmdir(pathdir) < 0) + q_status_message1(SM_ORDER, 0, 2, _("Could not remove temporary directory %s"), pathdir); + } } } rv = 10; /* forces redraw */ @@ -1319,13 +1323,71 @@ manage_certs_tool(struct pine *ps, int cmd, CONF_S **cl, unsigned flags) break; case MC_DELETE: - if ((*cl)->d.s.deleted != 0) - q_status_message(SM_ORDER, 1, 3, _("Certificate already deleted")); - else{ - (*cl)->d.s.deleted = 1; - rv = 10 + (*cl)->varmem; /* forces redraw */ - mark_cert_deleted(ctype, (*cl)->varmem, 1); - q_status_message(SM_ORDER, 1, 3, _("Certificate marked deleted")); + if(ctype == Password){ + EVP_PKEY *key = NULL; + PERSONAL_CERT *pc = (PERSONAL_CERT *) ps->pwdcert; + RSA *rsa = NULL; + const EVP_CIPHER *enc = NULL; + BIO *out = NULL; + BIO *in = NULL; + char filename[MAXPATH+1]; + char passwd[MAILTMPLEN]; + char prompt[MAILTMPLEN]; + + if (pc != NULL && pc->key != NULL){ + strncpy(prompt, _("Enter password to unlock key: "), sizeof(prompt)); + prompt[sizeof(prompt)-1] = '\0'; + passwd[0] = '\0'; + + rv = alpine_get_password(prompt, passwd, sizeof(passwd)); + + if(rv == 1) + q_status_message(SM_ORDER, 1, 3, _("Password deletion cancelled")); + else if(rv == 0){ + snprintf(filename, sizeof(filename), "%s/%s.key", ps->pwdcertdir, pc->name); + filename[sizeof(filename)-1] = '\0'; + if((in = BIO_new_file(filename, "r")) != NULL){ + key = PEM_read_bio_PrivateKey(in, NULL, NULL, passwd); + if(key != NULL){ + if((rsa = EVP_PKEY_get1_RSA(key)) != NULL + && (out = BIO_new(BIO_s_file())) != NULL + && BIO_write_filename(out, filename) > 0 + && PEM_write_bio_RSAPrivateKey(out, rsa, enc, NULL, 0, NULL, passwd) > 0){ + q_status_message(SM_ORDER, 1, 3, _("Password Removed from private key")); + ps->keyemptypwd = 1; + } + else + rv = 1; + } + else{ + rv = 1; + q_status_message(SM_ORDER, 1, 3, _("Failed to unlock private key")); + } + BIO_free(in); + } + else + rv = 1; + } + if(rv == 1) + q_status_message(SM_ORDER, 1, 3, _("Failed to remove password from private key")); + rv += 10; /* forces redraw */ + if(out != NULL) + BIO_free_all(out); + if(rsa != NULL) + RSA_free(rsa); + if(key != NULL) + EVP_PKEY_free(key); + } + } + else { + if ((*cl)->d.s.deleted != 0) + q_status_message(SM_ORDER, 1, 3, _("Certificate already deleted")); + else{ + (*cl)->d.s.deleted = 1; + rv = 10 + (*cl)->varmem; /* forces redraw */ + mark_cert_deleted(ctype, (*cl)->varmem, 1); + q_status_message(SM_ORDER, 1, 3, _("Certificate marked deleted")); + } } break; @@ -1406,6 +1468,7 @@ void manage_password_file_certificates(struct pine *ps) dprint((9, "manage_password_file_certificates")); ps->next_screen = SCREEN_FUN_NULL; + ps->keyemptypwd = 0; /* just in case */ do { CONF_S *ctmp = NULL, *first_line = NULL; @@ -1422,6 +1485,7 @@ void manage_password_file_certificates(struct pine *ps) memset(&screen, 0, sizeof(screen)); screen.deferred_ro_warning = readonly_warning; + rv = conf_scroll_screen(ps, &screen, first_line, _("MANAGE PASSWORD FILE CERTS"), /* TRANSLATORS: Print something1 using something2. @@ -1430,6 +1494,7 @@ void manage_password_file_certificates(struct pine *ps) } while (rv != 0); ps->mangled_screen = 1; + ps->keyemptypwd = 0; /* reset this so it will not confuse other routines */ smime_reinit(); } @@ -1444,9 +1509,12 @@ smime_manage_password_file_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **f CertList *cl; int i; void *pwdcert = NULL; /* this is our current password file */ - PERSONAL_CERT *pc; X509_LOOKUP *lookup = NULL; X509_STORE *store = NULL; + char filename[MAXPATH+1]; + BIO *in = NULL; + EVP_PKEY *key = NULL; + PERSONAL_CERT *pc; if(*state == 0){ /* first time around? */ setup_pwdcert(&pwdcert); @@ -1459,6 +1527,16 @@ smime_manage_password_file_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **f } pc = (PERSONAL_CERT *) ps_global->pwdcert; + snprintf(filename, sizeof(filename), "%s/%s.key", ps->pwdcertdir, pc->name); + filename[sizeof(filename)-1] = '\0'; + if((in = BIO_new_file(filename, "r")) != NULL + && (key = PEM_read_bio_PrivateKey(in, NULL, NULL, "")) != NULL) + ps->keyemptypwd = 1; + if(in != NULL) + BIO_free(in); + if(key != NULL) + EVP_PKEY_free(key); + ps->pwdcertlist = cl = smime_X509_to_cert_info(X509_dup(pc->cert), pc->name); for(i = 0; i < sizeof(tmp) && i < (ps->ttyo ? ps->ttyo->screen_cols : sizeof(tmp)); i++) @@ -1531,9 +1609,10 @@ smime_manage_password_file_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **f (*ctmp)->d.s.deleted = 0; (*ctmp)->help = h_config_smime_password_file_certificates; (*ctmp)->tool = manage_certs_tool; - (*ctmp)->keymenu = &config_smime_manage_view_cert_keymenu; + (*ctmp)->keymenu = ps->keyemptypwd == 0 + ? &config_smime_manage_view_cert_keymenu + : &config_smime_manage_view_cert_keymenu_no_delete; (*ctmp)->varmem = 0; - (*ctmp)->help = h_config_smime_manage_public_menu; strncpy((*ctmp)->d.s.address, cl->name, sizeof((*ctmp)->d.s.address)); (*ctmp)->d.s.address[sizeof((*ctmp)->d.s.address) - 1] = '\0'; snprintf(tmp, sizeof(tmp), u, @@ -1541,8 +1620,7 @@ smime_manage_password_file_certs_init(struct pine *ps, CONF_S **ctmp, CONF_S **f cl->name, DATEFROMCERT(cl), DATETOCERT(cl), MD5CERT(cl)); (*ctmp)->value = cpystr(tmp); - - } + } } #endif /* PASSFILE */ diff --git a/pith/pine.hlp b/pith/pine.hlp index 0c712e0..547cb10 100644 --- a/pith/pine.hlp +++ b/pith/pine.hlp @@ -140,7 +140,7 @@ with help text for the config screen and the composer that didn't have any reasonable place to be called from. Dummy change to get revision in pine.hlp ============= h_revision ================= -Alpine Commit 232 2017-11-21 12:33:12 +Alpine Commit 233 2017-11-22 11:29:36 ============= h_news ================= @@ -189,6 +189,11 @@ when spelling. Sample usage: -dict "en_US, de_DE, fr_FR".
  • Improvements to the configure stage of compilation. Some of these contributed by Helmut Grohne. See Bug 876164 in Debian. + +
  • Add "remove password" command to the management screen for the +password file encryption key. This allows users to use their password file +without entering a master password. +

    @@ -35901,13 +35906,30 @@ 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.

    -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. +Depending on the version of Alpine that you used for the first time +to set this up, you might have had to enter a password to enter this +screen. In the case that you did not enter a password to enter this +screen, you should know two things that are important: +

    +

    Needless to say, this is not advisable. You should keep your +password file protected. In order to do so, all you need to do is use +the "Create Key" command to create a key. Once you do this, +Alpine will use that key, encrypted with the password used to create that +key, to protect your password file.

    -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. +In this screen you can import a new key to encrypt your password file, +and read cryptographic information on your current key.

    To import a new key press "RETURN" and enter the location of the new key. You will be asked to enter the password of the new key. If @@ -35927,6 +35949,12 @@ certificates are saved, and the old keys are permanently deleted. 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. +

    +Observe that you can use this screen to remove the password for the key. +As explained earlier, this is not advisable, but you can always restore the +password to encrypt your password file by creating a new key. +

    +Be safe and keep your password file encrypted with a password.

    diff --git a/pith/state.h b/pith/state.h index 316a589..75cff1c 100644 --- a/pith/state.h +++ b/pith/state.h @@ -362,6 +362,7 @@ struct pine { PRINT_S *print; #ifdef SMIME + int keyemptypwd; /* can we load the key without a password? */ char *smimedir; SMIME_STUFF_S *smime; char *pwdcertdir; /* path to location of certificates for password file */ -- 2.11.4.GIT