* packet.h, main.h, sig-check.c (signature_check2, check_key_signature2,
[gnupg.git] / g10 / sign.c
index ac6f077..73286fc 100644 (file)
@@ -1,5 +1,6 @@
 /* sign.c - sign data
- * Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002,
+ *               2003 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 
 
 #ifdef HAVE_DOSISH_SYSTEM
-  #define LF "\r\n"
-  void __stdcall Sleep(ulong);
-  #define sleep(a)  Sleep((a)*1000)
+#define LF "\r\n"
+void __stdcall Sleep(ulong);
+#define sleep(a)  Sleep((a)*1000)
 #else
-  #define LF "\n"
+#define LF "\n"
 #endif
 
 static int recipient_digest_algo=0;
@@ -122,8 +123,8 @@ mk_notation_and_policy( PKT_signature *sig,
        m_free(buf);
     }
 
-    if(opt.show_notation)
-      show_notation(sig,0);
+    if(opt.list_options&LIST_SHOW_NOTATION)
+      show_notation(sig,0,0);
 
     /* set policy URL */
     if( IS_SIG(sig) && opt.sig_policy_url )
@@ -160,8 +161,8 @@ mk_notation_and_policy( PKT_signature *sig,
        m_free(s);
       }
 
-    if(opt.show_policy_url)
-      show_policy_url(sig,0);
+    if(opt.list_options&LIST_SHOW_POLICY)
+      show_policy_url(sig,0,0);
 }
 
 
@@ -308,9 +309,11 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig,
        log_error(_("signing failed: %s\n"), g10_errstr(rc) );
     else {
        if( opt.verbose ) {
-           char *ustr = get_user_id_string( sig->keyid );
-           log_info(_("%s signature from: %s\n"),
-                     pubkey_algo_to_string(sk->pubkey_algo), ustr );
+           char *ustr = get_user_id_string_printable (sig->keyid);
+           log_info(_("%s/%s signature from: \"%s\"\n"),
+                    pubkey_algo_to_string(sk->pubkey_algo),
+                    digest_algo_to_string(sig->digest_algo),
+                    ustr );
            m_free(ustr);
        }
     }
@@ -332,14 +335,38 @@ complete_sig( PKT_signature *sig, PKT_secret_key *sk, MD_HANDLE md )
 static int
 hash_for(int pubkey_algo, int packet_version )
 {
-    if( opt.def_digest_algo )
-       return opt.def_digest_algo;
-    if( recipient_digest_algo )
-        return recipient_digest_algo;
-    if( pubkey_algo == PUBKEY_ALGO_DSA )
-       return DIGEST_ALGO_SHA1;
-    if( pubkey_algo == PUBKEY_ALGO_RSA && packet_version < 4 )
-       return DIGEST_ALGO_MD5;
+  if( opt.def_digest_algo )
+    return opt.def_digest_algo;
+  else if( recipient_digest_algo )
+    return recipient_digest_algo;
+  else if(PGP2 && pubkey_algo == PUBKEY_ALGO_RSA && packet_version < 4 )
+    {
+      /* Old-style PGP only understands MD5 */
+      return DIGEST_ALGO_MD5;
+    }
+  else if( pubkey_algo == PUBKEY_ALGO_DSA )
+    {
+      /* We need a 160-bit hash for DSA, so we can't just take the first
+        in the pref list */
+
+      if(opt.personal_digest_prefs)
+       {
+         prefitem_t *prefs;
+
+         for(prefs=opt.personal_digest_prefs;prefs->type;prefs++)
+           if(md_digest_length(prefs->value)==20)
+             return prefs->value;
+       }
+
+      return DIGEST_ALGO_SHA1;
+    }
+  else if( opt.personal_digest_prefs )
+    {
+      /* It's not DSA, so we can use whatever the first hash algorithm
+        is in the pref list */
+      return opt.personal_digest_prefs[0].value;
+    }
+  else
     return DEFAULT_DIGEST_ALGO;
 }
 
@@ -443,7 +470,8 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
     if (!opt.no_literal) {
         if (fname || opt.set_filename) {
             char *s = make_basename (opt.set_filename? opt.set_filename
-                                                     : fname);
+                                                     : fname,
+                                     iobuf_get_real_fname(inp));
             pt = m_alloc (sizeof *pt + strlen(s) - 1);
             pt->namelen = strlen (s);
             memcpy (pt->name, s, pt->namelen);
@@ -456,7 +484,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
     }
 
     /* try to calculate the length of the data */
