[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>
pull/1171/head
Michael Brown 2024-08-23 12:25:36 +01:00
parent 46937a9df6
commit bdb5b4aef4
2 changed files with 15 additions and 29 deletions

View File

@ -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;

View File

@ -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;