mirror of
https://github.com/ipxe/ipxe
synced 2025-12-14 16:01:38 +03:00
[crypto] Generalise cms_signature to cms_message
There is some exploitable similarity between the data structures used for representing CMS signatures and CMS encryption keys. In both cases, the CMS message fundamentally encodes a list of participants (either message signers or message recipients), where each participant has an associated certificate and an opaque octet string representing the signature or encrypted cipher key. The ASN.1 structures are not identical, but are sufficiently similar to be worth exploiting: for example, the SignerIdentifier and RecipientIdentifier data structures are defined identically. Rename data structures and functions, and add the concept of a CMS message type. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
519
src/crypto/cms.c
519
src/crypto/cms.c
@@ -59,60 +59,68 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
__einfo_error ( EINFO_EACCES_NO_SIGNATURES )
|
__einfo_error ( EINFO_EACCES_NO_SIGNATURES )
|
||||||
#define EINFO_EACCES_NO_SIGNATURES \
|
#define EINFO_EACCES_NO_SIGNATURES \
|
||||||
__einfo_uniqify ( EINFO_EACCES, 0x05, "No signatures present" )
|
__einfo_uniqify ( EINFO_EACCES, 0x05, "No signatures present" )
|
||||||
#define EINVAL_DIGEST \
|
#define ENOTSUP_TYPE \
|
||||||
__einfo_error ( EINFO_EINVAL_DIGEST )
|
__einfo_error ( EINFO_ENOTSUP_TYPE )
|
||||||
#define EINFO_EINVAL_DIGEST \
|
#define EINFO_ENOTSUP_TYPE \
|
||||||
__einfo_uniqify ( EINFO_EINVAL, 0x01, "Not a digest algorithm" )
|
__einfo_uniqify ( EINFO_ENOTSUP, 0x01, "Unrecognised message type" )
|
||||||
#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 */
|
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 };
|
static uint8_t oid_signeddata[] = { ASN1_OID_SIGNEDDATA };
|
||||||
|
|
||||||
/** "pkcs7-signedData" object identifier cursor */
|
/** CMS message types */
|
||||||
static struct asn1_cursor oid_signeddata_cursor =
|
static struct cms_type cms_types[] = {
|
||||||
ASN1_CURSOR ( oid_signeddata );
|
{
|
||||||
|
.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
|
* @v raw ASN.1 cursor
|
||||||
* @ret rc Return status code
|
* @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 ) {
|
const struct asn1_cursor *raw ) {
|
||||||
struct asn1_cursor cursor;
|
struct asn1_cursor cursor;
|
||||||
|
struct cms_type *type;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
/* Enter contentType */
|
/* Enter contentType */
|
||||||
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
||||||
asn1_enter ( &cursor, ASN1_OID );
|
asn1_enter ( &cursor, ASN1_OID );
|
||||||
|
|
||||||
/* Check OID is pkcs7-signedData */
|
/* Check for a recognised OID */
|
||||||
if ( asn1_compare ( &cursor, &oid_signeddata_cursor ) != 0 ) {
|
for ( i = 0 ; i < ( sizeof ( cms_types ) /
|
||||||
DBGC ( sig, "CMS %p does not contain signedData:\n", sig );
|
sizeof ( cms_types[0] ) ) ; i++ ) {
|
||||||
DBGC_HDA ( sig, 0, raw->data, raw->len );
|
type = &cms_types[i];
|
||||||
return -ENOTSUP_SIGNEDDATA;
|
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 );
|
DBGC ( cms, "CMS %p is not a recognised message type:\n", cms );
|
||||||
return 0;
|
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
|
* @v raw ASN.1 cursor
|
||||||
* @ret rc Return status code
|
* @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 ) {
|
const struct asn1_cursor *raw ) {
|
||||||
struct asn1_cursor cursor;
|
struct asn1_cursor cursor;
|
||||||
struct x509_certificate *cert;
|
struct x509_certificate *cert;
|
||||||
@@ -126,16 +134,16 @@ static int cms_parse_certificates ( struct cms_signature *sig,
|
|||||||
while ( cursor.len ) {
|
while ( cursor.len ) {
|
||||||
|
|
||||||
/* Add certificate to chain */
|
/* 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 ) {
|
cursor.len ) ) != 0 ) {
|
||||||
DBGC ( sig, "CMS %p could not append certificate: %s\n",
|
DBGC ( cms, "CMS %p could not append certificate: %s\n",
|
||||||
sig, strerror ( rc) );
|
cms, strerror ( rc) );
|
||||||
DBGC_HDA ( sig, 0, cursor.data, cursor.len );
|
DBGC_HDA ( cms, 0, cursor.data, cursor.len );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
cert = x509_last ( sig->certificates );
|
cert = x509_last ( cms->certificates );
|
||||||
DBGC ( sig, "CMS %p found certificate %s\n",
|
DBGC ( cms, "CMS %p found certificate %s\n",
|
||||||
sig, x509_name ( cert ) );
|
cms, x509_name ( cert ) );
|
||||||
|
|
||||||
/* Move to next certificate */
|
/* Move to next certificate */
|
||||||
asn1_skip_any ( &cursor );
|
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 cms CMS message
|
||||||
* @v info Signer information to fill in
|
* @v part Participant information to fill in
|
||||||
* @v raw ASN.1 cursor
|
* @v raw ASN.1 cursor
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int cms_parse_signer_identifier ( struct cms_signature *sig,
|
static int cms_parse_identifier ( struct cms_message *cms,
|
||||||
struct cms_signer_info *info,
|
struct cms_participant *part,
|
||||||
const struct asn1_cursor *raw ) {
|
const struct asn1_cursor *raw ) {
|
||||||
struct asn1_cursor cursor;
|
struct asn1_cursor cursor;
|
||||||
struct asn1_cursor serial;
|
struct asn1_cursor serial;
|
||||||
struct asn1_cursor issuer;
|
struct asn1_cursor issuer;
|
||||||
@@ -168,46 +176,46 @@ static int cms_parse_signer_identifier ( struct cms_signature *sig,
|
|||||||
/* Identify issuer */
|
/* Identify issuer */
|
||||||
memcpy ( &issuer, &cursor, sizeof ( issuer ) );
|
memcpy ( &issuer, &cursor, sizeof ( issuer ) );
|
||||||
if ( ( rc = asn1_shrink ( &issuer, ASN1_SEQUENCE ) ) != 0 ) {
|
if ( ( rc = asn1_shrink ( &issuer, ASN1_SEQUENCE ) ) != 0 ) {
|
||||||
DBGC ( sig, "CMS %p/%p could not locate issuer: %s\n",
|
DBGC ( cms, "CMS %p/%p could not locate issuer: %s\n",
|
||||||
sig, info, strerror ( rc ) );
|
cms, part, strerror ( rc ) );
|
||||||
DBGC_HDA ( sig, 0, raw->data, raw->len );
|
DBGC_HDA ( cms, 0, raw->data, raw->len );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
DBGC ( sig, "CMS %p/%p issuer is:\n", sig, info );
|
DBGC ( cms, "CMS %p/%p issuer is:\n", cms, part );
|
||||||
DBGC_HDA ( sig, 0, issuer.data, issuer.len );
|
DBGC_HDA ( cms, 0, issuer.data, issuer.len );
|
||||||
asn1_skip_any ( &cursor );
|
asn1_skip_any ( &cursor );
|
||||||
|
|
||||||
/* Identify serialNumber */
|
/* Identify serialNumber */
|
||||||
memcpy ( &serial, &cursor, sizeof ( serial ) );
|
memcpy ( &serial, &cursor, sizeof ( serial ) );
|
||||||
if ( ( rc = asn1_shrink ( &serial, ASN1_INTEGER ) ) != 0 ) {
|
if ( ( rc = asn1_shrink ( &serial, ASN1_INTEGER ) ) != 0 ) {
|
||||||
DBGC ( sig, "CMS %p/%p could not locate serialNumber: %s\n",
|
DBGC ( cms, "CMS %p/%p could not locate serialNumber: %s\n",
|
||||||
sig, info, strerror ( rc ) );
|
cms, part, strerror ( rc ) );
|
||||||
DBGC_HDA ( sig, 0, raw->data, raw->len );
|
DBGC_HDA ( cms, 0, raw->data, raw->len );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
DBGC ( sig, "CMS %p/%p serial number is:\n", sig, info );
|
DBGC ( cms, "CMS %p/%p serial number is:\n", cms, part );
|
||||||
DBGC_HDA ( sig, 0, serial.data, serial.len );
|
DBGC_HDA ( cms, 0, serial.data, serial.len );
|
||||||
|
|
||||||
/* Identify certificate */
|
/* Identify certificate */
|
||||||
cert = x509_find_issuer_serial ( sig->certificates, &issuer, &serial );
|
cert = x509_find_issuer_serial ( cms->certificates, &issuer, &serial );
|
||||||
if ( ! cert ) {
|
if ( ! cert ) {
|
||||||
DBGC ( sig, "CMS %p/%p could not identify signer's "
|
DBGC ( cms, "CMS %p/%p could not identify certificate\n",
|
||||||
"certificate\n", sig, info );
|
cms, part );
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Append certificate to chain */
|
/* Append certificate to chain */
|
||||||
if ( ( rc = x509_append ( info->chain, cert ) ) != 0 ) {
|
if ( ( rc = x509_append ( part->chain, cert ) ) != 0 ) {
|
||||||
DBGC ( sig, "CMS %p/%p could not append certificate: %s\n",
|
DBGC ( cms, "CMS %p/%p could not append certificate: %s\n",
|
||||||
sig, info, strerror ( rc ) );
|
cms, part, strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Append remaining certificates to chain */
|
/* Append remaining certificates to chain */
|
||||||
if ( ( rc = x509_auto_append ( info->chain,
|
if ( ( rc = x509_auto_append ( part->chain,
|
||||||
sig->certificates ) ) != 0 ) {
|
cms->certificates ) ) != 0 ) {
|
||||||
DBGC ( sig, "CMS %p/%p could not append certificates: %s\n",
|
DBGC ( cms, "CMS %p/%p could not append certificates: %s\n",
|
||||||
sig, info, strerror ( rc ) );
|
cms, part, strerror ( rc ) );
|
||||||
return 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 cms CMS message
|
||||||
* @v info Signer information to fill in
|
* @v part Participant information to fill in
|
||||||
* @v raw ASN.1 cursor
|
* @v raw ASN.1 cursor
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int cms_parse_digest_algorithm ( struct cms_signature *sig,
|
static int cms_parse_digest_algorithm ( struct cms_message *cms,
|
||||||
struct cms_signer_info *info,
|
struct cms_participant *part,
|
||||||
const struct asn1_cursor *raw ) {
|
const struct asn1_cursor *raw ) {
|
||||||
struct asn1_algorithm *algorithm;
|
struct asn1_algorithm *algorithm;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Identify algorithm */
|
/* Identify algorithm */
|
||||||
if ( ( rc = asn1_digest_algorithm ( raw, &algorithm ) ) != 0 ) {
|
if ( ( rc = asn1_digest_algorithm ( raw, &algorithm ) ) != 0 ) {
|
||||||
DBGC ( sig, "CMS %p/%p could not identify digest algorithm: "
|
DBGC ( cms, "CMS %p/%p could not identify digest algorithm: "
|
||||||
"%s\n", sig, info, strerror ( rc ) );
|
"%s\n", cms, part, strerror ( rc ) );
|
||||||
DBGC_HDA ( sig, 0, raw->data, raw->len );
|
DBGC_HDA ( cms, 0, raw->data, raw->len );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record digest algorithm */
|
/* Record digest algorithm */
|
||||||
info->digest = algorithm->digest;
|
part->digest = algorithm->digest;
|
||||||
DBGC ( sig, "CMS %p/%p digest algorithm is %s\n",
|
DBGC ( cms, "CMS %p/%p digest algorithm is %s\n",
|
||||||
sig, info, algorithm->name );
|
cms, part, algorithm->name );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse CMS signature algorithm
|
* Parse CMS message public-key algorithm
|
||||||
*
|
*
|
||||||
* @v sig CMS signature
|
* @v cms CMS message
|
||||||
* @v info Signer information to fill in
|
* @v part Participant information to fill in
|
||||||
* @v raw ASN.1 cursor
|
* @v raw ASN.1 cursor
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int cms_parse_signature_algorithm ( struct cms_signature *sig,
|
static int cms_parse_pubkey_algorithm ( struct cms_message *cms,
|
||||||
struct cms_signer_info *info,
|
struct cms_participant *part,
|
||||||
const struct asn1_cursor *raw ) {
|
const struct asn1_cursor *raw ) {
|
||||||
struct asn1_algorithm *algorithm;
|
struct asn1_algorithm *algorithm;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Identify algorithm */
|
/* Identify algorithm */
|
||||||
if ( ( rc = asn1_pubkey_algorithm ( raw, &algorithm ) ) != 0 ) {
|
if ( ( rc = asn1_pubkey_algorithm ( raw, &algorithm ) ) != 0 ) {
|
||||||
DBGC ( sig, "CMS %p/%p could not identify public-key "
|
DBGC ( cms, "CMS %p/%p could not identify public-key "
|
||||||
"algorithm: %s\n", sig, info, strerror ( rc ) );
|
"algorithm: %s\n", cms, part, strerror ( rc ) );
|
||||||
DBGC_HDA ( sig, 0, raw->data, raw->len );
|
DBGC_HDA ( cms, 0, raw->data, raw->len );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record signature algorithm */
|
/* Record public-key algorithm */
|
||||||
info->pubkey = algorithm->pubkey;
|
part->pubkey = algorithm->pubkey;
|
||||||
DBGC ( sig, "CMS %p/%p public-key algorithm is %s\n",
|
DBGC ( cms, "CMS %p/%p public-key algorithm is %s\n",
|
||||||
sig, info, algorithm->name );
|
cms, part, algorithm->name );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse CMS signature value
|
* Parse CMS message signature or key value
|
||||||
*
|
*
|
||||||
* @v sig CMS signature
|
* @v cms CMS message
|
||||||
* @v info Signer information to fill in
|
* @v part Participant information to fill in
|
||||||
* @v raw ASN.1 cursor
|
* @v raw ASN.1 cursor
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int cms_parse_signature_value ( struct cms_signature *sig,
|
static int cms_parse_value ( struct cms_message *cms,
|
||||||
struct cms_signer_info *info,
|
struct cms_participant *part,
|
||||||
const struct asn1_cursor *raw ) {
|
const struct asn1_cursor *raw ) {
|
||||||
struct asn1_cursor cursor;
|
struct asn1_cursor cursor;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Enter signature */
|
/* Enter signature */
|
||||||
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
||||||
if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) {
|
if ( ( rc = asn1_enter ( &cursor, ASN1_OCTET_STRING ) ) != 0 ) {
|
||||||
DBGC ( sig, "CMS %p/%p could not locate signature:\n",
|
DBGC ( cms, "CMS %p/%p could not locate value:\n",
|
||||||
sig, info );
|
cms, part );
|
||||||
DBGC_HDA ( sig, 0, raw->data, raw->len );
|
DBGC_HDA ( cms, 0, raw->data, raw->len );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Record signature */
|
/* Record signature */
|
||||||
info->signature_len = cursor.len;
|
part->len = cursor.len;
|
||||||
info->signature = malloc ( info->signature_len );
|
part->value = malloc ( part->len );
|
||||||
if ( ! info->signature )
|
if ( ! part->value )
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
memcpy ( info->signature, cursor.data, info->signature_len );
|
memcpy ( part->value, cursor.data, part->len );
|
||||||
DBGC ( sig, "CMS %p/%p signature value is:\n", sig, info );
|
DBGC ( cms, "CMS %p/%p value is:\n", cms, part );
|
||||||
DBGC_HDA ( sig, 0, info->signature, info->signature_len );
|
DBGC_HDA ( cms, 0, part->value, part->len );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse CMS signature signer information
|
* Parse CMS message participant information
|
||||||
*
|
*
|
||||||
* @v sig CMS signature
|
* @v cms CMS message
|
||||||
* @v info Signer information to fill in
|
* @v part Participant information to fill in
|
||||||
* @v raw ASN.1 cursor
|
* @v raw ASN.1 cursor
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int cms_parse_signer_info ( struct cms_signature *sig,
|
static int cms_parse_participant ( struct cms_message *cms,
|
||||||
struct cms_signer_info *info,
|
struct cms_participant *part,
|
||||||
const struct asn1_cursor *raw ) {
|
const struct asn1_cursor *raw ) {
|
||||||
struct asn1_cursor cursor;
|
struct asn1_cursor cursor;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -331,12 +339,13 @@ static int cms_parse_signer_info ( struct cms_signature *sig,
|
|||||||
asn1_skip ( &cursor, ASN1_INTEGER );
|
asn1_skip ( &cursor, ASN1_INTEGER );
|
||||||
|
|
||||||
/* Parse sid */
|
/* Parse sid */
|
||||||
if ( ( rc = cms_parse_signer_identifier ( sig, info, &cursor ) ) != 0 )
|
if ( ( rc = cms_parse_identifier ( cms, part, &cursor ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
asn1_skip_any ( &cursor );
|
asn1_skip_any ( &cursor );
|
||||||
|
|
||||||
/* Parse digestAlgorithm */
|
/* Parse digestAlgorithm */
|
||||||
if ( ( rc = cms_parse_digest_algorithm ( sig, info, &cursor ) ) != 0 )
|
if ( ( rc = cms_parse_digest_algorithm ( cms, part,
|
||||||
|
&cursor ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
asn1_skip_any ( &cursor );
|
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 ) );
|
asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
|
||||||
|
|
||||||
/* Parse signatureAlgorithm */
|
/* Parse signatureAlgorithm */
|
||||||
if ( ( rc = cms_parse_signature_algorithm ( sig, info, &cursor ) ) != 0)
|
if ( ( rc = cms_parse_pubkey_algorithm ( cms, part, &cursor ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
asn1_skip_any ( &cursor );
|
asn1_skip_any ( &cursor );
|
||||||
|
|
||||||
/* Parse signature */
|
/* Parse signature */
|
||||||
if ( ( rc = cms_parse_signature_value ( sig, info, &cursor ) ) != 0 )
|
if ( ( rc = cms_parse_value ( cms, part, &cursor ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
return 0;
|
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
|
* @v raw ASN.1 cursor
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int cms_parse ( struct cms_signature *sig,
|
static int cms_parse_participants ( struct cms_message *cms,
|
||||||
const struct asn1_cursor *raw ) {
|
const struct asn1_cursor *raw ) {
|
||||||
struct asn1_cursor cursor;
|
struct asn1_cursor cursor;
|
||||||
struct cms_signer_info *info;
|
struct cms_participant *part;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Enter contentInfo */
|
/* Enter signerInfos */
|
||||||
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
||||||
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
asn1_enter ( &cursor, ASN1_SET );
|
||||||
|
|
||||||
/* Parse contentType */
|
/* Add each signerInfo. Errors are handled by ensuring that
|
||||||
if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 )
|
* cms_put() will always be able to free any allocated memory.
|
||||||
return rc;
|
*/
|
||||||
asn1_skip_any ( &cursor );
|
while ( cursor.len ) {
|
||||||
|
|
||||||
/* Enter content */
|
/* Allocate participant information block */
|
||||||
asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 0 ) );
|
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 */
|
/* Enter signedData */
|
||||||
|
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
||||||
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
||||||
|
|
||||||
/* Skip version */
|
/* Skip version */
|
||||||
@@ -393,111 +438,113 @@ static int cms_parse ( struct cms_signature *sig,
|
|||||||
asn1_skip ( &cursor, ASN1_SEQUENCE );
|
asn1_skip ( &cursor, ASN1_SEQUENCE );
|
||||||
|
|
||||||
/* Parse certificates */
|
/* Parse certificates */
|
||||||
if ( ( rc = cms_parse_certificates ( sig, &cursor ) ) != 0 )
|
if ( ( rc = cms_parse_certificates ( cms, &cursor ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
asn1_skip_any ( &cursor );
|
asn1_skip_any ( &cursor );
|
||||||
|
|
||||||
/* Skip crls, if present */
|
/* Skip crls, if present */
|
||||||
asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 1 ) );
|
asn1_skip_if_exists ( &cursor, ASN1_EXPLICIT_TAG ( 1 ) );
|
||||||
|
|
||||||
/* Enter signerInfos */
|
/* Parse signerInfos */
|
||||||
asn1_enter ( &cursor, ASN1_SET );
|
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 ) {
|
|
||||||
|
|
||||||
/* Allocate signer information block */
|
|
||||||
info = zalloc ( sizeof ( *info ) );
|
|
||||||
if ( ! info )
|
|
||||||
return -ENOMEM;
|
|
||||||
list_add ( &info->list, &sig->info );
|
|
||||||
|
|
||||||
/* Allocate certificate chain */
|
|
||||||
info->chain = x509_alloc_chain();
|
|
||||||
if ( ! info->chain )
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* Parse signerInfo */
|
|
||||||
if ( ( rc = cms_parse_signer_info ( sig, info,
|
|
||||||
&cursor ) ) != 0 )
|
|
||||||
return rc;
|
|
||||||
asn1_skip_any ( &cursor );
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free CMS signature
|
* 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;
|
||||||
|
|
||||||
|
/* Enter contentInfo */
|
||||||
|
memcpy ( &cursor, raw, sizeof ( cursor ) );
|
||||||
|
asn1_enter ( &cursor, ASN1_SEQUENCE );
|
||||||
|
|
||||||
|
/* 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 message
|
||||||
*
|
*
|
||||||
* @v refcnt Reference count
|
* @v refcnt Reference count
|
||||||
*/
|
*/
|
||||||
static void cms_free ( struct refcnt *refcnt ) {
|
static void cms_free ( struct refcnt *refcnt ) {
|
||||||
struct cms_signature *sig =
|
struct cms_message *cms =
|
||||||
container_of ( refcnt, struct cms_signature, refcnt );
|
container_of ( refcnt, struct cms_message, refcnt );
|
||||||
struct cms_signer_info *info;
|
struct cms_participant *part;
|
||||||
struct cms_signer_info *tmp;
|
struct cms_participant *tmp;
|
||||||
|
|
||||||
list_for_each_entry_safe ( info, tmp, &sig->info, list ) {
|
list_for_each_entry_safe ( part, tmp, &cms->participants, list ) {
|
||||||
list_del ( &info->list );
|
list_del ( &part->list );
|
||||||
x509_chain_put ( info->chain );
|
x509_chain_put ( part->chain );
|
||||||
free ( info->signature );
|
free ( part->value );
|
||||||
free ( info );
|
free ( part );
|
||||||
}
|
}
|
||||||
x509_chain_put ( sig->certificates );
|
x509_chain_put ( cms->certificates );
|
||||||
free ( sig );
|
free ( cms );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create CMS signature
|
* Create CMS message
|
||||||
*
|
*
|
||||||
* @v image Image
|
* @v image Image
|
||||||
* @ret sig CMS signature
|
* @ret sig CMS message
|
||||||
* @ret rc Return status code
|
* @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().
|
* 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;
|
struct asn1_cursor *raw;
|
||||||
int next;
|
int next;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Allocate and initialise signature */
|
/* Allocate and initialise message */
|
||||||
*sig = zalloc ( sizeof ( **sig ) );
|
*cms = zalloc ( sizeof ( **cms ) );
|
||||||
if ( ! *sig ) {
|
if ( ! *cms ) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto err_alloc;
|
goto err_alloc;
|
||||||
}
|
}
|
||||||
ref_init ( &(*sig)->refcnt, cms_free );
|
ref_init ( &(*cms)->refcnt, cms_free );
|
||||||
INIT_LIST_HEAD ( &(*sig)->info );
|
INIT_LIST_HEAD ( &(*cms)->participants );
|
||||||
|
|
||||||
/* Allocate certificate list */
|
/* Get raw message data */
|
||||||
(*sig)->certificates = x509_alloc_chain();
|
|
||||||
if ( ! (*sig)->certificates ) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto err_alloc_chain;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get raw signature data */
|
|
||||||
next = image_asn1 ( image, 0, &raw );
|
next = image_asn1 ( image, 0, &raw );
|
||||||
if ( next < 0 ) {
|
if ( next < 0 ) {
|
||||||
rc = next;
|
rc = next;
|
||||||
DBGC ( *sig, "CMS %p could not get raw ASN.1 data: %s\n",
|
DBGC ( *cms, "CMS %p could not get raw ASN.1 data: %s\n",
|
||||||
*sig, strerror ( rc ) );
|
*cms, strerror ( rc ) );
|
||||||
goto err_asn1;
|
goto err_asn1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use only first signature in image */
|
/* Use only first message in image */
|
||||||
asn1_shrink_any ( raw );
|
asn1_shrink_any ( raw );
|
||||||
|
|
||||||
/* Parse signature */
|
/* Parse message */
|
||||||
if ( ( rc = cms_parse ( *sig, raw ) ) != 0 )
|
if ( ( rc = cms_parse ( *cms, raw ) ) != 0 )
|
||||||
goto err_parse;
|
goto err_parse;
|
||||||
|
|
||||||
/* Free raw signature data */
|
/* Free raw message data */
|
||||||
free ( raw );
|
free ( raw );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -505,8 +552,7 @@ int cms_signature ( struct image *image, struct cms_signature **sig ) {
|
|||||||
err_parse:
|
err_parse:
|
||||||
free ( raw );
|
free ( raw );
|
||||||
err_asn1:
|
err_asn1:
|
||||||
err_alloc_chain:
|
cms_put ( *cms );
|
||||||
cms_put ( *sig );
|
|
||||||
err_alloc:
|
err_alloc:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -514,16 +560,16 @@ int cms_signature ( struct image *image, struct cms_signature **sig ) {
|
|||||||
/**
|
/**
|
||||||
* Calculate digest of CMS-signed data
|
* Calculate digest of CMS-signed data
|
||||||
*
|
*
|
||||||
* @v sig CMS signature
|
* @v cms CMS message
|
||||||
* @v info Signer information
|
* @v part Participant information
|
||||||
* @v data Signed data
|
* @v data Signed data
|
||||||
* @v len Length of signed data
|
* @v len Length of signed data
|
||||||
* @v out Digest output
|
* @v out Digest output
|
||||||
*/
|
*/
|
||||||
static void cms_digest ( struct cms_signature *sig,
|
static void cms_digest ( struct cms_message *cms,
|
||||||
struct cms_signer_info *info,
|
struct cms_participant *part,
|
||||||
userptr_t data, size_t len, void *out ) {
|
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 ctx[ digest->ctxsize ];
|
||||||
uint8_t block[ digest->blocksize ];
|
uint8_t block[ digest->blocksize ];
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
@@ -546,48 +592,47 @@ static void cms_digest ( struct cms_signature *sig,
|
|||||||
/* Finalise digest */
|
/* Finalise digest */
|
||||||
digest_final ( digest, ctx, out );
|
digest_final ( digest, ctx, out );
|
||||||
|
|
||||||
DBGC ( sig, "CMS %p/%p digest value:\n", sig, info );
|
DBGC ( cms, "CMS %p/%p digest value:\n", cms, part );
|
||||||
DBGC_HDA ( sig, 0, out, digest->digestsize );
|
DBGC_HDA ( cms, 0, out, digest->digestsize );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify digest of CMS-signed data
|
* Verify digest of CMS-signed data
|
||||||
*
|
*
|
||||||
* @v sig CMS signature
|
* @v cms CMS message
|
||||||
* @v info Signer information
|
* @v part Participant information
|
||||||
* @v cert Corresponding certificate
|
* @v cert Corresponding certificate
|
||||||
* @v data Signed data
|
* @v data Signed data
|
||||||
* @v len Length of signed data
|
* @v len Length of signed data
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int cms_verify_digest ( struct cms_signature *sig,
|
static int cms_verify_digest ( struct cms_message *cms,
|
||||||
struct cms_signer_info *info,
|
struct cms_participant *part,
|
||||||
struct x509_certificate *cert,
|
struct x509_certificate *cert,
|
||||||
userptr_t data, size_t len ) {
|
userptr_t data, size_t len ) {
|
||||||
struct digest_algorithm *digest = info->digest;
|
struct digest_algorithm *digest = part->digest;
|
||||||
struct pubkey_algorithm *pubkey = info->pubkey;
|
struct pubkey_algorithm *pubkey = part->pubkey;
|
||||||
struct x509_public_key *public_key = &cert->subject.public_key;
|
struct x509_public_key *public_key = &cert->subject.public_key;
|
||||||
uint8_t digest_out[ digest->digestsize ];
|
uint8_t digest_out[ digest->digestsize ];
|
||||||
uint8_t ctx[ pubkey->ctxsize ];
|
uint8_t ctx[ pubkey->ctxsize ];
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Generate digest */
|
/* Generate digest */
|
||||||
cms_digest ( sig, info, data, len, digest_out );
|
cms_digest ( cms, part, data, len, digest_out );
|
||||||
|
|
||||||
/* Initialise public-key algorithm */
|
/* Initialise public-key algorithm */
|
||||||
if ( ( rc = pubkey_init ( pubkey, ctx, public_key->raw.data,
|
if ( ( rc = pubkey_init ( pubkey, ctx, public_key->raw.data,
|
||||||
public_key->raw.len ) ) != 0 ) {
|
public_key->raw.len ) ) != 0 ) {
|
||||||
DBGC ( sig, "CMS %p/%p could not initialise public key: %s\n",
|
DBGC ( cms, "CMS %p/%p could not initialise public key: %s\n",
|
||||||
sig, info, strerror ( rc ) );
|
cms, part, strerror ( rc ) );
|
||||||
goto err_init;
|
goto err_init;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify digest */
|
/* Verify digest */
|
||||||
if ( ( rc = pubkey_verify ( pubkey, ctx, digest, digest_out,
|
if ( ( rc = pubkey_verify ( pubkey, ctx, digest, digest_out,
|
||||||
info->signature,
|
part->value, part->len ) ) != 0 ) {
|
||||||
info->signature_len ) ) != 0 ) {
|
DBGC ( cms, "CMS %p/%p signature verification failed: %s\n",
|
||||||
DBGC ( sig, "CMS %p/%p signature verification failed: %s\n",
|
cms, part, strerror ( rc ) );
|
||||||
sig, info, strerror ( rc ) );
|
|
||||||
goto err_verify;
|
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 cms CMS message
|
||||||
* @v info Signer information
|
* @v part Participant information
|
||||||
* @v data Signed data
|
* @v data Signed data
|
||||||
* @v len Length of signed data
|
* @v len Length of signed data
|
||||||
* @v time Time at which to validate certificates
|
* @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
|
* @v root Root certificate list, or NULL to use default
|
||||||
* @ret rc Return status code
|
* @ret rc Return status code
|
||||||
*/
|
*/
|
||||||
static int cms_verify_signer_info ( struct cms_signature *sig,
|
static int cms_verify_signer ( struct cms_message *cms,
|
||||||
struct cms_signer_info *info,
|
struct cms_participant *part,
|
||||||
userptr_t data, size_t len,
|
userptr_t data, size_t len,
|
||||||
time_t time, struct x509_chain *store,
|
time_t time, struct x509_chain *store,
|
||||||
struct x509_root *root ) {
|
struct x509_root *root ) {
|
||||||
struct x509_certificate *cert;
|
struct x509_certificate *cert;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Validate certificate chain */
|
/* Validate certificate chain */
|
||||||
if ( ( rc = x509_validate_chain ( info->chain, time, store,
|
if ( ( rc = x509_validate_chain ( part->chain, time, store,
|
||||||
root ) ) != 0 ) {
|
root ) ) != 0 ) {
|
||||||
DBGC ( sig, "CMS %p/%p could not validate chain: %s\n",
|
DBGC ( cms, "CMS %p/%p could not validate chain: %s\n",
|
||||||
sig, info, strerror ( rc ) );
|
cms, part, strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Extract code-signing certificate */
|
/* Extract code-signing certificate */
|
||||||
cert = x509_first ( info->chain );
|
cert = x509_first ( part->chain );
|
||||||
assert ( cert != NULL );
|
assert ( cert != NULL );
|
||||||
|
|
||||||
/* Check that certificate can create digital signatures */
|
/* Check that certificate can create digital signatures */
|
||||||
if ( ! ( cert->extensions.usage.bits & X509_DIGITAL_SIGNATURE ) ) {
|
if ( ! ( cert->extensions.usage.bits & X509_DIGITAL_SIGNATURE ) ) {
|
||||||
DBGC ( sig, "CMS %p/%p certificate cannot create signatures\n",
|
DBGC ( cms, "CMS %p/%p certificate cannot create signatures\n",
|
||||||
sig, info );
|
cms, part );
|
||||||
return -EACCES_NON_SIGNING;
|
return -EACCES_NON_SIGNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that certificate can sign code */
|
/* Check that certificate can sign code */
|
||||||
if ( ! ( cert->extensions.ext_usage.bits & X509_CODE_SIGNING ) ) {
|
if ( ! ( cert->extensions.ext_usage.bits & X509_CODE_SIGNING ) ) {
|
||||||
DBGC ( sig, "CMS %p/%p certificate is not code-signing\n",
|
DBGC ( cms, "CMS %p/%p certificate is not code-signing\n",
|
||||||
sig, info );
|
cms, part );
|
||||||
return -EACCES_NON_CODE_SIGNING;
|
return -EACCES_NON_CODE_SIGNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Verify digest */
|
/* 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 rc;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -653,7 +698,7 @@ static int cms_verify_signer_info ( struct cms_signature *sig,
|
|||||||
/**
|
/**
|
||||||
* Verify CMS signature
|
* Verify CMS signature
|
||||||
*
|
*
|
||||||
* @v sig CMS signature
|
* @v cms CMS message
|
||||||
* @v image Signed image
|
* @v image Signed image
|
||||||
* @v name Required common name, or NULL to check all signatures
|
* @v name Required common name, or NULL to check all signatures
|
||||||
* @v time Time at which to validate certificates
|
* @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
|
* @v root Root certificate list, or NULL to use default
|
||||||
* @ret rc Return status code
|
* @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,
|
const char *name, time_t time, struct x509_chain *store,
|
||||||
struct x509_root *root ) {
|
struct x509_root *root ) {
|
||||||
struct cms_signer_info *info;
|
struct cms_participant *part;
|
||||||
struct x509_certificate *cert;
|
struct x509_certificate *cert;
|
||||||
int count = 0;
|
int count = 0;
|
||||||
int rc;
|
int rc;
|
||||||
@@ -672,14 +717,18 @@ int cms_verify ( struct cms_signature *sig, struct image *image,
|
|||||||
/* Mark image as untrusted */
|
/* Mark image as untrusted */
|
||||||
image_untrust ( image );
|
image_untrust ( image );
|
||||||
|
|
||||||
/* Verify using all signerInfos */
|
/* Sanity check */
|
||||||
list_for_each_entry ( info, &sig->info, list ) {
|
if ( ! cms_is_signature ( cms ) )
|
||||||
cert = x509_first ( info->chain );
|
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 ) )
|
if ( name && ( x509_check_name ( cert, name ) != 0 ) )
|
||||||
continue;
|
continue;
|
||||||
if ( ( rc = cms_verify_signer_info ( sig, info, image->data,
|
if ( ( rc = cms_verify_signer ( cms, part, image->data,
|
||||||
image->len, time, store,
|
image->len, time, store,
|
||||||
root ) ) != 0 )
|
root ) ) != 0 )
|
||||||
return rc;
|
return rc;
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
@@ -687,11 +736,11 @@ int cms_verify ( struct cms_signature *sig, struct image *image,
|
|||||||
/* Check that we have verified at least one signature */
|
/* Check that we have verified at least one signature */
|
||||||
if ( count == 0 ) {
|
if ( count == 0 ) {
|
||||||
if ( name ) {
|
if ( name ) {
|
||||||
DBGC ( sig, "CMS %p had no signatures matching name "
|
DBGC ( cms, "CMS %p had no signatures matching name "
|
||||||
"%s\n", sig, name );
|
"%s\n", cms, name );
|
||||||
return -EACCES_WRONG_NAME;
|
return -EACCES_WRONG_NAME;
|
||||||
} else {
|
} else {
|
||||||
DBGC ( sig, "CMS %p had no signatures\n", sig );
|
DBGC ( cms, "CMS %p had no signatures\n", cms );
|
||||||
return -EACCES_NO_SIGNATURES;
|
return -EACCES_NO_SIGNATURES;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ struct asn1_builder_header {
|
|||||||
ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ), \
|
ASN1_OID_SINGLE ( 5 ), ASN1_OID_SINGLE ( 7 ), \
|
||||||
ASN1_OID_SINGLE ( 3 ), ASN1_OID_SINGLE ( 3 )
|
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 \
|
#define ASN1_OID_SIGNEDDATA \
|
||||||
ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \
|
ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \
|
||||||
ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \
|
ASN1_OID_TRIPLE ( 113549 ), ASN1_OID_SINGLE ( 1 ), \
|
||||||
|
|||||||
@@ -17,61 +17,92 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
#include <ipxe/uaccess.h>
|
#include <ipxe/uaccess.h>
|
||||||
|
|
||||||
struct image;
|
struct image;
|
||||||
|
struct cms_message;
|
||||||
|
|
||||||
/** CMS signer information */
|
/** A CMS message type */
|
||||||
struct cms_signer_info {
|
struct cms_type {
|
||||||
/** List of signer information blocks */
|
/** 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;
|
struct list_head list;
|
||||||
|
|
||||||
/** Certificate chain */
|
/** Certificate chain */
|
||||||
struct x509_chain *chain;
|
struct x509_chain *chain;
|
||||||
|
|
||||||
/** Digest algorithm */
|
/** Digest algorithm (for signature messages) */
|
||||||
struct digest_algorithm *digest;
|
struct digest_algorithm *digest;
|
||||||
/** Public-key algorithm */
|
/** Public-key algorithm */
|
||||||
struct pubkey_algorithm *pubkey;
|
struct pubkey_algorithm *pubkey;
|
||||||
|
|
||||||
/** Signature */
|
/** Signature or key value */
|
||||||
void *signature;
|
void *value;
|
||||||
/** Length of signature */
|
/** Length of signature or key value */
|
||||||
size_t signature_len;
|
size_t len;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** A CMS signature */
|
/** A CMS message */
|
||||||
struct cms_signature {
|
struct cms_message {
|
||||||
/** Reference count */
|
/** Reference count */
|
||||||
struct refcnt refcnt;
|
struct refcnt refcnt;
|
||||||
/** List of all certificates */
|
/** Message type */
|
||||||
|
struct cms_type *type;
|
||||||
|
|
||||||
|
/** List of all certificates (for signature messages) */
|
||||||
struct x509_chain *certificates;
|
struct x509_chain *certificates;
|
||||||
/** List of signer information blocks */
|
/** List of participant information blocks */
|
||||||
struct list_head info;
|
struct list_head participants;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get reference to CMS signature
|
* Get reference to CMS message
|
||||||
*
|
*
|
||||||
* @v sig CMS signature
|
* @v cms CMS message
|
||||||
* @ret sig CMS signature
|
* @ret cms CMS message
|
||||||
*/
|
*/
|
||||||
static inline __attribute__ (( always_inline )) struct cms_signature *
|
static inline __attribute__ (( always_inline )) struct cms_message *
|
||||||
cms_get ( struct cms_signature *sig ) {
|
cms_get ( struct cms_message *cms ) {
|
||||||
ref_get ( &sig->refcnt );
|
ref_get ( &cms->refcnt );
|
||||||
return sig;
|
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
|
static inline __attribute__ (( always_inline )) void
|
||||||
cms_put ( struct cms_signature *sig ) {
|
cms_put ( struct cms_message *cms ) {
|
||||||
ref_put ( &sig->refcnt );
|
ref_put ( &cms->refcnt );
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int cms_signature ( struct image *image,
|
/**
|
||||||
struct cms_signature **sig );
|
* Check if CMS message is a signature message
|
||||||
extern int cms_verify ( struct cms_signature *sig, struct image *image,
|
*
|
||||||
|
* @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_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,
|
const char *name, time_t time, struct x509_chain *store,
|
||||||
struct x509_root *root );
|
struct x509_root *root );
|
||||||
|
|
||||||
|
|||||||
@@ -55,8 +55,8 @@ struct cms_test_code {
|
|||||||
struct cms_test_signature {
|
struct cms_test_signature {
|
||||||
/** Signature image */
|
/** Signature image */
|
||||||
struct image image;
|
struct image image;
|
||||||
/** Parsed signature */
|
/** Parsed message */
|
||||||
struct cms_signature *sig;
|
struct cms_message *cms;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Define inline data */
|
/** Define inline data */
|
||||||
@@ -1366,7 +1366,7 @@ static void cms_signature_okx ( struct cms_test_signature *sgn,
|
|||||||
sgn->image.data = virt_to_user ( data );
|
sgn->image.data = virt_to_user ( data );
|
||||||
|
|
||||||
/* Check ability to parse signature */
|
/* 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 */
|
/* Reset image data pointer */
|
||||||
sgn->image.data = ( ( userptr_t ) data );
|
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 );
|
code->image.data = virt_to_user ( data );
|
||||||
|
|
||||||
/* Invalidate any certificates from previous tests */
|
/* Invalidate any certificates from previous tests */
|
||||||
x509_invalidate_chain ( sgn->sig->certificates );
|
x509_invalidate_chain ( sgn->cms->certificates );
|
||||||
|
|
||||||
/* Check ability to verify signature */
|
/* 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 );
|
root ) == 0, file, line );
|
||||||
okx ( code->image.flags & IMAGE_TRUSTED, 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 );
|
code->image.data = virt_to_user ( data );
|
||||||
|
|
||||||
/* Invalidate any certificates from previous tests */
|
/* Invalidate any certificates from previous tests */
|
||||||
x509_invalidate_chain ( sgn->sig->certificates );
|
x509_invalidate_chain ( sgn->cms->certificates );
|
||||||
|
|
||||||
/* Check inability to verify signature */
|
/* 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 );
|
root ) != 0, file, line );
|
||||||
okx ( ! ( code->image.flags & IMAGE_TRUSTED ), file, line );
|
okx ( ! ( code->image.flags & IMAGE_TRUSTED ), file, line );
|
||||||
|
|
||||||
@@ -1498,11 +1498,11 @@ static void cms_test_exec ( void ) {
|
|||||||
/* Sanity check */
|
/* Sanity check */
|
||||||
assert ( list_empty ( &empty_store.links ) );
|
assert ( list_empty ( &empty_store.links ) );
|
||||||
|
|
||||||
/* Drop signature references */
|
/* Drop message references */
|
||||||
cms_put ( nonsigned_sig.sig );
|
cms_put ( nonsigned_sig.cms );
|
||||||
cms_put ( genericsigned_sig.sig );
|
cms_put ( genericsigned_sig.cms );
|
||||||
cms_put ( brokenchain_sig.sig );
|
cms_put ( brokenchain_sig.cms );
|
||||||
cms_put ( codesigned_sig.sig );
|
cms_put ( codesigned_sig.cms );
|
||||||
}
|
}
|
||||||
|
|
||||||
/** CMS self-test */
|
/** CMS self-test */
|
||||||
|
|||||||
@@ -50,18 +50,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
*/
|
*/
|
||||||
int imgverify ( struct image *image, struct image *signature,
|
int imgverify ( struct image *image, struct image *signature,
|
||||||
const char *name ) {
|
const char *name ) {
|
||||||
struct cms_signature *sig;
|
struct cms_message *cms;
|
||||||
struct cms_signer_info *info;
|
struct cms_participant *part;
|
||||||
time_t now;
|
time_t now;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* Parse signature */
|
/* Parse signature */
|
||||||
if ( ( rc = cms_signature ( signature, &sig ) ) != 0 )
|
if ( ( rc = cms_message ( signature, &cms ) ) != 0 )
|
||||||
goto err_parse;
|
goto err_parse;
|
||||||
|
|
||||||
/* Complete all certificate chains */
|
/* Complete all certificate chains */
|
||||||
list_for_each_entry ( info, &sig->info, list ) {
|
list_for_each_entry ( part, &cms->participants, list ) {
|
||||||
if ( ( rc = create_validator ( &monojob, info->chain,
|
if ( ( rc = create_validator ( &monojob, part->chain,
|
||||||
NULL ) ) != 0 )
|
NULL ) ) != 0 )
|
||||||
goto err_create_validator;
|
goto err_create_validator;
|
||||||
if ( ( rc = monojob_wait ( NULL, 0 ) ) != 0 )
|
if ( ( rc = monojob_wait ( NULL, 0 ) ) != 0 )
|
||||||
@@ -70,12 +70,12 @@ int imgverify ( struct image *image, struct image *signature,
|
|||||||
|
|
||||||
/* Use signature to verify image */
|
/* Use signature to verify image */
|
||||||
now = time ( NULL );
|
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;
|
goto err_verify;
|
||||||
|
|
||||||
/* Drop reference to signature */
|
/* Drop reference to message */
|
||||||
cms_put ( sig );
|
cms_put ( cms );
|
||||||
sig = NULL;
|
cms = NULL;
|
||||||
|
|
||||||
/* Record signature verification */
|
/* Record signature verification */
|
||||||
syslog ( LOG_NOTICE, "Image \"%s\" signature OK\n", image->name );
|
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_verify:
|
||||||
err_validator_wait:
|
err_validator_wait:
|
||||||
err_create_validator:
|
err_create_validator:
|
||||||
cms_put ( sig );
|
cms_put ( cms );
|
||||||
err_parse:
|
err_parse:
|
||||||
syslog ( LOG_ERR, "Image \"%s\" signature bad: %s\n",
|
syslog ( LOG_ERR, "Image \"%s\" signature bad: %s\n",
|
||||||
image->name, strerror ( rc ) );
|
image->name, strerror ( rc ) );
|
||||||
|
|||||||
Reference in New Issue
Block a user