-    if (fname) {
+    if (fname && *fname && !(*fname=='-' && !fname[1])) {
         if( !(filesize = iobuf_get_filelength(inp)) )
             log_info (_("WARNING: `%s' is an empty file\n"), fname);
 
@@ -483,7 +511,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
         pt->timestamp = make_timestamp ();
         pt->mode = ptmode;
         pt->len = filesize;
-        pt->new_ctb = !pt->len && !opt.rfc1991;
+        pt->new_ctb = !pt->len && !RFC1991;
         pt->buf = inp;
         init_packet(&pkt);
         pkt.pkttype = PKT_PLAINTEXT;
@@ -505,7 +533,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
                            g10_errstr(rc));
                 break;
             }
-        memset(copy_buffer, 0, 4096); /* burn buffer */
+        wipememory(copy_buffer,4096); /* burn buffer */
     }
     /* fixme: it seems that we never freed pt/pkt */
     
@@ -534,7 +562,7 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, MD_HANDLE hash,
 
        /* build the signature packet */
        sig = m_alloc_clear (sizeof *sig);
-       if(opt.force_v3_sigs || opt.rfc1991)
+       if(opt.force_v3_sigs || RFC1991)
          sig->version=3;
        else if(duration || opt.sig_policy_url || opt.sig_notation_data)
          sig->version=4;
@@ -606,6 +634,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
     compress_filter_context_t zfx;
     md_filter_context_t mfx;
     text_filter_context_t tfx;
+    progress_filter_context_t pfx;
     encrypt_filter_context_t efx;
     IOBUF inp = NULL, out = NULL;
     PACKET pkt;
@@ -614,12 +643,11 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
     SK_LIST sk_list = NULL;
     SK_LIST sk_rover = NULL;
     int multifile = 0;
-    u32 timestamp=0,duration=0;
+    u32 duration=0;
 
     memset( &afx, 0, sizeof afx);
     memset( &zfx, 0, sizeof zfx);
     memset( &mfx, 0, sizeof mfx);
-    memset( &tfx, 0, sizeof tfx);
     memset( &efx, 0, sizeof efx);
     init_packet( &pkt );
 
@@ -633,18 +661,17 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
     if( fname && filenames->next && (!detached || encryptflag) )
        log_bug("multiple files can only be detached signed");
 
-    if(opt.ask_sig_expire && !opt.force_v3_sigs && !opt.batch && !opt.rfc1991)
+    if(opt.ask_sig_expire && !opt.force_v3_sigs && !opt.batch && !RFC1991)
       duration=ask_expire_interval(1);
 
     if( (rc=build_sk_list( locusr, &sk_list, 1, PUBKEY_USAGE_SIG )) )
        goto leave;
 
-    if(opt.pgp2 && !only_old_style(sk_list))
+    if(PGP2 && !only_old_style(sk_list))
       {
        log_info(_("you can only detach-sign with PGP 2.x style keys "
                   "while in --pgp2 mode\n"));
-       log_info(_("this message may not be usable by %s\n"),"PGP 2.x");
-       opt.pgp2=0;
+       compliance_failure();
       }
 
     if(encryptflag && (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC )))
@@ -653,11 +680,15 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
     /* prepare iobufs */
     if( multifile )  /* have list of filenames */
        inp = NULL; /* we do it later */
