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(-) 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