diff --git a/etc/opensc.conf.in b/etc/opensc.conf.in index fad82f7f..3e8c727a 100644 --- a/etc/opensc.conf.in +++ b/etc/opensc.conf.in @@ -594,6 +594,27 @@ app opensc-pkcs11 { # Default: false # lock_login = true; + # By default, interacting with the OpenSC PKCS#11 module may change the + # state of the token, e.g. whether a user is logged in or not. + # + # Thus other users or other applications may change or use the state of + # the token unknowingly. Other applications may create signatures + # abusing an existing login or they may logout unnoticed. + # + # With this setting enabled the login state of the token is tracked and + # cached (including the PIN). Every transaction is preceeded by + # restoring the login state. After every transaction a logout is + # performed. This setting by default also enables `lock_login` (see + # above) to disable access for other applications during the atomic + # transactions. + # + # Please note that any PIN-pad should be disabled (see `enable_pinpad` + # above), because the user would have to input his PIN for every + # transaction. + # + # Default: false + # atomic = true; + # With this setting disabled, the OpenSC PKCS#11 module will initialize # the slots available when the application calls `C_GetSlotList`. With # this setting enabled, the slots will also get initialized when diff --git a/src/libopensc/card-cardos.c b/src/libopensc/card-cardos.c index 7b5b51fd..0e048bce 100644 --- a/src/libopensc/card-cardos.c +++ b/src/libopensc/card-cardos.c @@ -1221,8 +1221,13 @@ cardos_pin_cmd(struct sc_card *card, struct sc_pin_cmd_data *data, static int cardos_logout(sc_card_t *card) { - if (card->type == SC_CARD_TYPE_CARDOS_M4_01 || - card->type == SC_CARD_TYPE_CARDOS_M4_2) { + if (card->type == SC_CARD_TYPE_CARDOS_M4_01 + || card->type == SC_CARD_TYPE_CARDOS_M4_2 + || card->type == SC_CARD_TYPE_CARDOS_M4_2B + || card->type == SC_CARD_TYPE_CARDOS_M4_2C + || card->type == SC_CARD_TYPE_CARDOS_M4_3 + || card->type == SC_CARD_TYPE_CARDOS_M4_4 + || card->type == SC_CARD_TYPE_CARDOS_V5_0) { sc_apdu_t apdu; int r; sc_path_t path; diff --git a/src/libopensc/libopensc.exports b/src/libopensc/libopensc.exports index cea8d42f..e7f725bb 100644 --- a/src/libopensc/libopensc.exports +++ b/src/libopensc/libopensc.exports @@ -125,6 +125,7 @@ sc_list_files sc_lock sc_logout sc_make_cache_dir +sc_mem_alloc_secure sc_mem_clear sc_mem_reverse sc_match_atr_block diff --git a/src/libopensc/pkcs15-sec.c b/src/libopensc/pkcs15-sec.c index df78f604..019d8a14 100644 --- a/src/libopensc/pkcs15-sec.c +++ b/src/libopensc/pkcs15-sec.c @@ -34,8 +34,8 @@ #include "pkcs15.h" static int select_key_file(struct sc_pkcs15_card *p15card, - const struct sc_pkcs15_prkey_info *prkey, - sc_security_env_t *senv) + const struct sc_pkcs15_prkey_info *prkey, + sc_security_env_t *senv) { sc_context_t *ctx = p15card->card->ctx; sc_path_t path, file_id; @@ -49,8 +49,8 @@ static int select_key_file(struct sc_pkcs15_card *p15card, /* TODO: Why file_app may be NULL -- at least 3F00 has to be present? * Check validity of the following assumption. */ /* For pkcs15-emulated cards, the file_app may be NULL, - in that case we allways assume an absolute path */ - if (!prkey->path.len && prkey->path.aid.len) { + * in that case we allways assume an absolute path */ + if (!prkey->path.len && prkey->path.aid.len) { /* Private key is a SDO allocated in application DF */ path = prkey->path; } @@ -62,7 +62,7 @@ static int select_key_file(struct sc_pkcs15_card *p15card, senv->file_ref = file_id; senv->flags |= SC_SEC_ENV_FILE_REF_PRESENT; } - else if (prkey->path.len > 2) { + else if (prkey->path.len > 2) { path = prkey->path; memcpy(file_id.value, prkey->path.value + prkey->path.len - 2, 2); file_id.len = 2; @@ -70,7 +70,7 @@ static int select_key_file(struct sc_pkcs15_card *p15card, senv->file_ref = file_id; senv->flags |= SC_SEC_ENV_FILE_REF_PRESENT; } - else { + else { LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "invalid private key path"); } @@ -79,11 +79,122 @@ static int select_key_file(struct sc_pkcs15_card *p15card, LOG_FUNC_RETURN(ctx, SC_SUCCESS); } + +static int use_key(struct sc_pkcs15_card *p15card, + const struct sc_pkcs15_object *obj, + sc_security_env_t *senv, + int (*card_command)(sc_card_t *card, + const u8 * in, size_t inlen, + u8 * out, size_t outlen), + const u8 * in, size_t inlen, u8 * out, size_t outlen) +{ + int r = SC_SUCCESS; + int revalidated_cached_pin = 0; + const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data; + + r = sc_lock(p15card->card); + LOG_TEST_RET(p15card->card->ctx, r, "sc_lock() failed"); + + do { + if (prkey->path.len != 0 || prkey->path.aid.len != 0) { + r = select_key_file(p15card, prkey, senv); + if (r < 0) { + sc_log(p15card->card->ctx, + "Unable to select private key file"); + } + } + if (r == SC_SUCCESS) + r = sc_set_security_env(p15card->card, senv, 0); + + if (r == SC_SUCCESS) + r = card_command(p15card->card, in, inlen, out, outlen); + + if (revalidated_cached_pin) + /* only re-validate once */ + break; + if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) { + r = sc_pkcs15_pincache_revalidate(p15card, obj); + if (r < 0) + break; + revalidated_cached_pin = 1; + } + } while (revalidated_cached_pin); + + sc_unlock(p15card->card); + + return r; +} + +static int format_senv(struct sc_pkcs15_card *p15card, + const struct sc_pkcs15_object *obj, + sc_security_env_t *senv_out, sc_algorithm_info_t **alg_info_out) +{ + sc_context_t *ctx = p15card->card->ctx; + const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data; + + memset(senv_out, 0, sizeof(*senv_out)); + + /* Card driver should have the access to supported algorithms from 'tokenInfo'. So that + * it can get value of card specific 'AlgorithmInfo::algRef'. */ + memcpy(senv_out->supported_algos, &p15card->tokeninfo->supported_algos, sizeof(senv_out->supported_algos)); + + if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) != SC_PKCS15_TYPE_PRKEY) + LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This is not a private key"); + + /* If the key is not native, we can't operate with it. */ + if (!prkey->native) + LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "This key is not native, cannot operate with it"); + + switch (obj->type) { + case SC_PKCS15_TYPE_PRKEY_RSA: + *alg_info_out = sc_card_find_rsa_alg(p15card->card, prkey->modulus_length); + if (*alg_info_out == NULL) { + sc_log(ctx, "Card does not support RSA with key length %d", prkey->modulus_length); + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); + } + senv_out->algorithm = SC_ALGORITHM_RSA; + break; + + case SC_PKCS15_TYPE_PRKEY_GOSTR3410: + *alg_info_out = sc_card_find_gostr3410_alg(p15card->card, prkey->modulus_length); + if (alg_info_out == NULL) { + sc_log(ctx, "Card does not support GOSTR3410 with key length %d", prkey->modulus_length); + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); + } + senv_out->algorithm = SC_ALGORITHM_GOSTR3410; + break; + + case SC_PKCS15_TYPE_PRKEY_EC: + *alg_info_out = sc_card_find_ec_alg(p15card->card, prkey->field_length, NULL); + if (*alg_info_out == NULL) { + sc_log(ctx, "Card does not support EC with field_size %d", prkey->field_length); + LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); + } + senv_out->algorithm = SC_ALGORITHM_EC; + + senv_out->flags |= SC_SEC_ENV_ALG_REF_PRESENT; + senv_out->algorithm_ref = prkey->field_length; + break; + /* add other crypto types here */ + default: + LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Key type not supported"); + } + senv_out->flags |= SC_SEC_ENV_ALG_PRESENT; + + /* optional keyReference attribute (the default value is -1) */ + if (prkey->key_reference >= 0) { + senv_out->key_ref_len = 1; + senv_out->key_ref[0] = prkey->key_reference & 0xFF; + senv_out->flags |= SC_SEC_ENV_KEY_REF_PRESENT; + } + + return SC_SUCCESS; +} int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card, - const struct sc_pkcs15_object *obj, - unsigned long flags, - const u8 * in, size_t inlen, u8 *out, size_t outlen) + const struct sc_pkcs15_object *obj, + unsigned long flags, + const u8 * in, size_t inlen, u8 *out, size_t outlen) { sc_context_t *ctx = p15card->card->ctx; int r; @@ -93,80 +204,21 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card, unsigned long pad_flags = 0, sec_flags = 0; LOG_FUNC_CALLED(ctx); - - memset(&senv, 0, sizeof(senv)); - - /* Card driver should have the access to supported algorithms from 'tokenInfo'. So that - * it can get value of card specific 'AlgorithmInfo::algRef'. */ - memcpy(&senv.supported_algos, &p15card->tokeninfo->supported_algos, sizeof(senv.supported_algos)); - - /* If the key is not native, we can't operate with it. */ - if (!prkey->native) - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "This key is not native, cannot operate with it"); - + if (!(prkey->usage & (SC_PKCS15_PRKEY_USAGE_DECRYPT|SC_PKCS15_PRKEY_USAGE_UNWRAP))) LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for decryption"); - switch (obj->type) { - case SC_PKCS15_TYPE_PRKEY_RSA: - alg_info = sc_card_find_rsa_alg(p15card->card, prkey->modulus_length); - if (alg_info == NULL) { - sc_log(ctx, "Card does not support RSA with key length %d", prkey->modulus_length); - LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); - } - senv.algorithm = SC_ALGORITHM_RSA; - break; - - case SC_PKCS15_TYPE_PRKEY_GOSTR3410: - alg_info = sc_card_find_gostr3410_alg(p15card->card, prkey->modulus_length); - if (alg_info == NULL) { - sc_log(ctx, "Card does not support GOSTR3410 with key length %d", prkey->modulus_length); - LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); - } - senv.algorithm = SC_ALGORITHM_GOSTR3410; - break; - - default: - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED,"Key type not supported"); - } + r = format_senv(p15card, obj, &senv, &alg_info); + LOG_TEST_RET(ctx, r, "Could not initialize security environment"); + senv.operation = SC_SEC_OPERATION_DECIPHER; r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags); LOG_TEST_RET(ctx, r, "cannot encode security operation flags"); - senv.algorithm_flags = sec_flags; - senv.operation = SC_SEC_OPERATION_DECIPHER; - senv.flags = 0; - /* optional keyReference attribute (the default value is -1) */ - if (prkey->key_reference >= 0) { - senv.key_ref_len = 1; - senv.key_ref[0] = prkey->key_reference & 0xFF; - senv.flags |= SC_SEC_ENV_KEY_REF_PRESENT; - } - senv.flags |= SC_SEC_ENV_ALG_PRESENT; - r = sc_lock(p15card->card); - LOG_TEST_RET(ctx, r, "sc_lock() failed"); - - if (prkey->path.len != 0 || prkey->path.aid.len != 0) { - r = select_key_file(p15card, prkey, &senv); - if (r < 0) { - sc_unlock(p15card->card); - LOG_TEST_RET(ctx, r,"Unable to select private key file"); - } - } - - r = sc_set_security_env(p15card->card, &senv, 0); - if (r < 0) { - sc_unlock(p15card->card); - LOG_TEST_RET(ctx, r, "sc_set_security_env() failed"); - } - r = sc_decipher(p15card->card, in, inlen, out, outlen); - if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) { - if (sc_pkcs15_pincache_revalidate(p15card, obj) == SC_SUCCESS) - r = sc_decipher(p15card->card, in, inlen, out, outlen); - } - sc_unlock(p15card->card); - LOG_TEST_RET(ctx, r, "sc_decipher() failed"); + r = use_key(p15card, obj, &senv, sc_decipher, in, inlen, out, + outlen); + LOG_TEST_RET(ctx, r, "use_key() failed"); /* Strip any padding */ if (pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) { @@ -185,10 +237,10 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card, * In that case r = 0, and *poutlen = expected size */ int sc_pkcs15_derive(struct sc_pkcs15_card *p15card, - const struct sc_pkcs15_object *obj, - unsigned long flags, - const u8 * in, size_t inlen, u8 *out, - unsigned long *poutlen) + const struct sc_pkcs15_object *obj, + unsigned long flags, + const u8 * in, size_t inlen, u8 *out, + unsigned long *poutlen) { sc_context_t *ctx = p15card->card->ctx; int r; @@ -199,81 +251,32 @@ int sc_pkcs15_derive(struct sc_pkcs15_card *p15card, LOG_FUNC_CALLED(ctx); - memset(&senv, 0, sizeof(senv)); - - /* Card driver should have the access to supported algorithms from 'tokenInfo'. So that - * it can get value of card specific 'AlgorithmInfo::algRef'. */ - memcpy(&senv.supported_algos, &p15card->tokeninfo->supported_algos, sizeof(senv.supported_algos)); - - /* If the key is not native, we can't operate with it. */ - if (!prkey->native) - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "This key is not native, cannot operate with it"); - if (!(prkey->usage & (SC_PKCS15_PRKEY_USAGE_DERIVE))) LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for derivation"); switch (obj->type) { case SC_PKCS15_TYPE_PRKEY_EC: - alg_info = sc_card_find_ec_alg(p15card->card, prkey->field_length, NULL); - if (alg_info == NULL) { - sc_log(ctx, "Card does not support EC with field_size %d", prkey->field_length); - LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); - } - if (out == NULL || *poutlen < (prkey->field_length + 7) / 8) { - *poutlen = (prkey->field_length + 7) / 8; - r = 0; /* say no data to return */ - goto out; + *poutlen = (prkey->field_length + 7) / 8; + r = 0; /* say no data to return */ + LOG_FUNC_RETURN(ctx, r); } - - senv.algorithm = SC_ALGORITHM_EC; - senv.flags |= SC_SEC_ENV_ALG_PRESENT; - - senv.flags |= SC_SEC_ENV_ALG_REF_PRESENT; - senv.algorithm_ref = prkey->field_length; break; default: LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED,"Key type not supported"); } + r = format_senv(p15card, obj, &senv, &alg_info); + LOG_TEST_RET(ctx, r, "Could not initialize security environment"); + senv.operation = SC_SEC_OPERATION_DERIVE; + r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags); LOG_TEST_RET(ctx, r, "cannot encode security operation flags"); - senv.algorithm_flags = sec_flags; - senv.operation = SC_SEC_OPERATION_DERIVE; - /* optional keyReference attribute (the default value is -1) */ - if (prkey->key_reference >= 0) { - senv.key_ref_len = 1; - senv.key_ref[0] = prkey->key_reference & 0xFF; - senv.flags |= SC_SEC_ENV_KEY_REF_PRESENT; - } - r = sc_lock(p15card->card); - LOG_TEST_RET(ctx, r, "sc_lock() failed"); - - if (prkey->path.len != 0 || prkey->path.aid.len != 0) { - r = select_key_file(p15card, prkey, &senv); - if (r < 0) { - sc_unlock(p15card->card); - LOG_TEST_RET(ctx, r,"Unable to select private key file"); - } - } - - r = sc_set_security_env(p15card->card, &senv, 0); - if (r < 0) { - sc_unlock(p15card->card); - LOG_TEST_RET(ctx, r, "sc_set_security_env() failed"); - } -/* TODO Do we need a sc_derive? PIV at least can use the decipher, - * senv.operation = SC_SEC_OPERATION_DERIVE; - */ - r = sc_decipher(p15card->card, in, inlen, out, *poutlen); - if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) { - if (sc_pkcs15_pincache_revalidate(p15card, obj) == SC_SUCCESS) - r = sc_decipher(p15card->card, in, inlen, out, *poutlen); - } - sc_unlock(p15card->card); - LOG_TEST_RET(ctx, r, "sc_decipher/derive() failed"); + r = use_key(p15card, obj, &senv, sc_decipher, in, inlen, out, + *poutlen); + LOG_TEST_RET(ctx, r, "use_key() failed"); /* Strip any padding */ if (pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) { @@ -283,9 +286,8 @@ int sc_pkcs15_derive(struct sc_pkcs15_card *p15card, } /* If card stores derived key on card, then no data is returned - * and the key must be used on the card. */ + * and the key must be used on the card. */ *poutlen = r; -out: LOG_FUNC_RETURN(ctx, r); } @@ -310,62 +312,25 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, unsigned long pad_flags = 0, sec_flags = 0; LOG_FUNC_CALLED(ctx); - sc_log(ctx, "security operation flags 0x%X", flags); - - memset(&senv, 0, sizeof(senv)); - - /* Card driver should have the access to supported algorithms from 'tokenInfo'. So that - * it can get value of card specific 'AlgorithmInfo::algRef'. */ - memcpy(&senv.supported_algos, &p15card->tokeninfo->supported_algos, sizeof(senv.supported_algos)); - - if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) != SC_PKCS15_TYPE_PRKEY) - LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This is not a private key"); - - /* If the key is not native, we can't operate with it. */ - if (!prkey->native) - LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "This key is not native, cannot operate with it"); if (!(prkey->usage & (SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_SIGNRECOVER| - SC_PKCS15_PRKEY_USAGE_NONREPUDIATION))) + SC_PKCS15_PRKEY_USAGE_NONREPUDIATION))) LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for signing"); + r = format_senv(p15card, obj, &senv, &alg_info); + LOG_TEST_RET(ctx, r, "Could not initialize security environment"); + senv.operation = SC_SEC_OPERATION_SIGN; + switch (obj->type) { case SC_PKCS15_TYPE_PRKEY_RSA: modlen = prkey->modulus_length / 8; - alg_info = sc_card_find_rsa_alg(p15card->card, prkey->modulus_length); - if (alg_info == NULL) { - sc_log(ctx, "Card does not support RSA with key length %d", prkey->modulus_length); - LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); - } - senv.flags |= SC_SEC_ENV_ALG_PRESENT; - senv.algorithm = SC_ALGORITHM_RSA; break; - case SC_PKCS15_TYPE_PRKEY_GOSTR3410: modlen = (prkey->modulus_length + 7) / 8 * 2; - alg_info = sc_card_find_gostr3410_alg(p15card->card, prkey->modulus_length); - if (alg_info == NULL) { - sc_log(ctx, "Card does not support GOSTR3410 with key length %d", prkey->modulus_length); - LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); - } - senv.flags |= SC_SEC_ENV_ALG_PRESENT; - senv.algorithm = SC_ALGORITHM_GOSTR3410; break; - case SC_PKCS15_TYPE_PRKEY_EC: modlen = ((prkey->field_length +7) / 8) * 2; /* 2*nLen */ - alg_info = sc_card_find_ec_alg(p15card->card, prkey->field_length, NULL); - if (alg_info == NULL) { - sc_log(ctx, "Card does not support EC with field_size %d", prkey->field_length); - LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); - } - senv.algorithm = SC_ALGORITHM_EC; - senv.flags |= SC_SEC_ENV_ALG_PRESENT; - - senv.flags |= SC_SEC_ENV_ALG_REF_PRESENT; - senv.algorithm_ref = prkey->field_length; break; - /* add other crypto types here */ default: LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Key type not supported"); } @@ -389,7 +354,7 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, * senv.algorithm_flags: what the card will have to do */ /* if the card has SC_ALGORITHM_NEED_USAGE set, and the - key is for signing and decryption, we need to emulate signing */ + * key is for signing and decryption, we need to emulate signing */ /* TODO: -DEE assume only RSA keys will ever use _NEED_USAGE */ sc_log(ctx, "supported algorithm flags 0x%X, private key usage 0x%X", alg_info->flags, prkey->usage); @@ -421,7 +386,7 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, /* If the card doesn't support the requested algorithm, see if we * can strip the input so a more restrictive algo can be used */ if ((flags == (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) && - !(alg_info->flags & (SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_NONE))) { + !(alg_info->flags & (SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_NONE))) { unsigned int algo; size_t tmplen = sizeof(buf); @@ -466,41 +431,10 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, inlen = modlen; } - senv.operation = SC_SEC_OPERATION_SIGN; - - /* optional keyReference attribute (the default value is -1) */ - if (prkey->key_reference >= 0) { - senv.key_ref_len = 1; - senv.key_ref[0] = prkey->key_reference & 0xFF; - senv.flags |= SC_SEC_ENV_KEY_REF_PRESENT; - } - - r = sc_lock(p15card->card); - LOG_TEST_RET(ctx, r, "sc_lock() failed"); - - sc_log(ctx, "Private key path '%s'", sc_print_path(&prkey->path)); - if (prkey->path.len != 0 || prkey->path.aid.len != 0) { - r = select_key_file(p15card, prkey, &senv); - if (r < 0) { - sc_unlock(p15card->card); - LOG_TEST_RET(ctx, r,"Unable to select private key file"); - } - } - - r = sc_set_security_env(p15card->card, &senv, 0); - if (r < 0) { - sc_unlock(p15card->card); - LOG_TEST_RET(ctx, r, "sc_set_security_env() failed"); - } - - r = sc_compute_signature(p15card->card, tmp, inlen, out, outlen); - if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) - if (sc_pkcs15_pincache_revalidate(p15card, obj) == SC_SUCCESS) - r = sc_compute_signature(p15card->card, tmp, inlen, out, outlen); - + r = use_key(p15card, obj, &senv, sc_compute_signature, tmp, inlen, + out, outlen); + LOG_TEST_RET(ctx, r, "use_key() failed"); sc_mem_clear(buf, sizeof(buf)); - sc_unlock(p15card->card); - LOG_TEST_RET(ctx, r, "sc_compute_signature() failed"); LOG_FUNC_RETURN(ctx, r); } diff --git a/src/pkcs11/misc.c b/src/pkcs11/misc.c index 2ade4f5d..910804d3 100644 --- a/src/pkcs11/misc.c +++ b/src/pkcs11/misc.c @@ -127,6 +127,121 @@ CK_RV sc_to_cryptoki_error(int rc, const char *ctx) } +struct sc_pkcs11_login { + CK_USER_TYPE userType; + CK_CHAR_PTR pPin; + CK_ULONG ulPinLen; +}; + +CK_RV restore_login_state(struct sc_pkcs11_slot *slot) +{ + CK_RV r = CKR_OK; + + if (sc_pkcs11_conf.atomic && slot) { + if (list_iterator_start(&slot->logins)) { + struct sc_pkcs11_login *login = list_iterator_next(&slot->logins); + while (login) { + r = slot->p11card->framework->login(slot, login->userType, + login->pPin, login->ulPinLen); + if (r != CKR_OK) + break; + login = list_iterator_next(&slot->logins); + } + list_iterator_stop(&slot->logins); + } + } + + return r; +} + +CK_RV reset_login_state(struct sc_pkcs11_slot *slot, CK_RV rv) +{ + if (slot) { + if (sc_pkcs11_conf.atomic + && slot->p11card && slot->p11card->framework) { + slot->p11card->framework->logout(slot); + } + + if (rv == CKR_USER_NOT_LOGGED_IN) { + slot->login_user = -1; + pop_all_login_states(slot); + } + } + + return rv; +} + +CK_RV push_login_state(struct sc_pkcs11_slot *slot, + CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) +{ + CK_RV r = CKR_HOST_MEMORY; + struct sc_pkcs11_login *login = NULL; + + if (!sc_pkcs11_conf.atomic || !slot) { + r = CKR_OK; + goto err; + } + + login = (struct sc_pkcs11_login *) malloc(sizeof *login); + if (login == NULL) { + goto err; + } + + login->pPin = sc_mem_alloc_secure(context, (sizeof *pPin)*ulPinLen); + if (login->pPin == NULL) { + goto err; + } + memcpy(login->pPin, pPin, (sizeof *pPin)*ulPinLen); + login->ulPinLen = ulPinLen; + login->userType = userType; + + if (0 > list_append(&slot->logins, login)) { + goto err; + } + + r = CKR_OK; + +err: + if (r != CKR_OK && login) { + sc_mem_clear(login->pPin, login->ulPinLen); + free(login->pPin); + free(login); + } + + return r; +} + +void pop_login_state(struct sc_pkcs11_slot *slot) +{ + if (slot) { + unsigned int size = list_size(&slot->logins); + if (size > 0) { + struct sc_pkcs11_login *login = list_get_at(&slot->logins, size-1); + if (login) { + sc_mem_clear(login->pPin, login->ulPinLen); + free(login->pPin); + free(login); + } + if (0 > list_delete_at(&slot->logins, size-1)) + sc_log(context, "Error deleting login state"); + } + } +} + +void pop_all_login_states(struct sc_pkcs11_slot *slot) +{ + if (sc_pkcs11_conf.atomic && slot) { + struct sc_pkcs11_login *login = list_fetch(&slot->logins); + while (login) { + sc_mem_clear(login->pPin, login->ulPinLen); + free(login->pPin); + free(login); + login = list_fetch(&slot->logins); + } + } +} + + /* Session manipulation */ CK_RV session_start_operation(struct sc_pkcs11_session * session, int type, sc_pkcs11_mechanism_type_t * mech, struct sc_pkcs11_operation ** operation) @@ -323,6 +438,7 @@ void load_pkcs11_parameters(struct sc_pkcs11_config *conf, sc_context_t * ctx) conf->slots_per_card = 4; } conf->hide_empty_tokens = 1; + conf->atomic = 0; conf->lock_login = 0; conf->init_sloppy = 1; conf->pin_unblock_style = SC_PKCS11_PIN_UNBLOCK_NOT_ALLOWED; @@ -339,6 +455,9 @@ void load_pkcs11_parameters(struct sc_pkcs11_config *conf, sc_context_t * ctx) conf->max_virtual_slots = scconf_get_int(conf_block, "max_virtual_slots", conf->max_virtual_slots); conf->slots_per_card = scconf_get_int(conf_block, "slots_per_card", conf->slots_per_card); conf->hide_empty_tokens = scconf_get_bool(conf_block, "hide_empty_tokens", conf->hide_empty_tokens); + conf->atomic = scconf_get_bool(conf_block, "atomic", conf->atomic); + if (conf->atomic) + conf->lock_login = 1; conf->lock_login = scconf_get_bool(conf_block, "lock_login", conf->lock_login); conf->init_sloppy = scconf_get_bool(conf_block, "init_sloppy", conf->init_sloppy); @@ -371,9 +490,9 @@ void load_pkcs11_parameters(struct sc_pkcs11_config *conf, sc_context_t * ctx) free(tmp); sc_log(ctx, "PKCS#11 options: plug_and_play=%d max_virtual_slots=%d slots_per_card=%d " - "hide_empty_tokens=%d lock_login=%d pin_unblock_style=%d " + "hide_empty_tokens=%d lock_login=%d atomic=%d pin_unblock_style=%d " "zero_ckaid_for_ca_certs=%d create_slots_flags=0x%X", conf->plug_and_play, conf->max_virtual_slots, conf->slots_per_card, - conf->hide_empty_tokens, conf->lock_login, conf->pin_unblock_style, + conf->hide_empty_tokens, conf->lock_login, conf->atomic, conf->pin_unblock_style, conf->zero_ckaid_for_ca_certs, conf->create_slots_flags); } diff --git a/src/pkcs11/pkcs11-global.c b/src/pkcs11/pkcs11-global.c index 86922b01..c492392f 100644 --- a/src/pkcs11/pkcs11-global.c +++ b/src/pkcs11/pkcs11-global.c @@ -324,6 +324,8 @@ CK_RV C_Finalize(CK_VOID_PTR pReserved) while ((slot = list_fetch(&virtual_slots))) { list_destroy(&slot->objects); + pop_all_login_states(slot); + list_destroy(&slot->logins); free(slot); } list_destroy(&virtual_slots); diff --git a/src/pkcs11/pkcs11-object.c b/src/pkcs11/pkcs11-object.c index 41bfe5c0..6e8d648b 100644 --- a/src/pkcs11/pkcs11-object.c +++ b/src/pkcs11/pkcs11-object.c @@ -541,7 +541,8 @@ C_Digest(CK_SESSION_HANDLE hSession, /* the session's handle */ if (rv == CKR_OK) rv = sc_pkcs11_md_final(session, pDigest, pulDigestLen); -out: sc_log(context, "C_Digest() = %s", lookup_enum ( RV_T, rv )); +out: + sc_log(context, "C_Digest() = %s", lookup_enum ( RV_T, rv )); sc_pkcs11_unlock(); return rv; } @@ -685,8 +686,12 @@ C_Sign(CK_SESSION_HANDLE hSession, /* the session's handle */ } rv = sc_pkcs11_sign_update(session, pData, ulDataLen); - if (rv == CKR_OK) - rv = sc_pkcs11_sign_final(session, pSignature, pulSignatureLen); + if (rv == CKR_OK) { + rv = restore_login_state(session->slot); + if (rv == CKR_OK) + rv = sc_pkcs11_sign_final(session, pSignature, pulSignatureLen); + rv = reset_login_state(session->slot, rv); + } out: sc_log(context, "C_Sign() = %s", lookup_enum ( RV_T, rv )); @@ -746,7 +751,10 @@ C_SignFinal(CK_SESSION_HANDLE hSession, /* the session's handle */ *pulSignatureLen = length; rv = pSignature ? CKR_BUFFER_TOO_SMALL : CKR_OK; } else { - rv = sc_pkcs11_sign_final(session, pSignature, pulSignatureLen); + rv = restore_login_state(session->slot); + if (rv == CKR_OK) + rv = sc_pkcs11_sign_final(session, pSignature, pulSignatureLen); + rv = reset_login_state(session->slot, rv); } out: @@ -859,7 +867,8 @@ CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession, /* the session's handle */ rv = sc_pkcs11_decr_init(session, pMechanism, object, key_type); -out: sc_log(context, "C_DecryptInit() = %s", lookup_enum ( RV_T, rv )); +out: + sc_log(context, "C_DecryptInit() = %s", lookup_enum ( RV_T, rv )); sc_pkcs11_unlock(); return rv; } @@ -878,9 +887,14 @@ CK_RV C_Decrypt(CK_SESSION_HANDLE hSession, /* the session's handle */ return rv; rv = get_session(hSession, &session); - if (rv == CKR_OK) - rv = sc_pkcs11_decr(session, pEncryptedData, ulEncryptedDataLen, - pData, pulDataLen); + if (rv == CKR_OK) { + rv = restore_login_state(session->slot); + if (rv == CKR_OK) { + rv = sc_pkcs11_decr(session, pEncryptedData, + ulEncryptedDataLen, pData, pulDataLen); + } + rv = reset_login_state(session->slot, rv); + } sc_log(context, "C_Decrypt() = %s", lookup_enum ( RV_T, rv )); sc_pkcs11_unlock(); @@ -985,11 +999,15 @@ CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE hSession, /* the session's handle */ slot = session->slot; if (slot->p11card->framework->gen_keypair == NULL) rv = CKR_FUNCTION_NOT_SUPPORTED; - else - rv = slot->p11card->framework->gen_keypair(slot, pMechanism, - pPublicKeyTemplate, ulPublicKeyAttributeCount, - pPrivateKeyTemplate, ulPrivateKeyAttributeCount, - phPublicKey, phPrivateKey); + else { + rv = restore_login_state(slot); + if (rv == CKR_OK) + rv = slot->p11card->framework->gen_keypair(slot, pMechanism, + pPublicKeyTemplate, ulPublicKeyAttributeCount, + pPrivateKeyTemplate, ulPrivateKeyAttributeCount, + phPublicKey, phPrivateKey); + rv = reset_login_state(session->slot, rv); + } out: sc_pkcs11_unlock(); @@ -1084,9 +1102,12 @@ CK_RV C_DeriveKey(CK_SESSION_HANDLE hSession, /* the session's handle */ goto out; } - rv = sc_pkcs11_deri(session, pMechanism, object, key_type, - hSession, *phKey, key_object); + rv = restore_login_state(session->slot); + if (rv == CKR_OK) + rv = sc_pkcs11_deri(session, pMechanism, object, key_type, + hSession, *phKey, key_object); /* TODO if (rv != CK_OK) need to destroy the object */ + rv = reset_login_state(session->slot, rv); break; default: @@ -1175,7 +1196,8 @@ CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, /* the session's handle */ rv = sc_pkcs11_verif_init(session, pMechanism, object, key_type); -out: sc_log(context, "C_VerifyInit() = %s", lookup_enum ( RV_T, rv )); +out: + sc_log(context, "C_VerifyInit() = %s", lookup_enum ( RV_T, rv )); sc_pkcs11_unlock(); return rv; #endif @@ -1202,10 +1224,15 @@ CK_RV C_Verify(CK_SESSION_HANDLE hSession, /* the session's handle */ goto out; rv = sc_pkcs11_verif_update(session, pData, ulDataLen); - if (rv == CKR_OK) - rv = sc_pkcs11_verif_final(session, pSignature, ulSignatureLen); + if (rv == CKR_OK) { + rv = restore_login_state(session->slot); + if (rv == CKR_OK) + rv = sc_pkcs11_verif_final(session, pSignature, ulSignatureLen); + rv = reset_login_state(session->slot, rv); + } -out: sc_log(context, "C_Verify() = %s", lookup_enum ( RV_T, rv )); +out: + sc_log(context, "C_Verify() = %s", lookup_enum ( RV_T, rv )); sc_pkcs11_unlock(); return rv; #endif @@ -1250,8 +1277,12 @@ CK_RV C_VerifyFinal(CK_SESSION_HANDLE hSession, /* the session's handle */ return rv; rv = get_session(hSession, &session); - if (rv == CKR_OK) - rv = sc_pkcs11_verif_final(session, pSignature, ulSignatureLen); + if (rv == CKR_OK) { + rv = restore_login_state(session->slot); + if (rv == CKR_OK) + rv = sc_pkcs11_verif_final(session, pSignature, ulSignatureLen); + rv = reset_login_state(session->slot, rv); + } sc_log(context, "C_VerifyFinal() = %s", lookup_enum ( RV_T, rv )); sc_pkcs11_unlock(); diff --git a/src/pkcs11/pkcs11-session.c b/src/pkcs11/pkcs11-session.c index c4ab857f..47110a99 100644 --- a/src/pkcs11/pkcs11-session.c +++ b/src/pkcs11/pkcs11-session.c @@ -107,7 +107,10 @@ static CK_RV sc_pkcs11_close_session(CK_SESSION_HANDLE hSession) slot->nsessions--; if (slot->nsessions == 0 && slot->login_user >= 0) { slot->login_user = -1; - slot->p11card->framework->logout(slot); + if (sc_pkcs11_conf.atomic) + pop_all_login_states(slot); + else + slot->p11card->framework->logout(slot); } if (list_delete(&sessions, session) != 0) @@ -166,7 +169,8 @@ CK_RV C_CloseAllSessions(CK_SLOT_ID slotID) rv = sc_pkcs11_close_all_sessions(slotID); - out:sc_pkcs11_unlock(); +out: + sc_pkcs11_unlock(); return rv; } @@ -269,10 +273,12 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession, /* the session's handle */ if (userType == CKU_CONTEXT_SPECIFIC) { if (slot->login_user == -1) { rv = CKR_OPERATION_NOT_INITIALIZED; - goto out; } else { - rv = slot->p11card->framework->login(slot, userType, pPin, ulPinLen); + rv = restore_login_state(slot); + if (rv == CKR_OK) + rv = slot->p11card->framework->login(slot, userType, pPin, ulPinLen); + rv = reset_login_state(slot, rv); } } else { @@ -285,11 +291,18 @@ CK_RV C_Login(CK_SESSION_HANDLE hSession, /* the session's handle */ goto out; } - sc_log(context, "C_Login() userType %li", userType); - rv = slot->p11card->framework->login(slot, userType, pPin, ulPinLen); - sc_log(context, "fLogin() rv %li", rv); + rv = restore_login_state(slot); + if (rv == CKR_OK) { + sc_log(context, "C_Login() userType %li", userType); + rv = slot->p11card->framework->login(slot, userType, pPin, ulPinLen); + sc_log(context, "fLogin() rv %li", rv); + } if (rv == CKR_OK) + rv = push_login_state(slot, userType, pPin, ulPinLen); + if (rv == CKR_OK) { slot->login_user = userType; + } + rv = reset_login_state(slot, rv); } out: @@ -319,11 +332,15 @@ CK_RV C_Logout(CK_SESSION_HANDLE hSession) if (slot->login_user >= 0) { slot->login_user = -1; - rv = slot->p11card->framework->logout(slot); + if (sc_pkcs11_conf.atomic) + pop_all_login_states(slot); + else + rv = slot->p11card->framework->logout(slot); } else rv = CKR_USER_NOT_LOGGED_IN; - out:sc_pkcs11_unlock(); +out: + sc_pkcs11_unlock(); return rv; } @@ -358,8 +375,12 @@ CK_RV C_InitPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) } else if (slot->p11card->framework->init_pin == NULL) { rv = CKR_FUNCTION_NOT_SUPPORTED; } else { - rv = slot->p11card->framework->init_pin(slot, pPin, ulPinLen); - sc_log(context, "C_InitPIN() init-pin result %li", rv); + rv = restore_login_state(slot); + if (rv == CKR_OK) { + rv = slot->p11card->framework->init_pin(slot, pPin, ulPinLen); + sc_log(context, "C_InitPIN() init-pin result %li", rv); + } + rv = reset_login_state(slot, rv); } out: @@ -395,7 +416,11 @@ CK_RV C_SetPIN(CK_SESSION_HANDLE hSession, goto out; } - rv = slot->p11card->framework->change_pin(slot, pOldPin, ulOldLen, pNewPin, ulNewLen); + rv = restore_login_state(slot); + if (rv == CKR_OK) + rv = slot->p11card->framework->change_pin(slot, pOldPin, ulOldLen, pNewPin, ulNewLen); + rv = reset_login_state(slot, rv); + out: sc_pkcs11_unlock(); return rv; diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h index 22e08235..42fad163 100644 --- a/src/pkcs11/sc-pkcs11.h +++ b/src/pkcs11/sc-pkcs11.h @@ -78,6 +78,7 @@ struct sc_pkcs11_config { unsigned int slots_per_card; unsigned char hide_empty_tokens; unsigned char lock_login; + unsigned char atomic; unsigned char init_sloppy; unsigned int pin_unblock_style; unsigned int create_puk_slot; @@ -218,6 +219,7 @@ struct sc_pkcs11_slot { int fw_data_idx; /* Index of framework data */ struct sc_app_info *app_info; /* Application assosiated to slot */ + list_t logins; /* tracks all calls to C_Login if atomic operations are requested */ }; typedef struct sc_pkcs11_slot sc_pkcs11_slot_t; @@ -348,6 +350,14 @@ CK_RV slot_token_removed(CK_SLOT_ID id); CK_RV slot_allocate(struct sc_pkcs11_slot **, struct sc_pkcs11_card *); CK_RV slot_find_changed(CK_SLOT_ID_PTR idp, int mask); +/* Login tracking functions */ +CK_RV restore_login_state(struct sc_pkcs11_slot *slot); +CK_RV reset_login_state(struct sc_pkcs11_slot *slot, CK_RV rv); +CK_RV push_login_state(struct sc_pkcs11_slot *slot, + CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG ulPinLen); +void pop_login_state(struct sc_pkcs11_slot *slot); +void pop_all_login_states(struct sc_pkcs11_slot *slot); + /* Session manipulation */ CK_RV get_session(CK_SESSION_HANDLE hSession, struct sc_pkcs11_session ** session); CK_RV session_start_operation(struct sc_pkcs11_session *, diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c index 857252c3..6806da13 100644 --- a/src/pkcs11/slot.c +++ b/src/pkcs11/slot.c @@ -92,6 +92,8 @@ CK_RV create_slot(sc_reader_t *reader) list_init(&slot->objects); list_attributes_seeker(&slot->objects, object_list_seeker); + list_init(&slot->logins); + init_slot_info(&slot->slot_info); if (reader != NULL) { slot->reader = reader;