* keygen.c (do_add_key_flags, parse_parameter_usage): Add support
authorWerner Koch <wk@gnupg.org>
Tue, 30 Sep 2003 08:00:08 +0000 (08:00 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 30 Sep 2003 08:00:08 +0000 (08:00 +0000)
the proposed AUTH key flag.
* getkey.c (fixup_uidnode, merge_selfsigs_main)
(merge_selfsigs_subkey, premerge_public_with_secret): Ditto.
* keylist.c (print_capabilities): Ditto.

* parse-packet.c (parse_key): Allow to parse the divert-to-card
S2K mode.
* build-packet.c (do_secret_key): Handle divert-to-card S2K
* seckey-cert.c (is_secret_key_protected): Ditto.
(check_secret_key): Ditto.

* keygen.c (do_ask_passphrase): Renamed from ask_passphrase.
* passphrase.c (ask_passphrase): New.

13 files changed:
g10/ChangeLog
g10/build-packet.c
g10/cardglue.c
g10/getkey.c
g10/keydb.h
g10/keygen.c
g10/keylist.c
g10/parse-packet.c
g10/passphrase.c
g10/seckey-cert.c
g10/sign.c
include/ChangeLog
include/cipher.h

index a0905ed..7b0448d 100644 (file)
@@ -1,3 +1,20 @@
+2003-09-29  Werner Koch  <wk@gnupg.org>
+
+       * keygen.c (do_add_key_flags, parse_parameter_usage): Add support
+       the proposed AUTH key flag.
+       * getkey.c (fixup_uidnode, merge_selfsigs_main) 
+       (merge_selfsigs_subkey, premerge_public_with_secret): Ditto.
+       * keylist.c (print_capabilities): Ditto.
+
+       * parse-packet.c (parse_key): Allow to parse the divert-to-card
+       S2K mode.
+       * build-packet.c (do_secret_key): Handle divert-to-card S2K
+       * seckey-cert.c (is_secret_key_protected): Ditto.
+       (check_secret_key): Ditto.
+
+       * keygen.c (do_ask_passphrase): Renamed from ask_passphrase.
+       * passphrase.c (ask_passphrase): New.
+
 2003-09-28  Werner Koch  <wk@gnupg.org>
 
        * g10.c (main): New commands --card-edit, --card-status and
index af97be4..cd0bb8a 100644 (file)
@@ -410,8 +410,9 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
            if( sk->protect.s2k.mode == 3 )
                iobuf_put(a, sk->protect.s2k.count ); 
 
-            /* For out special mode 1001 we do not need an IV */
-           if( sk->protect.s2k.mode != 1001 )
+            /* For out special modes 1001, 1002 we do not need an IV */
+           if( sk->protect.s2k.mode != 1001 
+              && sk->protect.s2k.mode != 1002 )
                iobuf_write(a, sk->protect.iv, sk->protect.ivlen );
        }
     }
@@ -420,6 +421,14 @@ do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
 
     if( sk->protect.s2k.mode == 1001 )
         ; /* GnuPG extension - don't write a secret key at all */ 
+    else if( sk->protect.s2k.mode == 1002 )
+      {  /* GnuPG extension - divert to OpenPGP smartcard. */ 
+       iobuf_put(a, sk->protect.ivlen ); /* length of the serial
+                                             number or 0 for no serial
+                                             number. */
+        /* The serial number gets stored in the IV field. */
+        iobuf_write(a, sk->protect.iv, sk->protect.ivlen);
+      }
     else if( sk->is_protected && sk->version >= 4 ) {
         /* The secret key is protected - write it out as it is */
        byte *p;
index 8924889..358eb90 100644 (file)
@@ -53,7 +53,7 @@ struct ctrl_ctx_s {
 
 
 static char *default_reader_port;
-
+static APP current_app;
 
 
 
@@ -246,6 +246,7 @@ open_card (void)
   int rc;
   APP app;
 
+  current_app = NULL;/* FIXME: Release it first.*/
   slot = apdu_open_reader (default_reader_port);
   if (slot == -1)
     {
@@ -265,6 +266,7 @@ open_card (void)
     }
 
   app->initialized = 1;
+  current_app = app;
   return app;
 }
 
@@ -443,7 +445,7 @@ agent_learn (struct agent_card_info_s *info)
   time_t stamp;
   char *serial;
   
-  app = open_card ();
+  app = current_app? current_app : open_card ();
   if (!app)
     return gpg_error (GPG_ERR_CARD);
 
@@ -462,13 +464,39 @@ agent_learn (struct agent_card_info_s *info)
   return rc;
 }
 
