mirror of https://github.com/ipxe/ipxe.git
[crypto] New command imgdigest, verify image using digest
The imgdigest works like imgverify, expect that the image is verified using a digest instead of a signature.pull/34/head
parent
03e71d5d1a
commit
76c7cdb0b2
|
@ -161,6 +161,69 @@ static int imgverify_exec ( int argc, char **argv ) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** "imgdigest" options */
|
||||||
|
struct imgdigest_options {
|
||||||
|
/** Download timeout */
|
||||||
|
unsigned long timeout;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** "imgdigest" option list */
|
||||||
|
static struct option_descriptor imgdigest_opts[] = {
|
||||||
|
OPTION_DESC ( "timeout", 't', required_argument,
|
||||||
|
struct imgdigest_options, timeout, parse_timeout),
|
||||||
|
};
|
||||||
|
|
||||||
|
/** "imgdigest" command descriptor */
|
||||||
|
static struct command_descriptor imgdigest_cmd =
|
||||||
|
COMMAND_DESC ( struct imgdigest_options, imgdigest_opts, 3, 3,
|
||||||
|
"<uri|image> <digestname> <digest>" );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The "imgdigest" command
|
||||||
|
*
|
||||||
|
* @v argc Argument count
|
||||||
|
* @v argv Argument list
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
static int imgdigest_exec ( int argc, char **argv ) {
|
||||||
|
struct imgdigest_options opts;
|
||||||
|
struct image *image;
|
||||||
|
const char *image_name_uri;
|
||||||
|
const char *digest_name;
|
||||||
|
const char *digest;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Parse options */
|
||||||
|
if ( ( rc = parse_options ( argc, argv, &imgdigest_cmd, &opts ) ) != 0 )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Parse image name/URI string */
|
||||||
|
image_name_uri = argv[optind];
|
||||||
|
|
||||||
|
/* Parse digest name */
|
||||||
|
digest_name = argv[ optind + 1 ];
|
||||||
|
|
||||||
|
/* Parse digest string */
|
||||||
|
digest = argv[ optind + 2 ];
|
||||||
|
|
||||||
|
/* Acquire the image */
|
||||||
|
if ( ( rc = imgacquire ( image_name_uri, opts.timeout, &image ) ) != 0 )
|
||||||
|
goto err_acquire_image;
|
||||||
|
|
||||||
|
/* Verify image */
|
||||||
|
if ( ( rc = imgverifydigest ( image, digest_name, digest ) ) != 0 ) {
|
||||||
|
printf ( "Could not verify: %s\n", strerror ( rc ) );
|
||||||
|
goto err_verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success */
|
||||||
|
rc = 0;
|
||||||
|
|
||||||
|
err_verify:
|
||||||
|
err_acquire_image:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/** Image trust management commands */
|
/** Image trust management commands */
|
||||||
struct command image_trust_commands[] __command = {
|
struct command image_trust_commands[] __command = {
|
||||||
{
|
{
|
||||||
|
@ -171,6 +234,10 @@ struct command image_trust_commands[] __command = {
|
||||||
.name = "imgverify",
|
.name = "imgverify",
|
||||||
.exec = imgverify_exec,
|
.exec = imgverify_exec,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "imgdigest",
|
||||||
|
.exec = imgdigest_exec,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Drag in objects via command list */
|
/* Drag in objects via command list */
|
||||||
|
|
|
@ -14,4 +14,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
extern int imgverify ( struct image *image, struct image *signature,
|
extern int imgverify ( struct image *image, struct image *signature,
|
||||||
const char *name );
|
const char *name );
|
||||||
|
|
||||||
|
extern int imgverifydigest ( struct image *image, const char *digest_name,
|
||||||
|
const char *digest );
|
||||||
|
|
||||||
#endif /* _USR_IMGTRUST_H */
|
#endif /* _USR_IMGTRUST_H */
|
||||||
|
|
|
@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||||
#include <ipxe/uaccess.h>
|
#include <ipxe/uaccess.h>
|
||||||
#include <ipxe/image.h>
|
#include <ipxe/image.h>
|
||||||
#include <ipxe/cms.h>
|
#include <ipxe/cms.h>
|
||||||
|
#include <ipxe/base16.h>
|
||||||
#include <ipxe/validator.h>
|
#include <ipxe/validator.h>
|
||||||
#include <ipxe/monojob.h>
|
#include <ipxe/monojob.h>
|
||||||
#include <usr/imgtrust.h>
|
#include <usr/imgtrust.h>
|
||||||
|
@ -112,3 +113,109 @@ int imgverify ( struct image *image, struct image *signature,
|
||||||
image->name, strerror ( rc ) );
|
image->name, strerror ( rc ) );
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate digest of user data
|
||||||
|
*
|
||||||
|
* @v digest Digest alogorithm
|
||||||
|
* @v data Data to digest
|
||||||
|
* @v len Length of data
|
||||||
|
* @v out Digest output
|
||||||
|
*/
|
||||||
|
static void digest_user_data ( struct digest_algorithm *digest, userptr_t data,
|
||||||
|
size_t len, void *out ) {
|
||||||
|
uint8_t ctx[ digest->ctxsize ];
|
||||||
|
uint8_t block[ digest->blocksize ];
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t frag_len;
|
||||||
|
|
||||||
|
/* Initialise digest */
|
||||||
|
digest_init ( digest, ctx );
|
||||||
|
|
||||||
|
/* Process data one block at a time */
|
||||||
|
while ( len ) {
|
||||||
|
frag_len = len;
|
||||||
|
if ( frag_len > sizeof ( block ) )
|
||||||
|
frag_len = sizeof ( block );
|
||||||
|
copy_from_user ( block, data, offset, frag_len );
|
||||||
|
digest_update ( digest, ctx, block, frag_len );
|
||||||
|
offset += frag_len;
|
||||||
|
len -= frag_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finalise digest */
|
||||||
|
digest_final ( digest, ctx, out );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identify a digest algorithm by name
|
||||||
|
*
|
||||||
|
* @v name Digest name
|
||||||
|
|
||||||
|
* @ret digest Digest algorithm, or NULL
|
||||||
|
*/
|
||||||
|
static struct digest_algorithm *
|
||||||
|
find_digest_algorithm ( const char *name ) {
|
||||||
|
struct asn1_algorithm *algorithm;
|
||||||
|
|
||||||
|
for_each_table_entry ( algorithm, ASN1_ALGORITHMS ) {
|
||||||
|
if ( strcmp ( algorithm->name, name ) == 0
|
||||||
|
&& algorithm->digest )
|
||||||
|
return algorithm->digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify image using the supplied digest
|
||||||
|
*
|
||||||
|
* @v image Image to verify
|
||||||
|
* @v digest_name Name of digest algorithm to use
|
||||||
|
* @v hex Hex encoded digest
|
||||||
|
* @ret rc Return status code
|
||||||
|
*/
|
||||||
|
int imgverifydigest ( struct image *image, const char *digest_name,
|
||||||
|
const char *hex ) {
|
||||||
|
struct digest_algorithm *digest;
|
||||||
|
uint8_t in[ base16_decoded_max_len ( hex ) ];
|
||||||
|
uint8_t out[ base16_decoded_max_len ( hex ) ];
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
/* Mark image as untrusted */
|
||||||
|
image_untrust ( image );
|
||||||
|
|
||||||
|
/* Parse digest name */
|
||||||
|
if ( ! ( digest = find_digest_algorithm ( digest_name ) ) ) {
|
||||||
|
syslog ( LOG_ERR, "Invalid digest name: %s\n", digest_name );
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto err_verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse hex input digest */
|
||||||
|
if ( base16_decode ( hex, in ) != (int) digest->digestsize ) {
|
||||||
|
syslog ( LOG_ERR, "Invalid digest: %s %s\n", digest_name, hex );
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto err_verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Verify digest */
|
||||||
|
digest_user_data ( digest, image->data, image->len, out );
|
||||||
|
if ( memcmp ( in, out, digest->digestsize ) != 0 ) {
|
||||||
|
rc = -EINVAL;
|
||||||
|
goto err_verify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark image as trusted */
|
||||||
|
image_trust ( image );
|
||||||
|
syslog ( LOG_NOTICE, "Image \"%s\" digest OK\n", image->name );
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_verify:
|
||||||
|
syslog ( LOG_ERR, "Image \"%s\" digest bad: %s\n",
|
||||||
|
image->name, strerror ( rc ) );
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue