* keygen.c (gen_card_key): Add optional argument to return a pointer
[gnupg.git] / g10 / keygen.c
index fb93363..d240856 100644 (file)
@@ -1,6 +1,6 @@
 /* keygen.c - generate a key pair
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- *               2005 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ *               2006 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -122,6 +122,7 @@ static void do_generate_keypair( struct para_data_s *para,
 static int  write_keyblock( IOBUF out, KBNODE node );
 static int gen_card_key (int algo, int keyno, int is_primary,
                          KBNODE pub_root, KBNODE sec_root,
+                        PKT_secret_key **ret_sk,
                          u32 expireval, struct para_data_s *para);
 static int gen_card_key_with_backup (int algo, int keyno, int is_primary,
                                      KBNODE pub_root, KBNODE sec_root,
@@ -190,9 +191,6 @@ do_add_key_flags (PKT_signature *sig, unsigned int use)
 {
     byte buf[1];
 
-    if (!use) 
-        return;
-
     buf[0] = 0;
 
     /* The spec says that all primary keys MUST be able to certify. */
@@ -205,6 +203,10 @@ do_add_key_flags (PKT_signature *sig, unsigned int use)
         buf[0] |= 0x04 | 0x08;
     if (use & PUBKEY_USAGE_AUTH)
         buf[0] |= 0x20;
+
+    if (!buf[0]) 
+        return;
+
     build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
 }
 
@@ -220,7 +222,7 @@ keygen_add_key_expire( PKT_signature *sig, void *opaque )
         if(pk->expiredate > pk->timestamp)
          u= pk->expiredate - pk->timestamp;
        else
-         u= 0;
+         u= 1;
 
        buf[0] = (u >> 24) & 0xff;
        buf[1] = (u >> 16) & 0xff;
@@ -529,8 +531,8 @@ PKT_user_id *keygen_get_std_prefs(void)
   uid->prefs[j].type=PREFTYPE_NONE;
   uid->prefs[j].value=0;
 
-  uid->mdc_feature=mdc_available;
-  uid->ks_modify=ks_modify;
+  uid->flags.mdc=mdc_available;
+  uid->flags.ks_modify=ks_modify;
 
   return uid;
 }
@@ -689,6 +691,55 @@ keygen_add_keyserver_url(PKT_signature *sig, void *opaque)
 }
 
 int
+keygen_add_notations(PKT_signature *sig,void *opaque)
+{
+  struct notation *notation;
+
+  /* We always start clean */
+  delete_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION);
+  delete_sig_subpkt(sig->unhashed,SIGSUBPKT_NOTATION);
+  sig->flags.notation=0;
+
+  for(notation=opaque;notation;notation=notation->next)
+    if(!notation->flags.ignore)
+      {
+       unsigned char *buf;
+       unsigned int n1,n2;
+
+       n1=strlen(notation->name);
+       if(notation->altvalue)
+         n2=strlen(notation->altvalue);
+       else if(notation->bdat)
+         n2=notation->blen;
+       else
+         n2=strlen(notation->value);
+
+       buf = xmalloc( 8 + n1 + n2 );
+
+       /* human readable or not */
+       buf[0] = notation->bdat?0:0x80;
+       buf[1] = buf[2] = buf[3] = 0;
+       buf[4] = n1 >> 8;
+       buf[5] = n1;
+       buf[6] = n2 >> 8;
+       buf[7] = n2;
+       memcpy(buf+8, notation->name, n1 );
+       if(notation->altvalue)
+         memcpy(buf+8+n1, notation->altvalue, n2 );
+       else if(notation->bdat)
+         memcpy(buf+8+n1, notation->bdat, n2 );
+       else
+         memcpy(buf+8+n1, notation->value, n2 );
+       build_sig_subpkt( sig, SIGSUBPKT_NOTATION |
+                         (notation->flags.critical?SIGSUBPKT_FLAG_CRITICAL:0),
+                         buf, 8+n1+n2 );
+       xfree(buf);
+      }
+
+  return 0;
+}
+
+int
 keygen_add_revkey(PKT_signature *sig, void *opaque)
 {
   struct revocation_key *revkey=opaque;
@@ -710,26 +761,18 @@ keygen_add_revkey(PKT_signature *sig, void *opaque)
   return 0;
 }
 
