mirror of https://github.com/ipxe/ipxe.git
[crypto] Add DER image format
Add DER-encoded ASN.1 as an image format. There is no fixed signature for DER files. We treat an image as DER if it comprises a single valid SEQUENCE object covering the entire length of the image. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/56/head
parent
ef50608029
commit
eb7188d04b
|
@ -188,6 +188,9 @@ REQUIRE_OBJECT ( pnm );
|
|||
#ifdef IMAGE_PNG
|
||||
REQUIRE_OBJECT ( png );
|
||||
#endif
|
||||
#ifdef IMAGE_DER
|
||||
REQUIRE_OBJECT ( der );
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Drag in all requested commands
|
||||
|
|
|
@ -112,6 +112,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
//#define IMAGE_SDI /* SDI image support */
|
||||
//#define IMAGE_PNM /* PNM image support */
|
||||
//#define IMAGE_PNG /* PNG image support */
|
||||
//#define IMAGE_DER /* DER image support */
|
||||
|
||||
/*
|
||||
* Command-line commands to include
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/der.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/image.h>
|
||||
|
||||
/** @file
|
||||
*
|
||||
* DER-encoded ASN.1 data
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Extract ASN.1 object from image
|
||||
*
|
||||
* @v image DER image
|
||||
* @v offset Offset within image
|
||||
* @v cursor ASN.1 cursor to fill in
|
||||
* @ret next Offset to next image, or negative error
|
||||
*
|
||||
* The caller is responsible for eventually calling free() on the
|
||||
* allocated ASN.1 cursor.
|
||||
*/
|
||||
static int der_asn1 ( struct image *image, size_t offset __unused,
|
||||
struct asn1_cursor **cursor ) {
|
||||
void *data;
|
||||
|
||||
/* Allocate cursor and data buffer */
|
||||
*cursor = malloc ( sizeof ( **cursor ) + image->len );
|
||||
if ( ! *cursor )
|
||||
return -ENOMEM;
|
||||
data = ( ( ( void * ) *cursor ) + sizeof ( **cursor ) );
|
||||
|
||||
/* Populate cursor and data buffer */
|
||||
(*cursor)->data = data;
|
||||
(*cursor)->len = image->len;
|
||||
copy_from_user ( data, image->data, 0, image->len );
|
||||
|
||||
return image->len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe DER image
|
||||
*
|
||||
* @v image DER image
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int der_probe ( struct image *image ) {
|
||||
struct asn1_cursor cursor;
|
||||
uint8_t buf[8];
|
||||
size_t extra;
|
||||
size_t total;
|
||||
int len;
|
||||
int rc;
|
||||
|
||||
/* Sanity check: no realistic DER image can be smaller than this */
|
||||
if ( image->len < sizeof ( buf ) )
|
||||
return -ENOEXEC;
|
||||
|
||||
/* Prepare partial cursor */
|
||||
cursor.data = buf;
|
||||
cursor.len = sizeof ( buf );
|
||||
copy_from_user ( buf, image->data, 0, sizeof ( buf ) );
|
||||
extra = ( image->len - sizeof ( buf ) );
|
||||
|
||||
/* Get length of ASN.1 sequence */
|
||||
len = asn1_start ( &cursor, ASN1_SEQUENCE, extra );
|
||||
if ( len < 0 ) {
|
||||
rc = len;
|
||||
DBGC ( image, "DER %s is not valid ASN.1: %s\n",
|
||||
image->name, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Add length of tag and length bytes consumed by asn1_start() */
|
||||
total = ( len + ( cursor.data - ( ( void * ) buf ) ) );
|
||||
assert ( total <= image->len );
|
||||
|
||||
/* Check that image comprises a single well-formed ASN.1 object */
|
||||
if ( total != image->len ) {
|
||||
DBGC ( image, "DER %s is not single ASN.1\n", image->name );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** DER image type */
|
||||
struct image_type der_image_type __image_type ( PROBE_NORMAL ) = {
|
||||
.name = "DER",
|
||||
.probe = der_probe,
|
||||
.asn1 = der_asn1,
|
||||
};
|
|
@ -0,0 +1,16 @@
|
|||
#ifndef _IPXE_DER_H
|
||||
#define _IPXE_DER_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* DER image format
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/image.h>
|
||||
|
||||
extern struct image_type der_image_type __image_type ( PROBE_NORMAL );
|
||||
|
||||
#endif /* _IPXE_DER_H */
|
|
@ -276,6 +276,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||
#define ERRFILE_embedded ( ERRFILE_IMAGE | 0x00050000 )
|
||||
#define ERRFILE_pnm ( ERRFILE_IMAGE | 0x00060000 )
|
||||
#define ERRFILE_png ( ERRFILE_IMAGE | 0x00070000 )
|
||||
#define ERRFILE_der ( ERRFILE_IMAGE | 0x00080000 )
|
||||
|
||||
#define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 )
|
||||
#define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 )
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* ASN.1 self-tests
|
||||
*
|
||||
*/
|
||||
|
||||
/* Forcibly enable assertions */
|
||||
#undef NDEBUG
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/test.h>
|
||||
#include "asn1_test.h"
|
||||
|
||||
/**
|
||||
* Report ASN.1 test result
|
||||
*
|
||||
* @v test ASN.1 test
|
||||
* @v file Test code file
|
||||
* @v line Test code line
|
||||
*/
|
||||
void asn1_okx ( struct asn1_test *test, const char *file, unsigned int line ) {
|
||||
struct digest_algorithm *digest = &asn1_test_digest_algorithm;
|
||||
struct asn1_cursor *cursor;
|
||||
uint8_t ctx[digest->ctxsize];
|
||||
uint8_t out[ASN1_TEST_DIGEST_SIZE];
|
||||
unsigned int i;
|
||||
size_t offset;
|
||||
int next;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( sizeof ( out ) == digest->digestsize );
|
||||
|
||||
/* Correct image data pointer */
|
||||
test->image->data = virt_to_user ( ( void * ) test->image->data );
|
||||
|
||||
/* Check that image is detected as correct type */
|
||||
okx ( register_image ( test->image ) == 0, file, line );
|
||||
okx ( test->image->type == test->type, file, line );
|
||||
|
||||
/* Check that all ASN.1 objects can be extracted */
|
||||
for ( offset = 0, i = 0 ; i < test->count ; offset = next, i++ ) {
|
||||
|
||||
/* Extract ASN.1 object */
|
||||
next = image_asn1 ( test->image, offset, &cursor );
|
||||
okx ( next >= 0, file, line );
|
||||
okx ( ( ( size_t ) next ) > offset, file, line );
|
||||
if ( next > 0 ) {
|
||||
|
||||
/* Calculate digest of ASN.1 object */
|
||||
digest_init ( digest, ctx );
|
||||
digest_update ( digest, ctx, cursor->data,
|
||||
cursor->len );
|
||||
digest_final ( digest, ctx, out );
|
||||
|
||||
/* Compare against expected digest */
|
||||
okx ( memcmp ( out, test->expected[i].digest,
|
||||
sizeof ( out ) ) == 0, file, line );
|
||||
|
||||
/* Free ASN.1 object */
|
||||
free ( cursor );
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that we have reached the end of the image */
|
||||
okx ( offset == test->image->len, file, line );
|
||||
|
||||
/* Unregister image */
|
||||
unregister_image ( test->image );
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
#ifndef _ASN1_TEST_H
|
||||
#define _ASN1_TEST_H
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <stdint.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/sha1.h>
|
||||
#include <ipxe/test.h>
|
||||
|
||||
/** Digest algorithm used for ASN.1 tests */
|
||||
#define asn1_test_digest_algorithm sha1_algorithm
|
||||
|
||||
/** Digest size used for ASN.1 tests */
|
||||
#define ASN1_TEST_DIGEST_SIZE SHA1_DIGEST_SIZE
|
||||
|
||||
/** An ASN.1 test digest */
|
||||
struct asn1_test_digest {
|
||||
/** Digest value */
|
||||
uint8_t digest[ASN1_TEST_DIGEST_SIZE];
|
||||
};
|
||||
|
||||
/** An ASN.1 test */
|
||||
struct asn1_test {
|
||||
/** Image type */
|
||||
struct image_type *type;
|
||||
/** Source image */
|
||||
struct image *image;
|
||||
/** Expected digests of ASN.1 objects */
|
||||
struct asn1_test_digest *expected;
|
||||
/** Number of ASN.1 objects */
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
/**
|
||||
* Define an ASN.1 test
|
||||
*
|
||||
* @v _name Test name
|
||||
* @v _type Test image file type
|
||||
* @v _file Test image file data
|
||||
* @v ... Expected ASN.1 object digests
|
||||
* @ret test ASN.1 test
|
||||
*/
|
||||
#define ASN1( _name, _type, _file, ... ) \
|
||||
static const char _name ## __file[] = _file; \
|
||||
static struct image _name ## __image = { \
|
||||
.refcnt = REF_INIT ( ref_no_free ), \
|
||||
.name = #_name, \
|
||||
.data = ( userptr_t ) ( _name ## __file ), \
|
||||
.len = sizeof ( _name ## __file ), \
|
||||
}; \
|
||||
static struct asn1_test_digest _name ## _expected[] = { \
|
||||
__VA_ARGS__ \
|
||||
}; \
|
||||
static struct asn1_test _name = { \
|
||||
.type = _type, \
|
||||
.image = & _name ## __image, \
|
||||
.expected = _name ## _expected, \
|
||||
.count = ( sizeof ( _name ## _expected ) / \
|
||||
sizeof ( _name ## _expected[0] ) ), \
|
||||
};
|
||||
|
||||
extern void asn1_okx ( struct asn1_test *test, const char *file,
|
||||
unsigned int line );
|
||||
|
||||
/**
|
||||
* Report ASN.1 test result
|
||||
*
|
||||
* @v test ASN.1 test
|
||||
*/
|
||||
#define asn1_ok( test ) asn1_okx ( test, __FILE__, __LINE__ )
|
||||
|
||||
#endif /* _ASN1_TEST_H */
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (C) 2016 Michael Brown <mbrown@fensystems.co.uk>.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 2 of the
|
||||
* License, or any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA.
|
||||
*
|
||||
* You can also choose to distribute this program under the terms of
|
||||
* the Unmodified Binary Distribution Licence (as given in the file
|
||||
* COPYING.UBDL), provided that you have satisfied its requirements.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
/** @file
|
||||
*
|
||||
* DER self-tests
|
||||
*
|
||||
*/
|
||||
|
||||
/* Forcibly enable assertions */
|
||||
#undef NDEBUG
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <ipxe/test.h>
|
||||
#include <ipxe/der.h>
|
||||
#include "asn1_test.h"
|
||||
|
||||
/** Define inline data */
|
||||
#define DATA(...) { __VA_ARGS__ }
|
||||
|
||||
/** Define inline expected digest */
|
||||
#define DIGEST(...) { { __VA_ARGS__ } }
|
||||
|
||||
/** 32-bit RSA private key */
|
||||
ASN1 ( rsa32, &der_image_type,
|
||||
DATA ( 0x30, 0x2c, 0x02, 0x01, 0x00, 0x02, 0x05, 0x00, 0xb7, 0x56,
|
||||
0x5c, 0xb1, 0x02, 0x03, 0x01, 0x00, 0x01, 0x02, 0x04, 0x66,
|
||||
0xa4, 0xc4, 0x35, 0x02, 0x03, 0x00, 0xda, 0x9f, 0x02, 0x03,
|
||||
0x00, 0xd6, 0xaf, 0x02, 0x02, 0x01, 0x59, 0x02, 0x02, 0x4e,
|
||||
0xe1, 0x02, 0x03, 0x00, 0xa6, 0x5a ),
|
||||
DIGEST ( 0x82, 0x66, 0x24, 0xd9, 0xc3, 0x98, 0x1e, 0x5e, 0x56, 0xed,
|
||||
0xd0, 0xd0, 0x2a, 0x5e, 0x9c, 0x3a, 0x58, 0xdf, 0x76, 0x0d ) );
|
||||
|
||||
/** 64-bit RSA private key */
|
||||
ASN1 ( rsa64, &der_image_type,
|
||||
DATA ( 0x30, 0x3e, 0x02, 0x01, 0x00, 0x02, 0x09, 0x00, 0xa1, 0xba,
|
||||
0xb5, 0x70, 0x00, 0x89, 0xc0, 0x43, 0x02, 0x03, 0x01, 0x00,
|
||||
0x01, 0x02, 0x08, 0x43, 0x98, 0xc6, 0x3c, 0x5f, 0xdc, 0x98,
|
||||
0x01, 0x02, 0x05, 0x00, 0xcf, 0x91, 0x1c, 0x5d, 0x02, 0x05,
|
||||
0x00, 0xc7, 0x77, 0x85, 0x1f, 0x02, 0x05, 0x00, 0xbc, 0xb3,
|
||||
0x33, 0x91, 0x02, 0x04, 0x1b, 0xf9, 0x38, 0x13, 0x02, 0x04,
|
||||
0x19, 0xf2, 0x58, 0x86 ),
|
||||
DIGEST ( 0xee, 0x17, 0x32, 0x31, 0xf0, 0x3d, 0xfd, 0xaa, 0x9b, 0x47,
|
||||
0xaf, 0x7b, 0x4b, 0x52, 0x0b, 0xb1, 0xab, 0x25, 0x3f, 0x11 ) );
|
||||
|
||||
/**
|
||||
* Perform DER self-test
|
||||
*
|
||||
*/
|
||||
static void der_test_exec ( void ) {
|
||||
|
||||
/* Perform tests */
|
||||
asn1_ok ( &rsa32 );
|
||||
asn1_ok ( &rsa64 );
|
||||
}
|
||||
|
||||
/** DER self-test */
|
||||
struct self_test der_test __self_test = {
|
||||
.name = "der",
|
||||
.exec = der_test_exec,
|
||||
};
|
|
@ -69,3 +69,4 @@ REQUIRE_OBJECT ( pccrc_test );
|
|||
REQUIRE_OBJECT ( linebuf_test );
|
||||
REQUIRE_OBJECT ( iobuf_test );
|
||||
REQUIRE_OBJECT ( bitops_test );
|
||||
REQUIRE_OBJECT ( der_test );
|
||||
|
|
Loading…
Reference in New Issue