1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "ask-password-api.h"
5 #include "dlfcn-util.h"
8 #include "format-table.h"
10 #include "memory-util.h"
11 #include "openssl-util.h"
12 #include "pkcs11-util.h"
13 #include "random-util.h"
14 #include "string-util.h"
17 bool pkcs11_uri_valid(const char *uri
) {
20 /* A very superficial checker for RFC7512 PKCS#11 URI syntax */
25 p
= startswith(uri
, "pkcs11:");
32 if (!in_charset(p
, ALPHANUMERICAL
".~/-_?;&%="))
40 static void *p11kit_dl
= NULL
;
42 DLSYM_PROTOTYPE(p11_kit_module_get_name
) = NULL
;
43 DLSYM_PROTOTYPE(p11_kit_modules_finalize_and_release
) = NULL
;
44 DLSYM_PROTOTYPE(p11_kit_modules_load_and_initialize
) = NULL
;
45 DLSYM_PROTOTYPE(p11_kit_strerror
) = NULL
;
46 DLSYM_PROTOTYPE(p11_kit_uri_format
) = NULL
;
47 DLSYM_PROTOTYPE(p11_kit_uri_free
) = NULL
;
48 DLSYM_PROTOTYPE(p11_kit_uri_get_attributes
) = NULL
;
49 DLSYM_PROTOTYPE(p11_kit_uri_get_attribute
) = NULL
;
50 DLSYM_PROTOTYPE(p11_kit_uri_set_attribute
) = NULL
;
51 DLSYM_PROTOTYPE(p11_kit_uri_get_module_info
) = NULL
;
52 DLSYM_PROTOTYPE(p11_kit_uri_get_slot_info
) = NULL
;
53 DLSYM_PROTOTYPE(p11_kit_uri_get_token_info
) = NULL
;
54 DLSYM_PROTOTYPE(p11_kit_uri_match_token_info
) = NULL
;
55 DLSYM_PROTOTYPE(p11_kit_uri_message
) = NULL
;
56 DLSYM_PROTOTYPE(p11_kit_uri_new
) = NULL
;
57 DLSYM_PROTOTYPE(p11_kit_uri_parse
) = NULL
;
59 int uri_from_string(const char *p
, P11KitUri
**ret
) {
60 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*uri
= NULL
;
70 uri
= sym_p11_kit_uri_new();
74 if (sym_p11_kit_uri_parse(p
, P11_KIT_URI_FOR_ANY
, uri
) != P11_KIT_URI_OK
)
81 P11KitUri
*uri_from_module_info(const CK_INFO
*info
) {
86 if (dlopen_p11kit() < 0)
89 uri
= sym_p11_kit_uri_new();
93 *sym_p11_kit_uri_get_module_info(uri
) = *info
;
97 P11KitUri
*uri_from_slot_info(const CK_SLOT_INFO
*slot_info
) {
102 if (dlopen_p11kit() < 0)
105 uri
= sym_p11_kit_uri_new();
109 *sym_p11_kit_uri_get_slot_info(uri
) = *slot_info
;
113 P11KitUri
*uri_from_token_info(const CK_TOKEN_INFO
*token_info
) {
118 if (dlopen_p11kit() < 0)
121 uri
= sym_p11_kit_uri_new();
125 *sym_p11_kit_uri_get_token_info(uri
) = *token_info
;
129 CK_RV
pkcs11_get_slot_list_malloc(
131 CK_SLOT_ID
**ret_slotids
,
132 CK_ULONG
*ret_n_slotids
) {
138 assert(ret_n_slotids
);
140 for (unsigned tries
= 0; tries
< 16; tries
++) {
141 _cleanup_free_ CK_SLOT_ID
*slotids
= NULL
;
142 CK_ULONG n_slotids
= 0;
144 rv
= m
->C_GetSlotList(0, NULL
, &n_slotids
);
147 if (n_slotids
== 0) {
153 slotids
= new(CK_SLOT_ID
, n_slotids
);
155 return CKR_HOST_MEMORY
;
157 rv
= m
->C_GetSlotList(0, slotids
, &n_slotids
);
159 *ret_slotids
= TAKE_PTR(slotids
);
160 *ret_n_slotids
= n_slotids
;
164 if (rv
!= CKR_BUFFER_TOO_SMALL
)
167 /* Hu? Maybe somebody plugged something in and things changed? Let's try again */
170 return CKR_BUFFER_TOO_SMALL
;
173 char* pkcs11_token_label(const CK_TOKEN_INFO
*token_info
) {
176 /* The label is not NUL terminated and likely padded with spaces, let's make a copy here, so that we
178 t
= strndup((char*) token_info
->label
, sizeof(token_info
->label
));
186 char* pkcs11_token_manufacturer_id(const CK_TOKEN_INFO
*token_info
) {
189 t
= strndup((char*) token_info
->manufacturerID
, sizeof(token_info
->manufacturerID
));
197 char* pkcs11_token_model(const CK_TOKEN_INFO
*token_info
) {
200 t
= strndup((char*) token_info
->model
, sizeof(token_info
->model
));
208 int pkcs11_token_login_by_pin(
210 CK_SESSION_HANDLE session
,
211 const CK_TOKEN_INFO
*token_info
,
212 const char *token_label
,
226 if (FLAGS_SET(token_info
->flags
, CKF_PROTECTED_AUTHENTICATION_PATH
)) {
227 rv
= m
->C_Login(session
, CKU_USER
, NULL
, 0);
229 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
230 "Failed to log into security token '%s': %s", token_label
, sym_p11_kit_strerror(rv
));
232 log_info("Successfully logged into security token '%s' via protected authentication path.", token_label
);
236 if (!FLAGS_SET(token_info
->flags
, CKF_LOGIN_REQUIRED
)) {
237 log_info("No login into security token '%s' required.", token_label
);
244 rv
= m
->C_Login(session
, CKU_USER
, (CK_UTF8CHAR
*) pin
, pin_size
);
246 log_info("Successfully logged into security token '%s'.", token_label
);
250 if (rv
== CKR_PIN_LOCKED
)
251 return log_error_errno(SYNTHETIC_ERRNO(EPERM
),
252 "PIN has been locked, please reset PIN of security token '%s'.", token_label
);
253 if (!IN_SET(rv
, CKR_PIN_INCORRECT
, CKR_PIN_LEN_RANGE
))
254 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
255 "Failed to log into security token '%s': %s", token_label
, sym_p11_kit_strerror(rv
));
257 return log_notice_errno(SYNTHETIC_ERRNO(ENOLCK
),
258 "PIN for token '%s' is incorrect, please try again.",
262 int pkcs11_token_login(
264 CK_SESSION_HANDLE session
,
266 const CK_TOKEN_INFO
*token_info
,
267 const char *friendly_name
,
268 const char *askpw_icon
,
269 const char *askpw_keyring
,
270 const char *askpw_credential
,
272 AskPasswordFlags askpw_flags
,
273 char **ret_used_pin
) {
275 _cleanup_free_
char *token_uri_string
= NULL
, *token_uri_escaped
= NULL
, *id
= NULL
, *token_label
= NULL
;
276 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*token_uri
= NULL
;
277 CK_TOKEN_INFO updated_token_info
;
288 token_label
= pkcs11_token_label(token_info
);
292 token_uri
= uri_from_token_info(token_info
);
296 uri_result
= sym_p11_kit_uri_format(token_uri
, P11_KIT_URI_FOR_ANY
, &token_uri_string
);
297 if (uri_result
!= P11_KIT_URI_OK
)
298 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN
), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result
));
300 r
= pkcs11_token_login_by_pin(m
, session
, token_info
, token_label
, /* pin= */ NULL
, 0);
301 if (r
== 0 && ret_used_pin
)
302 *ret_used_pin
= NULL
;
304 if (r
!= -ENOANO
) /* pin required */
307 token_uri_escaped
= cescape(token_uri_string
);
308 if (!token_uri_escaped
)
311 id
= strjoin("pkcs11:", token_uri_escaped
);
315 for (unsigned tries
= 0; tries
< 3; tries
++) {
316 _cleanup_strv_free_erase_
char **passwords
= NULL
;
317 _cleanup_(erase_and_freep
) char *envpin
= NULL
;
319 r
= getenv_steal_erase("PIN", &envpin
);
321 return log_error_errno(r
, "Failed to acquire PIN from environment: %m");
323 passwords
= strv_new(envpin
);
327 } else if (FLAGS_SET(askpw_flags
, ASK_PASSWORD_HEADLESS
))
328 return log_error_errno(SYNTHETIC_ERRNO(ENOPKG
), "PIN querying disabled via 'headless' option. Use the 'PIN' environment variable.");
330 _cleanup_free_
char *text
= NULL
;
332 if (FLAGS_SET(token_info
->flags
, CKF_USER_PIN_FINAL_TRY
))
334 "Please enter correct PIN for security token '%s' in order to unlock %s (final try):",
335 token_label
, friendly_name
);
336 else if (FLAGS_SET(token_info
->flags
, CKF_USER_PIN_COUNT_LOW
))
338 "PIN has been entered incorrectly previously, please enter correct PIN for security token '%s' in order to unlock %s:",
339 token_label
, friendly_name
);
342 "Please enter PIN for security token '%s' in order to unlock %s:",
343 token_label
, friendly_name
);
346 "Please enter PIN for security token '%s' in order to unlock %s (try #%u):",
347 token_label
, friendly_name
, tries
+1);
351 AskPasswordRequest req
= {
356 .keyring
= askpw_keyring
,
357 .credential
= askpw_credential
,
362 /* We never cache PINs, simply because it's fatal if we use wrong PINs, since usually there are only 3 tries */
363 r
= ask_password_auto(&req
, askpw_flags
, &passwords
);
365 return log_error_errno(r
, "Failed to query PIN for security token '%s': %m", token_label
);
368 STRV_FOREACH(i
, passwords
) {
369 r
= pkcs11_token_login_by_pin(m
, session
, token_info
, token_label
, *i
, strlen(*i
));
370 if (r
== 0 && ret_used_pin
) {
383 /* Refresh the token info, so that we can prompt knowing the new flags if they changed. */
384 rv
= m
->C_GetTokenInfo(slotid
, &updated_token_info
);
386 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
387 "Failed to acquire updated security token information for slot %lu: %s",
388 slotid
, sym_p11_kit_strerror(rv
));
390 token_info
= &updated_token_info
;
394 return log_error_errno(SYNTHETIC_ERRNO(EPERM
), "Too many attempts to log into token '%s'.", token_label
);
398 static int read_public_key_info(
400 CK_SESSION_HANDLE session
,
401 CK_OBJECT_HANDLE object
,
402 EVP_PKEY
**ret_pkey
) {
404 CK_ATTRIBUTE attribute
= { CKA_PUBLIC_KEY_INFO
, NULL_PTR
, 0 };
405 _cleanup_(EVP_PKEY_freep
) EVP_PKEY
*pkey
= NULL
;
408 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
410 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
),
411 "Failed to get size of CKA_PUBLIC_KEY_INFO: %s", sym_p11_kit_strerror(rv
));
413 if (attribute
.ulValueLen
== 0)
414 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
), "CKA_PUBLIC_KEY_INFO is empty");
416 _cleanup_free_
void *buffer
= malloc(attribute
.ulValueLen
);
418 return log_oom_debug();
420 attribute
.pValue
= buffer
;
422 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
424 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
425 "Failed to read CKA_PUBLIC_KEY_INFO: %s", sym_p11_kit_strerror(rv
));
427 const unsigned char *value
= attribute
.pValue
;
428 pkey
= d2i_PUBKEY(NULL
, &value
, attribute
.ulValueLen
);
430 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG
), "Failed to parse CKA_PUBLIC_KEY_INFO");
432 *ret_pkey
= TAKE_PTR(pkey
);
436 int pkcs11_token_read_public_key(
438 CK_SESSION_HANDLE session
,
439 CK_OBJECT_HANDLE object
,
440 EVP_PKEY
**ret_pkey
) {
442 _cleanup_(EVP_PKEY_freep
) EVP_PKEY
*pkey
= NULL
;
446 r
= read_public_key_info(m
, session
, object
, &pkey
);
448 *ret_pkey
= TAKE_PTR(pkey
);
452 CK_KEY_TYPE key_type
;
453 CK_ATTRIBUTE attribute
= { CKA_KEY_TYPE
, &key_type
, sizeof(key_type
) };
455 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
457 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
458 "Failed to get CKA_KEY_TYPE of a public key: %s", sym_p11_kit_strerror(rv
));
462 CK_ATTRIBUTE rsa_attributes
[] = {
463 { CKA_MODULUS
, NULL_PTR
, 0 },
464 { CKA_PUBLIC_EXPONENT
, NULL_PTR
, 0 },
467 rv
= m
->C_GetAttributeValue(session
, object
, rsa_attributes
, ELEMENTSOF(rsa_attributes
));
469 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
470 "Failed to get size of attributes of an RSA public key: %s", sym_p11_kit_strerror(rv
));
472 if (rsa_attributes
[0].ulValueLen
== 0)
473 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "An RSA public key has empty CKA_MODULUS.");
475 _cleanup_free_
void *modulus
= malloc(rsa_attributes
[0].ulValueLen
);
477 return log_oom_debug();
479 rsa_attributes
[0].pValue
= modulus
;
481 if (rsa_attributes
[1].ulValueLen
== 0)
482 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "An RSA public key has empty CKA_PUBLIC_EXPONENT.");
484 _cleanup_free_
void *public_exponent
= malloc(rsa_attributes
[1].ulValueLen
);
485 if (!public_exponent
)
486 return log_oom_debug();
488 rsa_attributes
[1].pValue
= public_exponent
;
490 rv
= m
->C_GetAttributeValue(session
, object
, rsa_attributes
, ELEMENTSOF(rsa_attributes
));
492 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
493 "Failed to get attributes of an RSA public key: %s", sym_p11_kit_strerror(rv
));
495 size_t n_size
= rsa_attributes
[0].ulValueLen
, e_size
= rsa_attributes
[1].ulValueLen
;
496 r
= rsa_pkey_from_n_e(rsa_attributes
[0].pValue
, n_size
, rsa_attributes
[1].pValue
, e_size
, &pkey
);
498 return log_debug_errno(r
, "Failed to create an EVP_PKEY from RSA parameters.");
503 CK_ATTRIBUTE ec_attributes
[] = {
504 { CKA_EC_PARAMS
, NULL_PTR
, 0 },
505 { CKA_EC_POINT
, NULL_PTR
, 0 },
508 rv
= m
->C_GetAttributeValue(session
, object
, ec_attributes
, ELEMENTSOF(ec_attributes
));
510 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
511 "Failed to get size of attributes of an EC public key: %s", sym_p11_kit_strerror(rv
));
513 if (ec_attributes
[0].ulValueLen
== 0)
514 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "An EC public key has empty CKA_EC_PARAMS.");
516 _cleanup_free_
void *ec_group
= malloc(ec_attributes
[0].ulValueLen
);
518 return log_oom_debug();
520 ec_attributes
[0].pValue
= ec_group
;
522 if (ec_attributes
[1].ulValueLen
== 0)
523 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "An EC public key has empty CKA_EC_POINT.");
525 _cleanup_free_
void *ec_point
= malloc(ec_attributes
[1].ulValueLen
);
527 return log_oom_debug();
529 ec_attributes
[1].pValue
= ec_point
;
531 rv
= m
->C_GetAttributeValue(session
, object
, ec_attributes
, ELEMENTSOF(ec_attributes
));
533 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
534 "Failed to get attributes of an EC public key: %s", sym_p11_kit_strerror(rv
));
536 _cleanup_(EC_GROUP_freep
) EC_GROUP
*group
= NULL
;
537 _cleanup_(ASN1_OCTET_STRING_freep
) ASN1_OCTET_STRING
*os
= NULL
;
539 const unsigned char *ec_params_value
= ec_attributes
[0].pValue
;
540 group
= d2i_ECPKParameters(NULL
, &ec_params_value
, ec_attributes
[0].ulValueLen
);
542 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode CKA_EC_PARAMS.");
544 const unsigned char *ec_point_value
= ec_attributes
[1].pValue
;
545 os
= d2i_ASN1_OCTET_STRING(NULL
, &ec_point_value
, ec_attributes
[1].ulValueLen
);
547 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode CKA_EC_POINT.");
549 #if OPENSSL_VERSION_MAJOR >= 3
550 _cleanup_(EVP_PKEY_CTX_freep
) EVP_PKEY_CTX
*ctx
= EVP_PKEY_CTX_new_from_name(NULL
, "EC", NULL
);
552 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to create an EVP_PKEY_CTX for EC.");
554 if (EVP_PKEY_fromdata_init(ctx
) != 1)
555 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to init an EVP_PKEY_CTX for EC.");
557 OSSL_PARAM ec_params
[8] = {
558 OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY
, os
->data
, os
->length
)
561 _cleanup_free_
void *order
= NULL
, *p
= NULL
, *a
= NULL
, *b
= NULL
, *generator
= NULL
;
562 size_t order_size
, p_size
, a_size
, b_size
, generator_size
;
564 int nid
= EC_GROUP_get_curve_name(group
);
565 if (nid
!= NID_undef
) {
566 const char* name
= OSSL_EC_curve_nid2name(nid
);
567 ec_params
[1] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME
, (char*)name
, strlen(name
));
568 ec_params
[2] = OSSL_PARAM_construct_end();
570 const char *field_type
= EC_GROUP_get_field_type(group
) == NID_X9_62_prime_field
?
571 "prime-field" : "characteristic-two-field";
573 const BIGNUM
*bn_order
= EC_GROUP_get0_order(group
);
575 _cleanup_(BN_CTX_freep
) BN_CTX
*bnctx
= BN_CTX_new();
577 return log_oom_debug();
579 _cleanup_(BN_freep
) BIGNUM
*bn_p
= BN_new();
581 return log_oom_debug();
583 _cleanup_(BN_freep
) BIGNUM
*bn_a
= BN_new();
585 return log_oom_debug();
587 _cleanup_(BN_freep
) BIGNUM
*bn_b
= BN_new();
589 return log_oom_debug();
591 if (EC_GROUP_get_curve(group
, bn_p
, bn_a
, bn_b
, bnctx
) != 1)
592 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to extract EC parameters from EC_GROUP.");
594 order_size
= BN_num_bytes(bn_order
);
595 p_size
= BN_num_bytes(bn_p
);
596 a_size
= BN_num_bytes(bn_a
);
597 b_size
= BN_num_bytes(bn_b
);
599 order
= malloc(order_size
);
601 return log_oom_debug();
605 return log_oom_debug();
609 return log_oom_debug();
613 return log_oom_debug();
615 if (BN_bn2nativepad(bn_order
, order
, order_size
) <= 0 ||
616 BN_bn2nativepad(bn_p
, p
, p_size
) <= 0 ||
617 BN_bn2nativepad(bn_a
, a
, a_size
) <= 0 ||
618 BN_bn2nativepad(bn_b
, b
, b_size
) <= 0 )
619 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to store EC parameters in native byte order.");
621 const EC_POINT
*point_gen
= EC_GROUP_get0_generator(group
);
622 generator_size
= EC_POINT_point2oct(group
, point_gen
, POINT_CONVERSION_UNCOMPRESSED
, NULL
, 0, bnctx
);
623 if (generator_size
== 0)
624 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to determine size of a EC generator.");
626 generator
= malloc(generator_size
);
628 return log_oom_debug();
630 generator_size
= EC_POINT_point2oct(group
, point_gen
, POINT_CONVERSION_UNCOMPRESSED
, generator
, generator_size
, bnctx
);
631 if (generator_size
== 0)
632 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to convert a EC generator to octet string.");
634 ec_params
[1] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_EC_FIELD_TYPE
, (char*)field_type
, strlen(field_type
));
635 ec_params
[2] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_EC_GENERATOR
, generator
, generator_size
);
636 ec_params
[3] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_ORDER
, order
, order_size
);
637 ec_params
[4] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_P
, p
, p_size
);
638 ec_params
[5] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_A
, a
, a_size
);
639 ec_params
[6] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_EC_B
, b
, b_size
);
640 ec_params
[7] = OSSL_PARAM_construct_end();
643 if (EVP_PKEY_fromdata(ctx
, &pkey
, EVP_PKEY_PUBLIC_KEY
, ec_params
) != 1)
644 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to create EVP_PKEY from EC parameters.");
646 _cleanup_(EC_POINT_freep
) EC_POINT
*point
= EC_POINT_new(group
);
648 return log_oom_debug();
650 if (EC_POINT_oct2point(group
, point
, os
->data
, os
->length
, NULL
) != 1)
651 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode CKA_EC_POINT.");
653 _cleanup_(EC_KEY_freep
) EC_KEY
*ec_key
= EC_KEY_new();
655 return log_oom_debug();
657 if (EC_KEY_set_group(ec_key
, group
) != 1)
658 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to set group for EC_KEY.");
660 if (EC_KEY_set_public_key(ec_key
, point
) != 1)
661 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to set public key for EC_KEY.");
663 pkey
= EVP_PKEY_new();
665 return log_oom_debug();
667 if (EVP_PKEY_set1_EC_KEY(pkey
, ec_key
) != 1)
668 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to assign EC_KEY to EVP_PKEY.");
673 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Unsupported type of public key: %lu", key_type
);
676 *ret_pkey
= TAKE_PTR(pkey
);
680 int pkcs11_token_read_x509_certificate(
682 CK_SESSION_HANDLE session
,
683 CK_OBJECT_HANDLE object
,
686 _cleanup_free_
char *t
= NULL
;
687 CK_ATTRIBUTE attribute
= {
691 _cleanup_(X509_freep
) X509
*x509
= NULL
;
692 X509_NAME
*name
= NULL
;
699 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
701 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
702 "Failed to read X.509 certificate size off token: %s", sym_p11_kit_strerror(rv
));
704 _cleanup_free_
void *buffer
= malloc(attribute
.ulValueLen
);
706 return log_oom_debug();
708 attribute
.pValue
= buffer
;
710 rv
= m
->C_GetAttributeValue(session
, object
, &attribute
, 1);
712 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
713 "Failed to read X.509 certificate data off token: %s", sym_p11_kit_strerror(rv
));
715 const unsigned char *p
= attribute
.pValue
;
716 x509
= d2i_X509(NULL
, &p
, attribute
.ulValueLen
);
718 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG
), "Failed to parse X.509 certificate.");
720 name
= X509_get_subject_name(x509
);
722 return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG
), "Failed to acquire X.509 subject name.");
724 t
= X509_NAME_oneline(name
, NULL
, 0);
726 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to format X.509 subject name as string.");
728 log_debug("Using X.509 certificate issued for '%s'.", t
);
730 *ret_cert
= TAKE_PTR(x509
);
735 int pkcs11_token_find_private_key(
737 CK_SESSION_HANDLE session
,
738 P11KitUri
*search_uri
,
739 CK_OBJECT_HANDLE
*ret_object
) {
741 bool found_class
= false;
742 _cleanup_free_ CK_ATTRIBUTE
*attributes_buffer
= NULL
;
743 CK_KEY_TYPE key_type
;
744 CK_BBOOL decrypt_value
, derive_value
;
745 CK_ATTRIBUTE optional_attributes
[] = {
746 { CKA_KEY_TYPE
, &key_type
, sizeof(key_type
) },
747 { CKA_DECRYPT
, &decrypt_value
, sizeof(decrypt_value
) },
748 { CKA_DERIVE
, &derive_value
, sizeof(derive_value
) },
750 uint8_t n_private_keys
= 0;
751 CK_OBJECT_HANDLE private_key
= CK_INVALID_HANDLE
;
758 CK_ULONG n_attributes
;
759 CK_ATTRIBUTE
*attributes
= sym_p11_kit_uri_get_attributes(search_uri
, &n_attributes
);
760 for (CK_ULONG i
= 0; i
< n_attributes
; i
++) {
762 /* We use the URI's included match attributes, but make them more strict. This allows users
763 * to specify a token URL instead of an object URL and the right thing should happen if
764 * there's only one suitable key on the token. */
766 switch (attributes
[i
].type
) {
768 if (attributes
[i
].ulValueLen
!= sizeof(CK_OBJECT_CLASS
))
769 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid PKCS#11 CKA_CLASS attribute size.");
771 CK_OBJECT_CLASS
*class = (CK_OBJECT_CLASS
*) attributes
[i
].pValue
;
772 if (*class != CKO_PRIVATE_KEY
)
773 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
774 "Selected PKCS#11 object is not a private key, refusing.");
782 /* Hmm, let's slightly extend the attribute list we search for */
783 static const CK_OBJECT_CLASS required_class
= CKO_PRIVATE_KEY
;
785 attributes_buffer
= new(CK_ATTRIBUTE
, n_attributes
+ 1);
786 if (!attributes_buffer
)
789 memcpy(attributes_buffer
, attributes
, sizeof(CK_ATTRIBUTE
) * n_attributes
);
791 attributes_buffer
[n_attributes
++] = (CK_ATTRIBUTE
) {
793 .pValue
= (CK_OBJECT_CLASS
*) &required_class
,
794 .ulValueLen
= sizeof(required_class
),
797 attributes
= attributes_buffer
;
800 rv
= m
->C_FindObjectsInit(session
, attributes
, n_attributes
);
802 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
803 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv
));
807 CK_OBJECT_HANDLE candidate
;
808 rv
= m
->C_FindObjects(session
, &candidate
, 1, &b
);
810 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
811 "Failed to find objects: %s", sym_p11_kit_strerror(rv
));
816 optional_attributes
[0].ulValueLen
= sizeof(key_type
);
817 optional_attributes
[1].ulValueLen
= sizeof(decrypt_value
);
818 optional_attributes
[2].ulValueLen
= sizeof(derive_value
);
820 rv
= m
->C_GetAttributeValue(session
, candidate
, optional_attributes
, ELEMENTSOF(optional_attributes
));
821 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
822 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
823 "Failed to get attributes of a found private key: %s", sym_p11_kit_strerror(rv
));
825 if (optional_attributes
[0].ulValueLen
== CK_UNAVAILABLE_INFORMATION
) {
826 log_debug("A found private key does not have CKA_KEY_TYPE, rejecting the key.");
830 if (key_type
== CKK_RSA
)
831 if (optional_attributes
[1].ulValueLen
== CK_UNAVAILABLE_INFORMATION
|| decrypt_value
== CK_FALSE
) {
832 log_debug("A found private RSA key can't decrypt, rejecting the key.");
836 if (key_type
== CKK_EC
)
837 if (optional_attributes
[2].ulValueLen
== CK_UNAVAILABLE_INFORMATION
|| derive_value
== CK_FALSE
) {
838 log_debug("A found private EC key can't derive, rejecting the key.");
843 if (n_private_keys
> 1)
845 private_key
= candidate
;
848 rv
= m
->C_FindObjectsFinal(session
);
850 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
851 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv
));
853 if (n_private_keys
== 0)
854 return log_error_errno(SYNTHETIC_ERRNO(ENOENT
),
855 "Failed to find selected private key suitable for decryption or derivation on token.");
857 if (n_private_keys
> 1)
858 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
859 "Configured private key URI matches multiple keys, refusing.");
861 *ret_object
= private_key
;
865 static const char* object_class_to_string(CK_OBJECT_CLASS
class) {
867 case CKO_CERTIFICATE
:
868 return "CKO_CERTIFICATE";
870 return "CKO_PUBLIC_KEY";
871 case CKO_PRIVATE_KEY
:
872 return "CKO_PRIVATE_KEY";
874 return "CKO_SECRET_KEY";
880 /* Returns an object with the given class and the same CKA_ID or CKA_LABEL as prototype */
881 int pkcs11_token_find_related_object(
883 CK_SESSION_HANDLE session
,
884 CK_OBJECT_HANDLE prototype
,
885 CK_OBJECT_CLASS
class,
886 CK_OBJECT_HANDLE
*ret_object
) {
888 _cleanup_free_
void *buffer
= NULL
;
889 CK_ATTRIBUTE attributes
[] = {
890 { CKA_ID
, NULL_PTR
, 0 },
891 { CKA_LABEL
, NULL_PTR
, 0 }
893 CK_OBJECT_CLASS search_class
= class;
894 CK_ATTRIBUTE search_attributes
[2] = {
895 { CKA_CLASS
, &search_class
, sizeof(search_class
) }
898 CK_OBJECT_HANDLE objects
[2];
901 rv
= m
->C_GetAttributeValue(session
, prototype
, attributes
, ELEMENTSOF(attributes
));
902 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
903 return log_debug_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve length of attributes: %s", sym_p11_kit_strerror(rv
));
905 if (attributes
[0].ulValueLen
!= CK_UNAVAILABLE_INFORMATION
) {
906 buffer
= malloc(attributes
[0].ulValueLen
);
910 attributes
[0].pValue
= buffer
;
911 rv
= m
->C_GetAttributeValue(session
, prototype
, &attributes
[0], 1);
913 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
914 "Failed to retrieve CKA_ID: %s", sym_p11_kit_strerror(rv
));
916 search_attributes
[1] = attributes
[0];
918 } else if (attributes
[1].ulValueLen
!= CK_UNAVAILABLE_INFORMATION
) {
919 buffer
= malloc(attributes
[1].ulValueLen
);
923 attributes
[1].pValue
= buffer
;
924 rv
= m
->C_GetAttributeValue(session
, prototype
, &attributes
[1], 1);
926 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
927 "Failed to retrieve CKA_LABEL: %s", sym_p11_kit_strerror(rv
));
929 search_attributes
[1] = attributes
[1];
932 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL
), "The prototype does not have CKA_ID or CKA_LABEL");
934 rv
= m
->C_FindObjectsInit(session
, search_attributes
, 2);
936 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
937 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv
));
939 rv
= m
->C_FindObjects(session
, objects
, 2, &n_objects
);
941 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
942 "Failed to find objects: %s", sym_p11_kit_strerror(rv
));
944 rv
= m
->C_FindObjectsFinal(session
);
946 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
947 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv
));
950 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
951 "Failed to find a related object with class %s", object_class_to_string(class));
954 log_warning("Found multiple related objects with class %s, using the first object.",
955 object_class_to_string(class));
957 *ret_object
= objects
[0];
962 static int ecc_convert_to_compressed(
964 CK_SESSION_HANDLE session
,
965 CK_OBJECT_HANDLE object
,
966 const void *uncompressed_point
,
967 size_t uncompressed_point_size
,
968 void **ret_compressed_point
,
969 size_t *ret_compressed_point_size
) {
971 _cleanup_free_
void *ec_params_buffer
= NULL
;
972 CK_ATTRIBUTE ec_params_attr
= { CKA_EC_PARAMS
, NULL_PTR
, 0 };
976 rv
= m
->C_GetAttributeValue(session
, object
, &ec_params_attr
, 1);
977 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
978 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
979 "Failed to retrieve length of CKA_EC_PARAMS: %s", sym_p11_kit_strerror(rv
));
981 if (ec_params_attr
.ulValueLen
!= CK_UNAVAILABLE_INFORMATION
) {
982 ec_params_buffer
= malloc(ec_params_attr
.ulValueLen
);
983 if (!ec_params_buffer
)
986 ec_params_attr
.pValue
= ec_params_buffer
;
987 rv
= m
->C_GetAttributeValue(session
, object
, &ec_params_attr
, 1);
989 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
990 "Failed to retrieve CKA_EC_PARAMS from a private key: %s", sym_p11_kit_strerror(rv
));
992 CK_OBJECT_HANDLE public_key
;
993 r
= pkcs11_token_find_related_object(m
, session
, object
, CKO_PUBLIC_KEY
, &public_key
);
995 return log_error_errno(r
, "Failed to find a public key for compressing a EC point");
997 ec_params_attr
.ulValueLen
= 0;
998 rv
= m
->C_GetAttributeValue(session
, public_key
, &ec_params_attr
, 1);
999 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
1000 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1001 "Failed to retrieve length of CKA_EC_PARAMS: %s", sym_p11_kit_strerror(rv
));
1003 if (ec_params_attr
.ulValueLen
== CK_UNAVAILABLE_INFORMATION
)
1004 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1005 "The public key does not have CKA_EC_PARAMS");
1007 ec_params_buffer
= malloc(ec_params_attr
.ulValueLen
);
1008 if (!ec_params_buffer
)
1011 ec_params_attr
.pValue
= ec_params_buffer
;
1012 rv
= m
->C_GetAttributeValue(session
, public_key
, &ec_params_attr
, 1);
1014 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1015 "Failed to retrieve CKA_EC_PARAMS from a public key: %s", sym_p11_kit_strerror(rv
));
1018 _cleanup_(EC_GROUP_freep
) EC_GROUP
*group
= NULL
;
1019 _cleanup_(EC_POINT_freep
) EC_POINT
*point
= NULL
;
1020 _cleanup_(BN_CTX_freep
) BN_CTX
*bnctx
= NULL
;
1021 _cleanup_free_
void *compressed_point
= NULL
;
1022 size_t compressed_point_size
;
1024 const unsigned char *ec_params_value
= ec_params_attr
.pValue
;
1025 group
= d2i_ECPKParameters(NULL
, &ec_params_value
, ec_params_attr
.ulValueLen
);
1027 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode CKA_EC_PARAMS");
1029 point
= EC_POINT_new(group
);
1033 bnctx
= BN_CTX_new();
1037 if (EC_POINT_oct2point(group
, point
, uncompressed_point
, uncompressed_point_size
, bnctx
) != 1)
1038 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Unable to decode an uncompressed EC point");
1040 compressed_point_size
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
, NULL
, 0, bnctx
);
1041 if (compressed_point_size
== 0)
1042 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to determine size of a compressed EC point");
1044 compressed_point
= malloc(compressed_point_size
);
1045 if (!compressed_point
)
1048 compressed_point_size
= EC_POINT_point2oct(group
, point
, POINT_CONVERSION_COMPRESSED
, compressed_point
, compressed_point_size
, bnctx
);
1049 if (compressed_point_size
== 0)
1050 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to convert a EC point to compressed format");
1052 *ret_compressed_point
= TAKE_PTR(compressed_point
);
1053 *ret_compressed_point_size
= compressed_point_size
;
1058 /* Since EC keys doesn't support encryption directly, we use ECDH protocol to derive shared secret here.
1059 * We use PKCS#11 C_DeriveKey function to derive a shared secret with a private key stored in the token and
1060 * a public key saved on enrollment. */
1061 static int pkcs11_token_decrypt_data_ecc(
1062 CK_FUNCTION_LIST
*m
,
1063 CK_SESSION_HANDLE session
,
1064 CK_OBJECT_HANDLE object
,
1065 const void *encrypted_data
,
1066 size_t encrypted_data_size
,
1067 void **ret_decrypted_data
,
1068 size_t *ret_decrypted_data_size
) {
1070 static const CK_BBOOL yes
= CK_TRUE
, no
= CK_FALSE
;
1071 static const CK_OBJECT_CLASS shared_secret_class
= CKO_SECRET_KEY
;
1072 static const CK_KEY_TYPE shared_secret_type
= CKK_GENERIC_SECRET
;
1073 static const CK_ATTRIBUTE shared_secret_template
[] = {
1074 { CKA_TOKEN
, (void*) &no
, sizeof(no
) },
1075 { CKA_CLASS
, (void*) &shared_secret_class
, sizeof(shared_secret_class
) },
1076 { CKA_KEY_TYPE
, (void*) &shared_secret_type
, sizeof(shared_secret_type
) },
1077 { CKA_SENSITIVE
, (void*) &no
, sizeof(no
) },
1078 { CKA_EXTRACTABLE
, (void*) &yes
, sizeof(yes
) }
1080 CK_ECDH1_DERIVE_PARAMS params
= {
1082 .pPublicData
= (void*) encrypted_data
,
1083 .ulPublicDataLen
= encrypted_data_size
1085 CK_MECHANISM mechanism
= {
1086 .mechanism
= CKM_ECDH1_DERIVE
,
1087 .pParameter
= ¶ms
,
1088 .ulParameterLen
= sizeof(params
)
1090 CK_OBJECT_HANDLE shared_secret_handle
;
1091 CK_SESSION_INFO session_info
;
1092 CK_MECHANISM_INFO mechanism_info
;
1095 _cleanup_free_
void *compressed_point
= NULL
;
1099 rv
= m
->C_GetSessionInfo(session
, &session_info
);
1101 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1102 "Failed to get information about the PKCS#11 session: %s", sym_p11_kit_strerror(rv
));
1104 rv
= m
->C_GetMechanismInfo(session_info
.slotID
, CKM_ECDH1_DERIVE
, &mechanism_info
);
1106 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1107 "Failed to get information about CKM_ECDH1_DERIVE: %s", sym_p11_kit_strerror(rv
));
1109 if (!(mechanism_info
.flags
& CKF_EC_UNCOMPRESS
)) {
1110 if (mechanism_info
.flags
& CKF_EC_COMPRESS
) {
1112 log_debug("CKM_ECDH1_DERIVE accepts compressed EC points only, trying to convert.");
1113 size_t compressed_point_size
= 0; /* Explicit initialization to appease gcc */
1114 r
= ecc_convert_to_compressed(m
, session
, object
, encrypted_data
, encrypted_data_size
, &compressed_point
, &compressed_point_size
);
1118 params
.pPublicData
= compressed_point
;
1119 params
.ulPublicDataLen
= compressed_point_size
;
1121 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1122 "CKM_ECDH1_DERIVE does not support uncompressed format of EC points");
1125 log_debug("Both CKF_EC_UNCOMPRESS and CKF_EC_COMPRESS are false for CKM_ECDH1_DERIVE, ignoring.");
1128 rv
= m
->C_DeriveKey(session
, &mechanism
, object
, (CK_ATTRIBUTE
*) shared_secret_template
, ELEMENTSOF(shared_secret_template
), &shared_secret_handle
);
1130 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to derive a shared secret: %s", sym_p11_kit_strerror(rv
));
1132 CK_ATTRIBUTE shared_secret_attr
= { CKA_VALUE
, NULL_PTR
, 0};
1134 rv
= m
->C_GetAttributeValue(session
, shared_secret_handle
, &shared_secret_attr
, 1);
1136 rv2
= m
->C_DestroyObject(session
, shared_secret_handle
);
1138 log_warning("Failed to destroy a shared secret, ignoring: %s", sym_p11_kit_strerror(rv2
));
1139 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve shared secret length: %s", sym_p11_kit_strerror(rv
));
1142 shared_secret_attr
.pValue
= malloc(shared_secret_attr
.ulValueLen
);
1143 if (!shared_secret_attr
.pValue
)
1146 rv
= m
->C_GetAttributeValue(session
, shared_secret_handle
, &shared_secret_attr
, 1);
1147 rv2
= m
->C_DestroyObject(session
, shared_secret_handle
);
1149 log_warning("Failed to destroy a shared secret, ignoring: %s", sym_p11_kit_strerror(rv2
));
1152 erase_and_free(shared_secret_attr
.pValue
);
1153 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve a shared secret: %s", sym_p11_kit_strerror(rv
));
1156 log_info("Successfully derived key with security token.");
1158 *ret_decrypted_data
= shared_secret_attr
.pValue
;
1159 *ret_decrypted_data_size
= shared_secret_attr
.ulValueLen
;
1163 static int pkcs11_token_decrypt_data_rsa(
1164 CK_FUNCTION_LIST
*m
,
1165 CK_SESSION_HANDLE session
,
1166 CK_OBJECT_HANDLE object
,
1167 const void *encrypted_data
,
1168 size_t encrypted_data_size
,
1169 void **ret_decrypted_data
,
1170 size_t *ret_decrypted_data_size
) {
1172 static const CK_MECHANISM mechanism
= {
1173 .mechanism
= CKM_RSA_PKCS
1175 _cleanup_(erase_and_freep
) CK_BYTE
*dbuffer
= NULL
;
1176 CK_ULONG dbuffer_size
= 0;
1179 rv
= m
->C_DecryptInit(session
, (CK_MECHANISM
*) &mechanism
, object
);
1181 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1182 "Failed to initialize decryption on security token: %s", sym_p11_kit_strerror(rv
));
1184 dbuffer_size
= encrypted_data_size
; /* Start with something reasonable */
1185 dbuffer
= malloc(dbuffer_size
);
1189 rv
= m
->C_Decrypt(session
, (CK_BYTE
*) encrypted_data
, encrypted_data_size
, dbuffer
, &dbuffer_size
);
1190 if (rv
== CKR_BUFFER_TOO_SMALL
) {
1191 erase_and_free(dbuffer
);
1193 dbuffer
= malloc(dbuffer_size
);
1197 rv
= m
->C_Decrypt(session
, (CK_BYTE
*) encrypted_data
, encrypted_data_size
, dbuffer
, &dbuffer_size
);
1200 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1201 "Failed to decrypt key on security token: %s", sym_p11_kit_strerror(rv
));
1203 log_info("Successfully decrypted key with security token.");
1205 *ret_decrypted_data
= TAKE_PTR(dbuffer
);
1206 *ret_decrypted_data_size
= dbuffer_size
;
1210 int pkcs11_token_decrypt_data(
1211 CK_FUNCTION_LIST
*m
,
1212 CK_SESSION_HANDLE session
,
1213 CK_OBJECT_HANDLE object
,
1214 const void *encrypted_data
,
1215 size_t encrypted_data_size
,
1216 void **ret_decrypted_data
,
1217 size_t *ret_decrypted_data_size
) {
1219 CK_KEY_TYPE key_type
;
1220 CK_ATTRIBUTE key_type_template
= { CKA_KEY_TYPE
, &key_type
, sizeof(key_type
) };
1224 assert(encrypted_data
);
1225 assert(encrypted_data_size
> 0);
1226 assert(ret_decrypted_data
);
1227 assert(ret_decrypted_data_size
);
1229 rv
= m
->C_GetAttributeValue(session
, object
, &key_type_template
, 1);
1231 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to retrieve private key type");
1236 return pkcs11_token_decrypt_data_rsa(m
, session
, object
, encrypted_data
, encrypted_data_size
, ret_decrypted_data
, ret_decrypted_data_size
);
1239 return pkcs11_token_decrypt_data_ecc(m
, session
, object
, encrypted_data
, encrypted_data_size
, ret_decrypted_data
, ret_decrypted_data_size
);
1242 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Unsupported private key type: %lu", key_type
);
1246 int pkcs11_token_acquire_rng(
1247 CK_FUNCTION_LIST
*m
,
1248 CK_SESSION_HANDLE session
) {
1250 _cleanup_free_
void *buffer
= NULL
;
1257 r
= dlopen_p11kit();
1261 /* While we are at it, let's read some RNG data from the PKCS#11 token and pass it to the kernel
1262 * random pool. This should be cheap if we are talking to the device already. Note that we don't
1263 * credit any entropy, since we don't know about the quality of the pkcs#11 token's RNG. Why bother
1264 * at all? There are two sides to the argument whether to generate private keys on tokens or on the
1265 * host. By crediting some data from the token RNG to the host's pool we at least can say that any
1266 * key generated from it is at least as good as both sources individually. */
1268 rps
= random_pool_size();
1270 buffer
= malloc(rps
);
1274 rv
= m
->C_GenerateRandom(session
, buffer
, rps
);
1276 return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1277 "Failed to generate RNG data on security token: %s", sym_p11_kit_strerror(rv
));
1279 r
= random_write_entropy(-1, buffer
, rps
, false);
1281 return log_debug_errno(r
, "Failed to write PKCS#11 acquired random data to /dev/urandom: %m");
1283 log_debug("Successfully written %zu bytes random data acquired via PKCS#11 to kernel random pool.", rps
);
1288 static int token_process(
1289 CK_FUNCTION_LIST
*m
,
1291 const CK_SLOT_INFO
*slot_info
,
1292 const CK_TOKEN_INFO
*token_info
,
1293 P11KitUri
*search_uri
,
1294 pkcs11_find_token_callback_t callback
,
1297 _cleanup_free_
char *token_label
= NULL
;
1298 CK_SESSION_HANDLE session
;
1306 token_label
= pkcs11_token_label(token_info
);
1310 rv
= m
->C_OpenSession(slotid
, CKF_SERIAL_SESSION
, NULL
, NULL
, &session
);
1312 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1313 "Failed to create session for security token '%s': %s", token_label
, sym_p11_kit_strerror(rv
));
1316 r
= callback(m
, session
, slotid
, slot_info
, token_info
, search_uri
, userdata
);
1318 r
= 1; /* if not callback was specified, just say we found what we were looking for */
1320 rv
= m
->C_CloseSession(session
);
1322 log_warning("Failed to close session on PKCS#11 token, ignoring: %s", sym_p11_kit_strerror(rv
));
1327 static int slot_process(
1328 CK_FUNCTION_LIST
*m
,
1330 P11KitUri
*search_uri
,
1331 pkcs11_find_token_callback_t callback
,
1334 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
* slot_uri
= NULL
, *token_uri
= NULL
;
1335 _cleanup_free_
char *token_uri_string
= NULL
;
1336 CK_TOKEN_INFO token_info
;
1337 CK_SLOT_INFO slot_info
;
1343 r
= dlopen_p11kit();
1347 /* We return -EAGAIN for all failures we can attribute to a specific slot in some way, so that the
1348 * caller might try other slots before giving up. */
1350 rv
= m
->C_GetSlotInfo(slotid
, &slot_info
);
1352 log_warning("Failed to acquire slot info for slot %lu, ignoring slot: %s", slotid
, sym_p11_kit_strerror(rv
));
1356 slot_uri
= uri_from_slot_info(&slot_info
);
1360 if (DEBUG_LOGGING
) {
1361 _cleanup_free_
char *slot_uri_string
= NULL
;
1363 uri_result
= sym_p11_kit_uri_format(slot_uri
, P11_KIT_URI_FOR_ANY
, &slot_uri_string
);
1364 if (uri_result
!= P11_KIT_URI_OK
) {
1365 log_warning("Failed to format slot URI, ignoring slot: %s", sym_p11_kit_uri_message(uri_result
));
1369 log_debug("Found slot with URI %s", slot_uri_string
);
1372 rv
= m
->C_GetTokenInfo(slotid
, &token_info
);
1373 if (rv
== CKR_TOKEN_NOT_PRESENT
) {
1374 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN
),
1375 "Token not present in slot, ignoring.");
1376 } else if (rv
!= CKR_OK
) {
1377 log_warning("Failed to acquire token info for slot %lu, ignoring slot: %s", slotid
, sym_p11_kit_strerror(rv
));
1381 token_uri
= uri_from_token_info(&token_info
);
1385 uri_result
= sym_p11_kit_uri_format(token_uri
, P11_KIT_URI_FOR_ANY
, &token_uri_string
);
1386 if (uri_result
!= P11_KIT_URI_OK
) {
1387 log_warning("Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result
));
1391 if (search_uri
&& !sym_p11_kit_uri_match_token_info(search_uri
, &token_info
))
1392 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN
),
1393 "Found non-matching token with URI %s.",
1396 log_debug("Found matching token with URI %s.", token_uri_string
);
1398 return token_process(
1408 static int module_process(
1409 CK_FUNCTION_LIST
*m
,
1410 P11KitUri
*search_uri
,
1411 pkcs11_find_token_callback_t callback
,
1414 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
* module_uri
= NULL
;
1415 _cleanup_free_
char *name
= NULL
, *module_uri_string
= NULL
;
1416 _cleanup_free_ CK_SLOT_ID
*slotids
= NULL
;
1417 CK_ULONG n_slotids
= 0;
1426 r
= dlopen_p11kit();
1430 /* We ignore most errors from modules here, in order to skip over faulty modules: one faulty module
1431 * should not have the effect that we don't try the others anymore. We indicate such per-module
1432 * failures with -EAGAIN, which let's the caller try the next module. */
1434 name
= sym_p11_kit_module_get_name(m
);
1438 log_debug("Trying PKCS#11 module %s.", name
);
1440 rv
= m
->C_GetInfo(&info
);
1442 log_warning("Failed to get info on PKCS#11 module, ignoring module: %s", sym_p11_kit_strerror(rv
));
1446 module_uri
= uri_from_module_info(&info
);
1450 uri_result
= sym_p11_kit_uri_format(module_uri
, P11_KIT_URI_FOR_ANY
, &module_uri_string
);
1451 if (uri_result
!= P11_KIT_URI_OK
) {
1452 log_warning("Failed to format module URI, ignoring module: %s", sym_p11_kit_uri_message(uri_result
));
1456 log_debug("Found module with URI %s", module_uri_string
);
1458 rv
= pkcs11_get_slot_list_malloc(m
, &slotids
, &n_slotids
);
1460 log_warning("Failed to get slot list, ignoring module: %s", sym_p11_kit_strerror(rv
));
1464 return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN
),
1465 "This module has no slots? Ignoring module.");
1467 for (k
= 0; k
< n_slotids
; k
++) {
1481 int pkcs11_find_token(
1482 const char *pkcs11_uri
,
1483 pkcs11_find_token_callback_t callback
,
1486 _cleanup_(sym_p11_kit_modules_finalize_and_releasep
) CK_FUNCTION_LIST
**modules
= NULL
;
1487 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*search_uri
= NULL
;
1490 r
= dlopen_p11kit();
1494 /* Execute the specified callback for each matching token found. If nothing is found returns
1495 * -EAGAIN. Logs about all errors, except for EAGAIN, which the caller has to log about. */
1498 r
= uri_from_string(pkcs11_uri
, &search_uri
);
1500 return log_error_errno(r
, "Failed to parse PKCS#11 URI '%s': %m", pkcs11_uri
);
1503 modules
= sym_p11_kit_modules_load_and_initialize(0);
1505 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to initialize pkcs11 modules");
1507 for (CK_FUNCTION_LIST
**i
= modules
; *i
; i
++) {
1521 struct pkcs11_acquire_public_key_callback_data
{
1524 const char *askpw_friendly_name
, *askpw_icon
, *askpw_credential
;
1525 AskPasswordFlags askpw_flags
;
1528 static void pkcs11_acquire_public_key_callback_data_release(struct pkcs11_acquire_public_key_callback_data
*data
) {
1529 erase_and_free(data
->pin_used
);
1530 EVP_PKEY_free(data
->pkey
);
1533 static int pkcs11_acquire_public_key_callback(
1534 CK_FUNCTION_LIST
*m
,
1535 CK_SESSION_HANDLE session
,
1537 const CK_SLOT_INFO
*slot_info
,
1538 const CK_TOKEN_INFO
*token_info
,
1542 _cleanup_(erase_and_freep
) char *pin_used
= NULL
;
1543 _cleanup_(EVP_PKEY_freep
) EVP_PKEY
*pkey
= NULL
;
1544 CK_OBJECT_CLASS
class;
1545 CK_CERTIFICATE_TYPE type
;
1546 CK_ATTRIBUTE candidate_attributes
[] = {
1547 { CKA_CLASS
, &class, sizeof(class) },
1548 { CKA_CERTIFICATE_TYPE
, &type
, sizeof(type
) },
1550 CK_OBJECT_HANDLE candidate
, public_key
= CK_INVALID_HANDLE
, certificate
= CK_INVALID_HANDLE
;
1551 uint8_t n_public_keys
= 0, n_certificates
= 0;
1560 struct pkcs11_acquire_public_key_callback_data
*data
= ASSERT_PTR(userdata
);
1562 /* Called for every token matching our URI */
1564 r
= pkcs11_token_login(
1569 data
->askpw_friendly_name
,
1572 data
->askpw_credential
,
1579 CK_ULONG n_attributes
;
1580 CK_ATTRIBUTE
*attributes
= sym_p11_kit_uri_get_attributes(uri
, &n_attributes
);
1581 for (CK_ULONG i
= 0; i
< n_attributes
; i
++) {
1582 switch (attributes
[i
].type
) {
1584 CK_OBJECT_CLASS requested_class
= *((CK_OBJECT_CLASS
*) attributes
[i
].pValue
);
1585 if (!IN_SET(requested_class
, CKO_PUBLIC_KEY
, CKO_CERTIFICATE
))
1586 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1587 "Selected PKCS#11 object is not a public key or certificate, refusing.");
1591 case CKA_CERTIFICATE_TYPE
: {
1592 CK_CERTIFICATE_TYPE requested_type
= *((CK_CERTIFICATE_TYPE
*) attributes
[i
].pValue
);
1593 if (requested_type
!= CKC_X_509
)
1594 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Selected PKCS#11 object is not an X.509 certificate, refusing.");
1599 rv
= m
->C_FindObjectsInit(session
, attributes
, n_attributes
);
1601 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1602 "Failed to initialize object find call: %s", sym_p11_kit_strerror(rv
));
1606 rv
= m
->C_FindObjects(session
, &candidate
, 1, &n
);
1608 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1609 "Failed to find objects: %s", sym_p11_kit_strerror(rv
));
1614 candidate_attributes
[0].ulValueLen
= sizeof(class);
1615 candidate_attributes
[1].ulValueLen
= sizeof(type
);
1616 rv
= m
->C_GetAttributeValue(session
, candidate
, candidate_attributes
, ELEMENTSOF(candidate_attributes
));
1617 if (!IN_SET(rv
, CKR_OK
, CKR_ATTRIBUTE_TYPE_INVALID
))
1618 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1619 "Failed to get attributes of a selected candidate: %s", sym_p11_kit_strerror(rv
));
1621 if (candidate_attributes
[0].ulValueLen
== CK_UNAVAILABLE_INFORMATION
) {
1622 log_debug("Failed to get CKA_CLASS of a selected candidate");
1626 if (class == CKO_PUBLIC_KEY
) {
1628 if (n_public_keys
> 1)
1630 public_key
= candidate
;
1634 if (class == CKO_CERTIFICATE
) {
1635 if (candidate_attributes
[1].ulValueLen
== CK_UNAVAILABLE_INFORMATION
) {
1636 log_debug("Failed to get CKA_CERTIFICATE_TYPE of a selected candidate");
1639 if (type
!= CKC_X_509
)
1642 if (n_certificates
> 1)
1644 certificate
= candidate
;
1649 rv
= m
->C_FindObjectsFinal(session
);
1651 return log_error_errno(SYNTHETIC_ERRNO(EIO
),
1652 "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv
));
1654 if (n_public_keys
== 0 && n_certificates
== 0)
1655 return log_error_errno(SYNTHETIC_ERRNO(ENOENT
),
1656 "Failed to find selected public key or X.509 certificate.");
1658 if (n_public_keys
> 1)
1659 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
1660 "Provided URI matches multiple public keys, refusing.");
1662 if (n_certificates
> 1)
1663 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
1664 "Provided URI matches multiple certificates, refusing.");
1666 if (n_public_keys
!= 0) {
1667 r
= pkcs11_token_read_public_key(m
, session
, public_key
, &pkey
);
1672 if (n_certificates
== 0)
1673 return log_error_errno(r
, "Failed to read a found public key.");
1676 _cleanup_(X509_freep
) X509
*cert
= NULL
;
1678 r
= pkcs11_token_read_x509_certificate(m
, session
, certificate
, &cert
);
1680 return log_error_errno(r
, "Failed to read a found X.509 certificate.");
1682 pkey
= X509_get_pubkey(cert
);
1684 return log_error_errno(SYNTHETIC_ERRNO(EIO
), "Failed to extract public key from X.509 certificate.");
1687 /* Let's read some random data off the token and write it to the kernel pool before we generate our
1688 * random key from it. This way we can claim the quality of the RNG is at least as good as the
1689 * kernel's and the token's pool */
1690 (void) pkcs11_token_acquire_rng(m
, session
);
1692 data
->pin_used
= TAKE_PTR(pin_used
);
1693 data
->pkey
= TAKE_PTR(pkey
);
1697 int pkcs11_acquire_public_key(
1699 const char *askpw_friendly_name
,
1700 const char *askpw_icon
,
1701 const char *askpw_credential
,
1702 AskPasswordFlags askpw_flags
,
1703 EVP_PKEY
**ret_pkey
,
1704 char **ret_pin_used
) {
1706 _cleanup_(pkcs11_acquire_public_key_callback_data_release
) struct pkcs11_acquire_public_key_callback_data data
= {
1707 .askpw_friendly_name
= askpw_friendly_name
,
1708 .askpw_icon
= askpw_icon
,
1709 .askpw_credential
= askpw_credential
,
1710 .askpw_flags
= askpw_flags
,
1717 r
= pkcs11_find_token(uri
, pkcs11_acquire_public_key_callback
, &data
);
1718 if (r
== -EAGAIN
) /* pkcs11_find_token() doesn't log about this error, but all others */
1719 return log_error_errno(SYNTHETIC_ERRNO(ENXIO
),
1720 "Specified PKCS#11 token with URI '%s' not found.",
1725 *ret_pkey
= TAKE_PTR(data
.pkey
);
1727 *ret_pin_used
= TAKE_PTR(data
.pin_used
);
1732 static int list_callback(
1733 CK_FUNCTION_LIST
*m
,
1734 CK_SESSION_HANDLE session
,
1736 const CK_SLOT_INFO
*slot_info
,
1737 const CK_TOKEN_INFO
*token_info
,
1741 _cleanup_free_
char *token_uri_string
= NULL
, *token_label
= NULL
, *token_manufacturer_id
= NULL
, *token_model
= NULL
;
1742 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*token_uri
= NULL
;
1743 Table
*t
= userdata
;
1749 r
= dlopen_p11kit();
1753 /* We only care about hardware devices here with a token inserted. Let's filter everything else
1754 * out. (Note that the user can explicitly specify non-hardware tokens if they like, but during
1755 * enumeration we'll filter those, since software tokens are typically the system certificate store
1756 * and such, and it's typically not what people want to bind their home directories to.) */
1757 if (!FLAGS_SET(slot_info
->flags
, CKF_HW_SLOT
|CKF_TOKEN_PRESENT
))
1760 token_label
= pkcs11_token_label(token_info
);
1764 token_manufacturer_id
= pkcs11_token_manufacturer_id(token_info
);
1765 if (!token_manufacturer_id
)
1768 token_model
= pkcs11_token_model(token_info
);
1772 token_uri
= uri_from_token_info(token_info
);
1776 uri_result
= sym_p11_kit_uri_format(token_uri
, P11_KIT_URI_FOR_ANY
, &token_uri_string
);
1777 if (uri_result
!= P11_KIT_URI_OK
)
1778 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN
), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result
));
1782 TABLE_STRING
, token_uri_string
,
1783 TABLE_STRING
, token_label
,
1784 TABLE_STRING
, token_manufacturer_id
,
1785 TABLE_STRING
, token_model
);
1787 return table_log_add_error(r
);
1789 return -EAGAIN
; /* keep scanning */
1793 int dlopen_p11kit(void) {
1795 ELF_NOTE_DLOPEN("p11-kit",
1796 "Support for PKCS11 hardware tokens",
1797 ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED
,
1800 return dlopen_many_sym_or_warn(
1802 "libp11-kit.so.0", LOG_DEBUG
,
1803 DLSYM_ARG(p11_kit_module_get_name
),
1804 DLSYM_ARG(p11_kit_modules_finalize_and_release
),
1805 DLSYM_ARG(p11_kit_modules_load_and_initialize
),
1806 DLSYM_ARG(p11_kit_strerror
),
1807 DLSYM_ARG(p11_kit_uri_format
),
1808 DLSYM_ARG(p11_kit_uri_free
),
1809 DLSYM_ARG(p11_kit_uri_get_attributes
),
1810 DLSYM_ARG(p11_kit_uri_get_attribute
),
1811 DLSYM_ARG(p11_kit_uri_set_attribute
),
1812 DLSYM_ARG(p11_kit_uri_get_module_info
),
1813 DLSYM_ARG(p11_kit_uri_get_slot_info
),
1814 DLSYM_ARG(p11_kit_uri_get_token_info
),
1815 DLSYM_ARG(p11_kit_uri_match_token_info
),
1816 DLSYM_ARG(p11_kit_uri_message
),
1817 DLSYM_ARG(p11_kit_uri_new
),
1818 DLSYM_ARG(p11_kit_uri_parse
));
1820 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "p11kit support is not compiled in.");
1824 int pkcs11_list_tokens(void) {
1826 _cleanup_(table_unrefp
) Table
*t
= NULL
;
1829 t
= table_new("uri", "label", "manufacturer", "model");
1833 r
= pkcs11_find_token(NULL
, list_callback
, t
);
1834 if (r
< 0 && r
!= -EAGAIN
)
1837 if (table_isempty(t
)) {
1838 log_info("No suitable PKCS#11 tokens found.");
1842 r
= table_print(t
, stdout
);
1844 return log_error_errno(r
, "Failed to show device table: %m");
1848 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1849 "PKCS#11 tokens not supported on this build.");
1854 static int auto_callback(
1855 CK_FUNCTION_LIST
*m
,
1856 CK_SESSION_HANDLE session
,
1858 const CK_SLOT_INFO
*slot_info
,
1859 const CK_TOKEN_INFO
*token_info
,
1863 _cleanup_(sym_p11_kit_uri_freep
) P11KitUri
*token_uri
= NULL
;
1864 char **t
= userdata
;
1870 r
= dlopen_p11kit();
1874 if (!FLAGS_SET(token_info
->flags
, CKF_HW_SLOT
|CKF_TOKEN_PRESENT
))
1878 return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ
),
1879 "More than one suitable PKCS#11 token found.");
1881 token_uri
= uri_from_token_info(token_info
);
1885 uri_result
= sym_p11_kit_uri_format(token_uri
, P11_KIT_URI_FOR_ANY
, t
);
1886 if (uri_result
!= P11_KIT_URI_OK
)
1887 return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN
), "Failed to format slot URI: %s", sym_p11_kit_uri_message(uri_result
));
1893 int pkcs11_find_token_auto(char **ret
) {
1897 r
= pkcs11_find_token(NULL
, auto_callback
, ret
);
1899 return log_error_errno(SYNTHETIC_ERRNO(ENODEV
), "No suitable PKCS#11 tokens found.");
1905 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
),
1906 "PKCS#11 tokens not supported on this build.");
1911 void pkcs11_crypt_device_callback_data_release(pkcs11_crypt_device_callback_data
*data
) {
1912 erase_and_free(data
->decrypted_key
);
1914 if (data
->free_encrypted_key
)
1915 free(data
->encrypted_key
);
1918 int pkcs11_crypt_device_callback(
1919 CK_FUNCTION_LIST
*m
,
1920 CK_SESSION_HANDLE session
,
1922 const CK_SLOT_INFO
*slot_info
,
1923 const CK_TOKEN_INFO
*token_info
,
1927 pkcs11_crypt_device_callback_data
*data
= ASSERT_PTR(userdata
);
1928 CK_OBJECT_HANDLE object
;
1936 /* Called for every token matching our URI */
1938 r
= pkcs11_token_login(
1943 data
->friendly_name
,
1946 data
->askpw_credential
,
1953 /* We are likely called during early boot, where entropy is scarce. Mix some data from the PKCS#11
1954 * token, if it supports that. It should be cheap, given that we already are talking to it anyway and
1955 * shouldn't hurt. */
1956 (void) pkcs11_token_acquire_rng(m
, session
);
1958 r
= pkcs11_token_find_private_key(m
, session
, uri
, &object
);
1962 r
= pkcs11_token_decrypt_data(
1966 data
->encrypted_key
,
1967 data
->encrypted_key_size
,
1968 &data
->decrypted_key
,
1969 &data
->decrypted_key_size
);