mirror of
https://github.com/ipxe/ipxe.git
synced 2026-01-21 08:31:37 +01:00
[crypto] Construct signatures using ASN.1 builders
Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
parent
8cd963ab96
commit
d4258272c6
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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:
|
||||
free ( raw.data );
|
||||
err_grow:
|
||||
free ( tbs.data );
|
||||
err_tbs:
|
||||
free ( spki.data );
|
||||
err_spki:
|
||||
free ( raw.data );
|
||||
free ( tbs.data );
|
||||
free ( spki.data );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
} __attribute__ (( packed )) header;
|
||||
|
||||
/* 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 ) );
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -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,
|
||||
&cursor ) != 0, file, line );
|
||||
asn1_built ( &signature ) ) == 0, file, line );
|
||||
*bad ^= 0x40;
|
||||
okx ( pubkey_verify ( pubkey, &test->public, digest, digestout,
|
||||
asn1_built ( &signature ) ) != 0, file, line );
|
||||
|
||||
/* Free signature */
|
||||
free ( signature.data );
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user