diff --git a/scd/app-common.h b/scd/app-common.h index 460046f89..5866c9b32 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -229,7 +229,9 @@ char *app_get_serialno (app_t app); void app_dump_state (void); void application_notify_card_reset (int slot); -gpg_error_t check_application_conflict (card_t card, const char *name); +gpg_error_t check_application_conflict (card_t card, const char *name, + const unsigned char *serialno_bin, + size_t serialno_bin_len); gpg_error_t card_reset (card_t card, ctrl_t ctrl, int send_reset); gpg_error_t select_application (ctrl_t ctrl, const char *name, card_t *r_app, int scan, const unsigned char *serialno_bin, diff --git a/scd/app.c b/scd/app.c index 1ad6b9ed6..ed7adc3a3 100644 --- a/scd/app.c +++ b/scd/app.c @@ -260,10 +260,15 @@ is_app_allowed (const char *name) * 0 - No conflict * GPG_ERR_FALSE - Another application is in use but it is possible * to switch to the requested application. - * other code - Switching is not possible. + * Other code - Switching is not possible. + * + * If SERIALNO_BIN is not NULL a coflict is onl asserted if the + * serialno of the card matches. */ gpg_error_t -check_application_conflict (card_t card, const char *name) +check_application_conflict (card_t card, const char *name, + const unsigned char *serialno_bin, + size_t serialno_bin_len) { app_t app; @@ -272,6 +277,13 @@ check_application_conflict (card_t card, const char *name) if (!card->app) return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED); /* Should not happen. */ + if (serialno_bin && card->serialno) + { + if (serialno_bin_len != card->serialnolen + || memcmp (serialno_bin, card->serialno, card->serialnolen)) + return 0; /* The card does not match the requested S/N. */ + } + /* Check whether the requested NAME matches any already selected * application. */ for (app = card->app; app; app = app->next) @@ -638,7 +650,7 @@ select_application (ctrl_t ctrl, const char *name, card_t *r_card, if (card) { - err = check_application_conflict (card, name); + err = check_application_conflict (card, name, NULL, 0); if (!err) { /* Note: We do not use card_ref as we are already locked. */ diff --git a/scd/command.c b/scd/command.c index f341b6ae2..0096ca96d 100644 --- a/scd/command.c +++ b/scd/command.c @@ -228,18 +228,22 @@ open_card_with_request (ctrl_t ctrl, size_t serialno_bin_len = 0; card_t card = ctrl->card_ctx; + if (serialno) + serialno_bin = hex_to_buffer (serialno, &serialno_bin_len); + /* If we are already initialized for one specific application we need to check that the client didn't requested a specific application different from the one in use before we continue. */ if (apptypestr && ctrl->card_ctx) { - err = check_application_conflict (ctrl->card_ctx, apptypestr); + err = check_application_conflict (ctrl->card_ctx, apptypestr, + serialno_bin, serialno_bin_len); if (gpg_err_code (err) == GPG_ERR_FALSE) { /* Different application but switching is supported. */ err = select_additional_application (ctrl, apptypestr); } - return err; + goto leave; } /* Re-scan USB devices. Release CARD, before the scan. */ @@ -247,13 +251,11 @@ open_card_with_request (ctrl_t ctrl, ctrl->card_ctx = NULL; card_unref (card); - if (serialno) - serialno_bin = hex_to_buffer (serialno, &serialno_bin_len); - err = select_application (ctrl, apptypestr, &ctrl->card_ctx, 1, serialno_bin, serialno_bin_len); - xfree (serialno_bin); + leave: + xfree (serialno_bin); return err; }