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;
}
* @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",
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;
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 */
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,
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;
}
* @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
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 );
}
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,
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 */
}
}
- /* 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;
}
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 );
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 );
}