cryptsetup: Add support for EC keys in PKCS#11 tokens

Since EC keys doesn't support encryption directly, we use ECDH protocol.
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.

Co-authored-by: MkfsSion <mkfssion@mkfssion.com>
This commit is contained in:
Vladimir Stoiakin 2023-08-15 20:51:54 +03:00
parent 876206f267
commit 3d05c05873
4 changed files with 295 additions and 120 deletions

View file

@ -104,10 +104,14 @@
see above and below.</para></listitem>
<listitem><para>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
<constant>AF_UNIX</constant>, 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>pkcs11-uri=</option> option described below to use this mechanism.</para></listitem>
smartcard. In this case a saved key used in unlock process is stored on disk/removable media, acquired via
<constant>AF_UNIX</constant>, 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>pkcs11-uri=</option> option described below to use this mechanism.
</para></listitem>
<listitem><para>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 @@
<term><option>pkcs11-uri=</option></term>
<listitem><para>Takes either the special value <literal>auto</literal> or an <ulink
url="https://tools.ietf.org/html/rfc7512">RFC7512 PKCS#11 URI</ulink> pointing to a private RSA key
url="https://tools.ietf.org/html/rfc7512">RFC7512 PKCS#11 URI</ulink> 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
<citerefentry><refentrytitle>systemd-cryptenroll</refentrytitle><manvolnum>1</manvolnum></citerefentry>
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
<literal>auto</literal>. In this mode the third column of the line should remain empty (that is,
specified as <literal>-</literal>).</para>
<para>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.</para>
<para>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.</para>
<para>Use <command>systemd-cryptenroll --pkcs11-token-uri=list</command> to list all suitable PKCS#11
security tokens currently plugged in, along with their URIs.</para>
@ -969,8 +973,8 @@ external /dev/sda3 keyfile:LABEL=keydev keyfile-timeout=10s,cipher=xchac
<title>Yubikey-based PKCS#11 Volume Unlocking Example</title>
<para>The 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 <citerefentry
or EC cryptographic 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 <citerefentry
project='debian'><refentrytitle>ykmap</refentrytitle><manvolnum>1</manvolnum></citerefentry> from the
yubikey-manager project to initialize the token and
<citerefentry><refentrytitle>systemd-cryptenroll</refentrytitle><manvolnum>1</manvolnum></citerefentry>

View file

@ -36,8 +36,8 @@
supports tokens and credentials of the following kind to be enrolled:</para>
<orderedlist>
<listitem><para>PKCS#11 security tokens and smartcards that may carry an RSA key pair (e.g. various
YubiKeys)</para></listitem>
<listitem><para>PKCS#11 security tokens and smartcards that may carry an RSA or EC key pair (e.g.
various YubiKeys)</para></listitem>
<listitem><para>FIDO2 security tokens that implement the <literal>hmac-secret</literal> extension (most
FIDO2 keys, including YubiKeys)</para></listitem>
@ -317,9 +317,16 @@
smartcard URI referring to the token. Alternatively the special value <literal>auto</literal> 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 <literal>list</literal> 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.</para>
enumerate all suitable PKCS#11 tokens currently plugged in.</para>
<para>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.</para>
<para>In order to unlock a LUKS2 volume with an enrolled PKCS#11 security token, specify the
<option>pkcs11-uri=</option> option in the respective <filename>/etc/crypttab</filename> line:</para>

View file

@ -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");

View file

@ -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 = &params,
.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) {