diff options
-rw-r--r-- | src/crypto/cms.c | 515 | ||||
-rw-r--r-- | src/include/ipxe/asn1.h | 2 | ||||
-rw-r--r-- | src/include/ipxe/cms.h | 87 | ||||
-rw-r--r-- | src/tests/cms_test.c | 24 | ||||
-rw-r--r-- | src/usr/imgtrust.c | 20 |
5 files changed, 364 insertions, 284 deletions
diff --git a/src/crypto/cms.c b/src/crypto/cms.c index cbc0736bb..1f33613f4 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -59,60 +59,68 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); __einfo_error ( EINFO_EACCES_NO_SIGNATURES ) #define EINFO_EACCES_NO_SIGNATURES \ __einfo_uniqify ( EINFO_EACCES, 0x05, "No signatures present" ) -#define EINVAL_DIGEST \ - __einfo_error ( EINFO_EINVAL_DIGEST ) -#define EINFO_EINVAL_DIGEST \ - __einfo_uniqify ( EINFO_EINVAL, 0x01, "Not a digest algorithm" ) -#define EINVAL_PUBKEY \ - __einfo_error ( EINFO_EINVAL_PUBKEY ) -#define EINFO_EINVAL_PUBKEY \ - __einfo_uniqify ( EINFO_EINVAL, 0x02, "Not a public-key algorithm" ) -#define ENOTSUP_SIGNEDDATA \ - __einfo_error ( EINFO_ENOTSUP_SIGNEDDATA ) -#define EINFO_ENOTSUP_SIGNEDDATA \ - __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Not a digital signature" ) - -/** "pkcs7-signedData" object identifier */ +#define ENOTSUP_TYPE \ + __einfo_error ( EINFO_ENOTSUP_TYPE ) +#define EINFO_ENOTSUP_TYPE \ + __einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unrecognised message type" ) + +static int cms_parse_signed ( struct cms_message *cms, + const struct asn1_cursor *raw ); + +/** "id-signedData" object identifier */ static uint8_t oid_signeddata[] = { ASN1_OID_SIGNEDDATA }; -/** "pkcs7-signedData" object identifier cursor */ -static struct asn1_cursor oid_signeddata_cursor = - ASN1_CURSOR ( oid_signeddata ); +/** CMS message types */ +static struct cms_type cms_types[] = { + { + .name = "signed", + .oid = ASN1_CURSOR ( oid_signeddata ), + .parse = cms_parse_signed, + }, +}; /** - * Parse CMS signature content type + * Parse CMS message content type * - * @v sig CMS signature + * @v cms CMS message * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_content_type ( struct cms_signature *sig, +static int cms_parse_content_type ( struct cms_message *cms, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; + struct cms_type *type; + unsigned int i; /* Enter contentType */ memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_OID ); - /* Check OID is pkcs7-signedData */ - if ( asn1_compare ( &cursor, &oid_signeddata_cursor ) != 0 ) { - DBGC ( sig, "CMS %p does not contain signedData:\n", sig ); - DBGC_HDA ( sig, 0, raw->data, raw->len ); - return -ENOTSUP_SIGNEDDATA; + /* Check for a recognised OID */ + for ( i = 0 ; i < ( sizeof ( cms_types ) / + sizeof ( cms_types[0] ) ) ; i++ ) { + type = &cms_types[i]; + if ( asn1_compare ( &cursor, &type->oid ) == 0 ) { + cms->type = type; + DBGC ( cms, "CMS %p contains %sData\n", + cms, type->name ); + return 0; + } } - DBGC ( sig, "CMS %p contains signedData\n", sig ); - return 0; + DBGC ( cms, "CMS %p is not a recognised message type:\n", cms ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); + return -ENOTSUP_TYPE; } /** - * Parse CMS signature certificate list + * Parse CMS message certificate list * - * @v sig CMS signature + * @v cms CMS message * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_certificates ( struct cms_signature *sig, +static int cms_parse_certificates ( struct cms_message *cms, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; struct x509_certificate *cert; @@ -126,16 +134,16 @@ static int cms_parse_certificates ( struct cms_signature *sig, while ( cursor.len ) { /* Add certificate to chain */ - if ( ( rc = x509_append_raw ( sig->certificates, cursor.data, + if ( ( rc = x509_append_raw ( cms->certificates, cursor.data, cursor.len ) ) != 0 ) { - DBGC ( sig, "CMS %p could not append certificate: %s\n", - sig, strerror ( rc) ); - DBGC_HDA ( sig, 0, cursor.data, cursor.len ); + DBGC ( cms, "CMS %p could not append certificate: %s\n", + cms, strerror ( rc) ); + DBGC_HDA ( cms, 0, cursor.data, cursor.len ); return rc; } - cert = x509_last ( sig->certificates ); - DBGC ( sig, "CMS %p found certificate %s\n", - sig, x509_name ( cert ) ); + cert = x509_last ( cms->certificates ); + DBGC ( cms, "CMS %p found certificate %s\n", + cms, x509_name ( cert ) ); /* Move to next certificate */ asn1_skip_any ( &cursor ); @@ -145,16 +153,16 @@ static int cms_parse_certificates ( struct cms_signature *sig, } /** - * Parse CMS signature signer identifier + * Parse CMS message participant identifier * - * @v sig CMS signature - * @v info Signer information to fill in + * @v cms CMS message + * @v part Participant information to fill in * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_signer_identifier ( struct cms_signature *sig, - struct cms_signer_info *info, - const struct asn1_cursor *raw ) { +static int cms_parse_identifier ( struct cms_message *cms, + struct cms_participant *part, + const struct asn1_cursor *raw ) { struct asn1_cursor cursor; struct asn1_cursor serial; struct asn1_cursor issuer; @@ -168,46 +176,46 @@ static int cms_parse_signer_identifier ( struct cms_signature *sig, /* Identify issuer */ memcpy ( &issuer, &cursor, sizeof ( issuer ) ); if ( ( rc = asn1_shrink ( &issuer, ASN1_SEQUENCE ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not locate issuer: %s\n", - sig, info, strerror ( rc ) ); - DBGC_HDA ( sig, 0, raw->data, raw->len ); + DBGC ( cms, "CMS %p/%p could not locate issuer: %s\n", + cms, part, strerror ( rc ) ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); return rc; } - DBGC ( sig, "CMS %p/%p issuer is:\n", sig, info ); - DBGC_HDA ( sig, 0, issuer.data, issuer.len ); + DBGC ( cms, "CMS %p/%p issuer is:\n", cms, part ); + DBGC_HDA ( cms, 0, issuer.data, issuer.len ); asn1_skip_any ( &cursor ); /* Identify serialNumber */ memcpy ( &serial, &cursor, sizeof ( serial ) ); if ( ( rc = asn1_shrink ( &serial, ASN1_INTEGER ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not locate serialNumber: %s\n", - sig, info, strerror ( rc ) ); - DBGC_HDA ( sig, 0, raw->data, raw->len ); + DBGC ( cms, "CMS %p/%p could not locate serialNumber: %s\n", + cms, part, strerror ( rc ) ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); return rc; } - DBGC ( sig, "CMS %p/%p serial number is:\n", sig, info ); - DBGC_HDA ( sig, 0, serial.data, serial.len ); + DBGC ( cms, "CMS %p/%p serial number is:\n", cms, part ); + DBGC_HDA ( cms, 0, serial.data, serial.len ); /* Identify certificate */ - cert = x509_find_issuer_serial ( sig->certificates, &issuer, &serial ); + cert = x509_find_issuer_serial ( cms->certificates, &issuer, &serial ); if ( ! cert ) { - DBGC ( sig, "CMS %p/%p could not identify signer's " - "certificate\n", sig, info ); + DBGC ( cms, "CMS %p/%p could not identify certificate\n", + cms, part ); return -ENOENT; } /* Append certificate to chain */ - if ( ( rc = x509_append ( info->chain, cert ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not append certificate: %s\n", - sig, info, strerror ( rc ) ); + if ( ( rc = x509_append ( part->chain, cert ) ) != 0 ) { + DBGC ( cms, "CMS %p/%p could not append certificate: %s\n", + cms, part, strerror ( rc ) ); return rc; } /* Append remaining certificates to chain */ - if ( ( rc = x509_auto_append ( info->chain, - sig->certificates ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not append certificates: %s\n", - sig, info, strerror ( rc ) ); + if ( ( rc = x509_auto_append ( part->chain, + cms->certificates ) ) != 0 ) { + DBGC ( cms, "CMS %p/%p could not append certificates: %s\n", + cms, part, strerror ( rc ) ); return rc; } @@ -215,110 +223,110 @@ static int cms_parse_signer_identifier ( struct cms_signature *sig, } /** - * Parse CMS signature digest algorithm + * Parse CMS message digest algorithm * - * @v sig CMS signature - * @v info Signer information to fill in + * @v cms CMS message + * @v part Participant information to fill in * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_digest_algorithm ( struct cms_signature *sig, - struct cms_signer_info *info, +static int cms_parse_digest_algorithm ( struct cms_message *cms, + struct cms_participant *part, const struct asn1_cursor *raw ) { struct asn1_algorithm *algorithm; int rc; /* Identify algorithm */ if ( ( rc = asn1_digest_algorithm ( raw, &algorithm ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not identify digest algorithm: " - "%s\n", sig, info, strerror ( rc ) ); - DBGC_HDA ( sig, 0, raw->data, raw->len ); + DBGC ( cms, "CMS %p/%p could not identify digest algorithm: " + "%s\n", cms, part, strerror ( rc ) ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); return rc; } /* Record digest algorithm */ - info->digest = algorithm->digest; - DBGC ( sig, "CMS %p/%p digest algorithm is %s\n", - sig, info, algorithm->name ); + part->digest = algorithm->digest; + DBGC ( cms, "CMS %p/%p digest algorithm is %s\n", + cms, part, algorithm->name ); return 0; } /** - * Parse CMS signature algorithm + * Parse CMS message public-key algorithm * - * @v sig CMS signature - * @v info Signer information to fill in + * @v cms CMS message + * @v part Participant information to fill in * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_signature_algorithm ( struct cms_signature *sig, - struct cms_signer_info *info, - const struct asn1_cursor *raw ) { +static int cms_parse_pubkey_algorithm ( struct cms_message *cms, + struct cms_participant *part, + const struct asn1_cursor *raw ) { struct asn1_algorithm *algorithm; int rc; /* Identify algorithm */ if ( ( rc = asn1_pubkey_algorithm ( raw, &algorithm ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not identify public-key " - "algorithm: %s\n", sig, info, strerror ( rc ) ); - DBGC_HDA ( sig, 0, raw->data, raw->len ); + DBGC ( cms, "CMS %p/%p could not identify public-key " + "algorithm: %s\n", cms, part, strerror ( rc ) ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); return rc; } - /* Record signature algorithm */ - info->pubkey = algorithm->pubkey; - DBGC ( sig, "CMS %p/%p public-key algorithm is %s\n", - sig, info, algorithm->name ); + /* Record public-key algorithm */ + part->pubkey = algorithm->pubkey; + DBGC ( cms, "CMS %p/%p public-key algorithm is %s\n", + cms, part, algorithm->name ); return 0; } /** - * Parse CMS signature value + * Parse CMS message signature or key value * - * @v sig CMS signature - * @v info Signer information to fill in + * @v cms CMS message + * @v part Participant information to fill in * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_signature_value ( struct cms_signature *sig, - struct cms_signer_info *info, - const struct asn1_cursor *raw ) { +static int cms_parse_value ( struct cms_message *cms, + struct cms_participant *part, + const struct asn1_cursor *raw ) { struct asn1_cursor cursor; int rc; /* Enter signature */ memcpy ( &cursor, raw, sizeof ( cursor ) ); if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not locate signature:\n", - sig, info ); - DBGC_HDA ( sig, 0, raw->data, raw->len ); + DBGC ( cms, "CMS %p/%p could not locate value:\n", + cms, part ); + DBGC_HDA ( cms, 0, raw->data, raw->len ); return rc; } /* Record signature */ - info->signature_len = cursor.len; - info->signature = malloc ( info->signature_len ); - if ( ! info->signature ) + part->len = cursor.len; + part->value = malloc ( part->len ); + if ( ! part->value ) return -ENOMEM; - memcpy ( info->signature, cursor.data, info->signature_len ); - DBGC ( sig, "CMS %p/%p signature value is:\n", sig, info ); - DBGC_HDA ( sig, 0, info->signature, info->signature_len ); + memcpy ( part->value, cursor.data, part->len ); + DBGC ( cms, "CMS %p/%p value is:\n", cms, part ); + DBGC_HDA ( cms, 0, part->value, part->len ); return 0; } /** - * Parse CMS signature signer information + * Parse CMS message participant information * - * @v sig CMS signature - * @v info Signer information to fill in + * @v cms CMS message + * @v part Participant information to fill in * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse_signer_info ( struct cms_signature *sig, - struct cms_signer_info *info, +static int cms_parse_participant ( struct cms_message *cms, + struct cms_participant *part, const struct asn1_cursor *raw ) { struct asn1_cursor cursor; int rc; @@ -331,12 +339,13 @@ static int cms_parse_signer_info ( struct cms_signature *sig, asn1_skip ( &cursor, ASN1_INTEGER ); /* Parse sid */ - if ( ( rc = cms_parse_signer_identifier ( sig, info, &cursor ) ) != 0 ) + if ( ( rc = cms_parse_identifier ( cms, part, &cursor ) ) != 0 ) return rc; asn1_skip_any ( &cursor ); /* Parse digestAlgorithm */ - if ( ( rc = cms_parse_digest_algorithm ( sig, info, &cursor ) ) != 0 ) + if ( ( rc = cms_parse_digest_algorithm ( cms, part, + &cursor ) ) != 0 ) return rc; asn1_skip_any ( &cursor ); @@ -344,43 +353,79 @@ static int cms_parse_signer_info ( struct cms_signature *sig, asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); /* Parse signatureAlgorithm */ - if ( ( rc = cms_parse_signature_algorithm ( sig, info, &cursor ) ) != 0) + if ( ( rc = cms_parse_pubkey_algorithm ( cms, part, &cursor ) ) != 0 ) return rc; asn1_skip_any ( &cursor ); /* Parse signature */ - if ( ( rc = cms_parse_signature_value ( sig, info, &cursor ) ) != 0 ) + if ( ( rc = cms_parse_value ( cms, part, &cursor ) ) != 0 ) return rc; return 0; } /** - * Parse CMS signature from ASN.1 data + * Parse CMS message participants information * - * @v sig CMS signature + * @v cms CMS message * @v raw ASN.1 cursor * @ret rc Return status code */ -static int cms_parse ( struct cms_signature *sig, - const struct asn1_cursor *raw ) { +static int cms_parse_participants ( struct cms_message *cms, + const struct asn1_cursor *raw ) { struct asn1_cursor cursor; - struct cms_signer_info *info; + struct cms_participant *part; int rc; - /* Enter contentInfo */ + /* Enter signerInfos */ memcpy ( &cursor, raw, sizeof ( cursor ) ); - asn1_enter ( &cursor, ASN1_SEQUENCE ); + asn1_enter ( &cursor, ASN1_SET ); - /* Parse contentType */ - if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 ) - return rc; - asn1_skip_any ( &cursor ); + /* Add each signerInfo. Errors are handled by ensuring that + * cms_put() will always be able to free any allocated memory. + */ + while ( cursor.len ) { - /* Enter content */ - asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); + /* Allocate participant information block */ + part = zalloc ( sizeof ( *part ) ); + if ( ! part ) + return -ENOMEM; + list_add ( &part->list, &cms->participants ); + + /* Allocate certificate chain */ + part->chain = x509_alloc_chain(); + if ( ! part->chain ) + return -ENOMEM; + + /* Parse signerInfo */ + if ( ( rc = cms_parse_participant ( cms, part, + &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + } + + return 0; +} + +/** + * Parse CMS signed data + * + * @v cms CMS message + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse_signed ( struct cms_message *cms, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int rc; + + /* Allocate certificate list */ + cms->certificates = x509_alloc_chain(); + if ( ! cms->certificates ) + return -ENOMEM; /* Enter signedData */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); asn1_enter ( &cursor, ASN1_SEQUENCE ); /* Skip version */ @@ -393,111 +438,113 @@ static int cms_parse ( struct cms_signature *sig, asn1_skip ( &cursor, ASN1_SEQUENCE ); /* Parse certificates */ - if ( ( rc = cms_parse_certificates ( sig, &cursor ) ) != 0 ) + if ( ( rc = cms_parse_certificates ( cms, &cursor ) ) != 0 ) return rc; asn1_skip_any ( &cursor ); /* Skip crls, if present */ asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 1 ) ); - /* Enter signerInfos */ - asn1_enter ( &cursor, ASN1_SET ); + /* Parse signerInfos */ + if ( ( rc = cms_parse_participants ( cms, &cursor ) ) != 0 ) + return rc; - /* Add each signerInfo. Errors are handled by ensuring that - * cms_put() will always be able to free any allocated memory. - */ - while ( cursor.len ) { + return 0; +} - /* Allocate signer information block */ - info = zalloc ( sizeof ( *info ) ); - if ( ! info ) - return -ENOMEM; - list_add ( &info->list, &sig->info ); +/** + * Parse CMS message from ASN.1 data + * + * @v cms CMS message + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int cms_parse ( struct cms_message *cms, + const struct asn1_cursor *raw ) { + struct asn1_cursor cursor; + int rc; - /* Allocate certificate chain */ - info->chain = x509_alloc_chain(); - if ( ! info->chain ) - return -ENOMEM; + /* Enter contentInfo */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); - /* Parse signerInfo */ - if ( ( rc = cms_parse_signer_info ( sig, info, - &cursor ) ) != 0 ) - return rc; - asn1_skip_any ( &cursor ); - } + /* Parse contentType */ + if ( ( rc = cms_parse_content_type ( cms, &cursor ) ) != 0 ) + return rc; + asn1_skip_any ( &cursor ); + + /* Enter content */ + asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) ); + + /* Parse type-specific content */ + if ( ( rc = cms->type->parse ( cms, &cursor ) ) != 0 ) + return rc; return 0; } /** - * Free CMS signature + * Free CMS message * * @v refcnt Reference count */ static void cms_free ( struct refcnt *refcnt ) { - struct cms_signature *sig = - container_of ( refcnt, struct cms_signature, refcnt ); - struct cms_signer_info *info; - struct cms_signer_info *tmp; - - list_for_each_entry_safe ( info, tmp, &sig->info, list ) { - list_del ( &info->list ); - x509_chain_put ( info->chain ); - free ( info->signature ); - free ( info ); + struct cms_message *cms = + container_of ( refcnt, struct cms_message, refcnt ); + struct cms_participant *part; + struct cms_participant *tmp; + + list_for_each_entry_safe ( part, tmp, &cms->participants, list ) { + list_del ( &part->list ); + x509_chain_put ( part->chain ); + free ( part->value ); + free ( part ); } - x509_chain_put ( sig->certificates ); - free ( sig ); + x509_chain_put ( cms->certificates ); + free ( cms ); } /** - * Create CMS signature + * Create CMS message * * @v image Image - * @ret sig CMS signature + * @ret sig CMS message * @ret rc Return status code * - * On success, the caller holds a reference to the CMS signature, and + * On success, the caller holds a reference to the CMS message, and * is responsible for ultimately calling cms_put(). */ -int cms_signature ( struct image *image, struct cms_signature **sig ) { +int cms_message ( struct image *image, struct cms_message **cms ) { struct asn1_cursor *raw; int next; int rc; - /* Allocate and initialise signature */ - *sig = zalloc ( sizeof ( **sig ) ); - if ( ! *sig ) { + /* Allocate and initialise message */ + *cms = zalloc ( sizeof ( **cms ) ); + if ( ! *cms ) { rc = -ENOMEM; goto err_alloc; } - ref_init ( &(*sig)->refcnt, cms_free ); - INIT_LIST_HEAD ( &(*sig)->info ); - - /* Allocate certificate list */ - (*sig)->certificates = x509_alloc_chain(); - if ( ! (*sig)->certificates ) { - rc = -ENOMEM; - goto err_alloc_chain; - } + ref_init ( &(*cms)->refcnt, cms_free ); + INIT_LIST_HEAD ( &(*cms)->participants ); - /* Get raw signature data */ + /* Get raw message 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 ) ); + DBGC ( *cms, "CMS %p could not get raw ASN.1 data: %s\n", + *cms, strerror ( rc ) ); goto err_asn1; } - /* Use only first signature in image */ + /* Use only first message in image */ asn1_shrink_any ( raw ); - /* Parse signature */ - if ( ( rc = cms_parse ( *sig, raw ) ) != 0 ) + /* Parse message */ + if ( ( rc = cms_parse ( *cms, raw ) ) != 0 ) goto err_parse; - /* Free raw signature data */ + /* Free raw message data */ free ( raw ); return 0; @@ -505,8 +552,7 @@ int cms_signature ( struct image *image, struct cms_signature **sig ) { err_parse: free ( raw ); err_asn1: - err_alloc_chain: - cms_put ( *sig ); + cms_put ( *cms ); err_alloc: return rc; } @@ -514,16 +560,16 @@ int cms_signature ( struct image *image, struct cms_signature **sig ) { /** * Calculate digest of CMS-signed data * - * @v sig CMS signature - * @v info Signer information + * @v cms CMS message + * @v part Participant information * @v data Signed data * @v len Length of signed data * @v out Digest output */ -static void cms_digest ( struct cms_signature *sig, - struct cms_signer_info *info, +static void cms_digest ( struct cms_message *cms, + struct cms_participant *part, userptr_t data, size_t len, void *out ) { - struct digest_algorithm *digest = info->digest; + struct digest_algorithm *digest = part->digest; uint8_t ctx[ digest->ctxsize ]; uint8_t block[ digest->blocksize ]; size_t offset = 0; @@ -546,48 +592,47 @@ static void cms_digest ( struct cms_signature *sig, /* Finalise digest */ digest_final ( digest, ctx, out ); - DBGC ( sig, "CMS %p/%p digest value:\n", sig, info ); - DBGC_HDA ( sig, 0, out, digest->digestsize ); + DBGC ( cms, "CMS %p/%p digest value:\n", cms, part ); + DBGC_HDA ( cms, 0, out, digest->digestsize ); } /** * Verify digest of CMS-signed data * - * @v sig CMS signature - * @v info Signer information + * @v cms CMS message + * @v part Participant information * @v cert Corresponding certificate * @v data Signed data * @v len Length of signed data * @ret rc Return status code */ -static int cms_verify_digest ( struct cms_signature *sig, - struct cms_signer_info *info, +static int cms_verify_digest ( struct cms_message *cms, + struct cms_participant *part, struct x509_certificate *cert, userptr_t data, size_t len ) { - struct digest_algorithm *digest = info->digest; - struct pubkey_algorithm *pubkey = info->pubkey; + struct digest_algorithm *digest = part->digest; + struct pubkey_algorithm *pubkey = part->pubkey; struct x509_public_key *public_key = &cert->subject.public_key; uint8_t digest_out[ digest->digestsize ]; uint8_t ctx[ pubkey->ctxsize ]; int rc; /* Generate digest */ - cms_digest ( sig, info, data, len, digest_out ); + cms_digest ( cms, part, data, len, digest_out ); /* Initialise public-key algorithm */ if ( ( rc = pubkey_init ( pubkey, ctx, public_key->raw.data, public_key->raw.len ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not initialise public key: %s\n", - sig, info, strerror ( rc ) ); + DBGC ( cms, "CMS %p/%p could not initialise public key: %s\n", + cms, part, strerror ( rc ) ); goto err_init; } /* Verify digest */ if ( ( rc = pubkey_verify ( pubkey, ctx, digest, digest_out, - info->signature, - info->signature_len ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p signature verification failed: %s\n", - sig, info, strerror ( rc ) ); + part->value, part->len ) ) != 0 ) { + DBGC ( cms, "CMS %p/%p signature verification failed: %s\n", + cms, part, strerror ( rc ) ); goto err_verify; } @@ -598,10 +643,10 @@ static int cms_verify_digest ( struct cms_signature *sig, } /** - * Verify CMS signature signer information + * Verify CMS message signer * - * @v sig CMS signature - * @v info Signer information + * @v cms CMS message + * @v part Participant information * @v data Signed data * @v len Length of signed data * @v time Time at which to validate certificates @@ -609,42 +654,42 @@ static int cms_verify_digest ( struct cms_signature *sig, * @v root Root certificate list, or NULL to use default * @ret rc Return status code */ -static int cms_verify_signer_info ( struct cms_signature *sig, - struct cms_signer_info *info, - userptr_t data, size_t len, - time_t time, struct x509_chain *store, - struct x509_root *root ) { +static int cms_verify_signer ( struct cms_message *cms, + struct cms_participant *part, + userptr_t data, size_t len, + time_t time, struct x509_chain *store, + struct x509_root *root ) { struct x509_certificate *cert; int rc; /* Validate certificate chain */ - if ( ( rc = x509_validate_chain ( info->chain, time, store, + if ( ( rc = x509_validate_chain ( part->chain, time, store, root ) ) != 0 ) { - DBGC ( sig, "CMS %p/%p could not validate chain: %s\n", - sig, info, strerror ( rc ) ); + DBGC ( cms, "CMS %p/%p could not validate chain: %s\n", + cms, part, strerror ( rc ) ); return rc; } /* Extract code-signing certificate */ - cert = x509_first ( info->chain ); + cert = x509_first ( part->chain ); assert ( cert != NULL ); /* Check that certificate can create digital signatures */ if ( ! ( cert->extensions.usage.bits & X509_DIGITAL_SIGNATURE ) ) { - DBGC ( sig, "CMS %p/%p certificate cannot create signatures\n", - sig, info ); + DBGC ( cms, "CMS %p/%p certificate cannot create signatures\n", + cms, part ); return -EACCES_NON_SIGNING; } /* Check that certificate can sign code */ if ( ! ( cert->extensions.ext_usage.bits & X509_CODE_SIGNING ) ) { - DBGC ( sig, "CMS %p/%p certificate is not code-signing\n", - sig, info ); + DBGC ( cms, "CMS %p/%p certificate is not code-signing\n", + cms, part ); return -EACCES_NON_CODE_SIGNING; } /* Verify digest */ - if ( ( rc = cms_verify_digest ( sig, info, cert, data, len ) ) != 0 ) + if ( ( rc = cms_verify_digest ( cms, part, cert, data, len ) ) != 0 ) return rc; return 0; @@ -653,7 +698,7 @@ static int cms_verify_signer_info ( struct cms_signature *sig, /** * Verify CMS signature * - * @v sig CMS signature + * @v cms CMS message * @v image Signed image * @v name Required common name, or NULL to check all signatures * @v time Time at which to validate certificates @@ -661,10 +706,10 @@ static int cms_verify_signer_info ( struct cms_signature *sig, * @v root Root certificate list, or NULL to use default * @ret rc Return status code */ -int cms_verify ( struct cms_signature *sig, struct image *image, +int cms_verify ( struct cms_message *cms, struct image *image, const char *name, time_t time, struct x509_chain *store, struct x509_root *root ) { - struct cms_signer_info *info; + struct cms_participant *part; struct x509_certificate *cert; int count = 0; int rc; @@ -672,14 +717,18 @@ int cms_verify ( struct cms_signature *sig, struct image *image, /* Mark image as untrusted */ image_untrust ( image ); - /* Verify using all signerInfos */ - list_for_each_entry ( info, &sig->info, list ) { - cert = x509_first ( info->chain ); + /* Sanity check */ + if ( ! cms_is_signature ( cms ) ) + return -ENOTTY; + + /* Verify using all signers */ + list_for_each_entry ( part, &cms->participants, list ) { + cert = x509_first ( part->chain ); if ( name && ( x509_check_name ( cert, name ) != 0 ) ) continue; - if ( ( rc = cms_verify_signer_info ( sig, info, image->data, - image->len, time, store, - root ) ) != 0 ) + if ( ( rc = cms_verify_signer ( cms, part, image->data, + image->len, time, store, + root ) ) != 0 ) return rc; count++; } @@ -687,11 +736,11 @@ int cms_verify ( struct cms_signature *sig, struct image *image, /* Check that we have verified at least one signature */ if ( count == 0 ) { if ( name ) { - DBGC ( sig, "CMS %p had no signatures matching name " - "%s\n", sig, name ); + DBGC ( cms, "CMS %p had no signatures matching name " + "%s\n", cms, name ); return -EACCES_WRONG_NAME; } else { - DBGC ( sig, "CMS %p had no signatures\n", sig ); + DBGC ( cms, "CMS %p had no signatures\n", cms ); return -EACCES_NO_SIGNATURES; } } diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index fd7244570..26dc47992 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -303,7 +303,7 @@ struct asn1_builder_header { ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ), \ ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 3 ) -/** ASN.1 OID for pkcs-signedData (1.2.840.113549.1.7.2) */ +/** ASN.1 OID for id-signedData (1.2.840.113549.1.7.2) */ #define ASN1_OID_SIGNEDDATA \ ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \ ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \ diff --git a/src/include/ipxe/cms.h b/src/include/ipxe/cms.h index cca7779c5..1c8a0c587 100644 --- a/src/include/ipxe/cms.h +++ b/src/include/ipxe/cms.h @@ -17,61 +17,92 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include <ipxe/uaccess.h> struct image; +struct cms_message; -/** CMS signer information */ -struct cms_signer_info { - /** List of signer information blocks */ - struct list_head list; +/** A CMS message type */ +struct cms_type { + /** Name */ + const char *name; + /** Object identifier */ + struct asn1_cursor oid; + /** Parse content + * + * @v cms CMS message + * @v raw ASN.1 cursor + * @ret rc Return status code + */ + int ( * parse ) ( struct cms_message *cms, + const struct asn1_cursor *raw ); +}; +/** CMS participant information */ +struct cms_participant { + /** List of participant information blocks */ + struct list_head list; /** Certificate chain */ struct x509_chain *chain; - /** Digest algorithm */ + /** Digest algorithm (for signature messages) */ struct digest_algorithm *digest; /** Public-key algorithm */ struct pubkey_algorithm *pubkey; - /** Signature */ - void *signature; - /** Length of signature */ - size_t signature_len; + /** Signature or key value */ + void *value; + /** Length of signature or key value */ + size_t len; }; -/** A CMS signature */ -struct cms_signature { +/** A CMS message */ +struct cms_message { /** Reference count */ struct refcnt refcnt; - /** List of all certificates */ + /** Message type */ + struct cms_type *type; + + /** List of all certificates (for signature messages) */ struct x509_chain *certificates; - /** List of signer information blocks */ - struct list_head info; + /** List of participant information blocks */ + struct list_head participants; }; /** - * Get reference to CMS signature + * Get reference to CMS message * - * @v sig CMS signature - * @ret sig CMS signature + * @v cms CMS message + * @ret cms CMS message */ -static inline __attribute__ (( always_inline )) struct cms_signature * -cms_get ( struct cms_signature *sig ) { - ref_get ( &sig->refcnt ); - return sig; +static inline __attribute__ (( always_inline )) struct cms_message * +cms_get ( struct cms_message *cms ) { + ref_get ( &cms->refcnt ); + return cms; } /** - * Drop reference to CMS signature + * Drop reference to CMS message * - * @v sig CMS signature + * @v cms CMS message */ static inline __attribute__ (( always_inline )) void -cms_put ( struct cms_signature *sig ) { - ref_put ( &sig->refcnt ); +cms_put ( struct cms_message *cms ) { + ref_put ( &cms->refcnt ); +} + +/** + * Check if CMS message is a signature message + * + * @v cms CMS message + * @ret is_signature Message is a signature message + */ +static inline __attribute__ (( always_inline )) int +cms_is_signature ( struct cms_message *cms ) { + + /* CMS signatures include an optional CertificateSet */ + return ( cms->certificates != NULL ); } -extern int cms_signature ( struct image *image, - struct cms_signature **sig ); -extern int cms_verify ( struct cms_signature *sig, struct image *image, +extern int cms_message ( struct image *image, struct cms_message **cms ); +extern int cms_verify ( struct cms_message *cms, 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 d98b2c3e5..86f9bb98f 100644 --- a/src/tests/cms_test.c +++ b/src/tests/cms_test.c @@ -55,8 +55,8 @@ struct cms_test_code { struct cms_test_signature { /** Signature image */ struct image image; - /** Parsed signature */ - struct cms_signature *sig; + /** Parsed message */ + struct cms_message *cms; }; /** Define inline data */ @@ -1366,7 +1366,7 @@ static void cms_signature_okx ( struct cms_test_signature *sgn, sgn->image.data = virt_to_user ( data ); /* Check ability to parse signature */ - okx ( cms_signature ( &sgn->image, &sgn->sig ) == 0, file, line ); + okx ( cms_message ( &sgn->image, &sgn->cms ) == 0, file, line ); /* Reset image data pointer */ sgn->image.data = ( ( userptr_t ) data ); @@ -1397,10 +1397,10 @@ static void cms_verify_okx ( struct cms_test_signature *sgn, code->image.data = virt_to_user ( data ); /* Invalidate any certificates from previous tests */ - x509_invalidate_chain ( sgn->sig->certificates ); + x509_invalidate_chain ( sgn->cms->certificates ); /* Check ability to verify signature */ - okx ( cms_verify ( sgn->sig, &code->image, name, time, store, + okx ( cms_verify ( sgn->cms, &code->image, name, time, store, root ) == 0, file, line ); okx ( code->image.flags & IMAGE_TRUSTED, file, line ); @@ -1434,10 +1434,10 @@ static void cms_verify_fail_okx ( struct cms_test_signature *sgn, code->image.data = virt_to_user ( data ); /* Invalidate any certificates from previous tests */ - x509_invalidate_chain ( sgn->sig->certificates ); + x509_invalidate_chain ( sgn->cms->certificates ); /* Check inability to verify signature */ - okx ( cms_verify ( sgn->sig, &code->image, name, time, store, + okx ( cms_verify ( sgn->cms, &code->image, name, time, store, root ) != 0, file, line ); okx ( ! ( code->image.flags & IMAGE_TRUSTED ), file, line ); @@ -1498,11 +1498,11 @@ static void cms_test_exec ( void ) { /* Sanity check */ assert ( list_empty ( &empty_store.links ) ); - /* Drop signature references */ - cms_put ( nonsigned_sig.sig ); - cms_put ( genericsigned_sig.sig ); - cms_put ( brokenchain_sig.sig ); - cms_put ( codesigned_sig.sig ); + /* Drop message references */ + cms_put ( nonsigned_sig.cms ); + cms_put ( genericsigned_sig.cms ); + cms_put ( brokenchain_sig.cms ); + cms_put ( codesigned_sig.cms ); } /** CMS self-test */ diff --git a/src/usr/imgtrust.c b/src/usr/imgtrust.c index 54ea3378f..7f7e7ed14 100644 --- a/src/usr/imgtrust.c +++ b/src/usr/imgtrust.c @@ -50,18 +50,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ int imgverify ( struct image *image, struct image *signature, const char *name ) { - struct cms_signature *sig; - struct cms_signer_info *info; + struct cms_message *cms; + struct cms_participant *part; time_t now; int rc; /* Parse signature */ - if ( ( rc = cms_signature ( signature, &sig ) ) != 0 ) + if ( ( rc = cms_message ( signature, &cms ) ) != 0 ) goto err_parse; /* Complete all certificate chains */ - list_for_each_entry ( info, &sig->info, list ) { - if ( ( rc = create_validator ( &monojob, info->chain, + list_for_each_entry ( part, &cms->participants, list ) { + if ( ( rc = create_validator ( &monojob, part->chain, NULL ) ) != 0 ) goto err_create_validator; if ( ( rc = monojob_wait ( NULL, 0 ) ) != 0 ) @@ -70,12 +70,12 @@ int imgverify ( struct image *image, struct image *signature, /* Use signature to verify image */ now = time ( NULL ); - if ( ( rc = cms_verify ( sig, image, name, now, NULL, NULL ) ) != 0 ) + if ( ( rc = cms_verify ( cms, image, name, now, NULL, NULL ) ) != 0 ) goto err_verify; - /* Drop reference to signature */ - cms_put ( sig ); - sig = NULL; + /* Drop reference to message */ + cms_put ( cms ); + cms = NULL; /* Record signature verification */ syslog ( LOG_NOTICE, "Image \"%s\" signature OK\n", image->name ); @@ -85,7 +85,7 @@ int imgverify ( struct image *image, struct image *signature, err_verify: err_validator_wait: err_create_validator: - cms_put ( sig ); + cms_put ( cms ); err_parse: syslog ( LOG_ERR, "Image \"%s\" signature bad: %s\n", image->name, strerror ( rc ) ); |