diff --git a/src/libopensc/card-piv.c b/src/libopensc/card-piv.c index d6381847..7cdb93ff 100644 --- a/src/libopensc/card-piv.c +++ b/src/libopensc/card-piv.c @@ -168,6 +168,7 @@ typedef struct piv_private_data { int logged_in; int pstate; int pin_cmd_verify; + int context_specific; int pin_cmd_noparse; unsigned int pin_cmd_verify_sw1; unsigned int pin_cmd_verify_sw2; @@ -919,6 +920,8 @@ piv_get_data(sc_card_t * card, int enumtag, u8 **buf, size_t *buf_len) SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE); sc_log(card->ctx, "#%d", enumtag); + sc_lock(card); /* do check len and get data in same transaction */ + /* assert(enumtag >= 0 && enumtag < PIV_OBJ_LAST_ENUM); */ tag_len = piv_objects[enumtag].tag_len; @@ -970,6 +973,7 @@ piv_get_data(sc_card_t * card, int enumtag, u8 **buf, size_t *buf_len) r = piv_general_io(card, 0xCB, 0x3F, 0xFF, tagbuf, p - tagbuf, buf, buf_len); err: + sc_unlock(card); LOG_FUNC_RETURN(card->ctx, r); } @@ -3032,7 +3036,7 @@ static int piv_match_card(sc_card_t *card) if (card->type == -1) card->type = type; - card->drv_data = priv; /* will frre if no match, or pass on to piv_init */ + card->drv_data = priv; /* will free if no match, or pass on to piv_init */ priv->aid_file = sc_file_new(); priv->selected_obj = -1; priv->pin_preference = 0x80; /* 800-73-3 part 1, table 3 */ @@ -3056,18 +3060,18 @@ static int piv_match_card(sc_card_t *card) * putting PIV driver first might help. * TODO could be cached too */ - i = piv_find_discovery(card); + i = piv_find_discovery(card); if (i < 0) { - /* Detect by selecting applet */ - i = piv_find_aid(card, &aidfile); + /* Detect by selecting applet */ + i = piv_find_aid(card, &aidfile); } if (i < 0) { piv_finish(card); - /* don't match. Does not have a PIV applet. */ - sc_unlock(card); - return 0; + /* don't match. Does not have a PIV applet. */ + sc_unlock(card); + return 0; } /* Matched, and priv is being passed to piv_init */ @@ -3218,7 +3222,16 @@ static int piv_check_sw(struct sc_card *card, unsigned int sw1, unsigned int sw2 if (priv->pin_cmd_verify) { priv->pin_cmd_verify_sw1 = sw1; priv->pin_cmd_verify_sw2 = sw2; + } else { + /* a command has completed and it is not verify */ + /* If we are in a context_specific sequence, unlock */ + if (priv->context_specific) { + sc_log(card->ctx,"Clearing CONTEXT_SPECIFIC lock"); + priv->context_specific = 0; + sc_unlock(card); + } } + if (priv->card_issues & CI_VERIFY_630X) { /* Handle the Yubikey NEO or any other PIV card which returns in response to a verify @@ -3360,10 +3373,30 @@ piv_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left) } } + /* + * If this was for a CKU_CONTEXT_SPECFIC login, lock the card one more time. + * to avoid any interference from other applications. + * Sc_unlock will be called at a later time after the next card command + * that should be a crypto operation. If its not then it is a error by the + * calling appication. + */ + if (data->cmd == SC_PIN_CMD_VERIFY && data->pin_type == SC_AC_CONTEXT_SPECIFIC) { + priv->context_specific = 1; + sc_log(card->ctx,"Starting CONTEXT_SPECIFIC verify"); + sc_lock(card); + } + priv->pin_cmd_verify = 1; /* tell piv_check_sw its a verify to save sw1, sw2 */ r = iso_drv->ops->pin_cmd(card, data, tries_left); priv->pin_cmd_verify = 0; + /* if verify failed, release the lock */ + if (data->cmd == SC_PIN_CMD_VERIFY && r < 0 && priv->context_specific) { + sc_log(card->ctx,"Clearing CONTEXT_SPECIFIC"); + priv->context_specific = 0; + sc_unlock(card); + } + /* if access to applet is know to be reset by other driver we select_aid and try again */ if ( priv->card_issues & CI_OTHER_AID_LOSE_STATE && priv->pin_cmd_verify_sw1 == 0x6DU) { sc_log(card->ctx, "AID may be lost doing piv_find_aid and retry pin_cmd"); @@ -3452,17 +3485,17 @@ static int piv_card_reader_lock_obtained(sc_card_t *card, int was_reset) /* We have a PCSC transaction and sc_lock */ if (priv == NULL || priv->pstate == PIV_STATE_MATCH) { sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, - priv ? "PIV_STATE_MATCH" : "priv==NULL"); + priv ? "PIV_STATE_MATCH" : "priv==NULL"); r = 0; /* do nothing, piv_match will take care of it */ goto err; } /* make sure our application is active */ - /* first see if AID is active AID be reading discovery obkect '7E' */ + /* first see if AID is active AID by reading discovery object '7E' */ /* If not try selecting AID */ r = piv_find_discovery(card); - if (r < 0) + if (r < 0) r = piv_select_aid(card, piv_aids[0].value, piv_aids[0].len_short, temp, &templen); if (r < 0) /* bad error return will show up in sc_lock as error*/ diff --git a/src/libopensc/iso7816.c b/src/libopensc/iso7816.c index e5916e7d..9ed49f2b 100644 --- a/src/libopensc/iso7816.c +++ b/src/libopensc/iso7816.c @@ -1017,6 +1017,7 @@ iso7816_build_pin_apdu(struct sc_card *card, struct sc_apdu *apdu, case SC_AC_CHV: /* fall through */ case SC_AC_SESSION: + case SC_AC_CONTEXT_SPECIFIC: break; default: return SC_ERROR_INVALID_ARGUMENTS; diff --git a/src/libopensc/types.h b/src/libopensc/types.h index e665c54b..ab0ddd8e 100644 --- a/src/libopensc/types.h +++ b/src/libopensc/types.h @@ -149,6 +149,7 @@ struct sc_crt { #define SC_AC_SCB 0x00000040 /* IAS/ECC SCB byte. */ #define SC_AC_IDA 0x00000080 /* PKCS#15 authentication ID */ #define SC_AC_SESSION 0x00000100 /* Session PIN */ +#define SC_AC_CONTEXT_SPECIFIC 0x00000200 /* Context specific login */ #define SC_AC_UNKNOWN 0xFFFFFFFE #define SC_AC_NEVER 0xFFFFFFFF diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c index a4a1e1c3..aee08a4a 100644 --- a/src/pkcs11/framework-pkcs15.c +++ b/src/pkcs11/framework-pkcs15.c @@ -1617,7 +1617,16 @@ pkcs15_login(struct sc_pkcs11_slot *slot, CK_USER_TYPE userType, } } - rc = sc_pkcs15_verify_pin(p15card, auth_object, pPin, ulPinLen); + if (userType == CKU_CONTEXT_SPECIFIC && pin_info) { + int auth_meth_saved = pin_info->auth_method; + + sc_log(context, "Setting SC_AC_CONTEXT_SPECIFIC"); + pin_info->auth_method = SC_AC_CONTEXT_SPECIFIC; + rc = sc_pkcs15_verify_pin(p15card, auth_object, pPin, ulPinLen); + pin_info->auth_method = auth_meth_saved; + } else + rc = sc_pkcs15_verify_pin(p15card, auth_object, pPin, ulPinLen); + sc_log(context, "PKCS15 verify PIN returned %d", rc); if (rc != SC_SUCCESS)