From ca6cb9c0892d29bd27bb82a3c3bc94ad9f33cc44 Mon Sep 17 00:00:00 2001 From: Vladimir Stoiakin Date: Sun, 18 Feb 2024 20:40:09 +0300 Subject: [PATCH] cryptsetup: make type-specific checks for PKCS#11 private keys --- src/shared/pkcs11-util.c | 68 +++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c index 8727fe24845..8077ec3019d 100644 --- a/src/shared/pkcs11-util.c +++ b/src/shared/pkcs11-util.c @@ -877,16 +877,17 @@ int pkcs11_token_find_private_key( P11KitUri *search_uri, CK_OBJECT_HANDLE *ret_object) { - uint_fast8_t n_objects = 0; bool found_class = false; _cleanup_free_ CK_ATTRIBUTE *attributes_buffer = NULL; - CK_OBJECT_HANDLE object = 0, candidate; - static const CK_OBJECT_CLASS class = CKO_PRIVATE_KEY; + CK_KEY_TYPE key_type; CK_BBOOL decrypt_value, derive_value; CK_ATTRIBUTE optional_attributes[] = { - { CKA_DECRYPT, &decrypt_value, sizeof(decrypt_value) }, - { CKA_DERIVE, &derive_value, sizeof(derive_value) } + { CKA_KEY_TYPE, &key_type, sizeof(key_type) }, + { CKA_DECRYPT, &decrypt_value, sizeof(decrypt_value) }, + { CKA_DERIVE, &derive_value, sizeof(derive_value) }, }; + uint8_t n_private_keys = 0; + CK_OBJECT_HANDLE private_key = CK_INVALID_HANDLE; CK_RV rv; assert(m); @@ -903,13 +904,11 @@ int pkcs11_token_find_private_key( switch (attributes[i].type) { case CKA_CLASS: { - CK_OBJECT_CLASS c; - - if (attributes[i].ulValueLen != sizeof(c)) + if (attributes[i].ulValueLen != sizeof(CK_OBJECT_CLASS)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid PKCS#11 CKA_CLASS attribute size."); - memcpy(&c, attributes[i].pValue, sizeof(c)); - if (c != CKO_PRIVATE_KEY) + CK_OBJECT_CLASS *class = (CK_OBJECT_CLASS*) attributes[i].pValue; + if (*class != CKO_PRIVATE_KEY) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Selected PKCS#11 object is not a private key, refusing."); @@ -920,6 +919,7 @@ int pkcs11_token_find_private_key( if (!found_class) { /* Hmm, let's slightly extend the attribute list we search for */ + static const CK_OBJECT_CLASS required_class = CKO_PRIVATE_KEY; attributes_buffer = new(CK_ATTRIBUTE, n_attributes + 1); if (!attributes_buffer) @@ -929,8 +929,8 @@ int pkcs11_token_find_private_key( attributes_buffer[n_attributes++] = (CK_ATTRIBUTE) { .type = CKA_CLASS, - .pValue = (CK_OBJECT_CLASS*) &class, - .ulValueLen = sizeof(class), + .pValue = (CK_OBJECT_CLASS*) &required_class, + .ulValueLen = sizeof(required_class), }; attributes = attributes_buffer; @@ -943,6 +943,7 @@ int pkcs11_token_find_private_key( for (;;) { CK_ULONG b; + CK_OBJECT_HANDLE candidate; rv = m->C_FindObjects(session, &candidate, 1, &b); if (rv != CKR_OK) return log_error_errno(SYNTHETIC_ERRNO(EIO), @@ -951,27 +952,36 @@ int pkcs11_token_find_private_key( 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); + optional_attributes[0].ulValueLen = sizeof(key_type); + optional_attributes[1].ulValueLen = sizeof(decrypt_value); + optional_attributes[2].ulValueLen = sizeof(derive_value); rv = m->C_GetAttributeValue(session, candidate, optional_attributes, ELEMENTSOF(optional_attributes)); if (!IN_SET(rv, CKR_OK, 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)); + "Failed to get attributes of a found 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[0].ulValueLen == CK_UNAVAILABLE_INFORMATION) { + log_debug("A found private key does not have CKA_KEY_TYPE, rejecting the key."); + continue; + } - if (optional_attributes[1].ulValueLen != CK_UNAVAILABLE_INFORMATION && derive_value == CK_TRUE) - can_derive = true; + if (key_type == CKK_RSA) + if (optional_attributes[1].ulValueLen == CK_UNAVAILABLE_INFORMATION || decrypt_value == CK_FALSE) { + log_debug("A found private RSA key can't decrypt, rejecting the key."); + continue; + } - if (can_decrypt || can_derive) { - n_objects++; - if (n_objects > 1) - break; - object = candidate; - } + if (key_type == CKK_EC) + if (optional_attributes[2].ulValueLen == CK_UNAVAILABLE_INFORMATION || derive_value == CK_FALSE) { + log_debug("A found private EC key can't derive, rejecting the key."); + continue; + } + + n_private_keys++; + if (n_private_keys > 1) + break; + private_key = candidate; } rv = m->C_FindObjectsFinal(session); @@ -979,15 +989,15 @@ int pkcs11_token_find_private_key( return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to finalize object find call: %s", sym_p11_kit_strerror(rv)); - if (n_objects == 0) + if (n_private_keys == 0) return log_error_errno(SYNTHETIC_ERRNO(ENOENT), "Failed to find selected private key suitable for decryption or derivation on token."); - if (n_objects > 1) + if (n_private_keys > 1) return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), "Configured private key URI matches multiple keys, refusing."); - *ret_object = object; + *ret_object = private_key; return 0; } -- 2.47.3