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