[crypto] Pass image as parameter to CMS functions
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 <mcb30@ipxe.org>
diff --git a/src/crypto/cms.c b/src/crypto/cms.c
index 19a0ce7..cbc0736 100644
--- a/src/crypto/cms.c
+++ b/src/crypto/cms.c
@@ -37,6 +37,7 @@
#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>
@@ -372,7 +373,6 @@
asn1_enter ( &cursor, ASN1_SEQUENCE );
/* Parse contentType */
-
if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 )
return rc;
asn1_skip_any ( &cursor );
@@ -453,16 +453,16 @@
/**
* 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 */
@@ -481,18 +481,30 @@
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:
@@ -642,15 +654,14 @@
* 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;
@@ -658,13 +669,17 @@
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++;
}
@@ -681,5 +696,8 @@
}
}
+ /* Mark image as trusted */
+ image_trust ( image );
+
return 0;
}
diff --git a/src/include/ipxe/cms.h b/src/include/ipxe/cms.h
index 7adf724..cca7779 100644
--- a/src/include/ipxe/cms.h
+++ b/src/include/ipxe/cms.h
@@ -16,6 +16,8 @@
#include <ipxe/refcnt.h>
#include <ipxe/uaccess.h>
+struct image;
+
/** CMS signer information */
struct cms_signer_info {
/** List of signer information blocks */
@@ -67,9 +69,9 @@
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 );
diff --git a/src/tests/cms_test.c b/src/tests/cms_test.c
index f35fa20..d98b2c3 100644
--- a/src/tests/cms_test.c
+++ b/src/tests/cms_test.c
@@ -36,7 +36,9 @@
#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>
@@ -45,19 +47,14 @@
/** 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;
};
@@ -69,19 +66,29 @@
#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 */
@@ -1353,9 +1360,16 @@
*/
static void cms_signature_okx ( struct cms_test_signature *sgn,
const char *file, unsigned int line ) {
+ const void *data = ( ( void * ) sgn->image.data );
- okx ( cms_signature ( sgn->data, sgn->len, &sgn->sig ) == 0,
- file, line );
+ /* 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 );
+
+ /* Reset image data pointer */
+ sgn->image.data = ( ( userptr_t ) data );
}
#define cms_signature_ok( sgn ) \
cms_signature_okx ( sgn, __FILE__, __LINE__ )
@@ -1377,10 +1391,21 @@
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, \
@@ -1403,10 +1428,21 @@
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, \
diff --git a/src/usr/imgtrust.c b/src/usr/imgtrust.c
index e7c2067..54ea337 100644
--- a/src/usr/imgtrust.c
+++ b/src/usr/imgtrust.c
@@ -50,31 +50,15 @@
*/
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,
@@ -86,16 +70,14 @@
/* 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;
@@ -105,8 +87,6 @@
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;