aboutsummaryrefslogtreecommitdiffstats
path: root/g10/sign.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/sign.c')
-rw-r--r--g10/sign.c108
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;
+}
+