mirror of
https://github.com/ipxe/ipxe
synced 2026-04-16 03:00:10 +03:00
[crypto] Remove userptr_t from ASN.1 parsers
Simplify the ASN.1 code by assuming that all objects are fully accessible via pointer dereferences. This allows the concept of "additional data beyond the end of the cursor" to be removed, and simplifies parsing of all ASN.1 image formats. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
+7
-17
@@ -28,7 +28,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <assert.h>
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/der.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/image.h>
|
||||
|
||||
/** @file
|
||||
@@ -49,7 +48,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* The caller is responsible for eventually calling free() on the
|
||||
* allocated ASN.1 cursor.
|
||||
*/
|
||||
int der_asn1 ( userptr_t data, size_t len, size_t offset,
|
||||
int der_asn1 ( const void *data, size_t len, size_t offset,
|
||||
struct asn1_cursor **cursor ) {
|
||||
size_t remaining;
|
||||
void *raw;
|
||||
@@ -67,7 +66,7 @@ int der_asn1 ( userptr_t data, size_t len, size_t offset,
|
||||
/* Populate cursor and data buffer */
|
||||
(*cursor)->data = raw;
|
||||
(*cursor)->len = remaining;
|
||||
copy_from_user ( raw, data, offset, remaining );
|
||||
memcpy ( raw, ( data + offset ), remaining );
|
||||
|
||||
/* Shrink cursor */
|
||||
asn1_shrink_any ( *cursor );
|
||||
@@ -83,30 +82,21 @@ int der_asn1 ( userptr_t data, size_t len, size_t offset,
|
||||
*/
|
||||
static int der_image_probe ( struct image *image ) {
|
||||
struct asn1_cursor cursor;
|
||||
uint8_t buf[8];
|
||||
size_t extra;
|
||||
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 ) );
|
||||
/* Prepare cursor */
|
||||
cursor.data = image->data;
|
||||
cursor.len = image->len;
|
||||
|
||||
/* Check that image begins with an ASN.1 sequence object */
|
||||
if ( ( rc = asn1_enter_partial ( &cursor, ASN1_SEQUENCE,
|
||||
&extra ) ) != 0 ) {
|
||||
if ( ( rc = asn1_skip ( &cursor, ASN1_SEQUENCE ) ) != 0 ) {
|
||||
DBGC ( image, "DER %s is not valid ASN.1: %s\n",
|
||||
image->name, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Check that image comprises a single well-formed ASN.1 object */
|
||||
if ( extra != ( image->len - sizeof ( buf ) ) ) {
|
||||
if ( cursor.len ) {
|
||||
DBGC ( image, "DER %s is not single ASN.1\n", image->name );
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
+26
-25
@@ -49,8 +49,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* @v dhdr Signature data header to fill in
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int efisig_find ( userptr_t data, size_t len, size_t *start,
|
||||
EFI_SIGNATURE_LIST *lhdr, EFI_SIGNATURE_DATA *dhdr ) {
|
||||
static int efisig_find ( const void *data, size_t len, size_t *start,
|
||||
const EFI_SIGNATURE_LIST **lhdr,
|
||||
const EFI_SIGNATURE_DATA **dhdr ) {
|
||||
size_t offset;
|
||||
size_t remaining;
|
||||
size_t skip;
|
||||
@@ -63,38 +64,38 @@ static int efisig_find ( userptr_t data, size_t len, size_t *start,
|
||||
/* Read list header */
|
||||
assert ( offset <= len );
|
||||
remaining = ( len - offset );
|
||||
if ( remaining < sizeof ( *lhdr ) ) {
|
||||
if ( remaining < sizeof ( **lhdr ) ) {
|
||||
DBGC ( data, "EFISIG [%#zx,%#zx) truncated header "
|
||||
"at +%#zx\n", *start, len, offset );
|
||||
return -EINVAL;
|
||||
}
|
||||
copy_from_user ( lhdr, data, offset, sizeof ( *lhdr ) );
|
||||
*lhdr = ( data + offset );
|
||||
|
||||
/* Get length of this signature list */
|
||||
if ( remaining < lhdr->SignatureListSize ) {
|
||||
if ( remaining < (*lhdr)->SignatureListSize ) {
|
||||
DBGC ( data, "EFISIG [%#zx,%#zx) truncated list at "
|
||||
"+%#zx\n", *start, len, offset );
|
||||
return -EINVAL;
|
||||
}
|
||||
remaining = lhdr->SignatureListSize;
|
||||
remaining = (*lhdr)->SignatureListSize;
|
||||
|
||||
/* Get length of each signature in list */
|
||||
dlen = lhdr->SignatureSize;
|
||||
if ( dlen < sizeof ( *dhdr ) ) {
|
||||
dlen = (*lhdr)->SignatureSize;
|
||||
if ( dlen < sizeof ( **dhdr ) ) {
|
||||
DBGC ( data, "EFISIG [%#zx,%#zx) underlength "
|
||||
"signatures at +%#zx\n", *start, len, offset );
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Strip list header (including variable portion) */
|
||||
if ( ( remaining < sizeof ( *lhdr ) ) ||
|
||||
( ( remaining - sizeof ( *lhdr ) ) <
|
||||
lhdr->SignatureHeaderSize ) ) {
|
||||
if ( ( remaining < sizeof ( **lhdr ) ) ||
|
||||
( ( remaining - sizeof ( **lhdr ) ) <
|
||||
(*lhdr)->SignatureHeaderSize ) ) {
|
||||
DBGC ( data, "EFISIG [%#zx,%#zx) malformed header at "
|
||||
"+%#zx\n", *start, len, offset );
|
||||
return -EINVAL;
|
||||
}
|
||||
skip = ( sizeof ( *lhdr ) + lhdr->SignatureHeaderSize );
|
||||
skip = ( sizeof ( **lhdr ) + (*lhdr)->SignatureHeaderSize );
|
||||
offset += skip;
|
||||
remaining -= skip;
|
||||
|
||||
@@ -113,12 +114,12 @@ static int efisig_find ( userptr_t data, size_t len, size_t *start,
|
||||
continue;
|
||||
|
||||
/* Read data header */
|
||||
copy_from_user ( dhdr, data, offset, sizeof ( *dhdr ));
|
||||
*dhdr = ( data + offset );
|
||||
DBGC2 ( data, "EFISIG [%#zx,%#zx) %s ",
|
||||
offset, ( offset + dlen ),
|
||||
efi_guid_ntoa ( &lhdr->SignatureType ) );
|
||||
efi_guid_ntoa ( &(*lhdr)->SignatureType ) );
|
||||
DBGC2 ( data, "owner %s\n",
|
||||
efi_guid_ntoa ( &dhdr->SignatureOwner ) );
|
||||
efi_guid_ntoa ( &(*dhdr)->SignatureOwner ) );
|
||||
*start = offset;
|
||||
return 0;
|
||||
}
|
||||
@@ -137,23 +138,23 @@ static int efisig_find ( userptr_t data, size_t len, size_t *start,
|
||||
* The caller is responsible for eventually calling free() on the
|
||||
* allocated ASN.1 cursor.
|
||||
*/
|
||||
int efisig_asn1 ( userptr_t data, size_t len, size_t offset,
|
||||
int efisig_asn1 ( const void *data, size_t len, size_t offset,
|
||||
struct asn1_cursor **cursor ) {
|
||||
EFI_SIGNATURE_LIST lhdr;
|
||||
EFI_SIGNATURE_DATA dhdr;
|
||||
int ( * asn1 ) ( userptr_t data, size_t len, size_t offset,
|
||||
const EFI_SIGNATURE_LIST *lhdr;
|
||||
const EFI_SIGNATURE_DATA *dhdr;
|
||||
int ( * asn1 ) ( const void *data, size_t len, size_t offset,
|
||||
struct asn1_cursor **cursor );
|
||||
size_t skip = offsetof ( typeof ( dhdr ), SignatureData );
|
||||
size_t skip = offsetof ( typeof ( *dhdr ), SignatureData );
|
||||
int next;
|
||||
int rc;
|
||||
|
||||
/* Locate signature list entry */
|
||||
if ( ( rc = efisig_find ( data, len, &offset, &lhdr, &dhdr ) ) != 0 )
|
||||
goto err_entry;
|
||||
len = ( offset + lhdr.SignatureSize );
|
||||
len = ( offset + lhdr->SignatureSize );
|
||||
|
||||
/* Parse as PEM or DER based on first character */
|
||||
asn1 = ( ( dhdr.SignatureData[0] == ASN1_SEQUENCE ) ?
|
||||
asn1 = ( ( dhdr->SignatureData[0] == ASN1_SEQUENCE ) ?
|
||||
der_asn1 : pem_asn1 );
|
||||
DBGC2 ( data, "EFISIG [%#zx,%#zx) extracting %s\n", offset, len,
|
||||
( ( asn1 == der_asn1 ) ? "DER" : "PEM" ) );
|
||||
@@ -189,8 +190,8 @@ int efisig_asn1 ( userptr_t data, size_t len, size_t offset,
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int efisig_image_probe ( struct image *image ) {
|
||||
EFI_SIGNATURE_LIST lhdr;
|
||||
EFI_SIGNATURE_DATA dhdr;
|
||||
const EFI_SIGNATURE_LIST *lhdr;
|
||||
const EFI_SIGNATURE_DATA *dhdr;
|
||||
size_t offset = 0;
|
||||
unsigned int count = 0;
|
||||
int rc;
|
||||
@@ -205,7 +206,7 @@ static int efisig_image_probe ( struct image *image ) {
|
||||
}
|
||||
|
||||
/* Skip this entry */
|
||||
offset += lhdr.SignatureSize;
|
||||
offset += lhdr->SignatureSize;
|
||||
count++;
|
||||
|
||||
/* Check if we have reached end of the image */
|
||||
|
||||
+11
-13
@@ -28,7 +28,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
#include <assert.h>
|
||||
#include <ipxe/asn1.h>
|
||||
#include <ipxe/base64.h>
|
||||
#include <ipxe/uaccess.h>
|
||||
#include <ipxe/image.h>
|
||||
#include <ipxe/pem.h>
|
||||
|
||||
@@ -46,14 +45,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
* @v offset Starting offset
|
||||
* @ret next Offset to next line
|
||||
*/
|
||||
static size_t pem_next ( userptr_t data, size_t len, size_t offset ) {
|
||||
off_t eol;
|
||||
static size_t pem_next ( const void *data, size_t len, size_t offset ) {
|
||||
const void *sep;
|
||||
|
||||
/* Find and skip next newline character, if any */
|
||||
eol = memchr_user ( data, offset, '\n', ( len - offset ) );
|
||||
if ( eol < 0 )
|
||||
sep = memchr ( ( data + offset ), '\n', ( len - offset ) );
|
||||
if ( ! sep )
|
||||
return len;
|
||||
return ( eol + 1 );
|
||||
return ( ( sep - data ) + 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,9 +64,9 @@ static size_t pem_next ( userptr_t data, size_t len, size_t offset ) {
|
||||
* @v marker Boundary marker
|
||||
* @ret offset Offset to boundary marker line, or negative error
|
||||
*/
|
||||
static int pem_marker ( userptr_t data, size_t len, size_t offset,
|
||||
static int pem_marker ( const void *data, size_t len, size_t offset,
|
||||
const char *marker ) {
|
||||
char buf[ strlen ( marker ) ];
|
||||
size_t marker_len = strlen ( marker );
|
||||
|
||||
/* Sanity check */
|
||||
assert ( offset <= len );
|
||||
@@ -76,10 +75,9 @@ static int pem_marker ( userptr_t data, size_t len, size_t offset,
|
||||
while ( offset < len ) {
|
||||
|
||||
/* Check for marker */
|
||||
if ( ( len - offset ) < sizeof ( buf ) )
|
||||
if ( ( len - offset ) < marker_len )
|
||||
break;
|
||||
copy_from_user ( buf, data, offset, sizeof ( buf ) );
|
||||
if ( memcmp ( buf, marker, sizeof ( buf ) ) == 0 )
|
||||
if ( memcmp ( ( data + offset ), marker, marker_len ) == 0 )
|
||||
return offset;
|
||||
|
||||
/* Move to next line */
|
||||
@@ -102,7 +100,7 @@ static int pem_marker ( userptr_t data, size_t len, size_t offset,
|
||||
* The caller is responsible for eventually calling free() on the
|
||||
* allocated ASN.1 cursor.
|
||||
*/
|
||||
int pem_asn1 ( userptr_t data, size_t len, size_t offset,
|
||||
int pem_asn1 ( const void *data, size_t len, size_t offset,
|
||||
struct asn1_cursor **cursor ) {
|
||||
size_t encoded_len;
|
||||
size_t decoded_max_len;
|
||||
@@ -140,7 +138,7 @@ int pem_asn1 ( userptr_t data, size_t len, size_t offset,
|
||||
rc = -ENOMEM;
|
||||
goto err_alloc_encoded;
|
||||
}
|
||||
copy_from_user ( encoded, data, begin, encoded_len );
|
||||
memcpy ( encoded, ( data + begin ), encoded_len );
|
||||
encoded[encoded_len] = '\0';
|
||||
|
||||
/* Allocate cursor and data buffer */
|
||||
|
||||
Reference in New Issue
Block a user