aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2003-06-27 20:53:09 +0000
committerWerner Koch <[email protected]>2003-06-27 20:53:09 +0000
commit5c46f134e22d57fafc901c95350fad11efc10516 (patch)
tree2e7682e37d1c3ffddf3437d63ab48a7bc0847531
parentFixes to the libgcrypt switch. Basically works now. (diff)
downloadgnupg-5c46f134e22d57fafc901c95350fad11efc10516.tar.gz
gnupg-5c46f134e22d57fafc901c95350fad11efc10516.zip
Key generation and signing using the OpenPGP card does rudimentary work.
-rw-r--r--NEWS2
-rw-r--r--g10/ChangeLog22
-rw-r--r--g10/Makefile.am3
-rw-r--r--g10/build-packet.c10
-rw-r--r--g10/call-agent.c311
-rw-r--r--g10/call-agent.h39
-rw-r--r--g10/g10.c13
-rw-r--r--g10/gpgv.c2
-rw-r--r--g10/keyedit.c4
-rw-r--r--g10/keygen.c926
-rw-r--r--g10/parse-packet.c32
-rw-r--r--g10/passphrase.c2
-rw-r--r--g10/seckey-cert.c3
-rw-r--r--g10/seskey.c5
-rw-r--r--g10/sign.c148
-rw-r--r--g10/tdbio.c5
16 files changed, 1140 insertions, 387 deletions
diff --git a/NEWS b/NEWS
index 5c8a8342a..794ad11f1 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
Noteworthy changes in version 1.9.0 (unreleased)
------------------------------------------------
+ * gpg does now also use libgcrypt, libgpg-error is required.
+
* New gpgsm commands --call-dirmngr and --call-protect-tool.
* Changing a passphrase is now possible using "gpgsm --passwd"
diff --git a/g10/ChangeLog b/g10/ChangeLog
index b4db7b5f0..023f66b0d 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,25 @@
+2003-06-27 Werner Koch <[email protected]>
+
+ * seckey-cert.c (check_secret_key): Bypass the unprotection for
+ mode 1002.
+ * sign.c (do_sign): Handle card case (i.e. mode 1002).
+
+2003-06-26 Werner Koch <[email protected]>
+
+ * build-packet.c (do_secret_key): Implement special protection
+ mode 1002.
+ * parse-packet.c (parse_key): Likewise.
+
+ * keygen.c (smartcard_gen_key): New.
+ * call-agent.c (agent_scd_setattr): New.
+
+2003-06-24 Werner Koch <[email protected]>
+
+ * Makefile.am: Removed signal.c
+
+ * g10.c (emergency_cleanup): New.
+ (main): Use gnupg_init_signals and register malloc for assuan.
+
2003-06-23 Werner Koch <[email protected]>
* keyid.c (do_fingerprint_md): Made it work again.
diff --git a/g10/Makefile.am b/g10/Makefile.am
index 6940be67a..3137bb894 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -63,8 +63,7 @@ common_source = \
plaintext.c \
sig-check.c \
keylist.c \
- pkglue.c pkglue.h \
- signal.c
+ pkglue.c pkglue.h
gpg_SOURCES = g10.c \
$(common_source) \
diff --git a/g10/build-packet.c b/g10/build-packet.c
index a3177525e..afc123624 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -415,8 +415,9 @@ do_secret_key( iobuf_t 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 and 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 );
}
}
@@ -425,6 +426,11 @@ do_secret_key( iobuf_t 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, 0 ); /* length of the serial number or 0 for unknown. */
+ /* fixme: write the serial number. */
+ }
else if( sk->is_protected && sk->version >= 4 ) {
/* The secret key is protected - write it out as it is */
byte *p;
diff --git a/g10/call-agent.c b/g10/call-agent.c
index e888820cc..67aa333ee 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -47,7 +47,7 @@
#endif
static ASSUAN_CONTEXT agent_ctx = NULL;
-static int force_pipe_server = 0;
+static int force_pipe_server = 1; /* FIXME: set this back to 0. */
struct cipher_parm_s {
ASSUAN_CONTEXT ctx;
@@ -61,11 +61,6 @@ struct genkey_parm_s {
size_t sexplen;
};
-struct learn_parm_s {
- int error;
- ASSUAN_CONTEXT ctx;
- struct membuf *data;
-};
/* Try to connect to the agent via socket or fork it off and work by
@@ -292,16 +287,59 @@ start_agent (void)
}
-static AssuanError
-membuf_data_cb (void *opaque, const void *buffer, size_t length)
+/* Return a new malloced string by unescaping the string S. Escaping
+ is percent escaping and '+'/space mapping. A binary nul will
+ silently be replaced by a 0xFF. Function returns NULL to indicate
+ an out of memory status. */
+static char *
+unescape_status_string (const unsigned char *s)
{
- membuf_t *data = opaque;
+ char *buffer, *d;
- if (buffer)
- put_membuf (data, buffer, length);
- return 0;
+ buffer = d = xtrymalloc (strlen (s)+1);
+ if (!buffer)
+ return NULL;
+ while (*s)
+ {
+ if (*s == '%' && s[1] && s[2])
+ {
+ s++;
+ *d = xtoi_2 (s);
+ if (!*d)
+ *d = '\xff';
+ d++;
+ s += 2;
+ }
+ else if (*s == '+')
+ {
+ *d++ = ' ';
+ s++;
+ }
+ else
+ *d++ = *s++;
+ }
+ *d = 0;
+ return buffer;
+}
+
+/* Take a 20 byte hexencoded string and put it into the the provided
+ 20 byte buffer FPR in binary format. */
+static int
+unhexify_fpr (const char *hexstr, unsigned char *fpr)
+{
+ const char *s;
+ int n;
+
+ for (s=hexstr, n=0; hexdigitp (s); s++, n++)
+ ;
+ if (*s || (n != 40))
+ return 0; /* no fingerprint (invalid or wrong length). */
+ n /= 2;
+ for (s=hexstr, n=0; *s; s += 2, n++)
+ fpr[n] = xtoi_2 (s);
+ return 1; /* okay */
}
-
+
#if 0
@@ -391,25 +429,258 @@ agent_havekey (const char *hexkeygrip)
}
-/* Ask the agent to change the passphrase of the key identified by
- HEXKEYGRIP. */
+static AssuanError
+learn_status_cb (void *opaque, const char *line)
+{
+ struct agent_card_info_s *parm = opaque;
+ const char *keyword = line;
+ int keywordlen;
+
+ log_debug ("got status line `%s'\n", line);
+ for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+ ;
+ while (spacep (line))
+ line++;
+
+ if (keywordlen == 9 && !memcmp (keyword, "DISP-NAME", keywordlen))
+ {
+ parm->disp_name = unescape_status_string (line);
+ }
+ else if (keywordlen == 10 && !memcmp (keyword, "PUBKEY_URL", keywordlen))
+ {
+ parm->pubkey_url = unescape_status_string (line);
+ }
+ else if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
+ {
+ int no = atoi (line);
+ while (!spacep (line))
+ line++;
+ while (spacep (line))
+ line++;
+ if (no == 1)
+ parm->fpr1valid = unhexify_fpr (line, parm->fpr1);
+ else if (no == 2)
+ parm->fpr2valid = unhexify_fpr (line, parm->fpr2);
+ else if (no == 3)
+ parm->fpr3valid = unhexify_fpr (line, parm->fpr3);
+ }
+
+ return 0;
+}
+
+/* Call the agent to learn about a smartcard */
int
-agent_passwd (const char *hexkeygrip)
+agent_learn (struct agent_card_info_s *info)
{
int rc;
- char line[ASSUAN_LINELENGTH];
rc = start_agent ();
if (rc)
return rc;
- if (!hexkeygrip || strlen (hexkeygrip) != 40)
+ memset (info, 0, sizeof *info);
+ rc = assuan_transact (agent_ctx, "LEARN --send",
+ NULL, NULL, NULL, NULL,
+ learn_status_cb, info);
+
+ return map_assuan_err (rc);
+}
+
+
+
+/* Send an setattr command to the SCdaemon. */
+int
+agent_scd_setattr (const char *name,
+ const unsigned char *value, size_t valuelen)
+{
+ int rc;
+ char line[ASSUAN_LINELENGTH];
+ char *p;
+
+ if (!*name || !valuelen)
return gpg_error (GPG_ERR_INV_VALUE);
- snprintf (line, DIM(line)-1, "PASSWD %s", hexkeygrip);
- line[DIM(line)-1] = 0;
+ /* We assume that NAME does not need escaping. */
+ if (12 + strlen (name) > DIM(line)-1)
+ return gpg_error (GPG_ERR_TOO_LARGE);
+
+ p = stpcpy (stpcpy (line, "SCD SETATTR "), name);
+ *p++ = ' ';
+ for (; valuelen; value++, valuelen--)
+ {
+ if (p >= line + DIM(line)-5 )
+ return gpg_error (GPG_ERR_TOO_LARGE);
+ if (*value < ' ' || *value == '+' || *value == '%')
+ {
+ sprintf (p, "%%%02X", *value);
+ p += 3;
+ }
+ else if (*value == ' ')
+ *p++ = '+';
+ else
+ *p++ = *value;
+ }
+ *p = 0;
+
+ rc = start_agent ();
+ if (rc)
+ return rc;
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
return map_assuan_err (rc);
}
+
+/* Status callback for the SCD GENKEY command. */
+static AssuanError
+scd_genkey_cb (void *opaque, const char *line)
+{
+ struct agent_card_genkey_s *parm = opaque;
+ const char *keyword = line;
+ int keywordlen;
+ gpg_error_t rc;
+
+ log_debug ("got status line `%s'\n", line);
+ for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+ ;
+ while (spacep (line))
+ line++;
+
+ if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
+ {
+ parm->fprvalid = unhexify_fpr (line, parm->fpr);
+ }
+ if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
+ {
+ gcry_mpi_t a;
+ const char *name = line;
+
+ while (!spacep (line))
+ line++;
+ while (spacep (line))
+ line++;
+
+ rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0);
+ if (rc)
+ log_error ("error parsing received key data: %s\n", gpg_strerror (rc));
+ else if (*name == 'n' && spacep (name+1))
+ parm->n = a;
+ else if (*name == 'e' && spacep (name+1))
+ parm->e = a;
+ else
+ {
+ log_info ("unknown parameter name in received key data\n");
+ gcry_mpi_release (a);
+ }
+ }
+ else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
+ {
+ parm->created_at = (u32)strtoul (line, NULL, 10);
+ }
+
+ return 0;
+}
+
+/* Send a GENKEY command to the SCdaemon. */
+int
+agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force)
+{
+ int rc;
+ char line[ASSUAN_LINELENGTH];
+
+ rc = start_agent ();
+ if (rc)
+ return rc;
+
+ memset (info, 0, sizeof *info);
+ snprintf (line, DIM(line)-1, "SCD GENKEY %s%d",
+ force? "--force ":"", keyno);
+ line[DIM(line)-1] = 0;
+
+ memset (info, 0, sizeof *info);
+ rc = assuan_transact (agent_ctx, line,
+ NULL, NULL, NULL, NULL,
+ scd_genkey_cb, info);
+
+ return map_assuan_err (rc);
+}
+
+
+static AssuanError
+membuf_data_cb (void *opaque, const void *buffer, size_t length)
+{
+ membuf_t *data = opaque;
+
+ if (buffer)
+ put_membuf (data, buffer, length);
+ return 0;
+}
+
+/* Send a sign command to the scdaemon via gpg-agent's pass thru
+ mechanism. */
+int
+agent_scd_pksign (const char *keyid, int hashalgo,
+ const unsigned char *indata, size_t indatalen,
+ char **r_buf, size_t *r_buflen)
+{
+ int rc, i;
+ char *p, line[ASSUAN_LINELENGTH];
+ membuf_t data;
+ size_t len;
+
+ /* Note, hashalgo is not yet used but hardwired to SHA1 in SCdaemon. */
+
+ *r_buf = NULL;
+ *r_buflen = 0;
+
+ rc = start_agent ();
+ if (rc)
+ return rc;
+
+ if (indatalen*2 + 50 > DIM(line))
+ return gpg_error (GPG_ERR_GENERAL);
+
+ sprintf (line, "SCD SETDATA ");
+ p = line + strlen (line);
+ for (i=0; i < indatalen ; i++, p += 2 )
+ sprintf (p, "%02X", indata[i]);
+ rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (rc)
+ return rc;
+
+ init_membuf (&data, 1024);
+ snprintf (line, DIM(line)-1, "SCD PKSIGN %s", keyid);
+ line[DIM(line)-1] = 0;
+ rc = assuan_transact (agent_ctx, line, membuf_data_cb, &data,
+ NULL, NULL, NULL, NULL);
+ if (rc)
+ {
+ xfree (get_membuf (&data, &len));
+ return rc;
+ }
+ *r_buf = get_membuf (&data, r_buflen);
+
+ return 0;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/g10/call-agent.h b/g10/call-agent.h
index fbb11958c..c620268f2 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -20,10 +20,46 @@
#ifndef GNUPG_G10_CALL_AGENT_H
#define GNUPG_G10_CALL_AGENT_H
+
+struct agent_card_info_s {
+ int error; /* private. */
+ char *disp_name; /* malloced. */
+ char *pubkey_url; /* malloced. */
+ char fpr1valid;
+ char fpr2valid;
+ char fpr3valid;
+ char fpr1[20];
+ char fpr2[20];
+ char fpr3[20];
+};
+
+struct agent_card_genkey_s {
+ char fprvalid;
+ char fpr[20];
+ u32 created_at;
+ gcry_mpi_t n;
+ gcry_mpi_t e;
+};
+
+/* Return card info. */
+int agent_learn (struct agent_card_info_s *info);
+
/* Check whether the secret key for the key identified by HEXKEYGRIP
is available. Return 0 for yes or an error code. */
int agent_havekey (const char *hexkeygrip);
+/* Send a SETATTR command to the SCdaemon. */
+int agent_scd_setattr (const char *name,
+ const unsigned char *value, size_t valuelen);
+
+/* Send a GENKEY command to the SCdaemon. */
+int 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,
+ const unsigned char *indata, size_t indatalen,
+ char **r_buf, size_t *r_buflen);
+
/* Ask the agent to let the user change the passphrase of the secret
key identified by HEXKEYGRIP. */
int agent_passwd (const char *hexkeygrip);
@@ -31,4 +67,7 @@ int agent_passwd (const char *hexkeygrip);
+
+
#endif /*GNUPG_G10_CALL_AGENT_H*/
+
diff --git a/g10/g10.c b/g10/g10.c
index cf6240d55..6909e0404 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -639,6 +639,7 @@ static void set_cmd( enum cmd_and_opt_values *ret_cmd,
static void print_mds( const char *fname, int algo );
static void add_notation_data( const char *string, int which );
static void add_policy_url( const char *string, int which );
+static void emergency_cleanup (void);
#ifdef __riscos__
RISCOS_GLOBAL_STATICS("GnuPG Heap")
@@ -1191,7 +1192,7 @@ main( int argc, char **argv )
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
may_coredump = disable_core_dumps();
- init_signals (); /* why not gnupg_init_signals. */
+ gnupg_init_signals (0, emergency_cleanup);
create_dotlock (NULL); /* register locking cleanup */
i18n_init();
@@ -1303,7 +1304,8 @@ main( int argc, char **argv )
maybe_setuid = 0;
/* Okay, we are now working under our real uid */
- /* malloc hooks gohere ... */
+ /* malloc hooks go here ... */
+ assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
set_native_charset (NULL); /* Try to auto set the character set */
@@ -2894,6 +2896,13 @@ main( int argc, char **argv )
return 8; /*NEVER REACHED*/
}
+/* Note: This function is used by signal handlers!. */
+static void
+emergency_cleanup (void)
+{
+ gcry_control (GCRYCTL_TERM_SECMEM );
+}
+
void
g10_exit( int rc )
diff --git a/g10/gpgv.c b/g10/gpgv.c
index 91574a78b..da108d225 100644
--- a/g10/gpgv.c
+++ b/g10/gpgv.c
@@ -147,7 +147,7 @@ main( int argc, char **argv )
set_strusage (my_strusage);
log_set_prefix ("gpgv", 1);
- init_signals();
+ gnupg_init_signals(0, NULL);
i18n_init();
opt.command_fd = -1; /* no command fd */
opt.pgp2_workarounds = 1;
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 38248a3d0..11e2d870e 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -921,6 +921,10 @@ change_passphrase( KBNODE keyblock )
tty_printf(_("Secret parts of primary key are not available.\n"));
no_primary_secrets = 1;
}
+ else if( sk->protect.s2k.mode == 1002 ) {
+ tty_printf(_("Secret key is actually stored on a card.\n"));
+ no_primary_secrets = 1;
+ }
else {
tty_printf(_("Key is protected.\n"));
rc = check_secret_key( sk, 0 );
diff --git a/g10/keygen.c b/g10/keygen.c
index 041a495bd..328647f03 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -38,6 +38,8 @@
#include "trustdb.h"
#include "status.h"
#include "i18n.h"
+#include "call-agent.h"
+
#define MAX_PREFS 30
@@ -111,8 +113,11 @@ static int nzip_prefs;
static int mdc_available,ks_modify;
static void do_generate_keypair( struct para_data_s *para,
- struct output_control_s *outctrl );
-static int write_keyblock( iobuf_t out, KBNODE node );
+ struct output_control_s *outctrl, int card);
+static int write_keyblock( iobuf_t out, KBNODE node );
+static int check_smartcard (void);
+static int gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root, u32 expireval);
+
static void
@@ -1752,7 +1757,7 @@ get_parameter_revkey( struct para_data_s *para, enum para_name key )
static int
proc_parameter_file( struct para_data_s *para, const char *fname,
- struct output_control_s *outctrl )
+ struct output_control_s *outctrl, int card )
{
struct para_data_s *r;
const char *s1, *s2, *s3;
@@ -1814,8 +1819,8 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
r = get_parameter( para, pPASSPHRASE );
if( r && *r->u.value ) {
/* we have a plain text passphrase - create a DEK from it.
- * It is a little bit ridiculous to keep it ih secure memory
- * but becuase we do this alwasy, why not here */
+ * It is a little bit ridiculous to keep it in secure memory
+ * but because we do this always, why not here. */
STRING2KEY *s2k;
DEK *dek;
@@ -1864,7 +1869,7 @@ proc_parameter_file( struct para_data_s *para, const char *fname,
return -1;
}
- do_generate_keypair( para, outctrl );
+ do_generate_keypair( para, outctrl, card);
return 0;
}
@@ -1948,7 +1953,7 @@ read_parameter_file( const char *fname )
outctrl.dryrun = 1;
else if( !ascii_strcasecmp( keyword, "%commit" ) ) {
outctrl.lnr = lnr;
- proc_parameter_file( para, fname, &outctrl );
+ proc_parameter_file( para, fname, &outctrl, 0 );
release_parameter_list( para );
para = NULL;
}
@@ -2008,7 +2013,7 @@ read_parameter_file( const char *fname )
if( keywords[i].key == pKEYTYPE && para ) {
outctrl.lnr = lnr;
- proc_parameter_file( para, fname, &outctrl );
+ proc_parameter_file( para, fname, &outctrl, 0 );
release_parameter_list( para );
para = NULL;
}
@@ -2036,7 +2041,7 @@ read_parameter_file( const char *fname )
}
else if( para ) {
outctrl.lnr = lnr;
- proc_parameter_file( para, fname, &outctrl );
+ proc_parameter_file( para, fname, &outctrl, 0 );
}
if( outctrl.use_files ) { /* close open streams */
@@ -2061,113 +2066,139 @@ read_parameter_file( const char *fname )
void
generate_keypair( const char *fname )
{
- unsigned int nbits;
- char *uid = NULL;
- DEK *dek;
- STRING2KEY *s2k;
- int algo;
- unsigned int use;
- int both = 0;
- u32 expire;
- struct para_data_s *para = NULL;
- struct para_data_s *r;
- struct output_control_s outctrl;
-
- memset( &outctrl, 0, sizeof( outctrl ) );
-
- if( opt.batch ) {
- read_parameter_file( fname );
- return;
+ unsigned int nbits;
+ char *uid = NULL;
+ DEK *dek;
+ STRING2KEY *s2k;
+ int algo;
+ unsigned int use;
+ int both = 0;
+ int card = 0;
+ u32 expire;
+ struct para_data_s *para = NULL;
+ struct para_data_s *r;
+ struct output_control_s outctrl;
+
+ memset (&outctrl, 0, sizeof (outctrl));
+
+ if (opt.batch)
+ {
+ read_parameter_file( fname );
+ return;
}
- algo = ask_algo( 0, &use );
- if( !algo ) { /* default: DSA with ElG subkey of the specified size */
- both = 1;
- r = xcalloc (1, sizeof *r + 20 );
- r->key = pKEYTYPE;
- sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
- r->next = para;
- para = r;
- tty_printf(_("DSA keypair will have 1024 bits.\n"));
- r = xcalloc (1, sizeof *r + 20 );
- r->key = pKEYLENGTH;
- strcpy( r->u.value, "1024" );
- r->next = para;
- para = r;
-
- algo = PUBKEY_ALGO_ELGAMAL_E;
- r = xcalloc (1, sizeof *r + 20 );
- r->key = pSUBKEYTYPE;
- sprintf( r->u.value, "%d", algo );
- r->next = para;
- para = r;
+ do
+ {
+ card = check_smartcard ();
+ if (card < 0)
+ return;
+ if (card > 1)
+ log_error (_("can't generate subkey here\n"));
}
- else {
- r = xcalloc (1, sizeof *r + 20 );
- r->key = pKEYTYPE;
- sprintf( r->u.value, "%d", algo );
- r->next = para;
- para = r;
+ while (card > 1);
- if (use) {
- r = xcalloc (1, sizeof *r + 20 );
- r->key = pKEYUSAGE;
- sprintf( r->u.value, "%s%s",
- (use & PUBKEY_USAGE_SIG)? "sign ":"",
- (use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
- r->next = para;
- para = r;
+ if (card)
+ {
+ algo = PUBKEY_ALGO_RSA;
+ use = PUBKEY_USAGE_SIG;
+ }
+ else
+ algo = ask_algo (0, &use);
+
+ if (!algo)
+ { /* default: DSA with ElG subkey of the specified size */
+ both = 1;
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pKEYTYPE;
+ sprintf( r->u.value, "%d", PUBKEY_ALGO_DSA );
+ r->next = para;
+ para = r;
+ tty_printf(_("DSA keypair will have 1024 bits.\n"));
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pKEYLENGTH;
+ strcpy( r->u.value, "1024" );
+ r->next = para;
+ para = r;
+
+ algo = PUBKEY_ALGO_ELGAMAL_E;
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pSUBKEYTYPE;
+ sprintf( r->u.value, "%d", algo );
+ r->next = para;
+ para = r;
+ }
+ else
+ {
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pKEYTYPE;
+ sprintf( r->u.value, "%d", algo );
+ r->next = para;
+ para = r;
+
+ if (use)
+ {
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pKEYUSAGE;
+ sprintf( r->u.value, "%s%s",
+ (use & PUBKEY_USAGE_SIG)? "sign ":"",
+ (use & PUBKEY_USAGE_ENC)? "encrypt ":"" );
+ r->next = para;
+ para = r;
}
-
}
- nbits = ask_keysize( algo );
- r = xcalloc (1, sizeof *r + 20 );
- r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
- sprintf( r->u.value, "%u", nbits);
- r->next = para;
- para = r;
-
- expire = ask_expire_interval(0);
- r = xcalloc (1, sizeof *r + 20 );
- r->key = pKEYEXPIRE;
- r->u.expire = expire;
- r->next = para;
- para = r;
- r = xcalloc (1, sizeof *r + 20 );
- r->key = pSUBKEYEXPIRE;
- r->u.expire = expire;
- r->next = para;
- para = r;
-
- uid = ask_user_id(0);
- if( !uid ) {
- log_error(_("Key generation canceled.\n"));
- release_parameter_list( para );
- return;
- }
- r = xcalloc (1, sizeof *r + strlen(uid) );
- r->key = pUSERID;
- strcpy( r->u.value, uid );
- r->next = para;
- para = r;
-
- dek = ask_passphrase( &s2k );
- if( dek ) {
- r = xcalloc (1, sizeof *r );
- r->key = pPASSPHRASE_DEK;
- r->u.dek = dek;
- r->next = para;
- para = r;
- r = xcalloc (1, sizeof *r );
- r->key = pPASSPHRASE_S2K;
- r->u.s2k = s2k;
- r->next = para;
- para = r;
+ if (!card)
+ {
+ nbits = ask_keysize( algo );
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
+ sprintf( r->u.value, "%u", nbits);
+ r->next = para;
+ para = r;
}
+
+ expire = ask_expire_interval(0);
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pKEYEXPIRE;
+ r->u.expire = expire;
+ r->next = para;
+ para = r;
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pSUBKEYEXPIRE;
+ r->u.expire = expire;
+ r->next = para;
+ para = r;
+
+ uid = ask_user_id(0);
+ if (!uid)
+ {
+ log_error(_("Key generation canceled.\n"));
+ release_parameter_list( para );
+ return;
+ }
+ r = xcalloc (1, sizeof *r + strlen(uid) );
+ r->key = pUSERID;
+ strcpy( r->u.value, uid );
+ r->next = para;
+ para = r;
- proc_parameter_file( para, "[internal]", &outctrl );
- release_parameter_list( para );
+ dek = card? NULL : ask_passphrase( &s2k );
+ if (dek)
+ {
+ r = xcalloc (1, sizeof *r );
+ r->key = pPASSPHRASE_DEK;
+ r->u.dek = dek;
+ r->next = para;
+ para = r;
+ r = xcalloc (1, sizeof *r );
+ r->key = pPASSPHRASE_S2K;
+ r->u.s2k = s2k;
+ r->next = para;
+ para = r;
+ }
+
+ proc_parameter_file (para, "[internal]", &outctrl, card);
+ release_parameter_list (para);
}
@@ -2189,225 +2220,271 @@ print_status_key_created (int letter, PKT_public_key *pk)
write_status_text (STATUS_KEY_CREATED, buf);
}
+
+
static void
-do_generate_keypair( struct para_data_s *para,
- struct output_control_s *outctrl )
+do_generate_keypair (struct para_data_s *para,
+ struct output_control_s *outctrl, int card)
{
- KBNODE pub_root = NULL;
- KBNODE sec_root = NULL;
- PKT_secret_key *sk = NULL;
- const char *s;
- struct revocation_key *revkey;
- int rc;
- int did_sub = 0;
-
- if( outctrl->dryrun ) {
- log_info("dry-run mode - key generation skipped\n");
- return;
+ KBNODE pub_root = NULL;
+ KBNODE sec_root = NULL;
+ PKT_secret_key *sk = NULL;
+ const char *s;
+ struct revocation_key *revkey;
+ int rc;
+ int did_sub = 0;
+
+ if (outctrl->dryrun)
+ {
+ log_info ("dry-run mode - key generation skipped\n");
+ return;
}
- if( outctrl->use_files ) {
- if( outctrl->pub.newfname ) {
- iobuf_close(outctrl->pub.stream);
- outctrl->pub.stream = NULL;
- xfree ( outctrl->pub.fname );
- outctrl->pub.fname = outctrl->pub.newfname;
- outctrl->pub.newfname = NULL;
-
- outctrl->pub.stream = iobuf_create( outctrl->pub.fname );
- if( !outctrl->pub.stream ) {
- log_error("can't create `%s': %s\n", outctrl->pub.newfname,
- strerror(errno) );
- return;
+ if (outctrl->use_files)
+ {
+ if (outctrl->pub.newfname)
+ {
+ iobuf_close (outctrl->pub.stream);
+ outctrl->pub.stream = NULL;
+ xfree (outctrl->pub.fname);
+ outctrl->pub.fname = outctrl->pub.newfname;
+ outctrl->pub.newfname = NULL;
+
+ outctrl->pub.stream = iobuf_create (outctrl->pub.fname);
+ if (!outctrl->pub.stream)
+ {
+ log_error ("can't create `%s': %s\n", outctrl->pub.newfname,
+ strerror (errno));
+ return;
}
- if( opt.armor ) {
- outctrl->pub.afx.what = 1;
- iobuf_push_filter( outctrl->pub.stream, armor_filter,
- &outctrl->pub.afx );
+ if (opt.armor)
+ {
+ outctrl->pub.afx.what = 1;
+ iobuf_push_filter (outctrl->pub.stream, armor_filter,
+ &outctrl->pub.afx);
}
}
- if( outctrl->sec.newfname ) {
- iobuf_close(outctrl->sec.stream);
- outctrl->sec.stream = NULL;
- xfree ( outctrl->sec.fname );
- outctrl->sec.fname = outctrl->sec.newfname;
- outctrl->sec.newfname = NULL;
-
- outctrl->sec.stream = iobuf_create( outctrl->sec.fname );
- if( !outctrl->sec.stream ) {
- log_error("can't create `%s': %s\n", outctrl->sec.newfname,
- strerror(errno) );
- return;
+ if (outctrl->sec.newfname)
+ {
+ iobuf_close (outctrl->sec.stream);
+ outctrl->sec.stream = NULL;
+ xfree (outctrl->sec.fname);
+ outctrl->sec.fname = outctrl->sec.newfname;
+ outctrl->sec.newfname = NULL;
+
+ outctrl->sec.stream = iobuf_create (outctrl->sec.fname);
+ if (!outctrl->sec.stream)
+ {
+ log_error ("can't create `%s': %s\n", outctrl->sec.newfname,
+ strerror (errno));
+ return;
}
- if( opt.armor ) {
- outctrl->sec.afx.what = 5;
- iobuf_push_filter( outctrl->sec.stream, armor_filter,
- &outctrl->sec.afx );
+ if (opt.armor)
+ {
+ outctrl->sec.afx.what = 5;
+ iobuf_push_filter (outctrl->sec.stream, armor_filter,
+ &outctrl->sec.afx);
}
}
- assert( outctrl->pub.stream );
- assert( outctrl->sec.stream );
- if( opt.verbose ) {
- log_info(_("writing public key to `%s'\n"), outctrl->pub.fname );
- log_info(_("writing secret key to `%s'\n"), outctrl->sec.fname );
- }
+ assert (outctrl->pub.stream);
+ assert (outctrl->sec.stream);
+ if (opt.verbose)
+ {
+ log_info (_("writing public key to `%s'\n"), outctrl->pub.fname);
+ if (card)
+ log_info (_("writing secret key stub to `%s'\n"),
+ outctrl->sec.fname);
+ else
+ log_info (_("writing secret key to `%s'\n"), outctrl->sec.fname);
+ }
}
- /* we create the packets as a tree of kbnodes. Because the structure
- * we create is known in advance we simply generate a linked list
- * The first packet is a dummy comment packet which we flag
- * as deleted. The very first packet must always be a KEY packet.
- */
- pub_root = make_comment_node("#"); delete_kbnode(pub_root);
- sec_root = make_comment_node("#"); delete_kbnode(sec_root);
-
- rc = do_create( get_parameter_algo( para, pKEYTYPE ),
- get_parameter_uint( para, pKEYLENGTH ),
- pub_root, sec_root,
- get_parameter_dek( para, pPASSPHRASE_DEK ),
- get_parameter_s2k( para, pPASSPHRASE_S2K ),
- &sk,
- get_parameter_u32( para, pKEYEXPIRE ) );
-
- if(!rc && (revkey=get_parameter_revkey(para,pREVOKER)))
- {
- rc=write_direct_sig(pub_root,pub_root,sk,revkey);
- if(!rc)
- write_direct_sig(sec_root,pub_root,sk,revkey);
- }
-
- if( !rc && (s=get_parameter_value(para, pUSERID)) ) {
- write_uid(pub_root, s );
- if( !rc )
- write_uid(sec_root, s );
- if( !rc )
- rc = write_selfsig(pub_root, pub_root, sk,
- get_parameter_uint (para, pKEYUSAGE));
- if( !rc )
- rc = write_selfsig(sec_root, pub_root, sk,
- get_parameter_uint (para, pKEYUSAGE));
- }
-
- if( get_parameter( para, pSUBKEYTYPE ) ) {
- rc = do_create( get_parameter_algo( para, pSUBKEYTYPE ),
- get_parameter_uint( para, pSUBKEYLENGTH ),
- pub_root, sec_root,
- get_parameter_dek( para, pPASSPHRASE_DEK ),
- get_parameter_s2k( para, pPASSPHRASE_S2K ),
- NULL,
- get_parameter_u32( para, pSUBKEYEXPIRE ) );
- if( !rc )
- rc = write_keybinding(pub_root, pub_root, sk,
- get_parameter_uint (para, pSUBKEYUSAGE));
- if( !rc )
- rc = write_keybinding(sec_root, pub_root, sk,
- get_parameter_uint (para, pSUBKEYUSAGE));
- did_sub = 1;
+ /* We create the packets as a tree of kbnodes. Because the structure
+ * we create is known in advance we simply generate a linked list.
+ * The first packet is a dummy comment packet which we flag
+ * as deleted. The very first packet must always be a KEY packet.
+ */
+ pub_root = make_comment_node ("#");
+ delete_kbnode (pub_root);
+ sec_root = make_comment_node ("#");
+ delete_kbnode (sec_root);
+ if (!card)
+ {
+ rc = do_create (get_parameter_algo (para, pKEYTYPE),
+ get_parameter_uint (para, pKEYLENGTH),
+ pub_root, sec_root,
+ get_parameter_dek (para, pPASSPHRASE_DEK),
+ get_parameter_s2k (para, pPASSPHRASE_S2K),
+ &sk, get_parameter_u32 (para, pKEYEXPIRE));
+ }
+ else
+ {
+ rc = gen_card_key (PUBKEY_ALGO_RSA, 1, pub_root, sec_root,
+ get_parameter_u32 (para, pKEYEXPIRE));
+ if (!rc)
+ {
+ sk = sec_root->next->pkt->pkt.secret_key;
+ assert (sk);
+ }
+
}
+ if (!rc && (revkey = get_parameter_revkey (para, pREVOKER)))
+ {
+ rc = write_direct_sig (pub_root, pub_root, sk, revkey);
+ if (!rc)
+ write_direct_sig (sec_root, pub_root, sk, revkey);
+ }
- if( !rc && outctrl->use_files ) { /* direct write to specified files */
- rc = write_keyblock( outctrl->pub.stream, pub_root );
- if( rc )
- log_error("can't write public key: %s\n", gpg_strerror (rc) );
- if( !rc ) {
- rc = write_keyblock( outctrl->sec.stream, sec_root );
- if( rc )
- log_error("can't write secret key: %s\n", gpg_strerror (rc) );
+ if (!rc && (s = get_parameter_value (para, pUSERID)))
+ {
+ write_uid (pub_root, s);
+ if (!rc)
+ write_uid (sec_root, s);
+ if (!rc)
+ rc = write_selfsig (pub_root, pub_root, sk,
+ get_parameter_uint (para, pKEYUSAGE));
+ if (!rc)
+ rc = write_selfsig (sec_root, pub_root, sk,
+ get_parameter_uint (para, pKEYUSAGE));
+ }
+
+ if (get_parameter (para, pSUBKEYTYPE))
+ {
+ rc = do_create (get_parameter_algo (para, pSUBKEYTYPE),
+ get_parameter_uint (para, pSUBKEYLENGTH),
+ pub_root, sec_root,
+ get_parameter_dek (para, pPASSPHRASE_DEK),
+ get_parameter_s2k (para, pPASSPHRASE_S2K),
+ NULL, get_parameter_u32 (para, pSUBKEYEXPIRE));
+ if (!rc)
+ rc = write_keybinding (pub_root, pub_root, sk,
+ get_parameter_uint (para, pSUBKEYUSAGE));
+ if (!rc)
+ rc = write_keybinding (sec_root, pub_root, sk,
+ get_parameter_uint (para, pSUBKEYUSAGE));
+ did_sub = 1;
+ }
+
+
+ if (!rc && outctrl->use_files)
+ { /* direct write to specified files */
+ rc = write_keyblock (outctrl->pub.stream, pub_root);
+ if (rc)
+ log_error ("can't write public key: %s\n", gpg_strerror (rc));
+ if (!rc)
+ {
+ rc = write_keyblock (outctrl->sec.stream, sec_root);
+ if (rc)
+ log_error ("can't write secret key: %s\n", gpg_strerror (rc));
}
}
- else if( !rc ) { /* write to the standard keyrings */
- KEYDB_HANDLE pub_hd = keydb_new (0);
- KEYDB_HANDLE sec_hd = keydb_new (1);
+ else if (!rc)
+ { /* write to the standard keyrings */
+ KEYDB_HANDLE pub_hd = keydb_new (0);
+ KEYDB_HANDLE sec_hd = keydb_new (1);
- /* FIXME: we may have to create the keyring first */
- rc = keydb_locate_writable (pub_hd, NULL);
- if (rc)
- log_error (_("no writable public keyring found: %s\n"),
- gpg_strerror (rc));
+ /* FIXME: we may have to create the keyring first */
+ rc = keydb_locate_writable (pub_hd, NULL);
+ if (rc)
+ log_error (_("no writable public keyring found: %s\n"),
+ gpg_strerror (rc));
- if (!rc) {
- rc = keydb_locate_writable (sec_hd, NULL);
- if (rc)
- log_error (_("no writable secret keyring found: %s\n"),
- gpg_strerror (rc));
- }
+ if (!rc)
+ {
+ rc = keydb_locate_writable (sec_hd, NULL);
+ if (rc)
+ log_error (_("no writable secret keyring found: %s\n"),
+ gpg_strerror (rc));
+ }
- if (!rc && opt.verbose) {
- log_info(_("writing public key to `%s'\n"),
- keydb_get_resource_name (pub_hd));
- log_info(_("writing secret key to `%s'\n"),
- keydb_get_resource_name (sec_hd));
- }
+ if (!rc && opt.verbose)
+ {
+ log_info (_("writing public key to `%s'\n"),
+ keydb_get_resource_name (pub_hd));
+ if (card)
+ log_info (_("writing secret key stub to `%s'\n"),
+ keydb_get_resource_name (sec_hd));
+ else
+ log_info (_("writing secret key to `%s'\n"),
+ keydb_get_resource_name (sec_hd));
+ }
- if (!rc) {
- rc = keydb_insert_keyblock (pub_hd, pub_root);
- if (rc)
- log_error (_("error writing public keyring `%s': %s\n"),
- keydb_get_resource_name (pub_hd), gpg_strerror (rc));
- }
+ if (!rc)
+ {
+ rc = keydb_insert_keyblock (pub_hd, pub_root);
+ if (rc)
+ log_error (_("error writing public keyring `%s': %s\n"),
+ keydb_get_resource_name (pub_hd), gpg_strerror (rc));
+ }
- if (!rc) {
- rc = keydb_insert_keyblock (sec_hd, sec_root);
- if (rc)
- log_error (_("error writing secret keyring `%s': %s\n"),
- keydb_get_resource_name (pub_hd), gpg_strerror (rc));
- }
+ if (!rc)
+ {
+ rc = keydb_insert_keyblock (sec_hd, sec_root);
+ if (rc)
+ log_error (_("error writing secret keyring `%s': %s\n"),
+ keydb_get_resource_name (pub_hd), gpg_strerror (rc));
+ }
+
+ keydb_release (pub_hd);
+ keydb_release (sec_hd);
+
+ if (!rc)
+ {
+ int no_enc_rsa =
+ get_parameter_algo (para, pKEYTYPE) == PUBKEY_ALGO_RSA
+ && get_parameter_uint (para, pKEYUSAGE)
+ && !(get_parameter_uint (para, pKEYUSAGE) & PUBKEY_USAGE_ENC);
+ PKT_public_key *pk = find_kbnode (pub_root,
+ PKT_PUBLIC_KEY)->pkt->pkt.
+ public_key;
+
+ update_ownertrust (pk,
+ ((get_ownertrust (pk) & ~TRUST_MASK)
+ | TRUST_ULTIMATE));
+
+ if (!opt.batch)
+ {
+ tty_printf (_("public and secret key created and signed.\n"));
+ tty_printf (_("key marked as ultimately trusted.\n"));
+ tty_printf ("\n");
+ list_keyblock (pub_root, 0, 1, NULL);
+ }
- keydb_release (pub_hd);
- keydb_release (sec_hd);
-
- if (!rc) {
- int no_enc_rsa =
- get_parameter_algo(para, pKEYTYPE) == PUBKEY_ALGO_RSA
- && get_parameter_uint( para, pKEYUSAGE )
- && !(get_parameter_uint( para,pKEYUSAGE) & PUBKEY_USAGE_ENC);
- PKT_public_key *pk = find_kbnode (pub_root,
- PKT_PUBLIC_KEY)->pkt->pkt.public_key;
-
- update_ownertrust (pk,
- ((get_ownertrust (pk) & ~TRUST_MASK)
- | TRUST_ULTIMATE ));
-
- if (!opt.batch) {
- tty_printf(_("public and secret key created and signed.\n") );
- tty_printf(_("key marked as ultimately trusted.\n") );
- tty_printf("\n");
- list_keyblock(pub_root,0,1,NULL);
- }
-
- if( !opt.batch
- && ( get_parameter_algo( para, pKEYTYPE ) == PUBKEY_ALGO_DSA
- || no_enc_rsa )
- && !get_parameter( para, pSUBKEYTYPE ) )
+ if (!opt.batch
+ && (get_parameter_algo (para, pKEYTYPE) == PUBKEY_ALGO_DSA
+ || no_enc_rsa) && !get_parameter (para, pSUBKEYTYPE))
{
- tty_printf(_("Note that this key cannot be used for "
- "encryption. You may want to use\n"
- "the command \"--edit-key\" to generate a "
- "secondary key for this purpose.\n") );
+ tty_printf (_("Note that this key cannot be used for "
+ "encryption. You may want to use\n"
+ "the command \"--edit-key\" to generate a "
+ "secondary key for this purpose.\n"));
}
}
}
- if( rc ) {
- if( opt.batch )
- log_error("key generation failed: %s\n", gpg_strerror (rc) );
- else
- tty_printf(_("Key generation failed: %s\n"), gpg_strerror (rc) );
+ if (rc)
+ {
+ if (opt.batch)
+ log_error ("key generation failed: %s\n", gpg_strerror (rc));
+ else
+ tty_printf (_("Key generation failed: %s\n"), gpg_strerror (rc));
}
- else {
- PKT_public_key *pk = find_kbnode (pub_root,
- PKT_PUBLIC_KEY)->pkt->pkt.public_key;
- print_status_key_created (did_sub? 'B':'P', pk);
+ else
+ {
+ PKT_public_key *pk = find_kbnode (pub_root,
+ PKT_PUBLIC_KEY)->pkt->pkt.public_key;
+ print_status_key_created (did_sub ? 'B' : 'P', pk);
}
- release_kbnode( pub_root );
- release_kbnode( sec_root );
- if( sk ) /* the unprotected secret key */
- free_secret_key(sk);
+
+ release_kbnode (pub_root);
+ release_kbnode (sec_root);
+ if (sk && !card) /* The unprotected secret key unless we have */
+ free_secret_key (sk); /* shallow copy in card mode. */
}
@@ -2534,3 +2611,268 @@ write_keyblock( iobuf_t out, KBNODE node )
}
return 0;
}
+
+
+static void
+show_sha1_fpr (const unsigned char *fpr)
+{
+ int i;
+
+ if (fpr)
+ {
+ for (i=0; i < 20 ; i+=2, fpr += 2 )
+ {
+ if (i == 10 )
+ tty_printf (" ");
+ tty_printf (" %02X%02X", *fpr, fpr[1]);
+ }
+ }
+ else
+ tty_printf ("[none]");
+ tty_printf ("\n");
+}
+
+static void
+show_smartcard (struct agent_card_info_s *info)
+{
+ /* FIXME: Sanitize what we show. */
+ tty_printf ("Name of cardholder: %s\n",
+ info->disp_name && *info->disp_name? info->disp_name
+ : "[not set]");
+ tty_printf ("URL of public key : %s\n",
+ info->pubkey_url && *info->pubkey_url? info->pubkey_url
+ : "[not set]");
+ tty_printf ("Signature key ....: ");
+ show_sha1_fpr (info->fpr1valid? info->fpr1:NULL);
+ tty_printf ("Encryption key....: ");
+ show_sha1_fpr (info->fpr2valid? info->fpr2:NULL);
+ tty_printf ("Authentication key: ");
+ show_sha1_fpr (info->fpr3valid? info->fpr3:NULL);
+}
+
+
+static char *
+smartcard_get_one_name (const char *prompt1, const char *prompt2)
+{
+ char *name;
+ int i;
+
+ for (;;)
+ {
+ name = cpr_get (prompt1, prompt2);
+ if (!name)
+ return NULL;
+ trim_spaces (name);
+ cpr_kill_prompt ();
+ for (i=0; name[i] && name[i] >= ' ' && name[i] <= 126; i++)
+ ;
+
+ /* The name must be in Latin-1 and not UTF-8 - lacking the code
+ to ensure this we restrict it to ASCII. */
+ if (name[i])
+ tty_printf (_("Error: Only plain ASCII is currently allowed.\n"));
+ else if (strchr (name, '<'))
+ tty_printf (_("Error: The \"<\" character may not be used.\n"));
+ else if (strstr (name, " "))
+ tty_printf (_("Error: Double spaces are not allowed.\n"));
+ else
+ return name;
+ xfree (name);
+ }
+}
+
+static int
+smartcard_change_name (const char *current_name)
+{
+ char *surname = NULL, *givenname = NULL;
+ char *isoname, *p;
+ int rc;
+
+ surname = smartcard_get_one_name ("keygen.smartcard.surname",
+ _("Cardholder's surname: "));
+ givenname = smartcard_get_one_name ("keygen.smartcard.givenname",
+ _("Cardholder's given name: "));
+ if (!surname || !givenname || (!*surname && !*givenname))
+ {
+ xfree (surname);
+ xfree (givenname);
+ return -1; /*canceled*/
+ }
+
+ isoname = xmalloc ( strlen (surname) + 2 + strlen (givenname) + 1);
+ strcpy (stpcpy (stpcpy (isoname, surname), "<<"), givenname);
+ xfree (surname);
+ xfree (givenname);
+ for (p=isoname; *p; p++)
+ if (*p == ' ')
+ *p = '<';
+
+ log_debug ("setting Name to `%s'\n", isoname);
+ rc = agent_scd_setattr ("DISP-NAME", isoname, strlen (isoname) );
+ if (rc)
+ log_error ("error setting Name: %s\n", gpg_strerror (rc));
+
+ return rc;
+}
+
+
+/* Check whether a smartcatrd is available and alow to select it as
+ the target for key generation.
+
+ Return values: -1 = Quit generation
+ 0 = No smartcard
+ 1 = Generate primary key
+ 2 = generate subkey
+*/
+static int
+check_smartcard (void)
+{
+ struct agent_card_info_s info;
+ int rc;
+
+ rc = agent_learn (&info);
+ if (rc)
+ {
+ tty_printf (_("OpenPGP card not available: %s\n"),
+ gpg_strerror (rc));
+ return 0;
+ }
+
+ tty_printf (_("OpenPGP card with serial number %s detected\n"), "xxx");
+
+
+ for (;;)
+ {
+ char *answer;
+ int reread = 0;
+
+ tty_printf ("\n");
+ show_smartcard (&info);
+
+ tty_printf ("\n"
+ "N - change cardholder name\n"
+ "U - change public key URL\n"
+ "1 - generate signature key\n"
+ "2 - generate encryption key\n"
+ "3 - generate authentication key\n"
+ "Q - quit\n"
+ "\n");
+
+ answer = cpr_get("keygen.smartcard.menu",_("Your selection? "));
+ cpr_kill_prompt();
+ if (strlen (answer) != 1)
+ continue;
+
+ rc = 0;
+ if ( *answer == 'N' || *answer == 'n')
+ {
+ if (!smartcard_change_name (info.disp_name))
+ reread = 1;
+ }
+ else if ( *answer == 'U' || *answer == 'u')
+ {
+ }
+ else if ( *answer == '1' || *answer == '2')
+ {
+ rc = *answer - '0';
+ break;
+ }
+ else if ( *answer == '3' )
+ {
+ tty_printf (_("Generation of authentication key"
+ " not yet implemented\n"));
+ }
+ else if ( *answer == 'q' || *answer == 'Q')
+ {
+ rc = -1;
+ break;
+ }
+
+ if (reread)
+ {
+ xfree (info.disp_name); info.disp_name = NULL;
+ xfree (info.pubkey_url); info.pubkey_url = NULL;
+ rc = agent_learn (&info);
+ if (rc)
+ {
+ tty_printf (_("OpenPGP card not anymore available: %s\n"),
+ gpg_strerror (rc));
+ g10_exit (1);
+ }
+ reread = 0;
+ }
+ }
+
+ xfree (info.disp_name);
+ xfree (info.pubkey_url);
+
+ return rc;
+}
+
+
+
+static int
+gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
+ u32 expireval)
+{
+ int rc;
+ struct agent_card_genkey_s info;
+ PACKET *pkt;
+ PKT_secret_key *sk;
+ PKT_public_key *pk;
+
+ assert (algo == PUBKEY_ALGO_RSA);
+
+ rc = agent_scd_genkey (&info, keyno, 0);
+ if (gpg_err_code (rc) == GPG_ERR_EEXIST)
+ {
+ tty_printf ("\n");
+ log_error ("WARNING: key does already exists!\n");
+ tty_printf ("\n");
+ if ( cpr_get_answer_is_yes( "keygen.card.replace_key",
+ _("Replace existing key? ")))
+ rc = agent_scd_genkey (&info, keyno, 1);
+ }
+
+ if (rc)
+ {
+ log_error ("key generation failed: %s\n", gpg_strerror (rc));
+ return rc;
+ }
+ if ( !info.n || !info.e )
+ {
+ log_error ("communication error with SCD\n");
+ gcry_mpi_release (info.n);
+ gcry_mpi_release (info.e);
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+
+
+ pk = xcalloc (1, sizeof *pk );
+ sk = xcalloc (1, sizeof *sk );
+ sk->timestamp = pk->timestamp = make_timestamp();
+ sk->version = pk->version = 4;
+ if (expireval)
+ sk->expiredate = pk->expiredate = pk->timestamp + expireval;
+ sk->pubkey_algo = pk->pubkey_algo = algo;
+ pk->pkey[0] = info.n;
+ pk->pkey[1] = info.e;
+ sk->skey[0] = mpi_copy (pk->pkey[0]);
+ sk->skey[1] = mpi_copy (pk->pkey[1]);
+ sk->skey[2] = mpi_set_opaque (NULL, xstrdup ("dummydata"), 10);
+ sk->is_protected = 1;
+ sk->protect.s2k.mode = 1002;
+
+ pkt = xcalloc (1,sizeof *pkt);
+ pkt->pkttype = keyno == 1 ? PKT_PUBLIC_KEY : PKT_PUBLIC_SUBKEY;
+ pkt->pkt.public_key = pk;
+ add_kbnode(pub_root, new_kbnode( pkt ));
+
+ pkt = xcalloc (1,sizeof *pkt);
+ pkt->pkttype = keyno == 1 ? PKT_SECRET_KEY : PKT_SECRET_SUBKEY;
+ pkt->pkt.secret_key = sk;
+ add_kbnode(sec_root, new_kbnode( pkt ));
+
+ return 0;
+}
+
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index c1a716b1d..fc9e2559f 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -1634,6 +1634,8 @@ parse_key( iobuf_t 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",
@@ -1669,6 +1671,31 @@ parse_key( iobuf_t inp, int pkttype, unsigned long pktlen,
printf("\tprotect count: %lu\n",
(ulong)sk->protect.s2k.count);
}
+ else if( sk->protect.s2k.mode == 1002 ) {
+ size_t snlen;
+ /* Read the serial number. */
+ if (pktlen < 1) {
+ rc = GPG_ERR_INV_PACKET;
+ goto leave;
+ }
+ snlen = iobuf_get (inp);
+ pktlen--;
+ if (pktlen < snlen || snlen == -1) {
+ rc = GPG_ERR_INV_PACKET;
+ goto leave;
+ }
+
+ if( list_mode ) {
+ printf("\tserial-number: ");
+ for (;snlen; snlen--)
+ printf ("%02X", (unsigned int)iobuf_get_noeof (inp));
+ putchar ('\n');
+ }
+ else {
+ for (;snlen; snlen--)
+ iobuf_get_noeof (inp);
+ }
+ }
}
/* Note that a sk->protect.algo > 110 is illegal, but I'm
not erroring on it here as otherwise there would be no
@@ -1698,6 +1725,8 @@ parse_key( iobuf_t 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 = 0;
if( pktlen < sk->protect.ivlen ) {
rc = GPG_ERR_INV_PACKET;
@@ -1719,7 +1748,8 @@ parse_key( iobuf_t 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, xstrdup ("dummydata"), 10);
pktlen = 0;
diff --git a/g10/passphrase.c b/g10/passphrase.c
index 41cd31f91..d00340109 100644
--- a/g10/passphrase.c
+++ b/g10/passphrase.c
@@ -794,7 +794,7 @@ agent_get_passphrase ( u32 *keyid, int mode, const char *tryagain_text,
tryagain_text = _(tryagain_text);
/* We allocate 2 time the needed space for atext so that there
- is nenough space for escaping */
+ is enough space for escaping */
line = xmalloc (15 + 46
+ 3*strlen (tryagain_text) + 3*strlen (atext) + 2);
strcpy (line, "GET_PASSPHRASE ");
diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c
index 573c78f7a..dff463c53 100644
--- a/g10/seckey-cert.c
+++ b/g10/seckey-cert.c
@@ -253,6 +253,9 @@ check_secret_key( PKT_secret_key *sk, int n )
int rc = gpg_error (GPG_ERR_BAD_PASSPHRASE);
int i,mode;
+ if (sk && sk->is_protected && sk->protect.s2k.mode == 1002)
+ return 0; /* Let the scdaemon handle it. */
+
if(n<0)
{
n=abs(n);
diff --git a/g10/seskey.c b/g10/seskey.c
index 9eeed2c74..5d0490cdf 100644
--- a/g10/seskey.c
+++ b/g10/seskey.c
@@ -231,3 +231,8 @@ encode_md_value (int pubkey_algo, gcry_md_hd_t md, int hash_algo,
return frame;
}
+
+
+
+
+
diff --git a/g10/sign.c b/g10/sign.c
index fa9e9ea3f..86159a4a1 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -249,74 +249,94 @@ static int
do_sign( PKT_secret_key *sk, PKT_signature *sig,
MD_HANDLE md, int digest_algo )
{
- gcry_mpi_t frame;
- byte *dp;
- int rc;
-
- if( sk->timestamp > sig->timestamp ) {
- ulong d = sk->timestamp - sig->timestamp;
- log_info( d==1 ? _("key has been created %lu second "
- "in future (time warp or clock problem)\n")
- : _("key has been created %lu seconds "
- "in future (time warp or clock problem)\n"), d );
- if( !opt.ignore_time_conflict )
- return GPG_ERR_TIME_CONFLICT;
+ gcry_mpi_t frame;
+ byte *dp;
+ int rc;
+
+ if( sk->timestamp > sig->timestamp ) {
+ ulong d = sk->timestamp - sig->timestamp;
+ log_info( d==1 ? _("key has been created %lu second "
+ "in future (time warp or clock problem)\n")
+ : _("key has been created %lu seconds "
+ "in future (time warp or clock problem)\n"), d );
+ if( !opt.ignore_time_conflict )
+ return GPG_ERR_TIME_CONFLICT;
+ }
+
+ print_pubkey_algo_note(sk->pubkey_algo);
+
+ if( !digest_algo )
+ digest_algo = gcry_md_get_algo(md);
+
+ print_digest_algo_note( digest_algo );
+ dp = gcry_md_read ( md, digest_algo );
+ sig->digest_algo = digest_algo;
+ sig->digest_start[0] = dp[0];
+ sig->digest_start[1] = dp[1];
+ if (sk->is_protected && sk->protect.s2k.mode == 1002)
+ { /* FIXME: Note that we do only support RSA for now. */
+ char *rbuf;
+ size_t rbuflen;
+
+ /* FIXME: We need to pass the correct keyid or better the
+ fingerprint to the scdaemon. */
+ rc = agent_scd_pksign ("nokeyid", digest_algo,
+ gcry_md_read (md, digest_algo),
+ gcry_md_get_algo_dlen (digest_algo),
+ &rbuf, &rbuflen);
+ if (!rc)
+ {
+ unsigned int nbytes = rbuflen;
+ if (gcry_mpi_scan (&sig->data[0], GCRYMPI_FMT_USG, rbuf, &nbytes ))
+ BUG ();
+ }
}
-
-
- print_pubkey_algo_note(sk->pubkey_algo);
-
- if( !digest_algo )
- digest_algo = gcry_md_get_algo(md);
-
- print_digest_algo_note( digest_algo );
- dp = gcry_md_read ( md, digest_algo );
- sig->digest_algo = digest_algo;
- sig->digest_start[0] = dp[0];
- sig->digest_start[1] = dp[1];
- frame = encode_md_value( sk->pubkey_algo, md,
- digest_algo, mpi_get_nbits(sk->skey[0]), 0 );
- if (!frame)
+ else
+ {
+ frame = encode_md_value( sk->pubkey_algo, md,
+ digest_algo, mpi_get_nbits(sk->skey[0]), 0 );
+ if (!frame)
return GPG_ERR_GENERAL;
- rc = pk_sign( sk->pubkey_algo, sig->data, frame, sk->skey );
- gcry_mpi_release (frame);
- if (!rc && !opt.no_sig_create_check) {
- /* check that the signature verification worked and nothing is
- * fooling us e.g. by a bug in the signature create
- * code or by deliberately introduced faults. */
- PKT_public_key *pk = xcalloc (1,sizeof *pk);
-
- if( get_pubkey( pk, sig->keyid ) )
- rc = GPG_ERR_NO_PUBKEY;
- else {
- frame = encode_md_value (pk->pubkey_algo, md,
- sig->digest_algo,
- mpi_get_nbits(pk->pkey[0]), 0);
- if (!frame)
- rc = GPG_ERR_GENERAL;
- else
- rc = pk_verify (pk->pubkey_algo, frame,
- sig->data, pk->pkey);
- gcry_mpi_release (frame);
- }
- if (rc)
- log_error (_("checking created signature failed: %s\n"),
- gpg_strerror (rc));
- free_public_key (pk);
+ rc = pk_sign( sk->pubkey_algo, sig->data, frame, sk->skey );
+ gcry_mpi_release (frame);
}
- if( rc )
- log_error(_("signing failed: %s\n"), gpg_strerror (rc) );
+ if (!rc && !opt.no_sig_create_check) {
+ /* check that the signature verification worked and nothing is
+ * fooling us e.g. by a bug in the signature create
+ * code or by deliberately introduced faults. */
+ PKT_public_key *pk = xcalloc (1,sizeof *pk);
+
+ if( get_pubkey( pk, sig->keyid ) )
+ rc = GPG_ERR_NO_PUBKEY;
else {
- if( opt.verbose ) {
- char *ustr = get_user_id_string_printable (sig->keyid);
- log_info(_("%s/%s signature from: \"%s\"\n"),
- gcry_pk_algo_name (sk->pubkey_algo),
- gcry_md_algo_name (sig->digest_algo),
- ustr );
- xfree (ustr);
- }
+ frame = encode_md_value (pk->pubkey_algo, md,
+ sig->digest_algo,
+ mpi_get_nbits(pk->pkey[0]), 0);
+ if (!frame)
+ rc = GPG_ERR_GENERAL;
+ else
+ rc = pk_verify (pk->pubkey_algo, frame,
+ sig->data, pk->pkey);
+ gcry_mpi_release (frame);
}
- return rc;
+ if (rc)
+ log_error (_("checking created signature failed: %s\n"),
+ gpg_strerror (rc));
+ free_public_key (pk);
+ }
+ if( rc )
+ log_error(_("signing failed: %s\n"), gpg_strerror (rc) );
+ else {
+ if( opt.verbose ) {
+ char *ustr = get_user_id_string_printable (sig->keyid);
+ log_info(_("%s/%s signature from: \"%s\"\n"),
+ gcry_pk_algo_name (sk->pubkey_algo),
+ gcry_md_algo_name (sig->digest_algo),
+ ustr );
+ xfree (ustr);
+ }
+ }
+ return rc;
}
@@ -1170,7 +1190,7 @@ sign_symencrypt_file (const char *fname, STRLIST locusr)
* SIGVERSION gives the minimal required signature packet version;
* this is needed so that special properties like local sign are not
* applied (actually: dropped) when a v3 key is used. TIMESTAMP is
- * the timestamp to use for the signature. 0 means "now" */
+ * the timestamp to use for the signature. 0 means "now". */
int
make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
PKT_user_id *uid, PKT_public_key *subpk,
diff --git a/g10/tdbio.c b/g10/tdbio.c
index d8af2ef8a..39239be20 100644
--- a/g10/tdbio.c
+++ b/g10/tdbio.c
@@ -372,10 +372,11 @@ tdbio_end_transaction()
else
is_locked = 1;
}
- block_all_signals();
+#warning block_all_signals is not yet available in ../common/signals.c
+ /* block_all_signals(); */
in_transaction = 0;
rc = tdbio_sync();
- unblock_all_signals();
+/* unblock_all_signals(); */
if( !opt.lock_once ) {
if( !release_dotlock( lockhandle ) )
is_locked = 0;