From 8dd60bf10c6ea041388ac1b307edbbfac4d6bf9b Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Feb 25 2015 22:33:39 +0000 Subject: Add framework for PIN, token certsave errors Add states and knowledge of wrong-PIN and missing-token errors encountered while attempting to save a newly-issued certificate. --- diff --git a/doc/design.txt b/doc/design.txt index 506b2d4..14a4563 100644 --- a/doc/design.txt +++ b/doc/design.txt @@ -41,6 +41,7 @@ Now with some arbitrarily-named states for our per-certificate state machine: information we think is interesting. States: NEED_TO_SAVE_CERT, PRE_SAVE_CERT[*], START_SAVING_CERT, SAVING_CERT [*], NEED_CERTSAVE_PERMS, + NEED_CERTSAVE_TOKEN, NEED_CERTSAVE_PIN, NEED_TO_READ_CERT, READING_CERT [*], SAVED_CERT, POST_SAVED_CERT[*] * Waiting for certificate to near expiration. @@ -388,6 +389,12 @@ State logic: if cert-save-needs-perms state_next = NEED_CERTSAVE_PERMS state_transition = now + elseif cert-save-needs-token + state_next = NEED_CERTSAVE_TOKEN + state_transition = now + elseif cert-save-needs-pin + state_next = NEED_CERTSAVE_PIN + state_transition = now else state_next = NEED_TO_NOTIFY_ISSUED_SAVE_FAILED state_transition = now @@ -399,6 +406,18 @@ State logic: state_transition = now break + NEED_CERTSAVE_TOKEN: + if starting-up + state_next = NEED_TO_SAVE_CERT + state_transition = now + break + + NEED_CERTSAVE_PIN: + if starting-up + state_next = NEED_TO_SAVE_CERT + state_transition = now + break + NEED_TO_SAVE_CA_CERTS: state_next = START_SAVING_CA_CERTS state_transition = now diff --git a/src/certsave-int.h b/src/certsave-int.h index ba5a14e..423a22f 100644 --- a/src/certsave-int.h +++ b/src/certsave-int.h @@ -25,6 +25,8 @@ enum cm_certsave_status { CM_CERTSAVE_STATUS_NICKNAME_CONFLICT = 3, CM_CERTSAVE_STATUS_INTERNAL = 4, CM_CERTSAVE_STATUS_PERMS = 5, + CM_CERTSAVE_STATUS_AUTH = 6, + CM_CERTSAVE_STATUS_NO_TOKEN = 7, }; struct cm_certsave_state_pvt { @@ -38,6 +40,12 @@ struct cm_certsave_state_pvt { int (*saved)(struct cm_certsave_state *state); /* Check if we failed due to filesystem permissions. */ int (*permissions_error)(struct cm_certsave_state *state); + /* Tell us if we need a token to be inserted to access the storage + * location. */ + int (*token_error)(struct cm_certsave_state *state); + /* Tell us if we need a PIN (or a new PIN) to access the storage + * location. */ + int (*pin_error)(struct cm_certsave_state *state); /* Check if we failed because the subject was already being used. */ int (*conflict_subject)(struct cm_certsave_state *state); /* Check if we failed because the nickname was already being used. */ diff --git a/src/certsave-n.c b/src/certsave-n.c index b5e447b..48c6fd1 100644 --- a/src/certsave-n.c +++ b/src/certsave-n.c @@ -613,6 +613,33 @@ cm_certsave_n_permissions_error(struct cm_certsave_state *state) return 0; } +/* Check if we failed because the right token wasn't present. */ +static int +cm_certsave_n_token_error(struct cm_certsave_state *state) +{ + int status; + status = cm_subproc_get_exitstatus(state->subproc); + if (!WIFEXITED(status) || + (WEXITSTATUS(status) != CM_CERTSAVE_STATUS_NO_TOKEN)) { + return -1; + } + return 0; +} + +/* Check if we failed because we didn't have the right PIN or password to + * access the storage location. */ +static int +cm_certsave_n_pin_error(struct cm_certsave_state *state) +{ + int status; + status = cm_subproc_get_exitstatus(state->subproc); + if (!WIFEXITED(status) || + (WEXITSTATUS(status) != CM_CERTSAVE_STATUS_AUTH)) { + return -1; + } + return 0; +} + /* Clean up after saving the certificate. */ static void cm_certsave_n_done(struct cm_certsave_state *state) @@ -645,6 +672,8 @@ cm_certsave_n_start(struct cm_store_entry *entry) state->pvt.conflict_subject = cm_certsave_n_conflict_subject; state->pvt.conflict_nickname = cm_certsave_n_conflict_nickname; state->pvt.permissions_error = cm_certsave_n_permissions_error; + state->pvt.token_error = cm_certsave_n_token_error; + state->pvt.pin_error = cm_certsave_n_pin_error; state->pvt.done= cm_certsave_n_done; state->entry = entry; state->subproc = cm_subproc_start(cm_certsave_n_main, state, diff --git a/src/certsave-o.c b/src/certsave-o.c index af46bc6..8757dcd 100644 --- a/src/certsave-o.c +++ b/src/certsave-o.c @@ -364,6 +364,33 @@ cm_certsave_o_permissions_error(struct cm_certsave_state *state) return 0; } +/* Check if we failed because the right token wasn't present. */ +static int +cm_certsave_o_token_error(struct cm_certsave_state *state) +{ + int status; + status = cm_subproc_get_exitstatus(state->subproc); + if (!WIFEXITED(status) || + (WEXITSTATUS(status) != CM_CERTSAVE_STATUS_NO_TOKEN)) { + return -1; + } + return 0; +} + +/* Check if we failed because we didn't have the right PIN or password to + * access the storage location. */ +static int +cm_certsave_o_pin_error(struct cm_certsave_state *state) +{ + int status; + status = cm_subproc_get_exitstatus(state->subproc); + if (!WIFEXITED(status) || + (WEXITSTATUS(status) != CM_CERTSAVE_STATUS_AUTH)) { + return -1; + } + return 0; +} + /* Get a selectable-for-read descriptor we can poll for status changes. */ static int cm_certsave_o_get_fd(struct cm_certsave_state *state) @@ -401,6 +428,8 @@ cm_certsave_o_start(struct cm_store_entry *entry) state->pvt.conflict_subject = cm_certsave_o_conflict_subject; state->pvt.conflict_nickname = cm_certsave_o_conflict_nickname; state->pvt.permissions_error = cm_certsave_o_permissions_error; + state->pvt.token_error = cm_certsave_o_token_error; + state->pvt.pin_error = cm_certsave_o_pin_error; state->entry = entry; state->subproc = cm_subproc_start(cm_certsave_o_main, state, NULL, entry, NULL); diff --git a/src/certsave.c b/src/certsave.c index b73f2c6..6eaafe5 100644 --- a/src/certsave.c +++ b/src/certsave.c @@ -99,6 +99,27 @@ cm_certsave_permissions_error(struct cm_certsave_state *state) return pvt->permissions_error(state); } +/* Check if we failed because the storage token is not present. */ +int +cm_certsave_token_error(struct cm_certsave_state *state) +{ + struct cm_certsave_state_pvt *pvt; + + pvt = (struct cm_certsave_state_pvt *) state; + return pvt->token_error(state); +} + +/* Check if we failed because we're missing a PIN or password that's required + * for accessing the data store. */ +int +cm_certsave_pin_error(struct cm_certsave_state *state) +{ + struct cm_certsave_state_pvt *pvt; + + pvt = (struct cm_certsave_state_pvt *) state; + return pvt->pin_error(state); +} + /* Clean up after saving the certificate. */ void cm_certsave_done(struct cm_certsave_state *state) diff --git a/src/certsave.h b/src/certsave.h index 6445463..824ceb5 100644 --- a/src/certsave.h +++ b/src/certsave.h @@ -44,6 +44,13 @@ int cm_certsave_conflict_nickname(struct cm_certsave_state *state); /* Check if we failed due to a permissions error. */ int cm_certsave_permissions_error(struct cm_certsave_state *state); +/* Check if we failed due to the storage token not being present. */ +int cm_certsave_token_error(struct cm_certsave_state *state); + +/* Check if we failed due to not having the right PIN for accessing the + * storage location. */ +int cm_certsave_pin_error(struct cm_certsave_state *state); + /* Clean up after saving the certificate. */ void cm_certsave_done(struct cm_certsave_state *state); diff --git a/src/getcert-list.1.in b/src/getcert-list.1.in index 17da296..d002d3b 100644 --- a/src/getcert-list.1.in +++ b/src/getcert-list.1.in @@ -1,4 +1,4 @@ -.TH certmonger 1 "6 February 2015" "certmonger Manual" +.TH certmonger 1 "25 February 2015" "certmonger Manual" .SH NAME getcert @@ -175,6 +175,15 @@ The service encountered a filesystem permission error while attempting to save the newly-issued certificate to the location where it has been told to save it. .TP +NEED_CERTSAVE_TOKEN +The service is unable to find the token in which the newly-issued +certificate is to be stored. +.TP +NEED_CERTSAVE_PIN +The service is missing the PIN which is required to access an NSS +database in order to save the newly-issued certificate to the location +where it has been told to save it. +.TP NEED_TO_SAVE_CA_CERTS The service is about to save the certificate of the issuing CA to the locations where it has been told to save them. diff --git a/src/getcert.c b/src/getcert.c index 3ec2bd7..9e8a9cc 100644 --- a/src/getcert.c +++ b/src/getcert.c @@ -2921,6 +2921,8 @@ list(const char *argv0, int argc, char **argv) case CM_START_SAVING_CERT: case CM_SAVING_CERT: case CM_NEED_CERTSAVE_PERMS: + case CM_NEED_CERTSAVE_TOKEN: + case CM_NEED_CERTSAVE_PIN: case CM_SAVED_CERT: case CM_POST_SAVED_CERT: case CM_NEED_TO_READ_CERT: diff --git a/src/iterate.c b/src/iterate.c index cd644ff..e2163e4 100644 --- a/src/iterate.c +++ b/src/iterate.c @@ -158,6 +158,12 @@ cm_entry_reset_state(struct cm_store_entry *entry) case CM_NEED_CERTSAVE_PERMS: entry->cm_state = CM_NEED_TO_SAVE_CERT; break; + case CM_NEED_CERTSAVE_TOKEN: + entry->cm_state = CM_NEED_TO_SAVE_CERT; + break; + case CM_NEED_CERTSAVE_PIN: + entry->cm_state = CM_NEED_TO_SAVE_CERT; + break; case CM_NEED_TO_SAVE_CA_CERTS: break; case CM_START_SAVING_CA_CERTS: @@ -1147,6 +1153,20 @@ cm_iterate_entry(struct cm_store_entry *entry, struct cm_store_ca *ca, state->cm_certsave_state = NULL; entry->cm_state = CM_NEED_CERTSAVE_PERMS; *when = cm_time_now; + } else + if (cm_certsave_token_error(state->cm_certsave_state) == 0) { + /* Whoops, we need help. */ + cm_certsave_done(state->cm_certsave_state); + state->cm_certsave_state = NULL; + entry->cm_state = CM_NEED_CERTSAVE_TOKEN; + *when = cm_time_now; + } else + if (cm_certsave_pin_error(state->cm_certsave_state) == 0) { + /* Whoops, we need help. */ + cm_certsave_done(state->cm_certsave_state); + state->cm_certsave_state = NULL; + entry->cm_state = CM_NEED_CERTSAVE_PIN; + *when = cm_time_now; } else { /* Failed to save cert; make a note and try * again in a bit. */ @@ -1171,6 +1191,16 @@ cm_iterate_entry(struct cm_store_entry *entry, struct cm_store_ca *ca, *when = cm_time_no_time; break; + case CM_NEED_CERTSAVE_TOKEN: + /* Revisit this later. */ + *when = cm_time_no_time; + break; + + case CM_NEED_CERTSAVE_PIN: + /* Revisit this later. */ + *when = cm_time_no_time; + break; + case CM_NEED_TO_READ_CERT: /* We should already have the lock here. In cases where we're * resuming things at startup, try to acquire it if we don't diff --git a/src/store-gen.c b/src/store-gen.c index a7d50ed..b0ba244 100644 --- a/src/store-gen.c +++ b/src/store-gen.c @@ -76,6 +76,8 @@ static const struct { {"START_SAVING_CERT", CM_START_SAVING_CERT}, {"SAVING_CERT", CM_SAVING_CERT}, {"NEED_CERTSAVE_PERMS", CM_NEED_CERTSAVE_PERMS}, + {"NEED_CERTSAVE_TOKEN", CM_NEED_CERTSAVE_TOKEN}, + {"NEED_CERTSAVE_PIN", CM_NEED_CERTSAVE_PIN}, {"NEED_TO_READ_CERT", CM_NEED_TO_READ_CERT}, {"READING_CERT", CM_READING_CERT}, {"SAVED_CERT", CM_SAVED_CERT}, diff --git a/src/store-int.h b/src/store-int.h index 230e1ae..748017d 100644 --- a/src/store-int.h +++ b/src/store-int.h @@ -174,6 +174,7 @@ struct cm_store_entry { CM_NEED_TO_SAVE_CERT, CM_PRE_SAVE_CERT, CM_START_SAVING_CERT, CM_SAVING_CERT, CM_NEED_CERTSAVE_PERMS, + CM_NEED_CERTSAVE_TOKEN, CM_NEED_CERTSAVE_PIN, CM_NEED_TO_SAVE_CA_CERTS, CM_START_SAVING_CA_CERTS, CM_SAVING_CA_CERTS, CM_NEED_CA_CERT_SAVE_PERMS, diff --git a/src/tdbush.c b/src/tdbush.c index 67a43b6..5525691 100644 --- a/src/tdbush.c +++ b/src/tdbush.c @@ -4015,6 +4015,8 @@ request_prop_get_stuck(struct cm_context *ctx, void *parent, case CM_NEWLY_ADDED_NEED_KEYINFO_READ_PIN: case CM_NEED_CA_CERT_SAVE_PERMS: case CM_NEED_CERTSAVE_PERMS: + case CM_NEED_CERTSAVE_TOKEN: + case CM_NEED_CERTSAVE_PIN: case CM_NEED_ONLY_CA_CERT_SAVE_PERMS: case CM_NEED_GUIDANCE: case CM_NEED_CA: