As promised a agent which already does some things. Not very useful
authorWerner Koch <wk@gnupg.org>
Sun, 25 Nov 2001 14:53:10 +0000 (14:53 +0000)
committerWerner Koch <wk@gnupg.org>
Sun, 25 Nov 2001 14:53:10 +0000 (14:53 +0000)
yet but may be of help for using it in ther contexts.

agent/Makefile.am
agent/agent.h
agent/command.c
agent/gpg-agent.c
agent/pksign.c

index f4b6bf8..a8172be 100644 (file)
@@ -29,6 +29,7 @@ gpg_agent_SOURCES = \
        pksign.c 
 
 gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a  \
+               ../common/libcommon.a \
               ../../libgcrypt/src/.libs/libgcrypt.so.1 
 
 
index e689b8e..95bfa08 100644 (file)
@@ -55,10 +55,11 @@ struct server_local_s;
 struct server_control_s {
   struct server_local_s *server_local;
   struct {
+    int algo;
     unsigned char value[MAX_DIGEST_LEN];
     int valuelen;
   } digest;
-
+  char keygrip[20];
 
 };
 typedef struct server_control_s *CTRL;
index 62950b3..80e1318 100644 (file)
                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
 
+#if MAX_DIGEST_LEN < 20
+#error MAX_DIGEST_LEN shorter than keygrip
+#endif
+
 /* Data used to associate an Assuan context with local server data */
 struct server_local_s {
   ASSUAN_CONTEXT assuan_ctx;
   int message_fd;
 };
 
-/* SETHASH <hexstring>
+
+static void
+reset_notify (ASSUAN_CONTEXT ctx)
+{
+  CTRL ctrl = assuan_get_pointer (ctx);
+
+  memset (ctrl->keygrip, 0, 20);
+  ctrl->digest.valuelen = 0;
+}
+
+/* SIGKEY <hexstring_with_keygrip>
+
+   Set the  key used for a sign operation */
+static int
+cmd_sigkey (ASSUAN_CONTEXT ctx, char *line)
+{
+  int n;
+  char *p;
+  CTRL ctrl = assuan_get_pointer (ctx);
+  unsigned char *buf;
+
+  /* parse the hash value */
+  for (p=line,n=0; hexdigitp (*p); p++, n++)
+    ;
+  if (*p)
+    return set_error (Parameter_Error, "invalid hexstring");
+  if ((n&1))
+    return set_error (Parameter_Error, "odd number of digits");
+  n /= 2;
+  if (n != 20)
+    return set_error (Parameter_Error, "invalid length of keygrip");
+
+  buf = ctrl->keygrip;
+  for (p=line, n=0; n < 20; p += 2, n++)
+    buf[n] = xtoi_2 (p);
+  return 0;
+}
+
+/* SETHASH <algonumber> <hexstring> 
 
   The client can use this command to tell the server about the data
   (which usually is a hash) to be signed. */
@@ -61,6 +103,16 @@ cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
   char *p;
   CTRL ctrl = assuan_get_pointer (ctx);
   unsigned char *buf;
+  char *endp;
+  int algo;
+
+  /* parse the algo number and check it */
+  algo = (int)strtoul (line, &endp, 10);
+  for (line = endp; *line == ' ' || *line == '\t'; line++)
+    ;
+  if (!algo || gcry_md_test_algo (algo))
+    return set_error (Unsupported_Algorithm, NULL);
+  ctrl->digest.algo = algo;
 
   /* parse the hash value */
   for (p=line,n=0; hexdigitp (*p); p++, n++)
@@ -102,36 +154,6 @@ cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
 }
 
 
-/* MESSAGE FD=<n>
-
-   Set the file descriptor to read a message which is used with
-   detached signatures */
-static int 
-cmd_message (ASSUAN_CONTEXT ctx, char *line)
-{
-#if 0
-  char *endp;
-  int fd;
-  CTRL ctrl = assuan_get_pointer (ctx);
-
-  if (strncmp (line, "FD=", 3))
-    return set_error (Syntax_Error, "FD=<n> expected");
-  line += 3;
-  if (!digitp (*line))
-    return set_error (Syntax_Error, "number required");
-  fd = strtoul (line, &endp, 10);
-  if (*endp)
-    return set_error (Syntax_Error, "garbage found");
-  if (fd == -1)
-    return set_error (No_Input, NULL);
-
-  ctrl->server_local->message_fd = fd;
-  return 0;
-#endif
-  return set_error (Not_Implemented, NULL);
-}
-
-
 \f
 /* Tell the assuan library about our commands */
 static int
@@ -142,11 +164,11 @@ register_commands (ASSUAN_CONTEXT ctx)
     int cmd_id;
     int (*handler)(ASSUAN_CONTEXT, char *line);
   } table[] = {
+    { "SIGKEY",     0,  cmd_sigkey },
     { "SETHASH",    0,  cmd_sethash },
     { "PKSIGN",     0,  cmd_pksign },
     { "",     ASSUAN_CMD_INPUT, NULL }, 
     { "",     ASSUAN_CMD_OUTPUT, NULL }, 
-    { "MESSAGE",    0,  cmd_message },
     { NULL }
   };
   int i, j, rc;
