From d7e58c5a812988c341ec4ad19f79faf067388d58 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 17 Apr 2024 15:49:37 +0100 Subject: [test] Add test cases for editable strings Signed-off-by: Michael Brown --- src/tests/editstring_test.c | 198 ++++++++++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 2 files changed, 199 insertions(+) create mode 100644 src/tests/editstring_test.c (limited to 'src/tests') diff --git a/src/tests/editstring_test.c b/src/tests/editstring_test.c new file mode 100644 index 000000000..72da33a77 --- /dev/null +++ b/src/tests/editstring_test.c @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * 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 (at your option) 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 + * + * Editable string tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include +#include +#include + +/** An editable string test */ +struct editstring_test { + /** Initial string, or NULL */ + const char *start; + /** Key sequence */ + const int *keys; + /** Length of key sequence */ + unsigned int count; + /** Expected result */ + const char *expected; +}; + +/** Define an inline key sequence */ +#define KEYS(...) { __VA_ARGS__ } + +/** Define an editable string test */ +#define EDITSTRING_TEST( name, START, EXPECTED, KEYS ) \ + static const int name ## _keys[] = KEYS; \ + static struct editstring_test name = { \ + .start = START, \ + .keys = name ## _keys, \ + .count = ( sizeof ( name ## _keys ) / \ + sizeof ( name ## _keys[0] ) ), \ + .expected = EXPECTED, \ + }; + +/* Simple typing */ +EDITSTRING_TEST ( simple, "", "hello world!", + KEYS ( 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', + 'd', '!' ) ); + +/* Simple typing from a NULL starting value */ +EDITSTRING_TEST ( simple_null, NULL, "hi there", + KEYS ( 'h', 'i', ' ', 't', 'h', 'e', 'r', 'e' ) ); + +/* Insertion */ +EDITSTRING_TEST ( insert, "in middle", "in the middle", + KEYS ( KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, + KEY_LEFT, 't', 'h', 'e', ' ' ) ); + +/* Backspace at end */ +EDITSTRING_TEST ( backspace_end, "byebye", "bye", + KEYS ( KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE ) ); + +/* Backspace of whole string */ +EDITSTRING_TEST ( backspace_all, "abc", "", + KEYS ( KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE ) ); + +/* Backspace of empty string */ +EDITSTRING_TEST ( backspace_empty, NULL, "", KEYS ( KEY_BACKSPACE ) ); + +/* Backspace beyond start of string */ +EDITSTRING_TEST ( backspace_beyond, "too far", "", + KEYS ( KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE, + KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE, + KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE ) ); + +/* Deletion of character at cursor via DEL */ +EDITSTRING_TEST ( delete_dc, "go away", "goaway", + KEYS ( KEY_HOME, KEY_RIGHT, KEY_RIGHT, KEY_DC ) ); + +/* Deletion of character at cursor via Ctrl-D */ +EDITSTRING_TEST ( delete_ctrl_d, "not here", "nohere", + KEYS ( KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, + KEY_LEFT, CTRL_D, CTRL_D ) ); + +/* Deletion of word at end of string */ +EDITSTRING_TEST ( word_end, "remove these two words", "remove these ", + KEYS ( CTRL_W, CTRL_W ) ); + +/* Deletion of word at start of string */ +EDITSTRING_TEST ( word_start, "no word", "word", + KEYS ( CTRL_A, KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, CTRL_W ) ); + +/* Deletion of word mid-string */ +EDITSTRING_TEST ( word_mid, "delete this word", "delete word", + KEYS ( KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, CTRL_W ) ); + +/* Deletion to start of line */ +EDITSTRING_TEST ( sol, "everything must go", "go", + KEYS ( KEY_LEFT, KEY_LEFT, CTRL_U ) ); + +/* Delete to end of line */ +EDITSTRING_TEST ( eol, "all is lost", "all", + KEYS ( KEY_HOME, KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, CTRL_K ) ); + +/** + * Report an editable string test result + * + * @v test Editable string test + * @v file Test code file + * @v line Test code line + */ +static void editstring_okx ( struct editstring_test *test, const char *file, + unsigned int line ) { + struct edit_string string; + unsigned int i; + char *actual; + int key; + + /* Initialise editable string */ + memset ( &string, 0, sizeof ( string ) ); + actual = NULL; + init_editstring ( &string, &actual ); + + /* Set initial string content */ + okx ( replace_string ( &string, test->start ) == 0, file, line ); + okx ( actual != NULL, file, line ); + okx ( string.cursor == ( test->start ? strlen ( test->start ) : 0 ), + file, line ); + DBGC ( test, "Initial string: \"%s\"\n", actual ); + + /* Inject keypresses */ + for ( i = 0 ; i < test->count ; i++ ) { + key = test->keys[i]; + okx ( edit_string ( &string, key ) == 0, file, line ); + okx ( actual != NULL, file, line ); + okx ( string.cursor <= strlen ( actual ), file, line ); + DBGC ( test, "After key %#02x (%c): \"%s\"\n", + key, ( isprint ( key ) ? key : '.' ), actual ); + } + + /* Verify result string */ + okx ( strcmp ( actual, test->expected ) == 0, file, line ); + + /* Free result string */ + free ( actual ); +} +#define editstring_ok( test ) editstring_okx ( test, __FILE__, __LINE__ ) + +/** + * Perform editable string self-tests + * + */ +static void editstring_test_exec ( void ) { + + editstring_ok ( &simple ); + editstring_ok ( &simple_null ); + editstring_ok ( &insert ); + editstring_ok ( &backspace_end ); + editstring_ok ( &backspace_all ); + editstring_ok ( &backspace_empty ); + editstring_ok ( &backspace_beyond ); + editstring_ok ( &delete_dc ); + editstring_ok ( &delete_ctrl_d ); + editstring_ok ( &word_end ); + editstring_ok ( &word_start ); + editstring_ok ( &word_mid ); + editstring_ok ( &sol ); + editstring_ok ( &eol ); +} + +/** Editable string self-test */ +struct self_test editstring_test __self_test = { + .name = "editstring", + .exec = editstring_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index cb296049e..0e9b3e806 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -85,3 +85,4 @@ REQUIRE_OBJECT ( x25519_test ); REQUIRE_OBJECT ( des_test ); REQUIRE_OBJECT ( mschapv2_test ); REQUIRE_OBJECT ( uuid_test ); +REQUIRE_OBJECT ( editstring_test ); -- cgit v1.2.3-55-g7522 From e965f179e1654103eca33feed7a9cc4c51d91be6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 23 May 2024 13:18:16 +0100 Subject: [libc] Add stpcpy() Signed-off-by: Michael Brown --- src/core/string.c | 17 +++++++++++++++-- src/include/string.h | 1 + src/tests/string_test.c | 18 ++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) (limited to 'src/tests') diff --git a/src/core/string.c b/src/core/string.c index 9a1b9b72a..364c4cf0e 100644 --- a/src/core/string.c +++ b/src/core/string.c @@ -321,9 +321,9 @@ char * strstr ( const char *haystack, const char *needle ) { * * @v dest Destination string * @v src Source string - * @ret dest Destination string + * @ret dnul Terminating NUL of destination string */ -char * strcpy ( char *dest, const char *src ) { +char * stpcpy ( char *dest, const char *src ) { const uint8_t *src_bytes = ( ( const uint8_t * ) src ); uint8_t *dest_bytes = ( ( uint8_t * ) dest ); @@ -333,6 +333,19 @@ char * strcpy ( char *dest, const char *src ) { if ( ! *dest_bytes ) break; } + return ( ( char * ) dest_bytes ); +} + +/** + * Copy string + * + * @v dest Destination string + * @v src Source string + * @ret dest Destination string + */ +char * strcpy ( char *dest, const char *src ) { + + stpcpy ( dest, src ); return dest; } diff --git a/src/include/string.h b/src/include/string.h index 5f5aecb92..4ee9c7344 100644 --- a/src/include/string.h +++ b/src/include/string.h @@ -43,6 +43,7 @@ extern char * __pure strchr ( const char *src, int character ) __nonnull; extern char * __pure strrchr ( const char *src, int character ) __nonnull; extern char * __pure strstr ( const char *haystack, const char *needle ) __nonnull; +extern char * stpcpy ( char *dest, const char *src ) __nonnull; extern char * strcpy ( char *dest, const char *src ) __nonnull; extern char * strncpy ( char *dest, const char *src, size_t max ) __nonnull; extern char * strcat ( char *dest, const char *src ) __nonnull; diff --git a/src/tests/string_test.c b/src/tests/string_test.c index 3afb8deb2..c0436c3ad 100644 --- a/src/tests/string_test.c +++ b/src/tests/string_test.c @@ -204,6 +204,24 @@ static void string_test_exec ( void ) { free ( dup ); } + /* Test stpcpy() */ + { + const char longer[12] = "duplicateme"; + const char shorter[6] = "hello"; + char dest[12]; + char *dnul; + + dnul = stpcpy ( dest, longer ); + ok ( *dnul == '\0' ); + ok ( dnul == &dest[11] ); + ok ( memcmp ( dest, longer, 12 ) == 0 ); + dnul = stpcpy ( dest, shorter ); + ok ( *dnul == '\0' ); + ok ( dnul == &dest[5] ); + ok ( memcmp ( dest, shorter, 6 ) == 0 ); + ok ( memcmp ( ( dest + 6 ), ( longer + 6 ), 6 ) == 0 ); + } + /* Test strcpy() */ { const char longer[7] = "copyme"; -- cgit v1.2.3-55-g7522 From 3b4d0cb555a01df8b56f422d9d17522ae60e17be Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 9 Aug 2024 16:33:51 +0100 Subject: [crypto] Pass image as parameter to CMS functions The cms_signature() and cms_verify() functions currently accept raw data pointers. This will not be possible for cms_decrypt(), which will need the ability to extract fragments of ASN.1 data from a potentially large image. Change cms_signature() and cms_verify() to accept an image as an input parameter, and move the responsibility for setting the image trust flag within cms_verify() since that now becomes a more natural fit. Signed-off-by: Michael Brown --- src/crypto/cms.c | 48 +++++++++++++++++++--------- src/include/ipxe/cms.h | 6 ++-- src/tests/cms_test.c | 86 +++++++++++++++++++++++++++++++++++--------------- src/usr/imgtrust.c | 26 ++------------- 4 files changed, 101 insertions(+), 65 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/cms.c b/src/crypto/cms.c index 19a0ce7ad..cbc0736bb 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -37,6 +37,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -372,7 +373,6 @@ static int cms_parse ( struct cms_signature *sig, asn1_enter ( &cursor, ASN1_SEQUENCE ); /* Parse contentType */ - if ( ( rc = cms_parse_content_type ( sig, &cursor ) ) != 0 ) return rc; asn1_skip_any ( &cursor ); @@ -453,16 +453,16 @@ static void cms_free ( struct refcnt *refcnt ) { /** * Create CMS signature * - * @v data Raw signature data - * @v len Length of raw data + * @v image Image * @ret sig CMS signature * @ret rc Return status code * * On success, the caller holds a reference to the CMS signature, and * is responsible for ultimately calling cms_put(). */ -int cms_signature ( const void *data, size_t len, struct cms_signature **sig ) { - struct asn1_cursor cursor; +int cms_signature ( struct image *image, struct cms_signature **sig ) { + struct asn1_cursor *raw; + int next; int rc; /* Allocate and initialise signature */ @@ -481,18 +481,30 @@ int cms_signature ( const void *data, size_t len, struct cms_signature **sig ) { goto err_alloc_chain; } - /* Initialise cursor */ - cursor.data = data; - cursor.len = len; - asn1_shrink_any ( &cursor ); + /* Get raw signature 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 ) ); + goto err_asn1; + } + + /* Use only first signature in image */ + asn1_shrink_any ( raw ); /* Parse signature */ - if ( ( rc = cms_parse ( *sig, &cursor ) ) != 0 ) + if ( ( rc = cms_parse ( *sig, raw ) ) != 0 ) goto err_parse; + /* Free raw signature data */ + free ( raw ); + return 0; err_parse: + free ( raw ); + err_asn1: err_alloc_chain: cms_put ( *sig ); err_alloc: @@ -642,15 +654,14 @@ static int cms_verify_signer_info ( struct cms_signature *sig, * Verify CMS signature * * @v sig CMS signature - * @v data Signed data - * @v len Length of signed data + * @v image Signed image * @v name Required common name, or NULL to check all signatures * @v time Time at which to validate certificates * @v store Certificate store, or NULL to use default * @v root Root certificate list, or NULL to use default * @ret rc Return status code */ -int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, +int cms_verify ( struct cms_signature *sig, struct image *image, const char *name, time_t time, struct x509_chain *store, struct x509_root *root ) { struct cms_signer_info *info; @@ -658,13 +669,17 @@ int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, int count = 0; int rc; + /* Mark image as untrusted */ + image_untrust ( image ); + /* Verify using all signerInfos */ list_for_each_entry ( info, &sig->info, list ) { cert = x509_first ( info->chain ); if ( name && ( x509_check_name ( cert, name ) != 0 ) ) continue; - if ( ( rc = cms_verify_signer_info ( sig, info, data, len, time, - store, root ) ) != 0 ) + if ( ( rc = cms_verify_signer_info ( sig, info, image->data, + image->len, time, store, + root ) ) != 0 ) return rc; count++; } @@ -681,5 +696,8 @@ int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, } } + /* Mark image as trusted */ + image_trust ( image ); + return 0; } diff --git a/src/include/ipxe/cms.h b/src/include/ipxe/cms.h index 7adf724b2..cca7779c5 100644 --- a/src/include/ipxe/cms.h +++ b/src/include/ipxe/cms.h @@ -16,6 +16,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +struct image; + /** CMS signer information */ struct cms_signer_info { /** List of signer information blocks */ @@ -67,9 +69,9 @@ cms_put ( struct cms_signature *sig ) { ref_put ( &sig->refcnt ); } -extern int cms_signature ( const void *data, size_t len, +extern int cms_signature ( struct image *image, struct cms_signature **sig ); -extern int cms_verify ( struct cms_signature *sig, userptr_t data, size_t len, +extern int cms_verify ( struct cms_signature *sig, 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 f35fa206d..d98b2c3e5 100644 --- a/src/tests/cms_test.c +++ b/src/tests/cms_test.c @@ -36,7 +36,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include +#include #include #include @@ -45,19 +47,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** CMS test code blob */ struct cms_test_code { - /** Data */ - const void *data; - /** Length of data */ - size_t len; + /** Code image */ + struct image image; }; /** CMS test signature */ struct cms_test_signature { - /** Data */ - const void *data; - /** Length of data */ - size_t len; - + /** Signature image */ + struct image image; /** Parsed signature */ struct cms_signature *sig; }; @@ -69,19 +66,29 @@ struct cms_test_signature { #define FINGERPRINT(...) { __VA_ARGS__ } /** Define a test code blob */ -#define SIGNED_CODE( name, DATA ) \ - static const uint8_t name ## _data[] = DATA; \ - static struct cms_test_code name = { \ - .data = name ## _data, \ - .len = sizeof ( name ## _data ), \ +#define SIGNED_CODE( NAME, DATA ) \ + static const uint8_t NAME ## _data[] = DATA; \ + static struct cms_test_code NAME = { \ + .image = { \ + .refcnt = REF_INIT ( ref_no_free ), \ + .name = #NAME, \ + .type = &der_image_type, \ + .data = ( userptr_t ) ( NAME ## _data ), \ + .len = sizeof ( NAME ## _data ), \ + }, \ } /** Define a test signature */ -#define SIGNATURE( name, DATA ) \ - static const uint8_t name ## _data[] = DATA; \ - static struct cms_test_signature name = { \ - .data = name ## _data, \ - .len = sizeof ( name ## _data ), \ +#define SIGNATURE( NAME, DATA ) \ + static const uint8_t NAME ## _data[] = DATA; \ + static struct cms_test_signature NAME = { \ + .image = { \ + .refcnt = REF_INIT ( ref_no_free ), \ + .name = #NAME, \ + .type = &der_image_type, \ + .data = ( userptr_t ) ( NAME ## _data ), \ + .len = sizeof ( NAME ## _data ), \ + }, \ } /** Code that has been signed */ @@ -1353,9 +1360,16 @@ static time_t test_expired = 1375573111ULL; /* Sat Aug 3 23:38:31 2013 */ */ static void cms_signature_okx ( struct cms_test_signature *sgn, const char *file, unsigned int line ) { + const void *data = ( ( void * ) sgn->image.data ); + + /* Fix up image data pointer */ + sgn->image.data = virt_to_user ( data ); + + /* Check ability to parse signature */ + okx ( cms_signature ( &sgn->image, &sgn->sig ) == 0, file, line ); - okx ( cms_signature ( sgn->data, sgn->len, &sgn->sig ) == 0, - file, line ); + /* Reset image data pointer */ + sgn->image.data = ( ( userptr_t ) data ); } #define cms_signature_ok( sgn ) \ cms_signature_okx ( sgn, __FILE__, __LINE__ ) @@ -1377,10 +1391,21 @@ static void cms_verify_okx ( struct cms_test_signature *sgn, time_t time, struct x509_chain *store, struct x509_root *root, const char *file, unsigned int line ) { + const void *data = ( ( void * ) code->image.data ); + /* Fix up image data pointer */ + code->image.data = virt_to_user ( data ); + + /* Invalidate any certificates from previous tests */ x509_invalidate_chain ( sgn->sig->certificates ); - okx ( cms_verify ( sgn->sig, virt_to_user ( code->data ), code->len, - name, time, store, root ) == 0, file, line ); + + /* Check ability to verify signature */ + okx ( cms_verify ( sgn->sig, &code->image, name, time, store, + root ) == 0, file, line ); + okx ( code->image.flags & IMAGE_TRUSTED, file, line ); + + /* Reset image data pointer */ + code->image.data = ( ( userptr_t ) data ); } #define cms_verify_ok( sgn, code, name, time, store, root ) \ cms_verify_okx ( sgn, code, name, time, store, root, \ @@ -1403,10 +1428,21 @@ static void cms_verify_fail_okx ( struct cms_test_signature *sgn, time_t time, struct x509_chain *store, struct x509_root *root, const char *file, unsigned int line ) { + const void *data = ( ( void * ) code->image.data ); + + /* Fix up image data pointer */ + code->image.data = virt_to_user ( data ); + /* Invalidate any certificates from previous tests */ x509_invalidate_chain ( sgn->sig->certificates ); - okx ( cms_verify ( sgn->sig, virt_to_user ( code->data ), code->len, - name, time, store, root ) != 0, file, line ); + + /* Check inability to verify signature */ + okx ( cms_verify ( sgn->sig, &code->image, name, time, store, + root ) != 0, file, line ); + okx ( ! ( code->image.flags & IMAGE_TRUSTED ), file, line ); + + /* Reset image data pointer */ + code->image.data = ( ( userptr_t ) data ); } #define cms_verify_fail_ok( sgn, code, name, time, store, root ) \ cms_verify_fail_okx ( sgn, code, name, time, store, root, \ diff --git a/src/usr/imgtrust.c b/src/usr/imgtrust.c index e7c2067a0..54ea3378f 100644 --- a/src/usr/imgtrust.c +++ b/src/usr/imgtrust.c @@ -50,31 +50,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ int imgverify ( struct image *image, struct image *signature, const char *name ) { - struct asn1_cursor *data; struct cms_signature *sig; struct cms_signer_info *info; time_t now; - int next; int rc; - /* Mark image as untrusted */ - image_untrust ( image ); - - /* Get raw signature data */ - next = image_asn1 ( signature, 0, &data ); - if ( next < 0 ) { - rc = next; - goto err_asn1; - } - /* Parse signature */ - if ( ( rc = cms_signature ( data->data, data->len, &sig ) ) != 0 ) + if ( ( rc = cms_signature ( signature, &sig ) ) != 0 ) goto err_parse; - /* Free raw signature data */ - free ( data ); - data = NULL; - /* Complete all certificate chains */ list_for_each_entry ( info, &sig->info, list ) { if ( ( rc = create_validator ( &monojob, info->chain, @@ -86,16 +70,14 @@ int imgverify ( struct image *image, struct image *signature, /* Use signature to verify image */ now = time ( NULL ); - if ( ( rc = cms_verify ( sig, image->data, image->len, - name, now, NULL, NULL ) ) != 0 ) + if ( ( rc = cms_verify ( sig, image, name, now, NULL, NULL ) ) != 0 ) goto err_verify; /* Drop reference to signature */ cms_put ( sig ); sig = NULL; - /* Mark image as trusted */ - image_trust ( image ); + /* Record signature verification */ syslog ( LOG_NOTICE, "Image \"%s\" signature OK\n", image->name ); return 0; @@ -105,8 +87,6 @@ int imgverify ( struct image *image, struct image *signature, err_create_validator: cms_put ( sig ); err_parse: - free ( data ); - err_asn1: syslog ( LOG_ERR, "Image \"%s\" signature bad: %s\n", image->name, strerror ( rc ) ); return rc; -- cgit v1.2.3-55-g7522 From 97635eb71b5ad7e81e79f32fef5f4394bcee0722 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 12 Aug 2024 12:36:41 +0100 Subject: [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 --- src/crypto/cms.c | 515 ++++++++++++++++++++++++++---------------------- src/include/ipxe/asn1.h | 2 +- src/include/ipxe/cms.h | 87 +++++--- src/tests/cms_test.c | 24 +-- src/usr/imgtrust.c | 20 +- 5 files changed, 364 insertions(+), 284 deletions(-) (limited to 'src/tests') 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 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 ) ); -- cgit v1.2.3-55-g7522 From 53f089b723e16eecb4fd2e2a59b74b3932431b30 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Aug 2024 10:43:52 +0100 Subject: [crypto] Pass asymmetric keys as ASN.1 cursors Asymmetric keys are invariably encountered within ASN.1 structures such as X.509 certificates, and the various large integers within an RSA key are themselves encoded using ASN.1. Simplify all code handling asymmetric keys by passing keys as a single ASN.1 cursor, rather than separate data and length pointers. Signed-off-by: Michael Brown --- src/crypto/cms.c | 3 +-- src/crypto/crypto_null.c | 4 +-- src/crypto/ocsp.c | 4 +-- src/crypto/rsa.c | 30 +++++---------------- src/crypto/x509.c | 9 +++---- src/drivers/net/iphone.c | 3 +-- src/include/ipxe/crypto.h | 23 +++++++--------- src/net/tls.c | 5 ++-- src/tests/pubkey_test.h | 37 ++++++++++---------------- src/tests/rsa_test.c | 68 +++++++++++++++++++++-------------------------- 10 files changed, 74 insertions(+), 112 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/cms.c b/src/crypto/cms.c index 1f33613f4..0b772f1cf 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -621,8 +621,7 @@ static int cms_verify_digest ( struct cms_message *cms, 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 ) { + if ( ( rc = pubkey_init ( pubkey, ctx, &public_key->raw ) ) != 0 ) { DBGC ( cms, "CMS %p/%p could not initialise public key: %s\n", cms, part, strerror ( rc ) ); goto err_init; diff --git a/src/crypto/crypto_null.c b/src/crypto/crypto_null.c index 0ad463c3e..b4169382b 100644 --- a/src/crypto/crypto_null.c +++ b/src/crypto/crypto_null.c @@ -93,8 +93,8 @@ struct cipher_algorithm cipher_null = { .auth = cipher_null_auth, }; -int pubkey_null_init ( void *ctx __unused, const void *key __unused, - size_t key_len __unused ) { +int pubkey_null_init ( void *ctx __unused, + const struct asn1_cursor *key __unused ) { return 0; } diff --git a/src/crypto/ocsp.c b/src/crypto/ocsp.c index cc957b40c..f35593454 100644 --- a/src/crypto/ocsp.c +++ b/src/crypto/ocsp.c @@ -857,8 +857,8 @@ static int ocsp_check_signature ( struct ocsp_check *ocsp, digest_final ( digest, digest_ctx, digest_out ); /* Initialise public-key algorithm */ - if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data, - public_key->raw.len ) ) != 0 ) { + if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, + &public_key->raw ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" could not initialise public key: " "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); goto err_init; diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index 16c67d822..2d288a953 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -233,27 +233,21 @@ static int rsa_parse_mod_exp ( struct asn1_cursor *modulus, * * @v ctx RSA context * @v key Key - * @v key_len Length of key * @ret rc Return status code */ -static int rsa_init ( void *ctx, const void *key, size_t key_len ) { +static int rsa_init ( void *ctx, const struct asn1_cursor *key ) { struct rsa_context *context = ctx; struct asn1_cursor modulus; struct asn1_cursor exponent; - struct asn1_cursor cursor; int rc; /* Initialise context */ memset ( context, 0, sizeof ( *context ) ); - /* Initialise cursor */ - cursor.data = key; - cursor.len = key_len; - /* Parse modulus and exponent */ - if ( ( rc = rsa_parse_mod_exp ( &modulus, &exponent, &cursor ) ) != 0 ){ + if ( ( rc = rsa_parse_mod_exp ( &modulus, &exponent, key ) ) != 0 ){ DBGC ( context, "RSA %p invalid modulus/exponent:\n", context ); - DBGC_HDA ( context, 0, cursor.data, cursor.len ); + DBGC_HDA ( context, 0, key->data, key->len ); goto err_parse; } @@ -592,33 +586,23 @@ static void rsa_final ( void *ctx ) { * Check for matching RSA public/private key pair * * @v private_key Private key - * @v private_key_len Private key length * @v public_key Public key - * @v public_key_len Public key length * @ret rc Return status code */ -static int rsa_match ( const void *private_key, size_t private_key_len, - const void *public_key, size_t public_key_len ) { +static int rsa_match ( const struct asn1_cursor *private_key, + const struct asn1_cursor *public_key ) { struct asn1_cursor private_modulus; struct asn1_cursor private_exponent; - struct asn1_cursor private_cursor; struct asn1_cursor public_modulus; struct asn1_cursor public_exponent; - struct asn1_cursor public_cursor; int rc; - /* Initialise cursors */ - private_cursor.data = private_key; - private_cursor.len = private_key_len; - public_cursor.data = public_key; - public_cursor.len = public_key_len; - /* Parse moduli and exponents */ if ( ( rc = rsa_parse_mod_exp ( &private_modulus, &private_exponent, - &private_cursor ) ) != 0 ) + private_key ) ) != 0 ) return rc; if ( ( rc = rsa_parse_mod_exp ( &public_modulus, &public_exponent, - &public_cursor ) ) != 0 ) + public_key ) ) != 0 ) return rc; /* Compare moduli */ diff --git a/src/crypto/x509.c b/src/crypto/x509.c index acb85620f..c0762740e 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -1149,8 +1149,8 @@ static int x509_check_signature ( struct x509_certificate *cert, } /* Verify signature using signer's public key */ - if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, public_key->raw.data, - public_key->raw.len ) ) != 0 ) { + if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, + &public_key->raw ) ) != 0 ) { DBGC ( cert, "X509 %p \"%s\" cannot initialise public key: " "%s\n", cert, x509_name ( cert ), strerror ( rc ) ); goto err_pubkey_init; @@ -1842,9 +1842,8 @@ struct x509_certificate * x509_find_key ( struct x509_chain *store, /* Check public key */ cert = link->cert; if ( pubkey_match ( cert->signature_algorithm->pubkey, - key->builder.data, key->builder.len, - cert->subject.public_key.raw.data, - cert->subject.public_key.raw.len ) == 0 ) + privkey_cursor ( key ), + &cert->subject.public_key.raw ) == 0 ) return x509_found ( store, cert ); } diff --git a/src/drivers/net/iphone.c b/src/drivers/net/iphone.c index bbac527bd..96eb0952b 100644 --- a/src/drivers/net/iphone.c +++ b/src/drivers/net/iphone.c @@ -367,8 +367,7 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject, int rc; /* Initialise "private" key */ - if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, private->data, - private->len ) ) != 0 ) { + if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, private ) ) != 0 ) { DBGC ( icert, "ICERT %p could not initialise private key: " "%s\n", icert, strerror ( rc ) ); goto err_pubkey_init; diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index a6f437655..8b6eb94f6 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include /** A message digest algorithm */ struct digest_algorithm { @@ -126,10 +127,9 @@ struct pubkey_algorithm { * * @v ctx Context * @v key Key - * @v key_len Length of key * @ret rc Return status code */ - int ( * init ) ( void *ctx, const void *key, size_t key_len ); + int ( * init ) ( void *ctx, const struct asn1_cursor *key ); /** Calculate maximum output length * * @v ctx Context @@ -186,13 +186,11 @@ struct pubkey_algorithm { /** Check that public key matches private key * * @v private_key Private key - * @v private_key_len Private key length * @v public_key Public key - * @v public_key_len Public key length * @ret rc Return status code */ - int ( * match ) ( const void *private_key, size_t private_key_len, - const void *public_key, size_t public_key_len ); + int ( * match ) ( const struct asn1_cursor *private_key, + const struct asn1_cursor *public_key ); }; /** An elliptic curve */ @@ -282,8 +280,8 @@ is_auth_cipher ( struct cipher_algorithm *cipher ) { static inline __attribute__ (( always_inline )) int pubkey_init ( struct pubkey_algorithm *pubkey, void *ctx, - const void *key, size_t key_len ) { - return pubkey->init ( ctx, key, key_len ); + const struct asn1_cursor *key ) { + return pubkey->init ( ctx, key ); } static inline __attribute__ (( always_inline )) size_t @@ -324,10 +322,9 @@ pubkey_final ( struct pubkey_algorithm *pubkey, void *ctx ) { static inline __attribute__ (( always_inline )) int pubkey_match ( struct pubkey_algorithm *pubkey, - const void *private_key, size_t private_key_len, - const void *public_key, size_t public_key_len ) { - return pubkey->match ( private_key, private_key_len, public_key, - public_key_len ); + const struct asn1_cursor *private_key, + const struct asn1_cursor *public_key ) { + return pubkey->match ( private_key, public_key ); } static inline __attribute__ (( always_inline )) int @@ -348,7 +345,7 @@ extern void cipher_null_decrypt ( void *ctx, const void *src, void *dst, size_t len ); extern void cipher_null_auth ( void *ctx, void *auth ); -extern int pubkey_null_init ( void *ctx, const void *key, size_t key_len ); +extern int pubkey_null_init ( void *ctx, const struct asn1_cursor *key ); extern size_t pubkey_null_max_len ( void *ctx ); extern int pubkey_null_encrypt ( void *ctx, const void *plaintext, size_t plaintext_len, void *ciphertext ); diff --git a/src/net/tls.c b/src/net/tls.c index c08057103..a22626f41 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1824,7 +1824,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { tls_verify_handshake ( tls, digest_out ); /* Initialise public-key algorithm */ - if ( ( rc = pubkey_init ( pubkey, ctx, key->data, key->len ) ) != 0 ) { + if ( ( rc = pubkey_init ( pubkey, ctx, key ) ) != 0 ) { DBGC ( tls, "TLS %p could not initialise %s client private " "key: %s\n", tls, pubkey->name, strerror ( rc ) ); goto err_pubkey_init; @@ -3581,8 +3581,7 @@ static void tls_validator_done ( struct tls_connection *tls, int rc ) { /* Initialise public key algorithm */ if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx, - cert->subject.public_key.raw.data, - cert->subject.public_key.raw.len ) ) != 0 ) { + &cert->subject.public_key.raw ) ) != 0 ) { DBGC ( tls, "TLS %p cannot initialise public key: %s\n", tls, strerror ( rc ) ); goto err; diff --git a/src/tests/pubkey_test.h b/src/tests/pubkey_test.h index cd65b8703..214992238 100644 --- a/src/tests/pubkey_test.h +++ b/src/tests/pubkey_test.h @@ -12,17 +12,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * * @v pubkey Public key algorithm * @v key Key - * @v key_len Key length * @v ciphertext Ciphertext * @v ciphertext_len Ciphertext length * @v expected Expected plaintext * @v expected_len Expected plaintext length */ -#define pubkey_decrypt_ok( pubkey, key, key_len, ciphertext, \ - ciphertext_len, expected, expected_len ) do {\ +#define pubkey_decrypt_ok( pubkey, key, ciphertext, ciphertext_len, \ + expected, expected_len ) do { \ uint8_t ctx[ (pubkey)->ctxsize ]; \ \ - ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 ); \ + ok ( pubkey_init ( (pubkey), ctx, (key) ) == 0 ); \ { \ size_t max_len = pubkey_max_len ( (pubkey), ctx ); \ uint8_t decrypted[ max_len ]; \ @@ -44,19 +43,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * * @v pubkey Public key algorithm * @v encrypt_key Encryption key - * @v encrypt_key_len Encryption key length * @v decrypt_key Decryption key - * @v decrypt_key_len Decryption key length * @v plaintext Plaintext * @v plaintext_len Plaintext length */ -#define pubkey_encrypt_ok( pubkey, encrypt_key, encrypt_key_len, \ - decrypt_key, decrypt_key_len, plaintext, \ +#define pubkey_encrypt_ok( pubkey, encrypt_key, decrypt_key, plaintext, \ plaintext_len ) do { \ uint8_t ctx[ (pubkey)->ctxsize ]; \ \ - ok ( pubkey_init ( (pubkey), ctx, (encrypt_key), \ - (encrypt_key_len) ) == 0 ); \ + ok ( pubkey_init ( (pubkey), ctx, (encrypt_key) ) == 0 ); \ { \ size_t max_len = pubkey_max_len ( (pubkey), ctx ); \ uint8_t encrypted[ max_len ]; \ @@ -68,9 +63,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); encrypted ); \ ok ( encrypted_len >= 0 ); \ pubkey_decrypt_ok ( (pubkey), (decrypt_key), \ - (decrypt_key_len), encrypted, \ - encrypted_len, (plaintext), \ - (plaintext_len) ); \ + encrypted, encrypted_len, \ + (plaintext), (plaintext_len) ); \ } \ pubkey_final ( (pubkey), ctx ); \ } while ( 0 ) @@ -80,15 +74,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * * @v pubkey Public key algorithm * @v key Key - * @v key_len Key length * @v digest Digest algorithm * @v plaintext Plaintext * @v plaintext_len Plaintext length * @v expected Expected signature * @v expected_len Expected signature length */ -#define pubkey_sign_ok( pubkey, key, key_len, digest, plaintext, \ - plaintext_len, expected, expected_len ) do { \ +#define pubkey_sign_ok( pubkey, key, digest, plaintext, plaintext_len, \ + expected, expected_len ) do { \ uint8_t ctx[ (pubkey)->ctxsize ]; \ uint8_t digestctx[ (digest)->ctxsize ]; \ uint8_t digestout[ (digest)->digestsize ]; \ @@ -98,7 +91,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); (plaintext_len) ); \ digest_final ( (digest), digestctx, digestout ); \ \ - ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 ); \ + ok ( pubkey_init ( (pubkey), ctx, (key) ) == 0 ); \ { \ size_t max_len = pubkey_max_len ( (pubkey), ctx ); \ uint8_t signature[ max_len ]; \ @@ -118,14 +111,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * * @v pubkey Public key algorithm * @v key Key - * @v key_len Key length * @v digest Digest algorithm * @v plaintext Plaintext * @v plaintext_len Plaintext length * @v signature Signature * @v signature_len Signature length */ -#define pubkey_verify_ok( pubkey, key, key_len, digest, plaintext, \ +#define pubkey_verify_ok( pubkey, key, digest, plaintext, \ plaintext_len, signature, signature_len ) do {\ uint8_t ctx[ (pubkey)->ctxsize ]; \ uint8_t digestctx[ (digest)->ctxsize ]; \ @@ -136,7 +128,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); (plaintext_len) ); \ digest_final ( (digest), digestctx, digestout ); \ \ - ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 ); \ + ok ( pubkey_init ( (pubkey), ctx, (key) ) == 0 ); \ ok ( pubkey_verify ( (pubkey), ctx, (digest), digestout, \ (signature), (signature_len) ) == 0 ); \ pubkey_final ( (pubkey), ctx ); \ @@ -147,14 +139,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * * @v pubkey Public key algorithm * @v key Key - * @v key_len Key length * @v digest Digest algorithm * @v plaintext Plaintext * @v plaintext_len Plaintext length * @v signature Signature * @v signature_len Signature length */ -#define pubkey_verify_fail_ok( pubkey, key, key_len, digest, plaintext, \ +#define pubkey_verify_fail_ok( pubkey, key, digest, plaintext, \ plaintext_len, signature, \ signature_len ) do { \ uint8_t ctx[ (pubkey)->ctxsize ]; \ @@ -166,7 +157,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); (plaintext_len) ); \ digest_final ( (digest), digestctx, digestout ); \ \ - ok ( pubkey_init ( (pubkey), ctx, (key), (key_len) ) == 0 ); \ + ok ( pubkey_init ( (pubkey), ctx, (key) ) == 0 ); \ ok ( pubkey_verify ( (pubkey), ctx, (digest), digestout, \ (signature), (signature_len) ) != 0 ); \ pubkey_final ( (pubkey), ctx ); \ diff --git a/src/tests/rsa_test.c b/src/tests/rsa_test.c index 46894f603..b1d522bc0 100644 --- a/src/tests/rsa_test.c +++ b/src/tests/rsa_test.c @@ -61,13 +61,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** An RSA encryption and decryption self-test */ struct rsa_encrypt_decrypt_test { /** Private key */ - const void *private; - /** Private key length */ - size_t private_len; + const struct asn1_cursor private; /** Public key */ - const void *public; - /** Public key length */ - size_t public_len; + const struct asn1_cursor public; /** Plaintext */ const void *plaintext; /** Plaintext length */ @@ -100,10 +96,14 @@ struct rsa_encrypt_decrypt_test { static const uint8_t name ## _plaintext[] = PLAINTEXT; \ static const uint8_t name ## _ciphertext[] = CIPHERTEXT; \ static struct rsa_encrypt_decrypt_test name = { \ - .private = name ## _private, \ - .private_len = sizeof ( name ## _private ), \ - .public = name ## _public, \ - .public_len = sizeof ( name ## _public ), \ + .private = { \ + .data = name ## _private, \ + .len = sizeof ( name ## _private ), \ + }, \ + .public = { \ + .data = name ## _public, \ + .len = sizeof ( name ## _public ), \ + }, \ .plaintext = name ## _plaintext, \ .plaintext_len = sizeof ( name ## _plaintext ), \ .ciphertext = name ## _ciphertext, \ @@ -113,13 +113,9 @@ struct rsa_encrypt_decrypt_test { /** An RSA signature self-test */ struct rsa_signature_test { /** Private key */ - const void *private; - /** Private key length */ - size_t private_len; + const struct asn1_cursor private; /** Public key */ - const void *public; - /** Public key length */ - size_t public_len; + const struct asn1_cursor public; /** Plaintext */ const void *plaintext; /** Plaintext length */ @@ -150,10 +146,14 @@ struct rsa_signature_test { static const uint8_t name ## _plaintext[] = PLAINTEXT; \ static const uint8_t name ## _signature[] = SIGNATURE; \ static struct rsa_signature_test name = { \ - .private = name ## _private, \ - .private_len = sizeof ( name ## _private ), \ - .public = name ## _public, \ - .public_len = sizeof ( name ## _public ), \ + .private = { \ + .data = name ## _private, \ + .len = sizeof ( name ## _private ), \ + }, \ + .public = { \ + .data = name ## _public, \ + .len = sizeof ( name ## _public ), \ + }, \ .plaintext = name ## _plaintext, \ .plaintext_len = sizeof ( name ## _plaintext ), \ .algorithm = ALGORITHM, \ @@ -167,17 +167,14 @@ struct rsa_signature_test { * @v test RSA encryption and decryption test */ #define rsa_encrypt_decrypt_ok( test ) do { \ - pubkey_decrypt_ok ( &rsa_algorithm, (test)->private, \ - (test)->private_len, (test)->ciphertext, \ - (test)->ciphertext_len, (test)->plaintext, \ + pubkey_decrypt_ok ( &rsa_algorithm, &(test)->private, \ + (test)->ciphertext, (test)->ciphertext_len, \ + (test)->plaintext, (test)->plaintext_len );\ + pubkey_encrypt_ok ( &rsa_algorithm, &(test)->private, \ + &(test)->public, (test)->plaintext, \ (test)->plaintext_len ); \ - pubkey_encrypt_ok ( &rsa_algorithm, (test)->private, \ - (test)->private_len, (test)->public, \ - (test)->public_len, (test)->plaintext, \ - (test)->plaintext_len ); \ - pubkey_encrypt_ok ( &rsa_algorithm, (test)->public, \ - (test)->public_len, (test)->private, \ - (test)->private_len, (test)->plaintext, \ + pubkey_encrypt_ok ( &rsa_algorithm, &(test)->public, \ + &(test)->private, (test)->plaintext, \ (test)->plaintext_len ); \ } while ( 0 ) @@ -190,18 +187,15 @@ struct rsa_signature_test { #define rsa_signature_ok( test ) do { \ struct digest_algorithm *digest = (test)->algorithm->digest; \ uint8_t bad_signature[ (test)->signature_len ]; \ - pubkey_sign_ok ( &rsa_algorithm, (test)->private, \ - (test)->private_len, digest, \ + pubkey_sign_ok ( &rsa_algorithm, &(test)->private, digest, \ (test)->plaintext, (test)->plaintext_len, \ (test)->signature, (test)->signature_len ); \ - pubkey_verify_ok ( &rsa_algorithm, (test)->public, \ - (test)->public_len, digest, \ + pubkey_verify_ok ( &rsa_algorithm, &(test)->public, digest, \ (test)->plaintext, (test)->plaintext_len, \ (test)->signature, (test)->signature_len ); \ memset ( bad_signature, 0, sizeof ( bad_signature ) ); \ - pubkey_verify_fail_ok ( &rsa_algorithm, (test)->public, \ - (test)->public_len, digest, \ - (test)->plaintext, \ + pubkey_verify_fail_ok ( &rsa_algorithm, &(test)->public, \ + digest, (test)->plaintext, \ (test)->plaintext_len, bad_signature, \ sizeof ( bad_signature ) ); \ } while ( 0 ) -- cgit v1.2.3-55-g7522 From 633f4f362dbdf1f3177ee0f6b5b63085af7c1be5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 18 Aug 2024 20:01:08 +0100 Subject: [test] Generalise public-key algorithm tests and use okx() Generalise the existing support for performing RSA public-key encryption, decryption, signature, and verification tests, and update the code to use okx() for neater reporting of test results. Signed-off-by: Michael Brown --- src/tests/pubkey_test.c | 187 +++++++++++++++++++++++++++++++++ src/tests/pubkey_test.h | 269 +++++++++++++++++++++++------------------------- src/tests/rsa_test.c | 189 ++++------------------------------ 3 files changed, 336 insertions(+), 309 deletions(-) create mode 100644 src/tests/pubkey_test.c (limited to 'src/tests') diff --git a/src/tests/pubkey_test.c b/src/tests/pubkey_test.c new file mode 100644 index 000000000..93962516a --- /dev/null +++ b/src/tests/pubkey_test.c @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2024 Michael Brown . + * + * 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 + * + * Public key self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include +#include +#include +#include "pubkey_test.h" + +/** + * Report public key encryption and decryption test result + * + * @v test Public key encryption and decryption test + * @v file Test code file + * @v line Test code line + */ +void pubkey_okx ( struct pubkey_test *test, const char *file, + unsigned int line ) { + struct pubkey_algorithm *pubkey = test->pubkey; + uint8_t private_ctx[pubkey->ctxsize]; + uint8_t public_ctx[pubkey->ctxsize]; + size_t max_len; + + /* Initialize contexts */ + okx ( pubkey_init ( pubkey, private_ctx, &test->private ) == 0, + file, line ); + okx ( pubkey_init ( pubkey, public_ctx, &test->public ) == 0, + file, line ); + max_len = pubkey_max_len ( pubkey, private_ctx ); + + /* Test decrypting with private key to obtain known plaintext */ + { + uint8_t decrypted[max_len]; + int decrypted_len; + + decrypted_len = pubkey_decrypt ( pubkey, private_ctx, + test->ciphertext, + test->ciphertext_len, + decrypted ); + okx ( decrypted_len == ( ( int ) test->plaintext_len ), + file, line ); + okx ( memcmp ( decrypted, test->plaintext, + test->plaintext_len ) == 0, file, line ); + } + + /* Test encrypting with private key and decrypting with public key */ + { + uint8_t encrypted[max_len]; + uint8_t decrypted[max_len]; + int encrypted_len; + int decrypted_len; + + encrypted_len = pubkey_encrypt ( pubkey, private_ctx, + test->plaintext, + test->plaintext_len, + encrypted ); + okx ( encrypted_len >= 0, file, line ); + decrypted_len = pubkey_decrypt ( pubkey, public_ctx, + encrypted, encrypted_len, + decrypted ); + okx ( decrypted_len == ( ( int ) test->plaintext_len ), + file, line ); + okx ( memcmp ( decrypted, test->plaintext, + test->plaintext_len ) == 0, file, line ); + } + + /* Test encrypting with public key and decrypting with private key */ + { + uint8_t encrypted[max_len]; + uint8_t decrypted[max_len]; + int encrypted_len; + int decrypted_len; + + encrypted_len = pubkey_encrypt ( pubkey, public_ctx, + test->plaintext, + test->plaintext_len, + encrypted ); + okx ( encrypted_len >= 0, file, line ); + decrypted_len = pubkey_decrypt ( pubkey, private_ctx, + encrypted, encrypted_len, + decrypted ); + okx ( decrypted_len == ( ( int ) test->plaintext_len ), + file, line ); + okx ( memcmp ( decrypted, test->plaintext, + test->plaintext_len ) == 0, file, line ); + } + + /* Free contexts */ + pubkey_final ( pubkey, public_ctx ); + pubkey_final ( pubkey, private_ctx ); +} + +/** + * Report public key signature test result + * + * @v test Public key signature test + * @v file Test code file + * @v line Test code line + */ +void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file, + unsigned int line ) { + struct pubkey_algorithm *pubkey = test->pubkey; + struct digest_algorithm *digest = test->digest; + uint8_t private_ctx[pubkey->ctxsize]; + uint8_t public_ctx[pubkey->ctxsize]; + uint8_t digestctx[digest->ctxsize ]; + uint8_t digestout[digest->digestsize]; + size_t max_len; + + /* Initialize contexts */ + okx ( pubkey_init ( pubkey, private_ctx, &test->private ) == 0, + file, line ); + okx ( pubkey_init ( pubkey, public_ctx, &test->public ) == 0, + file, line ); + max_len = pubkey_max_len ( pubkey, private_ctx ); + + /* Construct digest over plaintext */ + digest_init ( digest, digestctx ); + digest_update ( digest, digestctx, test->plaintext, + test->plaintext_len ); + digest_final ( digest, digestctx, digestout ); + + /* Test signing using private key */ + { + uint8_t signature[max_len]; + int signature_len; + + signature_len = pubkey_sign ( pubkey, private_ctx, digest, + digestout, signature ); + okx ( signature_len == ( ( int ) test->signature_len ), + file, line ); + okx ( memcmp ( signature, test->signature, + test->signature_len ) == 0, file, line ); + } + + /* Test verification using public key */ + okx ( pubkey_verify ( pubkey, public_ctx, digest, digestout, + test->signature, test->signature_len ) == 0, + file, line ); + + /* Test verification failure of modified signature */ + { + uint8_t bad[test->signature_len]; + + memcpy ( bad, test->signature, test->signature_len ); + bad[ test->signature_len / 2 ] ^= 0x40; + okx ( pubkey_verify ( pubkey, public_ctx, digest, digestout, + bad, sizeof ( bad ) ) != 0, file, line ); + } + + /* Free contexts */ + pubkey_final ( pubkey, public_ctx ); + pubkey_final ( pubkey, private_ctx ); +} diff --git a/src/tests/pubkey_test.h b/src/tests/pubkey_test.h index 214992238..20bb94355 100644 --- a/src/tests/pubkey_test.h +++ b/src/tests/pubkey_test.h @@ -7,160 +7,151 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -/** - * Report public key decryption test result - * - * @v pubkey Public key algorithm - * @v key Key - * @v ciphertext Ciphertext - * @v ciphertext_len Ciphertext length - * @v expected Expected plaintext - * @v expected_len Expected plaintext length - */ -#define pubkey_decrypt_ok( pubkey, key, ciphertext, ciphertext_len, \ - expected, expected_len ) do { \ - uint8_t ctx[ (pubkey)->ctxsize ]; \ - \ - ok ( pubkey_init ( (pubkey), ctx, (key) ) == 0 ); \ - { \ - size_t max_len = pubkey_max_len ( (pubkey), ctx ); \ - uint8_t decrypted[ max_len ]; \ - int decrypted_len; \ - \ - decrypted_len = pubkey_decrypt ( (pubkey), ctx, \ - (ciphertext), \ - (ciphertext_len), \ - decrypted ); \ - ok ( decrypted_len == ( ( int ) (expected_len) ) ); \ - ok ( memcmp ( decrypted, (expected), \ - (expected_len) ) == 0 ); \ - } \ - pubkey_final ( (pubkey), ctx ); \ - } while ( 0 ) +/** A public-key encryption and decryption test */ +struct pubkey_test { + /** Public-key algorithm */ + struct pubkey_algorithm *pubkey; + /** Private key */ + const struct asn1_cursor private; + /** Public key */ + const struct asn1_cursor public; + /** Plaintext */ + const void *plaintext; + /** Length of plaintext */ + size_t plaintext_len; + /** Ciphertext + * + * Note that the encryption process may include some random + * padding, so a given plaintext will encrypt to multiple + * different ciphertexts. + */ + const void *ciphertext; + /** Length of ciphertext */ + size_t ciphertext_len; +}; + +/** A public-key signature test */ +struct pubkey_sign_test { + /** Public-key algorithm */ + struct pubkey_algorithm *pubkey; + /** Private key */ + const struct asn1_cursor private; + /** Public key */ + const struct asn1_cursor public; + /** Plaintext */ + const void *plaintext; + /** Plaintext length */ + size_t plaintext_len; + /** Signature algorithm */ + struct digest_algorithm *digest; + /** Signature */ + const void *signature; + /** Signature length */ + size_t signature_len; +}; + +/** Define inline private key data */ +#define PRIVATE(...) { __VA_ARGS__ } + +/** Define inline public key data */ +#define PUBLIC(...) { __VA_ARGS__ } + +/** Define inline plaintext data */ +#define PLAINTEXT(...) { __VA_ARGS__ } + +/** Define inline ciphertext data */ +#define CIPHERTEXT(...) { __VA_ARGS__ } + +/** Define inline signature data */ +#define SIGNATURE(...) { __VA_ARGS__ } /** - * Report public key encryption and decryption test result + * Define a public-key encryption and decryption test * - * @v pubkey Public key algorithm - * @v encrypt_key Encryption key - * @v decrypt_key Decryption key - * @v plaintext Plaintext - * @v plaintext_len Plaintext length + * @v name Test name + * @v PUBKEY Public-key algorithm + * @v PRIVATE Private key + * @v PUBLIC Public key + * @v PLAINTEXT Plaintext + * @v CIPHERTEXT Ciphertext + * @ret test Encryption and decryption test */ -#define pubkey_encrypt_ok( pubkey, encrypt_key, decrypt_key, plaintext, \ - plaintext_len ) do { \ - uint8_t ctx[ (pubkey)->ctxsize ]; \ - \ - ok ( pubkey_init ( (pubkey), ctx, (encrypt_key) ) == 0 ); \ - { \ - size_t max_len = pubkey_max_len ( (pubkey), ctx ); \ - uint8_t encrypted[ max_len ]; \ - int encrypted_len; \ - \ - encrypted_len = pubkey_encrypt ( (pubkey), ctx, \ - (plaintext), \ - (plaintext_len), \ - encrypted ); \ - ok ( encrypted_len >= 0 ); \ - pubkey_decrypt_ok ( (pubkey), (decrypt_key), \ - encrypted, encrypted_len, \ - (plaintext), (plaintext_len) ); \ - } \ - pubkey_final ( (pubkey), ctx ); \ - } while ( 0 ) +#define PUBKEY_TEST( name, PUBKEY, PRIVATE, PUBLIC, PLAINTEXT, \ + CIPHERTEXT ) \ + static const uint8_t name ## _private[] = PRIVATE; \ + static const uint8_t name ## _public[] = PUBLIC; \ + static const uint8_t name ## _plaintext[] = PLAINTEXT; \ + static const uint8_t name ## _ciphertext[] = CIPHERTEXT; \ + static struct pubkey_test name = { \ + .pubkey = PUBKEY, \ + .private = { \ + .data = name ## _private, \ + .len = sizeof ( name ## _private ), \ + }, \ + .public = { \ + .data = name ## _public, \ + .len = sizeof ( name ## _public ), \ + }, \ + .plaintext = name ## _plaintext, \ + .plaintext_len = sizeof ( name ## _plaintext ), \ + .ciphertext = name ## _ciphertext, \ + .ciphertext_len = sizeof ( name ## _ciphertext ), \ + } /** - * Report public key signature test result + * Define a public-key signature test * - * @v pubkey Public key algorithm - * @v key Key - * @v digest Digest algorithm - * @v plaintext Plaintext - * @v plaintext_len Plaintext length - * @v expected Expected signature - * @v expected_len Expected signature length + * @v name Test name + * @v PUBKEY Public-key algorithm + * @v PRIVATE Private key + * @v PUBLIC Public key + * @v PLAINTEXT Plaintext + * @v DIGEST Digest algorithm + * @v SIGNATURE Signature + * @ret test Signature test */ -#define pubkey_sign_ok( pubkey, key, digest, plaintext, plaintext_len, \ - expected, expected_len ) do { \ - uint8_t ctx[ (pubkey)->ctxsize ]; \ - uint8_t digestctx[ (digest)->ctxsize ]; \ - uint8_t digestout[ (digest)->digestsize ]; \ - \ - digest_init ( (digest), digestctx ); \ - digest_update ( (digest), digestctx, (plaintext), \ - (plaintext_len) ); \ - digest_final ( (digest), digestctx, digestout ); \ - \ - ok ( pubkey_init ( (pubkey), ctx, (key) ) == 0 ); \ - { \ - size_t max_len = pubkey_max_len ( (pubkey), ctx ); \ - uint8_t signature[ max_len ]; \ - int signature_len; \ - \ - signature_len = pubkey_sign ( (pubkey), ctx, (digest), \ - digestout, signature ); \ - ok ( signature_len == ( ( int ) (expected_len) ) ); \ - ok ( memcmp ( signature, (expected), \ - (expected_len) ) == 0 ); \ - } \ - pubkey_final ( (pubkey), ctx ); \ - } while ( 0 ) +#define PUBKEY_SIGN_TEST( name, PUBKEY, PRIVATE, PUBLIC, PLAINTEXT, \ + DIGEST, SIGNATURE ) \ + static const uint8_t name ## _private[] = PRIVATE; \ + static const uint8_t name ## _public[] = PUBLIC; \ + static const uint8_t name ## _plaintext[] = PLAINTEXT; \ + static const uint8_t name ## _signature[] = SIGNATURE; \ + static struct pubkey_sign_test name = { \ + .pubkey = PUBKEY, \ + .private = { \ + .data = name ## _private, \ + .len = sizeof ( name ## _private ), \ + }, \ + .public = { \ + .data = name ## _public, \ + .len = sizeof ( name ## _public ), \ + }, \ + .plaintext = name ## _plaintext, \ + .plaintext_len = sizeof ( name ## _plaintext ), \ + .digest = DIGEST, \ + .signature = name ## _signature, \ + .signature_len = sizeof ( name ## _signature ), \ + } + +extern void pubkey_okx ( struct pubkey_test *test, + const char *file, unsigned int line ); +extern void pubkey_sign_okx ( struct pubkey_sign_test *test, + const char *file, unsigned int line ); /** - * Report public key verification test result + * Report a public key encryption and decryption test result * - * @v pubkey Public key algorithm - * @v key Key - * @v digest Digest algorithm - * @v plaintext Plaintext - * @v plaintext_len Plaintext length - * @v signature Signature - * @v signature_len Signature length + * @v test Public key encryption and decryption test */ -#define pubkey_verify_ok( pubkey, key, digest, plaintext, \ - plaintext_len, signature, signature_len ) do {\ - uint8_t ctx[ (pubkey)->ctxsize ]; \ - uint8_t digestctx[ (digest)->ctxsize ]; \ - uint8_t digestout[ (digest)->digestsize ]; \ - \ - digest_init ( (digest), digestctx ); \ - digest_update ( (digest), digestctx, (plaintext), \ - (plaintext_len) ); \ - digest_final ( (digest), digestctx, digestout ); \ - \ - ok ( pubkey_init ( (pubkey), ctx, (key) ) == 0 ); \ - ok ( pubkey_verify ( (pubkey), ctx, (digest), digestout, \ - (signature), (signature_len) ) == 0 ); \ - pubkey_final ( (pubkey), ctx ); \ - } while ( 0 ) +#define pubkey_ok( test ) \ + pubkey_okx ( test, __FILE__, __LINE__ ) /** - * Report public key verification test result + * Report a public key signature test result * - * @v pubkey Public key algorithm - * @v key Key - * @v digest Digest algorithm - * @v plaintext Plaintext - * @v plaintext_len Plaintext length - * @v signature Signature - * @v signature_len Signature length + * @v test Public key signature test */ -#define pubkey_verify_fail_ok( pubkey, key, digest, plaintext, \ - plaintext_len, signature, \ - signature_len ) do { \ - uint8_t ctx[ (pubkey)->ctxsize ]; \ - uint8_t digestctx[ (digest)->ctxsize ]; \ - uint8_t digestout[ (digest)->digestsize ]; \ - \ - digest_init ( (digest), digestctx ); \ - digest_update ( (digest), digestctx, (plaintext), \ - (plaintext_len) ); \ - digest_final ( (digest), digestctx, digestout ); \ - \ - ok ( pubkey_init ( (pubkey), ctx, (key) ) == 0 ); \ - ok ( pubkey_verify ( (pubkey), ctx, (digest), digestout, \ - (signature), (signature_len) ) != 0 ); \ - pubkey_final ( (pubkey), ctx ); \ - } while ( 0 ) +#define pubkey_sign_ok( test ) \ + pubkey_sign_okx ( test, __FILE__, __LINE__ ) #endif /* _PUBKEY_TEST_H */ diff --git a/src/tests/rsa_test.c b/src/tests/rsa_test.c index b1d522bc0..13160934a 100644 --- a/src/tests/rsa_test.c +++ b/src/tests/rsa_test.c @@ -43,165 +43,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include "pubkey_test.h" -/** Define inline private key data */ -#define PRIVATE(...) { __VA_ARGS__ } - -/** Define inline public key data */ -#define PUBLIC(...) { __VA_ARGS__ } - -/** Define inline plaintext data */ -#define PLAINTEXT(...) { __VA_ARGS__ } - -/** Define inline ciphertext data */ -#define CIPHERTEXT(...) { __VA_ARGS__ } - -/** Define inline signature data */ -#define SIGNATURE(...) { __VA_ARGS__ } - -/** An RSA encryption and decryption self-test */ -struct rsa_encrypt_decrypt_test { - /** Private key */ - const struct asn1_cursor private; - /** Public key */ - const struct asn1_cursor public; - /** Plaintext */ - const void *plaintext; - /** Plaintext length */ - size_t plaintext_len; - /** Ciphertext - * - * Note that the encryption process includes some random - * padding, so a given plaintext will encrypt to multiple - * different ciphertexts. - */ - const void *ciphertext; - /** Ciphertext length */ - size_t ciphertext_len; -}; - -/** - * Define an RSA encryption and decryption test - * - * @v name Test name - * @v PRIVATE Private key - * @v PUBLIC Public key - * @v PLAINTEXT Plaintext - * @v CIPHERTEXT Ciphertext - * @ret test Encryption and decryption test - */ -#define RSA_ENCRYPT_DECRYPT_TEST( name, PRIVATE, PUBLIC, PLAINTEXT, \ - CIPHERTEXT ) \ - static const uint8_t name ## _private[] = PRIVATE; \ - static const uint8_t name ## _public[] = PUBLIC; \ - static const uint8_t name ## _plaintext[] = PLAINTEXT; \ - static const uint8_t name ## _ciphertext[] = CIPHERTEXT; \ - static struct rsa_encrypt_decrypt_test name = { \ - .private = { \ - .data = name ## _private, \ - .len = sizeof ( name ## _private ), \ - }, \ - .public = { \ - .data = name ## _public, \ - .len = sizeof ( name ## _public ), \ - }, \ - .plaintext = name ## _plaintext, \ - .plaintext_len = sizeof ( name ## _plaintext ), \ - .ciphertext = name ## _ciphertext, \ - .ciphertext_len = sizeof ( name ## _ciphertext ), \ - } - -/** An RSA signature self-test */ -struct rsa_signature_test { - /** Private key */ - const struct asn1_cursor private; - /** Public key */ - const struct asn1_cursor public; - /** Plaintext */ - const void *plaintext; - /** Plaintext length */ - size_t plaintext_len; - /** Signature algorithm */ - struct asn1_algorithm *algorithm; - /** Signature */ - const void *signature; - /** Signature length */ - size_t signature_len; -}; - -/** - * Define an RSA signature test - * - * @v name Test name - * @v PRIVATE Private key - * @v PUBLIC Public key - * @v PLAINTEXT Plaintext - * @v ALGORITHM Signature algorithm - * @v SIGNATURE Signature - * @ret test Signature test - */ -#define RSA_SIGNATURE_TEST( name, PRIVATE, PUBLIC, PLAINTEXT, \ - ALGORITHM, SIGNATURE ) \ - static const uint8_t name ## _private[] = PRIVATE; \ - static const uint8_t name ## _public[] = PUBLIC; \ - static const uint8_t name ## _plaintext[] = PLAINTEXT; \ - static const uint8_t name ## _signature[] = SIGNATURE; \ - static struct rsa_signature_test name = { \ - .private = { \ - .data = name ## _private, \ - .len = sizeof ( name ## _private ), \ - }, \ - .public = { \ - .data = name ## _public, \ - .len = sizeof ( name ## _public ), \ - }, \ - .plaintext = name ## _plaintext, \ - .plaintext_len = sizeof ( name ## _plaintext ), \ - .algorithm = ALGORITHM, \ - .signature = name ## _signature, \ - .signature_len = sizeof ( name ## _signature ), \ - } - -/** - * Report RSA encryption and decryption test result - * - * @v test RSA encryption and decryption test - */ -#define rsa_encrypt_decrypt_ok( test ) do { \ - pubkey_decrypt_ok ( &rsa_algorithm, &(test)->private, \ - (test)->ciphertext, (test)->ciphertext_len, \ - (test)->plaintext, (test)->plaintext_len );\ - pubkey_encrypt_ok ( &rsa_algorithm, &(test)->private, \ - &(test)->public, (test)->plaintext, \ - (test)->plaintext_len ); \ - pubkey_encrypt_ok ( &rsa_algorithm, &(test)->public, \ - &(test)->private, (test)->plaintext, \ - (test)->plaintext_len ); \ - } while ( 0 ) - - -/** - * Report RSA signature test result - * - * @v test RSA signature test - */ -#define rsa_signature_ok( test ) do { \ - struct digest_algorithm *digest = (test)->algorithm->digest; \ - uint8_t bad_signature[ (test)->signature_len ]; \ - pubkey_sign_ok ( &rsa_algorithm, &(test)->private, digest, \ - (test)->plaintext, (test)->plaintext_len, \ - (test)->signature, (test)->signature_len ); \ - pubkey_verify_ok ( &rsa_algorithm, &(test)->public, digest, \ - (test)->plaintext, (test)->plaintext_len, \ - (test)->signature, (test)->signature_len ); \ - memset ( bad_signature, 0, sizeof ( bad_signature ) ); \ - pubkey_verify_fail_ok ( &rsa_algorithm, &(test)->public, \ - digest, (test)->plaintext, \ - (test)->plaintext_len, bad_signature, \ - sizeof ( bad_signature ) ); \ - } while ( 0 ) - /** "Hello world" encryption and decryption test (traditional PKCS#1 key) */ -RSA_ENCRYPT_DECRYPT_TEST ( hw_test, +PUBKEY_TEST ( hw_test, &rsa_algorithm, PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xd2, 0xf1, 0x04, 0x67, 0xf6, 0x2c, 0x96, 0x07, 0xa6, 0xbd, 0x85, 0xac, 0xc1, 0x17, 0x5d, 0xe8, 0xf0, 0x93, 0x94, 0x0c, @@ -255,7 +98,7 @@ RSA_ENCRYPT_DECRYPT_TEST ( hw_test, 0x38, 0x43, 0xf9, 0x41 ) ); /** "Hello world" encryption and decryption test (PKCS#8 key) */ -RSA_ENCRYPT_DECRYPT_TEST ( hw_test_pkcs8, +PUBKEY_TEST ( hw_test_pkcs8, &rsa_algorithm, PRIVATE ( 0x30, 0x82, 0x01, 0x55, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82, 0x01, 0x3f, 0x30, 0x82, 0x01, 0x3b, @@ -312,7 +155,7 @@ RSA_ENCRYPT_DECRYPT_TEST ( hw_test_pkcs8, 0x38, 0x43, 0xf9, 0x41 ) ); /** Random message MD5 signature test */ -RSA_SIGNATURE_TEST ( md5_test, +PUBKEY_SIGN_TEST ( md5_test, &rsa_algorithm, PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xf9, 0x3f, 0x78, 0x44, 0xe2, 0x0e, 0x25, 0xf1, 0x0e, 0x94, 0xcd, 0xca, 0x6f, 0x9e, 0xea, 0x6d, 0xdf, 0xcd, 0xa0, 0x7c, @@ -375,7 +218,7 @@ RSA_SIGNATURE_TEST ( md5_test, 0xf2, 0x8d, 0xfc, 0xfc, 0x37, 0xf7, 0xc7, 0x6d, 0x6c, 0xd8, 0x24, 0x0c, 0x6a, 0xec, 0x82, 0x5c, 0x72, 0xf1, 0xfc, 0x05, 0xed, 0x8e, 0xe8, 0xd9, 0x8b, 0x8b, 0x67, 0x02, 0x95 ), - &md5_with_rsa_encryption_algorithm, + &md5_algorithm, SIGNATURE ( 0xdb, 0x56, 0x3d, 0xea, 0xae, 0x81, 0x4b, 0x3b, 0x2e, 0x8e, 0xb8, 0xee, 0x13, 0x61, 0xc6, 0xe7, 0xd7, 0x50, 0xcd, 0x0d, 0x34, 0x3a, 0xfe, 0x9a, 0x8d, 0xf8, 0xfb, 0xd6, 0x7e, 0xbd, @@ -385,7 +228,7 @@ RSA_SIGNATURE_TEST ( md5_test, 0xac, 0x45, 0x00, 0xa8 ) ); /** Random message SHA-1 signature test */ -RSA_SIGNATURE_TEST ( sha1_test, +PUBKEY_SIGN_TEST ( sha1_test, &rsa_algorithm, PRIVATE ( 0x30, 0x82, 0x01, 0x3b, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xe0, 0x3a, 0x8d, 0x35, 0xe1, 0x92, 0x2f, 0xea, 0x0d, 0x82, 0x60, 0x2e, 0xb6, 0x0b, 0x02, 0xd3, 0xf4, 0x39, 0xfb, 0x06, @@ -448,7 +291,7 @@ RSA_SIGNATURE_TEST ( sha1_test, 0x30, 0x91, 0x1c, 0xaa, 0x6c, 0x24, 0x42, 0x1b, 0x1a, 0xba, 0x30, 0x40, 0x49, 0x83, 0xd9, 0xd7, 0x66, 0x7e, 0x5c, 0x1a, 0x4b, 0x7f, 0xa6, 0x8e, 0x8a, 0xd6, 0x0c, 0x65, 0x75 ), - &sha1_with_rsa_encryption_algorithm, + &sha1_algorithm, SIGNATURE ( 0xa5, 0x5a, 0x8a, 0x67, 0x81, 0x76, 0x7e, 0xad, 0x99, 0x22, 0xf1, 0x47, 0x64, 0xd2, 0xfb, 0x81, 0x45, 0xeb, 0x85, 0x56, 0xf8, 0x7d, 0xb8, 0xec, 0x41, 0x17, 0x84, 0xf7, 0x2b, 0xbb, @@ -458,7 +301,7 @@ RSA_SIGNATURE_TEST ( sha1_test, 0x0e, 0x3d, 0x80, 0x80 ) ); /** Random message SHA-256 signature test */ -RSA_SIGNATURE_TEST ( sha256_test, +PUBKEY_SIGN_TEST ( sha256_test, &rsa_algorithm, PRIVATE ( 0x30, 0x82, 0x01, 0x3a, 0x02, 0x01, 0x00, 0x02, 0x41, 0x00, 0xa5, 0xe9, 0xdb, 0xa9, 0x1a, 0x6e, 0xd6, 0x4c, 0x25, 0x50, 0xfe, 0x61, 0x77, 0x08, 0x7a, 0x80, 0x36, 0xcb, 0x88, 0x49, @@ -521,7 +364,7 @@ RSA_SIGNATURE_TEST ( sha256_test, 0x91, 0x71, 0xd6, 0x2d, 0xa1, 0xae, 0x81, 0x0c, 0xed, 0x54, 0x48, 0x79, 0x8a, 0x78, 0x05, 0x74, 0x4d, 0x4f, 0xf0, 0xe0, 0x3c, 0x41, 0x5c, 0x04, 0x0b, 0x68, 0x57, 0xc5, 0xd6 ), - &sha256_with_rsa_encryption_algorithm, + &sha256_algorithm, SIGNATURE ( 0x02, 0x2e, 0xc5, 0x2a, 0x2b, 0x7f, 0xb4, 0x80, 0xca, 0x9d, 0x96, 0x5b, 0xaf, 0x1f, 0x72, 0x5b, 0x6e, 0xf1, 0x69, 0x7f, 0x4d, 0x41, 0xd5, 0x9f, 0x00, 0xdc, 0x47, 0xf4, 0x68, 0x8f, @@ -536,11 +379,11 @@ RSA_SIGNATURE_TEST ( sha256_test, */ static void rsa_test_exec ( void ) { - rsa_encrypt_decrypt_ok ( &hw_test ); - rsa_encrypt_decrypt_ok ( &hw_test_pkcs8 ); - rsa_signature_ok ( &md5_test ); - rsa_signature_ok ( &sha1_test ); - rsa_signature_ok ( &sha256_test ); + pubkey_ok ( &hw_test ); + pubkey_ok ( &hw_test_pkcs8 ); + pubkey_sign_ok ( &md5_test ); + pubkey_sign_ok ( &sha1_test ); + pubkey_sign_ok ( &sha256_test ); } /** RSA self-test */ @@ -548,3 +391,9 @@ struct self_test rsa_test __self_test = { .name = "rsa", .exec = rsa_test_exec, }; + +/* Drag in required ASN.1 OID-identified algorithms */ +REQUIRING_SYMBOL ( rsa_test ); +REQUIRE_OBJECT ( rsa_md5 ); +REQUIRE_OBJECT ( rsa_sha1 ); +REQUIRE_OBJECT ( rsa_sha256 ); -- cgit v1.2.3-55-g7522 From 46937a9df622d1e9fb5b1e926a04176b8855fdce Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 21 Aug 2024 16:25:10 +0100 Subject: [crypto] Remove the concept of a public-key algorithm reusable context Instances of cipher and digest algorithms tend to get called repeatedly to process substantial amounts of data. This is not true for public-key algorithms, which tend to get called only once or twice for a given key. Simplify the public-key algorithm API so that there is no reusable algorithm context. In particular, this allows callers to omit the error handling currently required to handle memory allocation (or key parsing) errors from pubkey_init(), and to omit the cleanup calls to pubkey_final(). This change does remove the ability for a caller to distinguish between a verification failure due to a memory allocation failure and a verification failure due to a bad signature. This difference is not material in practice: in both cases, for whatever reason, the caller was unable to verify the signature and so cannot proceed further, and the cause of the error will be visible to the user via the return status code. Signed-off-by: Michael Brown --- src/crypto/cms.c | 19 +-- src/crypto/crypto_null.c | 24 ++-- src/crypto/ocsp.c | 21 +--- src/crypto/rsa.c | 295 +++++++++++++++++++++++++++++----------------- src/crypto/x509.c | 13 +- src/drivers/net/iphone.c | 18 +-- src/include/ipxe/crypto.h | 96 ++++++--------- src/include/ipxe/rsa.h | 25 ---- src/include/ipxe/tls.h | 4 +- src/net/tls.c | 45 ++----- src/tests/pubkey_test.c | 142 +++++++--------------- 11 files changed, 304 insertions(+), 398 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/cms.c b/src/crypto/cms.c index 0b772f1cf..2e153d819 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -612,33 +612,22 @@ static int cms_verify_digest ( struct cms_message *cms, userptr_t data, size_t len ) { struct digest_algorithm *digest = part->digest; struct pubkey_algorithm *pubkey = part->pubkey; - struct x509_public_key *public_key = &cert->subject.public_key; + struct asn1_cursor *key = &cert->subject.public_key.raw; uint8_t digest_out[ digest->digestsize ]; - uint8_t ctx[ pubkey->ctxsize ]; int rc; /* Generate digest */ cms_digest ( cms, part, data, len, digest_out ); - /* Initialise public-key algorithm */ - if ( ( rc = pubkey_init ( pubkey, ctx, &public_key->raw ) ) != 0 ) { - 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, + if ( ( rc = pubkey_verify ( pubkey, key, digest, digest_out, part->value, part->len ) ) != 0 ) { DBGC ( cms, "CMS %p/%p signature verification failed: %s\n", cms, part, strerror ( rc ) ); - goto err_verify; + return rc; } - err_verify: - pubkey_final ( pubkey, ctx ); - err_init: - return rc; + return 0; } /** diff --git a/src/crypto/crypto_null.c b/src/crypto/crypto_null.c index b4169382b..d5863f958 100644 --- a/src/crypto/crypto_null.c +++ b/src/crypto/crypto_null.c @@ -93,34 +93,31 @@ struct cipher_algorithm cipher_null = { .auth = cipher_null_auth, }; -int pubkey_null_init ( void *ctx __unused, - const struct asn1_cursor *key __unused ) { +size_t pubkey_null_max_len ( const struct asn1_cursor *key __unused ) { return 0; } -size_t pubkey_null_max_len ( void *ctx __unused ) { - return 0; -} - -int pubkey_null_encrypt ( void *ctx __unused, const void *plaintext __unused, +int pubkey_null_encrypt ( const struct asn1_cursor *key __unused, + const void *plaintext __unused, size_t plaintext_len __unused, void *ciphertext __unused ) { return 0; } -int pubkey_null_decrypt ( void *ctx __unused, const void *ciphertext __unused, +int pubkey_null_decrypt ( const struct asn1_cursor *key __unused, + const void *ciphertext __unused, size_t ciphertext_len __unused, void *plaintext __unused ) { return 0; } -int pubkey_null_sign ( void *ctx __unused, +int pubkey_null_sign ( const struct asn1_cursor *key __unused, struct digest_algorithm *digest __unused, const void *value __unused, void *signature __unused ) { return 0; } -int pubkey_null_verify ( void *ctx __unused, +int pubkey_null_verify ( const struct asn1_cursor *key __unused, struct digest_algorithm *digest __unused, const void *value __unused, const void *signature __unused , @@ -128,18 +125,11 @@ int pubkey_null_verify ( void *ctx __unused, return 0; } -void pubkey_null_final ( void *ctx __unused ) { - /* Do nothing */ -} - struct pubkey_algorithm pubkey_null = { .name = "null", - .ctxsize = 0, - .init = pubkey_null_init, .max_len = pubkey_null_max_len, .encrypt = pubkey_null_encrypt, .decrypt = pubkey_null_decrypt, .sign = pubkey_null_sign, .verify = pubkey_null_verify, - .final = pubkey_null_final, }; diff --git a/src/crypto/ocsp.c b/src/crypto/ocsp.c index f35593454..e65f7180a 100644 --- a/src/crypto/ocsp.c +++ b/src/crypto/ocsp.c @@ -844,10 +844,9 @@ static int ocsp_check_signature ( struct ocsp_check *ocsp, struct ocsp_response *response = &ocsp->response; struct digest_algorithm *digest = response->algorithm->digest; struct pubkey_algorithm *pubkey = response->algorithm->pubkey; - struct x509_public_key *public_key = &signer->subject.public_key; + struct asn1_cursor *key = &signer->subject.public_key.raw; uint8_t digest_ctx[ digest->ctxsize ]; uint8_t digest_out[ digest->digestsize ]; - uint8_t pubkey_ctx[ pubkey->ctxsize ]; int rc; /* Generate digest */ @@ -856,30 +855,18 @@ static int ocsp_check_signature ( struct ocsp_check *ocsp, response->tbs.len ); digest_final ( digest, digest_ctx, digest_out ); - /* Initialise public-key algorithm */ - if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, - &public_key->raw ) ) != 0 ) { - DBGC ( ocsp, "OCSP %p \"%s\" could not initialise public key: " - "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); - goto err_init; - } - /* Verify digest */ - if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out, + if ( ( rc = pubkey_verify ( pubkey, key, digest, digest_out, response->signature.data, response->signature.len ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" signature verification failed: " "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); - goto err_verify; + return rc; } DBGC2 ( ocsp, "OCSP %p \"%s\" signature is correct\n", ocsp, x509_name ( ocsp->cert ) ); - - err_verify: - pubkey_final ( pubkey, pubkey_ctx ); - err_init: - return rc; + return 0; } /** diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index 2d288a953..19472c121 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -47,6 +47,28 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define EINFO_EACCES_VERIFY \ __einfo_uniqify ( EINFO_EACCES, 0x01, "RSA signature incorrect" ) +/** An RSA context */ +struct rsa_context { + /** Allocated memory */ + void *dynamic; + /** Modulus */ + bigint_element_t *modulus0; + /** Modulus size */ + unsigned int size; + /** Modulus length */ + size_t max_len; + /** Exponent */ + bigint_element_t *exponent0; + /** Exponent size */ + unsigned int exponent_size; + /** Input buffer */ + bigint_element_t *input0; + /** Output buffer */ + bigint_element_t *output0; + /** Temporary working space for modular exponentiation */ + void *tmp; +}; + /** * Identify RSA prefix * @@ -69,10 +91,9 @@ rsa_find_prefix ( struct digest_algorithm *digest ) { * * @v context RSA context */ -static void rsa_free ( struct rsa_context *context ) { +static inline void rsa_free ( struct rsa_context *context ) { free ( context->dynamic ); - context->dynamic = NULL; } /** @@ -98,9 +119,6 @@ static int rsa_alloc ( struct rsa_context *context, size_t modulus_len, uint8_t tmp[tmp_len]; } __attribute__ (( packed )) *dynamic; - /* Free any existing dynamic storage */ - rsa_free ( context ); - /* Allocate dynamic storage */ dynamic = malloc ( sizeof ( *dynamic ) ); if ( ! dynamic ) @@ -231,12 +249,12 @@ static int rsa_parse_mod_exp ( struct asn1_cursor *modulus, /** * Initialise RSA cipher * - * @v ctx RSA context + * @v context RSA context * @v key Key * @ret rc Return status code */ -static int rsa_init ( void *ctx, const struct asn1_cursor *key ) { - struct rsa_context *context = ctx; +static int rsa_init ( struct rsa_context *context, + const struct asn1_cursor *key ) { struct asn1_cursor modulus; struct asn1_cursor exponent; int rc; @@ -277,13 +295,22 @@ static int rsa_init ( void *ctx, const struct asn1_cursor *key ) { /** * Calculate RSA maximum output length * - * @v ctx RSA context + * @v key Key * @ret max_len Maximum output length */ -static size_t rsa_max_len ( void *ctx ) { - struct rsa_context *context = ctx; +static size_t rsa_max_len ( const struct asn1_cursor *key ) { + struct asn1_cursor modulus; + struct asn1_cursor exponent; + int rc; - return context->max_len; + /* Parse moduli and exponents */ + if ( ( rc = rsa_parse_mod_exp ( &modulus, &exponent, key ) ) != 0 ) { + /* Return a zero maximum length on error */ + return 0; + } + + /* Output length can never exceed modulus length */ + return modulus.len; } /** @@ -314,111 +341,147 @@ static void rsa_cipher ( struct rsa_context *context, /** * Encrypt using RSA * - * @v ctx RSA context + * @v key Key * @v plaintext Plaintext * @v plaintext_len Length of plaintext * @v ciphertext Ciphertext * @ret ciphertext_len Length of ciphertext, or negative error */ -static int rsa_encrypt ( void *ctx, const void *plaintext, +static int rsa_encrypt ( const struct asn1_cursor *key, const void *plaintext, size_t plaintext_len, void *ciphertext ) { - struct rsa_context *context = ctx; + struct rsa_context context; void *temp; uint8_t *encoded; - size_t max_len = ( context->max_len - 11 ); - size_t random_nz_len = ( max_len - plaintext_len + 8 ); + size_t max_len; + size_t random_nz_len; int rc; + DBGC ( &context, "RSA %p encrypting:\n", &context ); + DBGC_HDA ( &context, 0, plaintext, plaintext_len ); + + /* Initialise context */ + if ( ( rc = rsa_init ( &context, key ) ) != 0 ) + goto err_init; + + /* Calculate lengths */ + max_len = ( context.max_len - 11 ); + random_nz_len = ( max_len - plaintext_len + 8 ); + /* Sanity check */ if ( plaintext_len > max_len ) { - DBGC ( context, "RSA %p plaintext too long (%zd bytes, max " - "%zd)\n", context, plaintext_len, max_len ); - return -ERANGE; + DBGC ( &context, "RSA %p plaintext too long (%zd bytes, max " + "%zd)\n", &context, plaintext_len, max_len ); + rc = -ERANGE; + goto err_sanity; } - DBGC ( context, "RSA %p encrypting:\n", context ); - DBGC_HDA ( context, 0, plaintext, plaintext_len ); /* Construct encoded message (using the big integer output * buffer as temporary storage) */ - temp = context->output0; + temp = context.output0; encoded = temp; encoded[0] = 0x00; encoded[1] = 0x02; if ( ( rc = get_random_nz ( &encoded[2], random_nz_len ) ) != 0 ) { - DBGC ( context, "RSA %p could not generate random data: %s\n", - context, strerror ( rc ) ); - return rc; + DBGC ( &context, "RSA %p could not generate random data: %s\n", + &context, strerror ( rc ) ); + goto err_random; } encoded[ 2 + random_nz_len ] = 0x00; - memcpy ( &encoded[ context->max_len - plaintext_len ], + memcpy ( &encoded[ context.max_len - plaintext_len ], plaintext, plaintext_len ); /* Encipher the encoded message */ - rsa_cipher ( context, encoded, ciphertext ); - DBGC ( context, "RSA %p encrypted:\n", context ); - DBGC_HDA ( context, 0, ciphertext, context->max_len ); + rsa_cipher ( &context, encoded, ciphertext ); + DBGC ( &context, "RSA %p encrypted:\n", &context ); + DBGC_HDA ( &context, 0, ciphertext, context.max_len ); + + /* Free context */ + rsa_free ( &context ); - return context->max_len; + return context.max_len; + + err_random: + err_sanity: + rsa_free ( &context ); + err_init: + return rc; } /** * Decrypt using RSA * - * @v ctx RSA context + * @v key Key * @v ciphertext Ciphertext * @v ciphertext_len Ciphertext length * @v plaintext Plaintext * @ret plaintext_len Plaintext length, or negative error */ -static int rsa_decrypt ( void *ctx, const void *ciphertext, +static int rsa_decrypt ( const struct asn1_cursor *key, const void *ciphertext, size_t ciphertext_len, void *plaintext ) { - struct rsa_context *context = ctx; + struct rsa_context context; void *temp; uint8_t *encoded; uint8_t *end; uint8_t *zero; uint8_t *start; size_t plaintext_len; + int rc; + + DBGC ( &context, "RSA %p decrypting:\n", &context ); + DBGC_HDA ( &context, 0, ciphertext, ciphertext_len ); + + /* Initialise context */ + if ( ( rc = rsa_init ( &context, key ) ) != 0 ) + goto err_init; /* Sanity check */ - if ( ciphertext_len != context->max_len ) { - DBGC ( context, "RSA %p ciphertext incorrect length (%zd " + if ( ciphertext_len != context.max_len ) { + DBGC ( &context, "RSA %p ciphertext incorrect length (%zd " "bytes, should be %zd)\n", - context, ciphertext_len, context->max_len ); - return -ERANGE; + &context, ciphertext_len, context.max_len ); + rc = -ERANGE; + goto err_sanity; } - DBGC ( context, "RSA %p decrypting:\n", context ); - DBGC_HDA ( context, 0, ciphertext, ciphertext_len ); /* Decipher the message (using the big integer input buffer as * temporary storage) */ - temp = context->input0; + temp = context.input0; encoded = temp; - rsa_cipher ( context, ciphertext, encoded ); + rsa_cipher ( &context, ciphertext, encoded ); /* Parse the message */ - end = ( encoded + context->max_len ); - if ( ( encoded[0] != 0x00 ) || ( encoded[1] != 0x02 ) ) - goto invalid; + end = ( encoded + context.max_len ); + if ( ( encoded[0] != 0x00 ) || ( encoded[1] != 0x02 ) ) { + rc = -EINVAL; + goto err_invalid; + } zero = memchr ( &encoded[2], 0, ( end - &encoded[2] ) ); - if ( ! zero ) - goto invalid; + if ( ! zero ) { + rc = -EINVAL; + goto err_invalid; + } start = ( zero + 1 ); plaintext_len = ( end - start ); /* Copy out message */ memcpy ( plaintext, start, plaintext_len ); - DBGC ( context, "RSA %p decrypted:\n", context ); - DBGC_HDA ( context, 0, plaintext, plaintext_len ); + DBGC ( &context, "RSA %p decrypted:\n", &context ); + DBGC_HDA ( &context, 0, plaintext, plaintext_len ); + + /* Free context */ + rsa_free ( &context ); return plaintext_len; - invalid: - DBGC ( context, "RSA %p invalid decrypted message:\n", context ); - DBGC_HDA ( context, 0, encoded, context->max_len ); - return -EINVAL; + err_invalid: + DBGC ( &context, "RSA %p invalid decrypted message:\n", &context ); + DBGC_HDA ( &context, 0, encoded, context.max_len ); + err_sanity: + rsa_free ( &context ); + err_init: + return rc; } /** @@ -452,9 +515,9 @@ static int rsa_encode_digest ( struct rsa_context *context, /* Sanity check */ max_len = ( context->max_len - 11 ); if ( digestinfo_len > max_len ) { - DBGC ( context, "RSA %p %s digestInfo too long (%zd bytes, max" - "%zd)\n", - context, digest->name, digestinfo_len, max_len ); + DBGC ( context, "RSA %p %s digestInfo too long (%zd bytes, " + "max %zd)\n", context, digest->name, digestinfo_len, + max_len ); return -ERANGE; } DBGC ( context, "RSA %p encoding %s digest:\n", @@ -482,104 +545,125 @@ static int rsa_encode_digest ( struct rsa_context *context, /** * Sign digest value using RSA * - * @v ctx RSA context + * @v key Key * @v digest Digest algorithm * @v value Digest value * @v signature Signature * @ret signature_len Signature length, or negative error */ -static int rsa_sign ( void *ctx, struct digest_algorithm *digest, - const void *value, void *signature ) { - struct rsa_context *context = ctx; +static int rsa_sign ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, + void *signature ) { + struct rsa_context context; void *temp; int rc; - DBGC ( context, "RSA %p signing %s digest:\n", context, digest->name ); - DBGC_HDA ( context, 0, value, digest->digestsize ); + DBGC ( &context, "RSA %p signing %s digest:\n", + &context, digest->name ); + DBGC_HDA ( &context, 0, value, digest->digestsize ); + + /* Initialise context */ + if ( ( rc = rsa_init ( &context, key ) ) != 0 ) + goto err_init; /* Encode digest (using the big integer output buffer as * temporary storage) */ - temp = context->output0; - if ( ( rc = rsa_encode_digest ( context, digest, value, temp ) ) != 0 ) - return rc; + temp = context.output0; + if ( ( rc = rsa_encode_digest ( &context, digest, value, temp ) ) != 0 ) + goto err_encode; /* Encipher the encoded digest */ - rsa_cipher ( context, temp, signature ); - DBGC ( context, "RSA %p signed %s digest:\n", context, digest->name ); - DBGC_HDA ( context, 0, signature, context->max_len ); + rsa_cipher ( &context, temp, signature ); + DBGC ( &context, "RSA %p signed %s digest:\n", &context, digest->name ); + DBGC_HDA ( &context, 0, signature, context.max_len ); + + /* Free context */ + rsa_free ( &context ); - return context->max_len; + return context.max_len; + + err_encode: + rsa_free ( &context ); + err_init: + return rc; } /** * Verify signed digest value using RSA * - * @v ctx RSA context + * @v key Key * @v digest Digest algorithm * @v value Digest value * @v signature Signature * @v signature_len Signature length * @ret rc Return status code */ -static int rsa_verify ( void *ctx, struct digest_algorithm *digest, - const void *value, const void *signature, - size_t signature_len ) { - struct rsa_context *context = ctx; +static int rsa_verify ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, + const void *signature, size_t signature_len ) { + struct rsa_context context; void *temp; void *expected; void *actual; int rc; + DBGC ( &context, "RSA %p verifying %s digest:\n", + &context, digest->name ); + DBGC_HDA ( &context, 0, value, digest->digestsize ); + DBGC_HDA ( &context, 0, signature, signature_len ); + + /* Initialise context */ + if ( ( rc = rsa_init ( &context, key ) ) != 0 ) + goto err_init; + /* Sanity check */ - if ( signature_len != context->max_len ) { - DBGC ( context, "RSA %p signature incorrect length (%zd " + if ( signature_len != context.max_len ) { + DBGC ( &context, "RSA %p signature incorrect length (%zd " "bytes, should be %zd)\n", - context, signature_len, context->max_len ); - return -ERANGE; + &context, signature_len, context.max_len ); + rc = -ERANGE; + goto err_sanity; } - DBGC ( context, "RSA %p verifying %s digest:\n", - context, digest->name ); - DBGC_HDA ( context, 0, value, digest->digestsize ); - DBGC_HDA ( context, 0, signature, signature_len ); /* Decipher the signature (using the big integer input buffer * as temporary storage) */ - temp = context->input0; + temp = context.input0; expected = temp; - rsa_cipher ( context, signature, expected ); - DBGC ( context, "RSA %p deciphered signature:\n", context ); - DBGC_HDA ( context, 0, expected, context->max_len ); + rsa_cipher ( &context, signature, expected ); + DBGC ( &context, "RSA %p deciphered signature:\n", &context ); + DBGC_HDA ( &context, 0, expected, context.max_len ); /* Encode digest (using the big integer output buffer as * temporary storage) */ - temp = context->output0; + temp = context.output0; actual = temp; - if ( ( rc = rsa_encode_digest ( context, digest, value, actual ) ) !=0 ) - return rc; + if ( ( rc = rsa_encode_digest ( &context, digest, value, + actual ) ) != 0 ) + goto err_encode; /* Verify the signature */ - if ( memcmp ( actual, expected, context->max_len ) != 0 ) { - DBGC ( context, "RSA %p signature verification failed\n", - context ); - return -EACCES_VERIFY; + if ( memcmp ( actual, expected, context.max_len ) != 0 ) { + DBGC ( &context, "RSA %p signature verification failed\n", + &context ); + rc = -EACCES_VERIFY; + goto err_verify; } - DBGC ( context, "RSA %p signature verified successfully\n", context ); - return 0; -} + /* Free context */ + rsa_free ( &context ); -/** - * Finalise RSA cipher - * - * @v ctx RSA context - */ -static void rsa_final ( void *ctx ) { - struct rsa_context *context = ctx; + DBGC ( &context, "RSA %p signature verified successfully\n", &context ); + return 0; - rsa_free ( context ); + err_verify: + err_encode: + err_sanity: + rsa_free ( &context ); + err_init: + return rc; } /** @@ -615,14 +699,11 @@ static int rsa_match ( const struct asn1_cursor *private_key, /** RSA public-key algorithm */ struct pubkey_algorithm rsa_algorithm = { .name = "rsa", - .ctxsize = RSA_CTX_SIZE, - .init = rsa_init, .max_len = rsa_max_len, .encrypt = rsa_encrypt, .decrypt = rsa_decrypt, .sign = rsa_sign, .verify = rsa_verify, - .final = rsa_final, .match = rsa_match, }; diff --git a/src/crypto/x509.c b/src/crypto/x509.c index c0762740e..4101c8094 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -1125,7 +1125,6 @@ static int x509_check_signature ( struct x509_certificate *cert, struct pubkey_algorithm *pubkey = algorithm->pubkey; uint8_t digest_ctx[ digest->ctxsize ]; uint8_t digest_out[ digest->digestsize ]; - uint8_t pubkey_ctx[ pubkey->ctxsize ]; int rc; /* Sanity check */ @@ -1149,14 +1148,8 @@ static int x509_check_signature ( struct x509_certificate *cert, } /* Verify signature using signer's public key */ - if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, - &public_key->raw ) ) != 0 ) { - DBGC ( cert, "X509 %p \"%s\" cannot initialise public key: " - "%s\n", cert, x509_name ( cert ), strerror ( rc ) ); - goto err_pubkey_init; - } - if ( ( rc = pubkey_verify ( pubkey, pubkey_ctx, digest, digest_out, - signature->value.data, + if ( ( rc = pubkey_verify ( pubkey, &public_key->raw, digest, + digest_out, signature->value.data, signature->value.len ) ) != 0 ) { DBGC ( cert, "X509 %p \"%s\" signature verification failed: " "%s\n", cert, x509_name ( cert ), strerror ( rc ) ); @@ -1167,8 +1160,6 @@ static int x509_check_signature ( struct x509_certificate *cert, rc = 0; err_pubkey_verify: - pubkey_final ( pubkey, pubkey_ctx ); - err_pubkey_init: err_mismatch: return rc; } diff --git a/src/drivers/net/iphone.c b/src/drivers/net/iphone.c index 96eb0952b..08459a6e2 100644 --- a/src/drivers/net/iphone.c +++ b/src/drivers/net/iphone.c @@ -362,17 +362,9 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject, struct asn1_builder raw = { NULL, 0 }; uint8_t digest_ctx[SHA256_CTX_SIZE]; uint8_t digest_out[SHA256_DIGEST_SIZE]; - uint8_t pubkey_ctx[RSA_CTX_SIZE]; int len; int rc; - /* Initialise "private" key */ - if ( ( rc = pubkey_init ( pubkey, pubkey_ctx, private ) ) != 0 ) { - DBGC ( icert, "ICERT %p could not initialise private key: " - "%s\n", icert, strerror ( rc ) ); - goto err_pubkey_init; - } - /* Construct subjectPublicKeyInfo */ if ( ( rc = ( asn1_prepend_raw ( &spki, public->data, public->len ), asn1_prepend_raw ( &spki, icert_nul, @@ -406,14 +398,14 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject, digest_update ( digest, digest_ctx, tbs.data, tbs.len ); digest_final ( digest, digest_ctx, digest_out ); - /* Construct signature */ - if ( ( rc = asn1_grow ( &raw, pubkey_max_len ( pubkey, - pubkey_ctx ) ) ) != 0 ) { + /* Construct signature using "private" key */ + if ( ( rc = asn1_grow ( &raw, + pubkey_max_len ( pubkey, private ) ) ) != 0 ) { DBGC ( icert, "ICERT %p could not build signature: %s\n", icert, strerror ( rc ) ); goto err_grow; } - if ( ( len = pubkey_sign ( pubkey, pubkey_ctx, digest, digest_out, + if ( ( len = pubkey_sign ( pubkey, private, digest, digest_out, raw.data ) ) < 0 ) { rc = len; DBGC ( icert, "ICERT %p could not sign: %s\n", @@ -452,8 +444,6 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject, err_tbs: free ( spki.data ); err_spki: - pubkey_final ( pubkey, pubkey_ctx ); - err_pubkey_init: return rc; } diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index 8b6eb94f6..dcc73f3ef 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -121,68 +121,55 @@ struct cipher_algorithm { struct pubkey_algorithm { /** Algorithm name */ const char *name; - /** Context size */ - size_t ctxsize; - /** Initialise algorithm - * - * @v ctx Context - * @v key Key - * @ret rc Return status code - */ - int ( * init ) ( void *ctx, const struct asn1_cursor *key ); /** Calculate maximum output length * - * @v ctx Context + * @v key Key * @ret max_len Maximum output length */ - size_t ( * max_len ) ( void *ctx ); + size_t ( * max_len ) ( const struct asn1_cursor *key ); /** Encrypt * - * @v ctx Context + * @v key Key * @v plaintext Plaintext * @v plaintext_len Length of plaintext * @v ciphertext Ciphertext * @ret ciphertext_len Length of ciphertext, or negative error */ - int ( * encrypt ) ( void *ctx, const void *data, size_t len, - void *out ); + int ( * encrypt ) ( const struct asn1_cursor *key, const void *data, + size_t len, void *out ); /** Decrypt * - * @v ctx Context + * @v key Key * @v ciphertext Ciphertext * @v ciphertext_len Ciphertext length * @v plaintext Plaintext * @ret plaintext_len Plaintext length, or negative error */ - int ( * decrypt ) ( void *ctx, const void *data, size_t len, - void *out ); + int ( * decrypt ) ( const struct asn1_cursor *key, const void *data, + size_t len, void *out ); /** Sign digest value * - * @v ctx Context + * @v key Key * @v digest Digest algorithm * @v value Digest value * @v signature Signature * @ret signature_len Signature length, or negative error */ - int ( * sign ) ( void *ctx, struct digest_algorithm *digest, - const void *value, void *signature ); + int ( * sign ) ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, + void *signature ); /** Verify signed digest value * - * @v ctx Context + * @v key Key * @v digest Digest algorithm * @v value Digest value * @v signature Signature * @v signature_len Signature length * @ret rc Return status code */ - int ( * verify ) ( void *ctx, struct digest_algorithm *digest, - const void *value, const void *signature, - size_t signature_len ); - /** Finalise algorithm - * - * @v ctx Context - */ - void ( * final ) ( void *ctx ); + int ( * verify ) ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, + const void *signature, size_t signature_len ); /** Check that public key matches private key * * @v private_key Private key @@ -278,46 +265,36 @@ is_auth_cipher ( struct cipher_algorithm *cipher ) { return cipher->authsize; } -static inline __attribute__ (( always_inline )) int -pubkey_init ( struct pubkey_algorithm *pubkey, void *ctx, - const struct asn1_cursor *key ) { - return pubkey->init ( ctx, key ); -} - static inline __attribute__ (( always_inline )) size_t -pubkey_max_len ( struct pubkey_algorithm *pubkey, void *ctx ) { - return pubkey->max_len ( ctx ); +pubkey_max_len ( struct pubkey_algorithm *pubkey, + const struct asn1_cursor *key ) { + return pubkey->max_len ( key ); } static inline __attribute__ (( always_inline )) int -pubkey_encrypt ( struct pubkey_algorithm *pubkey, void *ctx, +pubkey_encrypt ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, const void *data, size_t len, void *out ) { - return pubkey->encrypt ( ctx, data, len, out ); + return pubkey->encrypt ( key, data, len, out ); } static inline __attribute__ (( always_inline )) int -pubkey_decrypt ( struct pubkey_algorithm *pubkey, void *ctx, +pubkey_decrypt ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, const void *data, size_t len, void *out ) { - return pubkey->decrypt ( ctx, data, len, out ); + return pubkey->decrypt ( key, data, len, out ); } static inline __attribute__ (( always_inline )) int -pubkey_sign ( struct pubkey_algorithm *pubkey, void *ctx, +pubkey_sign ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, struct digest_algorithm *digest, const void *value, void *signature ) { - return pubkey->sign ( ctx, digest, value, signature ); + return pubkey->sign ( key, digest, value, signature ); } static inline __attribute__ (( always_inline )) int -pubkey_verify ( struct pubkey_algorithm *pubkey, void *ctx, +pubkey_verify ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, struct digest_algorithm *digest, const void *value, const void *signature, size_t signature_len ) { - return pubkey->verify ( ctx, digest, value, signature, signature_len ); -} - -static inline __attribute__ (( always_inline )) void -pubkey_final ( struct pubkey_algorithm *pubkey, void *ctx ) { - pubkey->final ( ctx ); + return pubkey->verify ( key, digest, value, signature, signature_len ); } static inline __attribute__ (( always_inline )) int @@ -345,15 +322,18 @@ extern void cipher_null_decrypt ( void *ctx, const void *src, void *dst, size_t len ); extern void cipher_null_auth ( void *ctx, void *auth ); -extern int pubkey_null_init ( void *ctx, const struct asn1_cursor *key ); -extern size_t pubkey_null_max_len ( void *ctx ); -extern int pubkey_null_encrypt ( void *ctx, const void *plaintext, - size_t plaintext_len, void *ciphertext ); -extern int pubkey_null_decrypt ( void *ctx, const void *ciphertext, - size_t ciphertext_len, void *plaintext ); -extern int pubkey_null_sign ( void *ctx, struct digest_algorithm *digest, +extern size_t pubkey_null_max_len ( const struct asn1_cursor *key ); +extern int pubkey_null_encrypt ( const struct asn1_cursor *key, + const void *plaintext, size_t plaintext_len, + void *ciphertext ); +extern int pubkey_null_decrypt ( const struct asn1_cursor *key, + const void *ciphertext, size_t ciphertext_len, + void *plaintext ); +extern int pubkey_null_sign ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, void *signature ); -extern int pubkey_null_verify ( void *ctx, struct digest_algorithm *digest, +extern int pubkey_null_verify ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, const void *signature , size_t signature_len ); diff --git a/src/include/ipxe/rsa.h b/src/include/ipxe/rsa.h index a1b5e0c03..e36a75edf 100644 --- a/src/include/ipxe/rsa.h +++ b/src/include/ipxe/rsa.h @@ -55,31 +55,6 @@ struct rsa_digestinfo_prefix { /** Declare an RSA digestInfo prefix */ #define __rsa_digestinfo_prefix __table_entry ( RSA_DIGESTINFO_PREFIXES, 01 ) -/** An RSA context */ -struct rsa_context { - /** Allocated memory */ - void *dynamic; - /** Modulus */ - bigint_element_t *modulus0; - /** Modulus size */ - unsigned int size; - /** Modulus length */ - size_t max_len; - /** Exponent */ - bigint_element_t *exponent0; - /** Exponent size */ - unsigned int exponent_size; - /** Input buffer */ - bigint_element_t *input0; - /** Output buffer */ - bigint_element_t *output0; - /** Temporary working space for modular exponentiation */ - void *tmp; -}; - -/** RSA context size */ -#define RSA_CTX_SIZE sizeof ( struct rsa_context ) - extern struct pubkey_algorithm rsa_algorithm; #endif /* _IPXE_RSA_H */ diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 9494eaa05..08d58689e 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -240,8 +240,6 @@ struct tls_cipherspec { struct tls_cipher_suite *suite; /** Dynamically-allocated storage */ void *dynamic; - /** Public key encryption context */ - void *pubkey_ctx; /** Bulk encryption cipher context */ void *cipher_ctx; /** MAC secret */ @@ -402,6 +400,8 @@ struct tls_server { struct x509_root *root; /** Certificate chain */ struct x509_chain *chain; + /** Public key (within server certificate) */ + struct asn1_cursor key; /** Certificate validator */ struct interface validator; /** Certificate validation pending operation */ diff --git a/src/net/tls.c b/src/net/tls.c index ec503e43d..ded100d0e 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -856,10 +856,6 @@ tls_find_cipher_suite ( unsigned int cipher_suite ) { static void tls_clear_cipher ( struct tls_connection *tls __unused, struct tls_cipherspec *cipherspec ) { - if ( cipherspec->suite ) { - pubkey_final ( cipherspec->suite->pubkey, - cipherspec->pubkey_ctx ); - } free ( cipherspec->dynamic ); memset ( cipherspec, 0, sizeof ( *cipherspec ) ); cipherspec->suite = &tls_cipher_suite_null; @@ -876,7 +872,6 @@ static void tls_clear_cipher ( struct tls_connection *tls __unused, static int tls_set_cipher ( struct tls_connection *tls, struct tls_cipherspec *cipherspec, struct tls_cipher_suite *suite ) { - struct pubkey_algorithm *pubkey = suite->pubkey; struct cipher_algorithm *cipher = suite->cipher; size_t total; void *dynamic; @@ -885,8 +880,7 @@ static int tls_set_cipher ( struct tls_connection *tls, tls_clear_cipher ( tls, cipherspec ); /* Allocate dynamic storage */ - total = ( pubkey->ctxsize + cipher->ctxsize + suite->mac_len + - suite->fixed_iv_len ); + total = ( cipher->ctxsize + suite->mac_len + suite->fixed_iv_len ); dynamic = zalloc ( total ); if ( ! dynamic ) { DBGC ( tls, "TLS %p could not allocate %zd bytes for crypto " @@ -896,7 +890,6 @@ static int tls_set_cipher ( struct tls_connection *tls, /* Assign storage */ cipherspec->dynamic = dynamic; - cipherspec->pubkey_ctx = dynamic; dynamic += pubkey->ctxsize; cipherspec->cipher_ctx = dynamic; dynamic += cipher->ctxsize; cipherspec->mac_secret = dynamic; dynamic += suite->mac_len; cipherspec->fixed_iv = dynamic; dynamic += suite->fixed_iv_len; @@ -1392,7 +1385,7 @@ static int tls_send_certificate ( struct tls_connection *tls ) { static int tls_send_client_key_exchange_pubkey ( struct tls_connection *tls ) { struct tls_cipherspec *cipherspec = &tls->tx.cipherspec.pending; struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey; - size_t max_len = pubkey_max_len ( pubkey, cipherspec->pubkey_ctx ); + size_t max_len = pubkey_max_len ( pubkey, &tls->server.key ); struct { uint16_t version; uint8_t random[46]; @@ -1419,8 +1412,8 @@ static int tls_send_client_key_exchange_pubkey ( struct tls_connection *tls ) { /* Encrypt pre-master secret using server's public key */ memset ( &key_xchg, 0, sizeof ( key_xchg ) ); - len = pubkey_encrypt ( pubkey, cipherspec->pubkey_ctx, - &pre_master_secret, sizeof ( pre_master_secret ), + len = pubkey_encrypt ( pubkey, &tls->server.key, &pre_master_secret, + sizeof ( pre_master_secret ), key_xchg.encrypted_pre_master_secret ); if ( len < 0 ) { rc = len; @@ -1523,7 +1516,7 @@ static int tls_verify_dh_params ( struct tls_connection *tls, digest_final ( digest, ctx, hash ); /* Verify signature */ - if ( ( rc = pubkey_verify ( pubkey, cipherspec->pubkey_ctx, + if ( ( rc = pubkey_verify ( pubkey, &tls->server.key, digest, hash, signature, signature_len ) ) != 0 ) { DBGC ( tls, "TLS %p ServerKeyExchange failed " @@ -1820,20 +1813,12 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { struct pubkey_algorithm *pubkey = cert->signature_algorithm->pubkey; struct asn1_cursor *key = privkey_cursor ( tls->client.key ); uint8_t digest_out[ digest->digestsize ]; - uint8_t ctx[ pubkey->ctxsize ]; struct tls_signature_hash_algorithm *sig_hash = NULL; int rc; /* Generate digest to be signed */ tls_verify_handshake ( tls, digest_out ); - /* Initialise public-key algorithm */ - if ( ( rc = pubkey_init ( pubkey, ctx, key ) ) != 0 ) { - DBGC ( tls, "TLS %p could not initialise %s client private " - "key: %s\n", tls, pubkey->name, strerror ( rc ) ); - goto err_pubkey_init; - } - /* TLSv1.2 and later use explicit algorithm identifiers */ if ( tls_version ( tls, TLS_VERSION_TLS_1_2 ) ) { sig_hash = tls_signature_hash_algorithm ( pubkey, digest ); @@ -1848,7 +1833,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { /* Generate and transmit record */ { - size_t max_len = pubkey_max_len ( pubkey, ctx ); + size_t max_len = pubkey_max_len ( pubkey, key ); int use_sig_hash = ( ( sig_hash == NULL ) ? 0 : 1 ); struct { uint32_t type_length; @@ -1860,7 +1845,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { int len; /* Sign digest */ - len = pubkey_sign ( pubkey, ctx, digest, digest_out, + len = pubkey_sign ( pubkey, key, digest, digest_out, certificate_verify.signature ); if ( len < 0 ) { rc = len; @@ -1893,8 +1878,6 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { err_pubkey_sign: err_sig_hash: - pubkey_final ( pubkey, ctx ); - err_pubkey_init: return rc; } @@ -2312,6 +2295,7 @@ static int tls_parse_chain ( struct tls_connection *tls, int rc; /* Free any existing certificate chain */ + memset ( &tls->server.key, 0, sizeof ( tls->server.key ) ); x509_chain_put ( tls->server.chain ); tls->server.chain = NULL; @@ -2371,6 +2355,7 @@ static int tls_parse_chain ( struct tls_connection *tls, err_parse: err_overlength: err_underlength: + memset ( &tls->server.key, 0, sizeof ( tls->server.key ) ); x509_chain_put ( tls->server.chain ); tls->server.chain = NULL; err_alloc_chain: @@ -3555,8 +3540,6 @@ static struct interface_descriptor tls_cipherstream_desc = */ static void tls_validator_done ( struct tls_connection *tls, int rc ) { struct tls_session *session = tls->session; - struct tls_cipherspec *cipherspec = &tls->tx.cipherspec.pending; - struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey; struct x509_certificate *cert; /* Mark validation as complete */ @@ -3584,13 +3567,9 @@ static void tls_validator_done ( struct tls_connection *tls, int rc ) { goto err; } - /* Initialise public key algorithm */ - if ( ( rc = pubkey_init ( pubkey, cipherspec->pubkey_ctx, - &cert->subject.public_key.raw ) ) != 0 ) { - DBGC ( tls, "TLS %p cannot initialise public key: %s\n", - tls, strerror ( rc ) ); - goto err; - } + /* Extract the now trusted server public key */ + memcpy ( &tls->server.key, &cert->subject.public_key.raw, + sizeof ( tls->server.key ) ); /* Schedule Client Key Exchange, Change Cipher, and Finished */ tls->tx.pending |= ( TLS_TX_CLIENT_KEY_EXCHANGE | diff --git a/src/tests/pubkey_test.c b/src/tests/pubkey_test.c index 93962516a..ff318bfb7 100644 --- a/src/tests/pubkey_test.c +++ b/src/tests/pubkey_test.c @@ -50,77 +50,41 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); void pubkey_okx ( struct pubkey_test *test, const char *file, unsigned int line ) { struct pubkey_algorithm *pubkey = test->pubkey; - uint8_t private_ctx[pubkey->ctxsize]; - uint8_t public_ctx[pubkey->ctxsize]; - size_t max_len; - - /* Initialize contexts */ - okx ( pubkey_init ( pubkey, private_ctx, &test->private ) == 0, - file, line ); - okx ( pubkey_init ( pubkey, public_ctx, &test->public ) == 0, - file, line ); - max_len = pubkey_max_len ( pubkey, private_ctx ); + size_t max_len = pubkey_max_len ( pubkey, &test->private ); + uint8_t encrypted[max_len]; + uint8_t decrypted[max_len]; + int encrypted_len; + int decrypted_len; /* Test decrypting with private key to obtain known plaintext */ - { - uint8_t decrypted[max_len]; - int decrypted_len; - - decrypted_len = pubkey_decrypt ( pubkey, private_ctx, - test->ciphertext, - test->ciphertext_len, - decrypted ); - okx ( decrypted_len == ( ( int ) test->plaintext_len ), - file, line ); - okx ( memcmp ( decrypted, test->plaintext, - test->plaintext_len ) == 0, file, line ); - } + decrypted_len = pubkey_decrypt ( pubkey, &test->private, + test->ciphertext, test->ciphertext_len, + decrypted ); + okx ( decrypted_len == ( ( int ) test->plaintext_len ), file, line ); + okx ( memcmp ( decrypted, test->plaintext, test->plaintext_len ) == 0, + file, line ); /* Test encrypting with private key and decrypting with public key */ - { - uint8_t encrypted[max_len]; - uint8_t decrypted[max_len]; - int encrypted_len; - int decrypted_len; - - encrypted_len = pubkey_encrypt ( pubkey, private_ctx, - test->plaintext, - test->plaintext_len, - encrypted ); - okx ( encrypted_len >= 0, file, line ); - decrypted_len = pubkey_decrypt ( pubkey, public_ctx, - encrypted, encrypted_len, - decrypted ); - okx ( decrypted_len == ( ( int ) test->plaintext_len ), - file, line ); - okx ( memcmp ( decrypted, test->plaintext, - test->plaintext_len ) == 0, file, line ); - } + encrypted_len = pubkey_encrypt ( pubkey, &test->private, + test->plaintext, test->plaintext_len, + encrypted ); + okx ( encrypted_len >= 0, file, line ); + decrypted_len = pubkey_decrypt ( pubkey, &test->public, encrypted, + encrypted_len, decrypted ); + okx ( decrypted_len == ( ( int ) test->plaintext_len ), file, line ); + okx ( memcmp ( decrypted, test->plaintext, test->plaintext_len ) == 0, + file, line ); /* Test encrypting with public key and decrypting with private key */ - { - uint8_t encrypted[max_len]; - uint8_t decrypted[max_len]; - int encrypted_len; - int decrypted_len; - - encrypted_len = pubkey_encrypt ( pubkey, public_ctx, - test->plaintext, - test->plaintext_len, - encrypted ); - okx ( encrypted_len >= 0, file, line ); - decrypted_len = pubkey_decrypt ( pubkey, private_ctx, - encrypted, encrypted_len, - decrypted ); - okx ( decrypted_len == ( ( int ) test->plaintext_len ), - file, line ); - okx ( memcmp ( decrypted, test->plaintext, - test->plaintext_len ) == 0, file, line ); - } - - /* Free contexts */ - pubkey_final ( pubkey, public_ctx ); - pubkey_final ( pubkey, private_ctx ); + encrypted_len = pubkey_encrypt ( pubkey, &test->public, + test->plaintext, test->plaintext_len, + encrypted ); + okx ( encrypted_len >= 0, file, line ); + decrypted_len = pubkey_decrypt ( pubkey, &test->private, encrypted, + encrypted_len, decrypted ); + okx ( decrypted_len == ( ( int ) test->plaintext_len ), file, line ); + okx ( memcmp ( decrypted, test->plaintext, test->plaintext_len ) == 0, + file, line ); } /** @@ -134,18 +98,12 @@ void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file, unsigned int line ) { struct pubkey_algorithm *pubkey = test->pubkey; struct digest_algorithm *digest = test->digest; - uint8_t private_ctx[pubkey->ctxsize]; - uint8_t public_ctx[pubkey->ctxsize]; + size_t max_len = pubkey_max_len ( pubkey, &test->private ); + uint8_t bad[test->signature_len]; uint8_t digestctx[digest->ctxsize ]; uint8_t digestout[digest->digestsize]; - size_t max_len; - - /* Initialize contexts */ - okx ( pubkey_init ( pubkey, private_ctx, &test->private ) == 0, - file, line ); - okx ( pubkey_init ( pubkey, public_ctx, &test->public ) == 0, - file, line ); - max_len = pubkey_max_len ( pubkey, private_ctx ); + uint8_t signature[max_len]; + int signature_len; /* Construct digest over plaintext */ digest_init ( digest, digestctx ); @@ -154,34 +112,20 @@ void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file, digest_final ( digest, digestctx, digestout ); /* Test signing using private key */ - { - uint8_t signature[max_len]; - int signature_len; - - signature_len = pubkey_sign ( pubkey, private_ctx, digest, - digestout, signature ); - okx ( signature_len == ( ( int ) test->signature_len ), - file, line ); - okx ( memcmp ( signature, test->signature, - test->signature_len ) == 0, file, line ); - } + signature_len = pubkey_sign ( pubkey, &test->private, digest, + digestout, signature ); + okx ( signature_len == ( ( int ) test->signature_len ), file, line ); + okx ( memcmp ( signature, test->signature, test->signature_len ) == 0, + file, line ); /* Test verification using public key */ - okx ( pubkey_verify ( pubkey, public_ctx, digest, digestout, + okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, test->signature, test->signature_len ) == 0, file, line ); /* Test verification failure of modified signature */ - { - uint8_t bad[test->signature_len]; - - memcpy ( bad, test->signature, test->signature_len ); - bad[ test->signature_len / 2 ] ^= 0x40; - okx ( pubkey_verify ( pubkey, public_ctx, digest, digestout, - bad, sizeof ( bad ) ) != 0, file, line ); - } - - /* Free contexts */ - pubkey_final ( pubkey, public_ctx ); - pubkey_final ( pubkey, private_ctx ); + memcpy ( bad, test->signature, test->signature_len ); + bad[ test->signature_len / 2 ] ^= 0x40; + okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, + bad, sizeof ( bad ) ) != 0, file, line ); } -- cgit v1.2.3-55-g7522 From b053ba19884415794504c1bcffa910f0295598f0 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 26 Aug 2024 15:15:09 +0100 Subject: [test] Update CMS self-test terminology Generalise CMS self-test data structure and macro names to refer to "messages" rather than "signatures", in preparation for adding image decryption tests. Signed-off-by: Michael Brown --- src/tests/cms_test.c | 117 +++++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 59 deletions(-) (limited to 'src/tests') diff --git a/src/tests/cms_test.c b/src/tests/cms_test.c index 86f9bb98f..2480263e1 100644 --- a/src/tests/cms_test.c +++ b/src/tests/cms_test.c @@ -45,15 +45,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** Fingerprint algorithm used for X.509 test certificates */ #define cms_test_algorithm sha256_algorithm -/** CMS test code blob */ -struct cms_test_code { - /** Code image */ +/** Test image */ +struct cms_test_image { + /** Image */ struct image image; }; -/** CMS test signature */ -struct cms_test_signature { - /** Signature image */ +/** Test CMS message */ +struct cms_test_message { + /** Message image */ struct image image; /** Parsed message */ struct cms_message *cms; @@ -65,23 +65,22 @@ struct cms_test_signature { /** Define inline fingerprint data */ #define FINGERPRINT(...) { __VA_ARGS__ } -/** Define a test code blob */ -#define SIGNED_CODE( NAME, DATA ) \ +/** Define a test image */ +#define IMAGE( NAME, DATA ) \ static const uint8_t NAME ## _data[] = DATA; \ - static struct cms_test_code NAME = { \ + static struct cms_test_image NAME = { \ .image = { \ .refcnt = REF_INIT ( ref_no_free ), \ .name = #NAME, \ - .type = &der_image_type, \ .data = ( userptr_t ) ( NAME ## _data ), \ .len = sizeof ( NAME ## _data ), \ }, \ } -/** Define a test signature */ -#define SIGNATURE( NAME, DATA ) \ +/** Define a test message */ +#define MESSAGE( NAME, DATA ) \ static const uint8_t NAME ## _data[] = DATA; \ - static struct cms_test_signature NAME = { \ + static struct cms_test_message NAME = { \ .image = { \ .refcnt = REF_INIT ( ref_no_free ), \ .name = #NAME, \ @@ -92,7 +91,7 @@ struct cms_test_signature { } /** Code that has been signed */ -SIGNED_CODE ( test_code, +IMAGE ( test_code, DATA ( 0x23, 0x21, 0x69, 0x70, 0x78, 0x65, 0x0a, 0x0a, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, @@ -104,7 +103,7 @@ SIGNED_CODE ( test_code, 0x65, 0x6c, 0x6c, 0x0a ) ); /** Code that has not been signed */ -SIGNED_CODE ( bad_code, +IMAGE ( bad_code, DATA ( 0x23, 0x21, 0x69, 0x70, 0x78, 0x65, 0x0a, 0x0a, 0x65, 0x63, 0x68, 0x6f, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x6c, 0x69, 0x63, 0x69, 0x6f, @@ -115,7 +114,7 @@ SIGNED_CODE ( bad_code, 0x68, 0x65, 0x6c, 0x6c, 0x0a ) ); /** Valid signature */ -SIGNATURE ( codesigned_sig, +MESSAGE ( codesigned_sig, DATA ( 0x30, 0x82, 0x0c, 0x41, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x0c, 0x32, 0x30, 0x82, 0x0c, 0x2e, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07, @@ -433,7 +432,7 @@ SIGNATURE ( codesigned_sig, 0xbf ) ); /** Signature with a broken certificate chain */ -SIGNATURE ( brokenchain_sig, +MESSAGE ( brokenchain_sig, DATA ( 0x30, 0x82, 0x09, 0x8a, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x09, 0x7b, 0x30, 0x82, 0x09, 0x77, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07, @@ -681,7 +680,7 @@ SIGNATURE ( brokenchain_sig, 0xf9, 0x71, 0x64, 0x03, 0x05, 0xbf ) ); /** Signature generated with a non-code-signing certificate */ -SIGNATURE ( genericsigned_sig, +MESSAGE ( genericsigned_sig, DATA ( 0x30, 0x82, 0x0c, 0x2f, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x0c, 0x20, 0x30, 0x82, 0x0c, 0x1c, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07, @@ -997,7 +996,7 @@ SIGNATURE ( genericsigned_sig, 0x7e, 0x7c, 0x99 ) ); /** Signature generated with a non-signing certificate */ -SIGNATURE ( nonsigned_sig, +MESSAGE ( nonsigned_sig, DATA ( 0x30, 0x82, 0x0c, 0x12, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02, 0xa0, 0x82, 0x0c, 0x03, 0x30, 0x82, 0x0b, 0xff, 0x02, 0x01, 0x01, 0x31, 0x09, 0x30, 0x07, @@ -1352,33 +1351,33 @@ static time_t test_time = 1332374737ULL; /* Thu Mar 22 00:05:37 2012 */ static time_t test_expired = 1375573111ULL; /* Sat Aug 3 23:38:31 2013 */ /** - * Report signature parsing test result + * Report message parsing test result * - * @v sgn Test signature + * @v msg Test message * @v file Test code file * @v line Test code line */ -static void cms_signature_okx ( struct cms_test_signature *sgn, - const char *file, unsigned int line ) { - const void *data = ( ( void * ) sgn->image.data ); +static void cms_message_okx ( struct cms_test_message *msg, + const char *file, unsigned int line ) { + const void *data = ( ( void * ) msg->image.data ); /* Fix up image data pointer */ - sgn->image.data = virt_to_user ( data ); + msg->image.data = virt_to_user ( data ); - /* Check ability to parse signature */ - okx ( cms_message ( &sgn->image, &sgn->cms ) == 0, file, line ); + /* Check ability to parse message */ + okx ( cms_message ( &msg->image, &msg->cms ) == 0, file, line ); /* Reset image data pointer */ - sgn->image.data = ( ( userptr_t ) data ); + msg->image.data = ( ( userptr_t ) data ); } -#define cms_signature_ok( sgn ) \ - cms_signature_okx ( sgn, __FILE__, __LINE__ ) +#define cms_message_ok( msg ) \ + cms_message_okx ( msg, __FILE__, __LINE__ ) /** * Report signature verification test result * - * @v sgn Test signature - * @v code Test signed code + * @v msg Test signature message + * @v img Test signed image * @v name Test verification name * @v time Test verification time * @v store Test certificate store @@ -1386,36 +1385,36 @@ static void cms_signature_okx ( struct cms_test_signature *sgn, * @v file Test code file * @v line Test code line */ -static void cms_verify_okx ( struct cms_test_signature *sgn, - struct cms_test_code *code, const char *name, +static void cms_verify_okx ( struct cms_test_message *msg, + struct cms_test_image *img, const char *name, time_t time, struct x509_chain *store, struct x509_root *root, const char *file, unsigned int line ) { - const void *data = ( ( void * ) code->image.data ); + const void *data = ( ( void * ) img->image.data ); /* Fix up image data pointer */ - code->image.data = virt_to_user ( data ); + img->image.data = virt_to_user ( data ); /* Invalidate any certificates from previous tests */ - x509_invalidate_chain ( sgn->cms->certificates ); + x509_invalidate_chain ( msg->cms->certificates ); /* Check ability to verify signature */ - okx ( cms_verify ( sgn->cms, &code->image, name, time, store, + okx ( cms_verify ( msg->cms, &img->image, name, time, store, root ) == 0, file, line ); - okx ( code->image.flags & IMAGE_TRUSTED, file, line ); + okx ( img->image.flags & IMAGE_TRUSTED, file, line ); /* Reset image data pointer */ - code->image.data = ( ( userptr_t ) data ); + img->image.data = ( ( userptr_t ) data ); } -#define cms_verify_ok( sgn, code, name, time, store, root ) \ - cms_verify_okx ( sgn, code, name, time, store, root, \ +#define cms_verify_ok( msg, img, name, time, store, root ) \ + cms_verify_okx ( msg, img, name, time, store, root, \ __FILE__, __LINE__ ) /** * Report signature verification failure test result * - * @v sgn Test signature - * @v code Test signed code + * @v msg Test signature message + * @v img Test signed image * @v name Test verification name * @v time Test verification time * @v store Test certificate store @@ -1423,29 +1422,29 @@ static void cms_verify_okx ( struct cms_test_signature *sgn, * @v file Test code file * @v line Test code line */ -static void cms_verify_fail_okx ( struct cms_test_signature *sgn, - struct cms_test_code *code, const char *name, +static void cms_verify_fail_okx ( struct cms_test_message *msg, + struct cms_test_image *img, const char *name, time_t time, struct x509_chain *store, struct x509_root *root, const char *file, unsigned int line ) { - const void *data = ( ( void * ) code->image.data ); + const void *data = ( ( void * ) img->image.data ); /* Fix up image data pointer */ - code->image.data = virt_to_user ( data ); + img->image.data = virt_to_user ( data ); /* Invalidate any certificates from previous tests */ - x509_invalidate_chain ( sgn->cms->certificates ); + x509_invalidate_chain ( msg->cms->certificates ); /* Check inability to verify signature */ - okx ( cms_verify ( sgn->cms, &code->image, name, time, store, + okx ( cms_verify ( msg->cms, &img->image, name, time, store, root ) != 0, file, line ); - okx ( ! ( code->image.flags & IMAGE_TRUSTED ), file, line ); + okx ( ! ( img->image.flags & IMAGE_TRUSTED ), file, line ); /* Reset image data pointer */ - code->image.data = ( ( userptr_t ) data ); + img->image.data = ( ( userptr_t ) data ); } -#define cms_verify_fail_ok( sgn, code, name, time, store, root ) \ - cms_verify_fail_okx ( sgn, code, name, time, store, root, \ +#define cms_verify_fail_ok( msg, img, name, time, store, root ) \ + cms_verify_fail_okx ( msg, img, name, time, store, root, \ __FILE__, __LINE__ ) /** @@ -1454,11 +1453,11 @@ static void cms_verify_fail_okx ( struct cms_test_signature *sgn, */ static void cms_test_exec ( void ) { - /* Check that all signatures can be parsed */ - cms_signature_ok ( &codesigned_sig ); - cms_signature_ok ( &brokenchain_sig ); - cms_signature_ok ( &genericsigned_sig ); - cms_signature_ok ( &nonsigned_sig ); + /* Check that all messages can be parsed */ + cms_message_ok ( &codesigned_sig ); + cms_message_ok ( &brokenchain_sig ); + cms_message_ok ( &genericsigned_sig ); + cms_message_ok ( &nonsigned_sig ); /* Check good signature */ cms_verify_ok ( &codesigned_sig, &test_code, "codesign.test.ipxe.org", -- cgit v1.2.3-55-g7522 From 301644ab480ab9787c617e1a94e19ca5c2774072 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 29 Aug 2024 23:31:40 +0100 Subject: [test] Add CMS decryption self-tests Signed-off-by: Michael Brown --- src/tests/cms_test.c | 355 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 353 insertions(+), 2 deletions(-) (limited to 'src/tests') diff --git a/src/tests/cms_test.c b/src/tests/cms_test.c index 2480263e1..fc4f6bd19 100644 --- a/src/tests/cms_test.c +++ b/src/tests/cms_test.c @@ -40,6 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include /** Fingerprint algorithm used for X.509 test certificates */ @@ -59,6 +60,18 @@ struct cms_test_message { struct cms_message *cms; }; +/** Test CMS key pair */ +struct cms_test_keypair { + /** Private key */ + struct private_key privkey; + /** Certificate data */ + const void *data; + /** Length of certificate data */ + size_t len; + /** Parsed certificate */ + struct x509_certificate *cert; +}; + /** Define inline data */ #define DATA(...) { __VA_ARGS__ } @@ -67,7 +80,7 @@ struct cms_test_message { /** Define a test image */ #define IMAGE( NAME, DATA ) \ - static const uint8_t NAME ## _data[] = DATA; \ + static uint8_t NAME ## _data[] = DATA; \ static struct cms_test_image NAME = { \ .image = { \ .refcnt = REF_INIT ( ref_no_free ), \ @@ -80,7 +93,7 @@ struct cms_test_message { /** Define a test message */ #define MESSAGE( NAME, DATA ) \ static const uint8_t NAME ## _data[] = DATA; \ - static struct cms_test_message NAME = { \ + static struct cms_test_message NAME = { \ .image = { \ .refcnt = REF_INIT ( ref_no_free ), \ .name = #NAME, \ @@ -90,6 +103,22 @@ struct cms_test_message { }, \ } +/** Define a test key pair */ +#define KEYPAIR( NAME, PRIVKEY, CERT ) \ + static uint8_t NAME ## _privkey[] = PRIVKEY; \ + static const uint8_t NAME ## _cert[] = CERT; \ + static struct cms_test_keypair NAME = { \ + .privkey = { \ + .refcnt = REF_INIT ( ref_no_free ), \ + .builder = { \ + .data = NAME ## _privkey, \ + .len = sizeof ( NAME ## _privkey ), \ + }, \ + }, \ + .data = NAME ## _cert, \ + .len = sizeof ( NAME ## _cert ), \ + } + /** Code that has been signed */ IMAGE ( test_code, DATA ( 0x23, 0x21, 0x69, 0x70, 0x78, 0x65, 0x0a, 0x0a, 0x65, 0x63, @@ -113,6 +142,123 @@ IMAGE ( bad_code, 0x6f, 0x75, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x21, 0x0a, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x0a ) ); +/** Plaintext of encrypted code */ +IMAGE ( hidden_code, + DATA ( 0x23, 0x21, 0x69, 0x70, 0x78, 0x65, 0x0a, 0x0a, 0x65, 0x63, + 0x68, 0x6f, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, + 0x20, 0x61, 0x20, 0x64, 0x65, 0x63, 0x72, 0x79, 0x70, 0x74, + 0x65, 0x64, 0x20, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x2e, 0x20, 0x20, 0x44, 0x6f, 0x20, + 0x61, 0x6e, 0x79, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x79, + 0x6f, 0x75, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x21, 0x0a, 0x73, + 0x68, 0x65, 0x6c, 0x6c, 0x0a ) ); + +/** Code encrypted with AES-256-CBC */ +IMAGE ( hidden_code_cbc_dat, + DATA ( 0xaa, 0x63, 0x9f, 0x12, 0xeb, 0x1e, 0xdd, 0x9b, 0xb6, 0x4d, + 0x81, 0xd5, 0xba, 0x2d, 0x86, 0x7a, 0x1c, 0x39, 0x10, 0x60, + 0x43, 0xac, 0x1b, 0x4e, 0x43, 0xb7, 0x50, 0x5a, 0x6d, 0x7a, + 0x4b, 0xd8, 0x65, 0x3c, 0x3e, 0xbd, 0x40, 0x9e, 0xb2, 0xe1, + 0x7d, 0x80, 0xf8, 0x22, 0x50, 0xf7, 0x32, 0x3a, 0x43, 0xf9, + 0xdf, 0xa6, 0xab, 0xa4, 0xb3, 0xdd, 0x27, 0x88, 0xd9, 0xb0, + 0x99, 0xb5, 0x7a, 0x89, 0x6c, 0xb7, 0x63, 0x45, 0x42, 0x7d, + 0xbe, 0x43, 0xab, 0x7e, 0x6c, 0x0c, 0xd5, 0xba, 0x9e, 0x37 ) ); + +/** Envelope for code encrypted with AES-256-CBC */ +MESSAGE ( hidden_code_cbc_env, + DATA ( 0x30, 0x82, 0x01, 0x70, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x07, 0x03, 0xa0, 0x82, 0x01, 0x61, 0x30, + 0x82, 0x01, 0x5d, 0x02, 0x01, 0x00, 0x31, 0x82, 0x01, 0x2a, + 0x30, 0x82, 0x01, 0x26, 0x02, 0x01, 0x00, 0x30, 0x81, 0x8e, + 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, + 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, + 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, + 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, + 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, 0x02, + 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x81, 0x80, + 0x10, 0x26, 0x94, 0x97, 0xe5, 0x84, 0x53, 0xf9, 0x03, 0xc4, + 0xf6, 0xc1, 0x55, 0xf5, 0x00, 0x23, 0xb9, 0x80, 0x20, 0x85, + 0xd2, 0xf2, 0xc4, 0x61, 0xdb, 0x73, 0x8d, 0xe1, 0xa1, 0x73, + 0x7d, 0x31, 0x12, 0xb7, 0xac, 0xa4, 0xe0, 0x40, 0x10, 0xcf, + 0xd5, 0x55, 0x70, 0x75, 0x9f, 0x7b, 0x61, 0xd3, 0x9e, 0xc6, + 0x58, 0x78, 0x05, 0x66, 0xc1, 0x86, 0x2f, 0x00, 0xcd, 0xe9, + 0x32, 0x63, 0x7c, 0x95, 0xd7, 0x75, 0x46, 0xde, 0x76, 0x7d, + 0x49, 0x64, 0x86, 0xd6, 0xeb, 0x0f, 0x1c, 0x01, 0x20, 0xb9, + 0xb9, 0x42, 0xc4, 0x20, 0x1f, 0x3f, 0xae, 0x5f, 0xb9, 0xd0, + 0xb6, 0x49, 0xcc, 0x4c, 0xd9, 0xcb, 0x36, 0xa4, 0x2f, 0xb1, + 0x97, 0x40, 0xf3, 0xe7, 0x19, 0x88, 0x93, 0x58, 0x61, 0x31, + 0xac, 0x9a, 0x93, 0x6e, 0x79, 0x31, 0x3a, 0x79, 0xa4, 0x20, + 0x38, 0x17, 0x92, 0x40, 0x7c, 0x98, 0xea, 0x86, 0x30, 0x2a, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, + 0x01, 0x30, 0x1d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, + 0x03, 0x04, 0x01, 0x2a, 0x04, 0x10, 0xd8, 0x80, 0xc5, 0xfa, + 0xc3, 0x25, 0xa0, 0x22, 0xb5, 0x6c, 0x0c, 0x27, 0x2c, 0xe9, + 0xba, 0xcf ) ); + +/** Code encrypted with AES-256-GCM (no block padding) */ +IMAGE ( hidden_code_gcm_dat, + DATA ( 0x0c, 0x96, 0xa6, 0x54, 0x9a, 0xc2, 0x24, 0x89, 0x15, 0x00, + 0x90, 0xe1, 0x35, 0xca, 0x4a, 0x84, 0x8e, 0x0b, 0xc3, 0x5e, + 0xc0, 0x61, 0x61, 0xbd, 0x2e, 0x69, 0x84, 0x7a, 0x2f, 0xf6, + 0xbe, 0x39, 0x04, 0x0a, 0x8d, 0x91, 0x6b, 0xaf, 0x63, 0xd4, + 0x03, 0xf1, 0x72, 0x38, 0xee, 0x27, 0xd6, 0x5a, 0xae, 0x15, + 0xd5, 0xec, 0xb6, 0xb6, 0x4f, 0x6f, 0xf6, 0x76, 0x22, 0x74, + 0xca, 0x72, 0x0b, 0xfa, 0x6a, 0x0e, 0x4a, 0x3e, 0x8c, 0x60, + 0x78, 0x24, 0x48, 0x58, 0xdd ) ); + +/** Envelope for code encrypted with AES-256-GCM (no block padding) */ +MESSAGE ( hidden_code_gcm_env, + DATA ( 0x30, 0x82, 0x01, 0x85, 0x06, 0x0b, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x09, 0x10, 0x01, 0x17, 0xa0, 0x82, 0x01, + 0x74, 0x30, 0x82, 0x01, 0x70, 0x02, 0x01, 0x00, 0x31, 0x82, + 0x01, 0x2a, 0x30, 0x82, 0x01, 0x26, 0x02, 0x01, 0x00, 0x30, + 0x81, 0x8e, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, + 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, + 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, + 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, + 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, + 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, + 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, + 0x41, 0x02, 0x01, 0x08, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, + 0x81, 0x80, 0x7e, 0xbc, 0xba, 0xee, 0xfa, 0x50, 0x46, 0xee, + 0xed, 0xf1, 0x54, 0xe1, 0x46, 0xeb, 0x57, 0x3e, 0x76, 0xd7, + 0x8f, 0xe3, 0x26, 0x42, 0x3d, 0x28, 0xf9, 0xdc, 0x20, 0xe6, + 0x27, 0x3b, 0x89, 0xcb, 0xab, 0xd5, 0xad, 0xc2, 0xf0, 0x4f, + 0xa8, 0xb9, 0x77, 0x5b, 0x6c, 0xe6, 0x34, 0x22, 0x73, 0x5b, + 0xa4, 0x8e, 0x1c, 0xc2, 0xf8, 0x50, 0xef, 0xe5, 0xcf, 0x80, + 0x16, 0x79, 0x6b, 0x0f, 0xa7, 0xfd, 0xdc, 0x60, 0x9c, 0x94, + 0x60, 0xa6, 0x12, 0x5a, 0xfb, 0xc2, 0xc8, 0x4c, 0x64, 0x83, + 0x99, 0x73, 0xfc, 0xa1, 0xf8, 0xa5, 0x82, 0x75, 0xba, 0x53, + 0xeb, 0xc8, 0x94, 0x0e, 0x29, 0x23, 0x9a, 0x2b, 0xa6, 0x63, + 0x2d, 0x5b, 0x9f, 0x38, 0x70, 0x21, 0xe8, 0xe9, 0xa6, 0xcf, + 0xf2, 0xbe, 0x66, 0xf4, 0xcc, 0x91, 0x01, 0x4f, 0x04, 0x00, + 0x4a, 0x55, 0xc9, 0x42, 0x76, 0xd4, 0x3f, 0x65, 0x0c, 0x76, + 0x30, 0x2b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x07, 0x01, 0x30, 0x1e, 0x06, 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, 0x01, 0x2e, 0x30, 0x11, 0x04, 0x0c, + 0x72, 0xb5, 0x14, 0xfb, 0x05, 0x78, 0x70, 0x1c, 0xf4, 0x4b, + 0xba, 0xbf, 0x02, 0x01, 0x10, 0x04, 0x10, 0x1e, 0x44, 0xda, + 0x5c, 0x75, 0x7e, 0x4f, 0xa7, 0xe7, 0xd9, 0x98, 0x80, 0x9c, + 0x25, 0x6a, 0xfb ) ); + /** Valid signature */ MESSAGE ( codesigned_sig, DATA ( 0x30, 0x82, 0x0c, 0x41, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, @@ -1308,6 +1454,138 @@ MESSAGE ( nonsigned_sig, 0x5d, 0x70, 0x47, 0x54, 0xbc, 0x15, 0xad, 0x9c, 0xe8, 0x90, 0x52, 0x3e, 0x49, 0x86 ) ); +/** Client certificate and private key */ +KEYPAIR ( client_keypair, + DATA ( 0x30, 0x82, 0x02, 0x77, 0x02, 0x01, 0x00, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x04, 0x82, 0x02, 0x61, 0x30, 0x82, 0x02, 0x5d, + 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xb7, 0x9f, 0xb5, + 0x90, 0xfa, 0x47, 0x25, 0xee, 0x3b, 0x04, 0x02, 0x4f, 0xd4, + 0x1d, 0x62, 0x46, 0x9d, 0xce, 0x79, 0x3a, 0x80, 0x3a, 0xc4, + 0x06, 0x6a, 0x67, 0xd4, 0x3a, 0x61, 0x71, 0xcd, 0xb3, 0xcc, + 0x1b, 0xfc, 0x2f, 0x17, 0xa8, 0xf2, 0x26, 0x9e, 0x54, 0xd3, + 0x49, 0x81, 0x22, 0xa9, 0x72, 0x4c, 0xe8, 0x92, 0xb7, 0x1e, + 0x44, 0x8f, 0xa9, 0x4d, 0x83, 0x0b, 0x89, 0x2a, 0xc7, 0xb3, + 0xad, 0x54, 0x32, 0x76, 0x62, 0x1e, 0xe5, 0xbe, 0xc1, 0xa8, + 0x7a, 0x2b, 0xf0, 0xa9, 0x9a, 0xfb, 0xb8, 0x18, 0x0c, 0x30, + 0x5a, 0x13, 0x9c, 0x21, 0x26, 0x96, 0x4f, 0x39, 0x98, 0x64, + 0x41, 0x3b, 0x94, 0xc8, 0xe3, 0xb7, 0x8c, 0x33, 0x9e, 0xd0, + 0x71, 0xd0, 0x2f, 0xe3, 0x7d, 0x2c, 0x57, 0x27, 0x42, 0x26, + 0xd9, 0x2c, 0xb4, 0x55, 0xd5, 0x66, 0xb7, 0xbf, 0x00, 0xa1, + 0xcc, 0x61, 0x19, 0x99, 0x61, 0x02, 0x03, 0x01, 0x00, 0x01, + 0x02, 0x81, 0x80, 0x50, 0x63, 0x2f, 0xe6, 0xb7, 0x5a, 0xfc, + 0x85, 0x0d, 0xfb, 0x14, 0x54, 0x04, 0x65, 0x94, 0xc7, 0x9b, + 0x80, 0x6f, 0xdc, 0x27, 0x95, 0x12, 0x8a, 0x48, 0x7d, 0x0a, + 0x11, 0x40, 0xe5, 0xc4, 0x8b, 0x29, 0x19, 0x3b, 0x4f, 0x16, + 0x89, 0x94, 0xf1, 0x49, 0x31, 0x93, 0x8a, 0x43, 0x69, 0x7c, + 0x4b, 0x18, 0xd6, 0x5c, 0x9c, 0xa4, 0x38, 0x99, 0xb8, 0x21, + 0xc1, 0xf4, 0x03, 0xe9, 0xe1, 0xa1, 0x8b, 0xcb, 0x51, 0x4f, + 0x64, 0x68, 0x1c, 0x73, 0xc0, 0x0d, 0xd2, 0xcd, 0x87, 0xcc, + 0x45, 0xe8, 0xbf, 0x88, 0xea, 0x6c, 0x42, 0xfa, 0x03, 0x7a, + 0x29, 0xd2, 0xcf, 0xf1, 0xcb, 0xae, 0xea, 0xfb, 0x50, 0xf2, + 0xbd, 0x02, 0x4f, 0x2f, 0x4f, 0xba, 0x82, 0xa9, 0xde, 0x60, + 0x56, 0xd4, 0x07, 0x73, 0xdf, 0x12, 0x09, 0x73, 0x7b, 0x54, + 0x35, 0xc6, 0x28, 0x10, 0xb0, 0xbd, 0xc8, 0xe1, 0x8f, 0xb2, + 0x41, 0x02, 0x41, 0x00, 0xd8, 0xf9, 0x6c, 0x70, 0x56, 0x3c, + 0x74, 0x44, 0x53, 0x13, 0xed, 0x92, 0xab, 0xbc, 0x0c, 0x5c, + 0x66, 0x2c, 0xd7, 0xed, 0x10, 0x82, 0xe3, 0xe3, 0x2e, 0xda, + 0x4d, 0x3e, 0x1f, 0xc0, 0x50, 0xa8, 0xf2, 0xce, 0x77, 0xa9, + 0xae, 0xa2, 0x2d, 0x49, 0x6a, 0x6f, 0x01, 0xe3, 0xca, 0x57, + 0xf4, 0xcc, 0xb4, 0x3f, 0xd9, 0xc3, 0x58, 0x54, 0xe7, 0x62, + 0xfc, 0x40, 0xc8, 0xba, 0x18, 0x0d, 0xfe, 0x89, 0x02, 0x41, + 0x00, 0xd8, 0xa6, 0xaa, 0x4b, 0xcc, 0xcf, 0xc4, 0x47, 0x84, + 0x13, 0x39, 0x5b, 0x2e, 0xcb, 0xe0, 0x41, 0xd0, 0x2c, 0x96, + 0x58, 0x73, 0xab, 0xf6, 0x41, 0x0c, 0x7b, 0xbe, 0x60, 0xa1, + 0xcb, 0x00, 0x1a, 0xb0, 0x4b, 0xc1, 0xf5, 0x27, 0x43, 0x97, + 0x87, 0x30, 0x3c, 0x27, 0xa3, 0xe3, 0xf1, 0xa7, 0x45, 0x01, + 0xe2, 0x1c, 0x43, 0xe9, 0x48, 0x43, 0x76, 0x24, 0x4b, 0x2b, + 0xc7, 0x67, 0x3e, 0x4e, 0x19, 0x02, 0x40, 0x6a, 0x43, 0x96, + 0x31, 0x5a, 0x7a, 0xd7, 0x32, 0x93, 0x41, 0xa2, 0x4c, 0x00, + 0x21, 0xe4, 0x27, 0xe8, 0xbe, 0xb3, 0xad, 0xde, 0x35, 0x4c, + 0xa8, 0xfa, 0x4c, 0x5e, 0x22, 0x3b, 0xe8, 0xb3, 0x58, 0x5b, + 0x3a, 0x75, 0x6e, 0xbc, 0x21, 0x9f, 0x6e, 0x62, 0x5b, 0x25, + 0xa0, 0xcb, 0x7b, 0xd2, 0x5f, 0xe3, 0x33, 0x96, 0x52, 0x4e, + 0xd3, 0x9e, 0x53, 0x63, 0x59, 0xd3, 0x35, 0x19, 0x0c, 0xd9, + 0x89, 0x02, 0x41, 0x00, 0x8f, 0x8d, 0xb7, 0xaf, 0x6c, 0x31, + 0x8b, 0x0c, 0x1c, 0x1e, 0xa4, 0xd5, 0x9f, 0x67, 0x65, 0xdc, + 0x15, 0xf5, 0x45, 0x55, 0xac, 0xa7, 0x98, 0x0f, 0x38, 0x17, + 0x52, 0x69, 0x33, 0x2b, 0x90, 0x91, 0x1e, 0x99, 0xc4, 0x16, + 0x0e, 0x03, 0x42, 0x87, 0x48, 0x55, 0xc3, 0xaa, 0x5b, 0xe2, + 0x86, 0x84, 0x3a, 0x20, 0x39, 0xbc, 0x61, 0xfa, 0x09, 0x01, + 0x62, 0x41, 0x10, 0xec, 0x1a, 0xa3, 0xf5, 0x19, 0x02, 0x41, + 0x00, 0x98, 0x04, 0xc8, 0x8e, 0xd0, 0xfa, 0xe5, 0xab, 0x8a, + 0x1c, 0x4a, 0xc2, 0xf7, 0xd4, 0xad, 0x52, 0x51, 0x81, 0xa6, + 0x59, 0x62, 0x84, 0x16, 0x82, 0xf2, 0x5d, 0xd0, 0x5d, 0x4a, + 0xcf, 0x94, 0x2f, 0x13, 0x47, 0xd4, 0xc2, 0x7f, 0x89, 0x2e, + 0x40, 0xf5, 0xfc, 0xf8, 0x82, 0xc6, 0x53, 0xd4, 0x75, 0x32, + 0x47, 0x1d, 0xcf, 0xd1, 0xae, 0x35, 0x41, 0x7a, 0xdc, 0x10, + 0x0c, 0xc2, 0xd6, 0xe1, 0xd5 ), + DATA ( 0x30, 0x82, 0x02, 0x7f, 0x30, 0x82, 0x01, 0xe8, 0x02, 0x01, + 0x08, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x81, 0x88, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, + 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, + 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, + 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, + 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, + 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, + 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, + 0x72, 0x67, 0x31, 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x0c, 0x16, 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, + 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, 0x6c, 0x65, + 0x61, 0x66, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x32, + 0x34, 0x30, 0x38, 0x32, 0x39, 0x32, 0x32, 0x31, 0x39, 0x35, + 0x38, 0x5a, 0x17, 0x0d, 0x32, 0x35, 0x30, 0x38, 0x32, 0x39, + 0x32, 0x32, 0x31, 0x39, 0x35, 0x38, 0x5a, 0x30, 0x81, 0x86, + 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, + 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, + 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, + 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, + 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, + 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, + 0x6f, 0x72, 0x67, 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, + 0x04, 0x03, 0x0c, 0x14, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, 0x70, 0x78, 0x65, + 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, + 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, + 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, + 0x81, 0x81, 0x00, 0xb7, 0x9f, 0xb5, 0x90, 0xfa, 0x47, 0x25, + 0xee, 0x3b, 0x04, 0x02, 0x4f, 0xd4, 0x1d, 0x62, 0x46, 0x9d, + 0xce, 0x79, 0x3a, 0x80, 0x3a, 0xc4, 0x06, 0x6a, 0x67, 0xd4, + 0x3a, 0x61, 0x71, 0xcd, 0xb3, 0xcc, 0x1b, 0xfc, 0x2f, 0x17, + 0xa8, 0xf2, 0x26, 0x9e, 0x54, 0xd3, 0x49, 0x81, 0x22, 0xa9, + 0x72, 0x4c, 0xe8, 0x92, 0xb7, 0x1e, 0x44, 0x8f, 0xa9, 0x4d, + 0x83, 0x0b, 0x89, 0x2a, 0xc7, 0xb3, 0xad, 0x54, 0x32, 0x76, + 0x62, 0x1e, 0xe5, 0xbe, 0xc1, 0xa8, 0x7a, 0x2b, 0xf0, 0xa9, + 0x9a, 0xfb, 0xb8, 0x18, 0x0c, 0x30, 0x5a, 0x13, 0x9c, 0x21, + 0x26, 0x96, 0x4f, 0x39, 0x98, 0x64, 0x41, 0x3b, 0x94, 0xc8, + 0xe3, 0xb7, 0x8c, 0x33, 0x9e, 0xd0, 0x71, 0xd0, 0x2f, 0xe3, + 0x7d, 0x2c, 0x57, 0x27, 0x42, 0x26, 0xd9, 0x2c, 0xb4, 0x55, + 0xd5, 0x66, 0xb7, 0xbf, 0x00, 0xa1, 0xcc, 0x61, 0x19, 0x99, + 0x61, 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x03, 0x81, 0x81, 0x00, 0x22, 0x6e, 0x8b, 0x81, 0xc3, + 0x13, 0x89, 0x31, 0xcc, 0x6d, 0x44, 0xa5, 0x77, 0x31, 0x79, + 0xff, 0xea, 0x8a, 0x4e, 0xe6, 0xb6, 0x4a, 0xf0, 0x01, 0xd3, + 0x9f, 0xd7, 0x23, 0x14, 0x4c, 0xdd, 0xa3, 0xdf, 0xd6, 0x2b, + 0x2a, 0xc4, 0xba, 0xf7, 0xef, 0xfd, 0x78, 0xd5, 0xd7, 0xfd, + 0xd7, 0x77, 0x17, 0x20, 0x4f, 0xf3, 0x94, 0xd6, 0x74, 0xd5, + 0x09, 0x54, 0x16, 0x49, 0x6e, 0xd9, 0x41, 0xa7, 0x43, 0x77, + 0x7f, 0xef, 0xd3, 0xd7, 0xbb, 0x8b, 0xf0, 0x7d, 0x1f, 0x00, + 0x4a, 0xac, 0x18, 0xff, 0x20, 0x32, 0xd1, 0x1c, 0x13, 0xf2, + 0xe0, 0xd7, 0x70, 0xec, 0xb6, 0xf7, 0xa3, 0x42, 0xa1, 0x64, + 0x26, 0x30, 0x9f, 0x47, 0xd4, 0xfb, 0xfb, 0x06, 0xdb, 0x0b, + 0xb3, 0x27, 0xe6, 0x04, 0xe2, 0x94, 0x35, 0x8b, 0xa5, 0xfd, + 0x80, 0x1d, 0xa6, 0x72, 0x32, 0x30, 0x99, 0x6c, 0xbf, 0xd3, + 0x26, 0xa3, 0x8a ) ); + /** iPXE self-test root CA certificate */ static uint8_t root_crt_fingerprint[] = FINGERPRINT ( 0x71, 0x5d, 0x51, 0x37, 0x5e, 0x18, 0xb3, 0xbc, @@ -1373,6 +1651,28 @@ static void cms_message_okx ( struct cms_test_message *msg, #define cms_message_ok( msg ) \ cms_message_okx ( msg, __FILE__, __LINE__ ) +/** + * Report key pair parsing test result + * + * @v keypair Test key pair + * @v file Test code file + * @v line Test code line + */ +static void cms_keypair_okx ( struct cms_test_keypair *keypair, + const char *file, unsigned int line ) { + + /* Check ability to parse certificate */ + okx ( x509_certificate ( keypair->data, keypair->len, + &keypair->cert ) == 0, file, line ); + okx ( keypair->cert != NULL, file, line ); + + /* Check certificate can be identified by public key */ + okx ( x509_find_key ( NULL, &keypair->privkey ) == keypair->cert, + file, line ); +} +#define cms_keypair_ok( keypair ) \ + cms_keypair_okx ( keypair, __FILE__, __LINE__ ) + /** * Report signature verification test result * @@ -1447,17 +1747,55 @@ static void cms_verify_fail_okx ( struct cms_test_message *msg, cms_verify_fail_okx ( msg, img, name, time, store, root, \ __FILE__, __LINE__ ) +/** + * Report decryption test result + * + * @v img Encrypted data image + * @v envelope Envelope message + * @v keypair Key pair + * @v expected Expected plaintext image + * @v file Test code file + * @v line Test code line + */ +static void cms_decrypt_okx ( struct cms_test_image *img, + struct cms_test_message *envelope, + struct cms_test_keypair *keypair, + struct cms_test_image *expected, + const char *file, unsigned int line ) { + const void *data = ( ( void * ) img->image.data ); + + /* Fix up image data pointer */ + img->image.data = virt_to_user ( data ); + + /* Check ability to decrypt image */ + okx ( cms_decrypt ( envelope->cms, &img->image, NULL, + &keypair->privkey ) == 0, file, line ); + + /* Check decrypted image matches expected plaintext */ + okx ( img->image.len == expected->image.len, file, line ); + okx ( memcmp_user ( img->image.data, 0, expected->image.data, 0, + expected->image.len ) == 0, file, line ); +} +#define cms_decrypt_ok( data, envelope, keypair, expected ) \ + cms_decrypt_okx ( data, envelope, keypair, expected, \ + __FILE__, __LINE__ ) + /** * Perform CMS self-tests * */ static void cms_test_exec ( void ) { + /* Check that all key pairs can be parsed */ + cms_keypair_ok ( &client_keypair ); + /* Check that all messages can be parsed */ cms_message_ok ( &codesigned_sig ); cms_message_ok ( &brokenchain_sig ); cms_message_ok ( &genericsigned_sig ); cms_message_ok ( &nonsigned_sig ); + cms_message_ok ( &hidden_code_cbc_env ); + cms_message_ok ( &hidden_code_gcm_env ); /* Check good signature */ cms_verify_ok ( &codesigned_sig, &test_code, "codesign.test.ipxe.org", @@ -1494,14 +1832,27 @@ static void cms_test_exec ( void ) { cms_verify_fail_ok ( &codesigned_sig, &test_code, NULL, test_expired, &empty_store, &test_root ); + /* Check CBC decryption (with padding) */ + cms_decrypt_ok ( &hidden_code_cbc_dat, &hidden_code_cbc_env, + &client_keypair, &hidden_code ); + + /* Check GCM decryption (no padding) */ + cms_decrypt_ok ( &hidden_code_gcm_dat, &hidden_code_gcm_env, + &client_keypair, &hidden_code ); + /* Sanity check */ assert ( list_empty ( &empty_store.links ) ); /* Drop message references */ + cms_put ( hidden_code_gcm_env.cms ); + cms_put ( hidden_code_cbc_env.cms ); cms_put ( nonsigned_sig.cms ); cms_put ( genericsigned_sig.cms ); cms_put ( brokenchain_sig.cms ); cms_put ( codesigned_sig.cms ); + + /* Drop certificate references */ + x509_put ( client_keypair.cert ); } /** CMS self-test */ -- cgit v1.2.3-55-g7522 From 1d43e535fb86537cb87f30c7fa45b175534489d6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 15 Sep 2024 02:00:14 +0100 Subject: [test] Add tests for 64-bit logical and arithmetic shifts For some 32-bit CPUs, we need to provide implementations of 64-bit shifts as libgcc helper functions. Add test cases to cover these. Signed-off-by: Michael Brown --- src/tests/math_test.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) (limited to 'src/tests') diff --git a/src/tests/math_test.c b/src/tests/math_test.c index 1a244f1eb..68e66c3e3 100644 --- a/src/tests/math_test.c +++ b/src/tests/math_test.c @@ -78,6 +78,42 @@ __attribute__ (( noinline )) int flsll_var ( long long value ) { return flsll ( value ); } +/** + * Force a use of runtime 64-bit shift left + * + * @v value Value + * @v shift Shift amount + * @ret value Shifted value + */ +__attribute__ (( noinline )) uint64_t lsl64_var ( uint64_t value, + unsigned int shift ) { + return ( value << shift ); +} + +/** + * Force a use of runtime 64-bit logical shift right + * + * @v value Value + * @v shift Shift amount + * @ret value Shifted value + */ +__attribute__ (( noinline )) uint64_t lsr64_var ( uint64_t value, + unsigned int shift ) { + return ( value >> shift ); +} + +/** + * Force a use of runtime 64-bit arithmetic shift right + * + * @v value Value + * @v shift Shift amount + * @ret value Shifted value + */ +__attribute__ (( noinline )) int64_t asr64_var ( int64_t value, + unsigned int shift ) { + return ( value >> shift ); +} + /** * Check current stack pointer * @@ -272,6 +308,72 @@ flsll_okx ( long long value, int msb, const char *file, unsigned int line ) { } #define flsll_ok( value, msb ) flsll_okx ( value, msb, __FILE__, __LINE__ ) +/** + * Report a 64-bit shift left test result + * + * @v value Value + * @v shift Shift amount + * @v expected Expected value + * @v file Test code file + * @v line Test code line + */ +static inline __attribute__ (( always_inline )) void +lsl64_okx ( uint64_t value, unsigned int shift, uint64_t expected, + const char *file, unsigned int line ) { + + /* Verify as a compile-time calculation */ + okx ( ( value << shift ) == expected, file, line ); + + /* Verify as a runtime calculation */ + okx ( lsl64_var ( value, shift ) == expected, file, line ); +} +#define lsl64_ok( value, shift, expected ) \ + lsl64_okx ( value, shift, expected, __FILE__, __LINE__ ) + +/** + * Report a 64-bit logical shift right test result + * + * @v value Value + * @v shift Shift amount + * @v expected Expected value + * @v file Test code file + * @v line Test code line + */ +static inline __attribute__ (( always_inline )) void +lsr64_okx ( uint64_t value, unsigned int shift, uint64_t expected, + const char *file, unsigned int line ) { + + /* Verify as a compile-time calculation */ + okx ( ( value >> shift ) == expected, file, line ); + + /* Verify as a runtime calculation */ + okx ( lsr64_var ( value, shift ) == expected, file, line ); +} +#define lsr64_ok( value, shift, expected ) \ + lsr64_okx ( value, shift, expected, __FILE__, __LINE__ ) + +/** + * Report a 64-bit arithmetic shift right test result + * + * @v value Value + * @v shift Shift amount + * @v expected Expected value + * @v file Test code file + * @v line Test code line + */ +static inline __attribute__ (( always_inline )) void +asr64_okx ( int64_t value, unsigned int shift, int64_t expected, + const char *file, unsigned int line ) { + + /* Verify as a compile-time calculation */ + okx ( ( value >> shift ) == expected, file, line ); + + /* Verify as a runtime calculation */ + okx ( asr64_var ( value, shift ) == expected, file, line ); +} +#define asr64_ok( value, shift, expected ) \ + asr64_okx ( value, shift, expected, __FILE__, __LINE__ ) + /** * Report a 64-bit unsigned integer division test result * @@ -375,6 +477,21 @@ static void math_test_exec ( void ) { * etc. (including checking that the implicit calling * convention assumed by gcc matches our expectations). */ + lsl64_ok ( 0x06760c14710540c2ULL, 0, 0x06760c14710540c2ULL ); + lsr64_ok ( 0x06760c14710540c2ULL, 0, 0x06760c14710540c2ULL ); + asr64_ok ( 0x06760c14710540c2ULL, 0, 0x06760c14710540c2ULL ); + lsl64_ok ( 0xccafd1a8cb724c13ULL, 20, 0x1a8cb724c1300000ULL ); + lsr64_ok ( 0xccafd1a8cb724c13ULL, 20, 0x00000ccafd1a8cb7ULL ); + asr64_ok ( 0xccafd1a8cb724c13ULL, 20, 0xfffffccafd1a8cb7ULL ); + lsl64_ok ( 0x83567264b1234518ULL, 32, 0xb123451800000000ULL ); + lsr64_ok ( 0x83567264b1234518ULL, 32, 0x0000000083567264ULL ); + asr64_ok ( 0x83567264b1234518ULL, 32, 0xffffffff83567264ULL ); + lsl64_ok ( 0x69ee42fcbf1a4ea4ULL, 47, 0x2752000000000000ULL ); + lsr64_ok ( 0x69ee42fcbf1a4ea4ULL, 47, 0x000000000000d3dcULL ); + asr64_ok ( 0x69ee42fcbf1a4ea4ULL, 47, 0x000000000000d3dcULL ); + lsl64_ok ( 0xaa20b8caddee4269ULL, 63, 0x8000000000000000ULL ); + lsr64_ok ( 0xaa20b8caddee4269ULL, 63, 0x0000000000000001ULL ); + asr64_ok ( 0xaa20b8caddee4269ULL, 63, 0xffffffffffffffffULL ); u64divmod_ok ( 0x2b90ddccf699f765ULL, 0xed9f5e73ULL, 0x2eef6ab4ULL, 0x0e12f089ULL ); s64divmod_ok ( 0x2b90ddccf699f765ULL, 0xed9f5e73ULL, -- cgit v1.2.3-55-g7522 From 3def13265d9475c861eed1a101584b761e97ae33 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 19 Sep 2024 16:23:32 +0100 Subject: [crypto] Use constant-time big integer multiplication Big integer multiplication currently performs immediate carry propagation from each step of the long multiplication, relying on the fact that the overall result has a known maximum value to minimise the number of carries performed without ever needing to explicitly check against the result buffer size. This is not a constant-time algorithm, since the number of carries performed will be a function of the input values. We could make it constant-time by always continuing to propagate the carry until reaching the end of the result buffer, but this would introduce a large number of redundant zero carries. Require callers of bigint_multiply() to provide a temporary carry storage buffer, of the same size as the result buffer. This allows the carry-out from the accumulation of each double-element product to be accumulated in the temporary carry space, and then added in via a single call to bigint_add() after the multiplication is complete. Since the structure of big integer multiplication is identical across all current CPU architectures, provide a single shared implementation of bigint_multiply(). The architecture-specific operation then becomes the multiplication of two big integer elements and the accumulation of the double-element product. Note that any intermediate carry arising from accumulating the lower half of the double-element product may be added to the upper half of the double-element product without risk of overflow, since the result of multiplying two n-bit integers can never have all n bits set in its upper half. This simplifies the carry calculations for architectures such as RISC-V and LoongArch64 that do not have a carry flag. Signed-off-by: Michael Brown --- src/arch/arm32/core/arm32_bigint.c | 106 ---------------------------- src/arch/arm32/include/bits/bigint.h | 34 +++++++-- src/arch/arm64/core/arm64_bigint.c | 107 ---------------------------- src/arch/arm64/include/bits/bigint.h | 35 ++++++++-- src/arch/loong64/core/loong64_bigint.c | 124 --------------------------------- src/arch/loong64/include/bits/bigint.h | 42 +++++++++-- src/arch/riscv/core/riscv_bigint.c | 112 ----------------------------- src/arch/riscv/include/bits/bigint.h | 43 ++++++++++-- src/arch/x86/core/x86_bigint.c | 100 -------------------------- src/arch/x86/include/bits/bigint.h | 34 +++++++-- src/crypto/bigint.c | 117 ++++++++++++++++++++++++++++++- src/crypto/x25519.c | 83 ++++++++++++++-------- src/include/ipxe/bigint.h | 18 +++-- src/tests/bigint_test.c | 12 +++- 14 files changed, 355 insertions(+), 612 deletions(-) delete mode 100644 src/arch/arm32/core/arm32_bigint.c delete mode 100644 src/arch/arm64/core/arm64_bigint.c delete mode 100644 src/arch/loong64/core/loong64_bigint.c delete mode 100644 src/arch/riscv/core/riscv_bigint.c delete mode 100644 src/arch/x86/core/x86_bigint.c (limited to 'src/tests') diff --git a/src/arch/arm32/core/arm32_bigint.c b/src/arch/arm32/core/arm32_bigint.c deleted file mode 100644 index 29fb40a7c..000000000 --- a/src/arch/arm32/core/arm32_bigint.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2016 Michael Brown . - * - * 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 -#include -#include - -/** @file - * - * Big integer support - */ - -/** - * Multiply big integers - * - * @v multiplicand0 Element 0 of big integer to be multiplied - * @v multiplicand_size Number of elements in multiplicand - * @v multiplier0 Element 0 of big integer to be multiplied - * @v multiplier_size Number of elements in multiplier - * @v result0 Element 0 of big integer to hold result - */ -void bigint_multiply_raw ( const uint32_t *multiplicand0, - unsigned int multiplicand_size, - const uint32_t *multiplier0, - unsigned int multiplier_size, - uint32_t *result0 ) { - unsigned int result_size = ( multiplicand_size + multiplier_size ); - const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) - *multiplicand = ( ( const void * ) multiplicand0 ); - const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) - *multiplier = ( ( const void * ) multiplier0 ); - bigint_t ( result_size ) __attribute__ (( may_alias )) - *result = ( ( void * ) result0 ); - unsigned int i; - unsigned int j; - uint32_t multiplicand_element; - uint32_t multiplier_element; - uint32_t *result_elements; - uint32_t discard_low; - uint32_t discard_high; - uint32_t discard_temp; - - /* Zero result */ - memset ( result, 0, sizeof ( *result ) ); - - /* Multiply integers one element at a time */ - for ( i = 0 ; i < multiplicand_size ; i++ ) { - multiplicand_element = multiplicand->element[i]; - for ( j = 0 ; j < multiplier_size ; j++ ) { - multiplier_element = multiplier->element[j]; - result_elements = &result->element[ i + j ]; - /* Perform a single multiply, and add the - * resulting double-element into the result, - * carrying as necessary. The carry can - * never overflow beyond the end of the - * result, since: - * - * a < 2^{n}, b < 2^{m} => ab < 2^{n+m} - */ - __asm__ __volatile__ ( "umull %1, %2, %5, %6\n\t" - "ldr %3, [%0]\n\t" - "adds %3, %1\n\t" - "stmia %0!, {%3}\n\t" - "ldr %3, [%0]\n\t" - "adcs %3, %2\n\t" - "stmia %0!, {%3}\n\t" - "bcc 2f\n\t" - "\n1:\n\t" - "ldr %3, [%0]\n\t" - "adcs %3, #0\n\t" - "stmia %0!, {%3}\n\t" - "bcs 1b\n\t" - "\n2:\n\t" - : "+l" ( result_elements ), - "=l" ( discard_low ), - "=l" ( discard_high ), - "=l" ( discard_temp ), - "+m" ( *result ) - : "l" ( multiplicand_element ), - "l" ( multiplier_element ) - : "cc" ); - } - } -} diff --git a/src/arch/arm32/include/bits/bigint.h b/src/arch/arm32/include/bits/bigint.h index e4b511da7..0a368a0c0 100644 --- a/src/arch/arm32/include/bits/bigint.h +++ b/src/arch/arm32/include/bits/bigint.h @@ -309,10 +309,34 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused, *(--out_byte) = *(value_byte++); } -extern void bigint_multiply_raw ( const uint32_t *multiplicand0, - unsigned int multiplicand_size, - const uint32_t *multiplier0, - unsigned int multiplier_size, - uint32_t *value0 ); +/** + * Multiply big integer elements + * + * @v multiplicand Multiplicand element + * @v multiplier Multiplier element + * @v result Result element pair + * @v carry Carry element + */ +static inline __attribute__ (( always_inline )) void +bigint_multiply_one ( const uint32_t multiplicand, const uint32_t multiplier, + uint32_t *result, uint32_t *carry ) { + uint32_t discard_low; + uint32_t discard_high; + + __asm__ __volatile__ ( /* Perform multiplication */ + "umull %0, %1, %5, %6\n\t" + /* Accumulate result */ + "adds %2, %0\n\t" + "adcs %3, %1\n\t" + /* Accumulate carry (cannot overflow) */ + "adc %4, #0\n\t" + : "=r" ( discard_low ), + "=r" ( discard_high ), + "+r" ( result[0] ), + "+r" ( result[1] ), + "+r" ( *carry ) + : "r" ( multiplicand ), + "r" ( multiplier ) ); +} #endif /* _BITS_BIGINT_H */ diff --git a/src/arch/arm64/core/arm64_bigint.c b/src/arch/arm64/core/arm64_bigint.c deleted file mode 100644 index 7740f1aef..000000000 --- a/src/arch/arm64/core/arm64_bigint.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (C) 2016 Michael Brown . - * - * 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 -#include -#include - -/** @file - * - * Big integer support - */ - -/** - * Multiply big integers - * - * @v multiplicand0 Element 0 of big integer to be multiplied - * @v multiplicand_size Number of elements in multiplicand - * @v multiplier0 Element 0 of big integer to be multiplied - * @v multiplier_size Number of elements in multiplier - * @v result0 Element 0 of big integer to hold result - */ -void bigint_multiply_raw ( const uint64_t *multiplicand0, - unsigned int multiplicand_size, - const uint64_t *multiplier0, - unsigned int multiplier_size, - uint64_t *result0 ) { - unsigned int result_size = ( multiplicand_size + multiplier_size ); - const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) - *multiplicand = ( ( const void * ) multiplicand0 ); - const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) - *multiplier = ( ( const void * ) multiplier0 ); - bigint_t ( result_size ) __attribute__ (( may_alias )) - *result = ( ( void * ) result0 ); - unsigned int i; - unsigned int j; - uint64_t multiplicand_element; - uint64_t multiplier_element; - uint64_t *result_elements; - uint64_t discard_low; - uint64_t discard_high; - uint64_t discard_temp_low; - uint64_t discard_temp_high; - - /* Zero result */ - memset ( result, 0, sizeof ( *result ) ); - - /* Multiply integers one element at a time */ - for ( i = 0 ; i < multiplicand_size ; i++ ) { - multiplicand_element = multiplicand->element[i]; - for ( j = 0 ; j < multiplier_size ; j++ ) { - multiplier_element = multiplier->element[j]; - result_elements = &result->element[ i + j ]; - /* Perform a single multiply, and add the - * resulting double-element into the result, - * carrying as necessary. The carry can - * never overflow beyond the end of the - * result, since: - * - * a < 2^{n}, b < 2^{m} => ab < 2^{n+m} - */ - __asm__ __volatile__ ( "mul %1, %6, %7\n\t" - "umulh %2, %6, %7\n\t" - "ldp %3, %4, [%0]\n\t" - "adds %3, %3, %1\n\t" - "adcs %4, %4, %2\n\t" - "stp %3, %4, [%0], #16\n\t" - "bcc 2f\n\t" - "\n1:\n\t" - "ldr %3, [%0]\n\t" - "adcs %3, %3, xzr\n\t" - "str %3, [%0], #8\n\t" - "bcs 1b\n\t" - "\n2:\n\t" - : "+r" ( result_elements ), - "=&r" ( discard_low ), - "=&r" ( discard_high ), - "=r" ( discard_temp_low ), - "=r" ( discard_temp_high ), - "+m" ( *result ) - : "r" ( multiplicand_element ), - "r" ( multiplier_element ) - : "cc" ); - } - } -} diff --git a/src/arch/arm64/include/bits/bigint.h b/src/arch/arm64/include/bits/bigint.h index 0d08bbd65..ca9feafbe 100644 --- a/src/arch/arm64/include/bits/bigint.h +++ b/src/arch/arm64/include/bits/bigint.h @@ -310,10 +310,35 @@ bigint_done_raw ( const uint64_t *value0, unsigned int size __unused, *(--out_byte) = *(value_byte++); } -extern void bigint_multiply_raw ( const uint64_t *multiplicand0, - unsigned int multiplicand_size, - const uint64_t *multiplier0, - unsigned int multiplier_size, - uint64_t *value0 ); +/** + * Multiply big integer elements + * + * @v multiplicand Multiplicand element + * @v multiplier Multiplier element + * @v result Result element pair + * @v carry Carry element + */ +static inline __attribute__ (( always_inline )) void +bigint_multiply_one ( const uint64_t multiplicand, const uint64_t multiplier, + uint64_t *result, uint64_t *carry ) { + uint64_t discard_low; + uint64_t discard_high; + + __asm__ __volatile__ ( /* Perform multiplication */ + "mul %0, %5, %6\n\t" + "umulh %1, %5, %6\n\t" + /* Accumulate result */ + "adds %2, %2, %0\n\t" + "adcs %3, %3, %1\n\t" + /* Accumulate carry (cannot overflow) */ + "adc %4, %4, xzr\n\t" + : "=&r" ( discard_low ), + "=r" ( discard_high ), + "+r" ( result[0] ), + "+r" ( result[1] ), + "+r" ( *carry ) + : "r" ( multiplicand ), + "r" ( multiplier ) ); +} #endif /* _BITS_BIGINT_H */ diff --git a/src/arch/loong64/core/loong64_bigint.c b/src/arch/loong64/core/loong64_bigint.c deleted file mode 100644 index b428e22c3..000000000 --- a/src/arch/loong64/core/loong64_bigint.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2012 Michael Brown . - * Copyright (c) 2023, Xiaotian Wu - * - * 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 -#include -#include - -/** @file - * - * Big integer support - */ - -/** - * Multiply big integers - * - * @v multiplicand0 Element 0 of big integer to be multiplied - * @v multiplicand_size Number of elements in multiplicand - * @v multiplier0 Element 0 of big integer to be multiplied - * @v multiplier_size Number of elements in multiplier - * @v result0 Element 0 of big integer to hold result - */ -void bigint_multiply_raw ( const uint64_t *multiplicand0, - unsigned int multiplicand_size, - const uint64_t *multiplier0, - unsigned int multiplier_size, - uint64_t *result0 ) { - unsigned int result_size = ( multiplicand_size + multiplier_size ); - const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) - *multiplicand = ( ( const void * ) multiplicand0 ); - const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) - *multiplier = ( ( const void * ) multiplier0 ); - bigint_t ( result_size ) __attribute__ (( may_alias )) - *result = ( ( void * ) result0 ); - unsigned int i; - unsigned int j; - uint64_t multiplicand_element; - uint64_t multiplier_element; - uint64_t *result_elements; - uint64_t discard_low; - uint64_t discard_high; - uint64_t discard_temp_low; - uint64_t discard_temp_high; - - /* Zero result */ - memset ( result, 0, sizeof ( *result ) ); - - /* Multiply integers one element at a time */ - for ( i = 0 ; i < multiplicand_size ; i++ ) { - multiplicand_element = multiplicand->element[i]; - for ( j = 0 ; j < multiplier_size ; j++ ) { - multiplier_element = multiplier->element[j]; - result_elements = &result->element[ i + j ]; - /* Perform a single multiply, and add the - * resulting double-element into the result, - * carrying as necessary. The carry can - * never overflow beyond the end of the - * result, since: - * - * a < 2^{n}, b < 2^{m} => ab < 2^{n+m} - */ - __asm__ __volatile__ ( "mul.d %1, %6, %7\n\t" - "mulh.du %2, %6, %7\n\t" - - "ld.d %3, %0, 0\n\t" - "ld.d %4, %0, 8\n\t" - - "add.d %3, %3, %1\n\t" - "sltu $t0, %3, %1\n\t" - - "add.d %4, %4, %2\n\t" - "sltu $t1, %4, %2\n\t" - - "add.d %4, %4, $t0\n\t" - "sltu $t0, %4, $t0\n\t" - "or $t0, $t0, $t1\n\t" - - "st.d %3, %0, 0\n\t" - "st.d %4, %0, 8\n\t" - - "addi.d %0, %0, 16\n\t" - "beqz $t0, 2f\n" - "1:\n\t" - "ld.d %3, %0, 0\n\t" - "add.d %3, %3, $t0\n\t" - "sltu $t0, %3, $t0\n\t" - "st.d %3, %0, 0\n\t" - "addi.d %0, %0, 8\n\t" - "bnez $t0, 1b\n" - "2:" - : "+r" ( result_elements ), - "=&r" ( discard_low ), - "=&r" ( discard_high ), - "=r" ( discard_temp_low ), - "=r" ( discard_temp_high ), - "+m" ( *result ) - : "r" ( multiplicand_element ), - "r" ( multiplier_element ) - : "t0", "t1" ); - } - } -} diff --git a/src/arch/loong64/include/bits/bigint.h b/src/arch/loong64/include/bits/bigint.h index bec748beb..ec6ca4b89 100644 --- a/src/arch/loong64/include/bits/bigint.h +++ b/src/arch/loong64/include/bits/bigint.h @@ -357,10 +357,42 @@ bigint_done_raw ( const uint64_t *value0, unsigned int size __unused, *(--out_byte) = *(value_byte++); } -extern void bigint_multiply_raw ( const uint64_t *multiplicand0, - unsigned int multiplicand_size, - const uint64_t *multiplier0, - unsigned int multiplier_size, - uint64_t *value0 ); +/** + * Multiply big integer elements + * + * @v multiplicand Multiplicand element + * @v multiplier Multiplier element + * @v result Result element pair + * @v carry Carry element + */ +static inline __attribute__ (( always_inline )) void +bigint_multiply_one ( const uint64_t multiplicand, const uint64_t multiplier, + uint64_t *result, uint64_t *carry ) { + uint64_t discard_low; + uint64_t discard_high; + uint64_t discard_carry; + + __asm__ __volatile__ ( /* Perform multiplication */ + "mul.d %0, %6, %7\n\t" + "mulh.du %1, %6, %7\n\t" + /* Accumulate low half */ + "add.d %3, %3, %0\n\t" + "sltu %2, %3, %0\n\t" + /* Add carry to high half (cannot overflow) */ + "add.d %1, %1, %2\n\t" + /* Accumulate high half */ + "add.d %4, %4, %1\n\t" + "sltu %2, %4, %1\n\t" + /* Accumulate carry (cannot overflow) */ + "add.d %5, %5, %2\n\t" + : "=&r" ( discard_low ), + "=r" ( discard_high ), + "=r" ( discard_carry ), + "+r" ( result[0] ), + "+r" ( result[1] ), + "+r" ( *carry ) + : "r" ( multiplicand ), + "r" ( multiplier ) ); +} #endif /* _BITS_BIGINT_H */ diff --git a/src/arch/riscv/core/riscv_bigint.c b/src/arch/riscv/core/riscv_bigint.c deleted file mode 100644 index cbc5631a3..000000000 --- a/src/arch/riscv/core/riscv_bigint.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2024 Michael Brown - * - * 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 -#include -#include - -/** @file - * - * Big integer support - */ - -/** - * Multiply big integers - * - * @v multiplicand0 Element 0 of big integer to be multiplied - * @v multiplicand_size Number of elements in multiplicand - * @v multiplier0 Element 0 of big integer to be multiplied - * @v multiplier_size Number of elements in multiplier - * @v result0 Element 0 of big integer to hold result - */ -void bigint_multiply_raw ( const unsigned long *multiplicand0, - unsigned int multiplicand_size, - const unsigned long *multiplier0, - unsigned int multiplier_size, - unsigned long *result0 ) { - unsigned int result_size = ( multiplicand_size + multiplier_size ); - const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) - *multiplicand = ( ( const void * ) multiplicand0 ); - const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) - *multiplier = ( ( const void * ) multiplier0 ); - bigint_t ( result_size ) __attribute__ (( may_alias )) - *result = ( ( void * ) result0 ); - unsigned int i; - unsigned int j; - unsigned long multiplicand_element; - unsigned long multiplier_element; - unsigned long *result_elements; - unsigned long discard_low; - unsigned long discard_high; - unsigned long discard_temp; - unsigned long discard_carry; - - /* Zero result */ - memset ( result, 0, sizeof ( *result ) ); - - /* Multiply integers one element at a time */ - for ( i = 0 ; i < multiplicand_size ; i++ ) { - multiplicand_element = multiplicand->element[i]; - for ( j = 0 ; j < multiplier_size ; j++ ) { - multiplier_element = multiplier->element[j]; - result_elements = &result->element[ i + j ]; - /* Perform a single multiply, and add the - * resulting double-element into the result, - * carrying as necessary. The carry can - * never overflow beyond the end of the - * result, since: - * - * a < 2^{n}, b < 2^{m} => ab < 2^{n+m} - */ - __asm__ __volatile__ ( /* Perform multiplication */ - "mulhu %2, %6, %7\n\t" - "mul %1, %6, %7\n\t" - /* Accumulate low half */ - LOADN " %3, (%0)\n\t" - "add %3, %3, %1\n\t" - "sltu %4, %3, %1\n\t" - STOREN " %3, 0(%0)\n\t" - /* Carry into high half */ - "add %4, %4, %2\n\t" - /* Propagate as necessary */ - "\n1:\n\t" - "addi %0, %0, %8\n\t" - LOADN " %3, 0(%0)\n\t" - "add %3, %3, %4\n\t" - "sltu %4, %3, %4\n\t" - STOREN " %3, 0(%0)\n\t" - "bnez %4, 1b\n\t" - : "+r" ( result_elements ), - "=r" ( discard_low ), - "=r" ( discard_high ), - "=r" ( discard_temp ), - "=r" ( discard_carry ), - "+m" ( *result ) - : "r" ( multiplicand_element ), - "r" ( multiplier_element ), - "i" ( sizeof ( *result0 ) ) ); - } - } -} diff --git a/src/arch/riscv/include/bits/bigint.h b/src/arch/riscv/include/bits/bigint.h index fcc0d51c3..c58233469 100644 --- a/src/arch/riscv/include/bits/bigint.h +++ b/src/arch/riscv/include/bits/bigint.h @@ -353,10 +353,43 @@ bigint_done_raw ( const unsigned long *value0, unsigned int size __unused, *(--out_byte) = *(value_byte++); } -extern void bigint_multiply_raw ( const unsigned long *multiplicand0, - unsigned int multiplicand_size, - const unsigned long *multiplier0, - unsigned int multiplier_size, - unsigned long *value0 ); +/** + * Multiply big integer elements + * + * @v multiplicand Multiplicand element + * @v multiplier Multiplier element + * @v result Result element pair + * @v carry Carry element + */ +static inline __attribute__ (( always_inline )) void +bigint_multiply_one ( const unsigned long multiplicand, + const unsigned long multiplier, + unsigned long *result, unsigned long *carry ) { + unsigned long discard_low; + unsigned long discard_high; + unsigned long discard_carry; + + __asm__ __volatile__ ( /* Perform multiplication */ + "mulhu %1, %6, %7\n\t" + "mul %0, %6, %7\n\t" + /* Accumulate low half */ + "add %3, %3, %0\n\t" + "sltu %2, %3, %0\n\t" + /* Add carry to high half (cannot overflow) */ + "add %1, %1, %2\n\t" + /* Accumulate high half */ + "add %4, %4, %1\n\t" + "sltu %2, %4, %1\n\t" + /* Accumulate carry (cannot overflow) */ + "add %5, %5, %2\n\t" + : "=r" ( discard_low ), + "=&r" ( discard_high ), + "=r" ( discard_carry ), + "+r" ( result[0] ), + "+r" ( result[1] ), + "+r" ( *carry ) + : "r" ( multiplicand ), + "r" ( multiplier ) ); +} #endif /* _BITS_BIGINT_H */ diff --git a/src/arch/x86/core/x86_bigint.c b/src/arch/x86/core/x86_bigint.c deleted file mode 100644 index 74e5da9a2..000000000 --- a/src/arch/x86/core/x86_bigint.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2012 Michael Brown . - * - * 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 -#include -#include - -/** @file - * - * Big integer support - */ - -/** - * Multiply big integers - * - * @v multiplicand0 Element 0 of big integer to be multiplied - * @v multiplicand_size Number of elements in multiplicand - * @v multiplier0 Element 0 of big integer to be multiplied - * @v multiplier_size Number of elements in multiplier - * @v result0 Element 0 of big integer to hold result - */ -void bigint_multiply_raw ( const uint32_t *multiplicand0, - unsigned int multiplicand_size, - const uint32_t *multiplier0, - unsigned int multiplier_size, - uint32_t *result0 ) { - unsigned int result_size = ( multiplicand_size + multiplier_size ); - const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) - *multiplicand = ( ( const void * ) multiplicand0 ); - const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) - *multiplier = ( ( const void * ) multiplier0 ); - bigint_t ( result_size ) __attribute__ (( may_alias )) - *result = ( ( void * ) result0 ); - unsigned int i; - unsigned int j; - uint32_t multiplicand_element; - uint32_t multiplier_element; - uint32_t *result_elements; - uint32_t discard_a; - uint32_t discard_d; - long index; - - /* Zero result */ - memset ( result, 0, sizeof ( *result ) ); - - /* Multiply integers one element at a time */ - for ( i = 0 ; i < multiplicand_size ; i++ ) { - multiplicand_element = multiplicand->element[i]; - for ( j = 0 ; j < multiplier_size ; j++ ) { - multiplier_element = multiplier->element[j]; - result_elements = &result->element[ i + j ]; - /* Perform a single multiply, and add the - * resulting double-element into the result, - * carrying as necessary. The carry can - * never overflow beyond the end of the - * result, since: - * - * a < 2^{n}, b < 2^{m} => ab < 2^{n+m} - */ - __asm__ __volatile__ ( "mull %5\n\t" - "addl %%eax, (%6,%2,4)\n\t" - "adcl %%edx, 4(%6,%2,4)\n\t" - "\n1:\n\t" - "adcl $0, 8(%6,%2,4)\n\t" - "inc %2\n\t" - /* Does not affect CF */ - "jc 1b\n\t" - : "=&a" ( discard_a ), - "=&d" ( discard_d ), - "=&r" ( index ), - "+m" ( *result ) - : "0" ( multiplicand_element ), - "g" ( multiplier_element ), - "r" ( result_elements ), - "2" ( 0 ) ); - } - } -} diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h index a6bc2ca1d..a481e90f7 100644 --- a/src/arch/x86/include/bits/bigint.h +++ b/src/arch/x86/include/bits/bigint.h @@ -322,10 +322,34 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused, : "eax" ); } -extern void bigint_multiply_raw ( const uint32_t *multiplicand0, - unsigned int multiplicand_size, - const uint32_t *multiplier0, - unsigned int multiplier_size, - uint32_t *value0 ); +/** + * Multiply big integer elements + * + * @v multiplicand Multiplicand element + * @v multiplier Multiplier element + * @v result Result element pair + * @v carry Carry element + */ +static inline __attribute__ (( always_inline )) void +bigint_multiply_one ( const uint32_t multiplicand, const uint32_t multiplier, + uint32_t *result, uint32_t *carry ) { + uint32_t discard_a; + uint32_t discard_d; + + __asm__ __volatile__ ( /* Perform multiplication */ + "mull %6\n\t" + /* Accumulate result */ + "addl %0, %2\n\t" + "adcl %1, %3\n\t" + /* Accumulate carry (cannot overflow) */ + "adcl $0, %4\n\t" + : "=a" ( discard_a ), + "=d" ( discard_d ), + "+m" ( result[0] ), + "+m" ( result[1] ), + "+m" ( *carry ) + : "0" ( multiplicand ), + "g" ( multiplier ) ); +} #endif /* _BITS_BIGINT_H */ diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index 656f979e5..5b7116e28 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -75,6 +75,115 @@ void bigint_swap_raw ( bigint_element_t *first0, bigint_element_t *second0, } } +/** + * Multiply big integers + * + * @v multiplicand0 Element 0 of big integer to be multiplied + * @v multiplicand_size Number of elements in multiplicand + * @v multiplier0 Element 0 of big integer to be multiplied + * @v multiplier_size Number of elements in multiplier + * @v result0 Element 0 of big integer to hold result + * @v carry0 Element 0 of big integer to hold temporary carry + */ +void bigint_multiply_raw ( const bigint_element_t *multiplicand0, + unsigned int multiplicand_size, + const bigint_element_t *multiplier0, + unsigned int multiplier_size, + bigint_element_t *result0, + bigint_element_t *carry0 ) { + unsigned int result_size = ( multiplicand_size + multiplier_size ); + const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) + *multiplicand = ( ( const void * ) multiplicand0 ); + const bigint_t ( multiplier_size ) __attribute__ (( may_alias )) + *multiplier = ( ( const void * ) multiplier0 ); + bigint_t ( result_size ) __attribute__ (( may_alias )) + *result = ( ( void * ) result0 ); + bigint_t ( result_size ) __attribute__ (( may_alias )) + *carry = ( ( void * ) carry0 ); + bigint_element_t multiplicand_element; + const bigint_element_t *multiplier_element; + bigint_element_t *result_elements; + bigint_element_t *carry_element; + unsigned int i; + unsigned int j; + + /* Zero result and temporary carry space */ + memset ( result, 0, sizeof ( *result ) ); + memset ( carry, 0, sizeof ( *carry ) ); + + /* Multiply integers one element at a time, adding the double + * element directly into the result and accumulating any + * overall carry out from this double-element addition into + * the temporary carry space. + * + * We could propagate the carry immediately instead of using a + * temporary carry space. However, this would cause the + * multiplication to run in non-constant time, which is + * undesirable. + * + * The carry elements can never overflow, provided that the + * element size is large enough to accommodate any plausible + * big integer. The total number of potential carries (across + * all elements) is the sum of the number of elements in the + * multiplicand and multiplier. With a 16-bit element size, + * this therefore allows for up to a 1Mbit multiplication + * result (e.g. a 512kbit integer multiplied by another + * 512kbit integer), which is around 100x higher than could be + * needed in practice. With a more realistic 32-bit element + * size, the limit becomes a totally implausible 128Gbit + * multiplication result. + */ + for ( i = 0 ; i < multiplicand_size ; i++ ) { + multiplicand_element = multiplicand->element[i]; + multiplier_element = &multiplier->element[0]; + result_elements = &result->element[i]; + carry_element = &carry->element[i]; + for ( j = 0 ; j < multiplier_size ; j++ ) { + bigint_multiply_one ( multiplicand_element, + *(multiplier_element++), + result_elements++, + carry_element++ ); + } + } + + /* Add the temporary carry into the result. The least + * significant element of the carry represents the carry out + * from multiplying the least significant elements of the + * multiplicand and multiplier, and therefore must be added to + * the third-least significant element of the result (i.e. the + * carry needs to be shifted left by two elements before being + * adding to the result). + * + * The most significant two elements of the carry are + * guaranteed to be zero, since: + * + * a < 2^{n}, b < 2^{m} => ab < 2^{n+m} + * + * and the overall result of the multiplication (including + * adding in the shifted carries) is therefore guaranteed not + * to overflow beyond the end of the result. + * + * We could avoid this shifting by writing the carry directly + * into the "correct" element during the element-by-element + * multiplication stage above. However, this would add + * complexity to the loop since we would have to arrange for + * the (provably zero) most significant two carry out results + * to be discarded, in order to avoid writing beyond the end + * of the temporary carry space. + * + * Performing the logical shift is essentially free, since we + * simply adjust the element pointers. + * + * To avoid requiring additional checks in each architecture's + * implementation of bigint_add_raw(), we explicitly avoid + * calling bigint_add_raw() with a size of zero. + */ + if ( result_size > 2 ) { + bigint_add_raw ( &carry->element[0], &result->element[2], + ( result_size - 2 ) ); + } +} + /** * Perform modular multiplication of big integers * @@ -100,7 +209,10 @@ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, ( ( void * ) result0 ); struct { bigint_t ( size * 2 ) result; - bigint_t ( size * 2 ) modulus; + union { + bigint_t ( size * 2 ) modulus; + bigint_t ( size * 2 ) carry; + }; } *temp = tmp; int rotation; int i; @@ -113,7 +225,8 @@ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, /* Perform multiplication */ profile_start ( &bigint_mod_multiply_multiply_profiler ); - bigint_multiply ( multiplicand, multiplier, &temp->result ); + bigint_multiply ( multiplicand, multiplier, &temp->result, + &temp->carry ); profile_stop ( &bigint_mod_multiply_multiply_profiler ); /* Rescale modulus to match result */ diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c index d58f7168c..553f43d34 100644 --- a/src/crypto/x25519.c +++ b/src/crypto/x25519.c @@ -43,7 +43,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Storage size of each big integer 128 40 * (in bytes) * - * Stack usage for key exchange 1144 360 + * Stack usage for key exchange 1144 424 * (in bytes, large objects only) * * Cost of big integer addition 16 5 @@ -207,35 +207,60 @@ union x25519_multiply_step3 { * We overlap the buffers used by each step of the multiplication * calculation to reduce the total stack space required: * - * |--------------------------------------------------------| - * | <- pad -> | <------------ step 1 result -------------> | - * | | <- low 256 bits -> | <-- high 260 bits --> | - * | <------- step 2 result ------> | <-- step 3 result --> | - * |--------------------------------------------------------| + * |--------------------------------------------------------------------------| + * | <------- step 1 carry ------> | <----------- step 1 result ------------> | + * | | <- low 256 bits -> | <- high 260 bits -> | + * | <- step 2 carry -> | <-- step 2 result --> | | | + * | <- s3 carry -> | <--------- pad ---------> | <- step 3 result -> | | + * |--------------------------------------------------------------------------| */ union x25519_multiply_workspace { - /** Step 1 result */ + /** Step 1 */ struct { - /** Padding to avoid collision between steps 1 and 2 - * - * The step 2 multiplication consumes the high 260 - * bits of step 1, and so the step 2 multiplication - * result must not overlap this portion of the step 1 - * result. - */ - uint8_t pad[ sizeof ( union x25519_multiply_step2 ) - - offsetof ( union x25519_multiply_step1, - parts.high_260bit ) ]; + /** Step 1 temporary carry workspace */ + union x25519_multiply_step1 carry; /** Step 1 result */ - union x25519_multiply_step1 step1; - } __attribute__ (( packed )); - /** Steps 2 and 3 results */ + union x25519_multiply_step1 result; + } __attribute__ (( packed )) step1; + /** Step 2 + * + * The step 2 multiplication consumes the high 260 bits of + * step 1, and so the step 2 multiplication result (and + * temporary carry workspace) must not overlap this portion of + * the step 1 result. + */ struct { + /** Step 2 temporary carry workspace */ + union x25519_multiply_step2 carry; /** Step 2 result */ - union x25519_multiply_step2 step2; + union x25519_multiply_step2 result; + /** Avoid collision between step 1 result and step 2 result */ + uint8_t pad[ ( int ) + ( sizeof ( union x25519_multiply_step1 ) + + offsetof ( union x25519_multiply_step1, + parts.high_260bit ) - + sizeof ( union x25519_multiply_step2 ) - + sizeof ( union x25519_multiply_step2 ) ) ]; + } __attribute__ (( packed )) step2; + /** Step 3 + * + * The step 3 multiplication consumes the high 11 bits of step + * 2, and so the step 3 multiplication result (and temporary + * carry workspace) must not overlap this portion of the step + * 2 result. + */ + struct { + /** Step 3 temporary carry workspace */ + union x25519_multiply_step3 carry; + /** Avoid collision between step 2 result and step 3 carry */ + uint8_t pad1[ ( int ) + ( sizeof ( union x25519_multiply_step2 ) - + sizeof ( union x25519_multiply_step3 ) ) ]; + /** Avoid collision between step 2 result and step 3 result */ + uint8_t pad2[ sizeof ( union x25519_multiply_step2 ) ]; /** Step 3 result */ - union x25519_multiply_step3 step3; - } __attribute__ (( packed )); + union x25519_multiply_step3 result; + } __attribute__ (( packed )) step3; }; /** An X25519 elliptic curve point in projective coordinates @@ -426,9 +451,9 @@ void x25519_multiply ( const union x25519_oct258 *multiplicand, const union x25519_oct258 *multiplier, union x25519_quad257 *result ) { union x25519_multiply_workspace tmp; - union x25519_multiply_step1 *step1 = &tmp.step1; - union x25519_multiply_step2 *step2 = &tmp.step2; - union x25519_multiply_step3 *step3 = &tmp.step3; + union x25519_multiply_step1 *step1 = &tmp.step1.result; + union x25519_multiply_step2 *step2 = &tmp.step2.result; + union x25519_multiply_step3 *step3 = &tmp.step3.result; /* Step 1: perform raw multiplication * @@ -439,7 +464,7 @@ void x25519_multiply ( const union x25519_oct258 *multiplicand, */ static_assert ( sizeof ( step1->product ) >= sizeof ( step1->parts ) ); bigint_multiply ( &multiplicand->value, &multiplier->value, - &step1->product ); + &step1->product, &tmp.step1.carry.product ); /* Step 2: reduce high-order 516-256=260 bits of step 1 result * @@ -465,7 +490,7 @@ void x25519_multiply ( const union x25519_oct258 *multiplicand, static_assert ( sizeof ( step2->product ) >= sizeof ( step2->parts ) ); bigint_grow ( &step1->parts.low_256bit, &result->value ); bigint_multiply ( &step1->parts.high_260bit, &x25519_reduce_256, - &step2->product ); + &step2->product, &tmp.step2.carry.product ); bigint_add ( &result->value, &step2->value ); /* Step 3: reduce high-order 267-256=11 bits of step 2 result @@ -503,7 +528,7 @@ void x25519_multiply ( const union x25519_oct258 *multiplicand, memset ( &step3->value, 0, sizeof ( step3->value ) ); bigint_grow ( &step2->parts.low_256bit, &result->value ); bigint_multiply ( &step2->parts.high_11bit, &x25519_reduce_256, - &step3->product ); + &step3->product, &tmp.step3.carry.product ); bigint_add ( &step3->value, &result->value ); /* Step 1 calculates the product of the input operands, and diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 3dc344dff..efe156596 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -208,13 +208,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v multiplicand Big integer to be multiplied * @v multiplier Big integer to be multiplied * @v result Big integer to hold result + * @v carry Big integer to hold temporary carry space */ -#define bigint_multiply( multiplicand, multiplier, result ) do { \ +#define bigint_multiply( multiplicand, multiplier, result, carry ) do { \ unsigned int multiplicand_size = bigint_size (multiplicand); \ unsigned int multiplier_size = bigint_size (multiplier); \ bigint_multiply_raw ( (multiplicand)->element, \ multiplicand_size, (multiplier)->element, \ - multiplier_size, (result)->element ); \ + multiplier_size, (result)->element, \ + (carry)->element ); \ } while ( 0 ) /** @@ -245,7 +247,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); unsigned int size = bigint_size (modulus); \ sizeof ( struct { \ bigint_t ( size * 2 ) temp_result; \ - bigint_t ( size * 2 ) temp_modulus; \ + union { \ + bigint_t ( size * 2 ) temp_modulus; \ + bigint_t ( size * 2 ) temp_carry; \ + }; \ } ); } ) /** @@ -311,11 +316,16 @@ void bigint_shrink_raw ( const bigint_element_t *source0, unsigned int dest_size ); void bigint_swap_raw ( bigint_element_t *first0, bigint_element_t *second0, unsigned int size, int swap ); +void bigint_multiply_one ( const bigint_element_t multiplicand, + const bigint_element_t multiplier, + bigint_element_t *result, + bigint_element_t *carry ); void bigint_multiply_raw ( const bigint_element_t *multiplicand0, unsigned int multiplicand_size, const bigint_element_t *multiplier0, unsigned int multiplier_size, - bigint_element_t *result0 ); + bigint_element_t *result0, + bigint_element_t *carry0 ); void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 76aca1059..fcc77f25f 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -173,7 +173,8 @@ void bigint_multiply_sample ( const bigint_element_t *multiplicand0, unsigned int multiplicand_size, const bigint_element_t *multiplier0, unsigned int multiplier_size, - bigint_element_t *result0 ) { + bigint_element_t *result0, + bigint_element_t *carry0 ) { unsigned int result_size = ( multiplicand_size + multiplier_size ); const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) *multiplicand = ( ( const void * ) multiplicand0 ); @@ -181,8 +182,10 @@ void bigint_multiply_sample ( const bigint_element_t *multiplicand0, *multiplier = ( ( const void * ) multiplier0 ); bigint_t ( result_size ) __attribute__ (( may_alias )) *result = ( ( void * ) result0 ); + bigint_t ( result_size ) __attribute__ (( may_alias )) + *carry = ( ( void * ) carry0 ); - bigint_multiply ( multiplicand, multiplier, result ); + bigint_multiply ( multiplicand, multiplier, result, carry ); } void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0, @@ -495,11 +498,14 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, bigint_t ( multiplicand_size ) multiplicand_temp; \ bigint_t ( multiplier_size ) multiplier_temp; \ bigint_t ( multiplicand_size + multiplier_size ) result_temp; \ + bigint_t ( multiplicand_size + multiplier_size ) carry_temp; \ {} /* Fix emacs alignment */ \ \ assert ( bigint_size ( &result_temp ) == \ ( bigint_size ( &multiplicand_temp ) + \ bigint_size ( &multiplier_temp ) ) ); \ + assert ( bigint_size ( &carry_temp ) == \ + bigint_size ( &result_temp ) ); \ bigint_init ( &multiplicand_temp, multiplicand_raw, \ sizeof ( multiplicand_raw ) ); \ bigint_init ( &multiplier_temp, multiplier_raw, \ @@ -508,7 +514,7 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, DBG_HDA ( 0, &multiplicand_temp, sizeof ( multiplicand_temp ) );\ DBG_HDA ( 0, &multiplier_temp, sizeof ( multiplier_temp ) ); \ bigint_multiply ( &multiplicand_temp, &multiplier_temp, \ - &result_temp ); \ + &result_temp, &carry_temp ); \ DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\ \ -- cgit v1.2.3-55-g7522 From 3f4f843920afdc1d808a8b20354cf3eca481401a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 26 Sep 2024 16:24:57 +0100 Subject: [crypto] Eliminate temporary carry space for big integer multiplication An n-bit multiplication product may be added to up to two n-bit integers without exceeding the range of a (2n)-bit integer: (2^n - 1)*(2^n - 1) + (2^n - 1) + (2^n - 1) = 2^(2n) - 1 Exploit this to perform big integer multiplication in constant time without requiring the caller to provide temporary carry space. Signed-off-by: Michael Brown --- src/arch/arm32/include/bits/bigint.h | 15 ++--- src/arch/arm64/include/bits/bigint.h | 17 +++--- src/arch/loong64/include/bits/bigint.h | 17 +++--- src/arch/riscv/include/bits/bigint.h | 17 +++--- src/arch/x86/include/bits/bigint.h | 25 ++++---- src/crypto/bigint.c | 108 ++++++++++----------------------- src/crypto/x25519.c | 83 +++++++++---------------- src/include/ipxe/bigint.h | 14 ++--- src/tests/bigint_test.c | 12 +--- 9 files changed, 111 insertions(+), 197 deletions(-) (limited to 'src/tests') diff --git a/src/arch/arm32/include/bits/bigint.h b/src/arch/arm32/include/bits/bigint.h index 0a368a0c0..c148d6be2 100644 --- a/src/arch/arm32/include/bits/bigint.h +++ b/src/arch/arm32/include/bits/bigint.h @@ -314,7 +314,7 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused, * * @v multiplicand Multiplicand element * @v multiplier Multiplier element - * @v result Result element pair + * @v result Result element * @v carry Carry element */ static inline __attribute__ (( always_inline )) void @@ -324,19 +324,20 @@ bigint_multiply_one ( const uint32_t multiplicand, const uint32_t multiplier, uint32_t discard_high; __asm__ __volatile__ ( /* Perform multiplication */ - "umull %0, %1, %5, %6\n\t" + "umull %0, %1, %4, %5\n\t" /* Accumulate result */ "adds %2, %0\n\t" - "adcs %3, %1\n\t" + "adc %1, #0\n\t" /* Accumulate carry (cannot overflow) */ - "adc %4, #0\n\t" + "adds %2, %3\n\t" + "adc %3, %1, #0\n\t" : "=r" ( discard_low ), "=r" ( discard_high ), - "+r" ( result[0] ), - "+r" ( result[1] ), + "+r" ( *result ), "+r" ( *carry ) : "r" ( multiplicand ), - "r" ( multiplier ) ); + "r" ( multiplier ) + : "cc" ); } #endif /* _BITS_BIGINT_H */ diff --git a/src/arch/arm64/include/bits/bigint.h b/src/arch/arm64/include/bits/bigint.h index ca9feafbe..6b62c809e 100644 --- a/src/arch/arm64/include/bits/bigint.h +++ b/src/arch/arm64/include/bits/bigint.h @@ -315,7 +315,7 @@ bigint_done_raw ( const uint64_t *value0, unsigned int size __unused, * * @v multiplicand Multiplicand element * @v multiplier Multiplier element - * @v result Result element pair + * @v result Result element * @v carry Carry element */ static inline __attribute__ (( always_inline )) void @@ -325,20 +325,21 @@ bigint_multiply_one ( const uint64_t multiplicand, const uint64_t multiplier, uint64_t discard_high; __asm__ __volatile__ ( /* Perform multiplication */ - "mul %0, %5, %6\n\t" - "umulh %1, %5, %6\n\t" + "mul %0, %4, %5\n\t" + "umulh %1, %4, %5\n\t" /* Accumulate result */ "adds %2, %2, %0\n\t" - "adcs %3, %3, %1\n\t" + "adc %1, %1, xzr\n\t" /* Accumulate carry (cannot overflow) */ - "adc %4, %4, xzr\n\t" + "adds %2, %2, %3\n\t" + "adc %3, %1, xzr\n\t" : "=&r" ( discard_low ), "=r" ( discard_high ), - "+r" ( result[0] ), - "+r" ( result[1] ), + "+r" ( *result ), "+r" ( *carry ) : "r" ( multiplicand ), - "r" ( multiplier ) ); + "r" ( multiplier ) + : "cc" ); } #endif /* _BITS_BIGINT_H */ diff --git a/src/arch/loong64/include/bits/bigint.h b/src/arch/loong64/include/bits/bigint.h index ec6ca4b89..23edaeea5 100644 --- a/src/arch/loong64/include/bits/bigint.h +++ b/src/arch/loong64/include/bits/bigint.h @@ -362,7 +362,7 @@ bigint_done_raw ( const uint64_t *value0, unsigned int size __unused, * * @v multiplicand Multiplicand element * @v multiplier Multiplier element - * @v result Result element pair + * @v result Result element * @v carry Carry element */ static inline __attribute__ (( always_inline )) void @@ -373,23 +373,20 @@ bigint_multiply_one ( const uint64_t multiplicand, const uint64_t multiplier, uint64_t discard_carry; __asm__ __volatile__ ( /* Perform multiplication */ - "mul.d %0, %6, %7\n\t" - "mulh.du %1, %6, %7\n\t" + "mul.d %0, %5, %6\n\t" + "mulh.du %1, %5, %6\n\t" /* Accumulate low half */ "add.d %3, %3, %0\n\t" "sltu %2, %3, %0\n\t" - /* Add carry to high half (cannot overflow) */ "add.d %1, %1, %2\n\t" - /* Accumulate high half */ - "add.d %4, %4, %1\n\t" - "sltu %2, %4, %1\n\t" /* Accumulate carry (cannot overflow) */ - "add.d %5, %5, %2\n\t" + "add.d %3, %3, %4\n\t" + "sltu %2, %3, %4\n\t" + "add.d %4, %1, %2\n\t" : "=&r" ( discard_low ), "=r" ( discard_high ), "=r" ( discard_carry ), - "+r" ( result[0] ), - "+r" ( result[1] ), + "+r" ( *result ), "+r" ( *carry ) : "r" ( multiplicand ), "r" ( multiplier ) ); diff --git a/src/arch/riscv/include/bits/bigint.h b/src/arch/riscv/include/bits/bigint.h index c58233469..13fd16759 100644 --- a/src/arch/riscv/include/bits/bigint.h +++ b/src/arch/riscv/include/bits/bigint.h @@ -358,7 +358,7 @@ bigint_done_raw ( const unsigned long *value0, unsigned int size __unused, * * @v multiplicand Multiplicand element * @v multiplier Multiplier element - * @v result Result element pair + * @v result Result element * @v carry Carry element */ static inline __attribute__ (( always_inline )) void @@ -370,23 +370,20 @@ bigint_multiply_one ( const unsigned long multiplicand, unsigned long discard_carry; __asm__ __volatile__ ( /* Perform multiplication */ - "mulhu %1, %6, %7\n\t" - "mul %0, %6, %7\n\t" + "mulhu %1, %5, %6\n\t" + "mul %0, %5, %6\n\t" /* Accumulate low half */ "add %3, %3, %0\n\t" "sltu %2, %3, %0\n\t" - /* Add carry to high half (cannot overflow) */ "add %1, %1, %2\n\t" - /* Accumulate high half */ - "add %4, %4, %1\n\t" - "sltu %2, %4, %1\n\t" /* Accumulate carry (cannot overflow) */ - "add %5, %5, %2\n\t" + "add %3, %3, %4\n\t" + "sltu %2, %3, %4\n\t" + "add %4, %1, %2\n\t" : "=r" ( discard_low ), "=&r" ( discard_high ), "=r" ( discard_carry ), - "+r" ( result[0] ), - "+r" ( result[1] ), + "+r" ( *result ), "+r" ( *carry ) : "r" ( multiplicand ), "r" ( multiplier ) ); diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h index a481e90f7..320d49498 100644 --- a/src/arch/x86/include/bits/bigint.h +++ b/src/arch/x86/include/bits/bigint.h @@ -327,29 +327,28 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused, * * @v multiplicand Multiplicand element * @v multiplier Multiplier element - * @v result Result element pair + * @v result Result element * @v carry Carry element */ static inline __attribute__ (( always_inline )) void bigint_multiply_one ( const uint32_t multiplicand, const uint32_t multiplier, uint32_t *result, uint32_t *carry ) { uint32_t discard_a; - uint32_t discard_d; __asm__ __volatile__ ( /* Perform multiplication */ - "mull %6\n\t" + "mull %3\n\t" + /* Accumulate carry */ + "addl %5, %0\n\t" + "adcl $0, %1\n\t" /* Accumulate result */ "addl %0, %2\n\t" - "adcl %1, %3\n\t" - /* Accumulate carry (cannot overflow) */ - "adcl $0, %4\n\t" - : "=a" ( discard_a ), - "=d" ( discard_d ), - "+m" ( result[0] ), - "+m" ( result[1] ), - "+m" ( *carry ) - : "0" ( multiplicand ), - "g" ( multiplier ) ); + "adcl $0, %1\n\t" + : "=&a" ( discard_a ), + "=&d" ( *carry ), + "+m" ( *result ) + : "g" ( multiplicand ), + "0" ( multiplier ), + "r" ( *carry ) ); } #endif /* _BITS_BIGINT_H */ diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index 5b7116e28..b63f7ccc1 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -83,14 +83,12 @@ void bigint_swap_raw ( bigint_element_t *first0, bigint_element_t *second0, * @v multiplier0 Element 0 of big integer to be multiplied * @v multiplier_size Number of elements in multiplier * @v result0 Element 0 of big integer to hold result - * @v carry0 Element 0 of big integer to hold temporary carry */ void bigint_multiply_raw ( const bigint_element_t *multiplicand0, unsigned int multiplicand_size, const bigint_element_t *multiplier0, unsigned int multiplier_size, - bigint_element_t *result0, - bigint_element_t *carry0 ) { + bigint_element_t *result0 ) { unsigned int result_size = ( multiplicand_size + multiplier_size ); const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) *multiplicand = ( ( const void * ) multiplicand0 ); @@ -98,89 +96,51 @@ void bigint_multiply_raw ( const bigint_element_t *multiplicand0, *multiplier = ( ( const void * ) multiplier0 ); bigint_t ( result_size ) __attribute__ (( may_alias )) *result = ( ( void * ) result0 ); - bigint_t ( result_size ) __attribute__ (( may_alias )) - *carry = ( ( void * ) carry0 ); bigint_element_t multiplicand_element; const bigint_element_t *multiplier_element; - bigint_element_t *result_elements; - bigint_element_t *carry_element; + bigint_element_t *result_element; + bigint_element_t carry_element; unsigned int i; unsigned int j; - /* Zero result and temporary carry space */ - memset ( result, 0, sizeof ( *result ) ); - memset ( carry, 0, sizeof ( *carry ) ); + /* Zero required portion of result + * + * All elements beyond the length of the multiplier will be + * written before they are read, and so do not need to be + * zeroed in advance. + */ + memset ( result, 0, sizeof ( *multiplier ) ); - /* Multiply integers one element at a time, adding the double - * element directly into the result and accumulating any - * overall carry out from this double-element addition into - * the temporary carry space. + /* Multiply integers one element at a time, adding the low + * half of the double-element product directly into the + * result, and maintaining a running single-element carry. + * + * The running carry can never overflow beyond a single + * element. At each step, the calculation we perform is: * - * We could propagate the carry immediately instead of using a - * temporary carry space. However, this would cause the - * multiplication to run in non-constant time, which is - * undesirable. + * carry:result[i+j] := ( ( multiplicand[i] * multiplier[j] ) + * + result[i+j] + carry ) * - * The carry elements can never overflow, provided that the - * element size is large enough to accommodate any plausible - * big integer. The total number of potential carries (across - * all elements) is the sum of the number of elements in the - * multiplicand and multiplier. With a 16-bit element size, - * this therefore allows for up to a 1Mbit multiplication - * result (e.g. a 512kbit integer multiplied by another - * 512kbit integer), which is around 100x higher than could be - * needed in practice. With a more realistic 32-bit element - * size, the limit becomes a totally implausible 128Gbit - * multiplication result. + * The maximum value (for n-bit elements) is therefore: + * + * (2^n - 1)*(2^n - 1) + (2^n - 1) + (2^n - 1) = 2^(2n) - 1 + * + * This is precisely the maximum value for a 2n-bit integer, + * and so the carry out remains within the range of an n-bit + * integer, i.e. a single element. */ for ( i = 0 ; i < multiplicand_size ; i++ ) { multiplicand_element = multiplicand->element[i]; multiplier_element = &multiplier->element[0]; - result_elements = &result->element[i]; - carry_element = &carry->element[i]; + result_element = &result->element[i]; + carry_element = 0; for ( j = 0 ; j < multiplier_size ; j++ ) { bigint_multiply_one ( multiplicand_element, *(multiplier_element++), - result_elements++, - carry_element++ ); + result_element++, + &carry_element ); } - } - - /* Add the temporary carry into the result. The least - * significant element of the carry represents the carry out - * from multiplying the least significant elements of the - * multiplicand and multiplier, and therefore must be added to - * the third-least significant element of the result (i.e. the - * carry needs to be shifted left by two elements before being - * adding to the result). - * - * The most significant two elements of the carry are - * guaranteed to be zero, since: - * - * a < 2^{n}, b < 2^{m} => ab < 2^{n+m} - * - * and the overall result of the multiplication (including - * adding in the shifted carries) is therefore guaranteed not - * to overflow beyond the end of the result. - * - * We could avoid this shifting by writing the carry directly - * into the "correct" element during the element-by-element - * multiplication stage above. However, this would add - * complexity to the loop since we would have to arrange for - * the (provably zero) most significant two carry out results - * to be discarded, in order to avoid writing beyond the end - * of the temporary carry space. - * - * Performing the logical shift is essentially free, since we - * simply adjust the element pointers. - * - * To avoid requiring additional checks in each architecture's - * implementation of bigint_add_raw(), we explicitly avoid - * calling bigint_add_raw() with a size of zero. - */ - if ( result_size > 2 ) { - bigint_add_raw ( &carry->element[0], &result->element[2], - ( result_size - 2 ) ); + *result_element = carry_element; } } @@ -209,10 +169,7 @@ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, ( ( void * ) result0 ); struct { bigint_t ( size * 2 ) result; - union { - bigint_t ( size * 2 ) modulus; - bigint_t ( size * 2 ) carry; - }; + bigint_t ( size * 2 ) modulus; } *temp = tmp; int rotation; int i; @@ -225,8 +182,7 @@ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, /* Perform multiplication */ profile_start ( &bigint_mod_multiply_multiply_profiler ); - bigint_multiply ( multiplicand, multiplier, &temp->result, - &temp->carry ); + bigint_multiply ( multiplicand, multiplier, &temp->result ); profile_stop ( &bigint_mod_multiply_multiply_profiler ); /* Rescale modulus to match result */ diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c index 553f43d34..d58f7168c 100644 --- a/src/crypto/x25519.c +++ b/src/crypto/x25519.c @@ -43,7 +43,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Storage size of each big integer 128 40 * (in bytes) * - * Stack usage for key exchange 1144 424 + * Stack usage for key exchange 1144 360 * (in bytes, large objects only) * * Cost of big integer addition 16 5 @@ -207,60 +207,35 @@ union x25519_multiply_step3 { * We overlap the buffers used by each step of the multiplication * calculation to reduce the total stack space required: * - * |--------------------------------------------------------------------------| - * | <------- step 1 carry ------> | <----------- step 1 result ------------> | - * | | <- low 256 bits -> | <- high 260 bits -> | - * | <- step 2 carry -> | <-- step 2 result --> | | | - * | <- s3 carry -> | <--------- pad ---------> | <- step 3 result -> | | - * |--------------------------------------------------------------------------| + * |--------------------------------------------------------| + * | <- pad -> | <------------ step 1 result -------------> | + * | | <- low 256 bits -> | <-- high 260 bits --> | + * | <------- step 2 result ------> | <-- step 3 result --> | + * |--------------------------------------------------------| */ union x25519_multiply_workspace { - /** Step 1 */ + /** Step 1 result */ struct { - /** Step 1 temporary carry workspace */ - union x25519_multiply_step1 carry; + /** Padding to avoid collision between steps 1 and 2 + * + * The step 2 multiplication consumes the high 260 + * bits of step 1, and so the step 2 multiplication + * result must not overlap this portion of the step 1 + * result. + */ + uint8_t pad[ sizeof ( union x25519_multiply_step2 ) - + offsetof ( union x25519_multiply_step1, + parts.high_260bit ) ]; /** Step 1 result */ - union x25519_multiply_step1 result; - } __attribute__ (( packed )) step1; - /** Step 2 - * - * The step 2 multiplication consumes the high 260 bits of - * step 1, and so the step 2 multiplication result (and - * temporary carry workspace) must not overlap this portion of - * the step 1 result. - */ + union x25519_multiply_step1 step1; + } __attribute__ (( packed )); + /** Steps 2 and 3 results */ struct { - /** Step 2 temporary carry workspace */ - union x25519_multiply_step2 carry; /** Step 2 result */ - union x25519_multiply_step2 result; - /** Avoid collision between step 1 result and step 2 result */ - uint8_t pad[ ( int ) - ( sizeof ( union x25519_multiply_step1 ) + - offsetof ( union x25519_multiply_step1, - parts.high_260bit ) - - sizeof ( union x25519_multiply_step2 ) - - sizeof ( union x25519_multiply_step2 ) ) ]; - } __attribute__ (( packed )) step2; - /** Step 3 - * - * The step 3 multiplication consumes the high 11 bits of step - * 2, and so the step 3 multiplication result (and temporary - * carry workspace) must not overlap this portion of the step - * 2 result. - */ - struct { - /** Step 3 temporary carry workspace */ - union x25519_multiply_step3 carry; - /** Avoid collision between step 2 result and step 3 carry */ - uint8_t pad1[ ( int ) - ( sizeof ( union x25519_multiply_step2 ) - - sizeof ( union x25519_multiply_step3 ) ) ]; - /** Avoid collision between step 2 result and step 3 result */ - uint8_t pad2[ sizeof ( union x25519_multiply_step2 ) ]; + union x25519_multiply_step2 step2; /** Step 3 result */ - union x25519_multiply_step3 result; - } __attribute__ (( packed )) step3; + union x25519_multiply_step3 step3; + } __attribute__ (( packed )); }; /** An X25519 elliptic curve point in projective coordinates @@ -451,9 +426,9 @@ void x25519_multiply ( const union x25519_oct258 *multiplicand, const union x25519_oct258 *multiplier, union x25519_quad257 *result ) { union x25519_multiply_workspace tmp; - union x25519_multiply_step1 *step1 = &tmp.step1.result; - union x25519_multiply_step2 *step2 = &tmp.step2.result; - union x25519_multiply_step3 *step3 = &tmp.step3.result; + union x25519_multiply_step1 *step1 = &tmp.step1; + union x25519_multiply_step2 *step2 = &tmp.step2; + union x25519_multiply_step3 *step3 = &tmp.step3; /* Step 1: perform raw multiplication * @@ -464,7 +439,7 @@ void x25519_multiply ( const union x25519_oct258 *multiplicand, */ static_assert ( sizeof ( step1->product ) >= sizeof ( step1->parts ) ); bigint_multiply ( &multiplicand->value, &multiplier->value, - &step1->product, &tmp.step1.carry.product ); + &step1->product ); /* Step 2: reduce high-order 516-256=260 bits of step 1 result * @@ -490,7 +465,7 @@ void x25519_multiply ( const union x25519_oct258 *multiplicand, static_assert ( sizeof ( step2->product ) >= sizeof ( step2->parts ) ); bigint_grow ( &step1->parts.low_256bit, &result->value ); bigint_multiply ( &step1->parts.high_260bit, &x25519_reduce_256, - &step2->product, &tmp.step2.carry.product ); + &step2->product ); bigint_add ( &result->value, &step2->value ); /* Step 3: reduce high-order 267-256=11 bits of step 2 result @@ -528,7 +503,7 @@ void x25519_multiply ( const union x25519_oct258 *multiplicand, memset ( &step3->value, 0, sizeof ( step3->value ) ); bigint_grow ( &step2->parts.low_256bit, &result->value ); bigint_multiply ( &step2->parts.high_11bit, &x25519_reduce_256, - &step3->product, &tmp.step3.carry.product ); + &step3->product ); bigint_add ( &step3->value, &result->value ); /* Step 1 calculates the product of the input operands, and diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index efe156596..bcb7af5ec 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -208,15 +208,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v multiplicand Big integer to be multiplied * @v multiplier Big integer to be multiplied * @v result Big integer to hold result - * @v carry Big integer to hold temporary carry space */ -#define bigint_multiply( multiplicand, multiplier, result, carry ) do { \ +#define bigint_multiply( multiplicand, multiplier, result ) do { \ unsigned int multiplicand_size = bigint_size (multiplicand); \ unsigned int multiplier_size = bigint_size (multiplier); \ bigint_multiply_raw ( (multiplicand)->element, \ multiplicand_size, (multiplier)->element, \ - multiplier_size, (result)->element, \ - (carry)->element ); \ + multiplier_size, (result)->element ); \ } while ( 0 ) /** @@ -247,10 +245,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); unsigned int size = bigint_size (modulus); \ sizeof ( struct { \ bigint_t ( size * 2 ) temp_result; \ - union { \ - bigint_t ( size * 2 ) temp_modulus; \ - bigint_t ( size * 2 ) temp_carry; \ - }; \ + bigint_t ( size * 2 ) temp_modulus; \ } ); } ) /** @@ -324,8 +319,7 @@ void bigint_multiply_raw ( const bigint_element_t *multiplicand0, unsigned int multiplicand_size, const bigint_element_t *multiplier0, unsigned int multiplier_size, - bigint_element_t *result0, - bigint_element_t *carry0 ); + bigint_element_t *result0 ); void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index fcc77f25f..76aca1059 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -173,8 +173,7 @@ void bigint_multiply_sample ( const bigint_element_t *multiplicand0, unsigned int multiplicand_size, const bigint_element_t *multiplier0, unsigned int multiplier_size, - bigint_element_t *result0, - bigint_element_t *carry0 ) { + bigint_element_t *result0 ) { unsigned int result_size = ( multiplicand_size + multiplier_size ); const bigint_t ( multiplicand_size ) __attribute__ (( may_alias )) *multiplicand = ( ( const void * ) multiplicand0 ); @@ -182,10 +181,8 @@ void bigint_multiply_sample ( const bigint_element_t *multiplicand0, *multiplier = ( ( const void * ) multiplier0 ); bigint_t ( result_size ) __attribute__ (( may_alias )) *result = ( ( void * ) result0 ); - bigint_t ( result_size ) __attribute__ (( may_alias )) - *carry = ( ( void * ) carry0 ); - bigint_multiply ( multiplicand, multiplier, result, carry ); + bigint_multiply ( multiplicand, multiplier, result ); } void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0, @@ -498,14 +495,11 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, bigint_t ( multiplicand_size ) multiplicand_temp; \ bigint_t ( multiplier_size ) multiplier_temp; \ bigint_t ( multiplicand_size + multiplier_size ) result_temp; \ - bigint_t ( multiplicand_size + multiplier_size ) carry_temp; \ {} /* Fix emacs alignment */ \ \ assert ( bigint_size ( &result_temp ) == \ ( bigint_size ( &multiplicand_temp ) + \ bigint_size ( &multiplier_temp ) ) ); \ - assert ( bigint_size ( &carry_temp ) == \ - bigint_size ( &result_temp ) ); \ bigint_init ( &multiplicand_temp, multiplicand_raw, \ sizeof ( multiplicand_raw ) ); \ bigint_init ( &multiplier_temp, multiplier_raw, \ @@ -514,7 +508,7 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, DBG_HDA ( 0, &multiplicand_temp, sizeof ( multiplicand_temp ) );\ DBG_HDA ( 0, &multiplier_temp, sizeof ( multiplier_temp ) ); \ bigint_multiply ( &multiplicand_temp, &multiplier_temp, \ - &result_temp, &carry_temp ); \ + &result_temp ); \ DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\ \ -- cgit v1.2.3-55-g7522 From 7e0bf4ec5cb3dd608d97735575e3f62252455878 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 7 Oct 2024 12:13:42 +0100 Subject: [crypto] Rename bigint_rol()/bigint_ror() to bigint_shl()/bigint_shr() The big integer shift operations are misleadingly described as rotations since the original x86 implementations are essentially trivial loops around the relevant rotate-through-carry instruction. The overall operation performed is a shift rather than a rotation. Update the function names and descriptions to reflect this. Signed-off-by: Michael Brown --- src/arch/arm32/include/bits/bigint.h | 8 +++--- src/arch/arm64/include/bits/bigint.h | 8 +++--- src/arch/loong64/include/bits/bigint.h | 8 +++--- src/arch/riscv/include/bits/bigint.h | 8 +++--- src/arch/x86/include/bits/bigint.h | 8 +++--- src/crypto/bigint.c | 16 ++++++------ src/include/ipxe/bigint.h | 16 ++++++------ src/tests/bigint_test.c | 48 +++++++++++++++++----------------- 8 files changed, 60 insertions(+), 60 deletions(-) (limited to 'src/tests') diff --git a/src/arch/arm32/include/bits/bigint.h b/src/arch/arm32/include/bits/bigint.h index c148d6be2..f11ec906b 100644 --- a/src/arch/arm32/include/bits/bigint.h +++ b/src/arch/arm32/include/bits/bigint.h @@ -112,13 +112,13 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, } /** - * Rotate big integer left + * Shift big integer left * * @v value0 Element 0 of big integer * @v size Number of elements */ static inline __attribute__ (( always_inline )) void -bigint_rol_raw ( uint32_t *value0, unsigned int size ) { +bigint_shl_raw ( uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint32_t *discard_value; @@ -141,13 +141,13 @@ bigint_rol_raw ( uint32_t *value0, unsigned int size ) { } /** - * Rotate big integer right + * Shift big integer right * * @v value0 Element 0 of big integer * @v size Number of elements */ static inline __attribute__ (( always_inline )) void -bigint_ror_raw ( uint32_t *value0, unsigned int size ) { +bigint_shr_raw ( uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint32_t *discard_value; diff --git a/src/arch/arm64/include/bits/bigint.h b/src/arch/arm64/include/bits/bigint.h index 6b62c809e..05095413b 100644 --- a/src/arch/arm64/include/bits/bigint.h +++ b/src/arch/arm64/include/bits/bigint.h @@ -111,13 +111,13 @@ bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, } /** - * Rotate big integer left + * Shift big integer left * * @v value0 Element 0 of big integer * @v size Number of elements */ static inline __attribute__ (( always_inline )) void -bigint_rol_raw ( uint64_t *value0, unsigned int size ) { +bigint_shl_raw ( uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint64_t *discard_value; @@ -140,13 +140,13 @@ bigint_rol_raw ( uint64_t *value0, unsigned int size ) { } /** - * Rotate big integer right + * Shift big integer right * * @v value0 Element 0 of big integer * @v size Number of elements */ static inline __attribute__ (( always_inline )) void -bigint_ror_raw ( uint64_t *value0, unsigned int size ) { +bigint_shr_raw ( uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint64_t *discard_value; diff --git a/src/arch/loong64/include/bits/bigint.h b/src/arch/loong64/include/bits/bigint.h index 23edaeea5..237275851 100644 --- a/src/arch/loong64/include/bits/bigint.h +++ b/src/arch/loong64/include/bits/bigint.h @@ -136,13 +136,13 @@ bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, } /** - * Rotate big integer left + * Shift big integer left * * @v value0 Element 0 of big integer * @v size Number of elements */ static inline __attribute__ (( always_inline )) void -bigint_rol_raw ( uint64_t *value0, unsigned int size ) { +bigint_shl_raw ( uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint64_t *discard_value; @@ -177,13 +177,13 @@ bigint_rol_raw ( uint64_t *value0, unsigned int size ) { } /** - * Rotate big integer right + * Shift big integer right * * @v value0 Element 0 of big integer * @v size Number of elements */ static inline __attribute__ (( always_inline )) void -bigint_ror_raw ( uint64_t *value0, unsigned int size ) { +bigint_shr_raw ( uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint64_t *discard_value; diff --git a/src/arch/riscv/include/bits/bigint.h b/src/arch/riscv/include/bits/bigint.h index 13fd16759..58351ac07 100644 --- a/src/arch/riscv/include/bits/bigint.h +++ b/src/arch/riscv/include/bits/bigint.h @@ -135,13 +135,13 @@ bigint_subtract_raw ( const unsigned long *subtrahend0, unsigned long *value0, } /** - * Rotate big integer left + * Shift big integer left * * @v value0 Element 0 of big integer * @v size Number of elements */ static inline __attribute__ (( always_inline )) void -bigint_rol_raw ( unsigned long *value0, unsigned int size ) { +bigint_shl_raw ( unsigned long *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); unsigned long *valueN = ( value0 + size ); @@ -174,13 +174,13 @@ bigint_rol_raw ( unsigned long *value0, unsigned int size ) { } /** - * Rotate big integer right + * Shift big integer right * * @v value0 Element 0 of big integer * @v size Number of elements */ static inline __attribute__ (( always_inline )) void -bigint_ror_raw ( unsigned long *value0, unsigned int size ) { +bigint_shr_raw ( unsigned long *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); unsigned long *valueN = ( value0 + size ); diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h index 320d49498..512b2724d 100644 --- a/src/arch/x86/include/bits/bigint.h +++ b/src/arch/x86/include/bits/bigint.h @@ -104,13 +104,13 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, } /** - * Rotate big integer left + * Shift big integer left * * @v value0 Element 0 of big integer * @v size Number of elements */ static inline __attribute__ (( always_inline )) void -bigint_rol_raw ( uint32_t *value0, unsigned int size ) { +bigint_shl_raw ( uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); long index; @@ -127,13 +127,13 @@ bigint_rol_raw ( uint32_t *value0, unsigned int size ) { } /** - * Rotate big integer right + * Shift big integer right * * @v value0 Element 0 of big integer * @v size Number of elements */ static inline __attribute__ (( always_inline )) void -bigint_ror_raw ( uint32_t *value0, unsigned int size ) { +bigint_shr_raw ( uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); long discard_c; diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index b63f7ccc1..c7b6dafc9 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -171,7 +171,7 @@ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, bigint_t ( size * 2 ) result; bigint_t ( size * 2 ) modulus; } *temp = tmp; - int rotation; + int shift; int i; /* Start profiling */ @@ -188,18 +188,18 @@ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, /* Rescale modulus to match result */ profile_start ( &bigint_mod_multiply_rescale_profiler ); bigint_grow ( modulus, &temp->modulus ); - rotation = ( bigint_max_set_bit ( &temp->result ) - - bigint_max_set_bit ( &temp->modulus ) ); - for ( i = 0 ; i < rotation ; i++ ) - bigint_rol ( &temp->modulus ); + shift = ( bigint_max_set_bit ( &temp->result ) - + bigint_max_set_bit ( &temp->modulus ) ); + for ( i = 0 ; i < shift ; i++ ) + bigint_shl ( &temp->modulus ); profile_stop ( &bigint_mod_multiply_rescale_profiler ); /* Subtract multiples of modulus */ profile_start ( &bigint_mod_multiply_subtract_profiler ); - for ( i = 0 ; i <= rotation ; i++ ) { + for ( i = 0 ; i <= shift ; i++ ) { if ( bigint_is_geq ( &temp->result, &temp->modulus ) ) bigint_subtract ( &temp->modulus, &temp->result ); - bigint_ror ( &temp->modulus ); + bigint_shr ( &temp->modulus ); } profile_stop ( &bigint_mod_multiply_subtract_profiler ); @@ -255,7 +255,7 @@ void bigint_mod_exp_raw ( const bigint_element_t *base0, bigint_mod_multiply ( result, &temp->base, modulus, result, temp->mod_multiply ); } - bigint_ror ( &temp->exponent ); + bigint_shr ( &temp->exponent ); bigint_mod_multiply ( &temp->base, &temp->base, modulus, &temp->base, temp->mod_multiply ); } diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index bcb7af5ec..19cd4e3dd 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -89,23 +89,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); } while ( 0 ) /** - * Rotate big integer left + * Shift big integer left * * @v value Big integer */ -#define bigint_rol( value ) do { \ +#define bigint_shl( value ) do { \ unsigned int size = bigint_size (value); \ - bigint_rol_raw ( (value)->element, size ); \ + bigint_shl_raw ( (value)->element, size ); \ } while ( 0 ) /** - * Rotate big integer right + * Shift big integer right * * @v value Big integer */ -#define bigint_ror( value ) do { \ +#define bigint_shr( value ) do { \ unsigned int size = bigint_size (value); \ - bigint_ror_raw ( (value)->element, size ); \ + bigint_shr_raw ( (value)->element, size ); \ } while ( 0 ) /** @@ -293,8 +293,8 @@ void bigint_add_raw ( const bigint_element_t *addend0, bigint_element_t *value0, unsigned int size ); void bigint_subtract_raw ( const bigint_element_t *subtrahend0, bigint_element_t *value0, unsigned int size ); -void bigint_rol_raw ( bigint_element_t *value0, unsigned int size ); -void bigint_ror_raw ( bigint_element_t *value0, unsigned int size ); +void bigint_shl_raw ( bigint_element_t *value0, unsigned int size ); +void bigint_shr_raw ( bigint_element_t *value0, unsigned int size ); int bigint_is_zero_raw ( const bigint_element_t *value0, unsigned int size ); int bigint_is_geq_raw ( const bigint_element_t *value0, const bigint_element_t *reference0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 76aca1059..65f124f24 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -78,18 +78,18 @@ void bigint_subtract_sample ( const bigint_element_t *subtrahend0, bigint_subtract ( subtrahend, value ); } -void bigint_rol_sample ( bigint_element_t *value0, unsigned int size ) { +void bigint_shl_sample ( bigint_element_t *value0, unsigned int size ) { bigint_t ( size ) *value __attribute__ (( may_alias )) = ( ( void * ) value0 ); - bigint_rol ( value ); + bigint_shl ( value ); } -void bigint_ror_sample ( bigint_element_t *value0, unsigned int size ) { +void bigint_shr_sample ( bigint_element_t *value0, unsigned int size ) { bigint_t ( size ) *value __attribute__ (( may_alias )) = ( ( void * ) value0 ); - bigint_ror ( value ); + bigint_shr ( value ); } int bigint_is_zero_sample ( const bigint_element_t *value0, @@ -290,12 +290,12 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, } while ( 0 ) /** - * Report result of big integer left rotation test + * Report result of big integer left shift test * * @v value Big integer * @v expected Big integer expected result */ -#define bigint_rol_ok( value, expected ) do { \ +#define bigint_shl_ok( value, expected ) do { \ static const uint8_t value_raw[] = value; \ static const uint8_t expected_raw[] = expected; \ uint8_t result_raw[ sizeof ( expected_raw ) ]; \ @@ -305,9 +305,9 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, {} /* Fix emacs alignment */ \ \ bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ - DBG ( "Rotate left:\n" ); \ + DBG ( "Shift left:\n" ); \ DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bigint_rol ( &value_temp ); \ + bigint_shl ( &value_temp ); \ DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ \ @@ -316,12 +316,12 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, } while ( 0 ) /** - * Report result of big integer right rotation test + * Report result of big integer right shift test * * @v value Big integer * @v expected Big integer expected result */ -#define bigint_ror_ok( value, expected ) do { \ +#define bigint_shr_ok( value, expected ) do { \ static const uint8_t value_raw[] = value; \ static const uint8_t expected_raw[] = expected; \ uint8_t result_raw[ sizeof ( expected_raw ) ]; \ @@ -331,9 +331,9 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, {} /* Fix emacs alignment */ \ \ bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ - DBG ( "Rotate right:\n" ); \ + DBG ( "Shift right:\n" ); \ DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bigint_ror ( &value_temp ); \ + bigint_shr ( &value_temp ); \ DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ \ @@ -801,15 +801,15 @@ static void bigint_test_exec ( void ) { 0xda, 0xc8, 0x8c, 0x71, 0x86, 0x97, 0x7f, 0xcb, 0x94, 0x31, 0x1d, 0xbc, 0x44, 0x1a ) ); - bigint_rol_ok ( BIGINT ( 0xe0 ), + bigint_shl_ok ( BIGINT ( 0xe0 ), BIGINT ( 0xc0 ) ); - bigint_rol_ok ( BIGINT ( 0x43, 0x1d ), + bigint_shl_ok ( BIGINT ( 0x43, 0x1d ), BIGINT ( 0x86, 0x3a ) ); - bigint_rol_ok ( BIGINT ( 0xac, 0xed, 0x9b ), + bigint_shl_ok ( BIGINT ( 0xac, 0xed, 0x9b ), BIGINT ( 0x59, 0xdb, 0x36 ) ); - bigint_rol_ok ( BIGINT ( 0x2c, 0xe8, 0x3a, 0x22 ), + bigint_shl_ok ( BIGINT ( 0x2c, 0xe8, 0x3a, 0x22 ), BIGINT ( 0x59, 0xd0, 0x74, 0x44 ) ); - bigint_rol_ok ( BIGINT ( 0x4e, 0x88, 0x4a, 0x05, 0x5e, 0x10, 0xee, + bigint_shl_ok ( BIGINT ( 0x4e, 0x88, 0x4a, 0x05, 0x5e, 0x10, 0xee, 0x5b, 0xc6, 0x40, 0x0e, 0x03, 0xd7, 0x0d, 0x28, 0xa5, 0x55, 0xb2, 0x50, 0xef, 0x69, 0xd1, 0x1d ), @@ -817,7 +817,7 @@ static void bigint_test_exec ( void ) { 0xb7, 0x8c, 0x80, 0x1c, 0x07, 0xae, 0x1a, 0x51, 0x4a, 0xab, 0x64, 0xa1, 0xde, 0xd3, 0xa2, 0x3a ) ); - bigint_rol_ok ( BIGINT ( 0x07, 0x62, 0x78, 0x70, 0x2e, 0xd4, 0x41, + bigint_shl_ok ( BIGINT ( 0x07, 0x62, 0x78, 0x70, 0x2e, 0xd4, 0x41, 0xaa, 0x9b, 0x50, 0xb1, 0x9a, 0x71, 0xf5, 0x1c, 0x2f, 0xe7, 0x0d, 0xf1, 0x46, 0x57, 0x04, 0x99, 0x78, 0x4e, 0x84, 0x78, 0xba, @@ -855,15 +855,15 @@ static void bigint_test_exec ( void ) { 0x49, 0x7c, 0x1e, 0xdb, 0xc7, 0x65, 0xa6, 0x0e, 0xd1, 0xd2, 0x00, 0xb3, 0x41, 0xc9, 0x3c, 0xbc ) ); - bigint_ror_ok ( BIGINT ( 0x8f ), + bigint_shr_ok ( BIGINT ( 0x8f ), BIGINT ( 0x47 ) ); - bigint_ror_ok ( BIGINT ( 0xaa, 0x1d ), + bigint_shr_ok ( BIGINT ( 0xaa, 0x1d ), BIGINT ( 0x55, 0x0e ) ); - bigint_ror_ok ( BIGINT ( 0xf0, 0xbd, 0x68 ), + bigint_shr_ok ( BIGINT ( 0xf0, 0xbd, 0x68 ), BIGINT ( 0x78, 0x5e, 0xb4 ) ); - bigint_ror_ok ( BIGINT ( 0x33, 0xa0, 0x3d, 0x95 ), + bigint_shr_ok ( BIGINT ( 0x33, 0xa0, 0x3d, 0x95 ), BIGINT ( 0x19, 0xd0, 0x1e, 0xca ) ); - bigint_ror_ok ( BIGINT ( 0xa1, 0xf4, 0xb9, 0x64, 0x91, 0x99, 0xa1, + bigint_shr_ok ( BIGINT ( 0xa1, 0xf4, 0xb9, 0x64, 0x91, 0x99, 0xa1, 0xf4, 0xae, 0xeb, 0x71, 0x97, 0x1b, 0x71, 0x09, 0x38, 0x3f, 0x8f, 0xc5, 0x3a, 0xb9, 0x75, 0x94 ), @@ -871,7 +871,7 @@ static void bigint_test_exec ( void ) { 0xfa, 0x57, 0x75, 0xb8, 0xcb, 0x8d, 0xb8, 0x84, 0x9c, 0x1f, 0xc7, 0xe2, 0x9d, 0x5c, 0xba, 0xca ) ); - bigint_ror_ok ( BIGINT ( 0xc0, 0xb3, 0x78, 0x46, 0x69, 0x6e, 0x35, + bigint_shr_ok ( BIGINT ( 0xc0, 0xb3, 0x78, 0x46, 0x69, 0x6e, 0x35, 0x94, 0xed, 0x28, 0xdc, 0xfd, 0xf6, 0xdb, 0x2d, 0x24, 0xcb, 0xa4, 0x6f, 0x0e, 0x58, 0x89, 0x04, 0xec, 0xc8, 0x0c, 0x2d, 0xb3, -- cgit v1.2.3-55-g7522 From 2bf16c6ffca1e294bb8233d19c9c36e43b31f041 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 15 Oct 2024 13:50:51 +0100 Subject: [crypto] Separate out bigint_reduce() from bigint_mod_multiply() Faster modular multiplication algorithms such as Montgomery multiplication will still require the ability to perform a single direct modular reduction. Neaten up the implementation of direct reduction and split it out into a separate bigint_reduce() function, complete with its own unit tests. Signed-off-by: Michael Brown --- src/crypto/bigint.c | 213 ++++++++++++++++++++++++++++++++++++++-------- src/include/ipxe/bigint.h | 34 ++++++++ src/tests/bigint_test.c | 86 +++++++++++++++++++ 3 files changed, 296 insertions(+), 37 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index c7b6dafc9..a8b99ec3c 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -34,22 +34,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Big integer support */ +/** Modular direct reduction profiler */ +static struct profiler bigint_mod_profiler __profiler = + { .name = "bigint_mod" }; + /** Modular multiplication overall profiler */ static struct profiler bigint_mod_multiply_profiler __profiler = { .name = "bigint_mod_multiply" }; -/** Modular multiplication multiply step profiler */ -static struct profiler bigint_mod_multiply_multiply_profiler __profiler = - { .name = "bigint_mod_multiply.multiply" }; - -/** Modular multiplication rescale step profiler */ -static struct profiler bigint_mod_multiply_rescale_profiler __profiler = - { .name = "bigint_mod_multiply.rescale" }; - -/** Modular multiplication subtract step profiler */ -static struct profiler bigint_mod_multiply_subtract_profiler __profiler = - { .name = "bigint_mod_multiply.subtract" }; - /** * Conditionally swap big integers (in constant time) * @@ -144,6 +136,175 @@ void bigint_multiply_raw ( const bigint_element_t *multiplicand0, } } +/** + * Reduce big integer + * + * @v minuend0 Element 0 of big integer to be reduced + * @v minuend_size Number of elements in minuend + * @v modulus0 Element 0 of big integer modulus + * @v modulus_size Number of elements in modulus and result + * @v result0 Element 0 of big integer to hold result + * @v tmp Temporary working space + */ +void bigint_reduce_raw ( const bigint_element_t *minuend0, + unsigned int minuend_size, + const bigint_element_t *modulus0, + unsigned int modulus_size, + bigint_element_t *result0, void *tmp ) { + const bigint_t ( minuend_size ) __attribute__ (( may_alias )) + *minuend = ( ( const void * ) minuend0 ); + const bigint_t ( modulus_size ) __attribute__ (( may_alias )) + *modulus = ( ( const void * ) modulus0 ); + bigint_t ( modulus_size ) __attribute__ (( may_alias )) + *result = ( ( void * ) result0 ); + struct { + bigint_t ( minuend_size ) minuend; + bigint_t ( minuend_size ) modulus; + } *temp = tmp; + const unsigned int width = ( 8 * sizeof ( bigint_element_t ) ); + const bigint_element_t msb_mask = ( 1UL << ( width - 1 ) ); + bigint_element_t *element; + unsigned int minuend_max; + unsigned int modulus_max; + unsigned int subshift; + bigint_element_t msb; + int offset; + int shift; + int i; + + /* Start profiling */ + profile_start ( &bigint_mod_profiler ); + + /* Sanity check */ + assert ( minuend_size >= modulus_size ); + assert ( sizeof ( *temp ) == bigint_reduce_tmp_len ( minuend ) ); + + /* Copy minuend and modulus to temporary working space */ + bigint_shrink ( minuend, &temp->minuend ); + bigint_grow ( modulus, &temp->modulus ); + + /* Normalise the modulus + * + * Scale the modulus by shifting left such that both modulus + * "m" and minuend "x" have the same most significant set bit. + * (If this is not possible, then the minuend is already less + * than the modulus, and we may therefore skip reduction + * completely.) + */ + minuend_max = bigint_max_set_bit ( minuend ); + modulus_max = bigint_max_set_bit ( modulus ); + shift = ( minuend_max - modulus_max ); + if ( shift < 0 ) + goto skip; + subshift = ( shift & ( width - 1 ) ); + offset = ( shift / width ); + element = temp->modulus.element; + for ( i = ( ( minuend_max - 1 ) / width ) ; ; i-- ) { + element[i] = ( element[ i - offset ] << subshift ); + if ( i <= offset ) + break; + if ( subshift ) { + element[i] |= ( element[ i - offset - 1 ] + >> ( width - subshift ) ); + } + } + for ( i-- ; i >= 0 ; i-- ) + element[i] = 0; + + /* Reduce the minuend "x" by iteratively adding or subtracting + * the scaled modulus "m". + * + * On each loop iteration, we maintain the invariant: + * + * -2m <= x < 2m + * + * If x is positive, we obtain the new minuend x' by + * subtracting m, otherwise we add m: + * + * 0 <= x < 2m => x' := x - m => -m <= x' < m + * -2m <= x < 0 => x' := x + m => -m <= x' < m + * + * and then halve the modulus (by shifting right): + * + * m' = m/2 + * + * We therefore end up with: + * + * -m <= x' < m => -2m' <= x' < 2m' + * + * i.e. we have preseved the invariant while reducing the + * bounds on x' by one power of two. + * + * The issue remains of how to determine on each iteration + * whether or not x is currently positive, given that both + * input values are unsigned big integers that may use all + * available bits (including the MSB). + * + * On the first loop iteration, we may simply assume that x is + * positive, since it is unmodified from the input value and + * so is positive by definition (even if the MSB is set). We + * therefore unconditionally perform a subtraction on the + * first loop iteration. + * + * Let k be the MSB after normalisation. We then have: + * + * 2^k <= m < 2^(k+1) + * 2^k <= x < 2^(k+1) + * + * On the first loop iteration, we therefore have: + * + * x' = (x - m) + * < 2^(k+1) - 2^k + * < 2^k + * + * Any positive value of x' therefore has its MSB set to zero, + * and so we may validly treat the MSB of x' as a sign bit at + * the end of the first loop iteration. + * + * On all subsequent loop iterations, the starting value m is + * guaranteed to have its MSB set to zero (since it has + * already been shifted right at least once). Since we know + * from above that we preserve the loop invariant: + * + * -m <= x' < m + * + * we immediately know that any positive value of x' also has + * its MSB set to zero, and so we may validly treat the MSB of + * x' as a sign bit at the end of all subsequent loop + * iterations. + * + * After the last loop iteration (when m' has been shifted + * back down to the original value of the modulus), we may + * need to add a single multiple of m' to ensure that x' is + * positive, i.e. lies within the range 0 <= x' < m'. To + * allow for reusing the (inlined) expansion of + * bigint_subtract(), we achieve this via a potential + * additional loop iteration that performs the addition and is + * then guaranteed to terminate (since the result will be + * positive). + */ + for ( msb = 0 ; ( msb || ( shift >= 0 ) ) ; shift-- ) { + if ( msb ) { + bigint_add ( &temp->modulus, &temp->minuend ); + } else { + bigint_subtract ( &temp->modulus, &temp->minuend ); + } + msb = ( temp->minuend.element[ minuend_size - 1 ] & msb_mask ); + if ( shift > 0 ) + bigint_shr ( &temp->modulus ); + } + + skip: + /* Sanity check */ + assert ( ! bigint_is_geq ( &temp->minuend, &temp->modulus ) ); + + /* Copy result */ + bigint_shrink ( &temp->minuend, result ); + + /* Stop profiling */ + profile_stop ( &bigint_mod_profiler ); +} + /** * Perform modular multiplication of big integers * @@ -171,8 +332,6 @@ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, bigint_t ( size * 2 ) result; bigint_t ( size * 2 ) modulus; } *temp = tmp; - int shift; - int i; /* Start profiling */ profile_start ( &bigint_mod_multiply_profiler ); @@ -181,33 +340,13 @@ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, assert ( sizeof ( *temp ) == bigint_mod_multiply_tmp_len ( modulus ) ); /* Perform multiplication */ - profile_start ( &bigint_mod_multiply_multiply_profiler ); bigint_multiply ( multiplicand, multiplier, &temp->result ); - profile_stop ( &bigint_mod_multiply_multiply_profiler ); - - /* Rescale modulus to match result */ - profile_start ( &bigint_mod_multiply_rescale_profiler ); - bigint_grow ( modulus, &temp->modulus ); - shift = ( bigint_max_set_bit ( &temp->result ) - - bigint_max_set_bit ( &temp->modulus ) ); - for ( i = 0 ; i < shift ; i++ ) - bigint_shl ( &temp->modulus ); - profile_stop ( &bigint_mod_multiply_rescale_profiler ); - - /* Subtract multiples of modulus */ - profile_start ( &bigint_mod_multiply_subtract_profiler ); - for ( i = 0 ; i <= shift ; i++ ) { - if ( bigint_is_geq ( &temp->result, &temp->modulus ) ) - bigint_subtract ( &temp->modulus, &temp->result ); - bigint_shr ( &temp->modulus ); - } - profile_stop ( &bigint_mod_multiply_subtract_profiler ); - /* Resize result */ - bigint_shrink ( &temp->result, result ); + /* Reduce result */ + bigint_reduce ( &temp->result, modulus, result, temp ); /* Sanity check */ - assert ( bigint_is_geq ( modulus, result ) ); + assert ( ! bigint_is_geq ( result, modulus ) ); /* Stop profiling */ profile_stop ( &bigint_mod_multiply_profiler ); diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index c556afbc1..c56b2155f 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -217,6 +217,35 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); multiplier_size, (result)->element ); \ } while ( 0 ) +/** + * Reduce big integer + * + * @v minuend Big integer to be reduced + * @v modulus Big integer modulus + * @v result Big integer to hold result + * @v tmp Temporary working space + */ +#define bigint_reduce( minuend, modulus, result, tmp ) do { \ + unsigned int minuend_size = bigint_size (minuend); \ + unsigned int modulus_size = bigint_size (modulus); \ + bigint_reduce_raw ( (minuend)->element, minuend_size, \ + (modulus)->element, modulus_size, \ + (result)->element, tmp ); \ + } while ( 0 ) + +/** + * Calculate temporary working space required for reduction + * + * @v minuend Big integer to be reduced + * @ret len Length of temporary working space + */ +#define bigint_reduce_tmp_len( minuend ) ( { \ + unsigned int size = bigint_size (minuend); \ + sizeof ( struct { \ + bigint_t ( size ) temp_minuend; \ + bigint_t ( size ) temp_modulus; \ + } ); } ) + /** * Perform modular multiplication of big integers * @@ -339,6 +368,11 @@ void bigint_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, unsigned int multiplier_size, bigint_element_t *result0 ); +void bigint_reduce_raw ( const bigint_element_t *minuend0, + unsigned int minuend_size, + const bigint_element_t *modulus0, + unsigned int modulus_size, + bigint_element_t *result0, void *tmp ); void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 65f124f24..104e1f362 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -185,6 +185,21 @@ void bigint_multiply_sample ( const bigint_element_t *multiplicand0, bigint_multiply ( multiplicand, multiplier, result ); } +void bigint_reduce_sample ( const bigint_element_t *minuend0, + unsigned int minuend_size, + const bigint_element_t *modulus0, + unsigned int modulus_size, + bigint_element_t *result0, void *tmp ) { + const bigint_t ( minuend_size ) __attribute__ (( may_alias )) + *minuend = ( ( const void * ) minuend0 ); + const bigint_t ( modulus_size ) __attribute__ (( may_alias )) + *modulus = ( ( const void * ) modulus0 ); + bigint_t ( modulus_size ) __attribute__ (( may_alias )) + *result = ( ( void * ) result0 ); + + bigint_reduce ( minuend, modulus, result, tmp ); +} + void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, @@ -516,6 +531,48 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, sizeof ( result_raw ) ) == 0 ); \ } while ( 0 ) +/** + * Report result of big integer modular direct reduction test + * + * @v minuend Big integer to be reduced + * @v modulus Big integer modulus + * @v expected Big integer expected result + */ +#define bigint_reduce_ok( minuend, modulus, expected ) do { \ + static const uint8_t minuend_raw[] = minuend; \ + static const uint8_t modulus_raw[] = modulus; \ + static const uint8_t expected_raw[] = expected; \ + uint8_t result_raw[ sizeof ( expected_raw ) ]; \ + unsigned int minuend_size = \ + bigint_required_size ( sizeof ( minuend_raw ) ); \ + unsigned int modulus_size = \ + bigint_required_size ( sizeof ( modulus_raw ) ); \ + bigint_t ( minuend_size ) minuend_temp; \ + bigint_t ( modulus_size ) modulus_temp; \ + bigint_t ( modulus_size ) result_temp; \ + size_t tmp_len = bigint_reduce_tmp_len ( &minuend_temp ); \ + uint8_t tmp[tmp_len]; \ + {} /* Fix emacs alignment */ \ + \ + assert ( bigint_size ( &result_temp ) == \ + bigint_size ( &modulus_temp ) ); \ + bigint_init ( &minuend_temp, minuend_raw, \ + sizeof ( minuend_raw ) ); \ + bigint_init ( &modulus_temp, modulus_raw, \ + sizeof ( modulus_raw ) ); \ + DBG ( "Modular reduce:\n" ); \ + DBG_HDA ( 0, &minuend_temp, sizeof ( minuend_temp ) ); \ + DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ + bigint_reduce ( &minuend_temp, &modulus_temp, &result_temp, \ + tmp ); \ + DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ + bigint_done ( &result_temp, result_raw, \ + sizeof ( result_raw ) ); \ + \ + ok ( memcmp ( result_raw, expected_raw, \ + sizeof ( result_raw ) ) == 0 ); \ + } while ( 0 ) + /** * Report result of big integer modular multiplication test * @@ -1674,6 +1731,35 @@ static void bigint_test_exec ( void ) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ) ); + bigint_reduce_ok ( BIGINT ( 0x00 ), + BIGINT ( 0xaf ), + BIGINT ( 0x00 ) ); + bigint_reduce_ok ( BIGINT ( 0xab ), + BIGINT ( 0xab ), + BIGINT ( 0x00 ) ); + bigint_reduce_ok ( BIGINT ( 0x1d, 0x97, 0x63, 0xc9, 0x97, 0xcd, 0x43, + 0xcb, 0x8e, 0x71, 0xac, 0x41, 0xdd ), + BIGINT ( 0xcc, 0x9d, 0xa0, 0x79, 0x96, 0x6a, 0x46, + 0xd5, 0xb4, 0x30, 0xd2, 0x2b, 0xbf ), + BIGINT ( 0x1d, 0x97, 0x63, 0xc9, 0x97, 0xcd, 0x43, + 0xcb, 0x8e, 0x71, 0xac, 0x41, 0xdd ) ); + bigint_reduce_ok ( BIGINT ( 0x21, 0xfa, 0x4f, 0xce, 0x0f, 0x0f, 0x4d, + 0x43, 0xaa, 0xad, 0x21, 0x30, 0xe5 ), + BIGINT ( 0x21, 0xfa, 0x4f, 0xce, 0x0f, 0x0f, 0x4d, + 0x43, 0xaa, 0xad, 0x21, 0x30, 0xe5 ), + BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) ); + bigint_reduce_ok ( BIGINT ( 0xf9, 0x78, 0x96, 0x39, 0xee, 0x98, 0x42, + 0x6a, 0xb8, 0x74, 0x0b, 0xe8, 0x5c, 0x76, + 0x34, 0xaf ), + BIGINT ( 0xf3, 0x65, 0x35, 0x41, 0x66, 0x65 ), + BIGINT ( 0xb3, 0x07, 0xe8, 0xb7, 0x01, 0xf6 ) ); + bigint_reduce_ok ( BIGINT ( 0xfe, 0x30, 0xe1, 0xc6, 0x65, 0x97, 0x48, + 0x2e, 0x94, 0xd4 ), + BIGINT ( 0x47, 0xaa, 0x88, 0x00, 0xd0, 0x30, 0x62, + 0xfb, 0x5d, 0x55 ), + BIGINT ( 0x27, 0x31, 0x49, 0xc3, 0xf5, 0x06, 0x1f, + 0x3c, 0x7c, 0xd5 ) ); bigint_mod_multiply_ok ( BIGINT ( 0x37 ), BIGINT ( 0x67 ), BIGINT ( 0x3f ), -- cgit v1.2.3-55-g7522 From fa1c24d14baf903c549fdb4f30a55b115eccad7d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 21 Oct 2024 16:09:44 +0100 Subject: [crypto] Add bigint_mod_invert() to calculate inverse modulo a power of two Montgomery multiplication requires calculating the inverse of the modulus modulo a larger power of two. Add bigint_mod_invert() to calculate the inverse of any (odd) big integer modulo an arbitrary power of two, using a lightly modified version of the algorithm presented in "A New Algorithm for Inversion mod p^k (Koç, 2017)". The power of two is taken to be 2^k, where k is the number of bits available in the big integer representation of the invertend. The inverse modulo any smaller power of two may be obtained simply by masking off the relevant bits in the inverse. Signed-off-by: Michael Brown --- src/crypto/bigint.c | 54 +++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/bigint.h | 28 ++++++++++++++++++++++ src/tests/bigint_test.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+) (limited to 'src/tests') diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index a8b99ec3c..3f5db8517 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -305,6 +305,60 @@ void bigint_reduce_raw ( const bigint_element_t *minuend0, profile_stop ( &bigint_mod_profiler ); } +/** + * Compute inverse of odd big integer modulo any power of two + * + * @v invertend0 Element 0 of odd big integer to be inverted + * @v inverse0 Element 0 of big integer to hold result + * @v size Number of elements in invertend and result + * @v tmp Temporary working space + */ +void bigint_mod_invert_raw ( const bigint_element_t *invertend0, + bigint_element_t *inverse0, + unsigned int size, void *tmp ) { + const bigint_t ( size ) __attribute__ (( may_alias )) + *invertend = ( ( const void * ) invertend0 ); + bigint_t ( size ) __attribute__ (( may_alias )) + *inverse = ( ( void * ) inverse0 ); + struct { + bigint_t ( size ) residue; + } *temp = tmp; + const unsigned int width = ( 8 * sizeof ( bigint_element_t ) ); + unsigned int i; + + /* Sanity check */ + assert ( invertend->element[0] & 1 ); + + /* Initialise temporary working space and output value */ + memset ( &temp->residue, 0xff, sizeof ( temp->residue ) ); + memset ( inverse, 0, sizeof ( *inverse ) ); + + /* Compute inverse modulo 2^(width) + * + * This method is a lightly modified version of the pseudocode + * presented in "A New Algorithm for Inversion mod p^k (Koç, + * 2017)". + * + * Each loop iteration calculates one bit of the inverse. The + * residue value is the two's complement negation of the value + * "b" as used by Koç, to allow for division by two using a + * logical right shift (since we have no arithmetic right + * shift operation for big integers). + * + * Due to the suffix property of inverses mod 2^k, the result + * represents the least significant bits of the inverse modulo + * an arbitrarily large 2^k. + */ + for ( i = 0 ; i < ( 8 * sizeof ( *inverse ) ) ; i++ ) { + if ( temp->residue.element[0] & 1 ) { + inverse->element[ i / width ] |= + ( 1UL << ( i % width ) ); + bigint_add ( invertend, &temp->residue ); + } + bigint_shr ( &temp->residue ); + } +} + /** * Perform modular multiplication of big integers * diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index c56b2155f..f7900e0e6 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -246,6 +246,31 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); bigint_t ( size ) temp_modulus; \ } ); } ) +/** + * Compute inverse of odd big integer modulo its own size + * + * @v invertend Odd big integer to be inverted + * @v inverse Big integer to hold result + * @v tmp Temporary working space + */ +#define bigint_mod_invert( invertend, inverse, tmp ) do { \ + unsigned int size = bigint_size (invertend); \ + bigint_mod_invert_raw ( (invertend)->element, \ + (inverse)->element, size, tmp ); \ + } while ( 0 ) + +/** + * Calculate temporary working space required for modular inversion + * + * @v invertend Odd big integer to be inverted + * @ret len Length of temporary working space + */ +#define bigint_mod_invert_tmp_len( invertend ) ( { \ + unsigned int size = bigint_size (invertend); \ + sizeof ( struct { \ + bigint_t ( size ) temp_residue; \ + } ); } ) + /** * Perform modular multiplication of big integers * @@ -373,6 +398,9 @@ void bigint_reduce_raw ( const bigint_element_t *minuend0, const bigint_element_t *modulus0, unsigned int modulus_size, bigint_element_t *result0, void *tmp ); +void bigint_mod_invert_raw ( const bigint_element_t *invertend0, + bigint_element_t *inverse0, + unsigned int size, void *tmp ); void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 104e1f362..166c771b9 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -200,6 +200,17 @@ void bigint_reduce_sample ( const bigint_element_t *minuend0, bigint_reduce ( minuend, modulus, result, tmp ); } +void bigint_mod_invert_sample ( const bigint_element_t *invertend0, + bigint_element_t *inverse0, + unsigned int size, void *tmp ) { + const bigint_t ( size ) __attribute__ (( may_alias )) + *invertend = ( ( const void * ) invertend0 ); + bigint_t ( size ) __attribute__ (( may_alias )) + *inverse = ( ( void * ) inverse0 ); + + bigint_mod_invert ( invertend, inverse, tmp ); +} + void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, @@ -573,6 +584,39 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, sizeof ( result_raw ) ) == 0 ); \ } while ( 0 ) +/** + * Report result of big integer modular inversion test + * + * @v invertend Big integer to be inverted + * @v expected Big integer expected result + */ +#define bigint_mod_invert_ok( invertend, expected ) do { \ + static const uint8_t invertend_raw[] = invertend; \ + static const uint8_t expected_raw[] = expected; \ + uint8_t inverse_raw[ sizeof ( expected_raw ) ]; \ + unsigned int size = \ + bigint_required_size ( sizeof ( invertend_raw ) ); \ + bigint_t ( size ) invertend_temp; \ + bigint_t ( size ) inverse_temp; \ + size_t tmp_len = bigint_mod_invert_tmp_len ( &invertend_temp ); \ + uint8_t tmp[tmp_len]; \ + {} /* Fix emacs alignment */ \ + \ + assert ( bigint_size ( &invertend_temp ) == \ + bigint_size ( &inverse_temp ) ); \ + bigint_init ( &invertend_temp, invertend_raw, \ + sizeof ( invertend_raw ) ); \ + DBG ( "Modular invert:\n" ); \ + DBG_HDA ( 0, &invertend_temp, sizeof ( invertend_temp ) ); \ + bigint_mod_invert ( &invertend_temp, &inverse_temp, tmp ); \ + DBG_HDA ( 0, &inverse_temp, sizeof ( inverse_temp ) ); \ + bigint_done ( &inverse_temp, inverse_raw, \ + sizeof ( inverse_raw ) ); \ + \ + ok ( memcmp ( inverse_raw, expected_raw, \ + sizeof ( inverse_raw ) ) == 0 ); \ + } while ( 0 ) + /** * Report result of big integer modular multiplication test * @@ -1760,6 +1804,23 @@ static void bigint_test_exec ( void ) { 0xfb, 0x5d, 0x55 ), BIGINT ( 0x27, 0x31, 0x49, 0xc3, 0xf5, 0x06, 0x1f, 0x3c, 0x7c, 0xd5 ) ); + bigint_mod_invert_ok ( BIGINT ( 0x01 ), BIGINT ( 0x01 ) ); + bigint_mod_invert_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff ), + BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff ) ); + bigint_mod_invert_ok ( BIGINT ( 0x95, 0x6a, 0xc5, 0xe7, 0x2e, 0x5b, + 0x44, 0xed, 0xbf, 0x7e, 0xfe, 0x8d, + 0xf4, 0x5a, 0x48, 0xc1 ), + BIGINT ( 0xad, 0xb8, 0x3d, 0x85, 0x10, 0xdf, + 0xea, 0x70, 0x71, 0x2c, 0x80, 0xf4, + 0x6e, 0x66, 0x47, 0x41 ) ); + bigint_mod_invert_ok ( BIGINT ( 0x35, 0xe4, 0x80, 0x48, 0xdd, 0xa1, + 0x46, 0xc0, 0x84, 0x63, 0xc1, 0xe4, + 0xf7, 0xbf, 0xb3, 0x05 ), + BIGINT ( 0xf2, 0x9c, 0x63, 0x29, 0xfa, 0xe4, + 0xbf, 0x90, 0xa6, 0x9a, 0xec, 0xcf, + 0x5f, 0xe2, 0x21, 0xcd ) ); bigint_mod_multiply_ok ( BIGINT ( 0x37 ), BIGINT ( 0x67 ), BIGINT ( 0x3f ), -- cgit v1.2.3-55-g7522 From 167a08f08928c7e469f50d5d364287abb784e99c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 26 Nov 2024 12:53:01 +0000 Subject: [crypto] Expose carry flag from big integer addition and subtraction Expose the effective carry (or borrow) out flag from big integer addition and subtraction, and use this to elide an explicit bit test when performing x25519 reduction. Signed-off-by: Michael Brown --- src/arch/arm32/include/bits/bigint.h | 23 ++++++++---- src/arch/arm64/include/bits/bigint.h | 19 +++++++--- src/arch/loong64/include/bits/bigint.h | 36 ++++++++++-------- src/arch/riscv/include/bits/bigint.h | 36 ++++++++++-------- src/arch/x86/include/bits/bigint.h | 20 +++++++--- src/crypto/x25519.c | 5 ++- src/include/ipxe/bigint.h | 18 +++++---- src/tests/bigint_test.c | 68 ++++++++++++++++++++++------------ 8 files changed, 140 insertions(+), 85 deletions(-) (limited to 'src/tests') diff --git a/src/arch/arm32/include/bits/bigint.h b/src/arch/arm32/include/bits/bigint.h index 39d3dc347..95de32d83 100644 --- a/src/arch/arm32/include/bits/bigint.h +++ b/src/arch/arm32/include/bits/bigint.h @@ -43,8 +43,9 @@ bigint_init_raw ( uint32_t *value0, unsigned int size, * @v addend0 Element 0 of big integer to add * @v value0 Element 0 of big integer to be added to * @v size Number of elements + * @ret carry Carry out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_add_raw ( const uint32_t *addend0, uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = @@ -54,8 +55,9 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0, uint32_t *discard_end; uint32_t discard_addend_i; uint32_t discard_value_i; + int carry; - __asm__ __volatile__ ( "adds %2, %0, %8, lsl #2\n\t" /* clear CF */ + __asm__ __volatile__ ( "adds %2, %0, %9, lsl #2\n\t" /* clear CF */ "\n1:\n\t" "ldmia %0!, {%3}\n\t" "ldr %4, [%1]\n\t" @@ -68,9 +70,11 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0, "=l" ( discard_end ), "=l" ( discard_addend_i ), "=l" ( discard_value_i ), + "=@cccs" ( carry ), "+m" ( *value ) - : "0" ( addend0 ), "1" ( value0 ), "l" ( size ) - : "cc" ); + : "0" ( addend0 ), "1" ( value0 ), + "l" ( size ) ); + return carry; } /** @@ -79,8 +83,9 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0, * @v subtrahend0 Element 0 of big integer to subtract * @v value0 Element 0 of big integer to be subtracted from * @v size Number of elements + * @ret borrow Borrow out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = @@ -90,8 +95,9 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, uint32_t *discard_end; uint32_t discard_subtrahend_i; uint32_t discard_value_i; + int borrow; - __asm__ __volatile__ ( "add %2, %0, %8, lsl #2\n\t" + __asm__ __volatile__ ( "add %2, %0, %9, lsl #2\n\t" "cmp %2, %0\n\t" /* set CF */ "\n1:\n\t" "ldmia %0!, {%3}\n\t" @@ -105,10 +111,11 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, "=l" ( discard_end ), "=l" ( discard_subtrahend_i ), "=l" ( discard_value_i ), + "=@cccc" ( borrow ), "+m" ( *value ) : "0" ( subtrahend0 ), "1" ( value0 ), - "l" ( size ) - : "cc" ); + "l" ( size ) ); + return borrow; } /** diff --git a/src/arch/arm64/include/bits/bigint.h b/src/arch/arm64/include/bits/bigint.h index 50493499e..5f79dc0c3 100644 --- a/src/arch/arm64/include/bits/bigint.h +++ b/src/arch/arm64/include/bits/bigint.h @@ -43,8 +43,9 @@ bigint_init_raw ( uint64_t *value0, unsigned int size, * @v addend0 Element 0 of big integer to add * @v value0 Element 0 of big integer to be added to * @v size Number of elements + * @ret carry Carry out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_add_raw ( const uint64_t *addend0, uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = @@ -54,6 +55,7 @@ bigint_add_raw ( const uint64_t *addend0, uint64_t *value0, uint64_t discard_addend_i; uint64_t discard_value_i; unsigned int discard_size; + int carry; __asm__ __volatile__ ( "cmn xzr, xzr\n\t" /* clear CF */ "\n1:\n\t" @@ -68,9 +70,11 @@ bigint_add_raw ( const uint64_t *addend0, uint64_t *value0, "=r" ( discard_size ), "=r" ( discard_addend_i ), "=r" ( discard_value_i ), + "=@cccs" ( carry ), "+m" ( *value ) - : "0" ( addend0 ), "1" ( value0 ), "2" ( size ) - : "cc" ); + : "0" ( addend0 ), "1" ( value0 ), + "2" ( size ) ); + return carry; } /** @@ -79,8 +83,9 @@ bigint_add_raw ( const uint64_t *addend0, uint64_t *value0, * @v subtrahend0 Element 0 of big integer to subtract * @v value0 Element 0 of big integer to be subtracted from * @v size Number of elements + * @ret borrow Borrow out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = @@ -90,6 +95,7 @@ bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, uint64_t discard_subtrahend_i; uint64_t discard_value_i; unsigned int discard_size; + int borrow; __asm__ __volatile__ ( "cmp xzr, xzr\n\t" /* set CF */ "\n1:\n\t" @@ -104,10 +110,11 @@ bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, "=r" ( discard_size ), "=r" ( discard_subtrahend_i ), "=r" ( discard_value_i ), + "=@cccc" ( borrow ), "+m" ( *value ) : "0" ( subtrahend0 ), "1" ( value0 ), - "2" ( size ) - : "cc" ); + "2" ( size ) ); + return borrow; } /** diff --git a/src/arch/loong64/include/bits/bigint.h b/src/arch/loong64/include/bits/bigint.h index 234d8dfa7..0222354df 100644 --- a/src/arch/loong64/include/bits/bigint.h +++ b/src/arch/loong64/include/bits/bigint.h @@ -43,8 +43,9 @@ bigint_init_raw ( uint64_t *value0, unsigned int size, * @v addend0 Element 0 of big integer to add * @v value0 Element 0 of big integer to be added to * @v size Number of elements + * @ret carry Carry out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_add_raw ( const uint64_t *addend0, uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = @@ -53,20 +54,20 @@ bigint_add_raw ( const uint64_t *addend0, uint64_t *value0, uint64_t *discard_value; uint64_t discard_addend_i; uint64_t discard_value_i; - uint64_t discard_carry; uint64_t discard_temp; unsigned int discard_size; + uint64_t carry; __asm__ __volatile__ ( "\n1:\n\t" /* Load addend[i] and value[i] */ "ld.d %3, %0, 0\n\t" "ld.d %4, %1, 0\n\t" /* Add carry flag and addend */ - "add.d %4, %4, %5\n\t" - "sltu %6, %4, %5\n\t" + "add.d %4, %4, %6\n\t" + "sltu %5, %4, %6\n\t" "add.d %4, %4, %3\n\t" - "sltu %5, %4, %3\n\t" - "or %5, %5, %6\n\t" + "sltu %6, %4, %3\n\t" + "or %6, %5, %6\n\t" /* Store value[i] */ "st.d %4, %1, 0\n\t" /* Loop */ @@ -79,11 +80,12 @@ bigint_add_raw ( const uint64_t *addend0, uint64_t *value0, "=r" ( discard_size ), "=r" ( discard_addend_i ), "=r" ( discard_value_i ), - "=r" ( discard_carry ), "=r" ( discard_temp ), + "=r" ( carry ), "+m" ( *value ) : "0" ( addend0 ), "1" ( value0 ), - "2" ( size ), "5" ( 0 ) ); + "2" ( size ), "6" ( 0 ) ); + return carry; } /** @@ -92,8 +94,9 @@ bigint_add_raw ( const uint64_t *addend0, uint64_t *value0, * @v subtrahend0 Element 0 of big integer to subtract * @v value0 Element 0 of big integer to be subtracted from * @v size Number of elements + * @ret borrow Borrow out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = @@ -102,20 +105,20 @@ bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, uint64_t *discard_value; uint64_t discard_subtrahend_i; uint64_t discard_value_i; - uint64_t discard_carry; uint64_t discard_temp; unsigned int discard_size; + uint64_t borrow; __asm__ __volatile__ ( "\n1:\n\t" /* Load subtrahend[i] and value[i] */ "ld.d %3, %0, 0\n\t" "ld.d %4, %1, 0\n\t" /* Subtract carry flag and subtrahend */ - "sltu %6, %4, %5\n\t" - "sub.d %4, %4, %5\n\t" - "sltu %5, %4, %3\n\t" + "sltu %5, %4, %6\n\t" + "sub.d %4, %4, %6\n\t" + "sltu %6, %4, %3\n\t" "sub.d %4, %4, %3\n\t" - "or %5, %5, %6\n\t" + "or %6, %5, %6\n\t" /* Store value[i] */ "st.d %4, %1, 0\n\t" /* Loop */ @@ -128,11 +131,12 @@ bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, "=r" ( discard_size ), "=r" ( discard_subtrahend_i ), "=r" ( discard_value_i ), - "=r" ( discard_carry ), "=r" ( discard_temp ), + "=r" ( borrow ), "+m" ( *value ) : "0" ( subtrahend0 ), "1" ( value0 ), - "2" ( size ), "5" ( 0 ) ); + "2" ( size ), "6" ( 0 ) ); + return borrow; } /** diff --git a/src/arch/riscv/include/bits/bigint.h b/src/arch/riscv/include/bits/bigint.h index 5b22b9ac7..ab1070d88 100644 --- a/src/arch/riscv/include/bits/bigint.h +++ b/src/arch/riscv/include/bits/bigint.h @@ -43,8 +43,9 @@ bigint_init_raw ( unsigned long *value0, unsigned int size, * @v addend0 Element 0 of big integer to add * @v value0 Element 0 of big integer to be added to * @v size Number of elements + * @ret carry Carry out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_add_raw ( const unsigned long *addend0, unsigned long *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = @@ -54,19 +55,19 @@ bigint_add_raw ( const unsigned long *addend0, unsigned long *value0, unsigned long *discard_value; unsigned long discard_addend_i; unsigned long discard_value_i; - unsigned long discard_carry; unsigned long discard_temp; + unsigned long carry; __asm__ __volatile__ ( "\n1:\n\t" /* Load addend[i] and value[i] */ LOADN " %2, (%0)\n\t" LOADN " %3, (%1)\n\t" /* Add carry flag and addend */ - "add %3, %3, %4\n\t" - "sltu %5, %3, %4\n\t" + "add %3, %3, %5\n\t" + "sltu %4, %3, %5\n\t" "add %3, %3, %2\n\t" - "sltu %4, %3, %2\n\t" - "or %4, %4, %5\n\t" + "sltu %5, %3, %2\n\t" + "or %5, %4, %5\n\t" /* Store value[i] */ STOREN " %3, (%1)\n\t" /* Loop */ @@ -77,12 +78,13 @@ bigint_add_raw ( const unsigned long *addend0, unsigned long *value0, "=&r" ( discard_value ), "=&r" ( discard_addend_i ), "=&r" ( discard_value_i ), - "=&r" ( discard_carry ), "=&r" ( discard_temp ), + "=&r" ( carry ), "+m" ( *value ) : "r" ( valueN ), "i" ( sizeof ( unsigned long ) ), - "0" ( addend0 ), "1" ( value0 ), "4" ( 0 ) ); + "0" ( addend0 ), "1" ( value0 ), "5" ( 0 ) ); + return carry; } /** @@ -91,8 +93,9 @@ bigint_add_raw ( const unsigned long *addend0, unsigned long *value0, * @v subtrahend0 Element 0 of big integer to subtract * @v value0 Element 0 of big integer to be subtracted from * @v size Number of elements + * @ret borrow Borrow out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_subtract_raw ( const unsigned long *subtrahend0, unsigned long *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = @@ -102,19 +105,19 @@ bigint_subtract_raw ( const unsigned long *subtrahend0, unsigned long *value0, unsigned long *discard_value; unsigned long discard_subtrahend_i; unsigned long discard_value_i; - unsigned long discard_carry; unsigned long discard_temp; + unsigned long borrow; __asm__ __volatile__ ( "\n1:\n\t" /* Load subtrahend[i] and value[i] */ LOADN " %2, (%0)\n\t" LOADN " %3, (%1)\n\t" /* Subtract carry flag and subtrahend */ - "sltu %5, %3, %4\n\t" - "sub %3, %3, %4\n\t" - "sltu %4, %3, %2\n\t" + "sltu %4, %3, %5\n\t" + "sub %3, %3, %5\n\t" + "sltu %5, %3, %2\n\t" "sub %3, %3, %2\n\t" - "or %4, %4, %5\n\t" + "or %5, %5, %4\n\t" /* Store value[i] */ STOREN " %3, (%1)\n\t" /* Loop */ @@ -125,13 +128,14 @@ bigint_subtract_raw ( const unsigned long *subtrahend0, unsigned long *value0, "=&r" ( discard_value ), "=&r" ( discard_subtrahend_i ), "=&r" ( discard_value_i ), - "=&r" ( discard_carry ), "=&r" ( discard_temp ), + "=&r" ( borrow ), "+m" ( *value ) : "r" ( valueN ), "i" ( sizeof ( unsigned long ) ), "0" ( subtrahend0 ), "1" ( value0 ), - "4" ( 0 ) ); + "5" ( 0 ) ); + return borrow; } /** diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h index 5580030ee..4026ca481 100644 --- a/src/arch/x86/include/bits/bigint.h +++ b/src/arch/x86/include/bits/bigint.h @@ -52,8 +52,9 @@ bigint_init_raw ( uint32_t *value0, unsigned int size, * @v addend0 Element 0 of big integer to add * @v value0 Element 0 of big integer to be added to * @v size Number of elements + * @ret carry Carry flag */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_add_raw ( const uint32_t *addend0, uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = @@ -61,17 +62,20 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0, long index; void *discard_S; long discard_c; + int carry; __asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */ "\n1:\n\t" "lodsl\n\t" - "adcl %%eax, (%4,%0,4)\n\t" + "adcl %%eax, (%5,%0,4)\n\t" "inc %0\n\t" /* Does not affect CF */ "loop 1b\n\t" : "=&r" ( index ), "=&S" ( discard_S ), - "=&c" ( discard_c ), "+m" ( *value ) + "=&c" ( discard_c ), "=@ccc" ( carry ), + "+m" ( *value ) : "r" ( value0 ), "1" ( addend0 ), "2" ( size ) : "eax" ); + return carry; } /** @@ -80,8 +84,9 @@ bigint_add_raw ( const uint32_t *addend0, uint32_t *value0, * @v subtrahend0 Element 0 of big integer to subtract * @v value0 Element 0 of big integer to be subtracted from * @v size Number of elements + * @ret borrow Borrow flag */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = @@ -89,18 +94,21 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, long index; void *discard_S; long discard_c; + int borrow; __asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */ "\n1:\n\t" "lodsl\n\t" - "sbbl %%eax, (%4,%0,4)\n\t" + "sbbl %%eax, (%5,%0,4)\n\t" "inc %0\n\t" /* Does not affect CF */ "loop 1b\n\t" : "=&r" ( index ), "=&S" ( discard_S ), - "=&c" ( discard_c ), "+m" ( *value ) + "=&c" ( discard_c ), "=@ccc" ( borrow ), + "+m" ( *value ) : "r" ( value0 ), "1" ( subtrahend0 ), "2" ( size ) : "eax" ); + return borrow; } /** diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c index 19f9a2c02..ab5d2e8b0 100644 --- a/src/crypto/x25519.c +++ b/src/crypto/x25519.c @@ -564,6 +564,7 @@ void x25519_invert ( const union x25519_oct258 *invertend, */ static void x25519_reduce_by ( const x25519_t *subtrahend, x25519_t *value ) { x25519_t tmp; + int underflow; /* Conditionally subtract subtrahend * @@ -571,8 +572,8 @@ static void x25519_reduce_by ( const x25519_t *subtrahend, x25519_t *value ) { * time) if the subtraction underflows. */ bigint_copy ( value, &tmp ); - bigint_subtract ( subtrahend, value ); - bigint_swap ( value, &tmp, bigint_msb_is_set ( value ) ); + underflow = bigint_subtract ( subtrahend, value ); + bigint_swap ( value, &tmp, underflow ); } /** diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index a85761815..2a0a200c5 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -70,23 +70,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * * @v addend Big integer to add * @v value Big integer to be added to + * @ret carry Carry out */ -#define bigint_add( addend, value ) do { \ +#define bigint_add( addend, value ) ( { \ unsigned int size = bigint_size (addend); \ bigint_add_raw ( (addend)->element, (value)->element, size ); \ - } while ( 0 ) + } ) /** * Subtract big integers * * @v subtrahend Big integer to subtract * @v value Big integer to be subtracted from + * @ret borrow Borrow out */ -#define bigint_subtract( subtrahend, value ) do { \ +#define bigint_subtract( subtrahend, value ) ( { \ unsigned int size = bigint_size (subtrahend); \ bigint_subtract_raw ( (subtrahend)->element, (value)->element, \ size ); \ - } while ( 0 ) + } ) /** * Shift big integer left @@ -389,10 +391,10 @@ void bigint_init_raw ( bigint_element_t *value0, unsigned int size, const void *data, size_t len ); void bigint_done_raw ( const bigint_element_t *value0, unsigned int size, void *out, size_t len ); -void bigint_add_raw ( const bigint_element_t *addend0, - bigint_element_t *value0, unsigned int size ); -void bigint_subtract_raw ( const bigint_element_t *subtrahend0, - bigint_element_t *value0, unsigned int size ); +int bigint_add_raw ( const bigint_element_t *addend0, + bigint_element_t *value0, unsigned int size ); +int bigint_subtract_raw ( const bigint_element_t *subtrahend0, + bigint_element_t *value0, unsigned int size ); void bigint_shl_raw ( bigint_element_t *value0, unsigned int size ); void bigint_shr_raw ( bigint_element_t *value0, unsigned int size ); int bigint_is_zero_raw ( const bigint_element_t *value0, unsigned int size ); diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 166c771b9..271d76723 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -58,24 +58,24 @@ void bigint_done_sample ( const bigint_element_t *value0, unsigned int size, bigint_done ( value, out, len ); } -void bigint_add_sample ( const bigint_element_t *addend0, - bigint_element_t *value0, unsigned int size ) { +int bigint_add_sample ( const bigint_element_t *addend0, + bigint_element_t *value0, unsigned int size ) { const bigint_t ( size ) *addend __attribute__ (( may_alias )) = ( ( const void * ) addend0 ); bigint_t ( size ) *value __attribute__ (( may_alias )) = ( ( void * ) value0 ); - bigint_add ( addend, value ); + return bigint_add ( addend, value ); } -void bigint_subtract_sample ( const bigint_element_t *subtrahend0, - bigint_element_t *value0, unsigned int size ) { +int bigint_subtract_sample ( const bigint_element_t *subtrahend0, + bigint_element_t *value0, unsigned int size ) { const bigint_t ( size ) *subtrahend __attribute__ (( may_alias )) = ( ( const void * ) subtrahend0 ); bigint_t ( size ) *value __attribute__ (( may_alias )) = ( ( void * ) value0 ); - bigint_subtract ( subtrahend, value ); + return bigint_subtract ( subtrahend, value ); } void bigint_shl_sample ( bigint_element_t *value0, unsigned int size ) { @@ -253,16 +253,19 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * @v addend Big integer to add * @v value Big integer to be added to * @v expected Big integer expected result + * @v overflow Expected result overflows range */ -#define bigint_add_ok( addend, value, expected ) do { \ +#define bigint_add_ok( addend, value, expected, overflow ) do { \ static const uint8_t addend_raw[] = addend; \ static const uint8_t value_raw[] = value; \ static const uint8_t expected_raw[] = expected; \ uint8_t result_raw[ sizeof ( expected_raw ) ]; \ unsigned int size = \ bigint_required_size ( sizeof ( value_raw ) ); \ + unsigned int msb = ( 8 * sizeof ( value_raw ) ); \ bigint_t ( size ) addend_temp; \ bigint_t ( size ) value_temp; \ + int carry; \ {} /* Fix emacs alignment */ \ \ assert ( bigint_size ( &addend_temp ) == \ @@ -273,12 +276,15 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, DBG ( "Add:\n" ); \ DBG_HDA ( 0, &addend_temp, sizeof ( addend_temp ) ); \ DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bigint_add ( &addend_temp, &value_temp ); \ + carry = bigint_add ( &addend_temp, &value_temp ); \ DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ \ ok ( memcmp ( result_raw, expected_raw, \ sizeof ( result_raw ) ) == 0 ); \ + if ( sizeof ( result_raw ) < sizeof ( value_temp ) ) \ + carry += bigint_bit_is_set ( &value_temp, msb ); \ + ok ( carry == overflow ); \ } while ( 0 ) /** @@ -287,8 +293,10 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * @v subtrahend Big integer to subtract * @v value Big integer to be subtracted from * @v expected Big integer expected result + * @v underflow Expected result underflows range */ -#define bigint_subtract_ok( subtrahend, value, expected ) do { \ +#define bigint_subtract_ok( subtrahend, value, expected, \ + underflow ) do { \ static const uint8_t subtrahend_raw[] = subtrahend; \ static const uint8_t value_raw[] = value; \ static const uint8_t expected_raw[] = expected; \ @@ -297,6 +305,7 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, bigint_required_size ( sizeof ( value_raw ) ); \ bigint_t ( size ) subtrahend_temp; \ bigint_t ( size ) value_temp; \ + int borrow; \ {} /* Fix emacs alignment */ \ \ assert ( bigint_size ( &subtrahend_temp ) == \ @@ -307,12 +316,13 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, DBG ( "Subtract:\n" ); \ DBG_HDA ( 0, &subtrahend_temp, sizeof ( subtrahend_temp ) ); \ DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bigint_subtract ( &subtrahend_temp, &value_temp ); \ + borrow = bigint_subtract ( &subtrahend_temp, &value_temp ); \ DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ \ ok ( memcmp ( result_raw, expected_raw, \ sizeof ( result_raw ) ) == 0 ); \ + ok ( borrow == underflow ); \ } while ( 0 ) /** @@ -724,16 +734,28 @@ static void bigint_test_exec ( void ) { bigint_add_ok ( BIGINT ( 0x8a ), BIGINT ( 0x43 ), - BIGINT ( 0xcd ) ); + BIGINT ( 0xcd ), 0 ); bigint_add_ok ( BIGINT ( 0xc5, 0x7b ), BIGINT ( 0xd6, 0xb1 ), - BIGINT ( 0x9c, 0x2c ) ); + BIGINT ( 0x9c, 0x2c ), 1 ); bigint_add_ok ( BIGINT ( 0xf9, 0xd9, 0xdc ), BIGINT ( 0x6d, 0x4b, 0xca ), - BIGINT ( 0x67, 0x25, 0xa6 ) ); + BIGINT ( 0x67, 0x25, 0xa6 ), 1 ); bigint_add_ok ( BIGINT ( 0xdd, 0xc2, 0x20, 0x5f ), BIGINT ( 0x80, 0x32, 0xc4, 0xb0 ), - BIGINT ( 0x5d, 0xf4, 0xe5, 0x0f ) ); + BIGINT ( 0x5d, 0xf4, 0xe5, 0x0f ), 1 ); + bigint_add_ok ( BIGINT ( 0x5e, 0x46, 0x4d, 0xc6, 0xa2, 0x7d, 0x45, + 0xc3 ), + BIGINT ( 0xd6, 0xc0, 0xd7, 0xd4, 0xf6, 0x04, 0x47, + 0xed ), + BIGINT ( 0x35, 0x07, 0x25, 0x9b, 0x98, 0x81, 0x8d, + 0xb0 ), 1 ); + bigint_add_ok ( BIGINT ( 0x0e, 0x46, 0x4d, 0xc6, 0xa2, 0x7d, 0x45, + 0xc3 ), + BIGINT ( 0xd6, 0xc0, 0xd7, 0xd4, 0xf6, 0x04, 0x47, + 0xed ), + BIGINT ( 0xe5, 0x07, 0x25, 0x9b, 0x98, 0x81, 0x8d, + 0xb0 ), 0 ); bigint_add_ok ( BIGINT ( 0x01, 0xed, 0x45, 0x4b, 0x41, 0xeb, 0x4c, 0x2e, 0x53, 0x07, 0x15, 0x51, 0x56, 0x47, 0x29, 0xfc, 0x9c, 0xbd, 0xbd, 0xfb, 0x1b, @@ -745,7 +767,7 @@ static void bigint_test_exec ( void ) { BIGINT ( 0x75, 0xdb, 0x41, 0x80, 0x73, 0x0e, 0x23, 0xe0, 0x3d, 0x98, 0x70, 0x36, 0x11, 0x03, 0xcb, 0x35, 0x0f, 0x6c, 0x09, 0x17, 0xdc, - 0xd6, 0xd0 ) ); + 0xd6, 0xd0 ), 0 ); bigint_add_ok ( BIGINT ( 0x06, 0x8e, 0xd6, 0x18, 0xbb, 0x4b, 0x0c, 0xc5, 0x85, 0xde, 0xee, 0x9b, 0x3f, 0x65, 0x63, 0x86, 0xf5, 0x5a, 0x9f, 0xa2, 0xd7, @@ -802,19 +824,19 @@ static void bigint_test_exec ( void ) { 0x68, 0x76, 0xf5, 0x20, 0xa1, 0xa8, 0x1a, 0x9f, 0x60, 0x58, 0xff, 0xb6, 0x76, 0x45, 0xe6, 0xed, 0x61, 0x8d, 0xe6, 0xc0, 0x72, - 0x1c, 0x07 ) ); + 0x1c, 0x07 ), 0 ); bigint_subtract_ok ( BIGINT ( 0x83 ), BIGINT ( 0x50 ), - BIGINT ( 0xcd ) ); + BIGINT ( 0xcd ), 1 ); bigint_subtract_ok ( BIGINT ( 0x2c, 0x7c ), BIGINT ( 0x49, 0x0e ), - BIGINT ( 0x1c, 0x92 ) ); + BIGINT ( 0x1c, 0x92 ), 0 ); bigint_subtract_ok ( BIGINT ( 0x9c, 0x30, 0xbf ), BIGINT ( 0xde, 0x4e, 0x07 ), - BIGINT ( 0x42, 0x1d, 0x48 ) ); + BIGINT ( 0x42, 0x1d, 0x48 ), 0 ); bigint_subtract_ok ( BIGINT ( 0xbb, 0x77, 0x32, 0x5a ), BIGINT ( 0x5a, 0xd5, 0xfe, 0x28 ), - BIGINT ( 0x9f, 0x5e, 0xcb, 0xce ) ); + BIGINT ( 0x9f, 0x5e, 0xcb, 0xce ), 1 ); bigint_subtract_ok ( BIGINT ( 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ), @@ -823,7 +845,7 @@ static void bigint_test_exec ( void ) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a ), BIGINT ( 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b ) ); + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b ), 1 ); bigint_subtract_ok ( BIGINT ( 0x7b, 0xaa, 0x16, 0xcf, 0x15, 0x87, 0xe0, 0x4f, 0x2c, 0xa3, 0xec, 0x2f, 0x46, 0xfb, 0x83, 0xc6, 0xe0, 0xee, @@ -835,7 +857,7 @@ static void bigint_test_exec ( void ) { BIGINT ( 0xca, 0xab, 0x9f, 0x54, 0x4e, 0x48, 0x75, 0x8c, 0x63, 0x28, 0x69, 0x78, 0xe8, 0x8a, 0x3d, 0xd8, 0x4b, 0x24, - 0xb8, 0xa4, 0x71, 0x6d, 0x6b ) ); + 0xb8, 0xa4, 0x71, 0x6d, 0x6b ), 1 ); bigint_subtract_ok ( BIGINT ( 0x5b, 0x06, 0x77, 0x7b, 0xfd, 0x34, 0x5f, 0x0f, 0xd9, 0xbd, 0x8e, 0x5d, 0xc8, 0x4a, 0x70, 0x95, 0x1b, 0xb6, @@ -901,7 +923,7 @@ static void bigint_test_exec ( void ) { 0x29, 0x8c, 0x43, 0x9f, 0xf0, 0x9d, 0xda, 0xc8, 0x8c, 0x71, 0x86, 0x97, 0x7f, 0xcb, 0x94, 0x31, 0x1d, 0xbc, - 0x44, 0x1a ) ); + 0x44, 0x1a ), 0 ); bigint_shl_ok ( BIGINT ( 0xe0 ), BIGINT ( 0xc0 ) ); bigint_shl_ok ( BIGINT ( 0x43, 0x1d ), -- cgit v1.2.3-55-g7522 From 9cbf5c4f86b45773badec2498fac22e8bc6d7dd1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 26 Nov 2024 14:45:51 +0000 Subject: [crypto] Eliminate temporary working space for bigint_reduce() Direct modular reduction is expected to be used in situations where there is no requirement to retain the original (unreduced) value. Modify the API for bigint_reduce() to reduce the value in place, (removing the separate result buffer), impose a constraint that the modulus and value have the same size, and require the modulus to be passed in writable memory (to allow for scaling in place). This removes the requirement for additional temporary working space. Reverse the order of arguments so that the constant input is first, to match the usage pattern for bigint_add() et al. Signed-off-by: Michael Brown --- src/crypto/bigint.c | 71 ++++++++++++++------------------------- src/include/ipxe/bigint.h | 34 ++++--------------- src/tests/bigint_test.c | 84 ++++++++++++++++++++++------------------------- 3 files changed, 72 insertions(+), 117 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index 35701a1d0..4b37c062b 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -139,32 +139,20 @@ void bigint_multiply_raw ( const bigint_element_t *multiplicand0, /** * Reduce big integer * - * @v minuend0 Element 0 of big integer to be reduced - * @v minuend_size Number of elements in minuend * @v modulus0 Element 0 of big integer modulus - * @v modulus_size Number of elements in modulus and result - * @v result0 Element 0 of big integer to hold result - * @v tmp Temporary working space + * @v value0 Element 0 of big integer to be reduced + * @v size Number of elements in modulus and value */ -void bigint_reduce_raw ( const bigint_element_t *minuend0, - unsigned int minuend_size, - const bigint_element_t *modulus0, - unsigned int modulus_size, - bigint_element_t *result0, void *tmp ) { - const bigint_t ( minuend_size ) __attribute__ (( may_alias )) - *minuend = ( ( const void * ) minuend0 ); - const bigint_t ( modulus_size ) __attribute__ (( may_alias )) - *modulus = ( ( const void * ) modulus0 ); - bigint_t ( modulus_size ) __attribute__ (( may_alias )) - *result = ( ( void * ) result0 ); - struct { - bigint_t ( minuend_size ) minuend; - bigint_t ( minuend_size ) modulus; - } *temp = tmp; +void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0, + unsigned int size ) { + bigint_t ( size ) __attribute__ (( may_alias )) + *modulus = ( ( void * ) modulus0 ); + bigint_t ( size ) __attribute__ (( may_alias )) + *value = ( ( void * ) value0 ); const unsigned int width = ( 8 * sizeof ( bigint_element_t ) ); bigint_element_t *element; - unsigned int minuend_max; unsigned int modulus_max; + unsigned int value_max; unsigned int subshift; int offset; int shift; @@ -174,31 +162,23 @@ void bigint_reduce_raw ( const bigint_element_t *minuend0, /* Start profiling */ profile_start ( &bigint_mod_profiler ); - /* Sanity check */ - assert ( minuend_size >= modulus_size ); - assert ( sizeof ( *temp ) == bigint_reduce_tmp_len ( minuend ) ); - - /* Copy minuend and modulus to temporary working space */ - bigint_shrink ( minuend, &temp->minuend ); - bigint_grow ( modulus, &temp->modulus ); - /* Normalise the modulus * * Scale the modulus by shifting left such that both modulus - * "m" and minuend "x" have the same most significant set bit. - * (If this is not possible, then the minuend is already less + * "m" and value "x" have the same most significant set bit. + * (If this is not possible, then the value is already less * than the modulus, and we may therefore skip reduction * completely.) */ - minuend_max = bigint_max_set_bit ( minuend ); + value_max = bigint_max_set_bit ( value ); modulus_max = bigint_max_set_bit ( modulus ); - shift = ( minuend_max - modulus_max ); + shift = ( value_max - modulus_max ); if ( shift < 0 ) goto skip; subshift = ( shift & ( width - 1 ) ); offset = ( shift / width ); - element = temp->modulus.element; - for ( i = ( ( minuend_max - 1 ) / width ) ; ; i-- ) { + element = modulus->element; + for ( i = ( ( value_max - 1 ) / width ) ; ; i-- ) { element[i] = ( element[ i - offset ] << subshift ); if ( i <= offset ) break; @@ -210,14 +190,14 @@ void bigint_reduce_raw ( const bigint_element_t *minuend0, for ( i-- ; i >= 0 ; i-- ) element[i] = 0; - /* Reduce the minuend "x" by iteratively adding or subtracting + /* Reduce the value "x" by iteratively adding or subtracting * the scaled modulus "m". * * On each loop iteration, we maintain the invariant: * * -2m <= x < 2m * - * If x is positive, we obtain the new minuend x' by + * If x is positive, we obtain the new value x' by * subtracting m, otherwise we add m: * * 0 <= x < 2m => x' := x - m => -m <= x' < m @@ -284,21 +264,18 @@ void bigint_reduce_raw ( const bigint_element_t *minuend0, */ for ( msb = 0 ; ( msb || ( shift >= 0 ) ) ; shift-- ) { if ( msb ) { - bigint_add ( &temp->modulus, &temp->minuend ); + bigint_add ( modulus, value ); } else { - bigint_subtract ( &temp->modulus, &temp->minuend ); + bigint_subtract ( modulus, value ); } - msb = bigint_msb_is_set ( &temp->minuend ); + msb = bigint_msb_is_set ( value ); if ( shift > 0 ) - bigint_shr ( &temp->modulus ); + bigint_shr ( modulus ); } skip: /* Sanity check */ - assert ( ! bigint_is_geq ( &temp->minuend, &temp->modulus ) ); - - /* Copy result */ - bigint_shrink ( &temp->minuend, result ); + assert ( ! bigint_is_geq ( value, modulus ) ); /* Stop profiling */ profile_stop ( &bigint_mod_profiler ); @@ -396,7 +373,9 @@ void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, bigint_multiply ( multiplicand, multiplier, &temp->result ); /* Reduce result */ - bigint_reduce ( &temp->result, modulus, result, temp ); + bigint_grow ( modulus, &temp->modulus ); + bigint_reduce ( &temp->modulus, &temp->result ); + bigint_shrink ( &temp->result, result ); /* Sanity check */ assert ( ! bigint_is_geq ( result, modulus ) ); diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 2a0a200c5..330d7deec 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -232,32 +232,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** * Reduce big integer * - * @v minuend Big integer to be reduced * @v modulus Big integer modulus - * @v result Big integer to hold result - * @v tmp Temporary working space + * @v value Big integer to be reduced */ -#define bigint_reduce( minuend, modulus, result, tmp ) do { \ - unsigned int minuend_size = bigint_size (minuend); \ - unsigned int modulus_size = bigint_size (modulus); \ - bigint_reduce_raw ( (minuend)->element, minuend_size, \ - (modulus)->element, modulus_size, \ - (result)->element, tmp ); \ +#define bigint_reduce( modulus, value ) do { \ + unsigned int size = bigint_size (modulus); \ + bigint_reduce_raw ( (modulus)->element, \ + (value)->element, size ); \ } while ( 0 ) -/** - * Calculate temporary working space required for reduction - * - * @v minuend Big integer to be reduced - * @ret len Length of temporary working space - */ -#define bigint_reduce_tmp_len( minuend ) ( { \ - unsigned int size = bigint_size (minuend); \ - sizeof ( struct { \ - bigint_t ( size ) temp_minuend; \ - bigint_t ( size ) temp_modulus; \ - } ); } ) - /** * Compute inverse of odd big integer modulo its own size * @@ -422,11 +405,8 @@ void bigint_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, unsigned int multiplier_size, bigint_element_t *result0 ); -void bigint_reduce_raw ( const bigint_element_t *minuend0, - unsigned int minuend_size, - const bigint_element_t *modulus0, - unsigned int modulus_size, - bigint_element_t *result0, void *tmp ); +void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0, + unsigned int size ); void bigint_mod_invert_raw ( const bigint_element_t *invertend0, bigint_element_t *inverse0, unsigned int size, void *tmp ); diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 271d76723..61f78fff9 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -185,19 +185,14 @@ void bigint_multiply_sample ( const bigint_element_t *multiplicand0, bigint_multiply ( multiplicand, multiplier, result ); } -void bigint_reduce_sample ( const bigint_element_t *minuend0, - unsigned int minuend_size, - const bigint_element_t *modulus0, - unsigned int modulus_size, - bigint_element_t *result0, void *tmp ) { - const bigint_t ( minuend_size ) __attribute__ (( may_alias )) - *minuend = ( ( const void * ) minuend0 ); - const bigint_t ( modulus_size ) __attribute__ (( may_alias )) - *modulus = ( ( const void * ) modulus0 ); - bigint_t ( modulus_size ) __attribute__ (( may_alias )) - *result = ( ( void * ) result0 ); +void bigint_reduce_sample ( bigint_element_t *modulus0, + bigint_element_t *value0, unsigned int size ) { + bigint_t ( size ) __attribute__ (( may_alias )) + *modulus = ( ( void * ) modulus0 ); + bigint_t ( size ) __attribute__ (( may_alias )) + *value = ( ( void * ) value0 ); - bigint_reduce ( minuend, modulus, result, tmp ); + bigint_reduce ( modulus, value ); } void bigint_mod_invert_sample ( const bigint_element_t *invertend0, @@ -555,43 +550,40 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, /** * Report result of big integer modular direct reduction test * - * @v minuend Big integer to be reduced * @v modulus Big integer modulus + * @v value Big integer to be reduced * @v expected Big integer expected result */ -#define bigint_reduce_ok( minuend, modulus, expected ) do { \ - static const uint8_t minuend_raw[] = minuend; \ +#define bigint_reduce_ok( modulus, value, expected ) do { \ static const uint8_t modulus_raw[] = modulus; \ + static const uint8_t value_raw[] = value; \ static const uint8_t expected_raw[] = expected; \ uint8_t result_raw[ sizeof ( expected_raw ) ]; \ - unsigned int minuend_size = \ - bigint_required_size ( sizeof ( minuend_raw ) ); \ - unsigned int modulus_size = \ + unsigned int size = \ bigint_required_size ( sizeof ( modulus_raw ) ); \ - bigint_t ( minuend_size ) minuend_temp; \ - bigint_t ( modulus_size ) modulus_temp; \ - bigint_t ( modulus_size ) result_temp; \ - size_t tmp_len = bigint_reduce_tmp_len ( &minuend_temp ); \ - uint8_t tmp[tmp_len]; \ + bigint_t ( size ) modulus_temp; \ + bigint_t ( size ) value_temp; \ {} /* Fix emacs alignment */ \ \ - assert ( bigint_size ( &result_temp ) == \ - bigint_size ( &modulus_temp ) ); \ - bigint_init ( &minuend_temp, minuend_raw, \ - sizeof ( minuend_raw ) ); \ + assert ( bigint_size ( &modulus_temp ) == \ + bigint_size ( &value_temp ) ); \ bigint_init ( &modulus_temp, modulus_raw, \ sizeof ( modulus_raw ) ); \ + bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ DBG ( "Modular reduce:\n" ); \ - DBG_HDA ( 0, &minuend_temp, sizeof ( minuend_temp ) ); \ DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ - bigint_reduce ( &minuend_temp, &modulus_temp, &result_temp, \ - tmp ); \ - DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ - bigint_done ( &result_temp, result_raw, \ - sizeof ( result_raw ) ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + bigint_reduce ( &modulus_temp, &value_temp ); \ + DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ + bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ \ ok ( memcmp ( result_raw, expected_raw, \ sizeof ( result_raw ) ) == 0 ); \ + \ + bigint_init ( &value_temp, modulus_raw, \ + sizeof ( modulus_raw ) ); \ + ok ( memcmp ( &modulus_temp, &value_temp, \ + sizeof ( modulus_temp ) ) == 0 ); \ } while ( 0 ) /** @@ -1797,16 +1789,16 @@ static void bigint_test_exec ( void ) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ) ); - bigint_reduce_ok ( BIGINT ( 0x00 ), - BIGINT ( 0xaf ), + bigint_reduce_ok ( BIGINT ( 0xaf ), + BIGINT ( 0x00 ), BIGINT ( 0x00 ) ); bigint_reduce_ok ( BIGINT ( 0xab ), BIGINT ( 0xab ), BIGINT ( 0x00 ) ); - bigint_reduce_ok ( BIGINT ( 0x1d, 0x97, 0x63, 0xc9, 0x97, 0xcd, 0x43, - 0xcb, 0x8e, 0x71, 0xac, 0x41, 0xdd ), - BIGINT ( 0xcc, 0x9d, 0xa0, 0x79, 0x96, 0x6a, 0x46, + bigint_reduce_ok ( BIGINT ( 0xcc, 0x9d, 0xa0, 0x79, 0x96, 0x6a, 0x46, 0xd5, 0xb4, 0x30, 0xd2, 0x2b, 0xbf ), + BIGINT ( 0x1d, 0x97, 0x63, 0xc9, 0x97, 0xcd, 0x43, + 0xcb, 0x8e, 0x71, 0xac, 0x41, 0xdd ), BIGINT ( 0x1d, 0x97, 0x63, 0xc9, 0x97, 0xcd, 0x43, 0xcb, 0x8e, 0x71, 0xac, 0x41, 0xdd ) ); bigint_reduce_ok ( BIGINT ( 0x21, 0xfa, 0x4f, 0xce, 0x0f, 0x0f, 0x4d, @@ -1815,15 +1807,19 @@ static void bigint_test_exec ( void ) { 0x43, 0xaa, 0xad, 0x21, 0x30, 0xe5 ), BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) ); - bigint_reduce_ok ( BIGINT ( 0xf9, 0x78, 0x96, 0x39, 0xee, 0x98, 0x42, + bigint_reduce_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xf3, 0x65, 0x35, 0x41, + 0x66, 0x65 ), + BIGINT ( 0xf9, 0x78, 0x96, 0x39, 0xee, 0x98, 0x42, 0x6a, 0xb8, 0x74, 0x0b, 0xe8, 0x5c, 0x76, 0x34, 0xaf ), - BIGINT ( 0xf3, 0x65, 0x35, 0x41, 0x66, 0x65 ), - BIGINT ( 0xb3, 0x07, 0xe8, 0xb7, 0x01, 0xf6 ) ); - bigint_reduce_ok ( BIGINT ( 0xfe, 0x30, 0xe1, 0xc6, 0x65, 0x97, 0x48, - 0x2e, 0x94, 0xd4 ), - BIGINT ( 0x47, 0xaa, 0x88, 0x00, 0xd0, 0x30, 0x62, + BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb3, 0x07, 0xe8, 0xb7, + 0x01, 0xf6 ) ); + bigint_reduce_ok ( BIGINT ( 0x47, 0xaa, 0x88, 0x00, 0xd0, 0x30, 0x62, 0xfb, 0x5d, 0x55 ), + BIGINT ( 0xfe, 0x30, 0xe1, 0xc6, 0x65, 0x97, 0x48, + 0x2e, 0x94, 0xd4 ), BIGINT ( 0x27, 0x31, 0x49, 0xc3, 0xf5, 0x06, 0x1f, 0x3c, 0x7c, 0xd5 ) ); bigint_mod_invert_ok ( BIGINT ( 0x01 ), BIGINT ( 0x01 ) ); -- cgit v1.2.3-55-g7522 From 7c2e68cc87a552c153e13517b0d0d6827f48e95b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 27 Nov 2024 12:51:04 +0000 Subject: [crypto] Eliminate temporary working space for bigint_mod_invert() With a slight modification to the algorithm to ignore bits of the residue that can never contribute to the result, it is possible to reuse the as-yet uncalculated portions of the inverse to hold the residue. This removes the requirement for additional temporary working space. Signed-off-by: Michael Brown --- src/crypto/bigint.c | 63 ++++++++++++++++++++++++++++++----------------- src/include/ipxe/bigint.h | 24 ++++-------------- src/tests/bigint_test.c | 24 ++++++++++++++---- 3 files changed, 65 insertions(+), 46 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index 4b37c062b..735fcdf61 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -287,27 +287,22 @@ void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0, * @v invertend0 Element 0 of odd big integer to be inverted * @v inverse0 Element 0 of big integer to hold result * @v size Number of elements in invertend and result - * @v tmp Temporary working space */ void bigint_mod_invert_raw ( const bigint_element_t *invertend0, - bigint_element_t *inverse0, - unsigned int size, void *tmp ) { + bigint_element_t *inverse0, unsigned int size ) { const bigint_t ( size ) __attribute__ (( may_alias )) *invertend = ( ( const void * ) invertend0 ); bigint_t ( size ) __attribute__ (( may_alias )) *inverse = ( ( void * ) inverse0 ); - struct { - bigint_t ( size ) residue; - } *temp = tmp; - const unsigned int width = ( 8 * sizeof ( bigint_element_t ) ); + bigint_element_t accum; + bigint_element_t bit; unsigned int i; /* Sanity check */ - assert ( invertend->element[0] & 1 ); + assert ( bigint_bit_is_set ( invertend, 0 ) ); - /* Initialise temporary working space and output value */ - memset ( &temp->residue, 0xff, sizeof ( temp->residue ) ); - memset ( inverse, 0, sizeof ( *inverse ) ); + /* Initialise output */ + memset ( inverse, 0xff, sizeof ( *inverse ) ); /* Compute inverse modulo 2^(width) * @@ -315,23 +310,47 @@ void bigint_mod_invert_raw ( const bigint_element_t *invertend0, * presented in "A New Algorithm for Inversion mod p^k (Koç, * 2017)". * - * Each loop iteration calculates one bit of the inverse. The - * residue value is the two's complement negation of the value - * "b" as used by Koç, to allow for division by two using a - * logical right shift (since we have no arithmetic right - * shift operation for big integers). + * Each inner loop iteration calculates one bit of the + * inverse. The residue value is the two's complement + * negation of the value "b" as used by Koç, to allow for + * division by two using a logical right shift (since we have + * no arithmetic right shift operation for big integers). + * + * The residue is stored in the as-yet uncalculated portion of + * the inverse. The size of the residue therefore decreases + * by one element for each outer loop iteration. Trivial + * inspection of the algorithm shows that any higher bits + * could not contribute to the eventual output value, and so + * we may safely reuse storage this way. * * Due to the suffix property of inverses mod 2^k, the result * represents the least significant bits of the inverse modulo * an arbitrarily large 2^k. */ - for ( i = 0 ; i < ( 8 * sizeof ( *inverse ) ) ; i++ ) { - if ( temp->residue.element[0] & 1 ) { - inverse->element[ i / width ] |= - ( 1UL << ( i % width ) ); - bigint_add ( invertend, &temp->residue ); + for ( i = size ; i > 0 ; i-- ) { + const bigint_t ( i ) __attribute__ (( may_alias )) + *addend = ( ( const void * ) invertend ); + bigint_t ( i ) __attribute__ (( may_alias )) + *residue = ( ( void * ) inverse ); + + /* Calculate one element's worth of inverse bits */ + for ( accum = 0, bit = 1 ; bit ; bit <<= 1 ) { + if ( bigint_bit_is_set ( residue, 0 ) ) { + accum |= bit; + bigint_add ( addend, residue ); + } + bigint_shr ( residue ); } - bigint_shr ( &temp->residue ); + + /* Store in the element no longer required to hold residue */ + inverse->element[ i - 1 ] = accum; + } + + /* Correct order of inverse elements */ + for ( i = 0 ; i < ( size / 2 ) ; i++ ) { + accum = inverse->element[i]; + inverse->element[i] = inverse->element[ size - 1 - i ]; + inverse->element[ size - 1 - i ] = accum; } } diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 330d7deec..e55c536c7 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -242,30 +242,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); } while ( 0 ) /** - * Compute inverse of odd big integer modulo its own size + * Compute inverse of odd big integer modulo any power of two * * @v invertend Odd big integer to be inverted * @v inverse Big integer to hold result - * @v tmp Temporary working space */ -#define bigint_mod_invert( invertend, inverse, tmp ) do { \ - unsigned int size = bigint_size (invertend); \ +#define bigint_mod_invert( invertend, inverse ) do { \ + unsigned int size = bigint_size ( invertend ); \ bigint_mod_invert_raw ( (invertend)->element, \ - (inverse)->element, size, tmp ); \ + (inverse)->element, size ); \ } while ( 0 ) -/** - * Calculate temporary working space required for modular inversion - * - * @v invertend Odd big integer to be inverted - * @ret len Length of temporary working space - */ -#define bigint_mod_invert_tmp_len( invertend ) ( { \ - unsigned int size = bigint_size (invertend); \ - sizeof ( struct { \ - bigint_t ( size ) temp_residue; \ - } ); } ) - /** * Perform modular multiplication of big integers * @@ -408,8 +395,7 @@ void bigint_multiply_raw ( const bigint_element_t *multiplicand0, void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0, unsigned int size ); void bigint_mod_invert_raw ( const bigint_element_t *invertend0, - bigint_element_t *inverse0, - unsigned int size, void *tmp ); + bigint_element_t *inverse0, unsigned int size ); void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 61f78fff9..608d8e874 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -197,13 +197,13 @@ void bigint_reduce_sample ( bigint_element_t *modulus0, void bigint_mod_invert_sample ( const bigint_element_t *invertend0, bigint_element_t *inverse0, - unsigned int size, void *tmp ) { + unsigned int size ) { const bigint_t ( size ) __attribute__ (( may_alias )) *invertend = ( ( const void * ) invertend0 ); bigint_t ( size ) __attribute__ (( may_alias )) *inverse = ( ( void * ) inverse0 ); - bigint_mod_invert ( invertend, inverse, tmp ); + bigint_mod_invert ( invertend, inverse ); } void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0, @@ -600,8 +600,6 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, bigint_required_size ( sizeof ( invertend_raw ) ); \ bigint_t ( size ) invertend_temp; \ bigint_t ( size ) inverse_temp; \ - size_t tmp_len = bigint_mod_invert_tmp_len ( &invertend_temp ); \ - uint8_t tmp[tmp_len]; \ {} /* Fix emacs alignment */ \ \ assert ( bigint_size ( &invertend_temp ) == \ @@ -610,7 +608,7 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, sizeof ( invertend_raw ) ); \ DBG ( "Modular invert:\n" ); \ DBG_HDA ( 0, &invertend_temp, sizeof ( invertend_temp ) ); \ - bigint_mod_invert ( &invertend_temp, &inverse_temp, tmp ); \ + bigint_mod_invert ( &invertend_temp, &inverse_temp ); \ DBG_HDA ( 0, &inverse_temp, sizeof ( inverse_temp ) ); \ bigint_done ( &inverse_temp, inverse_raw, \ sizeof ( inverse_raw ) ); \ @@ -1827,6 +1825,10 @@ static void bigint_test_exec ( void ) { 0xff, 0xff ), BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ) ); + bigint_mod_invert_ok ( BIGINT ( 0xa4, 0xcb, 0xbc, 0xc9, 0x9f, 0x7a, + 0x65, 0xbf ), + BIGINT ( 0xb9, 0xd5, 0xf4, 0x88, 0x0b, 0xf8, + 0x8a, 0x3f ) ); bigint_mod_invert_ok ( BIGINT ( 0x95, 0x6a, 0xc5, 0xe7, 0x2e, 0x5b, 0x44, 0xed, 0xbf, 0x7e, 0xfe, 0x8d, 0xf4, 0x5a, 0x48, 0xc1 ), @@ -1839,6 +1841,18 @@ static void bigint_test_exec ( void ) { BIGINT ( 0xf2, 0x9c, 0x63, 0x29, 0xfa, 0xe4, 0xbf, 0x90, 0xa6, 0x9a, 0xec, 0xcf, 0x5f, 0xe2, 0x21, 0xcd ) ); + bigint_mod_invert_ok ( BIGINT ( 0xb9, 0xbb, 0x7f, 0x9c, 0x7a, 0x32, + 0x43, 0xed, 0x9d, 0xd4, 0x0d, 0x6f, + 0x32, 0xfa, 0x4b, 0x62, 0x38, 0x3a, + 0xbf, 0x4c, 0xbd, 0xa8, 0x47, 0xce, + 0xa2, 0x30, 0x34, 0xe0, 0x2c, 0x09, + 0x14, 0x89 ), + BIGINT ( 0xfc, 0x05, 0xc4, 0x2a, 0x90, 0x99, + 0x82, 0xf8, 0x81, 0x1d, 0x87, 0xb8, + 0xca, 0xe4, 0x95, 0xe2, 0xac, 0x18, + 0xb3, 0xe1, 0x3e, 0xc6, 0x5a, 0x03, + 0x51, 0x6f, 0xb7, 0xe3, 0xa5, 0xd6, + 0xa1, 0xb9 ) ); bigint_mod_multiply_ok ( BIGINT ( 0x37 ), BIGINT ( 0x67 ), BIGINT ( 0x3f ), -- cgit v1.2.3-55-g7522 From 96f385d7a48ffe259295991043a86b2cefce1891 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 27 Nov 2024 12:56:22 +0000 Subject: [crypto] Use inverse size as effective size for bigint_mod_invert() Montgomery reduction requires only the least significant element of an inverse modulo 2^k, which in turn depends upon only the least significant element of the invertend. Use the inverse size (rather than the invertend size) as the effective size for bigint_mod_invert(). This eliminates around 97% of the loop iterations for a typical 2048-bit RSA modulus. Signed-off-by: Michael Brown --- src/include/ipxe/bigint.h | 2 +- src/tests/bigint_test.c | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) (limited to 'src/tests') diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index e55c536c7..14f3c5f28 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -248,7 +248,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v inverse Big integer to hold result */ #define bigint_mod_invert( invertend, inverse ) do { \ - unsigned int size = bigint_size ( invertend ); \ + unsigned int size = bigint_size ( inverse ); \ bigint_mod_invert_raw ( (invertend)->element, \ (inverse)->element, size ); \ } while ( 0 ) diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 608d8e874..bee36de25 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -596,14 +596,14 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, static const uint8_t invertend_raw[] = invertend; \ static const uint8_t expected_raw[] = expected; \ uint8_t inverse_raw[ sizeof ( expected_raw ) ]; \ - unsigned int size = \ + unsigned int invertend_size = \ bigint_required_size ( sizeof ( invertend_raw ) ); \ - bigint_t ( size ) invertend_temp; \ - bigint_t ( size ) inverse_temp; \ + unsigned int inverse_size = \ + bigint_required_size ( sizeof ( inverse_raw ) ); \ + bigint_t ( invertend_size ) invertend_temp; \ + bigint_t ( inverse_size ) inverse_temp; \ {} /* Fix emacs alignment */ \ \ - assert ( bigint_size ( &invertend_temp ) == \ - bigint_size ( &inverse_temp ) ); \ bigint_init ( &invertend_temp, invertend_raw, \ sizeof ( invertend_raw ) ); \ DBG ( "Modular invert:\n" ); \ @@ -1853,6 +1853,11 @@ static void bigint_test_exec ( void ) { 0xb3, 0xe1, 0x3e, 0xc6, 0x5a, 0x03, 0x51, 0x6f, 0xb7, 0xe3, 0xa5, 0xd6, 0xa1, 0xb9 ) ); + bigint_mod_invert_ok ( BIGINT ( 0xfe, 0x43, 0xf6, 0xa0, 0x32, 0x02, + 0x47, 0xaa, 0xaa, 0x0e, 0x33, 0x19, + 0x2e, 0xe6, 0x22, 0x07 ), + BIGINT ( 0x7b, 0xd1, 0x0f, 0x78, 0x0c, 0x65, + 0xab, 0xb7 ) ); bigint_mod_multiply_ok ( BIGINT ( 0x37 ), BIGINT ( 0x67 ), BIGINT ( 0x3f ), -- cgit v1.2.3-55-g7522 From 4f7dd7fbba205d413cf9b989f7cdc928fa02caf2 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 27 Nov 2024 13:25:18 +0000 Subject: [crypto] Add bigint_montgomery() to perform Montgomery reduction Montgomery reduction is substantially faster than direct reduction, and is better suited for modular exponentiation operations. Add bigint_montgomery() to perform the Montgomery reduction operation (often referred to as "REDC"), along with some test vectors. Signed-off-by: Michael Brown --- src/crypto/bigint.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/bigint.h | 21 +++++++++++++ src/tests/bigint_test.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) (limited to 'src/tests') diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index 735fcdf61..6d75fbe9b 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -354,6 +354,83 @@ void bigint_mod_invert_raw ( const bigint_element_t *invertend0, } } +/** + * Perform Montgomery reduction (REDC) of a big integer product + * + * @v modulus0 Element 0 of big integer modulus + * @v modinv0 Element 0 of the inverse of the modulus modulo 2^k + * @v mont0 Element 0 of big integer Montgomery product + * @v result0 Element 0 of big integer to hold result + * @v size Number of elements in modulus and result + * + * Note that only the least significant element of the inverse modulo + * 2^k is required, and that the Montgomery product will be + * overwritten. + */ +void bigint_montgomery_raw ( const bigint_element_t *modulus0, + const bigint_element_t *modinv0, + bigint_element_t *mont0, + bigint_element_t *result0, unsigned int size ) { + const bigint_t ( size ) __attribute__ (( may_alias )) + *modulus = ( ( const void * ) modulus0 ); + const bigint_t ( 1 ) __attribute__ (( may_alias )) + *modinv = ( ( const void * ) modinv0 ); + union { + bigint_t ( size * 2 ) full; + struct { + bigint_t ( size ) low; + bigint_t ( size ) high; + } __attribute__ (( packed )); + } __attribute__ (( may_alias )) *mont = ( ( void * ) mont0 ); + bigint_t ( size ) __attribute__ (( may_alias )) + *result = ( ( void * ) result0 ); + bigint_element_t negmodinv = -modinv->element[0]; + bigint_element_t multiple; + bigint_element_t carry; + unsigned int i; + unsigned int j; + int overflow; + int underflow; + + /* Sanity checks */ + assert ( bigint_bit_is_set ( modulus, 0 ) ); + + /* Perform multiprecision Montgomery reduction */ + for ( i = 0 ; i < size ; i++ ) { + + /* Determine scalar multiple for this round */ + multiple = ( mont->low.element[i] * negmodinv ); + + /* Multiply value to make it divisible by 2^(width*i) */ + carry = 0; + for ( j = 0 ; j < size ; j++ ) { + bigint_multiply_one ( multiple, modulus->element[j], + &mont->full.element[ i + j ], + &carry ); + } + + /* Since value is now divisible by 2^(width*i), we + * know that the current low element must have been + * zeroed. We can store the multiplication carry out + * in this element, avoiding the need to immediately + * propagate the carry through the remaining elements. + */ + assert ( mont->low.element[i] == 0 ); + mont->low.element[i] = carry; + } + + /* Add the accumulated carries */ + overflow = bigint_add ( &mont->low, &mont->high ); + + /* Conditionally subtract the modulus once */ + memcpy ( result, &mont->high, sizeof ( *result ) ); + underflow = bigint_subtract ( modulus, result ); + bigint_swap ( result, &mont->high, ( underflow & ~overflow ) ); + + /* Sanity check */ + assert ( ! bigint_is_geq ( result, modulus ) ); +} + /** * Perform modular multiplication of big integers * diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 14f3c5f28..6c9730252 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -253,6 +253,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); (inverse)->element, size ); \ } while ( 0 ) +/** + * Perform Montgomery reduction (REDC) of a big integer product + * + * @v modulus Big integer modulus + * @v modinv Big integer inverse of the modulus modulo 2^k + * @v mont Big integer Montgomery product + * @v result Big integer to hold result + * + * Note that the Montgomery product will be overwritten. + */ +#define bigint_montgomery( modulus, modinv, mont, result ) do { \ + unsigned int size = bigint_size (modulus); \ + bigint_montgomery_raw ( (modulus)->element, (modinv)->element, \ + (mont)->element, (result)->element, \ + size ); \ + } while ( 0 ) + /** * Perform modular multiplication of big integers * @@ -396,6 +413,10 @@ void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0, unsigned int size ); void bigint_mod_invert_raw ( const bigint_element_t *invertend0, bigint_element_t *inverse0, unsigned int size ); +void bigint_montgomery_raw ( const bigint_element_t *modulus0, + const bigint_element_t *modinv0, + bigint_element_t *mont0, + bigint_element_t *result0, unsigned int size ); void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index bee36de25..1f2f5f244 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -206,6 +206,23 @@ void bigint_mod_invert_sample ( const bigint_element_t *invertend0, bigint_mod_invert ( invertend, inverse ); } +void bigint_montgomery_sample ( const bigint_element_t *modulus0, + const bigint_element_t *modinv0, + bigint_element_t *mont0, + bigint_element_t *result0, + unsigned int size ) { + const bigint_t ( size ) __attribute__ (( may_alias )) + *modulus = ( ( const void * ) modulus0 ); + const bigint_t ( 1 ) __attribute__ (( may_alias )) + *modinv = ( ( const void * ) modinv0 ); + bigint_t ( 2 * size ) __attribute__ (( may_alias )) + *mont = ( ( void * ) mont0 ); + bigint_t ( size ) __attribute__ (( may_alias )) + *result = ( ( void * ) result0 ); + + bigint_montgomery ( modulus, modinv, mont, result ); +} + void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, const bigint_element_t *modulus0, @@ -617,6 +634,46 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, sizeof ( inverse_raw ) ) == 0 ); \ } while ( 0 ) +/** + * Report result of Montgomery reduction (REDC) test + * + * @v modulus Big integer modulus + * @v mont Big integer Montgomery product + * @v expected Big integer expected result + */ +#define bigint_montgomery_ok( modulus, mont, expected ) do { \ + static const uint8_t modulus_raw[] = modulus; \ + static const uint8_t mont_raw[] = mont; \ + static const uint8_t expected_raw[] = expected; \ + uint8_t result_raw[ sizeof ( expected_raw ) ]; \ + unsigned int size = \ + bigint_required_size ( sizeof ( modulus_raw ) ); \ + bigint_t ( size ) modulus_temp; \ + bigint_t ( 1 ) modinv_temp; \ + bigint_t ( 2 * size ) mont_temp; \ + bigint_t ( size ) result_temp; \ + {} /* Fix emacs alignment */ \ + \ + assert ( ( sizeof ( modulus_raw ) % \ + sizeof ( bigint_element_t ) ) == 0 ); \ + bigint_init ( &modulus_temp, modulus_raw, \ + sizeof ( modulus_raw ) ); \ + bigint_init ( &mont_temp, mont_raw, sizeof ( mont_raw ) ); \ + bigint_mod_invert ( &modulus_temp, &modinv_temp ); \ + DBG ( "Montgomery:\n" ); \ + DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ + DBG_HDA ( 0, &modinv_temp, sizeof ( modinv_temp ) ); \ + DBG_HDA ( 0, &mont_temp, sizeof ( mont_temp ) ); \ + bigint_montgomery ( &modulus_temp, &modinv_temp, &mont_temp, \ + &result_temp ); \ + DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ + bigint_done ( &result_temp, result_raw, \ + sizeof ( result_raw ) ); \ + \ + ok ( memcmp ( result_raw, expected_raw, \ + sizeof ( result_raw ) ) == 0 ); \ + } while ( 0 ) + /** * Report result of big integer modular multiplication test * @@ -1858,6 +1915,25 @@ static void bigint_test_exec ( void ) { 0x2e, 0xe6, 0x22, 0x07 ), BIGINT ( 0x7b, 0xd1, 0x0f, 0x78, 0x0c, 0x65, 0xab, 0xb7 ) ); + bigint_montgomery_ok ( BIGINT ( 0x74, 0xdf, 0xd1, 0xb8, 0x14, 0xf7, + 0x05, 0x83 ), + BIGINT ( 0x50, 0x6a, 0x38, 0x55, 0x9f, 0xb9, + 0x9d, 0xba, 0xff, 0x23, 0x86, 0x65, + 0xe3, 0x2c, 0x3f, 0x17 ), + BIGINT ( 0x45, 0x1f, 0x51, 0x44, 0x6f, 0x3c, + 0x09, 0x6b ) ); + bigint_montgomery_ok ( BIGINT ( 0x2e, 0x32, 0x90, 0x69, 0x6e, 0xa8, + 0x47, 0x4c, 0xad, 0xe4, 0xe7, 0x4c, + 0x03, 0xcb, 0xe6, 0x55 ), + BIGINT ( 0x1e, 0x43, 0xf9, 0xc2, 0x61, 0xdd, + 0xe8, 0xbf, 0xb8, 0xea, 0xe0, 0xdb, + 0xed, 0x66, 0x80, 0x1e, 0xe8, 0xf8, + 0xd1, 0x1d, 0xca, 0x8d, 0x45, 0xe9, + 0xc5, 0xeb, 0x77, 0x21, 0x34, 0xe0, + 0xf5, 0x5a ), + BIGINT ( 0x03, 0x38, 0xfb, 0xb6, 0xf3, 0x80, + 0x91, 0xb2, 0x68, 0x2f, 0x81, 0x44, + 0xbf, 0x43, 0x0a, 0x4e ) ); bigint_mod_multiply_ok ( BIGINT ( 0x37 ), BIGINT ( 0x67 ), BIGINT ( 0x3f ), -- cgit v1.2.3-55-g7522 From 83ac98ce22b5b735cba4d1a21db8cc8e8648dfa4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 25 Nov 2024 15:59:22 +0000 Subject: [crypto] Use Montgomery reduction for modular exponentiation Speed up modular exponentiation by using Montgomery reduction rather than direct modular reduction. Montgomery reduction in base 2^n requires the modulus to be coprime to 2^n, which would limit us to requiring that the modulus is an odd number. Extend the implementation to include support for exponentiation with even moduli via Garner's algorithm as described in "Montgomery reduction with even modulus" (Koç, 1994). Since almost all use cases for modular exponentation require a large prime (and hence odd) modulus, the support for even moduli could potentially be removed in future. Signed-off-by: Michael Brown --- src/crypto/bigint.c | 147 +++++++++++++++++++++++++++++++++++++++++----- src/crypto/dhe.c | 3 +- src/crypto/rsa.c | 3 +- src/include/ipxe/bigint.h | 10 +--- src/tests/bigint_test.c | 30 +++++++++- 5 files changed, 164 insertions(+), 29 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index 6d75fbe9b..39e1a25cd 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -505,25 +505,142 @@ void bigint_mod_exp_raw ( const bigint_element_t *base0, *exponent = ( ( const void * ) exponent0 ); bigint_t ( size ) __attribute__ (( may_alias )) *result = ( ( void * ) result0 ); - size_t mod_multiply_len = bigint_mod_multiply_tmp_len ( modulus ); + const unsigned int width = ( 8 * sizeof ( bigint_element_t ) ); struct { - bigint_t ( size ) base; - bigint_t ( exponent_size ) exponent; - uint8_t mod_multiply[mod_multiply_len]; + union { + bigint_t ( 2 * size ) padded_modulus; + struct { + bigint_t ( size ) modulus; + bigint_t ( size ) stash; + }; + }; + union { + bigint_t ( 2 * size ) full; + bigint_t ( size ) low; + } product; } *temp = tmp; - static const uint8_t start[1] = { 0x01 }; + const uint8_t one[1] = { 1 }; + bigint_t ( 1 ) modinv; + bigint_element_t submask; + unsigned int subsize; + unsigned int scale; + unsigned int max; + unsigned int bit; + + /* Sanity check */ + assert ( sizeof ( *temp ) == bigint_mod_exp_tmp_len ( modulus ) ); + + /* Handle degenerate case of zero modulus */ + if ( ! bigint_max_set_bit ( modulus ) ) { + memset ( result, 0, sizeof ( *result ) ); + return; + } - memcpy ( &temp->base, base, sizeof ( temp->base ) ); - memcpy ( &temp->exponent, exponent, sizeof ( temp->exponent ) ); - bigint_init ( result, start, sizeof ( start ) ); + /* Factor modulus as (N * 2^scale) where N is odd */ + bigint_grow ( modulus, &temp->padded_modulus ); + for ( scale = 0 ; ( ! bigint_bit_is_set ( &temp->modulus, 0 ) ) ; + scale++ ) { + bigint_shr ( &temp->modulus ); + } + subsize = ( ( scale + width - 1 ) / width ); + submask = ( ( 1UL << ( scale % width ) ) - 1 ); + if ( ! submask ) + submask = ~submask; + + /* Calculate inverse of (scaled) modulus N modulo element size */ + bigint_mod_invert ( &temp->modulus, &modinv ); + + /* Calculate (R^2 mod N) via direct reduction of (R^2 - N) */ + memset ( &temp->product.full, 0, sizeof ( temp->product.full ) ); + bigint_subtract ( &temp->padded_modulus, &temp->product.full ); + bigint_reduce ( &temp->padded_modulus, &temp->product.full ); + bigint_copy ( &temp->product.low, &temp->stash ); + + /* Initialise result = Montgomery(1, R^2 mod N) */ + bigint_montgomery ( &temp->modulus, &modinv, + &temp->product.full, result ); + + /* Convert base into Montgomery form */ + bigint_multiply ( base, &temp->stash, &temp->product.full ); + bigint_montgomery ( &temp->modulus, &modinv, &temp->product.full, + &temp->stash ); + + /* Calculate x1 = base^exponent modulo N */ + max = bigint_max_set_bit ( exponent ); + for ( bit = 1 ; bit <= max ; bit++ ) { + + /* Square (and reduce) */ + bigint_multiply ( result, result, &temp->product.full ); + bigint_montgomery ( &temp->modulus, &modinv, + &temp->product.full, result ); + + /* Multiply (and reduce) */ + bigint_multiply ( &temp->stash, result, &temp->product.full ); + bigint_montgomery ( &temp->modulus, &modinv, + &temp->product.full, &temp->product.low ); + + /* Conditionally swap the multiplied result */ + bigint_swap ( result, &temp->product.low, + bigint_bit_is_set ( exponent, ( max - bit ) ) ); + } - while ( ! bigint_is_zero ( &temp->exponent ) ) { - if ( bigint_bit_is_set ( &temp->exponent, 0 ) ) { - bigint_mod_multiply ( result, &temp->base, modulus, - result, temp->mod_multiply ); + /* Convert back out of Montgomery form */ + bigint_grow ( result, &temp->product.full ); + bigint_montgomery ( &temp->modulus, &modinv, &temp->product.full, + result ); + + /* Handle even moduli via Garner's algorithm */ + if ( subsize ) { + const bigint_t ( subsize ) __attribute__ (( may_alias )) + *subbase = ( ( const void * ) base ); + bigint_t ( subsize ) __attribute__ (( may_alias )) + *submodulus = ( ( void * ) &temp->modulus ); + bigint_t ( subsize ) __attribute__ (( may_alias )) + *substash = ( ( void * ) &temp->stash ); + bigint_t ( subsize ) __attribute__ (( may_alias )) + *subresult = ( ( void * ) result ); + union { + bigint_t ( 2 * subsize ) full; + bigint_t ( subsize ) low; + } __attribute__ (( may_alias )) + *subproduct = ( ( void * ) &temp->product.full ); + + /* Calculate x2 = base^exponent modulo 2^k */ + bigint_init ( substash, one, sizeof ( one ) ); + for ( bit = 1 ; bit <= max ; bit++ ) { + + /* Square (and reduce) */ + bigint_multiply ( substash, substash, + &subproduct->full ); + bigint_copy ( &subproduct->low, substash ); + + /* Multiply (and reduce) */ + bigint_multiply ( subbase, substash, + &subproduct->full ); + + /* Conditionally swap the multiplied result */ + bigint_swap ( substash, &subproduct->low, + bigint_bit_is_set ( exponent, + ( max - bit ) ) ); } - bigint_shr ( &temp->exponent ); - bigint_mod_multiply ( &temp->base, &temp->base, modulus, - &temp->base, temp->mod_multiply ); + + /* Calculate N^-1 modulo 2^k */ + bigint_mod_invert ( submodulus, &subproduct->low ); + bigint_copy ( &subproduct->low, submodulus ); + + /* Calculate y = (x2 - x1) * N^-1 modulo 2^k */ + bigint_subtract ( subresult, substash ); + bigint_multiply ( substash, submodulus, &subproduct->full ); + subproduct->low.element[ subsize - 1 ] &= submask; + bigint_grow ( &subproduct->low, &temp->stash ); + + /* Reconstruct N */ + bigint_mod_invert ( submodulus, &subproduct->low ); + bigint_copy ( &subproduct->low, submodulus ); + + /* Calculate x = x1 + N * y */ + bigint_multiply ( &temp->modulus, &temp->stash, + &temp->product.full ); + bigint_add ( &temp->product.low, result ); } } diff --git a/src/crypto/dhe.c b/src/crypto/dhe.c index 2da107d24..a249f9b40 100644 --- a/src/crypto/dhe.c +++ b/src/crypto/dhe.c @@ -57,8 +57,7 @@ int dhe_key ( const void *modulus, size_t len, const void *generator, unsigned int size = bigint_required_size ( len ); unsigned int private_size = bigint_required_size ( private_len ); bigint_t ( size ) *mod; - bigint_t ( private_size ) *exp; - size_t tmp_len = bigint_mod_exp_tmp_len ( mod, exp ); + size_t tmp_len = bigint_mod_exp_tmp_len ( mod ); struct { bigint_t ( size ) modulus; bigint_t ( size ) generator; diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index 19472c121..44041da3e 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -109,8 +109,7 @@ static int rsa_alloc ( struct rsa_context *context, size_t modulus_len, unsigned int size = bigint_required_size ( modulus_len ); unsigned int exponent_size = bigint_required_size ( exponent_len ); bigint_t ( size ) *modulus; - bigint_t ( exponent_size ) *exponent; - size_t tmp_len = bigint_mod_exp_tmp_len ( modulus, exponent ); + size_t tmp_len = bigint_mod_exp_tmp_len ( modulus ); struct { bigint_t ( size ) modulus; bigint_t ( exponent_size ) exponent; diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 6c9730252..3ca871962 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -322,18 +322,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Calculate temporary working space required for moduluar exponentiation * * @v modulus Big integer modulus - * @v exponent Big integer exponent * @ret len Length of temporary working space */ -#define bigint_mod_exp_tmp_len( modulus, exponent ) ( { \ +#define bigint_mod_exp_tmp_len( modulus ) ( { \ unsigned int size = bigint_size (modulus); \ - unsigned int exponent_size = bigint_size (exponent); \ - size_t mod_multiply_len = \ - bigint_mod_multiply_tmp_len (modulus); \ sizeof ( struct { \ - bigint_t ( size ) temp_base; \ - bigint_t ( exponent_size ) temp_exponent; \ - uint8_t mod_multiply[mod_multiply_len]; \ + bigint_t ( size ) temp[4]; \ } ); } ) #include diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 1f2f5f244..f3291f6a6 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -746,8 +746,7 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, bigint_t ( size ) modulus_temp; \ bigint_t ( exponent_size ) exponent_temp; \ bigint_t ( size ) result_temp; \ - size_t tmp_len = bigint_mod_exp_tmp_len ( &modulus_temp, \ - &exponent_temp ); \ + size_t tmp_len = bigint_mod_exp_tmp_len ( &modulus_temp ); \ uint8_t tmp[tmp_len]; \ {} /* Fix emacs alignment */ \ \ @@ -2070,6 +2069,14 @@ static void bigint_test_exec ( void ) { BIGINT ( 0xb9 ), BIGINT ( 0x39, 0x68, 0xba, 0x7d ), BIGINT ( 0x17 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x71, 0x4d, 0x02, 0xe9 ), + BIGINT ( 0x00, 0x00, 0x00, 0x00 ), + BIGINT ( 0x91, 0x7f, 0x4e, 0x3a, 0x5d, 0x5c ), + BIGINT ( 0x00, 0x00, 0x00, 0x00 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x2b, 0xf5, 0x07, 0xaf ), + BIGINT ( 0x6e, 0xb5, 0xda, 0x5a ), + BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00 ), + BIGINT ( 0x00, 0x00, 0x00, 0x01 ) ); bigint_mod_exp_ok ( BIGINT ( 0x2e ), BIGINT ( 0xb7 ), BIGINT ( 0x39, 0x07, 0x1b, 0x49, 0x5b, 0xea, @@ -2774,6 +2781,25 @@ static void bigint_test_exec ( void ) { 0xfa, 0x83, 0xd4, 0x7c, 0xe9, 0x77, 0x46, 0x91, 0x3a, 0x50, 0x0d, 0x6a, 0x25, 0xd0 ) ); + bigint_mod_exp_ok ( BIGINT ( 0x5b, 0x80, 0xc5, 0x03, 0xb3, 0x1e, + 0x46, 0x9b, 0xa3, 0x0a, 0x70, 0x43, + 0x51, 0x2a, 0x4a, 0x44, 0xcb, 0x87, + 0x3e, 0x00, 0x2a, 0x48, 0x46, 0xf5, + 0xb3, 0xb9, 0x73, 0xa7, 0x77, 0xfc, + 0x2a, 0x1d ), + BIGINT ( 0x5e, 0x8c, 0x80, 0x03, 0xe7, 0xb0, + 0x45, 0x23, 0x8f, 0xe0, 0x77, 0x02, + 0xc0, 0x7e, 0xfb, 0xc4, 0xbe, 0x7b, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 ), + BIGINT ( 0x71, 0xd9, 0x38, 0xb6 ), + BIGINT ( 0x52, 0xfc, 0x73, 0x55, 0x2f, 0x86, + 0x0f, 0xde, 0x04, 0xbc, 0x6d, 0xb8, + 0xfd, 0x48, 0xf8, 0x8c, 0x91, 0x1c, + 0xa0, 0x8a, 0x70, 0xa8, 0xc6, 0x20, + 0x0a, 0x0d, 0x3b, 0x2a, 0x92, 0x65, + 0x9c, 0x59 ) ); } /** Big integer self-test */ -- cgit v1.2.3-55-g7522 From 5202f83345e17c56da4935205f0a97bd4aa20714 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 28 Nov 2024 15:05:06 +0000 Subject: [crypto] Remove obsolete bigint_mod_multiply() There is no further need for a standalone modular multiplication primitive, since the only consumer is modular exponentiation (which now uses Montgomery multiplication instead). Remove the now obsolete bigint_mod_multiply(). Signed-off-by: Michael Brown --- src/crypto/bigint.c | 53 ------------- src/include/ipxe/bigint.h | 36 --------- src/tests/bigint_test.c | 188 ---------------------------------------------- 3 files changed, 277 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index 39e1a25cd..b357ea29f 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -38,10 +38,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); static struct profiler bigint_mod_profiler __profiler = { .name = "bigint_mod" }; -/** Modular multiplication overall profiler */ -static struct profiler bigint_mod_multiply_profiler __profiler = - { .name = "bigint_mod_multiply" }; - /** * Conditionally swap big integers (in constant time) * @@ -431,55 +427,6 @@ void bigint_montgomery_raw ( const bigint_element_t *modulus0, assert ( ! bigint_is_geq ( result, modulus ) ); } -/** - * Perform modular multiplication of big integers - * - * @v multiplicand0 Element 0 of big integer to be multiplied - * @v multiplier0 Element 0 of big integer to be multiplied - * @v modulus0 Element 0 of big integer modulus - * @v result0 Element 0 of big integer to hold result - * @v size Number of elements in base, modulus, and result - * @v tmp Temporary working space - */ -void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, - const bigint_element_t *multiplier0, - const bigint_element_t *modulus0, - bigint_element_t *result0, - unsigned int size, void *tmp ) { - const bigint_t ( size ) __attribute__ (( may_alias )) *multiplicand = - ( ( const void * ) multiplicand0 ); - const bigint_t ( size ) __attribute__ (( may_alias )) *multiplier = - ( ( const void * ) multiplier0 ); - const bigint_t ( size ) __attribute__ (( may_alias )) *modulus = - ( ( const void * ) modulus0 ); - bigint_t ( size ) __attribute__ (( may_alias )) *result = - ( ( void * ) result0 ); - struct { - bigint_t ( size * 2 ) result; - bigint_t ( size * 2 ) modulus; - } *temp = tmp; - - /* Start profiling */ - profile_start ( &bigint_mod_multiply_profiler ); - - /* Sanity check */ - assert ( sizeof ( *temp ) == bigint_mod_multiply_tmp_len ( modulus ) ); - - /* Perform multiplication */ - bigint_multiply ( multiplicand, multiplier, &temp->result ); - - /* Reduce result */ - bigint_grow ( modulus, &temp->modulus ); - bigint_reduce ( &temp->modulus, &temp->result ); - bigint_shrink ( &temp->result, result ); - - /* Sanity check */ - assert ( ! bigint_is_geq ( result, modulus ) ); - - /* Stop profiling */ - profile_stop ( &bigint_mod_multiply_profiler ); -} - /** * Perform modular exponentiation of big integers * diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 3ca871962..3058547a6 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -270,37 +270,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); size ); \ } while ( 0 ) -/** - * Perform modular multiplication of big integers - * - * @v multiplicand Big integer to be multiplied - * @v multiplier Big integer to be multiplied - * @v modulus Big integer modulus - * @v result Big integer to hold result - * @v tmp Temporary working space - */ -#define bigint_mod_multiply( multiplicand, multiplier, modulus, \ - result, tmp ) do { \ - unsigned int size = bigint_size (multiplicand); \ - bigint_mod_multiply_raw ( (multiplicand)->element, \ - (multiplier)->element, \ - (modulus)->element, \ - (result)->element, size, tmp ); \ - } while ( 0 ) - -/** - * Calculate temporary working space required for moduluar multiplication - * - * @v modulus Big integer modulus - * @ret len Length of temporary working space - */ -#define bigint_mod_multiply_tmp_len( modulus ) ( { \ - unsigned int size = bigint_size (modulus); \ - sizeof ( struct { \ - bigint_t ( size * 2 ) temp_result; \ - bigint_t ( size * 2 ) temp_modulus; \ - } ); } ) - /** * Perform modular exponentiation of big integers * @@ -411,11 +380,6 @@ void bigint_montgomery_raw ( const bigint_element_t *modulus0, const bigint_element_t *modinv0, bigint_element_t *mont0, bigint_element_t *result0, unsigned int size ); -void bigint_mod_multiply_raw ( const bigint_element_t *multiplicand0, - const bigint_element_t *multiplier0, - const bigint_element_t *modulus0, - bigint_element_t *result0, - unsigned int size, void *tmp ); void bigint_mod_exp_raw ( const bigint_element_t *base0, const bigint_element_t *modulus0, const bigint_element_t *exponent0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index f3291f6a6..dc74740e6 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -223,24 +223,6 @@ void bigint_montgomery_sample ( const bigint_element_t *modulus0, bigint_montgomery ( modulus, modinv, mont, result ); } -void bigint_mod_multiply_sample ( const bigint_element_t *multiplicand0, - const bigint_element_t *multiplier0, - const bigint_element_t *modulus0, - bigint_element_t *result0, - unsigned int size, - void *tmp ) { - const bigint_t ( size ) *multiplicand __attribute__ (( may_alias )) - = ( ( const void * ) multiplicand0 ); - const bigint_t ( size ) *multiplier __attribute__ (( may_alias )) - = ( ( const void * ) multiplier0 ); - const bigint_t ( size ) *modulus __attribute__ (( may_alias )) - = ( ( const void * ) modulus0 ); - bigint_t ( size ) *result __attribute__ (( may_alias )) - = ( ( void * ) result0 ); - - bigint_mod_multiply ( multiplicand, multiplier, modulus, result, tmp ); -} - void bigint_mod_exp_sample ( const bigint_element_t *base0, const bigint_element_t *modulus0, const bigint_element_t *exponent0, @@ -674,56 +656,6 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, sizeof ( result_raw ) ) == 0 ); \ } while ( 0 ) -/** - * Report result of big integer modular multiplication test - * - * @v multiplicand Big integer to be multiplied - * @v multiplier Big integer to be multiplied - * @v modulus Big integer modulus - * @v expected Big integer expected result - */ -#define bigint_mod_multiply_ok( multiplicand, multiplier, modulus, \ - expected ) do { \ - static const uint8_t multiplicand_raw[] = multiplicand; \ - static const uint8_t multiplier_raw[] = multiplier; \ - static const uint8_t modulus_raw[] = modulus; \ - static const uint8_t expected_raw[] = expected; \ - uint8_t result_raw[ sizeof ( expected_raw ) ]; \ - unsigned int size = \ - bigint_required_size ( sizeof ( multiplicand_raw ) ); \ - bigint_t ( size ) multiplicand_temp; \ - bigint_t ( size ) multiplier_temp; \ - bigint_t ( size ) modulus_temp; \ - bigint_t ( size ) result_temp; \ - size_t tmp_len = bigint_mod_multiply_tmp_len ( &modulus_temp ); \ - uint8_t tmp[tmp_len]; \ - {} /* Fix emacs alignment */ \ - \ - assert ( bigint_size ( &multiplier_temp ) == \ - bigint_size ( &multiplicand_temp ) ); \ - assert ( bigint_size ( &multiplier_temp ) == \ - bigint_size ( &modulus_temp ) ); \ - assert ( bigint_size ( &multiplier_temp ) == \ - bigint_size ( &result_temp ) ); \ - bigint_init ( &multiplicand_temp, multiplicand_raw, \ - sizeof ( multiplicand_raw ) ); \ - bigint_init ( &multiplier_temp, multiplier_raw, \ - sizeof ( multiplier_raw ) ); \ - bigint_init ( &modulus_temp, modulus_raw, \ - sizeof ( modulus_raw ) ); \ - DBG ( "Modular multiply:\n" ); \ - DBG_HDA ( 0, &multiplicand_temp, sizeof ( multiplicand_temp ) );\ - DBG_HDA ( 0, &multiplier_temp, sizeof ( multiplier_temp ) ); \ - DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ - bigint_mod_multiply ( &multiplicand_temp, &multiplier_temp, \ - &modulus_temp, &result_temp, tmp ); \ - DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ - bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\ - \ - ok ( memcmp ( result_raw, expected_raw, \ - sizeof ( result_raw ) ) == 0 ); \ - } while ( 0 ) - /** * Report result of big integer modular exponentiation test * @@ -1933,126 +1865,6 @@ static void bigint_test_exec ( void ) { BIGINT ( 0x03, 0x38, 0xfb, 0xb6, 0xf3, 0x80, 0x91, 0xb2, 0x68, 0x2f, 0x81, 0x44, 0xbf, 0x43, 0x0a, 0x4e ) ); - bigint_mod_multiply_ok ( BIGINT ( 0x37 ), - BIGINT ( 0x67 ), - BIGINT ( 0x3f ), - BIGINT ( 0x3a ) ); - bigint_mod_multiply_ok ( BIGINT ( 0x45, 0x94 ), - BIGINT ( 0xbd, 0xd2 ), - BIGINT ( 0xca, 0xc7 ), - BIGINT ( 0xac, 0xc1 ) ); - bigint_mod_multiply_ok ( BIGINT ( 0x8e, 0xcd, 0x74 ), - BIGINT ( 0xe2, 0xf1, 0xea ), - BIGINT ( 0x59, 0x51, 0x53 ), - BIGINT ( 0x22, 0xdd, 0x1c ) ); - bigint_mod_multiply_ok ( BIGINT ( 0xc2, 0xa8, 0x40, 0x6f ), - BIGINT ( 0x29, 0xd7, 0xf4, 0x77 ), - BIGINT ( 0xbb, 0xbd, 0xdb, 0x3d ), - BIGINT ( 0x8f, 0x39, 0xd0, 0x47 ) ); - bigint_mod_multiply_ok ( BIGINT ( 0x2e, 0xcb, 0x74, 0x7c, 0x64, 0x60, - 0xb3, 0x44, 0xf3, 0x23, 0x49, 0x4a, - 0xc6, 0xb6, 0xbf, 0xea, 0x80, 0xd8, - 0x34, 0xc5, 0x54, 0x22, 0x09 ), - BIGINT ( 0x61, 0x2c, 0x5a, 0xc5, 0xde, 0x07, - 0x65, 0x8e, 0xab, 0x88, 0x1a, 0x2e, - 0x7a, 0x95, 0x17, 0xe3, 0x3b, 0x17, - 0xe4, 0x21, 0xb0, 0xb4, 0x57 ), - BIGINT ( 0x8e, 0x46, 0xa5, 0x87, 0x7b, 0x7f, - 0xc4, 0xd7, 0x31, 0xb1, 0x94, 0xe7, - 0xe7, 0x1c, 0x7e, 0x7a, 0xc2, 0x6c, - 0xce, 0xcb, 0xc8, 0x5d, 0x70 ), - BIGINT ( 0x1e, 0xd1, 0x5b, 0x3d, 0x1d, 0x17, - 0x7c, 0x31, 0x95, 0x13, 0x1b, 0xd8, - 0xee, 0x0a, 0xb0, 0xe1, 0x5b, 0x13, - 0xad, 0x83, 0xe9, 0xf8, 0x7f ) ); - bigint_mod_multiply_ok ( BIGINT ( 0x56, 0x37, 0xab, 0x07, 0x8b, 0x25, - 0xa7, 0xc2, 0x50, 0x30, 0x43, 0xfc, - 0x63, 0x8b, 0xdf, 0x84, 0x68, 0x85, - 0xca, 0xce, 0x44, 0x5c, 0xb1, 0x14, - 0xa4, 0xb5, 0xba, 0x43, 0xe0, 0x31, - 0x45, 0x6b, 0x82, 0xa9, 0x0b, 0x9e, - 0x3a, 0xb0, 0x39, 0x09, 0x2a, 0x68, - 0x2e, 0x0f, 0x09, 0x54, 0x47, 0x04, - 0xdb, 0xcf, 0x4a, 0x3a, 0x2d, 0x7b, - 0x7d, 0x50, 0xa4, 0xc5, 0xeb, 0x13, - 0xdd, 0x49, 0x61, 0x7d, 0x18, 0xa1, - 0x0d, 0x6b, 0x58, 0xba, 0x9f, 0x7c, - 0x81, 0x34, 0x9e, 0xf9, 0x9c, 0x9e, - 0x28, 0xa8, 0x1c, 0x15, 0x16, 0x20, - 0x3c, 0x0a, 0xb1, 0x11, 0x06, 0x93, - 0xbc, 0xd8, 0x4e, 0x49, 0xae, 0x7b, - 0xb4, 0x02, 0x8b, 0x1c, 0x5b, 0x18, - 0xb4, 0xac, 0x7f, 0xdd, 0x70, 0xef, - 0x87, 0xac, 0x1b, 0xac, 0x25, 0xa3, - 0xc9, 0xa7, 0x3a, 0xc5, 0x76, 0x68, - 0x09, 0x1f, 0xa1, 0x48, 0x53, 0xb6, - 0x13, 0xac ), - BIGINT ( 0xef, 0x5c, 0x1f, 0x1a, 0x44, 0x64, - 0x66, 0xcf, 0xdd, 0x3f, 0x0b, 0x27, - 0x81, 0xa7, 0x91, 0x7a, 0x35, 0x7b, - 0x0f, 0x46, 0x5e, 0xca, 0xbf, 0xf8, - 0x50, 0x5e, 0x99, 0x7c, 0xc6, 0x64, - 0x43, 0x00, 0x9f, 0xb2, 0xda, 0xfa, - 0x42, 0x15, 0x9c, 0xa3, 0xd6, 0xc8, - 0x64, 0xa7, 0x65, 0x4a, 0x98, 0xf7, - 0xb3, 0x96, 0x5f, 0x42, 0xf9, 0x73, - 0xe1, 0x75, 0xc3, 0xc4, 0x0b, 0x5d, - 0x5f, 0xf3, 0x04, 0x8a, 0xee, 0x59, - 0xa6, 0x1b, 0x06, 0x38, 0x0b, 0xa2, - 0x9f, 0xb4, 0x4f, 0x6d, 0x50, 0x5e, - 0x37, 0x37, 0x21, 0x83, 0x9d, 0xa3, - 0x12, 0x16, 0x4d, 0xab, 0x36, 0x51, - 0x21, 0xb1, 0x74, 0x66, 0x40, 0x9a, - 0xd3, 0x72, 0xcc, 0x18, 0x40, 0x53, - 0x89, 0xff, 0xd7, 0x00, 0x8d, 0x7e, - 0x93, 0x81, 0xdb, 0x29, 0xb6, 0xd7, - 0x23, 0x2b, 0x67, 0x2f, 0x11, 0x98, - 0x49, 0x87, 0x2f, 0x46, 0xb7, 0x33, - 0x6d, 0x12 ), - BIGINT ( 0x67, 0x7a, 0x17, 0x6a, 0xd2, 0xf8, - 0x49, 0xfb, 0x7c, 0x95, 0x25, 0x54, - 0xf0, 0xab, 0x5b, 0xb3, 0x0e, 0x01, - 0xab, 0xd3, 0x65, 0x6f, 0x7e, 0x18, - 0x05, 0xed, 0x9b, 0xc4, 0x90, 0x6c, - 0xd0, 0x6d, 0x94, 0x79, 0x28, 0xd6, - 0x24, 0x77, 0x9a, 0x08, 0xd2, 0x2f, - 0x7c, 0x2d, 0xa0, 0x0c, 0x14, 0xbe, - 0x7b, 0xee, 0x9e, 0x48, 0x88, 0x3c, - 0x8f, 0x9f, 0xb9, 0x7a, 0xcb, 0x98, - 0x76, 0x61, 0x0d, 0xee, 0xa2, 0x42, - 0x67, 0x1b, 0x2c, 0x42, 0x8f, 0x41, - 0xcc, 0x78, 0xba, 0xba, 0xaa, 0xa2, - 0x92, 0xb0, 0x6e, 0x0c, 0x4e, 0xe1, - 0xa5, 0x13, 0x7d, 0x8a, 0x8f, 0x81, - 0x95, 0x8a, 0xdf, 0x57, 0x93, 0x88, - 0x27, 0x4f, 0x1a, 0x59, 0xa4, 0x74, - 0x22, 0xa9, 0x78, 0xe5, 0xed, 0xb1, - 0x09, 0x26, 0x59, 0xde, 0x88, 0x21, - 0x8d, 0xa2, 0xa8, 0x58, 0x10, 0x7b, - 0x65, 0x96, 0xbf, 0x69, 0x3b, 0xc5, - 0x55, 0xf8 ), - BIGINT ( 0x15, 0xf7, 0x00, 0xeb, 0xc7, 0x5a, - 0x6f, 0xf0, 0x50, 0xf3, 0x21, 0x8a, - 0x8e, 0xa6, 0xf6, 0x67, 0x56, 0x7d, - 0x07, 0x45, 0x89, 0xdb, 0xd7, 0x7e, - 0x9e, 0x28, 0x7f, 0xfb, 0xed, 0xca, - 0x2c, 0xbf, 0x47, 0x77, 0x99, 0x95, - 0xf3, 0xd6, 0x9d, 0xc5, 0x57, 0x81, - 0x7f, 0x97, 0xf2, 0x6b, 0x24, 0xee, - 0xce, 0xc5, 0x9b, 0xe6, 0x42, 0x2d, - 0x37, 0xb7, 0xeb, 0x3d, 0xb5, 0xf7, - 0x1e, 0x86, 0xc2, 0x40, 0x44, 0xc9, - 0x85, 0x5a, 0x1a, 0xc0, 0xac, 0x9e, - 0x78, 0x69, 0x00, 0x7b, 0x93, 0x65, - 0xd7, 0x7f, 0x0c, 0xd6, 0xba, 0x4f, - 0x06, 0x00, 0x61, 0x05, 0xb2, 0x44, - 0xb4, 0xe7, 0xbb, 0x3b, 0x96, 0xb0, - 0x6d, 0xe8, 0x43, 0xd2, 0x03, 0xb7, - 0x0a, 0xc4, 0x6d, 0x30, 0xd8, 0xd5, - 0xe6, 0x54, 0x65, 0xdd, 0xa9, 0x1b, - 0x50, 0xc0, 0xb9, 0x95, 0xb0, 0x7d, - 0x7c, 0xca, 0x63, 0xf8, 0x72, 0xbe, - 0x3b, 0x00 ) ); bigint_mod_exp_ok ( BIGINT ( 0xcd ), BIGINT ( 0xbb ), BIGINT ( 0x25 ), -- cgit v1.2.3-55-g7522 From 97079553b66ea9036348543e2b92cbe29bfd2c6b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 16 Dec 2024 15:09:56 +0000 Subject: [crypto] Calculate inverse of modulus on demand in bigint_montgomery() Reduce the number of parameters passed to bigint_montgomery() by calculating the inverse of the modulus modulo the element size on demand. Cache the result, since Montgomery reduction will be used repeatedly with the same modulus value. In all currently supported algorithms, the modulus is a public value (or a fixed value defined by specification) and so this non-constant timing does not leak any private information. Signed-off-by: Michael Brown --- src/crypto/bigint.c | 40 ++++++++++++++++++---------------------- src/include/ipxe/bigint.h | 8 +++----- src/tests/bigint_test.c | 11 ++--------- 3 files changed, 23 insertions(+), 36 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index b357ea29f..3ef96d13d 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -354,23 +354,17 @@ void bigint_mod_invert_raw ( const bigint_element_t *invertend0, * Perform Montgomery reduction (REDC) of a big integer product * * @v modulus0 Element 0 of big integer modulus - * @v modinv0 Element 0 of the inverse of the modulus modulo 2^k * @v mont0 Element 0 of big integer Montgomery product * @v result0 Element 0 of big integer to hold result * @v size Number of elements in modulus and result * - * Note that only the least significant element of the inverse modulo - * 2^k is required, and that the Montgomery product will be - * overwritten. + * Note that the Montgomery product will be overwritten. */ void bigint_montgomery_raw ( const bigint_element_t *modulus0, - const bigint_element_t *modinv0, bigint_element_t *mont0, bigint_element_t *result0, unsigned int size ) { const bigint_t ( size ) __attribute__ (( may_alias )) *modulus = ( ( const void * ) modulus0 ); - const bigint_t ( 1 ) __attribute__ (( may_alias )) - *modinv = ( ( const void * ) modinv0 ); union { bigint_t ( size * 2 ) full; struct { @@ -380,7 +374,8 @@ void bigint_montgomery_raw ( const bigint_element_t *modulus0, } __attribute__ (( may_alias )) *mont = ( ( void * ) mont0 ); bigint_t ( size ) __attribute__ (( may_alias )) *result = ( ( void * ) result0 ); - bigint_element_t negmodinv = -modinv->element[0]; + static bigint_t ( 1 ) cached; + static bigint_t ( 1 ) negmodinv; bigint_element_t multiple; bigint_element_t carry; unsigned int i; @@ -391,11 +386,18 @@ void bigint_montgomery_raw ( const bigint_element_t *modulus0, /* Sanity checks */ assert ( bigint_bit_is_set ( modulus, 0 ) ); + /* Calculate inverse (or use cached version) */ + if ( cached.element[0] != modulus->element[0] ) { + bigint_mod_invert ( modulus, &negmodinv ); + negmodinv.element[0] = -negmodinv.element[0]; + cached.element[0] = modulus->element[0]; + } + /* Perform multiprecision Montgomery reduction */ for ( i = 0 ; i < size ; i++ ) { /* Determine scalar multiple for this round */ - multiple = ( mont->low.element[i] * negmodinv ); + multiple = ( mont->low.element[i] * negmodinv.element[0] ); /* Multiply value to make it divisible by 2^(width*i) */ carry = 0; @@ -467,7 +469,6 @@ void bigint_mod_exp_raw ( const bigint_element_t *base0, } product; } *temp = tmp; const uint8_t one[1] = { 1 }; - bigint_t ( 1 ) modinv; bigint_element_t submask; unsigned int subsize; unsigned int scale; @@ -494,9 +495,6 @@ void bigint_mod_exp_raw ( const bigint_element_t *base0, if ( ! submask ) submask = ~submask; - /* Calculate inverse of (scaled) modulus N modulo element size */ - bigint_mod_invert ( &temp->modulus, &modinv ); - /* Calculate (R^2 mod N) via direct reduction of (R^2 - N) */ memset ( &temp->product.full, 0, sizeof ( temp->product.full ) ); bigint_subtract ( &temp->padded_modulus, &temp->product.full ); @@ -504,12 +502,11 @@ void bigint_mod_exp_raw ( const bigint_element_t *base0, bigint_copy ( &temp->product.low, &temp->stash ); /* Initialise result = Montgomery(1, R^2 mod N) */ - bigint_montgomery ( &temp->modulus, &modinv, - &temp->product.full, result ); + bigint_montgomery ( &temp->modulus, &temp->product.full, result ); /* Convert base into Montgomery form */ bigint_multiply ( base, &temp->stash, &temp->product.full ); - bigint_montgomery ( &temp->modulus, &modinv, &temp->product.full, + bigint_montgomery ( &temp->modulus, &temp->product.full, &temp->stash ); /* Calculate x1 = base^exponent modulo N */ @@ -518,13 +515,13 @@ void bigint_mod_exp_raw ( const bigint_element_t *base0, /* Square (and reduce) */ bigint_multiply ( result, result, &temp->product.full ); - bigint_montgomery ( &temp->modulus, &modinv, - &temp->product.full, result ); + bigint_montgomery ( &temp->modulus, &temp->product.full, + result ); /* Multiply (and reduce) */ bigint_multiply ( &temp->stash, result, &temp->product.full ); - bigint_montgomery ( &temp->modulus, &modinv, - &temp->product.full, &temp->product.low ); + bigint_montgomery ( &temp->modulus, &temp->product.full, + &temp->product.low ); /* Conditionally swap the multiplied result */ bigint_swap ( result, &temp->product.low, @@ -533,8 +530,7 @@ void bigint_mod_exp_raw ( const bigint_element_t *base0, /* Convert back out of Montgomery form */ bigint_grow ( result, &temp->product.full ); - bigint_montgomery ( &temp->modulus, &modinv, &temp->product.full, - result ); + bigint_montgomery ( &temp->modulus, &temp->product.full, result ); /* Handle even moduli via Garner's algorithm */ if ( subsize ) { diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 3058547a6..90e212b54 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -257,16 +257,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Perform Montgomery reduction (REDC) of a big integer product * * @v modulus Big integer modulus - * @v modinv Big integer inverse of the modulus modulo 2^k * @v mont Big integer Montgomery product * @v result Big integer to hold result * * Note that the Montgomery product will be overwritten. */ -#define bigint_montgomery( modulus, modinv, mont, result ) do { \ +#define bigint_montgomery( modulus, mont, result ) do { \ unsigned int size = bigint_size (modulus); \ - bigint_montgomery_raw ( (modulus)->element, (modinv)->element, \ - (mont)->element, (result)->element, \ + bigint_montgomery_raw ( (modulus)->element, (mont)->element, \ + (result)->element, \ size ); \ } while ( 0 ) @@ -377,7 +376,6 @@ void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0, void bigint_mod_invert_raw ( const bigint_element_t *invertend0, bigint_element_t *inverse0, unsigned int size ); void bigint_montgomery_raw ( const bigint_element_t *modulus0, - const bigint_element_t *modinv0, bigint_element_t *mont0, bigint_element_t *result0, unsigned int size ); void bigint_mod_exp_raw ( const bigint_element_t *base0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index dc74740e6..07ba13bb4 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -207,20 +207,17 @@ void bigint_mod_invert_sample ( const bigint_element_t *invertend0, } void bigint_montgomery_sample ( const bigint_element_t *modulus0, - const bigint_element_t *modinv0, bigint_element_t *mont0, bigint_element_t *result0, unsigned int size ) { const bigint_t ( size ) __attribute__ (( may_alias )) *modulus = ( ( const void * ) modulus0 ); - const bigint_t ( 1 ) __attribute__ (( may_alias )) - *modinv = ( ( const void * ) modinv0 ); bigint_t ( 2 * size ) __attribute__ (( may_alias )) *mont = ( ( void * ) mont0 ); bigint_t ( size ) __attribute__ (( may_alias )) *result = ( ( void * ) result0 ); - bigint_montgomery ( modulus, modinv, mont, result ); + bigint_montgomery ( modulus, mont, result ); } void bigint_mod_exp_sample ( const bigint_element_t *base0, @@ -631,7 +628,6 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, unsigned int size = \ bigint_required_size ( sizeof ( modulus_raw ) ); \ bigint_t ( size ) modulus_temp; \ - bigint_t ( 1 ) modinv_temp; \ bigint_t ( 2 * size ) mont_temp; \ bigint_t ( size ) result_temp; \ {} /* Fix emacs alignment */ \ @@ -641,13 +637,10 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, bigint_init ( &modulus_temp, modulus_raw, \ sizeof ( modulus_raw ) ); \ bigint_init ( &mont_temp, mont_raw, sizeof ( mont_raw ) ); \ - bigint_mod_invert ( &modulus_temp, &modinv_temp ); \ DBG ( "Montgomery:\n" ); \ DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ - DBG_HDA ( 0, &modinv_temp, sizeof ( modinv_temp ) ); \ DBG_HDA ( 0, &mont_temp, sizeof ( mont_temp ) ); \ - bigint_montgomery ( &modulus_temp, &modinv_temp, &mont_temp, \ - &result_temp ); \ + bigint_montgomery ( &modulus_temp, &mont_temp, &result_temp ); \ DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ bigint_done ( &result_temp, result_raw, \ sizeof ( result_raw ) ); \ -- cgit v1.2.3-55-g7522 From 83ba34076ad4ca79be81a71f25303b340c60e7b8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 18 Dec 2024 14:03:37 +0000 Subject: [crypto] Allow for relaxed Montgomery reduction Classic Montgomery reduction involves a single conditional subtraction to ensure that the result is strictly less than the modulus. When performing chains of Montgomery multiplications (potentially interspersed with additions and subtractions), it can be useful to work with values that are stored modulo some small multiple of the modulus, thereby allowing some reductions to be elided. Each addition and subtraction stage will increase this running multiple, and the following multiplication stages can be used to reduce the running multiple since the reduction carried out for multiplication products is generally strong enough to absorb some additional bits in the inputs. This approach is already used in the x25519 code, where multiplication takes two 258-bit inputs and produces a 257-bit output. Split out the conditional subtraction from bigint_montgomery() and provide a separate bigint_montgomery_relaxed() for callers who do not require immediate reduction to within the range of the modulus. Modular exponentiation could potentially make use of relaxed Montgomery multiplication, but this would require R>4N, i.e. that the two most significant bits of the modulus be zero. For both RSA and DHE, this would necessitate extending the modulus size by one element, which would negate any speed increase from omitting the conditional subtractions. We therefore retain the use of classic Montgomery reduction for modular exponentiation, apart from the final conversion out of Montgomery form. Signed-off-by: Michael Brown --- src/crypto/bigint.c | 175 ++++++++++++++++++++++++++++++++++++++++------ src/include/ipxe/bigint.h | 36 +++++++--- src/tests/bigint_test.c | 6 +- 3 files changed, 184 insertions(+), 33 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index 3ef96d13d..92747982e 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -351,18 +351,113 @@ void bigint_mod_invert_raw ( const bigint_element_t *invertend0, } /** - * Perform Montgomery reduction (REDC) of a big integer product + * Perform relaxed Montgomery reduction (REDC) of a big integer * - * @v modulus0 Element 0 of big integer modulus - * @v mont0 Element 0 of big integer Montgomery product + * @v modulus0 Element 0 of big integer odd modulus + * @v value0 Element 0 of big integer to be reduced * @v result0 Element 0 of big integer to hold result * @v size Number of elements in modulus and result + * @ret carry Carry out + * + * The value to be reduced will be made divisible by the size of the + * modulus while retaining its residue class (i.e. multiples of the + * modulus will be added until the low half of the value is zero). + * + * The result may be expressed as + * + * tR = x + mN + * + * where x is the input value, N is the modulus, R=2^n (where n is the + * number of bits in the representation of the modulus, including any + * leading zero bits), and m is the number of multiples of the modulus + * added to make the result tR divisible by R. + * + * The maximum addend is mN <= (R-1)*N (and such an m can be proven to + * exist since N is limited to being odd and therefore coprime to R). + * + * Since the result of this addition is one bit larger than the input + * value, a carry out bit is also returned. The caller may be able to + * prove that the carry out is always zero, in which case it may be + * safely ignored. + * + * The upper half of the output value (i.e. t) will also be copied to + * the result pointer. It is permissible for the result pointer to + * overlap the lower half of the input value. + * + * External knowledge of constraints on the modulus and the input + * value may be used to prove constraints on the result. The + * constraint on the modulus may be generally expressed as + * + * R > kN + * + * for some positive integer k. The value k=1 is allowed, and simply + * expresses that the modulus fits within the number of bits in its + * own representation. + * + * For classic Montgomery reduction, we have k=1, i.e. R > N and a + * separate constraint that the input value is in the range x < RN. + * This gives the result constraint + * + * tR < RN + (R-1)N + * < 2RN - N + * < 2RN + * t < 2N + * + * A single subtraction of the modulus may therefore be required to + * bring it into the range t < N. * - * Note that the Montgomery product will be overwritten. + * When the input value is known to be a product of two integers A and + * B, with A < aN and B < bN, we get the result constraint + * + * tR < abN^2 + (R-1)N + * < (ab/k)RN + RN - N + * < (1 + ab/k)RN + * t < (1 + ab/k)N + * + * If we have k=a=b=1, i.e. R > N with A < N and B < N, then the + * result is in the range t < 2N and may require a single subtraction + * of the modulus to bring it into the range t < N so that it may be + * used as an input on a subsequent iteration. + * + * If we have k=4 and a=b=2, i.e. R > 4N with A < 2N and B < 2N, then + * the result is in the range t < 2N and may immediately be used as an + * input on a subsequent iteration, without requiring a subtraction. + * + * Larger values of k may be used to allow for larger values of a and + * b, which can be useful to elide intermediate reductions in a + * calculation chain that involves additions and subtractions between + * multiplications (as used in elliptic curve point addition, for + * example). As a general rule: each intermediate addition or + * subtraction will require k to be doubled. + * + * When the input value is known to be a single integer A, with A < aN + * (as used when converting out of Montgomery form), we get the result + * constraint + * + * tR < aN + (R-1)N + * < RN + (a-1)N + * + * If we have a=1, i.e. A < N, then the constraint becomes + * + * tR < RN + * t < N + * + * and so the result is immediately in the range t < N with no + * subtraction of the modulus required. + * + * For any larger value of a, the result value t=N becomes possible. + * Additional external knowledge may potentially be used to prove that + * t=N cannot occur. For example: if the caller is performing modular + * exponentiation with a prime modulus (or, more generally, a modulus + * that is coprime to the base), then there is no way for a non-zero + * base value to end up producing an exact multiple of the modulus. + * If t=N cannot be disproved, then conversion out of Montgomery form + * may require an additional subtraction of the modulus. */ -void bigint_montgomery_raw ( const bigint_element_t *modulus0, - bigint_element_t *mont0, - bigint_element_t *result0, unsigned int size ) { +int bigint_montgomery_relaxed_raw ( const bigint_element_t *modulus0, + bigint_element_t *value0, + bigint_element_t *result0, + unsigned int size ) { const bigint_t ( size ) __attribute__ (( may_alias )) *modulus = ( ( const void * ) modulus0 ); union { @@ -371,7 +466,7 @@ void bigint_montgomery_raw ( const bigint_element_t *modulus0, bigint_t ( size ) low; bigint_t ( size ) high; } __attribute__ (( packed )); - } __attribute__ (( may_alias )) *mont = ( ( void * ) mont0 ); + } __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); bigint_t ( size ) __attribute__ (( may_alias )) *result = ( ( void * ) result0 ); static bigint_t ( 1 ) cached; @@ -381,7 +476,6 @@ void bigint_montgomery_raw ( const bigint_element_t *modulus0, unsigned int i; unsigned int j; int overflow; - int underflow; /* Sanity checks */ assert ( bigint_bit_is_set ( modulus, 0 ) ); @@ -397,33 +491,73 @@ void bigint_montgomery_raw ( const bigint_element_t *modulus0, for ( i = 0 ; i < size ; i++ ) { /* Determine scalar multiple for this round */ - multiple = ( mont->low.element[i] * negmodinv.element[0] ); + multiple = ( value->low.element[i] * negmodinv.element[0] ); /* Multiply value to make it divisible by 2^(width*i) */ carry = 0; for ( j = 0 ; j < size ; j++ ) { bigint_multiply_one ( multiple, modulus->element[j], - &mont->full.element[ i + j ], + &value->full.element[ i + j ], &carry ); } /* Since value is now divisible by 2^(width*i), we * know that the current low element must have been - * zeroed. We can store the multiplication carry out - * in this element, avoiding the need to immediately - * propagate the carry through the remaining elements. + * zeroed. + */ + assert ( value->low.element[i] == 0 ); + + /* Store the multiplication carry out in the result, + * avoiding the need to immediately propagate the + * carry through the remaining elements. */ - assert ( mont->low.element[i] == 0 ); - mont->low.element[i] = carry; + result->element[i] = carry; } /* Add the accumulated carries */ - overflow = bigint_add ( &mont->low, &mont->high ); + overflow = bigint_add ( result, &value->high ); + + /* Copy to result buffer */ + bigint_copy ( &value->high, result ); + + return overflow; +} + +/** + * Perform classic Montgomery reduction (REDC) of a big integer + * + * @v modulus0 Element 0 of big integer odd modulus + * @v value0 Element 0 of big integer to be reduced + * @v result0 Element 0 of big integer to hold result + * @v size Number of elements in modulus and result + */ +void bigint_montgomery_raw ( const bigint_element_t *modulus0, + bigint_element_t *value0, + bigint_element_t *result0, + unsigned int size ) { + const bigint_t ( size ) __attribute__ (( may_alias )) + *modulus = ( ( const void * ) modulus0 ); + union { + bigint_t ( size * 2 ) full; + struct { + bigint_t ( size ) low; + bigint_t ( size ) high; + } __attribute__ (( packed )); + } __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); + bigint_t ( size ) __attribute__ (( may_alias )) + *result = ( ( void * ) result0 ); + int overflow; + int underflow; + + /* Sanity check */ + assert ( ! bigint_is_geq ( &value->high, modulus ) ); + + /* Perform relaxed Montgomery reduction */ + overflow = bigint_montgomery_relaxed ( modulus, &value->full, result ); /* Conditionally subtract the modulus once */ - memcpy ( result, &mont->high, sizeof ( *result ) ); underflow = bigint_subtract ( modulus, result ); - bigint_swap ( result, &mont->high, ( underflow & ~overflow ) ); + bigint_swap ( result, &value->high, ( underflow & ~overflow ) ); /* Sanity check */ assert ( ! bigint_is_geq ( result, modulus ) ); @@ -530,7 +664,8 @@ void bigint_mod_exp_raw ( const bigint_element_t *base0, /* Convert back out of Montgomery form */ bigint_grow ( result, &temp->product.full ); - bigint_montgomery ( &temp->modulus, &temp->product.full, result ); + bigint_montgomery_relaxed ( &temp->modulus, &temp->product.full, + result ); /* Handle even moduli via Garner's algorithm */ if ( subsize ) { diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 90e212b54..db907f1cd 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -235,7 +235,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v modulus Big integer modulus * @v value Big integer to be reduced */ -#define bigint_reduce( modulus, value ) do { \ +#define bigint_reduce( modulus, value ) do { \ unsigned int size = bigint_size (modulus); \ bigint_reduce_raw ( (modulus)->element, \ (value)->element, size ); \ @@ -254,19 +254,31 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); } while ( 0 ) /** - * Perform Montgomery reduction (REDC) of a big integer product + * Perform relaxed Montgomery reduction (REDC) of a big integer * - * @v modulus Big integer modulus - * @v mont Big integer Montgomery product + * @v modulus Big integer odd modulus + * @v value Big integer to be reduced * @v result Big integer to hold result + * @ret carry Carry out + */ +#define bigint_montgomery_relaxed( modulus, value, result ) ( { \ + unsigned int size = bigint_size (modulus); \ + bigint_montgomery_relaxed_raw ( (modulus)->element, \ + (value)->element, \ + (result)->element, size ); \ + } ) + +/** + * Perform classic Montgomery reduction (REDC) of a big integer * - * Note that the Montgomery product will be overwritten. + * @v modulus Big integer odd modulus + * @v value Big integer to be reduced + * @v result Big integer to hold result */ -#define bigint_montgomery( modulus, mont, result ) do { \ +#define bigint_montgomery( modulus, value, result ) do { \ unsigned int size = bigint_size (modulus); \ - bigint_montgomery_raw ( (modulus)->element, (mont)->element, \ - (result)->element, \ - size ); \ + bigint_montgomery_raw ( (modulus)->element, (value)->element, \ + (result)->element, size ); \ } while ( 0 ) /** @@ -375,8 +387,12 @@ void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0, unsigned int size ); void bigint_mod_invert_raw ( const bigint_element_t *invertend0, bigint_element_t *inverse0, unsigned int size ); +int bigint_montgomery_relaxed_raw ( const bigint_element_t *modulus0, + bigint_element_t *value0, + bigint_element_t *result0, + unsigned int size ); void bigint_montgomery_raw ( const bigint_element_t *modulus0, - bigint_element_t *mont0, + bigint_element_t *value0, bigint_element_t *result0, unsigned int size ); void bigint_mod_exp_raw ( const bigint_element_t *base0, const bigint_element_t *modulus0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 07ba13bb4..fce5f5ca3 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -207,17 +207,17 @@ void bigint_mod_invert_sample ( const bigint_element_t *invertend0, } void bigint_montgomery_sample ( const bigint_element_t *modulus0, - bigint_element_t *mont0, + bigint_element_t *value0, bigint_element_t *result0, unsigned int size ) { const bigint_t ( size ) __attribute__ (( may_alias )) *modulus = ( ( const void * ) modulus0 ); bigint_t ( 2 * size ) __attribute__ (( may_alias )) - *mont = ( ( void * ) mont0 ); + *value = ( ( void * ) value0 ); bigint_t ( size ) __attribute__ (( may_alias )) *result = ( ( void * ) result0 ); - bigint_montgomery ( modulus, mont, result ); + bigint_montgomery ( modulus, value, result ); } void bigint_mod_exp_sample ( const bigint_element_t *base0, -- cgit v1.2.3-55-g7522 From c2f21a21852741e869b5a64d02d6a49ef16a94cd Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 22 Jan 2025 12:58:54 +0000 Subject: [test] Add generic tests for elliptic curve point multiplication Signed-off-by: Michael Brown --- src/tests/elliptic_test.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++ src/tests/elliptic_test.h | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/tests/elliptic_test.c create mode 100644 src/tests/elliptic_test.h (limited to 'src/tests') diff --git a/src/tests/elliptic_test.c b/src/tests/elliptic_test.c new file mode 100644 index 000000000..4c42e5848 --- /dev/null +++ b/src/tests/elliptic_test.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 + * + * Elliptic curve self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include +#include +#include "elliptic_test.h" + +/** + * Report elliptic curve point multiplication test result + * + * @v test Elliptic curve point multiplication test + * @v file Test code file + * @v line Test code line + */ +void elliptic_okx ( struct elliptic_test *test, const char *file, + unsigned int line ) { + struct elliptic_curve *curve = test->curve; + size_t pointsize = curve->pointsize; + size_t keysize = curve->keysize; + uint8_t actual[pointsize]; + int rc; + + /* Sanity checks */ + okx ( ( test->base_len == pointsize ) || ( ! test->base_len ), + file, line ); + okx ( test->scalar_len == keysize, file, line ); + okx ( ( test->expected_len == pointsize ) || ( ! test->expected_len ), + file, line ); + + /* Perform point multiplication */ + rc = elliptic_multiply ( curve, ( test->base_len ? test->base : NULL ), + test->scalar, actual ); + if ( test->expected_len ) { + okx ( rc == 0, file, line ); + } else { + okx ( rc != 0, file, line ); + } + + /* Check expected result */ + okx ( memcmp ( actual, test->expected, test->expected_len ) == 0, + file, line ); +} diff --git a/src/tests/elliptic_test.h b/src/tests/elliptic_test.h new file mode 100644 index 000000000..94fca60aa --- /dev/null +++ b/src/tests/elliptic_test.h @@ -0,0 +1,77 @@ +#ifndef _ELLIPTIC_TEST_H +#define _ELLIPTIC_TEST_H + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include + +/** An elliptic curve point multiplication test */ +struct elliptic_test { + /** Elliptic curve */ + struct elliptic_curve *curve; + /** Base point */ + const void *base; + /** Length of base point (or 0 to use generator) */ + size_t base_len; + /** Scalar multiple */ + const void *scalar; + /** Length of scalar multiple */ + size_t scalar_len; + /** Expected result point */ + const void *expected; + /** Length of expected result point (or 0 to expect failure) */ + size_t expected_len; +}; + +/** Define inline base point */ +#define BASE(...) { __VA_ARGS__ } + +/** Define base point to be curve's generator */ +#define BASE_GENERATOR BASE() + +/** Define inline scalar multiple */ +#define SCALAR(...) { __VA_ARGS__ } + +/** Define inline expected result point */ +#define EXPECTED(...) { __VA_ARGS__ } + +/** Define result as an expected failure */ +#define EXPECTED_FAIL EXPECTED() + +/** + * Define an elliptic curve point multiplication test + * + * @v name Test name + * @v CURVE Elliptic curve + * @v BASE Base point + * @v SCALAR Scalar multiple + * @v EXPECTED Expected result point + * @ret test Elliptic curve point multiplication test + */ +#define ELLIPTIC_TEST( name, CURVE, BASE, SCALAR, EXPECTED ) \ + static const uint8_t name ## _base[] = BASE; \ + static const uint8_t name ## _scalar[] = SCALAR; \ + static const uint8_t name ## _expected[] = EXPECTED; \ + static struct elliptic_test name = { \ + .curve = CURVE, \ + .base = name ## _base, \ + .base_len = sizeof ( name ## _base ), \ + .scalar = name ## _scalar, \ + .scalar_len = sizeof ( name ## _scalar ), \ + .expected = name ## _expected, \ + .expected_len = sizeof ( name ## _expected ), \ + }; + +extern void elliptic_okx ( struct elliptic_test *test, const char *file, + unsigned int line ); + +/** + * Report an elliptic curve point multiplication test result + * + * @v test Elliptic curve point multiplication test + */ +#define elliptic_ok( test ) elliptic_okx ( test, __FILE__, __LINE__ ) + +#endif /* _ELLIPTIC_TEST_H */ -- cgit v1.2.3-55-g7522 From bc5f3dbe3e03bc67a846981c1fb93206f5557283 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 22 Jan 2025 13:07:23 +0000 Subject: [crypto] Add definitions and tests for the NIST P-256 elliptic curve Signed-off-by: Michael Brown --- src/config/config_crypto.c | 5 ++ src/config/crypto.h | 3 + src/crypto/mishmash/oid_p256.c | 47 +++++++++++ src/crypto/p256.c | 67 ++++++++++++++++ src/include/ipxe/asn1.h | 6 ++ src/include/ipxe/p256.h | 19 +++++ src/include/ipxe/tls.h | 1 + src/tests/p256_test.c | 176 +++++++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 9 files changed, 325 insertions(+) create mode 100644 src/crypto/mishmash/oid_p256.c create mode 100644 src/crypto/p256.c create mode 100644 src/include/ipxe/p256.h create mode 100644 src/tests/p256_test.c (limited to 'src/tests') diff --git a/src/config/config_crypto.c b/src/config/config_crypto.c index f118a9709..99acd3076 100644 --- a/src/config/config_crypto.c +++ b/src/config/config_crypto.c @@ -88,6 +88,11 @@ REQUIRE_OBJECT ( oid_sha512_256 ); REQUIRE_OBJECT ( oid_x25519 ); #endif +/* P-256 */ +#if defined ( CRYPTO_CURVE_P256 ) +REQUIRE_OBJECT ( oid_p256 ); +#endif + /* AES-CBC */ #if defined ( CRYPTO_CIPHER_AES_CBC ) REQUIRE_OBJECT ( oid_aes_cbc ); diff --git a/src/config/crypto.h b/src/config/crypto.h index 589c4f0da..5e96be4aa 100644 --- a/src/config/crypto.h +++ b/src/config/crypto.h @@ -60,6 +60,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** X25519 elliptic curve */ #define CRYPTO_CURVE_X25519 +/** P-256 elliptic curve */ +#define CRYPTO_CURVE_P256 + /** Margin of error (in seconds) allowed in signed timestamps * * We default to allowing a reasonable margin of error: 12 hours to diff --git a/src/crypto/mishmash/oid_p256.c b/src/crypto/mishmash/oid_p256.c new file mode 100644 index 000000000..d473df09f --- /dev/null +++ b/src/crypto/mishmash/oid_p256.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 (at your option) 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 +#include +#include +#include + +/** "prime256v1" object identifier */ +static uint8_t oid_prime256v1[] = { ASN1_OID_PRIME256V1 }; + +/** "prime256v1" OID-identified algorithm */ +struct asn1_algorithm prime256v1_algorithm __asn1_algorithm = { + .name = "prime256v1", + .curve = &p256_curve, + .oid = ASN1_CURSOR ( oid_prime256v1 ), +}; + +/** P-256 named curve */ +struct tls_named_curve tls_secp256r1_named_curve __tls_named_curve ( 01 ) = { + .curve = &p256_curve, + .code = htons ( TLS_NAMED_CURVE_SECP256R1 ), + .format = TLS_POINT_FORMAT_UNCOMPRESSED, + .pre_master_secret_len = P256_LEN, +}; diff --git a/src/crypto/p256.c b/src/crypto/p256.c new file mode 100644 index 000000000..9b0b542a1 --- /dev/null +++ b/src/crypto/p256.c @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 + * + * NIST P-256 elliptic curve + * + */ + +#include + +/** P-256 field prime */ +static const uint8_t p256_prime[P256_LEN] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +/** P-256 constant "a" */ +static const uint8_t p256_a[P256_LEN] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc +}; + +/** P-256 constant "b" */ +static const uint8_t p256_b[P256_LEN] = { + 0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd, + 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x06, 0xb0, 0xcc, 0x53, + 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b +}; + +/** P-256 base point */ +static const uint8_t p256_base[ P256_LEN * 2 ] = { + 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, + 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, + 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, 0x4f, + 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, + 0x7c, 0x0f, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, + 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5 +}; + +/** P-256 elliptic curve */ +WEIERSTRASS_CURVE ( p256, p256_curve, P256_LEN, + p256_prime, p256_a, p256_b, p256_base ); diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index 752b423b9..d503ccf9b 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -127,6 +127,12 @@ struct asn1_builder_header { #define ASN1_OID_TRIPLE( value ) \ ( 0x80 | ( ( (value) >> 14 ) & 0x7f ) ), ASN1_OID_DOUBLE ( (value) ) +/** ASN.1 OID for prime256v1 (1.2.840.10045.3.1.7) */ +#define ASN1_OID_PRIME256V1 \ + ASN1_OID_INITIAL ( 1, 1 ), ASN1_OID_DOUBLE ( 840 ), \ + ASN1_OID_DOUBLE ( 10045 ), ASN1_OID_SINGLE ( 3 ), \ + ASN1_OID_SINGLE ( 1 ), ASN1_OID_SINGLE ( 7 ) + /** ASN.1 OID for rsaEncryption (1.2.840.113549.1.1.1) */ #define ASN1_OID_RSAENCRYPTION \ ASN1_OID_INITIAL ( 1, 2 ), ASN1_OID_DOUBLE ( 840 ), \ diff --git a/src/include/ipxe/p256.h b/src/include/ipxe/p256.h new file mode 100644 index 000000000..0c4e81665 --- /dev/null +++ b/src/include/ipxe/p256.h @@ -0,0 +1,19 @@ +#ifndef _IPXE_P256_H +#define _IPXE_P256_H + +/** @file + * + * NIST P-256 elliptic curve + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** P-256 value length */ +#define P256_LEN ( 256 / 8 ) + +extern struct elliptic_curve p256_curve; + +#endif /* _IPXE_P256_H */ diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index bf9807230..685c62e6d 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -127,6 +127,7 @@ struct tls_header { /* TLS named curve extension */ #define TLS_NAMED_CURVE 10 +#define TLS_NAMED_CURVE_SECP256R1 23 #define TLS_NAMED_CURVE_X25519 29 /* TLS signature algorithms extension */ diff --git a/src/tests/p256_test.c b/src/tests/p256_test.c new file mode 100644 index 000000000..62b8d9247 --- /dev/null +++ b/src/tests/p256_test.c @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 + * + * NIST P-256 elliptic curve self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include "elliptic_test.h" + +/* http://point-at-infinity.org/ecc/nisttv k=1 */ +ELLIPTIC_TEST ( poi_1, &p256_curve, BASE_GENERATOR, + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED ( 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, + 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, + 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, + 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, + 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, + 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, + 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5 ) ); + +/* http://point-at-infinity.org/ecc/nisttv k=2 */ +ELLIPTIC_TEST ( poi_2, &p256_curve, BASE_GENERATOR, + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 ), + EXPECTED ( 0x7c, 0xf2, 0x7b, 0x18, 0x8d, 0x03, 0x4f, 0x7e, + 0x8a, 0x52, 0x38, 0x03, 0x04, 0xb5, 0x1a, 0xc3, + 0xc0, 0x89, 0x69, 0xe2, 0x77, 0xf2, 0x1b, 0x35, + 0xa6, 0x0b, 0x48, 0xfc, 0x47, 0x66, 0x99, 0x78, + 0x07, 0x77, 0x55, 0x10, 0xdb, 0x8e, 0xd0, 0x40, + 0x29, 0x3d, 0x9a, 0xc6, 0x9f, 0x74, 0x30, 0xdb, + 0xba, 0x7d, 0xad, 0xe6, 0x3c, 0xe9, 0x82, 0x29, + 0x9e, 0x04, 0xb7, 0x9d, 0x22, 0x78, 0x73, 0xd1 ) ); + +/* http://point-at-infinity.org/ecc/nisttv k=2 (as base) to k=20 */ +ELLIPTIC_TEST ( poi_2_20, &p256_curve, + BASE ( 0x7c, 0xf2, 0x7b, 0x18, 0x8d, 0x03, 0x4f, 0x7e, + 0x8a, 0x52, 0x38, 0x03, 0x04, 0xb5, 0x1a, 0xc3, + 0xc0, 0x89, 0x69, 0xe2, 0x77, 0xf2, 0x1b, 0x35, + 0xa6, 0x0b, 0x48, 0xfc, 0x47, 0x66, 0x99, 0x78, + 0x07, 0x77, 0x55, 0x10, 0xdb, 0x8e, 0xd0, 0x40, + 0x29, 0x3d, 0x9a, 0xc6, 0x9f, 0x74, 0x30, 0xdb, + 0xba, 0x7d, 0xad, 0xe6, 0x3c, 0xe9, 0x82, 0x29, + 0x9e, 0x04, 0xb7, 0x9d, 0x22, 0x78, 0x73, 0xd1 ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a ), + EXPECTED ( 0x83, 0xa0, 0x1a, 0x93, 0x78, 0x39, 0x5b, 0xab, + 0x9b, 0xcd, 0x6a, 0x0a, 0xd0, 0x3c, 0xc5, 0x6d, + 0x56, 0xe6, 0xb1, 0x92, 0x50, 0x46, 0x5a, 0x94, + 0xa2, 0x34, 0xdc, 0x4c, 0x6b, 0x28, 0xda, 0x9a, + 0x76, 0xe4, 0x9b, 0x6d, 0xe2, 0xf7, 0x32, 0x34, + 0xae, 0x6a, 0x5e, 0xb9, 0xd6, 0x12, 0xb7, 0x5c, + 0x9f, 0x22, 0x02, 0xbb, 0x69, 0x23, 0xf5, 0x4f, + 0xf8, 0x24, 0x0a, 0xaa, 0x86, 0xf6, 0x40, 0xb8 ) ); + +/* http://point-at-infinity.org/ecc/nisttv k=112233445566778899 */ +ELLIPTIC_TEST ( poi_mid, &p256_curve, BASE_GENERATOR, + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x8e, 0xbb, 0xb9, 0x5e, 0xed, 0x0e, 0x13 ), + EXPECTED ( 0x33, 0x91, 0x50, 0x84, 0x4e, 0xc1, 0x52, 0x34, + 0x80, 0x7f, 0xe8, 0x62, 0xa8, 0x6b, 0xe7, 0x79, + 0x77, 0xdb, 0xfb, 0x3a, 0xe3, 0xd9, 0x6f, 0x4c, + 0x22, 0x79, 0x55, 0x13, 0xae, 0xaa, 0xb8, 0x2f, + 0xb1, 0xc1, 0x4d, 0xdf, 0xdc, 0x8e, 0xc1, 0xb2, + 0x58, 0x3f, 0x51, 0xe8, 0x5a, 0x5e, 0xb3, 0xa1, + 0x55, 0x84, 0x0f, 0x20, 0x34, 0x73, 0x0e, 0x9b, + 0x5a, 0xda, 0x38, 0xb6, 0x74, 0x33, 0x6a, 0x21 ) ); + +/* http://point-at-infinity.org/ecc/nisttv k= */ +ELLIPTIC_TEST ( poi_large, &p256_curve, BASE_GENERATOR, + SCALAR ( 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, + 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x50 ), + EXPECTED ( 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, + 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, + 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, + 0xb0, 0x1c, 0xbd, 0x1c, 0x01, 0xe5, 0x80, 0x65, + 0x71, 0x18, 0x14, 0xb5, 0x83, 0xf0, 0x61, 0xe9, + 0xd4, 0x31, 0xcc, 0xa9, 0x94, 0xce, 0xa1, 0x31, + 0x34, 0x49, 0xbf, 0x97, 0xc8, 0x40, 0xae, 0x0a ) ); + +/* Invalid curve point zero */ +ELLIPTIC_TEST ( invalid_zero, &p256_curve, + BASE ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED_FAIL ); + +/* Invalid curve point (base_x, base_y - 1) */ +ELLIPTIC_TEST ( invalid_one, &p256_curve, + BASE ( 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, + 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, + 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, + 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, + 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, + 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, + 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf4 ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED_FAIL ); + +/** + * Perform P-256 self-test + * + */ +static void p256_test_exec ( void ) { + + /* Tests from http://point-at-infinity.org/ecc/nisttv */ + elliptic_ok ( &poi_1 ); + elliptic_ok ( &poi_2 ); + elliptic_ok ( &poi_2_20 ); + elliptic_ok ( &poi_mid ); + elliptic_ok ( &poi_large ); + + /* Invalid point tests */ + elliptic_ok ( &invalid_zero ); + elliptic_ok ( &invalid_one ); +} + +/** P-256 self-test */ +struct self_test p256_test __self_test = { + .name = "p256", + .exec = p256_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index 0e9b3e806..a1659fb29 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -86,3 +86,4 @@ REQUIRE_OBJECT ( des_test ); REQUIRE_OBJECT ( mschapv2_test ); REQUIRE_OBJECT ( uuid_test ); REQUIRE_OBJECT ( editstring_test ); +REQUIRE_OBJECT ( p256_test ); -- cgit v1.2.3-55-g7522 From c85de315a601d95a6348c4caf5d3af6b146274b7 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 30 Jan 2025 15:35:34 +0000 Subject: [crypto] Add definitions and tests for the NIST P-384 elliptic curve Signed-off-by: Michael Brown --- src/config/config_crypto.c | 5 + src/config/crypto.h | 3 + src/crypto/mishmash/oid_p384.c | 47 +++++++++ src/crypto/p384.c | 76 ++++++++++++++ src/include/ipxe/asn1.h | 5 + src/include/ipxe/p384.h | 19 ++++ src/include/ipxe/tls.h | 1 + src/tests/p384_test.c | 222 +++++++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 9 files changed, 379 insertions(+) create mode 100644 src/crypto/mishmash/oid_p384.c create mode 100644 src/crypto/p384.c create mode 100644 src/include/ipxe/p384.h create mode 100644 src/tests/p384_test.c (limited to 'src/tests') diff --git a/src/config/config_crypto.c b/src/config/config_crypto.c index 99acd3076..19d6d032e 100644 --- a/src/config/config_crypto.c +++ b/src/config/config_crypto.c @@ -93,6 +93,11 @@ REQUIRE_OBJECT ( oid_x25519 ); REQUIRE_OBJECT ( oid_p256 ); #endif +/* P-384 */ +#if defined ( CRYPTO_CURVE_P384 ) +REQUIRE_OBJECT ( oid_p384 ); +#endif + /* AES-CBC */ #if defined ( CRYPTO_CIPHER_AES_CBC ) REQUIRE_OBJECT ( oid_aes_cbc ); diff --git a/src/config/crypto.h b/src/config/crypto.h index 5e96be4aa..f2ee9fd0d 100644 --- a/src/config/crypto.h +++ b/src/config/crypto.h @@ -63,6 +63,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** P-256 elliptic curve */ #define CRYPTO_CURVE_P256 +/** P-384 elliptic curve */ +#define CRYPTO_CURVE_P384 + /** Margin of error (in seconds) allowed in signed timestamps * * We default to allowing a reasonable margin of error: 12 hours to diff --git a/src/crypto/mishmash/oid_p384.c b/src/crypto/mishmash/oid_p384.c new file mode 100644 index 000000000..968fb45c1 --- /dev/null +++ b/src/crypto/mishmash/oid_p384.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 (at your option) 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 +#include +#include +#include + +/** "secp384r1" object identifier */ +static uint8_t oid_secp384r1[] = { ASN1_OID_SECP384R1 }; + +/** "secp384r1" OID-identified algorithm */ +struct asn1_algorithm secp384r1_algorithm __asn1_algorithm = { + .name = "secp384r1", + .curve = &p384_curve, + .oid = ASN1_CURSOR ( oid_secp384r1 ), +}; + +/** P-384 named curve */ +struct tls_named_curve tls_secp384r1_named_curve __tls_named_curve ( 01 ) = { + .curve = &p384_curve, + .code = htons ( TLS_NAMED_CURVE_SECP384R1 ), + .format = TLS_POINT_FORMAT_UNCOMPRESSED, + .pre_master_secret_len = P384_LEN, +}; diff --git a/src/crypto/p384.c b/src/crypto/p384.c new file mode 100644 index 000000000..887bf161d --- /dev/null +++ b/src/crypto/p384.c @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 + * + * NIST P-384 elliptic curve + * + */ + +#include + +/** P-384 field prime */ +static const uint8_t p384_prime[P384_LEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff +}; + +/** P-384 constant "a" */ +static const uint8_t p384_a[P384_LEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xfc +}; + +/** P-384 constant "b" */ +static const uint8_t p384_b[P384_LEN] = { + 0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e, 0xe7, 0xe4, 0x98, 0x8e, 0x05, + 0x6b, 0xe3, 0xf8, 0x2d, 0x19, 0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81, + 0x41, 0x12, 0x03, 0x14, 0x08, 0x8f, 0x50, 0x13, 0x87, 0x5a, 0xc6, + 0x56, 0x39, 0x8d, 0x8a, 0x2e, 0xd1, 0x9d, 0x2a, 0x85, 0xc8, 0xed, + 0xd3, 0xec, 0x2a, 0xef +}; + +/** P-384 base point */ +static const uint8_t p384_base[ P384_LEN * 2 ] = { + 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, 0x8e, 0xb1, 0xc7, + 0x1e, 0xf3, 0x20, 0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, + 0x9b, 0x98, 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, 0x55, + 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, + 0x72, 0x76, 0x0a, 0xb7, 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, + 0x6f, 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, + 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, 0xe9, 0xda, 0x31, 0x13, 0xb5, + 0xf0, 0xb8, 0xc0, 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, + 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f +}; + +/** P-384 elliptic curve */ +WEIERSTRASS_CURVE ( p384, p384_curve, P384_LEN, + p384_prime, p384_a, p384_b, p384_base ); diff --git a/src/include/ipxe/asn1.h b/src/include/ipxe/asn1.h index d503ccf9b..8a7461cd3 100644 --- a/src/include/ipxe/asn1.h +++ b/src/include/ipxe/asn1.h @@ -198,6 +198,11 @@ struct asn1_builder_header { ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_SINGLE ( 101 ), \ ASN1_OID_SINGLE ( 110 ) +/** ASN.1 OID for secp384r1 (1.3.132.0.34) */ +#define ASN1_OID_SECP384R1 \ + ASN1_OID_INITIAL ( 1, 3 ), ASN1_OID_DOUBLE ( 132 ), \ + ASN1_OID_SINGLE ( 0 ), ASN1_OID_SINGLE ( 34 ) + /** ASN.1 OID for id-aes128-cbc (2.16.840.1.101.3.4.1.2) */ #define ASN1_OID_AES128_CBC \ ASN1_OID_INITIAL ( 2, 16 ), ASN1_OID_DOUBLE ( 840 ), \ diff --git a/src/include/ipxe/p384.h b/src/include/ipxe/p384.h new file mode 100644 index 000000000..f4631b5f2 --- /dev/null +++ b/src/include/ipxe/p384.h @@ -0,0 +1,19 @@ +#ifndef _IPXE_P384_H +#define _IPXE_P384_H + +/** @file + * + * NIST P-384 elliptic curve + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** P-384 value length */ +#define P384_LEN ( 384 / 8 ) + +extern struct elliptic_curve p384_curve; + +#endif /* _IPXE_P384_H */ diff --git a/src/include/ipxe/tls.h b/src/include/ipxe/tls.h index 685c62e6d..7abbe4ff9 100644 --- a/src/include/ipxe/tls.h +++ b/src/include/ipxe/tls.h @@ -128,6 +128,7 @@ struct tls_header { /* TLS named curve extension */ #define TLS_NAMED_CURVE 10 #define TLS_NAMED_CURVE_SECP256R1 23 +#define TLS_NAMED_CURVE_SECP384R1 24 #define TLS_NAMED_CURVE_X25519 29 /* TLS signature algorithms extension */ diff --git a/src/tests/p384_test.c b/src/tests/p384_test.c new file mode 100644 index 000000000..101cfc24c --- /dev/null +++ b/src/tests/p384_test.c @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 + * + * NIST P-384 elliptic curve self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include "elliptic_test.h" + +/* http://point-at-infinity.org/ecc/nisttv k=1 */ +ELLIPTIC_TEST ( poi_1, &p384_curve, BASE_GENERATOR, + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, + 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, + 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, + 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, + 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, + 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, + 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, + 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, + 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, + 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, + 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, + 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f ) ); + +/* http://point-at-infinity.org/ecc/nisttv k=2 */ +ELLIPTIC_TEST ( poi_2, &p384_curve, BASE_GENERATOR, + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 ), + EXPECTED ( 0x08, 0xd9, 0x99, 0x05, 0x7b, 0xa3, 0xd2, 0xd9, + 0x69, 0x26, 0x00, 0x45, 0xc5, 0x5b, 0x97, 0xf0, + 0x89, 0x02, 0x59, 0x59, 0xa6, 0xf4, 0x34, 0xd6, + 0x51, 0xd2, 0x07, 0xd1, 0x9f, 0xb9, 0x6e, 0x9e, + 0x4f, 0xe0, 0xe8, 0x6e, 0xbe, 0x0e, 0x64, 0xf8, + 0x5b, 0x96, 0xa9, 0xc7, 0x52, 0x95, 0xdf, 0x61, + 0x8e, 0x80, 0xf1, 0xfa, 0x5b, 0x1b, 0x3c, 0xed, + 0xb7, 0xbf, 0xe8, 0xdf, 0xfd, 0x6d, 0xba, 0x74, + 0xb2, 0x75, 0xd8, 0x75, 0xbc, 0x6c, 0xc4, 0x3e, + 0x90, 0x4e, 0x50, 0x5f, 0x25, 0x6a, 0xb4, 0x25, + 0x5f, 0xfd, 0x43, 0xe9, 0x4d, 0x39, 0xe2, 0x2d, + 0x61, 0x50, 0x1e, 0x70, 0x0a, 0x94, 0x0e, 0x80 ) ); + +/* http://point-at-infinity.org/ecc/nisttv k=2 (as base) to k=20 */ +ELLIPTIC_TEST ( poi_2_20, &p384_curve, + BASE ( 0x08, 0xd9, 0x99, 0x05, 0x7b, 0xa3, 0xd2, 0xd9, + 0x69, 0x26, 0x00, 0x45, 0xc5, 0x5b, 0x97, 0xf0, + 0x89, 0x02, 0x59, 0x59, 0xa6, 0xf4, 0x34, 0xd6, + 0x51, 0xd2, 0x07, 0xd1, 0x9f, 0xb9, 0x6e, 0x9e, + 0x4f, 0xe0, 0xe8, 0x6e, 0xbe, 0x0e, 0x64, 0xf8, + 0x5b, 0x96, 0xa9, 0xc7, 0x52, 0x95, 0xdf, 0x61, + 0x8e, 0x80, 0xf1, 0xfa, 0x5b, 0x1b, 0x3c, 0xed, + 0xb7, 0xbf, 0xe8, 0xdf, 0xfd, 0x6d, 0xba, 0x74, + 0xb2, 0x75, 0xd8, 0x75, 0xbc, 0x6c, 0xc4, 0x3e, + 0x90, 0x4e, 0x50, 0x5f, 0x25, 0x6a, 0xb4, 0x25, + 0x5f, 0xfd, 0x43, 0xe9, 0x4d, 0x39, 0xe2, 0x2d, + 0x61, 0x50, 0x1e, 0x70, 0x0a, 0x94, 0x0e, 0x80 ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a ), + EXPECTED ( 0x60, 0x55, 0x08, 0xec, 0x02, 0xc5, 0x34, 0xbc, + 0xee, 0xe9, 0x48, 0x4c, 0x86, 0x08, 0x6d, 0x21, + 0x39, 0x84, 0x9e, 0x2b, 0x11, 0xc1, 0xa9, 0xca, + 0x1e, 0x28, 0x08, 0xde, 0xc2, 0xea, 0xf1, 0x61, + 0xac, 0x8a, 0x10, 0x5d, 0x70, 0xd4, 0xf8, 0x5c, + 0x50, 0x59, 0x9b, 0xe5, 0x80, 0x0a, 0x62, 0x3f, + 0x51, 0x58, 0xee, 0x87, 0x96, 0x2a, 0xc6, 0xb8, + 0x1f, 0x00, 0xa1, 0x03, 0xb8, 0x54, 0x3a, 0x07, + 0x38, 0x1b, 0x76, 0x39, 0xa3, 0xa6, 0x5f, 0x13, + 0x53, 0xae, 0xf1, 0x1b, 0x73, 0x31, 0x06, 0xdd, + 0xe9, 0x2e, 0x99, 0xb7, 0x8d, 0xe3, 0x67, 0xb4, + 0x8e, 0x23, 0x8c, 0x38, 0xda, 0xd8, 0xee, 0xdd ) ); + +/* http://point-at-infinity.org/ecc/nisttv k=112233445566778899 */ +ELLIPTIC_TEST ( poi_mid, &p384_curve, BASE_GENERATOR, + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x8e, 0xbb, 0xb9, 0x5e, 0xed, 0x0e, 0x13 ), + EXPECTED ( 0xa4, 0x99, 0xef, 0xe4, 0x88, 0x39, 0xbc, 0x3a, + 0xbc, 0xd1, 0xc5, 0xce, 0xdb, 0xdd, 0x51, 0x90, + 0x4f, 0x95, 0x14, 0xdb, 0x44, 0xf4, 0x68, 0x6d, + 0xb9, 0x18, 0x98, 0x3b, 0x0c, 0x9d, 0xc3, 0xae, + 0xe0, 0x5a, 0x88, 0xb7, 0x24, 0x33, 0xe9, 0x51, + 0x5f, 0x91, 0xa3, 0x29, 0xf5, 0xf4, 0xfa, 0x60, + 0x3b, 0x7c, 0xa2, 0x8e, 0xf3, 0x1f, 0x80, 0x9c, + 0x2f, 0x1b, 0xa2, 0x4a, 0xae, 0xd8, 0x47, 0xd0, + 0xf8, 0xb4, 0x06, 0xa4, 0xb8, 0x96, 0x85, 0x42, + 0xde, 0x13, 0x9d, 0xb5, 0x82, 0x8c, 0xa4, 0x10, + 0xe6, 0x15, 0xd1, 0x18, 0x2e, 0x25, 0xb9, 0x1b, + 0x11, 0x31, 0xe2, 0x30, 0xb7, 0x27, 0xd3, 0x6a ) ); + +/* http://point-at-infinity.org/ecc/nisttv k= */ +ELLIPTIC_TEST ( poi_large, &p384_curve, BASE_GENERATOR, + SCALAR ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf, + 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a, + 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x72 ), + EXPECTED ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, + 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, + 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, + 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, + 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, + 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, + 0xc9, 0xe8, 0x21, 0xb5, 0x69, 0xd9, 0xd3, 0x90, + 0xa2, 0x61, 0x67, 0x40, 0x6d, 0x6d, 0x23, 0xd6, + 0x07, 0x0b, 0xe2, 0x42, 0xd7, 0x65, 0xeb, 0x83, + 0x16, 0x25, 0xce, 0xec, 0x4a, 0x0f, 0x47, 0x3e, + 0xf5, 0x9f, 0x4e, 0x30, 0xe2, 0x81, 0x7e, 0x62, + 0x85, 0xbc, 0xe2, 0x84, 0x6f, 0x15, 0xf1, 0xa0 ) ); + +/* Invalid curve point zero */ +ELLIPTIC_TEST ( invalid_zero, &p384_curve, + BASE ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED_FAIL ); + +/* Invalid curve point (base_x, base_y - 1) */ +ELLIPTIC_TEST ( invalid_one, &p384_curve, + BASE ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, + 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, + 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, + 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, + 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, + 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, + 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, + 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, + 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, + 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, + 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, + 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5e ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED_FAIL ); + +/** + * Perform P-384 self-test + * + */ +static void p384_test_exec ( void ) { + + /* Tests from http://point-at-infinity.org/ecc/nisttv */ + elliptic_ok ( &poi_1 ); + elliptic_ok ( &poi_2 ); + elliptic_ok ( &poi_2_20 ); + elliptic_ok ( &poi_mid ); + elliptic_ok ( &poi_large ); + + /* Invalid point tests */ + elliptic_ok ( &invalid_zero ); + elliptic_ok ( &invalid_one ); +} + +/** P-384 self-test */ +struct self_test p384_test __self_test = { + .name = "p384", + .exec = p384_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index a1659fb29..96687423f 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -87,3 +87,4 @@ REQUIRE_OBJECT ( mschapv2_test ); REQUIRE_OBJECT ( uuid_test ); REQUIRE_OBJECT ( editstring_test ); REQUIRE_OBJECT ( p256_test ); +REQUIRE_OBJECT ( p384_test ); -- cgit v1.2.3-55-g7522 From 5056e8ad936742ba410031cff14c0f72d87805fc Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 13 Feb 2025 14:18:15 +0000 Subject: [crypto] Expose shifted out bit from big integer shifts Expose the bit shifted out as a result of shifting a big integer left or right. Signed-off-by: Michael Brown --- src/arch/arm32/include/bits/bigint.h | 22 ++++++---- src/arch/arm64/include/bits/bigint.h | 31 +++++++++------ src/arch/loong64/include/bits/bigint.h | 36 +++++++++-------- src/arch/riscv/include/bits/bigint.h | 36 +++++++++-------- src/arch/x86/include/bits/bigint.h | 19 ++++++--- src/include/ipxe/bigint.h | 14 ++++--- src/tests/bigint_test.c | 73 ++++++++++++++++++++++++---------- 7 files changed, 146 insertions(+), 85 deletions(-) (limited to 'src/tests') diff --git a/src/arch/arm32/include/bits/bigint.h b/src/arch/arm32/include/bits/bigint.h index 95de32d83..988bef5ff 100644 --- a/src/arch/arm32/include/bits/bigint.h +++ b/src/arch/arm32/include/bits/bigint.h @@ -123,16 +123,18 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, * * @v value0 Element 0 of big integer * @v size Number of elements + * @ret out Bit shifted out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_shl_raw ( uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint32_t *discard_value; uint32_t *discard_end; uint32_t discard_value_i; + int carry; - __asm__ __volatile__ ( "adds %1, %0, %5, lsl #2\n\t" /* clear CF */ + __asm__ __volatile__ ( "adds %1, %0, %1, lsl #2\n\t" /* clear CF */ "\n1:\n\t" "ldr %2, [%0]\n\t" "adcs %2, %2\n\t" @@ -142,9 +144,10 @@ bigint_shl_raw ( uint32_t *value0, unsigned int size ) { : "=l" ( discard_value ), "=l" ( discard_end ), "=l" ( discard_value_i ), + "=@cccs" ( carry ), "+m" ( *value ) - : "0" ( value0 ), "1" ( size ) - : "cc" ); + : "0" ( value0 ), "1" ( size ) ); + return carry; } /** @@ -152,16 +155,18 @@ bigint_shl_raw ( uint32_t *value0, unsigned int size ) { * * @v value0 Element 0 of big integer * @v size Number of elements + * @ret out Bit shifted out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_shr_raw ( uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint32_t *discard_value; uint32_t *discard_end; uint32_t discard_value_i; + int carry; - __asm__ __volatile__ ( "adds %1, %0, %5, lsl #2\n\t" /* clear CF */ + __asm__ __volatile__ ( "adds %1, %0, %1, lsl #2\n\t" /* clear CF */ "\n1:\n\t" "ldmdb %1!, {%2}\n\t" "rrxs %2, %2\n\t" @@ -171,9 +176,10 @@ bigint_shr_raw ( uint32_t *value0, unsigned int size ) { : "=l" ( discard_value ), "=l" ( discard_end ), "=l" ( discard_value_i ), + "=@cccs" ( carry ), "+m" ( *value ) - : "0" ( value0 ), "1" ( size ) - : "cc" ); + : "0" ( value0 ), "1" ( size ) ); + return carry; } /** diff --git a/src/arch/arm64/include/bits/bigint.h b/src/arch/arm64/include/bits/bigint.h index 5f79dc0c3..f4032e335 100644 --- a/src/arch/arm64/include/bits/bigint.h +++ b/src/arch/arm64/include/bits/bigint.h @@ -122,14 +122,16 @@ bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, * * @v value0 Element 0 of big integer * @v size Number of elements + * @ret out Bit shifted out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_shl_raw ( uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint64_t *discard_value; uint64_t discard_value_i; unsigned int discard_size; + int carry; __asm__ __volatile__ ( "cmn xzr, xzr\n\t" /* clear CF */ "\n1:\n\t" @@ -141,9 +143,10 @@ bigint_shl_raw ( uint64_t *value0, unsigned int size ) { : "=r" ( discard_value ), "=r" ( discard_size ), "=r" ( discard_value_i ), + "=@cccs" ( carry ), "+m" ( *value ) - : "0" ( value0 ), "1" ( size ) - : "cc" ); + : "0" ( value0 ), "1" ( size ) ); + return carry; } /** @@ -151,30 +154,32 @@ bigint_shl_raw ( uint64_t *value0, unsigned int size ) { * * @v value0 Element 0 of big integer * @v size Number of elements + * @ret out Bit shifted out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_shr_raw ( uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint64_t *discard_value; - uint64_t discard_value_i; - uint64_t discard_value_j; + uint64_t discard_high; unsigned int discard_size; + uint64_t low; - __asm__ __volatile__ ( "mov %3, #0\n\t" + __asm__ __volatile__ ( "mov %2, #0\n\t" "\n1:\n\t" "sub %w1, %w1, #1\n\t" - "ldr %2, [%0, %1, lsl #3]\n\t" - "extr %3, %3, %2, #1\n\t" - "str %3, [%0, %1, lsl #3]\n\t" - "mov %3, %2\n\t" + "ldr %3, [%0, %1, lsl #3]\n\t" + "extr %2, %2, %3, #1\n\t" + "str %2, [%0, %1, lsl #3]\n\t" + "mov %2, %3\n\t" "cbnz %w1, 1b\n\t" : "=r" ( discard_value ), "=r" ( discard_size ), - "=r" ( discard_value_i ), - "=r" ( discard_value_j ), + "=r" ( discard_high ), + "=r" ( low ), "+m" ( *value ) : "0" ( value0 ), "1" ( size ) ); + return ( low & 1 ); } /** diff --git a/src/arch/loong64/include/bits/bigint.h b/src/arch/loong64/include/bits/bigint.h index 0222354df..6a879503a 100644 --- a/src/arch/loong64/include/bits/bigint.h +++ b/src/arch/loong64/include/bits/bigint.h @@ -144,26 +144,27 @@ bigint_subtract_raw ( const uint64_t *subtrahend0, uint64_t *value0, * * @v value0 Element 0 of big integer * @v size Number of elements + * @ret out Bit shifted out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_shl_raw ( uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint64_t *discard_value; uint64_t discard_value_i; - uint64_t discard_carry; uint64_t discard_temp; unsigned int discard_size; + uint64_t carry; __asm__ __volatile__ ( "\n1:\n\t" /* Load value[i] */ "ld.d %2, %0, 0\n\t" /* Shift left */ "rotri.d %2, %2, 63\n\t" - "andi %4, %2, 1\n\t" - "xor %2, %2, %4\n\t" - "or %2, %2, %3\n\t" - "move %3, %4\n\t" + "andi %3, %2, 1\n\t" + "xor %2, %2, %3\n\t" + "or %2, %2, %4\n\t" + "move %4, %3\n\t" /* Store value[i] */ "st.d %2, %0, 0\n\t" /* Loop */ @@ -173,11 +174,12 @@ bigint_shl_raw ( uint64_t *value0, unsigned int size ) { : "=r" ( discard_value ), "=r" ( discard_size ), "=r" ( discard_value_i ), - "=r" ( discard_carry ), "=r" ( discard_temp ), + "=r" ( carry ), "+m" ( *value ) - : "0" ( value0 ), "1" ( size ), "3" ( 0 ) + : "0" ( value0 ), "1" ( size ), "4" ( 0 ) : "cc" ); + return ( carry & 1 ); } /** @@ -185,25 +187,26 @@ bigint_shl_raw ( uint64_t *value0, unsigned int size ) { * * @v value0 Element 0 of big integer * @v size Number of elements + * @ret out Bit shifted out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_shr_raw ( uint64_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); uint64_t *discard_value; uint64_t discard_value_i; - uint64_t discard_carry; uint64_t discard_temp; unsigned int discard_size; + uint64_t carry; __asm__ __volatile__ ( "\n1:\n\t" /* Load value[i] */ "ld.d %2, %0, -8\n\t" /* Shift right */ - "andi %4, %2, 1\n\t" - "xor %2, %2, %4\n\t" - "or %2, %2, %3\n\t" - "move %3, %4\n\t" + "andi %3, %2, 1\n\t" + "xor %2, %2, %3\n\t" + "or %2, %2, %4\n\t" + "move %4, %3\n\t" "rotri.d %2, %2, 1\n\t" /* Store value[i] */ "st.d %2, %0, -8\n\t" @@ -214,11 +217,12 @@ bigint_shr_raw ( uint64_t *value0, unsigned int size ) { : "=r" ( discard_value ), "=r" ( discard_size ), "=r" ( discard_value_i ), - "=r" ( discard_carry ), "=r" ( discard_temp ), + "=r" ( carry ), "+m" ( *value ) - : "0" ( value0 + size ), "1" ( size ), "3" ( 0 ) + : "0" ( value0 + size ), "1" ( size ), "4" ( 0 ) : "cc" ); + return ( carry & 1 ); } /** diff --git a/src/arch/riscv/include/bits/bigint.h b/src/arch/riscv/include/bits/bigint.h index ab1070d88..7f87d9748 100644 --- a/src/arch/riscv/include/bits/bigint.h +++ b/src/arch/riscv/include/bits/bigint.h @@ -143,38 +143,40 @@ bigint_subtract_raw ( const unsigned long *subtrahend0, unsigned long *value0, * * @v value0 Element 0 of big integer * @v size Number of elements + * @ret out Bit shifted out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_shl_raw ( unsigned long *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); unsigned long *valueN = ( value0 + size ); unsigned long *discard_value; unsigned long discard_value_i; - unsigned long discard_carry; unsigned long discard_temp; + unsigned long carry; __asm__ __volatile__ ( "\n1:\n\t" /* Load value[i] */ LOADN " %1, (%0)\n\t" /* Shift left */ - "slli %3, %1, 1\n\t" - "or %3, %3, %2\n\t" - "srli %2, %1, %7\n\t" + "slli %2, %1, 1\n\t" + "or %2, %2, %3\n\t" + "srli %3, %1, %7\n\t" /* Store value[i] */ - STOREN " %3, (%0)\n\t" + STOREN " %2, (%0)\n\t" /* Loop */ "addi %0, %0, %6\n\t" "bne %0, %5, 1b\n\t" : "=&r" ( discard_value ), "=&r" ( discard_value_i ), - "=&r" ( discard_carry ), "=&r" ( discard_temp ), + "=&r" ( carry ), "+m" ( *value ) : "r" ( valueN ), "i" ( sizeof ( unsigned long ) ), "i" ( ( 8 * sizeof ( unsigned long ) - 1 ) ), - "0" ( value0 ), "2" ( 0 ) ); + "0" ( value0 ), "3" ( 0 ) ); + return carry; } /** @@ -182,38 +184,40 @@ bigint_shl_raw ( unsigned long *value0, unsigned int size ) { * * @v value0 Element 0 of big integer * @v size Number of elements + * @ret out Bit shifted out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_shr_raw ( unsigned long *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); unsigned long *valueN = ( value0 + size ); unsigned long *discard_value; unsigned long discard_value_i; - unsigned long discard_carry; unsigned long discard_temp; + unsigned long carry; __asm__ __volatile__ ( "\n1:\n\t" /* Load value[i] */ LOADN " %1, %6(%0)\n\t" /* Shift right */ - "srli %3, %1, 1\n\t" - "or %3, %3, %2\n\t" - "slli %2, %1, %7\n\t" + "srli %2, %1, 1\n\t" + "or %2, %2, %3\n\t" + "slli %3, %1, %7\n\t" /* Store value[i] */ - STOREN " %3, %6(%0)\n\t" + STOREN " %2, %6(%0)\n\t" /* Loop */ "addi %0, %0, %6\n\t" "bne %0, %5, 1b\n\t" : "=&r" ( discard_value ), "=&r" ( discard_value_i ), - "=&r" ( discard_carry ), "=&r" ( discard_temp ), + "=&r" ( carry ), "+m" ( *value ) : "r" ( value0 ), "i" ( -( sizeof ( unsigned long ) ) ), "i" ( ( 8 * sizeof ( unsigned long ) - 1 ) ), - "0" ( valueN ), "2" ( 0 ) ); + "0" ( valueN ), "3" ( 0 ) ); + return ( !! carry ); } /** diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h index 4026ca481..4bab3ebf7 100644 --- a/src/arch/x86/include/bits/bigint.h +++ b/src/arch/x86/include/bits/bigint.h @@ -116,22 +116,25 @@ bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0, * * @v value0 Element 0 of big integer * @v size Number of elements + * @ret out Bit shifted out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_shl_raw ( uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); long index; long discard_c; + int out; __asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */ "\n1:\n\t" - "rcll $1, (%3,%0,4)\n\t" + "rcll $1, (%4,%0,4)\n\t" "inc %0\n\t" /* Does not affect CF */ "loop 1b\n\t" : "=&r" ( index ), "=&c" ( discard_c ), - "+m" ( *value ) + "=@ccc" ( out ), "+m" ( *value ) : "r" ( value0 ), "1" ( size ) ); + return out; } /** @@ -139,19 +142,23 @@ bigint_shl_raw ( uint32_t *value0, unsigned int size ) { * * @v value0 Element 0 of big integer * @v size Number of elements + * @ret out Bit shifted out */ -static inline __attribute__ (( always_inline )) void +static inline __attribute__ (( always_inline )) int bigint_shr_raw ( uint32_t *value0, unsigned int size ) { bigint_t ( size ) __attribute__ (( may_alias )) *value = ( ( void * ) value0 ); long discard_c; + int out; __asm__ __volatile__ ( "clc\n\t" "\n1:\n\t" - "rcrl $1, -4(%2,%0,4)\n\t" + "rcrl $1, -4(%3,%0,4)\n\t" "loop 1b\n\t" - : "=&c" ( discard_c ), "+m" ( *value ) + : "=&c" ( discard_c ), "=@ccc" ( out ), + "+m" ( *value ) : "r" ( value0 ), "0" ( size ) ); + return out; } /** diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 410d0fd90..d8f4571e3 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -105,21 +105,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Shift big integer left * * @v value Big integer + * @ret out Bit shifted out */ -#define bigint_shl( value ) do { \ +#define bigint_shl( value ) ( { \ unsigned int size = bigint_size (value); \ bigint_shl_raw ( (value)->element, size ); \ - } while ( 0 ) + } ) /** * Shift big integer right * * @v value Big integer + * @ret out Bit shifted out */ -#define bigint_shr( value ) do { \ +#define bigint_shr( value ) ( { \ unsigned int size = bigint_size (value); \ bigint_shr_raw ( (value)->element, size ); \ - } while ( 0 ) + } ) /** * Test if big integer is equal to zero @@ -413,8 +415,8 @@ int bigint_add_raw ( const bigint_element_t *addend0, bigint_element_t *value0, unsigned int size ); int bigint_subtract_raw ( const bigint_element_t *subtrahend0, bigint_element_t *value0, unsigned int size ); -void bigint_shl_raw ( bigint_element_t *value0, unsigned int size ); -void bigint_shr_raw ( bigint_element_t *value0, unsigned int size ); +int bigint_shl_raw ( bigint_element_t *value0, unsigned int size ); +int bigint_shr_raw ( bigint_element_t *value0, unsigned int size ); int bigint_is_zero_raw ( const bigint_element_t *value0, unsigned int size ); int bigint_is_geq_raw ( const bigint_element_t *value0, const bigint_element_t *reference0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index fce5f5ca3..a1207fedd 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -78,18 +78,18 @@ int bigint_subtract_sample ( const bigint_element_t *subtrahend0, return bigint_subtract ( subtrahend, value ); } -void bigint_shl_sample ( bigint_element_t *value0, unsigned int size ) { +int bigint_shl_sample ( bigint_element_t *value0, unsigned int size ) { bigint_t ( size ) *value __attribute__ (( may_alias )) = ( ( void * ) value0 ); - bigint_shl ( value ); + return bigint_shl ( value ); } -void bigint_shr_sample ( bigint_element_t *value0, unsigned int size ) { +int bigint_shr_sample ( bigint_element_t *value0, unsigned int size ) { bigint_t ( size ) *value __attribute__ (( may_alias )) = ( ( void * ) value0 ); - bigint_shr ( value ); + return bigint_shr ( value ); } int bigint_is_zero_sample ( const bigint_element_t *value0, @@ -321,25 +321,31 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * * @v value Big integer * @v expected Big integer expected result + * @v bit Expected bit shifted out */ -#define bigint_shl_ok( value, expected ) do { \ +#define bigint_shl_ok( value, expected, bit ) do { \ static const uint8_t value_raw[] = value; \ static const uint8_t expected_raw[] = expected; \ uint8_t result_raw[ sizeof ( expected_raw ) ]; \ unsigned int size = \ bigint_required_size ( sizeof ( value_raw ) ); \ + unsigned int msb = ( 8 * sizeof ( value_raw ) ); \ bigint_t ( size ) value_temp; \ + int out; \ {} /* Fix emacs alignment */ \ \ bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ DBG ( "Shift left:\n" ); \ DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bigint_shl ( &value_temp ); \ + out = bigint_shl ( &value_temp ); \ DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ \ ok ( memcmp ( result_raw, expected_raw, \ sizeof ( result_raw ) ) == 0 ); \ + if ( sizeof ( result_raw ) < sizeof ( value_temp ) ) \ + out += bigint_bit_is_set ( &value_temp, msb ); \ + ok ( out == bit ); \ } while ( 0 ) /** @@ -347,25 +353,28 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * * @v value Big integer * @v expected Big integer expected result + * @v bit Expected bit shifted out */ -#define bigint_shr_ok( value, expected ) do { \ +#define bigint_shr_ok( value, expected, bit ) do { \ static const uint8_t value_raw[] = value; \ static const uint8_t expected_raw[] = expected; \ uint8_t result_raw[ sizeof ( expected_raw ) ]; \ unsigned int size = \ bigint_required_size ( sizeof ( value_raw ) ); \ bigint_t ( size ) value_temp; \ + int out; \ {} /* Fix emacs alignment */ \ \ bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ DBG ( "Shift right:\n" ); \ DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bigint_shr ( &value_temp ); \ + out = bigint_shr ( &value_temp ); \ DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ \ ok ( memcmp ( result_raw, expected_raw, \ sizeof ( result_raw ) ) == 0 ); \ + ok ( out == bit ); \ } while ( 0 ) /** @@ -896,13 +905,13 @@ static void bigint_test_exec ( void ) { 0x7f, 0xcb, 0x94, 0x31, 0x1d, 0xbc, 0x44, 0x1a ), 0 ); bigint_shl_ok ( BIGINT ( 0xe0 ), - BIGINT ( 0xc0 ) ); + BIGINT ( 0xc0 ), 1 ); bigint_shl_ok ( BIGINT ( 0x43, 0x1d ), - BIGINT ( 0x86, 0x3a ) ); + BIGINT ( 0x86, 0x3a ), 0 ); bigint_shl_ok ( BIGINT ( 0xac, 0xed, 0x9b ), - BIGINT ( 0x59, 0xdb, 0x36 ) ); + BIGINT ( 0x59, 0xdb, 0x36 ), 1 ); bigint_shl_ok ( BIGINT ( 0x2c, 0xe8, 0x3a, 0x22 ), - BIGINT ( 0x59, 0xd0, 0x74, 0x44 ) ); + BIGINT ( 0x59, 0xd0, 0x74, 0x44 ), 0 ); bigint_shl_ok ( BIGINT ( 0x4e, 0x88, 0x4a, 0x05, 0x5e, 0x10, 0xee, 0x5b, 0xc6, 0x40, 0x0e, 0x03, 0xd7, 0x0d, 0x28, 0xa5, 0x55, 0xb2, 0x50, 0xef, 0x69, @@ -910,7 +919,19 @@ static void bigint_test_exec ( void ) { BIGINT ( 0x9d, 0x10, 0x94, 0x0a, 0xbc, 0x21, 0xdc, 0xb7, 0x8c, 0x80, 0x1c, 0x07, 0xae, 0x1a, 0x51, 0x4a, 0xab, 0x64, 0xa1, 0xde, 0xd3, - 0xa2, 0x3a ) ); + 0xa2, 0x3a ), 0 ); + bigint_shl_ok ( BIGINT ( 0x84, 0x56, 0xaa, 0xb4, 0x23, 0xd4, 0x4e, + 0xea, 0x92, 0x34, 0x61, 0x11, 0x3e, 0x38, + 0x31, 0x8b ), + BIGINT ( 0x08, 0xad, 0x55, 0x68, 0x47, 0xa8, 0x9d, + 0xd5, 0x24, 0x68, 0xc2, 0x22, 0x7c, 0x70, + 0x63, 0x16 ), 1 ); + bigint_shl_ok ( BIGINT ( 0x4a, 0x2b, 0x6b, 0x7c, 0xbf, 0x8a, 0x43, + 0x71, 0x96, 0xd6, 0x2f, 0x14, 0xa0, 0x2a, + 0xf8, 0x15 ), + BIGINT ( 0x94, 0x56, 0xd6, 0xf9, 0x7f, 0x14, 0x86, + 0xe3, 0x2d, 0xac, 0x5e, 0x29, 0x40, 0x55, + 0xf0, 0x2a ), 0 ); bigint_shl_ok ( BIGINT ( 0x07, 0x62, 0x78, 0x70, 0x2e, 0xd4, 0x41, 0xaa, 0x9b, 0x50, 0xb1, 0x9a, 0x71, 0xf5, 0x1c, 0x2f, 0xe7, 0x0d, 0xf1, 0x46, 0x57, @@ -948,15 +969,15 @@ static void bigint_test_exec ( void ) { 0x10, 0xee, 0x09, 0xea, 0x09, 0x9a, 0xd6, 0x49, 0x7c, 0x1e, 0xdb, 0xc7, 0x65, 0xa6, 0x0e, 0xd1, 0xd2, 0x00, 0xb3, 0x41, 0xc9, - 0x3c, 0xbc ) ); + 0x3c, 0xbc ), 0 ); bigint_shr_ok ( BIGINT ( 0x8f ), - BIGINT ( 0x47 ) ); + BIGINT ( 0x47 ), 1 ); bigint_shr_ok ( BIGINT ( 0xaa, 0x1d ), - BIGINT ( 0x55, 0x0e ) ); + BIGINT ( 0x55, 0x0e ), 1 ); bigint_shr_ok ( BIGINT ( 0xf0, 0xbd, 0x68 ), - BIGINT ( 0x78, 0x5e, 0xb4 ) ); + BIGINT ( 0x78, 0x5e, 0xb4 ), 0 ); bigint_shr_ok ( BIGINT ( 0x33, 0xa0, 0x3d, 0x95 ), - BIGINT ( 0x19, 0xd0, 0x1e, 0xca ) ); + BIGINT ( 0x19, 0xd0, 0x1e, 0xca ), 1 ); bigint_shr_ok ( BIGINT ( 0xa1, 0xf4, 0xb9, 0x64, 0x91, 0x99, 0xa1, 0xf4, 0xae, 0xeb, 0x71, 0x97, 0x1b, 0x71, 0x09, 0x38, 0x3f, 0x8f, 0xc5, 0x3a, 0xb9, @@ -964,7 +985,19 @@ static void bigint_test_exec ( void ) { BIGINT ( 0x50, 0xfa, 0x5c, 0xb2, 0x48, 0xcc, 0xd0, 0xfa, 0x57, 0x75, 0xb8, 0xcb, 0x8d, 0xb8, 0x84, 0x9c, 0x1f, 0xc7, 0xe2, 0x9d, 0x5c, - 0xba, 0xca ) ); + 0xba, 0xca ), 0 ); + bigint_shr_ok ( BIGINT ( 0xa4, 0x19, 0xbb, 0x93, 0x0b, 0x3f, 0x47, + 0x5b, 0xb4, 0xb5, 0x7d, 0x75, 0x42, 0x22, + 0xcc, 0xdf ), + BIGINT ( 0x52, 0x0c, 0xdd, 0xc9, 0x85, 0x9f, 0xa3, + 0xad, 0xda, 0x5a, 0xbe, 0xba, 0xa1, 0x11, + 0x66, 0x6f ), 1 ); + bigint_shr_ok ( BIGINT ( 0x27, 0x7e, 0x8f, 0x60, 0x40, 0x93, 0x43, + 0xd6, 0x89, 0x3e, 0x40, 0x61, 0x9a, 0x04, + 0x4c, 0x02 ), + BIGINT ( 0x13, 0xbf, 0x47, 0xb0, 0x20, 0x49, 0xa1, + 0xeb, 0x44, 0x9f, 0x20, 0x30, 0xcd, 0x02, + 0x26, 0x01 ), 0 ); bigint_shr_ok ( BIGINT ( 0xc0, 0xb3, 0x78, 0x46, 0x69, 0x6e, 0x35, 0x94, 0xed, 0x28, 0xdc, 0xfd, 0xf6, 0xdb, 0x2d, 0x24, 0xcb, 0xa4, 0x6f, 0x0e, 0x58, @@ -1002,7 +1035,7 @@ static void bigint_test_exec ( void ) { 0x10, 0x64, 0x55, 0x07, 0xec, 0xa8, 0xc7, 0x46, 0xa8, 0x94, 0xb0, 0xf7, 0xa4, 0x57, 0x1f, 0x72, 0x88, 0x5f, 0xed, 0x4d, 0xc9, - 0x59, 0xbb ) ); + 0x59, 0xbb ), 1 ); bigint_is_zero_ok ( BIGINT ( 0x9b ), 0 ); bigint_is_zero_ok ( BIGINT ( 0x5a, 0x9d ), -- cgit v1.2.3-55-g7522 From 8e6b914c53732b6764c344856787cf67dd44026c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 13 Feb 2025 13:35:45 +0000 Subject: [crypto] Support direct reduction only for Montgomery constant R^2 mod N The only remaining use case for direct reduction (outside of the unit tests) is in calculating the constant R^2 mod N used during Montgomery multiplication. The current implementation of direct reduction requires a writable copy of the modulus (to allow for shifting), and both the modulus and the result buffer must be padded to be large enough to hold (R^2 - N), which is twice the size of the actual values involved. For the special case of reducing R^2 mod N (or any power of two mod N), we can run the same algorithm without needing either a writable copy of the modulus or a padded result buffer. The working state required is only two bits larger than the result buffer, and these additional bits may be held in local variables instead. Rewrite bigint_reduce() to handle only this use case, and remove the no longer necessary uses of double-sized big integers. Signed-off-by: Michael Brown --- src/crypto/bigint.c | 248 +++++++++++++++++++--------------------------- src/crypto/weierstrass.c | 15 +-- src/include/ipxe/bigint.h | 85 ++++++++++++---- src/tests/bigint_test.c | 106 ++++++++++---------- 4 files changed, 221 insertions(+), 233 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/bigint.c b/src/crypto/bigint.c index ad22af771..9ccd9ff88 100644 --- a/src/crypto/bigint.c +++ b/src/crypto/bigint.c @@ -27,7 +27,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include /** @file @@ -35,10 +34,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Big integer support */ -/** Modular direct reduction profiler */ -static struct profiler bigint_mod_profiler __profiler = - { .name = "bigint_mod" }; - /** Minimum number of least significant bytes included in transcription */ #define BIGINT_NTOA_LSB_MIN 16 @@ -180,172 +175,136 @@ void bigint_multiply_raw ( const bigint_element_t *multiplicand0, } /** - * Reduce big integer + * Reduce big integer R^2 modulo N * * @v modulus0 Element 0 of big integer modulus - * @v value0 Element 0 of big integer to be reduced - * @v size Number of elements in modulus and value + * @v result0 Element 0 of big integer to hold result + * @v size Number of elements in modulus and result + * + * Reduce the value R^2 modulo N, where R=2^n and n is the number of + * bits in the representation of the modulus N, including any leading + * zero bits. */ -void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0, - unsigned int size ) { - bigint_t ( size ) __attribute__ (( may_alias )) - *modulus = ( ( void * ) modulus0 ); +void bigint_reduce_raw ( const bigint_element_t *modulus0, + bigint_element_t *result0, unsigned int size ) { + const bigint_t ( size ) __attribute__ (( may_alias )) + *modulus = ( ( const void * ) modulus0 ); bigint_t ( size ) __attribute__ (( may_alias )) - *value = ( ( void * ) value0 ); + *result = ( ( void * ) result0 ); const unsigned int width = ( 8 * sizeof ( bigint_element_t ) ); - bigint_element_t *element; - unsigned int modulus_max; - unsigned int value_max; - unsigned int subshift; - int offset; - int shift; + unsigned int shift; + int max; + int sign; int msb; - int i; - - /* Start profiling */ - profile_start ( &bigint_mod_profiler ); + int carry; - /* Normalise the modulus + /* We have the constants: * - * Scale the modulus by shifting left such that both modulus - * "m" and value "x" have the same most significant set bit. - * (If this is not possible, then the value is already less - * than the modulus, and we may therefore skip reduction - * completely.) - */ - value_max = bigint_max_set_bit ( value ); - modulus_max = bigint_max_set_bit ( modulus ); - shift = ( value_max - modulus_max ); - if ( shift < 0 ) - goto skip; - subshift = ( shift & ( width - 1 ) ); - offset = ( shift / width ); - element = modulus->element; - for ( i = ( ( value_max - 1 ) / width ) ; ; i-- ) { - element[i] = ( element[ i - offset ] << subshift ); - if ( i <= offset ) - break; - if ( subshift ) { - element[i] |= ( element[ i - offset - 1 ] - >> ( width - subshift ) ); - } - } - for ( i-- ; i >= 0 ; i-- ) - element[i] = 0; - - /* Reduce the value "x" by iteratively adding or subtracting - * the scaled modulus "m". + * N = modulus * - * On each loop iteration, we maintain the invariant: + * n = number of bits in the modulus (including any leading zeros) * - * -2m <= x < 2m + * R = 2^n * - * If x is positive, we obtain the new value x' by - * subtracting m, otherwise we add m: + * Let r be the extension of the n-bit result register by a + * separate two's complement sign bit, such that -R <= r < R, + * and define: * - * 0 <= x < 2m => x' := x - m => -m <= x' < m - * -2m <= x < 0 => x' := x + m => -m <= x' < m + * x = r * 2^k * - * and then halve the modulus (by shifting right): + * as the value being reduced modulo N, where k is a + * non-negative integer bit shift. * - * m' = m/2 + * We want to reduce the initial value R^2=2^(2n), which we + * may trivially represent using r=1 and k=2n. * - * We therefore end up with: + * We then iterate over decrementing k, maintaining the loop + * invariant: * - * -m <= x' < m => -2m' <= x' < 2m' + * -N <= r < N * - * i.e. we have preseved the invariant while reducing the - * bounds on x' by one power of two. + * On each iteration we must first double r, to compensate for + * having decremented k: * - * The issue remains of how to determine on each iteration - * whether or not x is currently positive, given that both - * input values are unsigned big integers that may use all - * available bits (including the MSB). + * k' = k - 1 * - * On the first loop iteration, we may simply assume that x is - * positive, since it is unmodified from the input value and - * so is positive by definition (even if the MSB is set). We - * therefore unconditionally perform a subtraction on the - * first loop iteration. + * r' = 2r * - * Let k be the MSB after normalisation. We then have: + * x = r * 2^k = 2r * 2^(k-1) = r' * 2^k' * - * 2^k <= m < 2^(k+1) - * 2^k <= x < 2^(k+1) + * Note that doubling the n-bit result register will create a + * value of n+1 bits: this extra bit needs to be handled + * separately during the calculation. * - * On the first loop iteration, we therefore have: + * We then subtract N (if r is currently non-negative) or add + * N (if r is currently negative) to restore the loop + * invariant: * - * x' = (x - m) - * < 2^(k+1) - 2^k - * < 2^k + * 0 <= r < N => r" = 2r - N => -N <= r" < N + * -N <= r < 0 => r" = 2r + N => -N <= r" < N * - * Any positive value of x' therefore has its MSB set to zero, - * and so we may validly treat the MSB of x' as a sign bit at - * the end of the first loop iteration. + * Note that since N may use all n bits, the most significant + * bit of the n-bit result register is not a valid two's + * complement sign bit for r: the extra sign bit therefore + * also needs to be handled separately. * - * On all subsequent loop iterations, the starting value m is - * guaranteed to have its MSB set to zero (since it has - * already been shifted right at least once). Since we know - * from above that we preserve the loop invariant: + * Once we reach k=0, we have x=r and therefore: * - * -m <= x' < m + * -N <= x < N * - * we immediately know that any positive value of x' also has - * its MSB set to zero, and so we may validly treat the MSB of - * x' as a sign bit at the end of all subsequent loop - * iterations. + * After this last loop iteration (with k=0), we may need to + * add a single multiple of N to ensure that x is positive, + * i.e. lies within the range 0 <= x < N. * - * After the last loop iteration (when m' has been shifted - * back down to the original value of the modulus), we may - * need to add a single multiple of m' to ensure that x' is - * positive, i.e. lies within the range 0 <= x' < m'. To - * allow for reusing the (inlined) expansion of - * bigint_subtract(), we achieve this via a potential - * additional loop iteration that performs the addition and is - * then guaranteed to terminate (since the result will be - * positive). + * Since neither the modulus nor the value R^2 are secret, we + * may elide approximately half of the total number of + * iterations by constructing the initial representation of + * R^2 as r=2^m and k=2n-m (for some m such that 2^m < N). */ - for ( msb = 0 ; ( msb || ( shift >= 0 ) ) ; shift-- ) { - if ( msb ) { - bigint_add ( modulus, value ); - } else { - bigint_subtract ( modulus, value ); - } - msb = bigint_msb_is_set ( value ); - if ( shift > 0 ) - bigint_shr ( modulus ); + + /* Initialise x=R^2 */ + memset ( result, 0, sizeof ( *result ) ); + max = ( bigint_max_set_bit ( modulus ) - 2 ); + if ( max < 0 ) { + /* Degenerate case of N=0 or N=1: return a zero result */ + return; } + bigint_set_bit ( result, max ); + shift = ( ( 2 * size * width ) - max ); + sign = 0; - skip: - /* Sanity check */ - assert ( ! bigint_is_geq ( value, modulus ) ); + /* Iterate as described above */ + while ( shift-- ) { - /* Stop profiling */ - profile_stop ( &bigint_mod_profiler ); -} + /* Calculate 2r, storing extra bit separately */ + msb = bigint_shl ( result ); -/** - * Reduce supremum of big integer representation - * - * @v modulus0 Element 0 of big integer modulus - * @v result0 Element 0 of big integer to hold result - * @v size Number of elements in modulus and value - * - * Reduce the value 2^k (where k is the bit width of the big integer - * representation) modulo the specified modulus. - */ -void bigint_reduce_supremum_raw ( bigint_element_t *modulus0, - bigint_element_t *result0, - unsigned int size ) { - bigint_t ( size ) __attribute__ (( may_alias )) - *modulus = ( ( void * ) modulus0 ); - bigint_t ( size ) __attribute__ (( may_alias )) - *result = ( ( void * ) result0 ); + /* Add or subtract N according to current sign */ + if ( sign ) { + carry = bigint_add ( modulus, result ); + } else { + carry = bigint_subtract ( modulus, result ); + } - /* Calculate (2^k) mod N via direct reduction of (2^k - N) mod N */ - memset ( result, 0, sizeof ( *result ) ); - bigint_subtract ( modulus, result ); - bigint_reduce ( modulus, result ); + /* Calculate new sign of result + * + * We know the result lies in the range -N <= r < N + * and so the tuple (old sign, msb, carry) cannot ever + * take the values (0, 1, 0) or (1, 0, 0). We can + * therefore treat these as don't-care inputs, which + * allows us to simplify the boolean expression by + * ignoring the old sign completely. + */ + assert ( ( sign == msb ) || carry ); + sign = ( msb ^ carry ); + } + + /* Add N to make result positive if necessary */ + if ( sign ) + bigint_add ( modulus, result ); + + /* Sanity check */ + assert ( ! bigint_is_geq ( result, modulus ) ); } /** @@ -805,12 +764,9 @@ void bigint_mod_exp_raw ( const bigint_element_t *base0, ( ( void * ) result0 ); const unsigned int width = ( 8 * sizeof ( bigint_element_t ) ); struct { - union { - bigint_t ( 2 * size ) padded_modulus; - struct { - bigint_t ( size ) modulus; - bigint_t ( size ) stash; - }; + struct { + bigint_t ( size ) modulus; + bigint_t ( size ) stash; }; union { bigint_t ( 2 * size ) full; @@ -833,7 +789,7 @@ void bigint_mod_exp_raw ( const bigint_element_t *base0, } /* Factor modulus as (N * 2^scale) where N is odd */ - bigint_grow ( modulus, &temp->padded_modulus ); + bigint_copy ( modulus, &temp->modulus ); for ( scale = 0 ; ( ! bigint_bit_is_set ( &temp->modulus, 0 ) ) ; scale++ ) { bigint_shr ( &temp->modulus ); @@ -844,10 +800,10 @@ void bigint_mod_exp_raw ( const bigint_element_t *base0, submask = ~submask; /* Calculate (R^2 mod N) */ - bigint_reduce_supremum ( &temp->padded_modulus, &temp->product.full ); - bigint_copy ( &temp->product.low, &temp->stash ); + bigint_reduce ( &temp->modulus, &temp->stash ); /* Initialise result = Montgomery(1, R^2 mod N) */ + bigint_grow ( &temp->stash, &temp->product.full ); bigint_montgomery ( &temp->modulus, &temp->product.full, result ); /* Convert base into Montgomery form */ diff --git a/src/crypto/weierstrass.c b/src/crypto/weierstrass.c index be3909542..c149c7b21 100644 --- a/src/crypto/weierstrass.c +++ b/src/crypto/weierstrass.c @@ -188,10 +188,6 @@ static void weierstrass_init ( struct weierstrass_curve *curve ) { ( ( void * ) curve->mont[0] ); bigint_t ( size ) __attribute__ (( may_alias )) *temp = ( ( void * ) curve->prime[1] ); - bigint_t ( size * 2 ) __attribute__ (( may_alias )) *prime_double = - ( ( void * ) prime ); - bigint_t ( size * 2 ) __attribute__ (( may_alias )) *square_double = - ( ( void * ) square ); bigint_t ( size * 2 ) __attribute__ (( may_alias )) *product = ( ( void * ) temp ); bigint_t ( size ) __attribute__ (( may_alias )) *two = @@ -206,15 +202,8 @@ static void weierstrass_init ( struct weierstrass_curve *curve ) { DBGC ( curve, "WEIERSTRASS %s N = %s\n", curve->name, bigint_ntoa ( prime ) ); - /* Calculate Montgomery constant R^2 mod N - * - * We rely on the fact that the subsequent big integers in the - * cache (i.e. the first prime multiple, and the constant "1") - * have not yet been written to, and so can be treated as - * being the (zero) upper halves required to hold the - * double-width value R^2. - */ - bigint_reduce_supremum ( prime_double, square_double ); + /* Calculate Montgomery constant R^2 mod N */ + bigint_reduce ( prime, square ); DBGC ( curve, "WEIERSTRASS %s R^2 = %s mod N\n", curve->name, bigint_ntoa ( square ) ); diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index d8f4571e3..396462f33 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -146,6 +146,28 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); bigint_is_geq_raw ( (value)->element, (reference)->element, \ size ); } ) +/** + * Set bit in big integer + * + * @v value Big integer + * @v bit Bit to set + */ +#define bigint_set_bit( value, bit ) do { \ + unsigned int size = bigint_size (value); \ + bigint_set_bit_raw ( (value)->element, size, bit ); \ + } while ( 0 ) + +/** + * Clear bit in big integer + * + * @v value Big integer + * @v bit Bit to set + */ +#define bigint_clear_bit( value, bit ) do { \ + unsigned int size = bigint_size (value); \ + bigint_clear_bit_raw ( (value)->element, size, bit ); \ + } while ( 0 ) + /** * Test if bit is set in big integer * @@ -243,29 +265,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); } while ( 0 ) /** - * Reduce big integer + * Reduce big integer R^2 modulo N * * @v modulus Big integer modulus - * @v value Big integer to be reduced + * @v result Big integer to hold result */ -#define bigint_reduce( modulus, value ) do { \ +#define bigint_reduce( modulus, result ) do { \ unsigned int size = bigint_size (modulus); \ - bigint_reduce_raw ( (modulus)->element, (value)->element, \ + bigint_reduce_raw ( (modulus)->element, (result)->element, \ size ); \ } while ( 0 ) -/** - * Reduce supremum of big integer representation - * - * @v modulus0 Big integer modulus - * @v result0 Big integer to hold result - */ -#define bigint_reduce_supremum( modulus, result ) do { \ - unsigned int size = bigint_size (modulus); \ - bigint_reduce_supremum_raw ( (modulus)->element, \ - (result)->element, size ); \ - } while ( 0 ) - /** * Compute inverse of odd big integer modulo any power of two * @@ -369,6 +379,42 @@ typedef void ( bigint_ladder_op_t ) ( const bigint_element_t *operand0, unsigned int size, const void *ctx, void *tmp ); +/** + * Set bit in big integer + * + * @v value0 Element 0 of big integer + * @v size Number of elements + * @v bit Bit to set + */ +static inline __attribute__ (( always_inline )) void +bigint_set_bit_raw ( bigint_element_t *value0, unsigned int size, + unsigned int bit ) { + bigint_t ( size ) __attribute__ (( may_alias )) *value = + ( ( void * ) value0 ); + unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) ); + unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) ); + + value->element[index] |= ( 1UL << subindex ); +} + +/** + * Clear bit in big integer + * + * @v value0 Element 0 of big integer + * @v size Number of elements + * @v bit Bit to clear + */ +static inline __attribute__ (( always_inline )) void +bigint_clear_bit_raw ( bigint_element_t *value0, unsigned int size, + unsigned int bit ) { + bigint_t ( size ) __attribute__ (( may_alias )) *value = + ( ( void * ) value0 ); + unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) ); + unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) ); + + value->element[index] &= ~( 1UL << subindex ); +} + /** * Test if bit is set in big integer * @@ -442,11 +488,8 @@ void bigint_multiply_raw ( const bigint_element_t *multiplicand0, const bigint_element_t *multiplier0, unsigned int multiplier_size, bigint_element_t *result0 ); -void bigint_reduce_raw ( bigint_element_t *modulus0, bigint_element_t *value0, - unsigned int size ); -void bigint_reduce_supremum_raw ( bigint_element_t *modulus0, - bigint_element_t *value0, - unsigned int size ); +void bigint_reduce_raw ( const bigint_element_t *modulus0, + bigint_element_t *result0, unsigned int size ); void bigint_mod_invert_raw ( const bigint_element_t *invertend0, bigint_element_t *inverse0, unsigned int size ); int bigint_montgomery_relaxed_raw ( const bigint_element_t *modulus0, diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index a1207fedd..496efdfe2 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -185,14 +185,14 @@ void bigint_multiply_sample ( const bigint_element_t *multiplicand0, bigint_multiply ( multiplicand, multiplier, result ); } -void bigint_reduce_sample ( bigint_element_t *modulus0, - bigint_element_t *value0, unsigned int size ) { - bigint_t ( size ) __attribute__ (( may_alias )) - *modulus = ( ( void * ) modulus0 ); +void bigint_reduce_sample ( const bigint_element_t *modulus0, + bigint_element_t *result0, unsigned int size ) { + const bigint_t ( size ) __attribute__ (( may_alias )) + *modulus = ( ( const void * ) modulus0 ); bigint_t ( size ) __attribute__ (( may_alias )) - *value = ( ( void * ) value0 ); + *result = ( ( void * ) result0 ); - bigint_reduce ( modulus, value ); + bigint_reduce ( modulus, result ); } void bigint_mod_invert_sample ( const bigint_element_t *invertend0, @@ -553,42 +553,35 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, } while ( 0 ) /** - * Report result of big integer modular direct reduction test + * Report result of big integer modular direct reduction of R^2 test * * @v modulus Big integer modulus - * @v value Big integer to be reduced * @v expected Big integer expected result */ -#define bigint_reduce_ok( modulus, value, expected ) do { \ +#define bigint_reduce_ok( modulus, expected ) do { \ static const uint8_t modulus_raw[] = modulus; \ - static const uint8_t value_raw[] = value; \ static const uint8_t expected_raw[] = expected; \ uint8_t result_raw[ sizeof ( expected_raw ) ]; \ unsigned int size = \ bigint_required_size ( sizeof ( modulus_raw ) ); \ bigint_t ( size ) modulus_temp; \ - bigint_t ( size ) value_temp; \ + bigint_t ( size ) result_temp; \ {} /* Fix emacs alignment */ \ \ assert ( bigint_size ( &modulus_temp ) == \ - bigint_size ( &value_temp ) ); \ + bigint_size ( &result_temp ) ); \ + assert ( sizeof ( result_temp ) == sizeof ( result_raw ) ); \ bigint_init ( &modulus_temp, modulus_raw, \ sizeof ( modulus_raw ) ); \ - bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ - DBG ( "Modular reduce:\n" ); \ + DBG ( "Modular reduce R^2:\n" ); \ DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bigint_reduce ( &modulus_temp, &value_temp ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ + bigint_reduce ( &modulus_temp, &result_temp ); \ + DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ + bigint_done ( &result_temp, result_raw, \ + sizeof ( result_raw ) ); \ \ ok ( memcmp ( result_raw, expected_raw, \ sizeof ( result_raw ) ) == 0 ); \ - \ - bigint_init ( &value_temp, modulus_raw, \ - sizeof ( modulus_raw ) ); \ - ok ( memcmp ( &modulus_temp, &value_temp, \ - sizeof ( modulus_temp ) ) == 0 ); \ } while ( 0 ) /** @@ -1801,39 +1794,46 @@ static void bigint_test_exec ( void ) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ) ); - bigint_reduce_ok ( BIGINT ( 0xaf ), - BIGINT ( 0x00 ), - BIGINT ( 0x00 ) ); - bigint_reduce_ok ( BIGINT ( 0xab ), - BIGINT ( 0xab ), - BIGINT ( 0x00 ) ); - bigint_reduce_ok ( BIGINT ( 0xcc, 0x9d, 0xa0, 0x79, 0x96, 0x6a, 0x46, - 0xd5, 0xb4, 0x30, 0xd2, 0x2b, 0xbf ), - BIGINT ( 0x1d, 0x97, 0x63, 0xc9, 0x97, 0xcd, 0x43, - 0xcb, 0x8e, 0x71, 0xac, 0x41, 0xdd ), - BIGINT ( 0x1d, 0x97, 0x63, 0xc9, 0x97, 0xcd, 0x43, - 0xcb, 0x8e, 0x71, 0xac, 0x41, 0xdd ) ); - bigint_reduce_ok ( BIGINT ( 0x21, 0xfa, 0x4f, 0xce, 0x0f, 0x0f, 0x4d, - 0x43, 0xaa, 0xad, 0x21, 0x30, 0xe5 ), - BIGINT ( 0x21, 0xfa, 0x4f, 0xce, 0x0f, 0x0f, 0x4d, - 0x43, 0xaa, 0xad, 0x21, 0x30, 0xe5 ), + bigint_reduce_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 ), BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) ); + 0x00 ) ); bigint_reduce_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xf3, 0x65, 0x35, 0x41, - 0x66, 0x65 ), - BIGINT ( 0xf9, 0x78, 0x96, 0x39, 0xee, 0x98, 0x42, - 0x6a, 0xb8, 0x74, 0x0b, 0xe8, 0x5c, 0x76, - 0x34, 0xaf ), + 0x01 ), + BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 ) ); + bigint_reduce_ok ( BIGINT ( 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x00 ), + BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 ) ); + bigint_reduce_ok ( BIGINT ( 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 ), + BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00 ) ); + bigint_reduce_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff ), BIGINT ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0xb3, 0x07, 0xe8, 0xb7, - 0x01, 0xf6 ) ); - bigint_reduce_ok ( BIGINT ( 0x47, 0xaa, 0x88, 0x00, 0xd0, 0x30, 0x62, - 0xfb, 0x5d, 0x55 ), - BIGINT ( 0xfe, 0x30, 0xe1, 0xc6, 0x65, 0x97, 0x48, - 0x2e, 0x94, 0xd4 ), - BIGINT ( 0x27, 0x31, 0x49, 0xc3, 0xf5, 0x06, 0x1f, - 0x3c, 0x7c, 0xd5 ) ); + 0x01 ) ); + bigint_reduce_ok ( BIGINT ( 0x39, 0x18, 0x47, 0xc9, 0xa2, 0x1d, 0x4b, + 0xa6 ), + BIGINT ( 0x30, 0x9d, 0xcc, 0xac, 0xd6, 0xf9, 0x2f, + 0xa0 ) ); + bigint_reduce_ok ( BIGINT ( 0x81, 0x96, 0xdb, 0x36, 0xa6, 0xb7, 0x41, + 0x45, 0x92, 0x37, 0x7d, 0x48, 0x1b, 0x2f, + 0x3c, 0xa6 ), + BIGINT ( 0x4a, 0x68, 0x25, 0xf7, 0x2b, 0x72, 0x91, + 0x6e, 0x09, 0x83, 0xca, 0xf1, 0x45, 0x79, + 0x84, 0x18 ) ); + bigint_reduce_ok ( BIGINT ( 0x84, 0x2d, 0xe4, 0x1c, 0xc3, 0x11, 0x4f, + 0xa0, 0x90, 0x4b, 0xa9, 0xa1, 0xdf, 0xed, + 0x4b, 0xe0, 0xb7, 0xfc, 0x5e, 0xd1, 0x91, + 0x59, 0x4d, 0xc2, 0xae, 0x2f, 0x46, 0x9e, + 0x32, 0x6e, 0xf4, 0x67 ), + BIGINT ( 0x46, 0xdd, 0x36, 0x6c, 0x0b, 0xac, 0x3a, + 0x8f, 0x9a, 0x25, 0x90, 0xb2, 0x39, 0xe9, + 0xa4, 0x65, 0xc1, 0xd4, 0xc1, 0x99, 0x61, + 0x95, 0x47, 0xab, 0x4f, 0xd7, 0xad, 0xd4, + 0x3e, 0xe9, 0x9c, 0xfc ) ); bigint_mod_invert_ok ( BIGINT ( 0x01 ), BIGINT ( 0x01 ) ); bigint_mod_invert_ok ( BIGINT ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ), -- cgit v1.2.3-55-g7522 From 5f3ecbde5a68c503ee92becd5ddf427c317c94f1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 11 Mar 2025 11:58:28 +0000 Subject: [crypto] Support extracting certificates from EFI signature list images Add support for the EFI signature list image format (as produced by tools such as efisecdb). The parsing code does not require any EFI boot services functions and so may be enabled even in non-EFI builds. We default to enabling it only for EFI builds. Signed-off-by: Michael Brown --- src/config/config_asn1.c | 3 + src/config/defaults/efi.h | 1 + src/config/general.h | 1 + src/image/efi_siglist.c | 253 +++++++++++++++++++++++++++++++++++++ src/include/ipxe/efi/efi_siglist.h | 22 ++++ src/include/ipxe/errfile.h | 1 + src/tests/efi_siglist_test.c | 167 ++++++++++++++++++++++++ src/tests/tests.c | 1 + 8 files changed, 449 insertions(+) create mode 100644 src/image/efi_siglist.c create mode 100644 src/include/ipxe/efi/efi_siglist.h create mode 100644 src/tests/efi_siglist_test.c (limited to 'src/tests') diff --git a/src/config/config_asn1.c b/src/config/config_asn1.c index c4419d04d..107f99c1d 100644 --- a/src/config/config_asn1.c +++ b/src/config/config_asn1.c @@ -37,3 +37,6 @@ REQUIRE_OBJECT ( der ); #ifdef IMAGE_PEM REQUIRE_OBJECT ( pem ); #endif +#ifdef IMAGE_EFISIG +REQUIRE_OBJECT ( efi_siglist ); +#endif diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index 607f94c14..d9814eab5 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -35,6 +35,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define IMAGE_EFI /* EFI image support */ #define IMAGE_SCRIPT /* iPXE script image support */ +#define IMAGE_EFISIG /* EFI signature list support */ #define SANBOOT_PROTO_ISCSI /* iSCSI protocol */ #define SANBOOT_PROTO_AOE /* AoE protocol */ diff --git a/src/config/general.h b/src/config/general.h index 763a34aa0..c40e4fdae 100644 --- a/src/config/general.h +++ b/src/config/general.h @@ -125,6 +125,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define IMAGE_PNG /* PNG image support */ #define IMAGE_DER /* DER image support */ #define IMAGE_PEM /* PEM image support */ +//#define IMAGE_EFISIG /* EFI signature list image support */ //#define IMAGE_ZLIB /* ZLIB image support */ //#define IMAGE_GZIP /* GZIP image support */ //#define IMAGE_UCODE /* Microcode update image support */ diff --git a/src/image/efi_siglist.c b/src/image/efi_siglist.c new file mode 100644 index 000000000..56c8493d6 --- /dev/null +++ b/src/image/efi_siglist.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 + * + * EFI signature lists + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Find EFI signature list entry + * + * @v data EFI signature list + * @v len Length of EFI signature list + * @v start Starting offset to update + * @v lhdr Signature list header to fill in + * @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 ) { + size_t offset; + size_t remaining; + size_t skip; + size_t dlen; + + /* Scan through signature list */ + offset = 0; + while ( 1 ) { + + /* Read list header */ + assert ( offset <= len ); + remaining = ( len - offset ); + 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 ) ); + + /* Get length of this signature list */ + if ( remaining < lhdr->SignatureListSize ) { + DBGC ( data, "EFISIG [%#zx,%#zx) truncated list at " + "+%#zx\n", *start, len, offset ); + return -EINVAL; + } + remaining = lhdr->SignatureListSize; + + /* Get length of each signature in list */ + 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 ) ) { + DBGC ( data, "EFISIG [%#zx,%#zx) malformed header at " + "+%#zx\n", *start, len, offset ); + return -EINVAL; + } + skip = ( sizeof ( *lhdr ) + lhdr->SignatureHeaderSize ); + offset += skip; + remaining -= skip; + + /* Read signatures */ + for ( ; remaining ; offset += dlen, remaining -= dlen ) { + + /* Check length */ + if ( remaining < dlen ) { + DBGC ( data, "EFISIG [%#zx,%#zx) truncated " + "at +%#zx\n", *start, len, offset ); + return -EINVAL; + } + + /* Continue until we find the requested signature */ + if ( offset < *start ) + continue; + + /* Read data header */ + copy_from_user ( dhdr, data, offset, sizeof ( *dhdr )); + DBGC2 ( data, "EFISIG [%#zx,%#zx) %s ", + offset, ( offset + dlen ), + efi_guid_ntoa ( &lhdr->SignatureType ) ); + DBGC2 ( data, "owner %s\n", + efi_guid_ntoa ( &dhdr->SignatureOwner ) ); + *start = offset; + return 0; + } + } +} + +/** + * Extract ASN.1 object from EFI signature list + * + * @v data EFI signature list + * @v len Length of EFI signature list + * @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. + */ +int efisig_asn1 ( userptr_t 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, + struct asn1_cursor **cursor ); + 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 ); + + /* Parse as PEM or DER based on first character */ + 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" ) ); + next = asn1 ( data, len, ( offset + skip ), cursor ); + if ( next < 0 ) { + rc = next; + DBGC ( data, "EFISIG [%#zx,%#zx) could not extract ASN.1: " + "%s\n", offset, len, strerror ( rc ) ); + goto err_asn1; + } + + /* Check that whole entry was consumed */ + if ( ( ( unsigned int ) next ) != len ) { + DBGC ( data, "EFISIG [%#zx,%#zx) malformed data\n", + offset, len ); + rc = -EINVAL; + goto err_whole; + } + + return len; + + err_whole: + free ( *cursor ); + err_asn1: + err_entry: + return rc; +} + +/** + * Probe EFI signature list image + * + * @v image EFI signature list + * @ret rc Return status code + */ +static int efisig_image_probe ( struct image *image ) { + EFI_SIGNATURE_LIST lhdr; + EFI_SIGNATURE_DATA dhdr; + size_t offset = 0; + unsigned int count = 0; + int rc; + + /* Check file is a well-formed signature list */ + while ( 1 ) { + + /* Find next signature list entry */ + if ( ( rc = efisig_find ( image->data, image->len, &offset, + &lhdr, &dhdr ) ) != 0 ) { + return rc; + } + + /* Skip this entry */ + offset += lhdr.SignatureSize; + count++; + + /* Check if we have reached end of the image */ + if ( offset == image->len ) { + DBGC ( image, "EFISIG %s contains %d signatures\n", + image->name, count ); + return 0; + } + } +} + +/** + * Extract ASN.1 object from EFI signature list image + * + * @v image EFI signature list + * @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 efisig_image_asn1 ( struct image *image, size_t offset, + struct asn1_cursor **cursor ) { + int next; + int rc; + + /* Extract ASN.1 object */ + if ( ( next = efisig_asn1 ( image->data, image->len, offset, + cursor ) ) < 0 ) { + rc = next; + DBGC ( image, "EFISIG %s could not extract ASN.1: %s\n", + image->name, strerror ( rc ) ); + return rc; + } + + return next; +} + +/** EFI signature list image type */ +struct image_type efisig_image_type __image_type ( PROBE_NORMAL ) = { + .name = "EFISIG", + .probe = efisig_image_probe, + .asn1 = efisig_image_asn1, +}; diff --git a/src/include/ipxe/efi/efi_siglist.h b/src/include/ipxe/efi/efi_siglist.h new file mode 100644 index 000000000..177f28b00 --- /dev/null +++ b/src/include/ipxe/efi/efi_siglist.h @@ -0,0 +1,22 @@ +#ifndef _IPXE_EFI_SIGLIST_H +#define _IPXE_EFI_SIGLIST_H + +/** @file + * + * PEM-encoded ASN.1 data + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include +#include +#include + +extern int efisig_asn1 ( userptr_t data, size_t len, size_t offset, + struct asn1_cursor **cursor ); + +extern struct image_type efisig_image_type __image_type ( PROBE_NORMAL ); + +#endif /* _IPXE_EFI_SIGLIST_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index b826a4a6f..15bb31b0e 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -323,6 +323,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_archive ( ERRFILE_IMAGE | 0x000a0000 ) #define ERRFILE_zlib ( ERRFILE_IMAGE | 0x000b0000 ) #define ERRFILE_gzip ( ERRFILE_IMAGE | 0x000c0000 ) +#define ERRFILE_efi_siglist ( ERRFILE_IMAGE | 0x000d0000 ) #define ERRFILE_asn1 ( ERRFILE_OTHER | 0x00000000 ) #define ERRFILE_chap ( ERRFILE_OTHER | 0x00010000 ) diff --git a/src/tests/efi_siglist_test.c b/src/tests/efi_siglist_test.c new file mode 100644 index 000000000..12d1ec6ac --- /dev/null +++ b/src/tests/efi_siglist_test.c @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 + * + * EFI signature list self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include +#include "asn1_test.h" + +/** Define inline data */ +#define DATA(...) { __VA_ARGS__ } + +/** Define inline expected digest */ +#define DIGEST(...) { { __VA_ARGS__ } } + +/** Two certificates, one PEM, one DER, created by efisecdb */ +ASN1 ( efisecdb, &efisig_image_type, + DATA ( 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, 0xa7, 0x4a, 0x87, 0xb5, + 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72, 0x94, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0xaf, 0x1e, + 0xbb, 0xc0, 0x33, 0x74, 0xa2, 0x4c, 0x93, 0xf2, 0xe9, 0x74, + 0x1b, 0x90, 0x98, 0x6c, 0x30, 0x82, 0x01, 0x64, 0x30, 0x82, + 0x01, 0x0e, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x01, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x10, 0x31, 0x0e, 0x30, + 0x0c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x05, 0x74, 0x65, + 0x73, 0x74, 0x32, 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x35, 0x30, + 0x33, 0x31, 0x31, 0x31, 0x31, 0x31, 0x37, 0x32, 0x36, 0x5a, + 0x17, 0x0d, 0x32, 0x35, 0x30, 0x34, 0x31, 0x30, 0x31, 0x31, + 0x31, 0x37, 0x32, 0x36, 0x5a, 0x30, 0x10, 0x31, 0x0e, 0x30, + 0x0c, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x05, 0x74, 0x65, + 0x73, 0x74, 0x32, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, + 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, + 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41, 0x00, 0xc6, 0x75, + 0x2e, 0xc8, 0x09, 0x37, 0x14, 0xd3, 0xc0, 0xa5, 0x88, 0x3e, + 0x0d, 0xf9, 0x6f, 0x9f, 0xf2, 0xab, 0x3a, 0xe4, 0x6c, 0x0e, + 0x2b, 0x78, 0x3c, 0xe9, 0x1a, 0x52, 0x66, 0xbc, 0x7b, 0x7f, + 0xbe, 0xaa, 0xcd, 0x23, 0x68, 0x76, 0x26, 0x95, 0x45, 0x42, + 0xb5, 0xc6, 0x16, 0x2e, 0x3b, 0x33, 0x9d, 0x82, 0x6e, 0x6a, + 0xcf, 0xa5, 0x72, 0x71, 0x40, 0xff, 0xdc, 0x1d, 0x77, 0xe6, + 0x6f, 0x87, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x53, 0x30, + 0x51, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, + 0x04, 0x14, 0x1c, 0x11, 0x40, 0xcc, 0x63, 0xab, 0xad, 0x6a, + 0xa8, 0x83, 0x17, 0xbb, 0xc5, 0xc6, 0x94, 0x29, 0xe1, 0xad, + 0x4e, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, + 0x18, 0x30, 0x16, 0x80, 0x14, 0x1c, 0x11, 0x40, 0xcc, 0x63, + 0xab, 0xad, 0x6a, 0xa8, 0x83, 0x17, 0xbb, 0xc5, 0xc6, 0x94, + 0x29, 0xe1, 0xad, 0x4e, 0x21, 0x30, 0x0f, 0x06, 0x03, 0x55, + 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x05, 0x30, 0x03, 0x01, + 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x41, 0x00, + 0x57, 0xa3, 0x3a, 0x9c, 0x83, 0xae, 0x94, 0x4c, 0xcd, 0x06, + 0x86, 0x9b, 0x25, 0x70, 0x87, 0x61, 0xfe, 0xbf, 0xb4, 0xa6, + 0x52, 0x0b, 0x37, 0x37, 0x85, 0xbb, 0xea, 0x79, 0x2b, 0x0b, + 0xc4, 0x29, 0x03, 0x8d, 0xa0, 0x26, 0xc2, 0xb4, 0x25, 0x1c, + 0x87, 0x08, 0xcb, 0x94, 0xee, 0x61, 0x48, 0xa4, 0xe1, 0x77, + 0xa6, 0x24, 0x2d, 0x15, 0x1b, 0x15, 0x62, 0x6a, 0x0f, 0x28, + 0x7c, 0xcc, 0xa6, 0xaf, 0xa1, 0x59, 0xc0, 0xa5, 0xe4, 0x94, + 0xa7, 0x4a, 0x87, 0xb5, 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72, + 0x4a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x02, + 0x00, 0x00, 0xaf, 0x1e, 0xbb, 0xc0, 0x33, 0x74, 0xa2, 0x4c, + 0x93, 0xf2, 0xe9, 0x74, 0x1b, 0x90, 0x98, 0x6c, 0x2d, 0x2d, + 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, + 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x42, + 0x5a, 0x44, 0x43, 0x43, 0x41, 0x51, 0x36, 0x67, 0x41, 0x77, + 0x49, 0x42, 0x41, 0x67, 0x49, 0x42, 0x41, 0x54, 0x41, 0x4e, + 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47, 0x39, 0x77, + 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x41, 0x51, + 0x4d, 0x51, 0x34, 0x77, 0x44, 0x41, 0x59, 0x44, 0x56, 0x51, + 0x51, 0x44, 0x44, 0x41, 0x56, 0x30, 0x5a, 0x58, 0x4e, 0x30, + 0x0a, 0x4d, 0x54, 0x41, 0x65, 0x46, 0x77, 0x30, 0x79, 0x4e, + 0x54, 0x41, 0x7a, 0x4d, 0x54, 0x45, 0x78, 0x4d, 0x54, 0x45, + 0x33, 0x4d, 0x44, 0x42, 0x61, 0x46, 0x77, 0x30, 0x79, 0x4e, + 0x54, 0x41, 0x30, 0x4d, 0x54, 0x41, 0x78, 0x4d, 0x54, 0x45, + 0x33, 0x4d, 0x44, 0x42, 0x61, 0x4d, 0x42, 0x41, 0x78, 0x44, + 0x6a, 0x41, 0x4d, 0x42, 0x67, 0x4e, 0x56, 0x42, 0x41, 0x4d, + 0x4d, 0x42, 0x58, 0x52, 0x6c, 0x0a, 0x63, 0x33, 0x51, 0x78, + 0x4d, 0x46, 0x77, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, + 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, + 0x42, 0x51, 0x41, 0x44, 0x53, 0x77, 0x41, 0x77, 0x53, 0x41, + 0x4a, 0x42, 0x41, 0x4e, 0x4d, 0x56, 0x4c, 0x35, 0x67, 0x78, + 0x76, 0x6c, 0x35, 0x31, 0x30, 0x32, 0x42, 0x4c, 0x6c, 0x31, + 0x78, 0x79, 0x7a, 0x56, 0x44, 0x6c, 0x4c, 0x77, 0x63, 0x62, + 0x0a, 0x59, 0x72, 0x6e, 0x52, 0x4e, 0x76, 0x53, 0x72, 0x68, + 0x6f, 0x2f, 0x59, 0x61, 0x31, 0x6f, 0x63, 0x31, 0x71, 0x76, + 0x73, 0x75, 0x34, 0x72, 0x71, 0x43, 0x64, 0x2f, 0x30, 0x68, + 0x65, 0x6a, 0x55, 0x6a, 0x4e, 0x66, 0x71, 0x4b, 0x47, 0x64, + 0x79, 0x57, 0x61, 0x49, 0x67, 0x43, 0x45, 0x38, 0x71, 0x78, + 0x4e, 0x50, 0x34, 0x68, 0x32, 0x64, 0x37, 0x4e, 0x72, 0x45, + 0x43, 0x41, 0x77, 0x45, 0x41, 0x0a, 0x41, 0x61, 0x4e, 0x54, + 0x4d, 0x46, 0x45, 0x77, 0x48, 0x51, 0x59, 0x44, 0x56, 0x52, + 0x30, 0x4f, 0x42, 0x42, 0x59, 0x45, 0x46, 0x47, 0x38, 0x46, + 0x4d, 0x78, 0x52, 0x6e, 0x53, 0x6b, 0x36, 0x34, 0x65, 0x79, + 0x42, 0x69, 0x56, 0x43, 0x35, 0x75, 0x67, 0x73, 0x35, 0x63, + 0x4f, 0x77, 0x38, 0x6a, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, + 0x55, 0x64, 0x49, 0x77, 0x51, 0x59, 0x4d, 0x42, 0x61, 0x41, + 0x0a, 0x46, 0x47, 0x38, 0x46, 0x4d, 0x78, 0x52, 0x6e, 0x53, + 0x6b, 0x36, 0x34, 0x65, 0x79, 0x42, 0x69, 0x56, 0x43, 0x35, + 0x75, 0x67, 0x73, 0x35, 0x63, 0x4f, 0x77, 0x38, 0x6a, 0x4d, + 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x45, + 0x42, 0x2f, 0x77, 0x51, 0x46, 0x4d, 0x41, 0x4d, 0x42, 0x41, + 0x66, 0x38, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a, + 0x49, 0x68, 0x76, 0x63, 0x4e, 0x0a, 0x41, 0x51, 0x45, 0x4c, + 0x42, 0x51, 0x41, 0x44, 0x51, 0x51, 0x41, 0x4a, 0x4d, 0x54, + 0x78, 0x6c, 0x62, 0x4e, 0x43, 0x58, 0x62, 0x6b, 0x2f, 0x73, + 0x6a, 0x79, 0x67, 0x4b, 0x30, 0x39, 0x58, 0x68, 0x50, 0x38, + 0x48, 0x74, 0x4c, 0x6b, 0x45, 0x2b, 0x34, 0x33, 0x6e, 0x61, + 0x67, 0x44, 0x39, 0x4b, 0x52, 0x48, 0x35, 0x53, 0x52, 0x47, + 0x6b, 0x68, 0x45, 0x43, 0x34, 0x50, 0x7a, 0x68, 0x53, 0x31, + 0x0a, 0x52, 0x76, 0x65, 0x34, 0x79, 0x4a, 0x35, 0x50, 0x2b, + 0x4b, 0x4a, 0x74, 0x36, 0x4d, 0x65, 0x78, 0x38, 0x4c, 0x48, + 0x37, 0x79, 0x2b, 0x74, 0x38, 0x61, 0x42, 0x62, 0x79, 0x68, + 0x56, 0x30, 0x47, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, + 0x4e, 0x44, 0x20, 0x43, 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, + 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a ), + DIGEST ( 0x87, 0x95, 0x3b, 0x90, 0xb5, 0x5c, 0xb6, 0x7b, 0xc3, 0xfb, + 0xcb, 0x2c, 0x72, 0xbd, 0x4c, 0x2d, 0xb9, 0x9f, 0x10, 0xda ), + DIGEST ( 0x9b, 0x08, 0xa2, 0x7d, 0x53, 0x35, 0x0a, 0xeb, 0x53, 0xca, + 0x50, 0x66, 0xc0, 0xfd, 0xbd, 0x70, 0x78, 0xf2, 0xa0, 0xc9 ) ); + +/** + * Perform EFI signature list self-test + * + */ +static void efisig_test_exec ( void ) { + + /* Perform tests */ + asn1_ok ( &efisecdb ); +} + +/** EFI signature list self-test */ +struct self_test efisig_test __self_test = { + .name = "efisig", + .exec = efisig_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index 96687423f..865818bdc 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -88,3 +88,4 @@ REQUIRE_OBJECT ( uuid_test ); REQUIRE_OBJECT ( editstring_test ); REQUIRE_OBJECT ( p256_test ); REQUIRE_OBJECT ( p384_test ); +REQUIRE_OBJECT ( efi_siglist_test ); -- cgit v1.2.3-55-g7522 From d6ee9a9242f7f2c3ea1fad6959ff16481b34f6b3 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 12 Mar 2025 14:15:16 +0000 Subject: [cpio] Fix calculation of name lengths in CPIO headers Commit 12ea8c4 ("[cpio] Allow for construction of parent directories as needed") introduced a regression in constructing CPIO archive headers for relative paths (e.g. simple filenames with no leading slash). Fix by counting the number of path components rather than the number of path separators, and add some test cases to cover CPIO header construction. Signed-off-by: Michael Brown --- src/core/cpio.c | 16 +-- src/tests/cpio_test.c | 263 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 3 files changed, 274 insertions(+), 6 deletions(-) create mode 100644 src/tests/cpio_test.c (limited to 'src/tests') diff --git a/src/core/cpio.c b/src/core/cpio.c index 4a7061960..63ac28ee6 100644 --- a/src/core/cpio.c +++ b/src/core/cpio.c @@ -63,14 +63,15 @@ static unsigned int cpio_max ( struct image *image ) { const char *name = cpio_name ( image ); unsigned int max = 0; char c; + char p; /* Check for existence of CPIO filename */ if ( ! name ) return 0; - /* Count number of path separators */ - while ( ( ( c = *(name++) ) ) && ( c != ' ' ) ) { - if ( c == '/' ) + /* Count number of path components */ + for ( p = '/' ; ( ( ( c = *(name++) ) ) && ( c != ' ' ) ) ; p = c ) { + if ( ( p == '/' ) && ( c != '/' ) ) max++; } @@ -88,13 +89,16 @@ static size_t cpio_name_len ( struct image *image, unsigned int depth ) { const char *name = cpio_name ( image ); size_t len; char c; + char p; - /* Sanity check */ + /* Sanity checks */ assert ( name != NULL ); + assert ( depth > 0 ); /* Calculate length up to specified path depth */ - for ( len = 0 ; ( ( ( c = name[len] ) ) && ( c != ' ' ) ) ; len++ ) { - if ( ( c == '/' ) && ( depth-- == 0 ) ) + for ( len = 0, p = '/' ; ( ( ( c = name[len] ) ) && ( c != ' ' ) ) ; + len++, p = c ) { + if ( ( c == '/' ) && ( p != '/' ) && ( --depth == 0 ) ) break; } diff --git a/src/tests/cpio_test.c b/src/tests/cpio_test.c new file mode 100644 index 000000000..3498c0f95 --- /dev/null +++ b/src/tests/cpio_test.c @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 + * + * CPIO self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include + +/** A CPIO test */ +struct cpio_test { + /** Test name */ + const char *name; + /** Image length */ + size_t len; + /** Image command line */ + const char *cmdline; + /** Expected CPIO headers */ + const uint8_t *expected; + /** Length of expected CPIO headers */ + size_t expected_len; + /** Expected number of CPIO headers */ + unsigned int expected_count; +}; + +/** Define an expected CPIO header */ +#define CPIO_HEADER( mode, filesize, namesize, pname ) \ + "070701" "00000000" mode "00000000" "00000000" "00000001" \ + "00000000" filesize "00000000" "00000000" "00000000" "00000000" \ + namesize "00000000" pname + +/** Define a one-byte padding */ +#define PAD1 "\0" + +/** Define a two-byte padding */ +#define PAD2 "\0\0" + +/** Define a three-byte padding */ +#define PAD3 "\0\0\0" + +/** Define four-byte padding */ +#define PAD4 "\0\0\0\0" + +/** Define a CPIO test */ +#define CPIO_TEST( NAME, LEN, CMDLINE, COUNT, EXPECTED ) \ + static const uint8_t NAME ## _expected[] = EXPECTED; \ + static struct cpio_test NAME = { \ + .name = #NAME, \ + .len = LEN, \ + .cmdline = CMDLINE, \ + .expected = NAME ## _expected, \ + .expected_len = ( sizeof ( NAME ## _expected ) \ + - 1 /* NUL */ ), \ + .expected_count = COUNT, \ + }; + +/** + * Report a CPIO test result + * + * @v test CPIO test + * @v file Test code file + * @v line Test code line + */ +static void cpio_okx ( struct cpio_test *test, const char *file, + unsigned int line ) { + struct cpio_header cpio; + struct image *image; + uint8_t *data; + size_t len; + size_t cpio_len; + unsigned int i; + unsigned int j; + + DBGC ( test, "CPIO len %#zx cmdline \"%s\"\n", + test->len, test->cmdline ); + DBGC2_HDA ( test, 0, test->expected, test->expected_len ); + + /* Sanity check */ + okx ( ( test->expected_len % CPIO_ALIGN ) == 0, file, line ); + + /* Construct dummy image */ + image = alloc_image ( NULL ); + okx ( image != NULL, file, line ); + okx ( image_set_name ( image, test->name ) == 0, file, line ); + okx ( image_set_len ( image, test->len ) == 0, file, line ); + okx ( image_set_cmdline ( image, test->cmdline ) == 0, file, line ); + + /* Calculate length of CPIO headers */ + len = 0; + for ( i = 0 ; ( cpio_len = cpio_header ( image, i, &cpio ) ) ; i++ ) { + okx ( cpio_len >= sizeof ( cpio ), file, line ); + len += ( cpio_len + cpio_pad_len ( cpio_len ) ); + okx ( cpio_pad_len ( cpio_len ) > 0, file, line ); + okx ( ( len % CPIO_ALIGN ) == 0, file, line ); + } + okx ( i == test->expected_count, file, line ); + okx ( len == test->expected_len, file, line ); + + /* Allocate space for CPIO headers */ + data = zalloc ( len ); + okx ( data != NULL, file, line ); + + /* Construct CPIO headers */ + len = 0; + for ( i = 0 ; ( cpio_len = cpio_header ( image, i, &cpio ) ) ; i++ ) { + memcpy ( ( data + len ), &cpio, sizeof ( cpio ) ); + memcpy ( ( data + len + sizeof ( cpio ) ), cpio_name ( image ), + ( cpio_len - sizeof ( cpio ) ) ); + DBGC ( test, "CPIO hdr %d: ", i ); + for ( j = 0 ; j < cpio_len ; j++ ) { + if ( ( j <= sizeof ( cpio ) && ! ( ( j + 2 ) % 8 ) ) ) + DBGC ( test, " " ); + DBGC ( test, "%c", data[ len + j ] ); + } + DBGC ( test, "\n" ); + len += ( cpio_len + cpio_pad_len ( cpio_len ) ); + } + okx ( i == test->expected_count, file, line ); + okx ( len == test->expected_len, file, line ); + + /* Verify constructed CPIO headers */ + DBGC2_HDA ( test, 0, data, len ); + okx ( memcmp ( data, test->expected, test->expected_len ) == 0, + file, line ); + + /* Free constructed headers */ + free ( data ); + + /* Drop reference to dummy image */ + image_put ( image ); +} +#define cpio_ok( test ) cpio_okx ( test, __FILE__, __LINE__ ) + +/* Image with no command line */ +CPIO_TEST ( no_cmdline, 42, NULL, 0, "" ); + +/* Image with empty command line */ +CPIO_TEST ( empty_cmdline, 154, "", 0, "" ); + +/* All slashes */ +CPIO_TEST ( all_slashes, 64, "////", 0, "" ); + +/* Simple filename */ +CPIO_TEST ( simple, 0x69, "wimboot", 1, + CPIO_HEADER ( "000081a4", "00000069", "00000008", + "wimboot" PAD3 ) ); + +/* Initial slash */ +CPIO_TEST ( init_slash, 0x273, "/wimboot", 1, + CPIO_HEADER ( "000081a4", "00000273", "00000009", + "/wimboot" PAD2 ) ); + +/* Initial slashes */ +CPIO_TEST ( init_slashes, 0x94, "///initscript", 1, + CPIO_HEADER ( "000081a4", "00000094", "0000000e", + "///initscript" PAD1 ) ); + +/* Full path */ +CPIO_TEST ( path, 0x341, "/usr/share/oem/config.ign", 1, + CPIO_HEADER ( "000081a4", "00000341", "0000001a", + "/usr/share/oem/config.ign" PAD1 ) ); + +/* Full path, mkdir=0 */ +CPIO_TEST ( path_mkdir_0, 0x341, "/usr/share/oem/config.ign mkdir=0", 1, + CPIO_HEADER ( "000081a4", "00000341", "0000001a", + "/usr/share/oem/config.ign" PAD1 ) ); + +/* Full path, mkdir=1 */ +CPIO_TEST ( path_mkdir_1, 0x341, "/usr/share/oem/config.ign mkdir=1", 2, + CPIO_HEADER ( "000041ed", "00000000", "0000000f", + "/usr/share/oem" PAD4 ) + CPIO_HEADER ( "000081a4", "00000341", "0000001a", + "/usr/share/oem/config.ign" PAD1 ) ); + +/* Full path, mkdir=2 */ +CPIO_TEST ( path_mkdir_2, 0x341, "/usr/share/oem/config.ign mkdir=2", 3, + CPIO_HEADER ( "000041ed", "00000000", "0000000b", + "/usr/share" PAD4 ) + CPIO_HEADER ( "000041ed", "00000000", "0000000f", + "/usr/share/oem" PAD4 ) + CPIO_HEADER ( "000081a4", "00000341", "0000001a", + "/usr/share/oem/config.ign" PAD1 ) ); + +/* Full path, mkdir=-1 */ +CPIO_TEST ( path_mkdir_all, 0x341, "/usr/share/oem/config.ign mkdir=-1", 4, + CPIO_HEADER ( "000041ed", "00000000", "00000005", + "/usr" PAD2 ) + CPIO_HEADER ( "000041ed", "00000000", "0000000b", + "/usr/share" PAD4 ) + CPIO_HEADER ( "000041ed", "00000000", "0000000f", + "/usr/share/oem" PAD4 ) + CPIO_HEADER ( "000081a4", "00000341", "0000001a", + "/usr/share/oem/config.ign" PAD1 ) ); + +/* Custom mode */ +CPIO_TEST ( mode, 39, "/sbin/init mode=755", 1, + CPIO_HEADER ( "000081ed", "00000027", "0000000b", + "/sbin/init" PAD4 ) ); + +/* Chaos */ +CPIO_TEST ( chaos, 73, "///etc//init.d///runthings mode=700 mkdir=99", 3, + CPIO_HEADER ( "000041ed", "00000000", "00000007", + "///etc" PAD4 ) + CPIO_HEADER ( "000041ed", "00000000", "0000000f", + "///etc//init.d" PAD4 ) + CPIO_HEADER ( "000081c0", "00000049", "0000001b", + "///etc//init.d///runthings" PAD4 ) ); + +/** + * Perform CPIO self-test + * + */ +static void cpio_test_exec ( void ) { + + cpio_ok ( &no_cmdline ); + cpio_ok ( &empty_cmdline ); + cpio_ok ( &all_slashes ); + cpio_ok ( &simple ); + cpio_ok ( &init_slash ); + cpio_ok ( &init_slashes ); + cpio_ok ( &path ); + cpio_ok ( &path_mkdir_0 ); + cpio_ok ( &path_mkdir_1 ); + cpio_ok ( &path_mkdir_2 ); + cpio_ok ( &path_mkdir_all ); + cpio_ok ( &mode ); + cpio_ok ( &chaos ); +} + +/** CPIO self-test */ +struct self_test cpio_test __self_test = { + .name = "cpio", + .exec = cpio_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index 865818bdc..447eec314 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -89,3 +89,4 @@ REQUIRE_OBJECT ( editstring_test ); REQUIRE_OBJECT ( p256_test ); REQUIRE_OBJECT ( p384_test ); REQUIRE_OBJECT ( efi_siglist_test ); +REQUIRE_OBJECT ( cpio_test ); -- cgit v1.2.3-55-g7522 From da3024d257d73d2c40e65c6fb9db5a2a6bc86dbb Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 12 Mar 2025 14:25:05 +0000 Subject: [cpio] Allow for the construction of pure directories Allow for the possibility of creating empty directories (without having to include a dummy file inside the directory) using a zero-length image and a CPIO filename with a trailing slash, such as: initrd emptyfile /usr/share/oem/ Signed-off-by: Michael Brown --- src/core/cpio.c | 11 +++++------ src/tests/cpio_test.c | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) (limited to 'src/tests') diff --git a/src/core/cpio.c b/src/core/cpio.c index 63ac28ee6..9f5d772e9 100644 --- a/src/core/cpio.c +++ b/src/core/cpio.c @@ -179,17 +179,16 @@ size_t cpio_header ( struct image *image, unsigned int index, /* Get filename length */ name_len = cpio_name_len ( image, depth ); - /* Calculate mode and length */ - if ( depth < max ) { - /* Directory */ + /* Set directory mode or file mode as appropriate */ + if ( name[name_len] == '/' ) { mode = ( CPIO_MODE_DIR | CPIO_DEFAULT_DIR_MODE ); - len = 0; } else { - /* File */ mode |= CPIO_MODE_FILE; - len = image->len; } + /* Set length on final header */ + len = ( ( depth < max ) ? 0 : image->len ); + /* Construct CPIO header */ memset ( cpio, '0', sizeof ( *cpio ) ); memcpy ( cpio->c_magic, CPIO_MAGIC, sizeof ( cpio->c_magic ) ); diff --git a/src/tests/cpio_test.c b/src/tests/cpio_test.c index 3498c0f95..7eb8b2c74 100644 --- a/src/tests/cpio_test.c +++ b/src/tests/cpio_test.c @@ -221,6 +221,20 @@ CPIO_TEST ( path_mkdir_all, 0x341, "/usr/share/oem/config.ign mkdir=-1", 4, CPIO_HEADER ( "000081a4", "00000341", "0000001a", "/usr/share/oem/config.ign" PAD1 ) ); +/* Simple directory */ +CPIO_TEST ( dir, 0, "/opt/", 1, + CPIO_HEADER ( "000041ed", "00000000", "00000005", + "/opt" PAD2 ) ); + +/* Directory tree */ +CPIO_TEST ( tree, 0, "/opt/oem/scripts/ mkdir=-1", 3, + CPIO_HEADER ( "000041ed", "00000000", "00000005", + "/opt" PAD2 ) + CPIO_HEADER ( "000041ed", "00000000", "00000009", + "/opt/oem" PAD2 ) + CPIO_HEADER ( "000041ed", "00000000", "00000011", + "/opt/oem/scripts" PAD2 ) ); + /* Custom mode */ CPIO_TEST ( mode, 39, "/sbin/init mode=755", 1, CPIO_HEADER ( "000081ed", "00000027", "0000000b", @@ -252,6 +266,8 @@ static void cpio_test_exec ( void ) { cpio_ok ( &path_mkdir_1 ); cpio_ok ( &path_mkdir_2 ); cpio_ok ( &path_mkdir_all ); + cpio_ok ( &dir ); + cpio_ok ( &tree ); cpio_ok ( &mode ); cpio_ok ( &chaos ); } -- cgit v1.2.3-55-g7522 From b1125007caec2dc5efc82f7efe5294d191733bcc Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 14 Apr 2025 13:40:31 +0100 Subject: [fdt] Add basic tests for reading values from a flattened device tree Signed-off-by: Michael Brown --- src/tests/fdt_test.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/tests/tests.c | 1 + 2 files changed, 228 insertions(+) create mode 100644 src/tests/fdt_test.c (limited to 'src/tests') diff --git a/src/tests/fdt_test.c b/src/tests/fdt_test.c new file mode 100644 index 000000000..ec0f0bd3c --- /dev/null +++ b/src/tests/fdt_test.c @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 + * + * Flattened device tree self-tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include + +/** Simplified QEMU sifive_u device tree blob */ +static const uint8_t sifive_u[] = { + 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x05, 0x43, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x04, 0x68, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, + 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x1b, + 0x73, 0x69, 0x66, 0x69, 0x76, 0x65, 0x2c, 0x68, 0x69, 0x66, 0x69, 0x76, + 0x65, 0x2d, 0x75, 0x6e, 0x6c, 0x65, 0x61, 0x73, 0x68, 0x65, 0x64, 0x2d, + 0x61, 0x30, 0x30, 0x00, 0x73, 0x69, 0x66, 0x69, 0x76, 0x65, 0x2c, 0x68, + 0x69, 0x66, 0x69, 0x76, 0x65, 0x2d, 0x75, 0x6e, 0x6c, 0x65, 0x61, 0x73, + 0x68, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1c, + 0x00, 0x00, 0x00, 0x26, 0x53, 0x69, 0x46, 0x69, 0x76, 0x65, 0x20, 0x48, + 0x69, 0x46, 0x69, 0x76, 0x65, 0x20, 0x55, 0x6e, 0x6c, 0x65, 0x61, 0x73, + 0x68, 0x65, 0x64, 0x20, 0x41, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x63, 0x68, 0x6f, 0x73, 0x65, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x2c, 0x2f, 0x73, 0x6f, 0x63, + 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x40, 0x31, 0x30, 0x30, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x01, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x38, + 0x2f, 0x73, 0x6f, 0x63, 0x2f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x40, + 0x31, 0x30, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x40, + 0x2f, 0x73, 0x6f, 0x63, 0x2f, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, + 0x74, 0x40, 0x31, 0x30, 0x30, 0x39, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x63, 0x70, 0x75, 0x73, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4a, + 0x00, 0x0f, 0x42, 0x40, 0x00, 0x00, 0x00, 0x01, 0x63, 0x70, 0x75, 0x40, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x5d, 0x63, 0x70, 0x75, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x6d, + 0x6f, 0x6b, 0x61, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1b, 0x72, 0x69, 0x73, 0x63, + 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x25, + 0x00, 0x00, 0x00, 0x74, 0x72, 0x76, 0x36, 0x34, 0x69, 0x6d, 0x61, 0x63, + 0x5f, 0x7a, 0x69, 0x63, 0x6e, 0x74, 0x72, 0x5f, 0x7a, 0x69, 0x63, 0x73, + 0x72, 0x5f, 0x7a, 0x69, 0x66, 0x65, 0x6e, 0x63, 0x65, 0x69, 0x5f, 0x7a, + 0x69, 0x68, 0x70, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7e, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x1b, 0x72, 0x69, 0x73, 0x63, 0x76, 0x2c, 0x63, 0x70, + 0x75, 0x2d, 0x69, 0x6e, 0x74, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, + 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x40, 0x38, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, + 0x00, 0x00, 0x00, 0x5d, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x69, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, + 0x73, 0x6f, 0x63, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1b, + 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2d, 0x62, 0x75, 0x73, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, + 0x00, 0x00, 0x00, 0x01, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x40, 0x31, + 0x30, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x1b, + 0x73, 0x69, 0x66, 0x69, 0x76, 0x65, 0x2c, 0x75, 0x61, 0x72, 0x74, 0x30, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, + 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x40, 0x31, 0x30, 0x30, + 0x39, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0xab, 0x52, 0x54, 0x00, 0x12, 0x34, 0x56, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbd, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, + 0x00, 0x00, 0x00, 0xc8, 0x67, 0x6d, 0x69, 0x69, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xd1, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x16, + 0x00, 0x00, 0x00, 0x1b, 0x73, 0x69, 0x66, 0x69, 0x76, 0x65, 0x2c, 0x66, + 0x75, 0x35, 0x34, 0x30, 0x2d, 0x63, 0x30, 0x30, 0x30, 0x2d, 0x67, 0x65, + 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x65, 0x74, 0x68, 0x65, + 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x70, 0x68, 0x79, 0x40, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, + 0x23, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2d, 0x63, 0x65, 0x6c, + 0x6c, 0x73, 0x00, 0x23, 0x73, 0x69, 0x7a, 0x65, 0x2d, 0x63, 0x65, 0x6c, + 0x6c, 0x73, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, + 0x65, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x00, 0x73, 0x74, 0x64, 0x6f, + 0x75, 0x74, 0x2d, 0x70, 0x61, 0x74, 0x68, 0x00, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x30, 0x00, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, + 0x30, 0x00, 0x74, 0x69, 0x6d, 0x65, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x66, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x00, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x00, 0x72, 0x65, 0x67, + 0x00, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x00, 0x72, 0x69, 0x73, 0x63, + 0x76, 0x2c, 0x69, 0x73, 0x61, 0x00, 0x23, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x6f, 0x6e, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x00, 0x72, 0x61, 0x6e, 0x67, + 0x65, 0x73, 0x00, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x63, + 0x2d, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x00, 0x70, 0x68, 0x79, + 0x2d, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x00, 0x70, 0x68, 0x79, 0x2d, + 0x6d, 0x6f, 0x64, 0x65, 0x00, 0x72, 0x65, 0x67, 0x2d, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x00 +}; + +/** + * Perform FDT self-test + * + */ +static void fdt_test_exec ( void ) { + struct fdt_header *hdr; + struct fdt fdt; + const char *string; + uint64_t u64; + unsigned int count; + unsigned int offset; + + /* Verify parsing */ + hdr = ( ( struct fdt_header * ) sifive_u ); + ok ( fdt_parse ( &fdt, hdr, 0 ) != 0 ); + ok ( fdt_parse ( &fdt, hdr, 1 ) != 0 ); + ok ( fdt_parse ( &fdt, hdr, ( sizeof ( sifive_u ) - 1 ) ) != 0 ); + ok ( fdt_parse ( &fdt, hdr, -1UL ) == 0 ); + ok ( fdt.len == sizeof ( sifive_u ) ); + ok ( fdt_parse ( &fdt, hdr, sizeof ( sifive_u ) ) == 0 ); + ok ( fdt.len == sizeof ( sifive_u ) ); + + /* Verify string properties */ + ok ( ( string = fdt_string ( &fdt, 0, "model" ) ) != NULL ); + ok ( strcmp ( string, "SiFive HiFive Unleashed A00" ) == 0 ); + ok ( ( string = fdt_string ( &fdt, 0, "nonexistent" ) ) == NULL ); + + /* Verify string list properties */ + ok ( ( string = fdt_strings ( &fdt, 0, "model", &count ) ) != NULL ); + ok ( count == 1 ); + ok ( memcmp ( string, "SiFive HiFive Unleashed A00", 28 ) == 0 ); + ok ( ( string = fdt_strings ( &fdt, 0, "compatible", + &count ) ) != NULL ); + ok ( count == 2 ); + ok ( memcmp ( string, "sifive,hifive-unleashed-a00\0" + "sifive,hifive-unleashed", 52 ) == 0 ); + ok ( ( string = fdt_strings ( &fdt, 0, "nonexistent", + &count ) ) == NULL ); + ok ( count == 0 ); + + /* Verify integer properties */ + ok ( fdt_u64 ( &fdt, 0, "#address-cells", &u64 ) == 0 ); + ok ( u64 == 2 ); + ok ( fdt_u64 ( &fdt, 0, "#nonexistent", &u64 ) != 0 ); + + /* Verify path lookup */ + ok ( fdt_path ( &fdt, "", &offset ) == 0 ); + ok ( offset == 0 ); + ok ( fdt_path ( &fdt, "/", &offset ) == 0 ); + ok ( offset == 0 ); + ok ( fdt_path ( &fdt, "/cpus/cpu@0/interrupt-controller", + &offset ) == 0 ); + ok ( ( string = fdt_string ( &fdt, offset, "compatible" ) ) != NULL ); + ok ( strcmp ( string, "riscv,cpu-intc" ) == 0 ); + ok ( fdt_path ( &fdt, "//soc/serial@10010000//", &offset ) == 0 ); + ok ( ( string = fdt_string ( &fdt, offset, "compatible" ) ) != NULL ); + ok ( strcmp ( string, "sifive,uart0" ) == 0 ); + ok ( fdt_path ( &fdt, "/nonexistent", &offset ) != 0 ); + ok ( fdt_path ( &fdt, "/cpus/nonexistent", &offset ) != 0 ); + + /* Verify alias lookup */ + ok ( fdt_alias ( &fdt, "serial0", &offset ) == 0 ); + ok ( ( string = fdt_string ( &fdt, offset, "compatible" ) ) != NULL ); + ok ( strcmp ( string, "sifive,uart0" ) == 0 ); + ok ( fdt_alias ( &fdt, "nonexistent0", &offset ) != 0 ); +} + +/** FDT self-test */ +struct self_test fdt_test __self_test = { + .name = "fdt", + .exec = fdt_test_exec, +}; diff --git a/src/tests/tests.c b/src/tests/tests.c index 447eec314..daf646798 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -90,3 +90,4 @@ REQUIRE_OBJECT ( p256_test ); REQUIRE_OBJECT ( p384_test ); REQUIRE_OBJECT ( efi_siglist_test ); REQUIRE_OBJECT ( cpio_test ); +REQUIRE_OBJECT ( fdt_test ); -- cgit v1.2.3-55-g7522 From d462aeb0ca9c7fb5fb61631121404661bf5e7809 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 14 Apr 2025 11:33:27 +0100 Subject: [fdt] Remove concept of a device tree cursor Refactor device tree traversal to operate on the basis of describing the token at a given offset, with no separate notion of a device tree cursor. Signed-off-by: Michael Brown --- src/core/fdt.c | 257 +++++++++++++++++++++++++------------------------ src/include/ipxe/fdt.h | 18 ++++ src/tests/fdt_test.c | 14 +++ 3 files changed, 165 insertions(+), 124 deletions(-) (limited to 'src/tests') diff --git a/src/core/fdt.c b/src/core/fdt.c index 714dba13b..85394a8e0 100644 --- a/src/core/fdt.c +++ b/src/core/fdt.c @@ -49,37 +49,16 @@ struct image_tag fdt_image __image_tag = { /** Amount of free space to add whenever we have to reallocate a tree */ #define FDT_INSERT_PAD 1024 -/** A position within a device tree */ -struct fdt_cursor { - /** Offset within structure block */ - unsigned int offset; - /** Tree depth */ - int depth; -}; - -/** A lexical descriptor */ -struct fdt_descriptor { - /** Offset within structure block */ - unsigned int offset; - /** Node or property name (if applicable) */ - const char *name; - /** Property data (if applicable) */ - const void *data; - /** Length of property data (if applicable) */ - size_t len; -}; - /** - * Traverse device tree + * Describe device tree token * * @v fdt Device tree - * @v pos Position within device tree - * @v desc Lexical descriptor to fill in + * @v offset Offset within structure block + * @v desc Token descriptor to fill in * @ret rc Return status code */ -static int fdt_traverse ( struct fdt *fdt, - struct fdt_cursor *pos, - struct fdt_descriptor *desc ) { +int fdt_describe ( struct fdt *fdt, unsigned int offset, + struct fdt_descriptor *desc ) { const fdt_token_t *token; const void *data; const struct fdt_prop *prop; @@ -88,18 +67,18 @@ static int fdt_traverse ( struct fdt *fdt, size_t len; /* Sanity checks */ - assert ( pos->offset <= fdt->len ); - assert ( ( pos->offset & ( FDT_STRUCTURE_ALIGN - 1 ) ) == 0 ); + assert ( offset <= fdt->len ); + assert ( ( offset & ( FDT_STRUCTURE_ALIGN - 1 ) ) == 0 ); /* Initialise descriptor */ memset ( desc, 0, sizeof ( *desc ) ); - desc->offset = pos->offset; + desc->offset = offset; /* Locate token and calculate remaining space */ - token = ( fdt->raw + fdt->structure + pos->offset ); - remaining = ( fdt->len - pos->offset ); + token = ( fdt->raw + fdt->structure + offset ); + remaining = ( fdt->len - offset ); if ( remaining < sizeof ( *token ) ) { - DBGC ( fdt, "FDT truncated tree at +%#04x\n", pos->offset ); + DBGC ( fdt, "FDT truncated tree at +%#04x\n", offset ); return -EINVAL; } remaining -= sizeof ( *token ); @@ -116,25 +95,16 @@ static int fdt_traverse ( struct fdt *fdt, len = ( strnlen ( desc->name, remaining ) + 1 /* NUL */ ); if ( remaining < len ) { DBGC ( fdt, "FDT unterminated node name at +%#04x\n", - pos->offset ); + offset ); return -EINVAL; } - pos->depth++; + desc->depth = +1; break; case cpu_to_be32 ( FDT_END_NODE ): /* End of node */ - if ( pos->depth < 0 ) { - DBGC ( fdt, "FDT spurious node end at +%#04x\n", - pos->offset ); - return -EINVAL; - } - pos->depth--; - if ( pos->depth < 0 ) { - /* End of (sub)tree */ - return -ENOENT; - } + desc->depth = -1; break; case cpu_to_be32 ( FDT_PROP ): @@ -143,7 +113,7 @@ static int fdt_traverse ( struct fdt *fdt, prop = data; if ( remaining < sizeof ( *prop ) ) { DBGC ( fdt, "FDT truncated property at +%#04x\n", - pos->offset ); + offset ); return -EINVAL; } desc->data = ( ( ( const void * ) prop ) + sizeof ( *prop ) ); @@ -151,13 +121,13 @@ static int fdt_traverse ( struct fdt *fdt, len = ( sizeof ( *prop ) + desc->len ); if ( remaining < len ) { DBGC ( fdt, "FDT overlength property at +%#04x\n", - pos->offset ); + offset ); return -EINVAL; } name_off = be32_to_cpu ( prop->name_off ); if ( name_off > fdt->strings_len ) { DBGC ( fdt, "FDT property name outside strings " - "block at +%#04x\n", pos->offset ); + "block at +%#04x\n", offset ); return -EINVAL; } desc->name = ( fdt->raw + fdt->strings + name_off ); @@ -172,21 +142,75 @@ static int fdt_traverse ( struct fdt *fdt, /* Unrecognised or unexpected token */ DBGC ( fdt, "FDT unexpected token %#08x at +%#04x\n", - be32_to_cpu ( *token ), pos->offset ); + be32_to_cpu ( *token ), offset ); return -EINVAL; } - /* Update cursor */ + /* Calculate offset to next token */ len = ( ( len + FDT_STRUCTURE_ALIGN - 1 ) & ~( FDT_STRUCTURE_ALIGN - 1 ) ); - pos->offset += ( sizeof ( *token ) + len ); + offset += ( sizeof ( *token ) + len ); + desc->next = offset; /* Sanity checks */ - assert ( pos->offset <= fdt->len ); + assert ( offset <= fdt->len ); return 0; } +/** + * Describe next device tree token + * + * @v fdt Device tree + * @v desc Token descriptor to update + * @ret rc Return status code + */ +static int fdt_next ( struct fdt *fdt, struct fdt_descriptor *desc ) { + + /* Describe next token */ + return fdt_describe ( fdt, desc->next, desc ); +} + +/** + * Enter node + * + * @v fdt Device tree + * @v offset Starting node offset + * @v desc Begin node descriptor to fill in + * @ret rc Return status code + */ +static int fdt_enter ( struct fdt *fdt, unsigned int offset, + struct fdt_descriptor *desc ) { + int rc; + + /* Find begin node token */ + for ( ; ; offset = desc->next ) { + + /* Describe token */ + if ( ( rc = fdt_describe ( fdt, offset, desc ) ) != 0 ) { + DBGC ( fdt, "FDT +%#04x has malformed node: %s\n", + offset, strerror ( rc ) ); + return rc; + } + + /* Check for begin node token */ + if ( desc->depth > 0 ) + return 0; + + /* Check for non-NOPs */ + if ( desc->depth ) { + DBGC ( fdt, "FDT +%#04x has spurious node end at " + "+%#04x\n", offset, desc->offset ); + return -EINVAL; + } + if ( desc->name ) { + DBGC ( fdt, "FDT +%#04x has spurious property at " + "+%#04x\n", offset, desc->offset ); + return -EINVAL; + } + } +} + /** * Find child node * @@ -198,51 +222,45 @@ static int fdt_traverse ( struct fdt *fdt, */ static int fdt_child ( struct fdt *fdt, unsigned int offset, const char *name, unsigned int *child ) { - struct fdt_cursor pos; struct fdt_descriptor desc; - unsigned int orig_offset; const char *sep; size_t name_len; + int depth; int rc; - /* Record original offset (for debugging) */ - orig_offset = offset; - - /* Initialise cursor */ - pos.offset = offset; - pos.depth = -1; - /* Determine length of name (may be terminated with NUL or '/') */ sep = strchr ( name, '/' ); name_len = ( sep ? ( ( size_t ) ( sep - name ) ) : strlen ( name ) ); - /* Find child node */ - while ( 1 ) { + /* Enter node */ + if ( ( rc = fdt_enter ( fdt, offset, &desc ) ) != 0 ) + return rc; - /* Record current offset */ - *child = pos.offset; + /* Find child node */ + for ( depth = 0 ; depth >= 0 ; depth += desc.depth ) { - /* Traverse tree */ - if ( ( rc = fdt_traverse ( fdt, &pos, &desc ) ) != 0 ) { - DBGC2 ( fdt, "FDT +%#04x has no child node \"%s\": " - "%s\n", orig_offset, name, strerror ( rc ) ); + /* Describe token */ + if ( ( rc = fdt_next ( fdt, &desc ) ) != 0 ) { + DBGC ( fdt, "FDT +%#04x has malformed node: %s\n", + offset, strerror ( rc ) ); return rc; } /* Check for matching immediate child node */ - if ( ( pos.depth == 1 ) && desc.name && ( ! desc.data ) ) { - DBGC2 ( fdt, "FDT +%#04x has child node \"%s\"\n", - orig_offset, desc.name ); + if ( ( depth == 0 ) && desc.name && ( ! desc.data ) ) { + DBGC2 ( fdt, "FDT +%#04x has child node \"%s\" at " + "+%#04x\n", offset, desc.name, desc.offset ); + assert ( desc.depth > 0 ); if ( ( strlen ( desc.name ) == name_len ) && ( memcmp ( name, desc.name, name_len ) == 0 ) ) { *child = desc.offset; - DBGC2 ( fdt, "FDT +%#04x found child node " - "\"%s\" at +%#04x\n", orig_offset, - desc.name, *child ); return 0; } } } + + DBGC2 ( fdt, "FDT +%#04x has no child node \"%s\"\n", offset, name ); + return -ENOENT; } /** @@ -255,38 +273,29 @@ static int fdt_child ( struct fdt *fdt, unsigned int offset, const char *name, */ static int fdt_end ( struct fdt *fdt, unsigned int offset, unsigned int *end ) { - struct fdt_cursor pos; struct fdt_descriptor desc; - unsigned int orig_offset; + int depth; int rc; - /* Record original offset (for debugging) */ - orig_offset = offset; - - /* Initialise cursor */ - pos.offset = offset; - pos.depth = 0; - - /* Find child node */ - while ( 1 ) { + /* Enter node */ + if ( ( rc = fdt_enter ( fdt, offset, &desc ) ) != 0 ) + return rc; - /* Record current offset */ - *end = pos.offset; + /* Find end of this node */ + for ( depth = 0 ; depth >= 0 ; depth += desc.depth ) { - /* Traverse tree */ - if ( ( rc = fdt_traverse ( fdt, &pos, &desc ) ) != 0 ) { + /* Describe token */ + if ( ( rc = fdt_next ( fdt, &desc ) ) != 0 ) { DBGC ( fdt, "FDT +%#04x has malformed node: %s\n", - orig_offset, strerror ( rc ) ); + offset, strerror ( rc ) ); return rc; } - - /* Check for end of current node */ - if ( pos.depth == 0 ) { - DBGC2 ( fdt, "FDT +%#04x has end at +%#04x\n", - orig_offset, *end ); - return 0; - } } + + /* Record end offset */ + *end = desc.offset; + DBGC2 ( fdt, "FDT +%#04x has end at +%#04x\n", offset, *end ); + return 0; } /** @@ -363,40 +372,43 @@ int fdt_alias ( struct fdt *fdt, const char *name, unsigned int *offset ) { * @v fdt Device tree * @v offset Starting node offset * @v name Property name - * @v desc Lexical descriptor to fill in + * @v desc Token descriptor to fill in * @ret rc Return status code */ static int fdt_property ( struct fdt *fdt, unsigned int offset, const char *name, struct fdt_descriptor *desc ) { - struct fdt_cursor pos; + int depth; int rc; - /* Initialise cursor */ - pos.offset = offset; - pos.depth = -1; + /* Enter node */ + if ( ( rc = fdt_enter ( fdt, offset, desc ) ) != 0 ) + return rc; /* Find property */ - while ( 1 ) { + for ( depth = 0 ; depth == 0 ; depth += desc->depth ) { - /* Traverse tree */ - if ( ( rc = fdt_traverse ( fdt, &pos, desc ) ) != 0 ) { - DBGC2 ( fdt, "FDT +%#04x has no property \"%s\": %s\n", - offset, name, strerror ( rc ) ); + /* Describe token */ + if ( ( rc = fdt_next ( fdt, desc ) ) != 0 ) { + DBGC ( fdt, "FDT +%#04x has malformed node: %s\n", + offset, strerror ( rc ) ); return rc; } /* Check for matching immediate child property */ - if ( ( pos.depth == 0 ) && desc->data ) { - DBGC2 ( fdt, "FDT +%#04x has property \"%s\" len " - "%#zx\n", offset, desc->name, desc->len ); + if ( desc->data ) { + DBGC2 ( fdt, "FDT +%#04x has property \"%s\" at " + "+%#04x len %#zx\n", offset, desc->name, + desc->offset, desc->len ); + assert ( desc->depth == 0 ); if ( strcmp ( name, desc->name ) == 0 ) { - DBGC2 ( fdt, "FDT +%#04x found property " - "\"%s\"\n", offset, desc->name ); DBGC2_HDA ( fdt, 0, desc->data, desc->len ); return 0; } } } + + DBGC2 ( fdt, "FDT +%#04x has no property \"%s\"\n", offset, name ); + return -ENOENT; } /** @@ -894,7 +906,6 @@ static int fdt_ensure_property ( struct fdt *fdt, unsigned int offset, const char *name, const void *data, size_t len ) { struct fdt_descriptor desc; - struct fdt_cursor pos; struct { fdt_token_t token; struct fdt_prop prop; @@ -909,15 +920,14 @@ static int fdt_ensure_property ( struct fdt *fdt, unsigned int offset, if ( ( rc = fdt_property ( fdt, offset, name, &desc ) ) == 0 ) { /* Reuse existing name */ - pos.offset = desc.offset; - hdr = ( fdt->raw + fdt->structure + pos.offset ); + hdr = ( fdt->raw + fdt->structure + desc.offset ); string = be32_to_cpu ( hdr->prop.name_off ); /* Erase existing property */ erase = ( sizeof ( *hdr ) + desc.len ); erase = ( ( erase + FDT_STRUCTURE_ALIGN - 1 ) & ~( FDT_STRUCTURE_ALIGN - 1 ) ); - fdt_nop ( fdt, pos.offset, erase ); + fdt_nop ( fdt, desc.offset, erase ); DBGC2 ( fdt, "FDT +%#04x erased property \"%s\"\n", offset, name ); @@ -931,22 +941,21 @@ static int fdt_ensure_property ( struct fdt *fdt, unsigned int offset, return rc; /* Enter node */ - pos.offset = offset; - pos.depth = 0; - if ( ( rc = fdt_traverse ( fdt, &pos, &desc ) ) != 0 ) + if ( ( rc = fdt_enter ( fdt, offset, &desc ) ) != 0 ) return rc; - assert ( pos.depth == 1 ); + assert ( desc.depth > 0 ); + desc.offset = desc.next; /* Calculate insertion length */ insert = ( sizeof ( *hdr ) + len ); } /* Insert space */ - if ( ( rc = fdt_insert_nop ( fdt, pos.offset, insert ) ) != 0 ) + if ( ( rc = fdt_insert_nop ( fdt, desc.offset, insert ) ) != 0 ) return rc; /* Construct property */ - hdr = ( fdt->raw + fdt->structure + pos.offset ); + hdr = ( fdt->raw + fdt->structure + desc.offset ); hdr->token = cpu_to_be32 ( FDT_PROP ); hdr->prop.len = cpu_to_be32 ( len ); hdr->prop.name_off = cpu_to_be32 ( string ); @@ -1082,8 +1091,8 @@ void fdt_remove ( struct fdt_header *hdr ) { ufree ( virt_to_user ( hdr ) ); } -/* Drag in objects via fdt_traverse() */ -REQUIRING_SYMBOL ( fdt_traverse ); +/* Drag in objects via fdt_describe() */ +REQUIRING_SYMBOL ( fdt_describe ); /* Drag in device tree configuration */ REQUIRE_OBJECT ( config_fdt ); diff --git a/src/include/ipxe/fdt.h b/src/include/ipxe/fdt.h index 1e05c9e2d..a41dcaa30 100644 --- a/src/include/ipxe/fdt.h +++ b/src/include/ipxe/fdt.h @@ -108,9 +108,27 @@ struct fdt { int ( * realloc ) ( struct fdt *fdt, size_t len ); }; +/** A device tree token descriptor */ +struct fdt_descriptor { + /** Offset within structure block */ + unsigned int offset; + /** Next offset within structure block */ + unsigned int next; + /** Node or property name (if applicable) */ + const char *name; + /** Property data (if applicable) */ + const void *data; + /** Length of property data (if applicable) */ + size_t len; + /** Depth change */ + int depth; +}; + extern struct image_tag fdt_image __image_tag; extern struct fdt sysfdt; +extern int fdt_describe ( struct fdt *fdt, unsigned int offset, + struct fdt_descriptor *desc ); extern int fdt_path ( struct fdt *fdt, const char *path, unsigned int *offset ); extern int fdt_alias ( struct fdt *fdt, const char *name, diff --git a/src/tests/fdt_test.c b/src/tests/fdt_test.c index ec0f0bd3c..738966df8 100644 --- a/src/tests/fdt_test.c +++ b/src/tests/fdt_test.c @@ -158,6 +158,7 @@ static const uint8_t sifive_u[] = { * */ static void fdt_test_exec ( void ) { + struct fdt_descriptor desc; struct fdt_header *hdr; struct fdt fdt; const char *string; @@ -218,6 +219,19 @@ static void fdt_test_exec ( void ) { ok ( ( string = fdt_string ( &fdt, offset, "compatible" ) ) != NULL ); ok ( strcmp ( string, "sifive,uart0" ) == 0 ); ok ( fdt_alias ( &fdt, "nonexistent0", &offset ) != 0 ); + + /* Verify node description */ + ok ( fdt_path ( &fdt, "/memory@80000000", &offset ) == 0 ); + ok ( fdt_describe ( &fdt, offset, &desc ) == 0 ); + ok ( desc.offset == offset ); + ok ( strcmp ( desc.name, "memory@80000000" ) == 0 ); + ok ( desc.data == NULL ); + ok ( desc.len == 0 ); + ok ( desc.depth == +1 ); + ok ( fdt_describe ( &fdt, desc.next, &desc ) == 0 ); + ok ( strcmp ( desc.name, "device_type" ) == 0 ); + ok ( strcmp ( desc.data, "memory" ) == 0 ); + ok ( desc.depth == 0 ); } /** FDT self-test */ -- cgit v1.2.3-55-g7522 From 99322fd3b37abd88867ccc3e9f60df0195730036 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 15 Apr 2025 20:14:03 +0100 Subject: [fdt] Add fdt_cells() to read cell-based properties such as "reg" Add fdt_cells() to read scalar values encoded within a cell array, reimplement fdt_u64() as a wrapper around this, and add fdt_u32() for completeness. Signed-off-by: Michael Brown --- src/core/fdt.c | 84 ++++++++++++++++++++++++++++++++++++-------- src/include/ipxe/fdt.h | 5 +++ src/tests/fdt_test.c | 94 ++++++++++++++++++++++++++++++++------------------ 3 files changed, 136 insertions(+), 47 deletions(-) (limited to 'src/tests') diff --git a/src/core/fdt.c b/src/core/fdt.c index 85394a8e0..54f930286 100644 --- a/src/core/fdt.c +++ b/src/core/fdt.c @@ -468,19 +468,21 @@ const char * fdt_string ( struct fdt *fdt, unsigned int offset, } /** - * Find integer property + * Get integer property * * @v fdt Device tree * @v offset Starting node offset * @v name Property name + * @v index Starting cell index + * @v count Number of cells (or 0 to read all remaining cells) * @v value Integer value to fill in * @ret rc Return status code */ -int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name, - uint64_t *value ) { +int fdt_cells ( struct fdt *fdt, unsigned int offset, const char *name, + unsigned int index, unsigned int count, uint64_t *value ) { struct fdt_descriptor desc; - const uint8_t *data; - size_t remaining; + const uint32_t *cell; + unsigned int total; int rc; /* Clear value */ @@ -489,19 +491,73 @@ int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name, /* Find property */ if ( ( rc = fdt_property ( fdt, offset, name, &desc ) ) != 0 ) return rc; + cell = desc.data; - /* Check range */ - if ( desc.len > sizeof ( *value ) ) { - DBGC ( fdt, "FDT oversized integer property \"%s\"\n", name ); + /* Determine number of cells */ + total = ( desc.len / sizeof ( *cell ) ); + if ( ( index > total ) || ( count > ( total - index ) ) ) { + DBGC ( fdt, "FDT truncated integer \"%s\"\n", name ); + return -ERANGE; + } + if ( ! count ) + count = ( total - index ); + if ( count > ( sizeof ( *value ) / sizeof ( *cell ) ) ) { + DBGC ( fdt, "FDT overlength integer \"%s\"\n", name ); return -ERANGE; } - /* Parse value */ - data = desc.data; - remaining = desc.len; - while ( remaining-- ) { - *value <<= 8; - *value |= *(data++); + /* Read value */ + for ( cell += index ; count ; cell++, count-- ) { + *value <<= 32; + *value |= be32_to_cpu ( *cell ); + } + + return 0; +} + +/** + * Get 64-bit integer property + * + * @v fdt Device tree + * @v offset Starting node offset + * @v name Property name + * @v value Integer value to fill in + * @ret rc Return status code + */ +int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name, + uint64_t *value ) { + int rc; + + /* Read value */ + if ( ( rc = fdt_cells ( fdt, offset, name, 0, 0, value ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Get 32-bit integer property + * + * @v fdt Device tree + * @v offset Starting node offset + * @v name Property name + * @v value Integer value to fill in + * @ret rc Return status code + */ +int fdt_u32 ( struct fdt *fdt, unsigned int offset, const char *name, + uint32_t *value ) { + uint64_t value64; + int rc; + + /* Read value */ + if ( ( rc = fdt_u64 ( fdt, offset, name, &value64 ) ) != 0 ) + return rc; + + /* Check range */ + *value = value64; + if ( *value != value64 ) { + DBGC ( fdt, "FDT overlength 32-bit integer \"%s\"\n", name ); + return -ERANGE; } return 0; diff --git a/src/include/ipxe/fdt.h b/src/include/ipxe/fdt.h index a41dcaa30..fb0ae7752 100644 --- a/src/include/ipxe/fdt.h +++ b/src/include/ipxe/fdt.h @@ -137,8 +137,13 @@ extern const char * fdt_strings ( struct fdt *fdt, unsigned int offset, const char *name, unsigned int *count ); extern const char * fdt_string ( struct fdt *fdt, unsigned int offset, const char *name ); +extern int fdt_cells ( struct fdt *fdt, unsigned int offset, const char *name, + unsigned int index, unsigned int count, + uint64_t *value ); extern int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name, uint64_t *value ); +extern int fdt_u32 ( struct fdt *fdt, unsigned int offset, const char *name, + uint32_t *value ); extern int fdt_mac ( struct fdt *fdt, unsigned int offset, struct net_device *netdev ); extern int fdt_parse ( struct fdt *fdt, struct fdt_header *hdr, diff --git a/src/tests/fdt_test.c b/src/tests/fdt_test.c index 738966df8..0a143ec62 100644 --- a/src/tests/fdt_test.c +++ b/src/tests/fdt_test.c @@ -38,10 +38,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** Simplified QEMU sifive_u device tree blob */ static const uint8_t sifive_u[] = { - 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x05, 0x43, 0x00, 0x00, 0x00, 0x38, - 0x00, 0x00, 0x04, 0x68, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, - 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdb, - 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x05, 0x61, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x04, 0x7c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, + 0x00, 0x00, 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, @@ -127,30 +127,32 @@ static const uint8_t sifive_u[] = { 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1b, 0x73, 0x69, 0x66, 0x69, 0x76, 0x65, 0x2c, 0x66, 0x75, 0x35, 0x34, 0x30, 0x2d, 0x63, 0x30, 0x30, 0x30, 0x2d, 0x67, 0x65, - 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x65, 0x74, 0x68, 0x65, - 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x70, 0x68, 0x79, 0x40, 0x30, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, - 0x23, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x2d, 0x63, 0x65, 0x6c, - 0x6c, 0x73, 0x00, 0x23, 0x73, 0x69, 0x7a, 0x65, 0x2d, 0x63, 0x65, 0x6c, - 0x6c, 0x73, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, - 0x65, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x00, 0x73, 0x74, 0x64, 0x6f, - 0x75, 0x74, 0x2d, 0x70, 0x61, 0x74, 0x68, 0x00, 0x73, 0x65, 0x72, 0x69, - 0x61, 0x6c, 0x30, 0x00, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, - 0x30, 0x00, 0x74, 0x69, 0x6d, 0x65, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x66, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, 0x00, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x00, 0x72, 0x65, 0x67, - 0x00, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x00, 0x72, 0x69, 0x73, 0x63, - 0x76, 0x2c, 0x69, 0x73, 0x61, 0x00, 0x23, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x6f, 0x6e, - 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x00, 0x72, 0x61, 0x6e, 0x67, - 0x65, 0x73, 0x00, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x63, - 0x2d, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x00, 0x70, 0x68, 0x79, - 0x2d, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x00, 0x70, 0x68, 0x79, 0x2d, - 0x6d, 0x6f, 0x64, 0x65, 0x00, 0x72, 0x65, 0x67, 0x2d, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x00 + 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x02, 0x54, 0x0b, 0xe4, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, + 0x2d, 0x70, 0x68, 0x79, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x23, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x23, + 0x73, 0x69, 0x7a, 0x65, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x63, + 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x00, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x00, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x2d, 0x70, + 0x61, 0x74, 0x68, 0x00, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x30, 0x00, + 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x30, 0x00, 0x74, 0x69, + 0x6d, 0x65, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x66, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x6e, 0x63, 0x79, 0x00, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x00, 0x72, 0x65, 0x67, 0x00, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x00, 0x72, 0x69, 0x73, 0x63, 0x76, 0x2c, 0x69, 0x73, + 0x61, 0x00, 0x23, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, + 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x00, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x00, 0x6c, + 0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x63, 0x2d, 0x61, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x00, 0x70, 0x68, 0x79, 0x2d, 0x68, 0x61, 0x6e, + 0x64, 0x6c, 0x65, 0x00, 0x70, 0x68, 0x79, 0x2d, 0x6d, 0x6f, 0x64, 0x65, + 0x00, 0x72, 0x65, 0x67, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x6d, + 0x61, 0x78, 0x2d, 0x73, 0x70, 0x65, 0x65, 0x64, 0x00 }; /** @@ -162,6 +164,7 @@ static void fdt_test_exec ( void ) { struct fdt_header *hdr; struct fdt fdt; const char *string; + uint32_t u32; uint64_t u64; unsigned int count; unsigned int offset; @@ -194,11 +197,6 @@ static void fdt_test_exec ( void ) { &count ) ) == NULL ); ok ( count == 0 ); - /* Verify integer properties */ - ok ( fdt_u64 ( &fdt, 0, "#address-cells", &u64 ) == 0 ); - ok ( u64 == 2 ); - ok ( fdt_u64 ( &fdt, 0, "#nonexistent", &u64 ) != 0 ); - /* Verify path lookup */ ok ( fdt_path ( &fdt, "", &offset ) == 0 ); ok ( offset == 0 ); @@ -214,6 +212,36 @@ static void fdt_test_exec ( void ) { ok ( fdt_path ( &fdt, "/nonexistent", &offset ) != 0 ); ok ( fdt_path ( &fdt, "/cpus/nonexistent", &offset ) != 0 ); + /* Verify 64-bit integer properties */ + ok ( fdt_u64 ( &fdt, 0, "#address-cells", &u64 ) == 0 ); + ok ( u64 == 2 ); + ok ( fdt_path ( &fdt, "/soc/ethernet@10090000", &offset ) == 0 ); + ok ( fdt_u64 ( &fdt, offset, "max-speed", &u64 ) == 0 ); + ok ( u64 == 10000000000ULL ); + ok ( fdt_u64 ( &fdt, offset, "#nonexistent", &u64 ) != 0 ); + + /* Verify 32-bit integer properties */ + ok ( fdt_u32 ( &fdt, 0, "#address-cells", &u32 ) == 0 ); + ok ( u32 == 2 ); + ok ( fdt_u32 ( &fdt, 0, "#nonexistent", &u32 ) != 0 ); + ok ( fdt_path ( &fdt, "/soc/ethernet@10090000", &offset ) == 0 ); + ok ( fdt_u32 ( &fdt, offset, "max-speed", &u32 ) != 0 ); + + /* Verify cell properties */ + ok ( fdt_path ( &fdt, "/soc/ethernet@10090000", &offset ) == 0 ); + ok ( fdt_cells ( &fdt, offset, "reg", 4, 2, &u64 ) == 0 ); + ok ( u64 == 0x100a0000 ); + ok ( fdt_cells ( &fdt, offset, "reg", 6, 2, &u64 ) == 0 ); + ok ( u64 == 0x1000 ); + ok ( fdt_cells ( &fdt, offset, "reg", 0, 2, &u64 ) == 0 ); + ok ( u64 == 0x10090000 ); + ok ( fdt_cells ( &fdt, offset, "reg", 6, 0, &u64 ) == 0 ); + ok ( u64 == 0x1000 ); + ok ( fdt_cells ( &fdt, offset, "reg", 8, 0, &u64 ) == 0 ); + ok ( u64 == 0 ); + ok ( fdt_cells ( &fdt, offset, "reg", 7, 2, &u64 ) != 0 ); + ok ( fdt_cells ( &fdt, offset, "notareg", 0, 1, &u64 ) != 0 ); + /* Verify alias lookup */ ok ( fdt_alias ( &fdt, "serial0", &offset ) == 0 ); ok ( ( string = fdt_string ( &fdt, offset, "compatible" ) ) != NULL ); -- cgit v1.2.3-55-g7522 From 89fe7886897be76ed902317e311d60ae654057aa Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sun, 20 Apr 2025 18:29:48 +0100 Subject: [uaccess] Remove redundant memcpy_user() and related string functions The memcpy_user(), memmove_user(), memcmp_user(), memset_user(), and strlen_user() functions are now just straightforward wrappers around the corresponding standard library functions. Remove these redundant wrappers. Signed-off-by: Michael Brown --- src/arch/x86/core/runtime.c | 2 +- src/arch/x86/image/bzimage.c | 13 +- src/arch/x86/image/com32.c | 2 +- src/arch/x86/image/comboot.c | 4 +- src/arch/x86/image/initrd.c | 12 +- src/arch/x86/image/multiboot.c | 6 +- src/arch/x86/image/nbi.c | 2 +- src/arch/x86/image/pxe_image.c | 2 +- src/arch/x86/image/sdi.c | 4 +- src/arch/x86/image/ucode.c | 2 +- src/arch/x86/include/librm.h | 32 ----- src/arch/x86/interface/pcbios/memtop_umalloc.c | 4 +- src/arch/x86/interface/pxe/pxe_file.c | 6 +- src/arch/x86/interface/syslinux/com32_call.c | 20 ++- src/arch/x86/interface/syslinux/comboot_call.c | 20 +-- src/arch/x86/transitions/librm_mgmt.c | 8 +- src/core/fbcon.c | 24 ++-- src/core/image.c | 2 +- src/core/uaccess.c | 4 - src/crypto/deflate.c | 4 +- src/drivers/net/exanic.c | 2 +- src/drivers/net/gve.c | 2 +- src/drivers/usb/xhci.c | 2 +- src/image/elf.c | 2 +- src/image/segment.c | 2 +- src/include/ipxe/linux/linux_uaccess.h | 32 ----- src/include/ipxe/uaccess.h | 166 +------------------------ src/interface/efi/efi_fbcon.c | 4 +- src/interface/efi/efi_umalloc.c | 4 +- src/interface/linux/linux_uaccess.c | 4 - src/interface/smbios/smbios.c | 2 +- src/tests/cms_test.c | 4 +- src/tests/gzip_test.c | 5 +- src/tests/pixbuf_test.c | 5 +- src/tests/zlib_test.c | 5 +- 35 files changed, 83 insertions(+), 331 deletions(-) (limited to 'src/tests') diff --git a/src/arch/x86/core/runtime.c b/src/arch/x86/core/runtime.c index 02072b5bf..2b803f772 100644 --- a/src/arch/x86/core/runtime.c +++ b/src/arch/x86/core/runtime.c @@ -125,7 +125,7 @@ static int cmdline_init ( void ) { return 0; } cmdline_user = phys_to_user ( cmdline_phys ); - len = ( strlen_user ( cmdline_user, 0 ) + 1 /* NUL */ ); + len = ( strlen ( cmdline_user ) + 1 /* NUL */ ); /* Allocate and copy command line */ cmdline_copy = malloc ( len ); diff --git a/src/arch/x86/image/bzimage.c b/src/arch/x86/image/bzimage.c index d00b9f155..29ebeb507 100644 --- a/src/arch/x86/image/bzimage.c +++ b/src/arch/x86/image/bzimage.c @@ -369,8 +369,8 @@ static size_t bzimage_load_initrd ( struct image *image, /* Copy in initrd image body and construct any cpio headers */ if ( address ) { - memmove_user ( address, len, initrd->data, 0, initrd->len ); - memset_user ( address, 0, 0, len ); + memmove ( ( address + len ), initrd->data, initrd->len ); + memset ( address, 0, len ); offset = 0; for ( i = 0 ; ( cpio_len = cpio_header ( initrd, i, &cpio ) ) ; i++ ) { @@ -395,7 +395,7 @@ static size_t bzimage_load_initrd ( struct image *image, /* Zero-pad to next INITRD_ALIGN boundary */ pad_len = ( ( -len ) & ( INITRD_ALIGN - 1 ) ); if ( address ) - memset_user ( address, len, 0, pad_len ); + memset ( ( address + len ), 0, pad_len ); return len; } @@ -562,10 +562,9 @@ static int bzimage_exec ( struct image *image ) { unregister_image ( image_get ( image ) ); /* Load segments */ - memcpy_user ( bzimg.rm_kernel, 0, image->data, - 0, bzimg.rm_filesz ); - memcpy_user ( bzimg.pm_kernel, 0, image->data, - bzimg.rm_filesz, bzimg.pm_sz ); + memcpy ( bzimg.rm_kernel, image->data, bzimg.rm_filesz ); + memcpy ( bzimg.pm_kernel, ( image->data + bzimg.rm_filesz ), + bzimg.pm_sz ); /* Store command line */ bzimage_set_cmdline ( image, &bzimg ); diff --git a/src/arch/x86/image/com32.c b/src/arch/x86/image/com32.c index 6f0e66041..3e38215cb 100644 --- a/src/arch/x86/image/com32.c +++ b/src/arch/x86/image/com32.c @@ -219,7 +219,7 @@ static int com32_load_image ( struct image *image ) { } /* Copy image to segment */ - memcpy_user ( buffer, 0, image->data, 0, filesz ); + memcpy ( buffer, image->data, filesz ); return 0; } diff --git a/src/arch/x86/image/comboot.c b/src/arch/x86/image/comboot.c index 9a847f0ff..8609eb0f7 100644 --- a/src/arch/x86/image/comboot.c +++ b/src/arch/x86/image/comboot.c @@ -267,10 +267,10 @@ static int comboot_prepare_segment ( struct image *image ) } /* Zero PSP */ - memset_user ( seg_userptr, 0, 0, 0x100 ); + memset ( seg_userptr, 0, 0x100 ); /* Copy image to segment:0100 */ - memcpy_user ( seg_userptr, 0x100, image->data, 0, image->len ); + memcpy ( ( seg_userptr + 0x100 ), image->data, image->len ); return 0; } diff --git a/src/arch/x86/image/initrd.c b/src/arch/x86/image/initrd.c index e32e40341..95f12d804 100644 --- a/src/arch/x86/image/initrd.c +++ b/src/arch/x86/image/initrd.c @@ -80,7 +80,7 @@ static userptr_t initrd_squash_high ( userptr_t top ) { user_to_phys ( highest->data, highest->len ), user_to_phys ( current, 0 ), user_to_phys ( current, highest->len ) ); - memmove_user ( current, 0, highest->data, 0, highest->len ); + memmove ( current, highest->data, highest->len ); highest->data = current; } @@ -96,8 +96,7 @@ static userptr_t initrd_squash_high ( userptr_t top ) { user_to_phys ( initrd->data, initrd->len ), user_to_phys ( current, 0 ), user_to_phys ( current, initrd->len ) ); - memcpy_user ( current, 0, initrd->data, 0, - initrd->len ); + memcpy ( current, initrd->data, initrd->len ); initrd->data = current; } } @@ -140,9 +139,10 @@ static void initrd_swap ( struct image *low, struct image *high, ~( INITRD_ALIGN - 1 ) ); /* Swap fragments */ - memcpy_user ( free, 0, high->data, len, frag_len ); - memmove_user ( low->data, new_len, low->data, len, low->len ); - memcpy_user ( low->data, len, free, 0, frag_len ); + memcpy ( free, ( high->data + len ), frag_len ); + memmove ( ( low->data + new_len ), ( low->data + len ), + low->len ); + memcpy ( ( low->data + len ), free, frag_len ); len = new_len; } diff --git a/src/arch/x86/image/multiboot.c b/src/arch/x86/image/multiboot.c index cada021ab..fe21f1f1a 100644 --- a/src/arch/x86/image/multiboot.c +++ b/src/arch/x86/image/multiboot.c @@ -222,8 +222,8 @@ static int multiboot_add_modules ( struct image *image, physaddr_t start, } /* Copy module */ - memcpy_user ( phys_to_user ( start ), 0, - module_image->data, 0, module_image->len ); + memcpy ( phys_to_user ( start ), module_image->data, + module_image->len ); /* Add module to list */ module = &modules[mbinfo->mods_count++]; @@ -350,7 +350,7 @@ static int multiboot_load_raw ( struct image *image, } /* Copy image to segment */ - memcpy_user ( buffer, 0, image->data, offset, filesz ); + memcpy ( buffer, ( image->data + offset ), filesz ); /* Record execution entry point and maximum used address */ *entry = hdr->mb.entry_addr; diff --git a/src/arch/x86/image/nbi.c b/src/arch/x86/image/nbi.c index 2f0d3164a..0b02a8985 100644 --- a/src/arch/x86/image/nbi.c +++ b/src/arch/x86/image/nbi.c @@ -131,7 +131,7 @@ static int nbi_prepare_segment ( struct image *image, size_t offset __unused, static int nbi_load_segment ( struct image *image, size_t offset, userptr_t dest, size_t filesz, size_t memsz __unused ) { - memcpy_user ( dest, 0, image->data, offset, filesz ); + memcpy ( dest, ( image->data + offset ), filesz ); return 0; } diff --git a/src/arch/x86/image/pxe_image.c b/src/arch/x86/image/pxe_image.c index b6bcb18b4..bdce165ca 100644 --- a/src/arch/x86/image/pxe_image.c +++ b/src/arch/x86/image/pxe_image.c @@ -66,7 +66,7 @@ static int pxe_exec ( struct image *image ) { } /* Copy image to segment */ - memcpy_user ( buffer, 0, image->data, 0, image->len ); + memcpy ( buffer, image->data, image->len ); /* Arbitrarily pick the most recently opened network device */ if ( ( netdev = last_opened_netdev() ) == NULL ) { diff --git a/src/arch/x86/image/sdi.c b/src/arch/x86/image/sdi.c index fa2d0b73f..5bb5a7569 100644 --- a/src/arch/x86/image/sdi.c +++ b/src/arch/x86/image/sdi.c @@ -97,8 +97,8 @@ static int sdi_exec ( struct image *image ) { user_to_phys ( image->data, sdi.boot_offset ), sdi.boot_size ); /* Copy boot code */ - memcpy_user ( real_to_user ( SDI_BOOT_SEG, SDI_BOOT_OFF ), 0, - image->data, sdi.boot_offset, sdi.boot_size ); + memcpy ( real_to_user ( SDI_BOOT_SEG, SDI_BOOT_OFF ), + ( image->data + sdi.boot_offset ), sdi.boot_size ); /* Jump to boot code */ sdiptr = ( user_to_phys ( image->data, 0 ) | SDI_WTF ); diff --git a/src/arch/x86/image/ucode.c b/src/arch/x86/image/ucode.c index 499c0a940..9b6b5067a 100644 --- a/src/arch/x86/image/ucode.c +++ b/src/arch/x86/image/ucode.c @@ -256,7 +256,7 @@ static int ucode_update_all ( struct image *image, rc = -ENOMEM; goto err_alloc; } - memset_user ( status, 0, 0, len ); + memset ( status, 0, len ); /* Construct control structure */ memset ( &control, 0, sizeof ( control ) ); diff --git a/src/arch/x86/include/librm.h b/src/arch/x86/include/librm.h index c0d910287..c117a8b5c 100644 --- a/src/arch/x86/include/librm.h +++ b/src/arch/x86/include/librm.h @@ -137,38 +137,6 @@ UACCESS_INLINE ( librm, user_to_virt ) ( userptr_t userptr, off_t offset ) { return trivial_user_to_virt ( userptr, offset ); } -static inline __always_inline void -UACCESS_INLINE ( librm, memcpy_user ) ( userptr_t dest, off_t dest_off, - userptr_t src, off_t src_off, - size_t len ) { - trivial_memcpy_user ( dest, dest_off, src, src_off, len ); -} - -static inline __always_inline void -UACCESS_INLINE ( librm, memmove_user ) ( userptr_t dest, off_t dest_off, - userptr_t src, off_t src_off, - size_t len ) { - trivial_memmove_user ( dest, dest_off, src, src_off, len ); -} - -static inline __always_inline int -UACCESS_INLINE ( librm, memcmp_user ) ( userptr_t first, off_t first_off, - userptr_t second, off_t second_off, - size_t len ) { - return trivial_memcmp_user ( first, first_off, second, second_off, len); -} - -static inline __always_inline void -UACCESS_INLINE ( librm, memset_user ) ( userptr_t buffer, off_t offset, - int c, size_t len ) { - trivial_memset_user ( buffer, offset, c, len ); -} - -static inline __always_inline size_t -UACCESS_INLINE ( librm, strlen_user ) ( userptr_t buffer, off_t offset ) { - return trivial_strlen_user ( buffer, offset ); -} - static inline __always_inline off_t UACCESS_INLINE ( librm, memchr_user ) ( userptr_t buffer, off_t offset, int c, size_t len ) { diff --git a/src/arch/x86/interface/pcbios/memtop_umalloc.c b/src/arch/x86/interface/pcbios/memtop_umalloc.c index e76b3df93..8239b23b8 100644 --- a/src/arch/x86/interface/pcbios/memtop_umalloc.c +++ b/src/arch/x86/interface/pcbios/memtop_umalloc.c @@ -203,8 +203,8 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { user_to_phys ( ptr, extmem.size ), user_to_phys ( new, 0 ), user_to_phys ( new, new_size )); - memmove_user ( new, 0, ptr, 0, ( ( extmem.size < new_size ) ? - extmem.size : new_size ) ); + memmove ( new, ptr, ( ( extmem.size < new_size ) ? + extmem.size : new_size ) ); bottom = new; heap_size -= ( new_size - extmem.size ); extmem.size = new_size; diff --git a/src/arch/x86/interface/pxe/pxe_file.c b/src/arch/x86/interface/pxe/pxe_file.c index 456ffb5fd..1235520de 100644 --- a/src/arch/x86/interface/pxe/pxe_file.c +++ b/src/arch/x86/interface/pxe/pxe_file.c @@ -61,8 +61,8 @@ static PXENV_EXIT_t pxenv_file_open ( struct s_PXENV_FILE_OPEN *file_open ) { /* Copy name from external program, and open it */ filename = real_to_user ( file_open->FileName.segment, - file_open->FileName.offset ); - filename_len = strlen_user ( filename, 0 ); + file_open->FileName.offset ); + filename_len = strlen ( filename ); { char uri_string[ filename_len + 1 ]; @@ -219,7 +219,7 @@ static PXENV_EXIT_t pxenv_file_exec ( struct s_PXENV_FILE_EXEC *file_exec ) { /* Copy name from external program, and exec it */ command = real_to_user ( file_exec->Command.segment, file_exec->Command.offset ); - command_len = strlen_user ( command, 0 ); + command_len = strlen ( command ); { char command_string[ command_len + 1 ]; diff --git a/src/arch/x86/interface/syslinux/com32_call.c b/src/arch/x86/interface/syslinux/com32_call.c index 19fdbaff9..da9d6491a 100644 --- a/src/arch/x86/interface/syslinux/com32_call.c +++ b/src/arch/x86/interface/syslinux/com32_call.c @@ -49,9 +49,8 @@ void __asmcall com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physad DBGC ( &com32_regs, "COM32 INT%x in %#08lx out %#08lx\n", interrupt, inregs_phys, outregs_phys ); - memcpy_user ( virt_to_user( &com32_regs ), 0, - phys_to_user ( inregs_phys ), 0, - sizeof(com32sys_t) ); + memcpy ( virt_to_user( &com32_regs ), phys_to_user ( inregs_phys ), + sizeof ( com32sys_t ) ); com32_int_vector = interrupt; @@ -108,9 +107,8 @@ void __asmcall com32_intcall ( uint8_t interrupt, physaddr_t inregs_phys, physad : : ); if ( outregs_phys ) { - memcpy_user ( phys_to_user ( outregs_phys ), 0, - virt_to_user( &com32_regs ), 0, - sizeof(com32sys_t) ); + memcpy ( phys_to_user ( outregs_phys ), + virt_to_user ( &com32_regs ), sizeof ( com32sys_t ) ); } } @@ -122,9 +120,8 @@ void __asmcall com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t DBGC ( &com32_regs, "COM32 farcall %04x:%04x in %#08lx out %#08lx\n", ( proc >> 16 ), ( proc & 0xffff ), inregs_phys, outregs_phys ); - memcpy_user ( virt_to_user( &com32_regs ), 0, - phys_to_user ( inregs_phys ), 0, - sizeof(com32sys_t) ); + memcpy ( virt_to_user( &com32_regs ), phys_to_user ( inregs_phys ), + sizeof ( com32sys_t ) ); com32_farcall_proc = proc; @@ -170,9 +167,8 @@ void __asmcall com32_farcall ( uint32_t proc, physaddr_t inregs_phys, physaddr_t : : ); if ( outregs_phys ) { - memcpy_user ( phys_to_user ( outregs_phys ), 0, - virt_to_user( &com32_regs ), 0, - sizeof(com32sys_t) ); + memcpy ( phys_to_user ( outregs_phys ), + virt_to_user ( &com32_regs ), sizeof ( com32sys_t ) ); } } diff --git a/src/arch/x86/interface/syslinux/comboot_call.c b/src/arch/x86/interface/syslinux/comboot_call.c index b75e8ef7c..f26fcad0a 100644 --- a/src/arch/x86/interface/syslinux/comboot_call.c +++ b/src/arch/x86/interface/syslinux/comboot_call.c @@ -119,7 +119,7 @@ static void shuffle ( unsigned int list_segment, unsigned int list_offset, unsig if ( shuf[ i ].src == 0xFFFFFFFF ) { /* Fill with 0 instead of copying */ - memset_user ( dest_u, 0, 0, shuf[ i ].len ); + memset ( dest_u, 0, shuf[ i ].len ); } else if ( shuf[ i ].dest == 0xFFFFFFFF ) { /* Copy new list of descriptors */ count = shuf[ i ].len / sizeof( comboot_shuffle_descriptor ); @@ -128,7 +128,7 @@ static void shuffle ( unsigned int list_segment, unsigned int list_offset, unsig i = -1; } else { /* Regular copy */ - memmove_user ( dest_u, 0, src_u, 0, shuf[ i ].len ); + memmove ( dest_u, src_u, shuf[ i ].len ); } } } @@ -347,7 +347,7 @@ static __asmcall __used void int22 ( struct i386_all_regs *ix86 ) { case 0x0003: /* Run command */ { userptr_t cmd_u = real_to_user ( ix86->segs.es, ix86->regs.bx ); - int len = strlen_user ( cmd_u, 0 ); + int len = strlen ( cmd_u ); char cmd[len + 1]; copy_from_user ( cmd, cmd_u, 0, len + 1 ); DBG ( "COMBOOT: executing command '%s'\n", cmd ); @@ -371,7 +371,7 @@ static __asmcall __used void int22 ( struct i386_all_regs *ix86 ) { { int fd; userptr_t file_u = real_to_user ( ix86->segs.es, ix86->regs.si ); - int len = strlen_user ( file_u, 0 ); + int len = strlen ( file_u ); char file[len + 1]; copy_from_user ( file, file_u, 0, len + 1 ); @@ -484,7 +484,7 @@ static __asmcall __used void int22 ( struct i386_all_regs *ix86 ) { case 0x0010: /* Resolve hostname */ { userptr_t hostname_u = real_to_user ( ix86->segs.es, ix86->regs.bx ); - int len = strlen_user ( hostname_u, 0 ); + int len = strlen ( hostname_u ); char hostname[len]; struct in_addr addr; @@ -551,8 +551,8 @@ static __asmcall __used void int22 ( struct i386_all_regs *ix86 ) { { userptr_t file_u = real_to_user ( ix86->segs.ds, ix86->regs.si ); userptr_t cmd_u = real_to_user ( ix86->segs.es, ix86->regs.bx ); - int file_len = strlen_user ( file_u, 0 ); - int cmd_len = strlen_user ( cmd_u, 0 ); + int file_len = strlen ( file_u ); + int cmd_len = strlen ( cmd_u ); char file[file_len + 1]; char cmd[cmd_len + 1]; @@ -595,9 +595,9 @@ static __asmcall __used void int22 ( struct i386_all_regs *ix86 ) { shuffle ( ix86->segs.es, ix86->regs.di, ix86->regs.cx ); /* Copy initial register values to .text16 */ - memcpy_user ( real_to_user ( rm_cs, (unsigned) __from_text16 ( &comboot_initial_regs ) ), 0, - real_to_user ( ix86->segs.ds, ix86->regs.si ), 0, - sizeof(syslinux_rm_regs) ); + memcpy ( real_to_user ( rm_cs, (unsigned) __from_text16 ( &comboot_initial_regs ) ), + real_to_user ( ix86->segs.ds, ix86->regs.si ), + sizeof(syslinux_rm_regs) ); /* Load initial register values */ __asm__ __volatile__ ( diff --git a/src/arch/x86/transitions/librm_mgmt.c b/src/arch/x86/transitions/librm_mgmt.c index ec31fceb1..7ebf62137 100644 --- a/src/arch/x86/transitions/librm_mgmt.c +++ b/src/arch/x86/transitions/librm_mgmt.c @@ -69,7 +69,7 @@ uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) { userptr_t rm_stack; rm_sp -= size; rm_stack = real_to_user ( rm_ss, rm_sp ); - memcpy_user ( rm_stack, 0, data, 0, size ); + memcpy ( rm_stack, data, size ); return rm_sp; }; @@ -83,7 +83,7 @@ uint16_t copy_user_to_rm_stack ( userptr_t data, size_t size ) { void remove_user_from_rm_stack ( userptr_t data, size_t size ) { if ( data ) { userptr_t rm_stack = real_to_user ( rm_ss, rm_sp ); - memcpy_user ( rm_stack, 0, data, 0, size ); + memcpy ( rm_stack, data, size ); } rm_sp += size; }; @@ -432,10 +432,6 @@ PROVIDE_UACCESS_INLINE ( librm, phys_to_user ); PROVIDE_UACCESS_INLINE ( librm, user_to_phys ); PROVIDE_UACCESS_INLINE ( librm, virt_to_user ); PROVIDE_UACCESS_INLINE ( librm, user_to_virt ); -PROVIDE_UACCESS_INLINE ( librm, memcpy_user ); -PROVIDE_UACCESS_INLINE ( librm, memmove_user ); -PROVIDE_UACCESS_INLINE ( librm, memset_user ); -PROVIDE_UACCESS_INLINE ( librm, strlen_user ); PROVIDE_UACCESS_INLINE ( librm, memchr_user ); PROVIDE_IOMAP_INLINE ( pages, io_to_bus ); PROVIDE_IOMAP ( pages, ioremap, ioremap_pages ); diff --git a/src/core/fbcon.c b/src/core/fbcon.c index ff3132ac7..8d05484e2 100644 --- a/src/core/fbcon.c +++ b/src/core/fbcon.c @@ -185,12 +185,12 @@ static void fbcon_draw ( struct fbcon *fbcon, struct fbcon_text_cell *cell, /* Draw background picture, if applicable */ if ( transparent ) { if ( fbcon->picture.start ) { - memcpy_user ( fbcon->start, offset, - fbcon->picture.start, offset, - fbcon->character.len ); + memcpy ( ( fbcon->start + offset ), + ( fbcon->picture.start + offset ), + fbcon->character.len ); } else { - memset_user ( fbcon->start, offset, 0, - fbcon->character.len ); + memset ( ( fbcon->start + offset ), 0, + fbcon->character.len ); } } @@ -247,8 +247,8 @@ static void fbcon_scroll ( struct fbcon *fbcon ) { /* Scroll up character array */ row_len = ( fbcon->character.width * sizeof ( struct fbcon_text_cell )); - memmove_user ( fbcon->text.start, 0, fbcon->text.start, row_len, - ( row_len * ( fbcon->character.height - 1 ) ) ); + memmove ( fbcon->text.start, ( fbcon->text.start + row_len ), + ( row_len * ( fbcon->character.height - 1 ) ) ); fbcon_clear ( fbcon, ( fbcon->character.height - 1 ) ); /* Update cursor position */ @@ -552,7 +552,7 @@ static int fbcon_picture_init ( struct fbcon *fbcon, ( ygap + pixbuf->height ) ); /* Convert to frame buffer raw format */ - memset_user ( picture->start, 0, 0, len ); + memset ( picture->start, 0, len ); for ( y = 0 ; y < height ; y++ ) { offset = ( indent + ( y * pixel->stride ) ); pixbuf_offset = ( pixbuf_indent + ( y * pixbuf_stride ) ); @@ -684,7 +684,7 @@ int fbcon_init ( struct fbcon *fbcon, userptr_t start, fbcon_clear ( fbcon, 0 ); /* Set framebuffer to all black (including margins) */ - memset_user ( fbcon->start, 0, 0, fbcon->len ); + memset ( fbcon->start, 0, fbcon->len ); /* Generate pixel buffer from background image, if applicable */ if ( config->pixbuf && @@ -692,10 +692,8 @@ int fbcon_init ( struct fbcon *fbcon, userptr_t start, goto err_picture; /* Draw background picture (including margins), if applicable */ - if ( fbcon->picture.start ) { - memcpy_user ( fbcon->start, 0, fbcon->picture.start, 0, - fbcon->len ); - } + if ( fbcon->picture.start ) + memcpy ( fbcon->start, fbcon->picture.start, fbcon->len ); /* Update console width and height */ console_set_size ( fbcon->character.width, fbcon->character.height ); diff --git a/src/core/image.c b/src/core/image.c index c69c05c93..709d0da9c 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -246,7 +246,7 @@ int image_set_data ( struct image *image, userptr_t data, size_t len ) { return rc; /* Copy in new image data */ - memcpy_user ( image->data, 0, data, 0, len ); + memcpy ( image->data, data, len ); return 0; } diff --git a/src/core/uaccess.c b/src/core/uaccess.c index ad17a58ab..01089e6fa 100644 --- a/src/core/uaccess.c +++ b/src/core/uaccess.c @@ -36,8 +36,4 @@ PROVIDE_UACCESS_INLINE ( flat, phys_to_user ); PROVIDE_UACCESS_INLINE ( flat, user_to_phys ); PROVIDE_UACCESS_INLINE ( flat, virt_to_user ); PROVIDE_UACCESS_INLINE ( flat, user_to_virt ); -PROVIDE_UACCESS_INLINE ( flat, memcpy_user ); -PROVIDE_UACCESS_INLINE ( flat, memmove_user ); -PROVIDE_UACCESS_INLINE ( flat, memset_user ); -PROVIDE_UACCESS_INLINE ( flat, strlen_user ); PROVIDE_UACCESS_INLINE ( flat, memchr_user ); diff --git a/src/crypto/deflate.c b/src/crypto/deflate.c index 7ad39ec1b..c6cce7516 100644 --- a/src/crypto/deflate.c +++ b/src/crypto/deflate.c @@ -464,8 +464,8 @@ static void deflate_copy ( struct deflate_chunk *out, if ( copy_len > len ) copy_len = len; while ( copy_len-- ) { - memcpy_user ( out->data, out_offset++, - start, offset++, 1 ); + memcpy ( ( out->data + out_offset++ ), + ( start + offset++ ), 1 ); } } out->offset += len; diff --git a/src/drivers/net/exanic.c b/src/drivers/net/exanic.c index aaa6a28a1..14a17df47 100644 --- a/src/drivers/net/exanic.c +++ b/src/drivers/net/exanic.c @@ -395,7 +395,7 @@ static int exanic_open ( struct net_device *netdev ) { } /* Reset receive region contents */ - memset_user ( port->rx, 0, 0xff, EXANIC_RX_LEN ); + memset ( port->rx, 0xff, EXANIC_RX_LEN ); /* Reset transmit feedback region */ *(port->txf) = 0; diff --git a/src/drivers/net/gve.c b/src/drivers/net/gve.c index 805feee3d..2cbc401f5 100644 --- a/src/drivers/net/gve.c +++ b/src/drivers/net/gve.c @@ -980,7 +980,7 @@ static int gve_start ( struct gve_nic *gve ) { } /* Invalidate receive completions */ - memset_user ( rx->cmplt, 0, 0, ( rx->count * rx->type->cmplt_len ) ); + memset ( rx->cmplt, 0, ( rx->count * rx->type->cmplt_len ) ); /* Reset receive sequence */ gve->seq = gve_next ( 0 ); diff --git a/src/drivers/usb/xhci.c b/src/drivers/usb/xhci.c index 3247ee69c..f244086ce 100644 --- a/src/drivers/usb/xhci.c +++ b/src/drivers/usb/xhci.c @@ -1000,7 +1000,7 @@ static int xhci_scratchpad_alloc ( struct xhci_device *xhci ) { rc = -ENOMEM; goto err_alloc; } - memset_user ( scratch->buffer, 0, 0, buffer_len ); + memset ( scratch->buffer, 0, buffer_len ); /* Allocate scratchpad array */ array_len = ( scratch->count * sizeof ( scratch->array[0] ) ); diff --git a/src/image/elf.c b/src/image/elf.c index 5c2f9db25..46c9fe8eb 100644 --- a/src/image/elf.c +++ b/src/image/elf.c @@ -66,7 +66,7 @@ static int elf_load_segment ( struct image *image, Elf_Phdr *phdr, } /* Copy image to segment */ - memcpy_user ( buffer, 0, image->data, phdr->p_offset, phdr->p_filesz ); + memcpy ( buffer, ( image->data + phdr->p_offset ), phdr->p_filesz ); return 0; } diff --git a/src/image/segment.c b/src/image/segment.c index 2d0f2f0fc..b7f8ef56c 100644 --- a/src/image/segment.c +++ b/src/image/segment.c @@ -83,7 +83,7 @@ int prep_segment ( userptr_t segment, size_t filesz, size_t memsz ) { if ( ( start >= memmap.regions[i].start ) && ( end <= memmap.regions[i].end ) ) { /* Found valid region: zero bss and return */ - memset_user ( segment, filesz, 0, ( memsz - filesz ) ); + memset ( ( segment + filesz ), 0, ( memsz - filesz ) ); return 0; } } diff --git a/src/include/ipxe/linux/linux_uaccess.h b/src/include/ipxe/linux/linux_uaccess.h index 790c75123..0c680c08f 100644 --- a/src/include/ipxe/linux/linux_uaccess.h +++ b/src/include/ipxe/linux/linux_uaccess.h @@ -69,38 +69,6 @@ UACCESS_INLINE ( linux, user_to_virt ) ( userptr_t userptr, off_t offset ) { return trivial_user_to_virt ( userptr, offset ); } -static inline __always_inline void -UACCESS_INLINE ( linux, memcpy_user ) ( userptr_t dest, off_t dest_off, - userptr_t src, off_t src_off, - size_t len ) { - trivial_memcpy_user ( dest, dest_off, src, src_off, len ); -} - -static inline __always_inline void -UACCESS_INLINE ( linux, memmove_user ) ( userptr_t dest, off_t dest_off, - userptr_t src, off_t src_off, - size_t len ) { - trivial_memmove_user ( dest, dest_off, src, src_off, len ); -} - -static inline __always_inline int -UACCESS_INLINE ( linux, memcmp_user ) ( userptr_t first, off_t first_off, - userptr_t second, off_t second_off, - size_t len ) { - return trivial_memcmp_user ( first, first_off, second, second_off, len); -} - -static inline __always_inline void -UACCESS_INLINE ( linux, memset_user ) ( userptr_t buffer, off_t offset, - int c, size_t len ) { - trivial_memset_user ( buffer, offset, c, len ); -} - -static inline __always_inline size_t -UACCESS_INLINE ( linux, strlen_user ) ( userptr_t buffer, off_t offset ) { - return trivial_strlen_user ( buffer, offset ); -} - static inline __always_inline off_t UACCESS_INLINE ( linux, memchr_user ) ( userptr_t buffer, off_t offset, int c, size_t len ) { diff --git a/src/include/ipxe/uaccess.h b/src/include/ipxe/uaccess.h index 93dc60d62..e84ca3eae 100644 --- a/src/include/ipxe/uaccess.h +++ b/src/include/ipxe/uaccess.h @@ -65,80 +65,6 @@ trivial_user_to_virt ( userptr_t userptr, off_t offset ) { return ( ( void * ) userptr + offset ); } -/** - * Copy data between user buffers - * - * @v dest Destination - * @v dest_off Destination offset - * @v src Source - * @v src_off Source offset - * @v len Length - */ -static inline __always_inline void -trivial_memcpy_user ( userptr_t dest, off_t dest_off, - userptr_t src, off_t src_off, size_t len ) { - memcpy ( ( ( void * ) dest + dest_off ), - ( ( void * ) src + src_off ), len ); -} - -/** - * Copy data between user buffers, allowing for overlap - * - * @v dest Destination - * @v dest_off Destination offset - * @v src Source - * @v src_off Source offset - * @v len Length - */ -static inline __always_inline void -trivial_memmove_user ( userptr_t dest, off_t dest_off, - userptr_t src, off_t src_off, size_t len ) { - memmove ( ( ( void * ) dest + dest_off ), - ( ( void * ) src + src_off ), len ); -} - -/** - * Compare data between user buffers - * - * @v first First buffer - * @v first_off First buffer offset - * @v second Second buffer - * @v second_off Second buffer offset - * @v len Length - * @ret diff Difference - */ -static inline __always_inline int -trivial_memcmp_user ( userptr_t first, off_t first_off, - userptr_t second, off_t second_off, size_t len ) { - return memcmp ( ( ( void * ) first + first_off ), - ( ( void * ) second + second_off ), len ); -} - -/** - * Fill user buffer with a constant byte - * - * @v buffer User buffer - * @v offset Offset within buffer - * @v c Constant byte with which to fill - * @v len Length - */ -static inline __always_inline void -trivial_memset_user ( userptr_t buffer, off_t offset, int c, size_t len ) { - memset ( ( ( void * ) buffer + offset ), c, len ); -} - -/** - * Find length of NUL-terminated string in user buffer - * - * @v buffer User buffer - * @v offset Offset within buffer - * @ret len Length of string (excluding NUL) - */ -static inline __always_inline size_t -trivial_strlen_user ( userptr_t buffer, off_t offset ) { - return strlen ( ( void * ) buffer + offset ); -} - /** * Find character in user buffer * @@ -207,38 +133,6 @@ UACCESS_INLINE ( flat, user_to_virt ) ( userptr_t userptr, off_t offset ) { return trivial_user_to_virt ( userptr, offset ); } -static inline __always_inline void -UACCESS_INLINE ( flat, memcpy_user ) ( userptr_t dest, off_t dest_off, - userptr_t src, off_t src_off, - size_t len ) { - trivial_memcpy_user ( dest, dest_off, src, src_off, len ); -} - -static inline __always_inline void -UACCESS_INLINE ( flat, memmove_user ) ( userptr_t dest, off_t dest_off, - userptr_t src, off_t src_off, - size_t len ) { - trivial_memmove_user ( dest, dest_off, src, src_off, len ); -} - -static inline __always_inline int -UACCESS_INLINE ( flat, memcmp_user ) ( userptr_t first, off_t first_off, - userptr_t second, off_t second_off, - size_t len ) { - return trivial_memcmp_user ( first, first_off, second, second_off, len); -} - -static inline __always_inline void -UACCESS_INLINE ( flat, memset_user ) ( userptr_t buffer, off_t offset, - int c, size_t len ) { - trivial_memset_user ( buffer, offset, c, len ); -} - -static inline __always_inline size_t -UACCESS_INLINE ( flat, strlen_user ) ( userptr_t buffer, off_t offset ) { - return trivial_strlen_user ( buffer, offset ); -} - static inline __always_inline off_t UACCESS_INLINE ( flat, memchr_user ) ( userptr_t buffer, off_t offset, int c, size_t len ) { @@ -310,18 +204,6 @@ static inline __always_inline void * phys_to_virt ( unsigned long phys_addr ) { return user_to_virt ( phys_to_user ( phys_addr ), 0 ); } -/** - * Copy data between user buffers - * - * @v dest Destination - * @v dest_off Destination offset - * @v src Source - * @v src_off Source offset - * @v len Length - */ -void memcpy_user ( userptr_t dest, off_t dest_off, - userptr_t src, off_t src_off, size_t len ); - /** * Copy data to user buffer * @@ -332,7 +214,7 @@ void memcpy_user ( userptr_t dest, off_t dest_off, */ static inline __always_inline void copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) { - memcpy_user ( dest, dest_off, virt_to_user ( src ), 0, len ); + memcpy ( ( dest + dest_off ), src, len ); } /** @@ -345,53 +227,9 @@ copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) { */ static inline __always_inline void copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) { - memcpy_user ( virt_to_user ( dest ), 0, src, src_off, len ); + memcpy ( dest, ( src + src_off ), len ); } -/** - * Copy data between user buffers, allowing for overlap - * - * @v dest Destination - * @v dest_off Destination offset - * @v src Source - * @v src_off Source offset - * @v len Length - */ -void memmove_user ( userptr_t dest, off_t dest_off, - userptr_t src, off_t src_off, size_t len ); - -/** - * Compare data between user buffers - * - * @v first First buffer - * @v first_off First buffer offset - * @v second Second buffer - * @v second_off Second buffer offset - * @v len Length - * @ret diff Difference - */ -int memcmp_user ( userptr_t first, off_t first_off, - userptr_t second, off_t second_off, size_t len ); - -/** - * Fill user buffer with a constant byte - * - * @v userptr User buffer - * @v offset Offset within buffer - * @v c Constant byte with which to fill - * @v len Length - */ -void memset_user ( userptr_t userptr, off_t offset, int c, size_t len ); - -/** - * Find length of NUL-terminated string in user buffer - * - * @v userptr User buffer - * @v offset Offset within buffer - * @ret len Length of string (excluding NUL) - */ -size_t strlen_user ( userptr_t userptr, off_t offset ); - /** * Find character in user buffer * diff --git a/src/interface/efi/efi_fbcon.c b/src/interface/efi/efi_fbcon.c index d388e0317..659ebd37e 100644 --- a/src/interface/efi/efi_fbcon.c +++ b/src/interface/efi/efi_fbcon.c @@ -124,7 +124,7 @@ static int efifb_draw ( unsigned int character, unsigned int index, /* Clear existing glyph */ offset = ( index * efifb.font.height ); - memset_user ( efifb.glyphs, offset, 0, efifb.font.height ); + memset ( ( efifb.glyphs + offset ), 0, efifb.font.height ); /* Get glyph */ blt = NULL; @@ -296,7 +296,7 @@ static int efifb_glyphs ( void ) { rc = -ENOMEM; goto err_alloc; } - memset_user ( efifb.glyphs, 0, 0, len ); + memset ( efifb.glyphs, 0, len ); /* Get font data */ for ( character = 0 ; character < EFIFB_ASCII ; character++ ) { diff --git a/src/interface/efi/efi_umalloc.c b/src/interface/efi/efi_umalloc.c index 175ae367e..488c53f3d 100644 --- a/src/interface/efi/efi_umalloc.c +++ b/src/interface/efi/efi_umalloc.c @@ -87,8 +87,8 @@ static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) { if ( old_ptr && ( old_ptr != UNOWHERE ) ) { copy_from_user ( &old_size, old_ptr, -EFI_PAGE_SIZE, sizeof ( old_size ) ); - memcpy_user ( new_ptr, 0, old_ptr, 0, - ( (old_size < new_size) ? old_size : new_size )); + memcpy ( new_ptr, old_ptr, + ( (old_size < new_size) ? old_size : new_size ) ); old_pages = ( EFI_SIZE_TO_PAGES ( old_size ) + 1 ); phys_addr = user_to_phys ( old_ptr, -EFI_PAGE_SIZE ); if ( ( efirc = bs->FreePages ( phys_addr, old_pages ) ) != 0 ){ diff --git a/src/interface/linux/linux_uaccess.c b/src/interface/linux/linux_uaccess.c index 9fc99c5e2..d777bf3dd 100644 --- a/src/interface/linux/linux_uaccess.c +++ b/src/interface/linux/linux_uaccess.c @@ -30,8 +30,4 @@ FILE_LICENCE(GPL2_OR_LATER); PROVIDE_UACCESS_INLINE(linux, user_to_phys); PROVIDE_UACCESS_INLINE(linux, virt_to_user); PROVIDE_UACCESS_INLINE(linux, user_to_virt); -PROVIDE_UACCESS_INLINE(linux, memcpy_user); -PROVIDE_UACCESS_INLINE(linux, memmove_user); -PROVIDE_UACCESS_INLINE(linux, memset_user); -PROVIDE_UACCESS_INLINE(linux, strlen_user); PROVIDE_UACCESS_INLINE(linux, memchr_user); diff --git a/src/interface/smbios/smbios.c b/src/interface/smbios/smbios.c index fdd14499f..3e69a0c15 100644 --- a/src/interface/smbios/smbios.c +++ b/src/interface/smbios/smbios.c @@ -277,7 +277,7 @@ int read_smbios_string ( struct smbios_structure *structure, * smbios_strings struct is constructed so as to * always end on a string boundary. */ - string_len = strlen_user ( smbios.address, offset ); + string_len = strlen ( smbios.address + offset ); if ( --index == 0 ) { /* Copy string, truncating as necessary. */ if ( len > string_len ) diff --git a/src/tests/cms_test.c b/src/tests/cms_test.c index fc4f6bd19..debbfeee7 100644 --- a/src/tests/cms_test.c +++ b/src/tests/cms_test.c @@ -1773,8 +1773,8 @@ static void cms_decrypt_okx ( struct cms_test_image *img, /* Check decrypted image matches expected plaintext */ okx ( img->image.len == expected->image.len, file, line ); - okx ( memcmp_user ( img->image.data, 0, expected->image.data, 0, - expected->image.len ) == 0, file, line ); + okx ( memcmp ( img->image.data, expected->image.data, + expected->image.len ) == 0, file, line ); } #define cms_decrypt_ok( data, envelope, keypair, expected ) \ cms_decrypt_okx ( data, envelope, keypair, expected, \ diff --git a/src/tests/gzip_test.c b/src/tests/gzip_test.c index fa76edc53..9226b4c26 100644 --- a/src/tests/gzip_test.c +++ b/src/tests/gzip_test.c @@ -128,9 +128,8 @@ static void gzip_okx ( struct gzip_test *test, const char *file, /* Verify extracted image content */ okx ( extracted->len == test->expected_len, file, line ); - okx ( memcmp_user ( extracted->data, 0, - virt_to_user ( test->expected ), 0, - test->expected_len ) == 0, file, line ); + okx ( memcmp ( extracted->data, virt_to_user ( test->expected ), + test->expected_len ) == 0, file, line ); /* Verify extracted image name */ okx ( strcmp ( extracted->name, test->expected_name ) == 0, diff --git a/src/tests/pixbuf_test.c b/src/tests/pixbuf_test.c index aaa516bb2..1f82e0018 100644 --- a/src/tests/pixbuf_test.c +++ b/src/tests/pixbuf_test.c @@ -71,9 +71,8 @@ void pixbuf_okx ( struct pixel_buffer_test *test, const char *file, /* Check pixel buffer data */ okx ( pixbuf->len == test->len, file, line ); - okx ( memcmp_user ( pixbuf->data, 0, - virt_to_user ( test->data ), 0, - test->len ) == 0, file, line ); + okx ( memcmp ( pixbuf->data, virt_to_user ( test->data ), + test->len ) == 0, file, line ); pixbuf_put ( pixbuf ); } diff --git a/src/tests/zlib_test.c b/src/tests/zlib_test.c index df52d09ac..2efdcbad8 100644 --- a/src/tests/zlib_test.c +++ b/src/tests/zlib_test.c @@ -103,9 +103,8 @@ static void zlib_okx ( struct zlib_test *test, const char *file, /* Verify extracted image content */ okx ( extracted->len == test->expected_len, file, line ); - okx ( memcmp_user ( extracted->data, 0, - virt_to_user ( test->expected ), 0, - test->expected_len ) == 0, file, line ); + okx ( memcmp ( extracted->data, virt_to_user ( test->expected ), + test->expected_len ) == 0, file, line ); /* Verify extracted image name */ okx ( strcmp ( extracted->name, test->expected_name ) == 0, -- cgit v1.2.3-55-g7522 From c059b341707863f8ecc4ecde75dd608dda72fdad Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 22 Apr 2025 12:13:22 +0100 Subject: [deflate] Remove userptr_t from decompression code Simplify the deflate, zlib, and gzip decompression code by assuming that all content is fully accessible via pointer dereferences. Signed-off-by: Michael Brown --- src/crypto/deflate.c | 122 +++++++++++++++++++++------------------------ src/image/gzip.c | 92 ++++++++++++++++++---------------- src/image/png.c | 7 ++- src/image/zlib.c | 27 ++++------ src/include/ipxe/deflate.h | 12 +++-- src/include/ipxe/zlib.h | 6 +-- src/tests/deflate_test.c | 30 +++++------ src/tests/gzip_test.c | 6 +-- src/tests/zlib_test.c | 5 +- 9 files changed, 153 insertions(+), 154 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/deflate.c b/src/crypto/deflate.c index c6cce7516..5d0101184 100644 --- a/src/crypto/deflate.c +++ b/src/crypto/deflate.c @@ -28,7 +28,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include /** @file @@ -300,24 +299,21 @@ static int deflate_alphabet ( struct deflate *deflate, * Attempt to accumulate bits from input stream * * @v deflate Decompressor - * @v in Compressed input data * @v target Number of bits to accumulate * @ret excess Number of excess bits accumulated (may be negative) */ static int deflate_accumulate ( struct deflate *deflate, - struct deflate_chunk *in, unsigned int target ) { uint8_t byte; while ( deflate->bits < target ) { /* Check for end of input */ - if ( in->offset >= in->len ) + if ( deflate->in == deflate->end ) break; /* Acquire byte from input */ - copy_from_user ( &byte, in->data, in->offset++, - sizeof ( byte ) ); + byte = *(deflate->in++); deflate->accumulator = ( deflate->accumulator | ( byte << deflate->bits ) ); deflate->rotalumucca = ( deflate->rotalumucca | @@ -359,12 +355,10 @@ static int deflate_consume ( struct deflate *deflate, unsigned int count ) { * Attempt to extract a fixed number of bits from input stream * * @v deflate Decompressor - * @v in Compressed input data * @v target Number of bits to extract * @ret data Extracted bits (or negative if not yet accumulated) */ -static int deflate_extract ( struct deflate *deflate, struct deflate_chunk *in, - unsigned int target ) { +static int deflate_extract ( struct deflate *deflate, unsigned int target ) { int excess; int data; @@ -373,7 +367,7 @@ static int deflate_extract ( struct deflate *deflate, struct deflate_chunk *in, return 0; /* Attempt to accumulate bits */ - excess = deflate_accumulate ( deflate, in, target ); + excess = deflate_accumulate ( deflate, target ); if ( excess < 0 ) return excess; @@ -389,12 +383,10 @@ static int deflate_extract ( struct deflate *deflate, struct deflate_chunk *in, * Attempt to decode a Huffman-coded symbol from input stream * * @v deflate Decompressor - * @v in Compressed input data * @v alphabet Huffman alphabet * @ret code Raw code (or negative if not yet accumulated) */ static int deflate_decode ( struct deflate *deflate, - struct deflate_chunk *in, struct deflate_alphabet *alphabet ) { struct deflate_huf_symbols *huf_sym; uint16_t huf; @@ -407,7 +399,7 @@ static int deflate_decode ( struct deflate *deflate, * even if the stream still contains some complete * Huffman-coded symbols. */ - deflate_accumulate ( deflate, in, DEFLATE_HUFFMAN_BITS ); + deflate_accumulate ( deflate, DEFLATE_HUFFMAN_BITS ); /* Normalise the bit-reversed accumulated value to 16 bits */ huf = ( deflate->rotalumucca >> 16 ); @@ -449,24 +441,22 @@ static void deflate_discard_to_byte ( struct deflate *deflate ) { * Copy data to output buffer (if available) * * @v out Output data buffer - * @v start Source data - * @v offset Starting offset within source data + * @v in Input data * @v len Length to copy */ -static void deflate_copy ( struct deflate_chunk *out, - userptr_t start, size_t offset, size_t len ) { - size_t out_offset = out->offset; +static void deflate_copy ( struct deflate_chunk *out, const void *in, + size_t len ) { + const uint8_t *in_byte = in; + uint8_t *out_byte = ( out->data + out->offset ); size_t copy_len; /* Copy data one byte at a time, to allow for overlap */ - if ( out_offset < out->len ) { - copy_len = ( out->len - out_offset ); + if ( out->offset < out->len ) { + copy_len = ( out->len - out->offset ); if ( copy_len > len ) copy_len = len; - while ( copy_len-- ) { - memcpy ( ( out->data + out_offset++ ), - ( start + offset++ ), 1 ); - } + while ( copy_len-- ) + *(out_byte++) = *(in_byte++); } out->offset += len; } @@ -475,7 +465,8 @@ static void deflate_copy ( struct deflate_chunk *out, * Inflate compressed data * * @v deflate Decompressor - * @v in Compressed input data + * @v data Compressed input data + * @v len Length of compressed input data * @v out Output data buffer * @ret rc Return status code * @@ -489,10 +480,13 @@ static void deflate_copy ( struct deflate_chunk *out, * caller can use this to find the length of the decompressed data * before allocating the output data buffer. */ -int deflate_inflate ( struct deflate *deflate, - struct deflate_chunk *in, +int deflate_inflate ( struct deflate *deflate, const void *data, size_t len, struct deflate_chunk *out ) { + /* Store input data pointers */ + deflate->in = data; + deflate->end = ( data + len ); + /* This could be implemented more neatly if gcc offered a * means for enforcing tail recursion. */ @@ -509,7 +503,7 @@ int deflate_inflate ( struct deflate *deflate, int cm; /* Extract header */ - header = deflate_extract ( deflate, in, ZLIB_HEADER_BITS ); + header = deflate_extract ( deflate, ZLIB_HEADER_BITS ); if ( header < 0 ) { deflate->resume = &&zlib_header; return 0; @@ -538,7 +532,7 @@ int deflate_inflate ( struct deflate *deflate, int btype; /* Extract block header */ - header = deflate_extract ( deflate, in, DEFLATE_HEADER_BITS ); + header = deflate_extract ( deflate, DEFLATE_HEADER_BITS ); if ( header < 0 ) { deflate->resume = &&block_header; return 0; @@ -571,17 +565,17 @@ int deflate_inflate ( struct deflate *deflate, } literal_len: { - int len; + int llen; /* Extract LEN field */ - len = deflate_extract ( deflate, in, DEFLATE_LITERAL_LEN_BITS ); - if ( len < 0 ) { + llen = deflate_extract ( deflate, DEFLATE_LITERAL_LEN_BITS ); + if ( llen < 0 ) { deflate->resume = &&literal_len; return 0; } /* Record length of literal data */ - deflate->remaining = len; + deflate->remaining = llen; DBGC2 ( deflate, "DEFLATE %p literal block length %#04zx\n", deflate, deflate->remaining ); } @@ -590,7 +584,7 @@ int deflate_inflate ( struct deflate *deflate, int nlen; /* Extract NLEN field */ - nlen = deflate_extract ( deflate, in, DEFLATE_LITERAL_LEN_BITS); + nlen = deflate_extract ( deflate, DEFLATE_LITERAL_LEN_BITS ); if ( nlen < 0 ) { deflate->resume = &&literal_nlen; return 0; @@ -608,20 +602,20 @@ int deflate_inflate ( struct deflate *deflate, literal_data: { size_t in_remaining; - size_t len; + size_t dlen; /* Calculate available amount of literal data */ - in_remaining = ( in->len - in->offset ); - len = deflate->remaining; - if ( len > in_remaining ) - len = in_remaining; + in_remaining = ( deflate->end - deflate->in ); + dlen = deflate->remaining; + if ( dlen > in_remaining ) + dlen = in_remaining; /* Copy data to output buffer */ - deflate_copy ( out, in->data, in->offset, len ); + deflate_copy ( out, deflate->in, dlen ); /* Consume data from input buffer */ - in->offset += len; - deflate->remaining -= len; + deflate->in += dlen; + deflate->remaining -= dlen; /* Finish processing if we are blocked */ if ( deflate->remaining ) { @@ -657,7 +651,7 @@ int deflate_inflate ( struct deflate *deflate, unsigned int hclen; /* Extract block header */ - header = deflate_extract ( deflate, in, DEFLATE_DYNAMIC_BITS ); + header = deflate_extract ( deflate, DEFLATE_DYNAMIC_BITS ); if ( header < 0 ) { deflate->resume = &&dynamic_header; return 0; @@ -684,7 +678,7 @@ int deflate_inflate ( struct deflate *deflate, } dynamic_codelen: { - int len; + int clen; unsigned int index; int rc; @@ -692,18 +686,18 @@ int deflate_inflate ( struct deflate *deflate, while ( deflate->length_index < deflate->length_target ) { /* Extract code length length */ - len = deflate_extract ( deflate, in, - DEFLATE_CODELEN_BITS ); - if ( len < 0 ) { + clen = deflate_extract ( deflate, + DEFLATE_CODELEN_BITS ); + if ( clen < 0 ) { deflate->resume = &&dynamic_codelen; return 0; } /* Store code length */ index = deflate_codelen_map[deflate->length_index++]; - deflate_set_length ( deflate, index, len ); + deflate_set_length ( deflate, index, clen ); DBGCP ( deflate, "DEFLATE %p codelen for %d is %d\n", - deflate, index, len ); + deflate, index, clen ); } /* Generate code length alphabet */ @@ -722,25 +716,25 @@ int deflate_inflate ( struct deflate *deflate, } dynamic_litlen_distance: { - int len; + int clen; int index; /* Decode literal/length/distance code length */ - len = deflate_decode ( deflate, in, &deflate->distance_codelen); - if ( len < 0 ) { + clen = deflate_decode ( deflate, &deflate->distance_codelen ); + if ( clen < 0 ) { deflate->resume = &&dynamic_litlen_distance; return 0; } /* Prepare for extra bits */ - if ( len < 16 ) { - deflate->length = len; + if ( clen < 16 ) { + deflate->length = clen; deflate->extra_bits = 0; deflate->dup_len = 1; } else { static const uint8_t dup_len[3] = { 3, 3, 11 }; static const uint8_t extra_bits[3] = { 2, 3, 7 }; - index = ( len - 16 ); + index = ( clen - 16 ); deflate->dup_len = dup_len[index]; deflate->extra_bits = extra_bits[index]; if ( index ) @@ -753,7 +747,7 @@ int deflate_inflate ( struct deflate *deflate, unsigned int dup_len; /* Extract extra bits */ - extra = deflate_extract ( deflate, in, deflate->extra_bits ); + extra = deflate_extract ( deflate, deflate->extra_bits ); if ( extra < 0 ) { deflate->resume = &&dynamic_litlen_distance_extra; return 0; @@ -830,7 +824,7 @@ int deflate_inflate ( struct deflate *deflate, while ( 1 ) { /* Decode Huffman code */ - code = deflate_decode ( deflate, in, &deflate->litlen ); + code = deflate_decode ( deflate, &deflate->litlen ); if ( code < 0 ) { deflate->resume = &&lzhuf_litlen; return 0; @@ -844,8 +838,7 @@ int deflate_inflate ( struct deflate *deflate, DBGCP ( deflate, "DEFLATE %p literal %#02x " "('%c')\n", deflate, byte, ( isprint ( byte ) ? byte : '.' ) ); - deflate_copy ( out, virt_to_user ( &byte ), 0, - sizeof ( byte ) ); + deflate_copy ( out, &byte, sizeof ( byte ) ); } else if ( code == DEFLATE_LITLEN_END ) { @@ -876,7 +869,7 @@ int deflate_inflate ( struct deflate *deflate, int extra; /* Extract extra bits */ - extra = deflate_extract ( deflate, in, deflate->extra_bits ); + extra = deflate_extract ( deflate, deflate->extra_bits ); if ( extra < 0 ) { deflate->resume = &&lzhuf_litlen_extra; return 0; @@ -892,8 +885,7 @@ int deflate_inflate ( struct deflate *deflate, unsigned int bits; /* Decode Huffman code */ - code = deflate_decode ( deflate, in, - &deflate->distance_codelen ); + code = deflate_decode ( deflate, &deflate->distance_codelen ); if ( code < 0 ) { deflate->resume = &&lzhuf_distance; return 0; @@ -914,7 +906,7 @@ int deflate_inflate ( struct deflate *deflate, size_t dup_distance; /* Extract extra bits */ - extra = deflate_extract ( deflate, in, deflate->extra_bits ); + extra = deflate_extract ( deflate, deflate->extra_bits ); if ( extra < 0 ) { deflate->resume = &&lzhuf_distance_extra; return 0; @@ -934,7 +926,7 @@ int deflate_inflate ( struct deflate *deflate, } /* Copy data, allowing for overlap */ - deflate_copy ( out, out->data, ( out->offset - dup_distance ), + deflate_copy ( out, ( out->data + out->offset - dup_distance ), dup_len ); /* Process next literal/length symbol */ @@ -972,7 +964,7 @@ int deflate_inflate ( struct deflate *deflate, * cases involved in calling deflate_extract() to * obtain a full 32 bits. */ - excess = deflate_accumulate ( deflate, in, ZLIB_ADLER32_BITS ); + excess = deflate_accumulate ( deflate, ZLIB_ADLER32_BITS ); if ( excess < 0 ) { deflate->resume = &&zlib_adler32; return 0; diff --git a/src/image/gzip.c b/src/image/gzip.c index 116d912d7..b72c3243e 100644 --- a/src/image/gzip.c +++ b/src/image/gzip.c @@ -24,10 +24,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include -#include #include #include #include @@ -46,83 +46,92 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @ret rc Return status code */ static int gzip_extract ( struct image *image, struct image *extracted ) { - struct gzip_header header; - struct gzip_extra_header extra; - struct gzip_crc_header crc; - struct gzip_footer footer; - struct deflate_chunk in; - unsigned int strings; - size_t offset; + const struct gzip_header *header; + const struct gzip_extra_header *extra; + const struct gzip_crc_header *crc; + const struct gzip_footer *footer; + const void *data; + size_t extra_len; + size_t string_len; size_t len; - off_t nul; + unsigned int strings; int rc; /* Sanity check */ - assert ( image->len >= ( sizeof ( header ) + sizeof ( footer ) ) ); + assert ( image->len >= ( sizeof ( *header ) + sizeof ( *footer ) ) ); + data = image->data; + len = image->len; /* Extract footer */ - len = ( image->len - sizeof ( footer ) ); - copy_from_user ( &footer, image->data, len, sizeof ( footer ) ); + assert ( len >= sizeof ( *footer ) ); + len -= sizeof ( *footer ); + footer = ( data + len ); /* Extract fixed header */ - copy_from_user ( &header, image->data, 0, sizeof ( header ) ); - offset = sizeof ( header ); - assert ( offset <= ( image->len - sizeof ( footer ) ) ); + assert ( len >= sizeof ( *header ) ); + header = data; + data += sizeof ( *header ); + len -= sizeof ( *header ); /* Skip extra header, if present */ - if ( header.flags & GZIP_FL_EXTRA ) { - copy_from_user ( &extra, image->data, offset, - sizeof ( extra ) ); - offset += sizeof ( extra ); - offset += le16_to_cpu ( extra.len ); - if ( offset > len ) { + if ( header->flags & GZIP_FL_EXTRA ) { + if ( len < sizeof ( *extra ) ) { DBGC ( image, "GZIP %p overlength extra header\n", image ); return -EINVAL; } + extra = data; + data += sizeof ( *extra ); + len -= sizeof ( *extra ); + extra_len = le16_to_cpu ( extra->len ); + if ( len < extra_len ) { + DBGC ( image, "GZIP %p overlength extra header\n", + image ); + return -EINVAL; + } + data += extra_len; + len -= extra_len; } - assert ( offset <= ( image->len - sizeof ( footer ) ) ); /* Skip name and/or comment, if present */ strings = 0; - if ( header.flags & GZIP_FL_NAME ) + if ( header->flags & GZIP_FL_NAME ) strings++; - if ( header.flags & GZIP_FL_COMMENT ) + if ( header->flags & GZIP_FL_COMMENT ) strings++; while ( strings-- ) { - nul = memchr_user ( image->data, offset, 0, ( len - offset ) ); - if ( nul < 0 ) { + string_len = strnlen ( data, len ); + if ( string_len == len ) { DBGC ( image, "GZIP %p overlength name/comment\n", image ); return -EINVAL; } - offset = ( nul + 1 /* NUL */ ); + data += ( string_len + 1 /* NUL */ ); + len -= ( string_len + 1 /* NUL */ ); } - assert ( offset <= ( image->len - sizeof ( footer ) ) ); /* Skip CRC, if present */ - if ( header.flags & GZIP_FL_HCRC ) { - offset += sizeof ( crc ); - if ( offset > len ) { + if ( header->flags & GZIP_FL_HCRC ) { + if ( len < sizeof ( *crc ) ) { DBGC ( image, "GZIP %p overlength CRC header\n", image ); return -EINVAL; } + data += sizeof ( *crc ); + len -= sizeof ( *crc ); } - /* Initialise input chunk */ - deflate_chunk_init ( &in, ( image->data + offset ), 0, len ); - /* Presize extracted image */ if ( ( rc = image_set_len ( extracted, - le32_to_cpu ( footer.len ) ) ) != 0 ) { + le32_to_cpu ( footer->len ) ) ) != 0 ) { DBGC ( image, "GZIP %p could not presize: %s\n", image, strerror ( rc ) ); return rc; } /* Decompress image (expanding if necessary) */ - if ( ( rc = zlib_deflate ( DEFLATE_RAW, &in, extracted ) ) != 0 ) { + if ( ( rc = zlib_deflate ( DEFLATE_RAW, data, len, + extracted ) ) != 0 ) { DBGC ( image, "GZIP %p could not decompress: %s\n", image, strerror ( rc ) ); return rc; @@ -138,19 +147,18 @@ static int gzip_extract ( struct image *image, struct image *extracted ) { * @ret rc Return status code */ static int gzip_probe ( struct image *image ) { - struct gzip_header header; - struct gzip_footer footer; + const struct gzip_header *header; + const struct gzip_footer *footer; /* Sanity check */ - if ( image->len < ( sizeof ( header ) + sizeof ( footer ) ) ) { + if ( image->len < ( sizeof ( *header ) + sizeof ( *footer ) ) ) { DBGC ( image, "GZIP %p image too short\n", image ); return -ENOEXEC; } + header = image->data; /* Check magic header */ - copy_from_user ( &header.magic, image->data, 0, - sizeof ( header.magic ) ); - if ( header.magic != cpu_to_be16 ( GZIP_MAGIC ) ) { + if ( header->magic != cpu_to_be16 ( GZIP_MAGIC ) ) { DBGC ( image, "GZIP %p invalid magic\n", image ); return -ENOEXEC; } diff --git a/src/image/png.c b/src/image/png.c index d5cf7fd8f..8b432e01a 100644 --- a/src/image/png.c +++ b/src/image/png.c @@ -336,13 +336,12 @@ static int png_palette ( struct image *image, struct png_context *png, */ static int png_image_data ( struct image *image, struct png_context *png, size_t len ) { - struct deflate_chunk in; int rc; /* Deflate this chunk */ - deflate_chunk_init ( &in, image->data, png->offset, - ( png->offset + len ) ); - if ( ( rc = deflate_inflate ( &png->deflate, &in, &png->raw ) ) != 0 ) { + if ( ( rc = deflate_inflate ( &png->deflate, + ( image->data + png->offset ), + len, &png->raw ) ) != 0 ) { DBGC ( image, "PNG %s could not decompress: %s\n", image->name, strerror ( rc ) ); return rc; diff --git a/src/image/zlib.c b/src/image/zlib.c index a42c47e1b..d7deee88b 100644 --- a/src/image/zlib.c +++ b/src/image/zlib.c @@ -27,7 +27,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include @@ -41,11 +40,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Extract compressed data to image * * @v format Compression format code - * @v in Compressed input chunk + * @v data Compressed input data + * @v len Length of compressed input data * @v extracted Extracted image * @ret rc Return status code */ -int zlib_deflate ( enum deflate_format format, struct deflate_chunk *in, +int zlib_deflate ( enum deflate_format format, const void *data, size_t len, struct image *extracted ) { struct deflate *deflate; struct deflate_chunk out; @@ -64,14 +64,12 @@ int zlib_deflate ( enum deflate_format format, struct deflate_chunk *in, /* (Re)initialise decompressor */ deflate_init ( deflate, format ); - /* (Re)initialise input chunk */ - in->offset = 0; - /* Initialise output chunk */ deflate_chunk_init ( &out, extracted->data, 0, extracted->len ); /* Decompress data */ - if ( ( rc = deflate_inflate ( deflate, in, &out ) ) != 0 ) { + if ( ( rc = deflate_inflate ( deflate, data, len, + &out ) ) != 0 ) { DBGC ( extracted, "ZLIB %p could not decompress: %s\n", extracted, strerror ( rc ) ); goto err_inflate; @@ -116,14 +114,11 @@ int zlib_deflate ( enum deflate_format format, struct deflate_chunk *in, * @ret rc Return status code */ static int zlib_extract ( struct image *image, struct image *extracted ) { - struct deflate_chunk in; int rc; - /* Initialise input chunk */ - deflate_chunk_init ( &in, image->data, 0, image->len ); - /* Decompress image */ - if ( ( rc = zlib_deflate ( DEFLATE_ZLIB, &in, extracted ) ) != 0 ) + if ( ( rc = zlib_deflate ( DEFLATE_ZLIB, image->data, image->len, + extracted ) ) != 0 ) return rc; return 0; @@ -136,17 +131,17 @@ static int zlib_extract ( struct image *image, struct image *extracted ) { * @ret rc Return status code */ static int zlib_probe ( struct image *image ) { - union zlib_magic magic; + const union zlib_magic *magic; /* Sanity check */ - if ( image->len < sizeof ( magic ) ) { + if ( image->len < sizeof ( *magic ) ) { DBGC ( image, "ZLIB %p image too short\n", image ); return -ENOEXEC; } + magic = image->data; /* Check magic header */ - copy_from_user ( &magic, image->data, 0, sizeof ( magic ) ); - if ( ! zlib_magic_is_valid ( &magic ) ) { + if ( ! zlib_magic_is_valid ( magic ) ) { DBGC ( image, "ZLIB %p invalid magic data\n", image ); return -ENOEXEC; } diff --git a/src/include/ipxe/deflate.h b/src/include/ipxe/deflate.h index b751aa9a3..67292d77e 100644 --- a/src/include/ipxe/deflate.h +++ b/src/include/ipxe/deflate.h @@ -11,7 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -#include /** Compression formats */ enum deflate_format { @@ -163,6 +162,11 @@ struct deflate { /** Format */ enum deflate_format format; + /** Current input data pointer */ + const uint8_t *in; + /** End of input data pointer */ + const uint8_t *end; + /** Accumulator */ uint32_t accumulator; /** Bit-reversed accumulator @@ -240,7 +244,7 @@ struct deflate { /** A chunk of data */ struct deflate_chunk { /** Data */ - userptr_t data; + void *data; /** Current offset */ size_t offset; /** Length of data */ @@ -256,7 +260,7 @@ struct deflate_chunk { * @v len Length */ static inline __attribute__ (( always_inline )) void -deflate_chunk_init ( struct deflate_chunk *chunk, userptr_t data, +deflate_chunk_init ( struct deflate_chunk *chunk, void *data, size_t offset, size_t len ) { chunk->data = data; @@ -277,7 +281,7 @@ static inline int deflate_finished ( struct deflate *deflate ) { extern void deflate_init ( struct deflate *deflate, enum deflate_format format ); extern int deflate_inflate ( struct deflate *deflate, - struct deflate_chunk *in, + const void *data, size_t len, struct deflate_chunk *out ); #endif /* _IPXE_DEFLATE_H */ diff --git a/src/include/ipxe/zlib.h b/src/include/ipxe/zlib.h index 29016c38e..3b0866bd1 100644 --- a/src/include/ipxe/zlib.h +++ b/src/include/ipxe/zlib.h @@ -28,15 +28,15 @@ union zlib_magic { * @v magic Magic header * @ret is_valid Magic header is valid */ -static inline int zlib_magic_is_valid ( union zlib_magic *magic ) { +static inline int zlib_magic_is_valid ( const union zlib_magic *magic ) { /* Check magic value as per RFC 6713 */ return ( ( ( magic->cmf & 0x8f ) == 0x08 ) && ( ( be16_to_cpu ( magic->check ) % 31 ) == 0 ) ); } -extern int zlib_deflate ( enum deflate_format format, struct deflate_chunk *in, - struct image *extracted ); +extern int zlib_deflate ( enum deflate_format format, const void *data, + size_t len, struct image *extracted ); extern struct image_type zlib_image_type __image_type ( PROBE_NORMAL ); diff --git a/src/tests/deflate_test.c b/src/tests/deflate_test.c index 20ff5b9a2..f7086b45d 100644 --- a/src/tests/deflate_test.c +++ b/src/tests/deflate_test.c @@ -156,19 +156,18 @@ static void deflate_okx ( struct deflate *deflate, struct deflate_test *test, struct deflate_test_fragments *frags, const char *file, unsigned int line ) { - uint8_t data[ test->expected_len ]; - struct deflate_chunk in; - struct deflate_chunk out; - size_t frag_len = -1UL; - size_t offset = 0; + uint8_t buf[ test->expected_len ]; + const void *data = test->compressed; size_t remaining = test->compressed_len; + size_t frag_len = -1UL; + struct deflate_chunk out; unsigned int i; /* Initialise decompressor */ deflate_init ( deflate, test->format ); /* Initialise output chunk */ - deflate_chunk_init ( &out, virt_to_user ( data ), 0, sizeof ( data ) ); + deflate_chunk_init ( &out, buf, 0, sizeof ( buf ) ); /* Process input (in fragments, if applicable) */ for ( i = 0 ; i < ( sizeof ( frags->len ) / @@ -179,16 +178,15 @@ static void deflate_okx ( struct deflate *deflate, frag_len = frags->len[i]; if ( frag_len > remaining ) frag_len = remaining; - deflate_chunk_init ( &in, virt_to_user ( test->compressed ), - offset, ( offset + frag_len ) ); /* Decompress this fragment */ - okx ( deflate_inflate ( deflate, &in, &out ) == 0, file, line ); - okx ( in.len == ( offset + frag_len ), file, line ); - okx ( in.offset == in.len, file, line ); + okx ( deflate_inflate ( deflate, data, frag_len, + &out ) == 0, file, line ); + okx ( deflate->in == ( data + frag_len ), file, line ); + okx ( deflate->end == ( data + frag_len ), file, line ); /* Move to next fragment */ - offset = in.offset; + data += frag_len; remaining -= frag_len; if ( ! remaining ) break; @@ -199,9 +197,13 @@ static void deflate_okx ( struct deflate *deflate, /* Check decompression has terminated as expected */ okx ( deflate_finished ( deflate ), file, line ); - okx ( offset == test->compressed_len, file, line ); + okx ( deflate->in == ( test->compressed + test->compressed_len ), + file, line ); + okx ( deflate->end == ( test->compressed + test->compressed_len ), + file, line ); okx ( out.offset == test->expected_len, file, line ); - okx ( memcmp ( data, test->expected, test->expected_len ) == 0, + okx ( out.data == buf, file, line ); + okx ( memcmp ( out.data, test->expected, test->expected_len ) == 0, file, line ); } #define deflate_ok( deflate, test, frags ) \ diff --git a/src/tests/gzip_test.c b/src/tests/gzip_test.c index 9226b4c26..6fd0ec854 100644 --- a/src/tests/gzip_test.c +++ b/src/tests/gzip_test.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #undef NDEBUG #include +#include #include #include #include @@ -114,8 +115,7 @@ static void gzip_okx ( struct gzip_test *test, const char *file, struct image *extracted; /* Construct compressed image */ - image = image_memory ( test->compressed_name, - virt_to_user ( test->compressed ), + image = image_memory ( test->compressed_name, test->compressed, test->compressed_len ); okx ( image != NULL, file, line ); okx ( image->len == test->compressed_len, file, line ); @@ -128,7 +128,7 @@ static void gzip_okx ( struct gzip_test *test, const char *file, /* Verify extracted image content */ okx ( extracted->len == test->expected_len, file, line ); - okx ( memcmp ( extracted->data, virt_to_user ( test->expected ), + okx ( memcmp ( extracted->data, test->expected, test->expected_len ) == 0, file, line ); /* Verify extracted image name */ diff --git a/src/tests/zlib_test.c b/src/tests/zlib_test.c index 2efdcbad8..807c5e429 100644 --- a/src/tests/zlib_test.c +++ b/src/tests/zlib_test.c @@ -89,8 +89,7 @@ static void zlib_okx ( struct zlib_test *test, const char *file, struct image *extracted; /* Construct compressed image */ - image = image_memory ( test->compressed_name, - virt_to_user ( test->compressed ), + image = image_memory ( test->compressed_name, test->compressed, test->compressed_len ); okx ( image != NULL, file, line ); okx ( image->len == test->compressed_len, file, line ); @@ -103,7 +102,7 @@ static void zlib_okx ( struct zlib_test *test, const char *file, /* Verify extracted image content */ okx ( extracted->len == test->expected_len, file, line ); - okx ( memcmp ( extracted->data, virt_to_user ( test->expected ), + okx ( memcmp ( extracted->data, test->expected, test->expected_len ) == 0, file, line ); /* Verify extracted image name */ -- cgit v1.2.3-55-g7522 From 0b3fc48fefd311b17b666fecf3a34688717727e8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 22 Apr 2025 14:13:45 +0100 Subject: [acpi] Remove userptr_t from ACPI table parsing Simplify the ACPI table parsing code by assuming that all table content is fully accessible via pointer dereferences. Signed-off-by: Michael Brown --- src/arch/x86/include/ipxe/rsdp.h | 4 +- src/arch/x86/interface/pcbios/acpi_timer.c | 9 +-- src/arch/x86/interface/pcbios/acpipwr.c | 18 ++--- src/arch/x86/interface/pcbios/rsdp.c | 33 ++++---- src/core/acpi.c | 116 +++++++++++++---------------- src/core/acpi_settings.c | 21 +++--- src/core/acpimac.c | 17 +++-- src/drivers/bus/ecam.c | 34 ++++----- src/include/ipxe/acpi.h | 24 +++--- src/include/ipxe/efi/efi_acpi.h | 4 +- src/include/ipxe/null_acpi.h | 6 +- src/interface/efi/efi_acpi.c | 7 +- src/interface/linux/linux_acpi.c | 9 ++- src/tests/acpi_test.c | 12 +-- 14 files changed, 152 insertions(+), 162 deletions(-) (limited to 'src/tests') diff --git a/src/arch/x86/include/ipxe/rsdp.h b/src/arch/x86/include/ipxe/rsdp.h index 14afcd774..daaa43077 100644 --- a/src/arch/x86/include/ipxe/rsdp.h +++ b/src/arch/x86/include/ipxe/rsdp.h @@ -20,9 +20,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * * @v signature Requested table signature * @v index Requested index of table with this signature - * @ret table Table, or UNULL if not found + * @ret table Table, or NULL if not found */ -static inline __attribute__ (( always_inline )) userptr_t +static inline __attribute__ (( always_inline )) const struct acpi_header * ACPI_INLINE ( rsdp, acpi_find ) ( uint32_t signature, unsigned int index ) { return acpi_find_via_rsdt ( signature, index ); diff --git a/src/arch/x86/interface/pcbios/acpi_timer.c b/src/arch/x86/interface/pcbios/acpi_timer.c index 2e4047e38..e1523578b 100644 --- a/src/arch/x86/interface/pcbios/acpi_timer.c +++ b/src/arch/x86/interface/pcbios/acpi_timer.c @@ -102,20 +102,19 @@ static void acpi_udelay ( unsigned long usecs ) { * @ret rc Return status code */ static int acpi_timer_probe ( void ) { - struct acpi_fadt fadtab; - userptr_t fadt; + const struct acpi_fadt *fadt; unsigned int pm_tmr_blk; /* Locate FADT */ - fadt = acpi_table ( FADT_SIGNATURE, 0 ); + fadt = container_of ( acpi_table ( FADT_SIGNATURE, 0 ), + struct acpi_fadt, acpi ); if ( ! fadt ) { DBGC ( &acpi_timer, "ACPI could not find FADT\n" ); return -ENOENT; } /* Read FADT */ - copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) ); - pm_tmr_blk = le32_to_cpu ( fadtab.pm_tmr_blk ); + pm_tmr_blk = le32_to_cpu ( fadt->pm_tmr_blk ); if ( ! pm_tmr_blk ) { DBGC ( &acpi_timer, "ACPI has no timer\n" ); return -ENOENT; diff --git a/src/arch/x86/interface/pcbios/acpipwr.c b/src/arch/x86/interface/pcbios/acpipwr.c index f08b4af25..bff53806b 100644 --- a/src/arch/x86/interface/pcbios/acpipwr.c +++ b/src/arch/x86/interface/pcbios/acpipwr.c @@ -62,8 +62,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * uglier hacks I have ever implemented, but it's still prettier than * the ACPI specification itself. */ -static int acpi_extract_sx ( userptr_t zsdt, size_t len, size_t offset, - void *data ) { +static int acpi_extract_sx ( const struct acpi_header *zsdt, size_t len, + size_t offset, void *data ) { unsigned int *sx = data; uint8_t bytes[4]; uint8_t *byte; @@ -77,7 +77,8 @@ static int acpi_extract_sx ( userptr_t zsdt, size_t len, size_t offset, } /* Read first four bytes of value */ - copy_from_user ( bytes, zsdt, offset, sizeof ( bytes ) ); + memcpy ( bytes, ( ( ( const void * ) zsdt ) + offset ), + sizeof ( bytes ) ); DBGC ( colour, "ACPI found \\_Sx containing %02x:%02x:%02x:%02x\n", bytes[0], bytes[1], bytes[2], bytes[3] ); @@ -111,8 +112,7 @@ static int acpi_extract_sx ( userptr_t zsdt, size_t len, size_t offset, * @ret rc Return status code */ int acpi_poweroff ( void ) { - struct acpi_fadt fadtab; - userptr_t fadt; + const struct acpi_fadt *fadt; unsigned int pm1a_cnt_blk; unsigned int pm1b_cnt_blk; unsigned int pm1a_cnt; @@ -123,16 +123,16 @@ int acpi_poweroff ( void ) { int rc; /* Locate FADT */ - fadt = acpi_table ( FADT_SIGNATURE, 0 ); + fadt = container_of ( acpi_table ( FADT_SIGNATURE, 0 ), + struct acpi_fadt, acpi ); if ( ! fadt ) { DBGC ( colour, "ACPI could not find FADT\n" ); return -ENOENT; } /* Read FADT */ - copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) ); - pm1a_cnt_blk = le32_to_cpu ( fadtab.pm1a_cnt_blk ); - pm1b_cnt_blk = le32_to_cpu ( fadtab.pm1b_cnt_blk ); + pm1a_cnt_blk = le32_to_cpu ( fadt->pm1a_cnt_blk ); + pm1b_cnt_blk = le32_to_cpu ( fadt->pm1b_cnt_blk ); pm1a_cnt = ( pm1a_cnt_blk + ACPI_PM1_CNT ); pm1b_cnt = ( pm1b_cnt_blk + ACPI_PM1_CNT ); diff --git a/src/arch/x86/interface/pcbios/rsdp.c b/src/arch/x86/interface/pcbios/rsdp.c index c2534c7f6..6bcf19b18 100644 --- a/src/arch/x86/interface/pcbios/rsdp.c +++ b/src/arch/x86/interface/pcbios/rsdp.c @@ -53,50 +53,51 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * * @v start Start address to search * @v len Length to search - * @ret rsdt ACPI root system description table, or UNULL + * @ret rsdt ACPI root system description table, or NULL */ -static userptr_t rsdp_find_rsdt_range ( userptr_t start, size_t len ) { +static const struct acpi_rsdt * rsdp_find_rsdt_range ( const void *start, + size_t len ) { static const char signature[8] = RSDP_SIGNATURE; - struct acpi_rsdp rsdp; - userptr_t rsdt; + const struct acpi_rsdp *rsdp; + const struct acpi_rsdt *rsdt; size_t offset; uint8_t sum; unsigned int i; /* Search for RSDP */ - for ( offset = 0 ; ( ( offset + sizeof ( rsdp ) ) < len ) ; + for ( offset = 0 ; ( ( offset + sizeof ( *rsdp ) ) < len ) ; offset += RSDP_STRIDE ) { /* Check signature and checksum */ - copy_from_user ( &rsdp, start, offset, sizeof ( rsdp ) ); - if ( memcmp ( rsdp.signature, signature, + rsdp = ( start + offset ); + if ( memcmp ( rsdp->signature, signature, sizeof ( signature ) ) != 0 ) continue; - for ( sum = 0, i = 0 ; i < sizeof ( rsdp ) ; i++ ) - sum += *( ( ( uint8_t * ) &rsdp ) + i ); + for ( sum = 0, i = 0 ; i < sizeof ( *rsdp ) ; i++ ) + sum += *( ( ( uint8_t * ) rsdp ) + i ); if ( sum != 0 ) continue; /* Extract RSDT */ - rsdt = phys_to_virt ( le32_to_cpu ( rsdp.rsdt ) ); + rsdt = phys_to_virt ( le32_to_cpu ( rsdp->rsdt ) ); DBGC ( rsdt, "RSDT %#08lx found via RSDP %#08lx\n", virt_to_phys ( rsdt ), ( virt_to_phys ( start ) + offset ) ); return rsdt; } - return UNULL; + return NULL; } /** * Locate ACPI root system description table * - * @ret rsdt ACPI root system description table, or UNULL + * @ret rsdt ACPI root system description table, or NULL */ -static userptr_t rsdp_find_rsdt ( void ) { - static userptr_t rsdt; +static const struct acpi_rsdt * rsdp_find_rsdt ( void ) { + static const struct acpi_rsdt *rsdt; + const void *ebda; uint16_t ebda_seg; - userptr_t ebda; size_t ebda_len; /* Return existing RSDT if already found */ @@ -119,7 +120,7 @@ static userptr_t rsdp_find_rsdt ( void ) { if ( rsdt ) return rsdt; - return UNULL; + return NULL; } PROVIDE_ACPI ( rsdp, acpi_find_rsdt, rsdp_find_rsdt ); diff --git a/src/core/acpi.c b/src/core/acpi.c index d7da0ccc1..6c5d1e079 100644 --- a/src/core/acpi.c +++ b/src/core/acpi.c @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include #include #include @@ -54,25 +55,17 @@ typeof ( acpi_find ) *acpi_finder __attribute__ (( weak )) = acpi_find; /** * Compute ACPI table checksum * - * @v table Any ACPI table + * @v acpi Any ACPI table header * @ret checksum 0 if checksum is good */ -static uint8_t acpi_checksum ( userptr_t table ) { - struct acpi_header acpi; +static uint8_t acpi_checksum ( const struct acpi_header *acpi ) { + const uint8_t *byte = ( ( const void * ) acpi ); + size_t len = le32_to_cpu ( acpi->length ); uint8_t sum = 0; - uint8_t data = 0; - unsigned int i; - - /* Read table length */ - copy_from_user ( &acpi.length, table, - offsetof ( typeof ( acpi ), length ), - sizeof ( acpi.length ) ); /* Compute checksum */ - for ( i = 0 ; i < le32_to_cpu ( acpi.length ) ; i++ ) { - copy_from_user ( &data, table, i, sizeof ( data ) ); - sum += data; - } + while ( len-- ) + sum += *(byte++); return sum; } @@ -85,7 +78,7 @@ static uint8_t acpi_checksum ( userptr_t table ) { void acpi_fix_checksum ( struct acpi_header *acpi ) { /* Update checksum */ - acpi->checksum -= acpi_checksum ( virt_to_user ( acpi ) ); + acpi->checksum -= acpi_checksum ( acpi ); } /** @@ -93,9 +86,10 @@ void acpi_fix_checksum ( struct acpi_header *acpi ) { * * @v signature Requested table signature * @v index Requested index of table with this signature - * @ret table Table, or UNULL if not found + * @ret table Table, or NULL if not found */ -userptr_t acpi_table ( uint32_t signature, unsigned int index ) { +const struct acpi_header * acpi_table ( uint32_t signature, + unsigned int index ) { return ( *acpi_finder ) ( signature, index ); } @@ -105,14 +99,12 @@ userptr_t acpi_table ( uint32_t signature, unsigned int index ) { * * @v signature Requested table signature * @v index Requested index of table with this signature - * @ret table Table, or UNULL if not found + * @ret table Table, or NULL if not found */ -userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ) { - struct acpi_header acpi; - struct acpi_rsdt *rsdtab; - typeof ( rsdtab->entry[0] ) entry; - userptr_t rsdt; - userptr_t table; +const struct acpi_header * acpi_find_via_rsdt ( uint32_t signature, + unsigned int index ) { + const struct acpi_rsdt *rsdt; + const struct acpi_header *table; size_t len; unsigned int count; unsigned int i; @@ -121,45 +113,38 @@ userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ) { rsdt = acpi_find_rsdt(); if ( ! rsdt ) { DBG ( "RSDT not found\n" ); - return UNULL; + return NULL; } /* Read RSDT header */ - copy_from_user ( &acpi, rsdt, 0, sizeof ( acpi ) ); - if ( acpi.signature != cpu_to_le32 ( RSDT_SIGNATURE ) ) { + if ( rsdt->acpi.signature != cpu_to_le32 ( RSDT_SIGNATURE ) ) { DBGC ( colour, "RSDT %#08lx has invalid signature:\n", virt_to_phys ( rsdt ) ); - DBGC_HDA ( colour, virt_to_phys ( rsdt ), &acpi, - sizeof ( acpi ) ); - return UNULL; + DBGC_HDA ( colour, virt_to_phys ( rsdt ), &rsdt->acpi, + sizeof ( rsdt->acpi ) ); + return NULL; } - len = le32_to_cpu ( acpi.length ); - if ( len < sizeof ( rsdtab->acpi ) ) { + len = le32_to_cpu ( rsdt->acpi.length ); + if ( len < sizeof ( rsdt->acpi ) ) { DBGC ( colour, "RSDT %#08lx has invalid length:\n", virt_to_phys ( rsdt ) ); - DBGC_HDA ( colour, virt_to_phys ( rsdt ), &acpi, - sizeof ( acpi ) ); - return UNULL; + DBGC_HDA ( colour, virt_to_phys ( rsdt ), &rsdt->acpi, + sizeof ( rsdt->acpi ) ); + return NULL; } /* Calculate number of entries */ - count = ( ( len - sizeof ( rsdtab->acpi ) ) / sizeof ( entry ) ); + count = ( ( len - sizeof ( rsdt->acpi ) ) / + sizeof ( rsdt->entry[0] ) ); /* Search through entries */ for ( i = 0 ; i < count ; i++ ) { - /* Get table address */ - copy_from_user ( &entry, rsdt, - offsetof ( typeof ( *rsdtab ), entry[i] ), - sizeof ( entry ) ); - /* Read table header */ - table = phys_to_virt ( entry ); - copy_from_user ( &acpi.signature, table, 0, - sizeof ( acpi.signature ) ); + table = phys_to_virt ( rsdt->entry[i] ); /* Check table signature */ - if ( acpi.signature != cpu_to_le32 ( signature ) ) + if ( table->signature != cpu_to_le32 ( signature ) ) continue; /* Check index */ @@ -169,13 +154,13 @@ userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ) { /* Check table integrity */ if ( acpi_checksum ( table ) != 0 ) { DBGC ( colour, "RSDT %#08lx found %s with bad " - "checksum at %08lx\n", virt_to_phys ( rsdt ), + "checksum at %#08lx\n", virt_to_phys ( rsdt ), acpi_name ( signature ), virt_to_phys ( table ) ); break; } - DBGC ( colour, "RSDT %#08lx found %s at %08lx\n", + DBGC ( colour, "RSDT %#08lx found %s at %#08lx\n", virt_to_phys ( rsdt ), acpi_name ( signature ), virt_to_phys ( table ) ); return table; @@ -183,7 +168,7 @@ userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ) { DBGC ( colour, "RSDT %#08lx could not find %s\n", virt_to_phys ( rsdt ), acpi_name ( signature ) ); - return UNULL; + return NULL; } /** @@ -195,26 +180,27 @@ userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ) { * @v extract Extraction method * @ret rc Return status code */ -static int acpi_zsdt ( userptr_t zsdt, uint32_t signature, void *data, - int ( * extract ) ( userptr_t zsdt, size_t len, - size_t offset, void *data ) ) { - struct acpi_header acpi; +static int acpi_zsdt ( const struct acpi_header *zsdt, + uint32_t signature, void *data, + int ( * extract ) ( const struct acpi_header *zsdt, + size_t len, size_t offset, + void *data ) ) { uint32_t buf; size_t offset; size_t len; int rc; /* Read table header */ - copy_from_user ( &acpi, zsdt, 0, sizeof ( acpi ) ); - len = le32_to_cpu ( acpi.length ); + len = le32_to_cpu ( zsdt->length ); /* Locate signature */ - for ( offset = sizeof ( acpi ) ; + for ( offset = sizeof ( *zsdt ) ; ( ( offset + sizeof ( buf ) /* signature */ ) < len ) ; offset++ ) { /* Check signature */ - copy_from_user ( &buf, zsdt, offset, sizeof ( buf ) ); + memcpy ( &buf, ( ( ( const void * ) zsdt ) + offset ), + sizeof ( buf ) ); if ( buf != cpu_to_le32 ( signature ) ) continue; DBGC ( zsdt, "DSDT/SSDT %#08lx found %s at offset %#zx\n", @@ -238,20 +224,20 @@ static int acpi_zsdt ( userptr_t zsdt, uint32_t signature, void *data, * @ret rc Return status code */ int acpi_extract ( uint32_t signature, void *data, - int ( * extract ) ( userptr_t zsdt, size_t len, - size_t offset, void *data ) ) { - struct acpi_fadt fadtab; - userptr_t fadt; - userptr_t dsdt; - userptr_t ssdt; + int ( * extract ) ( const struct acpi_header *zsdt, + size_t len, size_t offset, + void *data ) ) { + const struct acpi_fadt *fadt; + const struct acpi_header *dsdt; + const struct acpi_header *ssdt; unsigned int i; int rc; /* Try DSDT first */ - fadt = acpi_table ( FADT_SIGNATURE, 0 ); + fadt = container_of ( acpi_table ( FADT_SIGNATURE, 0 ), + struct acpi_fadt, acpi ); if ( fadt ) { - copy_from_user ( &fadtab, fadt, 0, sizeof ( fadtab ) ); - dsdt = phys_to_virt ( fadtab.dsdt ); + dsdt = phys_to_virt ( fadt->dsdt ); if ( ( rc = acpi_zsdt ( dsdt, signature, data, extract ) ) == 0 ) return 0; diff --git a/src/core/acpi_settings.c b/src/core/acpi_settings.c index b9e2b7f61..cdee1f865 100644 --- a/src/core/acpi_settings.c +++ b/src/core/acpi_settings.c @@ -64,14 +64,15 @@ static int acpi_settings_applies ( struct settings *settings __unused, static int acpi_settings_fetch ( struct settings *settings, struct setting *setting, void *data, size_t len ) { - struct acpi_header acpi; + const struct acpi_header *acpi; + const uint8_t *src; + uint8_t *dst; uint32_t tag_high; uint32_t tag_low; uint32_t tag_signature; unsigned int tag_index; size_t tag_offset; size_t tag_len; - userptr_t table; size_t offset; size_t max_len; int delta; @@ -88,15 +89,12 @@ static int acpi_settings_fetch ( struct settings *settings, acpi_name ( tag_signature ), tag_index, tag_offset, tag_len ); /* Locate ACPI table */ - table = acpi_table ( tag_signature, tag_index ); - if ( ! table ) + acpi = acpi_table ( tag_signature, tag_index ); + if ( ! acpi ) return -ENOENT; - /* Read table header */ - copy_from_user ( &acpi, table, 0, sizeof ( acpi ) ); - /* Calculate starting offset and maximum available length */ - max_len = le32_to_cpu ( acpi.length ); + max_len = le32_to_cpu ( acpi->length ); if ( tag_offset > max_len ) return -ENOENT; offset = tag_offset; @@ -115,10 +113,11 @@ static int acpi_settings_fetch ( struct settings *settings, } /* Read data */ + src = ( ( ( const void * ) acpi ) + offset ); + dst = data; for ( i = 0 ; ( ( i < max_len ) && ( i < len ) ) ; i++ ) { - copy_from_user ( data, table, offset, 1 ); - data++; - offset += delta; + *(dst++) = *src; + src += delta; } /* Set type if not already specified */ diff --git a/src/core/acpimac.c b/src/core/acpimac.c index e0074ba43..11ac3243e 100644 --- a/src/core/acpimac.c +++ b/src/core/acpimac.c @@ -142,8 +142,9 @@ static struct acpimac_extractor acpimac_rtxmac = { * string that appears shortly after an "AMAC" or "MACA" signature. * This should work for most implementations encountered in practice. */ -static int acpimac_extract ( userptr_t zsdt, size_t len, size_t offset, - void *data, struct acpimac_extractor *extractor ){ +static int acpimac_extract ( const struct acpi_header *zsdt, size_t len, + size_t offset, void *data, + struct acpimac_extractor *extractor ) { size_t prefix_len = strlen ( extractor->prefix ); uint8_t *hw_addr = data; size_t skip = 0; @@ -161,8 +162,8 @@ static int acpimac_extract ( userptr_t zsdt, size_t len, size_t offset, skip++ ) { /* Read value */ - copy_from_user ( buf, zsdt, ( offset + skip ), - sizeof ( buf ) ); + memcpy ( buf, ( ( ( const void * ) zsdt ) + offset + skip ), + sizeof ( buf ) ); /* Check for expected format */ if ( memcmp ( buf, extractor->prefix, prefix_len ) != 0 ) @@ -203,8 +204,8 @@ static int acpimac_extract ( userptr_t zsdt, size_t len, size_t offset, * @v data Data buffer * @ret rc Return status code */ -static int acpimac_extract_auxmac ( userptr_t zsdt, size_t len, size_t offset, - void *data ) { +static int acpimac_extract_auxmac ( const struct acpi_header *zsdt, + size_t len, size_t offset, void *data ) { return acpimac_extract ( zsdt, len, offset, data, &acpimac_auxmac ); } @@ -218,8 +219,8 @@ static int acpimac_extract_auxmac ( userptr_t zsdt, size_t len, size_t offset, * @v data Data buffer * @ret rc Return status code */ -static int acpimac_extract_rtxmac ( userptr_t zsdt, size_t len, size_t offset, - void *data ) { +static int acpimac_extract_rtxmac ( const struct acpi_header *zsdt, + size_t len, size_t offset, void *data ) { return acpimac_extract ( zsdt, len, offset, data, &acpimac_rtxmac ); } diff --git a/src/drivers/bus/ecam.c b/src/drivers/bus/ecam.c index cde5952b8..58d513e88 100644 --- a/src/drivers/bus/ecam.c +++ b/src/drivers/bus/ecam.c @@ -46,49 +46,43 @@ static struct ecam_mapping ecam; */ static int ecam_find ( uint32_t busdevfn, struct pci_range *range, struct ecam_allocation *alloc ) { - struct ecam_allocation tmp; + struct ecam_table *mcfg; + struct ecam_allocation *tmp; unsigned int best = 0; - unsigned int offset; unsigned int count; unsigned int index; - userptr_t mcfg; - uint32_t length; + unsigned int i; uint32_t start; /* Return empty range on error */ range->count = 0; /* Locate MCFG table */ - mcfg = acpi_table ( ECAM_SIGNATURE, 0 ); + mcfg = container_of ( acpi_table ( ECAM_SIGNATURE, 0 ), + struct ecam_table, acpi ); if ( ! mcfg ) { DBGC ( &ecam, "ECAM found no MCFG table\n" ); return -ENOTSUP; } - /* Get length of table */ - copy_from_user ( &length, mcfg, - offsetof ( struct ecam_table, acpi.length ), - sizeof ( length ) ); - /* Iterate over allocations */ - for ( offset = offsetof ( struct ecam_table, alloc ) ; - ( offset + sizeof ( tmp ) ) <= le32_to_cpu ( length ) ; - offset += sizeof ( tmp ) ) { + for ( i = 0 ; ( offsetof ( typeof ( *mcfg ), alloc[ i + 1 ] ) <= + le32_to_cpu ( mcfg->acpi.length ) ) ; i++ ) { /* Read allocation */ - copy_from_user ( &tmp, mcfg, offset, sizeof ( tmp ) ); + tmp = &mcfg->alloc[i]; DBGC2 ( &ecam, "ECAM %04x:[%02x-%02x] has base %08llx\n", - le16_to_cpu ( tmp.segment ), tmp.start, tmp.end, - ( ( unsigned long long ) le64_to_cpu ( tmp.base ) ) ); - start = PCI_BUSDEVFN ( le16_to_cpu ( tmp.segment ), - tmp.start, 0, 0 ); - count = PCI_BUSDEVFN ( 0, ( tmp.end - tmp.start + 1 ), 0, 0 ); + le16_to_cpu ( tmp->segment ), tmp->start, tmp->end, + ( ( unsigned long long ) le64_to_cpu ( tmp->base ) ) ); + start = PCI_BUSDEVFN ( le16_to_cpu ( tmp->segment ), + tmp->start, 0, 0 ); + count = PCI_BUSDEVFN ( 0, ( tmp->end - tmp->start + 1 ), 0, 0 ); /* Check for a matching or new closest allocation */ index = ( busdevfn - start ); if ( ( index < count ) || ( index > best ) ) { if ( alloc ) - memcpy ( alloc, &tmp, sizeof ( *alloc ) ); + memcpy ( alloc, tmp, sizeof ( *alloc ) ); range->start = start; range->count = count; best = index; diff --git a/src/include/ipxe/acpi.h b/src/include/ipxe/acpi.h index c34681238..40a44cffc 100644 --- a/src/include/ipxe/acpi.h +++ b/src/include/ipxe/acpi.h @@ -14,7 +14,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include #include @@ -355,7 +354,8 @@ struct acpi_model { #define PROVIDE_ACPI_INLINE( _subsys, _api_func ) \ PROVIDE_SINGLE_API_INLINE ( ACPI_PREFIX_ ## _subsys, _api_func ) -extern userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ); +extern const struct acpi_header * acpi_find_via_rsdt ( uint32_t signature, + unsigned int index ); /* Include all architecture-independent ACPI API headers */ #include @@ -368,31 +368,35 @@ extern userptr_t acpi_find_via_rsdt ( uint32_t signature, unsigned int index ); /** * Locate ACPI root system description table * - * @ret rsdt ACPI root system description table, or UNULL + * @ret rsdt ACPI root system description table, or NULL */ -userptr_t acpi_find_rsdt ( void ); +const struct acpi_rsdt * acpi_find_rsdt ( void ); /** * Locate ACPI table * * @v signature Requested table signature * @v index Requested index of table with this signature - * @ret table Table, or UNULL if not found + * @ret table Table, or NULL if not found */ -userptr_t acpi_find ( uint32_t signature, unsigned int index ); +const struct acpi_header * acpi_find ( uint32_t signature, + unsigned int index ); extern struct acpi_descriptor * acpi_describe ( struct interface *interface ); #define acpi_describe_TYPE( object_type ) \ typeof ( struct acpi_descriptor * ( object_type ) ) -extern userptr_t ( * acpi_finder ) ( uint32_t signature, unsigned int index ); +extern const struct acpi_header * ( * acpi_finder ) ( uint32_t signature, + unsigned int index ); extern void acpi_fix_checksum ( struct acpi_header *acpi ); -extern userptr_t acpi_table ( uint32_t signature, unsigned int index ); +extern const struct acpi_header * acpi_table ( uint32_t signature, + unsigned int index ); extern int acpi_extract ( uint32_t signature, void *data, - int ( * extract ) ( userptr_t zsdt, size_t len, - size_t offset, void *data ) ); + int ( * extract ) ( const struct acpi_header *zsdt, + size_t len, size_t offset, + void *data ) ); extern void acpi_add ( struct acpi_descriptor *desc ); extern void acpi_del ( struct acpi_descriptor *desc ); extern int acpi_install ( int ( * install ) ( struct acpi_header *acpi ) ); diff --git a/src/include/ipxe/efi/efi_acpi.h b/src/include/ipxe/efi/efi_acpi.h index a698863a6..68f9c5be7 100644 --- a/src/include/ipxe/efi/efi_acpi.h +++ b/src/include/ipxe/efi/efi_acpi.h @@ -20,9 +20,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * * @v signature Requested table signature * @v index Requested index of table with this signature - * @ret table Table, or UNULL if not found + * @ret table Table, or NULL if not found */ -static inline __attribute__ (( always_inline )) userptr_t +static inline __attribute__ (( always_inline )) const struct acpi_header * ACPI_INLINE ( efi, acpi_find ) ( uint32_t signature, unsigned int index ) { return acpi_find_via_rsdt ( signature, index ); diff --git a/src/include/ipxe/null_acpi.h b/src/include/ipxe/null_acpi.h index cedb02839..18f059964 100644 --- a/src/include/ipxe/null_acpi.h +++ b/src/include/ipxe/null_acpi.h @@ -9,17 +9,19 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include + #ifdef ACPI_NULL #define ACPI_PREFIX_null #else #define ACPI_PREFIX_null __null_ #endif -static inline __attribute__ (( always_inline )) userptr_t +static inline __attribute__ (( always_inline )) const struct acpi_header * ACPI_INLINE ( null, acpi_find ) ( uint32_t signature __unused, unsigned int index __unused ) { - return UNULL; + return NULL; } #endif /* _IPXE_NULL_ACPI_H */ diff --git a/src/interface/efi/efi_acpi.c b/src/interface/efi/efi_acpi.c index c1046c01a..a2021a4f6 100644 --- a/src/interface/efi/efi_acpi.c +++ b/src/interface/efi/efi_acpi.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include +#include #include #include #include @@ -42,15 +43,15 @@ EFI_USE_TABLE ( ACPI_10_TABLE, &rsdp, 0 ); /** * Locate ACPI root system description table * - * @ret rsdt ACPI root system description table, or UNULL + * @ret rsdt ACPI root system description table, or NULL */ -static userptr_t efi_find_rsdt ( void ) { +static const struct acpi_rsdt * efi_find_rsdt ( void ) { /* Locate RSDT via ACPI configuration table, if available */ if ( rsdp ) return phys_to_virt ( rsdp->RsdtAddress ); - return UNULL; + return NULL; } PROVIDE_ACPI ( efi, acpi_find_rsdt, efi_find_rsdt ); diff --git a/src/interface/linux/linux_acpi.c b/src/interface/linux/linux_acpi.c index 846db2f1f..a2a8bf12e 100644 --- a/src/interface/linux/linux_acpi.c +++ b/src/interface/linux/linux_acpi.c @@ -42,7 +42,7 @@ struct linux_acpi_table { /** Index */ unsigned int index; /** Cached data */ - userptr_t data; + void *data; }; /** List of cached ACPI tables */ @@ -53,9 +53,10 @@ static LIST_HEAD ( linux_acpi_tables ); * * @v signature Requested table signature * @v index Requested index of table with this signature - * @ret table Table, or UNULL if not found + * @ret table Table, or NULL if not found */ -static userptr_t linux_acpi_find ( uint32_t signature, unsigned int index ) { +static const struct acpi_header * linux_acpi_find ( uint32_t signature, + unsigned int index ) { struct linux_acpi_table *table; struct acpi_header *header; union { @@ -121,7 +122,7 @@ static userptr_t linux_acpi_find ( uint32_t signature, unsigned int index ) { err_read: free ( table ); err_alloc: - return UNULL; + return NULL; } /** diff --git a/src/tests/acpi_test.c b/src/tests/acpi_test.c index 1ca5befaf..6e8840217 100644 --- a/src/tests/acpi_test.c +++ b/src/tests/acpi_test.c @@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /* Forcibly enable assertions */ #undef NDEBUG +#include #include #include #include @@ -185,26 +186,27 @@ static struct acpi_test_tables *acpi_test_tables; * * @v signature Requested table signature * @v index Requested index of table with this signature - * @ret table Table, or UNULL if not found + * @ret table Table, or NULL if not found */ -static userptr_t acpi_test_find ( uint32_t signature, unsigned int index ) { +static const struct acpi_header * acpi_test_find ( uint32_t signature, + unsigned int index ) { struct acpi_test_table *table; unsigned int i; /* Fail if no test tables are installed */ if ( ! acpi_test_tables ) - return UNULL; + return NULL; /* Scan through test tables */ for ( i = 0 ; i < acpi_test_tables->count ; i++ ) { table = acpi_test_tables->table[i]; if ( ( signature == le32_to_cpu ( table->signature.raw ) ) && ( index-- == 0 ) ) { - return virt_to_user ( table->data ); + return table->data; } } - return UNULL; + return NULL; } /** Override ACPI table finder */ -- cgit v1.2.3-55-g7522 From 839540cb95a310ebf96d6302afecc3ac97ccf746 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 23 Apr 2025 12:47:53 +0100 Subject: [umalloc] Remove userptr_t from user memory allocations Use standard void pointers for umalloc(), urealloc(), and ufree(), with the "u" prefix retained to indicate that these allocations are made from external ("user") memory rather than from the internal heap. Signed-off-by: Michael Brown --- src/arch/riscv/interface/sbi/sbi_umalloc.c | 11 +++---- src/arch/x86/interface/pcbios/memtop_umalloc.c | 42 ++++++++++++-------------- src/core/dma.c | 9 +++--- src/core/malloc.c | 17 ----------- src/core/xferbuf.c | 12 ++++---- src/include/ipxe/dma.h | 20 ++++++------ src/include/ipxe/malloc.h | 18 +++++++++++ src/include/ipxe/umalloc.h | 23 +++++++------- src/include/ipxe/xferbuf.h | 3 +- src/interface/efi/efi_pci.c | 36 ++-------------------- src/interface/efi/efi_umalloc.c | 25 ++++++++------- src/interface/linux/linux_umalloc.c | 31 +++++++------------ src/tests/umalloc_test.c | 5 ++- 13 files changed, 101 insertions(+), 151 deletions(-) (limited to 'src/tests') diff --git a/src/arch/riscv/interface/sbi/sbi_umalloc.c b/src/arch/riscv/interface/sbi/sbi_umalloc.c index 2f9935adb..0e351748b 100644 --- a/src/arch/riscv/interface/sbi/sbi_umalloc.c +++ b/src/arch/riscv/interface/sbi/sbi_umalloc.c @@ -32,23 +32,20 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ -/** Equivalent of NOWHERE for user pointers */ -#define UNOWHERE ( ~UNULL ) - /** * Reallocate external memory * - * @v old_ptr Memory previously allocated by umalloc(), or UNULL + * @v old_ptr Memory previously allocated by umalloc(), or NULL * @v new_size Requested size - * @ret new_ptr Allocated memory, or UNULL + * @ret new_ptr Allocated memory, or NULL * * Calling realloc() with a new size of zero is a valid way to free a * memory block. */ -static userptr_t sbi_urealloc ( userptr_t old_ptr, size_t new_size ) { +static void * sbi_urealloc ( void * old_ptr, size_t new_size ) { /* External allocation not yet implemented: allocate from heap */ - return ( ( userptr_t ) realloc ( ( ( void * ) old_ptr ), new_size ) ); + return ( realloc ( old_ptr, new_size ) ); } PROVIDE_UMALLOC ( sbi, urealloc, sbi_urealloc ); diff --git a/src/arch/x86/interface/pcbios/memtop_umalloc.c b/src/arch/x86/interface/pcbios/memtop_umalloc.c index b87d22516..d4489fb01 100644 --- a/src/arch/x86/interface/pcbios/memtop_umalloc.c +++ b/src/arch/x86/interface/pcbios/memtop_umalloc.c @@ -44,9 +44,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** Alignment of external allocated memory */ #define EM_ALIGN ( 4 * 1024 ) -/** Equivalent of NOWHERE for user pointers */ -#define UNOWHERE ( ( userptr_t ) ~( ( intptr_t ) 0 ) ) - /** An external memory block */ struct external_memory { /** Size of this memory block (excluding this header) */ @@ -56,10 +53,10 @@ struct external_memory { }; /** Top of heap */ -static userptr_t top = UNULL; +static void *top = NULL; /** Bottom of heap (current lowest allocated block) */ -static userptr_t bottom = UNULL; +static void *bottom = NULL; /** Remaining space on heap */ static size_t heap_size; @@ -70,7 +67,7 @@ static size_t heap_size; * @ret start Start of region * @ret len Length of region */ -size_t largest_memblock ( userptr_t *start ) { +size_t largest_memblock ( void **start ) { struct memory_map memmap; struct memory_region *region; physaddr_t max = EM_MAX_ADDRESS; @@ -81,7 +78,7 @@ size_t largest_memblock ( userptr_t *start ) { size_t len = 0; /* Avoid returning uninitialised data on error */ - *start = UNULL; + *start = NULL; /* Scan through all memory regions */ get_memmap ( &memmap ); @@ -119,7 +116,7 @@ size_t largest_memblock ( userptr_t *start ) { * */ static void init_eheap ( void ) { - userptr_t base; + void *base; heap_size = largest_memblock ( &base ); bottom = top = ( base + heap_size ); @@ -137,8 +134,8 @@ static void ecollect_free ( void ) { /* Walk the free list and collect empty blocks */ while ( bottom != top ) { - copy_from_user ( &extmem, bottom, -sizeof ( extmem ), - sizeof ( extmem ) ); + memcpy ( &extmem, ( bottom - sizeof ( extmem ) ), + sizeof ( extmem ) ); if ( extmem.used ) break; DBG ( "EXTMEM freeing [%lx,%lx)\n", virt_to_phys ( bottom ), @@ -152,16 +149,16 @@ static void ecollect_free ( void ) { /** * Reallocate external memory * - * @v old_ptr Memory previously allocated by umalloc(), or UNULL + * @v old_ptr Memory previously allocated by umalloc(), or NULL * @v new_size Requested size - * @ret new_ptr Allocated memory, or UNULL + * @ret new_ptr Allocated memory, or NULL * * Calling realloc() with a new size of zero is a valid way to free a * memory block. */ -static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { +static void * memtop_urealloc ( void *ptr, size_t new_size ) { struct external_memory extmem; - userptr_t new = ptr; + void *new = ptr; size_t align; /* (Re)initialise external memory allocator if necessary */ @@ -169,15 +166,15 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { init_eheap(); /* Get block properties into extmem */ - if ( ptr && ( ptr != UNOWHERE ) ) { + if ( ptr && ( ptr != NOWHERE ) ) { /* Determine old size */ - copy_from_user ( &extmem, ptr, -sizeof ( extmem ), - sizeof ( extmem ) ); + memcpy ( &extmem, ( ptr - sizeof ( extmem ) ), + sizeof ( extmem ) ); } else { /* Create a zero-length block */ if ( heap_size < sizeof ( extmem ) ) { DBG ( "EXTMEM out of space\n" ); - return UNULL; + return NULL; } ptr = bottom = ( bottom - sizeof ( extmem ) ); heap_size -= sizeof ( extmem ); @@ -196,7 +193,7 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { new -= align; if ( new_size > ( heap_size + extmem.size ) ) { DBG ( "EXTMEM out of space\n" ); - return UNULL; + return NULL; } DBG ( "EXTMEM expanding [%lx,%lx) to [%lx,%lx)\n", virt_to_phys ( ptr ), @@ -215,13 +212,12 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { DBG ( "EXTMEM cannot expand [%lx,%lx)\n", virt_to_phys ( ptr ), ( virt_to_phys ( ptr ) + extmem.size ) ); - return UNULL; + return NULL; } } /* Write back block properties */ - copy_to_user ( new, -sizeof ( extmem ), &extmem, - sizeof ( extmem ) ); + memcpy ( ( new - sizeof ( extmem ) ), &extmem, sizeof ( extmem ) ); /* Collect any free blocks and update hidden memory region */ ecollect_free(); @@ -229,7 +225,7 @@ static userptr_t memtop_urealloc ( userptr_t ptr, size_t new_size ) { ( ( bottom == top ) ? 0 : sizeof ( extmem ) ) ), virt_to_phys ( top ) ); - return ( new_size ? new : UNOWHERE ); + return ( new_size ? new : NOWHERE ); } PROVIDE_UMALLOC ( memtop, urealloc, memtop_urealloc ); diff --git a/src/core/dma.c b/src/core/dma.c index 5d6868216..1f3c1d8a6 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -130,9 +130,9 @@ static void dma_op_free ( struct dma_mapping *map, void *addr, size_t len ) { * @v align Physical alignment * @ret addr Buffer address, or NULL on error */ -static userptr_t dma_op_umalloc ( struct dma_device *dma, - struct dma_mapping *map, - size_t len, size_t align ) { +static void * dma_op_umalloc ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align ) { struct dma_operations *op = dma->op; if ( ! op ) @@ -147,8 +147,7 @@ static userptr_t dma_op_umalloc ( struct dma_device *dma, * @v addr Buffer address * @v len Length of buffer */ -static void dma_op_ufree ( struct dma_mapping *map, userptr_t addr, - size_t len ) { +static void dma_op_ufree ( struct dma_mapping *map, void *addr, size_t len ) { struct dma_device *dma = map->dma; assert ( dma != NULL ); diff --git a/src/core/malloc.c b/src/core/malloc.c index c499ce6fd..ec29513ef 100644 --- a/src/core/malloc.c +++ b/src/core/malloc.c @@ -71,23 +71,6 @@ struct autosized_block { char data[0]; }; -/** - * Address for zero-length memory blocks - * - * @c malloc(0) or @c realloc(ptr,0) will return the special value @c - * NOWHERE. Calling @c free(NOWHERE) will have no effect. - * - * This is consistent with the ANSI C standards, which state that - * "either NULL or a pointer suitable to be passed to free()" must be - * returned in these cases. Using a special non-NULL value means that - * the caller can take a NULL return value to indicate failure, - * without first having to check for a requested size of zero. - * - * Code outside of malloc.c do not ever need to refer to the actual - * value of @c NOWHERE; this is an internal definition. - */ -#define NOWHERE ( ( void * ) ~( ( intptr_t ) 0 ) ) - /** List of free memory blocks */ static LIST_HEAD ( free_blocks ); diff --git a/src/core/xferbuf.c b/src/core/xferbuf.c index 240118557..1c08f8bc3 100644 --- a/src/core/xferbuf.c +++ b/src/core/xferbuf.c @@ -237,8 +237,8 @@ struct xfer_buffer_operations xferbuf_malloc_operations = { * @ret rc Return status code */ static int xferbuf_umalloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) { - userptr_t *udata = xferbuf->data; - userptr_t new_udata; + void **udata = xferbuf->data; + void *new_udata; new_udata = urealloc ( *udata, len ); if ( ! new_udata ) @@ -257,9 +257,9 @@ static int xferbuf_umalloc_realloc ( struct xfer_buffer *xferbuf, size_t len ) { */ static void xferbuf_umalloc_write ( struct xfer_buffer *xferbuf, size_t offset, const void *data, size_t len ) { - userptr_t *udata = xferbuf->data; + void **udata = xferbuf->data; - copy_to_user ( *udata, offset, data, len ); + memcpy ( ( *udata + offset ), data, len ); } /** @@ -272,9 +272,9 @@ static void xferbuf_umalloc_write ( struct xfer_buffer *xferbuf, size_t offset, */ static void xferbuf_umalloc_read ( struct xfer_buffer *xferbuf, size_t offset, void *data, size_t len ) { - userptr_t *udata = xferbuf->data; + void **udata = xferbuf->data; - copy_from_user ( data, *udata, offset, len ); + memcpy ( data, ( *udata + offset ), len ); } /** umalloc()-based data buffer operations */ diff --git a/src/include/ipxe/dma.h b/src/include/ipxe/dma.h index 385e4baf7..6e5c43289 100644 --- a/src/include/ipxe/dma.h +++ b/src/include/ipxe/dma.h @@ -106,9 +106,9 @@ struct dma_operations { * @v align Physical alignment * @ret addr Buffer address, or NULL on error */ - userptr_t ( * umalloc ) ( struct dma_device *dma, - struct dma_mapping *map, - size_t len, size_t align ); + void * ( * umalloc ) ( struct dma_device *dma, + struct dma_mapping *map, + size_t len, size_t align ); /** * Unmap and free DMA-coherent buffer from external (user) memory * @@ -118,7 +118,7 @@ struct dma_operations { * @v len Length of buffer */ void ( * ufree ) ( struct dma_device *dma, struct dma_mapping *map, - userptr_t addr, size_t len ); + void *addr, size_t len ); /** * Set addressable space mask * @@ -265,11 +265,11 @@ DMAAPI_INLINE ( flat, dma_free ) ( struct dma_mapping *map, * @v align Physical alignment * @ret addr Buffer address, or NULL on error */ -static inline __always_inline userptr_t +static inline __always_inline void * DMAAPI_INLINE ( flat, dma_umalloc ) ( struct dma_device *dma, struct dma_mapping *map, size_t len, size_t align __unused ) { - userptr_t addr; + void *addr; /* Allocate buffer */ addr = umalloc ( len ); @@ -292,7 +292,7 @@ DMAAPI_INLINE ( flat, dma_umalloc ) ( struct dma_device *dma, */ static inline __always_inline void DMAAPI_INLINE ( flat, dma_ufree ) ( struct dma_mapping *map, - userptr_t addr, size_t len __unused ) { + void *addr, size_t len __unused ) { /* Free buffer */ ufree ( addr ); @@ -397,8 +397,8 @@ void dma_free ( struct dma_mapping *map, void *addr, size_t len ); * @v align Physical alignment * @ret addr Buffer address, or NULL on error */ -userptr_t dma_umalloc ( struct dma_device *dma, struct dma_mapping *map, - size_t len, size_t align ); +void * dma_umalloc ( struct dma_device *dma, struct dma_mapping *map, + size_t len, size_t align ); /** * Unmap and free DMA-coherent buffer from external (user) memory @@ -407,7 +407,7 @@ userptr_t dma_umalloc ( struct dma_device *dma, struct dma_mapping *map, * @v addr Buffer address * @v len Length of buffer */ -void dma_ufree ( struct dma_mapping *map, userptr_t addr, size_t len ); +void dma_ufree ( struct dma_mapping *map, void *addr, size_t len ); /** * Set addressable space mask diff --git a/src/include/ipxe/malloc.h b/src/include/ipxe/malloc.h index f0fde0bc3..8c3a7769d 100644 --- a/src/include/ipxe/malloc.h +++ b/src/include/ipxe/malloc.h @@ -21,6 +21,24 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +/** + * Address for zero-length memory blocks + * + * @c malloc(0) or @c realloc(ptr,0) will return the special value @c + * NOWHERE. Calling @c free(NOWHERE) will have no effect. + * + * This is consistent with the ANSI C standards, which state that + * "either NULL or a pointer suitable to be passed to free()" must be + * returned in these cases. Using a special non-NULL value means that + * the caller can take a NULL return value to indicate failure, + * without first having to check for a requested size of zero. + * + * Code outside of the memory allocators themselves does not ever need + * to refer to the actual value of @c NOWHERE; this is an internal + * definition. + */ +#define NOWHERE ( ( void * ) ~( ( intptr_t ) 0 ) ) + extern size_t freemem; extern size_t usedmem; extern size_t maxusedmem; diff --git a/src/include/ipxe/umalloc.h b/src/include/ipxe/umalloc.h index 3892ef53b..a6476a390 100644 --- a/src/include/ipxe/umalloc.h +++ b/src/include/ipxe/umalloc.h @@ -10,9 +10,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include +#include #include -#include /** * Provide a user memory allocation API implementation @@ -34,36 +35,36 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** * Reallocate external memory * - * @v userptr Memory previously allocated by umalloc(), or UNULL + * @v old_ptr Memory previously allocated by umalloc(), or NULL * @v new_size Requested size - * @ret userptr Allocated memory, or UNULL + * @ret new_ptr Allocated memory, or NULL * * Calling realloc() with a new size of zero is a valid way to free a * memory block. */ -userptr_t urealloc ( userptr_t userptr, size_t new_size ); +void * urealloc ( void *ptr, size_t new_size ); /** * Allocate external memory * * @v size Requested size - * @ret userptr Memory, or UNULL + * @ret ptr Memory, or NULL * * Memory is guaranteed to be aligned to a page boundary. */ -static inline __always_inline userptr_t umalloc ( size_t size ) { - return urealloc ( UNULL, size ); +static inline __always_inline void * umalloc ( size_t size ) { + return urealloc ( NULL, size ); } /** * Free external memory * - * @v userptr Memory allocated by umalloc(), or UNULL + * @v ptr Memory allocated by umalloc(), or NULL * - * If @c ptr is UNULL, no action is taken. + * If @c ptr is NULL, no action is taken. */ -static inline __always_inline void ufree ( userptr_t userptr ) { - urealloc ( userptr, 0 ); +static inline __always_inline void ufree ( void *ptr ) { + urealloc ( ptr, 0 ); } #endif /* _IPXE_UMALLOC_H */ diff --git a/src/include/ipxe/xferbuf.h b/src/include/ipxe/xferbuf.h index cb0b1a0e8..04635999d 100644 --- a/src/include/ipxe/xferbuf.h +++ b/src/include/ipxe/xferbuf.h @@ -11,7 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -#include #include #include @@ -84,7 +83,7 @@ xferbuf_malloc_init ( struct xfer_buffer *xferbuf ) { * @v data User pointer */ static inline __attribute__ (( always_inline )) void -xferbuf_umalloc_init ( struct xfer_buffer *xferbuf, userptr_t *data ) { +xferbuf_umalloc_init ( struct xfer_buffer *xferbuf, void **data ) { xferbuf->data = data; xferbuf->op = &xferbuf_umalloc_operations; } diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index 01351df51..b8c7df38d 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -640,38 +640,6 @@ static void efipci_dma_free ( struct dma_device *dma, struct dma_mapping *map, dma->allocated--; } -/** - * Allocate and map DMA-coherent buffer from external (user) memory - * - * @v dma DMA device - * @v map DMA mapping to fill in - * @v len Length of buffer - * @v align Physical alignment - * @ret addr Buffer address, or NULL on error - */ -static userptr_t efipci_dma_umalloc ( struct dma_device *dma, - struct dma_mapping *map, - size_t len, size_t align ) { - void *addr; - - addr = efipci_dma_alloc ( dma, map, len, align ); - return virt_to_user ( addr ); -} - -/** - * Unmap and free DMA-coherent buffer from external (user) memory - * - * @v dma DMA device - * @v map DMA mapping - * @v addr Buffer address - * @v len Length of buffer - */ -static void efipci_dma_ufree ( struct dma_device *dma, struct dma_mapping *map, - userptr_t addr, size_t len ) { - - efipci_dma_free ( dma, map, addr, len ); -} - /** * Set addressable space mask * @@ -710,8 +678,8 @@ static struct dma_operations efipci_dma_operations = { .unmap = efipci_dma_unmap, .alloc = efipci_dma_alloc, .free = efipci_dma_free, - .umalloc = efipci_dma_umalloc, - .ufree = efipci_dma_ufree, + .umalloc = efipci_dma_alloc, + .ufree = efipci_dma_free, .set_mask = efipci_dma_set_mask, }; diff --git a/src/interface/efi/efi_umalloc.c b/src/interface/efi/efi_umalloc.c index 0636cb7fd..419d9b294 100644 --- a/src/interface/efi/efi_umalloc.c +++ b/src/interface/efi/efi_umalloc.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include @@ -35,25 +36,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ -/** Equivalent of NOWHERE for user pointers */ -#define UNOWHERE ( ( userptr_t ) ~( ( intptr_t ) 0 ) ) - /** * Reallocate external memory * - * @v old_ptr Memory previously allocated by umalloc(), or UNULL + * @v old_ptr Memory previously allocated by umalloc(), or NULL * @v new_size Requested size - * @ret new_ptr Allocated memory, or UNULL + * @ret new_ptr Allocated memory, or NULL * * Calling realloc() with a new size of zero is a valid way to free a * memory block. */ -static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) { +static void * efi_urealloc ( void *old_ptr, size_t new_size ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; EFI_PHYSICAL_ADDRESS phys_addr; unsigned int new_pages, old_pages; - userptr_t new_ptr = UNOWHERE; + void *new_ptr = NOWHERE; size_t old_size; + size_t *info; EFI_STATUS efirc; int rc; @@ -69,12 +68,12 @@ static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) { rc = -EEFI ( efirc ); DBG ( "EFI could not allocate %d pages: %s\n", new_pages, strerror ( rc ) ); - return UNULL; + return NULL; } assert ( phys_addr != 0 ); new_ptr = phys_to_virt ( phys_addr + EFI_PAGE_SIZE ); - copy_to_user ( new_ptr, -EFI_PAGE_SIZE, - &new_size, sizeof ( new_size ) ); + info = ( new_ptr - EFI_PAGE_SIZE ); + *info = new_size; DBG ( "EFI allocated %d pages at %llx\n", new_pages, phys_addr ); } @@ -84,9 +83,9 @@ static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) { * is valid, or (b) new_size is 0; either way, the memcpy() is * valid. */ - if ( old_ptr && ( old_ptr != UNOWHERE ) ) { - copy_from_user ( &old_size, old_ptr, -EFI_PAGE_SIZE, - sizeof ( old_size ) ); + if ( old_ptr && ( old_ptr != NOWHERE ) ) { + info = ( old_ptr - EFI_PAGE_SIZE ); + old_size = *info; memcpy ( new_ptr, old_ptr, ( (old_size < new_size) ? old_size : new_size ) ); old_pages = ( EFI_SIZE_TO_PAGES ( old_size ) + 1 ); diff --git a/src/interface/linux/linux_umalloc.c b/src/interface/linux/linux_umalloc.c index a7250fa5b..ab5770e9c 100644 --- a/src/interface/linux/linux_umalloc.c +++ b/src/interface/linux/linux_umalloc.c @@ -31,9 +31,6 @@ FILE_LICENCE(GPL2_OR_LATER); #include -/** Special address returned for empty allocations */ -#define NOWHERE ((void *)-1) - /** Poison to make the metadata more unique */ #define POISON 0xa5a5a5a5 #define min(a,b) (((a)<(b))?(a):(b)) @@ -47,7 +44,16 @@ struct metadata #define SIZE_MD (sizeof(struct metadata)) -/** Simple realloc which passes most of the work to mmap(), mremap() and munmap() */ +/** + * Reallocate external memory + * + * @v old_ptr Memory previously allocated by umalloc(), or NULL + * @v new_size Requested size + * @ret new_ptr Allocated memory, or NULL + * + * Calling realloc() with a new size of zero is a valid way to free a + * memory block. + */ static void * linux_realloc(void *ptr, size_t size) { struct metadata md = {0, 0}; @@ -136,19 +142,4 @@ static void * linux_realloc(void *ptr, size_t size) return ptr; } -/** - * Reallocate external memory - * - * @v old_ptr Memory previously allocated by umalloc(), or UNULL - * @v new_size Requested size - * @ret new_ptr Allocated memory, or UNULL - * - * Calling realloc() with a new size of zero is a valid way to free a - * memory block. - */ -static userptr_t linux_urealloc(userptr_t old_ptr, size_t new_size) -{ - return (userptr_t)linux_realloc((void *)old_ptr, new_size); -} - -PROVIDE_UMALLOC(linux, urealloc, linux_urealloc); +PROVIDE_UMALLOC(linux, urealloc, linux_realloc); diff --git a/src/tests/umalloc_test.c b/src/tests/umalloc_test.c index 53810833c..1a32a0531 100644 --- a/src/tests/umalloc_test.c +++ b/src/tests/umalloc_test.c @@ -1,12 +1,11 @@ #include -#include #include #include void umalloc_test ( void ) { struct memory_map memmap; - userptr_t bob; - userptr_t fred; + void *bob; + void *fred; printf ( "Before allocation:\n" ); get_memmap ( &memmap ); -- cgit v1.2.3-55-g7522 From e8ffe2cd644000c1cca51c40ba14edb546ca769b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 24 Apr 2025 01:30:50 +0100 Subject: [uaccess] Remove trivial uses of userptr_t Signed-off-by: Michael Brown --- src/arch/x86/core/vram_settings.c | 5 +++-- src/arch/x86/image/pxe_image.c | 2 +- src/arch/x86/include/realmode.h | 4 ++-- src/arch/x86/interface/pxe/pxe_preboot.c | 5 ++--- src/arch/x86/interface/pxe/pxe_tftp.c | 12 +++++------- src/arch/x86/interface/pxe/pxe_udp.c | 9 ++++----- src/core/cachedhcp.c | 4 ++-- src/core/dma.c | 2 +- src/core/fdt.c | 6 +++--- src/drivers/infiniband/arbel.c | 2 +- src/drivers/infiniband/arbel.h | 5 ++--- src/drivers/infiniband/golan.c | 12 ++++++------ src/drivers/infiniband/golan.h | 2 +- src/drivers/infiniband/hermon.c | 2 +- src/drivers/infiniband/hermon.h | 5 ++--- src/drivers/net/efi/nii.c | 2 +- src/drivers/net/netvsc.c | 2 +- src/drivers/net/netvsc.h | 2 +- src/drivers/usb/xhci.h | 3 +-- src/image/segment.c | 2 +- src/include/ipxe/cachedhcp.h | 3 +-- src/include/ipxe/linux_sysfs.h | 4 +--- src/include/ipxe/memblock.h | 3 +-- src/include/ipxe/segment.h | 4 ++-- src/include/ipxe/vmbus.h | 3 +-- src/interface/efi/efi_block.c | 3 +-- src/interface/efi/efi_bofm.c | 3 +-- src/interface/efi/efi_cachedhcp.c | 10 ++++------ src/interface/efi/efi_file.c | 17 +++++++---------- src/interface/hyperv/vmbus.c | 4 ++-- src/interface/linux/linux_acpi.c | 1 + src/interface/linux/linux_smbios.c | 1 + src/interface/linux/linux_sysfs.c | 6 +++--- src/tests/bofm_test.c | 5 ++--- 34 files changed, 69 insertions(+), 86 deletions(-) (limited to 'src/tests') diff --git a/src/arch/x86/core/vram_settings.c b/src/arch/x86/core/vram_settings.c index ceeada467..a97a463fe 100644 --- a/src/arch/x86/core/vram_settings.c +++ b/src/arch/x86/core/vram_settings.c @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include #include @@ -47,12 +48,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @ret len Length of setting data, or negative error */ static int vram_fetch ( void *data, size_t len ) { - userptr_t vram = phys_to_virt ( VRAM_BASE ); + const void *vram = phys_to_virt ( VRAM_BASE ); /* Copy video RAM */ if ( len > VRAM_LEN ) len = VRAM_LEN; - copy_from_user ( data, vram, 0, len ); + memcpy ( data, vram, len ); return VRAM_LEN; } diff --git a/src/arch/x86/image/pxe_image.c b/src/arch/x86/image/pxe_image.c index 5472ea594..9f8044fa1 100644 --- a/src/arch/x86/image/pxe_image.c +++ b/src/arch/x86/image/pxe_image.c @@ -54,7 +54,7 @@ const char *pxe_cmdline; * @ret rc Return status code */ static int pxe_exec ( struct image *image ) { - userptr_t buffer = real_to_virt ( 0, 0x7c00 ); + void *buffer = real_to_virt ( 0, 0x7c00 ); struct net_device *netdev; int rc; diff --git a/src/arch/x86/include/realmode.h b/src/arch/x86/include/realmode.h index 0017b42c0..75f7d16e7 100644 --- a/src/arch/x86/include/realmode.h +++ b/src/arch/x86/include/realmode.h @@ -87,7 +87,7 @@ real_to_virt ( unsigned int segment, unsigned int offset ) { static inline __always_inline void copy_to_real ( unsigned int dest_seg, unsigned int dest_off, void *src, size_t n ) { - copy_to_user ( real_to_virt ( dest_seg, dest_off ), 0, src, n ); + memcpy ( real_to_virt ( dest_seg, dest_off ), src, n ); } /** @@ -101,7 +101,7 @@ copy_to_real ( unsigned int dest_seg, unsigned int dest_off, static inline __always_inline void copy_from_real ( void *dest, unsigned int src_seg, unsigned int src_off, size_t n ) { - copy_from_user ( dest, real_to_virt ( src_seg, src_off ), 0, n ); + memcpy ( dest, real_to_virt ( src_seg, src_off ), n ); } /** diff --git a/src/arch/x86/interface/pxe/pxe_preboot.c b/src/arch/x86/interface/pxe/pxe_preboot.c index 727d8e1ea..77dcf66e7 100644 --- a/src/arch/x86/interface/pxe/pxe_preboot.c +++ b/src/arch/x86/interface/pxe/pxe_preboot.c @@ -33,7 +33,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include #include @@ -184,7 +183,7 @@ pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO *get_cached_info ) { union pxe_cached_info *info; unsigned int idx; size_t len; - userptr_t buffer; + void *buffer; DBGC ( &pxe_netdev, "PXENV_GET_CACHED_INFO %s to %04x:%04x+%x", pxenv_get_cached_info_name ( get_cached_info->PacketType ), @@ -245,7 +244,7 @@ pxenv_get_cached_info ( struct s_PXENV_GET_CACHED_INFO *get_cached_info ) { DBGC ( &pxe_netdev, " buffer may be too short" ); buffer = real_to_virt ( get_cached_info->Buffer.segment, get_cached_info->Buffer.offset ); - copy_to_user ( buffer, 0, info, len ); + memcpy ( buffer, info, len ); get_cached_info->BufferSize = len; } diff --git a/src/arch/x86/interface/pxe/pxe_tftp.c b/src/arch/x86/interface/pxe/pxe_tftp.c index 073414dce..aa675fd13 100644 --- a/src/arch/x86/interface/pxe/pxe_tftp.c +++ b/src/arch/x86/interface/pxe/pxe_tftp.c @@ -33,7 +33,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include #include @@ -49,7 +48,7 @@ struct pxe_tftp_connection { /** Data transfer interface */ struct interface xfer; /** Data buffer */ - userptr_t buffer; + void *buffer; /** Size of data buffer */ size_t size; /** Starting offset of data buffer */ @@ -121,9 +120,8 @@ static int pxe_tftp_xfer_deliver ( struct pxe_tftp_connection *pxe_tftp, ( pxe_tftp->start + pxe_tftp->size ) ); rc = -ENOBUFS; } else { - copy_to_user ( pxe_tftp->buffer, - ( pxe_tftp->offset - pxe_tftp->start ), - iobuf->data, len ); + memcpy ( ( pxe_tftp->buffer + pxe_tftp->offset - + pxe_tftp->start ), iobuf->data, len ); } /* Calculate new buffer position */ @@ -385,7 +383,7 @@ static PXENV_EXIT_t pxenv_tftp_read ( struct s_PXENV_TFTP_READ *tftp_read ) { while ( ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) && ( pxe_tftp.offset == pxe_tftp.start ) ) step(); - pxe_tftp.buffer = UNULL; + pxe_tftp.buffer = NULL; tftp_read->BufferSize = ( pxe_tftp.offset - pxe_tftp.start ); tftp_read->PacketNumber = ++pxe_tftp.blkidx; @@ -496,7 +494,7 @@ PXENV_EXIT_t pxenv_tftp_read_file ( struct s_PXENV_TFTP_READ_FILE pxe_tftp.size = tftp_read_file->BufferSize; while ( ( rc = pxe_tftp.rc ) == -EINPROGRESS ) step(); - pxe_tftp.buffer = UNULL; + pxe_tftp.buffer = NULL; tftp_read_file->BufferSize = pxe_tftp.max_offset; /* Close TFTP file */ diff --git a/src/arch/x86/interface/pxe/pxe_udp.c b/src/arch/x86/interface/pxe/pxe_udp.c index 47abb7df4..61c858dde 100644 --- a/src/arch/x86/interface/pxe/pxe_udp.c +++ b/src/arch/x86/interface/pxe/pxe_udp.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -296,7 +295,7 @@ pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) { }; size_t len; struct io_buffer *iobuf; - userptr_t buffer; + const void *buffer; int rc; DBG ( "PXENV_UDP_WRITE" ); @@ -330,7 +329,7 @@ pxenv_udp_write ( struct s_PXENV_UDP_WRITE *pxenv_udp_write ) { } buffer = real_to_virt ( pxenv_udp_write->buffer.segment, pxenv_udp_write->buffer.offset ); - copy_from_user ( iob_put ( iobuf, len ), buffer, 0, len ); + memcpy ( iob_put ( iobuf, len ), buffer, len ); DBG ( " %04x:%04x+%x %d->%s:%d\n", pxenv_udp_write->buffer.segment, pxenv_udp_write->buffer.offset, pxenv_udp_write->buffer_size, @@ -400,7 +399,7 @@ static PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) { struct pxe_udp_pseudo_header *pshdr; uint16_t d_port_wanted = pxenv_udp_read->d_port; uint16_t d_port; - userptr_t buffer; + void *buffer; size_t len; /* Try receiving a packet, if the queue is empty */ @@ -443,7 +442,7 @@ static PXENV_EXIT_t pxenv_udp_read ( struct s_PXENV_UDP_READ *pxenv_udp_read ) { len = iob_len ( iobuf ); if ( len > pxenv_udp_read->buffer_size ) len = pxenv_udp_read->buffer_size; - copy_to_user ( buffer, 0, iobuf->data, len ); + memcpy ( buffer, iobuf->data, len ); pxenv_udp_read->buffer_size = len; /* Fill in source/dest information */ diff --git a/src/core/cachedhcp.c b/src/core/cachedhcp.c index 07589f0b8..0d400db16 100644 --- a/src/core/cachedhcp.c +++ b/src/core/cachedhcp.c @@ -198,7 +198,7 @@ static int cachedhcp_apply ( struct cached_dhcp_packet *cache, * @ret rc Return status code */ int cachedhcp_record ( struct cached_dhcp_packet *cache, unsigned int vlan, - userptr_t data, size_t max_len ) { + const void *data, size_t max_len ) { struct dhcp_packet *dhcppkt; struct dhcp_packet *tmp; struct dhcphdr *dhcphdr; @@ -216,7 +216,7 @@ int cachedhcp_record ( struct cached_dhcp_packet *cache, unsigned int vlan, return -ENOMEM; } dhcphdr = ( ( ( void * ) dhcppkt ) + sizeof ( *dhcppkt ) ); - copy_from_user ( dhcphdr, data, 0, max_len ); + memcpy ( dhcphdr, data, max_len ); dhcppkt_init ( dhcppkt, dhcphdr, max_len ); /* Shrink packet to required length. If reallocation fails, diff --git a/src/core/dma.c b/src/core/dma.c index 1f3c1d8a6..cf4b20379 100644 --- a/src/core/dma.c +++ b/src/core/dma.c @@ -136,7 +136,7 @@ static void * dma_op_umalloc ( struct dma_device *dma, struct dma_operations *op = dma->op; if ( ! op ) - return UNULL; + return NULL; return op->umalloc ( dma, map, len, align ); } diff --git a/src/core/fdt.c b/src/core/fdt.c index 4c709b342..7c7127aed 100644 --- a/src/core/fdt.c +++ b/src/core/fdt.c @@ -1037,7 +1037,7 @@ static int fdt_urealloc ( struct fdt *fdt, size_t len ) { assert ( len >= fdt->used ); /* Attempt reallocation */ - new = urealloc ( virt_to_user ( fdt->raw ), len ); + new = urealloc ( fdt->raw, len ); if ( ! new ) { DBGC ( fdt, "FDT could not reallocate from +%#04zx to " "+%#04zx\n", fdt->len, len ); @@ -1129,7 +1129,7 @@ int fdt_create ( struct fdt_header **hdr, const char *cmdline ) { return 0; err_bootargs: - ufree ( virt_to_user ( fdt.raw ) ); + ufree ( fdt.raw ); err_alloc: err_image: return rc; @@ -1143,7 +1143,7 @@ int fdt_create ( struct fdt_header **hdr, const char *cmdline ) { void fdt_remove ( struct fdt_header *hdr ) { /* Free modifiable copy */ - ufree ( virt_to_user ( hdr ) ); + ufree ( hdr ); } /* Drag in objects via fdt_describe() */ diff --git a/src/drivers/infiniband/arbel.c b/src/drivers/infiniband/arbel.c index 4cb4167e0..0789ea593 100644 --- a/src/drivers/infiniband/arbel.c +++ b/src/drivers/infiniband/arbel.c @@ -2119,7 +2119,7 @@ static void arbel_stop_firmware ( struct arbel *arbel ) { DBGC ( arbel, "Arbel %p FATAL could not stop firmware: %s\n", arbel, strerror ( rc ) ); /* Leak memory and return; at least we avoid corruption */ - arbel->firmware_area = UNULL; + arbel->firmware_area = NULL; return; } } diff --git a/src/drivers/infiniband/arbel.h b/src/drivers/infiniband/arbel.h index 8a5a996a3..a31e59934 100644 --- a/src/drivers/infiniband/arbel.h +++ b/src/drivers/infiniband/arbel.h @@ -10,7 +10,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include -#include #include #include "mlx_bitops.h" #include "MT25218_PRM.h" @@ -492,7 +491,7 @@ struct arbel { * final teardown, in order to avoid memory map changes at * runtime. */ - userptr_t firmware_area; + void *firmware_area; /** ICM size */ size_t icm_len; /** ICM AUX size */ @@ -503,7 +502,7 @@ struct arbel { * final teardown, in order to avoid memory map changes at * runtime. */ - userptr_t icm; + void *icm; /** Offset within ICM of doorbell records */ size_t db_rec_offset; /** Doorbell records */ diff --git a/src/drivers/infiniband/golan.c b/src/drivers/infiniband/golan.c index a33bad9ff..ffa78fabf 100755 --- a/src/drivers/infiniband/golan.c +++ b/src/drivers/infiniband/golan.c @@ -52,7 +52,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); struct golan_page { struct list_head list; - userptr_t addr; + void *addr; }; static void golan_free_fw_areas ( struct golan *golan ) { @@ -61,7 +61,7 @@ static void golan_free_fw_areas ( struct golan *golan ) { for (i = 0; i < GOLAN_FW_AREAS_NUM; i++) { if ( golan->fw_areas[i].area ) { ufree ( golan->fw_areas[i].area ); - golan->fw_areas[i].area = UNULL; + golan->fw_areas[i].area = NULL; } } } @@ -75,7 +75,7 @@ static int golan_init_fw_areas ( struct golan *golan ) { } for (i = 0; i < GOLAN_FW_AREAS_NUM; i++) - golan->fw_areas[i].area = UNULL; + golan->fw_areas[i].area = NULL; return rc; @@ -448,12 +448,12 @@ static inline int golan_provide_pages ( struct golan *golan , uint32_t pages int size_ibox = 0; int size_obox = 0; int rc = 0; - userptr_t next_page_addr = UNULL; + void *next_page_addr = NULL; DBGC(golan, "%s\n", __FUNCTION__); if ( ! fw_area->area ) { fw_area->area = umalloc ( GOLAN_PAGE_SIZE * pages ); - if ( fw_area->area == UNULL ) { + if ( fw_area->area == NULL ) { rc = -ENOMEM; DBGC (golan ,"Failed to allocated %d pages \n",pages); goto err_golan_alloc_fw_area; @@ -467,7 +467,7 @@ static inline int golan_provide_pages ( struct golan *golan , uint32_t pages unsigned i, j; struct golan_cmd_layout *cmd; struct golan_manage_pages_inbox *in; - userptr_t addr = 0; + void *addr = NULL; mailbox = GET_INBOX(golan, MEM_MBOX); size_ibox = sizeof(struct golan_manage_pages_inbox) + (pas_num * GOLAN_PAS_SIZE); diff --git a/src/drivers/infiniband/golan.h b/src/drivers/infiniband/golan.h index f7da1e960..8122f8d38 100755 --- a/src/drivers/infiniband/golan.h +++ b/src/drivers/infiniband/golan.h @@ -121,7 +121,7 @@ struct golan_firmware_area { * final teardown, in order to avoid memory map changes at * runtime. */ - userptr_t area; + void *area; }; /* Queue Pair */ #define GOLAN_SEND_WQE_BB_SIZE 64 diff --git a/src/drivers/infiniband/hermon.c b/src/drivers/infiniband/hermon.c index 3138d8bfb..d25f4f011 100644 --- a/src/drivers/infiniband/hermon.c +++ b/src/drivers/infiniband/hermon.c @@ -2422,7 +2422,7 @@ static void hermon_stop_firmware ( struct hermon *hermon ) { DBGC ( hermon, "Hermon %p FATAL could not stop firmware: %s\n", hermon, strerror ( rc ) ); /* Leak memory and return; at least we avoid corruption */ - hermon->firmware_area = UNULL; + hermon->firmware_area = NULL; return; } } diff --git a/src/drivers/infiniband/hermon.h b/src/drivers/infiniband/hermon.h index a952bbd81..be79ff9d0 100644 --- a/src/drivers/infiniband/hermon.h +++ b/src/drivers/infiniband/hermon.h @@ -10,7 +10,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include -#include #include #include #include @@ -887,7 +886,7 @@ struct hermon { * final teardown, in order to avoid memory map changes at * runtime. */ - userptr_t firmware_area; + void *firmware_area; /** ICM map */ struct hermon_icm_map icm_map[HERMON_ICM_NUM_REGIONS]; /** ICM size */ @@ -900,7 +899,7 @@ struct hermon { * final teardown, in order to avoid memory map changes at * runtime. */ - userptr_t icm; + void *icm; /** Event queue */ struct hermon_event_queue eq; diff --git a/src/drivers/net/efi/nii.c b/src/drivers/net/efi/nii.c index 6381fb2dd..c60d4ca18 100644 --- a/src/drivers/net/efi/nii.c +++ b/src/drivers/net/efi/nii.c @@ -177,7 +177,7 @@ struct nii_nic { size_t mtu; /** Hardware transmit/receive buffer */ - userptr_t buffer; + void *buffer; /** Hardware transmit/receive buffer length */ size_t buffer_len; diff --git a/src/drivers/net/netvsc.c b/src/drivers/net/netvsc.c index 5be52fb8e..4bdf7b517 100644 --- a/src/drivers/net/netvsc.c +++ b/src/drivers/net/netvsc.c @@ -622,7 +622,7 @@ static int netvsc_buffer_copy ( struct vmbus_xfer_pages *pages, void *data, return -ERANGE; /* Copy data from buffer */ - copy_from_user ( data, buffer->data, offset, len ); + memcpy ( data, ( buffer->data + offset ), len ); return 0; } diff --git a/src/drivers/net/netvsc.h b/src/drivers/net/netvsc.h index 93192357f..41db49af7 100644 --- a/src/drivers/net/netvsc.h +++ b/src/drivers/net/netvsc.h @@ -305,7 +305,7 @@ struct netvsc_buffer { /** Buffer length */ size_t len; /** Buffer */ - userptr_t data; + void *data; /** GPADL ID */ unsigned int gpadl; }; diff --git a/src/drivers/usb/xhci.h b/src/drivers/usb/xhci.h index a3c8888af..22bc115c2 100644 --- a/src/drivers/usb/xhci.h +++ b/src/drivers/usb/xhci.h @@ -11,7 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -#include #include /** Minimum alignment required for data structures @@ -1054,7 +1053,7 @@ struct xhci_scratchpad { /** Number of page-sized scratchpad buffers */ unsigned int count; /** Scratchpad buffer area */ - userptr_t buffer; + void *buffer; /** Buffer DMA mapping */ struct dma_mapping buffer_map; /** Scratchpad array */ diff --git a/src/image/segment.c b/src/image/segment.c index ebc2b703d..2cb637dc2 100644 --- a/src/image/segment.c +++ b/src/image/segment.c @@ -57,7 +57,7 @@ struct errortab segment_errors[] __errortab = { * @v memsz Size of the segment * @ret rc Return status code */ -int prep_segment ( userptr_t segment, size_t filesz, size_t memsz ) { +int prep_segment ( void *segment, size_t filesz, size_t memsz ) { struct memory_map memmap; physaddr_t start = virt_to_phys ( segment ); physaddr_t mid = ( start + filesz ); diff --git a/src/include/ipxe/cachedhcp.h b/src/include/ipxe/cachedhcp.h index 8ebee3b7b..5b19bc59e 100644 --- a/src/include/ipxe/cachedhcp.h +++ b/src/include/ipxe/cachedhcp.h @@ -10,7 +10,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include -#include struct net_device; struct cached_dhcp_packet; @@ -20,7 +19,7 @@ extern struct cached_dhcp_packet cached_proxydhcp; extern struct cached_dhcp_packet cached_pxebs; extern int cachedhcp_record ( struct cached_dhcp_packet *cache, - unsigned int vlan, userptr_t data, + unsigned int vlan, const void *data, size_t max_len ); extern void cachedhcp_recycle ( struct net_device *netdev ); diff --git a/src/include/ipxe/linux_sysfs.h b/src/include/ipxe/linux_sysfs.h index d97b649c0..fbe1e6e8a 100644 --- a/src/include/ipxe/linux_sysfs.h +++ b/src/include/ipxe/linux_sysfs.h @@ -9,8 +9,6 @@ FILE_LICENCE ( GPL2_OR_LATER ); -#include - -extern int linux_sysfs_read ( const char *filename, userptr_t *data ); +extern int linux_sysfs_read ( const char *filename, void **data ); #endif /* _IPXE_LINUX_SYSFS_H */ diff --git a/src/include/ipxe/memblock.h b/src/include/ipxe/memblock.h index 2bb38c460..4b6c64156 100644 --- a/src/include/ipxe/memblock.h +++ b/src/include/ipxe/memblock.h @@ -10,8 +10,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include -#include -extern size_t largest_memblock ( userptr_t *start ); +extern size_t largest_memblock ( void **start ); #endif /* _IPXE_MEMBLOCK_H */ diff --git a/src/include/ipxe/segment.h b/src/include/ipxe/segment.h index 9d5ecbd9b..b37c93c93 100644 --- a/src/include/ipxe/segment.h +++ b/src/include/ipxe/segment.h @@ -10,8 +10,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); -#include +#include -extern int prep_segment ( userptr_t segment, size_t filesz, size_t memsz ); +extern int prep_segment ( void *segment, size_t filesz, size_t memsz ); #endif /* _IPXE_SEGMENT_H */ diff --git a/src/include/ipxe/vmbus.h b/src/include/ipxe/vmbus.h index 682441857..5eee230fe 100644 --- a/src/include/ipxe/vmbus.h +++ b/src/include/ipxe/vmbus.h @@ -13,7 +13,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include @@ -634,7 +633,7 @@ vmbus_gpadl_is_obsolete ( unsigned int gpadl ) { return ( gpadl <= vmbus_obsolete_gpadl ); } -extern int vmbus_establish_gpadl ( struct vmbus_device *vmdev, userptr_t data, +extern int vmbus_establish_gpadl ( struct vmbus_device *vmdev, void *data, size_t len ); extern int vmbus_gpadl_teardown ( struct vmbus_device *vmdev, unsigned int gpadl ); diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c index 5165bd804..94e2aae06 100644 --- a/src/interface/efi/efi_block.c +++ b/src/interface/efi/efi_block.c @@ -110,8 +110,7 @@ static int efi_block_rw ( struct san_device *sandev, uint64_t lba, } /* Read from / write to block device */ - if ( ( rc = sandev_rw ( sandev, lba, count, - virt_to_user ( data ) ) ) != 0 ) { + if ( ( rc = sandev_rw ( sandev, lba, count, data ) ) != 0 ) { DBGC ( sandev->drive, "EFIBLK %#02x I/O failed: %s\n", sandev->drive, strerror ( rc ) ); return rc; diff --git a/src/interface/efi/efi_bofm.c b/src/interface/efi/efi_bofm.c index b64770d8a..7d1d3619f 100644 --- a/src/interface/efi/efi_bofm.c +++ b/src/interface/efi/efi_bofm.c @@ -284,8 +284,7 @@ static int efi_bofm_start ( struct efi_device *efidev ) { efi_handle_name ( device ) ); DBGC2_HD ( device, bofmtab2, bofmtab2->Parameters.Length ); } - bofmrc = bofm ( virt_to_user ( bofmtab2 ? bofmtab2 : bofmtab ), - &efipci.pci ); + bofmrc = bofm ( ( bofmtab2 ? bofmtab2 : bofmtab ), &efipci.pci ); DBGC ( device, "EFIBOFM %s status %08x\n", efi_handle_name ( device ), bofmrc ); DBGC2 ( device, "EFIBOFM %s version 1 after processing:\n", diff --git a/src/interface/efi/efi_cachedhcp.c b/src/interface/efi/efi_cachedhcp.c index eb41a8e43..6bba4173a 100644 --- a/src/interface/efi/efi_cachedhcp.c +++ b/src/interface/efi/efi_cachedhcp.c @@ -72,8 +72,7 @@ int efi_cachedhcp_record ( EFI_HANDLE device, /* Record DHCPACK, if present */ if ( mode->DhcpAckReceived && - ( ( rc = cachedhcp_record ( &cached_dhcpack, vlan, - virt_to_user ( &mode->DhcpAck ), + ( ( rc = cachedhcp_record ( &cached_dhcpack, vlan, &mode->DhcpAck, sizeof ( mode->DhcpAck ) ) ) != 0 ) ) { DBGC ( device, "EFI %s could not record DHCPACK: %s\n", efi_handle_name ( device ), strerror ( rc ) ); @@ -83,7 +82,7 @@ int efi_cachedhcp_record ( EFI_HANDLE device, /* Record ProxyDHCPOFFER, if present */ if ( mode->ProxyOfferReceived && ( ( rc = cachedhcp_record ( &cached_proxydhcp, vlan, - virt_to_user ( &mode->ProxyOffer ), + &mode->ProxyOffer, sizeof ( mode->ProxyOffer ) ) ) != 0)){ DBGC ( device, "EFI %s could not record ProxyDHCPOFFER: %s\n", efi_handle_name ( device ), strerror ( rc ) ); @@ -92,9 +91,8 @@ int efi_cachedhcp_record ( EFI_HANDLE device, /* Record PxeBSACK, if present */ if ( mode->PxeReplyReceived && - ( ( rc = cachedhcp_record ( &cached_pxebs, vlan, - virt_to_user ( &mode->PxeReply ), - sizeof ( mode->PxeReply ) ) ) != 0)){ + ( ( rc = cachedhcp_record ( &cached_pxebs, vlan, &mode->PxeReply, + sizeof ( mode->PxeReply ) ) ) != 0 )){ DBGC ( device, "EFI %s could not record PXEBSACK: %s\n", efi_handle_name ( device ), strerror ( rc ) ); return rc; diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c index b7b97aee7..79330641d 100644 --- a/src/interface/efi/efi_file.c +++ b/src/interface/efi/efi_file.c @@ -177,12 +177,12 @@ static size_t efi_file_len ( struct efi_file *file ) { * Read chunk of EFI file * * @v reader EFI file reader - * @v data Input data, or UNULL to zero-fill + * @v data Input data, or NULL to zero-fill * @v len Length of input data * @ret len Length of output data */ static size_t efi_file_read_chunk ( struct efi_file_reader *reader, - userptr_t data, size_t len ) { + const void *data, size_t len ) { struct efi_file *file = reader->file; size_t offset; @@ -203,7 +203,7 @@ static size_t efi_file_read_chunk ( struct efi_file_reader *reader, /* Copy or zero output data */ if ( data ) { - copy_from_user ( reader->data, data, offset, len ); + memcpy ( reader->data, ( data + offset ), len ); } else { memset ( reader->data, 0, len ); } @@ -262,7 +262,7 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) { efi_file_name ( file ), reader->pos, ( reader->pos + pad_len ) ); } - len += efi_file_read_chunk ( reader, UNULL, pad_len ); + len += efi_file_read_chunk ( reader, NULL, pad_len ); /* Read CPIO header(s), if applicable */ name = cpio_name ( image ); @@ -274,13 +274,10 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) { efi_file_name ( file ), reader->pos, ( reader->pos + cpio_len + pad_len ), image->name ); - len += efi_file_read_chunk ( reader, - virt_to_user ( &cpio ), + len += efi_file_read_chunk ( reader, &cpio, sizeof ( cpio ) ); - len += efi_file_read_chunk ( reader, - virt_to_user ( name ), - name_len ); - len += efi_file_read_chunk ( reader, UNULL, pad_len ); + len += efi_file_read_chunk ( reader, name, name_len ); + len += efi_file_read_chunk ( reader, NULL, pad_len ); } /* Read file data */ diff --git a/src/interface/hyperv/vmbus.c b/src/interface/hyperv/vmbus.c index 49ccf69c8..1c44cab5e 100644 --- a/src/interface/hyperv/vmbus.c +++ b/src/interface/hyperv/vmbus.c @@ -273,7 +273,7 @@ static int vmbus_negotiate_version ( struct hv_hypervisor *hv ) { * @v len Length of data buffer * @ret gpadl GPADL ID, or negative error */ -int vmbus_establish_gpadl ( struct vmbus_device *vmdev, userptr_t data, +int vmbus_establish_gpadl ( struct vmbus_device *vmdev, void *data, size_t len ) { struct hv_hypervisor *hv = vmdev->hv; struct vmbus *vmbus = hv->vmbus; @@ -442,7 +442,7 @@ int vmbus_open ( struct vmbus_device *vmdev, memset ( ring, 0, len ); /* Establish GPADL for ring buffer */ - gpadl = vmbus_establish_gpadl ( vmdev, virt_to_user ( ring ), len ); + gpadl = vmbus_establish_gpadl ( vmdev, ring, len ); if ( gpadl < 0 ) { rc = gpadl; goto err_establish; diff --git a/src/interface/linux/linux_acpi.c b/src/interface/linux/linux_acpi.c index a2a8bf12e..21a2e27cc 100644 --- a/src/interface/linux/linux_acpi.c +++ b/src/interface/linux/linux_acpi.c @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +#include #include #include #include diff --git a/src/interface/linux/linux_smbios.c b/src/interface/linux/linux_smbios.c index a12c936ed..1450fcf1b 100644 --- a/src/interface/linux/linux_smbios.c +++ b/src/interface/linux/linux_smbios.c @@ -19,6 +19,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include #include #include #include diff --git a/src/interface/linux/linux_sysfs.c b/src/interface/linux/linux_sysfs.c index cbb23d81d..321824ba9 100644 --- a/src/interface/linux/linux_sysfs.c +++ b/src/interface/linux/linux_sysfs.c @@ -42,8 +42,8 @@ FILE_LICENCE ( GPL2_OR_LATER ); * @v data Data to fill in * @ret len Length read, or negative error */ -int linux_sysfs_read ( const char *filename, userptr_t *data ) { - userptr_t tmp; +int linux_sysfs_read ( const char *filename, void **data ) { + void *tmp; ssize_t read; size_t len; int fd; @@ -59,7 +59,7 @@ int linux_sysfs_read ( const char *filename, userptr_t *data ) { } /* Read file */ - for ( *data = UNULL, len = 0 ; ; len += read ) { + for ( *data = NULL, len = 0 ; ; len += read ) { /* (Re)allocate space */ tmp = urealloc ( *data, ( len + LINUX_SYSFS_BLKSIZE ) ); diff --git a/src/tests/bofm_test.c b/src/tests/bofm_test.c index 829924887..dbef1eb90 100644 --- a/src/tests/bofm_test.c +++ b/src/tests/bofm_test.c @@ -26,7 +26,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include #include @@ -111,7 +110,7 @@ void bofm_test ( struct pci_device *pci ) { printf ( "BOFMTEST performing harvest\n" ); bofmtab_harvest.en.busdevfn = pci->busdevfn; DBG_HDA ( 0, &bofmtab_harvest, sizeof ( bofmtab_harvest ) ); - bofmrc = bofm ( virt_to_user ( &bofmtab_harvest ), pci ); + bofmrc = bofm ( &bofmtab_harvest, pci ); printf ( "BOFMTEST harvest result %08x\n", bofmrc ); if ( bofmtab_harvest.en.options & BOFM_EN_HVST ) { printf ( "BOFMTEST harvested MAC address %s\n", @@ -125,7 +124,7 @@ void bofm_test ( struct pci_device *pci ) { printf ( "BOFMTEST performing update\n" ); bofmtab_update.en.busdevfn = pci->busdevfn; DBG_HDA ( 0, &bofmtab_update, sizeof ( bofmtab_update ) ); - bofmrc = bofm ( virt_to_user ( &bofmtab_update ), pci ); + bofmrc = bofm ( &bofmtab_update, pci ); printf ( "BOFMTEST update result %08x\n", bofmrc ); if ( bofmtab_update.en.options & BOFM_EN_CSM_SUCCESS ) { printf ( "BOFMTEST updated MAC address to %s\n", -- cgit v1.2.3-55-g7522 From 54c4217bdd403c85af03c944b1b5d18a0655da5c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 29 Apr 2025 09:17:14 +0100 Subject: [peerdist] Remove userptr_t from PeerDist content information parsing Signed-off-by: Michael Brown --- src/include/ipxe/pccrc.h | 5 ++--- src/net/pccrc.c | 5 +++-- src/tests/pccrc_test.c | 6 ++---- 3 files changed, 7 insertions(+), 9 deletions(-) (limited to 'src/tests') diff --git a/src/include/ipxe/pccrc.h b/src/include/ipxe/pccrc.h index 7f0963428..bec2b271a 100644 --- a/src/include/ipxe/pccrc.h +++ b/src/include/ipxe/pccrc.h @@ -11,7 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -#include #include /****************************************************************************** @@ -300,7 +299,7 @@ struct peerdist_info_v2_segment { /** Raw content information */ struct peerdist_raw { /** Data buffer */ - userptr_t data; + const void *data; /** Length of data buffer */ size_t len; }; @@ -435,7 +434,7 @@ struct peerdist_info_operations { extern struct digest_algorithm sha512_trunc_algorithm; -extern int peerdist_info ( userptr_t data, size_t len, +extern int peerdist_info ( const void *data, size_t len, struct peerdist_info *info ); extern int peerdist_info_segment ( const struct peerdist_info *info, struct peerdist_info_segment *segment, diff --git a/src/net/pccrc.c b/src/net/pccrc.c index a94bc0e11..29adc4b16 100644 --- a/src/net/pccrc.c +++ b/src/net/pccrc.c @@ -88,7 +88,7 @@ static int peerdist_info_get ( const struct peerdist_info *info, void *data, } /* Copy data */ - copy_from_user ( data, info->raw.data, offset, len ); + memcpy ( data, ( info->raw.data + offset ), len ); return 0; } @@ -667,7 +667,8 @@ static struct peerdist_info_operations peerdist_info_v2_operations = { * @v info Content information to fill in * @ret rc Return status code */ -int peerdist_info ( userptr_t data, size_t len, struct peerdist_info *info ) { +int peerdist_info ( const void *data, size_t len, + struct peerdist_info *info ) { union peerdist_info_version version; int rc; diff --git a/src/tests/pccrc_test.c b/src/tests/pccrc_test.c index e69493202..f3f38d360 100644 --- a/src/tests/pccrc_test.c +++ b/src/tests/pccrc_test.c @@ -35,7 +35,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include #include @@ -362,11 +361,10 @@ static void peerdist_info_okx ( struct peerdist_info_test *test, const char *file, unsigned int line ) { /* Parse content information */ - okx ( peerdist_info ( virt_to_user ( test->data ), test->len, - info ) == 0, file, line ); + okx ( peerdist_info ( test->data, test->len, info ) == 0, file, line ); /* Verify content information */ - okx ( info->raw.data == virt_to_user ( test->data ), file, line ); + okx ( info->raw.data == test->data, file, line ); okx ( info->raw.len == test->len, file, line ); okx ( info->digest == test->expected_digest, file, line ); okx ( info->digestsize == test->expected_digestsize, file, line ); -- cgit v1.2.3-55-g7522 From 08007238456b7349a16c67b2cc76a10368734fea Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 29 Apr 2025 13:39:12 +0100 Subject: [bofm] Allow BOFM tests to be run without a BOFM-capable device driver The BOFM tests are not part of the standard unit test suite, since they are designed to allow for exercising real BOFM driver code outside of the context of a real IBM blade server. Allow for the BOFM tests to be run without a real BOFM driver, by providing a dummy driver for the specified PCI test device. Signed-off-by: Michael Brown --- src/include/ipxe/bofm.h | 3 ++ src/tests/bofm_test.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 113 insertions(+), 1 deletion(-) (limited to 'src/tests') diff --git a/src/include/ipxe/bofm.h b/src/include/ipxe/bofm.h index bc994ea8b..816effd4d 100644 --- a/src/include/ipxe/bofm.h +++ b/src/include/ipxe/bofm.h @@ -328,6 +328,9 @@ struct bofm_operations { #define __bofm_driver #endif +/** Declare a BOFM test driver */ +#define __bofm_test_driver __table_entry ( BOFM_DRIVERS, 02 ) + /** * Initialise BOFM device * diff --git a/src/tests/bofm_test.c b/src/tests/bofm_test.c index dbef1eb90..6d472bc7e 100644 --- a/src/tests/bofm_test.c +++ b/src/tests/bofm_test.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include @@ -135,6 +136,109 @@ void bofm_test ( struct pci_device *pci ) { DBG_HDA ( 0, &bofmtab_update, sizeof ( bofmtab_update ) ); } +/** + * Harvest dummy Ethernet MAC + * + * @v bofm BOFM device + * @v mport Multi-port index + * @v mac MAC to fill in + * @ret rc Return status code + */ +static int bofm_dummy_harvest ( struct bofm_device *bofm, unsigned int mport, + uint8_t *mac ) { + struct { + uint16_t vendor; + uint16_t device; + uint16_t mport; + } __attribute__ (( packed )) dummy_mac; + + /* Construct dummy MAC address */ + dummy_mac.vendor = cpu_to_be16 ( bofm->pci->vendor ); + dummy_mac.device = cpu_to_be16 ( bofm->pci->device ); + dummy_mac.mport = cpu_to_be16 ( mport ); + memcpy ( mac, &dummy_mac, sizeof ( dummy_mac ) ); + printf ( "BOFMTEST mport %d constructed dummy MAC %s\n", + mport, eth_ntoa ( mac ) ); + + return 0; +} + +/** + * Update Ethernet MAC for BOFM + * + * @v bofm BOFM device + * @v mport Multi-port index + * @v mac MAC to fill in + * @ret rc Return status code + */ +static int bofm_dummy_update ( struct bofm_device *bofm __unused, + unsigned int mport, const uint8_t *mac ) { + + printf ( "BOFMTEST mport %d asked to update MAC to %s\n", + mport, eth_ntoa ( mac ) ); + return 0; +} + +/** Dummy BOFM operations */ +static struct bofm_operations bofm_dummy_operations = { + .harvest = bofm_dummy_harvest, + .update = bofm_dummy_update, +}; + +/** Dummy BOFM device */ +static struct bofm_device bofm_dummy; + +/** + * Probe dummy BOFM device + * + * @v pci PCI device + * @v id PCI ID + * @ret rc Return status code + */ +static int bofm_dummy_probe ( struct pci_device *pci ) { + int rc; + + /* Ignore probe for any other devices */ + if ( pci->busdevfn != bofm_dummy.pci->busdevfn ) + return 0; + + /* Register BOFM device */ + if ( ( rc = bofm_register ( &bofm_dummy ) ) != 0 ) + return rc; + + printf ( "BOFMTEST using dummy BOFM driver\n" ); + return 0; +} + +/** + * Remove dummy BOFM device + * + * @v pci PCI device + */ +static void bofm_dummy_remove ( struct pci_device *pci ) { + + /* Ignore removal for any other devices */ + if ( pci->busdevfn != bofm_dummy.pci->busdevfn ) + return; + + /* Unregister BOFM device */ + bofm_unregister ( &bofm_dummy ); +} + +/** Dummy BOFM driver PCI IDs */ +static struct pci_device_id bofm_dummy_ids[1] = { + { .name = "dummy" }, +}; + +/** Dummy BOFM driver */ +struct pci_driver bofm_dummy_driver __bofm_test_driver = { + .ids = bofm_dummy_ids, + .id_count = ( sizeof ( bofm_dummy_ids ) / + sizeof ( bofm_dummy_ids[0] ) ), + .probe = bofm_dummy_probe, + .remove = bofm_dummy_remove, +}; + /** * Perform BOFM test at initialisation time * @@ -148,7 +252,7 @@ static void bofm_test_init ( void ) { * bus:dev.fn address in order to perform a BOFM test at * initialisation time. */ - // busdevfn = PCI_BUSDEVFN ( , , ); + // busdevfn = PCI_BUSDEVFN ( , , , ); /* Skip test if no PCI bus:dev.fn is defined */ if ( busdevfn < 0 ) @@ -163,6 +267,11 @@ static void bofm_test_init ( void ) { return; } + /* Initialise dummy BOFM device */ + bofm_init ( &bofm_dummy, &pci, &bofm_dummy_operations ); + bofm_dummy_ids[0].vendor = pci.vendor; + bofm_dummy_ids[0].device = pci.device; + /* Perform test */ bofm_test ( &pci ); } -- cgit v1.2.3-55-g7522 From b6f9e4bab082c3b7a9b587ef64109069fba59baa Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 30 Apr 2025 15:18:34 +0100 Subject: [uaccess] Remove redundant copy_from_user() and copy_to_user() Remove the now-redundant copy_from_user() and copy_to_user() wrapper functions. Signed-off-by: Michael Brown --- src/arch/x86/core/runtime.c | 1 + src/arch/x86/drivers/xen/hvm.c | 1 + src/arch/x86/image/elfboot.c | 1 + src/arch/x86/image/initrd.c | 1 + src/arch/x86/image/multiboot.c | 1 + src/arch/x86/image/nbi.c | 1 + src/arch/x86/image/pxe_image.c | 1 + src/arch/x86/image/ucode.c | 1 + src/arch/x86/include/realmode.h | 1 + src/arch/x86/interface/pcbios/acpipwr.c | 1 + src/arch/x86/interface/pcbios/bios_cachedhcp.c | 1 + src/arch/x86/interface/pcbios/bios_reboot.c | 1 + src/arch/x86/interface/pcbios/biosint.c | 1 + src/arch/x86/interface/pcbios/hidemem.c | 1 + src/arch/x86/interface/pcbios/int13.c | 1 + src/arch/x86/interface/pcbios/memmap.c | 1 + src/arch/x86/interface/pcbios/memtop_umalloc.c | 1 + src/arch/x86/interface/pcbios/rsdp.c | 1 + src/core/blocktrans.c | 1 + src/core/cachedhcp.c | 1 + src/core/downloader.c | 1 + src/core/pixbuf.c | 1 + src/core/sanboot.c | 1 + src/drivers/bus/devtree.c | 1 + src/drivers/bus/ecam.c | 1 + src/drivers/bus/pci_settings.c | 1 + src/drivers/bus/usb_settings.c | 1 + src/drivers/infiniband/flexboot_nodnic.c | 1 + src/drivers/infiniband/linda.c | 1 + .../mlx_utils_flexboot/src/mlx_memory_priv.c | 1 + src/drivers/infiniband/qib7322.c | 1 + src/drivers/linux/slirp.c | 1 + src/drivers/net/ath/ath.h | 1 + src/drivers/net/ath/ath5k/ath5k.h | 1 + src/drivers/net/b44.c | 1 + src/drivers/net/bnxt/bnxt.c | 1 + src/drivers/net/eepro100.c | 1 + src/drivers/net/etherfabric.c | 1 + src/drivers/net/marvell/atl2_hw.c | 1 + src/drivers/net/marvell/atl_hw.c | 1 + src/drivers/net/myri10ge.c | 2 +- src/drivers/net/netvsc.c | 1 + src/drivers/net/rtl818x/rtl818x.c | 1 + src/drivers/net/sfc/efx_hunt.c | 1 + src/drivers/net/sfc/sfc_hunt.c | 1 + src/drivers/net/skge.c | 1 + src/drivers/net/sky2.c | 1 + src/drivers/net/tg3/tg3.c | 1 + src/drivers/net/tg3/tg3_hw.c | 1 + src/drivers/net/tg3/tg3_phy.c | 1 + src/drivers/net/vmxnet3.c | 1 + src/drivers/net/vxge/vxge_config.c | 1 + src/drivers/net/vxge/vxge_traffic.c | 1 + src/drivers/nvs/nvsvpd.c | 1 + src/drivers/usb/usbblk.c | 1 + src/hci/commands/cert_cmd.c | 1 + src/hci/commands/image_cmd.c | 1 + src/hci/commands/image_crypt_cmd.c | 1 + src/hci/commands/image_trust_cmd.c | 1 + src/hci/commands/pci_cmd.c | 1 + src/hci/commands/usb_cmd.c | 1 + src/image/der.c | 1 + src/image/efi_image.c | 1 + src/image/efi_siglist.c | 1 + src/image/elf.c | 1 + src/image/pnm.c | 1 + src/image/segment.c | 1 + src/include/ipxe/dummy_pio.h | 2 ++ src/include/ipxe/iomap_virt.h | 2 ++ src/include/ipxe/uaccess.h | 27 ---------------------- src/interface/efi/efi_bofm.c | 1 + src/interface/efi/efi_cmdline.c | 1 + src/interface/efi/efi_pci.c | 1 + src/interface/xen/xenbus.c | 1 + src/net/eapol.c | 1 + src/net/fcoe.c | 1 + src/net/lldp.c | 1 + src/net/peerblk.c | 1 + src/net/peermux.c | 1 + src/net/tcp/httpblock.c | 1 + src/net/tcp/syslogs.c | 1 + src/net/udp/syslog.c | 1 + src/tests/asn1_test.c | 1 + src/tests/cpio_test.c | 1 + src/tests/pixbuf_test.c | 1 + src/tests/test.c | 1 + src/usr/imgarchive.c | 1 + src/usr/imgmgmt.c | 1 + src/usr/imgtrust.c | 1 + 89 files changed, 90 insertions(+), 28 deletions(-) (limited to 'src/tests') diff --git a/src/arch/x86/core/runtime.c b/src/arch/x86/core/runtime.c index 1fdf80497..461188d04 100644 --- a/src/arch/x86/core/runtime.c +++ b/src/arch/x86/core/runtime.c @@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include diff --git a/src/arch/x86/drivers/xen/hvm.c b/src/arch/x86/drivers/xen/hvm.c index b77cdd14c..cf41cc955 100644 --- a/src/arch/x86/drivers/xen/hvm.c +++ b/src/arch/x86/drivers/xen/hvm.c @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/arch/x86/image/elfboot.c b/src/arch/x86/image/elfboot.c index 63a3460d3..f662e366f 100644 --- a/src/arch/x86/image/elfboot.c +++ b/src/arch/x86/image/elfboot.c @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include #include #include diff --git a/src/arch/x86/image/initrd.c b/src/arch/x86/image/initrd.c index 8acdd95f7..cb4879036 100644 --- a/src/arch/x86/image/initrd.c +++ b/src/arch/x86/image/initrd.c @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include #include #include diff --git a/src/arch/x86/image/multiboot.c b/src/arch/x86/image/multiboot.c index 7c8963475..9444c4047 100644 --- a/src/arch/x86/image/multiboot.c +++ b/src/arch/x86/image/multiboot.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include +#include #include #include #include diff --git a/src/arch/x86/image/nbi.c b/src/arch/x86/image/nbi.c index 0a60283fb..0f57bdfcd 100644 --- a/src/arch/x86/image/nbi.c +++ b/src/arch/x86/image/nbi.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/src/arch/x86/image/pxe_image.c b/src/arch/x86/image/pxe_image.c index d7acd0084..3e6cf7268 100644 --- a/src/arch/x86/image/pxe_image.c +++ b/src/arch/x86/image/pxe_image.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +#include #include #include #include diff --git a/src/arch/x86/image/ucode.c b/src/arch/x86/image/ucode.c index 0ae3863cb..fd4689e00 100644 --- a/src/arch/x86/image/ucode.c +++ b/src/arch/x86/image/ucode.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/arch/x86/include/realmode.h b/src/arch/x86/include/realmode.h index 75f7d16e7..5cf644a23 100644 --- a/src/arch/x86/include/realmode.h +++ b/src/arch/x86/include/realmode.h @@ -2,6 +2,7 @@ #define REALMODE_H #include +#include #include #include diff --git a/src/arch/x86/interface/pcbios/acpipwr.c b/src/arch/x86/interface/pcbios/acpipwr.c index bff53806b..cb82ef1b4 100644 --- a/src/arch/x86/interface/pcbios/acpipwr.c +++ b/src/arch/x86/interface/pcbios/acpipwr.c @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include #include #include diff --git a/src/arch/x86/interface/pcbios/bios_cachedhcp.c b/src/arch/x86/interface/pcbios/bios_cachedhcp.c index 05d89b3b7..897858143 100644 --- a/src/arch/x86/interface/pcbios/bios_cachedhcp.c +++ b/src/arch/x86/interface/pcbios/bios_cachedhcp.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include diff --git a/src/arch/x86/interface/pcbios/bios_reboot.c b/src/arch/x86/interface/pcbios/bios_reboot.c index 463470245..c7f25405f 100644 --- a/src/arch/x86/interface/pcbios/bios_reboot.c +++ b/src/arch/x86/interface/pcbios/bios_reboot.c @@ -29,6 +29,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +#include #include #include #include diff --git a/src/arch/x86/interface/pcbios/biosint.c b/src/arch/x86/interface/pcbios/biosint.c index 667e9ed81..f5e54ede8 100644 --- a/src/arch/x86/interface/pcbios/biosint.c +++ b/src/arch/x86/interface/pcbios/biosint.c @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/src/arch/x86/interface/pcbios/hidemem.c b/src/arch/x86/interface/pcbios/hidemem.c index 1a3022c5d..6983c1f4a 100644 --- a/src/arch/x86/interface/pcbios/hidemem.c +++ b/src/arch/x86/interface/pcbios/hidemem.c @@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include #include #include diff --git a/src/arch/x86/interface/pcbios/int13.c b/src/arch/x86/interface/pcbios/int13.c index 73fdfebd3..045d78e8d 100644 --- a/src/arch/x86/interface/pcbios/int13.c +++ b/src/arch/x86/interface/pcbios/int13.c @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/arch/x86/interface/pcbios/memmap.c b/src/arch/x86/interface/pcbios/memmap.c index daae382b8..3bc1229aa 100644 --- a/src/arch/x86/interface/pcbios/memmap.c +++ b/src/arch/x86/interface/pcbios/memmap.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include diff --git a/src/arch/x86/interface/pcbios/memtop_umalloc.c b/src/arch/x86/interface/pcbios/memtop_umalloc.c index d4489fb01..bfaffc4bb 100644 --- a/src/arch/x86/interface/pcbios/memtop_umalloc.c +++ b/src/arch/x86/interface/pcbios/memtop_umalloc.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include +#include #include #include #include diff --git a/src/arch/x86/interface/pcbios/rsdp.c b/src/arch/x86/interface/pcbios/rsdp.c index 6bcf19b18..6913be552 100644 --- a/src/arch/x86/interface/pcbios/rsdp.c +++ b/src/arch/x86/interface/pcbios/rsdp.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include +#include #include #include #include diff --git a/src/core/blocktrans.c b/src/core/blocktrans.c index 362721747..b793185fe 100644 --- a/src/core/blocktrans.c +++ b/src/core/blocktrans.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include +#include #include #include #include diff --git a/src/core/cachedhcp.c b/src/core/cachedhcp.c index 0d400db16..1510f3321 100644 --- a/src/core/cachedhcp.c +++ b/src/core/cachedhcp.c @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/core/downloader.c b/src/core/downloader.c index 449761836..9950fe5e4 100644 --- a/src/core/downloader.c +++ b/src/core/downloader.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include diff --git a/src/core/pixbuf.c b/src/core/pixbuf.c index d0b80b2a9..506a28c38 100644 --- a/src/core/pixbuf.c +++ b/src/core/pixbuf.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include +#include #include #include #include diff --git a/src/core/sanboot.c b/src/core/sanboot.c index bdac813ff..e90c5ef1d 100644 --- a/src/core/sanboot.c +++ b/src/core/sanboot.c @@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/drivers/bus/devtree.c b/src/drivers/bus/devtree.c index cbd8ea8fa..654f8d14f 100644 --- a/src/drivers/bus/devtree.c +++ b/src/drivers/bus/devtree.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/drivers/bus/ecam.c b/src/drivers/bus/ecam.c index 58d513e88..35556a8d9 100644 --- a/src/drivers/bus/ecam.c +++ b/src/drivers/bus/ecam.c @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include #include #include diff --git a/src/drivers/bus/pci_settings.c b/src/drivers/bus/pci_settings.c index 98005559d..84aa76827 100644 --- a/src/drivers/bus/pci_settings.c +++ b/src/drivers/bus/pci_settings.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include diff --git a/src/drivers/bus/usb_settings.c b/src/drivers/bus/usb_settings.c index db6f94d8a..4fd190d83 100644 --- a/src/drivers/bus/usb_settings.c +++ b/src/drivers/bus/usb_settings.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include diff --git a/src/drivers/infiniband/flexboot_nodnic.c b/src/drivers/infiniband/flexboot_nodnic.c index c6e19b955..a9e6fdd71 100644 --- a/src/drivers/infiniband/flexboot_nodnic.c +++ b/src/drivers/infiniband/flexboot_nodnic.c @@ -20,6 +20,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include #include #include #include diff --git a/src/drivers/infiniband/linda.c b/src/drivers/infiniband/linda.c index 0c8a043a1..2e2b469e4 100644 --- a/src/drivers/infiniband/linda.c +++ b/src/drivers/infiniband/linda.c @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_memory_priv.c b/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_memory_priv.c index e368d459b..b35c30dee 100644 --- a/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_memory_priv.c +++ b/src/drivers/infiniband/mlx_utils_flexboot/src/mlx_memory_priv.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include "../../mlx_utils/include/private/mlx_memory_priv.h" diff --git a/src/drivers/infiniband/qib7322.c b/src/drivers/infiniband/qib7322.c index a011dafc1..a9e4566dc 100644 --- a/src/drivers/infiniband/qib7322.c +++ b/src/drivers/infiniband/qib7322.c @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/drivers/linux/slirp.c b/src/drivers/linux/slirp.c index 8341c9676..d7ab6419e 100644 --- a/src/drivers/linux/slirp.c +++ b/src/drivers/linux/slirp.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include diff --git a/src/drivers/net/ath/ath.h b/src/drivers/net/ath/ath.h index 589bb5634..21f795b70 100644 --- a/src/drivers/net/ath/ath.h +++ b/src/drivers/net/ath/ath.h @@ -23,6 +23,7 @@ FILE_LICENCE ( BSD2 ); #include +#include #include /* This block of functions are from kernel.h v3.0.1 */ diff --git a/src/drivers/net/ath/ath5k/ath5k.h b/src/drivers/net/ath/ath5k/ath5k.h index fa62e8ce5..727d41279 100644 --- a/src/drivers/net/ath/ath5k/ath5k.h +++ b/src/drivers/net/ath/ath5k/ath5k.h @@ -24,6 +24,7 @@ FILE_LICENCE ( MIT ); #include +#include #include #include #include diff --git a/src/drivers/net/b44.c b/src/drivers/net/b44.c index 30ece5574..c6ca99865 100644 --- a/src/drivers/net/b44.c +++ b/src/drivers/net/b44.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); +#include #include #include #include diff --git a/src/drivers/net/bnxt/bnxt.c b/src/drivers/net/bnxt/bnxt.c index 5de8d094e..402439eef 100644 --- a/src/drivers/net/bnxt/bnxt.c +++ b/src/drivers/net/bnxt/bnxt.c @@ -3,6 +3,7 @@ FILE_LICENCE ( GPL2_ONLY ); #include #include +#include #include #include #include diff --git a/src/drivers/net/eepro100.c b/src/drivers/net/eepro100.c index 49b00d443..318db1883 100644 --- a/src/drivers/net/eepro100.c +++ b/src/drivers/net/eepro100.c @@ -101,6 +101,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); */ #include +#include #include #include #include diff --git a/src/drivers/net/etherfabric.c b/src/drivers/net/etherfabric.c index be30b71f7..a58b71568 100644 --- a/src/drivers/net/etherfabric.c +++ b/src/drivers/net/etherfabric.c @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL_ANY ); #include #include #include +#include #include #include #include diff --git a/src/drivers/net/marvell/atl2_hw.c b/src/drivers/net/marvell/atl2_hw.c index 805820709..07822a9c2 100644 --- a/src/drivers/net/marvell/atl2_hw.c +++ b/src/drivers/net/marvell/atl2_hw.c @@ -31,6 +31,7 @@ FILE_LICENCE ( BSD2 ); +#include #include #include #include diff --git a/src/drivers/net/marvell/atl_hw.c b/src/drivers/net/marvell/atl_hw.c index e0843e6f4..fa7f2a9b8 100644 --- a/src/drivers/net/marvell/atl_hw.c +++ b/src/drivers/net/marvell/atl_hw.c @@ -31,6 +31,7 @@ FILE_LICENCE ( BSD2 ); +#include #include #include #include diff --git a/src/drivers/net/myri10ge.c b/src/drivers/net/myri10ge.c index 6d0f723f2..fb9dc01b2 100644 --- a/src/drivers/net/myri10ge.c +++ b/src/drivers/net/myri10ge.c @@ -74,7 +74,7 @@ FILE_LICENCE ( GPL2_ONLY ); */ #include - +#include #include #include #include diff --git a/src/drivers/net/netvsc.c b/src/drivers/net/netvsc.c index 4bdf7b517..9b6ee88b4 100644 --- a/src/drivers/net/netvsc.c +++ b/src/drivers/net/netvsc.c @@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * bus (VMBus). It provides a transport layer for RNDIS packets. */ +#include #include #include #include diff --git a/src/drivers/net/rtl818x/rtl818x.c b/src/drivers/net/rtl818x/rtl818x.c index 599d36fad..3bae8a797 100644 --- a/src/drivers/net/rtl818x/rtl818x.c +++ b/src/drivers/net/rtl818x/rtl818x.c @@ -20,6 +20,7 @@ FILE_LICENCE(GPL2_ONLY); #include +#include #include #include #include diff --git a/src/drivers/net/sfc/efx_hunt.c b/src/drivers/net/sfc/efx_hunt.c index abe3e8320..92c0fda62 100644 --- a/src/drivers/net/sfc/efx_hunt.c +++ b/src/drivers/net/sfc/efx_hunt.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include diff --git a/src/drivers/net/sfc/sfc_hunt.c b/src/drivers/net/sfc/sfc_hunt.c index 43ac229ab..f763fc9d0 100644 --- a/src/drivers/net/sfc/sfc_hunt.c +++ b/src/drivers/net/sfc/sfc_hunt.c @@ -19,6 +19,7 @@ ***************************************************************************/ #include #include +#include #include #include #include diff --git a/src/drivers/net/skge.c b/src/drivers/net/skge.c index cc7f0b91b..828a2a4c9 100755 --- a/src/drivers/net/skge.c +++ b/src/drivers/net/skge.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_ONLY ); #include +#include #include #include #include diff --git a/src/drivers/net/sky2.c b/src/drivers/net/sky2.c index 4f8ec3e42..db3f6aaa1 100644 --- a/src/drivers/net/sky2.c +++ b/src/drivers/net/sky2.c @@ -28,6 +28,7 @@ FILE_LICENCE ( GPL2_ONLY ); #include +#include #include #include #include diff --git a/src/drivers/net/tg3/tg3.c b/src/drivers/net/tg3/tg3.c index 05af22d61..a6736305c 100644 --- a/src/drivers/net/tg3/tg3.c +++ b/src/drivers/net/tg3/tg3.c @@ -3,6 +3,7 @@ FILE_LICENCE ( GPL2_ONLY ); #include #include +#include #include #include #include diff --git a/src/drivers/net/tg3/tg3_hw.c b/src/drivers/net/tg3/tg3_hw.c index 9a70413b6..5c9506dce 100644 --- a/src/drivers/net/tg3/tg3_hw.c +++ b/src/drivers/net/tg3/tg3_hw.c @@ -18,6 +18,7 @@ FILE_LICENCE ( GPL2_ONLY ); #include +#include #include #include #include diff --git a/src/drivers/net/tg3/tg3_phy.c b/src/drivers/net/tg3/tg3_phy.c index e88b0be0f..a2322329e 100644 --- a/src/drivers/net/tg3/tg3_phy.c +++ b/src/drivers/net/tg3/tg3_phy.c @@ -1,6 +1,7 @@ #include #include +#include #include #include #include diff --git a/src/drivers/net/vmxnet3.c b/src/drivers/net/vmxnet3.c index 3800d6b72..2cc6738f2 100644 --- a/src/drivers/net/vmxnet3.c +++ b/src/drivers/net/vmxnet3.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include diff --git a/src/drivers/net/vxge/vxge_config.c b/src/drivers/net/vxge/vxge_config.c index f4d217097..8c6ee9e96 100644 --- a/src/drivers/net/vxge/vxge_config.c +++ b/src/drivers/net/vxge/vxge_config.c @@ -16,6 +16,7 @@ FILE_LICENCE(GPL2_ONLY); #include #include +#include #include #include #include diff --git a/src/drivers/net/vxge/vxge_traffic.c b/src/drivers/net/vxge/vxge_traffic.c index dbd799015..0adaea2aa 100644 --- a/src/drivers/net/vxge/vxge_traffic.c +++ b/src/drivers/net/vxge/vxge_traffic.c @@ -15,6 +15,7 @@ FILE_LICENCE(GPL2_ONLY); #include +#include #include #include "vxge_traffic.h" diff --git a/src/drivers/nvs/nvsvpd.c b/src/drivers/nvs/nvsvpd.c index 3e88531c7..195973319 100644 --- a/src/drivers/nvs/nvsvpd.c +++ b/src/drivers/nvs/nvsvpd.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include diff --git a/src/drivers/usb/usbblk.c b/src/drivers/usb/usbblk.c index 39adc012f..cb377efb0 100644 --- a/src/drivers/usb/usbblk.c +++ b/src/drivers/usb/usbblk.c @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/hci/commands/cert_cmd.c b/src/hci/commands/cert_cmd.c index 24b18bf5c..75d2ccbed 100644 --- a/src/hci/commands/cert_cmd.c +++ b/src/hci/commands/cert_cmd.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include diff --git a/src/hci/commands/image_cmd.c b/src/hci/commands/image_cmd.c index bf97b4deb..4b42695c4 100644 --- a/src/hci/commands/image_cmd.c +++ b/src/hci/commands/image_cmd.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include diff --git a/src/hci/commands/image_crypt_cmd.c b/src/hci/commands/image_crypt_cmd.c index 26e9d79f8..4dfb5b131 100644 --- a/src/hci/commands/image_crypt_cmd.c +++ b/src/hci/commands/image_crypt_cmd.c @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/hci/commands/image_trust_cmd.c b/src/hci/commands/image_trust_cmd.c index b34378f93..9b9e3f859 100644 --- a/src/hci/commands/image_trust_cmd.c +++ b/src/hci/commands/image_trust_cmd.c @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/hci/commands/pci_cmd.c b/src/hci/commands/pci_cmd.c index 5bae66fbe..fa1fa5ece 100644 --- a/src/hci/commands/pci_cmd.c +++ b/src/hci/commands/pci_cmd.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include diff --git a/src/hci/commands/usb_cmd.c b/src/hci/commands/usb_cmd.c index d1086fd7e..4ee2f2ddb 100644 --- a/src/hci/commands/usb_cmd.c +++ b/src/hci/commands/usb_cmd.c @@ -22,6 +22,7 @@ */ #include +#include #include #include #include diff --git a/src/image/der.c b/src/image/der.c index 600e163c9..67117d43b 100644 --- a/src/image/der.c +++ b/src/image/der.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include diff --git a/src/image/efi_image.c b/src/image/efi_image.c index f71630f4a..f7ee7ff50 100644 --- a/src/image/efi_image.c +++ b/src/image/efi_image.c @@ -21,6 +21,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include +#include #include #include #include diff --git a/src/image/efi_siglist.c b/src/image/efi_siglist.c index 2bd273dbd..b264ac558 100644 --- a/src/image/efi_siglist.c +++ b/src/image/efi_siglist.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include +#include #include #include #include diff --git a/src/image/elf.c b/src/image/elf.c index 83712c3b0..97e07f37f 100644 --- a/src/image/elf.c +++ b/src/image/elf.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * common ELF-related functionality. */ +#include #include #include #include diff --git a/src/image/pnm.c b/src/image/pnm.c index 4b5020b64..489a43304 100644 --- a/src/image/pnm.c +++ b/src/image/pnm.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include +#include #include #include #include diff --git a/src/image/segment.c b/src/image/segment.c index 2cb637dc2..52272170a 100644 --- a/src/image/segment.c +++ b/src/image/segment.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * */ +#include #include #include #include diff --git a/src/include/ipxe/dummy_pio.h b/src/include/ipxe/dummy_pio.h index 1cdabba14..e7a4cabef 100644 --- a/src/include/ipxe/dummy_pio.h +++ b/src/include/ipxe/dummy_pio.h @@ -13,6 +13,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include + #define DUMMY_INX( _prefix, _suffix, _type ) \ static inline __always_inline _type \ IOAPI_INLINE ( _prefix, in ## _suffix ) ( volatile _type *io_addr __unused) { \ diff --git a/src/include/ipxe/iomap_virt.h b/src/include/ipxe/iomap_virt.h index 4962b7c37..731d083d5 100644 --- a/src/include/ipxe/iomap_virt.h +++ b/src/include/ipxe/iomap_virt.h @@ -9,6 +9,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include + #ifdef IOMAP_VIRT #define IOMAP_PREFIX_virt #else diff --git a/src/include/ipxe/uaccess.h b/src/include/ipxe/uaccess.h index 948ef1fa2..82f29f793 100644 --- a/src/include/ipxe/uaccess.h +++ b/src/include/ipxe/uaccess.h @@ -11,7 +11,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include -#include #include #include @@ -127,30 +126,4 @@ virt_to_phys ( volatile const void *virt ); */ void * __attribute__ (( const )) phys_to_virt ( physaddr_t phys ); -/** - * Copy data to user buffer - * - * @v dest Destination - * @v dest_off Destination offset - * @v src Source - * @v len Length - */ -static inline __always_inline void -copy_to_user ( userptr_t dest, off_t dest_off, const void *src, size_t len ) { - memcpy ( ( dest + dest_off ), src, len ); -} - -/** - * Copy data from user buffer - * - * @v dest Destination - * @v src Source - * @v src_off Source offset - * @v len Length - */ -static inline __always_inline void -copy_from_user ( void *dest, userptr_t src, off_t src_off, size_t len ) { - memcpy ( dest, ( src + src_off ), len ); -} - #endif /* _IPXE_UACCESS_H */ diff --git a/src/interface/efi/efi_bofm.c b/src/interface/efi/efi_bofm.c index 7d1d3619f..3d956800e 100644 --- a/src/interface/efi/efi_bofm.c +++ b/src/interface/efi/efi_bofm.c @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include #include #include diff --git a/src/interface/efi/efi_cmdline.c b/src/interface/efi/efi_cmdline.c index b33bebd8c..13ad0fc35 100644 --- a/src/interface/efi/efi_cmdline.c +++ b/src/interface/efi/efi_cmdline.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c index b8c7df38d..1b1f05816 100644 --- a/src/interface/efi/efi_pci.c +++ b/src/interface/efi/efi_pci.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include diff --git a/src/interface/xen/xenbus.c b/src/interface/xen/xenbus.c index 5dd01dfa3..8b5ee0a0d 100644 --- a/src/interface/xen/xenbus.c +++ b/src/interface/xen/xenbus.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include diff --git a/src/net/eapol.c b/src/net/eapol.c index 8b09ca231..0c573d198 100644 --- a/src/net/eapol.c +++ b/src/net/eapol.c @@ -23,6 +23,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include #include #include #include diff --git a/src/net/fcoe.c b/src/net/fcoe.c index 9f3ddf88b..d54f1d431 100644 --- a/src/net/fcoe.c +++ b/src/net/fcoe.c @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/net/lldp.c b/src/net/lldp.c index a854d0ace..2b707c874 100644 --- a/src/net/lldp.c +++ b/src/net/lldp.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include +#include #include #include #include diff --git a/src/net/peerblk.c b/src/net/peerblk.c index bbd5f16ed..58b185102 100644 --- a/src/net/peerblk.c +++ b/src/net/peerblk.c @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/net/peermux.c b/src/net/peermux.c index 431ca76e0..5c814b03e 100644 --- a/src/net/peermux.c +++ b/src/net/peermux.c @@ -25,6 +25,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/net/tcp/httpblock.c b/src/net/tcp/httpblock.c index 156f11e47..8eff1942c 100644 --- a/src/net/tcp/httpblock.c +++ b/src/net/tcp/httpblock.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include +#include #include #include #include diff --git a/src/net/tcp/syslogs.c b/src/net/tcp/syslogs.c index f1f70d59e..5676f3e3e 100644 --- a/src/net/tcp/syslogs.c +++ b/src/net/tcp/syslogs.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/net/udp/syslog.c b/src/net/udp/syslog.c index a45fc459d..198c86ef7 100644 --- a/src/net/udp/syslog.c +++ b/src/net/udp/syslog.c @@ -31,6 +31,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/tests/asn1_test.c b/src/tests/asn1_test.c index df3f01b63..b522b85d7 100644 --- a/src/tests/asn1_test.c +++ b/src/tests/asn1_test.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #undef NDEBUG #include +#include #include #include #include diff --git a/src/tests/cpio_test.c b/src/tests/cpio_test.c index 7eb8b2c74..24baf947b 100644 --- a/src/tests/cpio_test.c +++ b/src/tests/cpio_test.c @@ -33,6 +33,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #undef NDEBUG #include +#include #include #include diff --git a/src/tests/pixbuf_test.c b/src/tests/pixbuf_test.c index 1f82e0018..a8ea1151e 100644 --- a/src/tests/pixbuf_test.c +++ b/src/tests/pixbuf_test.c @@ -32,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /* Forcibly enable assertions */ #undef NDEBUG +#include #include #include #include diff --git a/src/tests/test.c b/src/tests/test.c index 4c49d4c16..1ec4b21ef 100644 --- a/src/tests/test.c +++ b/src/tests/test.c @@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include #include diff --git a/src/usr/imgarchive.c b/src/usr/imgarchive.c index 6849dd510..91600760e 100644 --- a/src/usr/imgarchive.c +++ b/src/usr/imgarchive.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include diff --git a/src/usr/imgmgmt.c b/src/usr/imgmgmt.c index 054137696..65b52fd3a 100644 --- a/src/usr/imgmgmt.c +++ b/src/usr/imgmgmt.c @@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include diff --git a/src/usr/imgtrust.c b/src/usr/imgtrust.c index 7f7e7ed14..4eb631e79 100644 --- a/src/usr/imgtrust.c +++ b/src/usr/imgtrust.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include -- cgit v1.2.3-55-g7522 From 2d9a6369dd0c9bba83aac20ddf4d1f04ec2c5e1c Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 30 Apr 2025 13:48:12 +0100 Subject: [test] Separate read-only and writable CMS test images Signed-off-by: Michael Brown --- src/tests/cms_test.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'src/tests') diff --git a/src/tests/cms_test.c b/src/tests/cms_test.c index debbfeee7..5e186cdf0 100644 --- a/src/tests/cms_test.c +++ b/src/tests/cms_test.c @@ -80,6 +80,18 @@ struct cms_test_keypair { /** Define a test image */ #define IMAGE( NAME, DATA ) \ + static const uint8_t NAME ## _data[] = DATA; \ + static struct cms_test_image NAME = { \ + .image = { \ + .refcnt = REF_INIT ( ref_no_free ), \ + .name = #NAME, \ + .data = ( userptr_t ) ( NAME ## _data ), \ + .len = sizeof ( NAME ## _data ), \ + }, \ + } + +/** Define a writable test image */ +#define IMAGE_RW( NAME, DATA ) \ static uint8_t NAME ## _data[] = DATA; \ static struct cms_test_image NAME = { \ .image = { \ @@ -154,7 +166,7 @@ IMAGE ( hidden_code, 0x68, 0x65, 0x6c, 0x6c, 0x0a ) ); /** Code encrypted with AES-256-CBC */ -IMAGE ( hidden_code_cbc_dat, +IMAGE_RW ( hidden_code_cbc_dat, DATA ( 0xaa, 0x63, 0x9f, 0x12, 0xeb, 0x1e, 0xdd, 0x9b, 0xb6, 0x4d, 0x81, 0xd5, 0xba, 0x2d, 0x86, 0x7a, 0x1c, 0x39, 0x10, 0x60, 0x43, 0xac, 0x1b, 0x4e, 0x43, 0xb7, 0x50, 0x5a, 0x6d, 0x7a, @@ -206,7 +218,7 @@ MESSAGE ( hidden_code_cbc_env, 0xba, 0xcf ) ); /** Code encrypted with AES-256-GCM (no block padding) */ -IMAGE ( hidden_code_gcm_dat, +IMAGE_RW ( hidden_code_gcm_dat, DATA ( 0x0c, 0x96, 0xa6, 0x54, 0x9a, 0xc2, 0x24, 0x89, 0x15, 0x00, 0x90, 0xe1, 0x35, 0xca, 0x4a, 0x84, 0x8e, 0x0b, 0xc3, 0x5e, 0xc0, 0x61, 0x61, 0xbd, 0x2e, 0x69, 0x84, 0x7a, 0x2f, 0xf6, -- cgit v1.2.3-55-g7522 From cd803ff2e2424b56a7ae5886e4cfe17b47652e6e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 30 Apr 2025 13:22:54 +0100 Subject: [image] Add the concept of a static image Not all images are allocated via alloc_image(). For example: embedded images, the static images created to hold a runtime command line, and the images used by unit tests are all static structures. Using image_set_cmdline() (via e.g. the "imgargs" command) to set the command-line arguments of a static image will succeed but will leak memory, since nothing will ever free the allocated command line. There are no code paths that can lead to calling image_set_len() on a static image, but there is no safety check against future code paths attempting this. Define a flag IMAGE_STATIC to mark an image as statically allocated, generalise free_image() to also handle freeing dynamically allocated portions of static images (such as the command line), and expose free_image() for use by static images. Define a related flag IMAGE_STATIC_NAME to mark the name as statically allocated. Allow a statically allocated name to be replaced with a dynamically allocated name since this is a potentially valid use case (e.g. if "imgdecrypt --name " is used on an embedded image). Signed-off-by: Michael Brown --- src/arch/x86/core/runtime.c | 2 ++ src/core/image.c | 44 ++++++++++++++++++++++++++++++++++++----- src/image/embedded.c | 3 ++- src/include/ipxe/image.h | 19 ++++++++++++++++-- src/interface/efi/efi_cmdline.c | 2 ++ src/tests/asn1_test.h | 1 + src/tests/cms_test.c | 3 +++ src/tests/pixbuf_test.h | 1 + src/tests/test.c | 1 + 9 files changed, 68 insertions(+), 8 deletions(-) (limited to 'src/tests') diff --git a/src/arch/x86/core/runtime.c b/src/arch/x86/core/runtime.c index 461188d04..86083b1f9 100644 --- a/src/arch/x86/core/runtime.c +++ b/src/arch/x86/core/runtime.c @@ -70,6 +70,7 @@ static void cmdline_image_free ( struct refcnt *refcnt ) { struct image *image = container_of ( refcnt, struct image, refcnt ); DBGC ( image, "RUNTIME freeing command line\n" ); + free_image ( refcnt ); free ( cmdline_copy ); } @@ -77,6 +78,7 @@ static void cmdline_image_free ( struct refcnt *refcnt ) { static struct image cmdline_image = { .refcnt = REF_INIT ( cmdline_image_free ), .name = "", + .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), .type = &script_image_type, }; diff --git a/src/core/image.c b/src/core/image.c index 72885ec09..4f92dfe57 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -76,22 +76,41 @@ static int require_trusted_images_permanent = 0; * Free executable image * * @v refcnt Reference counter + * + * Image consumers must call image_put() rather than calling + * free_image() directly. This function is exposed for use only by + * static images. */ -static void free_image ( struct refcnt *refcnt ) { +void free_image ( struct refcnt *refcnt ) { struct image *image = container_of ( refcnt, struct image, refcnt ); struct image_tag *tag; + /* Sanity check: free_image() should not be called directly on + * dynamically allocated images. + */ + assert ( refcnt->count < 0 ); DBGC ( image, "IMAGE %s freed\n", image->name ); + + /* Clear any tag weak references */ for_each_table_entry ( tag, IMAGE_TAGS ) { if ( tag->image == image ) tag->image = NULL; } - free ( image->name ); + + /* Free dynamic allocations used by both static and dynamic images */ free ( image->cmdline ); uri_put ( image->uri ); - ufree ( image->data ); image_put ( image->replacement ); - free ( image ); + + /* Free image name, if dynamically allocated */ + if ( ! ( image->flags & IMAGE_STATIC_NAME ) ) + free ( image->name ); + + /* Free image data and image itself, if dynamically allocated */ + if ( ! ( image->flags & IMAGE_STATIC ) ) { + ufree ( image->data ); + free ( image ); + } } /** @@ -165,9 +184,13 @@ int image_set_name ( struct image *image, const char *name ) { if ( ! name_copy ) return -ENOMEM; + /* Free existing name, if not statically allocated */ + if ( ! ( image->flags & IMAGE_STATIC_NAME ) ) + free ( image->name ); + /* Replace existing name */ - free ( image->name ); image->name = name_copy; + image->flags &= ~IMAGE_STATIC_NAME; return 0; } @@ -220,6 +243,10 @@ int image_set_cmdline ( struct image *image, const char *cmdline ) { int image_set_len ( struct image *image, size_t len ) { void *new; + /* Refuse to reallocate static images */ + if ( image->flags & IMAGE_STATIC ) + return -ENOTTY; + /* (Re)allocate image data */ new = urealloc ( image->data, len ); if ( ! new ) @@ -288,6 +315,13 @@ int register_image ( struct image *image ) { char name[8]; /* "imgXXXX" */ int rc; + /* Sanity checks */ + if ( image->flags & IMAGE_STATIC ) { + assert ( ( image->name == NULL ) || + ( image->flags & IMAGE_STATIC_NAME ) ); + assert ( image->cmdline == NULL ); + } + /* Create image name if it doesn't already have one */ if ( ! image->name ) { snprintf ( name, sizeof ( name ), "img%d", imgindex++ ); diff --git a/src/image/embedded.c b/src/image/embedded.c index 58833ac30..028f49308 100644 --- a/src/image/embedded.c +++ b/src/image/embedded.c @@ -31,8 +31,9 @@ EMBED_ALL /* Image structures for all embedded images */ #undef EMBED #define EMBED( _index, _path, _name ) { \ - .refcnt = REF_INIT ( ref_no_free ), \ + .refcnt = REF_INIT ( free_image ), \ .name = _name, \ + .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ .data = ( userptr_t ) ( embedded_image_ ## _index ## _data ), \ .len = ( size_t ) embedded_image_ ## _index ## _len, \ }, diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index bf2d77626..8ff938a17 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -30,14 +30,22 @@ struct image { /** URI of image */ struct uri *uri; - /** Name */ + /** Name + * + * If the @c IMAGE_STATIC_NAME flag is set, then this is a + * statically allocated string. + */ char *name; /** Flags */ unsigned int flags; /** Command line to pass to image */ char *cmdline; - /** Raw file image */ + /** Raw file image + * + * If the @c IMAGE_STATIC flag is set, then this is a + * statically allocated image. + */ void *data; /** Length of raw file image */ size_t len; @@ -72,6 +80,12 @@ struct image { /** Image will be hidden from enumeration */ #define IMAGE_HIDDEN 0x0008 +/** Image is statically allocated */ +#define IMAGE_STATIC 0x0010 + +/** Image name is statically allocated */ +#define IMAGE_STATIC_NAME 0x0020 + /** An executable image type */ struct image_type { /** Name of this image type */ @@ -185,6 +199,7 @@ static inline struct image * first_image ( void ) { return list_first_entry ( &images, struct image, list ); } +extern void free_image ( struct refcnt *refcnt ); extern struct image * alloc_image ( struct uri *uri ); extern int image_set_uri ( struct image *image, struct uri *uri ); extern int image_set_name ( struct image *image, const char *name ); diff --git a/src/interface/efi/efi_cmdline.c b/src/interface/efi/efi_cmdline.c index 13ad0fc35..59bce925f 100644 --- a/src/interface/efi/efi_cmdline.c +++ b/src/interface/efi/efi_cmdline.c @@ -58,6 +58,7 @@ static void efi_cmdline_free ( struct refcnt *refcnt ) { struct image *image = container_of ( refcnt, struct image, refcnt ); DBGC ( image, "CMDLINE freeing command line\n" ); + free_image ( refcnt ); free ( efi_cmdline_copy ); } @@ -65,6 +66,7 @@ static void efi_cmdline_free ( struct refcnt *refcnt ) { static struct image efi_cmdline_image = { .refcnt = REF_INIT ( efi_cmdline_free ), .name = "", + .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), .type = &script_image_type, }; diff --git a/src/tests/asn1_test.h b/src/tests/asn1_test.h index c8167ed36..f69a4bf2a 100644 --- a/src/tests/asn1_test.h +++ b/src/tests/asn1_test.h @@ -46,6 +46,7 @@ struct asn1_test { static struct image _name ## __image = { \ .refcnt = REF_INIT ( ref_no_free ), \ .name = #_name, \ + .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ .data = ( userptr_t ) ( _name ## __file ), \ .len = sizeof ( _name ## __file ), \ }; \ diff --git a/src/tests/cms_test.c b/src/tests/cms_test.c index 5e186cdf0..f80fbaa86 100644 --- a/src/tests/cms_test.c +++ b/src/tests/cms_test.c @@ -85,6 +85,7 @@ struct cms_test_keypair { .image = { \ .refcnt = REF_INIT ( ref_no_free ), \ .name = #NAME, \ + .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ .data = ( userptr_t ) ( NAME ## _data ), \ .len = sizeof ( NAME ## _data ), \ }, \ @@ -97,6 +98,7 @@ struct cms_test_keypair { .image = { \ .refcnt = REF_INIT ( ref_no_free ), \ .name = #NAME, \ + .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ .data = ( userptr_t ) ( NAME ## _data ), \ .len = sizeof ( NAME ## _data ), \ }, \ @@ -109,6 +111,7 @@ struct cms_test_keypair { .image = { \ .refcnt = REF_INIT ( ref_no_free ), \ .name = #NAME, \ + .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ .type = &der_image_type, \ .data = ( userptr_t ) ( NAME ## _data ), \ .len = sizeof ( NAME ## _data ), \ diff --git a/src/tests/pixbuf_test.h b/src/tests/pixbuf_test.h index d12829d89..991c16ba3 100644 --- a/src/tests/pixbuf_test.h +++ b/src/tests/pixbuf_test.h @@ -41,6 +41,7 @@ struct pixel_buffer_test { static struct image _name ## __image = { \ .refcnt = REF_INIT ( ref_no_free ), \ .name = #_name, \ + .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ .data = ( userptr_t ) ( _name ## __file ), \ .len = sizeof ( _name ## __file ), \ }; \ diff --git a/src/tests/test.c b/src/tests/test.c index 1ec4b21ef..9fa12e27a 100644 --- a/src/tests/test.c +++ b/src/tests/test.c @@ -162,6 +162,7 @@ static struct image_type test_image_type = { static struct image test_image = { .refcnt = REF_INIT ( ref_no_free ), .name = "", + .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), .type = &test_image_type, }; -- cgit v1.2.3-55-g7522 From 05ad7833c51c942a5cb91540a054852bb991333b Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 30 Apr 2025 14:14:51 +0100 Subject: [image] Make image data read-only to most consumers Almost all image consumers do not need to modify the content of the image. Now that the image data is a pointer type (rather than the opaque userptr_t type), we can rely on the compiler to enforce this at build time. Change the .data field to be a const pointer, so that the compiler can verify that image consumers do not modify the image content. Provide a transparent .rwdata field for consumers who have a legitimate (and now explicit) reason to modify the image content. We do not attempt to impose any runtime restriction on checking whether or not an image is writable. The only existing instances of genuinely read-only images are the various unit test images, and it is acceptable for defective test cases to result in a segfault rather than a runtime error. Signed-off-by: Michael Brown --- src/arch/x86/image/initrd.c | 11 +++++------ src/arch/x86/image/sdi.c | 2 +- src/core/fdt.c | 2 +- src/core/image.c | 8 ++++---- src/crypto/cms.c | 6 +++--- src/image/efi_image.c | 18 ++++++++++++++---- src/image/embedded.c | 13 +------------ src/image/zlib.c | 3 ++- src/include/ipxe/image.h | 7 ++++++- src/interface/efi/efi_cmdline.c | 2 +- src/tests/asn1_test.c | 3 --- src/tests/asn1_test.h | 2 +- src/tests/cms_test.c | 32 +++----------------------------- src/tests/pixbuf_test.c | 7 ++----- src/tests/pixbuf_test.h | 2 +- 15 files changed, 45 insertions(+), 73 deletions(-) (limited to 'src/tests') diff --git a/src/arch/x86/image/initrd.c b/src/arch/x86/image/initrd.c index cb4879036..98c7a3804 100644 --- a/src/arch/x86/image/initrd.c +++ b/src/arch/x86/image/initrd.c @@ -63,10 +63,9 @@ static physaddr_t initrd_squash_high ( physaddr_t top ) { /* Find the highest image not yet in its final position */ highest = NULL; for_each_image ( initrd ) { - data = initrd->data; - if ( ( virt_to_phys ( data ) < current ) && + if ( ( virt_to_phys ( initrd->data ) < current ) && ( ( highest == NULL ) || - ( virt_to_phys ( data ) > + ( virt_to_phys ( initrd->data ) > virt_to_phys ( highest->data ) ) ) ) { highest = initrd; } @@ -144,9 +143,9 @@ static void initrd_swap ( struct image *low, struct image *high, /* Swap fragments */ memcpy ( free, ( high->data + len ), frag_len ); - memmove ( ( low->data + new_len ), ( low->data + len ), + memmove ( ( low->rwdata + new_len ), ( low->data + len ), low->len ); - memcpy ( ( low->data + len ), free, frag_len ); + memcpy ( ( low->rwdata + len ), free, frag_len ); len = new_len; } @@ -165,8 +164,8 @@ static void initrd_swap ( struct image *low, struct image *high, static int initrd_swap_any ( void *free, size_t free_len ) { struct image *low; struct image *high; + const void *adjacent; size_t padded_len; - void *adjacent; /* Find any pair of initrds that can be swapped */ for_each_image ( low ) { diff --git a/src/arch/x86/image/sdi.c b/src/arch/x86/image/sdi.c index cdfdeb369..c0cded239 100644 --- a/src/arch/x86/image/sdi.c +++ b/src/arch/x86/image/sdi.c @@ -51,7 +51,7 @@ FEATURE ( FEATURE_IMAGE, "SDI", DHCP_EB_FEATURE_SDI, 1 ); * @ret rc Return status code */ static int sdi_exec ( struct image *image ) { - struct sdi_header *sdi; + const struct sdi_header *sdi; uint32_t sdiptr; /* Sanity check */ diff --git a/src/core/fdt.c b/src/core/fdt.c index 7c7127aed..744e0e705 100644 --- a/src/core/fdt.c +++ b/src/core/fdt.c @@ -734,7 +734,7 @@ static int fdt_parse_image ( struct fdt *fdt, struct image *image ) { int rc; /* Parse image */ - if ( ( rc = fdt_parse ( fdt, image->data, image->len ) ) != 0 ) { + if ( ( rc = fdt_parse ( fdt, image->rwdata, image->len ) ) != 0 ) { DBGC ( fdt, "FDT image \"%s\" is invalid: %s\n", image->name, strerror ( rc ) ); return rc; diff --git a/src/core/image.c b/src/core/image.c index 4f92dfe57..a06466b72 100644 --- a/src/core/image.c +++ b/src/core/image.c @@ -108,7 +108,7 @@ void free_image ( struct refcnt *refcnt ) { /* Free image data and image itself, if dynamically allocated */ if ( ! ( image->flags & IMAGE_STATIC ) ) { - ufree ( image->data ); + ufree ( image->rwdata ); free ( image ); } } @@ -248,10 +248,10 @@ int image_set_len ( struct image *image, size_t len ) { return -ENOTTY; /* (Re)allocate image data */ - new = urealloc ( image->data, len ); + new = urealloc ( image->rwdata, len ); if ( ! new ) return -ENOMEM; - image->data = new; + image->rwdata = new; image->len = len; return 0; @@ -273,7 +273,7 @@ int image_set_data ( struct image *image, const void *data, size_t len ) { return rc; /* Copy in new image data */ - memcpy ( image->data, data, len ); + memcpy ( image->rwdata, data, len ); return 0; } diff --git a/src/crypto/cms.c b/src/crypto/cms.c index 36b87c644..edfcc7fdc 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -1079,7 +1079,7 @@ int cms_decrypt ( struct cms_message *cms, struct image *image, final_len = ( ( image->len && is_block_cipher ( cipher ) ) ? cipher->blocksize : 0 ); bulk_len = ( image->len - final_len ); - cipher_decrypt ( cipher, ctx, image->data, image->data, bulk_len ); + cipher_decrypt ( cipher, ctx, image->data, image->rwdata, bulk_len ); /* Decrypt final block */ cipher_decrypt ( cipher, ctx, ( image->data + bulk_len ), final, @@ -1117,7 +1117,7 @@ int cms_decrypt ( struct cms_message *cms, struct image *image, * have to include include any error-handling code path to * reconstruct the block padding. */ - memcpy ( ( image->data + bulk_len ), final, final_len ); + memcpy ( ( image->rwdata + bulk_len ), final, final_len ); image->len -= pad_len; /* Clear image type and re-register image, if applicable */ @@ -1137,7 +1137,7 @@ int cms_decrypt ( struct cms_message *cms, struct image *image, * containing the potentially invalid (and therefore * unreproducible) block padding. */ - cipher_encrypt ( cipher, ctxdup, image->data, image->data, bulk_len ); + cipher_encrypt ( cipher, ctxdup, image->data, image->rwdata, bulk_len ); if ( original_flags & IMAGE_REGISTERED ) { register_image ( image ); /* Cannot fail on re-registration */ image_put ( image ); diff --git a/src/image/efi_image.c b/src/image/efi_image.c index f7ee7ff50..e7b19c4ce 100644 --- a/src/image/efi_image.c +++ b/src/image/efi_image.c @@ -243,10 +243,15 @@ static int efi_image_exec ( struct image *image ) { goto err_shim_install; } - /* Attempt loading image */ + /* Attempt loading image + * + * LoadImage() does not (allegedly) modify the image content, + * but requires a non-const pointer to SourceBuffer. We + * therefore use the .rwdata field rather than .data. + */ handle = NULL; if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, path, - exec->data, exec->len, + exec->rwdata, exec->len, &handle ) ) != 0 ) { /* Not an EFI image */ rc = -EEFI_LOAD ( efirc ); @@ -377,10 +382,15 @@ static int efi_image_probe ( struct image *image ) { EFI_STATUS efirc; int rc; - /* Attempt loading image */ + /* Attempt loading image + * + * LoadImage() does not (allegedly) modify the image content, + * but requires a non-const pointer to SourceBuffer. We + * therefore use the .rwdata field rather than .data. + */ handle = NULL; if ( ( efirc = bs->LoadImage ( FALSE, efi_image_handle, &empty_path, - image->data, image->len, + image->rwdata, image->len, &handle ) ) != 0 ) { /* Not an EFI image */ rc = -EEFI_LOAD ( efirc ); diff --git a/src/image/embedded.c b/src/image/embedded.c index 028f49308..76d256c9b 100644 --- a/src/image/embedded.c +++ b/src/image/embedded.c @@ -10,7 +10,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include -#include #include /* Raw image data for all embedded images */ @@ -34,7 +33,7 @@ EMBED_ALL .refcnt = REF_INIT ( free_image ), \ .name = _name, \ .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ - .data = ( userptr_t ) ( embedded_image_ ## _index ## _data ), \ + .rwdata = embedded_image_ ## _index ## _data, \ .len = ( size_t ) embedded_image_ ## _index ## _len, \ }, static struct image embedded_images[] = { @@ -58,18 +57,8 @@ static void embedded_init ( void ) { for ( i = 0 ; i < ( int ) ( sizeof ( embedded_images ) / sizeof ( embedded_images[0] ) ) ; i++ ) { image = &embedded_images[i]; - - /* virt_to_user() cannot be used in a static - * initialiser, so we cast the pointer to a userptr_t - * in the initialiser and fix it up here. (This will - * actually be a no-op on most platforms.) - */ - data = ( ( void * ) image->data ); - image->data = virt_to_user ( data ); - DBG ( "Embedded image \"%s\": %zd bytes at %p\n", image->name, image->len, data ); - if ( ( rc = register_image ( image ) ) != 0 ) { DBG ( "Could not register embedded image \"%s\": " "%s\n", image->name, strerror ( rc ) ); diff --git a/src/image/zlib.c b/src/image/zlib.c index d7deee88b..23eb50e7d 100644 --- a/src/image/zlib.c +++ b/src/image/zlib.c @@ -65,7 +65,8 @@ int zlib_deflate ( enum deflate_format format, const void *data, size_t len, deflate_init ( deflate, format ); /* Initialise output chunk */ - deflate_chunk_init ( &out, extracted->data, 0, extracted->len ); + deflate_chunk_init ( &out, extracted->rwdata, 0, + extracted->len ); /* Decompress data */ if ( ( rc = deflate_inflate ( deflate, data, len, diff --git a/src/include/ipxe/image.h b/src/include/ipxe/image.h index 8ff938a17..fbf2b63b9 100644 --- a/src/include/ipxe/image.h +++ b/src/include/ipxe/image.h @@ -46,7 +46,12 @@ struct image { * If the @c IMAGE_STATIC flag is set, then this is a * statically allocated image. */ - void *data; + union { + /** Read-only data */ + const void *data; + /** Writable data */ + void *rwdata; + }; /** Length of raw file image */ size_t len; diff --git a/src/interface/efi/efi_cmdline.c b/src/interface/efi/efi_cmdline.c index 59bce925f..d5ec6cee3 100644 --- a/src/interface/efi/efi_cmdline.c +++ b/src/interface/efi/efi_cmdline.c @@ -113,7 +113,7 @@ static int efi_cmdline_init ( void ) { DBGC ( colour, "CMDLINE using command line \"%s\"\n", cmdline ); /* Prepare and register image */ - efi_cmdline_image.data = virt_to_user ( cmdline ); + efi_cmdline_image.data = cmdline; efi_cmdline_image.len = strlen ( cmdline ); if ( efi_cmdline_image.len && ( ( rc = register_image ( &efi_cmdline_image ) ) != 0 ) ) { diff --git a/src/tests/asn1_test.c b/src/tests/asn1_test.c index b522b85d7..4760b97fb 100644 --- a/src/tests/asn1_test.c +++ b/src/tests/asn1_test.c @@ -59,9 +59,6 @@ void asn1_okx ( struct asn1_test *test, const char *file, unsigned int line ) { /* 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 ); diff --git a/src/tests/asn1_test.h b/src/tests/asn1_test.h index f69a4bf2a..f8310f5ba 100644 --- a/src/tests/asn1_test.h +++ b/src/tests/asn1_test.h @@ -47,7 +47,7 @@ struct asn1_test { .refcnt = REF_INIT ( ref_no_free ), \ .name = #_name, \ .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ - .data = ( userptr_t ) ( _name ## __file ), \ + .data = _name ## __file, \ .len = sizeof ( _name ## __file ), \ }; \ static struct asn1_test_digest _name ## _expected[] = { \ diff --git a/src/tests/cms_test.c b/src/tests/cms_test.c index f80fbaa86..b71190cba 100644 --- a/src/tests/cms_test.c +++ b/src/tests/cms_test.c @@ -37,7 +37,6 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include -#include #include #include #include @@ -86,7 +85,7 @@ struct cms_test_keypair { .refcnt = REF_INIT ( ref_no_free ), \ .name = #NAME, \ .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ - .data = ( userptr_t ) ( NAME ## _data ), \ + .data = NAME ## _data, \ .len = sizeof ( NAME ## _data ), \ }, \ } @@ -99,7 +98,7 @@ struct cms_test_keypair { .refcnt = REF_INIT ( ref_no_free ), \ .name = #NAME, \ .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ - .data = ( userptr_t ) ( NAME ## _data ), \ + .data = NAME ## _data, \ .len = sizeof ( NAME ## _data ), \ }, \ } @@ -113,7 +112,7 @@ struct cms_test_keypair { .name = #NAME, \ .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ .type = &der_image_type, \ - .data = ( userptr_t ) ( NAME ## _data ), \ + .data = NAME ## _data, \ .len = sizeof ( NAME ## _data ), \ }, \ } @@ -1652,16 +1651,9 @@ static time_t test_expired = 1375573111ULL; /* Sat Aug 3 23:38:31 2013 */ */ static void cms_message_okx ( struct cms_test_message *msg, const char *file, unsigned int line ) { - const void *data = ( ( void * ) msg->image.data ); - - /* Fix up image data pointer */ - msg->image.data = virt_to_user ( data ); /* Check ability to parse message */ okx ( cms_message ( &msg->image, &msg->cms ) == 0, file, line ); - - /* Reset image data pointer */ - msg->image.data = ( ( userptr_t ) data ); } #define cms_message_ok( msg ) \ cms_message_okx ( msg, __FILE__, __LINE__ ) @@ -1705,10 +1697,6 @@ static void cms_verify_okx ( struct cms_test_message *msg, time_t time, struct x509_chain *store, struct x509_root *root, const char *file, unsigned int line ) { - const void *data = ( ( void * ) img->image.data ); - - /* Fix up image data pointer */ - img->image.data = virt_to_user ( data ); /* Invalidate any certificates from previous tests */ x509_invalidate_chain ( msg->cms->certificates ); @@ -1717,9 +1705,6 @@ static void cms_verify_okx ( struct cms_test_message *msg, okx ( cms_verify ( msg->cms, &img->image, name, time, store, root ) == 0, file, line ); okx ( img->image.flags & IMAGE_TRUSTED, file, line ); - - /* Reset image data pointer */ - img->image.data = ( ( userptr_t ) data ); } #define cms_verify_ok( msg, img, name, time, store, root ) \ cms_verify_okx ( msg, img, name, time, store, root, \ @@ -1742,10 +1727,6 @@ static void cms_verify_fail_okx ( struct cms_test_message *msg, time_t time, struct x509_chain *store, struct x509_root *root, const char *file, unsigned int line ) { - const void *data = ( ( void * ) img->image.data ); - - /* Fix up image data pointer */ - img->image.data = virt_to_user ( data ); /* Invalidate any certificates from previous tests */ x509_invalidate_chain ( msg->cms->certificates ); @@ -1754,9 +1735,6 @@ static void cms_verify_fail_okx ( struct cms_test_message *msg, okx ( cms_verify ( msg->cms, &img->image, name, time, store, root ) != 0, file, line ); okx ( ! ( img->image.flags & IMAGE_TRUSTED ), file, line ); - - /* Reset image data pointer */ - img->image.data = ( ( userptr_t ) data ); } #define cms_verify_fail_ok( msg, img, name, time, store, root ) \ cms_verify_fail_okx ( msg, img, name, time, store, root, \ @@ -1777,10 +1755,6 @@ static void cms_decrypt_okx ( struct cms_test_image *img, struct cms_test_keypair *keypair, struct cms_test_image *expected, const char *file, unsigned int line ) { - const void *data = ( ( void * ) img->image.data ); - - /* Fix up image data pointer */ - img->image.data = virt_to_user ( data ); /* Check ability to decrypt image */ okx ( cms_decrypt ( envelope->cms, &img->image, NULL, diff --git a/src/tests/pixbuf_test.c b/src/tests/pixbuf_test.c index a8ea1151e..cbc3a7617 100644 --- a/src/tests/pixbuf_test.c +++ b/src/tests/pixbuf_test.c @@ -55,9 +55,6 @@ void pixbuf_okx ( struct pixel_buffer_test *test, const char *file, assert ( ( test->width * test->height * sizeof ( test->data[0] ) ) == test->len ); - /* 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 ); @@ -72,8 +69,8 @@ void pixbuf_okx ( struct pixel_buffer_test *test, const char *file, /* Check pixel buffer data */ okx ( pixbuf->len == test->len, file, line ); - okx ( memcmp ( pixbuf->data, virt_to_user ( test->data ), - test->len ) == 0, file, line ); + okx ( memcmp ( pixbuf->data, test->data, test->len ) == 0, + file, line ); pixbuf_put ( pixbuf ); } diff --git a/src/tests/pixbuf_test.h b/src/tests/pixbuf_test.h index 991c16ba3..cf3d548f9 100644 --- a/src/tests/pixbuf_test.h +++ b/src/tests/pixbuf_test.h @@ -42,7 +42,7 @@ struct pixel_buffer_test { .refcnt = REF_INIT ( ref_no_free ), \ .name = #_name, \ .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ), \ - .data = ( userptr_t ) ( _name ## __file ), \ + .data = _name ## __file, \ .len = sizeof ( _name ## __file ), \ }; \ static struct pixel_buffer_test _name = { \ -- cgit v1.2.3-55-g7522 From f6f11c101c833aa6f6eaa8dfaf4f3903bbe89fdf Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 15 May 2025 15:46:02 +0100 Subject: [tests] Remove prehistoric umalloc() test code Signed-off-by: Michael Brown --- src/tests/umalloc_test.c | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 src/tests/umalloc_test.c (limited to 'src/tests') diff --git a/src/tests/umalloc_test.c b/src/tests/umalloc_test.c deleted file mode 100644 index 1a32a0531..000000000 --- a/src/tests/umalloc_test.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include - -void umalloc_test ( void ) { - struct memory_map memmap; - void *bob; - void *fred; - - printf ( "Before allocation:\n" ); - get_memmap ( &memmap ); - - bob = umalloc ( 1234 ); - bob = urealloc ( bob, 12345 ); - fred = umalloc ( 999 ); - - printf ( "After allocation:\n" ); - get_memmap ( &memmap ); - - ufree ( bob ); - ufree ( fred ); - - printf ( "After freeing:\n" ); - get_memmap ( &memmap ); -} -- cgit v1.2.3-55-g7522 From d64250918c4863750ffc1f76d6c8bff95c9a5cf9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 30 May 2025 14:15:43 +0100 Subject: [fdt] Add tests for device tree creation Signed-off-by: Michael Brown --- src/tests/fdt_test.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/tests') diff --git a/src/tests/fdt_test.c b/src/tests/fdt_test.c index 0a143ec62..1dead2126 100644 --- a/src/tests/fdt_test.c +++ b/src/tests/fdt_test.c @@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include /** Simplified QEMU sifive_u device tree blob */ @@ -164,6 +165,7 @@ static void fdt_test_exec ( void ) { struct fdt_header *hdr; struct fdt fdt; const char *string; + struct image *image; uint32_t u32; uint64_t u64; unsigned int count; @@ -260,6 +262,22 @@ static void fdt_test_exec ( void ) { ok ( strcmp ( desc.name, "device_type" ) == 0 ); ok ( strcmp ( desc.data, "memory" ) == 0 ); ok ( desc.depth == 0 ); + + /* Verify device tree creation */ + image = image_memory ( "test.dtb", sifive_u, sizeof ( sifive_u ) ); + ok ( image != NULL ); + image_tag ( image, &fdt_image ); + ok ( fdt_create ( &hdr, "hello world", 0xabcd0000, 0x00001234 ) == 0 ); + ok ( fdt_parse ( &fdt, hdr, -1UL ) == 0 ); + ok ( fdt_path ( &fdt, "/chosen", &offset ) == 0 ); + ok ( ( string = fdt_string ( &fdt, offset, "bootargs" ) ) != NULL ); + ok ( strcmp ( string, "hello world" ) == 0 ); + ok ( fdt_u64 ( &fdt, offset, "linux,initrd-start", &u64 ) == 0 ); + ok ( u64 == 0xabcd0000 ); + ok ( fdt_u64 ( &fdt, offset, "linux,initrd-end", &u64 ) == 0 ); + ok ( u64 == 0xabcd1234 ); + fdt_remove ( hdr ); + unregister_image ( image ); } /** FDT self-test */ -- cgit v1.2.3-55-g7522 From 1762568ec52b8b29b5bc3b870adb00f46178b51e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 30 May 2025 16:37:28 +0100 Subject: [fdt] Provide ability to locate the parent device node Signed-off-by: Michael Brown --- src/core/fdt.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++- src/include/ipxe/fdt.h | 2 ++ src/tests/fdt_test.c | 12 +++++++ 3 files changed, 109 insertions(+), 1 deletion(-) (limited to 'src/tests') diff --git a/src/core/fdt.c b/src/core/fdt.c index c8ae4d949..b2ee0133b 100644 --- a/src/core/fdt.c +++ b/src/core/fdt.c @@ -181,7 +181,7 @@ static int fdt_next ( struct fdt *fdt, struct fdt_descriptor *desc ) { * @ret rc Return status code */ static int fdt_enter ( struct fdt *fdt, unsigned int offset, - struct fdt_descriptor *desc ) { + struct fdt_descriptor *desc ) { int rc; /* Find begin node token */ @@ -212,6 +212,100 @@ static int fdt_enter ( struct fdt *fdt, unsigned int offset, } } +/** + * Find node relative depth + * + * @v fdt Device tree + * @v offset Starting node offset + * @v target Target node offset + * @ret depth Depth, or negative error + */ +static int fdt_depth ( struct fdt *fdt, unsigned int offset, + unsigned int target ) { + struct fdt_descriptor desc; + int depth; + int rc; + + /* Enter node */ + if ( ( rc = fdt_enter ( fdt, offset, &desc ) ) != 0 ) + return rc; + + /* Find target node */ + for ( depth = 0 ; depth >= 0 ; depth += desc.depth ) { + + /* Describe token */ + if ( ( rc = fdt_next ( fdt, &desc ) ) != 0 ) { + DBGC ( fdt, "FDT +%#04x has malformed node: %s\n", + offset, strerror ( rc ) ); + return rc; + } + + /* Check for target node */ + if ( desc.offset == target ) { + DBGC2 ( fdt, "FDT +%#04x has descendant node +%#04x " + "at depth +%d\n", offset, target, depth ); + return depth; + } + } + + DBGC ( fdt, "FDT +#%04x has no descendant node +%#04x\n", + offset, target ); + return -ENOENT; +} + +/** + * Find parent node + * + * @v fdt Device tree + * @v offset Starting node offset + * @v parent Parent node offset to fill in + * @ret rc Return status code + */ +int fdt_parent ( struct fdt *fdt, unsigned int offset, unsigned int *parent ) { + struct fdt_descriptor desc; + int pdepth; + int depth; + int rc; + + /* Find depth from root of tree */ + depth = fdt_depth ( fdt, 0, offset ); + if ( depth < 0 ) { + rc = depth; + return rc; + } + pdepth = ( depth - 1 ); + + /* Enter root node */ + if ( ( rc = fdt_enter ( fdt, 0, &desc ) ) != 0 ) + return rc; + *parent = desc.offset; + + /* Find parent node */ + for ( depth = 0 ; depth >= 0 ; depth += desc.depth ) { + + /* Describe token */ + if ( ( rc = fdt_next ( fdt, &desc ) ) != 0 ) { + DBGC ( fdt, "FDT +%#04x has malformed node: %s\n", + offset, strerror ( rc ) ); + return rc; + } + + /* Record possible parent node */ + if ( ( depth == pdepth ) && desc.name && ( ! desc.data ) ) + *parent = desc.offset; + + /* Check for target node */ + if ( desc.offset == offset ) { + DBGC2 ( fdt, "FDT +%#04x has parent node at +%#04x\n", + offset, *parent ); + return 0; + } + } + + DBGC ( fdt, "FDT +#%04x has no parent node\n", offset ); + return -ENOENT; +} + /** * Find child node * diff --git a/src/include/ipxe/fdt.h b/src/include/ipxe/fdt.h index 461b09632..d5a0d2179 100644 --- a/src/include/ipxe/fdt.h +++ b/src/include/ipxe/fdt.h @@ -170,6 +170,8 @@ fdt_reservations ( struct fdt *fdt ) { extern int fdt_describe ( struct fdt *fdt, unsigned int offset, struct fdt_descriptor *desc ); +extern int fdt_parent ( struct fdt *fdt, unsigned int offset, + unsigned int *parent ); extern int fdt_path ( struct fdt *fdt, const char *path, unsigned int *offset ); extern int fdt_alias ( struct fdt *fdt, const char *name, diff --git a/src/tests/fdt_test.c b/src/tests/fdt_test.c index 1dead2126..408f77c6d 100644 --- a/src/tests/fdt_test.c +++ b/src/tests/fdt_test.c @@ -263,6 +263,18 @@ static void fdt_test_exec ( void ) { ok ( strcmp ( desc.data, "memory" ) == 0 ); ok ( desc.depth == 0 ); + /* Verify parent lookup */ + ok ( fdt_path ( &fdt, "/soc/ethernet@10090000/ethernet-phy@0", + &offset ) == 0 ); + ok ( fdt_parent ( &fdt, offset, &offset ) == 0 ); + ok ( fdt_describe ( &fdt, offset, &desc ) == 0 ); + ok ( strcmp ( desc.name, "ethernet@10090000" ) == 0 ); + ok ( fdt_parent ( &fdt, offset, &offset ) == 0 ); + ok ( fdt_describe ( &fdt, offset, &desc ) == 0 ); + ok ( strcmp ( desc.name, "soc" ) == 0 ); + ok ( fdt_parent ( &fdt, offset, &offset ) == 0 ); + ok ( offset == 0 ); + /* Verify device tree creation */ image = image_memory ( "test.dtb", sifive_u, sizeof ( sifive_u ) ); ok ( image != NULL ); -- cgit v1.2.3-55-g7522 From 1ae75a3bde3f1b87c79de5af9881cb9374489784 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 10 Jun 2025 13:32:10 +0100 Subject: [test] Add infrastructure for test network devices Signed-off-by: Michael Brown --- src/tests/netdev_test.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++++ src/tests/netdev_test.h | 111 ++++++++++++++++++++++++ 2 files changed, 329 insertions(+) create mode 100644 src/tests/netdev_test.c create mode 100644 src/tests/netdev_test.h (limited to 'src/tests') diff --git a/src/tests/netdev_test.c b/src/tests/netdev_test.c new file mode 100644 index 000000000..388a5af88 --- /dev/null +++ b/src/tests/netdev_test.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 + * + * Network device tests + * + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include +#include +#include "netdev_test.h" + +/** + * Open network device + * + * @v netdev Network device + * @ret rc Return status code + */ +static int testnet_open ( struct net_device *netdev __unused ) { + + /* Do nothing, successfully */ + return 0; +} + +/** + * Close network device + * + * @v netdev Network device + */ +static void testnet_close ( struct net_device *netdev __unused ) { + + /* Do nothing */ +} + +/** + * Transmit packet + * + * @v netdev Network device + * @v iobuf I/O buffer + * @ret rc Return status code + */ +static int testnet_transmit ( struct net_device *netdev, + struct io_buffer *iobuf ) { + + /* Complete immediately */ + netdev_tx_complete ( netdev, iobuf ); + return 0; +} + +/** + * Poll for completed and received packets + * + * @v netdev Network device + */ +static void testnet_poll ( struct net_device *netdev __unused ) { + + /* Do nothing */ +} + +/** Test network device operations */ +static struct net_device_operations testnet_operations = { + .open = testnet_open, + .close = testnet_close, + .transmit = testnet_transmit, + .poll = testnet_poll, +}; + +/** + * Report a network device creation test result + * + * @v testnet Test network device + * @v file Test code file + * @v line Test code line + */ +void testnet_okx ( struct testnet *testnet, const char *file, + unsigned int line ) { + struct testnet_setting *testset; + unsigned int i; + + /* Allocate device */ + testnet->netdev = alloc_etherdev ( 0 ); + okx ( testnet->netdev != NULL, file, line ); + netdev_init ( testnet->netdev, &testnet_operations ); + testnet->netdev->dev = &testnet->dev; + snprintf ( testnet->netdev->name, sizeof ( testnet->netdev->name ), + "%s", testnet->dev.name ); + + /* Register device */ + okx ( register_netdev ( testnet->netdev ) == 0, file, line ); + + /* Open device */ + testnet_open_okx ( testnet, file, line ); + + /* Apply initial settings */ + for ( i = 0 ; i < testnet->count ; i++ ) { + testset = &testnet->testset[i]; + testnet_set_okx ( testnet, testset->name, testset->value, + file, line ); + } +} + +/** + * Report a network device opening test result + * + * @v testnet Test network device + * @v file Test code file + * @v line Test code line + */ +void testnet_open_okx ( struct testnet *testnet, const char *file, + unsigned int line ) { + + /* Sanity check */ + okx ( testnet->netdev != NULL, file, line ); + + /* Open device */ + okx ( netdev_open ( testnet->netdev ) == 0, file, line ); +} + +/** + * Report a network device setting test result + * + * @v testnet Test network device + * @v name Setting name (relative to network device's settings) + * @v value Setting value + * @v file Test code file + * @v line Test code line + */ +void testnet_set_okx ( struct testnet *testnet, const char *name, + const char *value, const char *file, + unsigned int line ) { + char fullname[ strlen ( testnet->dev.name ) + 1 /* "." or "/" */ + + strlen ( name ) + 1 /* NUL */ ]; + struct settings *settings; + struct setting setting; + + /* Sanity check */ + okx ( testnet->netdev != NULL, file, line ); + settings = netdev_settings ( testnet->netdev ); + okx ( settings != NULL, file, line ); + okx ( strcmp ( settings->name, testnet->dev.name ) == 0, file, line ); + + /* Construct setting name */ + snprintf ( fullname, sizeof ( fullname ), "%s%c%s", testnet->dev.name, + ( strchr ( name, '/' ) ? '.' : '/' ), name ); + + /* Parse setting name */ + okx ( parse_setting_name ( fullname, autovivify_child_settings, + &settings, &setting ) == 0, file, line ); + + /* Apply setting */ + okx ( storef_setting ( settings, &setting, value ) == 0, file, line ); +} + +/** + * Report a network device closing test result + * + * @v testnet Test network device + * @v file Test code file + * @v line Test code line + */ +void testnet_close_okx ( struct testnet *testnet, const char *file, + unsigned int line ) { + + /* Sanity check */ + okx ( testnet->netdev != NULL, file, line ); + + /* Close device */ + netdev_close ( testnet->netdev ); +} + +/** + * Report a network device removal test result + * + * @v testnet Test network device + * @v file Test code file + * @v line Test code line + */ +void testnet_remove_okx ( struct testnet *testnet, const char *file, + unsigned int line ) { + + /* Sanity check */ + okx ( testnet->netdev != NULL, file, line ); + + /* Remove device */ + unregister_netdev ( testnet->netdev ); + netdev_nullify ( testnet->netdev ); + netdev_put ( testnet->netdev ); + testnet->netdev = NULL; +} diff --git a/src/tests/netdev_test.h b/src/tests/netdev_test.h new file mode 100644 index 000000000..ddb8c9b11 --- /dev/null +++ b/src/tests/netdev_test.h @@ -0,0 +1,111 @@ +#ifndef _NETDEV_TEST_H +#define _NETDEV_TEST_H + +/** @file + * + * Network device tests + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include +#include + +/** A test network device setting */ +struct testnet_setting { + /** Setting name (relative to network device's settings) */ + const char *name; + /** Value */ + const char *value; +}; + +/** A test network device */ +struct testnet { + /** Network device */ + struct net_device *netdev; + /** Dummy physical device */ + struct device dev; + /** Initial settings */ + struct testnet_setting *testset; + /** Number of initial settings */ + unsigned int count; +}; + +/** + * Declare a test network device + * + * @v NAME Network device name + * @v ... Initial network device settings + */ +#define TESTNET( NAME, ... ) \ + static struct testnet_setting NAME ## _setting[] = { \ + __VA_ARGS__ \ + }; \ + static struct testnet NAME = { \ + .dev = { \ + .name = #NAME, \ + .driver_name = "testnet", \ + .siblings = \ + LIST_HEAD_INIT ( NAME.dev.siblings ), \ + .children = \ + LIST_HEAD_INIT ( NAME.dev.children ), \ + }, \ + .testset = NAME ## _setting, \ + .count = ( sizeof ( NAME ## _setting ) / \ + sizeof ( NAME ## _setting[0] ) ), \ + }; + +/** + * Report a network device creation test result + * + * @v testnet Test network device + */ +#define testnet_ok( testnet ) testnet_okx ( testnet, __FILE__, __LINE__ ) +extern void testnet_okx ( struct testnet *testnet, const char *file, + unsigned int line ); + +/** + * Report a network device opening test result + * + * @v testnet Test network device + */ +#define testnet_open_ok( testnet ) \ + testnet_open_okx ( testnet, __FILE__, __LINE__ ) +extern void testnet_open_okx ( struct testnet *testnet, const char *file, + unsigned int line ); + +/** + * Report a network device setting test result + * + * @v testnet Test network device + * @v name Setting name (relative to network device's settings) + * @v value Setting value + */ +#define testnet_set_ok( testnet, name, value ) \ + testnet_set_okx ( testnet, name, value, __FILE__, __LINE__ ) +extern void testnet_set_okx ( struct testnet *testnet, const char *name, + const char *value, const char *file, + unsigned int line ); + +/** + * Report a network device closing test result + * + * @v testnet Test network device + */ +#define testnet_close_ok( testnet ) \ + testnet_close_okx ( testnet, __FILE__, __LINE__ ) +extern void testnet_close_okx ( struct testnet *testnet, const char *file, + unsigned int line ); + +/** + * Report a network device removal test result + * + * @v testnet Test network device + */ +#define testnet_remove_ok( testnet ) \ + testnet_remove_okx ( testnet, __FILE__, __LINE__ ) +extern void testnet_remove_okx ( struct testnet *testnet, const char *file, + unsigned int line ); + +#endif /* _NETDEV_TEST_H */ -- cgit v1.2.3-55-g7522 From 96f58646607f554b05e1c4f32e1cefe85f0346e6 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 10 Jun 2025 13:37:31 +0100 Subject: [ipv4] Add self-tests for IPv4 routing Signed-off-by: Michael Brown --- src/include/ipxe/ip.h | 2 + src/net/ipv4.c | 4 +- src/tests/ipv4_test.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 2 deletions(-) (limited to 'src/tests') diff --git a/src/include/ipxe/ip.h b/src/include/ipxe/ip.h index b1b5cb2e7..a2c5d4265 100644 --- a/src/include/ipxe/ip.h +++ b/src/include/ipxe/ip.h @@ -92,6 +92,8 @@ extern struct list_head ipv4_miniroutes; extern struct net_protocol ipv4_protocol __net_protocol; +extern struct ipv4_miniroute * ipv4_route ( unsigned int scope_id, + struct in_addr *dest ); extern int ipv4_has_any_addr ( struct net_device *netdev ); extern int parse_ipv4_setting ( const struct setting_type *type, const char *value, void *buf, size_t len ); diff --git a/src/net/ipv4.c b/src/net/ipv4.c index 5d0cb0f9a..425656f6c 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -157,8 +157,8 @@ static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) { * If the route requires use of a gateway, the next hop destination * address will be overwritten with the gateway address. */ -static struct ipv4_miniroute * ipv4_route ( unsigned int scope_id, - struct in_addr *dest ) { +struct ipv4_miniroute * ipv4_route ( unsigned int scope_id, + struct in_addr *dest ) { struct ipv4_miniroute *miniroute; /* Find first usable route in routing table */ diff --git a/src/tests/ipv4_test.c b/src/tests/ipv4_test.c index f84a8b81f..a5aa4a4b1 100644 --- a/src/tests/ipv4_test.c +++ b/src/tests/ipv4_test.c @@ -34,9 +34,12 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include +#include #include #include +#include #include +#include "netdev_test.h" /** Define inline IPv4 address */ #define IPV4(a,b,c,d) \ @@ -104,6 +107,113 @@ static void inet_aton_fail_okx ( const char *text, const char *file, #define inet_aton_fail_ok( text ) \ inet_aton_fail_okx ( text, __FILE__, __LINE__ ) +/** + * Report an ipv4_route() test result + * + * @v dest Destination address + * @v scope Destination scope test network device, or NULL + * @v next Expected next hop address (on success) + * @v egress Expected egress device, or NULL to expect failure + * @v src Expected source address (on success) + * @v bcast Expected broadcast packet (on success) + * @v file Test code file + * @v line Test code line + */ +static void ipv4_route_okx ( const char *dest, struct testnet *scope, + const char *next, struct testnet *egress, + const char *src, int bcast, + const char *file, unsigned int line ) { + struct ipv4_miniroute *miniroute; + struct in_addr in_dest; + struct in_addr in_src; + struct in_addr in_next; + struct in_addr actual; + unsigned int scope_id; + + /* Sanity checks */ + assert ( ( scope == NULL ) || ( scope->netdev != NULL ) ); + assert ( ( egress == NULL ) == ( src == NULL ) ); + + /* Parse addresses */ + okx ( inet_aton ( dest, &in_dest ) != 0, file, line ); + if ( src ) + okx ( inet_aton ( src, &in_src ) != 0, file, line ); + if ( next ) { + okx ( inet_aton ( next, &in_next ) != 0, file, line ); + } else { + in_next.s_addr = in_dest.s_addr; + } + + /* Perform routing */ + actual.s_addr = in_dest.s_addr; + scope_id = ( scope ? scope->netdev->scope_id : 0 ); + miniroute = ipv4_route ( scope_id, &actual ); + + /* Validate result */ + if ( src ) { + + /* Check that a route was found */ + okx ( miniroute != NULL, file, line ); + DBG ( "ipv4_route ( %s, %s ) = %s", + ( scope ? scope->dev.name : "" ), dest, + inet_ntoa ( actual ) ); + DBG ( " from %s via %s\n", + inet_ntoa ( miniroute->address ), egress->dev.name ); + + /* Check that expected network device was used */ + okx ( miniroute->netdev == egress->netdev, file, line ); + + /* Check that expected source address was used */ + okx ( miniroute->address.s_addr == in_src.s_addr, file, line ); + + /* Check that expected next hop address was used */ + okx ( actual.s_addr == in_next.s_addr, file, line ); + + /* Check that expected broadcast choice was used */ + okx ( ( ! ( ( ~actual.s_addr ) & miniroute->hostmask.s_addr ) ) + == ( !! bcast ), file, line ); + + } else { + + /* Routing is expected to fail */ + okx ( miniroute == NULL, file, line ); + DBG ( "ipv4_route ( %s, %s ) = \n", + ( scope ? scope->dev.name : "" ), dest ); + } +} +#define ipv4_route_ok( dest, scope, next, egress, src, bcast ) \ + ipv4_route_okx ( dest, scope, next, egress, src, bcast, \ + __FILE__, __LINE__ ) + +/** net0: Single address and gateway (DHCP assignment) */ +TESTNET ( net0, + { "dhcp/ip", "192.168.0.1" }, + { "dhcp/netmask", "255.255.255.0" }, + { "dhcp/gateway", "192.168.0.254" } ); + +/** net1: Single address and gateway (DHCP assignment) */ +TESTNET ( net1, + { "dhcp/ip", "192.168.0.2" }, + { "dhcp/netmask", "255.255.255.0" }, + { "dhcp/gateway", "192.168.0.254" } ); + +/** net2: Small /31 subnet mask */ +TESTNET ( net2, + { "ip", "10.31.31.0" }, + { "netmask", "255.255.255.254" }, + { "gateway", "10.31.31.1" } ); + +/** net3: Small /32 subnet mask */ +TESTNET ( net3, + { "ip", "10.32.32.32" }, + { "netmask", "255.255.255.255" }, + { "gateway", "192.168.32.254" } ); + +/** net4: Local subnet with no gateway */ +TESTNET ( net4, + { "ip", "192.168.86.1" }, + { "netmask", "255.255.240.0" } ); + /** * Perform IPv4 self-tests * @@ -145,6 +255,48 @@ static void ipv4_test_exec ( void ) { inet_aton_fail_ok ( "127.0.0" ); /* Too short */ inet_aton_fail_ok ( "1.2.3.a" ); /* Invalid characters */ inet_aton_fail_ok ( "127.0..1" ); /* Missing bytes */ + + /* Single address and gateway */ + testnet_ok ( &net0 ); + ipv4_route_ok ( "192.168.0.10", NULL, + "192.168.0.10", &net0, "192.168.0.1", 0 ); + ipv4_route_ok ( "10.0.0.6", NULL, + "192.168.0.254", &net0, "192.168.0.1", 0 ); + ipv4_route_ok ( "192.168.0.255", NULL, + "192.168.0.255", &net0, "192.168.0.1", 1 ); + testnet_remove_ok ( &net0 ); + + /* Overridden DHCP-assigned address */ + testnet_ok ( &net1 ); + ipv4_route_ok ( "192.168.1.3", NULL, + "192.168.0.254", &net1, "192.168.0.2", 0 ); + testnet_set_ok ( &net1, "ip", "192.168.1.2" ); + ipv4_route_ok ( "192.168.1.3", NULL, + "192.168.1.3", &net1, "192.168.1.2", 0 ); + testnet_remove_ok ( &net1 ); + + /* Small /31 subnet */ + testnet_ok ( &net2 ); + ipv4_route_ok ( "10.31.31.1", NULL, + "10.31.31.1", &net2, "10.31.31.0", 0 ); + ipv4_route_ok ( "212.13.204.60", NULL, + "10.31.31.1", &net2, "10.31.31.0", 0 ); + testnet_remove_ok ( &net2 ); + + /* Small /32 subnet */ + testnet_ok ( &net3 ); + ipv4_route_ok ( "10.32.32.31", NULL, + "192.168.32.254", &net3, "10.32.32.32", 0 ); + ipv4_route_ok ( "8.8.8.8", NULL, + "192.168.32.254", &net3, "10.32.32.32", 0 ); + testnet_remove_ok ( &net3 ); + + /* No gateway */ + testnet_ok ( &net4 ); + ipv4_route_ok ( "192.168.87.1", NULL, + "192.168.87.1", &net4, "192.168.86.1", 0 ); + ipv4_route_ok ( "192.168.96.1", NULL, NULL, NULL, NULL, 0 ); + testnet_remove_ok ( &net4 ); } /** IPv4 self-test */ -- cgit v1.2.3-55-g7522 From e648d23fba09c7e0c50e205448448b132a5711b5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 5 Jun 2025 16:49:42 +0100 Subject: [ipv4] Extend routing mechanism to handle non-default routes Extend the definition of an IPv4 routing table entry to allow for the expression of non-default gateways for specified off-link subnets, and of on-link secondary subnets (where we can send directly to the destination address even though our source address is not within the subnet). This more precise definition also allows us to correctly handle routing in the (uncommon for iPXE) case when multiple network interfaces are open concurrently and more than one interface has a default gateway. The common case of a single IPv4 address/netmask and a default gateway now results in two routing table entries. To retain backwards compatibility with existing documentation (and to avoid on-screen clutter), the "route" command prints default gateways on the same line as the locally assigned address. There is therefore no change in output from the "route" command unless explicit additional (off-link or on-link) routes are present. Signed-off-by: Michael Brown --- src/include/ipxe/ip.h | 77 ++++++++++++++++++++++++++------- src/net/ipv4.c | 116 +++++++++++++++++++++++++++++++++++--------------- src/tests/ipv4_test.c | 30 +++++++++++++ src/usr/route_ipv4.c | 47 +++++++++++++++++--- 4 files changed, 213 insertions(+), 57 deletions(-) (limited to 'src/tests') diff --git a/src/include/ipxe/ip.h b/src/include/ipxe/ip.h index a2c5d4265..e2cd512ac 100644 --- a/src/include/ipxe/ip.h +++ b/src/include/ipxe/ip.h @@ -54,38 +54,83 @@ struct ipv4_pseudo_header { uint16_t len; }; -/** An IPv4 address/routing table entry */ +/** An IPv4 address/routing table entry + * + * Routing table entries are maintained in order of specificity. For + * a given destination address, the first matching table entry will be + * used as the egress route. + */ struct ipv4_miniroute { /** List of miniroutes */ struct list_head list; - /** Network device */ + /** Network device + * + * When this routing table entry is matched, this is the + * egress network device to be used. + */ struct net_device *netdev; - /** IPv4 address */ + /** IPv4 address + * + * When this routing table entry is matched, this is the + * source address to be used. + * + * The presence of this routing table entry also indicates + * that this address is a valid local destination address for + * the matching network device. + */ struct in_addr address; + /** Subnet network address + * + * A subnet is a range of addresses defined by a network + * address and subnet mask. A destination address with all of + * the subnet mask bits in common with the network address is + * within the subnet and therefore matches this routing table + * entry. + */ + struct in_addr network; /** Subnet mask * - * An address with all of these bits in common with our IPv4 - * address is in the local subnet. + * An address with all of these bits in common with the + * network address matches this routing table entry. */ struct in_addr netmask; + /** Gateway address, or zero + * + * When this routing table entry is matched and this address + * is non-zero, it will be used as the next-hop address. + * + * When this routing table entry is matched and this address + * is zero, the subnet is local (on-link) and the next-hop + * address will be the original destination address. + */ + struct in_addr gateway; /** Host mask * - * An address in the local subnet with all of these bits set - * to zero represents the network address, and an address in - * the local subnet with all of these bits set to one - * represents the directed broadcast address. All other - * addresses in the local subnet are valid host addresses. + * An address in a local subnet with all of these bits set to + * zero represents the network address, and an address in a + * local subnet with all of these bits set to one represents + * the local directed broadcast address. All other addresses + * in a local subnet are valid host addresses. + * + * For most local subnets, this is the inverse of the subnet + * mask. In a small subnet (/31 or /32) there is no network + * address or directed broadcast address, and all addresses in + * the subnet are valid host addresses. * - * For most subnets, this is the inverse of the subnet mask. - * In a small subnet (/31 or /32) there is no network address - * or directed broadcast address, and all addresses in the - * subnet are valid host addresses. + * When this routing table entry is matched and the subnet is + * local, a next-hop address with all of these bits set to one + * will be treated as a local broadcast address. All other + * next-hop addresses will be treated as unicast addresses. + * + * When this routing table entry is matched and the subnet is + * non-local, the next-hop address is always a unicast + * address. The host mask for non-local subnets is therefore + * set to @c INADDR_NONE to allow the same logic to be used as + * for local subnets. */ struct in_addr hostmask; - /** Gateway address, or zero for no gateway */ - struct in_addr gateway; }; extern struct list_head ipv4_miniroutes; diff --git a/src/net/ipv4.c b/src/net/ipv4.c index 425656f6c..ec96e4242 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -77,24 +77,32 @@ static struct profiler ipv4_rx_profiler __profiler = { .name = "ipv4.rx" }; * * @v netdev Network device * @v address IPv4 address + * @v network Subnet address * @v netmask Subnet mask * @v gateway Gateway address (if any) * @ret rc Return status code */ -static int add_ipv4_miniroute ( struct net_device *netdev, - struct in_addr address, struct in_addr netmask, +static int ipv4_add_miniroute ( struct net_device *netdev, + struct in_addr address, + struct in_addr network, + struct in_addr netmask, struct in_addr gateway ) { struct ipv4_miniroute *miniroute; + struct ipv4_miniroute *before; struct in_addr hostmask; struct in_addr broadcast; /* Calculate host mask */ - hostmask.s_addr = ( IN_IS_SMALL ( netmask.s_addr ) ? - INADDR_NONE : ~netmask.s_addr ); - broadcast.s_addr = ( address.s_addr | hostmask.s_addr ); + if ( gateway.s_addr || IN_IS_SMALL ( netmask.s_addr ) ) { + hostmask.s_addr = INADDR_NONE; + } else { + hostmask.s_addr = ~netmask.s_addr; + } + broadcast.s_addr = ( network.s_addr | hostmask.s_addr ); /* Print debugging information */ DBGC ( netdev, "IPv4 add %s", inet_ntoa ( address ) ); + DBGC ( netdev, " for %s", inet_ntoa ( network ) ); DBGC ( netdev, "/%s ", inet_ntoa ( netmask ) ); DBGC ( netdev, "bc %s ", inet_ntoa ( broadcast ) ); if ( gateway.s_addr ) @@ -111,18 +119,49 @@ static int add_ipv4_miniroute ( struct net_device *netdev, /* Record routing information */ miniroute->netdev = netdev_get ( netdev ); miniroute->address = address; + miniroute->network = network; miniroute->netmask = netmask; miniroute->hostmask = hostmask; miniroute->gateway = gateway; - /* Add to end of list if we have a gateway, otherwise - * to start of list. - */ - if ( gateway.s_addr ) { - list_add_tail ( &miniroute->list, &ipv4_miniroutes ); - } else { - list_add ( &miniroute->list, &ipv4_miniroutes ); + /* Add to routing table ahead of any less specific routes */ + list_for_each_entry ( before, &ipv4_miniroutes, list ) { + if ( netmask.s_addr & ~before->netmask.s_addr ) + break; } + list_add_tail ( &miniroute->list, &before->list ); + + return 0; +} + +/** + * Add IPv4 minirouting table entries + * + * @v netdev Network device + * @v address IPv4 address + * @v netmask Subnet mask + * @v gateway Gateway address (if any) + * @ret rc Return status code + */ +static int ipv4_add_miniroutes ( struct net_device *netdev, + struct in_addr address, + struct in_addr netmask, + struct in_addr gateway ) { + struct in_addr none = { 0 }; + struct in_addr network; + int rc; + + /* Add local address */ + network.s_addr = ( address.s_addr & netmask.s_addr ); + if ( ( rc = ipv4_add_miniroute ( netdev, address, network, netmask, + none ) ) != 0 ) + return rc; + + /* Add default gateway, if applicable */ + if ( gateway.s_addr && + ( ( rc = ipv4_add_miniroute ( netdev, address, none, none, + gateway ) ) != 0 ) ) + return rc; return 0; } @@ -132,10 +171,11 @@ static int add_ipv4_miniroute ( struct net_device *netdev, * * @v miniroute Routing table entry */ -static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) { +static void ipv4_del_miniroute ( struct ipv4_miniroute *miniroute ) { struct net_device *netdev = miniroute->netdev; DBGC ( netdev, "IPv4 del %s", inet_ntoa ( miniroute->address ) ); + DBGC ( netdev, " for %s", inet_ntoa ( miniroute->network ) ); DBGC ( netdev, "/%s ", inet_ntoa ( miniroute->netmask ) ); if ( miniroute->gateway.s_addr ) DBGC ( netdev, "gw %s ", inet_ntoa ( miniroute->gateway ) ); @@ -146,6 +186,19 @@ static void del_ipv4_miniroute ( struct ipv4_miniroute *miniroute ) { free ( miniroute ); } +/** + * Delete IPv4 minirouting table entries + * + */ +static void ipv4_del_miniroutes ( void ) { + struct ipv4_miniroute *miniroute; + struct ipv4_miniroute *tmp; + + /* Delete all existing routes */ + list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list ) + ipv4_del_miniroute ( miniroute ); +} + /** * Perform IPv4 routing * @@ -170,27 +223,23 @@ struct ipv4_miniroute * ipv4_route ( unsigned int scope_id, if ( IN_IS_MULTICAST ( dest->s_addr ) ) { - /* If destination is non-global, and the scope ID - * matches this network device, then use this route. + /* If destination is non-global, and the scope + * ID matches this network device, then use + * the first matching route. */ if ( miniroute->netdev->scope_id == scope_id ) return miniroute; } else { - /* If destination is an on-link global - * address, then use this route. + /* If destination is global, then use the + * first matching route (via its gateway if + * specified). */ - if ( ( ( dest->s_addr ^ miniroute->address.s_addr ) - & miniroute->netmask.s_addr ) == 0 ) - return miniroute; - - /* If destination is an off-link global - * address, and we have a default gateway, - * then use this route. - */ - if ( miniroute->gateway.s_addr ) { - *dest = miniroute->gateway; + if ( ( ( dest->s_addr ^ miniroute->network.s_addr ) + & miniroute->netmask.s_addr ) == 0 ) { + if ( miniroute->gateway.s_addr ) + *dest = miniroute->gateway; return miniroute; } } @@ -913,20 +962,17 @@ static int ipv4_settings ( int ( * apply ) ( struct net_device *netdev, * * @ret rc Return status code */ -static int ipv4_create_routes ( void ) { - struct ipv4_miniroute *miniroute; - struct ipv4_miniroute *tmp; +static int ipv4_apply_routes ( void ) { int rc; /* Send gratuitous ARPs for any new IPv4 addresses */ ipv4_settings ( ipv4_gratuitous_arp ); /* Delete all existing routes */ - list_for_each_entry_safe ( miniroute, tmp, &ipv4_miniroutes, list ) - del_ipv4_miniroute ( miniroute ); + ipv4_del_miniroutes(); - /* Create a route for each configured network device */ - if ( ( rc = ipv4_settings ( add_ipv4_miniroute ) ) != 0 ) + /* Create routes for each configured network device */ + if ( ( rc = ipv4_settings ( ipv4_add_miniroutes ) ) != 0 ) return rc; return 0; @@ -934,7 +980,7 @@ static int ipv4_create_routes ( void ) { /** IPv4 settings applicator */ struct settings_applicator ipv4_settings_applicator __settings_applicator = { - .apply = ipv4_create_routes, + .apply = ipv4_apply_routes, }; /* Drag in objects via ipv4_protocol */ diff --git a/src/tests/ipv4_test.c b/src/tests/ipv4_test.c index a5aa4a4b1..63e1e1dc5 100644 --- a/src/tests/ipv4_test.c +++ b/src/tests/ipv4_test.c @@ -297,6 +297,36 @@ static void ipv4_test_exec ( void ) { "192.168.87.1", &net4, "192.168.86.1", 0 ); ipv4_route_ok ( "192.168.96.1", NULL, NULL, NULL, NULL, 0 ); testnet_remove_ok ( &net4 ); + + /* Multiple interfaces */ + testnet_ok ( &net0 ); + testnet_ok ( &net1 ); + testnet_ok ( &net2 ); + testnet_close_ok ( &net1 ); + ipv4_route_ok ( "192.168.0.9", NULL, + "192.168.0.9", &net0, "192.168.0.1", 0 ); + ipv4_route_ok ( "10.31.31.1", NULL, + "10.31.31.1", &net2, "10.31.31.0", 0 ); + testnet_close_ok ( &net0 ); + testnet_open_ok ( &net1 ); + ipv4_route_ok ( "192.168.0.9", NULL, + "192.168.0.9", &net1, "192.168.0.2", 0 ); + ipv4_route_ok ( "10.31.31.1", NULL, + "10.31.31.1", &net2, "10.31.31.0", 0 ); + testnet_close_ok ( &net2 ); + ipv4_route_ok ( "8.8.8.8", NULL, + "192.168.0.254", &net1, "192.168.0.2", 0 ); + testnet_close_ok ( &net1 ); + testnet_open_ok ( &net0 ); + ipv4_route_ok ( "8.8.8.8", NULL, + "192.168.0.254", &net0, "192.168.0.1", 0 ); + testnet_close_ok ( &net0 ); + testnet_open_ok ( &net2 ); + ipv4_route_ok ( "8.8.8.8", NULL, + "10.31.31.1", &net2, "10.31.31.0", 0 ); + testnet_remove_ok ( &net2 ); + testnet_remove_ok ( &net1 ); + testnet_remove_ok ( &net0 ); } /** IPv4 self-test */ diff --git a/src/usr/route_ipv4.c b/src/usr/route_ipv4.c index 6260335ac..f79c0ad8f 100644 --- a/src/usr/route_ipv4.c +++ b/src/usr/route_ipv4.c @@ -41,16 +41,51 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ static void route_ipv4_print ( struct net_device *netdev ) { struct ipv4_miniroute *miniroute; + struct ipv4_miniroute *defroute; + struct in_addr address; + struct in_addr network; + struct in_addr netmask; + struct in_addr gateway; + int remote; + /* Print routing table */ list_for_each_entry ( miniroute, &ipv4_miniroutes, list ) { + + /* Skip non-matching network devices */ if ( miniroute->netdev != netdev ) continue; - printf ( "%s: %s/", netdev->name, - inet_ntoa ( miniroute->address ) ); - printf ( "%s", inet_ntoa ( miniroute->netmask ) ); - if ( miniroute->gateway.s_addr ) - printf ( " gw %s", inet_ntoa ( miniroute->gateway ) ); - if ( ! netdev_is_open ( miniroute->netdev ) ) + address = miniroute->address; + network = miniroute->network; + netmask = miniroute->netmask; + gateway = miniroute->gateway; + assert ( ( network.s_addr & ~netmask.s_addr ) == 0 ); + + /* Defer default routes to be printed with local addresses */ + if ( ! netmask.s_addr ) + continue; + + /* Print local address and destination subnet */ + remote = ( ( address.s_addr ^ network.s_addr ) & + netmask.s_addr ); + printf ( "%s: %s", netdev->name, inet_ntoa ( address ) ); + if ( remote ) + printf ( " for %s", inet_ntoa ( network ) ); + printf ( "/%s", inet_ntoa ( netmask ) ); + if ( gateway.s_addr ) + printf ( " gw %s", inet_ntoa ( gateway ) ); + + /* Print default routes with local subnets */ + list_for_each_entry ( defroute, &ipv4_miniroutes, list ) { + if ( ( defroute->netdev == netdev ) && + ( defroute->address.s_addr = address.s_addr ) && + ( ! defroute->netmask.s_addr ) && ( ! remote ) ) { + printf ( " gw %s", + inet_ntoa ( defroute->gateway ) ); + } + } + + /* Print trailer */ + if ( ! netdev_is_open ( netdev ) ) printf ( " (inaccessible)" ); printf ( "\n" ); } -- cgit v1.2.3-55-g7522 From b5fb7353fa3856cee7e0a6760c2341ca617d6ef4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 10 Jun 2025 16:55:18 +0100 Subject: [ipv4] Add support for classless static routes Add support for RFC 3442 classless static routes provided via DHCP option 121. Originally-implemented-by: Hazel Smith Originally-implemented-by: Raphael Pour Signed-off-by: Michael Brown --- src/include/ipxe/dhcp.h | 3 + src/include/ipxe/settings.h | 2 + src/net/ipv4.c | 165 ++++++++++++++++++++++++++++++++------------ src/net/udp/dhcp.c | 2 +- src/tests/ipv4_test.c | 29 ++++++++ 5 files changed, 157 insertions(+), 44 deletions(-) (limited to 'src/tests') diff --git a/src/include/ipxe/dhcp.h b/src/include/ipxe/dhcp.h index 4d68d3ca5..43729d0c5 100644 --- a/src/include/ipxe/dhcp.h +++ b/src/include/ipxe/dhcp.h @@ -344,6 +344,9 @@ struct dhcp_client_uuid { /** DNS domain search list */ #define DHCP_DOMAIN_SEARCH 119 +/** Classless static routes */ +#define DHCP_STATIC_ROUTES 121 + /** Etherboot-specific encapsulated options * * This encapsulated options field is used to contain all options diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index 0301da12e..689e011d3 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -437,6 +437,8 @@ netmask_setting __setting ( SETTING_IP4, netmask ); extern const struct setting gateway_setting __setting ( SETTING_IP4, gateway ); extern const struct setting +static_route_setting __setting ( SETTING_IP4, static_routes ); +extern const struct setting dns_setting __setting ( SETTING_IP4_EXTRA, dns ); extern const struct setting ip6_setting __setting ( SETTING_IP6, ip6 ); diff --git a/src/net/ipv4.c b/src/net/ipv4.c index ec96e4242..03517840b 100644 --- a/src/net/ipv4.c +++ b/src/net/ipv4.c @@ -134,36 +134,132 @@ static int ipv4_add_miniroute ( struct net_device *netdev, return 0; } +/** + * Add static route minirouting table entries + * + * @v netdev Network device + * @v address IPv4 address + * @v routes Static routes + * @v len Length of static routes + * @ret rc Return status code + */ +static int ipv4_add_static ( struct net_device *netdev, struct in_addr address, + const void *routes, size_t len ) { + const struct { + struct in_addr address; + } __attribute__ (( packed )) *encoded; + struct in_addr netmask; + struct in_addr network; + struct in_addr gateway; + unsigned int width; + unsigned int masklen; + size_t remaining; + const void *data; + int rc; + + /* Parse and add static routes */ + for ( data = routes, remaining = len ; remaining ; ) { + + /* Extract subnet mask width */ + width = *( ( uint8_t * ) data ); + data++; + remaining--; + masklen = ( ( width + 7 ) / 8 ); + + /* Check remaining length */ + if ( ( masklen + sizeof ( gateway ) ) > remaining ) { + DBGC ( netdev, "IPv4 invalid static route:\n" ); + DBGC_HDA ( netdev, 0, routes, len ); + return -EINVAL; + } + + /* Calculate subnet mask */ + if ( width ) { + netmask.s_addr = htonl ( -1UL << ( 32 - width ) ); + } else { + netmask.s_addr = 0; + } + + /* Extract network address */ + encoded = data; + network.s_addr = ( encoded->address.s_addr & netmask.s_addr ); + data += masklen; + remaining -= masklen; + + /* Extract gateway address */ + encoded = data; + gateway.s_addr = encoded->address.s_addr; + data += sizeof ( gateway ); + remaining -= sizeof ( gateway ); + + /* Add route */ + if ( ( rc = ipv4_add_miniroute ( netdev, address, network, + netmask, gateway ) ) != 0 ) + return rc; + } + + return 0; +} + /** * Add IPv4 minirouting table entries * * @v netdev Network device * @v address IPv4 address - * @v netmask Subnet mask - * @v gateway Gateway address (if any) * @ret rc Return status code */ static int ipv4_add_miniroutes ( struct net_device *netdev, - struct in_addr address, - struct in_addr netmask, - struct in_addr gateway ) { + struct in_addr address ) { + struct settings *settings = netdev_settings ( netdev ); struct in_addr none = { 0 }; + struct in_addr netmask; + struct in_addr gateway; struct in_addr network; + void *routes; + int len; int rc; + /* Get subnet mask */ + fetch_ipv4_setting ( settings, &netmask_setting, &netmask ); + + /* Calculate default netmask, if necessary */ + if ( ! netmask.s_addr ) { + if ( IN_IS_CLASSA ( address.s_addr ) ) { + netmask.s_addr = INADDR_NET_CLASSA; + } else if ( IN_IS_CLASSB ( address.s_addr ) ) { + netmask.s_addr = INADDR_NET_CLASSB; + } else if ( IN_IS_CLASSC ( address.s_addr ) ) { + netmask.s_addr = INADDR_NET_CLASSC; + } + } + + /* Get default gateway, if present */ + fetch_ipv4_setting ( settings, &gateway_setting, &gateway ); + + /* Get static routes, if present */ + len = fetch_raw_setting_copy ( settings, &static_route_setting, + &routes ); + /* Add local address */ network.s_addr = ( address.s_addr & netmask.s_addr ); if ( ( rc = ipv4_add_miniroute ( netdev, address, network, netmask, none ) ) != 0 ) - return rc; - - /* Add default gateway, if applicable */ - if ( gateway.s_addr && - ( ( rc = ipv4_add_miniroute ( netdev, address, none, none, - gateway ) ) != 0 ) ) - return rc; + goto done; + + /* Add static routes or default gateway, as applicable */ + if ( len >= 0 ) { + if ( ( rc = ipv4_add_static ( netdev, address, routes, + len ) ) != 0 ) + goto done; + } else if ( gateway.s_addr ) { + if ( ( rc = ipv4_add_miniroute ( netdev, address, none, none, + gateway ) ) != 0 ) + goto done; + } - return 0; + done: + free ( routes ); + return rc; } /** @@ -871,19 +967,24 @@ const struct setting gateway_setting __setting ( SETTING_IP4, gateway ) = { .type = &setting_type_ipv4, }; +/** Classless static routes setting */ +const struct setting static_route_setting __setting ( SETTING_IP4, + static_routes ) = { + .name = "static-routes", + .description = "Static routes", + .tag = DHCP_STATIC_ROUTES, + .type = &setting_type_hex, +}; + /** * Send gratuitous ARP, if applicable * * @v netdev Network device * @v address IPv4 address - * @v netmask Subnet mask - * @v gateway Gateway address (if any) * @ret rc Return status code */ static int ipv4_gratuitous_arp ( struct net_device *netdev, - struct in_addr address, - struct in_addr netmask __unused, - struct in_addr gateway __unused ) { + struct in_addr address ) { int rc; /* Do nothing if network device already has this IPv4 address */ @@ -910,14 +1011,10 @@ static int ipv4_gratuitous_arp ( struct net_device *netdev, * @ret rc Return status code */ static int ipv4_settings ( int ( * apply ) ( struct net_device *netdev, - struct in_addr address, - struct in_addr netmask, - struct in_addr gateway ) ) { + struct in_addr address ) ) { struct net_device *netdev; struct settings *settings; - struct in_addr address = { 0 }; - struct in_addr netmask = { 0 }; - struct in_addr gateway = { 0 }; + struct in_addr address; int rc; /* Process settings for each network device */ @@ -927,30 +1024,12 @@ static int ipv4_settings ( int ( * apply ) ( struct net_device *netdev, settings = netdev_settings ( netdev ); /* Get IPv4 address */ - address.s_addr = 0; fetch_ipv4_setting ( settings, &ip_setting, &address ); if ( ! address.s_addr ) continue; - /* Get subnet mask */ - fetch_ipv4_setting ( settings, &netmask_setting, &netmask ); - - /* Calculate default netmask, if necessary */ - if ( ! netmask.s_addr ) { - if ( IN_IS_CLASSA ( address.s_addr ) ) { - netmask.s_addr = INADDR_NET_CLASSA; - } else if ( IN_IS_CLASSB ( address.s_addr ) ) { - netmask.s_addr = INADDR_NET_CLASSB; - } else if ( IN_IS_CLASSC ( address.s_addr ) ) { - netmask.s_addr = INADDR_NET_CLASSC; - } - } - - /* Get default gateway, if present */ - fetch_ipv4_setting ( settings, &gateway_setting, &gateway ); - /* Apply settings */ - if ( ( rc = apply ( netdev, address, netmask, gateway ) ) != 0 ) + if ( ( rc = apply ( netdev, address ) ) != 0 ) return rc; } diff --git a/src/net/udp/dhcp.c b/src/net/udp/dhcp.c index 8e2e97f10..daa37b96b 100644 --- a/src/net/udp/dhcp.c +++ b/src/net/udp/dhcp.c @@ -94,7 +94,7 @@ static uint8_t dhcp_request_options_data[] = { DHCP_ROOT_PATH, DHCP_MTU, DHCP_NTP_SERVERS, DHCP_VENDOR_ENCAP, DHCP_VENDOR_CLASS_ID, DHCP_TFTP_SERVER_NAME, DHCP_BOOTFILE_NAME, - DHCP_DOMAIN_SEARCH, + DHCP_DOMAIN_SEARCH, DHCP_STATIC_ROUTES, 128, 129, 130, 131, 132, 133, 134, 135, /* for PXE */ DHCP_EB_ENCAP, DHCP_ISCSI_INITIATOR_IQN ), DHCP_END diff --git a/src/tests/ipv4_test.c b/src/tests/ipv4_test.c index 63e1e1dc5..be2760027 100644 --- a/src/tests/ipv4_test.c +++ b/src/tests/ipv4_test.c @@ -214,6 +214,17 @@ TESTNET ( net4, { "ip", "192.168.86.1" }, { "netmask", "255.255.240.0" } ); +/** net5: Static routes */ +TESTNET ( net5, + { "ip", "10.42.0.1" }, + { "netmask", "255.255.0.0" }, + { "gateway", "10.42.0.254" /* should be ignored */ }, + { "static-routes", + "19:0a:2b:2b:80:0a:2a:2b:2b:" /* 10.43.43.128/25 via 10.42.43.43 */ + "10:c0:a8:0a:2a:c0:a8:" /* 192.168.0.0/16 via 10.42.192.168 */ + "18:c0:a8:00:00:00:00:00:" /* 192.168.0.0/24 on-link */ + "00:0a:2a:01:01" /* default via 10.42.1.1 */ } ); + /** * Perform IPv4 self-tests * @@ -327,6 +338,24 @@ static void ipv4_test_exec ( void ) { testnet_remove_ok ( &net2 ); testnet_remove_ok ( &net1 ); testnet_remove_ok ( &net0 ); + + /* Static routes */ + testnet_ok ( &net5 ); + ipv4_route_ok ( "10.42.99.0", NULL, + "10.42.99.0", &net5, "10.42.0.1", 0 ); + ipv4_route_ok ( "8.8.8.8", NULL, + "10.42.1.1", &net5, "10.42.0.1", 0 ); + ipv4_route_ok ( "10.43.43.1", NULL, + "10.42.1.1", &net5, "10.42.0.1", 0 ); + ipv4_route_ok ( "10.43.43.129", NULL, + "10.42.43.43", &net5, "10.42.0.1", 0 ); + ipv4_route_ok ( "192.168.54.8", NULL, + "10.42.192.168", &net5, "10.42.0.1", 0 ); + ipv4_route_ok ( "192.168.0.8", NULL, + "192.168.0.8", &net5, "10.42.0.1", 0 ); + ipv4_route_ok ( "192.168.0.255", NULL, + "192.168.0.255", &net5, "10.42.0.1", 1 ); + testnet_remove_ok ( &net5 ); } /** IPv4 self-test */ -- cgit v1.2.3-55-g7522 From 7e96e5f2ef074c6c17a75dad20beb2a61ecca2f8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 11 Jun 2025 16:08:42 +0100 Subject: [fdt] Allow paths and aliases to be terminated with separator characters Non-permitted name characters such as a colon are sometimes used to separate alias names or paths from additional metadata, such as the baud rate for a UART in the "/chosen/stdout-path" property. Support the use of such alias names and paths by allowing any character not permitted in a property name to terminate a property or node name match. (This is a very relaxed matching rule that will produce false positive matches on invalid input, but this is unlikely to cause problems in practice.) Signed-off-by: Michael Brown --- src/core/fdt.c | 39 ++++++++++++++++++++++++++++++--------- src/tests/fdt_test.c | 7 +++++++ 2 files changed, 37 insertions(+), 9 deletions(-) (limited to 'src/tests') diff --git a/src/core/fdt.c b/src/core/fdt.c index b2ee0133b..149348199 100644 --- a/src/core/fdt.c +++ b/src/core/fdt.c @@ -24,6 +24,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include +#include #include #include #include @@ -50,6 +51,33 @@ struct image_tag fdt_image __image_tag = { /** Amount of free space to add whenever we have to reallocate a tree */ #define FDT_INSERT_PAD 1024 +/** + * Check if character is permitted in a name + * + * @v ch Character + * @ret is_permitted Character is permitted in a name + */ +static int fdt_permitted ( char ch ) { + static const char permitted[] = ",._+?#-"; + + return ( isalnum ( ch ) || strchr ( permitted, ch ) ); +} + +/** + * Compare node name + * + * @v desc Token descriptor + * @v name Name (terminated by NUL or any non-permitted character) + * @ret is_match Name matches token descriptor + */ +static int fdt_match ( const struct fdt_descriptor *desc, const char *name ) { + size_t len = strlen ( desc->name ); + + /* Check name and terminator */ + return ( ( memcmp ( desc->name, name, len ) == 0 ) && + ( ! ( name[len] && fdt_permitted ( name[len] ) ) ) ); +} + /** * Describe device tree token * @@ -318,15 +346,9 @@ int fdt_parent ( struct fdt *fdt, unsigned int offset, unsigned int *parent ) { static int fdt_child ( struct fdt *fdt, unsigned int offset, const char *name, unsigned int *child ) { struct fdt_descriptor desc; - const char *sep; - size_t name_len; int depth; int rc; - /* Determine length of name (may be terminated with NUL or '/') */ - sep = strchr ( name, '/' ); - name_len = ( sep ? ( ( size_t ) ( sep - name ) ) : strlen ( name ) ); - /* Enter node */ if ( ( rc = fdt_enter ( fdt, offset, &desc ) ) != 0 ) return rc; @@ -346,8 +368,7 @@ static int fdt_child ( struct fdt *fdt, unsigned int offset, const char *name, DBGC2 ( fdt, "FDT +%#04x has child node \"%s\" at " "+%#04x\n", offset, desc.name, desc.offset ); assert ( desc.depth > 0 ); - if ( ( strlen ( desc.name ) == name_len ) && - ( memcmp ( name, desc.name, name_len ) == 0 ) ) { + if ( fdt_match ( &desc, name ) ) { *child = desc.offset; return 0; } @@ -495,7 +516,7 @@ static int fdt_property ( struct fdt *fdt, unsigned int offset, "+%#04x len %#zx\n", offset, desc->name, desc->offset, desc->len ); assert ( desc->depth == 0 ); - if ( strcmp ( name, desc->name ) == 0 ) { + if ( fdt_match ( desc, name ) ) { DBGC2_HDA ( fdt, 0, desc->data, desc->len ); return 0; } diff --git a/src/tests/fdt_test.c b/src/tests/fdt_test.c index 408f77c6d..0be0acdbc 100644 --- a/src/tests/fdt_test.c +++ b/src/tests/fdt_test.c @@ -213,6 +213,10 @@ static void fdt_test_exec ( void ) { ok ( strcmp ( string, "sifive,uart0" ) == 0 ); ok ( fdt_path ( &fdt, "/nonexistent", &offset ) != 0 ); ok ( fdt_path ( &fdt, "/cpus/nonexistent", &offset ) != 0 ); + ok ( fdt_path ( &fdt, "/soc/serial@10010000:115200n8", + &offset ) == 0 ); + ok ( ( string = fdt_string ( &fdt, offset, "compatible" ) ) != NULL ); + ok ( strcmp ( string, "sifive,uart0" ) == 0 ); /* Verify 64-bit integer properties */ ok ( fdt_u64 ( &fdt, 0, "#address-cells", &u64 ) == 0 ); @@ -249,6 +253,9 @@ static void fdt_test_exec ( void ) { ok ( ( string = fdt_string ( &fdt, offset, "compatible" ) ) != NULL ); ok ( strcmp ( string, "sifive,uart0" ) == 0 ); ok ( fdt_alias ( &fdt, "nonexistent0", &offset ) != 0 ); + ok ( fdt_alias ( &fdt, "ethernet0:params", &offset ) == 0 ); + ok ( ( string = fdt_string ( &fdt, offset, "phy-mode" ) ) != NULL ); + ok ( strcmp ( string, "gmii" ) == 0 ); /* Verify node description */ ok ( fdt_path ( &fdt, "/memory@80000000", &offset ) == 0 ); -- cgit v1.2.3-55-g7522 From 19f1407ad90d39d3bab9293bf2849afc42dd2e9d Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 7 Jul 2025 13:21:24 +0100 Subject: [iobuf] Ensure I/O buffer data sits within unshared cachelines On platforms where DMA devices are not in the same coherency domain as the CPU cache, we must ensure that DMA I/O buffers do not share cachelines with other data. Align the start and end of I/O buffers to IOB_ZLEN, which is larger than any cacheline size we expect to encounter. Signed-off-by: Michael Brown --- src/core/iobuf.c | 38 +++++++++++++++++++------------------- src/include/ipxe/iobuf.h | 6 +++++- src/tests/iobuf_test.c | 8 +++++++- 3 files changed, 31 insertions(+), 21 deletions(-) (limited to 'src/tests') diff --git a/src/core/iobuf.c b/src/core/iobuf.c index 9f8a263d2..78fa23924 100644 --- a/src/core/iobuf.c +++ b/src/core/iobuf.c @@ -47,22 +47,26 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { struct io_buffer *iobuf; + size_t headroom; + size_t tailroom; size_t padding; size_t threshold; unsigned int align_log2; void *data; - /* Calculate padding required below alignment boundary to - * ensure that a correctly aligned inline struct io_buffer - * could fit (regardless of the requested offset). + /* Round up requested alignment and calculate initial headroom + * and tailroom to ensure that no cachelines are shared + * between I/O buffer data and other data structures. */ - padding = ( sizeof ( *iobuf ) + __alignof__ ( *iobuf ) - 1 ); - - /* Round up requested alignment to at least the size of the - * padding, to simplify subsequent calculations. - */ - if ( align < padding ) - align = padding; + if ( align < IOB_ZLEN ) + align = IOB_ZLEN; + headroom = ( offset & ( IOB_ZLEN - 1 ) ); + tailroom = ( ( - len - offset ) & ( IOB_ZLEN - 1 ) ); + padding = ( headroom + tailroom ); + offset -= headroom; + len += padding; + if ( len < padding ) + return NULL; /* Round up alignment to the nearest power of two, avoiding * a potentially undefined shift operation. @@ -73,8 +77,8 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { align = ( 1UL << align_log2 ); /* Calculate length threshold */ - assert ( align >= padding ); - threshold = ( align - padding ); + assert ( align >= sizeof ( *iobuf ) ); + threshold = ( align - sizeof ( *iobuf ) ); /* Allocate buffer plus an inline descriptor as a single unit, * unless doing so would push the total size over the @@ -82,11 +86,6 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { */ if ( len <= threshold ) { - /* Round up buffer length to ensure that struct - * io_buffer is aligned. - */ - len += ( ( - len - offset ) & ( __alignof__ ( *iobuf ) - 1 ) ); - /* Allocate memory for buffer plus descriptor */ data = malloc_phys_offset ( len + sizeof ( *iobuf ), align, offset ); @@ -111,7 +110,8 @@ struct io_buffer * alloc_iob_raw ( size_t len, size_t align, size_t offset ) { /* Populate descriptor */ memset ( &iobuf->map, 0, sizeof ( iobuf->map ) ); - iobuf->head = iobuf->data = iobuf->tail = data; + iobuf->head = data; + iobuf->data = iobuf->tail = ( data + headroom ); iobuf->end = ( data + len ); return iobuf; @@ -266,7 +266,7 @@ struct io_buffer * iob_concatenate ( struct list_head *list ) { len += iob_len ( iobuf ); /* Allocate new I/O buffer */ - concatenated = alloc_iob_raw ( len, __alignof__ ( *iobuf ), 0 ); + concatenated = alloc_iob_raw ( len, IOB_ZLEN, 0 ); if ( ! concatenated ) return NULL; diff --git a/src/include/ipxe/iobuf.h b/src/include/ipxe/iobuf.h index 3e079c064..2bdca6b5d 100644 --- a/src/include/ipxe/iobuf.h +++ b/src/include/ipxe/iobuf.h @@ -15,11 +15,15 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include /** - * Minimum I/O buffer length + * Minimum I/O buffer length and alignment * * alloc_iob() will round up the allocated length to this size if * necessary. This is used on behalf of hardware that is not capable * of auto-padding. + * + * This length must be at least as large as the largest cacheline size + * that we expect to encounter, to allow for platforms where DMA + * devices are not in the same coherency domain as the CPU cache. */ #define IOB_ZLEN 128 diff --git a/src/tests/iobuf_test.c b/src/tests/iobuf_test.c index a417c2e8c..27fbccf0d 100644 --- a/src/tests/iobuf_test.c +++ b/src/tests/iobuf_test.c @@ -62,7 +62,7 @@ static inline void alloc_iob_okx ( size_t len, size_t align, size_t offset, "offset %#zx\n", iobuf, virt_to_phys ( iobuf->data ), iob_tailroom ( iobuf ), len, align, offset ); - /* Validate requested length and alignment */ + /* Validate requested length and data alignment */ okx ( ( ( ( intptr_t ) iobuf ) & ( __alignof__ ( *iobuf ) - 1 ) ) == 0, file, line ); okx ( iob_tailroom ( iobuf ) >= len, file, line ); @@ -70,6 +70,12 @@ static inline void alloc_iob_okx ( size_t len, size_t align, size_t offset, ( ( virt_to_phys ( iobuf->data ) & ( align - 1 ) ) == ( offset & ( align - 1 ) ) ) ), file, line ); + /* Validate overall buffer alignment */ + okx ( ( ( ( intptr_t ) iobuf->head ) & ( IOB_ZLEN - 1 ) ) == 0, + file, line ); + okx ( ( ( ( intptr_t ) iobuf->end ) & ( IOB_ZLEN - 1 ) ) == 0, + file, line ); + /* Overwrite entire content of I/O buffer (for Valgrind) */ memset ( iob_put ( iobuf, len ), 0x55, len ); -- cgit v1.2.3-55-g7522 From 1e3fb1b37e16cd7cd30f6b20b9eee929568f35a9 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 15 Jul 2025 14:08:15 +0100 Subject: [init] Show initialisation function names in debug messages Signed-off-by: Michael Brown --- src/arch/x86/core/cpuid_settings.c | 1 + src/arch/x86/core/debugcon.c | 1 + src/arch/x86/core/pci_autoboot.c | 1 + src/arch/x86/core/video_subr.c | 1 + src/arch/x86/interface/pcbios/bios_cachedhcp.c | 1 + src/arch/x86/interface/pcbios/int13con.c | 1 + src/arch/x86/interface/pcbios/pcicloud.c | 1 + src/arch/x86/interface/pxe/pxe_call.c | 1 + src/arch/x86/interface/vmware/guestinfo.c | 1 + src/arch/x86/interface/vmware/vmconsole.c | 1 + src/core/acpi_settings.c | 1 + src/core/fnrec.c | 1 + src/core/init.c | 4 +++- src/core/malloc.c | 1 + src/core/memmap_settings.c | 1 + src/core/process.c | 1 + src/core/serial.c | 1 + src/core/settings.c | 1 + src/core/timer.c | 1 + src/crypto/certstore.c | 1 + src/crypto/des.c | 1 + src/crypto/x25519.c | 1 + src/drivers/bus/pci_settings.c | 1 + src/drivers/bus/usb_settings.c | 1 + src/drivers/net/efi/snponly.c | 1 + src/image/embedded.c | 1 + src/include/ipxe/init.h | 1 + src/interface/efi/efi_cacert.c | 1 + src/interface/efi/efi_console.c | 1 + src/interface/efi/efi_fdt.c | 1 + src/interface/efi/efi_settings.c | 1 + src/interface/efi/efiprefix.c | 1 + src/interface/smbios/smbios_settings.c | 1 + src/net/netdev_settings.c | 1 + src/tests/bofm_test.c | 1 + src/tests/test.c | 1 + 36 files changed, 38 insertions(+), 1 deletion(-) (limited to 'src/tests') diff --git a/src/arch/x86/core/cpuid_settings.c b/src/arch/x86/core/cpuid_settings.c index 9bc69f477..44d38debc 100644 --- a/src/arch/x86/core/cpuid_settings.c +++ b/src/arch/x86/core/cpuid_settings.c @@ -250,6 +250,7 @@ static void cpuid_settings_init ( void ) { /** CPUID settings initialiser */ struct init_fn cpuid_settings_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "cpuid", .initialise = cpuid_settings_init, }; diff --git a/src/arch/x86/core/debugcon.c b/src/arch/x86/core/debugcon.c index 60de61f55..0e3a5dfc7 100644 --- a/src/arch/x86/core/debugcon.c +++ b/src/arch/x86/core/debugcon.c @@ -86,5 +86,6 @@ static void debugcon_init ( void ) { * Debug port console initialisation function */ struct init_fn debugcon_init_fn __init_fn ( INIT_EARLY ) = { + .name = "debugcon", .initialise = debugcon_init, }; diff --git a/src/arch/x86/core/pci_autoboot.c b/src/arch/x86/core/pci_autoboot.c index 337598091..243e45026 100644 --- a/src/arch/x86/core/pci_autoboot.c +++ b/src/arch/x86/core/pci_autoboot.c @@ -44,5 +44,6 @@ static void pci_autoboot_init ( void ) { /** PCI autoboot device initialisation function */ struct init_fn pci_autoboot_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "autoboot", .initialise = pci_autoboot_init, }; diff --git a/src/arch/x86/core/video_subr.c b/src/arch/x86/core/video_subr.c index f5cc4cdd4..4e9ef466f 100644 --- a/src/arch/x86/core/video_subr.c +++ b/src/arch/x86/core/video_subr.c @@ -109,5 +109,6 @@ struct console_driver vga_console __console_driver = { }; struct init_fn video_init_fn __init_fn ( INIT_EARLY ) = { + .name = "video", .initialise = video_init, }; diff --git a/src/arch/x86/interface/pcbios/bios_cachedhcp.c b/src/arch/x86/interface/pcbios/bios_cachedhcp.c index 897858143..60191c9c5 100644 --- a/src/arch/x86/interface/pcbios/bios_cachedhcp.c +++ b/src/arch/x86/interface/pcbios/bios_cachedhcp.c @@ -74,5 +74,6 @@ static void cachedhcp_init ( void ) { /** Cached DHCPACK initialisation function */ struct init_fn cachedhcp_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "cachedhcp", .initialise = cachedhcp_init, }; diff --git a/src/arch/x86/interface/pcbios/int13con.c b/src/arch/x86/interface/pcbios/int13con.c index 8106cd153..925228874 100644 --- a/src/arch/x86/interface/pcbios/int13con.c +++ b/src/arch/x86/interface/pcbios/int13con.c @@ -288,6 +288,7 @@ static void int13con_init ( void ) { * INT13 console initialisation function */ struct init_fn int13con_init_fn __init_fn ( INIT_CONSOLE ) = { + .name = "int13con", .initialise = int13con_init, }; diff --git a/src/arch/x86/interface/pcbios/pcicloud.c b/src/arch/x86/interface/pcbios/pcicloud.c index f7d4a2da1..5d4d02ac4 100644 --- a/src/arch/x86/interface/pcbios/pcicloud.c +++ b/src/arch/x86/interface/pcbios/pcicloud.c @@ -191,5 +191,6 @@ static void pcicloud_init ( void ) { /** Cloud VM PCI configuration space access initialisation function */ struct init_fn pcicloud_init_fn __init_fn ( INIT_EARLY ) = { + .name = "pcicloud", .initialise = pcicloud_init, }; diff --git a/src/arch/x86/interface/pxe/pxe_call.c b/src/arch/x86/interface/pxe/pxe_call.c index a530f919f..9a6a20dd3 100644 --- a/src/arch/x86/interface/pxe/pxe_call.c +++ b/src/arch/x86/interface/pxe/pxe_call.c @@ -257,6 +257,7 @@ static void pxe_init_structures ( void ) { /** PXE structure initialiser */ struct init_fn pxe_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "pxe", .initialise = pxe_init_structures, }; diff --git a/src/arch/x86/interface/vmware/guestinfo.c b/src/arch/x86/interface/vmware/guestinfo.c index 4134515c1..c181d96e9 100644 --- a/src/arch/x86/interface/vmware/guestinfo.c +++ b/src/arch/x86/interface/vmware/guestinfo.c @@ -200,6 +200,7 @@ static void guestinfo_init ( void ) { /** GuestInfo settings initialiser */ struct init_fn guestinfo_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "guestinfo", .initialise = guestinfo_init, }; diff --git a/src/arch/x86/interface/vmware/vmconsole.c b/src/arch/x86/interface/vmware/vmconsole.c index f7df4f75b..3b892c837 100644 --- a/src/arch/x86/interface/vmware/vmconsole.c +++ b/src/arch/x86/interface/vmware/vmconsole.c @@ -134,5 +134,6 @@ static void vmconsole_init ( void ) { * VMware logfile console initialisation function */ struct init_fn vmconsole_init_fn __init_fn ( INIT_CONSOLE ) = { + .name = "vmconsole", .initialise = vmconsole_init, }; diff --git a/src/core/acpi_settings.c b/src/core/acpi_settings.c index cdee1f865..63f271855 100644 --- a/src/core/acpi_settings.c +++ b/src/core/acpi_settings.c @@ -156,5 +156,6 @@ static void acpi_settings_init ( void ) { /** ACPI settings initialiser */ struct init_fn acpi_settings_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "acpi", .initialise = acpi_settings_init, }; diff --git a/src/core/fnrec.c b/src/core/fnrec.c index 0430817f8..b63ffc1f5 100644 --- a/src/core/fnrec.c +++ b/src/core/fnrec.c @@ -177,6 +177,7 @@ static void fnrec_init ( void ) { } struct init_fn fnrec_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "fnrec", .initialise = fnrec_init, }; diff --git a/src/core/init.c b/src/core/init.c index c13fd1667..406d22d7b 100644 --- a/src/core/init.c +++ b/src/core/init.c @@ -53,8 +53,10 @@ void initialise ( void ) { struct init_fn *init_fn; /* Call registered initialisation functions */ - for_each_table_entry ( init_fn, INIT_FNS ) + for_each_table_entry ( init_fn, INIT_FNS ) { + DBGC ( colour, "INIT initialising %s...\n", init_fn->name ); init_fn->initialise (); + } } /** diff --git a/src/core/malloc.c b/src/core/malloc.c index 545927a30..a05871085 100644 --- a/src/core/malloc.c +++ b/src/core/malloc.c @@ -765,6 +765,7 @@ static void init_heap ( void ) { /** Memory allocator initialisation function */ struct init_fn heap_init_fn __init_fn ( INIT_EARLY ) = { + .name = "heap", .initialise = init_heap, }; diff --git a/src/core/memmap_settings.c b/src/core/memmap_settings.c index d07e9747e..f54de9150 100644 --- a/src/core/memmap_settings.c +++ b/src/core/memmap_settings.c @@ -243,6 +243,7 @@ static void memmap_settings_init ( void ) { /** Memory map settings initialiser */ struct init_fn memmap_settings_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "memmap", .initialise = memmap_settings_init, }; diff --git a/src/core/process.c b/src/core/process.c index 69852c416..c944b6f50 100644 --- a/src/core/process.c +++ b/src/core/process.c @@ -133,5 +133,6 @@ static void init_processes ( void ) { /** Process initialiser */ struct init_fn process_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "process", .initialise = init_processes, }; diff --git a/src/core/serial.c b/src/core/serial.c index 4b569ffad..0883ad051 100644 --- a/src/core/serial.c +++ b/src/core/serial.c @@ -180,6 +180,7 @@ static void serial_shutdown ( int flags __unused ) { /** Serial console initialisation function */ struct init_fn serial_console_init_fn __init_fn ( INIT_CONSOLE ) = { + .name = "serial", .initialise = serial_init, }; diff --git a/src/core/settings.c b/src/core/settings.c index 9fbf753ab..05e495dcf 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -2819,5 +2819,6 @@ static void builtin_init ( void ) { /** Built-in settings initialiser */ struct init_fn builtin_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "builtin", .initialise = builtin_init, }; diff --git a/src/core/timer.c b/src/core/timer.c index 24745cef7..d45797adb 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -170,6 +170,7 @@ static void timer_probe ( void ) { /** Timer initialisation function */ struct init_fn timer_init_fn __init_fn ( INIT_EARLY ) = { + .name = "timer", .initialise = timer_probe, }; diff --git a/src/crypto/certstore.c b/src/crypto/certstore.c index 81179f9cc..aad874297 100644 --- a/src/crypto/certstore.c +++ b/src/crypto/certstore.c @@ -210,6 +210,7 @@ static void certstore_init ( void ) { /** Certificate store initialisation function */ struct init_fn certstore_init_fn __init_fn ( INIT_LATE ) = { + .name = "certstore", .initialise = certstore_init, }; diff --git a/src/crypto/des.c b/src/crypto/des.c index 6918bec3e..206f78d50 100644 --- a/src/crypto/des.c +++ b/src/crypto/des.c @@ -369,6 +369,7 @@ static void des_init ( void ) { /** Initialisation function */ struct init_fn des_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "des", .initialise = des_init, }; diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c index 995cfa352..41bc5fc5e 100644 --- a/src/crypto/x25519.c +++ b/src/crypto/x25519.c @@ -334,6 +334,7 @@ static void x25519_init_constants ( void ) { /** Initialisation function */ struct init_fn x25519_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "x25519", .initialise = x25519_init_constants, }; diff --git a/src/drivers/bus/pci_settings.c b/src/drivers/bus/pci_settings.c index 84aa76827..fc73c651e 100644 --- a/src/drivers/bus/pci_settings.c +++ b/src/drivers/bus/pci_settings.c @@ -125,5 +125,6 @@ static void pci_settings_init ( void ) { /** PCI device settings initialiser */ struct init_fn pci_settings_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "pci", .initialise = pci_settings_init, }; diff --git a/src/drivers/bus/usb_settings.c b/src/drivers/bus/usb_settings.c index 4fd190d83..bb01f34d5 100644 --- a/src/drivers/bus/usb_settings.c +++ b/src/drivers/bus/usb_settings.c @@ -173,5 +173,6 @@ static void usb_settings_init ( void ) { /** USB device settings initialiser */ struct init_fn usb_settings_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "usb", .initialise = usb_settings_init, }; diff --git a/src/drivers/net/efi/snponly.c b/src/drivers/net/efi/snponly.c index f0a5277a2..876479133 100644 --- a/src/drivers/net/efi/snponly.c +++ b/src/drivers/net/efi/snponly.c @@ -259,5 +259,6 @@ static void chained_init ( void ) { /** EFI chainloaded-device-only initialisation function */ struct init_fn chained_init_fn __init_fn ( INIT_LATE ) = { + .name = "chained", .initialise = chained_init, }; diff --git a/src/image/embedded.c b/src/image/embedded.c index 2934d4ee7..652cfc85f 100644 --- a/src/image/embedded.c +++ b/src/image/embedded.c @@ -80,5 +80,6 @@ static void embedded_init ( void ) { /** Embedded image initialisation function */ struct init_fn embedded_init_fn __init_fn ( INIT_LATE ) = { + .name = "embedded", .initialise = embedded_init, }; diff --git a/src/include/ipxe/init.h b/src/include/ipxe/init.h index 32927e3a6..da01b2953 100644 --- a/src/include/ipxe/init.h +++ b/src/include/ipxe/init.h @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * call to initialise(). */ struct init_fn { + const char *name; void ( * initialise ) ( void ); }; diff --git a/src/interface/efi/efi_cacert.c b/src/interface/efi/efi_cacert.c index 2b6c5c343..64bb0bae2 100644 --- a/src/interface/efi/efi_cacert.c +++ b/src/interface/efi/efi_cacert.c @@ -178,6 +178,7 @@ static void efi_cacert_init ( void ) { /** EFI CA certificates initialisation function */ struct init_fn efi_cacert_init_fn __init_fn ( INIT_LATE ) = { + .name = "eficacert", .initialise = efi_cacert_init, }; diff --git a/src/interface/efi/efi_console.c b/src/interface/efi/efi_console.c index 9fc3c65c0..4557671a0 100644 --- a/src/interface/efi/efi_console.c +++ b/src/interface/efi/efi_console.c @@ -448,5 +448,6 @@ static void efi_console_init ( void ) { * EFI console initialisation function */ struct init_fn efi_console_init_fn __init_fn ( INIT_EARLY ) = { + .name = "eficonsole", .initialise = efi_console_init, }; diff --git a/src/interface/efi/efi_fdt.c b/src/interface/efi/efi_fdt.c index 3a90fd7ce..3c249693e 100644 --- a/src/interface/efi/efi_fdt.c +++ b/src/interface/efi/efi_fdt.c @@ -77,6 +77,7 @@ static void efi_fdt_init ( void ) { /** EFI Flattened Device Tree initialisation function */ struct init_fn efi_fdt_init_fn __init_fn ( INIT_EARLY ) = { + .name = "efifdt", .initialise = efi_fdt_init, }; diff --git a/src/interface/efi/efi_settings.c b/src/interface/efi/efi_settings.c index cde0ff8d1..5ddbe12f1 100644 --- a/src/interface/efi/efi_settings.c +++ b/src/interface/efi/efi_settings.c @@ -232,5 +232,6 @@ static void efivars_init ( void ) { /** EFI variable settings initialiser */ struct init_fn efivars_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "efivars", .initialise = efivars_init, }; diff --git a/src/interface/efi/efiprefix.c b/src/interface/efi/efiprefix.c index 10d8f0bf6..ddce6aa60 100644 --- a/src/interface/efi/efiprefix.c +++ b/src/interface/efi/efiprefix.c @@ -98,6 +98,7 @@ static void efi_init_application ( void ) { /** EFI application initialisation function */ struct init_fn efi_init_application_fn __init_fn ( INIT_NORMAL ) = { + .name = "efi", .initialise = efi_init_application, }; diff --git a/src/interface/smbios/smbios_settings.c b/src/interface/smbios/smbios_settings.c index 1fe545f38..6358a4709 100644 --- a/src/interface/smbios/smbios_settings.c +++ b/src/interface/smbios/smbios_settings.c @@ -200,6 +200,7 @@ static void smbios_init ( void ) { /** SMBIOS settings initialiser */ struct init_fn smbios_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "smbios", .initialise = smbios_init, }; diff --git a/src/net/netdev_settings.c b/src/net/netdev_settings.c index 9432dc2fa..90b804c6c 100644 --- a/src/net/netdev_settings.c +++ b/src/net/netdev_settings.c @@ -429,6 +429,7 @@ static void netdev_redirect_settings_init ( void ) { /** "netX" settings initialiser */ struct init_fn netdev_redirect_settings_init_fn __init_fn ( INIT_LATE ) = { + .name = "netX", .initialise = netdev_redirect_settings_init, }; diff --git a/src/tests/bofm_test.c b/src/tests/bofm_test.c index 6d472bc7e..bc400284f 100644 --- a/src/tests/bofm_test.c +++ b/src/tests/bofm_test.c @@ -278,5 +278,6 @@ static void bofm_test_init ( void ) { /** BOFM test initialisation function */ struct init_fn bofm_test_init_fn __init_fn ( INIT_NORMAL ) = { + .name = "bofm", .initialise = bofm_test_init, }; diff --git a/src/tests/test.c b/src/tests/test.c index 9fa12e27a..e4f5eb838 100644 --- a/src/tests/test.c +++ b/src/tests/test.c @@ -180,5 +180,6 @@ static void test_init ( void ) { /** Self-test initialisation function */ struct init_fn test_init_fn __init_fn ( INIT_EARLY ) = { + .name = "test", .initialise = test_init, }; -- cgit v1.2.3-55-g7522 From fb082bd4cd6a49609785b3b3537b1713d568f7c4 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 22 Jul 2025 13:37:05 +0100 Subject: [fdt] Add ability to locate node by phandle Signed-off-by: Michael Brown --- src/core/fdt.c | 51 ++++++++++++++++++ src/include/ipxe/fdt.h | 2 + src/tests/fdt_test.c | 143 +++++++++++++++++++++++++++---------------------- 3 files changed, 131 insertions(+), 65 deletions(-) (limited to 'src/tests') diff --git a/src/core/fdt.c b/src/core/fdt.c index 149348199..6989690bf 100644 --- a/src/core/fdt.c +++ b/src/core/fdt.c @@ -482,6 +482,57 @@ int fdt_alias ( struct fdt *fdt, const char *name, unsigned int *offset ) { return 0; } +/** + * Find node by package handle (phandle) + * + * @v fdt Device tree + * @v phandle Package handle + * @v offset Offset to fill in + * @ret rc Return status code + */ +int fdt_phandle ( struct fdt *fdt, uint32_t phandle, unsigned int *offset ) { + struct fdt_descriptor desc; + uint32_t value; + int depth; + int rc; + + /* Initialise offset */ + *offset = 0; + + /* Find node with matching phandle */ + for ( depth = -1 ; ; depth += desc.depth, *offset = desc.next ) { + + /* Describe token */ + if ( ( rc = fdt_describe ( fdt, *offset, &desc ) ) != 0 ) { + DBGC ( fdt, "FDT +%#04x has malformed node: %s\n", + *offset, strerror ( rc ) ); + return rc; + } + + /* Terminate when we exit the root node */ + if ( ( depth == 0 ) && ( desc.depth < 0 ) ) + break; + + /* Ignore non-nodes */ + if ( ( ! desc.name ) || desc.data ) + continue; + + /* Check for matching "phandle" or "linux-phandle" property */ + if ( ( ( ( rc = fdt_u32 ( fdt, *offset, "phandle", + &value ) ) == 0 ) || + ( ( rc = fdt_u32 ( fdt, *offset, "linux,phandle", + &value ) ) == 0 ) ) && + ( value == phandle ) ) { + DBGC2 ( fdt, "FDT +%#04x has phandle %#02x\n", + *offset, phandle ); + return 0; + } + } + + DBGC ( fdt, "FDT has no phandle %#02x\n", phandle ); + return -ENOENT; +} + /** * Find property * diff --git a/src/include/ipxe/fdt.h b/src/include/ipxe/fdt.h index d5a0d2179..c73389ad7 100644 --- a/src/include/ipxe/fdt.h +++ b/src/include/ipxe/fdt.h @@ -176,6 +176,8 @@ extern int fdt_path ( struct fdt *fdt, const char *path, unsigned int *offset ); extern int fdt_alias ( struct fdt *fdt, const char *name, unsigned int *offset ); +extern int fdt_phandle ( struct fdt *fdt, uint32_t phandle, + unsigned int *offset ); extern const char * fdt_strings ( struct fdt *fdt, unsigned int offset, const char *name, unsigned int *count ); extern const char * fdt_string ( struct fdt *fdt, unsigned int offset, diff --git a/src/tests/fdt_test.c b/src/tests/fdt_test.c index 0be0acdbc..099a093b4 100644 --- a/src/tests/fdt_test.c +++ b/src/tests/fdt_test.c @@ -39,10 +39,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** Simplified QEMU sifive_u device tree blob */ static const uint8_t sifive_u[] = { - 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x05, 0x61, 0x00, 0x00, 0x00, 0x38, - 0x00, 0x00, 0x04, 0x7c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, - 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, - 0x00, 0x00, 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd0, 0x0d, 0xfe, 0xed, 0x00, 0x00, 0x05, 0x8f, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x04, 0x9c, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x11, + 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, + 0x00, 0x00, 0x04, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, @@ -90,70 +90,74 @@ static const uint8_t sifive_u[] = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1b, 0x72, 0x69, 0x73, 0x63, 0x76, 0x2c, 0x63, 0x70, - 0x75, 0x2d, 0x69, 0x6e, 0x74, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, - 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x40, 0x38, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x07, - 0x00, 0x00, 0x00, 0x5d, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x00, 0x00, + 0x75, 0x2d, 0x69, 0x6e, 0x74, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x01, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x40, 0x38, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x5d, 0x6d, 0x65, 0x6d, 0x6f, + 0x72, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x01, 0x73, 0x6f, 0x63, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, + 0x00, 0x00, 0x00, 0x1b, 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2d, 0x62, + 0x75, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x01, 0x73, 0x65, 0x72, 0x69, + 0x61, 0x6c, 0x40, 0x31, 0x30, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x69, - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, - 0x73, 0x6f, 0x63, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x1b, - 0x73, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x2d, 0x62, 0x75, 0x73, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, - 0x00, 0x00, 0x00, 0x01, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x40, 0x31, - 0x30, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x1b, - 0x73, 0x69, 0x66, 0x69, 0x76, 0x65, 0x2c, 0x75, 0x61, 0x72, 0x74, 0x30, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, - 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x40, 0x31, 0x30, 0x30, - 0x39, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x06, - 0x00, 0x00, 0x00, 0xab, 0x52, 0x54, 0x00, 0x12, 0x34, 0x56, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xbd, - 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, - 0x00, 0x00, 0x00, 0xc8, 0x67, 0x6d, 0x69, 0x69, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xd1, - 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x16, - 0x00, 0x00, 0x00, 0x1b, 0x73, 0x69, 0x66, 0x69, 0x76, 0x65, 0x2c, 0x66, - 0x75, 0x35, 0x34, 0x30, 0x2d, 0x63, 0x30, 0x30, 0x30, 0x2d, 0x67, 0x65, - 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, - 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, 0x02, 0x54, 0x0b, 0xe4, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0d, + 0x00, 0x00, 0x00, 0x1b, 0x73, 0x69, 0x66, 0x69, 0x76, 0x65, 0x2c, 0x75, + 0x61, 0x72, 0x74, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, - 0x2d, 0x70, 0x68, 0x79, 0x40, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x31, 0x30, 0x30, 0x39, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0f, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb9, 0x52, 0x54, 0x00, 0x12, + 0x34, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0xd6, 0x67, 0x6d, 0x69, 0x69, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, + 0x00, 0x00, 0x00, 0xdf, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x69, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x0a, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x1b, 0x73, 0x69, 0x66, 0x69, + 0x76, 0x65, 0x2c, 0x66, 0x75, 0x35, 0x34, 0x30, 0x2d, 0x63, 0x30, 0x30, + 0x30, 0x2d, 0x67, 0x65, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x02, + 0x54, 0x0b, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x01, 0x65, 0x74, 0x68, 0x65, + 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x70, 0x68, 0x79, 0x40, 0x30, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x69, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, + 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x09, 0x23, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x23, - 0x73, 0x69, 0x7a, 0x65, 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x63, - 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x69, 0x62, 0x6c, 0x65, 0x00, 0x6d, 0x6f, - 0x64, 0x65, 0x6c, 0x00, 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x2d, 0x70, - 0x61, 0x74, 0x68, 0x00, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x30, 0x00, - 0x65, 0x74, 0x68, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x30, 0x00, 0x74, 0x69, - 0x6d, 0x65, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x66, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x6e, 0x63, 0x79, 0x00, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, - 0x74, 0x79, 0x70, 0x65, 0x00, 0x72, 0x65, 0x67, 0x00, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x00, 0x72, 0x69, 0x73, 0x63, 0x76, 0x2c, 0x69, 0x73, - 0x61, 0x00, 0x23, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, - 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x69, 0x6e, 0x74, 0x65, 0x72, - 0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, - 0x6c, 0x65, 0x72, 0x00, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x00, 0x6c, - 0x6f, 0x63, 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x63, 0x2d, 0x61, 0x64, 0x64, - 0x72, 0x65, 0x73, 0x73, 0x00, 0x70, 0x68, 0x79, 0x2d, 0x68, 0x61, 0x6e, - 0x64, 0x6c, 0x65, 0x00, 0x70, 0x68, 0x79, 0x2d, 0x6d, 0x6f, 0x64, 0x65, - 0x00, 0x72, 0x65, 0x67, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x6d, - 0x61, 0x78, 0x2d, 0x73, 0x70, 0x65, 0x65, 0x64, 0x00 + 0x00, 0x00, 0x00, 0x09, 0x23, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, + 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x23, 0x73, 0x69, 0x7a, 0x65, + 0x2d, 0x63, 0x65, 0x6c, 0x6c, 0x73, 0x00, 0x63, 0x6f, 0x6d, 0x70, 0x61, + 0x74, 0x69, 0x62, 0x6c, 0x65, 0x00, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x00, + 0x73, 0x74, 0x64, 0x6f, 0x75, 0x74, 0x2d, 0x70, 0x61, 0x74, 0x68, 0x00, + 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x30, 0x00, 0x65, 0x74, 0x68, 0x65, + 0x72, 0x6e, 0x65, 0x74, 0x30, 0x00, 0x74, 0x69, 0x6d, 0x65, 0x62, 0x61, + 0x73, 0x65, 0x2d, 0x66, 0x72, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x79, + 0x00, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, + 0x00, 0x72, 0x65, 0x67, 0x00, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x00, + 0x72, 0x69, 0x73, 0x63, 0x76, 0x2c, 0x69, 0x73, 0x61, 0x00, 0x23, 0x69, + 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, 0x2d, 0x63, 0x65, 0x6c, + 0x6c, 0x73, 0x00, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x72, 0x75, 0x70, 0x74, + 0x2d, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x00, + 0x6c, 0x69, 0x6e, 0x75, 0x78, 0x2c, 0x70, 0x68, 0x61, 0x6e, 0x64, 0x6c, + 0x65, 0x00, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x00, 0x6c, 0x6f, 0x63, + 0x61, 0x6c, 0x2d, 0x6d, 0x61, 0x63, 0x2d, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x00, 0x70, 0x68, 0x79, 0x2d, 0x68, 0x61, 0x6e, 0x64, 0x6c, + 0x65, 0x00, 0x70, 0x68, 0x79, 0x2d, 0x6d, 0x6f, 0x64, 0x65, 0x00, 0x72, + 0x65, 0x67, 0x2d, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x00, 0x6d, 0x61, 0x78, + 0x2d, 0x73, 0x70, 0x65, 0x65, 0x64, 0x00 }; /** @@ -257,6 +261,15 @@ static void fdt_test_exec ( void ) { ok ( ( string = fdt_string ( &fdt, offset, "phy-mode" ) ) != NULL ); ok ( strcmp ( string, "gmii" ) == 0 ); + /* Verify phandle lookup */ + ok ( fdt_phandle ( &fdt, 0x03, &offset ) == 0 ); + ok ( fdt_describe ( &fdt, offset, &desc ) == 0 ); + ok ( strcmp ( desc.name, "interrupt-controller" ) == 0 ); + ok ( fdt_phandle ( &fdt, 0x08, &offset ) == 0 ); + ok ( fdt_describe ( &fdt, offset, &desc ) == 0 ); + ok ( strcmp ( desc.name, "ethernet-phy@0" ) == 0 ); + ok ( fdt_phandle ( &fdt, 0x2a, &offset ) != 0 ); + /* Verify node description */ ok ( fdt_path ( &fdt, "/memory@80000000", &offset ) == 0 ); ok ( fdt_describe ( &fdt, offset, &desc ) == 0 ); -- cgit v1.2.3-55-g7522 From 5f10b7455547fc563caab58f8941111346346433 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 4 Aug 2025 14:52:00 +0100 Subject: [fdt] Use phandle as device location Consumption of phandles will be in the form of locating a functional device (e.g. a GPIO device, or an I2C device, or a reset controller) by phandle, rather than locating the device tree node to which the phandle refers. Repurpose fdt_phandle() to obtain the phandle value (instead of searching by phandle), and record this value as the bus location within the generic device structure. Signed-off-by: Michael Brown --- src/core/fdt.c | 73 ++++++++++++++--------------------------------- src/drivers/bus/devtree.c | 1 + src/include/ipxe/fdt.h | 3 +- src/tests/fdt_test.c | 19 ++++++------ 4 files changed, 34 insertions(+), 62 deletions(-) (limited to 'src/tests') diff --git a/src/core/fdt.c b/src/core/fdt.c index 6989690bf..ae723213b 100644 --- a/src/core/fdt.c +++ b/src/core/fdt.c @@ -482,57 +482,6 @@ int fdt_alias ( struct fdt *fdt, const char *name, unsigned int *offset ) { return 0; } -/** - * Find node by package handle (phandle) - * - * @v fdt Device tree - * @v phandle Package handle - * @v offset Offset to fill in - * @ret rc Return status code - */ -int fdt_phandle ( struct fdt *fdt, uint32_t phandle, unsigned int *offset ) { - struct fdt_descriptor desc; - uint32_t value; - int depth; - int rc; - - /* Initialise offset */ - *offset = 0; - - /* Find node with matching phandle */ - for ( depth = -1 ; ; depth += desc.depth, *offset = desc.next ) { - - /* Describe token */ - if ( ( rc = fdt_describe ( fdt, *offset, &desc ) ) != 0 ) { - DBGC ( fdt, "FDT +%#04x has malformed node: %s\n", - *offset, strerror ( rc ) ); - return rc; - } - - /* Terminate when we exit the root node */ - if ( ( depth == 0 ) && ( desc.depth < 0 ) ) - break; - - /* Ignore non-nodes */ - if ( ( ! desc.name ) || desc.data ) - continue; - - /* Check for matching "phandle" or "linux-phandle" property */ - if ( ( ( ( rc = fdt_u32 ( fdt, *offset, "phandle", - &value ) ) == 0 ) || - ( ( rc = fdt_u32 ( fdt, *offset, "linux,phandle", - &value ) ) == 0 ) ) && - ( value == phandle ) ) { - DBGC2 ( fdt, "FDT +%#04x has phandle %#02x\n", - *offset, phandle ); - return 0; - } - } - - DBGC ( fdt, "FDT has no phandle %#02x\n", phandle ); - return -ENOENT; -} - /** * Find property * @@ -730,6 +679,28 @@ int fdt_u32 ( struct fdt *fdt, unsigned int offset, const char *name, return 0; } +/** + * Get package handle (phandle) property + * + * @v fdt Device tree + * @v offset Starting node offset + * @ret phandle Package handle, or 0 on error + */ +uint32_t fdt_phandle ( struct fdt *fdt, unsigned int offset ) { + uint32_t phandle; + int rc; + + /* Get "phandle" or "linux,phandle" property */ + if ( ( ( rc = fdt_u32 ( fdt, offset, "phandle", &phandle ) ) == 0 ) || + ( ( rc = fdt_u32 ( fdt, offset, "linux,phandle", + &phandle ) ) == 0 ) ) { + assert ( phandle != 0 ); + return phandle; + } + + return 0; +} + /** * Get region cell size specification * diff --git a/src/drivers/bus/devtree.c b/src/drivers/bus/devtree.c index 59bbc9bf7..cd5bb09a0 100644 --- a/src/drivers/bus/devtree.c +++ b/src/drivers/bus/devtree.c @@ -219,6 +219,7 @@ int dt_probe_node ( struct device *parent, unsigned int offset ) { dt->name = dt->dev.name; snprintf ( dt->dev.name, sizeof ( dt->dev.name ), "%s", name ); dt->dev.desc.bus_type = BUS_TYPE_DT; + dt->dev.desc.location = fdt_phandle ( &sysfdt, offset ); dt->dev.parent = parent; INIT_LIST_HEAD ( &dt->dev.children ); list_add_tail ( &dt->dev.siblings, &parent->children ); diff --git a/src/include/ipxe/fdt.h b/src/include/ipxe/fdt.h index c73389ad7..eec02c5b3 100644 --- a/src/include/ipxe/fdt.h +++ b/src/include/ipxe/fdt.h @@ -176,8 +176,6 @@ extern int fdt_path ( struct fdt *fdt, const char *path, unsigned int *offset ); extern int fdt_alias ( struct fdt *fdt, const char *name, unsigned int *offset ); -extern int fdt_phandle ( struct fdt *fdt, uint32_t phandle, - unsigned int *offset ); extern const char * fdt_strings ( struct fdt *fdt, unsigned int offset, const char *name, unsigned int *count ); extern const char * fdt_string ( struct fdt *fdt, unsigned int offset, @@ -189,6 +187,7 @@ extern int fdt_u64 ( struct fdt *fdt, unsigned int offset, const char *name, uint64_t *value ); extern int fdt_u32 ( struct fdt *fdt, unsigned int offset, const char *name, uint32_t *value ); +extern uint32_t fdt_phandle ( struct fdt *fdt, unsigned int offset ); extern void fdt_reg_cells ( struct fdt *fdt, unsigned int offset, struct fdt_reg_cells *regs ); extern int fdt_reg_count ( struct fdt *fdt, unsigned int offset, diff --git a/src/tests/fdt_test.c b/src/tests/fdt_test.c index 099a093b4..07f7e8911 100644 --- a/src/tests/fdt_test.c +++ b/src/tests/fdt_test.c @@ -237,6 +237,16 @@ static void fdt_test_exec ( void ) { ok ( fdt_path ( &fdt, "/soc/ethernet@10090000", &offset ) == 0 ); ok ( fdt_u32 ( &fdt, offset, "max-speed", &u32 ) != 0 ); + /* Verify phandle properties */ + ok ( fdt_path ( &fdt, "/cpus/cpu@0/interrupt-controller", + &offset ) == 0 ); + ok ( fdt_phandle ( &fdt, offset ) == 0x03 ); + ok ( fdt_path ( &fdt, "/soc/ethernet@10090000/ethernet-phy@0", + &offset ) == 0 ); + ok ( fdt_phandle ( &fdt, offset ) == 0x08 ); + ok ( fdt_path ( &fdt, "/soc/serial@10010000", &offset ) == 0 ); + ok ( fdt_phandle ( &fdt, offset ) == 0 ); + /* Verify cell properties */ ok ( fdt_path ( &fdt, "/soc/ethernet@10090000", &offset ) == 0 ); ok ( fdt_cells ( &fdt, offset, "reg", 4, 2, &u64 ) == 0 ); @@ -261,15 +271,6 @@ static void fdt_test_exec ( void ) { ok ( ( string = fdt_string ( &fdt, offset, "phy-mode" ) ) != NULL ); ok ( strcmp ( string, "gmii" ) == 0 ); - /* Verify phandle lookup */ - ok ( fdt_phandle ( &fdt, 0x03, &offset ) == 0 ); - ok ( fdt_describe ( &fdt, offset, &desc ) == 0 ); - ok ( strcmp ( desc.name, "interrupt-controller" ) == 0 ); - ok ( fdt_phandle ( &fdt, 0x08, &offset ) == 0 ); - ok ( fdt_describe ( &fdt, offset, &desc ) == 0 ); - ok ( strcmp ( desc.name, "ethernet-phy@0" ) == 0 ); - ok ( fdt_phandle ( &fdt, 0x2a, &offset ) != 0 ); - /* Verify node description */ ok ( fdt_path ( &fdt, "/memory@80000000", &offset ) == 0 ); ok ( fdt_describe ( &fdt, offset, &desc ) == 0 ); -- cgit v1.2.3-55-g7522 From 5bec2604a3565f6db31419a4630e0317384ebe61 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 28 Aug 2025 15:12:41 +0100 Subject: [libc] Add wcsnlen() Signed-off-by: Michael Brown --- src/core/wchar.c | 19 ++++++++++++++++--- src/include/wchar.h | 1 + src/tests/string_test.c | 18 ++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) (limited to 'src/tests') diff --git a/src/core/wchar.c b/src/core/wchar.c index 860322820..b06cf452a 100644 --- a/src/core/wchar.c +++ b/src/core/wchar.c @@ -36,12 +36,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * Calculate length of wide-character string * * @v string String - * @ret len Length (excluding terminating NUL) + * @v max Maximum length (in wide characters) + * @ret len Length (in wide characters, excluding terminating NUL) */ -size_t wcslen ( const wchar_t *string ) { +size_t wcsnlen ( const wchar_t *string, size_t max ) { size_t len = 0; - while ( *(string++) ) + while ( max-- && *(string++) ) len++; return len; } + +/** + * Calculate length of wide-character string + * + * @v string String + * @ret len Length (in wide characters, excluding terminating NUL) + */ +size_t wcslen ( const wchar_t *string ) { + + return wcsnlen ( string, ( ( ~( ( size_t ) 0 ) ) / + sizeof ( string[0] ) ) ); +} diff --git a/src/include/wchar.h b/src/include/wchar.h index d054b8d5b..a7e9de4f2 100644 --- a/src/include/wchar.h +++ b/src/include/wchar.h @@ -24,6 +24,7 @@ size_t wcrtomb ( char *buf, wchar_t wc, mbstate_t *ps __unused ) { return 1; } +extern size_t wcsnlen ( const wchar_t *string, size_t max ); extern size_t wcslen ( const wchar_t *string ); #endif /* WCHAR_H */ diff --git a/src/tests/string_test.c b/src/tests/string_test.c index c0436c3ad..6662848d3 100644 --- a/src/tests/string_test.c +++ b/src/tests/string_test.c @@ -38,6 +38,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include @@ -322,6 +323,23 @@ static void string_test_exec ( void ) { + 17 ) * 26 + 10 ) ); ok ( endp == &string[6] ); } + + /* Test wcslen() */ + ok ( wcslen ( L"" ) == 0 ); + ok ( wcslen ( L"Helloo" ) == 6 ); + ok ( wcslen ( L"Helloo woorld!" ) == 14 ); + ok ( wcslen ( L"Helloo\0woorld!" ) == 6 ); + + /* Test wcsnlen() */ + ok ( wcsnlen ( L"", 0 ) == 0 ); + ok ( wcsnlen ( L"", 10 ) == 0 ); + ok ( wcsnlen ( L"Helloo", 0 ) == 0 ); + ok ( wcsnlen ( L"Helloo", 3 ) == 3 ); + ok ( wcsnlen ( L"Helloo", 5 ) == 5 ); + ok ( wcsnlen ( L"Helloo", 16 ) == 6 ); + ok ( wcsnlen ( L"Helloo woorld!", 5 ) == 5 ); + ok ( wcsnlen ( L"Helloo woorld!", 11 ) == 11 ); + ok ( wcsnlen ( L"Helloo woorld!", 16 ) == 14 ); } /** String self-test */ -- cgit v1.2.3-55-g7522 From 8cd963ab9657d3b14ad36a37a73522fc91415c90 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 1 Dec 2025 14:47:51 +0000 Subject: [crypto] Pass signatures for verification as ASN.1 cursors Signed-off-by: Michael Brown --- src/crypto/cms.c | 2 +- src/crypto/crypto_null.c | 3 +-- src/crypto/ocsp.c | 3 +-- src/crypto/rsa.c | 11 +++++------ src/crypto/x509.c | 3 +-- src/include/ipxe/crypto.h | 11 +++++------ src/net/tls.c | 10 +++++----- src/tests/pubkey_test.c | 20 +++++++++++--------- src/tests/pubkey_test.h | 10 +++++----- 9 files changed, 35 insertions(+), 38 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/cms.c b/src/crypto/cms.c index e3571f330..a3c03a9b4 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -757,7 +757,7 @@ static int cms_verify_digest ( struct cms_message *cms, /* Verify digest */ if ( ( rc = pubkey_verify ( pubkey, key, digest, digest_out, - value->data, value->len ) ) != 0 ) { + value ) ) != 0 ) { DBGC ( cms, "CMS %p/%p signature verification failed: %s\n", cms, part, strerror ( rc ) ); return rc; diff --git a/src/crypto/crypto_null.c b/src/crypto/crypto_null.c index d5863f958..ca4e1b134 100644 --- a/src/crypto/crypto_null.c +++ b/src/crypto/crypto_null.c @@ -120,8 +120,7 @@ int pubkey_null_sign ( const struct asn1_cursor *key __unused, int pubkey_null_verify ( const struct asn1_cursor *key __unused, struct digest_algorithm *digest __unused, const void *value __unused, - const void *signature __unused , - size_t signature_len __unused ) { + const struct asn1_cursor *signature __unused ) { return 0; } diff --git a/src/crypto/ocsp.c b/src/crypto/ocsp.c index ae70f320c..1712d614e 100644 --- a/src/crypto/ocsp.c +++ b/src/crypto/ocsp.c @@ -858,8 +858,7 @@ static int ocsp_check_signature ( struct ocsp_check *ocsp, /* Verify digest */ if ( ( rc = pubkey_verify ( pubkey, key, digest, digest_out, - response->signature.data, - response->signature.len ) ) != 0 ) { + &response->signature ) ) != 0 ) { DBGC ( ocsp, "OCSP %p \"%s\" signature verification failed: " "%s\n", ocsp, x509_name ( ocsp->cert ), strerror ( rc )); return rc; diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index f9041eede..b93437518 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -591,12 +591,11 @@ static int rsa_sign ( const struct asn1_cursor *key, * @v digest Digest algorithm * @v value Digest value * @v signature Signature - * @v signature_len Signature length * @ret rc Return status code */ static int rsa_verify ( const struct asn1_cursor *key, struct digest_algorithm *digest, const void *value, - const void *signature, size_t signature_len ) { + const struct asn1_cursor *signature ) { struct rsa_context context; void *temp; void *expected; @@ -606,17 +605,17 @@ static int rsa_verify ( const struct asn1_cursor *key, DBGC ( &context, "RSA %p verifying %s digest:\n", &context, digest->name ); DBGC_HDA ( &context, 0, value, digest->digestsize ); - DBGC_HDA ( &context, 0, signature, signature_len ); + DBGC_HDA ( &context, 0, signature->data, signature->len ); /* Initialise context */ if ( ( rc = rsa_init ( &context, key ) ) != 0 ) goto err_init; /* Sanity check */ - if ( signature_len != context.max_len ) { + if ( signature->len != context.max_len ) { DBGC ( &context, "RSA %p signature incorrect length (%zd " "bytes, should be %zd)\n", - &context, signature_len, context.max_len ); + &context, signature->len, context.max_len ); rc = -ERANGE; goto err_sanity; } @@ -626,7 +625,7 @@ static int rsa_verify ( const struct asn1_cursor *key, */ temp = context.input0; expected = temp; - rsa_cipher ( &context, signature, expected ); + rsa_cipher ( &context, signature->data, expected ); DBGC ( &context, "RSA %p deciphered signature:\n", &context ); DBGC_HDA ( &context, 0, expected, context.max_len ); diff --git a/src/crypto/x509.c b/src/crypto/x509.c index 0b01171b6..5d39a1dd8 100644 --- a/src/crypto/x509.c +++ b/src/crypto/x509.c @@ -1152,8 +1152,7 @@ static int x509_check_signature ( struct x509_certificate *cert, /* Verify signature using signer's public key */ if ( ( rc = pubkey_verify ( pubkey, &public_key->raw, digest, - digest_out, signature->value.data, - signature->value.len ) ) != 0 ) { + digest_out, &signature->value ) ) != 0 ) { DBGC ( cert, "X509 %p \"%s\" signature verification failed: " "%s\n", cert, x509_name ( cert ), strerror ( rc ) ); goto err_pubkey_verify; diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index 4bd543ae2..5b87d1a47 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -164,12 +164,11 @@ struct pubkey_algorithm { * @v digest Digest algorithm * @v value Digest value * @v signature Signature - * @v signature_len Signature length * @ret rc Return status code */ int ( * verify ) ( const struct asn1_cursor *key, struct digest_algorithm *digest, const void *value, - const void *signature, size_t signature_len ); + const struct asn1_cursor *signature ); /** Check that public key matches private key * * @v private_key Private key @@ -295,8 +294,8 @@ pubkey_sign ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, static inline __attribute__ (( always_inline )) int pubkey_verify ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, struct digest_algorithm *digest, const void *value, - const void *signature, size_t signature_len ) { - return pubkey->verify ( key, digest, value, signature, signature_len ); + const struct asn1_cursor *signature ) { + return pubkey->verify ( key, digest, value, signature ); } static inline __attribute__ (( always_inline )) int @@ -336,8 +335,8 @@ extern int pubkey_null_sign ( const struct asn1_cursor *key, const void *value, void *signature ); extern int pubkey_null_verify ( const struct asn1_cursor *key, struct digest_algorithm *digest, - const void *value, const void *signature , - size_t signature_len ); + const void *value, + const struct asn1_cursor *signature ); extern struct digest_algorithm digest_null; extern struct cipher_algorithm cipher_null; diff --git a/src/net/tls.c b/src/net/tls.c index 1d5a6c6d8..1bcb5c027 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1495,6 +1495,7 @@ static int tls_verify_dh_params ( struct tls_connection *tls, uint16_t signature_len; uint8_t signature[0]; } __attribute__ (( packed )) *sig; + struct asn1_cursor signature; const void *data; size_t remaining; int rc; @@ -1515,6 +1516,8 @@ static int tls_verify_dh_params ( struct tls_connection *tls, tls->server.exchange_len ); return -EINVAL_KEY_EXCHANGE; } + signature.data = sig->signature; + signature.len = ntohs ( sig->signature_len ); /* Identify signature and hash algorithm */ if ( use_sig_hash ) { @@ -1538,8 +1541,6 @@ static int tls_verify_dh_params ( struct tls_connection *tls, /* Verify signature */ { - const void *signature = sig->signature; - size_t signature_len = ntohs ( sig->signature_len ); uint8_t ctx[digest->ctxsize]; uint8_t hash[digest->digestsize]; @@ -1553,9 +1554,8 @@ static int tls_verify_dh_params ( struct tls_connection *tls, digest_final ( digest, ctx, hash ); /* Verify signature */ - if ( ( rc = pubkey_verify ( pubkey, &tls->server.key, - digest, hash, signature, - signature_len ) ) != 0 ) { + if ( ( rc = pubkey_verify ( pubkey, &tls->server.key, digest, + hash, &signature ) ) != 0 ) { DBGC ( tls, "TLS %p ServerKeyExchange failed " "verification\n", tls ); DBGC_HDA ( tls, 0, tls->server.exchange, diff --git a/src/tests/pubkey_test.c b/src/tests/pubkey_test.c index ff318bfb7..2e0eeb116 100644 --- a/src/tests/pubkey_test.c +++ b/src/tests/pubkey_test.c @@ -99,10 +99,11 @@ void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file, struct pubkey_algorithm *pubkey = test->pubkey; struct digest_algorithm *digest = test->digest; size_t max_len = pubkey_max_len ( pubkey, &test->private ); - uint8_t bad[test->signature_len]; + uint8_t bad[test->signature.len]; uint8_t digestctx[digest->ctxsize ]; uint8_t digestout[digest->digestsize]; uint8_t signature[max_len]; + struct asn1_cursor cursor; int signature_len; /* Construct digest over plaintext */ @@ -114,18 +115,19 @@ void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file, /* Test signing using private key */ signature_len = pubkey_sign ( pubkey, &test->private, digest, digestout, signature ); - okx ( signature_len == ( ( int ) test->signature_len ), file, line ); - okx ( memcmp ( signature, test->signature, test->signature_len ) == 0, - file, line ); + okx ( signature_len == ( ( int ) test->signature.len ), file, line ); + okx ( memcmp ( signature, test->signature.data, + test->signature.len ) == 0, file, line ); /* Test verification using public key */ okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, - test->signature, test->signature_len ) == 0, - file, line ); + &test->signature ) == 0, file, line ); /* Test verification failure of modified signature */ - memcpy ( bad, test->signature, test->signature_len ); - bad[ test->signature_len / 2 ] ^= 0x40; + memcpy ( bad, test->signature.data, test->signature.len ); + bad[ test->signature.len / 2 ] ^= 0x40; + cursor.data = bad; + cursor.len = test->signature.len; okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, - bad, sizeof ( bad ) ) != 0, file, line ); + &cursor ) != 0, file, line ); } diff --git a/src/tests/pubkey_test.h b/src/tests/pubkey_test.h index 20bb94355..1bb6caf51 100644 --- a/src/tests/pubkey_test.h +++ b/src/tests/pubkey_test.h @@ -45,9 +45,7 @@ struct pubkey_sign_test { /** Signature algorithm */ struct digest_algorithm *digest; /** Signature */ - const void *signature; - /** Signature length */ - size_t signature_len; + const struct asn1_cursor signature; }; /** Define inline private key data */ @@ -129,8 +127,10 @@ struct pubkey_sign_test { .plaintext = name ## _plaintext, \ .plaintext_len = sizeof ( name ## _plaintext ), \ .digest = DIGEST, \ - .signature = name ## _signature, \ - .signature_len = sizeof ( name ## _signature ), \ + .signature = { \ + .data = name ## _signature, \ + .len = sizeof ( name ## _signature ), \ + }, \ } extern void pubkey_okx ( struct pubkey_test *test, -- cgit v1.2.3-55-g7522 From d4258272c679c8bd42430fc2df57402cdc03d711 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 1 Dec 2025 16:02:54 +0000 Subject: [crypto] Construct signatures using ASN.1 builders Signed-off-by: Michael Brown --- src/crypto/crypto_null.c | 3 ++- src/crypto/rsa.c | 24 +++++++++-------- src/drivers/net/iphone.c | 18 +++---------- src/include/ipxe/crypto.h | 9 ++++--- src/net/tls.c | 69 ++++++++++++++++++++++++----------------------- src/tests/pubkey_test.c | 30 ++++++++++----------- 6 files changed, 74 insertions(+), 79 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/crypto_null.c b/src/crypto/crypto_null.c index ca4e1b134..ee948e00d 100644 --- a/src/crypto/crypto_null.c +++ b/src/crypto/crypto_null.c @@ -113,7 +113,8 @@ int pubkey_null_decrypt ( const struct asn1_cursor *key __unused, int pubkey_null_sign ( const struct asn1_cursor *key __unused, struct digest_algorithm *digest __unused, - const void *value __unused, void *signature __unused ) { + const void *value __unused, + struct asn1_builder *signature __unused ) { return 0; } diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index b93437518..fd6a1ef39 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -544,13 +544,12 @@ static int rsa_encode_digest ( struct rsa_context *context, * @v digest Digest algorithm * @v value Digest value * @v signature Signature - * @ret signature_len Signature length, or negative error + * @ret rc Return status code */ static int rsa_sign ( const struct asn1_cursor *key, struct digest_algorithm *digest, const void *value, - void *signature ) { + struct asn1_builder *signature ) { struct rsa_context context; - void *temp; int rc; DBGC ( &context, "RSA %p signing %s digest:\n", @@ -561,24 +560,27 @@ static int rsa_sign ( const struct asn1_cursor *key, if ( ( rc = rsa_init ( &context, key ) ) != 0 ) goto err_init; - /* Encode digest (using the big integer output buffer as - * temporary storage) - */ - temp = context.output0; - if ( ( rc = rsa_encode_digest ( &context, digest, value, temp ) ) != 0 ) + /* Create space for encoded digest and signature */ + if ( ( rc = asn1_grow ( signature, context.max_len ) ) != 0 ) + goto err_grow; + + /* Encode digest */ + if ( ( rc = rsa_encode_digest ( &context, digest, value, + signature->data ) ) != 0 ) goto err_encode; /* Encipher the encoded digest */ - rsa_cipher ( &context, temp, signature ); + rsa_cipher ( &context, signature->data, signature->data ); DBGC ( &context, "RSA %p signed %s digest:\n", &context, digest->name ); - DBGC_HDA ( &context, 0, signature, context.max_len ); + DBGC_HDA ( &context, 0, signature->data, signature->len ); /* Free context */ rsa_free ( &context ); - return context.max_len; + return 0; err_encode: + err_grow: rsa_free ( &context ); err_init: return rc; diff --git a/src/drivers/net/iphone.c b/src/drivers/net/iphone.c index bcc9949fe..11f763553 100644 --- a/src/drivers/net/iphone.c +++ b/src/drivers/net/iphone.c @@ -362,7 +362,6 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject, struct asn1_builder raw = { NULL, 0 }; uint8_t digest_ctx[SHA256_CTX_SIZE]; uint8_t digest_out[SHA256_DIGEST_SIZE]; - int len; int rc; /* Construct subjectPublicKeyInfo */ @@ -399,20 +398,12 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject, digest_final ( digest, digest_ctx, digest_out ); /* Construct signature using "private" key */ - if ( ( rc = asn1_grow ( &raw, - pubkey_max_len ( pubkey, private ) ) ) != 0 ) { - DBGC ( icert, "ICERT %p could not build signature: %s\n", - icert, strerror ( rc ) ); - goto err_grow; - } - if ( ( len = pubkey_sign ( pubkey, private, digest, digest_out, - raw.data ) ) < 0 ) { - rc = len; + if ( ( rc = pubkey_sign ( pubkey, private, digest, digest_out, + &raw ) ) != 0 ) { DBGC ( icert, "ICERT %p could not sign: %s\n", icert, strerror ( rc ) ); goto err_pubkey_sign; } - assert ( ( ( size_t ) len ) == raw.len ); /* Construct raw certificate data */ if ( ( rc = ( asn1_prepend_raw ( &raw, icert_nul, @@ -438,12 +429,11 @@ static int icert_cert ( struct icert *icert, struct asn1_cursor *subject, err_x509: err_raw: err_pubkey_sign: + err_tbs: + err_spki: free ( raw.data ); - err_grow: free ( tbs.data ); - err_tbs: free ( spki.data ); - err_spki: return rc; } diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index 5b87d1a47..c457a74b1 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -153,11 +153,11 @@ struct pubkey_algorithm { * @v digest Digest algorithm * @v value Digest value * @v signature Signature - * @ret signature_len Signature length, or negative error + * @ret rc Return status code */ int ( * sign ) ( const struct asn1_cursor *key, struct digest_algorithm *digest, const void *value, - void *signature ); + struct asn1_builder *builder ); /** Verify signed digest value * * @v key Key @@ -287,7 +287,7 @@ pubkey_decrypt ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, static inline __attribute__ (( always_inline )) int pubkey_sign ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, struct digest_algorithm *digest, const void *value, - void *signature ) { + struct asn1_builder *signature ) { return pubkey->sign ( key, digest, value, signature ); } @@ -332,7 +332,8 @@ extern int pubkey_null_decrypt ( const struct asn1_cursor *key, void *plaintext ); extern int pubkey_null_sign ( const struct asn1_cursor *key, struct digest_algorithm *digest, - const void *value, void *signature ); + const void *value, + struct asn1_builder *signature ); extern int pubkey_null_verify ( const struct asn1_cursor *key, struct digest_algorithm *digest, const void *value, diff --git a/src/net/tls.c b/src/net/tls.c index 1bcb5c027..c01ce9515 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1863,6 +1863,7 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { struct asn1_cursor *key = privkey_cursor ( tls->client.key ); uint8_t digest_out[ digest->digestsize ]; struct tls_signature_hash_algorithm *sig_hash = NULL; + struct asn1_builder builder = { NULL, 0 }; int rc; /* Generate digest to be signed */ @@ -1880,53 +1881,53 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) { } } - /* Generate and transmit record */ + /* Sign digest */ + if ( ( rc = pubkey_sign ( pubkey, key, digest, digest_out, + &builder ) ) != 0 ) { + DBGC ( tls, "TLS %p could not sign %s digest using %s client " + "private key: %s\n", tls, digest->name, pubkey->name, + strerror ( rc ) ); + goto err_pubkey_sign; + } + + /* Construct Certificate Verify record */ { - size_t max_len = pubkey_max_len ( pubkey, key ); int use_sig_hash = ( ( sig_hash == NULL ) ? 0 : 1 ); struct { uint32_t type_length; struct tls_signature_hash_id sig_hash[use_sig_hash]; uint16_t signature_len; - uint8_t signature[max_len]; - } __attribute__ (( packed )) certificate_verify; - size_t unused; - int len; - - /* Sign digest */ - len = pubkey_sign ( pubkey, key, digest, digest_out, - certificate_verify.signature ); - if ( len < 0 ) { - rc = len; - DBGC ( tls, "TLS %p could not sign %s digest using %s " - "client private key: %s\n", tls, digest->name, - pubkey->name, strerror ( rc ) ); - goto err_pubkey_sign; - } - unused = ( max_len - len ); - - /* Construct Certificate Verify record */ - certificate_verify.type_length = - ( cpu_to_le32 ( TLS_CERTIFICATE_VERIFY ) | - htonl ( sizeof ( certificate_verify ) - - sizeof ( certificate_verify.type_length ) - - unused ) ); + } __attribute__ (( packed )) header; + + header.type_length = ( cpu_to_le32 ( TLS_CERTIFICATE_VERIFY ) | + htonl ( builder.len + + sizeof ( header ) - + sizeof ( header.type_length ))); if ( use_sig_hash ) { - memcpy ( &certificate_verify.sig_hash[0], - &sig_hash->code, - sizeof ( certificate_verify.sig_hash[0] ) ); + memcpy ( &header.sig_hash[0], &sig_hash->code, + sizeof ( header.sig_hash[0] ) ); } - certificate_verify.signature_len = - htons ( sizeof ( certificate_verify.signature ) - - unused ); + header.signature_len = htons ( builder.len ); - /* Transmit record */ - rc = tls_send_handshake ( tls, &certificate_verify, - ( sizeof ( certificate_verify ) - unused ) ); + if ( ( rc = asn1_prepend_raw ( &builder, &header, + sizeof ( header ) ) ) != 0 ) { + DBGC ( tls, "TLS %p could not construct Certificate " + "Verify: %s\n", tls, strerror ( rc ) ); + goto err_prepend; + } + } + + /* Transmit record */ + if ( ( rc = tls_send_handshake ( tls, builder.data, + builder.len ) ) != 0 ) { + goto err_send; } + err_send: + err_prepend: err_pubkey_sign: err_sig_hash: + free ( builder.data ); return rc; } diff --git a/src/tests/pubkey_test.c b/src/tests/pubkey_test.c index 2e0eeb116..e3fbc3b3f 100644 --- a/src/tests/pubkey_test.c +++ b/src/tests/pubkey_test.c @@ -98,13 +98,10 @@ void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file, unsigned int line ) { struct pubkey_algorithm *pubkey = test->pubkey; struct digest_algorithm *digest = test->digest; - size_t max_len = pubkey_max_len ( pubkey, &test->private ); - uint8_t bad[test->signature.len]; uint8_t digestctx[digest->ctxsize ]; uint8_t digestout[digest->digestsize]; - uint8_t signature[max_len]; - struct asn1_cursor cursor; - int signature_len; + struct asn1_builder signature = { NULL, 0 }; + uint8_t *bad; /* Construct digest over plaintext */ digest_init ( digest, digestctx ); @@ -113,21 +110,24 @@ void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file, digest_final ( digest, digestctx, digestout ); /* Test signing using private key */ - signature_len = pubkey_sign ( pubkey, &test->private, digest, - digestout, signature ); - okx ( signature_len == ( ( int ) test->signature.len ), file, line ); - okx ( memcmp ( signature, test->signature.data, - test->signature.len ) == 0, file, line ); + okx ( pubkey_sign ( pubkey, &test->private, digest, digestout, + &signature ) == 0, file, line ); + okx ( signature.len != 0, file, line ); + okx ( asn1_compare ( asn1_built ( &signature ), + &test->signature ) == 0, file, line ); /* Test verification using public key */ okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, &test->signature ) == 0, file, line ); /* Test verification failure of modified signature */ - memcpy ( bad, test->signature.data, test->signature.len ); - bad[ test->signature.len / 2 ] ^= 0x40; - cursor.data = bad; - cursor.len = test->signature.len; + bad = ( signature.data + ( test->signature.len / 2 ) ); + okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, + asn1_built ( &signature ) ) == 0, file, line ); + *bad ^= 0x40; okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, - &cursor ) != 0, file, line ); + asn1_built ( &signature ) ) != 0, file, line ); + + /* Free signature */ + free ( signature.data ); } -- cgit v1.2.3-55-g7522 From 1ccc320ee99651622ced9b33764d5e7890ca3f57 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Tue, 2 Dec 2025 13:12:25 +0000 Subject: [crypto] Construct asymmetric ciphered data using ASN.1 builders Signed-off-by: Michael Brown --- src/crypto/cms.c | 24 ++++++++--------- src/crypto/crypto_null.c | 10 +++---- src/crypto/rsa.c | 65 +++++++++++++++++++++++++------------------- src/include/ipxe/crypto.h | 34 +++++++++++++----------- src/net/tls.c | 68 +++++++++++++++++++++++++++-------------------- src/tests/pubkey_test.c | 64 ++++++++++++++++++++++++-------------------- src/tests/pubkey_test.h | 20 +++++++------- 7 files changed, 156 insertions(+), 129 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/cms.c b/src/crypto/cms.c index a3c03a9b4..7775e581b 100644 --- a/src/crypto/cms.c +++ b/src/crypto/cms.c @@ -917,29 +917,26 @@ static int cms_cipher_key ( struct cms_message *cms, struct pubkey_algorithm *pubkey = part->pubkey; const struct asn1_cursor *key = privkey_cursor ( private_key ); const struct asn1_cursor *value = &part->value; - size_t max_len = pubkey_max_len ( pubkey, key ); - uint8_t cipher_key[max_len]; - int len; + struct asn1_builder cipher_key = { NULL, 0 }; int rc; /* Decrypt cipher key */ - len = pubkey_decrypt ( pubkey, key, value->data, value->len, - cipher_key ); - if ( len < 0 ) { - rc = len; + if ( ( rc = pubkey_decrypt ( pubkey, key, value, + &cipher_key ) ) != 0 ) { DBGC ( cms, "CMS %p/%p could not decrypt cipher key: %s\n", cms, part, strerror ( rc ) ); DBGC_HDA ( cms, 0, value->data, value->len ); - return rc; + goto err_decrypt; } DBGC ( cms, "CMS %p/%p cipher key:\n", cms, part ); - DBGC_HDA ( cms, 0, cipher_key, len ); + DBGC_HDA ( cms, 0, cipher_key.data, cipher_key.len ); /* Set cipher key */ - if ( ( rc = cipher_setkey ( cipher, ctx, cipher_key, len ) ) != 0 ) { + if ( ( rc = cipher_setkey ( cipher, ctx, cipher_key.data, + cipher_key.len ) ) != 0 ) { DBGC ( cms, "CMS %p could not set cipher key: %s\n", cms, strerror ( rc ) ); - return rc; + goto err_setkey; } /* Set cipher initialization vector */ @@ -949,7 +946,10 @@ static int cms_cipher_key ( struct cms_message *cms, DBGC_HDA ( cms, 0, cms->iv.data, cms->iv.len ); } - return 0; + err_setkey: + err_decrypt: + free ( cipher_key.data ); + return rc; } /** diff --git a/src/crypto/crypto_null.c b/src/crypto/crypto_null.c index ee948e00d..e8f8cbde8 100644 --- a/src/crypto/crypto_null.c +++ b/src/crypto/crypto_null.c @@ -98,16 +98,14 @@ size_t pubkey_null_max_len ( const struct asn1_cursor *key __unused ) { } int pubkey_null_encrypt ( const struct asn1_cursor *key __unused, - const void *plaintext __unused, - size_t plaintext_len __unused, - void *ciphertext __unused ) { + const struct asn1_cursor *plaintext __unused, + struct asn1_builder *ciphertext __unused ) { return 0; } int pubkey_null_decrypt ( const struct asn1_cursor *key __unused, - const void *ciphertext __unused, - size_t ciphertext_len __unused, - void *plaintext __unused ) { + const struct asn1_cursor *ciphertext __unused, + struct asn1_builder *plaintext __unused ) { return 0; } diff --git a/src/crypto/rsa.c b/src/crypto/rsa.c index fd6a1ef39..18b2b1c14 100644 --- a/src/crypto/rsa.c +++ b/src/crypto/rsa.c @@ -338,12 +338,12 @@ static void rsa_cipher ( struct rsa_context *context, * * @v key Key * @v plaintext Plaintext - * @v plaintext_len Length of plaintext * @v ciphertext Ciphertext * @ret ciphertext_len Length of ciphertext, or negative error */ -static int rsa_encrypt ( const struct asn1_cursor *key, const void *plaintext, - size_t plaintext_len, void *ciphertext ) { +static int rsa_encrypt ( const struct asn1_cursor *key, + const struct asn1_cursor *plaintext, + struct asn1_builder *ciphertext ) { struct rsa_context context; void *temp; uint8_t *encoded; @@ -352,7 +352,7 @@ static int rsa_encrypt ( const struct asn1_cursor *key, const void *plaintext, int rc; DBGC ( &context, "RSA %p encrypting:\n", &context ); - DBGC_HDA ( &context, 0, plaintext, plaintext_len ); + DBGC_HDA ( &context, 0, plaintext->data, plaintext->len ); /* Initialise context */ if ( ( rc = rsa_init ( &context, key ) ) != 0 ) @@ -360,12 +360,12 @@ static int rsa_encrypt ( const struct asn1_cursor *key, const void *plaintext, /* Calculate lengths */ max_len = ( context.max_len - 11 ); - random_nz_len = ( max_len - plaintext_len + 8 ); + random_nz_len = ( max_len - plaintext->len + 8 ); /* Sanity check */ - if ( plaintext_len > max_len ) { + if ( plaintext->len > max_len ) { DBGC ( &context, "RSA %p plaintext too long (%zd bytes, max " - "%zd)\n", &context, plaintext_len, max_len ); + "%zd)\n", &context, plaintext->len, max_len ); rc = -ERANGE; goto err_sanity; } @@ -383,19 +383,24 @@ static int rsa_encrypt ( const struct asn1_cursor *key, const void *plaintext, goto err_random; } encoded[ 2 + random_nz_len ] = 0x00; - memcpy ( &encoded[ context.max_len - plaintext_len ], - plaintext, plaintext_len ); + memcpy ( &encoded[ context.max_len - plaintext->len ], + plaintext->data, plaintext->len ); + + /* Create space for ciphertext */ + if ( ( rc = asn1_grow ( ciphertext, context.max_len ) ) != 0 ) + goto err_grow; /* Encipher the encoded message */ - rsa_cipher ( &context, encoded, ciphertext ); + rsa_cipher ( &context, encoded, ciphertext->data ); DBGC ( &context, "RSA %p encrypted:\n", &context ); - DBGC_HDA ( &context, 0, ciphertext, context.max_len ); + DBGC_HDA ( &context, 0, ciphertext->data, context.max_len ); /* Free context */ rsa_free ( &context ); - return context.max_len; + return 0; + err_grow: err_random: err_sanity: rsa_free ( &context ); @@ -408,33 +413,33 @@ static int rsa_encrypt ( const struct asn1_cursor *key, const void *plaintext, * * @v key Key * @v ciphertext Ciphertext - * @v ciphertext_len Ciphertext length * @v plaintext Plaintext - * @ret plaintext_len Plaintext length, or negative error + * @ret rc Return status code */ -static int rsa_decrypt ( const struct asn1_cursor *key, const void *ciphertext, - size_t ciphertext_len, void *plaintext ) { +static int rsa_decrypt ( const struct asn1_cursor *key, + const struct asn1_cursor *ciphertext, + struct asn1_builder *plaintext ) { struct rsa_context context; void *temp; uint8_t *encoded; uint8_t *end; uint8_t *zero; uint8_t *start; - size_t plaintext_len; + size_t len; int rc; DBGC ( &context, "RSA %p decrypting:\n", &context ); - DBGC_HDA ( &context, 0, ciphertext, ciphertext_len ); + DBGC_HDA ( &context, 0, ciphertext->data, ciphertext->len ); /* Initialise context */ if ( ( rc = rsa_init ( &context, key ) ) != 0 ) goto err_init; /* Sanity check */ - if ( ciphertext_len != context.max_len ) { + if ( ciphertext->len != context.max_len ) { DBGC ( &context, "RSA %p ciphertext incorrect length (%zd " "bytes, should be %zd)\n", - &context, ciphertext_len, context.max_len ); + &context, ciphertext->len, context.max_len ); rc = -ERANGE; goto err_sanity; } @@ -444,7 +449,7 @@ static int rsa_decrypt ( const struct asn1_cursor *key, const void *ciphertext, */ temp = context.input0; encoded = temp; - rsa_cipher ( &context, ciphertext, encoded ); + rsa_cipher ( &context, ciphertext->data, encoded ); /* Parse the message */ end = ( encoded + context.max_len ); @@ -454,25 +459,31 @@ static int rsa_decrypt ( const struct asn1_cursor *key, const void *ciphertext, } zero = memchr ( &encoded[2], 0, ( end - &encoded[2] ) ); if ( ! zero ) { + DBGC ( &context, "RSA %p invalid decrypted message:\n", + &context ); + DBGC_HDA ( &context, 0, encoded, context.max_len ); rc = -EINVAL; goto err_invalid; } start = ( zero + 1 ); - plaintext_len = ( end - start ); + len = ( end - start ); + + /* Create space for plaintext */ + if ( ( rc = asn1_grow ( plaintext, len ) ) != 0 ) + goto err_grow; /* Copy out message */ - memcpy ( plaintext, start, plaintext_len ); + memcpy ( plaintext->data, start, len ); DBGC ( &context, "RSA %p decrypted:\n", &context ); - DBGC_HDA ( &context, 0, plaintext, plaintext_len ); + DBGC_HDA ( &context, 0, plaintext->data, len ); /* Free context */ rsa_free ( &context ); - return plaintext_len; + return 0; + err_grow: err_invalid: - DBGC ( &context, "RSA %p invalid decrypted message:\n", &context ); - DBGC_HDA ( &context, 0, encoded, context.max_len ); err_sanity: rsa_free ( &context ); err_init: diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index c457a74b1..68bd23048 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -131,22 +131,22 @@ struct pubkey_algorithm { * * @v key Key * @v plaintext Plaintext - * @v plaintext_len Length of plaintext * @v ciphertext Ciphertext - * @ret ciphertext_len Length of ciphertext, or negative error + * @ret rc Return status code */ - int ( * encrypt ) ( const struct asn1_cursor *key, const void *data, - size_t len, void *out ); + int ( * encrypt ) ( const struct asn1_cursor *key, + const struct asn1_cursor *plaintext, + struct asn1_builder *ciphertext ); /** Decrypt * * @v key Key * @v ciphertext Ciphertext - * @v ciphertext_len Ciphertext length * @v plaintext Plaintext - * @ret plaintext_len Plaintext length, or negative error + * @ret rc Return status code */ - int ( * decrypt ) ( const struct asn1_cursor *key, const void *data, - size_t len, void *out ); + int ( * decrypt ) ( const struct asn1_cursor *key, + const struct asn1_cursor *ciphertext, + struct asn1_builder *plaintext ); /** Sign digest value * * @v key Key @@ -274,14 +274,16 @@ pubkey_max_len ( struct pubkey_algorithm *pubkey, static inline __attribute__ (( always_inline )) int pubkey_encrypt ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, - const void *data, size_t len, void *out ) { - return pubkey->encrypt ( key, data, len, out ); + const struct asn1_cursor *plaintext, + struct asn1_builder *ciphertext ) { + return pubkey->encrypt ( key, plaintext, ciphertext ); } static inline __attribute__ (( always_inline )) int pubkey_decrypt ( struct pubkey_algorithm *pubkey, const struct asn1_cursor *key, - const void *data, size_t len, void *out ) { - return pubkey->decrypt ( key, data, len, out ); + const struct asn1_cursor *ciphertext, + struct asn1_builder *plaintext ) { + return pubkey->decrypt ( key, ciphertext, plaintext ); } static inline __attribute__ (( always_inline )) int @@ -325,11 +327,11 @@ extern void cipher_null_auth ( void *ctx, void *auth ); extern size_t pubkey_null_max_len ( const struct asn1_cursor *key ); extern int pubkey_null_encrypt ( const struct asn1_cursor *key, - const void *plaintext, size_t plaintext_len, - void *ciphertext ); + const struct asn1_cursor *plaintext, + struct asn1_builder *ciphertext ); extern int pubkey_null_decrypt ( const struct asn1_cursor *key, - const void *ciphertext, size_t ciphertext_len, - void *plaintext ); + const struct asn1_cursor *ciphertext, + struct asn1_builder *plaintext ); extern int pubkey_null_sign ( const struct asn1_cursor *key, struct digest_algorithm *digest, const void *value, diff --git a/src/net/tls.c b/src/net/tls.c index c01ce9515..6140ca58a 100644 --- a/src/net/tls.c +++ b/src/net/tls.c @@ -1416,59 +1416,69 @@ static int tls_send_certificate ( struct tls_connection *tls ) { static int tls_send_client_key_exchange_pubkey ( struct tls_connection *tls ) { struct tls_cipherspec *cipherspec = &tls->tx.cipherspec.pending; struct pubkey_algorithm *pubkey = cipherspec->suite->pubkey; - size_t max_len = pubkey_max_len ( pubkey, &tls->server.key ); struct { uint16_t version; uint8_t random[46]; } __attribute__ (( packed )) pre_master_secret; - struct { - uint32_t type_length; - uint16_t encrypted_pre_master_secret_len; - uint8_t encrypted_pre_master_secret[max_len]; - } __attribute__ (( packed )) key_xchg; - size_t unused; - int len; + struct asn1_cursor cursor = { + .data = &pre_master_secret, + .len = sizeof ( pre_master_secret ), + }; + struct asn1_builder builder = { NULL, 0 }; int rc; /* Generate pre-master secret */ pre_master_secret.version = htons ( TLS_VERSION_MAX ); if ( ( rc = tls_generate_random ( tls, &pre_master_secret.random, ( sizeof ( pre_master_secret.random ) ) ) ) != 0 ) { - return rc; + goto err_random; } /* Encrypt pre-master secret using server's public key */ - memset ( &key_xchg, 0, sizeof ( key_xchg ) ); - len = pubkey_encrypt ( pubkey, &tls->server.key, &pre_master_secret, - sizeof ( pre_master_secret ), - key_xchg.encrypted_pre_master_secret ); - if ( len < 0 ) { - rc = len; + if ( ( rc = pubkey_encrypt ( pubkey, &tls->server.key, &cursor, + &builder ) ) != 0 ) { DBGC ( tls, "TLS %p could not encrypt pre-master secret: %s\n", tls, strerror ( rc ) ); - return rc; + goto err_encrypt; + } + + /* Construct Client Key Exchange record */ + { + struct { + uint32_t type_length; + uint16_t encrypted_pre_master_secret_len; + } __attribute__ (( packed )) header; + + header.type_length = + ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) | + htonl ( builder.len + sizeof ( header ) - + sizeof ( header.type_length ) ) ); + header.encrypted_pre_master_secret_len = htons ( builder.len ); + + if ( ( rc = asn1_prepend_raw ( &builder, &header, + sizeof ( header ) ) ) != 0 ) { + DBGC ( tls, "TLS %p could not construct Client Key " + "Exchange: %s\n", tls, strerror ( rc ) ); + goto err_prepend; + } } - unused = ( max_len - len ); - key_xchg.type_length = - ( cpu_to_le32 ( TLS_CLIENT_KEY_EXCHANGE ) | - htonl ( sizeof ( key_xchg ) - - sizeof ( key_xchg.type_length ) - unused ) ); - key_xchg.encrypted_pre_master_secret_len = - htons ( sizeof ( key_xchg.encrypted_pre_master_secret ) - - unused ); /* Transmit Client Key Exchange record */ - if ( ( rc = tls_send_handshake ( tls, &key_xchg, - ( sizeof ( key_xchg ) - - unused ) ) ) != 0 ) { - return rc; + if ( ( rc = tls_send_handshake ( tls, builder.data, + builder.len ) ) != 0 ) { + goto err_send; } /* Generate master secret */ tls_generate_master_secret ( tls, &pre_master_secret, sizeof ( pre_master_secret ) ); - return 0; + err_random: + err_encrypt: + err_prepend: + err_send: + free ( builder.data ); + return rc; } /** Public key exchange algorithm */ diff --git a/src/tests/pubkey_test.c b/src/tests/pubkey_test.c index e3fbc3b3f..d110b2946 100644 --- a/src/tests/pubkey_test.c +++ b/src/tests/pubkey_test.c @@ -50,41 +50,47 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); void pubkey_okx ( struct pubkey_test *test, const char *file, unsigned int line ) { struct pubkey_algorithm *pubkey = test->pubkey; - size_t max_len = pubkey_max_len ( pubkey, &test->private ); - uint8_t encrypted[max_len]; - uint8_t decrypted[max_len]; - int encrypted_len; - int decrypted_len; + struct asn1_builder plaintext; + struct asn1_builder ciphertext; /* Test decrypting with private key to obtain known plaintext */ - decrypted_len = pubkey_decrypt ( pubkey, &test->private, - test->ciphertext, test->ciphertext_len, - decrypted ); - okx ( decrypted_len == ( ( int ) test->plaintext_len ), file, line ); - okx ( memcmp ( decrypted, test->plaintext, test->plaintext_len ) == 0, - file, line ); + plaintext.data = NULL; + plaintext.len = 0; + okx ( pubkey_decrypt ( pubkey, &test->private, &test->ciphertext, + &plaintext ) == 0, file, line ); + okx ( asn1_compare ( asn1_built ( &plaintext ), + &test->plaintext ) == 0, file, line ); + free ( plaintext.data ); /* Test encrypting with private key and decrypting with public key */ - encrypted_len = pubkey_encrypt ( pubkey, &test->private, - test->plaintext, test->plaintext_len, - encrypted ); - okx ( encrypted_len >= 0, file, line ); - decrypted_len = pubkey_decrypt ( pubkey, &test->public, encrypted, - encrypted_len, decrypted ); - okx ( decrypted_len == ( ( int ) test->plaintext_len ), file, line ); - okx ( memcmp ( decrypted, test->plaintext, test->plaintext_len ) == 0, - file, line ); + ciphertext.data = NULL; + ciphertext.len = 0; + plaintext.data = NULL; + plaintext.len = 0; + okx ( pubkey_encrypt ( pubkey, &test->private, &test->plaintext, + &ciphertext ) == 0, file, line ); + okx ( pubkey_decrypt ( pubkey, &test->public, + asn1_built ( &ciphertext ), + &plaintext ) == 0, file, line ); + okx ( asn1_compare ( asn1_built ( &plaintext ), + &test->plaintext ) == 0, file, line ); + free ( ciphertext.data ); + free ( plaintext.data ); /* Test encrypting with public key and decrypting with private key */ - encrypted_len = pubkey_encrypt ( pubkey, &test->public, - test->plaintext, test->plaintext_len, - encrypted ); - okx ( encrypted_len >= 0, file, line ); - decrypted_len = pubkey_decrypt ( pubkey, &test->private, encrypted, - encrypted_len, decrypted ); - okx ( decrypted_len == ( ( int ) test->plaintext_len ), file, line ); - okx ( memcmp ( decrypted, test->plaintext, test->plaintext_len ) == 0, - file, line ); + ciphertext.data = NULL; + ciphertext.len = 0; + plaintext.data = NULL; + plaintext.len = 0; + okx ( pubkey_encrypt ( pubkey, &test->public, &test->plaintext, + &ciphertext ) == 0, file, line ); + okx ( pubkey_decrypt ( pubkey, &test->private, + asn1_built ( &ciphertext ), + &plaintext ) == 0, file, line ); + okx ( asn1_compare ( asn1_built ( &plaintext ), + &test->plaintext ) == 0, file, line ); + free ( ciphertext.data ); + free ( plaintext.data ); } /** diff --git a/src/tests/pubkey_test.h b/src/tests/pubkey_test.h index 1bb6caf51..33b301a6e 100644 --- a/src/tests/pubkey_test.h +++ b/src/tests/pubkey_test.h @@ -16,18 +16,14 @@ struct pubkey_test { /** Public key */ const struct asn1_cursor public; /** Plaintext */ - const void *plaintext; - /** Length of plaintext */ - size_t plaintext_len; + const struct asn1_cursor plaintext; /** Ciphertext * * Note that the encryption process may include some random * padding, so a given plaintext will encrypt to multiple * different ciphertexts. */ - const void *ciphertext; - /** Length of ciphertext */ - size_t ciphertext_len; + const struct asn1_cursor ciphertext; }; /** A public-key signature test */ @@ -90,10 +86,14 @@ struct pubkey_sign_test { .data = name ## _public, \ .len = sizeof ( name ## _public ), \ }, \ - .plaintext = name ## _plaintext, \ - .plaintext_len = sizeof ( name ## _plaintext ), \ - .ciphertext = name ## _ciphertext, \ - .ciphertext_len = sizeof ( name ## _ciphertext ), \ + .plaintext = { \ + .data = name ## _plaintext, \ + .len = sizeof ( name ## _plaintext ), \ + }, \ + .ciphertext = { \ + .data = name ## _ciphertext, \ + .len = sizeof ( name ## _ciphertext ), \ + }, \ } /** -- cgit v1.2.3-55-g7522 From e6610b793a8971ed20d55fa2d6f95077e826f4db Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 3 Dec 2025 15:18:37 +0000 Subject: [test] Include key matching in existing public-key tests Signed-off-by: Michael Brown --- src/tests/pubkey_test.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/tests') diff --git a/src/tests/pubkey_test.c b/src/tests/pubkey_test.c index d110b2946..3bb414e47 100644 --- a/src/tests/pubkey_test.c +++ b/src/tests/pubkey_test.c @@ -53,6 +53,10 @@ void pubkey_okx ( struct pubkey_test *test, const char *file, struct asn1_builder plaintext; struct asn1_builder ciphertext; + /* Test key matching */ + okx ( pubkey_match ( pubkey, &test->private, &test->public ) == 0, + file, line ); + /* Test decrypting with private key to obtain known plaintext */ plaintext.data = NULL; plaintext.len = 0; @@ -109,6 +113,10 @@ void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file, struct asn1_builder signature = { NULL, 0 }; uint8_t *bad; + /* Test key matching */ + okx ( pubkey_match ( pubkey, &test->private, &test->public ) == 0, + file, line ); + /* Construct digest over plaintext */ digest_init ( digest, digestctx ); digest_update ( digest, digestctx, test->plaintext, -- cgit v1.2.3-55-g7522 From e50e30a7f8eafea0a1975c555a6fdcab35d8243a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 5 Dec 2025 13:00:12 +0000 Subject: [crypto] Expose the base point as an explicit elliptic curve property Add the generator base point as an explicit property of an elliptic curve, and remove the ability to pass a NULL to elliptic_multiply() to imply the use of the generator base point. Signed-off-by: Michael Brown --- src/crypto/ecdhe.c | 2 +- src/crypto/weierstrass.c | 6 +----- src/crypto/x25519.c | 7 ++----- src/include/ipxe/crypto.h | 4 +++- src/include/ipxe/weierstrass.h | 1 + src/tests/elliptic_test.c | 5 +++-- 6 files changed, 11 insertions(+), 14 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/ecdhe.c b/src/crypto/ecdhe.c index 5481b02eb..592c8ca1a 100644 --- a/src/crypto/ecdhe.c +++ b/src/crypto/ecdhe.c @@ -55,7 +55,7 @@ int ecdhe_key ( struct elliptic_curve *curve, const void *partner, } /* Construct public key */ - if ( ( rc = elliptic_multiply ( curve, NULL, private, + if ( ( rc = elliptic_multiply ( curve, curve->base, private, public ) ) != 0 ) { DBGC ( curve, "CURVE %s could not generate public key: %s\n", curve->name, strerror ( rc ) ); diff --git a/src/crypto/weierstrass.c b/src/crypto/weierstrass.c index c149c7b21..4974e5252 100644 --- a/src/crypto/weierstrass.c +++ b/src/crypto/weierstrass.c @@ -762,7 +762,7 @@ static int weierstrass_verify_raw ( const struct weierstrass_curve *curve, * Multiply curve point by scalar * * @v curve Weierstrass curve - * @v base Base point (or NULL to use generator) + * @v base Base point * @v scalar Scalar multiple * @v result Result point to fill in * @ret rc Return status code @@ -806,10 +806,6 @@ int weierstrass_multiply ( struct weierstrass_curve *curve, const void *base, if ( ! prime2->element[0] ) weierstrass_init ( curve ); - /* Use generator if applicable */ - if ( ! base ) - base = curve->base; - /* Convert input to projective coordinates in Montgomery form */ DBGC ( curve, "WEIERSTRASS %s base (", curve->name ); for ( i = 0, offset = 0 ; i < WEIERSTRASS_AXES ; i++, offset += len ) { diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c index 41bc5fc5e..00a791877 100644 --- a/src/crypto/x25519.c +++ b/src/crypto/x25519.c @@ -822,7 +822,7 @@ int x25519_key ( const struct x25519_value *base, /** * Multiply scalar by curve point * - * @v base Base point (or NULL to use generator) + * @v base Base point * @v scalar Scalar multiple * @v result Result point to fill in * @ret rc Return status code @@ -830,10 +830,6 @@ int x25519_key ( const struct x25519_value *base, static int x25519_curve_multiply ( const void *base, const void *scalar, void *result ) { - /* Use base point if applicable */ - if ( ! base ) - base = &x25519_generator; - return x25519_key ( base, scalar, result ); } @@ -842,5 +838,6 @@ struct elliptic_curve x25519_curve = { .name = "x25519", .pointsize = sizeof ( struct x25519_value ), .keysize = sizeof ( struct x25519_value ), + .base = x25519_generator.raw, .multiply = x25519_curve_multiply, }; diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index ee63423c9..d2adea5d6 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -181,9 +181,11 @@ struct elliptic_curve { size_t pointsize; /** Scalar (and private key) size */ size_t keysize; + /** Generator base point */ + const void *base; /** Multiply scalar by curve point * - * @v base Base point (or NULL to use generator) + * @v base Base point * @v scalar Scalar multiple * @v result Result point to fill in * @ret rc Return status code diff --git a/src/include/ipxe/weierstrass.h b/src/include/ipxe/weierstrass.h index fb09fa6fa..e5e411499 100644 --- a/src/include/ipxe/weierstrass.h +++ b/src/include/ipxe/weierstrass.h @@ -160,6 +160,7 @@ extern int weierstrass_multiply ( struct weierstrass_curve *curve, .name = #_name, \ .pointsize = ( WEIERSTRASS_AXES * (_len) ), \ .keysize = (_len), \ + .base = (_base), \ .multiply = _name ## _multiply, \ } diff --git a/src/tests/elliptic_test.c b/src/tests/elliptic_test.c index 4c42e5848..d8cdf2c0f 100644 --- a/src/tests/elliptic_test.c +++ b/src/tests/elliptic_test.c @@ -52,6 +52,7 @@ void elliptic_okx ( struct elliptic_test *test, const char *file, size_t pointsize = curve->pointsize; size_t keysize = curve->keysize; uint8_t actual[pointsize]; + const void *base; int rc; /* Sanity checks */ @@ -62,8 +63,8 @@ void elliptic_okx ( struct elliptic_test *test, const char *file, file, line ); /* Perform point multiplication */ - rc = elliptic_multiply ( curve, ( test->base_len ? test->base : NULL ), - test->scalar, actual ); + base = ( test->base_len ? test->base : curve->base ); + rc = elliptic_multiply ( curve, base, test->scalar, actual ); if ( test->expected_len ) { okx ( rc == 0, file, line ); } else { -- cgit v1.2.3-55-g7522 From b362f77bdf1214ad254fee5900ee52e4ee77b30e Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 5 Dec 2025 13:17:58 +0000 Subject: [test] Allow for elliptic curve tests other than multiplication Rename elliptic_ok() to elliptic_multiply_ok() etc, to create namespace for tests of other elliptic curve operations. Signed-off-by: Michael Brown --- src/tests/elliptic_test.c | 4 +- src/tests/elliptic_test.h | 13 +- src/tests/p256_test.c | 216 ++++++++++++++++---------------- src/tests/p384_test.c | 308 +++++++++++++++++++++++----------------------- 4 files changed, 271 insertions(+), 270 deletions(-) (limited to 'src/tests') diff --git a/src/tests/elliptic_test.c b/src/tests/elliptic_test.c index d8cdf2c0f..f856dcc7e 100644 --- a/src/tests/elliptic_test.c +++ b/src/tests/elliptic_test.c @@ -46,8 +46,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @v file Test code file * @v line Test code line */ -void elliptic_okx ( struct elliptic_test *test, const char *file, - unsigned int line ) { +void elliptic_multiply_okx ( struct elliptic_multiply_test *test, + const char *file, unsigned int line ) { struct elliptic_curve *curve = test->curve; size_t pointsize = curve->pointsize; size_t keysize = curve->keysize; diff --git a/src/tests/elliptic_test.h b/src/tests/elliptic_test.h index 94fca60aa..ea2fb97d9 100644 --- a/src/tests/elliptic_test.h +++ b/src/tests/elliptic_test.h @@ -8,7 +8,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include /** An elliptic curve point multiplication test */ -struct elliptic_test { +struct elliptic_multiply_test { /** Elliptic curve */ struct elliptic_curve *curve; /** Base point */ @@ -50,11 +50,11 @@ struct elliptic_test { * @v EXPECTED Expected result point * @ret test Elliptic curve point multiplication test */ -#define ELLIPTIC_TEST( name, CURVE, BASE, SCALAR, EXPECTED ) \ +#define ELLIPTIC_MULTIPLY_TEST( name, CURVE, BASE, SCALAR, EXPECTED ) \ static const uint8_t name ## _base[] = BASE; \ static const uint8_t name ## _scalar[] = SCALAR; \ static const uint8_t name ## _expected[] = EXPECTED; \ - static struct elliptic_test name = { \ + static struct elliptic_multiply_test name = { \ .curve = CURVE, \ .base = name ## _base, \ .base_len = sizeof ( name ## _base ), \ @@ -64,14 +64,15 @@ struct elliptic_test { .expected_len = sizeof ( name ## _expected ), \ }; -extern void elliptic_okx ( struct elliptic_test *test, const char *file, - unsigned int line ); +extern void elliptic_multiply_okx ( struct elliptic_multiply_test *test, + const char *file, unsigned int line ); /** * Report an elliptic curve point multiplication test result * * @v test Elliptic curve point multiplication test */ -#define elliptic_ok( test ) elliptic_okx ( test, __FILE__, __LINE__ ) +#define elliptic_multiply_ok( test ) \ + elliptic_multiply_okx ( test, __FILE__, __LINE__ ) #endif /* _ELLIPTIC_TEST_H */ diff --git a/src/tests/p256_test.c b/src/tests/p256_test.c index 62b8d9247..e6db61a53 100644 --- a/src/tests/p256_test.c +++ b/src/tests/p256_test.c @@ -37,119 +37,119 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include "elliptic_test.h" /* http://point-at-infinity.org/ecc/nisttv k=1 */ -ELLIPTIC_TEST ( poi_1, &p256_curve, BASE_GENERATOR, - SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), - EXPECTED ( 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, - 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, - 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, - 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, - 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, - 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, - 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, - 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5 ) ); +ELLIPTIC_MULTIPLY_TEST ( poi_1, &p256_curve, BASE_GENERATOR, + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED ( 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, + 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, + 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, + 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, + 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, + 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, + 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5 ) ); /* http://point-at-infinity.org/ecc/nisttv k=2 */ -ELLIPTIC_TEST ( poi_2, &p256_curve, BASE_GENERATOR, - SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 ), - EXPECTED ( 0x7c, 0xf2, 0x7b, 0x18, 0x8d, 0x03, 0x4f, 0x7e, - 0x8a, 0x52, 0x38, 0x03, 0x04, 0xb5, 0x1a, 0xc3, - 0xc0, 0x89, 0x69, 0xe2, 0x77, 0xf2, 0x1b, 0x35, - 0xa6, 0x0b, 0x48, 0xfc, 0x47, 0x66, 0x99, 0x78, - 0x07, 0x77, 0x55, 0x10, 0xdb, 0x8e, 0xd0, 0x40, - 0x29, 0x3d, 0x9a, 0xc6, 0x9f, 0x74, 0x30, 0xdb, - 0xba, 0x7d, 0xad, 0xe6, 0x3c, 0xe9, 0x82, 0x29, - 0x9e, 0x04, 0xb7, 0x9d, 0x22, 0x78, 0x73, 0xd1 ) ); +ELLIPTIC_MULTIPLY_TEST ( poi_2, &p256_curve, BASE_GENERATOR, + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 ), + EXPECTED ( 0x7c, 0xf2, 0x7b, 0x18, 0x8d, 0x03, 0x4f, 0x7e, + 0x8a, 0x52, 0x38, 0x03, 0x04, 0xb5, 0x1a, 0xc3, + 0xc0, 0x89, 0x69, 0xe2, 0x77, 0xf2, 0x1b, 0x35, + 0xa6, 0x0b, 0x48, 0xfc, 0x47, 0x66, 0x99, 0x78, + 0x07, 0x77, 0x55, 0x10, 0xdb, 0x8e, 0xd0, 0x40, + 0x29, 0x3d, 0x9a, 0xc6, 0x9f, 0x74, 0x30, 0xdb, + 0xba, 0x7d, 0xad, 0xe6, 0x3c, 0xe9, 0x82, 0x29, + 0x9e, 0x04, 0xb7, 0x9d, 0x22, 0x78, 0x73, 0xd1 ) ); /* http://point-at-infinity.org/ecc/nisttv k=2 (as base) to k=20 */ -ELLIPTIC_TEST ( poi_2_20, &p256_curve, - BASE ( 0x7c, 0xf2, 0x7b, 0x18, 0x8d, 0x03, 0x4f, 0x7e, - 0x8a, 0x52, 0x38, 0x03, 0x04, 0xb5, 0x1a, 0xc3, - 0xc0, 0x89, 0x69, 0xe2, 0x77, 0xf2, 0x1b, 0x35, - 0xa6, 0x0b, 0x48, 0xfc, 0x47, 0x66, 0x99, 0x78, - 0x07, 0x77, 0x55, 0x10, 0xdb, 0x8e, 0xd0, 0x40, - 0x29, 0x3d, 0x9a, 0xc6, 0x9f, 0x74, 0x30, 0xdb, - 0xba, 0x7d, 0xad, 0xe6, 0x3c, 0xe9, 0x82, 0x29, - 0x9e, 0x04, 0xb7, 0x9d, 0x22, 0x78, 0x73, 0xd1 ), - SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a ), - EXPECTED ( 0x83, 0xa0, 0x1a, 0x93, 0x78, 0x39, 0x5b, 0xab, - 0x9b, 0xcd, 0x6a, 0x0a, 0xd0, 0x3c, 0xc5, 0x6d, - 0x56, 0xe6, 0xb1, 0x92, 0x50, 0x46, 0x5a, 0x94, - 0xa2, 0x34, 0xdc, 0x4c, 0x6b, 0x28, 0xda, 0x9a, - 0x76, 0xe4, 0x9b, 0x6d, 0xe2, 0xf7, 0x32, 0x34, - 0xae, 0x6a, 0x5e, 0xb9, 0xd6, 0x12, 0xb7, 0x5c, - 0x9f, 0x22, 0x02, 0xbb, 0x69, 0x23, 0xf5, 0x4f, - 0xf8, 0x24, 0x0a, 0xaa, 0x86, 0xf6, 0x40, 0xb8 ) ); +ELLIPTIC_MULTIPLY_TEST ( poi_2_20, &p256_curve, + BASE ( 0x7c, 0xf2, 0x7b, 0x18, 0x8d, 0x03, 0x4f, 0x7e, + 0x8a, 0x52, 0x38, 0x03, 0x04, 0xb5, 0x1a, 0xc3, + 0xc0, 0x89, 0x69, 0xe2, 0x77, 0xf2, 0x1b, 0x35, + 0xa6, 0x0b, 0x48, 0xfc, 0x47, 0x66, 0x99, 0x78, + 0x07, 0x77, 0x55, 0x10, 0xdb, 0x8e, 0xd0, 0x40, + 0x29, 0x3d, 0x9a, 0xc6, 0x9f, 0x74, 0x30, 0xdb, + 0xba, 0x7d, 0xad, 0xe6, 0x3c, 0xe9, 0x82, 0x29, + 0x9e, 0x04, 0xb7, 0x9d, 0x22, 0x78, 0x73, 0xd1 ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a ), + EXPECTED ( 0x83, 0xa0, 0x1a, 0x93, 0x78, 0x39, 0x5b, 0xab, + 0x9b, 0xcd, 0x6a, 0x0a, 0xd0, 0x3c, 0xc5, 0x6d, + 0x56, 0xe6, 0xb1, 0x92, 0x50, 0x46, 0x5a, 0x94, + 0xa2, 0x34, 0xdc, 0x4c, 0x6b, 0x28, 0xda, 0x9a, + 0x76, 0xe4, 0x9b, 0x6d, 0xe2, 0xf7, 0x32, 0x34, + 0xae, 0x6a, 0x5e, 0xb9, 0xd6, 0x12, 0xb7, 0x5c, + 0x9f, 0x22, 0x02, 0xbb, 0x69, 0x23, 0xf5, 0x4f, + 0xf8, 0x24, 0x0a, 0xaa, 0x86, 0xf6, 0x40, 0xb8 ) ); /* http://point-at-infinity.org/ecc/nisttv k=112233445566778899 */ -ELLIPTIC_TEST ( poi_mid, &p256_curve, BASE_GENERATOR, - SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x8e, 0xbb, 0xb9, 0x5e, 0xed, 0x0e, 0x13 ), - EXPECTED ( 0x33, 0x91, 0x50, 0x84, 0x4e, 0xc1, 0x52, 0x34, - 0x80, 0x7f, 0xe8, 0x62, 0xa8, 0x6b, 0xe7, 0x79, - 0x77, 0xdb, 0xfb, 0x3a, 0xe3, 0xd9, 0x6f, 0x4c, - 0x22, 0x79, 0x55, 0x13, 0xae, 0xaa, 0xb8, 0x2f, - 0xb1, 0xc1, 0x4d, 0xdf, 0xdc, 0x8e, 0xc1, 0xb2, - 0x58, 0x3f, 0x51, 0xe8, 0x5a, 0x5e, 0xb3, 0xa1, - 0x55, 0x84, 0x0f, 0x20, 0x34, 0x73, 0x0e, 0x9b, - 0x5a, 0xda, 0x38, 0xb6, 0x74, 0x33, 0x6a, 0x21 ) ); +ELLIPTIC_MULTIPLY_TEST ( poi_mid, &p256_curve, BASE_GENERATOR, + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x8e, 0xbb, 0xb9, 0x5e, 0xed, 0x0e, 0x13 ), + EXPECTED ( 0x33, 0x91, 0x50, 0x84, 0x4e, 0xc1, 0x52, 0x34, + 0x80, 0x7f, 0xe8, 0x62, 0xa8, 0x6b, 0xe7, 0x79, + 0x77, 0xdb, 0xfb, 0x3a, 0xe3, 0xd9, 0x6f, 0x4c, + 0x22, 0x79, 0x55, 0x13, 0xae, 0xaa, 0xb8, 0x2f, + 0xb1, 0xc1, 0x4d, 0xdf, 0xdc, 0x8e, 0xc1, 0xb2, + 0x58, 0x3f, 0x51, 0xe8, 0x5a, 0x5e, 0xb3, 0xa1, + 0x55, 0x84, 0x0f, 0x20, 0x34, 0x73, 0x0e, 0x9b, + 0x5a, 0xda, 0x38, 0xb6, 0x74, 0x33, 0x6a, 0x21 ) ); /* http://point-at-infinity.org/ecc/nisttv k= */ -ELLIPTIC_TEST ( poi_large, &p256_curve, BASE_GENERATOR, - SCALAR ( 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, - 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x50 ), - EXPECTED ( 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, - 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, - 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, - 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, - 0xb0, 0x1c, 0xbd, 0x1c, 0x01, 0xe5, 0x80, 0x65, - 0x71, 0x18, 0x14, 0xb5, 0x83, 0xf0, 0x61, 0xe9, - 0xd4, 0x31, 0xcc, 0xa9, 0x94, 0xce, 0xa1, 0x31, - 0x34, 0x49, 0xbf, 0x97, 0xc8, 0x40, 0xae, 0x0a ) ); +ELLIPTIC_MULTIPLY_TEST ( poi_large, &p256_curve, BASE_GENERATOR, + SCALAR ( 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, 0x9e, 0x84, + 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x50 ), + EXPECTED ( 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, + 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, + 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, + 0xb0, 0x1c, 0xbd, 0x1c, 0x01, 0xe5, 0x80, 0x65, + 0x71, 0x18, 0x14, 0xb5, 0x83, 0xf0, 0x61, 0xe9, + 0xd4, 0x31, 0xcc, 0xa9, 0x94, 0xce, 0xa1, 0x31, + 0x34, 0x49, 0xbf, 0x97, 0xc8, 0x40, 0xae, 0x0a ) ); /* Invalid curve point zero */ -ELLIPTIC_TEST ( invalid_zero, &p256_curve, - BASE ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), - SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), - EXPECTED_FAIL ); +ELLIPTIC_MULTIPLY_TEST ( invalid_zero, &p256_curve, + BASE ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED_FAIL ); /* Invalid curve point (base_x, base_y - 1) */ -ELLIPTIC_TEST ( invalid_one, &p256_curve, - BASE ( 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, - 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, - 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, - 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, - 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, - 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, - 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, - 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf4 ), - SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), - EXPECTED_FAIL ); +ELLIPTIC_MULTIPLY_TEST ( invalid_one, &p256_curve, + BASE ( 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, + 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, + 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, + 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, + 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, + 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, + 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf4 ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED_FAIL ); /** * Perform P-256 self-test @@ -158,15 +158,15 @@ ELLIPTIC_TEST ( invalid_one, &p256_curve, static void p256_test_exec ( void ) { /* Tests from http://point-at-infinity.org/ecc/nisttv */ - elliptic_ok ( &poi_1 ); - elliptic_ok ( &poi_2 ); - elliptic_ok ( &poi_2_20 ); - elliptic_ok ( &poi_mid ); - elliptic_ok ( &poi_large ); + elliptic_multiply_ok ( &poi_1 ); + elliptic_multiply_ok ( &poi_2 ); + elliptic_multiply_ok ( &poi_2_20 ); + elliptic_multiply_ok ( &poi_mid ); + elliptic_multiply_ok ( &poi_large ); /* Invalid point tests */ - elliptic_ok ( &invalid_zero ); - elliptic_ok ( &invalid_one ); + elliptic_multiply_ok ( &invalid_zero ); + elliptic_multiply_ok ( &invalid_one ); } /** P-256 self-test */ diff --git a/src/tests/p384_test.c b/src/tests/p384_test.c index 101cfc24c..35c5679f8 100644 --- a/src/tests/p384_test.c +++ b/src/tests/p384_test.c @@ -37,165 +37,165 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include "elliptic_test.h" /* http://point-at-infinity.org/ecc/nisttv k=1 */ -ELLIPTIC_TEST ( poi_1, &p384_curve, BASE_GENERATOR, - SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), - EXPECTED ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, - 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, - 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, - 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, - 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, - 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, - 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, - 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, - 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, - 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, - 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, - 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f ) ); +ELLIPTIC_MULTIPLY_TEST ( poi_1, &p384_curve, BASE_GENERATOR, + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, + 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, + 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, + 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, + 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, + 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, + 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, + 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, + 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, + 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, + 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, + 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f ) ); /* http://point-at-infinity.org/ecc/nisttv k=2 */ -ELLIPTIC_TEST ( poi_2, &p384_curve, BASE_GENERATOR, - SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 ), - EXPECTED ( 0x08, 0xd9, 0x99, 0x05, 0x7b, 0xa3, 0xd2, 0xd9, - 0x69, 0x26, 0x00, 0x45, 0xc5, 0x5b, 0x97, 0xf0, - 0x89, 0x02, 0x59, 0x59, 0xa6, 0xf4, 0x34, 0xd6, - 0x51, 0xd2, 0x07, 0xd1, 0x9f, 0xb9, 0x6e, 0x9e, - 0x4f, 0xe0, 0xe8, 0x6e, 0xbe, 0x0e, 0x64, 0xf8, - 0x5b, 0x96, 0xa9, 0xc7, 0x52, 0x95, 0xdf, 0x61, - 0x8e, 0x80, 0xf1, 0xfa, 0x5b, 0x1b, 0x3c, 0xed, - 0xb7, 0xbf, 0xe8, 0xdf, 0xfd, 0x6d, 0xba, 0x74, - 0xb2, 0x75, 0xd8, 0x75, 0xbc, 0x6c, 0xc4, 0x3e, - 0x90, 0x4e, 0x50, 0x5f, 0x25, 0x6a, 0xb4, 0x25, - 0x5f, 0xfd, 0x43, 0xe9, 0x4d, 0x39, 0xe2, 0x2d, - 0x61, 0x50, 0x1e, 0x70, 0x0a, 0x94, 0x0e, 0x80 ) ); +ELLIPTIC_MULTIPLY_TEST ( poi_2, &p384_curve, BASE_GENERATOR, + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 ), + EXPECTED ( 0x08, 0xd9, 0x99, 0x05, 0x7b, 0xa3, 0xd2, 0xd9, + 0x69, 0x26, 0x00, 0x45, 0xc5, 0x5b, 0x97, 0xf0, + 0x89, 0x02, 0x59, 0x59, 0xa6, 0xf4, 0x34, 0xd6, + 0x51, 0xd2, 0x07, 0xd1, 0x9f, 0xb9, 0x6e, 0x9e, + 0x4f, 0xe0, 0xe8, 0x6e, 0xbe, 0x0e, 0x64, 0xf8, + 0x5b, 0x96, 0xa9, 0xc7, 0x52, 0x95, 0xdf, 0x61, + 0x8e, 0x80, 0xf1, 0xfa, 0x5b, 0x1b, 0x3c, 0xed, + 0xb7, 0xbf, 0xe8, 0xdf, 0xfd, 0x6d, 0xba, 0x74, + 0xb2, 0x75, 0xd8, 0x75, 0xbc, 0x6c, 0xc4, 0x3e, + 0x90, 0x4e, 0x50, 0x5f, 0x25, 0x6a, 0xb4, 0x25, + 0x5f, 0xfd, 0x43, 0xe9, 0x4d, 0x39, 0xe2, 0x2d, + 0x61, 0x50, 0x1e, 0x70, 0x0a, 0x94, 0x0e, 0x80 ) ); /* http://point-at-infinity.org/ecc/nisttv k=2 (as base) to k=20 */ -ELLIPTIC_TEST ( poi_2_20, &p384_curve, - BASE ( 0x08, 0xd9, 0x99, 0x05, 0x7b, 0xa3, 0xd2, 0xd9, - 0x69, 0x26, 0x00, 0x45, 0xc5, 0x5b, 0x97, 0xf0, - 0x89, 0x02, 0x59, 0x59, 0xa6, 0xf4, 0x34, 0xd6, - 0x51, 0xd2, 0x07, 0xd1, 0x9f, 0xb9, 0x6e, 0x9e, - 0x4f, 0xe0, 0xe8, 0x6e, 0xbe, 0x0e, 0x64, 0xf8, - 0x5b, 0x96, 0xa9, 0xc7, 0x52, 0x95, 0xdf, 0x61, - 0x8e, 0x80, 0xf1, 0xfa, 0x5b, 0x1b, 0x3c, 0xed, - 0xb7, 0xbf, 0xe8, 0xdf, 0xfd, 0x6d, 0xba, 0x74, - 0xb2, 0x75, 0xd8, 0x75, 0xbc, 0x6c, 0xc4, 0x3e, - 0x90, 0x4e, 0x50, 0x5f, 0x25, 0x6a, 0xb4, 0x25, - 0x5f, 0xfd, 0x43, 0xe9, 0x4d, 0x39, 0xe2, 0x2d, - 0x61, 0x50, 0x1e, 0x70, 0x0a, 0x94, 0x0e, 0x80 ), - SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a ), - EXPECTED ( 0x60, 0x55, 0x08, 0xec, 0x02, 0xc5, 0x34, 0xbc, - 0xee, 0xe9, 0x48, 0x4c, 0x86, 0x08, 0x6d, 0x21, - 0x39, 0x84, 0x9e, 0x2b, 0x11, 0xc1, 0xa9, 0xca, - 0x1e, 0x28, 0x08, 0xde, 0xc2, 0xea, 0xf1, 0x61, - 0xac, 0x8a, 0x10, 0x5d, 0x70, 0xd4, 0xf8, 0x5c, - 0x50, 0x59, 0x9b, 0xe5, 0x80, 0x0a, 0x62, 0x3f, - 0x51, 0x58, 0xee, 0x87, 0x96, 0x2a, 0xc6, 0xb8, - 0x1f, 0x00, 0xa1, 0x03, 0xb8, 0x54, 0x3a, 0x07, - 0x38, 0x1b, 0x76, 0x39, 0xa3, 0xa6, 0x5f, 0x13, - 0x53, 0xae, 0xf1, 0x1b, 0x73, 0x31, 0x06, 0xdd, - 0xe9, 0x2e, 0x99, 0xb7, 0x8d, 0xe3, 0x67, 0xb4, - 0x8e, 0x23, 0x8c, 0x38, 0xda, 0xd8, 0xee, 0xdd ) ); +ELLIPTIC_MULTIPLY_TEST ( poi_2_20, &p384_curve, + BASE ( 0x08, 0xd9, 0x99, 0x05, 0x7b, 0xa3, 0xd2, 0xd9, + 0x69, 0x26, 0x00, 0x45, 0xc5, 0x5b, 0x97, 0xf0, + 0x89, 0x02, 0x59, 0x59, 0xa6, 0xf4, 0x34, 0xd6, + 0x51, 0xd2, 0x07, 0xd1, 0x9f, 0xb9, 0x6e, 0x9e, + 0x4f, 0xe0, 0xe8, 0x6e, 0xbe, 0x0e, 0x64, 0xf8, + 0x5b, 0x96, 0xa9, 0xc7, 0x52, 0x95, 0xdf, 0x61, + 0x8e, 0x80, 0xf1, 0xfa, 0x5b, 0x1b, 0x3c, 0xed, + 0xb7, 0xbf, 0xe8, 0xdf, 0xfd, 0x6d, 0xba, 0x74, + 0xb2, 0x75, 0xd8, 0x75, 0xbc, 0x6c, 0xc4, 0x3e, + 0x90, 0x4e, 0x50, 0x5f, 0x25, 0x6a, 0xb4, 0x25, + 0x5f, 0xfd, 0x43, 0xe9, 0x4d, 0x39, 0xe2, 0x2d, + 0x61, 0x50, 0x1e, 0x70, 0x0a, 0x94, 0x0e, 0x80 ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a ), + EXPECTED ( 0x60, 0x55, 0x08, 0xec, 0x02, 0xc5, 0x34, 0xbc, + 0xee, 0xe9, 0x48, 0x4c, 0x86, 0x08, 0x6d, 0x21, + 0x39, 0x84, 0x9e, 0x2b, 0x11, 0xc1, 0xa9, 0xca, + 0x1e, 0x28, 0x08, 0xde, 0xc2, 0xea, 0xf1, 0x61, + 0xac, 0x8a, 0x10, 0x5d, 0x70, 0xd4, 0xf8, 0x5c, + 0x50, 0x59, 0x9b, 0xe5, 0x80, 0x0a, 0x62, 0x3f, + 0x51, 0x58, 0xee, 0x87, 0x96, 0x2a, 0xc6, 0xb8, + 0x1f, 0x00, 0xa1, 0x03, 0xb8, 0x54, 0x3a, 0x07, + 0x38, 0x1b, 0x76, 0x39, 0xa3, 0xa6, 0x5f, 0x13, + 0x53, 0xae, 0xf1, 0x1b, 0x73, 0x31, 0x06, 0xdd, + 0xe9, 0x2e, 0x99, 0xb7, 0x8d, 0xe3, 0x67, 0xb4, + 0x8e, 0x23, 0x8c, 0x38, 0xda, 0xd8, 0xee, 0xdd ) ); /* http://point-at-infinity.org/ecc/nisttv k=112233445566778899 */ -ELLIPTIC_TEST ( poi_mid, &p384_curve, BASE_GENERATOR, - SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x8e, 0xbb, 0xb9, 0x5e, 0xed, 0x0e, 0x13 ), - EXPECTED ( 0xa4, 0x99, 0xef, 0xe4, 0x88, 0x39, 0xbc, 0x3a, - 0xbc, 0xd1, 0xc5, 0xce, 0xdb, 0xdd, 0x51, 0x90, - 0x4f, 0x95, 0x14, 0xdb, 0x44, 0xf4, 0x68, 0x6d, - 0xb9, 0x18, 0x98, 0x3b, 0x0c, 0x9d, 0xc3, 0xae, - 0xe0, 0x5a, 0x88, 0xb7, 0x24, 0x33, 0xe9, 0x51, - 0x5f, 0x91, 0xa3, 0x29, 0xf5, 0xf4, 0xfa, 0x60, - 0x3b, 0x7c, 0xa2, 0x8e, 0xf3, 0x1f, 0x80, 0x9c, - 0x2f, 0x1b, 0xa2, 0x4a, 0xae, 0xd8, 0x47, 0xd0, - 0xf8, 0xb4, 0x06, 0xa4, 0xb8, 0x96, 0x85, 0x42, - 0xde, 0x13, 0x9d, 0xb5, 0x82, 0x8c, 0xa4, 0x10, - 0xe6, 0x15, 0xd1, 0x18, 0x2e, 0x25, 0xb9, 0x1b, - 0x11, 0x31, 0xe2, 0x30, 0xb7, 0x27, 0xd3, 0x6a ) ); +ELLIPTIC_MULTIPLY_TEST ( poi_mid, &p384_curve, BASE_GENERATOR, + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x8e, 0xbb, 0xb9, 0x5e, 0xed, 0x0e, 0x13 ), + EXPECTED ( 0xa4, 0x99, 0xef, 0xe4, 0x88, 0x39, 0xbc, 0x3a, + 0xbc, 0xd1, 0xc5, 0xce, 0xdb, 0xdd, 0x51, 0x90, + 0x4f, 0x95, 0x14, 0xdb, 0x44, 0xf4, 0x68, 0x6d, + 0xb9, 0x18, 0x98, 0x3b, 0x0c, 0x9d, 0xc3, 0xae, + 0xe0, 0x5a, 0x88, 0xb7, 0x24, 0x33, 0xe9, 0x51, + 0x5f, 0x91, 0xa3, 0x29, 0xf5, 0xf4, 0xfa, 0x60, + 0x3b, 0x7c, 0xa2, 0x8e, 0xf3, 0x1f, 0x80, 0x9c, + 0x2f, 0x1b, 0xa2, 0x4a, 0xae, 0xd8, 0x47, 0xd0, + 0xf8, 0xb4, 0x06, 0xa4, 0xb8, 0x96, 0x85, 0x42, + 0xde, 0x13, 0x9d, 0xb5, 0x82, 0x8c, 0xa4, 0x10, + 0xe6, 0x15, 0xd1, 0x18, 0x2e, 0x25, 0xb9, 0x1b, + 0x11, 0x31, 0xe2, 0x30, 0xb7, 0x27, 0xd3, 0x6a ) ); /* http://point-at-infinity.org/ecc/nisttv k= */ -ELLIPTIC_TEST ( poi_large, &p384_curve, BASE_GENERATOR, - SCALAR ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf, - 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a, - 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x72 ), - EXPECTED ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, - 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, - 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, - 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, - 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, - 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, - 0xc9, 0xe8, 0x21, 0xb5, 0x69, 0xd9, 0xd3, 0x90, - 0xa2, 0x61, 0x67, 0x40, 0x6d, 0x6d, 0x23, 0xd6, - 0x07, 0x0b, 0xe2, 0x42, 0xd7, 0x65, 0xeb, 0x83, - 0x16, 0x25, 0xce, 0xec, 0x4a, 0x0f, 0x47, 0x3e, - 0xf5, 0x9f, 0x4e, 0x30, 0xe2, 0x81, 0x7e, 0x62, - 0x85, 0xbc, 0xe2, 0x84, 0x6f, 0x15, 0xf1, 0xa0 ) ); +ELLIPTIC_MULTIPLY_TEST ( poi_large, &p384_curve, BASE_GENERATOR, + SCALAR ( 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf, + 0x58, 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a, + 0xec, 0xec, 0x19, 0x6a, 0xcc, 0xc5, 0x29, 0x72 ), + EXPECTED ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, + 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, + 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, + 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, + 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, + 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, + 0xc9, 0xe8, 0x21, 0xb5, 0x69, 0xd9, 0xd3, 0x90, + 0xa2, 0x61, 0x67, 0x40, 0x6d, 0x6d, 0x23, 0xd6, + 0x07, 0x0b, 0xe2, 0x42, 0xd7, 0x65, 0xeb, 0x83, + 0x16, 0x25, 0xce, 0xec, 0x4a, 0x0f, 0x47, 0x3e, + 0xf5, 0x9f, 0x4e, 0x30, 0xe2, 0x81, 0x7e, 0x62, + 0x85, 0xbc, 0xe2, 0x84, 0x6f, 0x15, 0xf1, 0xa0 ) ); /* Invalid curve point zero */ -ELLIPTIC_TEST ( invalid_zero, &p384_curve, - BASE ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), - SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), - EXPECTED_FAIL ); +ELLIPTIC_MULTIPLY_TEST ( invalid_zero, &p384_curve, + BASE ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED_FAIL ); /* Invalid curve point (base_x, base_y - 1) */ -ELLIPTIC_TEST ( invalid_one, &p384_curve, - BASE ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, - 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, - 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, - 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, - 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, - 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, - 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, - 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, - 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, - 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, - 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, - 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5e ), - SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), - EXPECTED_FAIL ); +ELLIPTIC_MULTIPLY_TEST ( invalid_one, &p384_curve, + BASE ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, + 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, + 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, + 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, + 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, + 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, + 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, + 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, + 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, + 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, + 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, + 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5e ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED_FAIL ); /** * Perform P-384 self-test @@ -204,15 +204,15 @@ ELLIPTIC_TEST ( invalid_one, &p384_curve, static void p384_test_exec ( void ) { /* Tests from http://point-at-infinity.org/ecc/nisttv */ - elliptic_ok ( &poi_1 ); - elliptic_ok ( &poi_2 ); - elliptic_ok ( &poi_2_20 ); - elliptic_ok ( &poi_mid ); - elliptic_ok ( &poi_large ); + elliptic_multiply_ok ( &poi_1 ); + elliptic_multiply_ok ( &poi_2 ); + elliptic_multiply_ok ( &poi_2_20 ); + elliptic_multiply_ok ( &poi_mid ); + elliptic_multiply_ok ( &poi_large ); /* Invalid point tests */ - elliptic_ok ( &invalid_zero ); - elliptic_ok ( &invalid_one ); + elliptic_multiply_ok ( &invalid_zero ); + elliptic_multiply_ok ( &invalid_one ); } /** P-384 self-test */ -- cgit v1.2.3-55-g7522 From d3adea83809537d7476430233994723c690ebfce Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 5 Dec 2025 14:47:55 +0000 Subject: [crypto] Expose the (prime) group order as an elliptic curve property ECDSA requires knowledge of the group order of the base point, and is defined only for curves with a prime group order (e.g. the NIST curves). Add the group order as an explicit property of an elliptic curve, and add tests to verify that the order is correct. Signed-off-by: Michael Brown --- src/crypto/p256.c | 9 ++++++++- src/crypto/p384.c | 11 ++++++++++- src/include/ipxe/crypto.h | 2 ++ src/include/ipxe/weierstrass.h | 4 +++- src/tests/elliptic_test.c | 43 ++++++++++++++++++++++++++++++++++++++++++ src/tests/elliptic_test.h | 10 ++++++++++ src/tests/p256_test.c | 3 +++ src/tests/p384_test.c | 3 +++ 8 files changed, 82 insertions(+), 3 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/p256.c b/src/crypto/p256.c index 9b0b542a1..2ba66e72c 100644 --- a/src/crypto/p256.c +++ b/src/crypto/p256.c @@ -62,6 +62,13 @@ static const uint8_t p256_base[ P256_LEN * 2 ] = { 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5 }; +/** P-256 group order */ +static const uint8_t p256_order[P256_LEN] = { + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xbc, 0xe6, 0xfa, 0xad, 0xa7, 0x17, + 0x9e, 0x84, 0xf3, 0xb9, 0xca, 0xc2, 0xfc, 0x63, 0x25, 0x51 +}; + /** P-256 elliptic curve */ WEIERSTRASS_CURVE ( p256, p256_curve, P256_LEN, - p256_prime, p256_a, p256_b, p256_base ); + p256_prime, p256_a, p256_b, p256_base, p256_order ); diff --git a/src/crypto/p384.c b/src/crypto/p384.c index 887bf161d..a53a9ce9d 100644 --- a/src/crypto/p384.c +++ b/src/crypto/p384.c @@ -71,6 +71,15 @@ static const uint8_t p384_base[ P384_LEN * 2 ] = { 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f }; +/** P-384 group order */ +static const uint8_t p384_order[P384_LEN] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xc7, 0x63, 0x4d, 0x81, 0xf4, 0x37, 0x2d, 0xdf, 0x58, + 0x1a, 0x0d, 0xb2, 0x48, 0xb0, 0xa7, 0x7a, 0xec, 0xec, 0x19, 0x6a, + 0xcc, 0xc5, 0x29, 0x73 +}; + /** P-384 elliptic curve */ WEIERSTRASS_CURVE ( p384, p384_curve, P384_LEN, - p384_prime, p384_a, p384_b, p384_base ); + p384_prime, p384_a, p384_b, p384_base, p384_order ); diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index d2adea5d6..8941ffa01 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -183,6 +183,8 @@ struct elliptic_curve { size_t keysize; /** Generator base point */ const void *base; + /** Order of the generator (if prime) */ + const void *order; /** Multiply scalar by curve point * * @v base Base point diff --git a/src/include/ipxe/weierstrass.h b/src/include/ipxe/weierstrass.h index e5e411499..b718886f6 100644 --- a/src/include/ipxe/weierstrass.h +++ b/src/include/ipxe/weierstrass.h @@ -128,7 +128,8 @@ extern int weierstrass_multiply ( struct weierstrass_curve *curve, void *result ); /** Define a Weierstrass curve */ -#define WEIERSTRASS_CURVE( _name, _curve, _len, _prime, _a, _b, _base ) \ +#define WEIERSTRASS_CURVE( _name, _curve, _len, _prime, _a, _b, _base, \ + _order ) \ static bigint_t ( weierstrass_size(_len) ) \ _name ## _cache[WEIERSTRASS_NUM_CACHED]; \ static struct weierstrass_curve _name ## _weierstrass = { \ @@ -161,6 +162,7 @@ extern int weierstrass_multiply ( struct weierstrass_curve *curve, .pointsize = ( WEIERSTRASS_AXES * (_len) ), \ .keysize = (_len), \ .base = (_base), \ + .order = (_order), \ .multiply = _name ## _multiply, \ } diff --git a/src/tests/elliptic_test.c b/src/tests/elliptic_test.c index f856dcc7e..a2266626d 100644 --- a/src/tests/elliptic_test.c +++ b/src/tests/elliptic_test.c @@ -35,10 +35,53 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include +#include #include #include #include "elliptic_test.h" +/** + * Report elliptic curve sanity test result + * + * @v curve Elliptic curve + * @v file Test code file + * @v line Test code line + */ +void elliptic_curve_okx ( struct elliptic_curve *curve, const char *file, + unsigned int line ) { + static const uint8_t one[] = { 1 }; + size_t pointsize = curve->pointsize; + size_t keysize = curve->keysize; + uint8_t point[pointsize]; + uint8_t scalar[keysize]; + struct { + bigint_t ( bigint_required_size ( keysize ) ) scalar; + bigint_t ( bigint_required_size ( keysize ) ) one; + } temp; + + /* Check that curve has the required properties */ + okx ( curve->base != NULL, file, line ); + okx ( curve->order != NULL, file, line ); + + /* Test multiplying base point by group order. Result should + * be the point at infinity, which should not be representable + * as a point in affine coordinates (and so should fail). + */ + okx ( elliptic_multiply ( curve, curve->base, curve->order, + point ) != 0, file, line ); + + /* Test multiplying base point by group order plus one, to get + * back to the base point. + */ + bigint_init ( &temp.scalar, curve->order, keysize ); + bigint_init ( &temp.one, one, sizeof ( one ) ); + bigint_add ( &temp.one, &temp.scalar ); + bigint_done ( &temp.scalar, scalar, sizeof ( scalar ) ); + okx ( elliptic_multiply ( curve, curve->base, scalar, point ) == 0, + file, line ); + okx ( memcmp ( point, curve->base, pointsize ) == 0, file, line ); +} + /** * Report elliptic curve point multiplication test result * diff --git a/src/tests/elliptic_test.h b/src/tests/elliptic_test.h index ea2fb97d9..1fcc4b108 100644 --- a/src/tests/elliptic_test.h +++ b/src/tests/elliptic_test.h @@ -64,9 +64,19 @@ struct elliptic_multiply_test { .expected_len = sizeof ( name ## _expected ), \ }; +extern void elliptic_curve_okx ( struct elliptic_curve *curve, + const char *file, unsigned int line ); extern void elliptic_multiply_okx ( struct elliptic_multiply_test *test, const char *file, unsigned int line ); +/** + * Report an elliptic curve sanity test result + * + * @v curve Elliptic curve + */ +#define elliptic_curve_ok( curve ) \ + elliptic_curve_okx ( curve, __FILE__, __LINE__ ) + /** * Report an elliptic curve point multiplication test result * diff --git a/src/tests/p256_test.c b/src/tests/p256_test.c index e6db61a53..8b425f215 100644 --- a/src/tests/p256_test.c +++ b/src/tests/p256_test.c @@ -157,6 +157,9 @@ ELLIPTIC_MULTIPLY_TEST ( invalid_one, &p256_curve, */ static void p256_test_exec ( void ) { + /* Curve sanity test */ + elliptic_curve_ok ( &p256_curve ); + /* Tests from http://point-at-infinity.org/ecc/nisttv */ elliptic_multiply_ok ( &poi_1 ); elliptic_multiply_ok ( &poi_2 ); diff --git a/src/tests/p384_test.c b/src/tests/p384_test.c index 35c5679f8..0b172c648 100644 --- a/src/tests/p384_test.c +++ b/src/tests/p384_test.c @@ -203,6 +203,9 @@ ELLIPTIC_MULTIPLY_TEST ( invalid_one, &p384_curve, */ static void p384_test_exec ( void ) { + /* Curve sanity test */ + elliptic_curve_ok ( &p384_curve ); + /* Tests from http://point-at-infinity.org/ecc/nisttv */ elliptic_multiply_ok ( &poi_1 ); elliptic_multiply_ok ( &poi_2 ); -- cgit v1.2.3-55-g7522 From c7f129fedef8c576c3399e20defcb32ad16fad36 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Sat, 6 Dec 2025 16:59:29 +0000 Subject: [crypto] Allow for addition of arbitrary Weierstrass curve points ECDSA verification requires the ability to add two arbitrary curve points (as well as the ability to multiply a curve point by a scalar). Add an elliptic curve method to perform arbitrary point addition. Pass in curve points as affine coordinates: this will require some redundant conversions between affine coorfinates and the internal representation as projective coordinates in Montgomery form, but keeps the API as simple as possible. Since we do not expect to perform a high volume of ECDSA signature verifications, these redundant calculations are an acceptable cost for keeping the code simple. Signed-off-by: Michael Brown --- src/crypto/weierstrass.c | 41 +++++++++++++++ src/crypto/x25519.c | 16 ++++++ src/include/ipxe/crypto.h | 14 +++++ src/include/ipxe/weierstrass.h | 9 ++++ src/tests/elliptic_test.c | 33 ++++++++++++ src/tests/elliptic_test.h | 58 +++++++++++++++++++++ src/tests/p256_test.c | 81 ++++++++++++++++++++++++++++- src/tests/p384_test.c | 113 ++++++++++++++++++++++++++++++++++++++++- 8 files changed, 363 insertions(+), 2 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/weierstrass.c b/src/crypto/weierstrass.c index ecc9699a1..b19970cef 100644 --- a/src/crypto/weierstrass.c +++ b/src/crypto/weierstrass.c @@ -953,3 +953,44 @@ int weierstrass_multiply ( struct weierstrass_curve *curve, const void *base, return 0; } + +/** + * Add curve points (as a one-off operation) + * + * @v curve Weierstrass curve + * @v addend Curve point to add + * @v augend Curve point to add + * @v result Curve point to hold result + * @ret rc Return status code + */ +int weierstrass_add_once ( struct weierstrass_curve *curve, const void *addend, + const void *augend, void *result ) { + unsigned int size = curve->size; + struct { + weierstrass_t ( size ) addend; + weierstrass_t ( size ) augend; + weierstrass_t ( size ) result; + } temp; + int rc; + + /* Convert inputs to projective coordinates in Montgomery form */ + if ( ( rc = weierstrass_init ( curve, &temp.addend, &temp.result, + addend ) ) != 0 ) { + return rc; + } + if ( ( rc = weierstrass_init ( curve, &temp.augend, &temp.result, + augend ) ) != 0 ) { + return rc; + } + + /* Add curve points */ + weierstrass_add ( curve, &temp.augend, &temp.addend, &temp.result ); + + /* Convert result back to affine co-ordinates */ + if ( ( rc = weierstrass_done ( curve, &temp.result, &temp.addend, + result ) ) != 0 ) { + return rc; + } + + return 0; +} diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c index 00a791877..11094ba6e 100644 --- a/src/crypto/x25519.c +++ b/src/crypto/x25519.c @@ -833,6 +833,21 @@ static int x25519_curve_multiply ( const void *base, const void *scalar, return x25519_key ( base, scalar, result ); } +/** + * Add curve points (as a one-off operation) + * + * @v addend Curve point to add + * @v augend Curve point to add + * @v result Curve point to hold result + * @ret rc Return status code + */ +static int x25519_curve_add ( const void *addend __unused, + const void *augend __unused, + void *result __unused ) { + + return -ENOTTY; +} + /** X25519 elliptic curve */ struct elliptic_curve x25519_curve = { .name = "x25519", @@ -840,4 +855,5 @@ struct elliptic_curve x25519_curve = { .keysize = sizeof ( struct x25519_value ), .base = x25519_generator.raw, .multiply = x25519_curve_multiply, + .add = x25519_curve_add, }; diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index 8941ffa01..93b718e15 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -194,6 +194,14 @@ struct elliptic_curve { */ int ( * multiply ) ( const void *base, const void *scalar, void *result ); + /** Add curve points (as a one-off operation) + * + * @v addend Curve point to add + * @v augend Curve point to add + * @v result Curve point to hold result + * @ret rc Return status code + */ + int ( * add ) ( const void *addend, const void *augend, void *result ); }; static inline __attribute__ (( always_inline )) void @@ -305,6 +313,12 @@ elliptic_multiply ( struct elliptic_curve *curve, return curve->multiply ( base, scalar, result ); } +static inline __attribute__ (( always_inline )) int +elliptic_add ( struct elliptic_curve *curve, const void *addend, + const void *augend, void *result ) { + return curve->add ( addend, augend, result ); +} + extern void digest_null_init ( void *ctx ); extern void digest_null_update ( void *ctx, const void *src, size_t len ); extern void digest_null_final ( void *ctx, void *out ); diff --git a/src/include/ipxe/weierstrass.h b/src/include/ipxe/weierstrass.h index b718886f6..ca3c216e6 100644 --- a/src/include/ipxe/weierstrass.h +++ b/src/include/ipxe/weierstrass.h @@ -126,6 +126,9 @@ struct weierstrass_curve { extern int weierstrass_multiply ( struct weierstrass_curve *curve, const void *base, const void *scalar, void *result ); +extern int weierstrass_add_once ( struct weierstrass_curve *curve, + const void *addend, const void *augend, + void *result ); /** Define a Weierstrass curve */ #define WEIERSTRASS_CURVE( _name, _curve, _len, _prime, _a, _b, _base, \ @@ -157,6 +160,11 @@ extern int weierstrass_multiply ( struct weierstrass_curve *curve, return weierstrass_multiply ( &_name ## _weierstrass, \ base, scalar, result ); \ } \ + static int _name ## _add ( const void *addend, \ + const void *augend, void *result) { \ + return weierstrass_add_once ( &_name ## _weierstrass, \ + addend, augend, result ); \ + } \ struct elliptic_curve _curve = { \ .name = #_name, \ .pointsize = ( WEIERSTRASS_AXES * (_len) ), \ @@ -164,6 +172,7 @@ extern int weierstrass_multiply ( struct weierstrass_curve *curve, .base = (_base), \ .order = (_order), \ .multiply = _name ## _multiply, \ + .add = _name ## _add, \ } #endif /* _IPXE_WEIERSTRASS_H */ diff --git a/src/tests/elliptic_test.c b/src/tests/elliptic_test.c index a2266626d..5b21ee00e 100644 --- a/src/tests/elliptic_test.c +++ b/src/tests/elliptic_test.c @@ -118,3 +118,36 @@ void elliptic_multiply_okx ( struct elliptic_multiply_test *test, okx ( memcmp ( actual, test->expected, test->expected_len ) == 0, file, line ); } + +/** + * Report elliptic curve point addition test result + * + * @v test Elliptic curve point addition test + * @v file Test code file + * @v line Test code line + */ +void elliptic_add_okx ( struct elliptic_add_test *test, + const char *file, unsigned int line ) { + struct elliptic_curve *curve = test->curve; + size_t pointsize = curve->pointsize; + uint8_t actual[pointsize]; + int rc; + + /* Sanity checks */ + okx ( test->addend_len == pointsize, file, line ); + okx ( test->augend_len == pointsize, file, line ); + okx ( ( test->expected_len == pointsize ) || ( ! test->expected_len ), + file, line ); + + /* Perform point addition */ + rc = elliptic_add ( curve, test->addend, test->augend, actual ); + if ( test->expected_len ) { + okx ( rc == 0, file, line ); + } else { + okx ( rc != 0, file, line ); + } + + /* Check expected result */ + okx ( memcmp ( actual, test->expected, test->expected_len ) == 0, + file, line ); +} diff --git a/src/tests/elliptic_test.h b/src/tests/elliptic_test.h index 1fcc4b108..eab242f17 100644 --- a/src/tests/elliptic_test.h +++ b/src/tests/elliptic_test.h @@ -25,6 +25,24 @@ struct elliptic_multiply_test { size_t expected_len; }; +/** An elliptic curve point addition test */ +struct elliptic_add_test { + /** Elliptic curve */ + struct elliptic_curve *curve; + /** Addend point */ + const void *addend; + /** Length of addend point */ + size_t addend_len; + /** Augend point */ + const void *augend; + /** Length of augend point */ + size_t augend_len; + /** Expected result point */ + const void *expected; + /** Length of expected result point (or 0 to expect failure) */ + size_t expected_len; +}; + /** Define inline base point */ #define BASE(...) { __VA_ARGS__ } @@ -34,6 +52,12 @@ struct elliptic_multiply_test { /** Define inline scalar multiple */ #define SCALAR(...) { __VA_ARGS__ } +/** Define inline addend point */ +#define ADDEND(...) { __VA_ARGS__ } + +/** Define inline augend point */ +#define AUGEND(...) { __VA_ARGS__ } + /** Define inline expected result point */ #define EXPECTED(...) { __VA_ARGS__ } @@ -64,10 +88,36 @@ struct elliptic_multiply_test { .expected_len = sizeof ( name ## _expected ), \ }; +/** + * Define an elliptic curve point addition test + * + * @v name Test name + * @v CURVE Elliptic curve + * @v ADDEND Addend point + * @v AUGEND Augend point + * @v EXPECTED Expected result point + * @ret test Elliptic curve point multiplication test + */ +#define ELLIPTIC_ADD_TEST( name, CURVE, ADDEND, AUGEND, EXPECTED ) \ + static const uint8_t name ## _addend[] = ADDEND; \ + static const uint8_t name ## _augend[] = AUGEND; \ + static const uint8_t name ## _expected[] = EXPECTED; \ + static struct elliptic_add_test name = { \ + .curve = CURVE, \ + .addend = name ## _addend, \ + .addend_len = sizeof ( name ## _addend ), \ + .augend = name ## _augend, \ + .augend_len = sizeof ( name ## _augend ), \ + .expected = name ## _expected, \ + .expected_len = sizeof ( name ## _expected ), \ + }; + extern void elliptic_curve_okx ( struct elliptic_curve *curve, const char *file, unsigned int line ); extern void elliptic_multiply_okx ( struct elliptic_multiply_test *test, const char *file, unsigned int line ); +extern void elliptic_add_okx ( struct elliptic_add_test *test, + const char *file, unsigned int line ); /** * Report an elliptic curve sanity test result @@ -85,4 +135,12 @@ extern void elliptic_multiply_okx ( struct elliptic_multiply_test *test, #define elliptic_multiply_ok( test ) \ elliptic_multiply_okx ( test, __FILE__, __LINE__ ) +/** + * Report an elliptic curve point addition test result + * + * @v test Elliptic curve point addition test + */ +#define elliptic_add_ok( test ) \ + elliptic_add_okx ( test, __FILE__, __LINE__ ) + #endif /* _ELLIPTIC_TEST_H */ diff --git a/src/tests/p256_test.c b/src/tests/p256_test.c index 8b425f215..b7bbe47b6 100644 --- a/src/tests/p256_test.c +++ b/src/tests/p256_test.c @@ -151,6 +151,80 @@ ELLIPTIC_MULTIPLY_TEST ( invalid_one, &p256_curve, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), EXPECTED_FAIL ); +/* http://point-at-infinity.org/ecc/nisttv k=2 + k=2 => k=4 */ +ELLIPTIC_ADD_TEST ( poi_2_2_4, &p256_curve, + ADDEND ( 0x7c, 0xf2, 0x7b, 0x18, 0x8d, 0x03, 0x4f, 0x7e, + 0x8a, 0x52, 0x38, 0x03, 0x04, 0xb5, 0x1a, 0xc3, + 0xc0, 0x89, 0x69, 0xe2, 0x77, 0xf2, 0x1b, 0x35, + 0xa6, 0x0b, 0x48, 0xfc, 0x47, 0x66, 0x99, 0x78, + 0x07, 0x77, 0x55, 0x10, 0xdb, 0x8e, 0xd0, 0x40, + 0x29, 0x3d, 0x9a, 0xc6, 0x9f, 0x74, 0x30, 0xdb, + 0xba, 0x7d, 0xad, 0xe6, 0x3c, 0xe9, 0x82, 0x29, + 0x9e, 0x04, 0xb7, 0x9d, 0x22, 0x78, 0x73, 0xd1 ), + AUGEND ( 0x7c, 0xf2, 0x7b, 0x18, 0x8d, 0x03, 0x4f, 0x7e, + 0x8a, 0x52, 0x38, 0x03, 0x04, 0xb5, 0x1a, 0xc3, + 0xc0, 0x89, 0x69, 0xe2, 0x77, 0xf2, 0x1b, 0x35, + 0xa6, 0x0b, 0x48, 0xfc, 0x47, 0x66, 0x99, 0x78, + 0x07, 0x77, 0x55, 0x10, 0xdb, 0x8e, 0xd0, 0x40, + 0x29, 0x3d, 0x9a, 0xc6, 0x9f, 0x74, 0x30, 0xdb, + 0xba, 0x7d, 0xad, 0xe6, 0x3c, 0xe9, 0x82, 0x29, + 0x9e, 0x04, 0xb7, 0x9d, 0x22, 0x78, 0x73, 0xd1 ), + EXPECTED ( 0xe2, 0x53, 0x4a, 0x35, 0x32, 0xd0, 0x8f, 0xbb, + 0xa0, 0x2d, 0xde, 0x65, 0x9e, 0xe6, 0x2b, 0xd0, + 0x03, 0x1f, 0xe2, 0xdb, 0x78, 0x55, 0x96, 0xef, + 0x50, 0x93, 0x02, 0x44, 0x6b, 0x03, 0x08, 0x52, + 0xe0, 0xf1, 0x57, 0x5a, 0x4c, 0x63, 0x3c, 0xc7, + 0x19, 0xdf, 0xee, 0x5f, 0xda, 0x86, 0x2d, 0x76, + 0x4e, 0xfc, 0x96, 0xc3, 0xf3, 0x0e, 0xe0, 0x05, + 0x5c, 0x42, 0xc2, 0x3f, 0x18, 0x4e, 0xd8, 0xc6 ) ); + +/* http://point-at-infinity.org/ecc/nisttv k=3 + k=5 => k=8 */ +ELLIPTIC_ADD_TEST ( poi_3_5_8, &p256_curve, + ADDEND ( 0x5e, 0xcb, 0xe4, 0xd1, 0xa6, 0x33, 0x0a, 0x44, + 0xc8, 0xf7, 0xef, 0x95, 0x1d, 0x4b, 0xf1, 0x65, + 0xe6, 0xc6, 0xb7, 0x21, 0xef, 0xad, 0xa9, 0x85, + 0xfb, 0x41, 0x66, 0x1b, 0xc6, 0xe7, 0xfd, 0x6c, + 0x87, 0x34, 0x64, 0x0c, 0x49, 0x98, 0xff, 0x7e, + 0x37, 0x4b, 0x06, 0xce, 0x1a, 0x64, 0xa2, 0xec, + 0xd8, 0x2a, 0xb0, 0x36, 0x38, 0x4f, 0xb8, 0x3d, + 0x9a, 0x79, 0xb1, 0x27, 0xa2, 0x7d, 0x50, 0x32 ), + AUGEND ( 0x51, 0x59, 0x0b, 0x7a, 0x51, 0x51, 0x40, 0xd2, + 0xd7, 0x84, 0xc8, 0x56, 0x08, 0x66, 0x8f, 0xdf, + 0xef, 0x8c, 0x82, 0xfd, 0x1f, 0x5b, 0xe5, 0x24, + 0x21, 0x55, 0x4a, 0x0d, 0xc3, 0xd0, 0x33, 0xed, + 0xe0, 0xc1, 0x7d, 0xa8, 0x90, 0x4a, 0x72, 0x7d, + 0x8a, 0xe1, 0xbf, 0x36, 0xbf, 0x8a, 0x79, 0x26, + 0x0d, 0x01, 0x2f, 0x00, 0xd4, 0xd8, 0x08, 0x88, + 0xd1, 0xd0, 0xbb, 0x44, 0xfd, 0xa1, 0x6d, 0xa4 ), + EXPECTED ( 0x62, 0xd9, 0x77, 0x9d, 0xbe, 0xe9, 0xb0, 0x53, + 0x40, 0x42, 0x74, 0x2d, 0x3a, 0xb5, 0x4c, 0xad, + 0xc1, 0xd2, 0x38, 0x98, 0x0f, 0xce, 0x97, 0xdb, + 0xb4, 0xdd, 0x9d, 0xc1, 0xdb, 0x6f, 0xb3, 0x93, + 0xad, 0x5a, 0xcc, 0xbd, 0x91, 0xe9, 0xd8, 0x24, + 0x4f, 0xf1, 0x5d, 0x77, 0x11, 0x67, 0xce, 0xe0, + 0xa2, 0xed, 0x51, 0xf6, 0xbb, 0xe7, 0x6a, 0x78, + 0xda, 0x54, 0x0a, 0x6a, 0x0f, 0x09, 0x95, 0x7e ) ); + +/* http://point-at-infinity.org/ecc/nisttv k=1 + k=n-1 => infinity */ +ELLIPTIC_ADD_TEST ( poi_1_n_1, &p256_curve, + ADDEND ( 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, + 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, + 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, + 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, + 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, + 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, + 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5 ), + AUGEND ( 0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, + 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, + 0x77, 0x03, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, + 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96, + 0xb0, 0x1c, 0xbd, 0x1c, 0x01, 0xe5, 0x80, 0x65, + 0x71, 0x18, 0x14, 0xb5, 0x83, 0xf0, 0x61, 0xe9, + 0xd4, 0x31, 0xcc, 0xa9, 0x94, 0xce, 0xa1, 0x31, + 0x34, 0x49, 0xbf, 0x97, 0xc8, 0x40, 0xae, 0x0a ), + EXPECTED_FAIL ); + /** * Perform P-256 self-test * @@ -160,7 +234,7 @@ static void p256_test_exec ( void ) { /* Curve sanity test */ elliptic_curve_ok ( &p256_curve ); - /* Tests from http://point-at-infinity.org/ecc/nisttv */ + /* Multiplication tests from http://point-at-infinity.org/ecc/nisttv */ elliptic_multiply_ok ( &poi_1 ); elliptic_multiply_ok ( &poi_2 ); elliptic_multiply_ok ( &poi_2_20 ); @@ -170,6 +244,11 @@ static void p256_test_exec ( void ) { /* Invalid point tests */ elliptic_multiply_ok ( &invalid_zero ); elliptic_multiply_ok ( &invalid_one ); + + /* Addition tests from http://point-at-infinity.org/ecc/nisttv */ + elliptic_add_ok ( &poi_2_2_4 ); + elliptic_add_ok ( &poi_3_5_8 ); + elliptic_add_ok ( &poi_1_n_1 ); } /** P-256 self-test */ diff --git a/src/tests/p384_test.c b/src/tests/p384_test.c index 0b172c648..c67cfbc79 100644 --- a/src/tests/p384_test.c +++ b/src/tests/p384_test.c @@ -197,6 +197,112 @@ ELLIPTIC_MULTIPLY_TEST ( invalid_one, &p384_curve, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), EXPECTED_FAIL ); +/* http://point-at-infinity.org/ecc/nisttv k=2 + k=2 => k=4 */ +ELLIPTIC_ADD_TEST ( poi_2_2_4, &p384_curve, + ADDEND ( 0x08, 0xd9, 0x99, 0x05, 0x7b, 0xa3, 0xd2, 0xd9, + 0x69, 0x26, 0x00, 0x45, 0xc5, 0x5b, 0x97, 0xf0, + 0x89, 0x02, 0x59, 0x59, 0xa6, 0xf4, 0x34, 0xd6, + 0x51, 0xd2, 0x07, 0xd1, 0x9f, 0xb9, 0x6e, 0x9e, + 0x4f, 0xe0, 0xe8, 0x6e, 0xbe, 0x0e, 0x64, 0xf8, + 0x5b, 0x96, 0xa9, 0xc7, 0x52, 0x95, 0xdf, 0x61, + 0x8e, 0x80, 0xf1, 0xfa, 0x5b, 0x1b, 0x3c, 0xed, + 0xb7, 0xbf, 0xe8, 0xdf, 0xfd, 0x6d, 0xba, 0x74, + 0xb2, 0x75, 0xd8, 0x75, 0xbc, 0x6c, 0xc4, 0x3e, + 0x90, 0x4e, 0x50, 0x5f, 0x25, 0x6a, 0xb4, 0x25, + 0x5f, 0xfd, 0x43, 0xe9, 0x4d, 0x39, 0xe2, 0x2d, + 0x61, 0x50, 0x1e, 0x70, 0x0a, 0x94, 0x0e, 0x80 ), + AUGEND ( 0x08, 0xd9, 0x99, 0x05, 0x7b, 0xa3, 0xd2, 0xd9, + 0x69, 0x26, 0x00, 0x45, 0xc5, 0x5b, 0x97, 0xf0, + 0x89, 0x02, 0x59, 0x59, 0xa6, 0xf4, 0x34, 0xd6, + 0x51, 0xd2, 0x07, 0xd1, 0x9f, 0xb9, 0x6e, 0x9e, + 0x4f, 0xe0, 0xe8, 0x6e, 0xbe, 0x0e, 0x64, 0xf8, + 0x5b, 0x96, 0xa9, 0xc7, 0x52, 0x95, 0xdf, 0x61, + 0x8e, 0x80, 0xf1, 0xfa, 0x5b, 0x1b, 0x3c, 0xed, + 0xb7, 0xbf, 0xe8, 0xdf, 0xfd, 0x6d, 0xba, 0x74, + 0xb2, 0x75, 0xd8, 0x75, 0xbc, 0x6c, 0xc4, 0x3e, + 0x90, 0x4e, 0x50, 0x5f, 0x25, 0x6a, 0xb4, 0x25, + 0x5f, 0xfd, 0x43, 0xe9, 0x4d, 0x39, 0xe2, 0x2d, + 0x61, 0x50, 0x1e, 0x70, 0x0a, 0x94, 0x0e, 0x80 ), + EXPECTED ( 0x13, 0x82, 0x51, 0xcd, 0x52, 0xac, 0x92, 0x98, + 0xc1, 0xc8, 0xaa, 0xd9, 0x77, 0x32, 0x1d, 0xeb, + 0x97, 0xe7, 0x09, 0xbd, 0x0b, 0x4c, 0xa0, 0xac, + 0xa5, 0x5d, 0xc8, 0xad, 0x51, 0xdc, 0xfc, 0x9d, + 0x15, 0x89, 0xa1, 0x59, 0x7e, 0x3a, 0x51, 0x20, + 0xe1, 0xef, 0xd6, 0x31, 0xc6, 0x3e, 0x18, 0x35, + 0xca, 0xca, 0xe2, 0x98, 0x69, 0xa6, 0x2e, 0x16, + 0x31, 0xe8, 0xa2, 0x81, 0x81, 0xab, 0x56, 0x61, + 0x6d, 0xc4, 0x5d, 0x91, 0x8a, 0xbc, 0x09, 0xf3, + 0xab, 0x0e, 0x63, 0xcf, 0x79, 0x2a, 0xa4, 0xdc, + 0xed, 0x73, 0x87, 0xbe, 0x37, 0xbb, 0xa5, 0x69, + 0x54, 0x9f, 0x1c, 0x02, 0xb2, 0x70, 0xed, 0x67 ) ); + +/* http://point-at-infinity.org/ecc/nisttv k=3 + k=5 => k=8 */ +ELLIPTIC_ADD_TEST ( poi_3_5_8, &p384_curve, + ADDEND ( 0x07, 0x7a, 0x41, 0xd4, 0x60, 0x6f, 0xfa, 0x14, + 0x64, 0x79, 0x3c, 0x7e, 0x5f, 0xdc, 0x7d, 0x98, + 0xcb, 0x9d, 0x39, 0x10, 0x20, 0x2d, 0xcd, 0x06, + 0xbe, 0xa4, 0xf2, 0x40, 0xd3, 0x56, 0x6d, 0xa6, + 0xb4, 0x08, 0xbb, 0xae, 0x50, 0x26, 0x58, 0x0d, + 0x02, 0xd7, 0xe5, 0xc7, 0x05, 0x00, 0xc8, 0x31, + 0xc9, 0x95, 0xf7, 0xca, 0x0b, 0x0c, 0x42, 0x83, + 0x7d, 0x0b, 0xbe, 0x96, 0x02, 0xa9, 0xfc, 0x99, + 0x85, 0x20, 0xb4, 0x1c, 0x85, 0x11, 0x5a, 0xa5, + 0xf7, 0x68, 0x4c, 0x0e, 0xdc, 0x11, 0x1e, 0xac, + 0xc2, 0x4a, 0xbd, 0x6b, 0xe4, 0xb5, 0xd2, 0x98, + 0xb6, 0x5f, 0x28, 0x60, 0x0a, 0x2f, 0x1d, 0xf1 ), + AUGEND ( 0x11, 0xde, 0x24, 0xa2, 0xc2, 0x51, 0xc7, 0x77, + 0x57, 0x3c, 0xac, 0x5e, 0xa0, 0x25, 0xe4, 0x67, + 0xf2, 0x08, 0xe5, 0x1d, 0xbf, 0xf9, 0x8f, 0xc5, + 0x4f, 0x66, 0x61, 0xcb, 0xe5, 0x65, 0x83, 0xb0, + 0x37, 0x88, 0x2f, 0x4a, 0x1c, 0xa2, 0x97, 0xe6, + 0x0a, 0xbc, 0xdb, 0xc3, 0x83, 0x6d, 0x84, 0xbc, + 0x8f, 0xa6, 0x96, 0xc7, 0x74, 0x40, 0xf9, 0x2d, + 0x0f, 0x58, 0x37, 0xe9, 0x0a, 0x00, 0xe7, 0xc5, + 0x28, 0x4b, 0x44, 0x77, 0x54, 0xd5, 0xde, 0xe8, + 0x8c, 0x98, 0x65, 0x33, 0xb6, 0x90, 0x1a, 0xeb, + 0x31, 0x77, 0x68, 0x6d, 0x0a, 0xe8, 0xfb, 0x33, + 0x18, 0x44, 0x14, 0xab, 0xe6, 0xc1, 0x71, 0x3a ), + EXPECTED ( 0x16, 0x92, 0x77, 0x8e, 0xa5, 0x96, 0xe0, 0xbe, + 0x75, 0x11, 0x42, 0x97, 0xa6, 0xfa, 0x38, 0x34, + 0x45, 0xbf, 0x22, 0x7f, 0xbe, 0x58, 0x19, 0x0a, + 0x90, 0x0c, 0x3c, 0x73, 0x25, 0x6f, 0x11, 0xfb, + 0x5a, 0x32, 0x58, 0xd6, 0xf4, 0x03, 0xd5, 0xec, + 0xe6, 0xe9, 0xb2, 0x69, 0xd8, 0x22, 0xc8, 0x7d, + 0xdc, 0xd2, 0x36, 0x57, 0x00, 0xd4, 0x10, 0x6a, + 0x83, 0x53, 0x88, 0xba, 0x3d, 0xb8, 0xfd, 0x0e, + 0x22, 0x55, 0x4a, 0xdc, 0x6d, 0x52, 0x1c, 0xd4, + 0xbd, 0x1c, 0x30, 0xc2, 0xec, 0x0e, 0xec, 0x19, + 0x6b, 0xad, 0xe1, 0xe9, 0xcd, 0xd1, 0x70, 0x8d, + 0x6f, 0x6a, 0xbf, 0xa4, 0x02, 0x2b, 0x0a, 0xd2 ) ); + +/* http://point-at-infinity.org/ecc/nisttv k=1 + k=n-1 => infinity */ +ELLIPTIC_ADD_TEST ( poi_1_n_1, &p384_curve, + ADDEND ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, + 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, + 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, + 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, + 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, + 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, + 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, + 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, + 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, + 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, + 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, + 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5f ), + AUGEND ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, + 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, + 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, + 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, + 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, + 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, + 0xc9, 0xe8, 0x21, 0xb5, 0x69, 0xd9, 0xd3, 0x90, + 0xa2, 0x61, 0x67, 0x40, 0x6d, 0x6d, 0x23, 0xd6, + 0x07, 0x0b, 0xe2, 0x42, 0xd7, 0x65, 0xeb, 0x83, + 0x16, 0x25, 0xce, 0xec, 0x4a, 0x0f, 0x47, 0x3e, + 0xf5, 0x9f, 0x4e, 0x30, 0xe2, 0x81, 0x7e, 0x62, + 0x85, 0xbc, 0xe2, 0x84, 0x6f, 0x15, 0xf1, 0xa0 ), + EXPECTED_FAIL ); + /** * Perform P-384 self-test * @@ -206,7 +312,7 @@ static void p384_test_exec ( void ) { /* Curve sanity test */ elliptic_curve_ok ( &p384_curve ); - /* Tests from http://point-at-infinity.org/ecc/nisttv */ + /* Multiplication tests from http://point-at-infinity.org/ecc/nisttv */ elliptic_multiply_ok ( &poi_1 ); elliptic_multiply_ok ( &poi_2 ); elliptic_multiply_ok ( &poi_2_20 ); @@ -216,6 +322,11 @@ static void p384_test_exec ( void ) { /* Invalid point tests */ elliptic_multiply_ok ( &invalid_zero ); elliptic_multiply_ok ( &invalid_one ); + + /* Addition tests from http://point-at-infinity.org/ecc/nisttv */ + elliptic_add_ok ( &poi_2_2_4 ); + elliptic_add_ok ( &poi_3_5_8 ); + elliptic_add_ok ( &poi_1_n_1 ); } /** P-384 self-test */ -- cgit v1.2.3-55-g7522 From af99310f55e496b587a711d2d2c218b0cfaef37a Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 17 Dec 2025 20:35:18 +0000 Subject: [test] Test signature verification independently of signing Copy and modify the signature defined within the test case for verification tests, rather than relying on the modifiable signature constructed by the signing portion of the same test. Signed-off-by: Michael Brown --- src/tests/pubkey_test.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'src/tests') diff --git a/src/tests/pubkey_test.c b/src/tests/pubkey_test.c index 3bb414e47..15b24f005 100644 --- a/src/tests/pubkey_test.c +++ b/src/tests/pubkey_test.c @@ -108,9 +108,11 @@ void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file, unsigned int line ) { struct pubkey_algorithm *pubkey = test->pubkey; struct digest_algorithm *digest = test->digest; - uint8_t digestctx[digest->ctxsize ]; + uint8_t digestctx[digest->ctxsize]; uint8_t digestout[digest->digestsize]; - struct asn1_builder signature = { NULL, 0 }; + uint8_t signature[test->signature.len]; + struct asn1_cursor cursor = { signature, sizeof ( signature ) }; + struct asn1_builder builder = { NULL, 0 }; uint8_t *bad; /* Test key matching */ @@ -123,25 +125,27 @@ void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file, test->plaintext_len ); digest_final ( digest, digestctx, digestout ); - /* Test signing using private key */ - okx ( pubkey_sign ( pubkey, &test->private, digest, digestout, - &signature ) == 0, file, line ); - okx ( signature.len != 0, file, line ); - okx ( asn1_compare ( asn1_built ( &signature ), - &test->signature ) == 0, file, line ); - /* Test verification using public key */ okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, &test->signature ) == 0, file, line ); /* Test verification failure of modified signature */ - bad = ( signature.data + ( test->signature.len / 2 ) ); + memcpy ( signature, test->signature.data, sizeof ( signature ) ); + bad = ( signature + ( sizeof ( signature ) / 2 ) ); + *bad ^= 0x40; okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, - asn1_built ( &signature ) ) == 0, file, line ); + &cursor ) != 0, file, line ); *bad ^= 0x40; okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, - asn1_built ( &signature ) ) != 0, file, line ); + &cursor ) == 0, file, line ); + + /* Test signing using private key */ + okx ( pubkey_sign ( pubkey, &test->private, digest, digestout, + &builder ) == 0, file, line ); + okx ( builder.len != 0, file, line ); + okx ( asn1_compare ( asn1_built ( &builder ), &test->signature ) == 0, + file, line ); /* Free signature */ - free ( signature.data ); + free ( builder.data ); } -- cgit v1.2.3-55-g7522 From cfbf0da93c27a33c6e76c0caac65708160425500 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 18 Dec 2025 15:38:11 +0000 Subject: [crypto] Allow for an explicit representation of point at infinity ECDSA requires the ability to add two arbitrary curve points, either of which may legitimately be the point at infinity. Update the API so that curves must choose an explicit affine representation for the point at infinity, and provide a method to test for this representation. Multiplication and addition will now allow this representation to be provided as an input, and will not fail if the result is the point at infinity. Callers must explicitly check for the point at infinity where needed (e.g. after computing the ECDHE shared secret curve point). Signed-off-by: Michael Brown --- src/crypto/ecdhe.c | 8 +++++ src/crypto/weierstrass.c | 76 ++++++++++++++++++++++++++++------------- src/crypto/x25519.c | 38 +++++++++++++++++---- src/include/ipxe/crypto.h | 15 ++++++++ src/include/ipxe/errfile.h | 1 + src/include/ipxe/weierstrass.h | 8 +++++ src/include/ipxe/x25519.h | 7 ++-- src/tests/elliptic_test.c | 7 ++-- src/tests/p256_test.c | 39 +++++++++++++++++++-- src/tests/p384_test.c | 77 ++++++++++++++++++++++++++++++++++-------- src/tests/x25519_test.c | 7 ++-- 11 files changed, 225 insertions(+), 58 deletions(-) (limited to 'src/tests') diff --git a/src/crypto/ecdhe.c b/src/crypto/ecdhe.c index 592c8ca1a..6c86b1c90 100644 --- a/src/crypto/ecdhe.c +++ b/src/crypto/ecdhe.c @@ -30,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); */ #include +#include #include /** @@ -62,5 +63,12 @@ int ecdhe_key ( struct elliptic_curve *curve, const void *partner, return rc; } + /* Check that partner and shared keys are not the point at infinity */ + if ( elliptic_is_infinity ( curve, shared ) ) { + DBGC ( curve, "CURVE %s constructed point at infinity\n", + curve->name ); + return -EPERM; + } + return 0; } diff --git a/src/crypto/weierstrass.c b/src/crypto/weierstrass.c index b19970cef..bb9b50bf8 100644 --- a/src/crypto/weierstrass.c +++ b/src/crypto/weierstrass.c @@ -658,7 +658,7 @@ static void weierstrass_add_ladder ( const bigint_element_t *operand0, } /** - * Verify point is on curve + * Verify freshly initialised point is on curve * * @v curve Weierstrass curve * @v point0 Element 0 of point (x,y,z) to be verified @@ -667,6 +667,10 @@ static void weierstrass_add_ladder ( const bigint_element_t *operand0, * As with point addition, points are represented in projective * coordinates, with all values in Montgomery form and in the range * [0,4N) where N is the field prime. + * + * This verification logic is valid only for points that have been + * freshly constructed via weierstrass_init() (i.e. must either have + * z=1 or be the point at infinity (0,1,0)). */ static int weierstrass_verify_raw ( const struct weierstrass_curve *curve, const bigint_element_t *point0 ) { @@ -719,6 +723,10 @@ static int weierstrass_verify_raw ( const struct weierstrass_curve *curve, * = 3*(x^3 + a*x + b - y^2) (mod 13N) */ WEIERSTRASS_ADD2 ( Wt, 3b ), + /* [Wt] check = 3Txaxyb * z (mod 2N) + * = 3*(x^3 + a*x + b - y^2) * z (mod 2N) + */ + WEIERSTRASS_MUL2 ( Wt, z1 ), /* Stop */ WEIERSTRASS_STOP }; @@ -728,6 +736,7 @@ static int weierstrass_verify_raw ( const struct weierstrass_curve *curve, regs[WEIERSTRASS_3b] = ( ( void * ) b3 ); regs[WEIERSTRASS_x1] = ( ( void * ) &point->x ); regs[WEIERSTRASS_y1] = ( ( void * ) &point->y ); + regs[WEIERSTRASS_z1] = ( ( void * ) &point->z ); regs[WEIERSTRASS_Wt] = &temp.Wt; regs[WEIERSTRASS_Wp] = &temp.Wp; @@ -748,7 +757,7 @@ static int weierstrass_verify_raw ( const struct weierstrass_curve *curve, } /** - * Verify point is on curve + * Verify freshly initialised point is on curve * * @v curve Weierstrass curve * @v point Point (x,y,z) to be verified @@ -787,6 +796,7 @@ static int weierstrass_init_raw ( struct weierstrass_curve *curve, weierstrass_t ( size ) point; } __attribute__ (( may_alias )) *temp = ( ( void * ) temp0 ); size_t offset; + int is_infinite; unsigned int i; int rc; @@ -810,7 +820,9 @@ static int weierstrass_init_raw ( struct weierstrass_curve *curve, bigint_montgomery_relaxed ( prime, &temp->product, &point->axis[i] ); } - bigint_copy ( one, &point->z ); + memset ( &point->z, 0, sizeof ( point->z ) ); + is_infinite = bigint_is_zero ( &point->xy ); + bigint_copy ( one, &point->axis[ is_infinite ? 1 : 2 ] ); DBGC ( curve, ")\n" ); /* Verify point is on curve */ @@ -841,11 +853,10 @@ static int weierstrass_init_raw ( struct weierstrass_curve *curve, * @v point0 Element 0 of point (x,y,z) * @v temp0 Element 0 of temporary point buffer * @v out Output buffer - * @ret rc Return status code */ -static int weierstrass_done_raw ( struct weierstrass_curve *curve, - bigint_element_t *point0, - bigint_element_t *temp0, void *out ) { +static void weierstrass_done_raw ( struct weierstrass_curve *curve, + bigint_element_t *point0, + bigint_element_t *temp0, void *out ) { unsigned int size = curve->size; size_t len = curve->len; const bigint_t ( size ) __attribute__ (( may_alias )) *prime = @@ -882,12 +893,6 @@ static int weierstrass_done_raw ( struct weierstrass_curve *curve, bigint_done ( &point->axis[i], ( out + offset ), len ); } DBGC ( curve, ")\n" ); - - /* Verify result is not the point at infinity */ - if ( bigint_is_zero ( &temp->point.z ) ) - return -EINVAL; - - return 0; } /** @@ -904,6 +909,36 @@ static int weierstrass_done_raw ( struct weierstrass_curve *curve, (temp)->all.element, (out) ); \ } ) +/** + * Check if this is the point at infinity + * + * @v point Curve point + * @ret is_infinity This is the point at infinity + */ +int weierstrass_is_infinity ( struct weierstrass_curve *curve, + const void *point ) { + unsigned int size = curve->size; + size_t len = curve->len; + struct { + bigint_t ( size ) axis; + } temp; + size_t offset; + int is_finite = 0; + unsigned int i; + + /* We use all zeroes to represent the point at infinity */ + DBGC ( curve, "WEIERSTRASS %s point (", curve->name ); + for ( i = 0, offset = 0 ; i < WEIERSTRASS_AXES ; i++, offset += len ) { + bigint_init ( &temp.axis, ( point + offset ), len ); + DBGC ( curve, "%s%s", ( i ? "," : "" ), + bigint_ntoa ( &temp.axis ) ); + is_finite |= ( ! bigint_is_zero ( &temp.axis ) ); + } + DBGC ( curve, ") is%s infinity\n", ( is_finite ? " not" : "" ) ); + + return ( ! is_finite ); +} + /** * Multiply curve point by scalar * @@ -946,10 +981,7 @@ int weierstrass_multiply ( struct weierstrass_curve *curve, const void *base, weierstrass_add_ladder, curve, NULL ); /* Convert result back to affine co-ordinates */ - if ( ( rc = weierstrass_done ( curve, &temp.result, &temp.multiple, - result ) ) != 0 ) { - return rc; - } + weierstrass_done ( curve, &temp.result, &temp.multiple, result ); return 0; } @@ -963,8 +995,9 @@ int weierstrass_multiply ( struct weierstrass_curve *curve, const void *base, * @v result Curve point to hold result * @ret rc Return status code */ -int weierstrass_add_once ( struct weierstrass_curve *curve, const void *addend, - const void *augend, void *result ) { +int weierstrass_add_once ( struct weierstrass_curve *curve, + const void *addend, const void *augend, + void *result ) { unsigned int size = curve->size; struct { weierstrass_t ( size ) addend; @@ -987,10 +1020,7 @@ int weierstrass_add_once ( struct weierstrass_curve *curve, const void *addend, weierstrass_add ( curve, &temp.augend, &temp.addend, &temp.result ); /* Convert result back to affine co-ordinates */ - if ( ( rc = weierstrass_done ( curve, &temp.result, &temp.addend, - result ) ) != 0 ) { - return rc; - } + weierstrass_done ( curve, &temp.result, &temp.addend, result ); return 0; } diff --git a/src/crypto/x25519.c b/src/crypto/x25519.c index 11094ba6e..4b4c489da 100644 --- a/src/crypto/x25519.c +++ b/src/crypto/x25519.c @@ -783,17 +783,30 @@ static void x25519_reverse ( struct x25519_value *value ) { } while ( ++low < --high ); } +/** + * Check if X25519 value is zero + * + * @v value Value to check + * @ret is_zero Value is zero + */ +int x25519_is_zero ( const struct x25519_value *value ) { + x25519_t point; + + /* Check if value is zero */ + bigint_init ( &point, value->raw, sizeof ( value->raw ) ); + return bigint_is_zero ( &point ); +} + /** * Calculate X25519 key * * @v base Base point * @v scalar Scalar multiple * @v result Point to hold result (may overlap base point) - * @ret rc Return status code */ -int x25519_key ( const struct x25519_value *base, - const struct x25519_value *scalar, - struct x25519_value *result ) { +void x25519_key ( const struct x25519_value *base, + const struct x25519_value *scalar, + struct x25519_value *result ) { struct x25519_value *tmp = result; union x25519_quad257 point; @@ -814,9 +827,18 @@ int x25519_key ( const struct x25519_value *base, /* Reverse result */ bigint_done ( &point.value, result->raw, sizeof ( result->raw ) ); x25519_reverse ( result ); +} + +/** + * Check if this is the point at infinity + * + * @v point Curve point + * @ret is_infinity This is the point at infinity + */ +static int x25519_curve_is_infinity ( const void *point ) { - /* Fail if result was all zeros (as required by RFC8422) */ - return ( bigint_is_zero ( &point.value ) ? -EPERM : 0 ); + /* We use all zeroes for the point at infinity (as per RFC8422) */ + return x25519_is_zero ( point ); } /** @@ -830,7 +852,8 @@ int x25519_key ( const struct x25519_value *base, static int x25519_curve_multiply ( const void *base, const void *scalar, void *result ) { - return x25519_key ( base, scalar, result ); + x25519_key ( base, scalar, result ); + return 0; } /** @@ -854,6 +877,7 @@ struct elliptic_curve x25519_curve = { .pointsize = sizeof ( struct x25519_value ), .keysize = sizeof ( struct x25519_value ), .base = x25519_generator.raw, + .is_infinity = x25519_curve_is_infinity, .multiply = x25519_curve_multiply, .add = x25519_curve_add, }; diff --git a/src/include/ipxe/crypto.h b/src/include/ipxe/crypto.h index 93b718e15..dd567fb2c 100644 --- a/src/include/ipxe/crypto.h +++ b/src/include/ipxe/crypto.h @@ -185,6 +185,16 @@ struct elliptic_curve { const void *base; /** Order of the generator (if prime) */ const void *order; + /** Check if this is the point at infinity + * + * @v point Curve point + * @ret is_infinity This is the point at infinity + * + * The point at infinity cannot be represented in affine + * coordinates. Each curve must choose a representation of + * the point at infinity (e.g. all zeroes). + */ + int ( * is_infinity ) ( const void *point ); /** Multiply scalar by curve point * * @v base Base point @@ -307,6 +317,11 @@ pubkey_match ( struct pubkey_algorithm *pubkey, return pubkey->match ( private_key, public_key ); } +static inline __attribute__ (( always_inline )) int +elliptic_is_infinity ( struct elliptic_curve *curve, const void *point ) { + return curve->is_infinity ( point ); +} + static inline __attribute__ (( always_inline )) int elliptic_multiply ( struct elliptic_curve *curve, const void *base, const void *scalar, void *result ) { diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index 0c28810ea..e8d010475 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -443,6 +443,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_usb_settings ( ERRFILE_OTHER | 0x00650000 ) #define ERRFILE_weierstrass ( ERRFILE_OTHER | 0x00660000 ) #define ERRFILE_efi_cacert ( ERRFILE_OTHER | 0x00670000 ) +#define ERRFILE_ecdhe ( ERRFILE_OTHER | 0x00680000 ) /** @} */ diff --git a/src/include/ipxe/weierstrass.h b/src/include/ipxe/weierstrass.h index ca3c216e6..15dd9ce03 100644 --- a/src/include/ipxe/weierstrass.h +++ b/src/include/ipxe/weierstrass.h @@ -62,6 +62,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); bigint_t ( size ) y; \ bigint_t ( size ) z; \ }; \ + bigint_t ( size * 2 ) xy; \ bigint_t ( size * 3 ) all; \ } @@ -123,6 +124,8 @@ struct weierstrass_curve { }; }; +extern int weierstrass_is_infinity ( struct weierstrass_curve *curve, + const void *point ); extern int weierstrass_multiply ( struct weierstrass_curve *curve, const void *base, const void *scalar, void *result ); @@ -154,6 +157,10 @@ extern int weierstrass_add_once ( struct weierstrass_curve *curve, .a = (_name ## _cache)[6].element, \ .b3 = (_name ## _cache)[7].element, \ }; \ + static int _name ## _is_infinity ( const void *point) { \ + return weierstrass_is_infinity ( &_name ## _weierstrass,\ + point ); \ + } \ static int _name ## _multiply ( const void *base, \ const void *scalar, \ void *result ) { \ @@ -171,6 +178,7 @@ extern int weierstrass_add_once ( struct weierstrass_curve *curve, .keysize = (_len), \ .base = (_base), \ .order = (_order), \ + .is_infinity = _name ## _is_infinity, \ .multiply = _name ## _multiply, \ .add = _name ## _add, \ } diff --git a/src/include/ipxe/x25519.h b/src/include/ipxe/x25519.h index fd7caeee9..d570282c5 100644 --- a/src/include/ipxe/x25519.h +++ b/src/include/ipxe/x25519.h @@ -85,9 +85,10 @@ extern void x25519_multiply ( const union x25519_oct258 *multiplicand, extern void x25519_invert ( const union x25519_oct258 *invertend, union x25519_quad257 *result ); extern void x25519_reduce ( union x25519_quad257 *value ); -extern int x25519_key ( const struct x25519_value *base, - const struct x25519_value *scalar, - struct x25519_value *result ); +extern void x25519_key ( const struct x25519_value *base, + const struct x25519_value *scalar, + struct x25519_value *result ); +extern int x25519_is_zero ( const struct x25519_value *value ); extern struct elliptic_curve x25519_curve; diff --git a/src/tests/elliptic_test.c b/src/tests/elliptic_test.c index 5b21ee00e..614257d92 100644 --- a/src/tests/elliptic_test.c +++ b/src/tests/elliptic_test.c @@ -62,13 +62,14 @@ void elliptic_curve_okx ( struct elliptic_curve *curve, const char *file, /* Check that curve has the required properties */ okx ( curve->base != NULL, file, line ); okx ( curve->order != NULL, file, line ); + okx ( ( ! elliptic_is_infinity ( curve, curve->base ) ), file, line ); /* Test multiplying base point by group order. Result should - * be the point at infinity, which should not be representable - * as a point in affine coordinates (and so should fail). + * be the point at infinity. */ okx ( elliptic_multiply ( curve, curve->base, curve->order, - point ) != 0, file, line ); + point ) == 0, file, line ); + okx ( elliptic_is_infinity ( curve, point ), file, line ); /* Test multiplying base point by group order plus one, to get * back to the base point. diff --git a/src/tests/p256_test.c b/src/tests/p256_test.c index b7bbe47b6..2a04b69c8 100644 --- a/src/tests/p256_test.c +++ b/src/tests/p256_test.c @@ -119,8 +119,8 @@ ELLIPTIC_MULTIPLY_TEST ( poi_large, &p256_curve, BASE_GENERATOR, 0xd4, 0x31, 0xcc, 0xa9, 0x94, 0xce, 0xa1, 0x31, 0x34, 0x49, 0xbf, 0x97, 0xc8, 0x40, 0xae, 0x0a ) ); -/* Invalid curve point zero */ -ELLIPTIC_MULTIPLY_TEST ( invalid_zero, &p256_curve, +/* Point at infinity */ +ELLIPTIC_MULTIPLY_TEST ( infinity, &p256_curve, BASE ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -129,6 +129,29 @@ ELLIPTIC_MULTIPLY_TEST ( invalid_zero, &p256_curve, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + SCALAR ( 0x8d, 0x50, 0x48, 0x0c, 0xbe, 0x22, 0x4d, 0x01, + 0xbc, 0xff, 0x67, 0x8d, 0xad, 0xb1, 0x87, 0x99, + 0x47, 0xb9, 0x79, 0x02, 0xb0, 0x70, 0x47, 0xf0, + 0x9f, 0x17, 0x25, 0x7e, 0xcf, 0x0b, 0x3e, 0x73 ), + EXPECTED ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) ); + +/* Invalid curve point (zero, base_y) */ +ELLIPTIC_MULTIPLY_TEST ( invalid_zero, &p256_curve, + BASE ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, + 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0x0f, 0x9e, 0x16, + 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, + 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf4 ), SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -223,7 +246,14 @@ ELLIPTIC_ADD_TEST ( poi_1_n_1, &p256_curve, 0x71, 0x18, 0x14, 0xb5, 0x83, 0xf0, 0x61, 0xe9, 0xd4, 0x31, 0xcc, 0xa9, 0x94, 0xce, 0xa1, 0x31, 0x34, 0x49, 0xbf, 0x97, 0xc8, 0x40, 0xae, 0x0a ), - EXPECTED_FAIL ); + EXPECTED ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) ); /** * Perform P-256 self-test @@ -241,6 +271,9 @@ static void p256_test_exec ( void ) { elliptic_multiply_ok ( &poi_mid ); elliptic_multiply_ok ( &poi_large ); + /* Point at infinity */ + elliptic_multiply_ok ( &infinity ); + /* Invalid point tests */ elliptic_multiply_ok ( &invalid_zero ); elliptic_multiply_ok ( &invalid_one ); diff --git a/src/tests/p384_test.c b/src/tests/p384_test.c index c67cfbc79..b1b93faa4 100644 --- a/src/tests/p384_test.c +++ b/src/tests/p384_test.c @@ -153,8 +153,8 @@ ELLIPTIC_MULTIPLY_TEST ( poi_large, &p384_curve, BASE_GENERATOR, 0xf5, 0x9f, 0x4e, 0x30, 0xe2, 0x81, 0x7e, 0x62, 0x85, 0xbc, 0xe2, 0x84, 0x6f, 0x15, 0xf1, 0xa0 ) ); -/* Invalid curve point zero */ -ELLIPTIC_MULTIPLY_TEST ( invalid_zero, &p384_curve, +/* Point at infinity */ +ELLIPTIC_MULTIPLY_TEST ( infinity, &p384_curve, BASE ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -173,22 +173,55 @@ ELLIPTIC_MULTIPLY_TEST ( invalid_zero, &p384_curve, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), + EXPECTED ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) ); + +/* Invalid curve point (zero, base_y) */ +ELLIPTIC_MULTIPLY_TEST ( invalid_zero, &p384_curve, + BASE ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, + 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, + 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, + 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, + 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, + 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5e ), + SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 ), EXPECTED_FAIL ); /* Invalid curve point (base_x, base_y - 1) */ ELLIPTIC_MULTIPLY_TEST ( invalid_one, &p384_curve, - BASE ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, - 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, - 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, - 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, - 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, - 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, - 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, - 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, - 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, - 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, - 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, - 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5e ), + BASE ( 0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x05, 0x37, + 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, + 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, + 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, + 0x55, 0x02, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, + 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0x0a, 0xb7, + 0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, + 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, + 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, + 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, + 0x0a, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, + 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0x0e, 0x5e ), SCALAR ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -301,7 +334,18 @@ ELLIPTIC_ADD_TEST ( poi_1_n_1, &p384_curve, 0x16, 0x25, 0xce, 0xec, 0x4a, 0x0f, 0x47, 0x3e, 0xf5, 0x9f, 0x4e, 0x30, 0xe2, 0x81, 0x7e, 0x62, 0x85, 0xbc, 0xe2, 0x84, 0x6f, 0x15, 0xf1, 0xa0 ), - EXPECTED_FAIL ); + EXPECTED ( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ) ); /** * Perform P-384 self-test @@ -319,6 +363,9 @@ static void p384_test_exec ( void ) { elliptic_multiply_ok ( &poi_mid ); elliptic_multiply_ok ( &poi_large ); + /* Point at infinity */ + elliptic_multiply_ok ( &infinity ); + /* Invalid point tests */ elliptic_multiply_ok ( &invalid_zero ); elliptic_multiply_ok ( &invalid_one ); diff --git a/src/tests/x25519_test.c b/src/tests/x25519_test.c index 3dfbd3393..bd348b832 100644 --- a/src/tests/x25519_test.c +++ b/src/tests/x25519_test.c @@ -263,7 +263,6 @@ static void x25519_key_okx ( struct x25519_key_test *test, struct x25519_value scalar; struct x25519_value actual; unsigned int i; - int rc; /* Construct input values */ memcpy ( &base, &test->base, sizeof ( test->base ) ); @@ -277,11 +276,11 @@ static void x25519_key_okx ( struct x25519_key_test *test, /* Calculate key */ for ( i = 0 ; i < test->count ; i++ ) { - rc = x25519_key ( &base, &scalar, &actual ); + x25519_key ( &base, &scalar, &actual ); if ( test->fail ) { - okx ( rc != 0, file, line ); + okx ( x25519_is_zero ( &actual ), file, line ); } else { - okx ( rc == 0, file, line ); + okx ( ( ! x25519_is_zero ( &actual ) ), file, line ); } memcpy ( &base, &scalar, sizeof ( base ) ); memcpy ( &scalar, &actual, sizeof ( scalar ) ); -- cgit v1.2.3-55-g7522 From 948677fe5e2a3d098b8099a0dff0bfbd22efc3a8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 18 Dec 2025 23:10:57 +0000 Subject: [test] Test verification of constructed signature Some signature schemes (such as ECDSA) allow for non-deterministic signatures. Provide more information in test results by performing verification of the constructed signature even when it does not match the expected test case result: this allows us to distinguish between a bug that is generating invalid signatures and a bug that is generating valid but non-canonical signatures. Signed-off-by: Michael Brown --- src/tests/pubkey_test.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/tests') diff --git a/src/tests/pubkey_test.c b/src/tests/pubkey_test.c index 15b24f005..b94ed90ff 100644 --- a/src/tests/pubkey_test.c +++ b/src/tests/pubkey_test.c @@ -146,6 +146,10 @@ void pubkey_sign_okx ( struct pubkey_sign_test *test, const char *file, okx ( asn1_compare ( asn1_built ( &builder ), &test->signature ) == 0, file, line ); + /* Test verification of constructed signature */ + okx ( pubkey_verify ( pubkey, &test->public, digest, digestout, + asn1_built ( &builder ) ) == 0, file, line ); + /* Free signature */ free ( builder.data ); } -- cgit v1.2.3-55-g7522 From 4e3cbeef83363425ddb9cc0d9691c8c1115a6929 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Thu, 18 Dec 2025 23:33:24 +0000 Subject: [crypto] Add support for ECDSA signatures Signed-off-by: Michael Brown --- src/crypto/ecdsa.c | 928 +++++++++++++++++++++++++++++++++++++++++++++ src/include/ipxe/ecdsa.h | 19 + src/include/ipxe/errfile.h | 1 + src/tests/ecdsa_test.c | 274 +++++++++++++ src/tests/tests.c | 1 + 5 files changed, 1223 insertions(+) create mode 100644 src/crypto/ecdsa.c create mode 100644 src/include/ipxe/ecdsa.h create mode 100644 src/tests/ecdsa_test.c (limited to 'src/tests') diff --git a/src/crypto/ecdsa.c b/src/crypto/ecdsa.c new file mode 100644 index 000000000..1e0571c7f --- /dev/null +++ b/src/crypto/ecdsa.c @@ -0,0 +1,928 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 + * + * Elliptic curve digital signature algorithm (ECDSA) + * + * The elliptic curve public key format is documented in RFC 5480. + * The original private key format is documented in RFC 5915, and the + * generic container PKCS#8 format documented in RFC 5208. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Disambiguate the various error causes */ +#define EINVAL_POINTSIZE \ + __einfo_error ( EINFO_EINVAL_POINTSIZE ) +#define EINFO_EINVAL_POINTSIZE \ + __einfo_uniqify ( EINFO_EINVAL, 0x01, "Invalid point size" ) +#define EINVAL_KEYSIZE \ + __einfo_error ( EINFO_EINVAL_KEYSIZE ) +#define EINFO_EINVAL_KEYSIZE \ + __einfo_uniqify ( EINFO_EINVAL, 0x02, "Invalid key size" ) +#define EINVAL_COMPRESSION \ + __einfo_error ( EINFO_EINVAL_COMPRESSION ) +#define EINFO_EINVAL_COMPRESSION \ + __einfo_uniqify ( EINFO_EINVAL, 0x03, "Invalid compression") +#define EINVAL_INFINITY \ + __einfo_error ( EINFO_EINVAL_INFINITY ) +#define EINFO_EINVAL_INFINITY \ + __einfo_uniqify ( EINFO_EINVAL, 0x04, "Point is infinity" ) +#define EINVAL_SIGNATURE \ + __einfo_error ( EINFO_EINVAL_SIGNATURE ) +#define EINFO_EINVAL_SIGNATURE \ + __einfo_uniqify ( EINFO_EINVAL, 0x05, "Invalid signature" ) + +/** An ECDSA key */ +struct ecdsa_key { + /** Elliptic curve */ + struct elliptic_curve *curve; + /** Public curve point */ + const void *public; + /** Private multiple of base curve point (if applicable) */ + const void *private; +}; + +/** ECDSA context */ +struct ecdsa_context { + /** Key */ + struct ecdsa_key key; + /** Big integer size */ + unsigned int size; + /** Digest algorithm */ + struct digest_algorithm *digest; + /** Digest length */ + size_t zlen; + + /** Dynamically allocated storage */ + void *dynamic; + /** Element 0 of modulus N (i.e. curve group order */ + bigint_element_t *modulus0; + /** Element 0 of constant N-2 (for Fermat's little theorem) */ + bigint_element_t *fermat0; + /** Element 0 of Montgomery constant R^2 mod N */ + bigint_element_t *square0; + /** Element 0 of constant 1 (in Montgomery form) */ + bigint_element_t *one0; + /** Element 0 of digest value "z" */ + bigint_element_t *z0; + /** Element 0 of random key "k" */ + bigint_element_t *k0; + /** Element 0 of signature value "r" */ + bigint_element_t *r0; + /** Element 0 of signature value "s" */ + bigint_element_t *s0; + /** Element 0 of temporary value */ + bigint_element_t *temp0; + /** Element 0 of product buffer */ + bigint_element_t *product0; + /** Curve point 1 */ + void *point1; + /** Curve point 2 */ + void *point2; + /** Scalar value */ + void *scalar; + /** HMAC_DRBG state for random value generation */ + struct hmac_drbg_state *drbg; +}; + +/** + * Parse ECDSA key + * + * @v key ECDSA key + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int ecdsa_parse_key ( struct ecdsa_key *key, + const struct asn1_cursor *raw ) { + struct asn1_algorithm *algorithm; + struct asn1_cursor cursor; + struct asn1_cursor curve; + struct asn1_cursor private; + const uint8_t *compression; + int is_private; + int rc; + + /* Enter subjectPublicKeyInfo/ECPrivateKey */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + asn1_invalidate_cursor ( &curve ); + asn1_invalidate_cursor ( &private ); + + /* Determine key format */ + if ( asn1_type ( &cursor ) == ASN1_INTEGER ) { + + /* Private key */ + is_private = 1; + + /* Skip version */ + asn1_skip_any ( &cursor ); + + /* Parse privateKeyAlgorithm, if present */ + if ( asn1_type ( &cursor ) == ASN1_SEQUENCE ) { + + /* PKCS#8 format */ + DBGC ( key, "ECDSA %p is in PKCS#8 format\n", key ); + + /* Parse privateKeyAlgorithm */ + memcpy ( &curve, &cursor, sizeof ( curve ) ); + asn1_skip_any ( &cursor ); + + /* Enter privateKey */ + asn1_enter ( &cursor, ASN1_OCTET_STRING ); + + /* Enter ECPrivateKey */ + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Skip version */ + asn1_skip ( &cursor, ASN1_INTEGER ); + } + + /* Parse privateKey */ + memcpy ( &private, &cursor, sizeof ( private ) ); + asn1_enter ( &private, ASN1_OCTET_STRING ); + asn1_skip_any ( &cursor ); + + /* Parse parameters, if present */ + if ( asn1_type ( &cursor ) == ASN1_EXPLICIT_TAG ( 0 ) ) { + memcpy ( &curve, &cursor, sizeof ( curve ) ); + asn1_enter_any ( &curve ); + asn1_skip_any ( &cursor ); + } + + /* Enter publicKey */ + asn1_enter ( &cursor, ASN1_EXPLICIT_TAG ( 1 ) ); + + } else { + + /* Public key */ + is_private = 0; + + /* Parse algorithm */ + memcpy ( &curve, &cursor, sizeof ( curve ) ); + asn1_skip_any ( &cursor ); + } + + /* Enter publicKey */ + asn1_enter_bits ( &cursor, NULL ); + + /* Identify curve */ + if ( ( rc = asn1_curve_algorithm ( &curve, &algorithm ) ) != 0 ) { + DBGC ( key, "ECDSA %p unknown curve: %s\n", + key, strerror ( rc ) ); + DBGC_HDA ( key, 0, raw->data, raw->len ); + return rc; + } + key->curve = algorithm->curve; + DBGC ( key, "ECDSA %p is a %s (%s) %s key\n", key, algorithm->name, + key->curve->name, ( is_private ? "private" : "public" ) ); + + /* Check public key length */ + if ( cursor.len != ( sizeof ( *compression ) + + key->curve->pointsize ) ) { + DBGC ( key, "ECDSA %p invalid public key length %zd\n", + key, cursor.len ); + DBGC_HDA ( key, 0, raw->data, raw->len ); + return -EINVAL_POINTSIZE; + } + + /* Check that key is uncompressed */ + compression = cursor.data; + if ( *compression != ECDSA_UNCOMPRESSED ) { + DBGC ( key, "ECDSA %p invalid compression %#02x\n", + key, *compression ); + DBGC_HDA ( key, 0, raw->data, raw->len ); + return -EINVAL_COMPRESSION; + } + + /* Extract public curve point */ + key->public = ( cursor.data + sizeof ( *compression ) ); + DBGC ( key, "ECDSA %p public curve point:\n", key ); + DBGC_HDA ( key, 0, key->public, key->curve->pointsize ); + + /* Check that public key is not the point at infinity */ + if ( elliptic_is_infinity ( key->curve, key->public ) ) { + DBGC ( key, "ECDSA %p public curve point is infinity\n", key ); + return -EINVAL_INFINITY; + } + + /* Extract private key, if applicable */ + if ( is_private ) { + + /* Check private key length */ + if ( private.len != key->curve->keysize ) { + DBGC ( key, "ECDSA %p invalid private key length " + "%zd\n", key, private.len ); + DBGC_HDA ( key, 0, raw->data, raw->len ); + return -EINVAL_KEYSIZE; + } + + /* Extract private key */ + key->private = private.data; + DBGC ( key, "ECDSA %p private multiplier:\n", key ); + DBGC_HDA ( key, 0, key->private, key->curve->keysize ); + + } else { + + /* No private key */ + key->private = NULL; + } + + return 0; +} + +/** + * Parse ECDSA signature value + * + * @v ctx ECDSA context + * @v rs0 Element 0 of signature "r" or "s" value + * @v raw ASN.1 cursor + * @ret rc Return status code + */ +static int ecdsa_parse_signature ( struct ecdsa_context *ctx, + bigint_element_t *rs0, + const struct asn1_cursor *raw ) { + size_t keysize = ctx->key.curve->keysize; + unsigned int size = ctx->size; + bigint_t ( size ) __attribute__ (( may_alias )) *modulus = + ( ( void * ) ctx->modulus0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *rs = + ( ( void * ) rs0 ); + struct asn1_cursor cursor; + int rc; + + /* Enter integer */ + memcpy ( &cursor, raw, sizeof ( cursor ) ); + if ( ( rc = asn1_enter_unsigned ( &cursor ) ) != 0 ) { + DBGC ( ctx, "ECDSA %p invalid integer:\n", ctx ); + DBGC_HDA ( ctx, 0, raw->data, raw->len ); + return rc; + } + + /* Extract value */ + if ( cursor.len > keysize ) { + DBGC ( ctx, "ECDSA %p invalid signature value:\n", ctx ); + DBGC_HDA ( ctx, 0, raw->data, raw->len ); + return -EINVAL_KEYSIZE; + } + bigint_init ( rs, cursor.data, cursor.len ); + + /* Check that value is within the required range */ + if ( bigint_is_zero ( rs ) || bigint_is_geq ( rs, modulus ) ) { + DBGC ( ctx, "ECDSA %p out-of-range signature value:\n", ctx ); + DBGC_HDA ( ctx, 0, raw->data, raw->len ); + return -ERANGE; + } + + return 0; +} + +/** + * Prepend ECDSA signature value + * + * @v ctx ECDSA context + * @v rs0 Element 0 of signature "r" or "s" value + * @v builder ASN.1 builder + * @ret rc Return status code + */ +static int ecdsa_prepend_signature ( struct ecdsa_context *ctx, + bigint_element_t *rs0, + struct asn1_builder *builder ) { + size_t keysize = ctx->key.curve->keysize; + unsigned int size = ctx->size; + bigint_t ( size ) __attribute__ (( may_alias )) *rs = + ( ( void * ) rs0 ); + uint8_t buf[ 1 /* potential sign byte */ + keysize ]; + uint8_t *data; + size_t len; + int rc; + + /* Construct value */ + buf[0] = 0; + bigint_done ( rs, &buf[1], keysize ); + + /* Strip leading zeros */ + data = buf; + len = sizeof ( buf ); + while ( ( len > 1 ) && ( data[0] == 0 ) && ( data[1] < 0x80 ) ) { + data++; + len--; + } + + /* Prepend integer */ + if ( ( rc = asn1_prepend ( builder, ASN1_INTEGER, data, len ) ) != 0 ) + return rc; + + return 0; +} + +/** + * Allocate ECDSA context dynamic storage + * + * @v ctx ECDSA context + * @ret rc Return status code + */ +static int ecdsa_alloc ( struct ecdsa_context *ctx ) { + struct elliptic_curve *curve = ctx->key.curve; + size_t pointsize = curve->pointsize; + size_t keysize = curve->keysize; + unsigned int size = + bigint_required_size ( keysize + 1 /* for addition */ ); + struct { + bigint_t ( size ) modulus; + bigint_t ( size ) fermat; + bigint_t ( size ) square; + bigint_t ( size ) one; + bigint_t ( size ) z; + bigint_t ( size ) k; + bigint_t ( size ) r; + bigint_t ( size ) s; + bigint_t ( size ) temp; + bigint_t ( size * 2 ) product; + uint8_t point1[pointsize]; + uint8_t point2[pointsize]; + uint8_t scalar[keysize]; + struct hmac_drbg_state drbg; + } *dynamic; + + /* Allocate dynamic storage */ + dynamic = malloc ( sizeof ( *dynamic ) ); + if ( ! dynamic ) + return -ENOMEM; + + /* Populate context */ + ctx->size = size; + ctx->dynamic = dynamic; + ctx->modulus0 = dynamic->modulus.element; + ctx->fermat0 = dynamic->fermat.element; + ctx->square0 = dynamic->square.element; + ctx->one0 = dynamic->one.element; + ctx->z0 = dynamic->z.element; + ctx->k0 = dynamic->k.element; + ctx->r0 = dynamic->r.element; + ctx->s0 = dynamic->s.element; + ctx->temp0 = dynamic->temp.element; + ctx->product0 = dynamic->product.element; + ctx->point1 = dynamic->point1; + ctx->point2 = dynamic->point2; + ctx->scalar = dynamic->scalar; + ctx->drbg = &dynamic->drbg; + + return 0; +} + +/** + * Free ECDSA context dynamic storage + * + * @v ctx ECDSA context + */ +static void ecdsa_free ( struct ecdsa_context *ctx ) { + + /* Free dynamic storage */ + free ( ctx->dynamic ); +} + +/** + * Initialise ECDSA values + * + * @v ctx ECDSA context + * @v digest Digest algorithm + * @v value Digest value + */ +static void ecdsa_init_values ( struct ecdsa_context *ctx, + struct digest_algorithm *digest, + const void *value ) { + struct elliptic_curve *curve = ctx->key.curve; + unsigned int size = ctx->size; + bigint_t ( size ) __attribute__ (( may_alias )) *modulus = + ( ( void * ) ctx->modulus0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *fermat = + ( ( void * ) ctx->fermat0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *square = + ( ( void * ) ctx->square0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *one = + ( ( void * ) ctx->one0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *z = + ( ( void * ) ctx->z0 ); + bigint_t ( size * 2 ) __attribute__ (( may_alias )) *product = + ( ( void * ) ctx->product0 ); + static const uint8_t two_raw[] = { 2 }; + size_t zlen; + + /* Initialise modulus N */ + bigint_init ( modulus, curve->order, curve->keysize ); + DBGC2 ( ctx, "ECDSA %p N = %s\n", ctx, bigint_ntoa ( modulus ) ); + + /* Calculate N-2 (using Montgomery constant as temporary buffer) */ + bigint_copy ( modulus, fermat ); + bigint_init ( square, two_raw, sizeof ( two_raw ) ); + bigint_subtract ( square, fermat ); + + /* Calculate Montgomery constant */ + bigint_reduce ( modulus, square ); + DBGC2 ( ctx, "ECDSA %p R^2 = %s mod N\n", + ctx, bigint_ntoa ( square ) ); + + /* Construct one in Montgomery form */ + bigint_grow ( square, product ); + bigint_montgomery ( modulus, product, one ); + DBGC2 ( ctx, "ECDSA %p R = %s mod N\n", + ctx, bigint_ntoa ( one ) ); + + /* Initialise digest */ + ctx->digest = digest; + zlen = ctx->key.curve->keysize; + if ( zlen > digest->digestsize ) + zlen = digest->digestsize; + ctx->zlen = zlen; + bigint_init ( z, value, zlen ); + DBGC2 ( ctx, "ECDSA %p z = %s (%s)\n", + ctx, bigint_ntoa ( z ), digest->name ); +} + +/** + * Initialise ECDSA context + * + * @v ctx ECDSA context + * @v key Key + * @v digest Digest algorithm + * @v value Digest value + * @ret rc Return status code + */ +static int ecdsa_init ( struct ecdsa_context *ctx, + const struct asn1_cursor *key, + struct digest_algorithm *digest, + const void *value ) { + int rc; + + /* Parse key */ + if ( ( rc = ecdsa_parse_key ( &ctx->key, key ) ) != 0 ) + goto err_parse; + + /* Allocate dynamic storage */ + if ( ( rc = ecdsa_alloc ( ctx ) ) != 0 ) + goto err_alloc; + + /* Initialise values */ + ecdsa_init_values ( ctx, digest, value ); + + return 0; + + ecdsa_free ( ctx ); + err_alloc: + err_parse: + return rc; +} + +/** + * Invert ECDSA value + * + * @v ctx ECDSA context + * @v val0 Element 0 of value to invert + */ +static void ecdsa_invert ( struct ecdsa_context *ctx, + bigint_element_t *val0 ) { + unsigned int size = ctx->size; + bigint_t ( size ) __attribute__ (( may_alias )) *modulus = + ( ( void * ) ctx->modulus0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *fermat = + ( ( void * ) ctx->fermat0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *square = + ( ( void * ) ctx->square0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *one = + ( ( void * ) ctx->one0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *temp = + ( ( void * ) ctx->temp0 ); + bigint_t ( size * 2 ) __attribute__ (( may_alias )) *product = + ( ( void * ) ctx->product0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *val = + ( ( void * ) val0 ); + + /* Convert value to Montgomery form */ + bigint_multiply ( val, square, product ); + bigint_montgomery ( modulus, product, temp ); + + /* Invert value via Fermat's little theorem */ + bigint_copy ( one, val ); + bigint_ladder ( val, temp, fermat, bigint_mod_exp_ladder, modulus, + product ); +} + +/** + * Generate ECDSA "r" and "s" values + * + * @v ctx ECDSA context + * @v sig Signature + * @ret rc Return status code + */ +static int ecdsa_sign_rs ( struct ecdsa_context *ctx ) { + struct digest_algorithm *digest = ctx->digest; + struct elliptic_curve *curve = ctx->key.curve; + size_t pointsize = curve->pointsize; + size_t keysize = curve->keysize; + unsigned int size = ctx->size; + bigint_t ( size ) __attribute__ (( may_alias )) *modulus = + ( ( void * ) ctx->modulus0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *square = + ( ( void * ) ctx->square0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *one = + ( ( void * ) ctx->one0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *z = + ( ( void * ) ctx->z0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *k = + ( ( void * ) ctx->k0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *r = + ( ( void * ) ctx->r0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *s = + ( ( void * ) ctx->s0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *temp = + ( ( void * ) ctx->temp0 ); + bigint_t ( size * 2 ) __attribute__ (( may_alias )) *product = + ( ( void * ) ctx->product0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *x1 = + ( ( void * ) temp ); + void *point1 = ctx->point1; + void *scalar = ctx->scalar; + int rc; + + /* Loop until a suitable signature is generated */ + while ( 1 ) { + + /* Generate pseudo-random data */ + if ( ( rc = hmac_drbg_generate ( digest, ctx->drbg, NULL, 0, + scalar, keysize ) ) != 0 ) { + DBGC ( ctx, "ECDSA %p could not generate: %s\n", + ctx, strerror ( rc ) ); + return rc; + } + + /* Check suitability of pseudo-random data */ + bigint_init ( k, scalar, keysize ); + DBGC2 ( ctx, "ECDSA %p k = %s\n", + ctx, bigint_ntoa ( k ) ); + if ( bigint_is_zero ( k ) ) + continue; + if ( bigint_is_geq ( k, modulus ) ) + continue; + + /* Calculate (x1,y1) = k*G */ + elliptic_multiply ( curve, curve->base, scalar, point1 ); + bigint_init ( x1, point1, ( pointsize / 2 ) ); + DBGC2 ( ctx, "ECDSA %p x1 = %s mod N\n", + ctx, bigint_ntoa ( x1 ) ); + + /* Calculate r = x1 mod N */ + bigint_multiply ( x1, one, product ); + bigint_montgomery ( modulus, product, r ); + DBGC2 ( ctx, "ECDSA %p r = %s\n", + ctx, bigint_ntoa ( r ) ); + + /* Check suitability of r */ + if ( bigint_is_zero ( r ) ) + continue; + + /* Calculate k^-1 mod N (in Montgomery form) */ + ecdsa_invert ( ctx, k->element ); + DBGC2 ( ctx, "ECDSA %p (k^-1)R = %s mod N\n", + ctx, bigint_ntoa ( k ) ); + + /* Calculate r * dA */ + bigint_init ( temp, ctx->key.private, keysize ); + DBGC2 ( ctx, "ECDSA %p dA = %s\n", + ctx, bigint_ntoa ( temp ) ); + bigint_multiply ( r, temp, product ); + bigint_montgomery ( modulus, product, temp ); + bigint_multiply ( temp, square, product ); + bigint_montgomery ( modulus, product, temp ); + DBGC2 ( ctx, "ECDSA %p r*dA = %s mod N\n", + ctx, bigint_ntoa ( temp ) ); + + /* Calculate k^-1 * (z + r*dA) */ + bigint_add ( z, temp ); + DBGC2 ( ctx, "ECDSA %p z+r*dA = %s mod N\n", + ctx, bigint_ntoa ( temp ) ); + bigint_multiply ( k, temp, product ); + bigint_montgomery ( modulus, product, s ); + DBGC2 ( ctx, "ECDSA %p s = %s\n", + ctx, bigint_ntoa ( s ) ); + + /* Check suitability of s */ + if ( bigint_is_zero ( s ) ) + continue; + + return 0; + } +} + +/** + * Verify ECDSA "r" and "s" values + * + * @v ctx ECDSA context + * @v sig Signature + * @ret rc Return status code + */ +static int ecdsa_verify_rs ( struct ecdsa_context *ctx ) { + struct elliptic_curve *curve = ctx->key.curve; + size_t pointsize = curve->pointsize; + size_t keysize = curve->keysize; + const void *public = ctx->key.public; + unsigned int size = ctx->size; + bigint_t ( size ) __attribute__ (( may_alias )) *modulus = + ( ( void * ) ctx->modulus0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *one = + ( ( void * ) ctx->one0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *z = + ( ( void * ) ctx->z0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *r = + ( ( void * ) ctx->r0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *s = + ( ( void * ) ctx->s0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *temp = + ( ( void * ) ctx->temp0 ); + bigint_t ( size * 2 ) __attribute__ (( may_alias )) *product = + ( ( void * ) ctx->product0 ); + bigint_t ( size ) __attribute__ (( may_alias )) *u1 = + ( ( void * ) temp ); + bigint_t ( size ) __attribute__ (( may_alias )) *u2 = + ( ( void * ) temp ); + bigint_t ( size ) __attribute__ (( may_alias )) *x1 = + ( ( void * ) temp ); + void *point1 = ctx->point1; + void *point2 = ctx->point2; + void *scalar = ctx->scalar; + int valid; + int rc; + + DBGC2 ( ctx, "ECDSA %p r = %s\n", ctx, bigint_ntoa ( r ) ); + DBGC2 ( ctx, "ECDSA %p s = %s\n", ctx, bigint_ntoa ( s ) ); + + /* Calculate s^-1 mod N (in Montgomery form) */ + ecdsa_invert ( ctx, s->element ); + DBGC2 ( ctx, "ECDSA %p (s^-1)R = %s mod N\n", ctx, bigint_ntoa ( s ) ); + + /* Calculate u1 = (z * s^-1) mod N */ + bigint_multiply ( z, s, product ); + bigint_montgomery ( modulus, product, u1 ); + DBGC2 ( ctx, "ECDSA %p u1 = %s mod N\n", + ctx, bigint_ntoa ( u1 ) ); + bigint_done ( u1, scalar, keysize ); + + /* Calculate u1 * G */ + if ( ( rc = elliptic_multiply ( curve, curve->base, scalar, + point1 ) ) != 0 ) { + DBGC ( ctx, "ECDSA %p could not calculate u1*G: %s\n", + ctx, strerror ( rc ) ); + return rc; + } + + /* Calculate u2 = (r * s^-1) mod N */ + bigint_multiply ( r, s, product ); + bigint_montgomery ( modulus, product, u2 ); + bigint_done ( u2, scalar, keysize ); + DBGC2 ( ctx, "ECDSA %p u2 = %s mod N\n", + ctx, bigint_ntoa ( u2 ) ); + + /* Calculate u2 * Qa */ + if ( ( rc = elliptic_multiply ( curve, public, scalar, + point2 ) ) != 0 ) { + DBGC ( ctx, "ECDSA %p could not calculate u2*Qa: %s\n", + ctx, strerror ( rc ) ); + return rc; + } + + /* Calculate u1 * G + u2 * Qa */ + if ( ( rc = elliptic_add ( curve, point1, point2, point1 ) ) != 0 ) { + DBGC ( ctx, "ECDSA %p could not calculate u1*G+u2*Qa: %s\n", + ctx, strerror ( rc ) ); + return rc; + } + + /* Check that result is not the point at infinity */ + if ( elliptic_is_infinity ( curve, point1 ) ) { + DBGC ( ctx, "ECDSA %p result is point at infinity\n", ctx ); + return -EINVAL; + } + + /* Calculate x1 mod N */ + bigint_init ( x1, point1, ( pointsize / 2 ) ); + DBGC2 ( ctx, "ECDSA %p x1 = %s mod N\n", ctx, bigint_ntoa ( x1 ) ); + bigint_multiply ( x1, one, product ); + bigint_montgomery ( modulus, product, x1 ); + DBGC2 ( ctx, "ECDSA %p x1 = %s\n", ctx, bigint_ntoa ( x1 ) ); + + /* Check signature */ + bigint_subtract ( x1, r ); + valid = bigint_is_zero ( r ); + DBGC2 ( ctx, "ECDSA %p signature is%s valid\n", + ctx, ( valid ? "" : " not" ) ); + + return ( valid ? 0 : -EINVAL_SIGNATURE ); +} + +/** + * Encrypt using ECDSA + * + * @v key Key + * @v plaintext Plaintext + * @v ciphertext Ciphertext + * @ret rc Return status code + */ +static int ecdsa_encrypt ( const struct asn1_cursor *key __unused, + const struct asn1_cursor *plaintext __unused, + struct asn1_builder *ciphertext __unused ) { + + /* Not a defined operation for ECDSA */ + return -ENOTTY; +} + +/** + * Decrypt using ECDSA + * + * @v key Key + * @v ciphertext Ciphertext + * @v plaintext Plaintext + * @ret rc Return status code + */ +static int ecdsa_decrypt ( const struct asn1_cursor *key __unused, + const struct asn1_cursor *ciphertext __unused, + struct asn1_builder *plaintext __unused ) { + + /* Not a defined operation for ECDSA */ + return -ENOTTY; +} + +/** + * Sign digest value using ECDSA + * + * @v key Key + * @v digest Digest algorithm + * @v value Digest value + * @v signature Signature + * @ret rc Return status code + */ +static int ecdsa_sign ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, + struct asn1_builder *signature ) { + struct ecdsa_context ctx; + int rc; + + /* Initialise context */ + if ( ( rc = ecdsa_init ( &ctx, key, digest, value ) ) != 0 ) + goto err_init; + + /* Fail unless we have a private key */ + if ( ! ctx.key.private ) { + rc = -ENOTTY; + goto err_no_key; + } + + /* Instantiate DRBG */ + hmac_drbg_instantiate ( digest, ctx.drbg, ctx.key.private, + ctx.key.curve->keysize, value, ctx.zlen ); + + /* Create signature */ + if ( ( rc = ecdsa_sign_rs ( &ctx ) ) != 0 ) + goto err_signature; + + /* Construct "r" and "s" values */ + if ( ( rc = ecdsa_prepend_signature ( &ctx, ctx.s0, signature ) ) != 0) + goto err_s; + if ( ( rc = ecdsa_prepend_signature ( &ctx, ctx.r0, signature ) ) != 0) + goto err_r; + if ( ( rc = asn1_wrap ( signature, ASN1_SEQUENCE ) ) != 0 ) + goto err_wrap; + + /* Free context */ + ecdsa_free ( &ctx ); + + return 0; + + err_wrap: + err_r: + err_s: + err_signature: + err_no_key: + ecdsa_free ( &ctx ); + err_init: + return rc; +} + +/** + * Verify signed digest using ECDSA + * + * @v key Key + * @v digest Digest algorithm + * @v value Digest value + * @v signature Signature + * @ret rc Return status code + */ +static int ecdsa_verify ( const struct asn1_cursor *key, + struct digest_algorithm *digest, const void *value, + const struct asn1_cursor *signature ) { + struct ecdsa_context ctx; + struct asn1_cursor cursor; + int rc; + + /* Initialise context */ + if ( ( rc = ecdsa_init ( &ctx, key, digest, value ) ) != 0 ) + goto err_init; + + /* Enter sequence */ + memcpy ( &cursor, signature, sizeof ( cursor ) ); + asn1_enter ( &cursor, ASN1_SEQUENCE ); + + /* Extract "r" and "s" values */ + if ( ( rc = ecdsa_parse_signature ( &ctx, ctx.r0, &cursor ) ) != 0 ) + goto err_r; + asn1_skip_any ( &cursor ); + if ( ( rc = ecdsa_parse_signature ( &ctx, ctx.s0, &cursor ) ) != 0 ) + goto err_s; + + /* Verify signature */ + if ( ( rc = ecdsa_verify_rs ( &ctx ) ) != 0 ) + goto err_verify; + + /* Free context */ + ecdsa_free ( &ctx ); + + return 0; + + err_verify: + err_s: + err_r: + ecdsa_free ( &ctx ); + err_init: + return rc; +} + +/** + * Check for matching ECDSA public/private key pair + * + * @v private_key Private key + * @v public_key Public key + * @ret rc Return status code + */ +static int ecdsa_match ( const struct asn1_cursor *private_key, + const struct asn1_cursor *public_key ) { + struct elliptic_curve *curve; + struct ecdsa_key privkey; + struct ecdsa_key pubkey; + int rc; + + /* Parse keys */ + if ( ( rc = ecdsa_parse_key ( &privkey, private_key ) ) != 0 ) + return rc; + if ( ( rc = ecdsa_parse_key ( &pubkey, public_key ) ) != 0 ) + return rc; + + /* Compare curves */ + if ( privkey.curve != pubkey.curve ) + return -ENOTTY; + curve = privkey.curve; + + /* Compare public curve points */ + if ( memcmp ( privkey.public, pubkey.public, curve->pointsize ) != 0 ) + return -ENOTTY; + + return 0; +} + +/** ECDSA public-key algorithm */ +struct pubkey_algorithm ecdsa_algorithm = { + .name = "ecdsa", + .encrypt = ecdsa_encrypt, + .decrypt = ecdsa_decrypt, + .sign = ecdsa_sign, + .verify = ecdsa_verify, + .match = ecdsa_match, +}; diff --git a/src/include/ipxe/ecdsa.h b/src/include/ipxe/ecdsa.h new file mode 100644 index 000000000..f55af3973 --- /dev/null +++ b/src/include/ipxe/ecdsa.h @@ -0,0 +1,19 @@ +#ifndef _IPXE_ECDSA_H +#define _IPXE_ECDSA_H + +/** @file + * + * Elliptic curve digital signature algorithm (ECDSA) + * + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +#include + +/** Uncompressed curve point */ +#define ECDSA_UNCOMPRESSED 0x04 + +extern struct pubkey_algorithm ecdsa_algorithm; + +#endif /* _IPXE_ECDSA_H */ diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index e8d010475..d97c5eca6 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -444,6 +444,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_weierstrass ( ERRFILE_OTHER | 0x00660000 ) #define ERRFILE_efi_cacert ( ERRFILE_OTHER | 0x00670000 ) #define ERRFILE_ecdhe ( ERRFILE_OTHER | 0x00680000 ) +#define ERRFILE_ecdsa ( ERRFILE_OTHER | 0x00690000 ) /** @} */ diff --git a/src/tests/ecdsa_test.c b/src/tests/ecdsa_test.c new file mode 100644 index 000000000..0ea039b1f --- /dev/null +++ b/src/tests/ecdsa_test.c @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2025 Michael Brown . + * + * 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 + * + * ECDSA self-tests + * + * These test vectors are generated using openssl's ecparam, pkey, + * pkcs8, and dgst tools. + */ + +/* Forcibly enable assertions */ +#undef NDEBUG + +#include +#include +#include +#include +#include +#include +#include "pubkey_test.h" + +/** "Hello world" P-256 signature test (traditional private key) */ +PUBKEY_SIGN_TEST ( p256_hw_test, &ecdsa_algorithm, + PRIVATE ( 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x5d, 0xc9, 0xbc, + 0x58, 0x82, 0x99, 0xaf, 0x56, 0x6a, 0x4a, 0x4d, 0xec, 0xce, + 0x9f, 0x6d, 0xfd, 0xb4, 0xfa, 0x5f, 0x8c, 0xd2, 0xfe, 0x5a, + 0x4b, 0x9b, 0x83, 0x0a, 0xe6, 0x86, 0x90, 0x13, 0x12, 0xa0, + 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, + 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x31, 0x20, 0x90, + 0xeb, 0xd1, 0x74, 0xc0, 0x88, 0x03, 0x97, 0x96, 0x67, 0x11, + 0xda, 0x74, 0xe9, 0x09, 0xd1, 0x64, 0x01, 0x26, 0x9b, 0x30, + 0x8c, 0x6a, 0xbe, 0xcf, 0x6f, 0x01, 0xd5, 0x86, 0xe2, 0xab, + 0x60, 0x8f, 0x5b, 0x60, 0x86, 0xc8, 0x2d, 0xee, 0xa7, 0x42, + 0x59, 0xd5, 0xdc, 0x3d, 0xb8, 0x13, 0x8f, 0x90, 0x26, 0xfc, + 0xf5, 0xce, 0xcb, 0xf9, 0x68, 0x91, 0x59, 0x87, 0xc6, 0x7d, + 0x2a ), + PUBLIC ( 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x31, 0x20, 0x90, + 0xeb, 0xd1, 0x74, 0xc0, 0x88, 0x03, 0x97, 0x96, 0x67, 0x11, + 0xda, 0x74, 0xe9, 0x09, 0xd1, 0x64, 0x01, 0x26, 0x9b, 0x30, + 0x8c, 0x6a, 0xbe, 0xcf, 0x6f, 0x01, 0xd5, 0x86, 0xe2, 0xab, + 0x60, 0x8f, 0x5b, 0x60, 0x86, 0xc8, 0x2d, 0xee, 0xa7, 0x42, + 0x59, 0xd5, 0xdc, 0x3d, 0xb8, 0x13, 0x8f, 0x90, 0x26, 0xfc, + 0xf5, 0xce, 0xcb, 0xf9, 0x68, 0x91, 0x59, 0x87, 0xc6, 0x7d, + 0x2a ), + PLAINTEXT ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, + 0x64, 0x0a ), + &sha256_algorithm, + SIGNATURE ( 0x30, 0x45, 0x02, 0x21, 0x00, 0xc4, 0xb5, 0xb9, 0x40, 0xf7, + 0x73, 0x9f, 0x77, 0x90, 0xa1, 0xa0, 0x0d, 0xc4, 0xd3, 0x1e, + 0x18, 0x08, 0xc0, 0xe9, 0xb1, 0xf5, 0x16, 0x71, 0xf0, 0x75, + 0x9f, 0xac, 0x5e, 0xeb, 0xca, 0x0d, 0x02, 0x02, 0x20, 0x32, + 0xb6, 0x77, 0x9e, 0x19, 0x1f, 0xde, 0x03, 0x1d, 0x8a, 0x29, + 0xe4, 0x97, 0xb9, 0x90, 0x1b, 0xff, 0xf3, 0x10, 0x8d, 0xc3, + 0x41, 0x4e, 0xc1, 0xef, 0x59, 0x37, 0xc3, 0xf7, 0xd5, 0xbe, + 0xb0 ) ); + +/** "Hello world" P-256 signature test (traditional private key, SHA-512) */ +PUBKEY_SIGN_TEST ( p256_hw_sha512_test, &ecdsa_algorithm, + PRIVATE ( 0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x5d, 0xc9, 0xbc, + 0x58, 0x82, 0x99, 0xaf, 0x56, 0x6a, 0x4a, 0x4d, 0xec, 0xce, + 0x9f, 0x6d, 0xfd, 0xb4, 0xfa, 0x5f, 0x8c, 0xd2, 0xfe, 0x5a, + 0x4b, 0x9b, 0x83, 0x0a, 0xe6, 0x86, 0x90, 0x13, 0x12, 0xa0, + 0x0a, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, + 0x07, 0xa1, 0x44, 0x03, 0x42, 0x00, 0x04, 0x31, 0x20, 0x90, + 0xeb, 0xd1, 0x74, 0xc0, 0x88, 0x03, 0x97, 0x96, 0x67, 0x11, + 0xda, 0x74, 0xe9, 0x09, 0xd1, 0x64, 0x01, 0x26, 0x9b, 0x30, + 0x8c, 0x6a, 0xbe, 0xcf, 0x6f, 0x01, 0xd5, 0x86, 0xe2, 0xab, + 0x60, 0x8f, 0x5b, 0x60, 0x86, 0xc8, 0x2d, 0xee, 0xa7, 0x42, + 0x59, 0xd5, 0xdc, 0x3d, 0xb8, 0x13, 0x8f, 0x90, 0x26, 0xfc, + 0xf5, 0xce, 0xcb, 0xf9, 0x68, 0x91, 0x59, 0x87, 0xc6, 0x7d, + 0x2a ), + PUBLIC ( 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x31, 0x20, 0x90, + 0xeb, 0xd1, 0x74, 0xc0, 0x88, 0x03, 0x97, 0x96, 0x67, 0x11, + 0xda, 0x74, 0xe9, 0x09, 0xd1, 0x64, 0x01, 0x26, 0x9b, 0x30, + 0x8c, 0x6a, 0xbe, 0xcf, 0x6f, 0x01, 0xd5, 0x86, 0xe2, 0xab, + 0x60, 0x8f, 0x5b, 0x60, 0x86, 0xc8, 0x2d, 0xee, 0xa7, 0x42, + 0x59, 0xd5, 0xdc, 0x3d, 0xb8, 0x13, 0x8f, 0x90, 0x26, 0xfc, + 0xf5, 0xce, 0xcb, 0xf9, 0x68, 0x91, 0x59, 0x87, 0xc6, 0x7d, + 0x2a ), + PLAINTEXT ( 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, + 0x64, 0x0a ), + &sha512_algorithm, + SIGNATURE ( 0x30, 0x45, 0x02, 0x21, 0x00, 0x8b, 0x62, 0xf5, 0xda, 0x49, + 0x41, 0x85, 0xfe, 0xac, 0x1c, 0x6f, 0xf3, 0x43, 0xd9, 0xa6, + 0x03, 0x89, 0x5f, 0x1c, 0x5a, 0xd4, 0x8e, 0xdd, 0x4a, 0x58, + 0x48, 0x8f, 0x07, 0xb3, 0x85, 0xdb, 0x07, 0x02, 0x20, 0x7c, + 0x82, 0x77, 0x9c, 0x03, 0xd1, 0xd9, 0x2f, 0xf9, 0x1e, 0xcb, + 0x06, 0x29, 0x37, 0x0c, 0x96, 0x17, 0xc7, 0xc4, 0x3c, 0x0d, + 0x4a, 0x2e, 0x85, 0xe1, 0x13, 0x29, 0xc2, 0x46, 0x2d, 0x2f, + 0x85 ) ); + +/** Random message P-256 signature test (PKCS#8 private key) */ +PUBKEY_SIGN_TEST ( p256_random_test, &ecdsa_algorithm, + PRIVATE ( 0x30, 0x81, 0x87, 0x02, 0x01, 0x00, 0x30, 0x13, 0x06, 0x07, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x04, 0x6d, 0x30, + 0x6b, 0x02, 0x01, 0x01, 0x04, 0x20, 0x5d, 0xc9, 0xbc, 0x58, + 0x82, 0x99, 0xaf, 0x56, 0x6a, 0x4a, 0x4d, 0xec, 0xce, 0x9f, + 0x6d, 0xfd, 0xb4, 0xfa, 0x5f, 0x8c, 0xd2, 0xfe, 0x5a, 0x4b, + 0x9b, 0x83, 0x0a, 0xe6, 0x86, 0x90, 0x13, 0x12, 0xa1, 0x44, + 0x03, 0x42, 0x00, 0x04, 0x31, 0x20, 0x90, 0xeb, 0xd1, 0x74, + 0xc0, 0x88, 0x03, 0x97, 0x96, 0x67, 0x11, 0xda, 0x74, 0xe9, + 0x09, 0xd1, 0x64, 0x01, 0x26, 0x9b, 0x30, 0x8c, 0x6a, 0xbe, + 0xcf, 0x6f, 0x01, 0xd5, 0x86, 0xe2, 0xab, 0x60, 0x8f, 0x5b, + 0x60, 0x86, 0xc8, 0x2d, 0xee, 0xa7, 0x42, 0x59, 0xd5, 0xdc, + 0x3d, 0xb8, 0x13, 0x8f, 0x90, 0x26, 0xfc, 0xf5, 0xce, 0xcb, + 0xf9, 0x68, 0x91, 0x59, 0x87, 0xc6, 0x7d, 0x2a ), + PUBLIC ( 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, + 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0x31, 0x20, 0x90, + 0xeb, 0xd1, 0x74, 0xc0, 0x88, 0x03, 0x97, 0x96, 0x67, 0x11, + 0xda, 0x74, 0xe9, 0x09, 0xd1, 0x64, 0x01, 0x26, 0x9b, 0x30, + 0x8c, 0x6a, 0xbe, 0xcf, 0x6f, 0x01, 0xd5, 0x86, 0xe2, 0xab, + 0x60, 0x8f, 0x5b, 0x60, 0x86, 0xc8, 0x2d, 0xee, 0xa7, 0x42, + 0x59, 0xd5, 0xdc, 0x3d, 0xb8, 0x13, 0x8f, 0x90, 0x26, 0xfc, + 0xf5, 0xce, 0xcb, 0xf9, 0x68, 0x91, 0x59, 0x87, 0xc6, 0x7d, + 0x2a ), + PLAINTEXT ( 0xe0, 0xf0, 0x1b, 0xd1, 0x95, 0xe0, 0x4b, 0xd1, 0xf7, 0x4a, + 0x18, 0xca, 0x60, 0x02, 0x29, 0xc1, 0x58, 0x03, 0xf8, 0xc2, + 0x3c, 0x0f, 0x86, 0x55, 0xc5, 0x22, 0x88, 0x7e, 0x1f, 0x6c, + 0x4e, 0x14, 0xb5, 0x7e, 0x52, 0x02, 0x40, 0xb2, 0x70, 0xa6, + 0x60, 0xef, 0xcb, 0xab, 0xbd, 0x9d, 0xbe, 0x88, 0x41, 0x3f, + 0x0f, 0x44, 0x24, 0xdf, 0x86, 0x1c, 0x41, 0x39, 0x38, 0xf9, + 0x7e, 0x26, 0xcb, 0x1e, 0x31, 0xa6, 0x4c, 0x38, 0x3f, 0x55, + 0xb6, 0xbe, 0x8a, 0xc8, 0xbd, 0xa8, 0x96, 0xef, 0x68, 0xf8, + 0x4e, 0x28, 0xd2, 0x4d, 0x31, 0x02, 0xb8, 0x4c, 0xb6, 0xd2, + 0x34, 0x1d, 0x95, 0xfa, 0x37, 0xfe, 0x29, 0x1f, 0xe3, 0x06, + 0x19, 0xe7, 0x21, 0x16, 0x3d, 0xa0, 0xdb, 0xb6, 0x9b, 0x5b, + 0x61, 0x28, 0x6f, 0x32, 0xe1, 0x5e, 0x6e, 0xe1, 0x11, 0xb3, + 0x28, 0x82, 0xf1, 0xf4, 0x75, 0x1f, 0x0d, 0x7c, 0x0d, 0x8f, + 0x43, 0x55, 0xc9, 0xad, 0x9d, 0x8a, 0xd4, 0xf9, 0xb4, 0xd5, + 0x9a, 0xda, 0xd7, 0xe3, 0x15, 0xcb, 0x09, 0x2c, 0x2d, 0xc4, + 0x9d, 0x9c, 0x34, 0xe1, 0x84, 0x1c, 0xbd, 0x38, 0x3b, 0x0e, + 0xa3, 0xfd, 0x78, 0x29, 0x79, 0xa9, 0x73, 0x36, 0x8f, 0xab, + 0xef, 0xb3, 0x4e, 0x93, 0xc8, 0x18, 0xba, 0x3a, 0x3d, 0x78, + 0x0f, 0x47, 0xa4, 0x0b, 0x87, 0xfd, 0x00, 0x11, 0x34, 0x41, + 0x6c, 0x01, 0x4e, 0xdd, 0x77, 0x81, 0x21, 0x54, 0x64, 0x60, + 0xa1, 0xe0, 0xc9, 0x4b, 0xc6, 0xc6, 0x07, 0x52, 0xa2, 0xba, + 0x51, 0xc9, 0xa0, 0xa8, 0xf6, 0xa4, 0xdf, 0x37, 0x80, 0xc5, + 0x03, 0x1d, 0x9c, 0x85, 0xf9, 0x93, 0x4d, 0x1b, 0xec, 0x1c, + 0x1f, 0xab, 0xb2, 0xfa, 0x0c, 0xc5, 0x59, 0x2e, 0xf7, 0x01, + 0xc6, 0x3b, 0x39, 0x0e, 0x90, 0x92, 0x42, 0x76, 0x80, 0xfe, + 0x67, 0x05, 0xdd, 0x80, 0xf4, 0x06 ), + &sha256_algorithm, + SIGNATURE ( 0x30, 0x44, 0x02, 0x20, 0x12, 0x9c, 0x69, 0xb2, 0x61, 0x49, + 0x95, 0x0e, 0xab, 0x3b, 0x8f, 0x15, 0x31, 0x97, 0x30, 0x73, + 0x68, 0xe1, 0xcb, 0x32, 0x45, 0xe7, 0x9c, 0x8f, 0x50, 0xa0, + 0x84, 0x89, 0x16, 0xf8, 0x59, 0xe9, 0x02, 0x20, 0x7f, 0x46, + 0x97, 0xf1, 0x99, 0x45, 0x09, 0x0f, 0x80, 0xe1, 0xf3, 0xfc, + 0x62, 0x6b, 0x35, 0xb1, 0x4c, 0xdb, 0x48, 0x0b, 0xff, 0x48, + 0xae, 0x3a, 0x5b, 0x20, 0x48, 0x31, 0x91, 0x88, 0xba, + 0xde ) ); + +/** Random message P-384 signature test (PKCS#8 private key) */ +PUBKEY_SIGN_TEST ( p384_random_test, &ecdsa_algorithm, + PRIVATE ( 0x30, 0x81, 0xb6, 0x02, 0x01, 0x00, 0x30, 0x10, 0x06, 0x07, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, + 0x81, 0x04, 0x00, 0x22, 0x04, 0x81, 0x9e, 0x30, 0x81, 0x9b, + 0x02, 0x01, 0x01, 0x04, 0x30, 0x5f, 0xc5, 0x6a, 0x6e, 0xf2, + 0x91, 0xf2, 0x1e, 0xa9, 0x80, 0xd3, 0xfd, 0xd3, 0x3a, 0x0b, + 0x6b, 0xd0, 0x8c, 0xdb, 0x4a, 0xd9, 0x72, 0x6d, 0x56, 0x11, + 0x43, 0x10, 0x64, 0x45, 0x20, 0x6e, 0x3a, 0x77, 0x99, 0x55, + 0x72, 0x86, 0x30, 0xd4, 0x69, 0xd6, 0x10, 0x2d, 0x2d, 0x46, + 0x72, 0x1f, 0x3e, 0xa1, 0x64, 0x03, 0x62, 0x00, 0x04, 0x6a, + 0xb2, 0x1a, 0x29, 0x54, 0x71, 0x27, 0x3c, 0x02, 0x3e, 0x3b, + 0x4c, 0x0e, 0x69, 0x4f, 0xe3, 0xdf, 0x8d, 0x02, 0x76, 0x7c, + 0x12, 0x2e, 0x31, 0xe7, 0x8b, 0xc8, 0x09, 0x1e, 0x0a, 0x5d, + 0x98, 0x0a, 0x3c, 0x43, 0xc6, 0xd4, 0x95, 0x53, 0xc0, 0x53, + 0x91, 0xdd, 0x70, 0x03, 0x77, 0xe7, 0xe8, 0xe9, 0x04, 0x46, + 0x7e, 0x9a, 0x8f, 0x0b, 0x21, 0x30, 0x06, 0x80, 0xa1, 0xc1, + 0xff, 0x20, 0x91, 0x68, 0x1f, 0x84, 0x01, 0x52, 0x28, 0xb8, + 0x18, 0xb0, 0xcc, 0x33, 0x9c, 0x44, 0x98, 0xa3, 0x59, 0x92, + 0x36, 0xe3, 0x46, 0x72, 0xa8, 0x86, 0xec, 0x69, 0x24, 0x29, + 0x29, 0xc0, 0xca, 0x2b, 0x40 ), + PUBLIC ( 0x30, 0x76, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, + 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22, + 0x03, 0x62, 0x00, 0x04, 0x6a, 0xb2, 0x1a, 0x29, 0x54, 0x71, + 0x27, 0x3c, 0x02, 0x3e, 0x3b, 0x4c, 0x0e, 0x69, 0x4f, 0xe3, + 0xdf, 0x8d, 0x02, 0x76, 0x7c, 0x12, 0x2e, 0x31, 0xe7, 0x8b, + 0xc8, 0x09, 0x1e, 0x0a, 0x5d, 0x98, 0x0a, 0x3c, 0x43, 0xc6, + 0xd4, 0x95, 0x53, 0xc0, 0x53, 0x91, 0xdd, 0x70, 0x03, 0x77, + 0xe7, 0xe8, 0xe9, 0x04, 0x46, 0x7e, 0x9a, 0x8f, 0x0b, 0x21, + 0x30, 0x06, 0x80, 0xa1, 0xc1, 0xff, 0x20, 0x91, 0x68, 0x1f, + 0x84, 0x01, 0x52, 0x28, 0xb8, 0x18, 0xb0, 0xcc, 0x33, 0x9c, + 0x44, 0x98, 0xa3, 0x59, 0x92, 0x36, 0xe3, 0x46, 0x72, 0xa8, + 0x86, 0xec, 0x69, 0x24, 0x29, 0x29, 0xc0, 0xca, 0x2b, 0x40 ), + PLAINTEXT ( 0xe0, 0xf0, 0x1b, 0xd1, 0x95, 0xe0, 0x4b, 0xd1, 0xf7, 0x4a, + 0x18, 0xca, 0x60, 0x02, 0x29, 0xc1, 0x58, 0x03, 0xf8, 0xc2, + 0x3c, 0x0f, 0x86, 0x55, 0xc5, 0x22, 0x88, 0x7e, 0x1f, 0x6c, + 0x4e, 0x14, 0xb5, 0x7e, 0x52, 0x02, 0x40, 0xb2, 0x70, 0xa6, + 0x60, 0xef, 0xcb, 0xab, 0xbd, 0x9d, 0xbe, 0x88, 0x41, 0x3f, + 0x0f, 0x44, 0x24, 0xdf, 0x86, 0x1c, 0x41, 0x39, 0x38, 0xf9, + 0x7e, 0x26, 0xcb, 0x1e, 0x31, 0xa6, 0x4c, 0x38, 0x3f, 0x55, + 0xb6, 0xbe, 0x8a, 0xc8, 0xbd, 0xa8, 0x96, 0xef, 0x68, 0xf8, + 0x4e, 0x28, 0xd2, 0x4d, 0x31, 0x02, 0xb8, 0x4c, 0xb6, 0xd2, + 0x34, 0x1d, 0x95, 0xfa, 0x37, 0xfe, 0x29, 0x1f, 0xe3, 0x06, + 0x19, 0xe7, 0x21, 0x16, 0x3d, 0xa0, 0xdb, 0xb6, 0x9b, 0x5b, + 0x61, 0x28, 0x6f, 0x32, 0xe1, 0x5e, 0x6e, 0xe1, 0x11, 0xb3, + 0x28, 0x82, 0xf1, 0xf4, 0x75, 0x1f, 0x0d, 0x7c, 0x0d, 0x8f, + 0x43, 0x55, 0xc9, 0xad, 0x9d, 0x8a, 0xd4, 0xf9, 0xb4, 0xd5, + 0x9a, 0xda, 0xd7, 0xe3, 0x15, 0xcb, 0x09, 0x2c, 0x2d, 0xc4, + 0x9d, 0x9c, 0x34, 0xe1, 0x84, 0x1c, 0xbd, 0x38, 0x3b, 0x0e, + 0xa3, 0xfd, 0x78, 0x29, 0x79, 0xa9, 0x73, 0x36, 0x8f, 0xab, + 0xef, 0xb3, 0x4e, 0x93, 0xc8, 0x18, 0xba, 0x3a, 0x3d, 0x78, + 0x0f, 0x47, 0xa4, 0x0b, 0x87, 0xfd, 0x00, 0x11, 0x34, 0x41, + 0x6c, 0x01, 0x4e, 0xdd, 0x77, 0x81, 0x21, 0x54, 0x64, 0x60, + 0xa1, 0xe0, 0xc9, 0x4b, 0xc6, 0xc6, 0x07, 0x52, 0xa2, 0xba, + 0x51, 0xc9, 0xa0, 0xa8, 0xf6, 0xa4, 0xdf, 0x37, 0x80, 0xc5, + 0x03, 0x1d, 0x9c, 0x85, 0xf9, 0x93, 0x4d, 0x1b, 0xec, 0x1c, + 0x1f, 0xab, 0xb2, 0xfa, 0x0c, 0xc5, 0x59, 0x2e, 0xf7, 0x01, + 0xc6, 0x3b, 0x39, 0x0e, 0x90, 0x92, 0x42, 0x76, 0x80, 0xfe, + 0x67, 0x05, 0xdd, 0x80, 0xf4, 0x06 ), + &sha512_algorithm, + SIGNATURE ( 0x30, 0x64, 0x02, 0x30, 0x17, 0xa4, 0x1f, 0x5d, 0xb7, 0x6d, + 0x85, 0xd0, 0x1f, 0xf1, 0x28, 0x5c, 0x45, 0x27, 0x15, 0x30, + 0x9c, 0xb5, 0xe3, 0x36, 0x70, 0xf3, 0x82, 0xa6, 0x1c, 0x4a, + 0xb7, 0x87, 0xc7, 0x86, 0xae, 0x5d, 0x99, 0xba, 0xa9, 0x9a, + 0x2b, 0x25, 0x0a, 0xd2, 0x25, 0x1d, 0xe9, 0x78, 0xff, 0x2d, + 0x8d, 0xd6, 0x02, 0x30, 0x55, 0x95, 0x5d, 0x4d, 0x74, 0x3d, + 0xd1, 0xae, 0xf0, 0x6d, 0x6a, 0x77, 0x40, 0xa6, 0x57, 0xb2, + 0xb1, 0xee, 0xef, 0xd5, 0xcf, 0xeb, 0xa8, 0x82, 0x22, 0x1a, + 0xaf, 0x1e, 0xbc, 0x51, 0x59, 0xb7, 0x66, 0xbb, 0x83, 0x38, + 0x8b, 0x28, 0xa7, 0x84, 0x4e, 0x5c, 0x0a, 0x07, 0x56, 0x75, + 0x01, 0x8a ) ); + +/** + * Perform ECDSA self-tests + * + */ +static void ecdsa_test_exec ( void ) { + + pubkey_sign_ok ( &p256_hw_test ); + pubkey_sign_ok ( &p256_hw_sha512_test ); + pubkey_sign_ok ( &p256_random_test ); + pubkey_sign_ok ( &p384_random_test ); +} + +/** ECDSA self-test */ +struct self_test ecdsa_test __self_test = { + .name = "ecdsa", + .exec = ecdsa_test_exec, +}; + +/* Drag in required ASN.1 OID-identified algorithms */ +REQUIRING_SYMBOL ( ecdsa_test ); +REQUIRE_OBJECT ( oid_p256 ); +REQUIRE_OBJECT ( oid_p384 ); diff --git a/src/tests/tests.c b/src/tests/tests.c index daf646798..130eba949 100644 --- a/src/tests/tests.c +++ b/src/tests/tests.c @@ -91,3 +91,4 @@ REQUIRE_OBJECT ( p384_test ); REQUIRE_OBJECT ( efi_siglist_test ); REQUIRE_OBJECT ( cpio_test ); REQUIRE_OBJECT ( fdt_test ); +REQUIRE_OBJECT ( ecdsa_test ); -- cgit v1.2.3-55-g7522 From f3147b42a16a472886671ebae55f5436263244f8 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Dec 2025 14:24:27 +0000 Subject: [test] Ensure OID-identified algorithms are present for X.509 tests The algorithms required for the X.509 tests are accessed indirectly via their OID-identified algorithms, rather than directly via symbols. Ensure that the required OID-identified algorithm definitions are included regardless of the configuration in config/crypto.h. Signed-off-by: Michael Brown --- src/tests/x509_test.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/tests') diff --git a/src/tests/x509_test.c b/src/tests/x509_test.c index 50eb4d787..e460e48b2 100644 --- a/src/tests/x509_test.c +++ b/src/tests/x509_test.c @@ -1135,8 +1135,7 @@ struct self_test x509_test __self_test = { /* Drag in algorithms required for tests */ REQUIRING_SYMBOL ( x509_test ); -REQUIRE_OBJECT ( rsa ); -REQUIRE_OBJECT ( sha1 ); -REQUIRE_OBJECT ( sha256 ); +REQUIRE_OBJECT ( rsa_sha1 ); +REQUIRE_OBJECT ( rsa_sha256 ); REQUIRE_OBJECT ( ipv4 ); REQUIRE_OBJECT ( ipv6 ); -- cgit v1.2.3-55-g7522 From f1e23b53a788431190f984ee946a0333ade65596 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 19 Dec 2025 14:45:09 +0000 Subject: [test] Add test cases for X.509 certificates with ECDSA signatures Signed-off-by: Michael Brown --- src/tests/x509_test.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) (limited to 'src/tests') diff --git a/src/tests/x509_test.c b/src/tests/x509_test.c index e460e48b2..1a8adc55e 100644 --- a/src/tests/x509_test.c +++ b/src/tests/x509_test.c @@ -646,6 +646,242 @@ CERTIFICATE ( bad_path_len_crt, 0x53, 0x5a, 0xc8, 0x99, 0xe5, 0xdf, 0x79, 0x07, 0x00, 0x2c, 0x9f, 0x49, 0x91, 0x21, 0xeb, 0xfc ) ); +/* + * subject iPXE self-test EC intermediate CA + * issuer iPXE self-test root CA + */ +CERTIFICATE ( ecintermediate_crt, + DATA ( 0x30, 0x82, 0x03, 0x3a, 0x30, 0x82, 0x02, 0xa3, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x01, 0x04, 0x30, 0x0d, 0x06, 0x09, + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, + 0x00, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, + 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, + 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, + 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, + 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, + 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, + 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, + 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1f, 0x30, + 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, 0x69, 0x50, + 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, + 0x73, 0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x35, 0x31, 0x32, 0x31, 0x39, + 0x31, 0x34, 0x33, 0x32, 0x35, 0x39, 0x5a, 0x17, 0x0d, 0x32, + 0x38, 0x30, 0x39, 0x31, 0x34, 0x31, 0x34, 0x33, 0x32, 0x35, + 0x39, 0x5a, 0x30, 0x81, 0x93, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, + 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, + 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, + 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x2a, + 0x30, 0x28, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x21, 0x69, + 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, + 0x65, 0x73, 0x74, 0x20, 0x45, 0x43, 0x20, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, + 0x43, 0x41, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xf8, + 0xb9, 0xac, 0x83, 0x58, 0xf1, 0xa9, 0x6f, 0x85, 0x22, 0xf7, + 0x04, 0x8d, 0x52, 0xff, 0xef, 0x85, 0xd1, 0x43, 0xfa, 0xdb, + 0x1a, 0xa1, 0x8d, 0x8b, 0x40, 0x6f, 0x85, 0x2f, 0x38, 0x4c, + 0x19, 0x79, 0xe0, 0x6a, 0x52, 0x1f, 0x6c, 0x78, 0x3e, 0x2e, + 0x06, 0x40, 0x35, 0x8b, 0x93, 0xe8, 0xe1, 0xef, 0x37, 0x93, + 0xe6, 0x70, 0x37, 0xf3, 0x12, 0x05, 0x82, 0x46, 0xdd, 0xf2, + 0x8a, 0x26, 0x70, 0xa3, 0x81, 0xed, 0x30, 0x81, 0xea, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, + 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0e, 0x06, 0x03, + 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, + 0x02, 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0x15, 0x30, 0x20, 0x14, 0x09, 0xba, 0x24, + 0x27, 0x38, 0x39, 0x28, 0xc9, 0x02, 0x62, 0x4e, 0x76, 0x79, + 0x91, 0x89, 0x9b, 0x30, 0x81, 0xa7, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x81, 0x9f, 0x30, 0x81, 0x9c, 0xa1, 0x81, 0x8e, + 0xa4, 0x81, 0x8b, 0x30, 0x81, 0x88, 0x31, 0x0b, 0x30, 0x09, + 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, + 0x17, 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, + 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, + 0x68, 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, + 0x55, 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, + 0x69, 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, + 0x55, 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, + 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, + 0x08, 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, + 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x16, + 0x69, 0x50, 0x58, 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, + 0x74, 0x65, 0x73, 0x74, 0x20, 0x72, 0x6f, 0x6f, 0x74, 0x20, + 0x43, 0x41, 0x82, 0x09, 0x00, 0xc6, 0xb8, 0x9c, 0x58, 0xd2, + 0xdc, 0xc9, 0x5d, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x03, 0x81, + 0x81, 0x00, 0x19, 0x30, 0x56, 0x0d, 0x5d, 0x6c, 0x4d, 0x7c, + 0x68, 0x47, 0x59, 0xf1, 0xde, 0xd6, 0x6b, 0xdc, 0xa4, 0x43, + 0x01, 0x1b, 0xff, 0xb3, 0xfc, 0x78, 0xda, 0x31, 0xe0, 0x36, + 0xd8, 0x0c, 0x5d, 0x4e, 0xb7, 0x33, 0xd2, 0xb3, 0x2c, 0x41, + 0xb0, 0xc6, 0x8a, 0xba, 0x64, 0xe8, 0x85, 0x46, 0x81, 0x3a, + 0x8f, 0xef, 0x17, 0x66, 0x68, 0x91, 0xbd, 0x54, 0xea, 0x03, + 0xa4, 0xf9, 0x15, 0x47, 0x2a, 0xde, 0xeb, 0xe0, 0x2c, 0xd8, + 0x49, 0x1a, 0x10, 0xed, 0x72, 0x78, 0x77, 0x94, 0xed, 0xf9, + 0x68, 0xe6, 0x93, 0x93, 0xb5, 0x99, 0x1b, 0xd7, 0x07, 0x1d, + 0xe3, 0x94, 0xa6, 0xd3, 0x48, 0xcc, 0x7a, 0x1f, 0x59, 0xba, + 0x31, 0x23, 0xf9, 0x09, 0xe5, 0x2f, 0xda, 0xea, 0xf3, 0xd8, + 0xc8, 0xa8, 0x71, 0xb9, 0x69, 0xf3, 0x17, 0x4c, 0xc2, 0xf1, + 0x67, 0xbb, 0xf5, 0x8c, 0x4e, 0x46, 0x63, 0x58, 0x54, 0x8e ), + FINGERPRINT ( 0x21, 0x7b, 0x48, 0x59, 0xf1, 0x5e, 0x8a, 0x75, + 0xd1, 0xee, 0x60, 0x4a, 0x7d, 0x8f, 0xa8, 0xe2, + 0x6c, 0x25, 0xc4, 0x05, 0x13, 0x46, 0x65, 0x63, + 0x0b, 0x8d, 0x46, 0x52, 0x6e, 0x3c, 0x4e, 0x10 ) ); + +/* + * subject iPXE self-test EC leaf CA + * issuer iPXE self-test EC intermediate CA + */ +CERTIFICATE ( ecleaf_crt, + DATA ( 0x30, 0x82, 0x02, 0x74, 0x30, 0x82, 0x02, 0x1b, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x01, 0x02, 0x30, 0x0a, 0x06, 0x08, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x81, + 0x93, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, + 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, + 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, + 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, + 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, + 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, + 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, + 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x2a, 0x30, 0x28, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x21, 0x69, 0x50, 0x58, 0x45, 0x20, + 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, + 0x45, 0x43, 0x20, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6d, 0x65, + 0x64, 0x69, 0x61, 0x74, 0x65, 0x20, 0x43, 0x41, 0x30, 0x1e, + 0x17, 0x0d, 0x32, 0x35, 0x31, 0x32, 0x31, 0x39, 0x31, 0x34, + 0x33, 0x32, 0x35, 0x39, 0x5a, 0x17, 0x0d, 0x32, 0x38, 0x30, + 0x39, 0x31, 0x34, 0x31, 0x34, 0x33, 0x32, 0x35, 0x39, 0x5a, + 0x30, 0x81, 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, + 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, + 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, + 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, + 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, + 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, + 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, + 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, + 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x19, 0x69, 0x50, 0x58, + 0x45, 0x20, 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, + 0x74, 0x20, 0x45, 0x43, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, + 0x43, 0x41, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86, + 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48, + 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xa4, + 0x10, 0x14, 0x39, 0xde, 0x28, 0x87, 0x52, 0xb0, 0xe3, 0x87, + 0x1b, 0x0f, 0xeb, 0xdf, 0x9b, 0x78, 0x47, 0xeb, 0x76, 0xbb, + 0xf6, 0x6d, 0x26, 0x0e, 0x2b, 0xec, 0xd2, 0x8e, 0x78, 0xac, + 0x35, 0x44, 0xd7, 0x79, 0x3f, 0x97, 0x01, 0x8e, 0x8f, 0x08, + 0xcb, 0x87, 0x1e, 0xd2, 0xba, 0x1b, 0x4b, 0xd2, 0x93, 0x99, + 0x62, 0x05, 0xeb, 0x75, 0x2a, 0x8f, 0xf9, 0xdb, 0x9c, 0xf4, + 0xbb, 0x60, 0x8d, 0xa3, 0x66, 0x30, 0x64, 0x30, 0x12, 0x06, + 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x08, 0x30, + 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x00, 0x30, 0x0e, 0x06, + 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, + 0x02, 0x02, 0x04, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, + 0x04, 0x16, 0x04, 0x14, 0xbc, 0xca, 0xd5, 0xfb, 0x11, 0x6d, + 0xf4, 0xa8, 0x43, 0x12, 0x5f, 0x72, 0xe8, 0x28, 0xe1, 0x9a, + 0xe8, 0xd5, 0xc7, 0x7f, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x15, 0x30, 0x20, + 0x14, 0x09, 0xba, 0x24, 0x27, 0x38, 0x39, 0x28, 0xc9, 0x02, + 0x62, 0x4e, 0x76, 0x79, 0x91, 0x89, 0x9b, 0x30, 0x0a, 0x06, + 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, + 0x47, 0x00, 0x30, 0x44, 0x02, 0x20, 0x22, 0x73, 0x07, 0xe2, + 0x21, 0xaa, 0xc5, 0x0a, 0x88, 0x51, 0xd6, 0x8e, 0x51, 0xf7, + 0x67, 0x88, 0x6e, 0xe4, 0xe4, 0x14, 0xb7, 0x5b, 0x4d, 0xd1, + 0xfc, 0x21, 0xc8, 0xd8, 0x94, 0xf6, 0x7e, 0x54, 0x02, 0x20, + 0x33, 0x2a, 0x0c, 0x58, 0xfd, 0x0f, 0xd5, 0x89, 0x79, 0x60, + 0x81, 0xeb, 0x23, 0x4f, 0x49, 0x92, 0x09, 0xa5, 0x0f, 0xb6, + 0xf3, 0x52, 0xa3, 0x2e, 0xf6, 0x37, 0xbf, 0x9f, 0x9d, 0x7a, + 0xbf, 0x15 ), + FINGERPRINT ( 0xe3, 0x46, 0x2e, 0x10, 0x43, 0x1b, 0xca, 0xb8, + 0x7c, 0x2e, 0xa0, 0xd5, 0x60, 0x09, 0xb6, 0xef, + 0x5d, 0x62, 0x23, 0xe1, 0xcd, 0xbb, 0x71, 0x28, + 0xf0, 0x93, 0xd7, 0xf3, 0x6e, 0x1e, 0x71, 0xe5 ) ); + +/* + * subject boot.test.ipxe.org + * issuer iPXE self-test EC leaf CA + */ +CERTIFICATE ( ecserver_crt, + DATA ( 0x30, 0x82, 0x02, 0x43, 0x30, 0x82, 0x01, 0xe8, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x01, 0x03, 0x30, 0x0a, 0x06, 0x08, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x30, 0x81, + 0x8b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, 0x30, 0x15, 0x06, 0x03, + 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, 0x61, 0x6d, 0x62, 0x72, + 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, 0x69, 0x72, 0x65, 0x31, + 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, + 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x31, + 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0f, + 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x11, 0x30, 0x0f, 0x06, + 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, 0x69, 0x70, 0x78, 0x65, + 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x22, 0x30, 0x20, 0x06, 0x03, + 0x55, 0x04, 0x03, 0x0c, 0x19, 0x69, 0x50, 0x58, 0x45, 0x20, + 0x73, 0x65, 0x6c, 0x66, 0x2d, 0x74, 0x65, 0x73, 0x74, 0x20, + 0x45, 0x43, 0x20, 0x6c, 0x65, 0x61, 0x66, 0x20, 0x43, 0x41, + 0x30, 0x1e, 0x17, 0x0d, 0x32, 0x35, 0x31, 0x32, 0x31, 0x39, + 0x31, 0x34, 0x33, 0x32, 0x35, 0x39, 0x5a, 0x17, 0x0d, 0x32, + 0x36, 0x31, 0x32, 0x31, 0x39, 0x31, 0x34, 0x33, 0x32, 0x35, + 0x39, 0x5a, 0x30, 0x81, 0x84, 0x31, 0x0b, 0x30, 0x09, 0x06, + 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x17, + 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x08, 0x0c, 0x0e, 0x43, + 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x73, 0x68, + 0x69, 0x72, 0x65, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, + 0x04, 0x07, 0x0c, 0x09, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, + 0x64, 0x67, 0x65, 0x31, 0x18, 0x30, 0x16, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x0c, 0x0f, 0x46, 0x65, 0x6e, 0x20, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x73, 0x20, 0x4c, 0x74, 0x64, 0x31, + 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x08, + 0x69, 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x31, 0x1b, + 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x12, 0x62, + 0x6f, 0x6f, 0x74, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x69, + 0x70, 0x78, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x30, 0x59, 0x30, + 0x13, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, + 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, + 0x03, 0x42, 0x00, 0x04, 0x81, 0xac, 0xb9, 0xde, 0x2e, 0xf9, + 0xae, 0x5c, 0x33, 0xba, 0x43, 0x54, 0xeb, 0xc6, 0x08, 0xa1, + 0xed, 0xf7, 0x6a, 0x78, 0x77, 0x8b, 0x2c, 0x59, 0x61, 0x6d, + 0x25, 0xaf, 0x2c, 0xe4, 0x3e, 0x22, 0x65, 0x85, 0xa4, 0x9a, + 0x7f, 0xe3, 0xbe, 0x6c, 0x65, 0xa1, 0x4f, 0x74, 0x60, 0x06, + 0x8b, 0xf2, 0x5f, 0xe3, 0xdf, 0x8b, 0xc2, 0xb9, 0x67, 0x0e, + 0xcc, 0x4e, 0x87, 0x53, 0x2e, 0xad, 0x71, 0xbb, 0xa3, 0x42, + 0x30, 0x40, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, + 0x16, 0x04, 0x14, 0x4f, 0xe2, 0x6c, 0x54, 0xd0, 0x6c, 0x66, + 0x39, 0xb8, 0x2a, 0x3f, 0x30, 0x6e, 0x56, 0x84, 0x3b, 0xb2, + 0x6b, 0xef, 0x89, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, + 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0xbc, 0xca, 0xd5, 0xfb, + 0x11, 0x6d, 0xf4, 0xa8, 0x43, 0x12, 0x5f, 0x72, 0xe8, 0x28, + 0xe1, 0x9a, 0xe8, 0xd5, 0xc7, 0x7f, 0x30, 0x0a, 0x06, 0x08, + 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x03, 0x49, + 0x00, 0x30, 0x46, 0x02, 0x21, 0x00, 0x8d, 0x22, 0x2a, 0x92, + 0xcf, 0x39, 0xc6, 0xbe, 0x01, 0x09, 0x82, 0x75, 0x2b, 0xe2, + 0xd7, 0xf0, 0x78, 0x2e, 0xde, 0x95, 0x0a, 0xbf, 0xbe, 0x2e, + 0xb4, 0x17, 0x0f, 0x44, 0x22, 0xa4, 0x27, 0x27, 0x02, 0x21, + 0x00, 0x80, 0xa8, 0x37, 0xab, 0xd6, 0xf4, 0x38, 0x73, 0xe0, + 0x48, 0x69, 0x67, 0xbc, 0xbb, 0xfd, 0x3e, 0x2a, 0xb4, 0xe7, + 0xd0, 0x93, 0xb3, 0xff, 0xc8, 0xd0, 0x9a, 0x8b, 0xc6, 0x06, + 0xfa, 0xe3, 0x8d ), + FINGERPRINT ( 0xcf, 0x32, 0x56, 0xb9, 0x9c, 0x0c, 0x4a, 0xf5, + 0x92, 0x59, 0x90, 0x11, 0x87, 0x17, 0x85, 0xea, + 0xc8, 0x8c, 0x5e, 0x13, 0xe2, 0x09, 0xb6, 0xe9, + 0x15, 0xa8, 0xf5, 0x57, 0x93, 0x47, 0x46, 0xc2 ) ); + /** Valid certificate chain up to boot.test.ipxe.org */ CHAIN ( server_chain, &server_crt, &leaf_crt, &intermediate_crt, &root_crt ); @@ -666,6 +902,13 @@ CHAIN ( useless_chain, &useless_crt, &leaf_crt, &intermediate_crt, &root_crt ); CHAIN ( bad_path_len_chain, &bad_path_len_crt, &useless_crt, &leaf_crt, &intermediate_crt, &root_crt ); +/** Valid certificate chain up to ECDSA boot.test.ipxe.org */ +CHAIN ( ecserver_chain, + &ecserver_crt, &ecleaf_crt, &ecintermediate_crt, &root_crt ); + +/** Broken certificate chain up to ECDSA boot.test.ipxe.org */ +CHAIN ( broken_ecserver_chain, &ecserver_crt, &ecintermediate_crt, &root_crt ); + /** Empty certificate store */ static struct x509_chain empty_store = { .refcnt = REF_INIT ( ref_no_free ), @@ -706,6 +949,9 @@ static struct x509_root dummy_root = { /** Time at which all test certificates are valid */ static time_t test_time = 1332374737ULL; /* Thu Mar 22 00:05:37 2012 */ +/** Time at which all ECDSA test certificates are valid */ +static time_t ectest_time = 1766154603ULL; /* Fri 19 Dec 14:30:03 GMT 2025 */ + /** Time at which end-entity test certificates are invalid */ static time_t test_expired = 1375573111ULL; /* Sat Aug 3 23:38:31 2013 */ @@ -994,6 +1240,9 @@ static void x509_test_exec ( void ) { x509_certificate_ok ( &server_crt ); x509_certificate_ok ( ¬_ca_crt ); x509_certificate_ok ( &bad_path_len_crt ); + x509_certificate_ok ( &ecintermediate_crt ); + x509_certificate_ok ( &ecleaf_crt ); + x509_certificate_ok ( &ecserver_crt ); /* Check cache functionality */ x509_cached_ok ( &root_crt ); @@ -1003,6 +1252,9 @@ static void x509_test_exec ( void ) { x509_cached_ok ( &server_crt ); x509_cached_ok ( ¬_ca_crt ); x509_cached_ok ( &bad_path_len_crt ); + x509_cached_ok ( &ecintermediate_crt ); + x509_cached_ok ( &ecleaf_crt ); + x509_cached_ok ( &ecserver_crt ); /* Check all certificate fingerprints */ x509_fingerprint_ok ( &root_crt ); @@ -1012,6 +1264,9 @@ static void x509_test_exec ( void ) { x509_fingerprint_ok ( &server_crt ); x509_fingerprint_ok ( ¬_ca_crt ); x509_fingerprint_ok ( &bad_path_len_crt ); + x509_fingerprint_ok ( &ecintermediate_crt ); + x509_fingerprint_ok ( &ecleaf_crt ); + x509_fingerprint_ok ( &ecserver_crt ); /* Check pairwise issuing */ x509_check_issuer_ok ( &intermediate_crt, &root_crt ); @@ -1020,6 +1275,9 @@ static void x509_test_exec ( void ) { x509_check_issuer_ok ( &server_crt, &leaf_crt ); x509_check_issuer_fail_ok ( ¬_ca_crt, &server_crt ); x509_check_issuer_ok ( &bad_path_len_crt, &useless_crt ); + x509_check_issuer_ok ( &ecintermediate_crt, &root_crt ); + x509_check_issuer_ok ( &ecleaf_crt, &ecintermediate_crt ); + x509_check_issuer_ok ( &ecserver_crt, &ecleaf_crt ); /* Check root certificate stores */ x509_check_root_ok ( &root_crt, &test_root ); @@ -1061,6 +1319,8 @@ static void x509_test_exec ( void ) { x509_chain_ok ( ¬_ca_chain ); x509_chain_ok ( &useless_chain ); x509_chain_ok ( &bad_path_len_chain ); + x509_chain_ok ( &ecserver_chain ); + x509_chain_ok ( &broken_ecserver_chain ); /* Check certificate chains */ x509_validate_chain_ok ( &server_chain, test_time, @@ -1081,6 +1341,10 @@ static void x509_test_exec ( void ) { &empty_store, &test_root ); x509_validate_chain_fail_ok ( &bad_path_len_chain, test_time, &empty_store, &test_root ); + x509_validate_chain_ok ( &ecserver_chain, ectest_time, &empty_store, + &test_root ); + x509_validate_chain_fail_ok ( &broken_ecserver_chain, ectest_time, + &empty_store, &test_root ); /* Check certificate chain expiry times */ x509_validate_chain_fail_ok ( &server_chain, test_expired, @@ -1110,6 +1374,8 @@ static void x509_test_exec ( void ) { assert ( list_empty ( &empty_store.links ) ); /* Drop chain references */ + x509_chain_put ( broken_ecserver_chain.chain ); + x509_chain_put ( ecserver_chain.chain ); x509_chain_put ( bad_path_len_chain.chain ); x509_chain_put ( useless_chain.chain ); x509_chain_put ( not_ca_chain.chain ); @@ -1118,6 +1384,9 @@ static void x509_test_exec ( void ) { x509_chain_put ( server_chain.chain ); /* Drop certificate references */ + x509_put ( ecserver_crt.cert ); + x509_put ( ecintermediate_crt.cert ); + x509_put ( ecleaf_crt.cert ); x509_put ( bad_path_len_crt.cert ); x509_put ( not_ca_crt.cert ); x509_put ( server_crt.cert ); @@ -1137,5 +1406,7 @@ struct self_test x509_test __self_test = { REQUIRING_SYMBOL ( x509_test ); REQUIRE_OBJECT ( rsa_sha1 ); REQUIRE_OBJECT ( rsa_sha256 ); +REQUIRE_OBJECT ( ecdsa_sha256 ); +REQUIRE_OBJECT ( oid_p256 ); REQUIRE_OBJECT ( ipv4 ); REQUIRE_OBJECT ( ipv6 ); -- cgit v1.2.3-55-g7522 From 01038893a3b6e98cb41c4033dd2620eb810121e5 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 29 Dec 2025 13:18:10 +0000 Subject: [test] Update big integer tests to use okx() Signed-off-by: Michael Brown --- src/tests/bigint_test.c | 720 ++++++++++++++++++++++++++++-------------------- 1 file changed, 428 insertions(+), 292 deletions(-) (limited to 'src/tests') diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 496efdfe2..4090494ae 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -40,6 +40,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** Define inline big integer */ #define BIGINT(...) { __VA_ARGS__ } +/** A big integer test value */ +struct bigint_test { + /** Raw value */ + const uint8_t *raw; + /** Length of raw value */ + size_t len; +}; + /* Provide global functions to allow inspection of generated assembly code */ void bigint_init_sample ( bigint_element_t *value0, unsigned int size, @@ -245,38 +253,49 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * @v value Big integer to be added to * @v expected Big integer expected result * @v overflow Expected result overflows range + * @v file Test code file + * @v line Test code line */ +static void bigint_add_okx ( struct bigint_test *addend, + struct bigint_test *value, + struct bigint_test *expected, int overflow, + const char *file, unsigned int line ) { + uint8_t result_raw[ expected->len ]; + unsigned int size = bigint_required_size ( value->len ); + unsigned int msb = ( 8 * value->len ); + bigint_t ( size ) addend_temp; + bigint_t ( size ) value_temp; + int carry; + + assert ( bigint_size ( &addend_temp ) == bigint_size ( &value_temp ) ); + bigint_init ( &value_temp, value->raw, value->len ); + bigint_init ( &addend_temp, addend->raw, addend->len ); + DBG ( "Add: 0x%s", bigint_ntoa ( &addend_temp ) ); + DBG ( " + 0x%s", bigint_ntoa ( &value_temp ) ); + carry = bigint_add ( &addend_temp, &value_temp ); + DBG ( " = 0x%s%s\n", bigint_ntoa ( &value_temp ), + ( carry ? " (carry)" : "" ) ); + bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); + + okx ( memcmp ( result_raw, expected->raw, sizeof ( result_raw ) ) == 0, + file, line ); + if ( sizeof ( result_raw ) < sizeof ( value_temp ) ) + carry += bigint_bit_is_set ( &value_temp, msb ); + okx ( carry == overflow, file, line ); +} #define bigint_add_ok( addend, value, expected, overflow ) do { \ static const uint8_t addend_raw[] = addend; \ static const uint8_t value_raw[] = value; \ static const uint8_t expected_raw[] = expected; \ - uint8_t result_raw[ sizeof ( expected_raw ) ]; \ - unsigned int size = \ - bigint_required_size ( sizeof ( value_raw ) ); \ - unsigned int msb = ( 8 * sizeof ( value_raw ) ); \ - bigint_t ( size ) addend_temp; \ - bigint_t ( size ) value_temp; \ - int carry; \ - {} /* Fix emacs alignment */ \ - \ - assert ( bigint_size ( &addend_temp ) == \ - bigint_size ( &value_temp ) ); \ - bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ - bigint_init ( &addend_temp, addend_raw, \ - sizeof ( addend_raw ) ); \ - DBG ( "Add:\n" ); \ - DBG_HDA ( 0, &addend_temp, sizeof ( addend_temp ) ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - carry = bigint_add ( &addend_temp, &value_temp ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ - \ - ok ( memcmp ( result_raw, expected_raw, \ - sizeof ( result_raw ) ) == 0 ); \ - if ( sizeof ( result_raw ) < sizeof ( value_temp ) ) \ - carry += bigint_bit_is_set ( &value_temp, msb ); \ - ok ( carry == overflow ); \ - } while ( 0 ) + static struct bigint_test addend_test = \ + { addend_raw, sizeof ( addend_raw ) }; \ + static struct bigint_test value_test = \ + { value_raw, sizeof ( value_raw ) }; \ + static struct bigint_test expected_test = \ + { expected_raw, sizeof ( expected_raw ) }; \ + bigint_add_okx ( &addend_test, &value_test, &expected_test, \ + overflow, __FILE__, __LINE__ ); \ +} while ( 0 ) /** * Report result of big integer subtraction test @@ -285,35 +304,48 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * @v value Big integer to be subtracted from * @v expected Big integer expected result * @v underflow Expected result underflows range + * @v file Test code file + * @v line Test code line */ +static void bigint_subtract_okx ( struct bigint_test *subtrahend, + struct bigint_test *value, + struct bigint_test *expected, int underflow, + const char *file, unsigned int line ) { + uint8_t result_raw[ expected->len ]; + unsigned int size = bigint_required_size ( value->len ); + bigint_t ( size ) subtrahend_temp; + bigint_t ( size ) value_temp; + int borrow; + + assert ( bigint_size ( &subtrahend_temp ) == + bigint_size ( &value_temp ) ); + bigint_init ( &value_temp, value->raw, value->len ); + bigint_init ( &subtrahend_temp, subtrahend->raw, subtrahend->len ); + DBG ( "Subtract: 0x%s", bigint_ntoa ( &value_temp ) ); + DBG ( " - 0x%s", bigint_ntoa ( &subtrahend_temp ) ); + borrow = bigint_subtract ( &subtrahend_temp, &value_temp ); + DBG ( " = 0x%s%s\n", bigint_ntoa ( &value_temp ), + ( borrow ? " (borrow)" : "" ) ); + bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); + + okx ( memcmp ( result_raw, expected->raw, sizeof ( result_raw ) ) == 0, + file, line ); + okx ( borrow == underflow, file, line ); +} #define bigint_subtract_ok( subtrahend, value, expected, \ underflow ) do { \ static const uint8_t subtrahend_raw[] = subtrahend; \ static const uint8_t value_raw[] = value; \ static const uint8_t expected_raw[] = expected; \ - uint8_t result_raw[ sizeof ( expected_raw ) ]; \ - unsigned int size = \ - bigint_required_size ( sizeof ( value_raw ) ); \ - bigint_t ( size ) subtrahend_temp; \ - bigint_t ( size ) value_temp; \ - int borrow; \ - {} /* Fix emacs alignment */ \ - \ - assert ( bigint_size ( &subtrahend_temp ) == \ - bigint_size ( &value_temp ) ); \ - bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ - bigint_init ( &subtrahend_temp, subtrahend_raw, \ - sizeof ( subtrahend_raw ) ); \ - DBG ( "Subtract:\n" ); \ - DBG_HDA ( 0, &subtrahend_temp, sizeof ( subtrahend_temp ) ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - borrow = bigint_subtract ( &subtrahend_temp, &value_temp ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ - \ - ok ( memcmp ( result_raw, expected_raw, \ - sizeof ( result_raw ) ) == 0 ); \ - ok ( borrow == underflow ); \ + static struct bigint_test subtrahend_test = \ + { subtrahend_raw, sizeof ( subtrahend_raw ) }; \ + static struct bigint_test value_test = \ + { value_raw, sizeof ( value_raw ) }; \ + static struct bigint_test expected_test = \ + { expected_raw, sizeof ( expected_raw ) }; \ + bigint_subtract_okx ( &subtrahend_test, &value_test, \ + &expected_test, underflow, \ + __FILE__, __LINE__ ); \ } while ( 0 ) /** @@ -322,30 +354,39 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * @v value Big integer * @v expected Big integer expected result * @v bit Expected bit shifted out + * @v file Test code file + * @v line Test code line */ +static void bigint_shl_okx ( struct bigint_test *value, + struct bigint_test *expected, int bit, + const char *file, unsigned int line ) { + uint8_t result_raw[ expected->len ]; + unsigned int size = bigint_required_size ( value->len ); + unsigned int msb = ( 8 * value->len ); + bigint_t ( size ) value_temp; + int out; + + bigint_init ( &value_temp, value->raw, value->len ); + DBG ( "Shift left 0x%s << 1", bigint_ntoa ( &value_temp ) ); + out = bigint_shl ( &value_temp ); + DBG ( " = 0x%s (%d)\n", bigint_ntoa ( &value_temp ), out ); + bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); + + okx ( memcmp ( result_raw, expected->raw, sizeof ( result_raw ) ) == 0, + file, line ); + if ( sizeof ( result_raw ) < sizeof ( value_temp ) ) + out += bigint_bit_is_set ( &value_temp, msb ); + okx ( out == bit, file, line ); +} #define bigint_shl_ok( value, expected, bit ) do { \ static const uint8_t value_raw[] = value; \ static const uint8_t expected_raw[] = expected; \ - uint8_t result_raw[ sizeof ( expected_raw ) ]; \ - unsigned int size = \ - bigint_required_size ( sizeof ( value_raw ) ); \ - unsigned int msb = ( 8 * sizeof ( value_raw ) ); \ - bigint_t ( size ) value_temp; \ - int out; \ - {} /* Fix emacs alignment */ \ - \ - bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ - DBG ( "Shift left:\n" ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - out = bigint_shl ( &value_temp ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ - \ - ok ( memcmp ( result_raw, expected_raw, \ - sizeof ( result_raw ) ) == 0 ); \ - if ( sizeof ( result_raw ) < sizeof ( value_temp ) ) \ - out += bigint_bit_is_set ( &value_temp, msb ); \ - ok ( out == bit ); \ + static struct bigint_test value_test = \ + { value_raw, sizeof ( value_raw ) }; \ + static struct bigint_test expected_test = \ + { expected_raw, sizeof ( expected_raw ) }; \ + bigint_shl_okx ( &value_test, &expected_test, bit, \ + __FILE__, __LINE__ ); \ } while ( 0 ) /** @@ -354,27 +395,36 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * @v value Big integer * @v expected Big integer expected result * @v bit Expected bit shifted out + * @v file Test code file + * @v line Test code line */ +static void bigint_shr_okx ( struct bigint_test *value, + struct bigint_test *expected, int bit, + const char *file, unsigned int line ) { + uint8_t result_raw[ expected->len ]; + unsigned int size = bigint_required_size ( value->len ); + bigint_t ( size ) value_temp; + int out; + + bigint_init ( &value_temp, value->raw, value->len ); + DBG ( "Shift right 0x%s >> 1", bigint_ntoa ( &value_temp ) ); + out = bigint_shr ( &value_temp ); + DBG ( " = 0x%s (%d)\n", bigint_ntoa ( &value_temp ), out ); + bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); + + okx ( memcmp ( result_raw, expected->raw, sizeof ( result_raw ) ) == 0, + file, line ); + okx ( out == bit, file, line ); +} #define bigint_shr_ok( value, expected, bit ) do { \ static const uint8_t value_raw[] = value; \ static const uint8_t expected_raw[] = expected; \ - uint8_t result_raw[ sizeof ( expected_raw ) ]; \ - unsigned int size = \ - bigint_required_size ( sizeof ( value_raw ) ); \ - bigint_t ( size ) value_temp; \ - int out; \ - {} /* Fix emacs alignment */ \ - \ - bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ - DBG ( "Shift right:\n" ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - out = bigint_shr ( &value_temp ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bigint_done ( &value_temp, result_raw, sizeof ( result_raw ) ); \ - \ - ok ( memcmp ( result_raw, expected_raw, \ - sizeof ( result_raw ) ) == 0 ); \ - ok ( out == bit ); \ + static struct bigint_test value_test = \ + { value_raw, sizeof ( value_raw ) }; \ + static struct bigint_test expected_test = \ + { expected_raw, sizeof ( expected_raw ) }; \ + bigint_shr_okx ( &value_test, &expected_test, bit, \ + __FILE__, __LINE__ ); \ } while ( 0 ) /** @@ -382,21 +432,27 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * * @v value Big integer * @v expected Expected result + * @v file Test code file + * @v line Test code line */ +static void bigint_is_zero_okx ( struct bigint_test *value, int expected, + const char *file, unsigned int line ) { + unsigned int size = bigint_required_size ( value->len ); + bigint_t ( size ) value_temp; + int is_zero; + + bigint_init ( &value_temp, value->raw, value->len ); + DBG ( "Zero comparison: 0x%s", bigint_ntoa ( &value_temp ) ); + is_zero = bigint_is_zero ( &value_temp ); + DBG ( " %s 0\n", ( is_zero ? "==" : "!=" ) ); + okx ( ( !! is_zero ) == ( !! (expected) ), file, line ); +} #define bigint_is_zero_ok( value, expected ) do { \ static const uint8_t value_raw[] = value; \ - unsigned int size = \ - bigint_required_size ( sizeof ( value_raw ) ); \ - bigint_t ( size ) value_temp; \ - int is_zero; \ - {} /* Fix emacs alignment */ \ - \ - bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ - DBG ( "Zero comparison:\n" ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - is_zero = bigint_is_zero ( &value_temp ); \ - DBG ( "...is %szero\n", ( is_zero ? "" : "not " ) ); \ - ok ( ( !! is_zero ) == ( !! (expected) ) ); \ + static struct bigint_test value_test = \ + { value_raw, sizeof ( value_raw ) }; \ + bigint_is_zero_okx ( &value_test, expected, \ + __FILE__, __LINE__ ); \ } while ( 0 ) /** @@ -405,29 +461,37 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * @v value Big integer * @v reference Reference big integer * @v expected Expected result + * @v file Test code file + * @v line Test code line */ +static void bigint_is_geq_okx ( struct bigint_test *value, + struct bigint_test *reference, int expected, + const char *file, unsigned int line ) { + unsigned int size = bigint_required_size ( value->len ); + bigint_t ( size ) value_temp; + bigint_t ( size ) reference_temp; + int is_geq; + + assert ( bigint_size ( &reference_temp ) == + bigint_size ( &value_temp ) ); + bigint_init ( &value_temp, value->raw, value->len ); + bigint_init ( &reference_temp, reference->raw, reference->len ); + DBG ( "Greater-than-or-equal comparison: 0x%s", + bigint_ntoa ( &value_temp ) ); + is_geq = bigint_is_geq ( &value_temp, &reference_temp ); + DBG ( " %s 0x%s\n", ( is_geq ? ">=" : "<" ), + bigint_ntoa ( &reference_temp ) ); + okx ( ( !! is_geq ) == ( !! (expected) ), file, line ); +} #define bigint_is_geq_ok( value, reference, expected ) do { \ static const uint8_t value_raw[] = value; \ static const uint8_t reference_raw[] = reference; \ - unsigned int size = \ - bigint_required_size ( sizeof ( value_raw ) ); \ - bigint_t ( size ) value_temp; \ - bigint_t ( size ) reference_temp; \ - int is_geq; \ - {} /* Fix emacs alignment */ \ - \ - assert ( bigint_size ( &reference_temp ) == \ - bigint_size ( &value_temp ) ); \ - bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ - bigint_init ( &reference_temp, reference_raw, \ - sizeof ( reference_raw ) ); \ - DBG ( "Greater-than-or-equal comparison:\n" ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - DBG_HDA ( 0, &reference_temp, sizeof ( reference_temp ) ); \ - is_geq = bigint_is_geq ( &value_temp, &reference_temp ); \ - DBG ( "...is %sgreater than or equal\n", \ - ( is_geq ? "" : "not " ) ); \ - ok ( ( !! is_geq ) == ( !! (expected) ) ); \ + static struct bigint_test value_test = \ + { value_raw, sizeof ( value_raw ) }; \ + static struct bigint_test reference_test = \ + { reference_raw, sizeof ( reference_raw ) }; \ + bigint_is_geq_okx ( &value_test, &reference_test, expected, \ + __FILE__, __LINE__ ); \ } while ( 0 ) /** @@ -436,22 +500,28 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * @v value Big integer * @v bit Bit to test * @v expected Expected result + * @v file Test code file + * @v line Test code line */ +static void bigint_bit_is_set_okx ( struct bigint_test *value, + unsigned int bit, int expected, + const char *file, unsigned int line ) { + unsigned int size = bigint_required_size ( value->len ); + bigint_t ( size ) value_temp; + int bit_is_set; + + bigint_init ( &value_temp, value->raw, value->len ); + DBG ( "Bit set: 0x%s bit %d", bigint_ntoa ( &value_temp ), bit ); + bit_is_set = bigint_bit_is_set ( &value_temp, bit ); + DBG ( " is %sset\n", ( bit_is_set ? "" : "not " ) ); + okx ( ( !! bit_is_set ) == ( !! (expected) ), file, line ); +} #define bigint_bit_is_set_ok( value, bit, expected ) do { \ static const uint8_t value_raw[] = value; \ - unsigned int size = \ - bigint_required_size ( sizeof ( value_raw ) ); \ - bigint_t ( size ) value_temp; \ - int bit_is_set; \ - {} /* Fix emacs alignment */ \ - \ - bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ - DBG ( "Bit set:\n" ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - bit_is_set = bigint_bit_is_set ( &value_temp, bit ); \ - DBG ( "...bit %d is %sset\n", bit, \ - ( bit_is_set ? "" : "not " ) ); \ - ok ( ( !! bit_is_set ) == ( !! (expected) ) ); \ + static struct bigint_test value_test = \ + { value_raw, sizeof ( value_raw ) }; \ + bigint_bit_is_set_okx ( &value_test, bit, expected, \ + __FILE__, __LINE__ ); \ } while ( 0 ) /** @@ -459,21 +529,27 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * * @v value Big integer * @v expected Expected result + * @v file Test code file + * @v line Test code line */ +static void bigint_max_set_bit_okx ( struct bigint_test *value, int expected, + const char *file, unsigned int line ) { + unsigned int size = bigint_required_size ( value->len ); + bigint_t ( size ) value_temp; + int max_set_bit; + + bigint_init ( &value_temp, value->raw, value->len ); + DBG ( "Maximum set bit: 0x%s", bigint_ntoa ( &value_temp ) ); + max_set_bit = bigint_max_set_bit ( &value_temp ); + DBG ( " MSB is bit %d\n", ( max_set_bit - 1 ) ); + okx ( max_set_bit == expected, file, line ); +} #define bigint_max_set_bit_ok( value, expected ) do { \ static const uint8_t value_raw[] = value; \ - unsigned int size = \ - bigint_required_size ( sizeof ( value_raw ) ); \ - bigint_t ( size ) value_temp; \ - int max_set_bit; \ - {} /* Fix emacs alignment */ \ - \ - bigint_init ( &value_temp, value_raw, sizeof ( value_raw ) ); \ - DBG ( "Maximum set bit:\n" ); \ - DBG_HDA ( 0, &value_temp, sizeof ( value_temp ) ); \ - max_set_bit = bigint_max_set_bit ( &value_temp ); \ - DBG ( "...maximum set bit is bit %d\n", ( max_set_bit - 1 ) ); \ - ok ( max_set_bit == (expected) ); \ + static struct bigint_test value_test = \ + { value_raw, sizeof ( value_raw ) }; \ + bigint_max_set_bit_okx ( &value_test, expected, \ + __FILE__, __LINE__ ); \ } while ( 0 ) /** @@ -481,35 +557,46 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * * @v first Big integer to be conditionally swapped * @v second Big integer to be conditionally swapped + * @v file Test code file + * @v line Test code line */ +static void bigint_swap_okx ( struct bigint_test *first, + struct bigint_test *second, + const char *file, unsigned int line ) { + uint8_t temp[ first->len ]; + unsigned int size = bigint_required_size ( sizeof ( temp) ); + bigint_t ( size ) first_temp; + bigint_t ( size ) second_temp; + + assert ( first->len == sizeof ( temp ) ); + assert ( second->len == sizeof ( temp ) ); + bigint_init ( &first_temp, first->raw, first->len ); + bigint_init ( &second_temp, second->raw, second->len ); + bigint_swap ( &first_temp, &second_temp, 0 ); + bigint_done ( &first_temp, temp, sizeof ( temp ) ); + okx ( memcmp ( temp, first->raw, sizeof ( temp ) ) == 0, file, line ); + bigint_done ( &second_temp, temp, sizeof ( temp ) ); + okx ( memcmp ( temp, second->raw, sizeof ( temp ) ) == 0, file, line ); + bigint_swap ( &first_temp, &second_temp, 1 ); + bigint_done ( &first_temp, temp, sizeof ( temp ) ); + okx ( memcmp ( temp, second->raw, sizeof ( temp ) ) == 0, file, line ); + bigint_done ( &second_temp, temp, sizeof ( temp ) ); + okx ( memcmp ( temp, first->raw, sizeof ( temp ) ) == 0, file, line ); + bigint_swap ( &first_temp, &second_temp, 1 ); + bigint_done ( &first_temp, temp, sizeof ( temp ) ); + okx ( memcmp ( temp, first->raw, sizeof ( temp ) ) == 0, file, line ); + bigint_done ( &second_temp, temp, sizeof ( temp ) ); + okx ( memcmp ( temp, second->raw, sizeof ( temp ) ) == 0, file, line ); +} #define bigint_swap_ok( first, second ) do { \ static const uint8_t first_raw[] = first; \ static const uint8_t second_raw[] = second; \ - uint8_t temp[ sizeof ( first_raw ) ]; \ - unsigned int size = bigint_required_size ( sizeof ( temp) ); \ - bigint_t ( size ) first_temp; \ - bigint_t ( size ) second_temp; \ - {} /* Fix emacs alignment */ \ - \ - assert ( sizeof ( first_raw ) == sizeof ( temp ) ); \ - assert ( sizeof ( second_raw ) == sizeof ( temp ) ); \ - bigint_init ( &first_temp, first_raw, sizeof ( first_raw ) ); \ - bigint_init ( &second_temp, second_raw, sizeof ( second_raw ) );\ - bigint_swap ( &first_temp, &second_temp, 0 ); \ - bigint_done ( &first_temp, temp, sizeof ( temp ) ); \ - ok ( memcmp ( temp, first_raw, sizeof ( temp ) ) == 0 ); \ - bigint_done ( &second_temp, temp, sizeof ( temp ) ); \ - ok ( memcmp ( temp, second_raw, sizeof ( temp ) ) == 0 ); \ - bigint_swap ( &first_temp, &second_temp, 1 ); \ - bigint_done ( &first_temp, temp, sizeof ( temp ) ); \ - ok ( memcmp ( temp, second_raw, sizeof ( temp ) ) == 0 ); \ - bigint_done ( &second_temp, temp, sizeof ( temp ) ); \ - ok ( memcmp ( temp, first_raw, sizeof ( temp ) ) == 0 ); \ - bigint_swap ( &first_temp, &second_temp, 1 ); \ - bigint_done ( &first_temp, temp, sizeof ( temp ) ); \ - ok ( memcmp ( temp, first_raw, sizeof ( temp ) ) == 0 ); \ - bigint_done ( &second_temp, temp, sizeof ( temp ) ); \ - ok ( memcmp ( temp, second_raw, sizeof ( temp ) ) == 0 ); \ + static struct bigint_test first_test = \ + { first_raw, sizeof ( first_raw ) }; \ + static struct bigint_test second_test = \ + { second_raw, sizeof ( second_raw ) }; \ + bigint_swap_okx ( &first_test, &second_test, \ + __FILE__, __LINE__ ); \ } while ( 0 ) /** @@ -518,38 +605,49 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * @v multiplicand Big integer to be multiplied * @v multiplier Big integer to be multiplied * @v expected Big integer expected result + * @v file Test code file + * @v line Test code line */ +static void bigint_multiply_okx ( struct bigint_test *multiplicand, + struct bigint_test *multiplier, + struct bigint_test *expected, + const char *file, unsigned int line ) { + uint8_t result_raw[ expected->len ]; + unsigned int multiplicand_size = + bigint_required_size ( multiplicand->len ); + unsigned int multiplier_size = + bigint_required_size ( multiplier->len ); + bigint_t ( multiplicand_size ) multiplicand_temp; + bigint_t ( multiplier_size ) multiplier_temp; + bigint_t ( multiplicand_size + multiplier_size ) result_temp; + + assert ( bigint_size ( &result_temp ) == + ( bigint_size ( &multiplicand_temp ) + + bigint_size ( &multiplier_temp ) ) ); + bigint_init ( &multiplicand_temp, multiplicand->raw, + multiplicand->len ); + bigint_init ( &multiplier_temp, multiplier->raw, multiplier->len ); + DBG ( "Multiply 0x%s", bigint_ntoa ( &multiplicand_temp ) ); + DBG ( " * 0x%s", bigint_ntoa ( &multiplier_temp ) ); + bigint_multiply ( &multiplicand_temp, &multiplier_temp, &result_temp ); + DBG ( " = 0x%s\n", bigint_ntoa ( &result_temp ) ); + bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) ); + + okx ( memcmp ( result_raw, expected->raw, sizeof ( result_raw ) ) == 0, + file, line ); +} #define bigint_multiply_ok( multiplicand, multiplier, expected ) do { \ static const uint8_t multiplicand_raw[] = multiplicand; \ static const uint8_t multiplier_raw[] = multiplier; \ static const uint8_t expected_raw[] = expected; \ - uint8_t result_raw[ sizeof ( expected_raw ) ]; \ - unsigned int multiplicand_size = \ - bigint_required_size ( sizeof ( multiplicand_raw ) ); \ - unsigned int multiplier_size = \ - bigint_required_size ( sizeof ( multiplier_raw ) ); \ - bigint_t ( multiplicand_size ) multiplicand_temp; \ - bigint_t ( multiplier_size ) multiplier_temp; \ - bigint_t ( multiplicand_size + multiplier_size ) result_temp; \ - {} /* Fix emacs alignment */ \ - \ - assert ( bigint_size ( &result_temp ) == \ - ( bigint_size ( &multiplicand_temp ) + \ - bigint_size ( &multiplier_temp ) ) ); \ - bigint_init ( &multiplicand_temp, multiplicand_raw, \ - sizeof ( multiplicand_raw ) ); \ - bigint_init ( &multiplier_temp, multiplier_raw, \ - sizeof ( multiplier_raw ) ); \ - DBG ( "Multiply:\n" ); \ - DBG_HDA ( 0, &multiplicand_temp, sizeof ( multiplicand_temp ) );\ - DBG_HDA ( 0, &multiplier_temp, sizeof ( multiplier_temp ) ); \ - bigint_multiply ( &multiplicand_temp, &multiplier_temp, \ - &result_temp ); \ - DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ - bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\ - \ - ok ( memcmp ( result_raw, expected_raw, \ - sizeof ( result_raw ) ) == 0 ); \ + static struct bigint_test multiplicand_test = \ + { multiplicand_raw, sizeof ( multiplicand_raw ) }; \ + static struct bigint_test multiplier_test = \ + { multiplier_raw, sizeof ( multiplier_raw ) }; \ + static struct bigint_test expected_test = \ + { expected_raw, sizeof ( expected_raw ) }; \ + bigint_multiply_okx ( &multiplicand_test, &multiplier_test, \ + &expected_test, __FILE__, __LINE__ ); \ } while ( 0 ) /** @@ -557,31 +655,40 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * * @v modulus Big integer modulus * @v expected Big integer expected result + * @v file Test code file + * @v line Test code line */ +static void bigint_reduce_okx ( struct bigint_test *modulus, + struct bigint_test *expected, + const char *file, unsigned int line ) { + uint8_t result_raw[ expected->len ]; + unsigned int size = bigint_required_size ( modulus->len ); + bigint_t ( size ) modulus_temp; + bigint_t ( size ) result_temp; + + assert ( bigint_size ( &modulus_temp ) == + bigint_size ( &result_temp ) ); + assert ( sizeof ( result_temp ) == sizeof ( result_raw ) ); + bigint_init ( &modulus_temp, modulus->raw, modulus->len ); + DBG ( "Modular reduce (2^%zd)", ( 2 * 8 * sizeof ( modulus_temp ) ) ); + bigint_reduce ( &modulus_temp, &result_temp ); + DBG ( " = 0x%s", bigint_ntoa ( &result_temp ) ); + DBG ( " (mod 0x%s)\n", bigint_ntoa ( &modulus_temp ) ); + + bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) ); + + okx ( memcmp ( result_raw, expected->raw, sizeof ( result_raw ) ) == 0, + file, line ); +} #define bigint_reduce_ok( modulus, expected ) do { \ static const uint8_t modulus_raw[] = modulus; \ static const uint8_t expected_raw[] = expected; \ - uint8_t result_raw[ sizeof ( expected_raw ) ]; \ - unsigned int size = \ - bigint_required_size ( sizeof ( modulus_raw ) ); \ - bigint_t ( size ) modulus_temp; \ - bigint_t ( size ) result_temp; \ - {} /* Fix emacs alignment */ \ - \ - assert ( bigint_size ( &modulus_temp ) == \ - bigint_size ( &result_temp ) ); \ - assert ( sizeof ( result_temp ) == sizeof ( result_raw ) ); \ - bigint_init ( &modulus_temp, modulus_raw, \ - sizeof ( modulus_raw ) ); \ - DBG ( "Modular reduce R^2:\n" ); \ - DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ - bigint_reduce ( &modulus_temp, &result_temp ); \ - DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ - bigint_done ( &result_temp, result_raw, \ - sizeof ( result_raw ) ); \ - \ - ok ( memcmp ( result_raw, expected_raw, \ - sizeof ( result_raw ) ) == 0 ); \ + static struct bigint_test modulus_test = \ + { modulus_raw, sizeof ( modulus_raw ) }; \ + static struct bigint_test expected_test = \ + { expected_raw, sizeof ( expected_raw ) }; \ + bigint_reduce_okx ( &modulus_test, &expected_test, \ + __FILE__, __LINE__ ); \ } while ( 0 ) /** @@ -589,30 +696,38 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * * @v invertend Big integer to be inverted * @v expected Big integer expected result + * @v file Test code file + * @v line Test code line */ +static void bigint_mod_invert_okx ( struct bigint_test *invertend, + struct bigint_test *expected, + const char *file, unsigned int line ) { + uint8_t inverse_raw[ expected->len ]; + unsigned int invertend_size = bigint_required_size ( invertend->len ); + unsigned int inverse_size = + bigint_required_size ( sizeof ( inverse_raw ) ); + bigint_t ( invertend_size ) invertend_temp; + bigint_t ( inverse_size ) inverse_temp; + + bigint_init ( &invertend_temp, invertend->raw, invertend->len ); + DBG ( "Modular invert: 0x%s", bigint_ntoa ( &invertend_temp ) ); + bigint_mod_invert ( &invertend_temp, &inverse_temp ); + DBG ( " * 0x%s = 1 (mod 2^%zd)\n", bigint_ntoa ( &inverse_temp ), + ( 8 * sizeof ( inverse_raw ) ) ); + bigint_done ( &inverse_temp, inverse_raw, sizeof ( inverse_raw ) ); + + okx ( memcmp ( inverse_raw, expected->raw, + sizeof ( inverse_raw ) ) == 0, file, line ); +} #define bigint_mod_invert_ok( invertend, expected ) do { \ static const uint8_t invertend_raw[] = invertend; \ static const uint8_t expected_raw[] = expected; \ - uint8_t inverse_raw[ sizeof ( expected_raw ) ]; \ - unsigned int invertend_size = \ - bigint_required_size ( sizeof ( invertend_raw ) ); \ - unsigned int inverse_size = \ - bigint_required_size ( sizeof ( inverse_raw ) ); \ - bigint_t ( invertend_size ) invertend_temp; \ - bigint_t ( inverse_size ) inverse_temp; \ - {} /* Fix emacs alignment */ \ - \ - bigint_init ( &invertend_temp, invertend_raw, \ - sizeof ( invertend_raw ) ); \ - DBG ( "Modular invert:\n" ); \ - DBG_HDA ( 0, &invertend_temp, sizeof ( invertend_temp ) ); \ - bigint_mod_invert ( &invertend_temp, &inverse_temp ); \ - DBG_HDA ( 0, &inverse_temp, sizeof ( inverse_temp ) ); \ - bigint_done ( &inverse_temp, inverse_raw, \ - sizeof ( inverse_raw ) ); \ - \ - ok ( memcmp ( inverse_raw, expected_raw, \ - sizeof ( inverse_raw ) ) == 0 ); \ + static struct bigint_test invertend_test = \ + { invertend_raw, sizeof ( invertend_raw ) }; \ + static struct bigint_test expected_test = \ + { expected_raw, sizeof ( expected_raw ) }; \ + bigint_mod_invert_okx ( &invertend_test, &expected_test, \ + __FILE__, __LINE__ ); \ } while ( 0 ) /** @@ -621,34 +736,44 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * @v modulus Big integer modulus * @v mont Big integer Montgomery product * @v expected Big integer expected result + * @v file Test code file + * @v line Test code line */ +static void bigint_montgomery_okx ( struct bigint_test *modulus, + struct bigint_test *mont, + struct bigint_test *expected, + const char *file, unsigned int line ) { + uint8_t result_raw[ expected->len ]; + unsigned int size = bigint_required_size ( modulus->len ); + bigint_t ( size ) modulus_temp; + bigint_t ( 2 * size ) mont_temp; + bigint_t ( size ) result_temp; + + assert ( ( modulus->len % sizeof ( bigint_element_t ) ) == 0 ); + bigint_init ( &modulus_temp, modulus->raw, modulus->len ); + bigint_init ( &mont_temp, mont->raw, mont->len ); + DBG ( "Montgomery 0x%s", bigint_ntoa ( &mont_temp ) ); + bigint_montgomery ( &modulus_temp, &mont_temp, &result_temp ); + DBG ( " = 0x%s * (2 ^ %zd)", bigint_ntoa ( &result_temp ), + ( 8 * sizeof ( modulus_temp ) ) ); + DBG ( " (mod 0x%s)\n", bigint_ntoa ( &modulus_temp ) ); + bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) ); + + okx ( memcmp ( result_raw, expected->raw, sizeof ( result_raw ) ) == 0, + file, line ); +} #define bigint_montgomery_ok( modulus, mont, expected ) do { \ static const uint8_t modulus_raw[] = modulus; \ static const uint8_t mont_raw[] = mont; \ static const uint8_t expected_raw[] = expected; \ - uint8_t result_raw[ sizeof ( expected_raw ) ]; \ - unsigned int size = \ - bigint_required_size ( sizeof ( modulus_raw ) ); \ - bigint_t ( size ) modulus_temp; \ - bigint_t ( 2 * size ) mont_temp; \ - bigint_t ( size ) result_temp; \ - {} /* Fix emacs alignment */ \ - \ - assert ( ( sizeof ( modulus_raw ) % \ - sizeof ( bigint_element_t ) ) == 0 ); \ - bigint_init ( &modulus_temp, modulus_raw, \ - sizeof ( modulus_raw ) ); \ - bigint_init ( &mont_temp, mont_raw, sizeof ( mont_raw ) ); \ - DBG ( "Montgomery:\n" ); \ - DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ - DBG_HDA ( 0, &mont_temp, sizeof ( mont_temp ) ); \ - bigint_montgomery ( &modulus_temp, &mont_temp, &result_temp ); \ - DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ - bigint_done ( &result_temp, result_raw, \ - sizeof ( result_raw ) ); \ - \ - ok ( memcmp ( result_raw, expected_raw, \ - sizeof ( result_raw ) ) == 0 ); \ + static struct bigint_test modulus_test = \ + { modulus_raw, sizeof ( modulus_raw ) }; \ + static struct bigint_test mont_test = \ + { mont_raw, sizeof ( mont_raw ) }; \ + static struct bigint_test expected_test = \ + { expected_raw, sizeof ( expected_raw ) }; \ + bigint_montgomery_okx ( &modulus_test, &mont_test, \ + &expected_test, __FILE__, __LINE__ ); \ } while ( 0 ) /** @@ -658,45 +783,56 @@ void bigint_mod_exp_sample ( const bigint_element_t *base0, * @v modulus Big integer modulus * @v exponent Big integer exponent * @v expected Big integer expected result + * @v file Test code file + * @v line Test code line */ +static void bigint_mod_exp_okx ( struct bigint_test *base, + struct bigint_test *modulus, + struct bigint_test *exponent, + struct bigint_test *expected, + const char *file, unsigned int line ) { + uint8_t result_raw[ expected->len ]; + unsigned int size = bigint_required_size ( base->len ); + unsigned int exponent_size = bigint_required_size ( exponent->len ); + bigint_t ( size ) base_temp; + bigint_t ( size ) modulus_temp; + bigint_t ( exponent_size ) exponent_temp; + bigint_t ( size ) result_temp; + size_t tmp_len = bigint_mod_exp_tmp_len ( &modulus_temp ); + uint8_t tmp[tmp_len]; + + assert ( bigint_size ( &modulus_temp ) == bigint_size ( &base_temp ) ); + assert ( bigint_size ( &modulus_temp ) == + bigint_size ( &result_temp ) ); + bigint_init ( &base_temp, base->raw, base->len ); + bigint_init ( &modulus_temp, modulus->raw, modulus->len ); + bigint_init ( &exponent_temp, exponent->raw, exponent->len ); + DBG ( "Modular exponentiation: 0x%s", bigint_ntoa ( &base_temp ) ); + DBG ( " ^ 0x%s", bigint_ntoa ( &exponent_temp ) ); + bigint_mod_exp ( &base_temp, &modulus_temp, &exponent_temp, + &result_temp, tmp ); + DBG ( " = 0x%s", bigint_ntoa ( &result_temp ) ); + DBG ( " (mod 0x%s)\n", bigint_ntoa ( &modulus_temp ) ); + bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) ); + + okx ( memcmp ( result_raw, expected->raw, sizeof ( result_raw ) ) == 0, + file, line ); +} #define bigint_mod_exp_ok( base, modulus, exponent, expected ) do { \ static const uint8_t base_raw[] = base; \ static const uint8_t modulus_raw[] = modulus; \ static const uint8_t exponent_raw[] = exponent; \ static const uint8_t expected_raw[] = expected; \ - uint8_t result_raw[ sizeof ( expected_raw ) ]; \ - unsigned int size = \ - bigint_required_size ( sizeof ( base_raw ) ); \ - unsigned int exponent_size = \ - bigint_required_size ( sizeof ( exponent_raw ) ); \ - bigint_t ( size ) base_temp; \ - bigint_t ( size ) modulus_temp; \ - bigint_t ( exponent_size ) exponent_temp; \ - bigint_t ( size ) result_temp; \ - size_t tmp_len = bigint_mod_exp_tmp_len ( &modulus_temp ); \ - uint8_t tmp[tmp_len]; \ - {} /* Fix emacs alignment */ \ - \ - assert ( bigint_size ( &modulus_temp ) == \ - bigint_size ( &base_temp ) ); \ - assert ( bigint_size ( &modulus_temp ) == \ - bigint_size ( &result_temp ) ); \ - bigint_init ( &base_temp, base_raw, sizeof ( base_raw ) ); \ - bigint_init ( &modulus_temp, modulus_raw, \ - sizeof ( modulus_raw ) ); \ - bigint_init ( &exponent_temp, exponent_raw, \ - sizeof ( exponent_raw ) ); \ - DBG ( "Modular exponentiation:\n" ); \ - DBG_HDA ( 0, &base_temp, sizeof ( base_temp ) ); \ - DBG_HDA ( 0, &modulus_temp, sizeof ( modulus_temp ) ); \ - DBG_HDA ( 0, &exponent_temp, sizeof ( exponent_temp ) ); \ - bigint_mod_exp ( &base_temp, &modulus_temp, &exponent_temp, \ - &result_temp, tmp ); \ - DBG_HDA ( 0, &result_temp, sizeof ( result_temp ) ); \ - bigint_done ( &result_temp, result_raw, sizeof ( result_raw ) );\ - \ - ok ( memcmp ( result_raw, expected_raw, \ - sizeof ( result_raw ) ) == 0 ); \ + static struct bigint_test base_test = \ + { base_raw, sizeof ( base_raw ) }; \ + static struct bigint_test modulus_test = \ + { modulus_raw, sizeof ( modulus_raw ) }; \ + static struct bigint_test exponent_test = \ + { exponent_raw, sizeof ( exponent_raw ) }; \ + static struct bigint_test expected_test = \ + { expected_raw, sizeof ( expected_raw ) }; \ + bigint_mod_exp_okx ( &base_test, &modulus_test, &exponent_test, \ + &expected_test, __FILE__, __LINE__ ); \ } while ( 0 ) /** -- cgit v1.2.3-55-g7522 From 7c39c04a537ce29dccc6f2bae9749d1d371429c1 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Mon, 29 Dec 2025 14:01:46 +0000 Subject: [crypto] Allow for zero-length big integer literals Ensure that zero-length big integer literals are treated as containing a zero value. Avoid tests on every big integer arithmetic operation by ensuring that bigint_required_size() always returns a non-zero value: the zero-length tests can therefore be restricted to only bigint_init() and bigint_done(). Signed-off-by: Michael Brown --- src/arch/x86/include/bits/bigint.h | 8 ++++++-- src/include/ipxe/bigint.h | 4 ++-- src/tests/bigint_test.c | 7 +++++++ 3 files changed, 15 insertions(+), 4 deletions(-) (limited to 'src/tests') diff --git a/src/arch/x86/include/bits/bigint.h b/src/arch/x86/include/bits/bigint.h index 4bab3ebf7..c6f097a34 100644 --- a/src/arch/x86/include/bits/bigint.h +++ b/src/arch/x86/include/bits/bigint.h @@ -32,10 +32,12 @@ bigint_init_raw ( uint32_t *value0, unsigned int size, long discard_c; /* Copy raw data in reverse order, padding with zeros */ - __asm__ __volatile__ ( "\n1:\n\t" + __asm__ __volatile__ ( "jecxz 2f\n\t" + "\n1:\n\t" "movb -1(%3,%1), %%al\n\t" "stosb\n\t" "loop 1b\n\t" + "\n2:\n\t" "xorl %%eax, %%eax\n\t" "mov %4, %1\n\t" "rep stosb\n\t" @@ -308,10 +310,12 @@ bigint_done_raw ( const uint32_t *value0, unsigned int size __unused, long discard_c; /* Copy raw data in reverse order */ - __asm__ __volatile__ ( "\n1:\n\t" + __asm__ __volatile__ ( "jecxz 2f\n\t" + "\n1:\n\t" "movb -1(%3,%1), %%al\n\t" "stosb\n\t" "loop 1b\n\t" + "\n2:\n\t" : "=&D" ( discard_D ), "=&c" ( discard_c ), "+m" ( *out_bytes ) : "r" ( value0 ), "0" ( out ), "1" ( len ) diff --git a/src/include/ipxe/bigint.h b/src/include/ipxe/bigint.h index 396462f33..9eab89d25 100644 --- a/src/include/ipxe/bigint.h +++ b/src/include/ipxe/bigint.h @@ -28,8 +28,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); * @ret size Number of elements */ #define bigint_required_size( len ) \ - ( ( (len) + sizeof ( bigint_element_t ) - 1 ) / \ - sizeof ( bigint_element_t ) ) + ( (len) ? ( ( (len) + sizeof ( bigint_element_t ) - 1 ) / \ + sizeof ( bigint_element_t ) ) : 1 ) /** * Determine number of elements in big-integer type diff --git a/src/tests/bigint_test.c b/src/tests/bigint_test.c index 4090494ae..b3ad02ea2 100644 --- a/src/tests/bigint_test.c +++ b/src/tests/bigint_test.c @@ -841,6 +841,7 @@ static void bigint_mod_exp_okx ( struct bigint_test *base, */ static void bigint_test_exec ( void ) { + bigint_add_ok ( BIGINT(), BIGINT(), BIGINT(), 0 ); bigint_add_ok ( BIGINT ( 0x8a ), BIGINT ( 0x43 ), BIGINT ( 0xcd ), 0 ); @@ -934,6 +935,7 @@ static void bigint_test_exec ( void ) { 0x9f, 0x60, 0x58, 0xff, 0xb6, 0x76, 0x45, 0xe6, 0xed, 0x61, 0x8d, 0xe6, 0xc0, 0x72, 0x1c, 0x07 ), 0 ); + bigint_subtract_ok ( BIGINT(), BIGINT(), BIGINT(), 0 ); bigint_subtract_ok ( BIGINT ( 0x83 ), BIGINT ( 0x50 ), BIGINT ( 0xcd ), 1 ); @@ -1033,6 +1035,7 @@ static void bigint_test_exec ( void ) { 0xda, 0xc8, 0x8c, 0x71, 0x86, 0x97, 0x7f, 0xcb, 0x94, 0x31, 0x1d, 0xbc, 0x44, 0x1a ), 0 ); + bigint_shl_ok ( BIGINT(), BIGINT(), 0 ); bigint_shl_ok ( BIGINT ( 0xe0 ), BIGINT ( 0xc0 ), 1 ); bigint_shl_ok ( BIGINT ( 0x43, 0x1d ), @@ -1099,6 +1102,7 @@ static void bigint_test_exec ( void ) { 0x49, 0x7c, 0x1e, 0xdb, 0xc7, 0x65, 0xa6, 0x0e, 0xd1, 0xd2, 0x00, 0xb3, 0x41, 0xc9, 0x3c, 0xbc ), 0 ); + bigint_shr_ok ( BIGINT(), BIGINT(), 0 ); bigint_shr_ok ( BIGINT ( 0x8f ), BIGINT ( 0x47 ), 1 ); bigint_shr_ok ( BIGINT ( 0xaa, 0x1d ), @@ -1165,6 +1169,7 @@ static void bigint_test_exec ( void ) { 0x46, 0xa8, 0x94, 0xb0, 0xf7, 0xa4, 0x57, 0x1f, 0x72, 0x88, 0x5f, 0xed, 0x4d, 0xc9, 0x59, 0xbb ), 1 ); + bigint_is_zero_ok ( BIGINT(), 1 ); bigint_is_zero_ok ( BIGINT ( 0x9b ), 0 ); bigint_is_zero_ok ( BIGINT ( 0x5a, 0x9d ), @@ -1273,6 +1278,7 @@ static void bigint_test_exec ( void ) { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ), 0 ); + bigint_is_geq_ok ( BIGINT(), BIGINT(), 1 ); bigint_is_geq_ok ( BIGINT ( 0xa2 ), BIGINT ( 0x58 ), 1 ); @@ -1540,6 +1546,7 @@ static void bigint_test_exec ( void ) { 0x83, 0xf8, 0xa2, 0x11, 0xf5, 0xd4, 0xcb, 0xe0 ), 1013, 0 ); + bigint_max_set_bit_ok ( BIGINT(), 0 ); bigint_max_set_bit_ok ( BIGINT ( 0x3a ), 6 ); bigint_max_set_bit_ok ( BIGINT ( 0x03 ), -- cgit v1.2.3-55-g7522