+static int 
+pin_cb (void *opaque, const char *info, char **retstr)
+{
+  char *value;
+  int canceled;
+
+  *retstr = NULL;
+  log_debug ("asking for PIN '%s'\n", info);
+
+  value = ask_passphrase (info, "Enter PIN: ", &canceled);
+  if (!value && canceled)
+    return -1;
+  else if (!value)
+    return G10ERR_GENERAL;
+
+  *retstr = value;
+  return 0;
+}
+
+
+
 /* Send a SETATTR command to the SCdaemon. */
 int 
 agent_scd_setattr (const char *name,
                    const unsigned char *value, size_t valuelen)
 {
+  APP app;
 
-  return gpg_error (GPG_ERR_CARD);
+  app = current_app? current_app : open_card ();
+  if (!app)
+    return gpg_error (GPG_ERR_CARD);
+
+  return app->fnc.setattr (app, name, pin_cb, NULL, value, valuelen);
 }
 
 /* Send a GENKEY command to the SCdaemon. */
@@ -481,12 +509,24 @@ agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
 
 /* Send a PKSIGN command to the SCdaemon. */
 int 
-agent_scd_pksign (const char *keyid, int hashalgo,
+agent_scd_pksign (const char *serialno, int hashalgo,
                   const unsigned char *indata, size_t indatalen,
                   char **r_buf, size_t *r_buflen)
 {
+  APP app;
 
-  return gpg_error (GPG_ERR_CARD);
+  *r_buf = NULL;
+  *r_buflen = 0;
+  app = current_app? current_app : open_card ();
+  if (!app)
+    return gpg_error (GPG_ERR_CARD);
+
+  /* Check that the card's serialnumber is as required.*/
+
+  return app->fnc.sign (app, serialno, hashalgo,
+                        pin_cb, NULL,
+                        indata, indatalen,
+                        r_buf, r_buflen);
 }
 
 
index 5e4ca44..72b80ba 100644 (file)
@@ -1279,6 +1279,8 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated )
             uid->help_key_usage |= PUBKEY_USAGE_ENC;
         /* Note: we do not set the CERT flag here because it can be assumed
          * that thre is no real policy to set it. */
+        if ( (*p & 0x20) )    
+            uid->help_key_usage |= PUBKEY_USAGE_AUTH;
     }
 
     /* ditto or the key expiration */
@@ -1490,6 +1492,8 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
                 key_usage |= PUBKEY_USAGE_SIG;
             if ( (*p & 12) )    
                 key_usage |= PUBKEY_USAGE_ENC;
+            if ( (*p & 0x20) )    
+                key_usage |= PUBKEY_USAGE_AUTH;
         }
 
        p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL);
@@ -1878,6 +1882,8 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
             key_usage |= PUBKEY_USAGE_SIG;
         if ( (*p & 12) )    
             key_usage |= PUBKEY_USAGE_ENC;
+        if ( (*p & 0x20) )    
+            key_usage |= PUBKEY_USAGE_AUTH;
     }
     if ( !key_usage ) { /* no key flags at all: get it from the algo */
         key_usage = openpgp_pk_algo_usage ( subpk->pubkey_algo );
@@ -2075,7 +2081,8 @@ premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
                             /* The secret parts are not available so
                                we can't use that key for signing etc.
                                Fix the pubkey usage */
-                            pk->pubkey_usage &= ~PUBKEY_USAGE_SIG;
+                            pk->pubkey_usage &= ~(PUBKEY_USAGE_SIG
+                                                  |PUBKEY_USAGE_AUTH);
                         }
                         /* transfer flag bits 0 and 1 to the pubblock */
                         pub->flag |= (sec->flag &3);