@@ -160,6 +182,7 @@ register_commands (ASSUAN_CONTEXT ctx)
       if (rc)
         return rc;
     } 
+  assuan_register_reset_notify (ctx, reset_notify);
   return 0;
 }
 
index 4215789..71e9090 100644 (file)
@@ -102,9 +102,13 @@ typedef struct {
 #define MAX_CACHE_AGE  1000 /* should fit into an integer */
 static volatile int caught_fatal_sig = 0;
 static volatile int shut_me_down = 0;
-static CACHE_SLOT the_cache[MAX_CACHE_ENTRIES];
+/*  static CACHE_SLOT the_cache[MAX_CACHE_ENTRIES]; */
 static char *socket_name = NULL;
 
+/* It is possible that we are currently running under setuid permissions */
+static int maybe_setuid = 1;
+
+
 #define buftou32( p )  ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \
                       (*((byte*)(p)+2) << 8) | (*((byte*)(p)+3)))
 #define u32tobuf( p, a ) do {                                  \
@@ -116,10 +120,7 @@ static char *socket_name = NULL;
 
 
 static int start_listening ( const char *name );
-static int writen ( int fd, const void *buf, size_t nbytes );
-static int readn ( int fd, void *buf, size_t buflen, size_t *ret_nread );
 
-static void process_request ( int fd );
 
 
 static const char *
@@ -204,6 +205,7 @@ main (int argc, char **argv )
 {
   ARGPARSE_ARGS pargs;
   int orig_argc;
+  int may_coredump;
   char **orig_argv;
   FILE *configfp = NULL;
   char *configname = NULL;
@@ -223,6 +225,10 @@ main (int argc, char **argv )
   char *logfile = NULL;
 
   set_strusage( my_strusage );
+  gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
+  /* Please note that we may running SUID(ROOT), so be very CAREFUL
+     when adding any stuff between here and the call to INIT_SECMEM()
+     somewhere after the option parsing */
   /*   log_set_name ("gpg-agent"); */
   srand (time (NULL)); /* the about dialog uses rand() */
   i18n_init ();
@@ -236,10 +242,13 @@ main (int argc, char **argv )
     }
 
   assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
+  gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
+
+  may_coredump = 0/* FIXME: disable_core_dumps()*/;
 
 
-  shell = getenv("SHELL");
-  if (shell && strlen(shell) >= 3 && !strcmp(shell+strlen(shell)-3, "csh") )
+  shell = getenv ("SHELL");
+  if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
     csh_style = 1;
   
   opt.homedir = getenv("GNUPGHOME");
@@ -275,6 +284,15 @@ main (int argc, char **argv )
           opt.homedir = pargs.r.ret_str;
     }
 
+  /* initialize the secure memory. */
+  gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
+  maybe_setuid = 0;
+
+  /* 
+     Now we are now working under our real uid 
+  */
+
+
   if (default_config)
     configname = make_filename (opt.homedir, "gpg-agent.conf", NULL );
   
@@ -648,6 +666,7 @@ start_listening (const char *name)
   return -1;
 }
 
+#if 0
 /* Look for the passprase as given by the 20 bytes DATA and return it's
   slot number.  If this passphrase is not in the cache, return -1 */
 static int
@@ -751,7 +770,6 @@ passphrase_dialog ( const byte *fpr, const char *user_string )
 }
 
 
-
 static int
 writen ( int fd, const void *buf, size_t nbytes )
 {
@@ -993,6 +1011,6 @@ process_request ( int fd )
   return;
 #endif
 }
-
+#endif
 
 
index 69093a0..f597c8a 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <assert.h>
 #include <unistd.h>
 
 #include "agent.h"
 
 
