Blob Blame History Raw
From 3f3e6b62719a263cb221c19a06d9a2c570234caa Mon Sep 17 00:00:00 2001
From: Jan Friesse <jfriesse@redhat.com>
Date: Thu, 27 Sep 2018 13:08:48 +0200
Subject: [PATCH] totemcrypto: Fix importing of the private key

Import key with length not dividable by wrap key block size was not
possible.

Wrapping of the key is standard crypto operation which needs data
aligned to cipher block size, otherwise it fails.

Possible solution is to use a zero filled buffer with size aligned to
required wrap key block size. Private key is copied to the beginning of
the buffer and unwrap operation keeps using only required private key
size.

Signed-off-by: Jan Friesse <jfriesse@redhat.com>
Reviewed-by: Fabio M. Di Nitto <fdinitto@redhat.com>
Reviewed-by: Christine Caulfield <ccaulfie@redhat.com>
---
 exec/totemcrypto.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/exec/totemcrypto.c b/exec/totemcrypto.c
index 273c567..55763af 100644
--- a/exec/totemcrypto.c
+++ b/exec/totemcrypto.c
@@ -247,7 +247,9 @@ static PK11SymKey *import_symmetric_key(struct crypto_instance *instance, enum s
 	SECItem tmp_sec_item;
 	SECItem wrapped_key;
 	int wrapped_key_len;
+	int wrap_key_block_size;
 	unsigned char wrapped_key_data[MAX_WRAPPED_KEY_LEN];
+	unsigned char pad_key_data[MAX_WRAPPED_KEY_LEN];
 	int case_processed;
 
 	memset(&key_item, 0, sizeof(key_item));
@@ -256,8 +258,15 @@ static PK11SymKey *import_symmetric_key(struct crypto_instance *instance, enum s
 	res_key = NULL;
 	wrap_key_crypt_context = NULL;
 
+	if (instance->private_key_len > sizeof(pad_key_data)) {
+		log_printf(instance->log_level_security, "Import symmetric key failed. Private key is too long");
+		goto exit_res_key;
+	}
+	memset(pad_key_data, 0, sizeof(pad_key_data));
+	memcpy(pad_key_data, instance->private_key, instance->private_key_len);
+
 	key_item.type = siBuffer;
-	key_item.data = instance->private_key;
+	key_item.data = pad_key_data;
 
 	case_processed = 0;
 	switch (key_type) {
@@ -318,6 +327,22 @@ static PK11SymKey *import_symmetric_key(struct crypto_instance *instance, enum s
 	 */
 
 	/*
+	 * Key must be padded to a block size
+	 */
+	wrap_key_block_size = PK11_GetBlockSize(wrap_mechanism, 0);
+	if (wrap_key_block_size < 0) {
+		log_printf(instance->log_level_security, "Unable to get wrap key block size (%d): %s",
+		    PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
+		goto exit_res_key;
+	}
+	if (sizeof(pad_key_data) % wrap_key_block_size != 0) {
+		log_printf(instance->log_level_security, "Padded key buffer size (%zu) is not dividable by "
+		    "wrap key block size (%u).", sizeof(pad_key_data), (unsigned int)wrap_key_block_size);
+
+		goto exit_res_key;
+	}
+
+	/*
 	 * Initialization of IV is not needed because PK11_GetBestWrapMechanism should return ECB mode
 	 */
 	memset(&tmp_sec_item, 0, sizeof(tmp_sec_item));
@@ -332,7 +357,7 @@ static PK11SymKey *import_symmetric_key(struct crypto_instance *instance, enum s
 	wrapped_key_len = (int)sizeof(wrapped_key_data);
 
 	if (PK11_CipherOp(wrap_key_crypt_context, wrapped_key_data, &wrapped_key_len,
-	    sizeof(wrapped_key_data), key_item.data, key_item.len) != SECSuccess) {
+	    sizeof(wrapped_key_data), key_item.data, sizeof(pad_key_data)) != SECSuccess) {
 		log_printf(instance->log_level_security, "Unable to encrypt authkey (%d): %s",
 			   PR_GetError(), PR_ErrorToString(PR_GetError(), PR_LANGUAGE_I_DEFAULT));
 		goto exit_res_key;
-- 
1.8.3.1