etc/pam_pkcs11.conf.example.in | 3 +++ src/common/pkcs11_lib.c | 20 +++++++++++++++++++ src/common/pkcs11_lib.h | 1 + src/pam_pkcs11/pam_config.c | 16 +++++++++++++-- src/pam_pkcs11/pam_config.h | 1 + src/pam_pkcs11/pam_pkcs11.c | 45 ++++++++++++++++++++++++++++++++++++++++++ src/tools/pkcs11_inspect.c | 2 +- src/tools/pkcs11_listcerts.c | 2 +- src/tools/pklogin_finder.c | 2 +- 9 files changed, 87 insertions(+), 5 deletions(-) diff --git a/etc/pam_pkcs11.conf.example.in b/etc/pam_pkcs11.conf.example.in index 648ec7a..b05778b 100644 --- a/etc/pam_pkcs11.conf.example.in +++ b/etc/pam_pkcs11.conf.example.in @@ -8,6 +8,9 @@ pam_pkcs11 { # Allow empty passwords nullok = true; + # Request PIN during smartcard operations (enabled by default) + ask_pin = true; + # Enable debugging support. debug = true; diff --git a/src/common/pkcs11_lib.c b/src/common/pkcs11_lib.c index 1e7b8bb..41b55d1 100644 --- a/src/common/pkcs11_lib.c +++ b/src/common/pkcs11_lib.c @@ -71,6 +71,26 @@ int pkcs11_pass_login(pkcs11_handle_t *h, int nullok) return 0; } +/* Like pkcs11_pass_login above, but skip PIN prompt if desired + * (e.g., if ask_pin is set; this is insecure). + */ +int pkcs11_nopass_login(pkcs11_handle_t *h) +{ + int rv; + + DBG("pkcs11_login is affected by false ask_pin; this might be insecure"); + + /* perform pkcs #11 login similarly to + CKF_PROTECTED_AUTHENTICATION_PATH in pam_pkcs11.c + (when the pinpad is to be used instead of asking for PIN here) */ + rv = pkcs11_login(h, NULL); + if (rv != 0) { + set_error("pkcs11_login() failed: %s", get_error()); + return -1; + } + return 0; +} + /* * memcmp_pad_max() is a specialized version of memcmp() which compares two * pieces of data up to a maximum length. If the two data match up the diff --git a/src/common/pkcs11_lib.h b/src/common/pkcs11_lib.h index 27ed910..628caa1 100644 --- a/src/common/pkcs11_lib.h +++ b/src/common/pkcs11_lib.h @@ -58,6 +58,7 @@ PKCS11_EXTERN int open_pkcs11_session(pkcs11_handle_t *h, unsigned int slot); PKCS11_EXTERN int close_pkcs11_session(pkcs11_handle_t *h); PKCS11_EXTERN int pkcs11_login(pkcs11_handle_t *h, char *password); PKCS11_EXTERN int pkcs11_pass_login(pkcs11_handle_t *h, int nullok); +PKCS11_EXTERN int pkcs11_nopass_login(pkcs11_handle_t *h); PKCS11_EXTERN int get_slot_login_required(pkcs11_handle_t *h); PKCS11_EXTERN int get_slot_protected_authentication_path(pkcs11_handle_t *h); PKCS11_EXTERN cert_object_t **get_certificate_list(pkcs11_handle_t *h, diff --git a/src/pam_pkcs11/pam_config.c b/src/pam_pkcs11/pam_config.c index 6739def..9d2ad40 100644 --- a/src/pam_pkcs11/pam_config.c +++ b/src/pam_pkcs11/pam_config.c @@ -65,7 +65,8 @@ struct configuration_st configuration = { N_("Smart card"), /* token_type */ NULL, /* char *username */ 0, /* int quiet */ - 0 /* err_display_time */ + 0, /* err_display_time */ + 1 /* ask_pin */ }; #ifdef DEBUG_CONFIG @@ -89,7 +90,8 @@ static void display_config (void) { DBG1("crl_policy %d",configuration.policy.crl_policy); DBG1("signature_policy %d",configuration.policy.signature_policy); DBG1("ocsp_policy %d",configuration.policy.ocsp_policy); - DBG1("err_display_time %d", configuration.err_display_time); + DBG1("err_display_time %d", configuration.err_display_time); + DBG1("ask_pin %d",configuration.ask_pin); } #endif @@ -143,6 +145,8 @@ static void parse_config_file(void) { scconf_get_bool(root,"wait_for_card",configuration.wait_for_card); configuration.pkcs11_module = ( char * ) scconf_get_str(root,"use_pkcs11_module",configuration.pkcs11_module); + configuration.ask_pin = + scconf_get_bool(root,"ask_pin",configuration.ask_pin); /* search pkcs11 module options */ pkcs11_mblocks = scconf_find_blocks(ctx,root,"pkcs11_module",configuration.pkcs11_module); if (!pkcs11_mblocks) { @@ -266,6 +270,14 @@ struct configuration_st *pk_configure( int argc, const char **argv ) { configuration.use_first_pass = 1; continue; } + if (strcmp("ask_pin", argv[i]) == 0) { + configuration.ask_pin = 1; + continue; + } + if (strcmp("dont_ask_pin", argv[i]) == 0) { + configuration.ask_pin = 0; + continue; + } if (strcmp("wait_for_card", argv[i]) == 0) { configuration.wait_for_card = 1; continue; diff --git a/src/pam_pkcs11/pam_config.h b/src/pam_pkcs11/pam_config.h index cf4e089..7ab1a48 100644 --- a/src/pam_pkcs11/pam_config.h +++ b/src/pam_pkcs11/pam_config.h @@ -46,6 +46,7 @@ struct configuration_st { const char *username; /* provided user name */ int quiet; int err_display_time; + int ask_pin; }; struct configuration_st *pk_configure( int argc, const char **argv ); diff --git a/src/pam_pkcs11/pam_pkcs11.c b/src/pam_pkcs11/pam_pkcs11.c index e8543c3..3cadabb 100644 --- a/src/pam_pkcs11/pam_pkcs11.c +++ b/src/pam_pkcs11/pam_pkcs11.c @@ -470,6 +470,46 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, cons return pkcs11_pam_fail; } + /* We split the code into two cases based on configuration->ask_pin: + first comes the simplified case, then the complete default one. + + There is some common code there, but we repeat it intentionally + because this way the implementation of the ask-pin-later feature (by raorn@) + will be as simple as just moving the second default part. */ + if (!configuration->ask_pin) { + + rv = get_slot_login_required(ph); + if (rv == -1) { + ERR1("get_slot_login_required() failed: %s", get_error()); + if (!configuration->quiet) { + pam_syslog(pamh, LOG_ERR, "get_slot_login_required() failed: %s", get_error()); + pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2314: Slot login failed")); + sleep(configuration->err_display_time); + } + release_pkcs11_module(ph); + return pkcs11_pam_fail; + } else if (rv) { + /* get password */ + pam_prompt(pamh, PAM_TEXT_INFO, NULL, + _("Welcome %.32s!"), get_slot_tokenlabel(ph)); + DBG("pkcs11_login is affected by false ask_pin (before ensuring that the user is the real owner of the card); this might be insecure"); + /* call pkcs#11 login to ensure that the user is the real owner of the card + * we need to do thise before get_certificate_list because some tokens + * can not read their certificates until the token is authenticated */ + rv = pkcs11_login(ph, NULL); + if (rv != 0) { + ERR1("open_pkcs11_login() failed: %s", get_error()); + if (!configuration->quiet) { + pam_syslog(pamh, LOG_ERR, "open_pkcs11_login() failed: %s", get_error()); + pam_prompt(pamh, PAM_ERROR_MSG , NULL, _("Error 2320: Wrong smartcard PIN")); + sleep(configuration->err_display_time); + } + goto auth_failed_nopw; + } + } + + } + cert_list = get_certificate_list(ph, &ncert); if (rv<0) { ERR1("get_certificate_list() failed: %s", get_error()); @@ -594,6 +634,9 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, cons } + if (configuration->ask_pin) + { + rv = get_slot_login_required(ph); if (rv == -1) { ERR1("get_slot_login_required() failed: %s", get_error()); @@ -681,6 +724,8 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, cons } } + } + /* if signature check is enforced, generate random data, sign and verify */ if (configuration->policy.signature_policy) { pam_prompt(pamh, PAM_TEXT_INFO, NULL, _("Checking signature")); diff --git a/src/tools/pkcs11_inspect.c b/src/tools/pkcs11_inspect.c index 7cde860..6aac407 100644 --- a/src/tools/pkcs11_inspect.c +++ b/src/tools/pkcs11_inspect.c @@ -104,7 +104,7 @@ int main(int argc, const char **argv) { } /* not really needed, but.... */ - rv = pkcs11_pass_login(ph,configuration->nullok); + rv = configuration->ask_pin ? pkcs11_pass_login(ph,configuration->nullok) : pkcs11_nopass_login(ph); if (rv != 0) { ERR1("pkcs11_pass_login() failed: %s", get_error()); return 2; diff --git a/src/tools/pkcs11_listcerts.c b/src/tools/pkcs11_listcerts.c index 24290ca..726addf 100644 --- a/src/tools/pkcs11_listcerts.c +++ b/src/tools/pkcs11_listcerts.c @@ -103,7 +103,7 @@ int main(int argc, const char **argv) { } /* do login */ - rv = pkcs11_pass_login(ph,configuration->nullok); + rv = configuration->ask_pin ? pkcs11_pass_login(ph,configuration->nullok) : pkcs11_nopass_login(ph); if (rv<0){ DBG1("Login failed: %s",get_error()); return 4; diff --git a/src/tools/pklogin_finder.c b/src/tools/pklogin_finder.c index 40f5f70..9ef04b9 100644 --- a/src/tools/pklogin_finder.c +++ b/src/tools/pklogin_finder.c @@ -104,7 +104,7 @@ int main(int argc, const char **argv) { #ifdef HAVE_NSS /* not really needed, but... */ - rv = pkcs11_pass_login(ph,configuration->nullok); + rv = configuration->ask_pin ? pkcs11_pass_login(ph,configuration->nullok) : pkcs11_nopass_login(ph); if (rv != 0) { DBG1("pkcs11_pass_login() failed: %s", get_error()); return 2;