index 216add2..d02e427 100644 (file)
@@ -186,6 +186,8 @@ int  build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list,
 int  have_static_passphrase(void);
 void read_passphrase_from_fd( int fd );
 void passphrase_clear_cache ( u32 *keyid, int algo );
+char *ask_passphrase (const char *description, const char *prompt,
+                      int *canceled);
 DEK *passphrase_to_dek( u32 *keyid, int pubkey_algo,
                        int cipher_algo, STRING2KEY *s2k, int mode,
                         const char *tryagain_text, int *canceled);
index 4b736e1..bcfdcfa 100644 (file)
@@ -145,6 +145,8 @@ do_add_key_flags (PKT_signature *sig, unsigned int use)
       }
     if (use & PUBKEY_USAGE_ENC)
         buf[0] |= 0x04 | 0x08;
+    if (use & PUBKEY_USAGE_AUTH)
+        buf[0] |= 0x20;
     build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
 }
 
@@ -1486,7 +1488,7 @@ ask_user_id( int mode )
 
 
 static DEK *
-ask_passphrase( STRING2KEY **ret_s2k )
+do_ask_passphrase( STRING2KEY **ret_s2k )
 {
     DEK *dek = NULL;
     STRING2KEY *s2k;
@@ -1651,6 +1653,8 @@ parse_parameter_usage (const char *fname,
             use |= PUBKEY_USAGE_SIG;
         else if ( !ascii_strcasecmp (p, "encrypt") )
             use |= PUBKEY_USAGE_ENC;
+        else if ( !ascii_strcasecmp (p, "auth") )
+            use |= PUBKEY_USAGE_AUTH;
         else {
             log_error("%s:%d: invalid usage list\n", fname, r->lnr );
             return -1; /* error */
@@ -2168,7 +2172,7 @@ generate_keypair( const char *fname )
     r->next = para;
     para = r;
 
-    dek = ask_passphrase( &s2k );
+    dek = do_ask_passphrase( &s2k );
     if( dek ) {
        r = m_alloc_clear( sizeof *r );
        r->key = pPASSPHRASE_DEK;
index 2628881..de5b575 100644 (file)
@@ -475,11 +475,14 @@ print_capabilities (PKT_public_key *pk, PKT_secret_key *sk, KBNODE keyblock)
          if( pk? pk->is_primary : sk->is_primary )
            putchar ('c');
        }
+
+      if ( (use & PUBKEY_USAGE_AUTH) )
+        putchar ('a');
     }
 
     if ( keyblock ) { /* figure out the usable capabilities */
         KBNODE k;
-        int enc=0, sign=0, cert=0, disabled=0;
+        int enc=0, sign=0, cert=0, auth=0, disabled=0;
 
         for (k=keyblock; k; k = k->next ) {
             if ( k->pkt->pkttype == PKT_PUBLIC_KEY 
@@ -498,6 +501,8 @@ print_capabilities (PKT_public_key *pk, PKT_secret_key *sk, KBNODE keyblock)
                        if(pk->is_primary)
                          cert = 1;
                      }
+                    if ( (pk->pubkey_usage & PUBKEY_USAGE_AUTH) )
+                      auth = 1;
                 }
             }
             else if ( k->pkt->pkttype == PKT_SECRET_KEY 
@@ -513,6 +518,8 @@ print_capabilities (PKT_public_key *pk, PKT_secret_key *sk, KBNODE keyblock)
                        if(sk->is_primary)
                          cert = 1;
                      }
+                    if ( (sk->pubkey_usage & PUBKEY_USAGE_AUTH) )
+                        auth = 1;
                 }
             }
         }
@@ -522,6 +529,8 @@ print_capabilities (PKT_public_key *pk, PKT_secret_key *sk, KBNODE keyblock)
             putchar ('S');
         if (cert)
             putchar ('C');
+        if (auth)
+            putchar ('A');
         if (disabled)
             putchar ('D');
     }
