1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include "ask-password-api.h"
6 #include "dlfcn-util.h"
10 #include "format-table.h"
12 #include "memory-util.h"
14 #include "openssl-util.h"
16 #include "pkcs11-util.h"
17 #include "random-util.h"
18 #include "string-util.h"
21 bool pkcs11_uri_valid(const char *uri
) {
24 /* A very superficial checker for RFC7512 PKCS#11 URI syntax */
29 p
= startswith(uri
, "pkcs11:");
36 if (!in_charset(p
, ALPHANUMERICAL
".~/-_?;&%="))
44 static void *p11kit_dl
= NULL
;
46 char *(*sym_p11_kit_module_get_name
)(CK_FUNCTION_LIST
*module
);
47 void (*sym_p11_kit_modules_finalize_and_release
)(CK_FUNCTION_LIST
**modules
);
48 CK_FUNCTION_LIST
**(*sym_p11_kit_modules_load_and_initialize
)(int flags
);
49 const char *(*sym_p11_kit_strerror
)(CK_RV rv
);
50 int (*sym_p11_kit_uri_format
)(P11KitUri
*uri
, P11KitUriType uri_type
, char **string
);
51 void (*sym_p11_kit_uri_free
)(P11KitUri
*uri
);
52 CK_ATTRIBUTE_PTR (*sym_p11_kit_uri_get_attributes
)(P11KitUri
*uri
, CK_ULONG
*n_attrs
);
53 CK_ATTRIBUTE_PTR (*sym_p11_kit_uri_get_attribute
)(P11KitUri
*uri
, CK_ATTRIBUTE_TYPE attr_type
);
54 int (*sym_p11_kit_uri_set_attribute
)(P11KitUri
*uri
, CK_ATTRIBUTE_PTR attr
);
55 CK_INFO_PTR (*sym_p11_kit_uri_get_module_info
)(P11KitUri
*uri
);
56 CK_SLOT_INFO_PTR (*sym_p11_kit_uri_get_slot_info
)(P11KitUri
*uri
);
57 CK_TOKEN_INFO_PTR (*sym_p11_kit_uri_get_token_info
)(P11KitUri
*uri
);
58 int (*sym_p11_kit_uri_match_token_info
)(const P11KitUri
*uri
, const CK_TOKEN_INFO
*token_info
);
59 const char *(*sym_p11_kit_uri_message
)(int code
);
60 P11KitUri
*(*sym_p11_kit_uri_new
)(void);
61 int (*sym_p11_kit_uri_parse
)(const char *string
, P11KitUriType uri_type
, P11KitUri
*uri
);
63 int dlopen_p11kit(void) {
64 return dlopen_many_sym_or_warn(
66 "libp11-kit.so.0", LOG_DEBUG
,
67 DLSYM_ARG(p11_kit_module_get_name
),
68 DLSYM_ARG(p11_kit_modules_finalize_and_release
),
69 DLSYM_ARG(p11_kit_modules_load_and_initialize
),
70 DLSYM_ARG(p11_kit_strerror
),
71 DLSYM_ARG(p11_kit_uri_format
),
72 DLSYM_ARG(p11_kit_uri_free
),
73 DLSYM_ARG(p11_kit_uri_get_attributes
),
74 DLSYM_ARG(p11_kit_uri_get_attribute
),
75 DLSYM_ARG(p11_kit_uri_set_attribute
),
76 DLSYM_ARG(p11_kit_uri_get_module_info
),
77 DLSYM_ARG(p11_kit_uri_get_slot_info
),
78 DLSYM_ARG(p11_kit_uri_get_token_info
),
79 DLSYM_ARG(p11_kit_uri_match_token_info
),
80 DLSYM_ARG(p11_kit_uri_message
),
81 DLSYM_ARG(p11_kit_uri_new
),
82 DLSYM_ARG(p11_kit_uri_parse
));
85 int uri_from_string(const char *p
, P11KitUri
**ret
) {
86 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*uri
= NULL
;
96 uri
= sym_p11_kit_uri_new();
100 if (sym_p11_kit_uri_parse(p
, P11_KIT_URI_FOR_ANY
, uri
) != P11_KIT_URI_OK
)
103 *ret
= TAKE_PTR(uri
);
107 P11KitUri
*uri_from_module_info(const CK_INFO
*info
) {
112 if (dlopen_p11kit() < 0)
115 uri
= sym_p11_kit_uri_new();
119 *sym_p11_kit_uri_get_module_info(uri
) = *info
;
123 P11KitUri
*uri_from_slot_info(const CK_SLOT_INFO
*slot_info
) {
128 if (dlopen_p11kit() < 0)
131 uri
= sym_p11_kit_uri_new();
135 *sym_p11_kit_uri_get_slot_info(uri
) = *slot_info
;
139 P11KitUri
*uri_from_token_info(const CK_TOKEN_INFO
*token_info
) {
144 if (dlopen_p11kit() < 0)
147 uri
= sym_p11_kit_uri_new();
151 *sym_p11_kit_uri_get_token_info(uri
) = *token_info
;
155 CK_RV
pkcs11_get_slot_list_malloc(
157 CK_SLOT_ID
**ret_slotids
,
158 CK_ULONG
*ret_n_slotids
) {
164 assert(ret_n_slotids
);
166 for (unsigned tries
= 0; tries
< 16; tries
++) {
167 _cleanup_free_ CK_SLOT_ID
*slotids
= NULL
;
168 CK_ULONG n_slotids
= 0;
170 rv
= m
->C_GetSlotList(0, NULL
, &n_slotids
);
173 if (n_slotids
== 0) {
179 slotids
= new(CK_SLOT_ID
, n_slotids
);
181 return CKR_HOST_MEMORY
;
183 rv
= m
->C_GetSlotList(0, slotids
, &n_slotids
);
185 *ret_slotids
= TAKE_PTR(slotids
);
186 *ret_n_slotids
= n_slotids
;
190 if (rv
!= CKR_BUFFER_TOO_SMALL
)
193 /* Hu? Maybe somebody plugged something in and things changed? Let's try again */
196 return CKR_BUFFER_TOO_SMALL
;
199 char *pkcs11_token_label(const CK_TOKEN_INFO
*token_info
) {
202 /* The label is not NUL terminated and likely padded with spaces, let's make a copy here, so that we
204 t
= strndup((char*) token_info
->label
, sizeof(token_info
->label
));
212 char *pkcs11_token_manufacturer_id(const CK_TOKEN_INFO
*token_info
) {
215 t
= strndup((char*) token_info
->manufacturerID
, sizeof(token_info
->manufacturerID
));
223 char *pkcs11_token_model(const CK_TOKEN_INFO
*token_info
) {
226 t
= strndup((char*) token_info
->model
, sizeof(token_info
->model
));
234 int pkcs11_token_login_by_pin(
236 CK_SESSION_HANDLE session
,
237 const CK_TOKEN_INFO
*token_info
,
238 const char *token_label
,
252 if (FLAGS_SET(token_info
->flags
, CKF_PROTECTED_AUTHENTICATION_PATH
)) {
253 rv
= m
->C_Login(session
, CKU_USER
, NULL
, 0);
255 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
256 "Failed to log into security token '%s': %s", token_label
, sym_p11_kit_strerror(rv
));
258 log_info("Successfully logged into security token '%s' via protected authentication path.", token_label
);
262 if (!FLAGS_SET(token_info
->flags
, CKF_LOGIN_REQUIRED
)) {
263 log_info("No login into security token '%s' required.", token_label
);
270 rv
= m
->C_Login(session
, CKU_USER
, (CK_UTF8CHAR
*) pin
, pin_size
);
272 log_info("Successfully logged into security token '%s'.", token_label
);
276 if (rv
== CKR_PIN_LOCKED
)
277 return log_error_errno(SYNTHETIC_ERRNO(EPERM
),
278 "PIN has been locked, please reset PIN of security token '%s'.", token_label
);
279 if (!IN_SET(rv
, CKR_PIN_INCORRECT
, CKR_PIN_LEN_RANGE
))
280 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
281 "Failed to log into security token '%s': %s", token_label
, sym_p11_kit_strerror(rv
));
283 return log_notice_errno(SYNTHETIC_ERRNO(ENOLCK
),
284 "PIN for token '%s' is incorrect, please try again.",
288 int pkcs11_token_login(
290 CK_SESSION_HANDLE session
,
292 const CK_TOKEN_INFO
*token_info
,
293 const char *friendly_name
,
294 const char *icon_name
,
295 const char *key_name
,
296 const char *credential_name
,
298 AskPasswordFlags ask_password_flags
,
300 char **ret_used_pin
) {
302 _cleanup_free_
char *token_uri_string
= NULL
, *token_uri_escaped
= NULL
, *id
= NULL
, *token_label
= NULL
;
303 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*token_uri
= NULL
;
304 CK_TOKEN_INFO updated_token_info
;
315 token_label
= pkcs11_token_label(token_info
);
319 token_uri
= uri_from_token_info(token_info
);
323 uri_result
= sym_p11_kit_uri_format(token_uri
, P11_KIT_URI_FOR_ANY
, &token_uri_string
);
324 if (uri_result
!= P11_KIT_URI_OK
)
325 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN
), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result
));
327 r
= pkcs11_token_login_by_pin(m
, session
, token_info
, token_label
, /* pin= */ NULL
, 0);
328 if (r
== 0 && ret_used_pin
)
329 *ret_used_pin
= NULL
;
331 if (r
!= -ENOANO
) /* pin required */
334 token_uri_escaped
= cescape(token_uri_string
);
335 if (!token_uri_escaped
)
338 id
= strjoin("pkcs11:", token_uri_escaped
);
342 for (unsigned tries
= 0; tries
< 3; tries
++) {
343 _cleanup_strv_free_erase_
char **passwords
= NULL
;
344 _cleanup_(erase_and_freep
) char *envpin
= NULL
;
346 r
= getenv_steal_erase("PIN", &envpin
);
348 return log_error_errno(r
, "Failed to acquire PIN from environment: %m");
350 passwords
= strv_new(envpin
);
355 return log_error_errno(SYNTHETIC_ERRNO(ENOPKG
), "PIN querying disabled via 'headless' option. Use the 'PIN' environment variable.");
357 _cleanup_free_
char *text
= NULL
;
359 if (FLAGS_SET(token_info
->flags
, CKF_USER_PIN_FINAL_TRY
))
361 "Please enter correct PIN for security token '%s' in order to unlock %s (final try):",
362 token_label
, friendly_name
);
363 else if (FLAGS_SET(token_info
->flags
, CKF_USER_PIN_COUNT_LOW
))
365 "PIN has been entered incorrectly previously, please enter correct PIN for security token '%s' in order to unlock %s:",
366 token_label
, friendly_name
);
369 "Please enter PIN for security token '%s' in order to unlock %s:",
370 token_label
, friendly_name
);
373 "Please enter PIN for security token '%s' in order to unlock %s (try #%u):",
374 token_label
, friendly_name
, tries
+1);
378 /* We never cache PINs, simply because it's fatal if we use wrong PINs, since usually there are only 3 tries */
379 r
= ask_password_auto(text
, icon_name
, id
, key_name
, credential_name
, until
, ask_password_flags
, &passwords
);
381 return log_error_errno(r
, "Failed to query PIN for security token '%s': %m", token_label
);
384 STRV_FOREACH(i
, passwords
) {
385 r
= pkcs11_token_login_by_pin(m
, session
, token_info
, token_label
, *i
, strlen(*i
));
386 if (r
== 0 && ret_used_pin
) {
399 /* Refresh the token info, so that we can prompt knowing the new flags if they changed. */
400 rv
= m
->C_GetTokenInfo(slotid
, &updated_token_info
);
402 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
403 "Failed to acquire updated security token information for slot %lu: %s",
404 slotid
, sym_p11_kit_strerror(rv
));
406 token_info
= &updated_token_info
;
410 return log_error_errno(SYNTHETIC_ERRNO(EPERM
), "Too many attempts to log into token '%s'.", token_label
);
413 int pkcs11_token_find_x509_certificate(
415 CK_SESSION_HANDLE session
,
416 P11KitUri
*search_uri
,
417 CK_OBJECT_HANDLE
*ret_object
) {
419 bool found_class
= false, found_certificate_type
= false;
420 _cleanup_free_ CK_ATTRIBUTE
*attributes_buffer
= NULL
;
421 CK_ULONG n_attributes
, a
, n_objects
;
422 CK_ATTRIBUTE
*attributes
= NULL
;
423 CK_OBJECT_HANDLE objects
[2];
435 attributes
= sym_p11_kit_uri_get_attributes(search_uri
, &n_attributes
);
436 for (a
= 0; a
< n_attributes
; a
++) {
438 /* We use the URI's included match attributes, but make them more strict. This allows users
439 * to specify a token URL instead of an object URL and the right thing should happen if
440 * there's only one suitable key on the token. */
442 switch (attributes
[a
].type
) {
447 if (attributes
[a
].ulValueLen
!= sizeof(c
))
448 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid PKCS#11 CKA_CLASS attribute size.");
450 memcpy(&c
, attributes
[a
].pValue
, sizeof(c
));
451 if (c
!= CKO_CERTIFICATE
)
452 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Selected PKCS#11 object is not an X.509 certificate, refusing.");
458 case CKA_CERTIFICATE_TYPE
: {
459 CK_CERTIFICATE_TYPE t
;
461 if (attributes
[a
].ulValueLen
!= sizeof(t
))
462 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid PKCS#11 CKA_CERTIFICATE_TYPE attribute size.");
464 memcpy(&t
, attributes
[a
].pValue
, sizeof(t
));
466 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Selected PKCS#11 object is not an X.509 certificate, refusing.");
468 found_certificate_type
= true;
473 if (!found_class
|| !found_certificate_type
) {
474 /* Hmm, let's slightly extend the attribute list we search for */
476 attributes_buffer
= new(CK_ATTRIBUTE
, n_attributes
+ !found_class
+ !found_certificate_type
);
477 if (!attributes_buffer
)
480 memcpy(attributes_buffer
, attributes
, sizeof(CK_ATTRIBUTE
) * n_attributes
);
483 static const CK_OBJECT_CLASS
class = CKO_CERTIFICATE
;
485 attributes_buffer
[n_attributes
++] = (CK_ATTRIBUTE
) {
487 .pValue
= (CK_OBJECT_CLASS
*) &class,
488 .ulValueLen
= sizeof(class),
492 if (!found_certificate_type
) {
493 static const CK_CERTIFICATE_TYPE type
= CKC_X_509
;
495 attributes_buffer
[n_attributes
++] = (CK_ATTRIBUTE
) {
496 .type
= CKA_CERTIFICATE_TYPE
,
497 .pValue
= (CK_CERTIFICATE_TYPE
*) &type
,
498 .ulValueLen
= sizeof(type
),
502 attributes
= attributes_buffer
;
505 rv
= m
->C_FindObjectsInit(session
, attributes
, n_attributes
);
507 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
508 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv
));
510 rv
= m
->C_FindObjects(session
, objects
, ELEMENTSOF(objects
), &n_objects
);
511 rv2
= m
->C_FindObjectsFinal(session
);
513 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
514 "Failed to find objects: %s", sym_p11_kit_strerror(rv
));
516 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
517 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv
));
519 return log_error_errno(SYNTHETIC_ERRNO(ENOENT
),
520 "Failed to find selected X509 certificate on token.");
522 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
523 "Configured URI matches multiple certificates, refusing.");
525 *ret_object
= objects
[0];
530 static int read_public_key_info(
532 CK_SESSION_HANDLE session
,
533 CK_OBJECT_HANDLE object
,
534 EVP_PKEY
**ret_pkey
) {
536 CK_ATTRIBUTE attribute
= { CKA_PUBLIC_KEY_INFO
, NULL_PTR
, 0 };
537 _cleanup_(EVP_PKEY_freep
) EVP_PKEY
*pkey
= NULL
;
540 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
542 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
543 "Failed to get size of CKA_PUBLIC_KEY_INFO: %s", sym_p11_kit_strerror(rv
));
545 if (attribute
.ulValueLen
== 0)
546 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
), "CKA_PUBLIC_KEY_INFO is empty");
548 _cleanup_free_
void *buffer
= malloc(attribute
.ulValueLen
);
550 return log_oom_debug();
552 attribute
.pValue
= buffer
;
554 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
556 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
557 "Failed to read CKA_PUBLIC_KEY_INFO: %s", sym_p11_kit_strerror(rv
));
559 const unsigned char *value
= attribute
.pValue
;
560 pkey
= d2i_PUBKEY(NULL
, &value
, attribute
.ulValueLen
);
562 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG
), "Failed to parse CKA_PUBLIC_KEY_INFO");
564 *ret_pkey
= TAKE_PTR(pkey
);
568 int pkcs11_token_read_public_key(
570 CK_SESSION_HANDLE session
,
571 CK_OBJECT_HANDLE object
,
572 EVP_PKEY
**ret_pkey
) {
574 _cleanup_(EVP_PKEY_freep
) EVP_PKEY
*pkey
= NULL
;
578 r
= read_public_key_info(m
, session
, object
, &pkey
);
580 *ret_pkey
= TAKE_PTR(pkey
);
584 CK_KEY_TYPE key_type
;
585 CK_ATTRIBUTE attribute
= { CKA_KEY_TYPE
, &key_type
, sizeof(key_type
) };
587 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
589 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
590 "Failed to get CKA_KEY_TYPE of a public key: %s", sym_p11_kit_strerror(rv
));
594 CK_ATTRIBUTE rsa_attributes
[] = {
595 { CKA_MODULUS
, NULL_PTR
, 0 },
596 { CKA_PUBLIC_EXPONENT
, NULL_PTR
, 0 },
599 rv
= m
->C_GetAttributeValue(session
, object
, rsa_attributes
, ELEMENTSOF(rsa_attributes
));
601 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
602 "Failed to get size of attributes of an RSA public key: %s", sym_p11_kit_strerror(rv
));
604 if (rsa_attributes
[0].ulValueLen
== 0)
605 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "An RSA public key has empty CKA_MODULUS.");
607 _cleanup_free_
void *modulus
= malloc(rsa_attributes
[0].ulValueLen
);
609 return log_oom_debug();
611 rsa_attributes
[0].pValue
= modulus
;
613 if (rsa_attributes
[1].ulValueLen
== 0)
614 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "An RSA public key has empty CKA_PUBLIC_EXPONENT.");
616 _cleanup_free_
void *public_exponent
= malloc(rsa_attributes
[1].ulValueLen
);
617 if (!public_exponent
)
618 return log_oom_debug();
620 rsa_attributes
[1].pValue
= public_exponent
;
622 rv
= m
->C_GetAttributeValue(session
, object
, rsa_attributes
, ELEMENTSOF(rsa_attributes
));
624 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
625 "Failed to get attributes of an RSA public key: %s", sym_p11_kit_strerror(rv
));
627 size_t n_size
= rsa_attributes
[0].ulValueLen
, e_size
= rsa_attributes
[1].ulValueLen
;
628 r
= rsa_pkey_from_n_e(rsa_attributes
[0].pValue
, n_size
, rsa_attributes
[1].pValue
, e_size
, &pkey
);
630 return log_debug_errno(r
, "Failed to create an EVP_PKEY from RSA parameters.");
635 CK_ATTRIBUTE ec_attributes
[] = {
636 { CKA_EC_PARAMS
, NULL_PTR
, 0 },
637 { CKA_EC_POINT
, NULL_PTR
, 0 },
640 rv
= m
->C_GetAttributeValue(session
, object
, ec_attributes
, ELEMENTSOF(ec_attributes
));
642 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
643 "Failed to get size of attributes of an EC public key: %s", sym_p11_kit_strerror(rv
));
645 if (ec_attributes
[0].ulValueLen
== 0)
646 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "An EC public key has empty CKA_EC_PARAMS.");
648 _cleanup_free_
void *ec_group
= malloc(ec_attributes
[0].ulValueLen
);
650 return log_oom_debug();
652 ec_attributes
[0].pValue
= ec_group
;
654 if (ec_attributes
[1].ulValueLen
== 0)
655 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "An EC public key has empty CKA_EC_POINT.");
657 _cleanup_free_
void *ec_point
= malloc(ec_attributes
[1].ulValueLen
);
659 return log_oom_debug();
661 ec_attributes
[1].pValue
= ec_point
;
663 rv
= m
->C_GetAttributeValue(session
, object
, ec_attributes
, ELEMENTSOF(ec_attributes
));
665 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
666 "Failed to get attributes of an EC public key: %s", sym_p11_kit_strerror(rv
));
668 _cleanup_(EC_GROUP_freep
) EC_GROUP
*group
= NULL
;
669 _cleanup_(ASN1_OCTET_STRING_freep
) ASN1_OCTET_STRING
*os
= NULL
;
671 const unsigned char *ec_params_value
= ec_attributes
[0].pValue
;
672 group
= d2i_ECPKParameters(NULL
, &ec_params_value
, ec_attributes
[0].ulValueLen
);
674 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode CKA_EC_PARAMS.");
676 const unsigned char *ec_point_value
= ec_attributes
[1].pValue
;
677 os
= d2i_ASN1_OCTET_STRING(NULL
, &ec_point_value
, ec_attributes
[1].ulValueLen
);
679 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode CKA_EC_POINT.");
681 #if OPENSSL_VERSION_MAJOR >= 3
682 _cleanup_(EVP_PKEY_CTX_freep
) EVP_PKEY_CTX
*ctx
= EVP_PKEY_CTX_new_from_name(NULL
, "EC", NULL
);
684 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to create an EVP_PKEY_CTX for EC.");
686 if (EVP_PKEY_fromdata_init(ctx
) != 1)
687 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to init an EVP_PKEY_CTX for EC.");
689 OSSL_PARAM ec_params
[8] = {
690 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY
, os
->data
, os
->length
)
693 _cleanup_free_
void *order
= NULL
, *p
= NULL
, *a
= NULL
, *b
= NULL
, *generator
= NULL
;
694 size_t order_size
, p_size
, a_size
, b_size
, generator_size
;
696 int nid
= EC_GROUP_get_curve_name(group
);
697 if (nid
!= NID_undef
) {
698 const char* name
= OSSL_EC_curve_nid2name(nid
);
699 ec_params
[1] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME
, (char*)name
, strlen(name
));
700 ec_params
[2] = OSSL_PARAM_construct_end();
702 const char *field_type
= EC_GROUP_get_field_type(group
) == NID_X9_62_prime_field
?
703 "prime-field" : "characteristic-two-field";
705 const BIGNUM
*bn_order
= EC_GROUP_get0_order(group
);
707 _cleanup_(BN_CTX_freep
) BN_CTX
*bnctx
= BN_CTX_new();
709 return log_oom_debug();
711 _cleanup_(BN_freep
) BIGNUM
*bn_p
= BN_new();
713 return log_oom_debug();
715 _cleanup_(BN_freep
) BIGNUM
*bn_a
= BN_new();
717 return log_oom_debug();
719 _cleanup_(BN_freep
) BIGNUM
*bn_b
= BN_new();
721 return log_oom_debug();
723 if (EC_GROUP_get_curve(group
, bn_p
, bn_a
, bn_b
, bnctx
) != 1)
724 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to extract EC parameters from EC_GROUP.");
726 order_size
= BN_num_bytes(bn_order
);
727 p_size
= BN_num_bytes(bn_p
);
728 a_size
= BN_num_bytes(bn_a
);
729 b_size
= BN_num_bytes(bn_b
);
731 order
= malloc(order_size
);
733 return log_oom_debug();
737 return log_oom_debug();
741 return log_oom_debug();
745 return log_oom_debug();
747 if (BN_bn2nativepad(bn_order
, order
, order_size
) <= 0 ||
748 BN_bn2nativepad(bn_p
, p
, p_size
) <= 0 ||
749 BN_bn2nativepad(bn_a
, a
, a_size
) <= 0 ||
750 BN_bn2nativepad(bn_b
, b
, b_size
) <= 0 )
751 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to store EC parameters in native byte order.");
753 const EC_POINT
*point_gen
= EC_GROUP_get0_generator(group
);
754 generator_size
= EC_POINT_point2oct(group
, point_gen
, POINT_CONVERSION_UNCOMPRESSED
, NULL
, 0, bnctx
);
755 if (generator_size
== 0)
756 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to determine size of a EC generator.");
758 generator
= malloc(generator_size
);
760 return log_oom_debug();
762 generator_size
= EC_POINT_point2oct(group
, point_gen
, POINT_CONVERSION_UNCOMPRESSED
, generator
, generator_size
, bnctx
);
763 if (generator_size
== 0)
764 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to convert a EC generator to octet string.");
766 ec_params
[1] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_EC_FIELD_TYPE
, (char*)field_type
, strlen(field_type
));
767 ec_params
[2] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_EC_GENERATOR
, generator
, generator_size
);
768 ec_params
[3] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_ORDER
, order
, order_size
);
769 ec_params
[4] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_P
, p
, p_size
);
770 ec_params
[5] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_A
, a
, a_size
);
771 ec_params
[6] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_B
, b
, b_size
);
772 ec_params
[7] = OSSL_PARAM_construct_end();
775 if (EVP_PKEY_fromdata(ctx
, &pkey
, EVP_PKEY_PUBLIC_KEY
, ec_params
) != 1)
776 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to create EVP_PKEY from EC parameters.");
778 _cleanup_(EC_POINT_freep
) EC_POINT
*point
= EC_POINT_new(group
);
780 return log_oom_debug();
782 if (EC_POINT_oct2point(group
, point
, os
->data
, os
->length
, NULL
) != 1)
783 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode CKA_EC_POINT.");
785 _cleanup_(EC_KEY_freep
) EC_KEY
*ec_key
= EC_KEY_new();
787 return log_oom_debug();
789 if (EC_KEY_set_group(ec_key
, group
) != 1)
790 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to set group for EC_KEY.");
792 if (EC_KEY_set_public_key(ec_key
, point
) != 1)
793 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to set public key for EC_KEY.");
795 pkey
= EVP_PKEY_new();
797 return log_oom_debug();
799 if (EVP_PKEY_set1_EC_KEY(pkey
, ec_key
) != 1)
800 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to assign EC_KEY to EVP_PKEY.");
805 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Unsupported type of public key: %lu", key_type
);
808 *ret_pkey
= TAKE_PTR(pkey
);
812 int pkcs11_token_read_x509_certificate(
814 CK_SESSION_HANDLE session
,
815 CK_OBJECT_HANDLE object
,
818 _cleanup_free_
char *t
= NULL
;
819 CK_ATTRIBUTE attribute
= {
823 _cleanup_(X509_freep
) X509
*x509
= NULL
;
824 X509_NAME
*name
= NULL
;
831 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
833 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
834 "Failed to read X.509 certificate size off token: %s", sym_p11_kit_strerror(rv
));
836 _cleanup_free_
void *buffer
= malloc(attribute
.ulValueLen
);
838 return log_oom_debug();
840 attribute
.pValue
= buffer
;
842 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
844 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
845 "Failed to read X.509 certificate data off token: %s", sym_p11_kit_strerror(rv
));
847 const unsigned char *p
= attribute
.pValue
;
848 x509
= d2i_X509(NULL
, &p
, attribute
.ulValueLen
);
850 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG
), "Failed to parse X.509 certificate.");
852 name
= X509_get_subject_name(x509
);
854 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG
), "Failed to acquire X.509 subject name.");
856 t
= X509_NAME_oneline(name
, NULL
, 0);
858 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to format X.509 subject name as string.");
860 log_debug("Using X.509 certificate issued for '%s'.", t
);
862 *ret_cert
= TAKE_PTR(x509
);
867 int pkcs11_token_find_private_key(
869 CK_SESSION_HANDLE session
,
870 P11KitUri
*search_uri
,
871 CK_OBJECT_HANDLE
*ret_object
) {
873 uint_fast8_t n_objects
= 0;
874 bool found_class
= false;
875 _cleanup_free_ CK_ATTRIBUTE
*attributes_buffer
= NULL
;
876 CK_OBJECT_HANDLE object
, candidate
;
877 static const CK_OBJECT_CLASS
class = CKO_PRIVATE_KEY
;
878 CK_BBOOL decrypt_value
, derive_value
;
879 CK_ATTRIBUTE optional_attributes
[] = {
880 { CKA_DECRYPT
, &decrypt_value
, sizeof(decrypt_value
) },
881 { CKA_DERIVE
, &derive_value
, sizeof(derive_value
) }
889 CK_ULONG n_attributes
;
890 CK_ATTRIBUTE
*attributes
= sym_p11_kit_uri_get_attributes(search_uri
, &n_attributes
);
891 for (CK_ULONG i
= 0; i
< n_attributes
; i
++) {
893 /* We use the URI's included match attributes, but make them more strict. This allows users
894 * to specify a token URL instead of an object URL and the right thing should happen if
895 * there's only one suitable key on the token. */
897 switch (attributes
[i
].type
) {
901 if (attributes
[i
].ulValueLen
!= sizeof(c
))
902 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid PKCS#11 CKA_CLASS attribute size.");
904 memcpy(&c
, attributes
[i
].pValue
, sizeof(c
));
905 if (c
!= CKO_PRIVATE_KEY
)
906 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
907 "Selected PKCS#11 object is not a private key, refusing.");
915 /* Hmm, let's slightly extend the attribute list we search for */
917 attributes_buffer
= new(CK_ATTRIBUTE
, n_attributes
+ 1);
918 if (!attributes_buffer
)
921 memcpy(attributes_buffer
, attributes
, sizeof(CK_ATTRIBUTE
) * n_attributes
);
923 attributes_buffer
[n_attributes
++] = (CK_ATTRIBUTE
) {
925 .pValue
= (CK_OBJECT_CLASS
*) &class,
926 .ulValueLen
= sizeof(class),
929 attributes
= attributes_buffer
;
932 rv
= m
->C_FindObjectsInit(session
, attributes
, n_attributes
);
934 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
935 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv
));
939 rv
= m
->C_FindObjects(session
, &candidate
, 1, &b
);
941 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
942 "Failed to find objects: %s", sym_p11_kit_strerror(rv
));
947 bool can_decrypt
= false, can_derive
= false;
948 optional_attributes
[0].ulValueLen
= sizeof(decrypt_value
);
949 optional_attributes
[1].ulValueLen
= sizeof(derive_value
);
951 rv
= m
->C_GetAttributeValue(session
, candidate
, optional_attributes
, ELEMENTSOF(optional_attributes
));
952 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
953 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
954 "Failed to get attributes of a selected private key: %s", sym_p11_kit_strerror(rv
));
956 if (optional_attributes
[0].ulValueLen
!= CK_UNAVAILABLE_INFORMATION
&& decrypt_value
== CK_TRUE
)
959 if (optional_attributes
[1].ulValueLen
!= CK_UNAVAILABLE_INFORMATION
&& derive_value
== CK_TRUE
)
962 if (can_decrypt
|| can_derive
) {
970 rv
= m
->C_FindObjectsFinal(session
);
972 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
973 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv
));
976 return log_error_errno(SYNTHETIC_ERRNO(ENOENT
),
977 "Failed to find selected private key suitable for decryption or derivation on token.");
980 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
981 "Configured private key URI matches multiple keys, refusing.");
983 *ret_object
= object
;
987 static const char* object_class_to_string(CK_OBJECT_CLASS
class) {
989 case CKO_CERTIFICATE
:
990 return "CKO_CERTIFICATE";
992 return "CKO_PUBLIC_KEY";
993 case CKO_PRIVATE_KEY
:
994 return "CKO_PRIVATE_KEY";
996 return "CKO_SECRET_KEY";
1002 /* Returns an object with the given class and the same CKA_ID or CKA_LABEL as prototype */
1003 int pkcs11_token_find_related_object(
1004 CK_FUNCTION_LIST
*m
,
1005 CK_SESSION_HANDLE session
,
1006 CK_OBJECT_HANDLE prototype
,
1007 CK_OBJECT_CLASS
class,
1008 CK_OBJECT_HANDLE
*ret_object
) {
1010 _cleanup_free_
void *buffer
= NULL
;
1011 CK_ATTRIBUTE attributes
[] = {
1012 { CKA_ID
, NULL_PTR
, 0 },
1013 { CKA_LABEL
, NULL_PTR
, 0 }
1015 CK_OBJECT_CLASS search_class
= class;
1016 CK_ATTRIBUTE search_attributes
[2] = {
1017 { CKA_CLASS
, &search_class
, sizeof(search_class
) }
1020 CK_OBJECT_HANDLE objects
[2];
1023 rv
= m
->C_GetAttributeValue(session
, prototype
, attributes
, ELEMENTSOF(attributes
));
1024 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
1025 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve length of attributes: %s", sym_p11_kit_strerror(rv
));
1027 if (attributes
[0].ulValueLen
!= CK_UNAVAILABLE_INFORMATION
) {
1028 buffer
= malloc(attributes
[0].ulValueLen
);
1032 attributes
[0].pValue
= buffer
;
1033 rv
= m
->C_GetAttributeValue(session
, prototype
, &attributes
[0], 1);
1035 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
1036 "Failed to retrieve CKA_ID: %s", sym_p11_kit_strerror(rv
));
1038 search_attributes
[1] = attributes
[0];
1040 } else if (attributes
[1].ulValueLen
!= CK_UNAVAILABLE_INFORMATION
) {
1041 buffer
= malloc(attributes
[1].ulValueLen
);
1045 attributes
[1].pValue
= buffer
;
1046 rv
= m
->C_GetAttributeValue(session
, prototype
, &attributes
[1], 1);
1048 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
1049 "Failed to retrieve CKA_LABEL: %s", sym_p11_kit_strerror(rv
));
1051 search_attributes
[1] = attributes
[1];
1054 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "The prototype does not have CKA_ID or CKA_LABEL");
1056 rv
= m
->C_FindObjectsInit(session
, search_attributes
, 2);
1058 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
1059 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv
));
1061 rv
= m
->C_FindObjects(session
, objects
, 2, &n_objects
);
1063 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
1064 "Failed to find objects: %s", sym_p11_kit_strerror(rv
));
1066 rv
= m
->C_FindObjectsFinal(session
);
1068 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
1069 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv
));
1072 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
1073 "Failed to find a related object with class %s", object_class_to_string(class));
1076 log_warning("Found multiple related objects with class %s, using the first object.",
1077 object_class_to_string(class));
1079 *ret_object
= objects
[0];
1084 static int ecc_convert_to_compressed(
1085 CK_FUNCTION_LIST
*m
,
1086 CK_SESSION_HANDLE session
,
1087 CK_OBJECT_HANDLE object
,
1088 const void *uncompressed_point
,
1089 size_t uncompressed_point_size
,
1090 void **ret_compressed_point
,
1091 size_t *ret_compressed_point_size
) {
1093 _cleanup_free_
void *ec_params_buffer
= NULL
;
1094 CK_ATTRIBUTE ec_params_attr
= { CKA_EC_PARAMS
, NULL_PTR
, 0 };
1098 rv
= m
->C_GetAttributeValue(session
, object
, &ec_params_attr
, 1);
1099 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
1100 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1101 "Failed to retrieve length of CKA_EC_PARAMS: %s", sym_p11_kit_strerror(rv
));
1103 if (ec_params_attr
.ulValueLen
!= CK_UNAVAILABLE_INFORMATION
) {
1104 ec_params_buffer
= malloc(ec_params_attr
.ulValueLen
);
1105 if (!ec_params_buffer
)
1108 ec_params_attr
.pValue
= ec_params_buffer
;
1109 rv
= m
->C_GetAttributeValue(session
, object
, &ec_params_attr
, 1);
1111 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1112 "Failed to retrieve CKA_EC_PARAMS from a private key: %s", sym_p11_kit_strerror(rv
));
1114 CK_OBJECT_HANDLE public_key
;
1115 r
= pkcs11_token_find_related_object(m
, session
, object
, CKO_PUBLIC_KEY
, &public_key
);
1117 return log_error_errno(r
, "Failed to find a public key for compressing a EC point");
1119 ec_params_attr
.ulValueLen
= 0;
1120 rv
= m
->C_GetAttributeValue(session
, public_key
, &ec_params_attr
, 1);
1121 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
1122 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1123 "Failed to retrieve length of CKA_EC_PARAMS: %s", sym_p11_kit_strerror(rv
));
1125 if (ec_params_attr
.ulValueLen
== CK_UNAVAILABLE_INFORMATION
)
1126 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1127 "The public key does not have CKA_EC_PARAMS");
1129 ec_params_buffer
= malloc(ec_params_attr
.ulValueLen
);
1130 if (!ec_params_buffer
)
1133 ec_params_attr
.pValue
= ec_params_buffer
;
1134 rv
= m
->C_GetAttributeValue(session
, public_key
, &ec_params_attr
, 1);
1136 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1137 "Failed to retrieve CKA_EC_PARAMS from a public key: %s", sym_p11_kit_strerror(rv
));
1140 _cleanup_(EC_GROUP_freep
) EC_GROUP
*group
= NULL
;
1141 _cleanup_(EC_POINT_freep
) EC_POINT
*point
= NULL
;
1142 _cleanup_(BN_CTX_freep
) BN_CTX
*bnctx
= NULL
;
1143 _cleanup_free_
void *compressed_point
= NULL
;
1144 size_t compressed_point_size
;
1146 const unsigned char *ec_params_value
= ec_params_attr
.pValue
;
1147 group
= d2i_ECPKParameters(NULL
, &ec_params_value
, ec_params_attr
.ulValueLen
);
1149 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode CKA_EC_PARAMS");
1151 point
= EC_POINT_new(group
);
1155 bnctx
= BN_CTX_new();
1159 if (EC_POINT_oct2point(group
, point
, uncompressed_point
, uncompressed_point_size
, bnctx
) != 1)
1160 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode an uncompressed EC point");
1162 compressed_point_size
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
, NULL
, 0, bnctx
);
1163 if (compressed_point_size
== 0)
1164 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to determine size of a compressed EC point");
1166 compressed_point
= malloc(compressed_point_size
);
1167 if (!compressed_point
)
1170 compressed_point_size
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
, compressed_point
, compressed_point_size
, bnctx
);
1171 if (compressed_point_size
== 0)
1172 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to convert a EC point to compressed format");
1174 *ret_compressed_point
= TAKE_PTR(compressed_point
);
1175 *ret_compressed_point_size
= compressed_point_size
;
1180 /* Since EC keys doesn't support encryption directly, we use ECDH protocol to derive shared secret here.
1181 * We use PKCS#11 C_DeriveKey function to derive a shared secret with a private key stored in the token and
1182 * a public key saved on enrollment. */
1183 static int pkcs11_token_decrypt_data_ecc(
1184 CK_FUNCTION_LIST
*m
,
1185 CK_SESSION_HANDLE session
,
1186 CK_OBJECT_HANDLE object
,
1187 const void *encrypted_data
,
1188 size_t encrypted_data_size
,
1189 void **ret_decrypted_data
,
1190 size_t *ret_decrypted_data_size
) {
1192 static const CK_BBOOL yes
= CK_TRUE
, no
= CK_FALSE
;
1193 static const CK_OBJECT_CLASS shared_secret_class
= CKO_SECRET_KEY
;
1194 static const CK_KEY_TYPE shared_secret_type
= CKK_GENERIC_SECRET
;
1195 static const CK_ATTRIBUTE shared_secret_template
[] = {
1196 { CKA_TOKEN
, (void*) &no
, sizeof(no
) },
1197 { CKA_CLASS
, (void*) &shared_secret_class
, sizeof(shared_secret_class
) },
1198 { CKA_KEY_TYPE
, (void*) &shared_secret_type
, sizeof(shared_secret_type
) },
1199 { CKA_SENSITIVE
, (void*) &no
, sizeof(no
) },
1200 { CKA_EXTRACTABLE
, (void*) &yes
, sizeof(yes
) }
1202 CK_ECDH1_DERIVE_PARAMS params
= {
1204 .pPublicData
= (void*) encrypted_data
,
1205 .ulPublicDataLen
= encrypted_data_size
1207 CK_MECHANISM mechanism
= {
1208 .mechanism
= CKM_ECDH1_DERIVE
,
1209 .pParameter
= ¶ms
,
1210 .ulParameterLen
= sizeof(params
)
1212 CK_OBJECT_HANDLE shared_secret_handle
;
1213 CK_SESSION_INFO session_info
;
1214 CK_MECHANISM_INFO mechanism_info
;
1217 _cleanup_free_
void *compressed_point
= NULL
;
1221 rv
= m
->C_GetSessionInfo(session
, &session_info
);
1223 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1224 "Failed to get information about the PKCS#11 session: %s", sym_p11_kit_strerror(rv
));
1226 rv
= m
->C_GetMechanismInfo(session_info
.slotID
, CKM_ECDH1_DERIVE
, &mechanism_info
);
1228 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1229 "Failed to get information about CKM_ECDH1_DERIVE: %s", sym_p11_kit_strerror(rv
));
1231 if (!(mechanism_info
.flags
& CKF_EC_UNCOMPRESS
)) {
1232 if (mechanism_info
.flags
& CKF_EC_COMPRESS
) {
1234 log_debug("CKM_ECDH1_DERIVE accepts compressed EC points only, trying to convert.");
1235 size_t compressed_point_size
= 0; /* Explicit initialization to appease gcc */
1236 r
= ecc_convert_to_compressed(m
, session
, object
, encrypted_data
, encrypted_data_size
, &compressed_point
, &compressed_point_size
);
1240 params
.pPublicData
= compressed_point
;
1241 params
.ulPublicDataLen
= compressed_point_size
;
1243 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1244 "CKM_ECDH1_DERIVE does not support uncompressed format of EC points");
1247 log_debug("Both CKF_EC_UNCOMPRESS and CKF_EC_COMPRESS are false for CKM_ECDH1_DERIVE, ignoring.");
1250 rv
= m
->C_DeriveKey(session
, &mechanism
, object
, (CK_ATTRIBUTE
*) shared_secret_template
, ELEMENTSOF(shared_secret_template
), &shared_secret_handle
);
1252 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to derive a shared secret: %s", sym_p11_kit_strerror(rv
));
1254 CK_ATTRIBUTE shared_secret_attr
= { CKA_VALUE
, NULL_PTR
, 0};
1256 rv
= m
->C_GetAttributeValue(session
, shared_secret_handle
, &shared_secret_attr
, 1);
1258 rv2
= m
->C_DestroyObject(session
, shared_secret_handle
);
1260 log_warning("Failed to destroy a shared secret, ignoring: %s", sym_p11_kit_strerror(rv2
));
1261 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve shared secret length: %s", sym_p11_kit_strerror(rv
));
1264 shared_secret_attr
.pValue
= malloc(shared_secret_attr
.ulValueLen
);
1265 if (!shared_secret_attr
.pValue
)
1268 rv
= m
->C_GetAttributeValue(session
, shared_secret_handle
, &shared_secret_attr
, 1);
1269 rv2
= m
->C_DestroyObject(session
, shared_secret_handle
);
1271 log_warning("Failed to destroy a shared secret, ignoring: %s", sym_p11_kit_strerror(rv2
));
1274 erase_and_free(shared_secret_attr
.pValue
);
1275 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve a shared secret: %s", sym_p11_kit_strerror(rv
));
1278 log_info("Successfully derived key with security token.");
1280 *ret_decrypted_data
= shared_secret_attr
.pValue
;
1281 *ret_decrypted_data_size
= shared_secret_attr
.ulValueLen
;
1285 static int pkcs11_token_decrypt_data_rsa(
1286 CK_FUNCTION_LIST
*m
,
1287 CK_SESSION_HANDLE session
,
1288 CK_OBJECT_HANDLE object
,
1289 const void *encrypted_data
,
1290 size_t encrypted_data_size
,
1291 void **ret_decrypted_data
,
1292 size_t *ret_decrypted_data_size
) {
1294 static const CK_MECHANISM mechanism
= {
1295 .mechanism
= CKM_RSA_PKCS
1297 _cleanup_(erase_and_freep
) CK_BYTE
*dbuffer
= NULL
;
1298 CK_ULONG dbuffer_size
= 0;
1301 rv
= m
->C_DecryptInit(session
, (CK_MECHANISM
*) &mechanism
, object
);
1303 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1304 "Failed to initialize decryption on security token: %s", sym_p11_kit_strerror(rv
));
1306 dbuffer_size
= encrypted_data_size
; /* Start with something reasonable */
1307 dbuffer
= malloc(dbuffer_size
);
1311 rv
= m
->C_Decrypt(session
, (CK_BYTE
*) encrypted_data
, encrypted_data_size
, dbuffer
, &dbuffer_size
);
1312 if (rv
== CKR_BUFFER_TOO_SMALL
) {
1313 erase_and_free(dbuffer
);
1315 dbuffer
= malloc(dbuffer_size
);
1319 rv
= m
->C_Decrypt(session
, (CK_BYTE
*) encrypted_data
, encrypted_data_size
, dbuffer
, &dbuffer_size
);
1322 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1323 "Failed to decrypt key on security token: %s", sym_p11_kit_strerror(rv
));
1325 log_info("Successfully decrypted key with security token.");
1327 *ret_decrypted_data
= TAKE_PTR(dbuffer
);
1328 *ret_decrypted_data_size
= dbuffer_size
;
1332 int pkcs11_token_decrypt_data(
1333 CK_FUNCTION_LIST
*m
,
1334 CK_SESSION_HANDLE session
,
1335 CK_OBJECT_HANDLE object
,
1336 const void *encrypted_data
,
1337 size_t encrypted_data_size
,
1338 void **ret_decrypted_data
,
1339 size_t *ret_decrypted_data_size
) {
1341 CK_KEY_TYPE key_type
;
1342 CK_ATTRIBUTE key_type_template
= { CKA_KEY_TYPE
, &key_type
, sizeof(key_type
) };
1346 assert(encrypted_data
);
1347 assert(encrypted_data_size
> 0);
1348 assert(ret_decrypted_data
);
1349 assert(ret_decrypted_data_size
);
1351 rv
= m
->C_GetAttributeValue(session
, object
, &key_type_template
, 1);
1353 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve private key type");
1358 return pkcs11_token_decrypt_data_rsa(m
, session
, object
, encrypted_data
, encrypted_data_size
, ret_decrypted_data
, ret_decrypted_data_size
);
1361 return pkcs11_token_decrypt_data_ecc(m
, session
, object
, encrypted_data
, encrypted_data_size
, ret_decrypted_data
, ret_decrypted_data_size
);
1364 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Unsupported private key type: %lu", key_type
);
1368 int pkcs11_token_acquire_rng(
1369 CK_FUNCTION_LIST
*m
,
1370 CK_SESSION_HANDLE session
) {
1372 _cleanup_free_
void *buffer
= NULL
;
1379 r
= dlopen_p11kit();
1383 /* While we are at it, let's read some RNG data from the PKCS#11 token and pass it to the kernel
1384 * random pool. This should be cheap if we are talking to the device already. Note that we don't
1385 * credit any entropy, since we don't know about the quality of the pkcs#11 token's RNG. Why bother
1386 * at all? There are two sides to the argument whether to generate private keys on tokens or on the
1387 * host. By crediting some data from the token RNG to the host's pool we at least can say that any
1388 * key generated from it is at least as good as both sources individually. */
1390 rps
= random_pool_size();
1392 buffer
= malloc(rps
);
1396 rv
= m
->C_GenerateRandom(session
, buffer
, rps
);
1398 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1399 "Failed to generate RNG data on security token: %s", sym_p11_kit_strerror(rv
));
1401 r
= random_write_entropy(-1, buffer
, rps
, false);
1403 return log_debug_errno(r
, "Failed to write PKCS#11 acquired random data to /dev/urandom: %m");
1405 log_debug("Successfully written %zu bytes random data acquired via PKCS#11 to kernel random pool.", rps
);
1410 static int token_process(
1411 CK_FUNCTION_LIST
*m
,
1413 const CK_SLOT_INFO
*slot_info
,
1414 const CK_TOKEN_INFO
*token_info
,
1415 P11KitUri
*search_uri
,
1416 pkcs11_find_token_callback_t callback
,
1419 _cleanup_free_
char *token_label
= NULL
;
1420 CK_SESSION_HANDLE session
;
1428 token_label
= pkcs11_token_label(token_info
);
1432 rv
= m
->C_OpenSession(slotid
, CKF_SERIAL_SESSION
, NULL
, NULL
, &session
);
1434 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1435 "Failed to create session for security token '%s': %s", token_label
, sym_p11_kit_strerror(rv
));
1438 r
= callback(m
, session
, slotid
, slot_info
, token_info
, search_uri
, userdata
);
1440 r
= 1; /* if not callback was specified, just say we found what we were looking for */
1442 rv
= m
->C_CloseSession(session
);
1444 log_warning("Failed to close session on PKCS#11 token, ignoring: %s", sym_p11_kit_strerror(rv
));
1449 static int slot_process(
1450 CK_FUNCTION_LIST
*m
,
1452 P11KitUri
*search_uri
,
1453 pkcs11_find_token_callback_t callback
,
1456 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
* slot_uri
= NULL
, *token_uri
= NULL
;
1457 _cleanup_free_
char *token_uri_string
= NULL
;
1458 CK_TOKEN_INFO token_info
;
1459 CK_SLOT_INFO slot_info
;
1465 r
= dlopen_p11kit();
1469 /* We return -EAGAIN for all failures we can attribute to a specific slot in some way, so that the
1470 * caller might try other slots before giving up. */
1472 rv
= m
->C_GetSlotInfo(slotid
, &slot_info
);
1474 log_warning("Failed to acquire slot info for slot %lu, ignoring slot: %s", slotid
, sym_p11_kit_strerror(rv
));
1478 slot_uri
= uri_from_slot_info(&slot_info
);
1482 if (DEBUG_LOGGING
) {
1483 _cleanup_free_
char *slot_uri_string
= NULL
;
1485 uri_result
= sym_p11_kit_uri_format(slot_uri
, P11_KIT_URI_FOR_ANY
, &slot_uri_string
);
1486 if (uri_result
!= P11_KIT_URI_OK
) {
1487 log_warning("Failed to format slot URI, ignoring slot: %s", sym_p11_kit_uri_message(uri_result
));
1491 log_debug("Found slot with URI %s", slot_uri_string
);
1494 rv
= m
->C_GetTokenInfo(slotid
, &token_info
);
1495 if (rv
== CKR_TOKEN_NOT_PRESENT
) {
1496 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN
),
1497 "Token not present in slot, ignoring.");
1498 } else if (rv
!= CKR_OK
) {
1499 log_warning("Failed to acquire token info for slot %lu, ignoring slot: %s", slotid
, sym_p11_kit_strerror(rv
));
1503 token_uri
= uri_from_token_info(&token_info
);
1507 uri_result
= sym_p11_kit_uri_format(token_uri
, P11_KIT_URI_FOR_ANY
, &token_uri_string
);
1508 if (uri_result
!= P11_KIT_URI_OK
) {
1509 log_warning("Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result
));
1513 if (search_uri
&& !sym_p11_kit_uri_match_token_info(search_uri
, &token_info
))
1514 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN
),
1515 "Found non-matching token with URI %s.",
1518 log_debug("Found matching token with URI %s.", token_uri_string
);
1520 return token_process(
1530 static int module_process(
1531 CK_FUNCTION_LIST
*m
,
1532 P11KitUri
*search_uri
,
1533 pkcs11_find_token_callback_t callback
,
1536 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
* module_uri
= NULL
;
1537 _cleanup_free_
char *name
= NULL
, *module_uri_string
= NULL
;
1538 _cleanup_free_ CK_SLOT_ID
*slotids
= NULL
;
1539 CK_ULONG n_slotids
= 0;
1548 r
= dlopen_p11kit();
1552 /* We ignore most errors from modules here, in order to skip over faulty modules: one faulty module
1553 * should not have the effect that we don't try the others anymore. We indicate such per-module
1554 * failures with -EAGAIN, which let's the caller try the next module. */
1556 name
= sym_p11_kit_module_get_name(m
);
1560 log_debug("Trying PKCS#11 module %s.", name
);
1562 rv
= m
->C_GetInfo(&info
);
1564 log_warning("Failed to get info on PKCS#11 module, ignoring module: %s", sym_p11_kit_strerror(rv
));
1568 module_uri
= uri_from_module_info(&info
);
1572 uri_result
= sym_p11_kit_uri_format(module_uri
, P11_KIT_URI_FOR_ANY
, &module_uri_string
);
1573 if (uri_result
!= P11_KIT_URI_OK
) {
1574 log_warning("Failed to format module URI, ignoring module: %s", sym_p11_kit_uri_message(uri_result
));
1578 log_debug("Found module with URI %s", module_uri_string
);
1580 rv
= pkcs11_get_slot_list_malloc(m
, &slotids
, &n_slotids
);
1582 log_warning("Failed to get slot list, ignoring module: %s", sym_p11_kit_strerror(rv
));
1586 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN
),
1587 "This module has no slots? Ignoring module.");
1589 for (k
= 0; k
< n_slotids
; k
++) {
1603 int pkcs11_find_token(
1604 const char *pkcs11_uri
,
1605 pkcs11_find_token_callback_t callback
,
1608 _cleanup_(sym_p11_kit_modules_finalize_and_releasep
) CK_FUNCTION_LIST
**modules
= NULL
;
1609 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*search_uri
= NULL
;
1612 r
= dlopen_p11kit();
1616 /* Execute the specified callback for each matching token found. If nothing is found returns
1617 * -EAGAIN. Logs about all errors, except for EAGAIN, which the caller has to log about. */
1620 r
= uri_from_string(pkcs11_uri
, &search_uri
);
1622 return log_error_errno(r
, "Failed to parse PKCS#11 URI '%s': %m", pkcs11_uri
);
1625 modules
= sym_p11_kit_modules_load_and_initialize(0);
1627 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to initialize pkcs11 modules");
1629 for (CK_FUNCTION_LIST
**i
= modules
; *i
; i
++) {
1643 struct pkcs11_acquire_public_key_callback_data
{
1646 const char *askpw_friendly_name
, *askpw_icon_name
;
1647 AskPasswordFlags askpw_flags
;
1651 static void pkcs11_acquire_public_key_callback_data_release(struct pkcs11_acquire_public_key_callback_data
*data
) {
1652 erase_and_free(data
->pin_used
);
1653 EVP_PKEY_free(data
->pkey
);
1656 static int pkcs11_acquire_public_key_callback(
1657 CK_FUNCTION_LIST
*m
,
1658 CK_SESSION_HANDLE session
,
1660 const CK_SLOT_INFO
*slot_info
,
1661 const CK_TOKEN_INFO
*token_info
,
1665 _cleanup_(erase_and_freep
) char *pin_used
= NULL
;
1666 _cleanup_(EVP_PKEY_freep
) EVP_PKEY
*pkey
= NULL
;
1667 CK_OBJECT_CLASS
class;
1668 CK_CERTIFICATE_TYPE type
;
1669 CK_ATTRIBUTE candidate_attributes
[] = {
1670 { CKA_CLASS
, &class, sizeof(class) },
1671 { CKA_CERTIFICATE_TYPE
, &type
, sizeof(type
) },
1673 CK_OBJECT_HANDLE candidate
, public_key
= CK_INVALID_HANDLE
, certificate
= CK_INVALID_HANDLE
;
1674 uint8_t n_public_keys
= 0, n_certificates
= 0;
1683 struct pkcs11_acquire_public_key_callback_data
*data
= ASSERT_PTR(userdata
);
1685 /* Called for every token matching our URI */
1687 r
= pkcs11_token_login(
1692 data
->askpw_friendly_name
,
1693 data
->askpw_icon_name
,
1703 CK_ULONG n_attributes
;
1704 CK_ATTRIBUTE
*attributes
= sym_p11_kit_uri_get_attributes(uri
, &n_attributes
);
1705 for (CK_ULONG i
= 0; i
< n_attributes
; i
++) {
1706 switch (attributes
[i
].type
) {
1708 CK_OBJECT_CLASS requested_class
= *((CK_OBJECT_CLASS
*) attributes
[i
].pValue
);
1709 if (requested_class
!= CKO_PUBLIC_KEY
&& requested_class
!= CKO_CERTIFICATE
)
1710 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1711 "Selected PKCS#11 object is not a public key or certificate, refusing.");
1715 case CKA_CERTIFICATE_TYPE
: {
1716 CK_CERTIFICATE_TYPE requested_type
= *((CK_CERTIFICATE_TYPE
*) attributes
[i
].pValue
);
1717 if (requested_type
!= CKC_X_509
)
1718 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Selected PKCS#11 object is not an X.509 certificate, refusing.");
1723 rv
= m
->C_FindObjectsInit(session
, attributes
, n_attributes
);
1725 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1726 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv
));
1730 rv
= m
->C_FindObjects(session
, &candidate
, 1, &n
);
1732 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1733 "Failed to find objects: %s", sym_p11_kit_strerror(rv
));
1738 candidate_attributes
[0].ulValueLen
= sizeof(class);
1739 candidate_attributes
[1].ulValueLen
= sizeof(type
);
1740 rv
= m
->C_GetAttributeValue(session
, candidate
, candidate_attributes
, ELEMENTSOF(candidate_attributes
));
1741 if (rv
!= CKR_OK
&& rv
!= CKR_ATTRIBUTE_TYPE_INVALID
)
1742 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1743 "Failed to get attributes of a selected candidate: %s", sym_p11_kit_strerror(rv
));
1745 if (candidate_attributes
[0].ulValueLen
== CK_UNAVAILABLE_INFORMATION
) {
1746 log_debug("Failed to get CKA_CLASS of a selected candidate");
1750 if (class == CKO_PUBLIC_KEY
) {
1752 if (n_public_keys
> 1)
1754 public_key
= candidate
;
1758 if (class == CKO_CERTIFICATE
) {
1759 if (candidate_attributes
[1].ulValueLen
== CK_UNAVAILABLE_INFORMATION
) {
1760 log_debug("Failed to get CKA_CERTIFICATE_TYPE of a selected candidate");
1763 if (type
!= CKC_X_509
)
1766 if (n_certificates
> 1)
1768 certificate
= candidate
;
1773 rv
= m
->C_FindObjectsFinal(session
);
1775 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1776 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv
));
1778 if (n_public_keys
== 0 && n_certificates
== 0)
1779 return log_error_errno(SYNTHETIC_ERRNO(ENOENT
),
1780 "Failed to find selected public key or X.509 certificate.");
1782 if (n_public_keys
> 1)
1783 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
1784 "Provided URI matches multiple public keys, refusing.");
1786 if (n_certificates
> 1)
1787 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
1788 "Provided URI matches multiple certificates, refusing.");
1790 if (n_public_keys
!= 0) {
1791 r
= pkcs11_token_read_public_key(m
, session
, public_key
, &pkey
);
1796 if (n_certificates
== 0)
1797 return log_error_errno(r
, "Failed to read a found public key.");
1800 _cleanup_(X509_freep
) X509
*cert
= NULL
;
1802 r
= pkcs11_token_read_x509_certificate(m
, session
, certificate
, &cert
);
1804 return log_error_errno(r
, "Failed to read a found X.509 certificate.");
1806 pkey
= X509_get_pubkey(cert
);
1808 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to extract public key from X.509 certificate.");
1811 /* Let's read some random data off the token and write it to the kernel pool before we generate our
1812 * random key from it. This way we can claim the quality of the RNG is at least as good as the
1813 * kernel's and the token's pool */
1814 (void) pkcs11_token_acquire_rng(m
, session
);
1816 data
->pin_used
= TAKE_PTR(pin_used
);
1817 data
->pkey
= TAKE_PTR(pkey
);
1821 int pkcs11_acquire_public_key(
1823 const char *askpw_friendly_name
,
1824 const char *askpw_icon_name
,
1825 EVP_PKEY
**ret_pkey
,
1826 char **ret_pin_used
) {
1828 _cleanup_(pkcs11_acquire_public_key_callback_data_release
) struct pkcs11_acquire_public_key_callback_data data
= {
1829 .askpw_friendly_name
= askpw_friendly_name
,
1830 .askpw_icon_name
= askpw_icon_name
,
1837 r
= pkcs11_find_token(uri
, pkcs11_acquire_public_key_callback
, &data
);
1838 if (r
== -EAGAIN
) /* pkcs11_find_token() doesn't log about this error, but all others */
1839 return log_error_errno(SYNTHETIC_ERRNO(ENXIO
),
1840 "Specified PKCS#11 token with URI '%s' not found.",
1845 *ret_pkey
= TAKE_PTR(data
.pkey
);
1847 *ret_pin_used
= TAKE_PTR(data
.pin_used
);
1852 static int list_callback(
1853 CK_FUNCTION_LIST
*m
,
1854 CK_SESSION_HANDLE session
,
1856 const CK_SLOT_INFO
*slot_info
,
1857 const CK_TOKEN_INFO
*token_info
,
1861 _cleanup_free_
char *token_uri_string
= NULL
, *token_label
= NULL
, *token_manufacturer_id
= NULL
, *token_model
= NULL
;
1862 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*token_uri
= NULL
;
1863 Table
*t
= userdata
;
1869 r
= dlopen_p11kit();
1873 /* We only care about hardware devices here with a token inserted. Let's filter everything else
1874 * out. (Note that the user can explicitly specify non-hardware tokens if they like, but during
1875 * enumeration we'll filter those, since software tokens are typically the system certificate store
1876 * and such, and it's typically not what people want to bind their home directories to.) */
1877 if (!FLAGS_SET(slot_info
->flags
, CKF_HW_SLOT
|CKF_TOKEN_PRESENT
))
1880 token_label
= pkcs11_token_label(token_info
);
1884 token_manufacturer_id
= pkcs11_token_manufacturer_id(token_info
);
1885 if (!token_manufacturer_id
)
1888 token_model
= pkcs11_token_model(token_info
);
1892 token_uri
= uri_from_token_info(token_info
);
1896 uri_result
= sym_p11_kit_uri_format(token_uri
, P11_KIT_URI_FOR_ANY
, &token_uri_string
);
1897 if (uri_result
!= P11_KIT_URI_OK
)
1898 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN
), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result
));
1902 TABLE_STRING
, token_uri_string
,
1903 TABLE_STRING
, token_label
,
1904 TABLE_STRING
, token_manufacturer_id
,
1905 TABLE_STRING
, token_model
);
1907 return table_log_add_error(r
);
1909 return -EAGAIN
; /* keep scanning */
1913 int pkcs11_list_tokens(void) {
1915 _cleanup_(table_unrefp
) Table
*t
= NULL
;
1918 t
= table_new("uri", "label", "manufacturer", "model");
1922 r
= pkcs11_find_token(NULL
, list_callback
, t
);
1923 if (r
< 0 && r
!= -EAGAIN
)
1926 if (table_isempty(t
)) {
1927 log_info("No suitable PKCS#11 tokens found.");
1931 r
= table_print(t
, stdout
);
1933 return log_error_errno(r
, "Failed to show device table: %m");
1937 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1938 "PKCS#11 tokens not supported on this build.");
1943 static int auto_callback(
1944 CK_FUNCTION_LIST
*m
,
1945 CK_SESSION_HANDLE session
,
1947 const CK_SLOT_INFO
*slot_info
,
1948 const CK_TOKEN_INFO
*token_info
,
1952 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*token_uri
= NULL
;
1953 char **t
= userdata
;
1959 r
= dlopen_p11kit();
1963 if (!FLAGS_SET(token_info
->flags
, CKF_HW_SLOT
|CKF_TOKEN_PRESENT
))
1967 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
1968 "More than one suitable PKCS#11 token found.");
1970 token_uri
= uri_from_token_info(token_info
);
1974 uri_result
= sym_p11_kit_uri_format(token_uri
, P11_KIT_URI_FOR_ANY
, t
);
1975 if (uri_result
!= P11_KIT_URI_OK
)
1976 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN
), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result
));
1982 int pkcs11_find_token_auto(char **ret
) {
1986 r
= pkcs11_find_token(NULL
, auto_callback
, ret
);
1988 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "No suitable PKCS#11 tokens found.");
1994 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1995 "PKCS#11 tokens not supported on this build.");
2000 void pkcs11_crypt_device_callback_data_release(pkcs11_crypt_device_callback_data
*data
) {
2001 erase_and_free(data
->decrypted_key
);
2003 if (data
->free_encrypted_key
)
2004 free(data
->encrypted_key
);
2007 int pkcs11_crypt_device_callback(
2008 CK_FUNCTION_LIST
*m
,
2009 CK_SESSION_HANDLE session
,
2011 const CK_SLOT_INFO
*slot_info
,
2012 const CK_TOKEN_INFO
*token_info
,
2016 pkcs11_crypt_device_callback_data
*data
= ASSERT_PTR(userdata
);
2017 CK_OBJECT_HANDLE object
;
2025 /* Called for every token matching our URI */
2027 r
= pkcs11_token_login(
2032 data
->friendly_name
,
2035 "cryptsetup.pkcs11-pin",
2043 /* We are likely called during early boot, where entropy is scarce. Mix some data from the PKCS#11
2044 * token, if it supports that. It should be cheap, given that we already are talking to it anyway and
2045 * shouldn't hurt. */
2046 (void) pkcs11_token_acquire_rng(m
, session
);
2048 r
= pkcs11_token_find_private_key(m
, session
, uri
, &object
);
2052 r
= pkcs11_token_decrypt_data(
2056 data
->encrypted_key
,
2057 data
->encrypted_key_size
,
2058 &data
->decrypted_key
,
2059 &data
->decrypted_key_size
);