#include <fcntl.h>
#include "ask-password-api.h"
+#include "env-util.h"
#include "escape.h"
#include "fd-util.h"
#include "format-table.h"
return t;
}
+int pkcs11_token_login_by_pin(
+ CK_FUNCTION_LIST *m,
+ CK_SESSION_HANDLE session,
+ const CK_TOKEN_INFO *token_info,
+ const char *token_label,
+ const void *pin,
+ size_t pin_size) {
+
+ CK_RV rv;
+
+ assert(m);
+ assert(token_info);
+
+ if (FLAGS_SET(token_info->flags, CKF_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);
+ return 0;
+ }
+
+ if (!FLAGS_SET(token_info->flags, CKF_LOGIN_REQUIRED)) {
+ log_info("No login into security token '%s' required.", token_label);
+ return 0;
+ }
+
+ if (!pin)
+ return -ENOANO;
+
+ rv = m->C_Login(session, CKU_USER, (CK_UTF8CHAR*) pin, pin_size);
+ if (rv == CKR_OK) {
+ log_info("Successfully logged into security token '%s'.", token_label);
+ return 0;
+ }
+
+ if (rv == CKR_PIN_LOCKED)
+ return log_error_errno(SYNTHETIC_ERRNO(EPERM),
+ "PIN has been locked, please reset PIN of security token '%s'.", token_label);
+ 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));
+
+ return log_notice_errno(SYNTHETIC_ERRNO(ENOLCK),
+ "PIN for token '%s' is incorrect, please try again.",
+ token_label);
+}
+
int pkcs11_token_login(
CK_FUNCTION_LIST *m,
CK_SESSION_HANDLE session,
const char *key_name,
const char *credential_name,
usec_t until,
+ bool headless,
char **ret_used_pin) {
_cleanup_free_ char *token_uri_string = NULL, *token_uri_escaped = NULL, *id = NULL, *token_label = NULL;
if (uri_result != P11_KIT_URI_OK)
return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result));
- if (FLAGS_SET(token_info->flags, CKF_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);
- if (ret_used_pin)
- *ret_used_pin = NULL;
- return 0;
- }
+ r = pkcs11_token_login_by_pin(m, session, token_info, token_label, /* pin= */ NULL, 0);
+ if (r == 0 && ret_used_pin)
+ *ret_used_pin = NULL;
- if (!FLAGS_SET(token_info->flags, CKF_LOGIN_REQUIRED)) {
- log_info("No login into security token '%s' required.", token_label);
- if (ret_used_pin)
- *ret_used_pin = NULL;
- return 0;
- }
+ if (r != -ENOANO) /* pin required */
+ return r;
token_uri_escaped = cescape(token_uri_string);
if (!token_uri_escaped)
for (unsigned tries = 0; tries < 3; tries++) {
_cleanup_strv_free_erase_ char **passwords = NULL;
- char **i, *e;
+ _cleanup_(erase_and_freep) char *envpin = NULL;
- e = getenv("PIN");
- if (e) {
- passwords = strv_new(e);
+ r = getenv_steal_erase("PIN", &envpin);
+ if (r < 0)
+ return log_error_errno(r, "Failed to acquire PIN from environment: %m");
+ if (r > 0) {
+ passwords = strv_new(envpin);
if (!passwords)
return log_oom();
- string_erase(e);
- if (unsetenv("PIN") < 0)
- return log_error_errno(errno, "Failed to unset $PIN: %m");
- } else {
+ } else if (headless)
+ return log_error_errno(SYNTHETIC_ERRNO(ENOPKG), "PIN querying disabled via 'headless' option. Use the 'PIN' environment variable.");
+ else {
_cleanup_free_ char *text = NULL;
if (FLAGS_SET(token_info->flags, CKF_USER_PIN_FINAL_TRY))
}
STRV_FOREACH(i, passwords) {
- rv = m->C_Login(session, CKU_USER, (CK_UTF8CHAR*) *i, strlen(*i));
- if (rv == CKR_OK) {
-
- if (ret_used_pin) {
- char *c;
+ r = pkcs11_token_login_by_pin(m, session, token_info, token_label, *i, strlen(*i));
+ if (r == 0 && ret_used_pin) {
+ char *c;
- c = strdup(*i);
- if (!c)
- return log_oom();
+ c = strdup(*i);
+ if (!c)
+ return log_oom();
- *ret_used_pin = c;
- }
-
- log_info("Successfully logged into security token '%s'.", token_label);
- return 0;
+ *ret_used_pin = c;
}
- if (rv == CKR_PIN_LOCKED)
- return log_error_errno(SYNTHETIC_ERRNO(EPERM),
- "PIN has been locked, please reset PIN of security token '%s'.", token_label);
- 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));
+
+ if (r != -ENOLCK)
+ return r;
/* Referesh the token info, so that we can prompt knowing the new flags if they changed. */
rv = m->C_GetTokenInfo(slotid, &updated_token_info);
slotid, p11_kit_strerror(rv));
token_info = &updated_token_info;
- log_notice("PIN for token '%s' is incorrect, please try again.", token_label);
}
}
void *userdata) {
_cleanup_(erase_and_freep) char *pin_used = NULL;
- struct pkcs11_acquire_certificate_callback_data *data = userdata;
+ struct pkcs11_acquire_certificate_callback_data *data = ASSERT_PTR(userdata);
CK_OBJECT_HANDLE object;
int r;
assert(slot_info);
assert(token_info);
assert(uri);
- assert(data);
/* Called for every token matching our URI */
- r = pkcs11_token_login(m, session, slot_id, token_info, data->askpw_friendly_name, data->askpw_icon_name, "pkcs11-pin", "pkcs11-pin", UINT64_MAX, &pin_used);
+ r = pkcs11_token_login(m, session, slot_id, token_info, data->askpw_friendly_name, data->askpw_icon_name, "pkcs11-pin", "pkcs11-pin", UINT64_MAX, false, &pin_used);
if (r < 0)
return r;
"PKCS#11 tokens not supported on this build.");
#endif
}
+
+#if HAVE_P11KIT
+void pkcs11_crypt_device_callback_data_release(pkcs11_crypt_device_callback_data *data) {
+ erase_and_free(data->decrypted_key);
+
+ if (data->free_encrypted_key)
+ free(data->encrypted_key);
+}
+
+int pkcs11_crypt_device_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) {
+
+ pkcs11_crypt_device_callback_data *data = ASSERT_PTR(userdata);
+ CK_OBJECT_HANDLE object;
+ int r;
+
+ assert(m);
+ assert(slot_info);
+ assert(token_info);
+ assert(uri);
+
+ /* Called for every token matching our URI */
+
+ r = pkcs11_token_login(
+ m,
+ session,
+ slot_id,
+ token_info,
+ data->friendly_name,
+ "drive-harddisk",
+ "pkcs11-pin",
+ "cryptsetup.pkcs11-pin",
+ data->until,
+ data->headless,
+ NULL);
+ if (r < 0)
+ return r;
+
+ /* We are likely called during early boot, where entropy is scarce. Mix some data from the PKCS#11
+ * token, if it supports that. It should be cheap, given that we already are talking to it anyway and
+ * shouldn't hurt. */
+ (void) pkcs11_token_acquire_rng(m, session);
+
+ 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->encrypted_key_size,
+ &data->decrypted_key,
+ &data->decrypted_key_size);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+#endif