summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS3
-rw-r--r--TODO2
-rw-r--r--agent/ChangeLog9
-rw-r--r--agent/agent.h2
-rw-r--r--agent/gpg-agent.c69
-rw-r--r--common/ChangeLog14
-rw-r--r--common/asshelp.c184
-rw-r--r--common/asshelp.h16
-rw-r--r--common/exechelp.c2
-rw-r--r--common/membuf.c9
-rw-r--r--common/membuf.h3
-rw-r--r--common/ttyio.c23
-rw-r--r--common/ttyio.h3
-rw-r--r--common/util.h6
-rw-r--r--doc/ChangeLog5
-rw-r--r--doc/glossary.texi5
-rw-r--r--doc/gpg-agent.texi8
-rw-r--r--doc/gpgsm.texi5
-rw-r--r--g10/ChangeLog9
-rw-r--r--g10/call-agent.c112
-rw-r--r--g10/gpg.h8
-rw-r--r--g10/main.h7
-rw-r--r--g10/sign.c1
-rw-r--r--scd/ChangeLog4
-rw-r--r--scd/scdaemon.h1
-rw-r--r--sm/ChangeLog12
-rw-r--r--sm/Makefile.am1
-rw-r--r--sm/call-agent.c157
-rw-r--r--sm/certreqgen-ui.c317
-rw-r--r--sm/certreqgen.c14
-rw-r--r--sm/gpgsm.c11
-rw-r--r--sm/gpgsm.h7
-rw-r--r--sm/server.c2
33 files changed, 714 insertions, 317 deletions
diff --git a/NEWS b/NEWS
index f54779089..a567c58f9 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,9 @@ Noteworthy changes in version 2.0.5
* Changes required for a port to Windows.
+ * The command --gen-key may now be used instead of the
+ gpgsm-gencert.sh script.
+
Noteworthy changes in version 2.0.4 (2007-05-09)
------------------------------------------------
diff --git a/TODO b/TODO
index 698cec446..649dbf2fd 100644
--- a/TODO
+++ b/TODO
@@ -95,7 +95,7 @@
* When requiring libksba 1.0.1
** Remove the extra GPG_ERR_NO_VALUE tests
- They have need added on 2006-10-18 to fix a libksba problem.
+ They have been added on 2006-10-18 to fix a libksba problem.
* When switching to libgcrypt 1.3
** scd#encode_md_for_card, g10#encode_md_value, sm@do_encode_md
diff --git a/agent/ChangeLog b/agent/ChangeLog
index 19564556e..653bcd032 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -1,3 +1,12 @@
+2007-06-21 Werner Koch <wk@g10code.com>
+
+ * agent.h (ctrl_t): Remove. It is now declared in ../common/util.h.
+
+ * gpg-agent.c (check_for_running_agent): New arg SILENT. Changed
+ all callers.
+ (create_server_socket): If the standard socket is in use check
+ whether a agent is running and avoid starting another one.
+
2007-06-18 Marcus Brinkmann <marcus@g10code.de>
* gpg-agent.c (main): Percent escape pathname in --gpgconf-list
diff --git a/agent/agent.h b/agent/agent.h
index cb1cca084..690a86df5 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -150,8 +150,6 @@ struct server_control_s
PKSIGN command to the scdaemon. */
};
-typedef struct server_control_s *ctrl_t;
-
struct pin_entry_info_s
{
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index a0646925c..360870f27 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -1,6 +1,6 @@
/* gpg-agent.c - The GnuPG Agent
- * Copyright (C) 2000, 2001, 2002, 2003, 2004,
- * 2005 Free Software Foundation, Inc.
+ * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005,
+ * 2006, 2007 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -93,7 +93,6 @@ enum cmd_and_opt_values
oMinPassphraseLen,
oUseStandardSocket,
oNoUseStandardSocket,
- oNoReuseStandardSocket,
oIgnoreCacheForSigning,
oAllowMarkTrusted,
@@ -131,8 +130,6 @@ static ARGPARSE_OPTS opts[] = {
{ oUseStandardSocket, "use-standard-socket", 0,
N_("use a standard location for the socket")},
{ oNoUseStandardSocket, "no-use-standard-socket", 0, "@"},
- { oNoReuseStandardSocket, "no-reuse-standard-socket", 0, "@"},
-
{ oPinentryProgram, "pinentry-program", 2 ,
N_("|PGM|use PGM as the PIN-Entry program") },
{ oPinentryTouchFile, "pinentry-touch-file", 2 , "@" },
@@ -188,10 +185,6 @@ static char *socket_name;
/* Name of the communication socket used for ssh-agent-emulation. */
static char *socket_name_ssh;
-/* If set to true and a standard socket is requested, we won't try to
- bind to a socket which is already in use. */
-static int no_reuse_standard_socket;
-
/* Default values for options passed to the pinentry. */
static char *default_display;
static char *default_ttyname;
@@ -228,7 +221,7 @@ static void agent_init_default_ctrl (ctrl_t ctrl);
static void agent_deinit_default_ctrl (ctrl_t ctrl);
static void handle_connections (int listen_fd, int listen_fd_ssh);
-static int check_for_running_agent (int);
+static int check_for_running_agent (int silent, int mode);
/* Pth wrapper function definitions. */
GCRY_THREAD_OPTION_PTH_IMPL;
@@ -627,7 +620,6 @@ main (int argc, char **argv )
case oUseStandardSocket: standard_socket = 1; break;
case oNoUseStandardSocket: standard_socket = 0; break;
- case oNoReuseStandardSocket: no_reuse_standard_socket = 1; break;
case oKeepTTY: opt.keep_tty = 1; break;
case oKeepDISPLAY: opt.keep_display = 1; break;
@@ -765,7 +757,7 @@ main (int argc, char **argv )
if (!pipe_server && !is_daemon)
{
log_set_prefix (NULL, JNLIB_LOG_WITH_PREFIX);
- check_for_running_agent (0);
+ check_for_running_agent (0, 0);
agent_exit (0);
}
@@ -1264,17 +1256,32 @@ create_server_socket (int is_standard_name, char *name)
#ifdef HAVE_W32_SYSTEM
rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len);
- if (is_standard_name && rc == -1 && errno == WSAEADDRINUSE
- && !no_reuse_standard_socket)
+ if (is_standard_name && rc == -1 && errno == WSAEADDRINUSE)
{
+ if (!check_for_running_agent (1, 1))
+ {
+ log_error (_("a gpg-agent is already running - "
+ "not starting a new one\n"));
+ *name = 0; /* Inhibit removal of the socket by cleanup(). */
+ close (fd);
+ agent_exit (2);
+ }
+
remove (name);
rc = _w32_sock_bind (fd, (struct sockaddr*) serv_addr, len);
}
#else
rc = bind (fd, (struct sockaddr*) serv_addr, len);
- if (is_standard_name && rc == -1 && errno == EADDRINUSE
- && !no_reuse_standard_socket)
+ if (is_standard_name && rc == -1 && errno == EADDRINUSE)
{
+ if (!check_for_running_agent (1, 1))
+ {
+ log_error (_("a gpg-agent is already running - "
+ "not starting a new one\n"));
+ *name = 0; /* Inhibit removal of the socket by cleanup(). */
+ close (fd);
+ agent_exit (2);
+ }
remove (name);
rc = bind (fd, (struct sockaddr*) serv_addr, len);
}
@@ -1288,7 +1295,7 @@ create_server_socket (int is_standard_name, char *name)
gpg_strerror (gpg_error_from_errno (errno)));
close (fd);
- if (is_standard_name && no_reuse_standard_socket)
+ if (is_standard_name)
*name = 0; /* Inhibit removal of the socket by cleanup(). */
agent_exit (2);
}
@@ -1725,9 +1732,10 @@ handle_connections (int listen_fd, int listen_fd_ssh)
/* Figure out whether an agent is available and running. Prints an
- error if not. Usually started with MODE 0. */
+ error if not. If SILENT is true, no mesdsages are printed. Usually
+ started with MODE 0. Returns 0 if the agent is running. */
static int
-check_for_running_agent (int mode)
+check_for_running_agent (int silent, int mode)
{
int rc;
char *infostr, *p;
@@ -1739,9 +1747,10 @@ check_for_running_agent (int mode)
infostr = getenv ("GPG_AGENT_INFO");
if (!infostr || !*infostr)
{
- if (!check_for_running_agent (1))
+ if (!check_for_running_agent (silent, 1))
return 0; /* Okay, its running on the standard socket. */
- log_error (_("no gpg-agent running in this session\n"));
+ if (!silent)
+ log_error (_("no gpg-agent running in this session\n"));
return -1;
}
@@ -1749,9 +1758,10 @@ check_for_running_agent (int mode)
if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
{
xfree (infostr);
- if (!check_for_running_agent (1))
+ if (!check_for_running_agent (silent, 1))
return 0; /* Okay, its running on the standard socket. */
- log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
+ if (!silent)
+ log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
return -1;
}
@@ -1763,9 +1773,10 @@ check_for_running_agent (int mode)
if (prot != 1)
{
xfree (infostr);
- log_error (_("gpg-agent protocol version %d is not supported\n"),
- prot);
- if (!check_for_running_agent (1))
+ if (!silent)
+ log_error (_("gpg-agent protocol version %d is not supported\n"),
+ prot);
+ if (!check_for_running_agent (silent, 1))
return 0; /* Okay, its running on the standard socket. */
return -1;
}
@@ -1781,15 +1792,15 @@ check_for_running_agent (int mode)
xfree (infostr);
if (rc)
{
- if (!mode && !check_for_running_agent (1))
+ if (!mode && !check_for_running_agent (silent, 1))
return 0; /* Okay, its running on the standard socket. */
- if (!mode)
+ if (!mode && !silent)
log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
return -1;
}
- if (!opt.quiet)
+ if (!opt.quiet && !silent)
log_info ("gpg-agent running and available\n");
assuan_disconnect (ctx);
diff --git a/common/ChangeLog b/common/ChangeLog
index 3f8fa41c4..e80e70359 100644
--- a/common/ChangeLog
+++ b/common/ChangeLog
@@ -1,3 +1,17 @@
+2007-06-21 Werner Koch <wk@g10code.com>
+
+ * membuf.h (get_membuf_len): New.
+
+ * membuf.c (init_membuf_secure): Really allocate in secure memory.
+ (put_membuf_str): New.
+
+ * ttyio.c (tty_getf): New.
+
+ * util.h (ctrl_t): Declare it here.
+
+ * asshelp.c (start_new_gpg_agent): New. Based on code from
+ ../sm/call-agent.c
+
2007-06-20 Werner Koch <wk@g10code.com>
* sysutils.c (gnupg_sleep): New.
diff --git a/common/asshelp.c b/common/asshelp.c
index 54d7224d8..024128042 100644
--- a/common/asshelp.c
+++ b/common/asshelp.c
@@ -29,8 +29,11 @@
#include <locale.h>
#endif
+#include "i18n.h"
#include "util.h"
-
+#include "exechelp.h"
+#include "sysutils.h"
+#include "errors.h" /* FIXME: This one conatisn only status code - rename it*/
#include "asshelp.h"
@@ -164,3 +167,182 @@ send_pinentry_environment (assuan_context_t ctx,
return 0;
}
+
+/* Try to connect to the agent via socket or fork it off and work by
+ pipes. Handle the server's initial greeting. Returns a new assuan
+ context at R_CTX or an error code. */
+gpg_error_t
+start_new_gpg_agent (assuan_context_t *r_ctx,
+ gpg_err_source_t errsource,
+ const char *homedir,
+ const char *agent_program,
+ const char *opt_display,
+ const char *opt_ttyname,
+ const char *opt_ttytype,
+ const char *opt_lc_ctype,
+ const char *opt_lc_messages,
+ int verbose, int debug,
+ gpg_error_t (*status_cb)(ctrl_t, int, ...),
+ ctrl_t status_cb_arg)
+{
+ /* If we ever failed to connect via a socket we will force the use
+ of the pipe based server for the lifetime of the process. */
+ static int force_pipe_server = 0;
+
+ gpg_error_t rc = 0;
+ char *infostr, *p;
+ assuan_context_t ctx;
+
+ *r_ctx = NULL;
+
+ restart:
+ infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
+ if (!infostr || !*infostr)
+ {
+ char *sockname;
+
+ /* First check whether we can connect at the standard
+ socket. */
+ sockname = make_filename (homedir, "S.gpg-agent", NULL);
+ rc = assuan_socket_connect (&ctx, sockname, 0);
+
+ if (rc)
+ {
+ /* With no success start a new server. */
+ if (verbose)
+ log_info (_("no running gpg-agent - starting one\n"));
+
+ if (status_cb)
+ status_cb (status_cb_arg, STATUS_PROGRESS,
+ "starting_agent ? 0 0", NULL);
+
+ if (fflush (NULL))
+ {
+ gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
+ log_error ("error flushing pending output: %s\n",
+ strerror (errno));
+ xfree (sockname);
+ return tmperr;
+ }
+
+ if (!agent_program || !*agent_program)
+ agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
+
+#ifdef HAVE_W32_SYSTEM
+ {
+ /* Under Windows we start the server in daemon mode. This
+ is because the default is to use the standard socket
+ and thus there is no need for the GPG_AGENT_INFO
+ envvar. This is possible as we don't have a real unix
+ domain socket but use a plain file and thus there is no
+ need to care about non-local file systems. */
+ const char *argv[3];
+
+ argv[0] = "--daemon";
+ argv[1] = "--use-standard-socket";
+ argv[2] = NULL;
+
+ rc = gnupg_spawn_process_detached (agent_program, argv, NULL);
+ if (rc)
+ log_debug ("failed to start agent `%s': %s\n",
+ agent_program, gpg_strerror (rc));
+ else
+ {
+ /* Give the agent some time to prepare itself. */
+ gnupg_sleep (3);
+ /* Now try again to connect the agent. */
+ rc = assuan_socket_connect (&ctx, sockname, 0);
+ }
+ }
+#else /*!HAVE_W32_SYSTEM*/
+ {
+ const char *pgmname;
+ const char *argv[3];
+ int no_close_list[3];
+ int i;
+
+ if ( !(pgmname = strrchr (agent_program, '/')))
+ pgmname = agent_program;
+ else
+ pgmname++;
+
+ argv[0] = pgmname;
+ argv[1] = "--server";
+ argv[2] = NULL;
+
+ i=0;
+ if (log_get_fd () != -1)
+ no_close_list[i++] = log_get_fd ();
+ no_close_list[i++] = fileno (stderr);
+ no_close_list[i] = -1;
+
+ /* Connect to the agent and perform initial handshaking. */
+ rc = assuan_pipe_connect (&ctx, agent_program, argv,
+ no_close_list);
+ }
+#endif /*!HAVE_W32_SYSTEM*/
+ }
+ xfree (sockname);
+ }
+ else
+ {
+ int prot;
+ int pid;
+
+ infostr = xstrdup (infostr);
+ if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
+ {
+ log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
+ xfree (infostr);
+ force_pipe_server = 1;
+ goto restart;
+ }
+ *p++ = 0;
+ pid = atoi (p);
+ while (*p && *p != PATHSEP_C)
+ p++;
+ prot = *p? atoi (p+1) : 0;
+ if (prot != 1)
+ {
+ log_error (_("gpg-agent protocol version %d is not supported\n"),
+ prot);
+ xfree (infostr);
+ force_pipe_server = 1;
+ goto restart;
+ }
+
+ rc = assuan_socket_connect (&ctx, infostr, pid);
+ xfree (infostr);
+ if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
+ {
+ log_info (_("can't connect to the agent - trying fall back\n"));
+ force_pipe_server = 1;
+ goto restart;
+ }
+ }
+
+ if (rc)
+ {
+ log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
+ return gpg_error (GPG_ERR_NO_AGENT);
+ }
+
+ if (debug)
+ log_debug ("connection to agent established\n");
+
+ rc = assuan_transact (ctx, "RESET",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (!rc)
+ rc = send_pinentry_environment (ctx, errsource,
+ opt_display, opt_ttyname, opt_ttytype,
+ opt_lc_ctype, opt_lc_messages);
+ if (rc)
+ {
+ assuan_disconnect (ctx);
+ return rc;
+ }
+
+ *r_ctx = ctx;
+ return 0;
+}
+
diff --git a/common/asshelp.h b/common/asshelp.h
index 9f4b5806b..adf81f9b7 100644
--- a/common/asshelp.h
+++ b/common/asshelp.h
@@ -34,5 +34,21 @@ send_pinentry_environment (assuan_context_t ctx,
const char *opt_lc_ctype,
const char *opt_lc_messages);
+/* This fucntion is used by the call-agent.c modules to fire up a new
+ agent. What a parameter list ;-). */
+gpg_error_t
+start_new_gpg_agent (assuan_context_t *r_ctx,
+ gpg_err_source_t errsource,
+ const char *homedir,
+ const char *agent_program,
+ const char *opt_display,
+ const char *opt_ttyname,
+ const char *opt_ttytype,
+ const char *opt_lc_ctype,
+ const char *opt_lc_messages,
+ int verbose, int debug,
+ gpg_error_t (*status_cb)(ctrl_t, int, ...),
+ ctrl_t status_cb_arg);
+
#endif /*GNUPG_COMMON_ASSHELP_H*/
diff --git a/common/exechelp.c b/common/exechelp.c
index d0be84047..c488e291a 100644
--- a/common/exechelp.c
+++ b/common/exechelp.c
@@ -593,7 +593,7 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
cmdline, /* Command line arguments. */
&sec_attr, /* Process security attributes. */
&sec_attr, /* Thread security attributes. */
- FALSE, /* Inherit handles. */
+ FALSE, /* Inherit handles. */
cr_flags, /* Creation flags. */
NULL, /* Environment. */
NULL, /* Use current drive/directory. */
diff --git a/common/membuf.c b/common/membuf.c
index 51014592b..eb436c466 100644
--- a/common/membuf.c
+++ b/common/membuf.c
@@ -52,7 +52,7 @@ init_membuf_secure (membuf_t *mb, int initiallen)
mb->len = 0;
mb->size = initiallen;
mb->out_of_core = 0;
- mb->buf = xtrymalloc (initiallen);
+ mb->buf = xtrymalloc_secure (initiallen);
if (!mb->buf)
mb->out_of_core = errno;
}
@@ -87,6 +87,13 @@ put_membuf (membuf_t *mb, const void *buf, size_t len)
}
+void
+put_membuf_str (membuf_t *mb, const char *string)
+{
+ put_membuf (mb, string, strlen (string));
+}
+
+
void *
get_membuf (membuf_t *mb, size_t *len)
{
diff --git a/common/membuf.h b/common/membuf.h
index f9c08a400..906ae156c 100644
--- a/common/membuf.h
+++ b/common/membuf.h
@@ -34,10 +34,13 @@ struct private_membuf_s
typedef struct private_membuf_s membuf_t;
+/* Return the current length of the membuf. */
+#define get_membuf_len(a) ((a)->len)
void init_membuf (membuf_t *mb, int initiallen);
void init_membuf_secure (membuf_t *mb, int initiallen);
void put_membuf (membuf_t *mb, const void *buf, size_t len);
+void put_membuf_str (membuf_t *mb, const char *string);
void *get_membuf (membuf_t *mb, size_t *len);
diff --git a/common/ttyio.c b/common/ttyio.c
index 831ad9048..98a4614fe 100644
--- a/common/ttyio.c
+++ b/common/ttyio.c
@@ -50,6 +50,7 @@
#include "util.h"
#include "ttyio.h"
+#include "estream-printf.h"
#include "common-defs.h"
#define CONTROL_D ('D' - 'A' + 1)
@@ -243,7 +244,7 @@ tty_printf( const char *fmt, ... )
}
-/* Same as tty_printf but if FP is not NULL, behave like a regualr
+/* Same as tty_printf but if FP is not NULL, behave like a regular
fprintf. */
void
tty_fprintf (FILE *fp, const char *fmt, ... )
@@ -563,6 +564,26 @@ tty_get( const char *prompt )
return do_get ( prompt, 0 );
}
+/* Variable argument version of tty_get. The prompt is is actually a
+ format string with arguments. */
+char *
+tty_getf (const char *promptfmt, ... )
+{
+ va_list arg_ptr;
+ char *prompt;
+ char *answer;
+
+ va_start (arg_ptr, promptfmt);
+ if (estream_vasprintf (&prompt, promptfmt, arg_ptr) < 0)
+ log_fatal ("estream_vasprintf failed: %s\n", strerror (errno));
+ va_end (arg_ptr);
+ answer = tty_get (prompt);
+ xfree (prompt);
+ return answer;
+}
+
+
+
char *
tty_get_hidden( const char *prompt )
{
diff --git a/common/ttyio.h b/common/ttyio.h
index d93906eab..eed6b0910 100644
--- a/common/ttyio.h
+++ b/common/ttyio.h
@@ -31,9 +31,12 @@ void tty_printf (const char *fmt, ... )
__attribute__ ((format (printf,1,2)));
void tty_fprintf (FILE *fp, const char *fmt, ... )
__attribute__ ((format (printf,2,3)));
+char *tty_getf (const char *promptfmt, ... )
+ __attribute__ ((format (printf,1,2)));
#else
void tty_printf (const char *fmt, ... );
void tty_fprintf (FILE *fp, const char *fmt, ... );
+char *tty_getf (const char *promptfmt, ... );
#endif
void tty_print_string (const unsigned char *p, size_t n);
void tty_print_utf8_string (const unsigned char *p, size_t n);
diff --git a/common/util.h b/common/util.h
index 42df1274f..39858216f 100644
--- a/common/util.h
+++ b/common/util.h
@@ -46,7 +46,6 @@
#define asprintf estream_asprintf
#define vasprintf estream_vasprintf
-
/* GCC attributes. */
#if __GNUC__ >= 4
# define GNUPG_GCC_A_SENTINEL(a) __attribute__ ((sentinel(a)))
@@ -246,5 +245,10 @@ ttyname (int fd)
#define xtoi_4(p) ((xtoi_2(p) * 256) + xtoi_2((p)+2))
+/*-- Forward declaration of the commonly used server control structure. */
+/* (We need it here as it is used by some callback prototypes.) */
+struct server_control_s;
+typedef struct server_control_s *ctrl_t;
+
#endif /*GNUPG_COMMON_UTIL_H*/
diff --git a/doc/ChangeLog b/doc/ChangeLog
index a87680b2b..27546e08f 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,3 +1,8 @@
+2007-06-21 Werner Koch <wk@g10code.com>
+
+ * gpgsm.texi (Certificate Management): Changed description of
+ --gen-key.
+
2007-06-19 Werner Koch <wk@g10code.com>
* glossary.texi (Glossary): Describe PSE.
diff --git a/doc/glossary.texi b/doc/glossary.texi
index 6eede19d2..22bd7adc5 100644
--- a/doc/glossary.texi
+++ b/doc/glossary.texi
@@ -16,6 +16,11 @@ certificates.
The @emph{Certificate Revocation List} is a list containing
certificates revoked by the issuer.
+@item CSR
+ The @emph{Certificate Signing Request} is a message send to a CA to
+ask them to issue a new certificate. The data format of such a signing
+request is called PCKS#10.
+
@item Keygrip
This term is used by GnuPG to describe a 20 byte hash value used
to identify a certain key without referencing to a concrete protocol.
diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi
index 85ce1acd4..e9ef3a9e9 100644
--- a/doc/gpg-agent.texi
+++ b/doc/gpg-agent.texi
@@ -369,20 +369,16 @@ this option at runtime does not kill an already forked scdaemon.
@item --use-standard-socket
@itemx --no-use-standard-socket
-@itemx --no-reuse-standard-socket
@opindex use-standard-socket
@opindex no-use-standard-socket
-@opindex no-reuse-standard-socket
By enabling this option @command{gpg-agent} will listen on the socket
named @file{S.gpg-agent}, located in the home directory, and not create
a random socket below a temporary directory. Tools connecting to
@command{gpg-agent} should first try to connect to the socket given in
environment variable @var{GPG_AGENT_INFO} and the fall back to this
socket. This option may not be used if the home directory is mounted as
-a remote file system. If @option{--no-reuse-standard-socket} is used,
-@command{gpg-agent} will not try to reuse a socket which is already in
-use. Note, that @option{--use-standard-socket} is the default on
-Windows systems.
+a remote file system. Note, that @option{--use-standard-socket} is the
+default on Windows systems.
@item --display @var{string}
diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi
index 69a7f10d7..b318ab877 100644
--- a/doc/gpgsm.texi
+++ b/doc/gpgsm.texi
@@ -164,8 +164,9 @@ use @samp{--help} to get a list of supported operations.
@table @gnupgtabopt
@item --gen-key
@opindex gen-key
-This command will only print an error message and direct the user to the
-@command{gpgsm-gencert.sh} script.
+This command allows the interactive creation of a certifcate signing
+request. It is commonly used along with the @option{--output} option to
+save the created CSR into a file.
@item --list-keys
@itemx -k
diff --git a/g10/ChangeLog b/g10/ChangeLog
index b49d8868b..e3db0f80f 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,12 @@
+2007-06-21 Werner Koch <wk@g10code.com>
+
+ * main.h: Include util.h.
+
+ * call-agent.c (start_agent): Factored almost all code out to
+ ../common/asshelp.c.
+
+ * gpg.h (ctrl_t): Remove. It is now declared in ../common/util.h.
+
2007-06-20 Werner Koch <wk@g10code.com>
* misc.c (setsysinfo, trap_unaligned): Remove. It is also in
diff --git a/g10/call-agent.c b/g10/call-agent.c
index f2edfc0f4..57a45f6fb 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -19,10 +19,6 @@
* USA.
*/
-#if 0 /* let Emacs display a red warning */
-#error fixme: this shares a lot of code with the file in ../sm
-#endif
-
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
@@ -49,7 +45,6 @@
#endif
static assuan_context_t agent_ctx = NULL;
-static int force_pipe_server;
struct cipher_parm_s
{
@@ -79,107 +74,18 @@ struct genkey_parm_s
static int
start_agent (void)
{
- int rc = 0;
- char *infostr, *p;
- assuan_context_t ctx;
-
if (agent_ctx)
- return 0; /* fixme: We need a context for each thread or serialize
+ return 0; /* Fixme: We need a context for each thread or serialize
the access to the agent. */
- infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
- if (!infostr || !*infostr)
- {
- const char *pgmname;
- const char *argv[3];
- int no_close_list[3];
- int i;
-
- if (opt.verbose)
- log_info (_("no running gpg-agent - starting one\n"));
-
- if (fflush (NULL))
- {
- gpg_error_t tmperr = gpg_error_from_syserror ();
- log_error ("error flushing pending output: %s\n", strerror (errno));
- return tmperr;
- }
-
- if (!opt.agent_program || !*opt.agent_program)
- opt.agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
- if ( !(pgmname = strrchr (opt.agent_program, '/')))
- pgmname = opt.agent_program;
- else
- pgmname++;
-
- argv[0] = pgmname;
- argv[1] = "--server";
- argv[2] = NULL;
-
- i=0;
- if (log_get_fd () != -1)
- no_close_list[i++] = log_get_fd ();
- no_close_list[i++] = fileno (stderr);
- no_close_list[i] = -1;
-
- /* connect to the agent and perform initial handshaking */
- rc = assuan_pipe_connect (&ctx, opt.agent_program, argv,
- no_close_list);
- }
- else
- {
- int prot;
- int pid;
-
- infostr = xstrdup (infostr);
- if ( !(p = strchr (infostr, ':')) || p == infostr)
- {
- log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
- xfree (infostr);
- force_pipe_server = 1;
- return start_agent ();
- }
- *p++ = 0;
- pid = atoi (p);
- while (*p && *p != ':')
- p++;
- prot = *p? atoi (p+1) : 0;
- if (prot != 1)
- {
- log_error (_("gpg-agent protocol version %d is not supported\n"),
- prot);
- xfree (infostr);
- force_pipe_server = 1;
- return start_agent ();
- }
-
- rc = assuan_socket_connect (&ctx, infostr, pid);
- xfree (infostr);
- if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
- {
- log_info (_("can't connect to the agent - trying fall back\n"));
- force_pipe_server = 1;
- return start_agent ();
- }
- }
-
- if (rc)
- {
- log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
- return gpg_error (GPG_ERR_NO_AGENT);
- }
- agent_ctx = ctx;
-
- if (DBG_ASSUAN)
- log_debug ("connection to agent established\n");
-
- rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL,NULL);
- if (rc)
- return rc;
-
- return send_pinentry_environment (agent_ctx, GPG_ERR_SOURCE_DEFAULT,
- opt.display, opt.ttyname, opt.ttytype,
- opt.lc_ctype, opt.lc_messages);
+ return start_new_gpg_agent (&agent_ctx,
+ GPG_ERR_SOURCE_DEFAULT,
+ opt.homedir,
+ opt.agent_program,
+ opt.display, opt.ttyname, opt.ttytype,
+ opt.lc_ctype, opt.lc_messages,
+ opt.verbose, DBG_ASSUAN,
+ NULL, NULL);
}
diff --git a/g10/gpg.h b/g10/gpg.h
index 9e0c9607e..d47c58fe2 100644
--- a/g10/gpg.h
+++ b/g10/gpg.h
@@ -64,14 +64,6 @@ struct server_control_s
{
struct server_local_s *server_local;
};
-typedef struct server_control_s *ctrl_t;
-
-
-
-
-/*-- server.c --*/
-int gpg_server (ctrl_t);
-
diff --git a/g10/main.h b/g10/main.h
index 1860853da..69e0d95f5 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -23,9 +23,11 @@
#define G10_MAIN_H
#include "types.h"
-#include "../common/iobuf.h"
+#include "iobuf.h"
#include "cipher.h"
#include "keydb.h"
+#include "util.h"
+
/* It could be argued that the default cipher should be 3DES rather
than CAST5, and the default compression should be 0
@@ -300,6 +302,9 @@ void block_all_signals(void);
void unblock_all_signals(void);
+/*-- server.c --*/
+int gpg_server (ctrl_t);
+
#ifdef ENABLE_CARD_SUPPORT
/*-- card-util.c --*/
void change_pin (int no, int allow_admin);
diff --git a/g10/sign.c b/g10/sign.c
index 1a1a80bc6..95ff96373 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -41,6 +41,7 @@
#include "status.h"
#include "i18n.h"
#include "pkglue.h"
+#include "sysutils.h"
#include "call-agent.h"
diff --git a/scd/ChangeLog b/scd/ChangeLog
index 0f2b59696..3db91a0f7 100644
--- a/scd/ChangeLog
+++ b/scd/ChangeLog
@@ -1,3 +1,7 @@
+2007-06-21 Werner Koch <wk@g10code.com>
+
+ * scdaemon.h (ctrl_t): Remove. It is now declared in ../common/util.h.
+
2007-06-18 Marcus Brinkmann <marcus@g10code.de>
* scdaemon.c (main): Percent escape output of --gpgconf-list.
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
index e1c5109d5..4086b854c 100644
--- a/scd/scdaemon.h
+++ b/scd/scdaemon.h
@@ -116,7 +116,6 @@ struct server_control_s
} in_data;
};
-typedef struct server_control_s *ctrl_t;
typedef struct app_ctx_s *app_t;
/*-- scdaemon.c --*/
diff --git a/sm/ChangeLog b/sm/ChangeLog
index 896b5c368..737a57d0c 100644
--- a/sm/ChangeLog
+++ b/sm/ChangeLog
@@ -1,3 +1,15 @@
+2007-06-21 Werner Koch <wk@g10code.com>
+
+ * certreqgen-ui.c: New.
+ * gpgsm.c (main): Let --gen-key call it.
+ * certreqgen.c (gpgsm_genkey): Add optional IN_STREAM arg and
+ adjusted caller.
+
+ * gpgsm.h (ctrl_t): Remove. It is now declared in ../common/util.h.
+
+ * call-agent.c (start_agent): Factored almost all code out to
+ ../common/asshelp.c.
+
2007-06-20 Werner Koch <wk@g10code.com>
* call-agent.c (start_agent) [W32]: Start the agent on the fly.
diff --git a/sm/Makefile.am b/sm/Makefile.am
index 7e5c154ac..e56064812 100644
--- a/sm/Makefile.am
+++ b/sm/Makefile.am
@@ -50,6 +50,7 @@ gpgsm_SOURCES = \
export.c \
delete.c \
certreqgen.c \
+ certreqgen-ui.c \
qualified.c
diff --git a/sm/call-agent.c b/sm/call-agent.c
index b30fe60df..9483785cc 100644
--- a/sm/call-agent.c
+++ b/sm/call-agent.c
@@ -38,11 +38,10 @@
#include "asshelp.h"
#include "keydb.h" /* fixme: Move this to import.c */
#include "membuf.h"
-#include "exechelp.h"
static assuan_context_t agent_ctx = NULL;
-static int force_pipe_server = 0;
+
struct cipher_parm_s
{
@@ -72,161 +71,25 @@ struct learn_parm_s
static int
start_agent (ctrl_t ctrl)
{
- int rc = 0;
- char *infostr, *p;
- assuan_context_t ctx;
-
if (agent_ctx)
return 0; /* fixme: We need a context for each thread or serialize
the access to the agent (which is suitable given that
the agent is not MT. */
- infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
- if (!infostr || !*infostr)
- {
- char *sockname;
-
- /* First check whether we can connect at the standard
- socket. */
- sockname = make_filename (opt.homedir, "S.gpg-agent", NULL);
- rc = assuan_socket_connect (&ctx, sockname, 0);
-
- if (rc)
- {
- /* With no success start a new server. */
- if (opt.verbose)
- log_info (_("no running gpg-agent - starting one\n"));
-
- gpgsm_status (ctrl, STATUS_PROGRESS, "starting_agent ? 0 0");
-
- if (fflush (NULL))
- {
- gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
- log_error ("error flushing pending output: %s\n",
- strerror (errno));
- xfree (sockname);
- return tmperr;
- }
-
- if (!opt.agent_program || !*opt.agent_program)
- opt.agent_program = gnupg_module_name (GNUPG_MODULE_NAME_AGENT);
-
-#ifdef HAVE_W32_SYSTEM
- {
- /* Under Windows we start the server in daemon mode. This
- is because the default is to use the standard socket
- and thus there is no need for the GPG_AGENT_INFO
- envvar. This is possible as we don't have a real unix
- domain socket but use a plain file and thus there is no
- need to care about non-local file systems. */
- const char *argv[3];
-
- /* The --no-reuse-standard option makes sure that we don't
- start a second instance of a agent in case another
- process has started one in the meantime. */
- argv[0] = "--daemon";
- argv[1] = "--no-reuse-standard-socket";
- argv[2] = NULL;
-
- rc = gnupg_spawn_process_detached (opt.agent_program, argv, NULL);
- if (rc)
- log_debug ("failed to start agent `%s': %s\n",
- opt.agent_program, gpg_strerror (rc));
- else
- {
- /* Give the agent some time to prepare itself. */
- gnupg_sleep (3);
- /* Now try again to connect the agent. */
- rc = assuan_socket_connect (&ctx, sockname, 0);
- }
- }
-#else /*!HAVE_W32_SYSTEM*/
- {
- const char *pgmname;
- const char *argv[3];
- int no_close_list[3];
- int i;
-
- if ( !(pgmname = strrchr (opt.agent_program, '/')))
- pgmname = opt.agent_program;
- else
- pgmname++;
-
- argv[0] = pgmname;
- argv[1] = "--server";
- argv[2] = NULL;
-
- i=0;
- if (log_get_fd () != -1)
- no_close_list[i++] = log_get_fd ();
- no_close_list[i++] = fileno (stderr);
- no_close_list[i] = -1;
-
- /* Connect to the agent and perform initial handshaking. */
- rc = assuan_pipe_connect (&ctx, opt.agent_program, argv,
- no_close_list);
- }
-#endif /*!HAVE_W32_SYSTEM*/
- }
- xfree (sockname);
- }
- else
- {
- int prot;
- int pid;
-
- infostr = xstrdup (infostr);
- if ( !(p = strchr (infostr, PATHSEP_C)) || p == infostr)
- {
- log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
- xfree (infostr);
- force_pipe_server = 1;
- return start_agent (ctrl);
- }
- *p++ = 0;
- pid = atoi (p);
- while (*p && *p != PATHSEP_C)
- p++;
- prot = *p? atoi (p+1) : 0;
- if (prot != 1)
- {
- log_error (_("gpg-agent protocol version %d is not supported\n"),
- prot);
- xfree (infostr);
- force_pipe_server = 1;
- return start_agent (ctrl);
- }
-
- rc = assuan_socket_connect (&ctx, infostr, pid);
- xfree (infostr);
- if (gpg_err_code (rc) == GPG_ERR_ASS_CONNECT_FAILED)
- {
- log_info (_("can't connect to the agent - trying fall back\n"));
- force_pipe_server = 1;
- return start_agent (ctrl);
- }
- }
- if (rc)
- {
- log_error ("can't connect to the agent: %s\n", gpg_strerror (rc));
- return gpg_error (GPG_ERR_NO_AGENT);
- }
- agent_ctx = ctx;
-
- if (DBG_ASSUAN)
- log_debug ("connection to agent established\n");
+ return start_new_gpg_agent (&agent_ctx,
+ GPG_ERR_SOURCE_DEFAULT,
+ opt.homedir,
+ opt.agent_program,
+ opt.display, opt.ttyname, opt.ttytype,
+ opt.lc_ctype, opt.lc_messages,
+ opt.verbose, DBG_ASSUAN,
+ gpgsm_status2, ctrl);
- rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return rc;
-
- return send_pinentry_environment (agent_ctx, GPG_ERR_SOURCE_DEFAULT,
- opt.display, opt.ttyname, opt.ttytype,
- opt.lc_ctype, opt.lc_messages);
}
+
static int
membuf_data_cb (void *opaque, const void *buffer, size_t length)
{
diff --git a/sm/certreqgen-ui.c b/sm/certreqgen-ui.c
new file mode 100644
index 000000000..738999ff8
--- /dev/null
+++ b/sm/certreqgen-ui.c
@@ -0,0 +1,317 @@
+/* certreqgen-ui.c - Simple user interface for certreqgen.c
+ * Copyright (C) 2007 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <assert.h>
+
+#include "gpgsm.h"
+#include <gcrypt.h>
+
+#include "i18n.h"
+#include "ttyio.h"
+#include "membuf.h"
+
+
+/* Prompt for lines and append them to MB. */
+static void
+ask_mb_lines (membuf_t *mb, const char *prefix)
+{
+ char *answer = NULL;
+
+ do
+ {
+ xfree (answer);
+ answer = tty_get ("> ");
+ tty_kill_prompt ();
+ trim_spaces (answer);
+ if (*answer)
+ {
+ put_membuf_str (mb, prefix);
+ put_membuf_str (mb, answer);
+ put_membuf (mb, "\n", 1);
+ }
+ }
+ while (*answer);
+ xfree (answer);
+}
+
+/* Helper to store stuff in a membuf. */
+void
+store_key_value_lf (membuf_t *mb, const char *key, const char *value)
+{
+ put_membuf_str (mb, key);
+ put_membuf_str (mb, value);
+ put_membuf (mb, "\n", 1);
+}
+
+/* Helper tp store a membuf create by mb_ask_lines into MB. Returns
+ -1 on error. */
+int
+store_mb_lines (membuf_t *mb, membuf_t *lines)
+{
+ char *p;
+
+ if (get_membuf_len (lines))
+ {
+ put_membuf (lines, "", 1);
+ p = get_membuf (lines, NULL);
+ if (!p)
+ return -1;
+ put_membuf_str (mb, p);
+ xfree (p);
+ }
+ return 0;
+}
+
+
+/* This function is used to create a certificate request from the
+ command line. In the past the similar gpgsm-gencert.sh script has
+ been used for it; however that scripts requires a full Unix shell
+ and thus is not suitable for the Windows port. So here is the
+ re-implementation. */
+void
+gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *output_fp)
+{
+ gpg_error_t err;
+ char *answer;
+ int selection;
+ FILE *fp = NULL;
+ int method;
+ char *keytype;
+ char *keygrip = NULL;
+ unsigned int nbits;
+ int minbits = 1024;
+ int maxbits = 4096;
+ int defbits = 2048;
+ const char *keyusage;
+ char *subject_name;
+ membuf_t mb_email, mb_dns, mb_uri, mb_result;
+ char *result = NULL;
+ int i;
+ const char *s, *s2;
+
+ init_membuf (&mb_email, 100);
+ init_membuf (&mb_dns, 100);
+ init_membuf (&mb_uri, 100);
+ init_membuf (&mb_result, 512);
+
+ /* Get the type of the key. */
+ tty_printf (_("Please select what kind of key you want:\n"));
+ tty_printf (_(" (%d) RSA\n"), 1 );
+ tty_printf (_(" (%d) Existing key\n"), 2 );
+ tty_printf (_(" (%d) Existing key from card\n"), 3 );
+
+ do
+ {
+ answer = tty_get (_("Your selection? "));
+ tty_kill_prompt ();
+ selection = *answer? atoi (answer): 1;
+ xfree (answer);
+ }
+ while (!(selection >= 1 && selection <= 3));
+ method = selection;
+
+ /* Get size of the key. */
+ if (method == 1)
+ {
+ keytype = xstrdup ("RSA");
+ for (;;)
+ {
+ answer = tty_getf (_("What keysize do you want? (%u) "), defbits);
+ tty_kill_prompt ();
+ nbits = *answer? atoi (answer): defbits;
+ xfree (answer);
+ if (nbits < minbits || nbits > maxbits)
+ tty_printf(_("%s keysizes must be in the range %u-%u\n"),
+ "RSA", minbits, maxbits);
+ else
+ break; /* Okay. */
+ }
+ tty_printf (_("Requested keysize is %u bits\n"), nbits);
+ /* We round it up so that it better matches the word size. */
+ if (( nbits % 64))
+ {
+ nbits = ((nbits + 63) / 64) * 64;
+ tty_printf (_("rounded up to %u bits\n"), nbits);
+ }
+ }
+ else if (method == 2)
+ {
+ tty_printf ("Not yet supported; "
+ "use the gpgsm-gencert.sh script instead\n");
+ keytype = xstrdup ("RSA");
+ nbits = defbits; /* We need a dummy value. */
+ }
+ else /* method == 3 */
+ {
+ tty_printf ("Not yet supported; "
+ "use the gpgsm-gencert.sh script instead\n");
+ keytype = xstrdup ("card:foobar");
+ nbits = defbits; /* We need a dummy value. */
+ }
+
+ /* Ask for the key usage. */
+ tty_printf (_("Possible actions for a %s key:\n"), "RSA");
+ tty_printf (_(" (%d) sign, encrypt\n"), 1 );
+ tty_printf (_(" (%d) sign\n"), 2 );
+ tty_printf (_(" (%d) encrypt\n"), 3 );
+ do
+ {
+ answer = tty_get (_("Your selection? "));
+ tty_kill_prompt ();
+ selection = *answer? atoi (answer): 1;
+ xfree (answer);
+ switch (selection)
+ {
+ case 1: keyusage = "sign, encrypt"; break;
+ case 2: keyusage = "sign"; break;
+ case 3: keyusage = "encrypt"; break;
+ default: keyusage = NULL; break;
+ }
+ }
+ while (!keyusage);
+
+ /* Get the subject name. */
+ answer = NULL;
+ do
+ {
+ size_t erroff, errlen;
+
+ xfree (answer);
+ answer = tty_get (_("Enter the X.509 subject name: "));
+ tty_kill_prompt ();
+ trim_spaces (answer);
+ if (!*answer)
+ tty_printf (_("No subject name given\n"));
+ else if ( (err = ksba_dn_teststr (answer, 0, &erroff, &errlen)) )
+ {
+ if (gpg_err_code (err) == GPG_ERR_UNKNOWN_NAME)
+ tty_printf (_("Invalid subject name label `%.*s'\n"),
+ (int)errlen, answer+erroff);
+ else
+ {
+ /* TRANSLATORS: The 22 in the second string is the
+ length of the first string up to the "%s". Please
+ adjust it do the length of your translation. The
+ second string is merely passed to atoi so you can
+ drop everything after the number. */
+ tty_printf (_("Invalid subject name `%s'\n"), answer);
+ tty_printf ("%*s^\n",
+ atoi (_("22 translator: see "
+ "certreg-ui.c:gpgsm_gencertreq_tty"))
+ + (int)erroff, "");
+ }
+ *answer = 0;
+ }
+ }
+ while (!*answer);
+ subject_name = answer;
+ answer = NULL;
+
+ /* Get the email addresses. */
+ tty_printf (_("Enter email addresses"));
+ tty_printf (_(" (end with an empty line):\n"));
+ ask_mb_lines (&mb_email, "Name-Email: ");
+
+ /* DNS names. */
+ tty_printf (_("Enter DNS names"));
+ tty_printf (_(" (optional; end with an empty line):\n"));
+ ask_mb_lines (&mb_email, "Name-DNS: ");
+
+ /* URIs. */
+ tty_printf (_("Enter URIs"));
+ tty_printf (_(" (optional; end with an empty line):\n"));
+ ask_mb_lines (&mb_email, "Name-URI: ");
+
+
+ /* Put it all together. */
+ store_key_value_lf (&mb_result, "Key-Type: ", keytype);
+ {
+ char numbuf[30];
+ snprintf (numbuf, sizeof numbuf, "%u", nbits);
+ store_key_value_lf (&mb_result, "Key-Length: ", numbuf);
+ }
+ store_key_value_lf (&mb_result, "Key-Usage: ", keyusage);
+ store_key_value_lf (&mb_result, "Name-DN: ", subject_name);
+ if (keygrip)
+ store_key_value_lf (&mb_result, "Key-Grip: ", keygrip);
+ if (store_mb_lines (&mb_result, &mb_email))
+ goto mem_error;
+ if (store_mb_lines (&mb_result, &mb_dns))
+ goto mem_error;
+ if (store_mb_lines (&mb_result, &mb_uri))
+ goto mem_error;
+ put_membuf (&mb_result, "", 1);
+ result = get_membuf (&mb_result, NULL);
+ if (!result)
+ goto mem_error;
+
+ tty_printf (_("Parameters to be used for the certificate request:\n"));
+ for (s=result; (s2 = strchr (s, '\n')); s = s2+1, i++)
+ tty_printf (" %.*s\n", (int)(s2-s), s);
+ tty_printf ("\n");
+
+
+ if (!tty_get_answer_is_yes ("Really create request? (y/N) "))
+ goto leave;
+
+ /* Now create a parameter file and generate the key. */
+ fp = tmpfile ();
+ if (!fp)
+ {
+ log_error (_("error creating temporary file: %s\n"), strerror (errno));
+ goto leave;
+ }
+ fputs (result, fp);
+ rewind (fp);
+ tty_printf (_("Now creating certificate request. "
+ "This may take a while ...\n"));
+ {
+ int save_pem = ctrl->create_pem;
+ ctrl->create_pem = 1; /* Force creation of PEM. */
+ err = gpgsm_genkey (ctrl, -1, fp, output_fp);
+ ctrl->create_pem = save_pem;
+ }
+ if (!err)
+ tty_printf (_("Ready. You should now send this request to your CA.\n"));
+
+
+ goto leave;
+ mem_error:
+ log_error (_("resource problem: out or core\n"));
+ leave:
+ if (fp)
+ fclose (fp);
+ xfree (keytype);
+ xfree (subject_name);
+ xfree (keygrip);
+ xfree (get_membuf (&mb_email, NULL));
+ xfree (get_membuf (&mb_dns, NULL));
+ xfree (get_membuf (&mb_uri, NULL));
+ xfree (get_membuf (&mb_result, NULL));
+ xfree (result);
+}
diff --git a/sm/certreqgen.c b/sm/certreqgen.c
index 043e218c4..4ffd8363e 100644
--- a/sm/certreqgen.c
+++ b/sm/certreqgen.c
@@ -831,17 +831,20 @@ create_request (ctrl_t ctrl,
-/* Create a new key by reading the parameters from in_fd. Multiple
- keys may be created */
+/* Create a new key by reading the parameters from in_fd or in_stream.
+ Multiple keys may be created */
int
-gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *out_fp)
+gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *in_stream, FILE *out_fp)
{
int rc;
FILE *in_fp;
Base64Context b64writer = NULL;
ksba_writer_t writer;
- in_fp = fdopen (dup (in_fd), "rb");
+ if (in_stream)
+ in_fp = in_stream;
+ else
+ in_fp = fdopen (dup (in_fd), "rb");
if (!in_fp)
{
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
@@ -877,7 +880,8 @@ gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *out_fp)
leave:
gpgsm_destroy_writer (b64writer);
- fclose (in_fp);
+ if (!in_stream)
+ fclose (in_fp);
return rc;
}
diff --git a/sm/gpgsm.c b/sm/gpgsm.c
index b6a3e69c2..ee6cf08cd 100644
--- a/sm/gpgsm.c
+++ b/sm/gpgsm.c
@@ -1590,12 +1590,15 @@ main ( int argc, char **argv)
case aKeygen: /* Generate a key; well kind of. */
- log_error
- (_("key generation is not available from the commandline\n"));
- log_info (_("please use the script \"%s\" to generate a new key\n"),
- "gpgsm-gencert.sh");
+ {
+ FILE *fp = open_fwrite (opt.outfile?opt.outfile:"-");
+ gpgsm_gencertreq_tty (&ctrl, fp);
+ if (fp != stdout)
+ fclose (fp);
+ }
break;
+
case aImport:
gpgsm_import_files (&ctrl, argc, argv, open_read);
break;
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 727b1cf98..62b106bfc 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -167,7 +167,6 @@ struct server_control_s
signer) */
int use_ocsp; /* Set to true if OCSP should be used. */
};
-typedef struct server_control_s *ctrl_t;
/* Data structure used in base64.c. */
@@ -317,7 +316,11 @@ int gpgsm_encrypt (ctrl_t ctrl, certlist_t recplist, int in_fd, FILE *out_fp);
int gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp);
/*-- certreqgen.c --*/
-int gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *out_fp);
+int gpgsm_genkey (ctrl_t ctrl, int in_fd, FILE *in_stream, FILE *out_fp);
+
+/*-- certreqgen-ui.c --*/
+void gpgsm_gencertreq_tty (ctrl_t ctrl, FILE *out_fp);
+
/*-- qualified.c --*/
gpg_error_t gpgsm_is_in_qualified_list (ctrl_t ctrl, ksba_cert_t cert,
diff --git a/sm/server.c b/sm/server.c
index 278f4ecbf..27749799c 100644
--- a/sm/server.c
+++ b/sm/server.c
@@ -865,7 +865,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
out_fp = fdopen ( dup(out_fd), "w");
if (!out_fp)
return set_error (GPG_ERR_ASS_GENERAL, "fdopen() failed");
- rc = gpgsm_genkey (ctrl, inp_fd, out_fp);
+ rc = gpgsm_genkey (ctrl, inp_fd, NULL, out_fp);
fclose (out_fp);
/* close and reset the fds */