index 0831d26..e84609e 100644 (file)
@@ -1590,6 +1590,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
     if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY ) {
        PKT_secret_key *sk = pkt->pkt.secret_key;
        byte temp[16];
+        size_t snlen = 0;
 
        if( !npkey ) {
            sk->skey[0] = mpi_set_opaque( NULL,
@@ -1662,6 +1663,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
                    break;
                  case 1001: if( list_mode ) printf(  "\tgnu-dummy S2K" );
                    break;
+                 case 1002: if (list_mode) printf("\tgnu-divert-to-card S2K");
+                   break;
                  default:
                    if( list_mode )
                        printf(  "\tunknown %sS2K %d\n",
@@ -1697,6 +1700,19 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
                        printf("\tprotect count: %lu\n",
                                            (ulong)sk->protect.s2k.count);
                }
+               else if( sk->protect.s2k.mode == 1002 ) {
+                    /* Read the serial number. */
+                    if (pktlen < 1) {
+                      rc = G10ERR_INVALID_PACKET;
+                       goto leave;
+                   }
+                   snlen = iobuf_get (inp);
+                   pktlen--;
+                    if (pktlen < snlen || snlen == -1) {
+                       rc = G10ERR_INVALID_PACKET;
+                       goto leave;
+                    }
+               }
            }
            /* Note that a sk->protect.algo > 110 is illegal, but I'm
               not erroring on it here as otherwise there would be no
@@ -1726,6 +1742,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
            }
            if( sk->protect.s2k.mode == 1001 )
                sk->protect.ivlen = 0;
+           else if( sk->protect.s2k.mode == 1002 )
+               sk->protect.ivlen = snlen < 16? snlen : 16;
 
            if( pktlen < sk->protect.ivlen ) {
                rc = G10ERR_INVALID_PACKET;
@@ -1734,7 +1752,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
            for(i=0; i < sk->protect.ivlen && pktlen; i++, pktlen-- )
                temp[i] = iobuf_get_noeof(inp);
            if( list_mode ) {
-               printf(  "\tprotect IV: ");
+               printf( sk->protect.s2k.mode == 1002? "\tserial-number: "
+                                                    : "\tprotect IV: ");
                for(i=0; i < sk->protect.ivlen; i++ )
                    printf(" %02x", temp[i] );
                putchar('\n');
@@ -1747,7 +1766,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
         * If the user is so careless, not to protect his secret key,
         * we can assume, that he operates an open system :=(.
         * So we put the key into secure memory when we unprotect it. */
-       if( sk->protect.s2k.mode == 1001 ) {
+       if( sk->protect.s2k.mode == 1001 
+            || sk->protect.s2k.mode == 1002 ) {
            /* better set some dummy stuff here */
            sk->skey[npkey] = mpi_set_opaque(NULL, m_strdup("dummydata"), 10);
            pktlen = 0;
index a48f220..10dd3ff 100644 (file)
@@ -1004,22 +1004,57 @@ passphrase_clear_cache ( u32 *keyid, int algo )
 
 
 /****************
- * Get a passphrase for the secret key with KEYID, display TEXT
- * if the user needs to enter the passphrase.
- * mode 0 = standard, 1 = same but don't show key info,
- *      2 = create new passphrase
- * Returns: a DEK with a session key; caller must free
- *         or NULL if the passphrase was not correctly repeated.
- *         (only for mode 2)
- *         a dek->keylen of 0 means: no passphrase entered.
- *         (only for mode 2)
- *
- * pubkey_algo is only informational.  Note that TRYAGAIN_TEXT must
- * not be translated as this is done within this function (required to
- * switch to utf-8 when the agent is in use).  If CANCELED is not
- * NULL, it is set to 1 if the user choosed to cancel the operation,
- * otherwise it will be set to 0.
+ * Ask for a passphrase and return that string.
  */
+char *
+ask_passphrase (const char *description, const char *prompt, int *canceled)
+{
+  char *pw = NULL;
+  
+  if (canceled)
+    *canceled = 0;
+
+  if (is_status_enabled())
+    write_status_text( STATUS_NEED_PASSPHRASE_SYM, "0 0 0");
+
+  if (!opt.batch && description)
+    tty_printf ("\n%s\n",description);
+               
+ agent_died:
+  if ( opt.use_agent ) 
+    {
+      pw = agent_get_passphrase (NULL, 0,  description, canceled );
+      if (!pw)
+        {
+          if (!opt.use_agent)
+            goto agent_died;
+          pw = NULL;
+        }
+    }
+  else if (fd_passwd) 
+    {
+      pw = m_alloc_secure (strlen(fd_passwd)+1);
+      strcpy (pw, fd_passwd);
+    }
+  else if (opt.batch)
+    {
+      log_error(_("can't query password in batchmode\n"));
+      pw = NULL;
+    }
+  else {
+    pw = cpr_get_hidden("passphrase.ask",
+                        prompt?prompt : _("Enter passphrase: ") );
+    tty_kill_prompt();
+  }
+
+  if (!pw || !*pw)
+    write_status( STATUS_MISSING_PASSPHRASE );
+
+  return pw;
+}
+
+
+
 DEK *
 passphrase_to_dek( u32 *keyid, int pubkey_algo,
                   int cipher_algo, STRING2KEY *s2k, int mode,
index 76f0ee2..5730735 100644 (file)
@@ -225,6 +225,9 @@ check_secret_key( PKT_secret_key *sk, int n )
     int rc = G10ERR_BAD_PASS;
     int i,mode;
 
+    if (sk && sk->is_protected && sk->protect.s2k.mode == 1002)
+      return 0; /* Let the card support stuff handle this. */
+
     if(n<0)
       {
        n=abs(n);
@@ -265,11 +268,14 @@ check_secret_key( PKT_secret_key *sk, int n )
 /****************
  * check whether the secret key is protected.
  * Returns: 0 not protected, -1 on error or the protection algorithm
+ *                           -2 indicates a card stub.
  */
 int
 is_secret_key_protected( PKT_secret_key *sk )
 {
-    return sk->is_protected? sk->protect.algo : 0;
+    return sk->is_protected?
+               sk->protect.s2k.mode == 1002? -2
+                                           : sk->protect.algo : 0;
 }
 
 
index d1d9814..b7fd7bb 100644 (file)
@@ -313,18 +313,19 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig,
         size_t rbuflen;
         char *snbuf;
         
-        snbuf = serialno_and_fpr_from_sk (sk->protect.iv, sk->protect.ivlen,sk);
-        rc = G10ERR_GENERAL;
-/*              agent_scd_pksign (snbuf, digest_algo, */
-/*                                gcry_md_read (md, digest_algo), */
-/*                                gcry_md_get_algo_dlen (digest_algo), */
-/*                                &rbuf, &rbuflen); */
+        snbuf = serialno_and_fpr_from_sk (sk->protect.iv,
+                                          sk->protect.ivlen, sk);
+        rc = agent_scd_pksign (snbuf, digest_algo,
+                               md_read (md, digest_algo),
+                               md_digest_length (digest_algo),
+                               &rbuf, &rbuflen);
         xfree (snbuf);
         if (!rc)
           {
-/*             if (gcry_mpi_scan (&sig->data[0], GCRYMPI_FMT_USG, */
-/*                                rbuf, rbuflen, NULL)) */
-              BUG ();
+            sig->data[0] = mpi_alloc ( (rbuflen+BYTES_PER_MPI_LIMB-1)
+                                       / BYTES_PER_MPI_LIMB );
+            mpi_set_buffer (sig->data[0], rbuf, rbuflen, 0);
+            xfree (rbuf);
           }
       }
     else 
index e9f720f..e0e1f35 100644 (file)
@@ -1,3 +1,7 @@
+2003-09-29  Werner Koch  <wk@gnupg.org>
+
+       * cipher.h (PUBKEY_USAGE_AUTH): New.
+
 2003-09-28  Timo Schulz  <twoaday@freakmail.de>
 
        * util.h [WIN32]: Prototype for asprintf.
index e450c14..1a29c71 100644 (file)
@@ -54,6 +54,7 @@
 #define PUBKEY_USAGE_SIG     1     /* key is good for signatures */
 #define PUBKEY_USAGE_ENC     2     /* key is good for encryption */
 #define PUBKEY_USAGE_CERT    4      /* key is also good to certify other keys*/
+#define PUBKEY_USAGE_AUTH    8      /* key is good for authentication */
 
 #define DIGEST_ALGO_MD5       1
 #define DIGEST_ALGO_SHA1      2