From: Michael Brown Date: Mon, 1 Dec 2025 16:02:54 +0000 (+0000) Subject: [crypto] Construct signatures using ASN.1 builders X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d4258272c679c8bd42430fc2df57402cdc03d711;p=thirdparty%2Fipxe.git [crypto] Construct signatures using ASN.1 builders Signed-off-by: Michael Brown --- 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 ); }