-static int
-make_backsig(PKT_signature *sig, PKT_public_key *pk,
-            PKT_public_key *sub_pk, PKT_secret_key *sub_sk)
+int
+make_backsig(PKT_signature *sig,PKT_public_key *pk,
+            PKT_public_key *sub_pk,PKT_secret_key *sub_sk)
 {
   PKT_signature *backsig;
   int rc;
 
-#ifndef DO_BACKSIGS
-  /* This is not enabled yet, as I want to get a bit closer to RFC day
-     before enabling this.  I've been burned before :) */
-
-  return 0;
-#endif
-
-  cache_public_key (sub_pk);
+  cache_public_key(sub_pk);
 
-  rc=make_keysig_packet(&backsig,pk,NULL,sub_pk,sub_sk, 0x19, 0, 0, 0, 0,
-                       NULL,NULL);
-  if( rc )
-    log_error("make_keysig_packet failed for backsig: %s\n", g10_errstr(rc) );
+  rc=make_keysig_packet(&backsig,pk,NULL,sub_pk,sub_sk,0x19,0,0,0,0,NULL,NULL);
+  if(rc)
+    log_error("make_keysig_packet failed for backsig: %s\n",g10_errstr(rc));
   else
     {
       /* get it into a binary packed form. */
@@ -895,7 +938,6 @@ write_selfsigs( KBNODE sec_root, KBNODE pub_root, PKT_secret_key *sk,
     return rc;
 }
 
-/* sub_sk is currently unused (reserved for backsigs) */
 static int
 write_keybinding( KBNODE root, KBNODE pub_root,
                  PKT_secret_key *pri_sk, PKT_secret_key *sub_sk,
@@ -1047,30 +1089,65 @@ gen_dsa(unsigned int nbits, KBNODE pub_root, KBNODE sec_root, DEK *dek,
     PKT_public_key *pk;
     MPI skey[5];
     MPI *factors;
+    unsigned int qbits;
 
-    if( nbits > 1024 || nbits < 512 ) {
+    if( nbits < 512 || (!opt.flags.dsa2 && nbits > 1024))
+      {
        nbits = 1024;
        log_info(_("keysize invalid; using %u bits\n"), nbits );
-    }
+      }
+    else if(nbits>3072)
+      {
+       nbits = 3072;
+       log_info(_("keysize invalid; using %u bits\n"), nbits );
+      }
 
-    if( (nbits % 64) ) {
+    if(nbits % 64)
+      {
        nbits = ((nbits + 63) / 64) * 64;
        log_info(_("keysize rounded up to %u bits\n"), nbits );
-    }
+      }
 
-    rc = pubkey_generate( PUBKEY_ALGO_DSA, nbits, skey, &factors );
-    if( rc ) {
-       log_error("pubkey_generate failed: %s\n", g10_errstr(rc) );
+    /*
+      Figure out a q size based on the key size.  FIPS 180-3 says:
+
+      L = 1024, N = 160
+      L = 2048, N = 224
+      L = 2048, N = 256
+      L = 3072, N = 256
+
+      2048/256 is an odd pair since there is also a 2048/224 and
+      3072/256.  Matching sizes is not a very exact science.
+      
+      We'll do 256 qbits for nbits over 2048, 224 for nbits over 1024
+      but less than 2048, and 160 for 1024 (DSA1).
+    */
+
+    if(nbits>2048)
+      qbits=256;
+    else if(nbits>1024)
+      qbits=224;
+    else
+      qbits=160;
+
+    if(qbits!=160)
+      log_info("WARNING: some OpenPGP programs can't"
+              " handle a DSA key with this digest size\n");
+
+    rc = dsa2_generate( PUBKEY_ALGO_DSA, nbits, qbits, skey, &factors );
+    if( rc )
+      {
+       log_error("dsa2_generate failed: %s\n", g10_errstr(rc) );
        return rc;
-    }
+      }
 
     sk = xmalloc_clear( sizeof *sk );
     pk = xmalloc_clear( sizeof *pk );
     sk->timestamp = pk->timestamp = make_timestamp();
     sk->version = pk->version = 4;
-    if( expireval ) {
-       sk->expiredate = pk->expiredate = sk->timestamp + expireval;
-    }
+    if( expireval )
+      sk->expiredate = pk->expiredate = sk->timestamp + expireval;
+
     sk->pubkey_algo = pk->pubkey_algo = PUBKEY_ALGO_DSA;
                       pk->pkey[0] = mpi_copy( skey[0] );
                       pk->pkey[1] = mpi_copy( skey[1] );
@@ -1238,6 +1315,9 @@ print_key_flags(int flags)
   if(flags&PUBKEY_USAGE_SIG)
     tty_printf("%s ",_("Sign"));
 
+  if(flags&PUBKEY_USAGE_CERT)
+    tty_printf("%s ",_("Certify"));
+
   if(flags&PUBKEY_USAGE_ENC)
     tty_printf("%s ",_("Encrypt"));
 
@@ -1248,7 +1328,7 @@ print_key_flags(int flags)
 
 /* Returns the key flags */
 static unsigned int
-ask_key_flags(int algo)
+ask_key_flags(int algo,int subkey)
 {
   const char *togglers=_("SsEeAaQq");
   char *answer=NULL;
@@ -1258,6 +1338,10 @@ ask_key_flags(int algo)
   if(strlen(togglers)!=8)
     BUG();
 
+  /* Only primary keys may certify. */
+  if(subkey)
+    possible&=~PUBKEY_USAGE_CERT;
+
   /* Preload the current set with the possible set, minus
      authentication, since nobody really uses auth yet. */
   current=possible&~PUBKEY_USAGE_AUTH;
@@ -1291,7 +1375,7 @@ ask_key_flags(int algo)
       cpr_kill_prompt();
 
       if(strlen(answer)>1)
-       continue;
+       tty_printf(_("Invalid selection.\n"));
       else if(*answer=='\0' || *answer==togglers[6] || *answer==togglers[7])
        break;
       else if((*answer==togglers[0] || *answer==togglers[1])
@@ -1318,6 +1402,8 @@ ask_key_flags(int algo)
          else
            current|=PUBKEY_USAGE_AUTH;
        }
+      else
+       tty_printf(_("Invalid selection.\n"));
     }
 
   xfree(answer);
@@ -1362,7 +1448,7 @@ ask_algo (int addmode, unsigned int *r_usage)
        }
        else if( algo == 7 && opt.expert ) {
            algo = PUBKEY_ALGO_RSA;
-           *r_usage=ask_key_flags(algo);
+           *r_usage=ask_key_flags(algo,addmode);
            break;
        }
        else if( algo == 6 && addmode ) {
@@ -1382,7 +1468,7 @@ ask_algo (int addmode, unsigned int *r_usage)
        }
        else if( algo == 3 && opt.expert ) {
            algo = PUBKEY_ALGO_DSA;
-           *r_usage=ask_key_flags(algo);
+           *r_usage=ask_key_flags(algo,addmode);
            break;
        }
        else if( algo == 2 ) {
@@ -1411,10 +1497,10 @@ ask_keysize( int algo )
   switch(algo)
     {
     case PUBKEY_ALGO_DSA:
-      if(opt.expert)
+      if(opt.flags.dsa2)
        {
          def=1024;
-         max=1024;
+         max=3072;
        }
       else
        {
@@ -1490,6 +1576,8 @@ parse_expire_string( const char *string )
 
     if( !*string )
       seconds = 0;
+    else if ( !strncmp (string, "seconds=", 8) )
+      seconds = atoi (string+8);
     else if( (abs_date = scan_isodatestr(string)) && abs_date > curtime )
       seconds = abs_date - curtime;
     else if( (mult=check_valid_days(string)) )
@@ -1951,7 +2039,7 @@ parse_parameter_usage (const char *fname,
         }
     }
     r->u.usage = use;
-    return 0;
+    return 1;
 }
 
 static int
@@ -2058,14 +2146,14 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
   const char *s1, *s2, *s3;
   size_t n;
   char *p;
-  int have_user_id=0;
+  int have_user_id=0,err,algo;
 
   /* Check that we have all required parameters. */
   r = get_parameter( para, pKEYTYPE );
   if(r)
     {
-      if(check_pubkey_algo2(get_parameter_algo(para,pKEYTYPE),
-                           PUBKEY_USAGE_SIG))
+      algo=get_parameter_algo(para,pKEYTYPE);
+      if(check_pubkey_algo2(algo,PUBKEY_USAGE_SIG))
        {
          log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
          return -1;
@@ -2077,19 +2165,41 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
       return -1;
     }
 
-  if (parse_parameter_usage (fname, para, pKEYUSAGE))
+  err=parse_parameter_usage (fname, para, pKEYUSAGE);
+  if(err==0)
+    {
+      /* Default to algo capabilities if key-usage is not provided */
+      r=xmalloc_clear(sizeof(*r));
+      r->key=pKEYUSAGE;
+      r->u.usage=openpgp_pk_algo_usage(algo);
+      r->next=para;
+      para=r;
+    }
+  else if(err==-1)
     return -1;
 
   r = get_parameter( para, pSUBKEYTYPE );
   if(r)
     {
-      if(check_pubkey_algo( get_parameter_algo( para, pSUBKEYTYPE)))
+      algo=get_parameter_algo( para, pSUBKEYTYPE);
+      if(check_pubkey_algo(algo))
        {
          log_error("%s:%d: invalid algorithm\n", fname, r->lnr );
          return -1;
        }
 
-      if(parse_parameter_usage (fname, para, pSUBKEYUSAGE))
+      err=parse_parameter_usage (fname, para, pSUBKEYUSAGE);
+      if(err==0)
+       {
+         /* Default to algo capabilities if subkey-usage is not
+            provided */
+         r=xmalloc_clear(sizeof(*r));
+         r->key=pSUBKEYUSAGE;
+         r->u.usage=openpgp_pk_algo_usage(algo);
+         r->next=para;
+         para=r;
+       }
+      else if(err==-1)
        return -1;
     }
 
@@ -2499,12 +2609,12 @@ generate_keypair (const char *fname, const char *card_serialno,
           sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
           r->next = para;
           para = r;
-          tty_printf(_("DSA keypair will have %u bits.\n"),1024);
-          r = xmalloc_clear( sizeof *r + 20 );
-          r->key = pKEYLENGTH;
-          strcpy( r->u.value, "1024" );
-          r->next = para;
-          para = r;
+         nbits = ask_keysize( PUBKEY_ALGO_DSA );
+         r = xmalloc_clear( sizeof *r + 20 );
+         r->key = pKEYLENGTH;
+         sprintf( r->u.value, "%u", nbits);
+         r->next = para;
+         para = r;
           r = xmalloc_clear( sizeof *r + 20 );
           r->key = pKEYUSAGE;
           strcpy( r->u.value, "sign" );
@@ -2544,7 +2654,7 @@ generate_keypair (const char *fname, const char *card_serialno,
             }
            
         }
-       
+
       nbits = ask_keysize( algo );
       r = xmalloc_clear( sizeof *r + 20 );
       r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
@@ -2798,7 +2908,7 @@ do_generate_keypair( struct para_data_s *para,
       }
     else
       {
-        rc = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, sec_root,
+        rc = gen_card_key (PUBKEY_ALGO_RSA, 1, 1, pub_root, sec_root, NULL,
                            get_parameter_u32 (para, pKEYEXPIRE), para);
         if (!rc)
           {
@@ -2834,7 +2944,7 @@ do_generate_keypair( struct para_data_s *para,
 
     if (!rc && card && get_parameter (para, pAUTHKEYTYPE))
       {
-        rc = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, sec_root,
+        rc = gen_card_key (PUBKEY_ALGO_RSA, 3, 0, pub_root, sec_root, NULL,
                            get_parameter_u32 (para, pKEYEXPIRE), para);
         
         if (!rc)
@@ -2870,6 +2980,7 @@ do_generate_keypair( struct para_data_s *para,
               }
             else
               rc = gen_card_key (PUBKEY_ALGO_RSA, 2, 0, pub_root, sec_root,
+                                NULL,
                                  get_parameter_u32 (para, pKEYEXPIRE), para);
           }
 
@@ -3094,7 +3205,7 @@ generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
     }
 
     rc = do_create( algo, nbits, pub_keyblock, sec_keyblock,
-                                     dek, s2k, &sub_sk, expire, 1 );
+                   dek, s2k, &sub_sk, expire, 1 );
     if( !rc )
        rc = write_keybinding(pub_keyblock, pub_keyblock, pri_sk, sub_sk, use);
     if( !rc )
@@ -3128,7 +3239,7 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
 {
   int okay=0, rc=0;
   KBNODE node;
-  PKT_secret_key *pri_sk = NULL;
+  PKT_secret_key *pri_sk = NULL, *sub_sk;
   int algo;
   unsigned int use;
   u32 expire;
@@ -3208,11 +3319,12 @@ generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock,
 
   if (passphrase)
     set_next_passphrase (passphrase);
-  rc = gen_card_key (algo, keyno, 0, pub_keyblock, sec_keyblock, expire, para);
+  rc = gen_card_key (algo, keyno, 0, pub_keyblock, sec_keyblock,
+                    &sub_sk, expire, para);
   if (!rc)
-    rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, NULL, use);
+    rc = write_keybinding (pub_keyblock, pub_keyblock, pri_sk, sub_sk, use);
   if (!rc)
-    rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, NULL, use);
+    rc = write_keybinding (sec_keyblock, pub_keyblock, pri_sk, sub_sk, use);
   if (!rc)
     {
       okay = 1;
@@ -3259,7 +3371,7 @@ write_keyblock( IOBUF out, KBNODE node )
 
 static int
 gen_card_key (int algo, int keyno, int is_primary,
-              KBNODE pub_root, KBNODE sec_root,
+              KBNODE pub_root, KBNODE sec_root, PKT_secret_key **ret_sk,
               u32 expireval, struct para_data_s *para)
 {
 #ifdef ENABLE_CARD_SUPPORT
@@ -3272,8 +3384,8 @@ gen_card_key (int algo, int keyno, int is_primary,
 
   assert (algo == PUBKEY_ALGO_RSA);
   
-
-  rc = agent_scd_genkey (&info, keyno, 1);
+  /* Fixme: We don't have the serialnumber available, thus passing NULL. */
+  rc = agent_scd_genkey (&info, keyno, 1, NULL);
 /*    if (gpg_err_code (rc) == GPG_ERR_EEXIST) */
 /*      { */
 /*        tty_printf ("\n"); */
@@ -3320,6 +3432,9 @@ gen_card_key (int algo, int keyno, int is_primary,
         sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
     }
 
+  if( ret_sk )
+    *ret_sk = sk;
+
   pkt = xcalloc (1,sizeof *pkt);
   pkt->pkttype = is_primary ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
   pkt->pkt.public_key = pk;
@@ -3548,7 +3663,9 @@ save_unprotected_key_to_card (PKT_secret_key *sk, int keyno)
   sprintf (numbuf, "%lu:", (unsigned long)strlen (numbuf2));
   p = stpcpy (stpcpy (stpcpy (p, numbuf), numbuf2), "))");
 
-  rc = agent_scd_writekey (keyno, sexp, p - sexp);
+  /* Fixme: Unfortunately we don't have the serialnumber available -
+     thus we can't pass it down to the agent. */ 
+  rc = agent_scd_writekey (keyno, NULL, sexp, p - sexp);
 
  leave:
   xfree (sexp);