diff options
-rw-r--r-- | src/crypto/cms.c | 48 | ||||
-rw-r--r-- | src/include/ipxe/cms.h | 6 | ||||
-rw-r--r-- | src/tests/cms_test.c | 86 | ||||
-rw-r--r-- | src/usr/imgtrust.c | 26 |
4 files changed, 101 insertions, 65 deletions
diff --git a/src/crypto/cms.c b/src/crypto/cms.c index 19a0ce7ad..cbc0736bb 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -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; } diff --git a/src/include/ipxe/cms.h b/src/include/ipxe/cms.h index 7adf724b2..cca7779c5 100644 --- a/src/include/ipxe/cms.h +++ b/src/include/ipxe/cms.h @@ -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 ); diff --git a/src/tests/cms_test.c b/src/tests/cms_test.c index f35fa206d..d98b2c3e5 100644 --- a/src/tests/cms_test.c +++ b/src/tests/cms_test.c @@ -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, \ diff --git a/src/usr/imgtrust.c b/src/usr/imgtrust.c index e7c2067a0..54ea3378f 100644 --- a/src/usr/imgtrust.c +++ b/src/usr/imgtrust.c @@ -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; |