Fix regression introduced by "editing only change".
[gnupg.git] / g10 / sign.c
index 9c73279..30dc66d 100644 (file)
@@ -227,120 +227,166 @@ hash_sigversion_to_magic (gcry_md_hd_t md, const PKT_signature *sig)
     }
 }
 
-
+/* Perform the sign operation.  If CACHE_NONCE is given the agent is
+   advised to use that cached passphrase fro the key.  */
 static int
 do_sign (PKT_public_key *pksk, PKT_signature *sig,
-        gcry_md_hd_t md, int digest_algo)
+        gcry_md_hd_t md, int mdalgo, const char *cache_nonce)
 {
-    gcry_mpi_t frame;
-    byte *dp;
-    int rc;
-
-    if (pksk->timestamp > sig->timestamp ) {
-       ulong d = pksk->timestamp - sig->timestamp;
-       log_info( d==1 ? _("key has been created %lu second "
-                          "in future (time warp or clock problem)\n")
-                      : _("key has been created %lu seconds "
-                          "in future (time warp or clock problem)\n"), d );
-       if( !opt.ignore_time_conflict )
-           return G10ERR_TIME_CONFLICT;
+  gpg_error_t err;
+  gcry_mpi_t frame;
+  byte *dp;
+  char *hexgrip;
+
+  if (pksk->timestamp > sig->timestamp )
+    {
+      ulong d = pksk->timestamp - sig->timestamp;
+      log_info (d==1 ? _("key has been created %lu second "
+                         "in future (time warp or clock problem)\n")
+                : _("key has been created %lu seconds "
+                    "in future (time warp or clock problem)\n"), d );
+      if (!opt.ignore_time_conflict)
+        return gpg_error (GPG_ERR_TIME_CONFLICT);
     }
 
+  
+  print_pubkey_algo_note (pksk->pubkey_algo);
 
-    print_pubkey_algo_note (pksk->pubkey_algo);
+  if (!mdalgo)
+    mdalgo = gcry_md_get_algo (md);
 
-    if( !digest_algo )
-       digest_algo = gcry_md_get_algo (md);
+  print_digest_algo_note (mdalgo);
+  dp = gcry_md_read  (md, mdalgo);
+  sig->digest_algo = mdalgo;
+  sig->digest_start[0] = dp[0];
+  sig->digest_start[1] = dp[1];
+  sig->data[0] = NULL;
+  sig->data[1] = NULL;
 
-    print_digest_algo_note( digest_algo );
-    dp = gcry_md_read ( md, digest_algo );
-    sig->digest_algo = digest_algo;
-    sig->digest_start[0] = dp[0];
-    sig->digest_start[1] = dp[1];
-
-    /* FIXME: Use agent.  */
-/*     if (pksk->is_protected && pksk->protect.s2k.mode == 1002)  */
-/*       {  */
-/* #ifdef ENABLE_CARD_SUPPORT */
-/*         unsigned char *rbuf; */
-/*         size_t rbuflen; */
-/*         char *snbuf; */
-        
-/*         snbuf = serialno_and_fpr_from_sk (sk->protect.iv, */
-/*                                           sk->protect.ivlen, sk); */
-/*         rc = agent_scd_pksign (snbuf, digest_algo, */
-/*                                gcry_md_read (md, digest_algo), */
-/*                                gcry_md_get_algo_dlen (digest_algo), */
-/*                                &rbuf, &rbuflen); */
-/*         xfree (snbuf); */
-/*         if (!rc) */
-/*           { */
-/*             if (gcry_mpi_scan (&sig->data[0], GCRYMPI_FMT_USG, */
-/*                                rbuf, rbuflen, NULL)) */
-/*               BUG (); */
-/*             xfree (rbuf); */
-/*           } */
-/* #else */
-/*         return gpg_error (GPG_ERR_NOT_SUPPORTED); */
-/* #endif /\* ENABLE_CARD_SUPPORT *\/ */
-/*       } */
-/*     else  */
-      {
-        frame = encode_md_value (NULL, pksk, md, digest_algo );
-        if (!frame)
-          return G10ERR_GENERAL;
-        rc = pk_sign (pksk->pubkey_algo, sig->data, frame, pksk->pkey );
-        gcry_mpi_release (frame);
-      }
+  
+  err = hexkeygrip_from_pk (pksk, &hexgrip);
+  if (!err)
+    {
+      char *desc;
+      gcry_sexp_t s_sigval;
+      
+      desc = gpg_format_keydesc (pksk, 0, 1);
+      err = agent_pksign (NULL/*ctrl*/, cache_nonce, hexgrip, desc, 
+                          dp, gcry_md_get_algo_dlen (mdalgo), mdalgo,
+                          &s_sigval);
+      xfree (desc);
+      
+      if (err)
+        ;
+      else if (pksk->pubkey_algo == GCRY_PK_RSA
+               || pksk->pubkey_algo == GCRY_PK_RSA_S)
+        sig->data[0] = mpi_from_sexp (s_sigval, "s");
+      else
+        {
+          sig->data[0] = mpi_from_sexp (s_sigval, "r");
+          sig->data[1] = mpi_from_sexp (s_sigval, "s");
+        }
+      
+      gcry_sexp_release (s_sigval);
+    }
+  xfree (hexgrip);
 
-    if (!rc && !opt.no_sig_create_check) {
-        /* Check that the signature verification worked and nothing is
-         * fooling us e.g. by a bug in the signature create
-         * code or by deliberately introduced faults. */
-        PKT_public_key *pk = xmalloc_clear (sizeof *pk);
+  /* Check that the signature verification worked and nothing is
+   * fooling us e.g. by a bug in the signature create code or by
+   * deliberately introduced faults.  */
+  if (!err && !opt.no_sig_create_check)
+    {
+      PKT_public_key *pk = xmalloc_clear (sizeof *pk);
 
-        if( get_pubkey( pk, sig->keyid ) )
-            rc = G10ERR_NO_PUBKEY;
-        else {
-           frame = encode_md_value (pk, NULL, md, sig->digest_algo );
-            if (!frame)
-              rc = G10ERR_GENERAL;
-            else
-              rc = pk_verify (pk->pubkey_algo, frame, sig->data, pk->pkey );
-            gcry_mpi_release (frame);
+      if (get_pubkey (pk, sig->keyid ))
+        err = gpg_error (GPG_ERR_NO_PUBKEY);
+      else 
+        {
+          frame = encode_md_value (pk, md, sig->digest_algo );
+          if (!frame)
+            err = gpg_error (GPG_ERR_GENERAL);
+          else
+            err = pk_verify (pk->pubkey_algo, frame, sig->data, pk->pkey);
+          gcry_mpi_release (frame);
         }
-        if (rc)
-            log_error (_("checking created signature failed: %s\n"),
-                         g10_errstr (rc));
-        free_public_key (pk);
+      if (err)
+        log_error (_("checking created signature failed: %s\n"),
+                   g10_errstr (err));
+      free_public_key (pk);
     }
-    if( rc )
-       log_error(_("signing failed: %s\n"), g10_errstr(rc) );
-    else {
-       if( opt.verbose ) {
-           char *ustr = get_user_id_string_native (sig->keyid);
-           log_info(_("%s/%s signature from: \"%s\"\n"),
-                    gcry_pk_algo_name (pksk->pubkey_algo),
-                    gcry_md_algo_name (sig->digest_algo),
-                    ustr );
-           xfree(ustr);
+
+  if (err)
+    log_error (_("signing failed: %s\n"), g10_errstr (err));
+  else 
+    {
+      if (opt.verbose)
+        {
+          char *ustr = get_user_id_string_native (sig->keyid);
+          log_info (_("%s/%s signature from: \"%s\"\n"),
+                    gcry_pk_algo_name (pksk->pubkey_algo),
+                    gcry_md_algo_name (sig->digest_algo),
+                    ustr);
+          xfree (ustr);
        }
     }
-    return rc;
+  return err;
 }
 
 
 int
-complete_sig( PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md )
+complete_sig (PKT_signature *sig, PKT_public_key *pksk, gcry_md_hd_t md,
+              const char *cache_nonce)
 {
   int rc;
 
-  if (!(rc = check_secret_key (pksk, 0)))
-    rc = do_sign (pksk, sig, md, 0);
+  /* if (!(rc = check_secret_key (pksk, 0))) */
+  rc = do_sign (pksk, sig, md, 0, cache_nonce);
   return rc;
 }
 
 
+/* Return true if the key seems to be on a version 1 OpenPGP card.
+   This works by asking the agent and may fail if the card has not yet
+   been used with the agent.  */
+static int
+openpgp_card_v1_p (PKT_public_key *pk)
+{
+  gpg_error_t err;
+  int result;
+
+  /* Shortcut if we are not using RSA: The v1 cards only support RSA
+     thus there is no point in looking any further.  */
+  if (!is_RSA (pk->pubkey_algo))
+    return 0;
+
+  if (!pk->flags.serialno_valid)
+    {
+      char *hexgrip;
+
+      err = hexkeygrip_from_pk (pk, &hexgrip);
+      if (err)
+        {
+          log_error ("error computing a keygrip: %s\n", gpg_strerror (err));
+          return 0; /* Ooops.  */
+        }
+
+      xfree (pk->serialno);
+      agent_get_keyinfo (NULL, hexgrip, &pk->serialno);
+      xfree (hexgrip);
+      pk->flags.serialno_valid = 1;
+    }
+
+  if (!pk->serialno)
+    result = 0; /* Error from a past agent_get_keyinfo or no card.  */
+  else
+    {
+      /* The version number of the card is included in the serialno.  */
+      result = !strncmp (pk->serialno, "D2760001240101", 14);
+    }
+  return result;
+}
+
+
 
 static int
 match_dsa_hash (unsigned int qbytes)
@@ -357,7 +403,7 @@ match_dsa_hash (unsigned int qbytes)
   if (qbytes <= 48)
     return DIGEST_ALGO_SHA384;
 
-  if (qbytes <= 64)
+  if (qbytes <= 66 )   /* 66 corresponds to 521 (64 to 512) */
     return DIGEST_ALGO_SHA512;
 
   return DEFAULT_DIGEST_ALGO;
@@ -390,10 +436,15 @@ hash_for (PKT_public_key *pk)
     {
       return recipient_digest_algo;
     }
-  else if (pk->pubkey_algo == PUBKEY_ALGO_DSA)
+  else if (pk->pubkey_algo == PUBKEY_ALGO_DSA
+           || pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
     {
-      unsigned int qbytes = gcry_mpi_get_nbits (pk->pkey[1]) / 8;
+      unsigned int qbytes = gcry_mpi_get_nbits (pk->pkey[1]);
 
+      if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
+        qbytes = ecdsa_qbits_from_Q (qbytes);
+      qbytes = qbytes/8;
+      
       /* It's a DSA key, so find a hash that is the same size as q or
         larger.  If q is 160, assume it is an old DSA key and use a
         160-bit hash unless --enable-dsa2 is set, in which case act
@@ -421,13 +472,13 @@ hash_for (PKT_public_key *pk)
 
       return match_dsa_hash(qbytes);
     }
-  else if (/*FIXME: call agent 
-             pk->is_protected && sk->protect.s2k.mode==1002*/ 0)
+  else if (openpgp_card_v1_p (pk))
     {
-      /* The secret key lives on a smartcard, and current smartcards only
-        handle SHA-1 and RIPEMD/160.  This is correct now, but may
-        need revision as the cards add algorithms. */
-
+      /* The sk lives on a smartcard, and old smartcards only handle
+        SHA-1 and RIPEMD/160.  Newer smartcards (v2.0) don't have
+        this restriction anymore.  Fortunately the serial number
+        encodes the version of the card and thus we know that this
+        key is on a v1 card. */
       if(opt.personal_digest_prefs)
        {
          prefitem_t *prefs;
@@ -625,7 +676,7 @@ write_plaintext_packet (IOBUF out, IOBUF inp, const char *fname, int ptmode)
 static int
 write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
                          int sigclass, u32 timestamp, u32 duration,
-                        int status_letter)
+                        int status_letter, const char *cache_nonce)
 {
   SK_LIST sk_rover;
   
@@ -672,7 +723,7 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
       hash_sigversion_to_magic (md, sig);
       gcry_md_final (md);
 
-      rc = do_sign (pk, sig, md, hash_for (pk));
+      rc = do_sign (pk, sig, md, hash_for (pk), cache_nonce);
       gcry_md_close (md);
       if (!rc)
         { 
@@ -710,7 +761,7 @@ write_signature_packets (SK_LIST sk_list, IOBUF out, gcry_md_hd_t hash,
  * uncompressed, non-armored and in binary mode.
  */
 int
-sign_file( strlist_t filenames, int detached, strlist_t locusr,
+sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
           int encryptflag, strlist_t remusr, const char *outfile )
 {
     const char *fname;
@@ -758,7 +809,9 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr,
          duration=parse_expire_string(opt.def_sig_expire);
       }
 
-    if( (rc=build_sk_list( locusr, &sk_list, 1, PUBKEY_USAGE_SIG )) )
+    /* Note: In the old non-agent version the following call used to
+       unprotect the secret key.  This is now done on demand by the agent.  */
+    if( (rc = build_sk_list (locusr, &sk_list, PUBKEY_USAGE_SIG )) )
        goto leave;
 
     if(PGP2 && !only_old_style(sk_list))
@@ -768,7 +821,8 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr,
        compliance_failure();
       }
 
-    if(encryptflag && (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC )))
+    if (encryptflag
+        && (rc=build_pk_list (ctrl, remusr, &pk_list, PUBKEY_USAGE_ENC)))
       goto leave;
 
     /* prepare iobufs */
@@ -780,7 +834,7 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr,
         {
           iobuf_close (inp);
           inp = NULL;
-          errno = EPERM;
+          gpg_err_set_errno (EPERM);
         }
       if( !inp ) 
         {
@@ -796,7 +850,7 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr,
     if( outfile ) {
         if (is_secured_filename ( outfile )) {
             out = NULL;
-            errno = EPERM;
+            gpg_err_set_errno (EPERM);
         }
         else
             out = iobuf_create( outfile );
@@ -826,7 +880,7 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr,
       gcry_md_start_debug (mfx.md, "sign");
 
     /* If we're encrypting and signing, it is reasonable to pick the
-       hash algorithm to use out of the recepient key prefs.  This is
+       hash algorithm to use out of the recipient key prefs.  This is
        best effort only, as in a DSA2 and smartcard world there are
        cases where we cannot please everyone with a single hash (DSA2
        wants >160 and smartcards want =160).  In the future this could
@@ -871,10 +925,15 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr,
 
            for (sk_rover = sk_list; sk_rover; sk_rover = sk_rover->next )
              {
-               if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA)
+               if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_DSA
+                    || sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
                  {
-                   int temp_hashlen = gcry_mpi_get_nbits
-                      (sk_rover->pk->pkey[1])+7/8;
+                   int temp_hashlen = (gcry_mpi_get_nbits
+                                        (sk_rover->pk->pkey[1]));
+
+                   if (sk_rover->pk->pubkey_algo == PUBKEY_ALGO_ECDSA)
+                     temp_hashlen = ecdsa_qbits_from_Q (temp_hashlen);
+                   temp_hashlen = (temp_hashlen+7)/8;
 
                    /* Pick a hash that is large enough for our
                       largest q */
@@ -975,7 +1034,7 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr,
                   {
                     iobuf_close (inp);
                     inp = NULL;
-                    errno = EPERM;
+                    gpg_err_set_errno (EPERM);
                   }
                if( !inp )
                  {
@@ -1018,7 +1077,7 @@ sign_file( strlist_t filenames, int detached, strlist_t locusr,
     /* write the signatures */
     rc = write_signature_packets (sk_list, out, mfx.md,
                                   opt.textmode && !outfile? 0x01 : 0x00,
-                                 0, duration, detached ? 'D':'S');
+                                 0, duration, detached ? 'D':'S', NULL);
     if( rc )
         goto leave;
 
@@ -1073,7 +1132,9 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
          duration=parse_expire_string(opt.def_sig_expire);
       }
 
-    if( (rc=build_sk_list( locusr, &sk_list, 1, PUBKEY_USAGE_SIG )) )
+    /* Note: In the old non-agent version the following call used to
+       unprotect the secret key.  This is now done on demand by the agent.  */
+    if( (rc=build_sk_list( locusr, &sk_list, PUBKEY_USAGE_SIG )) )
        goto leave;
 
     if( !old_style && !duration )
@@ -1092,7 +1153,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
       {
         iobuf_close (inp);
         inp = NULL;
-        errno = EPERM;
+        gpg_err_set_errno (EPERM);
       }
     if( !inp ) {
         rc = gpg_error_from_syserror ();
@@ -1105,7 +1166,7 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
     if( outfile ) {
         if (is_secured_filename (outfile) ) {
             outfile = NULL;
-            errno = EPERM;
+            gpg_err_set_errno (EPERM);
         }
         else 
             out = iobuf_create( outfile );
@@ -1180,8 +1241,9 @@ clearsign_file( const char *fname, strlist_t locusr, const char *outfile )
     afx->what = 2;
     push_armor_filter (afx, out);
 
-    /* write the signatures */
-    rc=write_signature_packets (sk_list, out, textmd, 0x01, 0, duration, 'C');
+    /* Write the signatures.  */
+    rc = write_signature_packets (sk_list, out, textmd, 0x01, 0, duration, 'C',
+                                  NULL);
     if( rc )
         goto leave;
 
@@ -1237,7 +1299,9 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
          duration=parse_expire_string(opt.def_sig_expire);
       }
 
-    rc = build_sk_list (locusr, &sk_list, 1, PUBKEY_USAGE_SIG);
+    /* Note: In the old non-agent version the following call used to
+       unprotect the secret key.  This is now done on demand by the agent.  */
+    rc = build_sk_list (locusr, &sk_list, PUBKEY_USAGE_SIG);
     if (rc) 
        goto leave;
 
@@ -1247,7 +1311,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
       {
         iobuf_close (inp);
         inp = NULL;
-        errno = EPERM;
+        gpg_err_set_errno (EPERM);
       }
     if( !inp ) {
         rc = gpg_error_from_syserror ();
@@ -1345,7 +1409,7 @@ sign_symencrypt_file (const char *fname, strlist_t locusr)
     /*(current filters: zip - encrypt - armor)*/
     rc = write_signature_packets (sk_list, out, mfx.md,
                                  opt.textmode? 0x01 : 0x00,
-                                 0, duration, 'S');
+                                 0, duration, 'S', NULL);
     if( rc )
         goto leave;
 
@@ -1383,8 +1447,8 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
                    PKT_public_key *pksk,
                    int sigclass, int digest_algo,
                     int sigversion, u32 timestamp, u32 duration,
-                   int (*mksubpkt)(PKT_signature *, void *), void *opaque
-                  )
+                   int (*mksubpkt)(PKT_signature *, void *), void *opaque,
+                    const char *cache_nonce)
 {
     PKT_signature *sig;
     int rc=0;
@@ -1421,11 +1485,14 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
 
        if(opt.cert_digest_algo)
          digest_algo=opt.cert_digest_algo;
-       else if(pksk->pubkey_algo==PUBKEY_ALGO_RSA
+       else if(pksk->pubkey_algo == PUBKEY_ALGO_RSA
                && pk->version<4 && sigversion<4)
          digest_algo = DIGEST_ALGO_MD5;
-       else if(pksk->pubkey_algo==PUBKEY_ALGO_DSA)
+       else if(pksk->pubkey_algo == PUBKEY_ALGO_DSA)
          digest_algo = match_dsa_hash (gcry_mpi_get_nbits (pksk->pkey[1])/8);
+        else if(pksk->pubkey_algo == PUBKEY_ALGO_ECDSA )
+         digest_algo = match_dsa_hash (ecdsa_qbits_from_Q
+                                        (gcry_mpi_get_nbits (pksk->pkey[1]))/8);
        else
          digest_algo = DIGEST_ALGO_SHA1;
       }
@@ -1477,7 +1544,7 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
         hash_sigversion_to_magic (md, sig);
        gcry_md_final (md);
 
-       rc = complete_sig (sig, pksk, md);
+       rc = complete_sig (sig, pksk, md, cache_nonce);
     }
 
     gcry_md_close (md);
@@ -1493,6 +1560,9 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
 /****************
  * Create a new signature packet based on an existing one.
  * Only user ID signatures are supported for now.
+ * PK is the public key to work on.
+ * PKSK is the key used to make the signature.
+ *
  * TODO: Merge this with make_keysig_packet.
  */
 int
@@ -1503,7 +1573,7 @@ update_keysig_packet( PKT_signature **ret_sig,
                       PKT_public_key *subpk,
                       PKT_public_key *pksk,
                       int (*mksubpkt)(PKT_signature *, void *),
-                      void *opaque )
+                      void *opaque)
 {
     PKT_signature *sig;
     int rc=0;
@@ -1560,7 +1630,7 @@ update_keysig_packet( PKT_signature **ret_sig,
         hash_sigversion_to_magic (md, sig);
        gcry_md_final (md);
 
-       rc = complete_sig (sig, pksk, md);
+       rc = complete_sig (sig, pksk, md, NULL);
     }
 
     gcry_md_close (md);