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 DLSYM_FUNCTION(p11_kit_module_get_name
);
47 DLSYM_FUNCTION(p11_kit_modules_finalize_and_release
);
48 DLSYM_FUNCTION(p11_kit_modules_load_and_initialize
);
49 DLSYM_FUNCTION(p11_kit_strerror
);
50 DLSYM_FUNCTION(p11_kit_uri_format
);
51 DLSYM_FUNCTION(p11_kit_uri_free
);
52 DLSYM_FUNCTION(p11_kit_uri_get_attributes
);
53 DLSYM_FUNCTION(p11_kit_uri_get_attribute
);
54 DLSYM_FUNCTION(p11_kit_uri_set_attribute
);
55 DLSYM_FUNCTION(p11_kit_uri_get_module_info
);
56 DLSYM_FUNCTION(p11_kit_uri_get_slot_info
);
57 DLSYM_FUNCTION(p11_kit_uri_get_token_info
);
58 DLSYM_FUNCTION(p11_kit_uri_match_token_info
);
59 DLSYM_FUNCTION(p11_kit_uri_message
);
60 DLSYM_FUNCTION(p11_kit_uri_new
);
61 DLSYM_FUNCTION(p11_kit_uri_parse
);
63 int dlopen_p11kit(void) {
64 ELF_NOTE_DLOPEN("p11-kit",
65 "Support for PKCS11 hardware tokens",
66 ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED
,
69 return dlopen_many_sym_or_warn(
71 "libp11-kit.so.0", LOG_DEBUG
,
72 DLSYM_ARG(p11_kit_module_get_name
),
73 DLSYM_ARG(p11_kit_modules_finalize_and_release
),
74 DLSYM_ARG(p11_kit_modules_load_and_initialize
),
75 DLSYM_ARG(p11_kit_strerror
),
76 DLSYM_ARG(p11_kit_uri_format
),
77 DLSYM_ARG(p11_kit_uri_free
),
78 DLSYM_ARG(p11_kit_uri_get_attributes
),
79 DLSYM_ARG(p11_kit_uri_get_attribute
),
80 DLSYM_ARG(p11_kit_uri_set_attribute
),
81 DLSYM_ARG(p11_kit_uri_get_module_info
),
82 DLSYM_ARG(p11_kit_uri_get_slot_info
),
83 DLSYM_ARG(p11_kit_uri_get_token_info
),
84 DLSYM_ARG(p11_kit_uri_match_token_info
),
85 DLSYM_ARG(p11_kit_uri_message
),
86 DLSYM_ARG(p11_kit_uri_new
),
87 DLSYM_ARG(p11_kit_uri_parse
));
90 int uri_from_string(const char *p
, P11KitUri
**ret
) {
91 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*uri
= NULL
;
101 uri
= sym_p11_kit_uri_new();
105 if (sym_p11_kit_uri_parse(p
, P11_KIT_URI_FOR_ANY
, uri
) != P11_KIT_URI_OK
)
108 *ret
= TAKE_PTR(uri
);
112 P11KitUri
*uri_from_module_info(const CK_INFO
*info
) {
117 if (dlopen_p11kit() < 0)
120 uri
= sym_p11_kit_uri_new();
124 *sym_p11_kit_uri_get_module_info(uri
) = *info
;
128 P11KitUri
*uri_from_slot_info(const CK_SLOT_INFO
*slot_info
) {
133 if (dlopen_p11kit() < 0)
136 uri
= sym_p11_kit_uri_new();
140 *sym_p11_kit_uri_get_slot_info(uri
) = *slot_info
;
144 P11KitUri
*uri_from_token_info(const CK_TOKEN_INFO
*token_info
) {
149 if (dlopen_p11kit() < 0)
152 uri
= sym_p11_kit_uri_new();
156 *sym_p11_kit_uri_get_token_info(uri
) = *token_info
;
160 CK_RV
pkcs11_get_slot_list_malloc(
162 CK_SLOT_ID
**ret_slotids
,
163 CK_ULONG
*ret_n_slotids
) {
169 assert(ret_n_slotids
);
171 for (unsigned tries
= 0; tries
< 16; tries
++) {
172 _cleanup_free_ CK_SLOT_ID
*slotids
= NULL
;
173 CK_ULONG n_slotids
= 0;
175 rv
= m
->C_GetSlotList(0, NULL
, &n_slotids
);
178 if (n_slotids
== 0) {
184 slotids
= new(CK_SLOT_ID
, n_slotids
);
186 return CKR_HOST_MEMORY
;
188 rv
= m
->C_GetSlotList(0, slotids
, &n_slotids
);
190 *ret_slotids
= TAKE_PTR(slotids
);
191 *ret_n_slotids
= n_slotids
;
195 if (rv
!= CKR_BUFFER_TOO_SMALL
)
198 /* Hu? Maybe somebody plugged something in and things changed? Let's try again */
201 return CKR_BUFFER_TOO_SMALL
;
204 char *pkcs11_token_label(const CK_TOKEN_INFO
*token_info
) {
207 /* The label is not NUL terminated and likely padded with spaces, let's make a copy here, so that we
209 t
= strndup((char*) token_info
->label
, sizeof(token_info
->label
));
217 char *pkcs11_token_manufacturer_id(const CK_TOKEN_INFO
*token_info
) {
220 t
= strndup((char*) token_info
->manufacturerID
, sizeof(token_info
->manufacturerID
));
228 char *pkcs11_token_model(const CK_TOKEN_INFO
*token_info
) {
231 t
= strndup((char*) token_info
->model
, sizeof(token_info
->model
));
239 int pkcs11_token_login_by_pin(
241 CK_SESSION_HANDLE session
,
242 const CK_TOKEN_INFO
*token_info
,
243 const char *token_label
,
257 if (FLAGS_SET(token_info
->flags
, CKF_PROTECTED_AUTHENTICATION_PATH
)) {
258 rv
= m
->C_Login(session
, CKU_USER
, NULL
, 0);
260 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
261 "Failed to log into security token '%s': %s", token_label
, sym_p11_kit_strerror(rv
));
263 log_info("Successfully logged into security token '%s' via protected authentication path.", token_label
);
267 if (!FLAGS_SET(token_info
->flags
, CKF_LOGIN_REQUIRED
)) {
268 log_info("No login into security token '%s' required.", token_label
);
275 rv
= m
->C_Login(session
, CKU_USER
, (CK_UTF8CHAR
*) pin
, pin_size
);
277 log_info("Successfully logged into security token '%s'.", token_label
);
281 if (rv
== CKR_PIN_LOCKED
)
282 return log_error_errno(SYNTHETIC_ERRNO(EPERM
),
283 "PIN has been locked, please reset PIN of security token '%s'.", token_label
);
284 if (!IN_SET(rv
, CKR_PIN_INCORRECT
, CKR_PIN_LEN_RANGE
))
285 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
286 "Failed to log into security token '%s': %s", token_label
, sym_p11_kit_strerror(rv
));
288 return log_notice_errno(SYNTHETIC_ERRNO(ENOLCK
),
289 "PIN for token '%s' is incorrect, please try again.",
293 int pkcs11_token_login(
295 CK_SESSION_HANDLE session
,
297 const CK_TOKEN_INFO
*token_info
,
298 const char *friendly_name
,
299 const char *askpw_icon
,
300 const char *askpw_keyring
,
301 const char *askpw_credential
,
303 AskPasswordFlags askpw_flags
,
304 char **ret_used_pin
) {
306 _cleanup_free_
char *token_uri_string
= NULL
, *token_uri_escaped
= NULL
, *id
= NULL
, *token_label
= NULL
;
307 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*token_uri
= NULL
;
308 CK_TOKEN_INFO updated_token_info
;
319 token_label
= pkcs11_token_label(token_info
);
323 token_uri
= uri_from_token_info(token_info
);
327 uri_result
= sym_p11_kit_uri_format(token_uri
, P11_KIT_URI_FOR_ANY
, &token_uri_string
);
328 if (uri_result
!= P11_KIT_URI_OK
)
329 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN
), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result
));
331 r
= pkcs11_token_login_by_pin(m
, session
, token_info
, token_label
, /* pin= */ NULL
, 0);
332 if (r
== 0 && ret_used_pin
)
333 *ret_used_pin
= NULL
;
335 if (r
!= -ENOANO
) /* pin required */
338 token_uri_escaped
= cescape(token_uri_string
);
339 if (!token_uri_escaped
)
342 id
= strjoin("pkcs11:", token_uri_escaped
);
346 for (unsigned tries
= 0; tries
< 3; tries
++) {
347 _cleanup_strv_free_erase_
char **passwords
= NULL
;
348 _cleanup_(erase_and_freep
) char *envpin
= NULL
;
350 r
= getenv_steal_erase("PIN", &envpin
);
352 return log_error_errno(r
, "Failed to acquire PIN from environment: %m");
354 passwords
= strv_new(envpin
);
358 } else if (FLAGS_SET(askpw_flags
, ASK_PASSWORD_HEADLESS
))
359 return log_error_errno(SYNTHETIC_ERRNO(ENOPKG
), "PIN querying disabled via 'headless' option. Use the 'PIN' environment variable.");
361 _cleanup_free_
char *text
= NULL
;
363 if (FLAGS_SET(token_info
->flags
, CKF_USER_PIN_FINAL_TRY
))
365 "Please enter correct PIN for security token '%s' in order to unlock %s (final try):",
366 token_label
, friendly_name
);
367 else if (FLAGS_SET(token_info
->flags
, CKF_USER_PIN_COUNT_LOW
))
369 "PIN has been entered incorrectly previously, please enter correct 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:",
374 token_label
, friendly_name
);
377 "Please enter PIN for security token '%s' in order to unlock %s (try #%u):",
378 token_label
, friendly_name
, tries
+1);
382 AskPasswordRequest req
= {
386 .keyring
= askpw_keyring
,
387 .credential
= askpw_credential
,
390 /* We never cache PINs, simply because it's fatal if we use wrong PINs, since usually there are only 3 tries */
391 r
= ask_password_auto(&req
, until
, askpw_flags
, &passwords
);
393 return log_error_errno(r
, "Failed to query PIN for security token '%s': %m", token_label
);
396 STRV_FOREACH(i
, passwords
) {
397 r
= pkcs11_token_login_by_pin(m
, session
, token_info
, token_label
, *i
, strlen(*i
));
398 if (r
== 0 && ret_used_pin
) {
411 /* Refresh the token info, so that we can prompt knowing the new flags if they changed. */
412 rv
= m
->C_GetTokenInfo(slotid
, &updated_token_info
);
414 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
415 "Failed to acquire updated security token information for slot %lu: %s",
416 slotid
, sym_p11_kit_strerror(rv
));
418 token_info
= &updated_token_info
;
422 return log_error_errno(SYNTHETIC_ERRNO(EPERM
), "Too many attempts to log into token '%s'.", token_label
);
425 int pkcs11_token_find_x509_certificate(
427 CK_SESSION_HANDLE session
,
428 P11KitUri
*search_uri
,
429 CK_OBJECT_HANDLE
*ret_object
) {
431 bool found_class
= false, found_certificate_type
= false;
432 _cleanup_free_ CK_ATTRIBUTE
*attributes_buffer
= NULL
;
433 CK_ULONG n_attributes
, a
, n_objects
;
434 CK_ATTRIBUTE
*attributes
= NULL
;
435 CK_OBJECT_HANDLE objects
[2];
447 attributes
= sym_p11_kit_uri_get_attributes(search_uri
, &n_attributes
);
448 for (a
= 0; a
< n_attributes
; a
++) {
450 /* We use the URI's included match attributes, but make them more strict. This allows users
451 * to specify a token URL instead of an object URL and the right thing should happen if
452 * there's only one suitable key on the token. */
454 switch (attributes
[a
].type
) {
459 if (attributes
[a
].ulValueLen
!= sizeof(c
))
460 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid PKCS#11 CKA_CLASS attribute size.");
462 memcpy(&c
, attributes
[a
].pValue
, sizeof(c
));
463 if (c
!= CKO_CERTIFICATE
)
464 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Selected PKCS#11 object is not an X.509 certificate, refusing.");
470 case CKA_CERTIFICATE_TYPE
: {
471 CK_CERTIFICATE_TYPE t
;
473 if (attributes
[a
].ulValueLen
!= sizeof(t
))
474 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid PKCS#11 CKA_CERTIFICATE_TYPE attribute size.");
476 memcpy(&t
, attributes
[a
].pValue
, sizeof(t
));
478 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Selected PKCS#11 object is not an X.509 certificate, refusing.");
480 found_certificate_type
= true;
485 if (!found_class
|| !found_certificate_type
) {
486 /* Hmm, let's slightly extend the attribute list we search for */
488 attributes_buffer
= new(CK_ATTRIBUTE
, n_attributes
+ !found_class
+ !found_certificate_type
);
489 if (!attributes_buffer
)
492 memcpy(attributes_buffer
, attributes
, sizeof(CK_ATTRIBUTE
) * n_attributes
);
495 static const CK_OBJECT_CLASS
class = CKO_CERTIFICATE
;
497 attributes_buffer
[n_attributes
++] = (CK_ATTRIBUTE
) {
499 .pValue
= (CK_OBJECT_CLASS
*) &class,
500 .ulValueLen
= sizeof(class),
504 if (!found_certificate_type
) {
505 static const CK_CERTIFICATE_TYPE type
= CKC_X_509
;
507 attributes_buffer
[n_attributes
++] = (CK_ATTRIBUTE
) {
508 .type
= CKA_CERTIFICATE_TYPE
,
509 .pValue
= (CK_CERTIFICATE_TYPE
*) &type
,
510 .ulValueLen
= sizeof(type
),
514 attributes
= attributes_buffer
;
517 rv
= m
->C_FindObjectsInit(session
, attributes
, n_attributes
);
519 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
520 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv
));
522 rv
= m
->C_FindObjects(session
, objects
, ELEMENTSOF(objects
), &n_objects
);
523 rv2
= m
->C_FindObjectsFinal(session
);
525 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
526 "Failed to find objects: %s", sym_p11_kit_strerror(rv
));
528 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
529 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv
));
531 return log_error_errno(SYNTHETIC_ERRNO(ENOENT
),
532 "Failed to find selected X509 certificate on token.");
534 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
535 "Configured URI matches multiple certificates, refusing.");
537 *ret_object
= objects
[0];
542 static int read_public_key_info(
544 CK_SESSION_HANDLE session
,
545 CK_OBJECT_HANDLE object
,
546 EVP_PKEY
**ret_pkey
) {
548 CK_ATTRIBUTE attribute
= { CKA_PUBLIC_KEY_INFO
, NULL_PTR
, 0 };
549 _cleanup_(EVP_PKEY_freep
) EVP_PKEY
*pkey
= NULL
;
552 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
554 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
555 "Failed to get size of CKA_PUBLIC_KEY_INFO: %s", sym_p11_kit_strerror(rv
));
557 if (attribute
.ulValueLen
== 0)
558 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
), "CKA_PUBLIC_KEY_INFO is empty");
560 _cleanup_free_
void *buffer
= malloc(attribute
.ulValueLen
);
562 return log_oom_debug();
564 attribute
.pValue
= buffer
;
566 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
568 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
569 "Failed to read CKA_PUBLIC_KEY_INFO: %s", sym_p11_kit_strerror(rv
));
571 const unsigned char *value
= attribute
.pValue
;
572 pkey
= d2i_PUBKEY(NULL
, &value
, attribute
.ulValueLen
);
574 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG
), "Failed to parse CKA_PUBLIC_KEY_INFO");
576 *ret_pkey
= TAKE_PTR(pkey
);
580 int pkcs11_token_read_public_key(
582 CK_SESSION_HANDLE session
,
583 CK_OBJECT_HANDLE object
,
584 EVP_PKEY
**ret_pkey
) {
586 _cleanup_(EVP_PKEY_freep
) EVP_PKEY
*pkey
= NULL
;
590 r
= read_public_key_info(m
, session
, object
, &pkey
);
592 *ret_pkey
= TAKE_PTR(pkey
);
596 CK_KEY_TYPE key_type
;
597 CK_ATTRIBUTE attribute
= { CKA_KEY_TYPE
, &key_type
, sizeof(key_type
) };
599 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
601 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
602 "Failed to get CKA_KEY_TYPE of a public key: %s", sym_p11_kit_strerror(rv
));
606 CK_ATTRIBUTE rsa_attributes
[] = {
607 { CKA_MODULUS
, NULL_PTR
, 0 },
608 { CKA_PUBLIC_EXPONENT
, NULL_PTR
, 0 },
611 rv
= m
->C_GetAttributeValue(session
, object
, rsa_attributes
, ELEMENTSOF(rsa_attributes
));
613 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
614 "Failed to get size of attributes of an RSA public key: %s", sym_p11_kit_strerror(rv
));
616 if (rsa_attributes
[0].ulValueLen
== 0)
617 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "An RSA public key has empty CKA_MODULUS.");
619 _cleanup_free_
void *modulus
= malloc(rsa_attributes
[0].ulValueLen
);
621 return log_oom_debug();
623 rsa_attributes
[0].pValue
= modulus
;
625 if (rsa_attributes
[1].ulValueLen
== 0)
626 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "An RSA public key has empty CKA_PUBLIC_EXPONENT.");
628 _cleanup_free_
void *public_exponent
= malloc(rsa_attributes
[1].ulValueLen
);
629 if (!public_exponent
)
630 return log_oom_debug();
632 rsa_attributes
[1].pValue
= public_exponent
;
634 rv
= m
->C_GetAttributeValue(session
, object
, rsa_attributes
, ELEMENTSOF(rsa_attributes
));
636 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
637 "Failed to get attributes of an RSA public key: %s", sym_p11_kit_strerror(rv
));
639 size_t n_size
= rsa_attributes
[0].ulValueLen
, e_size
= rsa_attributes
[1].ulValueLen
;
640 r
= rsa_pkey_from_n_e(rsa_attributes
[0].pValue
, n_size
, rsa_attributes
[1].pValue
, e_size
, &pkey
);
642 return log_debug_errno(r
, "Failed to create an EVP_PKEY from RSA parameters.");
647 CK_ATTRIBUTE ec_attributes
[] = {
648 { CKA_EC_PARAMS
, NULL_PTR
, 0 },
649 { CKA_EC_POINT
, NULL_PTR
, 0 },
652 rv
= m
->C_GetAttributeValue(session
, object
, ec_attributes
, ELEMENTSOF(ec_attributes
));
654 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
655 "Failed to get size of attributes of an EC public key: %s", sym_p11_kit_strerror(rv
));
657 if (ec_attributes
[0].ulValueLen
== 0)
658 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "An EC public key has empty CKA_EC_PARAMS.");
660 _cleanup_free_
void *ec_group
= malloc(ec_attributes
[0].ulValueLen
);
662 return log_oom_debug();
664 ec_attributes
[0].pValue
= ec_group
;
666 if (ec_attributes
[1].ulValueLen
== 0)
667 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "An EC public key has empty CKA_EC_POINT.");
669 _cleanup_free_
void *ec_point
= malloc(ec_attributes
[1].ulValueLen
);
671 return log_oom_debug();
673 ec_attributes
[1].pValue
= ec_point
;
675 rv
= m
->C_GetAttributeValue(session
, object
, ec_attributes
, ELEMENTSOF(ec_attributes
));
677 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
678 "Failed to get attributes of an EC public key: %s", sym_p11_kit_strerror(rv
));
680 _cleanup_(EC_GROUP_freep
) EC_GROUP
*group
= NULL
;
681 _cleanup_(ASN1_OCTET_STRING_freep
) ASN1_OCTET_STRING
*os
= NULL
;
683 const unsigned char *ec_params_value
= ec_attributes
[0].pValue
;
684 group
= d2i_ECPKParameters(NULL
, &ec_params_value
, ec_attributes
[0].ulValueLen
);
686 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode CKA_EC_PARAMS.");
688 const unsigned char *ec_point_value
= ec_attributes
[1].pValue
;
689 os
= d2i_ASN1_OCTET_STRING(NULL
, &ec_point_value
, ec_attributes
[1].ulValueLen
);
691 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode CKA_EC_POINT.");
693 #if OPENSSL_VERSION_MAJOR >= 3
694 _cleanup_(EVP_PKEY_CTX_freep
) EVP_PKEY_CTX
*ctx
= EVP_PKEY_CTX_new_from_name(NULL
, "EC", NULL
);
696 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to create an EVP_PKEY_CTX for EC.");
698 if (EVP_PKEY_fromdata_init(ctx
) != 1)
699 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to init an EVP_PKEY_CTX for EC.");
701 OSSL_PARAM ec_params
[8] = {
702 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY
, os
->data
, os
->length
)
705 _cleanup_free_
void *order
= NULL
, *p
= NULL
, *a
= NULL
, *b
= NULL
, *generator
= NULL
;
706 size_t order_size
, p_size
, a_size
, b_size
, generator_size
;
708 int nid
= EC_GROUP_get_curve_name(group
);
709 if (nid
!= NID_undef
) {
710 const char* name
= OSSL_EC_curve_nid2name(nid
);
711 ec_params
[1] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME
, (char*)name
, strlen(name
));
712 ec_params
[2] = OSSL_PARAM_construct_end();
714 const char *field_type
= EC_GROUP_get_field_type(group
) == NID_X9_62_prime_field
?
715 "prime-field" : "characteristic-two-field";
717 const BIGNUM
*bn_order
= EC_GROUP_get0_order(group
);
719 _cleanup_(BN_CTX_freep
) BN_CTX
*bnctx
= BN_CTX_new();
721 return log_oom_debug();
723 _cleanup_(BN_freep
) BIGNUM
*bn_p
= BN_new();
725 return log_oom_debug();
727 _cleanup_(BN_freep
) BIGNUM
*bn_a
= BN_new();
729 return log_oom_debug();
731 _cleanup_(BN_freep
) BIGNUM
*bn_b
= BN_new();
733 return log_oom_debug();
735 if (EC_GROUP_get_curve(group
, bn_p
, bn_a
, bn_b
, bnctx
) != 1)
736 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to extract EC parameters from EC_GROUP.");
738 order_size
= BN_num_bytes(bn_order
);
739 p_size
= BN_num_bytes(bn_p
);
740 a_size
= BN_num_bytes(bn_a
);
741 b_size
= BN_num_bytes(bn_b
);
743 order
= malloc(order_size
);
745 return log_oom_debug();
749 return log_oom_debug();
753 return log_oom_debug();
757 return log_oom_debug();
759 if (BN_bn2nativepad(bn_order
, order
, order_size
) <= 0 ||
760 BN_bn2nativepad(bn_p
, p
, p_size
) <= 0 ||
761 BN_bn2nativepad(bn_a
, a
, a_size
) <= 0 ||
762 BN_bn2nativepad(bn_b
, b
, b_size
) <= 0 )
763 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to store EC parameters in native byte order.");
765 const EC_POINT
*point_gen
= EC_GROUP_get0_generator(group
);
766 generator_size
= EC_POINT_point2oct(group
, point_gen
, POINT_CONVERSION_UNCOMPRESSED
, NULL
, 0, bnctx
);
767 if (generator_size
== 0)
768 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to determine size of a EC generator.");
770 generator
= malloc(generator_size
);
772 return log_oom_debug();
774 generator_size
= EC_POINT_point2oct(group
, point_gen
, POINT_CONVERSION_UNCOMPRESSED
, generator
, generator_size
, bnctx
);
775 if (generator_size
== 0)
776 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to convert a EC generator to octet string.");
778 ec_params
[1] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_EC_FIELD_TYPE
, (char*)field_type
, strlen(field_type
));
779 ec_params
[2] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_EC_GENERATOR
, generator
, generator_size
);
780 ec_params
[3] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_ORDER
, order
, order_size
);
781 ec_params
[4] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_P
, p
, p_size
);
782 ec_params
[5] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_A
, a
, a_size
);
783 ec_params
[6] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_B
, b
, b_size
);
784 ec_params
[7] = OSSL_PARAM_construct_end();
787 if (EVP_PKEY_fromdata(ctx
, &pkey
, EVP_PKEY_PUBLIC_KEY
, ec_params
) != 1)
788 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to create EVP_PKEY from EC parameters.");
790 _cleanup_(EC_POINT_freep
) EC_POINT
*point
= EC_POINT_new(group
);
792 return log_oom_debug();
794 if (EC_POINT_oct2point(group
, point
, os
->data
, os
->length
, NULL
) != 1)
795 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode CKA_EC_POINT.");
797 _cleanup_(EC_KEY_freep
) EC_KEY
*ec_key
= EC_KEY_new();
799 return log_oom_debug();
801 if (EC_KEY_set_group(ec_key
, group
) != 1)
802 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to set group for EC_KEY.");
804 if (EC_KEY_set_public_key(ec_key
, point
) != 1)
805 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to set public key for EC_KEY.");
807 pkey
= EVP_PKEY_new();
809 return log_oom_debug();
811 if (EVP_PKEY_set1_EC_KEY(pkey
, ec_key
) != 1)
812 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to assign EC_KEY to EVP_PKEY.");
817 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Unsupported type of public key: %lu", key_type
);
820 *ret_pkey
= TAKE_PTR(pkey
);
824 int pkcs11_token_read_x509_certificate(
826 CK_SESSION_HANDLE session
,
827 CK_OBJECT_HANDLE object
,
830 _cleanup_free_
char *t
= NULL
;
831 CK_ATTRIBUTE attribute
= {
835 _cleanup_(X509_freep
) X509
*x509
= NULL
;
836 X509_NAME
*name
= NULL
;
843 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
845 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
846 "Failed to read X.509 certificate size off token: %s", sym_p11_kit_strerror(rv
));
848 _cleanup_free_
void *buffer
= malloc(attribute
.ulValueLen
);
850 return log_oom_debug();
852 attribute
.pValue
= buffer
;
854 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
856 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
857 "Failed to read X.509 certificate data off token: %s", sym_p11_kit_strerror(rv
));
859 const unsigned char *p
= attribute
.pValue
;
860 x509
= d2i_X509(NULL
, &p
, attribute
.ulValueLen
);
862 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG
), "Failed to parse X.509 certificate.");
864 name
= X509_get_subject_name(x509
);
866 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG
), "Failed to acquire X.509 subject name.");
868 t
= X509_NAME_oneline(name
, NULL
, 0);
870 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to format X.509 subject name as string.");
872 log_debug("Using X.509 certificate issued for '%s'.", t
);
874 *ret_cert
= TAKE_PTR(x509
);
879 int pkcs11_token_find_private_key(
881 CK_SESSION_HANDLE session
,
882 P11KitUri
*search_uri
,
883 CK_OBJECT_HANDLE
*ret_object
) {
885 bool found_class
= false;
886 _cleanup_free_ CK_ATTRIBUTE
*attributes_buffer
= NULL
;
887 CK_KEY_TYPE key_type
;
888 CK_BBOOL decrypt_value
, derive_value
;
889 CK_ATTRIBUTE optional_attributes
[] = {
890 { CKA_KEY_TYPE
, &key_type
, sizeof(key_type
) },
891 { CKA_DECRYPT
, &decrypt_value
, sizeof(decrypt_value
) },
892 { CKA_DERIVE
, &derive_value
, sizeof(derive_value
) },
894 uint8_t n_private_keys
= 0;
895 CK_OBJECT_HANDLE private_key
= CK_INVALID_HANDLE
;
902 CK_ULONG n_attributes
;
903 CK_ATTRIBUTE
*attributes
= sym_p11_kit_uri_get_attributes(search_uri
, &n_attributes
);
904 for (CK_ULONG i
= 0; i
< n_attributes
; i
++) {
906 /* We use the URI's included match attributes, but make them more strict. This allows users
907 * to specify a token URL instead of an object URL and the right thing should happen if
908 * there's only one suitable key on the token. */
910 switch (attributes
[i
].type
) {
912 if (attributes
[i
].ulValueLen
!= sizeof(CK_OBJECT_CLASS
))
913 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid PKCS#11 CKA_CLASS attribute size.");
915 CK_OBJECT_CLASS
*class = (CK_OBJECT_CLASS
*) attributes
[i
].pValue
;
916 if (*class != CKO_PRIVATE_KEY
)
917 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
918 "Selected PKCS#11 object is not a private key, refusing.");
926 /* Hmm, let's slightly extend the attribute list we search for */
927 static const CK_OBJECT_CLASS required_class
= CKO_PRIVATE_KEY
;
929 attributes_buffer
= new(CK_ATTRIBUTE
, n_attributes
+ 1);
930 if (!attributes_buffer
)
933 memcpy(attributes_buffer
, attributes
, sizeof(CK_ATTRIBUTE
) * n_attributes
);
935 attributes_buffer
[n_attributes
++] = (CK_ATTRIBUTE
) {
937 .pValue
= (CK_OBJECT_CLASS
*) &required_class
,
938 .ulValueLen
= sizeof(required_class
),
941 attributes
= attributes_buffer
;
944 rv
= m
->C_FindObjectsInit(session
, attributes
, n_attributes
);
946 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
947 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv
));
951 CK_OBJECT_HANDLE candidate
;
952 rv
= m
->C_FindObjects(session
, &candidate
, 1, &b
);
954 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
955 "Failed to find objects: %s", sym_p11_kit_strerror(rv
));
960 optional_attributes
[0].ulValueLen
= sizeof(key_type
);
961 optional_attributes
[1].ulValueLen
= sizeof(decrypt_value
);
962 optional_attributes
[2].ulValueLen
= sizeof(derive_value
);
964 rv
= m
->C_GetAttributeValue(session
, candidate
, optional_attributes
, ELEMENTSOF(optional_attributes
));
965 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
966 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
967 "Failed to get attributes of a found private key: %s", sym_p11_kit_strerror(rv
));
969 if (optional_attributes
[0].ulValueLen
== CK_UNAVAILABLE_INFORMATION
) {
970 log_debug("A found private key does not have CKA_KEY_TYPE, rejecting the key.");
974 if (key_type
== CKK_RSA
)
975 if (optional_attributes
[1].ulValueLen
== CK_UNAVAILABLE_INFORMATION
|| decrypt_value
== CK_FALSE
) {
976 log_debug("A found private RSA key can't decrypt, rejecting the key.");
980 if (key_type
== CKK_EC
)
981 if (optional_attributes
[2].ulValueLen
== CK_UNAVAILABLE_INFORMATION
|| derive_value
== CK_FALSE
) {
982 log_debug("A found private EC key can't derive, rejecting the key.");
987 if (n_private_keys
> 1)
989 private_key
= candidate
;
992 rv
= m
->C_FindObjectsFinal(session
);
994 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
995 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv
));
997 if (n_private_keys
== 0)
998 return log_error_errno(SYNTHETIC_ERRNO(ENOENT
),
999 "Failed to find selected private key suitable for decryption or derivation on token.");
1001 if (n_private_keys
> 1)
1002 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
1003 "Configured private key URI matches multiple keys, refusing.");
1005 *ret_object
= private_key
;
1009 static const char* object_class_to_string(CK_OBJECT_CLASS
class) {
1011 case CKO_CERTIFICATE
:
1012 return "CKO_CERTIFICATE";
1013 case CKO_PUBLIC_KEY
:
1014 return "CKO_PUBLIC_KEY";
1015 case CKO_PRIVATE_KEY
:
1016 return "CKO_PRIVATE_KEY";
1017 case CKO_SECRET_KEY
:
1018 return "CKO_SECRET_KEY";
1024 /* Returns an object with the given class and the same CKA_ID or CKA_LABEL as prototype */
1025 int pkcs11_token_find_related_object(
1026 CK_FUNCTION_LIST
*m
,
1027 CK_SESSION_HANDLE session
,
1028 CK_OBJECT_HANDLE prototype
,
1029 CK_OBJECT_CLASS
class,
1030 CK_OBJECT_HANDLE
*ret_object
) {
1032 _cleanup_free_
void *buffer
= NULL
;
1033 CK_ATTRIBUTE attributes
[] = {
1034 { CKA_ID
, NULL_PTR
, 0 },
1035 { CKA_LABEL
, NULL_PTR
, 0 }
1037 CK_OBJECT_CLASS search_class
= class;
1038 CK_ATTRIBUTE search_attributes
[2] = {
1039 { CKA_CLASS
, &search_class
, sizeof(search_class
) }
1042 CK_OBJECT_HANDLE objects
[2];
1045 rv
= m
->C_GetAttributeValue(session
, prototype
, attributes
, ELEMENTSOF(attributes
));
1046 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
1047 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve length of attributes: %s", sym_p11_kit_strerror(rv
));
1049 if (attributes
[0].ulValueLen
!= CK_UNAVAILABLE_INFORMATION
) {
1050 buffer
= malloc(attributes
[0].ulValueLen
);
1054 attributes
[0].pValue
= buffer
;
1055 rv
= m
->C_GetAttributeValue(session
, prototype
, &attributes
[0], 1);
1057 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
1058 "Failed to retrieve CKA_ID: %s", sym_p11_kit_strerror(rv
));
1060 search_attributes
[1] = attributes
[0];
1062 } else if (attributes
[1].ulValueLen
!= CK_UNAVAILABLE_INFORMATION
) {
1063 buffer
= malloc(attributes
[1].ulValueLen
);
1067 attributes
[1].pValue
= buffer
;
1068 rv
= m
->C_GetAttributeValue(session
, prototype
, &attributes
[1], 1);
1070 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
1071 "Failed to retrieve CKA_LABEL: %s", sym_p11_kit_strerror(rv
));
1073 search_attributes
[1] = attributes
[1];
1076 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "The prototype does not have CKA_ID or CKA_LABEL");
1078 rv
= m
->C_FindObjectsInit(session
, search_attributes
, 2);
1080 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
1081 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv
));
1083 rv
= m
->C_FindObjects(session
, objects
, 2, &n_objects
);
1085 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
1086 "Failed to find objects: %s", sym_p11_kit_strerror(rv
));
1088 rv
= m
->C_FindObjectsFinal(session
);
1090 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
1091 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv
));
1094 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
1095 "Failed to find a related object with class %s", object_class_to_string(class));
1098 log_warning("Found multiple related objects with class %s, using the first object.",
1099 object_class_to_string(class));
1101 *ret_object
= objects
[0];
1106 static int ecc_convert_to_compressed(
1107 CK_FUNCTION_LIST
*m
,
1108 CK_SESSION_HANDLE session
,
1109 CK_OBJECT_HANDLE object
,
1110 const void *uncompressed_point
,
1111 size_t uncompressed_point_size
,
1112 void **ret_compressed_point
,
1113 size_t *ret_compressed_point_size
) {
1115 _cleanup_free_
void *ec_params_buffer
= NULL
;
1116 CK_ATTRIBUTE ec_params_attr
= { CKA_EC_PARAMS
, NULL_PTR
, 0 };
1120 rv
= m
->C_GetAttributeValue(session
, object
, &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 ec_params_buffer
= malloc(ec_params_attr
.ulValueLen
);
1127 if (!ec_params_buffer
)
1130 ec_params_attr
.pValue
= ec_params_buffer
;
1131 rv
= m
->C_GetAttributeValue(session
, object
, &ec_params_attr
, 1);
1133 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1134 "Failed to retrieve CKA_EC_PARAMS from a private key: %s", sym_p11_kit_strerror(rv
));
1136 CK_OBJECT_HANDLE public_key
;
1137 r
= pkcs11_token_find_related_object(m
, session
, object
, CKO_PUBLIC_KEY
, &public_key
);
1139 return log_error_errno(r
, "Failed to find a public key for compressing a EC point");
1141 ec_params_attr
.ulValueLen
= 0;
1142 rv
= m
->C_GetAttributeValue(session
, public_key
, &ec_params_attr
, 1);
1143 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
1144 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1145 "Failed to retrieve length of CKA_EC_PARAMS: %s", sym_p11_kit_strerror(rv
));
1147 if (ec_params_attr
.ulValueLen
== CK_UNAVAILABLE_INFORMATION
)
1148 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1149 "The public key does not have CKA_EC_PARAMS");
1151 ec_params_buffer
= malloc(ec_params_attr
.ulValueLen
);
1152 if (!ec_params_buffer
)
1155 ec_params_attr
.pValue
= ec_params_buffer
;
1156 rv
= m
->C_GetAttributeValue(session
, public_key
, &ec_params_attr
, 1);
1158 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1159 "Failed to retrieve CKA_EC_PARAMS from a public key: %s", sym_p11_kit_strerror(rv
));
1162 _cleanup_(EC_GROUP_freep
) EC_GROUP
*group
= NULL
;
1163 _cleanup_(EC_POINT_freep
) EC_POINT
*point
= NULL
;
1164 _cleanup_(BN_CTX_freep
) BN_CTX
*bnctx
= NULL
;
1165 _cleanup_free_
void *compressed_point
= NULL
;
1166 size_t compressed_point_size
;
1168 const unsigned char *ec_params_value
= ec_params_attr
.pValue
;
1169 group
= d2i_ECPKParameters(NULL
, &ec_params_value
, ec_params_attr
.ulValueLen
);
1171 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode CKA_EC_PARAMS");
1173 point
= EC_POINT_new(group
);
1177 bnctx
= BN_CTX_new();
1181 if (EC_POINT_oct2point(group
, point
, uncompressed_point
, uncompressed_point_size
, bnctx
) != 1)
1182 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode an uncompressed EC point");
1184 compressed_point_size
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
, NULL
, 0, bnctx
);
1185 if (compressed_point_size
== 0)
1186 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to determine size of a compressed EC point");
1188 compressed_point
= malloc(compressed_point_size
);
1189 if (!compressed_point
)
1192 compressed_point_size
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
, compressed_point
, compressed_point_size
, bnctx
);
1193 if (compressed_point_size
== 0)
1194 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to convert a EC point to compressed format");
1196 *ret_compressed_point
= TAKE_PTR(compressed_point
);
1197 *ret_compressed_point_size
= compressed_point_size
;
1202 /* Since EC keys doesn't support encryption directly, we use ECDH protocol to derive shared secret here.
1203 * We use PKCS#11 C_DeriveKey function to derive a shared secret with a private key stored in the token and
1204 * a public key saved on enrollment. */
1205 static int pkcs11_token_decrypt_data_ecc(
1206 CK_FUNCTION_LIST
*m
,
1207 CK_SESSION_HANDLE session
,
1208 CK_OBJECT_HANDLE object
,
1209 const void *encrypted_data
,
1210 size_t encrypted_data_size
,
1211 void **ret_decrypted_data
,
1212 size_t *ret_decrypted_data_size
) {
1214 static const CK_BBOOL yes
= CK_TRUE
, no
= CK_FALSE
;
1215 static const CK_OBJECT_CLASS shared_secret_class
= CKO_SECRET_KEY
;
1216 static const CK_KEY_TYPE shared_secret_type
= CKK_GENERIC_SECRET
;
1217 static const CK_ATTRIBUTE shared_secret_template
[] = {
1218 { CKA_TOKEN
, (void*) &no
, sizeof(no
) },
1219 { CKA_CLASS
, (void*) &shared_secret_class
, sizeof(shared_secret_class
) },
1220 { CKA_KEY_TYPE
, (void*) &shared_secret_type
, sizeof(shared_secret_type
) },
1221 { CKA_SENSITIVE
, (void*) &no
, sizeof(no
) },
1222 { CKA_EXTRACTABLE
, (void*) &yes
, sizeof(yes
) }
1224 CK_ECDH1_DERIVE_PARAMS params
= {
1226 .pPublicData
= (void*) encrypted_data
,
1227 .ulPublicDataLen
= encrypted_data_size
1229 CK_MECHANISM mechanism
= {
1230 .mechanism
= CKM_ECDH1_DERIVE
,
1231 .pParameter
= ¶ms
,
1232 .ulParameterLen
= sizeof(params
)
1234 CK_OBJECT_HANDLE shared_secret_handle
;
1235 CK_SESSION_INFO session_info
;
1236 CK_MECHANISM_INFO mechanism_info
;
1239 _cleanup_free_
void *compressed_point
= NULL
;
1243 rv
= m
->C_GetSessionInfo(session
, &session_info
);
1245 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1246 "Failed to get information about the PKCS#11 session: %s", sym_p11_kit_strerror(rv
));
1248 rv
= m
->C_GetMechanismInfo(session_info
.slotID
, CKM_ECDH1_DERIVE
, &mechanism_info
);
1250 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1251 "Failed to get information about CKM_ECDH1_DERIVE: %s", sym_p11_kit_strerror(rv
));
1253 if (!(mechanism_info
.flags
& CKF_EC_UNCOMPRESS
)) {
1254 if (mechanism_info
.flags
& CKF_EC_COMPRESS
) {
1256 log_debug("CKM_ECDH1_DERIVE accepts compressed EC points only, trying to convert.");
1257 size_t compressed_point_size
= 0; /* Explicit initialization to appease gcc */
1258 r
= ecc_convert_to_compressed(m
, session
, object
, encrypted_data
, encrypted_data_size
, &compressed_point
, &compressed_point_size
);
1262 params
.pPublicData
= compressed_point
;
1263 params
.ulPublicDataLen
= compressed_point_size
;
1265 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1266 "CKM_ECDH1_DERIVE does not support uncompressed format of EC points");
1269 log_debug("Both CKF_EC_UNCOMPRESS and CKF_EC_COMPRESS are false for CKM_ECDH1_DERIVE, ignoring.");
1272 rv
= m
->C_DeriveKey(session
, &mechanism
, object
, (CK_ATTRIBUTE
*) shared_secret_template
, ELEMENTSOF(shared_secret_template
), &shared_secret_handle
);
1274 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to derive a shared secret: %s", sym_p11_kit_strerror(rv
));
1276 CK_ATTRIBUTE shared_secret_attr
= { CKA_VALUE
, NULL_PTR
, 0};
1278 rv
= m
->C_GetAttributeValue(session
, shared_secret_handle
, &shared_secret_attr
, 1);
1280 rv2
= m
->C_DestroyObject(session
, shared_secret_handle
);
1282 log_warning("Failed to destroy a shared secret, ignoring: %s", sym_p11_kit_strerror(rv2
));
1283 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve shared secret length: %s", sym_p11_kit_strerror(rv
));
1286 shared_secret_attr
.pValue
= malloc(shared_secret_attr
.ulValueLen
);
1287 if (!shared_secret_attr
.pValue
)
1290 rv
= m
->C_GetAttributeValue(session
, shared_secret_handle
, &shared_secret_attr
, 1);
1291 rv2
= m
->C_DestroyObject(session
, shared_secret_handle
);
1293 log_warning("Failed to destroy a shared secret, ignoring: %s", sym_p11_kit_strerror(rv2
));
1296 erase_and_free(shared_secret_attr
.pValue
);
1297 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve a shared secret: %s", sym_p11_kit_strerror(rv
));
1300 log_info("Successfully derived key with security token.");
1302 *ret_decrypted_data
= shared_secret_attr
.pValue
;
1303 *ret_decrypted_data_size
= shared_secret_attr
.ulValueLen
;
1307 static int pkcs11_token_decrypt_data_rsa(
1308 CK_FUNCTION_LIST
*m
,
1309 CK_SESSION_HANDLE session
,
1310 CK_OBJECT_HANDLE object
,
1311 const void *encrypted_data
,
1312 size_t encrypted_data_size
,
1313 void **ret_decrypted_data
,
1314 size_t *ret_decrypted_data_size
) {
1316 static const CK_MECHANISM mechanism
= {
1317 .mechanism
= CKM_RSA_PKCS
1319 _cleanup_(erase_and_freep
) CK_BYTE
*dbuffer
= NULL
;
1320 CK_ULONG dbuffer_size
= 0;
1323 rv
= m
->C_DecryptInit(session
, (CK_MECHANISM
*) &mechanism
, object
);
1325 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1326 "Failed to initialize decryption on security token: %s", sym_p11_kit_strerror(rv
));
1328 dbuffer_size
= encrypted_data_size
; /* Start with something reasonable */
1329 dbuffer
= malloc(dbuffer_size
);
1333 rv
= m
->C_Decrypt(session
, (CK_BYTE
*) encrypted_data
, encrypted_data_size
, dbuffer
, &dbuffer_size
);
1334 if (rv
== CKR_BUFFER_TOO_SMALL
) {
1335 erase_and_free(dbuffer
);
1337 dbuffer
= malloc(dbuffer_size
);
1341 rv
= m
->C_Decrypt(session
, (CK_BYTE
*) encrypted_data
, encrypted_data_size
, dbuffer
, &dbuffer_size
);
1344 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1345 "Failed to decrypt key on security token: %s", sym_p11_kit_strerror(rv
));
1347 log_info("Successfully decrypted key with security token.");
1349 *ret_decrypted_data
= TAKE_PTR(dbuffer
);
1350 *ret_decrypted_data_size
= dbuffer_size
;
1354 int pkcs11_token_decrypt_data(
1355 CK_FUNCTION_LIST
*m
,
1356 CK_SESSION_HANDLE session
,
1357 CK_OBJECT_HANDLE object
,
1358 const void *encrypted_data
,
1359 size_t encrypted_data_size
,
1360 void **ret_decrypted_data
,
1361 size_t *ret_decrypted_data_size
) {
1363 CK_KEY_TYPE key_type
;
1364 CK_ATTRIBUTE key_type_template
= { CKA_KEY_TYPE
, &key_type
, sizeof(key_type
) };
1368 assert(encrypted_data
);
1369 assert(encrypted_data_size
> 0);
1370 assert(ret_decrypted_data
);
1371 assert(ret_decrypted_data_size
);
1373 rv
= m
->C_GetAttributeValue(session
, object
, &key_type_template
, 1);
1375 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve private key type");
1380 return pkcs11_token_decrypt_data_rsa(m
, session
, object
, encrypted_data
, encrypted_data_size
, ret_decrypted_data
, ret_decrypted_data_size
);
1383 return pkcs11_token_decrypt_data_ecc(m
, session
, object
, encrypted_data
, encrypted_data_size
, ret_decrypted_data
, ret_decrypted_data_size
);
1386 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Unsupported private key type: %lu", key_type
);
1390 int pkcs11_token_acquire_rng(
1391 CK_FUNCTION_LIST
*m
,
1392 CK_SESSION_HANDLE session
) {
1394 _cleanup_free_
void *buffer
= NULL
;
1401 r
= dlopen_p11kit();
1405 /* While we are at it, let's read some RNG data from the PKCS#11 token and pass it to the kernel
1406 * random pool. This should be cheap if we are talking to the device already. Note that we don't
1407 * credit any entropy, since we don't know about the quality of the pkcs#11 token's RNG. Why bother
1408 * at all? There are two sides to the argument whether to generate private keys on tokens or on the
1409 * host. By crediting some data from the token RNG to the host's pool we at least can say that any
1410 * key generated from it is at least as good as both sources individually. */
1412 rps
= random_pool_size();
1414 buffer
= malloc(rps
);
1418 rv
= m
->C_GenerateRandom(session
, buffer
, rps
);
1420 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1421 "Failed to generate RNG data on security token: %s", sym_p11_kit_strerror(rv
));
1423 r
= random_write_entropy(-1, buffer
, rps
, false);
1425 return log_debug_errno(r
, "Failed to write PKCS#11 acquired random data to /dev/urandom: %m");
1427 log_debug("Successfully written %zu bytes random data acquired via PKCS#11 to kernel random pool.", rps
);
1432 static int token_process(
1433 CK_FUNCTION_LIST
*m
,
1435 const CK_SLOT_INFO
*slot_info
,
1436 const CK_TOKEN_INFO
*token_info
,
1437 P11KitUri
*search_uri
,
1438 pkcs11_find_token_callback_t callback
,
1441 _cleanup_free_
char *token_label
= NULL
;
1442 CK_SESSION_HANDLE session
;
1450 token_label
= pkcs11_token_label(token_info
);
1454 rv
= m
->C_OpenSession(slotid
, CKF_SERIAL_SESSION
, NULL
, NULL
, &session
);
1456 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1457 "Failed to create session for security token '%s': %s", token_label
, sym_p11_kit_strerror(rv
));
1460 r
= callback(m
, session
, slotid
, slot_info
, token_info
, search_uri
, userdata
);
1462 r
= 1; /* if not callback was specified, just say we found what we were looking for */
1464 rv
= m
->C_CloseSession(session
);
1466 log_warning("Failed to close session on PKCS#11 token, ignoring: %s", sym_p11_kit_strerror(rv
));
1471 static int slot_process(
1472 CK_FUNCTION_LIST
*m
,
1474 P11KitUri
*search_uri
,
1475 pkcs11_find_token_callback_t callback
,
1478 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
* slot_uri
= NULL
, *token_uri
= NULL
;
1479 _cleanup_free_
char *token_uri_string
= NULL
;
1480 CK_TOKEN_INFO token_info
;
1481 CK_SLOT_INFO slot_info
;
1487 r
= dlopen_p11kit();
1491 /* We return -EAGAIN for all failures we can attribute to a specific slot in some way, so that the
1492 * caller might try other slots before giving up. */
1494 rv
= m
->C_GetSlotInfo(slotid
, &slot_info
);
1496 log_warning("Failed to acquire slot info for slot %lu, ignoring slot: %s", slotid
, sym_p11_kit_strerror(rv
));
1500 slot_uri
= uri_from_slot_info(&slot_info
);
1504 if (DEBUG_LOGGING
) {
1505 _cleanup_free_
char *slot_uri_string
= NULL
;
1507 uri_result
= sym_p11_kit_uri_format(slot_uri
, P11_KIT_URI_FOR_ANY
, &slot_uri_string
);
1508 if (uri_result
!= P11_KIT_URI_OK
) {
1509 log_warning("Failed to format slot URI, ignoring slot: %s", sym_p11_kit_uri_message(uri_result
));
1513 log_debug("Found slot with URI %s", slot_uri_string
);
1516 rv
= m
->C_GetTokenInfo(slotid
, &token_info
);
1517 if (rv
== CKR_TOKEN_NOT_PRESENT
) {
1518 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN
),
1519 "Token not present in slot, ignoring.");
1520 } else if (rv
!= CKR_OK
) {
1521 log_warning("Failed to acquire token info for slot %lu, ignoring slot: %s", slotid
, sym_p11_kit_strerror(rv
));
1525 token_uri
= uri_from_token_info(&token_info
);
1529 uri_result
= sym_p11_kit_uri_format(token_uri
, P11_KIT_URI_FOR_ANY
, &token_uri_string
);
1530 if (uri_result
!= P11_KIT_URI_OK
) {
1531 log_warning("Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result
));
1535 if (search_uri
&& !sym_p11_kit_uri_match_token_info(search_uri
, &token_info
))
1536 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN
),
1537 "Found non-matching token with URI %s.",
1540 log_debug("Found matching token with URI %s.", token_uri_string
);
1542 return token_process(
1552 static int module_process(
1553 CK_FUNCTION_LIST
*m
,
1554 P11KitUri
*search_uri
,
1555 pkcs11_find_token_callback_t callback
,
1558 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
* module_uri
= NULL
;
1559 _cleanup_free_
char *name
= NULL
, *module_uri_string
= NULL
;
1560 _cleanup_free_ CK_SLOT_ID
*slotids
= NULL
;
1561 CK_ULONG n_slotids
= 0;
1570 r
= dlopen_p11kit();
1574 /* We ignore most errors from modules here, in order to skip over faulty modules: one faulty module
1575 * should not have the effect that we don't try the others anymore. We indicate such per-module
1576 * failures with -EAGAIN, which let's the caller try the next module. */
1578 name
= sym_p11_kit_module_get_name(m
);
1582 log_debug("Trying PKCS#11 module %s.", name
);
1584 rv
= m
->C_GetInfo(&info
);
1586 log_warning("Failed to get info on PKCS#11 module, ignoring module: %s", sym_p11_kit_strerror(rv
));
1590 module_uri
= uri_from_module_info(&info
);
1594 uri_result
= sym_p11_kit_uri_format(module_uri
, P11_KIT_URI_FOR_ANY
, &module_uri_string
);
1595 if (uri_result
!= P11_KIT_URI_OK
) {
1596 log_warning("Failed to format module URI, ignoring module: %s", sym_p11_kit_uri_message(uri_result
));
1600 log_debug("Found module with URI %s", module_uri_string
);
1602 rv
= pkcs11_get_slot_list_malloc(m
, &slotids
, &n_slotids
);
1604 log_warning("Failed to get slot list, ignoring module: %s", sym_p11_kit_strerror(rv
));
1608 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN
),
1609 "This module has no slots? Ignoring module.");
1611 for (k
= 0; k
< n_slotids
; k
++) {
1625 int pkcs11_find_token(
1626 const char *pkcs11_uri
,
1627 pkcs11_find_token_callback_t callback
,
1630 _cleanup_(sym_p11_kit_modules_finalize_and_releasep
) CK_FUNCTION_LIST
**modules
= NULL
;
1631 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*search_uri
= NULL
;
1634 r
= dlopen_p11kit();
1638 /* Execute the specified callback for each matching token found. If nothing is found returns
1639 * -EAGAIN. Logs about all errors, except for EAGAIN, which the caller has to log about. */
1642 r
= uri_from_string(pkcs11_uri
, &search_uri
);
1644 return log_error_errno(r
, "Failed to parse PKCS#11 URI '%s': %m", pkcs11_uri
);
1647 modules
= sym_p11_kit_modules_load_and_initialize(0);
1649 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to initialize pkcs11 modules");
1651 for (CK_FUNCTION_LIST
**i
= modules
; *i
; i
++) {
1665 struct pkcs11_acquire_public_key_callback_data
{
1668 const char *askpw_friendly_name
, *askpw_icon
, *askpw_credential
;
1669 AskPasswordFlags askpw_flags
;
1672 static void pkcs11_acquire_public_key_callback_data_release(struct pkcs11_acquire_public_key_callback_data
*data
) {
1673 erase_and_free(data
->pin_used
);
1674 EVP_PKEY_free(data
->pkey
);
1677 static int pkcs11_acquire_public_key_callback(
1678 CK_FUNCTION_LIST
*m
,
1679 CK_SESSION_HANDLE session
,
1681 const CK_SLOT_INFO
*slot_info
,
1682 const CK_TOKEN_INFO
*token_info
,
1686 _cleanup_(erase_and_freep
) char *pin_used
= NULL
;
1687 _cleanup_(EVP_PKEY_freep
) EVP_PKEY
*pkey
= NULL
;
1688 CK_OBJECT_CLASS
class;
1689 CK_CERTIFICATE_TYPE type
;
1690 CK_ATTRIBUTE candidate_attributes
[] = {
1691 { CKA_CLASS
, &class, sizeof(class) },
1692 { CKA_CERTIFICATE_TYPE
, &type
, sizeof(type
) },
1694 CK_OBJECT_HANDLE candidate
, public_key
= CK_INVALID_HANDLE
, certificate
= CK_INVALID_HANDLE
;
1695 uint8_t n_public_keys
= 0, n_certificates
= 0;
1704 struct pkcs11_acquire_public_key_callback_data
*data
= ASSERT_PTR(userdata
);
1706 /* Called for every token matching our URI */
1708 r
= pkcs11_token_login(
1713 data
->askpw_friendly_name
,
1716 data
->askpw_credential
,
1723 CK_ULONG n_attributes
;
1724 CK_ATTRIBUTE
*attributes
= sym_p11_kit_uri_get_attributes(uri
, &n_attributes
);
1725 for (CK_ULONG i
= 0; i
< n_attributes
; i
++) {
1726 switch (attributes
[i
].type
) {
1728 CK_OBJECT_CLASS requested_class
= *((CK_OBJECT_CLASS
*) attributes
[i
].pValue
);
1729 if (!IN_SET(requested_class
, CKO_PUBLIC_KEY
, CKO_CERTIFICATE
))
1730 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1731 "Selected PKCS#11 object is not a public key or certificate, refusing.");
1735 case CKA_CERTIFICATE_TYPE
: {
1736 CK_CERTIFICATE_TYPE requested_type
= *((CK_CERTIFICATE_TYPE
*) attributes
[i
].pValue
);
1737 if (requested_type
!= CKC_X_509
)
1738 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Selected PKCS#11 object is not an X.509 certificate, refusing.");
1743 rv
= m
->C_FindObjectsInit(session
, attributes
, n_attributes
);
1745 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1746 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv
));
1750 rv
= m
->C_FindObjects(session
, &candidate
, 1, &n
);
1752 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1753 "Failed to find objects: %s", sym_p11_kit_strerror(rv
));
1758 candidate_attributes
[0].ulValueLen
= sizeof(class);
1759 candidate_attributes
[1].ulValueLen
= sizeof(type
);
1760 rv
= m
->C_GetAttributeValue(session
, candidate
, candidate_attributes
, ELEMENTSOF(candidate_attributes
));
1761 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
1762 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1763 "Failed to get attributes of a selected candidate: %s", sym_p11_kit_strerror(rv
));
1765 if (candidate_attributes
[0].ulValueLen
== CK_UNAVAILABLE_INFORMATION
) {
1766 log_debug("Failed to get CKA_CLASS of a selected candidate");
1770 if (class == CKO_PUBLIC_KEY
) {
1772 if (n_public_keys
> 1)
1774 public_key
= candidate
;
1778 if (class == CKO_CERTIFICATE
) {
1779 if (candidate_attributes
[1].ulValueLen
== CK_UNAVAILABLE_INFORMATION
) {
1780 log_debug("Failed to get CKA_CERTIFICATE_TYPE of a selected candidate");
1783 if (type
!= CKC_X_509
)
1786 if (n_certificates
> 1)
1788 certificate
= candidate
;
1793 rv
= m
->C_FindObjectsFinal(session
);
1795 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1796 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv
));
1798 if (n_public_keys
== 0 && n_certificates
== 0)
1799 return log_error_errno(SYNTHETIC_ERRNO(ENOENT
),
1800 "Failed to find selected public key or X.509 certificate.");
1802 if (n_public_keys
> 1)
1803 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
1804 "Provided URI matches multiple public keys, refusing.");
1806 if (n_certificates
> 1)
1807 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
1808 "Provided URI matches multiple certificates, refusing.");
1810 if (n_public_keys
!= 0) {
1811 r
= pkcs11_token_read_public_key(m
, session
, public_key
, &pkey
);
1816 if (n_certificates
== 0)
1817 return log_error_errno(r
, "Failed to read a found public key.");
1820 _cleanup_(X509_freep
) X509
*cert
= NULL
;
1822 r
= pkcs11_token_read_x509_certificate(m
, session
, certificate
, &cert
);
1824 return log_error_errno(r
, "Failed to read a found X.509 certificate.");
1826 pkey
= X509_get_pubkey(cert
);
1828 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to extract public key from X.509 certificate.");
1831 /* Let's read some random data off the token and write it to the kernel pool before we generate our
1832 * random key from it. This way we can claim the quality of the RNG is at least as good as the
1833 * kernel's and the token's pool */
1834 (void) pkcs11_token_acquire_rng(m
, session
);
1836 data
->pin_used
= TAKE_PTR(pin_used
);
1837 data
->pkey
= TAKE_PTR(pkey
);
1841 int pkcs11_acquire_public_key(
1843 const char *askpw_friendly_name
,
1844 const char *askpw_icon
,
1845 const char *askpw_credential
,
1846 AskPasswordFlags askpw_flags
,
1847 EVP_PKEY
**ret_pkey
,
1848 char **ret_pin_used
) {
1850 _cleanup_(pkcs11_acquire_public_key_callback_data_release
) struct pkcs11_acquire_public_key_callback_data data
= {
1851 .askpw_friendly_name
= askpw_friendly_name
,
1852 .askpw_icon
= askpw_icon
,
1853 .askpw_credential
= askpw_credential
,
1854 .askpw_flags
= askpw_flags
,
1861 r
= pkcs11_find_token(uri
, pkcs11_acquire_public_key_callback
, &data
);
1862 if (r
== -EAGAIN
) /* pkcs11_find_token() doesn't log about this error, but all others */
1863 return log_error_errno(SYNTHETIC_ERRNO(ENXIO
),
1864 "Specified PKCS#11 token with URI '%s' not found.",
1869 *ret_pkey
= TAKE_PTR(data
.pkey
);
1871 *ret_pin_used
= TAKE_PTR(data
.pin_used
);
1876 static int list_callback(
1877 CK_FUNCTION_LIST
*m
,
1878 CK_SESSION_HANDLE session
,
1880 const CK_SLOT_INFO
*slot_info
,
1881 const CK_TOKEN_INFO
*token_info
,
1885 _cleanup_free_
char *token_uri_string
= NULL
, *token_label
= NULL
, *token_manufacturer_id
= NULL
, *token_model
= NULL
;
1886 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*token_uri
= NULL
;
1887 Table
*t
= userdata
;
1893 r
= dlopen_p11kit();
1897 /* We only care about hardware devices here with a token inserted. Let's filter everything else
1898 * out. (Note that the user can explicitly specify non-hardware tokens if they like, but during
1899 * enumeration we'll filter those, since software tokens are typically the system certificate store
1900 * and such, and it's typically not what people want to bind their home directories to.) */
1901 if (!FLAGS_SET(slot_info
->flags
, CKF_HW_SLOT
|CKF_TOKEN_PRESENT
))
1904 token_label
= pkcs11_token_label(token_info
);
1908 token_manufacturer_id
= pkcs11_token_manufacturer_id(token_info
);
1909 if (!token_manufacturer_id
)
1912 token_model
= pkcs11_token_model(token_info
);
1916 token_uri
= uri_from_token_info(token_info
);
1920 uri_result
= sym_p11_kit_uri_format(token_uri
, P11_KIT_URI_FOR_ANY
, &token_uri_string
);
1921 if (uri_result
!= P11_KIT_URI_OK
)
1922 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN
), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result
));
1926 TABLE_STRING
, token_uri_string
,
1927 TABLE_STRING
, token_label
,
1928 TABLE_STRING
, token_manufacturer_id
,
1929 TABLE_STRING
, token_model
);
1931 return table_log_add_error(r
);
1933 return -EAGAIN
; /* keep scanning */
1937 int pkcs11_list_tokens(void) {
1939 _cleanup_(table_unrefp
) Table
*t
= NULL
;
1942 t
= table_new("uri", "label", "manufacturer", "model");
1946 r
= pkcs11_find_token(NULL
, list_callback
, t
);
1947 if (r
< 0 && r
!= -EAGAIN
)
1950 if (table_isempty(t
)) {
1951 log_info("No suitable PKCS#11 tokens found.");
1955 r
= table_print(t
, stdout
);
1957 return log_error_errno(r
, "Failed to show device table: %m");
1961 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1962 "PKCS#11 tokens not supported on this build.");
1967 static int auto_callback(
1968 CK_FUNCTION_LIST
*m
,
1969 CK_SESSION_HANDLE session
,
1971 const CK_SLOT_INFO
*slot_info
,
1972 const CK_TOKEN_INFO
*token_info
,
1976 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*token_uri
= NULL
;
1977 char **t
= userdata
;
1983 r
= dlopen_p11kit();
1987 if (!FLAGS_SET(token_info
->flags
, CKF_HW_SLOT
|CKF_TOKEN_PRESENT
))
1991 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
1992 "More than one suitable PKCS#11 token found.");
1994 token_uri
= uri_from_token_info(token_info
);
1998 uri_result
= sym_p11_kit_uri_format(token_uri
, P11_KIT_URI_FOR_ANY
, t
);
1999 if (uri_result
!= P11_KIT_URI_OK
)
2000 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN
), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result
));
2006 int pkcs11_find_token_auto(char **ret
) {
2010 r
= pkcs11_find_token(NULL
, auto_callback
, ret
);
2012 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "No suitable PKCS#11 tokens found.");
2018 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
2019 "PKCS#11 tokens not supported on this build.");
2024 void pkcs11_crypt_device_callback_data_release(pkcs11_crypt_device_callback_data
*data
) {
2025 erase_and_free(data
->decrypted_key
);
2027 if (data
->free_encrypted_key
)
2028 free(data
->encrypted_key
);
2031 int pkcs11_crypt_device_callback(
2032 CK_FUNCTION_LIST
*m
,
2033 CK_SESSION_HANDLE session
,
2035 const CK_SLOT_INFO
*slot_info
,
2036 const CK_TOKEN_INFO
*token_info
,
2040 pkcs11_crypt_device_callback_data
*data
= ASSERT_PTR(userdata
);
2041 CK_OBJECT_HANDLE object
;
2049 /* Called for every token matching our URI */
2051 r
= pkcs11_token_login(
2056 data
->friendly_name
,
2059 data
->askpw_credential
,
2066 /* We are likely called during early boot, where entropy is scarce. Mix some data from the PKCS#11
2067 * token, if it supports that. It should be cheap, given that we already are talking to it anyway and
2068 * shouldn't hurt. */
2069 (void) pkcs11_token_acquire_rng(m
, session
);
2071 r
= pkcs11_token_find_private_key(m
, session
, uri
, &object
);
2075 r
= pkcs11_token_decrypt_data(
2079 data
->encrypted_key
,
2080 data
->encrypted_key_size
,
2081 &data
->decrypted_key
,
2082 &data
->decrypted_key_size
);