From 2420211e7f0d81680e010b7b16aa42d365214271 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Jun 2026 14:11:46 +0100 Subject: [PATCH] [crypto] Allow cipher_setiv() to return an error GCM ciphers can accept initialisation vectors of any length. Move the responsibility for checking the initialisation vector length from the caller into the implementation of cipher_setiv(). Signed-off-by: Michael Brown --- src/crypto/cbc.c | 14 +++++++++++--- src/crypto/cms.c | 8 +++++++- src/crypto/crypto_null.c | 7 ++++--- src/crypto/gcm.c | 6 ++++-- src/include/ipxe/cbc.h | 4 ++-- src/include/ipxe/crypto.h | 13 +++++++------ src/include/ipxe/errfile.h | 1 + src/include/ipxe/gcm.h | 4 ++-- src/net/peerblk.c | 20 ++++++++++---------- src/net/tls.c | 16 +++++++++++++--- src/tests/cipher_test.c | 15 ++++++++++----- 11 files changed, 71 insertions(+), 37 deletions(-) diff --git a/src/crypto/cbc.c b/src/crypto/cbc.c index ff45dd9e8..9179607f9 100644 --- a/src/crypto/cbc.c +++ b/src/crypto/cbc.c @@ -26,6 +26,7 @@ FILE_SECBOOT ( PERMITTED ); #include #include +#include #include #include @@ -61,15 +62,22 @@ int cbc_setkey ( struct cipher_algorithm *cipher, void *ctx, * @v ctx Context * @v iv Initialisation vector * @v ivlen Initialisation vector length + * @ret rc Return status code */ -void cbc_setiv ( struct cipher_algorithm *cipher, void *ctx, - const void *iv, size_t ivlen ) { +int cbc_setiv ( struct cipher_algorithm *cipher, void *ctx, + const void *iv, size_t ivlen ) { size_t blocksize = cipher->blocksize; size_t ctxsize = cipher->ctxsize; cbc_context_t ( blocksize, ctxsize ) *context = ctx; - assert ( ivlen == sizeof ( context->cbc ) ); + /* Check length */ + if ( ivlen != sizeof ( context->cbc ) ) + return -ENOTSUP; + + /* Record IV */ memcpy ( context->cbc, iv, sizeof ( context->cbc ) ); + + return 0; } /** diff --git a/src/crypto/cms.c b/src/crypto/cms.c index 4c0f3f5a6..f1f224dae 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -941,12 +941,18 @@ static int cms_cipher_key ( struct cms_message *cms, } /* Set cipher initialization vector */ - cipher_setiv ( cipher, ctx, cms->iv.data, cms->iv.len ); + if ( ( rc = cipher_setiv ( cipher, ctx, cms->iv.data, + cms->iv.len ) ) != 0 ) { + DBGC ( cms, "CMS %p could not set cipher IV: %s\n", + cms, strerror ( rc ) ); + goto err_setiv; + } if ( cms->iv.len ) { DBGC ( cms, "CMS %p cipher IV:\n", cms ); DBGC_HDA ( cms, 0, cms->iv.data, cms->iv.len ); } + err_setiv: err_setkey: err_decrypt: free ( cipher_key.data ); diff --git a/src/crypto/crypto_null.c b/src/crypto/crypto_null.c index 5d0531f11..a8d4519f8 100644 --- a/src/crypto/crypto_null.c +++ b/src/crypto/crypto_null.c @@ -67,10 +67,11 @@ int cipher_null_setkey ( struct cipher_algorithm *cipher __unused, return 0; } -void cipher_null_setiv ( struct cipher_algorithm *cipher __unused, - void *ctx __unused, const void *iv __unused, - size_t ivlen __unused ) { +int cipher_null_setiv ( struct cipher_algorithm *cipher __unused, + void *ctx __unused, const void *iv __unused, + size_t ivlen __unused ) { /* Do nothing */ + return 0; } void cipher_null_encrypt ( struct cipher_algorithm *cipher __unused, diff --git a/src/crypto/gcm.c b/src/crypto/gcm.c index c0e32a320..3948e0a07 100644 --- a/src/crypto/gcm.c +++ b/src/crypto/gcm.c @@ -452,9 +452,10 @@ int gcm_setkey ( struct cipher_algorithm *cipher, void *ctx, * @v ctx Context * @v iv Initialisation vector * @v ivlen Initialisation vector length + * @ret rc Return status code */ -void gcm_setiv ( struct cipher_algorithm *cipher, void *ctx, - const void *iv, size_t ivlen ) { +int gcm_setiv ( struct cipher_algorithm *cipher, void *ctx, + const void *iv, size_t ivlen ) { gcm_context_t ( cipher->ctxsize ) *context = ctx; /* Reset non-key state */ @@ -490,6 +491,7 @@ void gcm_setiv ( struct cipher_algorithm *cipher, void *ctx, DBGC2 ( context, "GCM %p Y[0]:\n", context ); DBGC2_HDA ( context, 0, &context->gcm.ctr, sizeof ( context->gcm.ctr ) ); + return 0; } /** diff --git a/src/include/ipxe/cbc.h b/src/include/ipxe/cbc.h index 11979f2e2..ddc9c5986 100644 --- a/src/include/ipxe/cbc.h +++ b/src/include/ipxe/cbc.h @@ -21,8 +21,8 @@ FILE_SECBOOT ( PERMITTED ); extern int cbc_setkey ( struct cipher_algorithm *cipher, void *ctx, const void *key, size_t keylen ); -extern void cbc_setiv ( struct cipher_algorithm *cipher, void *ctx, - const void *iv, size_t ivlen ); +extern int cbc_setiv ( struct cipher_algorithm *cipher, void *ctx, + const void *iv, size_t ivlen ); extern void cbc_encrypt ( struct cipher_algorithm *cipher, void *ctx, const void *src, void *dst, size_t len ); extern void cbc_decrypt ( struct cipher_algorithm *cipher, void *ctx, diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index 933103dfb..d2e0d18db 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -96,9 +96,10 @@ struct cipher_algorithm { * @v ctx Context * @v iv Initialisation vector * @v ivlen Initialisation vector length + * @ret rc Return status code */ - void ( * setiv ) ( struct cipher_algorithm *cipher, void *ctx, - const void *iv, size_t ivlen ); + int ( * setiv ) ( struct cipher_algorithm *cipher, void *ctx, + const void *iv, size_t ivlen ); /** Encrypt data * * @v cipher Cipher algorithm @@ -296,10 +297,10 @@ cipher_setkey ( struct cipher_algorithm *cipher, void *ctx, return cipher->setkey ( cipher, ctx, key, keylen ); } -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int cipher_setiv ( struct cipher_algorithm *cipher, void *ctx, const void *iv, size_t ivlen ) { - cipher->setiv ( cipher, ctx, iv, ivlen ); + return cipher->setiv ( cipher, ctx, iv, ivlen ); } static inline __attribute__ (( always_inline )) void @@ -414,8 +415,8 @@ extern void digest_null_final ( struct digest_algorithm *digest, void *ctx, extern int cipher_null_setkey ( struct cipher_algorithm *cipher, void *ctx, const void *key, size_t keylen ); -extern void cipher_null_setiv ( struct cipher_algorithm *cipehr, void *ctx, - const void *iv, size_t ivlen ); +extern int cipher_null_setiv ( struct cipher_algorithm *cipehr, void *ctx, + const void *iv, size_t ivlen ); extern void cipher_null_encrypt ( struct cipher_algorithm *cipher, void *ctx, const void *src, void *dst, size_t len ); extern void cipher_null_decrypt ( struct cipher_algorithm *cipher, void *ctx, diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 9f4661790..19570d09e 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -451,6 +451,7 @@ FILE_SECBOOT ( PERMITTED ); #define ERRFILE_ecdsa ( ERRFILE_OTHER | 0x00690000 ) #define ERRFILE_crypto_null ( ERRFILE_OTHER | 0x006a0000 ) #define ERRFILE_ffdhe ( ERRFILE_OTHER | 0x006b0000 ) +#define ERRFILE_cbc ( ERRFILE_OTHER | 0x006c0000 ) /** @} */ diff --git a/src/include/ipxe/gcm.h b/src/include/ipxe/gcm.h index d794a7283..9976a4d82 100644 --- a/src/include/ipxe/gcm.h +++ b/src/include/ipxe/gcm.h @@ -67,8 +67,8 @@ struct gcm_context { extern int gcm_setkey ( struct cipher_algorithm *cipher, void *ctx, const void *key, size_t keylen ); -extern void gcm_setiv ( struct cipher_algorithm *cipher, void *ctx, - const void *iv, size_t ivlen ); +extern int gcm_setiv ( struct cipher_algorithm *cipher, void *ctx, + const void *iv, size_t ivlen ); extern void gcm_encrypt ( struct cipher_algorithm *cipher, void *ctx, const void *src, void *dst, size_t len ); extern void gcm_decrypt ( struct cipher_algorithm *cipher, void *ctx, diff --git a/src/net/peerblk.c b/src/net/peerblk.c index 6efd4ebf6..e469f6d6c 100644 --- a/src/net/peerblk.c +++ b/src/net/peerblk.c @@ -1017,6 +1017,8 @@ static int peerblk_parse_iv ( struct peerdist_block *peerblk, size_t buf_len, peerblk_msg_blk_t ( digestsize, buf_len, vrf_len, blksize ) *msg = peerblk->buffer.data; size_t len = peerblk->buffer.len; + size_t ivlen; + int rc; /* Check message length */ if ( len < sizeof ( *msg ) ) { @@ -1025,18 +1027,16 @@ static int peerblk_parse_iv ( struct peerdist_block *peerblk, size_t buf_len, peerblk->segment, peerblk->block, len ); return -ERANGE; } - - /* Check initialisation vector size */ - if ( ntohl ( msg->msg.iv.iv.blksize ) != blksize ) { - DBGC ( peerblk, "PEERBLK %p %d.%d incorrect IV size %d\n", - peerblk, peerblk->segment, peerblk->block, - ntohl ( msg->msg.iv.iv.blksize ) ); - return -EPROTO; - } + ivlen = ntohl ( msg->msg.iv.iv.blksize ); /* Set initialisation vector */ - cipher_setiv ( peerblk->cipher, peerblk->cipherctx, msg->msg.iv.data, - blksize ); + if ( ( rc = cipher_setiv ( peerblk->cipher, peerblk->cipherctx, + msg->msg.iv.data, ivlen ) ) != 0 ) { + DBGC ( peerblk, "PEERBLK %p %d.%d could not set IV: %s\n", + peerblk, peerblk->segment, peerblk->block, + strerror ( rc ) ); + return rc; + } return 0; } diff --git a/src/net/tls.c b/src/net/tls.c index b5aa8a43c..a8ca95162 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -3089,8 +3089,12 @@ static int tls_send_record ( struct tls_connection *tls, unsigned int type, sizeof ( iv.rec ) ) ) != 0 ) { goto err_random; } - cipher_setiv ( cipher, cipherspec->cipher_ctx, &iv, - sizeof ( iv ) ); + if ( ( rc = cipher_setiv ( cipher, cipherspec->cipher_ctx, &iv, + sizeof ( iv ) ) ) != 0 ) { + DBGC ( tls, "TLS %p could not set TX IV: %s\n", + tls, strerror ( rc ) ); + goto err_setiv; + } /* Construct and process authentication data */ authhdr.seq = cpu_to_be64 ( tls->tx.seq ); @@ -3171,6 +3175,7 @@ static int tls_send_record ( struct tls_connection *tls, unsigned int type, return 0; err_deliver: + err_setiv: err_random: free_iob ( iobuf ); return rc; @@ -3304,7 +3309,12 @@ static int tls_new_ciphertext ( struct tls_connection *tls, authhdr.header.length = htons ( len ); /* Set initialisation vector */ - cipher_setiv ( cipher, cipherspec->cipher_ctx, &iv, sizeof ( iv ) ); + if ( ( rc = cipher_setiv ( cipher, cipherspec->cipher_ctx, &iv, + sizeof ( iv ) ) ) != 0 ) { + DBGC ( tls, "TLS %p could not set RX IV: %s\n", + tls, strerror ( rc ) ); + return rc; + } /* Process authentication data, if applicable */ if ( is_auth_cipher ( cipher ) ) { diff --git a/src/tests/cipher_test.c b/src/tests/cipher_test.c index b7a982752..68108cef6 100644 --- a/src/tests/cipher_test.c +++ b/src/tests/cipher_test.c @@ -62,7 +62,8 @@ void cipher_encrypt_okx ( struct cipher_test *test, const char *file, /* Initialise cipher */ okx ( cipher_setkey ( cipher, ctx, test->key, test->key_len ) == 0, file, line ); - cipher_setiv ( cipher, ctx, test->iv, test->iv_len ); + okx ( cipher_setiv ( cipher, ctx, test->iv, test->iv_len ) == 0, + file, line ); /* Process additional data, if applicable */ if ( test->additional_len ) { @@ -83,7 +84,8 @@ void cipher_encrypt_okx ( struct cipher_test *test, const char *file, okx ( memcmp ( auth, test->auth, test->auth_len ) == 0, file, line ); /* Reset initialisation vector */ - cipher_setiv ( cipher, ctx, test->iv, test->iv_len ); + okx ( cipher_setiv ( cipher, ctx, test->iv, test->iv_len ) == 0, + file, line ); /* Process additional data, if applicable */ if ( test->additional_len ) { @@ -121,7 +123,8 @@ void cipher_decrypt_okx ( struct cipher_test *test, const char *file, /* Initialise cipher */ okx ( cipher_setkey ( cipher, ctx, test->key, test->key_len ) == 0, file, line ); - cipher_setiv ( cipher, ctx, test->iv, test->iv_len ); + okx ( cipher_setiv ( cipher, ctx, test->iv, test->iv_len ) == 0, + file, line ); /* Process additional data, if applicable */ if ( test->additional_len ) { @@ -142,7 +145,8 @@ void cipher_decrypt_okx ( struct cipher_test *test, const char *file, okx ( memcmp ( auth, test->auth, test->auth_len ) == 0, file, line ); /* Reset initialisation vector */ - cipher_setiv ( cipher, ctx, test->iv, test->iv_len ); + okx ( cipher_setiv ( cipher, ctx, test->iv, test->iv_len ) == 0, + file, line ); /* Process additional data, if applicable */ if ( test->additional_len ) { @@ -219,7 +223,8 @@ cipher_cost ( struct cipher_algorithm *cipher, size_t key_len, /* Initialise cipher */ rc = cipher_setkey ( cipher, ctx, key, key_len ); assert ( rc == 0 ); - cipher_setiv ( cipher, ctx, iv, sizeof ( iv ) ); + rc = cipher_setiv ( cipher, ctx, iv, sizeof ( iv ) ); + assert ( rc == 0 ); /* Profile cipher operation */ memset ( &profiler, 0, sizeof ( profiler ) );