diff --git a/man/crypttab.xml b/man/crypttab.xml
index eb742be0582..c35d782c8dd 100644
--- a/man/crypttab.xml
+++ b/man/crypttab.xml
@@ -104,10 +104,14 @@
see above and below.
The key may be acquired via a PKCS#11 compatible hardware security token or
- smartcard. In this case an encrypted key is stored on disk/removable media, acquired via
- AF_UNIX, or stored in the LUKS2 JSON token metadata header. The encrypted key is
- then decrypted by the PKCS#11 token with an RSA key stored on it, and then used to unlock the encrypted
- volume. Use the option described below to use this mechanism.
+ smartcard. In this case a saved key used in unlock process is stored on disk/removable media, acquired via
+ AF_UNIX, or stored in the LUKS2 JSON token metadata header. For RSA, the saved key
+ is an encrypted volume key. The encrypted volume key is then decrypted by the PKCS#11 token with an RSA
+ private key stored on it, and used to unlock the encrypted volume. For elliptic-curve (EC) cryptography,
+ the saved key is the public key generated in enrollment process. The public key is then used to derive
+ a shared secret with a private key stored in the PKCS#11 token. The derived shared secret is then used
+ to unlock the volume. Use the option described below to use this mechanism.
+
Similarly, the key may be acquired via a FIDO2 compatible hardware security token
(which must implement the "hmac-secret" extension). In this case a key generated randomly during
@@ -643,7 +647,7 @@
Takes either the special value auto or an RFC7512 PKCS#11 URI pointing to a private RSA key
+ url="https://tools.ietf.org/html/rfc7512">RFC7512 PKCS#11 URI pointing to a private key
which is used to decrypt the encrypted key specified in the third column of the line. This is useful
for unlocking encrypted volumes through PKCS#11 compatible security tokens or smartcards. See below
for an example how to set up this mechanism for unlocking a LUKS2 volume with a YubiKey security
@@ -653,16 +657,16 @@
security token metadata in its LUKS2 JSON token section. In this mode the URI and the encrypted key
are automatically read from the LUKS2 JSON token header. Use
systemd-cryptenroll1
- as simple tool for enrolling PKCS#11 security tokens or smartcards in a way compatible with
+ as a simple tool for enrolling PKCS#11 security tokens or smartcards in a way compatible with
auto. In this mode the third column of the line should remain empty (that is,
specified as -).
- The specified URI can refer directly to a private RSA key stored on a token or alternatively
- just to a slot or token, in which case a search for a suitable private RSA key will be performed. In
- this case if multiple suitable objects are found the token is refused. The encrypted key configured
- in the third column of the line is passed as is (i.e. in binary form, unprocessed) to RSA
- decryption. The resulting decrypted key is then Base64 encoded before it is used to unlock the LUKS
- volume.
+ The specified URI can refer directly to a private key stored on a token or alternatively
+ just to a slot or token, in which case a search for a suitable private key will be performed. In
+ this case if multiple suitable objects are found the token is refused. The keyfile configured
+ in the third column of the line is used as is (i.e. in binary form, unprocessed). The resulting
+ decrypted key (for RSA) or derived shared secret (for ECC) is then Base64 encoded before it is used
+ to unlock the LUKS volume.Use systemd-cryptenroll --pkcs11-token-uri=list to list all suitable PKCS#11
security tokens currently plugged in, along with their URIs.
@@ -969,8 +973,8 @@ external /dev/sda3 keyfile:LABEL=keydev keyfile-timeout=10s,cipher=xchac
Yubikey-based PKCS#11 Volume Unlocking ExampleThe PKCS#11 logic allows hooking up any compatible security token that is capable of storing RSA
- decryption keys for unlocking an encrypted volume. Here's an example how to set up a Yubikey security
- token for this purpose on a LUKS2 volume, using ykmap1 from the
yubikey-manager project to initialize the token and
systemd-cryptenroll1
diff --git a/man/systemd-cryptenroll.xml b/man/systemd-cryptenroll.xml
index 8fd885cb264..40e07ce24d9 100644
--- a/man/systemd-cryptenroll.xml
+++ b/man/systemd-cryptenroll.xml
@@ -36,8 +36,8 @@
supports tokens and credentials of the following kind to be enrolled:
- PKCS#11 security tokens and smartcards that may carry an RSA key pair (e.g. various
- YubiKeys)
+ PKCS#11 security tokens and smartcards that may carry an RSA or EC key pair (e.g.
+ various YubiKeys)FIDO2 security tokens that implement the hmac-secret extension (most
FIDO2 keys, including YubiKeys)
@@ -317,9 +317,16 @@
smartcard URI referring to the token. Alternatively the special value auto may
be specified, in order to automatically determine the URI of a currently plugged in security token
(of which there must be exactly one). The special value list may be used to
- enumerate all suitable PKCS#11 tokens currently plugged in. The security token must contain an RSA
- key pair which is used to encrypt the randomly generated key that is used to unlock the LUKS2
- volume. The encrypted key is then stored in the LUKS2 JSON token header area.
+ enumerate all suitable PKCS#11 tokens currently plugged in.
+
+ The PKCS#11 token must contain an RSA or EC key pair which will be used to unlock a LUKS2 volume.
+ For RSA, a randomly generated volume key is encrypted with a public key in the token, and stored in
+ the LUKS2 JSON token header area. To unlock a volume, the stored encrypted volume key will be decrypted
+ with a private key in the token. For ECC, ECDH algorithm is used: we generate a pair of EC keys in
+ the same EC group, then derive a shared secret using the generated private key and the public key
+ in the token. The derived shared secret is used as a volume key. The generated public key is
+ stored in the LUKS2 JSON token header area. The generated private key is erased. To unlock a volume,
+ we derive the shared secret with the stored public key and a private key in the token.In order to unlock a LUKS2 volume with an enrolled PKCS#11 security token, specify the
option in the respective /etc/crypttab line:
diff --git a/src/shared/openssl-util.c b/src/shared/openssl-util.c
index f94df54c207..d4a689cf852 100644
--- a/src/shared/openssl-util.c
+++ b/src/shared/openssl-util.c
@@ -8,8 +8,8 @@
#include "string-util.h"
#if HAVE_OPENSSL
-/* For each error in the the OpenSSL thread error queue, log the provided message and the OpenSSL error
- * string. If there are no errors in the OpenSSL thread queue, this logs the message with "No openssl
+/* For each error in the OpenSSL thread error queue, log the provided message and the OpenSSL error
+ * string. If there are no errors in the OpenSSL thread queue, this logs the message with "No OpenSSL
* errors." This logs at level debug. Returns -EIO (or -ENOMEM). */
#define log_openssl_errors(fmt, ...) _log_openssl_errors(UNIQ, fmt, ##__VA_ARGS__)
#define _log_openssl_errors(u, fmt, ...) \
@@ -524,7 +524,6 @@ int rsa_encrypt_bytes(
*ret_encrypt_key = TAKE_PTR(b);
*ret_encrypt_key_size = l;
-
return 0;
}
@@ -990,7 +989,7 @@ int ecc_ecdh(const EVP_PKEY *private_pkey,
if (EVP_PKEY_derive(ctx, NULL, &shared_secret_size) <= 0)
return log_openssl_errors("Failed to get ECC shared secret size");
- _cleanup_free_ void *shared_secret = malloc(shared_secret_size);
+ _cleanup_(erase_and_freep) void *shared_secret = malloc(shared_secret_size);
if (!shared_secret)
return log_oom_debug();
@@ -1130,6 +1129,95 @@ int string_hashsum(
}
# endif
+static int ecc_pkey_generate_volume_keys(
+ EVP_PKEY *pkey,
+ void **ret_decrypted_key,
+ size_t *ret_decrypted_key_size,
+ void **ret_saved_key,
+ size_t *ret_saved_key_size) {
+
+ _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey_new = NULL;
+ _cleanup_(erase_and_freep) void *decrypted_key = NULL;
+ _cleanup_free_ unsigned char *saved_key = NULL;
+ size_t decrypted_key_size, saved_key_size;
+ int nid = NID_undef;
+ int r;
+
+#if OPENSSL_VERSION_MAJOR >= 3
+ _cleanup_free_ char *curve_name = NULL;
+ size_t len = 0;
+
+ if (EVP_PKEY_get_group_name(pkey, NULL, 0, &len) != 1 || len == 0)
+ return log_openssl_errors("Failed to determine PKEY group name length");
+
+ len++;
+ curve_name = new(char, len);
+ if (!curve_name)
+ return log_oom_debug();
+
+ if (EVP_PKEY_get_group_name(pkey, curve_name, len, &len) != 1)
+ return log_openssl_errors("Failed to get PKEY group name");
+
+ nid = OBJ_sn2nid(curve_name);
+#else
+ EC_KEY *ec_key = EVP_PKEY_get0_EC_KEY(pkey);
+ if (!ec_key)
+ return log_openssl_errors("PKEY doesn't have EC_KEY associated");
+
+ if (EC_KEY_check_key(ec_key) != 1)
+ return log_openssl_errors("EC_KEY associated with PKEY is not valid");
+
+ nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
+#endif
+
+ r = ecc_pkey_new(nid, &pkey_new);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to generate a new EC keypair: %m");
+
+ r = ecc_ecdh(pkey_new, pkey, &decrypted_key, &decrypted_key_size);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to derive shared secret: %m");
+
+#if OPENSSL_VERSION_MAJOR >= 3
+ /* EVP_PKEY_get1_encoded_public_key() always returns uncompressed format of EC points.
+ See https://github.com/openssl/openssl/discussions/22835 */
+ saved_key_size = EVP_PKEY_get1_encoded_public_key(pkey_new, &saved_key);
+ if (saved_key_size == 0)
+ return log_openssl_errors("Failed to convert the generated public key to SEC1 format");
+#else
+ EC_KEY *ec_key_new = EVP_PKEY_get0_EC_KEY(pkey_new);
+ if (!ec_key_new)
+ return log_openssl_errors("The generated key doesn't have associated EC_KEY");
+
+ if (EC_KEY_check_key(ec_key_new) != 1)
+ return log_openssl_errors("EC_KEY associated with the generated key is not valid");
+
+ saved_key_size = EC_POINT_point2oct(EC_KEY_get0_group(ec_key_new),
+ EC_KEY_get0_public_key(ec_key_new),
+ POINT_CONVERSION_UNCOMPRESSED,
+ NULL, 0, NULL);
+ if (saved_key_size == 0)
+ return log_openssl_errors("Failed to determine size of the generated public key");
+
+ saved_key = malloc(saved_key_size);
+ if (!saved_key)
+ return log_oom_debug();
+
+ saved_key_size = EC_POINT_point2oct(EC_KEY_get0_group(ec_key_new),
+ EC_KEY_get0_public_key(ec_key_new),
+ POINT_CONVERSION_UNCOMPRESSED,
+ saved_key, saved_key_size, NULL);
+ if (saved_key_size == 0)
+ return log_openssl_errors("Failed to convert the generated public key to SEC1 format");
+#endif
+
+ *ret_decrypted_key = TAKE_PTR(decrypted_key);
+ *ret_decrypted_key_size = decrypted_key_size;
+ *ret_saved_key = TAKE_PTR(saved_key);
+ *ret_saved_key_size = saved_key_size;
+ return 0;
+}
+
static int rsa_pkey_generate_volume_keys(
EVP_PKEY *pkey,
void **ret_decrypted_key,
@@ -1194,6 +1282,9 @@ int x509_generate_volume_keys(
case EVP_PKEY_RSA:
return rsa_pkey_generate_volume_keys(pkey, ret_decrypted_key, ret_decrypted_key_size, ret_saved_key, ret_saved_key_size);
+ case EVP_PKEY_EC:
+ return ecc_pkey_generate_volume_keys(pkey, ret_decrypted_key, ret_decrypted_key_size, ret_saved_key, ret_saved_key_size);
+
case NID_undef:
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine a type of public key");
diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c
index 6e88dc38038..22cb794633d 100644
--- a/src/shared/pkcs11-util.c
+++ b/src/shared/pkcs11-util.c
@@ -586,114 +586,61 @@ int pkcs11_token_find_private_key(
P11KitUri *search_uri,
CK_OBJECT_HANDLE *ret_object) {
- bool found_decrypt = false, found_class = false, found_key_type = false;
+ uint_fast8_t n_objects = 0;
+ bool found_class = false;
_cleanup_free_ CK_ATTRIBUTE *attributes_buffer = NULL;
- CK_ULONG n_attributes, a, n_objects;
- CK_ATTRIBUTE *attributes = NULL;
- CK_OBJECT_HANDLE objects[2];
- CK_RV rv, rv2;
- int r;
+ CK_OBJECT_HANDLE object, candidate;
+ static const CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
+ CK_BBOOL decrypt_value, derive_value;
+ CK_ATTRIBUTE optional_attributes[] = {
+ { CKA_DECRYPT, &decrypt_value, sizeof(decrypt_value) },
+ { CKA_DERIVE, &derive_value, sizeof(derive_value) }
+ };
+ CK_RV rv;
assert(m);
assert(search_uri);
assert(ret_object);
- r = dlopen_p11kit();
- if (r < 0)
- return r;
-
- attributes = sym_p11_kit_uri_get_attributes(search_uri, &n_attributes);
- for (a = 0; a < n_attributes; a++) {
+ CK_ULONG n_attributes;
+ CK_ATTRIBUTE *attributes = sym_p11_kit_uri_get_attributes(search_uri, &n_attributes);
+ for (CK_ULONG i = 0; i < n_attributes; i++) {
/* We use the URI's included match attributes, but make them more strict. This allows users
* to specify a token URL instead of an object URL and the right thing should happen if
* there's only one suitable key on the token. */
- switch (attributes[a].type) {
-
+ switch (attributes[i].type) {
case CKA_CLASS: {
CK_OBJECT_CLASS c;
- if (attributes[a].ulValueLen != sizeof(c))
+ if (attributes[i].ulValueLen != sizeof(c))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PKCS#11 CKA_CLASS attribute size.");
- memcpy(&c, attributes[a].pValue, sizeof(c));
+ memcpy(&c, attributes[i].pValue, sizeof(c));
if (c != CKO_PRIVATE_KEY)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Selected PKCS#11 object is not a private key, refusing.");
found_class = true;
break;
- }
-
- case CKA_DECRYPT: {
- CK_BBOOL b;
-
- if (attributes[a].ulValueLen != sizeof(b))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PKCS#11 CKA_DECRYPT attribute size.");
-
- memcpy(&b, attributes[a].pValue, sizeof(b));
- if (!b)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
- "Selected PKCS#11 object is not suitable for decryption, refusing.");
-
- found_decrypt = true;
- break;
- }
-
- case CKA_KEY_TYPE: {
- CK_KEY_TYPE t;
-
- if (attributes[a].ulValueLen != sizeof(t))
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PKCS#11 CKA_KEY_TYPE attribute size.");
-
- memcpy(&t, attributes[a].pValue, sizeof(t));
- if (t != CKK_RSA)
- return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected PKCS#11 object is not an RSA key, refusing.");
-
- found_key_type = true;
- break;
}}
}
- if (!found_decrypt || !found_class || !found_key_type) {
+ if (!found_class) {
/* Hmm, let's slightly extend the attribute list we search for */
- attributes_buffer = new(CK_ATTRIBUTE, n_attributes + !found_decrypt + !found_class + !found_key_type);
+ attributes_buffer = new(CK_ATTRIBUTE, n_attributes + 1);
if (!attributes_buffer)
return log_oom();
memcpy(attributes_buffer, attributes, sizeof(CK_ATTRIBUTE) * n_attributes);
- if (!found_decrypt) {
- static const CK_BBOOL yes = true;
-
- attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) {
- .type = CKA_DECRYPT,
- .pValue = (CK_BBOOL*) &yes,
- .ulValueLen = sizeof(yes),
- };
- }
-
- if (!found_class) {
- static const CK_OBJECT_CLASS class = CKO_PRIVATE_KEY;
-
- attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) {
- .type = CKA_CLASS,
- .pValue = (CK_OBJECT_CLASS*) &class,
- .ulValueLen = sizeof(class),
- };
- }
-
- if (!found_key_type) {
- static const CK_KEY_TYPE type = CKK_RSA;
-
- attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) {
- .type = CKA_KEY_TYPE,
- .pValue = (CK_KEY_TYPE*) &type,
- .ulValueLen = sizeof(type),
- };
- }
+ attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) {
+ .type = CKA_CLASS,
+ .pValue = (CK_OBJECT_CLASS*) &class,
+ .ulValueLen = sizeof(class),
+ };
attributes = attributes_buffer;
}
@@ -703,26 +650,127 @@ int pkcs11_token_find_private_key(
return log_error_errno(SYNTHETIC_ERRNO(EIO),
"Failed to initialize object find call: %s", sym_p11_kit_strerror(rv));
- rv = m->C_FindObjects(session, objects, ELEMENTSOF(objects), &n_objects);
- rv2 = m->C_FindObjectsFinal(session);
+ for (;;) {
+ CK_ULONG b;
+ rv = m->C_FindObjects(session, &candidate, 1, &b);
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+ "Failed to find objects: %s", sym_p11_kit_strerror(rv));
+
+ if (b == 0)
+ break;
+
+ bool can_decrypt = false, can_derive = false;
+ optional_attributes[0].ulValueLen = sizeof(decrypt_value);
+ optional_attributes[1].ulValueLen = sizeof(derive_value);
+
+ rv = m->C_GetAttributeValue(session, candidate, optional_attributes, ELEMENTSOF(optional_attributes));
+ if (rv != CKR_OK && rv != CKR_ATTRIBUTE_TYPE_INVALID)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO),
+ "Failed to get attributes of a selected private key: %s", sym_p11_kit_strerror(rv));
+
+ if (optional_attributes[0].ulValueLen != CK_UNAVAILABLE_INFORMATION && decrypt_value == CK_TRUE)
+ can_decrypt = true;
+
+ if (optional_attributes[1].ulValueLen != CK_UNAVAILABLE_INFORMATION && derive_value == CK_TRUE)
+ can_derive = true;
+
+ if (can_decrypt || can_derive) {
+ n_objects++;
+ if (n_objects > 1)
+ break;
+ object = candidate;
+ }
+ }
+
+ rv = m->C_FindObjectsFinal(session);
if (rv != CKR_OK)
return log_error_errno(SYNTHETIC_ERRNO(EIO),
- "Failed to find objects: %s", sym_p11_kit_strerror(rv));
- if (rv2 != CKR_OK)
- return log_error_errno(SYNTHETIC_ERRNO(EIO),
- "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv));
+ "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv));
+
if (n_objects == 0)
return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
- "Failed to find selected private key suitable for decryption on token.");
+ "Failed to find selected private key suitable for decryption or derivation on token.");
+
if (n_objects > 1)
return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ),
- "Configured private key URI matches multiple keys, refusing.");
+ "Configured private key URI matches multiple keys, refusing.");
- *ret_object = objects[0];
+ *ret_object = object;
return 0;
}
-int pkcs11_token_decrypt_data(
+/* Since EC keys doesn't support encryption directly, we use ECDH protocol to derive shared secret here.
+ * We use PKCS#11 C_DeriveKey function to derive a shared secret with a private key stored in the token and
+ * a public key saved on enrollment. */
+static int pkcs11_token_decrypt_data_ecc(
+ CK_FUNCTION_LIST *m,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object,
+ const void *encrypted_data,
+ size_t encrypted_data_size,
+ void **ret_decrypted_data,
+ size_t *ret_decrypted_data_size) {
+
+ static const CK_BBOOL yes = CK_TRUE, no = CK_FALSE;
+ static const CK_OBJECT_CLASS shared_secret_class = CKO_SECRET_KEY;
+ static const CK_KEY_TYPE shared_secret_type = CKK_GENERIC_SECRET;
+ static const CK_ATTRIBUTE shared_secret_template[] = {
+ { CKA_TOKEN, (void*) &no, sizeof(no) },
+ { CKA_CLASS, (void*) &shared_secret_class, sizeof(shared_secret_class) },
+ { CKA_KEY_TYPE, (void*) &shared_secret_type, sizeof(shared_secret_type) },
+ { CKA_SENSITIVE, (void*) &no, sizeof(no) },
+ { CKA_EXTRACTABLE, (void*) &yes, sizeof(yes) }
+ };
+ CK_ECDH1_DERIVE_PARAMS params = {
+ .kdf = CKD_NULL,
+ .pPublicData = (void*) encrypted_data,
+ .ulPublicDataLen = encrypted_data_size
+ };
+ CK_MECHANISM mechanism = {
+ .mechanism = CKM_ECDH1_DERIVE,
+ .pParameter = ¶ms,
+ .ulParameterLen = sizeof(params)
+ };
+ CK_OBJECT_HANDLE shared_secret_handle;
+ CK_RV rv, rv2;
+
+ rv = m->C_DeriveKey(session, &mechanism, object, (CK_ATTRIBUTE*) shared_secret_template, ELEMENTSOF(shared_secret_template), &shared_secret_handle);
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to derive a shared secret: %s", sym_p11_kit_strerror(rv));
+
+ CK_ATTRIBUTE shared_secret_attr = { CKA_VALUE, NULL_PTR, 0};
+
+ rv = m->C_GetAttributeValue(session, shared_secret_handle, &shared_secret_attr, 1);
+ if (rv != CKR_OK) {
+ rv2 = m->C_DestroyObject(session, shared_secret_handle);
+ if (rv2 != CKR_OK)
+ log_warning("Failed to destroy a shared secret, ignoring: %s", sym_p11_kit_strerror(rv2));
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve shared secret length: %s", sym_p11_kit_strerror(rv));
+ }
+
+ shared_secret_attr.pValue = malloc(shared_secret_attr.ulValueLen);
+ if (!shared_secret_attr.pValue)
+ return log_oom();
+
+ rv = m->C_GetAttributeValue(session, shared_secret_handle, &shared_secret_attr, 1);
+ rv2 = m->C_DestroyObject(session, shared_secret_handle);
+ if (rv2 != CKR_OK)
+ log_warning("Failed to destroy a shared secret, ignoring: %s", sym_p11_kit_strerror(rv2));
+
+ if (rv != CKR_OK) {
+ erase_and_free(shared_secret_attr.pValue);
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve a shared secret: %s", sym_p11_kit_strerror(rv));
+ }
+
+ log_info("Successfully derived key with security token.");
+
+ *ret_decrypted_data = shared_secret_attr.pValue;
+ *ret_decrypted_data_size = shared_secret_attr.ulValueLen;
+ return 0;
+}
+
+static int pkcs11_token_decrypt_data_rsa(
CK_FUNCTION_LIST *m,
CK_SESSION_HANDLE session,
CK_OBJECT_HANDLE object,
@@ -737,17 +785,6 @@ int pkcs11_token_decrypt_data(
_cleanup_(erase_and_freep) CK_BYTE *dbuffer = NULL;
CK_ULONG dbuffer_size = 0;
CK_RV rv;
- int r;
-
- assert(m);
- assert(encrypted_data);
- assert(encrypted_data_size > 0);
- assert(ret_decrypted_data);
- assert(ret_decrypted_data_size);
-
- r = dlopen_p11kit();
- if (r < 0)
- return r;
rv = m->C_DecryptInit(session, (CK_MECHANISM*) &mechanism, object);
if (rv != CKR_OK)
@@ -780,6 +817,42 @@ int pkcs11_token_decrypt_data(
return 0;
}
+int pkcs11_token_decrypt_data(
+ CK_FUNCTION_LIST *m,
+ CK_SESSION_HANDLE session,
+ CK_OBJECT_HANDLE object,
+ const void *encrypted_data,
+ size_t encrypted_data_size,
+ void **ret_decrypted_data,
+ size_t *ret_decrypted_data_size) {
+
+ CK_KEY_TYPE key_type;
+ CK_ATTRIBUTE key_type_template = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
+ CK_RV rv;
+
+ assert(m);
+ assert(encrypted_data);
+ assert(encrypted_data_size > 0);
+ assert(ret_decrypted_data);
+ assert(ret_decrypted_data_size);
+
+ rv = m->C_GetAttributeValue(session, object, &key_type_template, 1);
+ if (rv != CKR_OK)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve private key type");
+
+ switch (key_type) {
+
+ case CKK_RSA:
+ return pkcs11_token_decrypt_data_rsa(m, session, object, encrypted_data, encrypted_data_size, ret_decrypted_data, ret_decrypted_data_size);
+
+ case CKK_EC:
+ return pkcs11_token_decrypt_data_ecc(m, session, object, encrypted_data, encrypted_data_size, ret_decrypted_data, ret_decrypted_data_size);
+
+ default:
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Unsupported private key type: %lu", key_type);
+ }
+}
+
int pkcs11_token_acquire_rng(
CK_FUNCTION_LIST *m,
CK_SESSION_HANDLE session) {