aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2024-08-23 12:25:36 +0100
committerMichael Brown <mcb30@ipxe.org>2024-08-23 13:43:42 +0100
commitbdb5b4aef46ed34b47094652f3eefc7d0463d166 (patch)
treefe75769107040f350e611c0bb4b4f5c340e1f861
parent46937a9df622d1e9fb5b1e926a04176b8855fdce (diff)
downloadipxe-bdb5b4aef46ed34b47094652f3eefc7d0463d166.tar.gz
[crypto] Hold CMS message as a single ASN.1 object
Reduce the number of dynamic allocations required to parse a CMS message by retaining the ASN.1 cursor returned from image_asn1() for the lifetime of the CMS message. This allows embedded ASN.1 cursors to be used for parsed objects within the message, such as embedded signatures. Signed-off-by: Michael Brown <mcb30@ipxe.org>
-rw-r--r--src/crypto/cms.c38
-rw-r--r--src/include/ipxe/cms.h6
2 files changed, 15 insertions, 29 deletions
diff --git a/src/crypto/cms.c b/src/crypto/cms.c
index 2e153d819..a596d22e2 100644
--- a/src/crypto/cms.c
+++ b/src/crypto/cms.c
@@ -293,26 +293,18 @@ static int cms_parse_pubkey_algorithm ( struct cms_message *cms,
static int cms_parse_value ( struct cms_message *cms,
struct cms_participant *part,
const struct asn1_cursor *raw ) {
- struct asn1_cursor cursor;
int rc;
/* Enter signature */
- memcpy ( &cursor, raw, sizeof ( cursor ) );
- if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) {
+ memcpy ( &part->value, raw, sizeof ( part->value ) );
+ if ( ( rc = asn1_enter ( &part->value, ASN1_OCTET_STRING ) ) != 0 ) {
DBGC ( cms, "CMS %p/%p could not locate value:\n",
cms, part );
DBGC_HDA ( cms, 0, raw->data, raw->len );
return rc;
}
-
- /* Record signature */
- part->len = cursor.len;
- part->value = malloc ( part->len );
- if ( ! part->value )
- return -ENOMEM;
- memcpy ( part->value, cursor.data, part->len );
DBGC ( cms, "CMS %p/%p value is:\n", cms, part );
- DBGC_HDA ( cms, 0, part->value, part->len );
+ DBGC_HDA ( cms, 0, part->value.data, part->value.len );
return 0;
}
@@ -456,16 +448,14 @@ static int cms_parse_signed ( struct cms_message *cms,
* Parse CMS message from ASN.1 data
*
* @v cms CMS message
- * @v raw ASN.1 cursor
* @ret rc Return status code
*/
-static int cms_parse ( struct cms_message *cms,
- const struct asn1_cursor *raw ) {
+static int cms_parse ( struct cms_message *cms ) {
struct asn1_cursor cursor;
int rc;
/* Enter contentInfo */
- memcpy ( &cursor, raw, sizeof ( cursor ) );
+ memcpy ( &cursor, cms->raw, sizeof ( cursor ) );
asn1_enter ( &cursor, ASN1_SEQUENCE );
/* Parse contentType */
@@ -497,10 +487,10 @@ static void cms_free ( struct refcnt *refcnt ) {
list_for_each_entry_safe ( part, tmp, &cms->participants, list ) {
list_del ( &part->list );
x509_chain_put ( part->chain );
- free ( part->value );
free ( part );
}
x509_chain_put ( cms->certificates );
+ free ( cms->raw );
free ( cms );
}
@@ -515,7 +505,6 @@ static void cms_free ( struct refcnt *refcnt ) {
* is responsible for ultimately calling cms_put().
*/
int cms_message ( struct image *image, struct cms_message **cms ) {
- struct asn1_cursor *raw;
int next;
int rc;
@@ -529,7 +518,7 @@ int cms_message ( struct image *image, struct cms_message **cms ) {
INIT_LIST_HEAD ( &(*cms)->participants );
/* Get raw message data */
- next = image_asn1 ( image, 0, &raw );
+ next = image_asn1 ( image, 0, &(*cms)->raw );
if ( next < 0 ) {
rc = next;
DBGC ( *cms, "CMS %p could not get raw ASN.1 data: %s\n",
@@ -538,19 +527,15 @@ int cms_message ( struct image *image, struct cms_message **cms ) {
}
/* Use only first message in image */
- asn1_shrink_any ( raw );
+ asn1_shrink_any ( (*cms)->raw );
/* Parse message */
- if ( ( rc = cms_parse ( *cms, raw ) ) != 0 )
+ if ( ( rc = cms_parse ( *cms ) ) != 0 )
goto err_parse;
- /* Free raw message data */
- free ( raw );
-
return 0;
err_parse:
- free ( raw );
err_asn1:
cms_put ( *cms );
err_alloc:
@@ -612,7 +597,8 @@ static int cms_verify_digest ( struct cms_message *cms,
userptr_t data, size_t len ) {
struct digest_algorithm *digest = part->digest;
struct pubkey_algorithm *pubkey = part->pubkey;
- struct asn1_cursor *key = &cert->subject.public_key.raw;
+ const struct asn1_cursor *key = &cert->subject.public_key.raw;
+ const struct asn1_cursor *value = &part->value;
uint8_t digest_out[ digest->digestsize ];
int rc;
@@ -621,7 +607,7 @@ static int cms_verify_digest ( struct cms_message *cms,
/* Verify digest */
if ( ( rc = pubkey_verify ( pubkey, key, digest, digest_out,
- part->value, part->len ) ) != 0 ) {
+ value->data, value->len ) ) != 0 ) {
DBGC ( cms, "CMS %p/%p signature verification failed: %s\n",
cms, part, strerror ( rc ) );
return rc;
diff --git a/src/include/ipxe/cms.h b/src/include/ipxe/cms.h
index 1c8a0c587..bffb06bfe 100644
--- a/src/include/ipxe/cms.h
+++ b/src/include/ipxe/cms.h
@@ -48,15 +48,15 @@ struct cms_participant {
struct pubkey_algorithm *pubkey;
/** Signature or key value */
- void *value;
- /** Length of signature or key value */
- size_t len;
+ struct asn1_cursor value;
};
/** A CMS message */
struct cms_message {
/** Reference count */
struct refcnt refcnt;
+ /** Raw ASN.1 data */
+ struct asn1_cursor *raw;
/** Message type */
struct cms_type *type;