]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[crypto] Pass image as parameter to CMS functions
authorMichael Brown <mcb30@ipxe.org>
Fri, 9 Aug 2024 15:33:51 +0000 (16:33 +0100)
committerMichael Brown <mcb30@ipxe.org>
Tue, 13 Aug 2024 11:30:51 +0000 (12:30 +0100)
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>
src/crypto/cms.c
src/include/ipxe/cms.h
src/tests/cms_test.c
src/usr/imgtrust.c

index 19a0ce7ad71dbacd4b6812fe96c94b419b15dde2..cbc0736bb2dc4a0b597ee4dca572450925b33b0b 100644 (file)
@@ -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>
@@ -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 );
@@ -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 */
@@ -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:
@@ -642,15 +654,14 @@ 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;
@@ -658,13 +669,17 @@ int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
        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 @@ int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len,
                }
        }
 
+       /* Mark image as trusted */
+       image_trust ( image );
+
        return 0;
 }
index 7adf724b2ba9050a5f8569bf69595610ec564f2c..cca7779c563d9fb42224758c1c82be9fa7396dd1 100644 (file)
@@ -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 */
@@ -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 );
 
index f35fa206d922c3c30111f546fb3076650109249e..d98b2c3e5c35969927f53da2507003d6f57ba2a5 100644 (file)
@@ -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>
 
@@ -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;
 };
@@ -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 */
@@ -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__ )
@@ -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,            \
@@ -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,       \
index e7c2067a0ba817ca33fe1e4e50e4fca5dc3e66b9..54ea3378fcc322e765f7c8fda95c84b786628b3e 100644 (file)
@@ -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,
@@ -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;
@@ -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;