diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index 18f80374..70e15054 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -237,6 +237,7 @@ sc_pkcs15_unbind sc_pkcs15_unblock_pin sc_pkcs15_verify_pin sc_pkcs15_get_pin_info +sc_pkcs15_verify_pin_with_session_pin sc_pkcs15emu_add_data_object sc_pkcs15emu_add_pin_obj sc_pkcs15emu_add_rsa_prkey diff --git a/src/libopensc/pkcs15-pin.c b/src/libopensc/pkcs15-pin.c index 28a39b70..1c7df891 100644 --- a/src/libopensc/pkcs15-pin.c +++ b/src/libopensc/pkcs15-pin.c @@ -330,6 +330,22 @@ sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pi int _sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pin_obj, const unsigned char *pincode, size_t pinlen) +{ + return sc_pkcs15_verify_pin_with_session_pin(p15card, pin_obj, pincode, + pinlen, NULL, NULL); +} + +/* + * Verify a PIN and generate a session PIN + * + * If the code given to us has zero length, this means we + * should ask the card reader to obtain the PIN from the + * reader's PIN pad + */ +int sc_pkcs15_verify_pin_with_session_pin(struct sc_pkcs15_card *p15card, + struct sc_pkcs15_object *pin_obj, + const unsigned char *pincode, size_t pinlen, + const unsigned char *sessionpin, size_t *sessionpinlen) { struct sc_context *ctx = p15card->card->ctx; struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data; @@ -350,7 +366,6 @@ _sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *p /* Initialize arguments */ memset(&data, 0, sizeof(data)); - data.cmd = SC_PIN_CMD_VERIFY; data.pin_type = auth_info->auth_method; if (auth_info->auth_type == SC_PKCS15_PIN_AUTH_TYPE_PIN) { @@ -404,6 +419,19 @@ _sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *p data.pin1.prompt = "Please enter PIN"; } + if (card->caps & SC_CARD_CAP_SESSION_PIN && sessionpin && sessionpinlen) { + /* session pin is requested and supported with standard verification*/ + data.cmd = SC_PIN_CMD_GET_SESSION_PIN; + memcpy(&data.pin2, &data.pin1, sizeof (data.pin1)); + data.pin2.data = sessionpin; + data.pin2.len = *sessionpinlen; + } else { + /* perform a standard verify */ + data.cmd = SC_PIN_CMD_VERIFY; + if (sessionpinlen) + *sessionpinlen = 0; + } + r = sc_lock(card); LOG_TEST_RET(ctx, r, "sc_lock() failed"); @@ -416,6 +444,16 @@ _sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *p r = sc_pin_cmd(card, &data, &auth_info->tries_left); sc_log(ctx, "PIN cmd result %i", r); + if (r == SC_SUCCESS) { + sc_pkcs15_pincache_add(p15card, pin_obj, pincode, pinlen); + if (data.cmd == SC_PIN_CMD_GET_SESSION_PIN) { + *sessionpinlen = data.pin2.len; + } + } else { + if (data.cmd == SC_PIN_CMD_GET_SESSION_PIN) { + *sessionpinlen = 0; + } + } out: sc_unlock(card); LOG_FUNC_RETURN(ctx, r); diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index 1746cd3d..5352f9fb 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -767,6 +767,10 @@ int sc_pkcs15_find_skey_by_id(struct sc_pkcs15_card *card, int sc_pkcs15_verify_pin(struct sc_pkcs15_card *card, struct sc_pkcs15_object *pin_obj, const u8 *pincode, size_t pinlen); +int sc_pkcs15_verify_pin_with_session_pin(struct sc_pkcs15_card *p15card, + struct sc_pkcs15_object *pin_obj, + const unsigned char *pincode, size_t pinlen, + const unsigned char *sessionpin, size_t *sessionpinlen); int sc_pkcs15_change_pin(struct sc_pkcs15_card *card, struct sc_pkcs15_object *pin_obj, const u8 *oldpincode, size_t oldpinlen, diff --git a/src/minidriver/minidriver.c b/src/minidriver/minidriver.c index 34b12887..0e6ab786 100644 --- a/src/minidriver/minidriver.c +++ b/src/minidriver/minidriver.c @@ -2346,18 +2346,21 @@ md_dialog_perform_pin_operation_thread(PVOID lpParameter) const u8 *pin1 = (const u8 *) parameter[3]; size_t pin1len = parameter[4]; const u8 *pin2 = (const u8 *) parameter[5]; - size_t pin2len = parameter[6]; + size_t *pin2len = (size_t *) parameter[6]; int rv = 0; switch (operation) { case SC_PIN_CMD_VERIFY: rv = sc_pkcs15_verify_pin(p15card, pin_obj, pin1, pin1len); break; + case SC_PIN_CMD_GET_SESSION_PIN: + rv = sc_pkcs15_verify_pin_with_session_pin(p15card, pin_obj, pin1, pin1len, pin2, pin2len); + break; case SC_PIN_CMD_CHANGE: - rv = sc_pkcs15_change_pin(p15card, pin_obj, pin1, pin1len,pin2, pin2len); + rv = sc_pkcs15_change_pin(p15card, pin_obj, pin1, pin1len,pin2, pin2len ? *pin2len : 0); break; case SC_PIN_CMD_UNBLOCK: - rv = sc_pkcs15_unblock_pin(p15card, pin_obj, pin1, pin1len,pin2, pin2len); + rv = sc_pkcs15_unblock_pin(p15card, pin_obj, pin1, pin1len,pin2, pin2len ? *pin2len : 0); break; default: rv = (DWORD) ERROR_INVALID_PARAMETER; @@ -2421,7 +2424,7 @@ static int md_dialog_perform_pin_operation(PCARD_DATA pCardData, int operation, struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pin_obj, const u8 *pin1, size_t pin1len, - const u8 *pin2, size_t pin2len, BOOL displayUI) + const u8 *pin2, size_t *pin2len, BOOL displayUI) { LONG_PTR parameter[10]; INT_PTR result = 0; @@ -4750,6 +4753,7 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, VENDOR_SPECIFIC *vs; struct sc_pkcs15_object *pin_obj = NULL; struct sc_pkcs15_auth_info *auth_info = NULL; + unsigned int auth_method; int r; BOOL DisplayPinpadUI = FALSE; @@ -4773,11 +4777,16 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, if ((vs->p15card) == NULL) return SCARD_F_INTERNAL_ERROR; +#if 0 + /* TODO do we need to return SCARD_E_UNSUPPORTED_FEATURE if the card + * doesn't support it or if the minidriver doesn't support it in general? + * */ if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN || dwFlags == CARD_AUTHENTICATE_SESSION_PIN) { if (! (vs->reader->capabilities & SC_READER_CAP_PIN_PAD || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) return SCARD_E_UNSUPPORTED_FEATURE; } +#endif if (dwFlags & ~(CARD_AUTHENTICATE_GENERATE_SESSION_PIN | CARD_AUTHENTICATE_SESSION_PIN | CARD_PIN_SILENT_CONTEXT)) return SCARD_E_INVALID_PARAMETER; @@ -4808,6 +4817,8 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, if (!pin_obj) return SCARD_F_INTERNAL_ERROR; auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data; + /* save the pin type */ + auth_method = auth_info->auth_method; /* Do we need to display a prompt to enter PIN on pin pad? */ logprintf(pCardData, 7, "PIN pad=%s, pbPinData=%p, hwndParent=%p\n", @@ -4815,13 +4826,53 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH ? "yes" : "no", pbPinData, vs->hwndParent); - /* check if the pin is the session pin generated by a previous authentication with a pinpad */ - if (pbPinData != NULL && cbPinData == sizeof(MAGIC_SESSION_PIN) && memcmp(MAGIC_SESSION_PIN, pbPinData, sizeof(MAGIC_SESSION_PIN)) == 0) { - pbPinData = NULL; - cbPinData = 0; + if (dwFlags & CARD_AUTHENTICATE_SESSION_PIN) { + /* check if the pin is the session pin generated by a previous authentication with a pinpad */ + if (pbPinData != NULL && cbPinData == sizeof(MAGIC_SESSION_PIN) && memcmp(MAGIC_SESSION_PIN, pbPinData, sizeof(MAGIC_SESSION_PIN)) == 0) { + logprintf(pCardData, 2, "use magic session pin"); + pbPinData = NULL; + cbPinData = 0; + } else { + /* seems we have a real session pin, set the pin type accordingly */ + logprintf(pCardData, 2, "use real session pin with %d bytes", cbPinData); + auth_info->auth_method = SC_AC_SESSION; + } } - r = md_dialog_perform_pin_operation(pCardData, SC_PIN_CMD_VERIFY, vs->p15card, pin_obj, (const u8 *) pbPinData, cbPinData, NULL, 0, DisplayPinpadUI); + /* set the session pin according to the minidriver specification */ + if (dwFlags & CARD_AUTHENTICATE_GENERATE_SESSION_PIN) { + logprintf(pCardData, 2, "generating session pin"); + if (ppbSessionPin) *ppbSessionPin = pCardData->pfnCspAlloc(SC_MAX_PIN_SIZE); + if (ppbSessionPin) *pcbSessionPin = SC_MAX_PIN_SIZE; + r = md_dialog_perform_pin_operation(pCardData, SC_PIN_CMD_GET_SESSION_PIN, vs->p15card, pin_obj, (const u8 *) pbPinData, cbPinData, + ppbSessionPin && *ppbSessionPin ? *ppbSessionPin : NULL, pcbSessionPin, DisplayPinpadUI); + if (r) { + if (ppbSessionPin) { + pCardData->pfnCspFree(*ppbSessionPin); + *ppbSessionPin = NULL; + } + if (pcbSessionPin) *pcbSessionPin = 0; + logprintf(pCardData, 2, "generating session pin failed"); + } else { + if (pcbSessionPin && *pcbSessionPin) { + logprintf(pCardData, 2, "generated session pin with %d bytes", *pcbSessionPin); + } else { + logprintf(pCardData, 2, "session pin not supported"); + if (ppbSessionPin) { + pCardData->pfnCspFree(*ppbSessionPin); + *ppbSessionPin = NULL; + } + } + } + } else { + if (pcbSessionPin) *pcbSessionPin = 0; + if (ppbSessionPin) *ppbSessionPin = NULL; + logprintf(pCardData, 2, "standard pin verification"); + r = md_dialog_perform_pin_operation(pCardData, SC_PIN_CMD_VERIFY, vs->p15card, pin_obj, (const u8 *) pbPinData, cbPinData, NULL, NULL, DisplayPinpadUI); + } + + /* restore the pin type */ + auth_info->auth_method = auth_method; if (r) { logprintf(pCardData, 1, "PIN code verification failed: %s; tries left %i\n", sc_strerror(r), auth_info->tries_left); @@ -4841,17 +4892,16 @@ DWORD WINAPI CardAuthenticateEx(__in PCARD_DATA pCardData, /* set the session pin according to the minidriver specification */ if (dwFlags == CARD_AUTHENTICATE_GENERATE_SESSION_PIN + && pcbSessionPin && *pcbSessionPin == 0 && (vs->reader->capabilities & SC_READER_CAP_PIN_PAD || vs->p15card->card->caps & SC_CARD_CAP_PROTECTED_AUTHENTICATION_PATH)) { - /* we set it to a special value for pinpad authentication to force a new pinpad authentication */ - if (pcbSessionPin) *pcbSessionPin = sizeof(MAGIC_SESSION_PIN); + /* If we could not generate a real session PIN, set it to a special + * value for pinpad authentication to force a new pinpad authentication */ + *pcbSessionPin = sizeof(MAGIC_SESSION_PIN); if (ppbSessionPin) { *ppbSessionPin = pCardData->pfnCspAlloc(sizeof(MAGIC_SESSION_PIN)); if (ppbSessionPin) memcpy(*ppbSessionPin, MAGIC_SESSION_PIN, sizeof(MAGIC_SESSION_PIN)); } - } else { - if (pcbSessionPin) *pcbSessionPin = 0; - if (ppbSessionPin) *ppbSessionPin = NULL; } return SCARD_S_SUCCESS; @@ -4945,7 +4995,7 @@ DWORD WINAPI CardChangeAuthenticatorEx(__in PCARD_DATA pCardData, (*pcAttemptsRemaining) = (DWORD) -1; rv = md_dialog_perform_pin_operation(pCardData, (dwFlags & PIN_CHANGE_FLAG_UNBLOCK ? SC_PIN_CMD_UNBLOCK:SC_PIN_CMD_CHANGE), - vs->p15card, pin_obj, (const u8 *) pbAuthenticatingPinData, cbAuthenticatingPinData, pbTargetData, cbTargetData, DisplayPinpadUI); + vs->p15card, pin_obj, (const u8 *) pbAuthenticatingPinData, cbAuthenticatingPinData, pbTargetData, &cbTargetData, DisplayPinpadUI); if (rv) { logprintf(pCardData, 2, "Failed to %s %s PIN: '%s' (%i)\n", @@ -5261,6 +5311,9 @@ DWORD WINAPI CardGetProperty(__in PCARD_DATA pCardData, if (cbData < sizeof(*p)) return ERROR_INSUFFICIENT_BUFFER; *p = CARD_PIN_STRENGTH_PLAINTEXT; + if (vs->p15card->card->caps & SC_CARD_CAP_SESSION_PIN) { + *p |= CARD_PIN_STRENGTH_SESSION_PIN; + } } else if (wcscmp(CP_KEY_IMPORT_SUPPORT, wszProperty) == 0) { DWORD *p = (DWORD *)pbData;