-    else if( !(inp = iobuf_open(fname)) ) {
-       log_error("can't open %s: %s\n", fname? fname: "[stdin]",
-                                       strerror(errno) );
-       rc = G10ERR_OPEN_FILE;
-       goto leave;
+    else {
+        if( !(inp = iobuf_open(fname)) ) {
+           log_error("can't open %s: %s\n", fname? fname: "[stdin]",
+                     strerror(errno) );
+           rc = G10ERR_OPEN_FILE;
+           goto leave;
+       }
+
+        handle_progress (&pfx, inp, fname);
     }
 
     if( outfile ) {
@@ -673,8 +704,12 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
        goto leave;
 
     /* prepare to calculate the MD over the input */
-    if( opt.textmode && !outfile )
+    if( opt.textmode && !outfile && !multifile )
+      {
+       memset( &tfx, 0, sizeof tfx);
        iobuf_push_filter( inp, text_filter, &tfx );
+      }
+
     mfx.md = md_open(0, 0);
 
    /* If we're encrypting and signing, it is reasonable to pick the
@@ -709,7 +744,8 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
                hashlen=20;
 
            if((algo=
-               select_algo_from_prefs(pk_list,PREFTYPE_HASH,-1,&hashlen))>0)
+               select_algo_from_prefs(pk_list,PREFTYPE_HASH,-1,
+                                      hashlen?&hashlen:NULL))>0)
              recipient_digest_algo=algo;
          }
       }
@@ -722,7 +758,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
     if( !multifile )
        iobuf_push_filter( inp, md_filter, &mfx );
 
-    if( detached && !encryptflag && !opt.rfc1991 )
+    if( detached && !encryptflag && !RFC1991 )
        afx.what = 2;
 
     if( opt.armor && !outfile  )
@@ -750,11 +786,11 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
  
            if((compr_algo=
                select_algo_from_prefs(pk_list,PREFTYPE_ZIP,-1,NULL))==-1)
-             compr_algo=DEFAULT_COMPRESS_ALGO;
+             compr_algo=default_compress_algo();
          }
-       else if(!opt.expert &&
-               select_algo_from_prefs(pk_list,PREFTYPE_ZIP,
-                                      compr_algo,NULL)!=compr_algo)
+       else if(!opt.expert && pk_list
+               && select_algo_from_prefs(pk_list,PREFTYPE_ZIP,
+                                         compr_algo,NULL)!=compr_algo)
          log_info(_("forcing compression algorithm %s (%d) "
                     "violates recipient preferences\n"),
                   compress_algo_to_string(compr_algo),compr_algo);
@@ -768,7 +804,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
       }
 
     /* Write the one-pass signature packets if needed */
-    if (!detached && !opt.rfc1991) {
+    if (!detached && !RFC1991) {
         rc = write_onepass_sig_packets (sk_list, out,
                                         opt.textmode && !outfile ? 0x01:0x00);
         if (rc)
@@ -791,8 +827,14 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
                    rc = G10ERR_OPEN_FILE;
                    goto leave;
                }
+                handle_progress (&pfx, inp, sl->d);
                if( opt.verbose )
                    fprintf(stderr, " `%s'", sl->d );
+               if(opt.textmode)
+                 {
+                   memset( &tfx, 0, sizeof tfx);
+                   iobuf_push_filter( inp, text_filter, &tfx );
+                 }
                iobuf_push_filter( inp, md_filter, &mfx );
                while( iobuf_get(inp) != -1 )
                    ;
@@ -819,7 +861,7 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
     /* write the signatures */
     rc = write_signature_packets (sk_list, out, mfx.md,
                                   opt.textmode && !outfile? 0x01 : 0x00,
-                                 timestamp, duration, detached ? 'D':'S');
+                                 0, duration, detached ? 'D':'S');
     if( rc )
         goto leave;
 
@@ -849,20 +891,21 @@ int
 clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
 {
     armor_filter_context_t afx;
+    progress_filter_context_t pfx;
     MD_HANDLE textmd = NULL;
     IOBUF inp = NULL, out = NULL;
     PACKET pkt;
     int rc = 0;
     SK_LIST sk_list = NULL;
     SK_LIST sk_rover = NULL;
-    int old_style = opt.rfc1991;
+    int old_style = RFC1991;
     int only_md5 = 0;
-    u32 timestamp=0,duration=0;
+    u32 duration=0;
 
     memset( &afx, 0, sizeof afx);
     init_packet( &pkt );
 
-    if(opt.ask_sig_expire && !opt.force_v3_sigs && !opt.batch && !opt.rfc1991)
+    if(opt.ask_sig_expire && !opt.force_v3_sigs && !opt.batch && !RFC1991)
       duration=ask_expire_interval(1);
 
     if( (rc=build_sk_list( locusr, &sk_list, 1, PUBKEY_USAGE_SIG )) )
@@ -871,12 +914,11 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
     if( !old_style && !duration )
        old_style = only_old_style( sk_list );
 
-    if(!old_style && opt.pgp2)
+    if(PGP2 && !only_old_style(sk_list))
       {
        log_info(_("you can only clearsign with PGP 2.x style keys "
                   "while in --pgp2 mode\n"));
-       log_info(_("this message may not be usable by %s\n"),"PGP 2.x");
-       opt.pgp2=0;
+       compliance_failure();
       }
 
     /* prepare iobufs */
@@ -886,6 +928,7 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
        rc = G10ERR_OPEN_FILE;
        goto leave;
     }
+    handle_progress (&pfx, inp, fname);
 
     if( outfile ) {
        if( !(out = iobuf_create( outfile )) ) {
@@ -949,8 +992,8 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
     }
     if ( DBG_HASHING )
        md_start_debug( textmd, "clearsign" );
-    copy_clearsig_text( out, inp, textmd,
-                       !opt.not_dash_escaped, opt.escape_from, old_style );
+    copy_clearsig_text( out, inp, textmd, !opt.not_dash_escaped,
+                       opt.escape_from, (old_style && only_md5) );
     /* fixme: check for read errors */
 
     /* now write the armor */
@@ -958,8 +1001,7 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
     iobuf_push_filter( out, armor_filter, &afx );
 
     /* write the signatures */
-    rc = write_signature_packets (sk_list, out, textmd, 0x01,
-                                 timestamp, duration, 'C');
+    rc=write_signature_packets (sk_list, out, textmd, 0x01, 0, duration, 'C');
     if( rc )
         goto leave;
 
@@ -982,6 +1024,7 @@ int
 sign_symencrypt_file (const char *fname, STRLIST locusr)
 {
     armor_filter_context_t afx;
+    progress_filter_context_t pfx;
     compress_filter_context_t zfx;
     md_filter_context_t mfx;
     text_filter_context_t tfx;
@@ -993,7 +1036,7 @@ sign_symencrypt_file (const char *fname, STRLIST locusr)
     SK_LIST sk_list = NULL;
     SK_LIST sk_rover = NULL;
     int algo;
-    u32 timestamp=0,duration=0;
+    u32 duration=0;
 
     memset( &afx, 0, sizeof afx);
     memset( &zfx, 0, sizeof zfx);
@@ -1002,7 +1045,7 @@ sign_symencrypt_file (const char *fname, STRLIST locusr)
     memset( &cfx, 0, sizeof cfx);
     init_packet( &pkt );
 
-    if(opt.ask_sig_expire && !opt.force_v3_sigs && !opt.batch && !opt.rfc1991)
+    if(opt.ask_sig_expire && !opt.force_v3_sigs && !opt.batch && !RFC1991)
       duration=ask_expire_interval(1);
 
     rc = build_sk_list (locusr, &sk_list, 1, PUBKEY_USAGE_SIG);
@@ -1017,18 +1060,18 @@ sign_symencrypt_file (const char *fname, STRLIST locusr)
        rc = G10ERR_OPEN_FILE;
        goto leave;
     }
+    handle_progress (&pfx, inp, fname);
 
     /* prepare key */
     s2k = m_alloc_clear( sizeof *s2k );
-    s2k->mode = opt.rfc1991? 0:opt.s2k_mode;
-    s2k->hash_algo = opt.def_digest_algo ? opt.def_digest_algo
-                                        : opt.s2k_digest_algo;
+    s2k->mode = RFC1991? 0:opt.s2k_mode;
+    s2k->hash_algo = opt.s2k_digest_algo;
 
-    algo = opt.def_cipher_algo ? opt.def_cipher_algo : opt.s2k_cipher_algo;
+    algo = default_cipher_algo();
     if (!opt.quiet || !opt.batch)
         log_info (_("%s encryption will be used\n"),
                    cipher_algo_to_string(algo) );
-    cfx.dek = passphrase_to_dek( NULL, 0, algo, s2k, 2, NULL );
+    cfx.dek = passphrase_to_dek( NULL, 0, algo, s2k, 2, NULL, NULL);
 
     if (!cfx.dek || !cfx.dek->keylen) {
         rc = G10ERR_PASSPHRASE;
@@ -1059,7 +1102,7 @@ sign_symencrypt_file (const char *fname, STRLIST locusr)
 
     /* Write the symmetric key packet */
     /*(current filters: armor)*/
-    if (!opt.rfc1991) {
+    if (!RFC1991) {
        PKT_symkey_enc *enc = m_alloc_clear( sizeof *enc );
        enc->version = 4;
        enc->cipher_algo = cfx.dek->algo;
@@ -1075,24 +1118,15 @@ sign_symencrypt_file (const char *fname, STRLIST locusr)
     iobuf_push_filter( out, cipher_filter, &cfx );
 
     /* Push the Zip filter */
-    if (opt.compress)
+    if (opt.compress && default_compress_algo())
       {
-       int compr_algo=opt.def_compress_algo;
-
-       /* Default */
-        if(compr_algo==-1)
-         compr_algo=DEFAULT_COMPRESS_ALGO;
-
-       if (compr_algo)
-         {
-           zfx.algo = compr_algo;
-           iobuf_push_filter( out, compress_filter, &zfx );
-         }
+       zfx.algo = default_compress_algo();
+       iobuf_push_filter( out, compress_filter, &zfx );
       }
 
     /* Write the one-pass signature packets */
     /*(current filters: zip - encrypt - armor)*/
-    if (!opt.rfc1991) {
+    if (!RFC1991) {
         rc = write_onepass_sig_packets (sk_list, out,
                                         opt.textmode? 0x01:0x00);
         if (rc)
@@ -1109,7 +1143,7 @@ sign_symencrypt_file (const char *fname, STRLIST locusr)
     /*(current filters: zip - encrypt - armor)*/
     rc = write_signature_packets (sk_list, out, mfx.md,
                                  opt.textmode? 0x01 : 0x00,
-                                 timestamp, duration, 'S');
+                                 0, duration, 'S');
     if( rc )
         goto leave;
 
@@ -1165,7 +1199,9 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
     /* If you are making a signature on a v4 key using your v3 key, it
        doesn't make sense to generate a v3 sig.  After all, no v3-only
        PGP implementation could understand the v4 key in the first
-       place. */
+       place.  Note that this implies that a signature on an attribute
+       uid is usually going to be v4 as well, since they are not
+       generally found on v3 keys. */
     if (sigversion < pk->version)
         sigversion = pk->version;
 
@@ -1215,12 +1251,15 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
     sig->sig_class = sigclass;
     if( sig->version >= 4 )
        build_sig_subpkt_from_sig( sig );
+    mk_notation_and_policy( sig, pk, sk );
 
+    /* Crucial that the call to mksubpkt comes LAST before the calls
+       to finalize the sig as that makes it possible for the mksubpkt
+       function to get a reliable pointer to the subpacket area. */
     if( sig->version >= 4 && mksubpkt )
        rc = (*mksubpkt)( sig, opaque );
 
     if( !rc ) {
-       mk_notation_and_policy( sig, pk, sk );
         hash_sigversion_to_magic (md, sig);
        md_final(md);
 
@@ -1247,6 +1286,7 @@ update_keysig_packet( PKT_signature **ret_sig,
                       PKT_signature *orig_sig,
                       PKT_public_key *pk,
                       PKT_user_id *uid, 
+                      PKT_public_key *subpk,
                       PKT_secret_key *sk,
                       int (*mksubpkt)(PKT_signature *, void *),
                       void *opaque
@@ -1256,32 +1296,52 @@ update_keysig_packet( PKT_signature **ret_sig,
     int rc=0;
     MD_HANDLE md;
 
-    if (!orig_sig || !pk || !uid || !sk)
-        return G10ERR_GENERAL;
-    if (orig_sig->sig_class < 0x10 || orig_sig->sig_class > 0x13 )
-        return G10ERR_GENERAL;
+    if ((!orig_sig || !pk || !sk)
+       || (orig_sig->sig_class >= 0x10 && orig_sig->sig_class <= 0x13 && !uid)
+       || (orig_sig->sig_class == 0x18 && !subpk))
+      return G10ERR_GENERAL;
 
     md = md_open( orig_sig->digest_algo, 0 );
 
     /* hash the public key certificate and the user id */
     hash_public_key( md, pk );
-    hash_uid (md, orig_sig->version, uid);
+
+    if( orig_sig->sig_class == 0x18 )
+      hash_public_key( md, subpk );
+    else
+      hash_uid (md, orig_sig->version, uid);
 
     /* create a new signature packet */
     sig = copy_signature (NULL, orig_sig);
-    if ( sig->version >= 4 && mksubpkt)
-       rc = (*mksubpkt)(sig, opaque);
-
-    /* we increase the timestamp by one second so that a future import
-       of this key will replace the existing one.  We also make sure that
-       we don't create a timestamp in the future */
-    sig->timestamp++; 
-    while (sig->timestamp >= make_timestamp())
-        sleep (1);
-    /* put the updated timestamp back into the data */
+
+    /* We need to create a new timestamp so that new sig expiration
+       calculations are done correctly... */
+    sig->timestamp=make_timestamp();
+
+    /* ... but we won't make a timestamp earlier than the existing
+       one. */
+    while(sig->timestamp<=orig_sig->timestamp)
+      {
+       sleep(1);
+       sig->timestamp=make_timestamp();
+      }
+
+    /* Note that already expired sigs will remain expired (with a
+       duration of 0) since build-packet.c:build_sig_subpkt_from_sig
+       detects this case. */
+
     if( sig->version >= 4 )
+      {
+       /* Put the updated timestamp into the sig.  Note that this
+          will automagically lower any sig expiration dates to
+          correctly correspond to the differences in the timestamps
+          (i.e. the duration will shrink). */
        build_sig_subpkt_from_sig( sig );
 
+       if (mksubpkt)
+         rc = (*mksubpkt)(sig, opaque);
+      }
+
     if (!rc) {
         hash_sigversion_to_magic (md, sig);
        md_final(md);