105 lines
4.4 KiB
C
105 lines
4.4 KiB
C
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
|
|
#include "hexdecoct.h"
|
|
#include "homework-pkcs11.h"
|
|
#include "pkcs11-util.h"
|
|
#include "strv.h"
|
|
|
|
int pkcs11_callback(
|
|
CK_FUNCTION_LIST *m,
|
|
CK_SESSION_HANDLE session,
|
|
CK_SLOT_ID slot_id,
|
|
const CK_SLOT_INFO *slot_info,
|
|
const CK_TOKEN_INFO *token_info,
|
|
P11KitUri *uri,
|
|
void *userdata) {
|
|
|
|
_cleanup_(erase_and_freep) void *decrypted_key = NULL;
|
|
struct pkcs11_callback_data *data = userdata;
|
|
_cleanup_free_ char *token_label = NULL;
|
|
CK_TOKEN_INFO updated_token_info;
|
|
size_t decrypted_key_size;
|
|
CK_OBJECT_HANDLE object;
|
|
char **i;
|
|
CK_RV rv;
|
|
int r;
|
|
|
|
assert(m);
|
|
assert(slot_info);
|
|
assert(token_info);
|
|
assert(uri);
|
|
assert(data);
|
|
|
|
/* Special return values:
|
|
*
|
|
* -ENOANO → if we need a PIN but have none
|
|
* -ERFKILL → if a "protected authentication path" is needed but we have no OK to use it
|
|
* -EOWNERDEAD → if the PIN is locked
|
|
* -ENOLCK → if the supplied PIN is incorrect
|
|
* -ETOOMANYREFS → ditto, but only a few tries left
|
|
* -EUCLEAN → ditto, but only a single try left
|
|
*/
|
|
|
|
token_label = pkcs11_token_label(token_info);
|
|
if (!token_label)
|
|
return log_oom();
|
|
|
|
if (FLAGS_SET(token_info->flags, CKF_PROTECTED_AUTHENTICATION_PATH)) {
|
|
|
|
if (data->secret->pkcs11_protected_authentication_path_permitted <= 0)
|
|
return log_error_errno(SYNTHETIC_ERRNO(ERFKILL), "Security token requires authentication through protected authentication path.");
|
|
|
|
rv = m->C_Login(session, CKU_USER, NULL, 0);
|
|
if (rv != CKR_OK)
|
|
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to log into security token '%s': %s", token_label, p11_kit_strerror(rv));
|
|
|
|
log_info("Successfully logged into security token '%s' via protected authentication path.", token_label);
|
|
goto decrypt;
|
|
}
|
|
|
|
if (!FLAGS_SET(token_info->flags, CKF_LOGIN_REQUIRED)) {
|
|
log_info("No login into security token '%s' required.", token_label);
|
|
goto decrypt;
|
|
}
|
|
|
|
if (strv_isempty(data->secret->pkcs11_pin))
|
|
return log_error_errno(SYNTHETIC_ERRNO(ENOANO), "Security Token requires PIN.");
|
|
|
|
STRV_FOREACH(i, data->secret->pkcs11_pin) {
|
|
rv = m->C_Login(session, CKU_USER, (CK_UTF8CHAR*) *i, strlen(*i));
|
|
if (rv == CKR_OK) {
|
|
log_info("Successfully logged into security token '%s' with PIN.", token_label);
|
|
goto decrypt;
|
|
}
|
|
if (rv == CKR_PIN_LOCKED)
|
|
return log_error_errno(SYNTHETIC_ERRNO(EOWNERDEAD), "PIN of security token is blocked. Please unblock it first.");
|
|
if (!IN_SET(rv, CKR_PIN_INCORRECT, CKR_PIN_LEN_RANGE))
|
|
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to log into security token '%s': %s", token_label, p11_kit_strerror(rv));
|
|
}
|
|
|
|
rv = m->C_GetTokenInfo(slot_id, &updated_token_info);
|
|
if (rv != CKR_OK)
|
|
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to acquire updated security token information for slot %lu: %s", slot_id, p11_kit_strerror(rv));
|
|
|
|
if (FLAGS_SET(updated_token_info.flags, CKF_USER_PIN_FINAL_TRY))
|
|
return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN), "PIN of security token incorrect, only a single try left.");
|
|
if (FLAGS_SET(updated_token_info.flags, CKF_USER_PIN_COUNT_LOW))
|
|
return log_error_errno(SYNTHETIC_ERRNO(ETOOMANYREFS), "PIN of security token incorrect, only a few tries left.");
|
|
|
|
return log_error_errno(SYNTHETIC_ERRNO(ENOLCK), "PIN of security token incorrect.");
|
|
|
|
decrypt:
|
|
r = pkcs11_token_find_private_key(m, session, uri, &object);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
r = pkcs11_token_decrypt_data(m, session, object, data->encrypted_key->data, data->encrypted_key->size, &decrypted_key, &decrypted_key_size);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
if (base64mem(decrypted_key, decrypted_key_size, &data->decrypted_password) < 0)
|
|
return log_oom();
|
|
|
|
return 1;
|
|
}
|