diff options
Diffstat (limited to 'g10/sign.c')
-rw-r--r-- | g10/sign.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/g10/sign.c b/g10/sign.c index 6192d5987..2aa9468e9 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -650,4 +650,112 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile ) } +/**************** + * Create a signature packet for the given public key certificate + * and the user id and return it in ret_sig. User signature class SIGCLASS + * user-id is not used (and may be NULL if sigclass is 0x20) + * If digest_algo is 0 the function selects an appropriate one. + */ +int +make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk, + PKT_user_id *uid, PKT_public_key *subpk, + PKT_secret_key *sk, + int sigclass, int digest_algo, + int (*mksubpkt)(PKT_signature *, void *), void *opaque + ) +{ + PKT_signature *sig; + int rc=0; + MD_HANDLE md; + + assert( (sigclass >= 0x10 && sigclass <= 0x13) + || sigclass == 0x20 || sigclass == 0x18 ); + if( !digest_algo ) { + switch( sk->pubkey_algo ) { + case PUBKEY_ALGO_DSA: digest_algo = DIGEST_ALGO_SHA1; break; + case PUBKEY_ALGO_RSA_S: + case PUBKEY_ALGO_RSA: digest_algo = DIGEST_ALGO_MD5; break; + default: digest_algo = DIGEST_ALGO_RMD160; break; + } + } + md = md_open( digest_algo, 0 ); + + /* hash the public key certificate and the user id */ + hash_public_key( md, pk ); + if( sigclass == 0x18 ) { /* subkey binding */ + hash_public_key( md, subpk ); + } + else if( sigclass != 0x20 ) { + if( sk->version >=4 ) { + byte buf[5]; + buf[0] = 0xb4; /* indicates a userid packet */ + buf[1] = uid->len >> 24; /* always use 4 length bytes */ + buf[2] = uid->len >> 16; + buf[3] = uid->len >> 8; + buf[4] = uid->len; + md_write( md, buf, 5 ); + } + md_write( md, uid->name, uid->len ); + } + /* and make the signature packet */ + sig = m_alloc_clear( sizeof *sig ); + sig->version = sk->version; + keyid_from_sk( sk, sig->keyid ); + sig->pubkey_algo = sk->pubkey_algo; + sig->digest_algo = digest_algo; + sig->timestamp = make_timestamp(); + sig->sig_class = sigclass; + if( sig->version >= 4 ) + build_sig_subpkt_from_sig( sig ); + + if( sig->version >= 4 && mksubpkt ) + rc = (*mksubpkt)( sig, opaque ); + + if( !rc ) { + if( sig->version >= 4 ) + md_putc( md, sig->version ); + md_putc( md, sig->sig_class ); + if( sig->version < 4 ) { + u32 a = sig->timestamp; + md_putc( md, (a >> 24) & 0xff ); + md_putc( md, (a >> 16) & 0xff ); + md_putc( md, (a >> 8) & 0xff ); + md_putc( md, a & 0xff ); + } + else { + byte buf[6]; + size_t n; + + md_putc( md, sig->pubkey_algo ); + md_putc( md, sig->digest_algo ); + if( sig->hashed_data ) { + n = (sig->hashed_data[0] << 8) | sig->hashed_data[1]; + md_write( md, sig->hashed_data, n+2 ); + n += 6; + } + else + n = 6; + /* add some magic */ + buf[0] = sig->version; + buf[1] = 0xff; + buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */ + buf[3] = n >> 16; + buf[4] = n >> 8; + buf[5] = n; + md_write( md, buf, 6 ); + + } + md_final(md); + + rc = complete_sig( sig, sk, md ); + } + + md_close( md ); + if( rc ) + free_seckey_enc( sig ); + else + *ret_sig = sig; + return rc; +} + |