aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2001-12-05 23:49:07 +0000
committerWerner Koch <[email protected]>2001-12-05 23:49:07 +0000
commit37be272ed854fcec8dd44c782258eaa341395caf (patch)
tree33a454374d556b40fe0f7a60b0d41c73adb7158f
parentStarted with decryption stuff (diff)
downloadgnupg-37be272ed854fcec8dd44c782258eaa341395caf.tar.gz
gnupg-37be272ed854fcec8dd44c782258eaa341395caf.zip
Added decryption, some code cleanup
Diffstat (limited to '')
-rw-r--r--agent/Makefile.am4
-rw-r--r--agent/agent.h9
-rw-r--r--agent/command.c84
-rw-r--r--agent/findkey.c91
-rw-r--r--agent/gpg-agent.c52
-rw-r--r--agent/pkdecrypt.c112
-rw-r--r--agent/pksign.c114
7 files changed, 375 insertions, 91 deletions
diff --git a/agent/Makefile.am b/agent/Makefile.am
index a8172bece..ce0b59218 100644
--- a/agent/Makefile.am
+++ b/agent/Makefile.am
@@ -26,7 +26,9 @@ LDFLAGS = @LDFLAGS@
gpg_agent_SOURCES = \
gpg-agent.c agent.h \
command.c \
- pksign.c
+ findkey.c \
+ pksign.c \
+ pkdecrypt.c
gpg_agent_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \
../common/libcommon.a \
diff --git a/agent/agent.h b/agent/agent.h
index 95bfa080e..e3ba2f262 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -21,6 +21,7 @@
#ifndef AGENT_H
#define AGENT_H
+#include <gcrypt.h>
#include "../common/util.h"
#include "../common/errors.h"
@@ -60,6 +61,7 @@ struct server_control_s {
int valuelen;
} digest;
char keygrip[20];
+ int have_keygrip;
};
typedef struct server_control_s *CTRL;
@@ -71,9 +73,16 @@ void agent_exit (int rc);
/*-- command.c --*/
void start_command_handler (void);
+/*-- findkey.c --*/
+GCRY_SEXP agent_key_from_file (const unsigned char *grip);
+
+
/*-- pksign.c --*/
int agent_pksign (CTRL ctrl, FILE *outfp);
+/*-- pkdecrypt.c --*/
+int agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
+ FILE *outfp);
#endif /*AGENT_H*/
diff --git a/agent/command.c b/agent/command.c
index 80e13182d..4e3da80a4 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -32,6 +32,10 @@
#include "agent.h"
#include "../assuan/assuan.h"
+/* maximum allowed size of the inquired ciphertext */
+#define MAXLEN_CIPHERTEXT 4096
+
+
#define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
#define digitp(a) ((a) >= '0' && (a) <= '9')
#define hexdigitp(a) (digitp (a) \
@@ -55,18 +59,62 @@ struct server_local_s {
};
+/* Map GNUPG_xxx error codes to Assuan status codes
+ FIXME: duplicated from ../sm/server.c */
+static int
+rc_to_assuan_status (int rc)
+{
+ switch (rc)
+ {
+ case 0: break;
+ case GNUPG_Bad_Certificate: rc = ASSUAN_Bad_Certificate; break;
+ case GNUPG_Bad_Certificate_Path: rc = ASSUAN_Bad_Certificate_Path; break;
+ case GNUPG_Missing_Certificate: rc = ASSUAN_Missing_Certificate; break;
+ case GNUPG_No_Data: rc = ASSUAN_No_Data_Available; break;
+ case GNUPG_Bad_Signature: rc = ASSUAN_Bad_Signature; break;
+ case GNUPG_Not_Implemented: rc = ASSUAN_Not_Implemented; break;
+ case GNUPG_No_Agent: rc = ASSUAN_No_Agent; break;
+ case GNUPG_Agent_Error: rc = ASSUAN_Agent_Error; break;
+ case GNUPG_No_Public_Key: rc = ASSUAN_No_Public_Key; break;
+ case GNUPG_No_Secret_Key: rc = ASSUAN_No_Secret_Key; break;
+ case GNUPG_Invalid_Data: rc = ASSUAN_Invalid_Data; break;
+
+ case GNUPG_Read_Error:
+ case GNUPG_Write_Error:
+ case GNUPG_IO_Error:
+ rc = ASSUAN_Server_IO_Error;
+ break;
+ case GNUPG_Out_Of_Core:
+ case GNUPG_Resource_Limit:
+ rc = ASSUAN_Server_Resource_Problem;
+ break;
+ case GNUPG_Bug:
+ case GNUPG_Internal_Error:
+ rc = ASSUAN_Server_Bug;
+ break;
+ default:
+ rc = ASSUAN_Server_Fault;
+ break;
+ }
+ return rc;
+}
+
+
+
static void
reset_notify (ASSUAN_CONTEXT ctx)
{
CTRL ctrl = assuan_get_pointer (ctx);
memset (ctrl->keygrip, 0, 20);
+ ctrl->have_keygrip = 0;
ctrl->digest.valuelen = 0;
}
/* SIGKEY <hexstring_with_keygrip>
-
- Set the key used for a sign operation */
+ SETKEY <hexstring_with_keygrip>
+
+ Set the key used for a sign or decrypt operation */
static int
cmd_sigkey (ASSUAN_CONTEXT ctx, char *line)
{
@@ -89,6 +137,7 @@ cmd_sigkey (ASSUAN_CONTEXT ctx, char *line)
buf = ctrl->keygrip;
for (p=line, n=0; n < 20; p += 2, n++)
buf[n] = xtoi_2 (p);
+ ctrl->have_keygrip = 1;
return 0;
}
@@ -140,17 +189,38 @@ cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
/* PKSIGN <options>
Perform the actual sign operation. Neither input nor output are
- sensitive to to eavesdropping */
+ sensitive to eavesdropping */
static int
cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
{
int rc;
CTRL ctrl = assuan_get_pointer (ctx);
- /* fixme: check that all required data is available */
rc = agent_pksign (ctrl, assuan_get_data_fp (ctx));
- /* fixme: return an error */
- return 0;
+ return rc_to_assuan_status (rc);
+}
+
+/* PKDECRYPT <options>
+
+ Perform the actual decrypt operation. Input is not
+ sensitive to eavesdropping */
+static int
+cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
+{
+ int rc;
+ CTRL ctrl = assuan_get_pointer (ctx);
+ char *value;
+ size_t valuelen;
+
+ /* First inquire the data to decrypt */
+ rc = assuan_inquire (ctx, "CIPHERTEXT",
+ &value, &valuelen, MAXLEN_CIPHERTEXT);
+ if (rc)
+ return rc;
+
+ rc = agent_pkdecrypt (ctrl, value, valuelen, assuan_get_data_fp (ctx));
+ xfree (value);
+ return rc_to_assuan_status (rc);
}
@@ -165,8 +235,10 @@ register_commands (ASSUAN_CONTEXT ctx)
int (*handler)(ASSUAN_CONTEXT, char *line);
} table[] = {
{ "SIGKEY", 0, cmd_sigkey },
+ { "SETKEY", 0, cmd_sigkey },
{ "SETHASH", 0, cmd_sethash },
{ "PKSIGN", 0, cmd_pksign },
+ { "PKDECRYPT", 0, cmd_pkdecrypt },
{ "", ASSUAN_CMD_INPUT, NULL },
{ "", ASSUAN_CMD_OUTPUT, NULL },
{ NULL }
diff --git a/agent/findkey.c b/agent/findkey.c
new file mode 100644
index 000000000..9b0eb157b
--- /dev/null
+++ b/agent/findkey.c
@@ -0,0 +1,91 @@
+/* findkey.c - locate the secret key
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "agent.h"
+
+/* Return the secret key as an S-Exp after locating it using the grip. Returns NULL if key is not available. */
+GCRY_SEXP
+agent_key_from_file (const unsigned char *grip)
+{
+ int i, rc;
+ char *fname;
+ FILE *fp;
+ struct stat st;
+ char *buf;
+ size_t buflen, erroff;
+ GCRY_SEXP s_skey;
+ char hexgrip[41];
+
+ for (i=0; i < 20; i++)
+ sprintf (hexgrip+2*i, "%02X", grip[i]);
+ hexgrip[40] = 0;
+
+ fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL );
+ fp = fopen (fname, "rb");
+ if (!fp)
+ {
+ log_error ("can't open `%s': %s\n", fname, strerror (errno));
+ xfree (fname);
+ return NULL;
+ }
+
+ if (fstat (fileno(fp), &st))
+ {
+ log_error ("can't stat `%s': %s\n", fname, strerror (errno));
+ xfree (fname);
+ fclose (fp);
+ return NULL;
+ }
+
+ buflen = st.st_size;
+ buf = xmalloc (buflen+1);
+ if (fread (buf, buflen, 1, fp) != 1)
+ {
+ log_error ("error reading `%s': %s\n", fname, strerror (errno));
+ xfree (fname);
+ fclose (fp);
+ xfree (buf);
+ return NULL;
+ }
+
+ rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
+ xfree (fname);
+ fclose (fp);
+ xfree (buf);
+ if (rc)
+ {
+ log_error ("failed to build S-Exp (off=%u): %s\n",
+ (unsigned int)erroff, gcry_strerror (rc));
+ return NULL;
+ }
+
+ return s_skey;
+}
+
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 71e909057..28f20dab0 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
+#include <stdarg.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
@@ -33,6 +34,7 @@
#include <gcrypt.h>
+#define JNLIB_NEED_LOG_LOGV
#include "agent.h"
#include "../assuan/assuan.h" /* malloc hooks */
@@ -177,6 +179,27 @@ cleanup (void)
}
}
+
+/* Use by gcry for logging */
+static void
+my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
+{
+ /* translate the log levels */
+ switch (level)
+ {
+ case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
+ case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
+ case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
+ case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
+ case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
+ case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break;
+ case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
+ default: level = JNLIB_LOG_ERROR; break;
+ }
+ log_logv (level, fmt, arg_ptr);
+}
+
+
static RETSIGTYPE
cleanup_sh (int sig)
{
@@ -224,13 +247,12 @@ main (int argc, char **argv )
int csh_style = 0;
char *logfile = NULL;
- set_strusage( my_strusage );
+ 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() */
+ log_set_prefix ("gpg-agent", 1|4);
i18n_init ();
/* check that the libraries are suitable. Do it here because
@@ -242,6 +264,7 @@ main (int argc, char **argv )
}
assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
+ gcry_set_log_handler (my_gcry_logger, NULL);
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
may_coredump = 0/* FIXME: disable_core_dumps()*/;
@@ -452,6 +475,19 @@ main (int argc, char **argv )
}
else if (server_mode)
{ /* for now this is the simple pipe based server */
+ if (logfile)
+ {
+ log_set_file (logfile);
+ log_set_prefix (NULL, 1|2|4);
+ }
+
+ if ( atexit( cleanup ) )
+ {
+ log_error ("atexit failed\n");
+ cleanup ();
+ exit (1);
+ }
+
start_command_handler ();
}
else
@@ -518,11 +554,17 @@ main (int argc, char **argv )
} /* end parent */
if ( (opt.debug & 1) )
- sleep( 20 ); /* give us some time to attach gdb to the child */
+ {
+ fprintf (stderr, "... 20 seconds to attach the debugger ...");
+ fflush (stderr);
+ sleep( 20 ); /* give us some time to attach gdb to the child */
+ putc ('\n', stderr);
+ }
if (logfile)
{
- /* FIXME:log_set_logfile (opt.logfile, -1);*/
+ log_set_file (logfile);
+ log_set_prefix (NULL, 1|2|4);
}
if ( atexit( cleanup ) )
diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c
new file mode 100644
index 000000000..78f70ad52
--- /dev/null
+++ b/agent/pkdecrypt.c
@@ -0,0 +1,112 @@
+/* pkdecrypt.c - public key decryption (well, acually using a secret key)
+ * Copyright (C) 2001 Free Software Foundation, Inc.
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "agent.h"
+
+
+/* DECRYPT the stuff in ciphertext which is expected to be a S-Exp.
+ Try to get the key from CTRL and write the decoded stuff back to
+ OUTFP. */
+int
+agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
+ FILE *outfp)
+{
+ GCRY_SEXP s_skey = NULL, s_cipher = NULL, s_plain = NULL;
+ int rc;
+ char *buf = NULL;
+ size_t len;
+
+ if (!ctrl->have_keygrip)
+ {
+ log_error ("speculative decryption not yet supported\n");
+ rc = seterr (No_Secret_Key);
+ goto leave;
+ }
+
+ rc = gcry_sexp_sscan (&s_cipher, NULL, ciphertext, ciphertextlen);
+ if (rc)
+ {
+ log_error ("failed to convert ciphertext: %s\n", gcry_strerror (rc));
+ rc = seterr (Invalid_Data);
+ goto leave;
+ }
+
+ if (DBG_CRYPTO)
+ {
+ log_printhex ("keygrip:", ctrl->keygrip, 20);
+ log_printhex ("cipher: ", ciphertext, ciphertextlen);
+ }
+ s_skey = agent_key_from_file (ctrl->keygrip);
+ if (!s_skey)
+ {
+ log_error ("failed to read the secret key\n");
+ rc = seterr (No_Secret_Key);
+ goto leave;
+ }
+
+ if (DBG_CRYPTO)
+ {
+ log_debug ("skey: ");
+ gcry_sexp_dump (s_skey);
+ }
+
+ rc = gcry_pk_decrypt (&s_plain, s_cipher, s_skey);
+ if (rc)
+ {
+ log_error ("decryption failed: %s\n", gcry_strerror (rc));
+ rc = map_gcry_err (rc);
+ goto leave;
+ }
+
+ if (DBG_CRYPTO)
+ {
+ log_debug ("plain: ");
+ gcry_sexp_dump (s_plain);
+ }
+ len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, NULL, 0);
+ assert (len);
+ buf = xmalloc (len);
+ len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, buf, len);
+ assert (len);
+
+ /* FIXME: we must make sure that no buffering takes place or we are
+ in full control of the buffer memory (easy to do) - should go
+ into assuan. */
+ fwrite (buf, 1, len, outfp);
+
+ leave:
+ gcry_sexp_release (s_skey);
+ gcry_sexp_release (s_plain);
+ gcry_sexp_release (s_cipher);
+ xfree (buf);
+ return rc;
+}
+
+
diff --git a/agent/pksign.c b/agent/pksign.c
index 4bf833ece..9d1ad4f67 100644
--- a/agent/pksign.c
+++ b/agent/pksign.c
@@ -75,13 +75,7 @@ do_encode_md (const unsigned char *digest, size_t digestlen, int algo,
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");
- }
+ log_printhex ("encoded hash:", frame, nframe);
gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, &nframe);
xfree (frame);
@@ -89,82 +83,26 @@ do_encode_md (const unsigned char *digest, size_t digestlen, int algo,
}
-static GCRY_SEXP
-key_from_file (const unsigned char *grip)
-{
- int i, rc;
- char *fname;
- FILE *fp;
- struct stat st;
- char *buf;
- size_t buflen, erroff;
- GCRY_SEXP s_skey;
- char hexgrip[41];
-
- for (i=0; i < 20; i++)
- sprintf (hexgrip+2*i, "%02X", grip[i]);
- hexgrip[40] = 0;
-
- fname = make_filename (opt.homedir, "private-keys-v1.d", hexgrip, NULL );
- fp = fopen (fname, "rb");
- if (!fp)
- {
- log_error ("can't open `%s': %s\n", fname, strerror (errno));
- xfree (fname);
- return NULL;
- }
-
- if (fstat (fileno(fp), &st))
- {
- log_error ("can't stat `%s': %s\n", fname, strerror (errno));
- xfree (fname);
- fclose (fp);
- return NULL;
- }
-
- buflen = st.st_size;
- buf = xmalloc (buflen+1);
- if (fread (buf, buflen, 1, fp) != 1)
- {
- log_error ("error reading `%s': %s\n", fname, strerror (errno));
- xfree (fname);
- fclose (fp);
- xfree (buf);
- return NULL;
- }
-
- rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
- xfree (fname);
- fclose (fp);
- xfree (buf);
- if (rc)
- {
- log_error ("failed to build S-Exp (off=%u): %s\n",
- (unsigned int)erroff, gcry_strerror (rc));
- return NULL;
- }
-
- return s_skey;
-}
-
-
-
/* SIGN whatever information we have accumulated in CTRL and write it
back to OUTFP. */
int
agent_pksign (CTRL ctrl, FILE *outfp)
{
- GCRY_SEXP s_skey, s_hash, s_sig;
- GCRY_MPI frame;
+ GCRY_SEXP s_skey = NULL, s_hash = NULL, s_sig = NULL;
+ GCRY_MPI frame = NULL;
int rc;
- char *buf;
+ char *buf = NULL;
size_t len;
- s_skey = key_from_file (ctrl->keygrip);
+ if (!ctrl->have_keygrip)
+ return seterr (No_Secret_Key);
+
+ s_skey = agent_key_from_file (ctrl->keygrip);
if (!s_skey)
{
log_error ("failed to read the secret key\n");
- return seterr (No_Secret_Key);
+ rc = seterr (No_Secret_Key);
+ goto leave;
}
/* put the hash into a sexp */
@@ -174,22 +112,33 @@ agent_pksign (CTRL ctrl, FILE *outfp)
gcry_pk_get_nbits (s_skey),
&frame);
if (rc)
- {
- /* fixme: clean up some things */
- return rc;
- }
+ goto leave;
if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
BUG ();
+ if (DBG_CRYPTO)
+ {
+ log_debug ("skey: ");
+ gcry_sexp_dump (s_skey);
+ }
+
/* 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);
+ rc = map_gcry_err (rc);
+ goto leave;
+ }
+
+ if (DBG_CRYPTO)
+ {
+ log_debug ("result: ");
+ gcry_sexp_dump (s_sig);
}
+
len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
assert (len);
buf = xmalloc (len);
@@ -199,8 +148,15 @@ agent_pksign (CTRL ctrl, FILE *outfp)
/* FIXME: we must make sure that no buffering takes place or we are
in full control of the buffer memory (easy to do) - should go
into assuan. */
- fwrite (buf, 1, strlen(buf), outfp);
- return 0;
+ fwrite (buf, 1, len, outfp);
+
+ leave:
+ gcry_sexp_release (s_skey);
+ gcry_sexp_release (s_hash);
+ gcry_sexp_release (s_sig);
+ gcry_mpi_release (frame);
+ xfree (buf);
+ return rc;
}