Skip to content
This repository has been archived by the owner on Aug 29, 2024. It is now read-only.

Commit

Permalink
[crypto] Pass asymmetric keys as ASN.1 cursors
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
mcb30 committed Aug 18, 2024
1 parent 950f6b5 commit 53f089b
Show file tree
Hide file tree
Showing 10 changed files with 74 additions and 112 deletions.
3 changes: 1 addition & 2 deletions src/crypto/cms.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 2 additions & 2 deletions src/crypto/crypto_null.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
4 changes: 2 additions & 2 deletions src/crypto/ocsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
30 changes: 7 additions & 23 deletions src/crypto/rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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 */
Expand Down
9 changes: 4 additions & 5 deletions src/crypto/x509.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 );
}

Expand Down
3 changes: 1 addition & 2 deletions src/drivers/net/iphone.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
23 changes: 10 additions & 13 deletions src/include/ipxe/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdint.h>
#include <stddef.h>
#include <assert.h>
#include <ipxe/asn1.h>

/** A message digest algorithm */
struct digest_algorithm {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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 );
Expand Down
5 changes: 2 additions & 3 deletions src/net/tls.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
37 changes: 14 additions & 23 deletions src/tests/pubkey_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 ]; \
Expand All @@ -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 ]; \
Expand All @@ -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 )
Expand All @@ -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 ]; \
Expand All @@ -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 ]; \
Expand All @@ -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 ]; \
Expand All @@ -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 ); \
Expand All @@ -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 ]; \
Expand All @@ -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 ); \
Expand Down
Loading

0 comments on commit 53f089b

Please sign in to comment.