Skip to content
This repository has been archived by the owner on Aug 29, 2024. It is now read-only.

Commit

Permalink
[crypto] Pass image as parameter to CMS functions
Browse files Browse the repository at this point in the history
The cms_signature() and cms_verify() functions currently accept raw
data pointers.  This will not be possible for cms_decrypt(), which
will need the ability to extract fragments of ASN.1 data from a
potentially large image.

Change cms_signature() and cms_verify() to accept an image as an input
parameter, and move the responsibility for setting the image trust
flag within cms_verify() since that now becomes a more natural fit.

Signed-off-by: Michael Brown <[email protected]>
  • Loading branch information
mcb30 committed Aug 13, 2024
1 parent 96fb7a0 commit 3b4d0cb
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 65 deletions.
48 changes: 33 additions & 15 deletions src/crypto/cms.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <errno.h>
#include <ipxe/asn1.h>
#include <ipxe/x509.h>
#include <ipxe/image.h>
#include <ipxe/malloc.h>
#include <ipxe/uaccess.h>
#include <ipxe/cms.h>
Expand Down Expand Up @@ -372,7 +373,6 @@ static int cms_parse ( struct cms_signature *sig,
asn1_enter ( &cursor, ASN1_SEQUENCE );

/* Parse contentType */

if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 )
return rc;
asn1_skip_any ( &cursor );
Expand Down Expand Up @@ -453,16 +453,16 @@ static void cms_free ( struct refcnt *refcnt ) {
/**
* Create CMS signature
*
* @v data Raw signature data
* @v len Length of raw data
* @v image Image
* @ret sig CMS signature
* @ret rc Return status code
*
* On success, the caller holds a reference to the CMS signature, and
* is responsible for ultimately calling cms_put().
*/
int cms_signature ( const void *data, size_t len, struct cms_signature **sig ) {
struct asn1_cursor cursor;
int cms_signature ( struct image *image, struct cms_signature **sig ) {
struct asn1_cursor *raw;
int next;
int rc;

/* Allocate and initialise signature */
Expand All @@ -481,18 +481,30 @@ int cms_signature ( const void *data, size_t len, struct cms_signature **sig ) {
goto err_alloc_chain;
}

/* Initialise cursor */
cursor.data = data;
cursor.len = len;
asn1_shrink_any ( &cursor );
/* Get raw signature data */
next = image_asn1 ( image, 0, &raw );
if ( next < 0 ) {
rc = next;
DBGC ( *sig, "CMS %p could not get raw ASN.1 data: %s\n",
*sig, strerror ( rc ) );
goto err_asn1;
}

/* Use only first signature in image */
asn1_shrink_any ( raw );

/* Parse signature */
if ( ( rc = cms_parse ( *sig, &cursor ) ) != 0 )
if ( ( rc = cms_parse ( *sig, raw ) ) != 0 )
goto err_parse;

/* Free raw signature data */
free ( raw );

return 0;

err_parse:
free ( raw );
err_asn1:
err_alloc_chain:
cms_put ( *sig );
err_alloc:
Expand Down Expand Up @@ -642,29 +654,32 @@ static int cms_verify_signer_info ( struct cms_signature *sig,
* Verify CMS signature
*
* @v sig CMS signature
* @v data Signed data
* @v len Length of signed data
* @v image Signed image
* @v name Required common name, or NULL to check all signatures
* @v time Time at which to validate certificates
* @v store Certificate store, or NULL to use default
* @v root Root certificate list, or NULL to use default
* @ret rc Return status code
*/
int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
int cms_verify ( struct cms_signature *sig, struct image *image,
const char *name, time_t time, struct x509_chain *store,
struct x509_root *root ) {
struct cms_signer_info *info;
struct x509_certificate *cert;
int count = 0;
int rc;

/* Mark image as untrusted */
image_untrust ( image );

/* Verify using all signerInfos */
list_for_each_entry ( info, &sig->info, list ) {
cert = x509_first ( info->chain );
if ( name && ( x509_check_name ( cert, name ) != 0 ) )
continue;
if ( ( rc = cms_verify_signer_info ( sig, info, data, len, time,
store, root ) ) != 0 )
if ( ( rc = cms_verify_signer_info ( sig, info, image->data,
image->len, time, store,
root ) ) != 0 )
return rc;
count++;
}
Expand All @@ -681,5 +696,8 @@ int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
}
}

/* Mark image as trusted */
image_trust ( image );

return 0;
}
6 changes: 4 additions & 2 deletions src/include/ipxe/cms.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/refcnt.h>
#include <ipxe/uaccess.h>

struct image;

/** CMS signer information */
struct cms_signer_info {
/** List of signer information blocks */
Expand Down Expand Up @@ -67,9 +69,9 @@ cms_put ( struct cms_signature *sig ) {
ref_put ( &sig->refcnt );
}

extern int cms_signature ( const void *data, size_t len,
extern int cms_signature ( struct image *image,
struct cms_signature **sig );
extern int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
extern int cms_verify ( struct cms_signature *sig, struct image *image,
const char *name, time_t time, struct x509_chain *store,
struct x509_root *root );

Expand Down
86 changes: 61 additions & 25 deletions src/tests/cms_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <string.h>
#include <ipxe/sha256.h>
#include <ipxe/x509.h>
#include <ipxe/image.h>
#include <ipxe/uaccess.h>
#include <ipxe/der.h>
#include <ipxe/cms.h>
#include <ipxe/test.h>

Expand All @@ -45,19 +47,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );

/** CMS test code blob */
struct cms_test_code {
/** Data */
const void *data;
/** Length of data */
size_t len;
/** Code image */
struct image image;
};

/** CMS test signature */
struct cms_test_signature {
/** Data */
const void *data;
/** Length of data */
size_t len;

/** Signature image */
struct image image;
/** Parsed signature */
struct cms_signature *sig;
};
Expand All @@ -69,19 +66,29 @@ struct cms_test_signature {
#define FINGERPRINT(...) { __VA_ARGS__ }

/** Define a test code blob */
#define SIGNED_CODE( name, DATA ) \
static const uint8_t name ## _data[] = DATA; \
static struct cms_test_code name = { \
.data = name ## _data, \
.len = sizeof ( name ## _data ), \
#define SIGNED_CODE( NAME, DATA ) \
static const uint8_t NAME ## _data[] = DATA; \
static struct cms_test_code NAME = { \
.image = { \
.refcnt = REF_INIT ( ref_no_free ), \
.name = #NAME, \
.type = &der_image_type, \
.data = ( userptr_t ) ( NAME ## _data ), \
.len = sizeof ( NAME ## _data ), \
}, \
}

/** Define a test signature */
#define SIGNATURE( name, DATA ) \
static const uint8_t name ## _data[] = DATA; \
static struct cms_test_signature name = { \
.data = name ## _data, \
.len = sizeof ( name ## _data ), \
#define SIGNATURE( NAME, DATA ) \
static const uint8_t NAME ## _data[] = DATA; \
static struct cms_test_signature NAME = { \
.image = { \
.refcnt = REF_INIT ( ref_no_free ), \
.name = #NAME, \
.type = &der_image_type, \
.data = ( userptr_t ) ( NAME ## _data ), \
.len = sizeof ( NAME ## _data ), \
}, \
}

/** Code that has been signed */
Expand Down Expand Up @@ -1353,9 +1360,16 @@ static time_t test_expired = 1375573111ULL; /* Sat Aug 3 23:38:31 2013 */
*/
static void cms_signature_okx ( struct cms_test_signature *sgn,
const char *file, unsigned int line ) {
const void *data = ( ( void * ) sgn->image.data );

/* Fix up image data pointer */
sgn->image.data = virt_to_user ( data );

/* Check ability to parse signature */
okx ( cms_signature ( &sgn->image, &sgn->sig ) == 0, file, line );

okx ( cms_signature ( sgn->data, sgn->len, &sgn->sig ) == 0,
file, line );
/* Reset image data pointer */
sgn->image.data = ( ( userptr_t ) data );
}
#define cms_signature_ok( sgn ) \
cms_signature_okx ( sgn, __FILE__, __LINE__ )
Expand All @@ -1377,10 +1391,21 @@ static void cms_verify_okx ( struct cms_test_signature *sgn,
time_t time, struct x509_chain *store,
struct x509_root *root, const char *file,
unsigned int line ) {
const void *data = ( ( void * ) code->image.data );

/* Fix up image data pointer */
code->image.data = virt_to_user ( data );

/* Invalidate any certificates from previous tests */
x509_invalidate_chain ( sgn->sig->certificates );
okx ( cms_verify ( sgn->sig, virt_to_user ( code->data ), code->len,
name, time, store, root ) == 0, file, line );

/* Check ability to verify signature */
okx ( cms_verify ( sgn->sig, &code->image, name, time, store,
root ) == 0, file, line );
okx ( code->image.flags & IMAGE_TRUSTED, file, line );

/* Reset image data pointer */
code->image.data = ( ( userptr_t ) data );
}
#define cms_verify_ok( sgn, code, name, time, store, root ) \
cms_verify_okx ( sgn, code, name, time, store, root, \
Expand All @@ -1403,10 +1428,21 @@ static void cms_verify_fail_okx ( struct cms_test_signature *sgn,
time_t time, struct x509_chain *store,
struct x509_root *root, const char *file,
unsigned int line ) {
const void *data = ( ( void * ) code->image.data );

/* Fix up image data pointer */
code->image.data = virt_to_user ( data );

/* Invalidate any certificates from previous tests */
x509_invalidate_chain ( sgn->sig->certificates );
okx ( cms_verify ( sgn->sig, virt_to_user ( code->data ), code->len,
name, time, store, root ) != 0, file, line );

/* Check inability to verify signature */
okx ( cms_verify ( sgn->sig, &code->image, name, time, store,
root ) != 0, file, line );
okx ( ! ( code->image.flags & IMAGE_TRUSTED ), file, line );

/* Reset image data pointer */
code->image.data = ( ( userptr_t ) data );
}
#define cms_verify_fail_ok( sgn, code, name, time, store, root ) \
cms_verify_fail_okx ( sgn, code, name, time, store, root, \
Expand Down
26 changes: 3 additions & 23 deletions src/usr/imgtrust.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,31 +50,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
int imgverify ( struct image *image, struct image *signature,
const char *name ) {
struct asn1_cursor *data;
struct cms_signature *sig;
struct cms_signer_info *info;
time_t now;
int next;
int rc;

/* Mark image as untrusted */
image_untrust ( image );

/* Get raw signature data */
next = image_asn1 ( signature, 0, &data );
if ( next < 0 ) {
rc = next;
goto err_asn1;
}

/* Parse signature */
if ( ( rc = cms_signature ( data->data, data->len, &sig ) ) != 0 )
if ( ( rc = cms_signature ( signature, &sig ) ) != 0 )
goto err_parse;

/* Free raw signature data */
free ( data );
data = NULL;

/* Complete all certificate chains */
list_for_each_entry ( info, &sig->info, list ) {
if ( ( rc = create_validator ( &monojob, info->chain,
Expand All @@ -86,16 +70,14 @@ int imgverify ( struct image *image, struct image *signature,

/* Use signature to verify image */
now = time ( NULL );
if ( ( rc = cms_verify ( sig, image->data, image->len,
name, now, NULL, NULL ) ) != 0 )
if ( ( rc = cms_verify ( sig, image, name, now, NULL, NULL ) ) != 0 )
goto err_verify;

/* Drop reference to signature */
cms_put ( sig );
sig = NULL;

/* Mark image as trusted */
image_trust ( image );
/* Record signature verification */
syslog ( LOG_NOTICE, "Image \"%s\" signature OK\n", image->name );

return 0;
Expand All @@ -105,8 +87,6 @@ int imgverify ( struct image *image, struct image *signature,
err_create_validator:
cms_put ( sig );
err_parse:
free ( data );
err_asn1:
syslog ( LOG_ERR, "Image \"%s\" signature bad: %s\n",
image->name, strerror ( rc ) );
return rc;
Expand Down

0 comments on commit 3b4d0cb

Please sign in to comment.