-/* SIGN whatever information we have accumulated in CTRL and write it back to 
-   OUTFP. */
+static int
+do_encode_md (const unsigned char *digest, size_t digestlen, int algo,
+              unsigned int nbits, GCRY_MPI *r_val)
+{
+  int nframe = (nbits+7) / 8;
+  byte *frame;
+  int i, n;
+  byte asn[100];
+  size_t asnlen;
+
+  asnlen = DIM(asn);
+  if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
+    {
+      log_error ("No object identifier for algo %d\n", algo);
+      return GNUPG_Internal_Error;
+    }
+
+  if (digestlen + asnlen + 4  > nframe )
+    {
+      log_error ("can't encode a %d bit MD into a %d bits frame\n",
+                 (int)(digestlen*8), (int)nbits);
+      return GNUPG_Internal_Error;
+    }
+  
+  /* We encode the MD in this way:
+   *
+   *      0  A PAD(n bytes)   0  ASN(asnlen bytes)  MD(len bytes)
+   *
+   * PAD consists of FF bytes.
+   */
+  frame = xtrymalloc (nframe);
+  if (!frame)
+    return GNUPG_Out_Of_Core;
+  n = 0;
+  frame[n++] = 0;
+  frame[n++] = 1; /* block type */
+  i = nframe - digestlen - asnlen -3 ;
+  assert ( i > 1 );
+  memset ( frame+n, 0xff, i ); n += i;
+  frame[n++] = 0;
+  memcpy ( frame+n, asn, asnlen ); n += asnlen;
+  memcpy ( frame+n, digest, digestlen ); n += digestlen;
+  assert ( n == nframe );
+  if (DBG_CRYPTO)
+    {
+      int j;
+      log_debug ("encoded hash:");
+      for (j=0; j < nframe; j++)
+        log_printf (" %02X", frame[j]);
+      log_printf ("\n");
+    }
+      
+  gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, &nframe);
+  xfree (frame);
+  return 0;
+}
+
+
+/* SIGN whatever information we have accumulated in CTRL and write it
+   back to OUTFP. */
 int
 agent_pksign (CTRL ctrl, FILE *outfp) 
 {
+  /* our sample key */
+  const char n[] = "#8732A669BB7C5057AD070EFA54E035C86DF474F7A7EBE2435"
+    "3DADEB86FFE74C32AEEF9E5C6BD7584CB572520167B3E8C89A1FA75C74FF9E938"
+    "2710F3B270B638EB96E7486491D81C53CA8A50B4E840B1C7458A4A1E52EC18D681"
+    "8A2805C9165827F77EF90D55014E4B2AF9386AE8F6462F46A547CB593ABD509311"
+    "4D3D16375F#";
+  const char e[] = "#11#";
+  const char d[] = "#07F3EBABDDDA22D7FB1E8869140D30571586D9B4370DE02213F"
+    "DD0DDAC3C24FC6BEFF0950BB0CAAD755F7AA788DA12BCF90987341AC8781CC7115"
+    "B59A115B05D9D99B3D7AF77854DC2EE6A36154512CC0EAD832601038A88E837112"
+    "AB2A39FD9FBE05E30D6FFA6F43D71C59F423CA43BC91C254A8C89673AB61F326B0"
+    "762FBC9#";
+  const char p[] = "#B2ABAD4328E66303E206C53CFBED17F18F712B1C47C966EE13DD"
+    "AA9AD3616A610ADF513F8376FA48BAE12FED64CECC1E73091A77B45119AF0FC1286A"
+    "85BD9BBD#";
+  const char q[] = "#C1B648B294BB9AEE7FEEB77C4F64E9333E4EA9A7C54D521356FB"
+    "BBB7558A0E7D6331EC7B42E3F0CD7BBBA9B7A013422F615F10DCC1E8462828BF8FC7"
+    "39C5E34B#";
+  const char  u[] = "#A9B5EFF9C80A4A356B9A95EB63E381B262071E5CE9C1F32FF03"
+    "83AD8289BED8BC690555E54411FA2FDB9B49638A21B2046C325F5633B4B1ECABEBFD"
+    "1B3519072#";
+
+  GCRY_SEXP s_skey, s_hash, s_sig;
+  GCRY_MPI frame;
+  int rc;
+  char *buf;
+  size_t len;
 
-  return -1;
+  /* create a secret key as an sexp */
+  log_debug ("Using HARDWIRED secret key\n");
+  asprintf (&buf, "(private-key(oid.1.2.840.113549.1.1.1"
+           "(n %s)(e %s)(d %s)(p %s)(q %s)(u %s)))",
+           n, e, d, p, q, u);
+  /* asprintf does not use our allocation fucntions, so we can't
+     use our free */
+  rc = gcry_sexp_sscan (&s_skey, NULL, buf, strlen(buf));
+  free (buf);
+  if (rc)
+    {
+      log_error ("failed to build S-Exp: %s\n", gcry_strerror (rc));
+      return map_gcry_err (rc);
+    }
+  
+  /* put the hash into a sexp */
+  rc = do_encode_md (ctrl->digest.value,
+                     ctrl->digest.valuelen,
+                     ctrl->digest.algo,
+                     gcry_pk_get_nbits (s_skey),
+                     &frame);
+  if (rc)
+    {
+      /* fixme: clean up some things */
+      return rc;
+    }
+  if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
+    BUG ();
+
+
+  /* sign */
+  rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
+  if (rc)
+    {
+      log_error ("signing failed: %s\n", gcry_strerror (rc));
+      return map_gcry_err (rc);
+    }
+
+  len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
+  assert (len);
+  buf = xmalloc (len);
+  len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, buf, len);
+  assert (len);
+
+  fwrite (buf, 1, strlen(buf), outfp);
+  return 0;
 }
+
+