From: Michael Brown Date: Mon, 21 Apr 2025 23:28:07 +0000 (+0100) Subject: [crypto] Remove userptr_t from CMS verification and decryption X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=e98b84f1b991515804195ec56ae612f1a8ec4fea;p=thirdparty%2Fipxe.git [crypto] Remove userptr_t from CMS verification and decryption Simplify the CMS code by assuming that all content is fully accessible via pointer dereferences. This avoids the need to use fragment loops for calculating digests and decrypting (or reencrypting) data. Signed-off-by: Michael Brown --- diff --git a/src/crypto/cms.c b/src/crypto/cms.c index 6c8217c0f..36b87c644 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -39,7 +39,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include @@ -81,13 +80,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define EINFO_ENOTSUP_TYPE \ __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unrecognised message type" ) -/** Buffer size for decryption - * - * Must be at least 256 to allow block padding to be removed if - * needed. - */ -#define CMS_DECRYPT_BLKSZ 2048 - static int cms_parse_signed ( struct cms_message *cms, const struct asn1_cursor *raw ); static int cms_parse_enveloped ( struct cms_message *cms, @@ -724,28 +716,13 @@ int cms_message ( struct image *image, struct cms_message **cms ) { */ static void cms_digest ( struct cms_message *cms, struct cms_participant *part, - userptr_t data, size_t len, void *out ) { + const void *data, size_t len, void *out ) { struct digest_algorithm *digest = part->digest; uint8_t ctx[ digest->ctxsize ]; - uint8_t block[ digest->blocksize ]; - size_t offset = 0; - size_t frag_len; - /* Initialise digest */ + /* Calculate digest */ digest_init ( digest, ctx ); - - /* Process data one block at a time */ - while ( len ) { - frag_len = len; - if ( frag_len > sizeof ( block ) ) - frag_len = sizeof ( block ); - copy_from_user ( block, data, offset, frag_len ); - digest_update ( digest, ctx, block, frag_len ); - offset += frag_len; - len -= frag_len; - } - - /* Finalise digest */ + digest_update ( digest, ctx, data, len ); digest_final ( digest, ctx, out ); DBGC ( cms, "CMS %p/%p digest value:\n", cms, part ); @@ -765,7 +742,7 @@ static void cms_digest ( struct cms_message *cms, static int cms_verify_digest ( struct cms_message *cms, struct cms_participant *part, struct x509_certificate *cert, - userptr_t data, size_t len ) { + const void *data, size_t len ) { struct digest_algorithm *digest = part->digest; struct pubkey_algorithm *pubkey = part->pubkey; const struct asn1_cursor *key = &cert->subject.public_key.raw; @@ -801,7 +778,7 @@ static int cms_verify_digest ( struct cms_message *cms, */ static int cms_verify_signer ( struct cms_message *cms, struct cms_participant *part, - userptr_t data, size_t len, + const void *data, size_t len, time_t time, struct x509_chain *store, struct x509_root *root ) { struct x509_certificate *cert; @@ -1060,14 +1037,13 @@ int cms_decrypt ( struct cms_message *cms, struct image *image, const char *name, struct private_key *private_key ) { struct cipher_algorithm *cipher = cms->cipher; const unsigned int original_flags = image->flags; - size_t offset; - size_t remaining; - size_t frag_len; + uint8_t ctx[ cipher->ctxsize ]; + uint8_t ctxdup[ cipher->ctxsize ]; + uint8_t auth[ cipher->authsize ]; + uint8_t final[ cipher->blocksize ]; + size_t final_len; + size_t bulk_len; int pad_len; - void *tmp; - void *ctx; - void *ctxdup; - void *auth; int rc; /* Sanity checks */ @@ -1083,17 +1059,6 @@ int cms_decrypt ( struct cms_message *cms, struct image *image, goto err_blocksize; } - /* Allocate temporary working space */ - tmp = malloc ( CMS_DECRYPT_BLKSZ + ( 2 * cipher->ctxsize ) + - cipher->authsize ); - if ( ! tmp ) { - rc = -ENOMEM; - goto err_alloc; - } - ctx = ( tmp + CMS_DECRYPT_BLKSZ ); - ctxdup = ( ctx + cipher->ctxsize ); - auth = ( ctxdup + cipher->ctxsize ); - /* Initialise cipher */ if ( ( rc = cms_cipher ( cms, private_key, ctx ) ) != 0 ) goto err_cipher; @@ -1110,29 +1075,15 @@ int cms_decrypt ( struct cms_message *cms, struct image *image, unregister_image ( image ); } - /* Decrypt one block at a time */ - offset = 0; - remaining = image->len; - frag_len = 0; - while ( remaining ) { - - /* Calculate fragment length */ - frag_len = remaining; - if ( frag_len > CMS_DECRYPT_BLKSZ ) - frag_len = CMS_DECRYPT_BLKSZ; - - /* Decrypt fragment */ - copy_from_user ( tmp, image->data, offset, frag_len ); - cipher_decrypt ( cipher, ctx, tmp, tmp, frag_len ); - - /* Overwrite all but the final fragment */ - if ( remaining > frag_len ) - copy_to_user ( image->data, offset, tmp, frag_len ); + /* Decrypt all but the final block */ + final_len = ( ( image->len && is_block_cipher ( cipher ) ) ? + cipher->blocksize : 0 ); + bulk_len = ( image->len - final_len ); + cipher_decrypt ( cipher, ctx, image->data, image->data, bulk_len ); - /* Move to next block */ - remaining -= frag_len; - offset += frag_len; - } + /* Decrypt final block */ + cipher_decrypt ( cipher, ctx, ( image->data + bulk_len ), final, + final_len ); /* Check authentication tag, if applicable */ cipher_auth ( cipher, ctx, auth ); @@ -1145,7 +1096,7 @@ int cms_decrypt ( struct cms_message *cms, struct image *image, } /* Check block padding, if applicable */ - if ( ( pad_len = cms_verify_padding ( cms, tmp, frag_len ) ) < 0 ) { + if ( ( pad_len = cms_verify_padding ( cms, final, final_len ) ) < 0 ) { rc = pad_len; goto err_pad; } @@ -1166,7 +1117,7 @@ int cms_decrypt ( struct cms_message *cms, struct image *image, * have to include include any error-handling code path to * reconstruct the block padding. */ - copy_to_user ( image->data, ( offset - frag_len ), tmp, frag_len ); + memcpy ( ( image->data + bulk_len ), final, final_len ); image->len -= pad_len; /* Clear image type and re-register image, if applicable */ @@ -1176,33 +1127,23 @@ int cms_decrypt ( struct cms_message *cms, struct image *image, image_put ( image ); } - /* Free temporary working space */ - free ( tmp ); - return 0; err_set_name: err_pad: err_auth: - /* Reencrypt all overwritten fragments. This can be done - * since we have deliberately not overwritten the final - * fragment containing the potentially invalid (and therefore + /* Reencrypt all overwritten portions. This can be done since + * we have deliberately not overwritten the final block + * containing the potentially invalid (and therefore * unreproducible) block padding. */ - remaining = ( offset - frag_len ); - for ( offset = 0 ; offset < remaining ; offset += CMS_DECRYPT_BLKSZ ) { - copy_from_user ( tmp, image->data, offset, CMS_DECRYPT_BLKSZ ); - cipher_encrypt ( cipher, ctxdup, tmp, tmp, CMS_DECRYPT_BLKSZ ); - copy_to_user ( image->data, offset, tmp, CMS_DECRYPT_BLKSZ ); - } + cipher_encrypt ( cipher, ctxdup, image->data, image->data, bulk_len ); if ( original_flags & IMAGE_REGISTERED ) { register_image ( image ); /* Cannot fail on re-registration */ image_put ( image ); } image->flags = original_flags; err_cipher: - free ( tmp ); - err_alloc: err_blocksize: err_no_cipher: return rc; diff --git a/src/include/ipxe/cms.h b/src/include/ipxe/cms.h index 6d4a78d48..084cd81f8 100644 --- a/src/include/ipxe/cms.h +++ b/src/include/ipxe/cms.h @@ -14,7 +14,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include struct image; struct cms_message;