aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--g10/ChangeLog20
-rw-r--r--g10/Makefile.am20
-rw-r--r--g10/app-openpgp.c25
-rw-r--r--g10/card-util.c88
-rw-r--r--g10/cardglue.c83
-rw-r--r--g10/cardglue.h5
-rw-r--r--g10/g10.c7
-rw-r--r--g10/gpgv.c6
-rw-r--r--g10/keygen.c434
-rw-r--r--g10/main.h9
-rw-r--r--g10/sign.c2
11 files changed, 552 insertions, 147 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 0306e2691..23f5db587 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,23 @@
+2003-10-08 Werner Koch <[email protected]>
+
+ * cardglue.c (pin_cb): Detect whether an admin or regular PIN is
+ requested.
+ (genkey_status_cb): New.
+ (agent_scd_genkey): Implemented.
+
+ * keygen.c (generate_keypair): New arg CARD_SERIALNO and prepare
+ parameters for on card key generation. Changed all callers.
+ (do_generate_keypair): Add new arg card and merged casrd specific
+ changes from 1.9.
+ (proc_parameter_file): New arg card, apss it down to
+ do_generate_keypair and changed all callers.
+ (gen_card_key): New.
+
+ * g10.c: Include cardclue.h.
+ (main): s/app_set_default_reader_port/card_set_reader_port/.
+ * cardglue.c (card_set_reader_port): New to address include file
+ issues.
+
2003-10-02 Werner Koch <[email protected]>
* cardglue.c (learn_status_cb): Release values before assignment
diff --git a/g10/Makefile.am b/g10/Makefile.am
index e289a8242..b64c448c6 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -142,12 +142,16 @@ install-data-local:
# Helper to update some source files.
update-source-from-gnupg-2:
- test -d ../../gnupg-1.9/scd
- @for i in $(card_support_source_scd); do \
- cp ../../gnupg-1.9/scd/$$i $$i; echo $$i; \
- done
- @for i in $(card_support_source_g10); do \
- cp ../../gnupg-1.9/g10/$$i $$i; echo $$i; \
- done
- @echo "Please remember to update the ChangeLog accordingly!"
+ @set -e; \
+ if test -d ../../gnupg-1.9/scd; then dir="../../gnupg-1.9"; \
+ elif test -d ../../gnupg/scd; then dir="../../gnupg"; \
+ else exit 1; \
+ fi; \
+ for i in $(card_support_source_scd); do \
+ cp $$dir/scd/$$i $$i; echo $$i; \
+ done ;\
+ for i in $(card_support_source_g10); do \
+ cp $$dir/g10/$$i $$i; echo $$i; \
+ done ; \
+ echo "Please remember to update the ChangeLog accordingly!"
diff --git a/g10/app-openpgp.c b/g10/app-openpgp.c
index e8fe19ea1..174d2e974 100644
--- a/g10/app-openpgp.c
+++ b/g10/app-openpgp.c
@@ -425,6 +425,8 @@ do_getattr (APP app, CTRL ctrl, const char *name)
{ "CA-FPR", 0x00C6, 3 },
{ "CHV-STATUS", 0x00C4, 1 },
{ "SIG-COUNTER", 0x0093, 2 },
+ { "SERIALNO", 0x004F, -1 },
+ { "AID", 0x004F },
{ NULL, 0 }
};
int idx, i;
@@ -437,6 +439,29 @@ do_getattr (APP app, CTRL ctrl, const char *name)
if (!table[idx].name)
return gpg_error (GPG_ERR_INV_NAME);
+ if (table[idx].special == -1)
+ {
+ /* The serial number is very special. We could have used the
+ AID DO to retrieve it, but we have it already in the app
+ context and the stanmp argument is required anyway which we
+ can't by other means. The AID DO is available anyway but not
+ hex formatted. */
+ char *serial;
+ time_t stamp;
+ char tmp[50];
+
+ if (!app_get_serial_and_stamp (app, &serial, &stamp))
+ {
+ sprintf (tmp, "%lu", (unsigned long)stamp);
+ send_status_info (ctrl, "SERIALNO",
+ serial, strlen (serial),
+ tmp, strlen (tmp),
+ NULL, 0);
+ xfree (serial);
+ }
+ return 0;
+ }
+
relptr = get_one_do (app->slot, table[idx].tag, &value, &valuelen);
if (relptr)
{
diff --git a/g10/card-util.c b/g10/card-util.c
index 70518e9ce..669927707 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -241,6 +241,17 @@ print_isoname (FILE *fp, const char *text, const char *tag, const char *name)
tty_fprintf (fp, "\n");
}
+/* Return true if the SHA1 fingerprint FPR consists only of zeroes. */
+static int
+fpr_is_zero (const char *fpr)
+{
+ int i;
+
+ for (i=0; i < 20 && !fpr[i]; i++)
+ ;
+ return (i == 20);
+}
+
/* Print all available information about the current card. */
void
@@ -569,6 +580,76 @@ toggle_forcesig (void)
}
+static void
+generate_card_keys (void)
+{
+ struct agent_card_info_s info;
+ int rc;
+ int forced_chv1;
+
+ memset (&info, 0, sizeof info);
+ rc = agent_scd_getattr ("KEY-FPR", &info);
+ if (!rc)
+ rc = agent_scd_getattr ("SERIALNO", &info);
+ if (!rc)
+ rc = agent_scd_getattr ("CHV-STATUS", &info);
+ if (!rc)
+ rc = agent_scd_getattr ("DISP-NAME", &info);
+ if (rc)
+ {
+ log_error ("error getting current key info: %s\n", gpg_strerror (rc));
+ return;
+ }
+ if ( (info.fpr1valid && !fpr_is_zero (info.fpr1))
+ || (info.fpr2valid && !fpr_is_zero (info.fpr2))
+ || (info.fpr3valid && !fpr_is_zero (info.fpr3)))
+ {
+ tty_printf ("\n");
+ log_info ("NOTE: keys are already stored on the card!\n");
+ tty_printf ("\n");
+ if ( !cpr_get_answer_is_yes( "cardedit.genkeys.replace_keys",
+ _("Replace existing keys? ")))
+ {
+ agent_release_card_info (&info);
+ return;
+ }
+ }
+ else if (!info.disp_name || !*info.disp_name)
+ {
+ tty_printf ("\n");
+ tty_printf (_("Please note that the factory settings of the PINs are\n"
+ " PIN = \"%s\" Admin PIN = \"%s\"\n"
+ "You should change them using the command --change-pin\n"),
+ "123456", "12345678");
+ tty_printf ("\n");
+ }
+
+ forced_chv1 = !info.chv1_cached;
+ if (forced_chv1)
+ { /* Switch of the forced mode so that during key generation we
+ don't get bothered with PIN queries for each
+ self-signature. */
+ rc = agent_scd_setattr ("CHV-STATUS-1", "\x01", 1);
+ if (rc)
+ {
+ log_error ("error clearing forced signature PIN flag: %s\n",
+ gpg_strerror (rc));
+ return;
+ }
+ }
+ generate_keypair (NULL, info.serialno);
+ agent_release_card_info (&info);
+ if (forced_chv1)
+ { /* Switch back to forced state. */
+ rc = agent_scd_setattr ("CHV-STATUS-1", "", 1);
+ if (rc)
+ {
+ log_error ("error setting forced signature PIN flag: %s\n",
+ gpg_strerror (rc));
+ return;
+ }
+ }
+}
/* Menu to edit all user changeable values on an OpenPGP card. Only
Key creation is not handled here. */
@@ -579,7 +660,7 @@ card_edit (STRLIST commands)
cmdNOP = 0,
cmdQUIT, cmdHELP, cmdLIST, cmdDEBUG,
cmdNAME, cmdURL, cmdLOGIN, cmdLANG, cmdSEX,
- cmdFORCESIG,
+ cmdFORCESIG, cmdGENERATE,
cmdINVCMD
};
@@ -601,6 +682,7 @@ card_edit (STRLIST commands)
{ N_("lang") , cmdLANG , N_("change the language preferences") },
{ N_("sex") , cmdSEX , N_("change card holder's sex") },
{ N_("forcesig"), cmdFORCESIG, N_("toggle the signature force PIN flag") },
+ { N_("generate"), cmdGENERATE, N_("generate new keys") },
{ NULL, cmdINVCMD }
};
@@ -725,6 +807,10 @@ card_edit (STRLIST commands)
toggle_forcesig ();
break;
+ case cmdGENERATE:
+ generate_card_keys ();
+ break;
+
case cmdQUIT:
goto leave;
diff --git a/g10/cardglue.c b/g10/cardglue.c
index 802bae5d1..fd7cf8b3d 100644
--- a/g10/cardglue.c
+++ b/g10/cardglue.c
@@ -184,6 +184,13 @@ app_set_default_reader_port (const char *portstr)
}
+void
+card_set_reader_port (const char *portstr)
+{
+ app_set_default_reader_port (portstr);
+}
+
+
/* Retrieve the serial number and the time of the last update of the
card. The serial number is returned as a malloced string (hex
encoded) in SERIAL and the time of update is returned in STAMP. If
@@ -493,7 +500,10 @@ pin_cb (void *opaque, const char *info, char **retstr)
*retstr = NULL;
log_debug ("asking for PIN '%s'\n", info);
- value = ask_passphrase (info, "Enter PIN: ", &canceled);
+ value = ask_passphrase (info,
+ info && strstr (info, "dmin")?
+ _("Enter Admin PIN: ") : _("Enter PIN: "),
+ &canceled);
if (!value && canceled)
return -1;
else if (!value)
@@ -519,19 +529,86 @@ agent_scd_setattr (const char *name,
return app->fnc.setattr (app, name, pin_cb, NULL, value, valuelen);
}
+
+static int
+genkey_status_cb (void *opaque, const char *line)
+{
+ struct agent_card_genkey_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 == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
+ {
+ parm->fprvalid = unhexify_fpr (line, parm->fpr);
+ }
+ if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
+ {
+ MPI a;
+ const char *name = line;
+ char *buf;
+
+ while (!spacep (line))
+ line++;
+ while (spacep (line))
+ line++;
+
+ buf = xmalloc ( 2 + strlen (line) + 1);
+ strcpy (stpcpy (buf, "0x"), line);
+ a = mpi_alloc (300);
+ if( mpi_fromstr (a, buf) )
+ log_error ("error parsing received key data\n");
+ 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");
+ mpi_free (a);
+ }
+ xfree (buf);
+ }
+ 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)
{
+ APP app;
+ char keynostr[20];
+ struct ctrl_ctx_s ctrl;
- return gpg_error (GPG_ERR_CARD);
+ app = current_app? current_app : open_card ();
+ if (!app)
+ return gpg_error (GPG_ERR_CARD);
+
+ memset (info, 0, sizeof *info);
+ sprintf (keynostr, "%d", keyno);
+ ctrl.status_cb = genkey_status_cb;
+ ctrl.status_cb_arg = info;
+
+ return app->fnc.genkey (app, &ctrl, keynostr,
+ force? 1:0,
+ pin_cb, NULL);
}
/* Send a PKSIGN command to the SCdaemon. */
int
agent_scd_pksign (const char *serialno, int hashalgo,
const unsigned char *indata, size_t indatalen,
- char **r_buf, size_t *r_buflen)
+ unsigned char **r_buf, size_t *r_buflen)
{
APP app;
diff --git a/g10/cardglue.h b/g10/cardglue.h
index 42a22b542..273b99313 100644
--- a/g10/cardglue.h
+++ b/g10/cardglue.h
@@ -67,6 +67,7 @@ typedef struct app_ctx_s *APP;
typedef struct ctrl_ctx_s *CTRL;
+#define GPG_ERR_GENERAL G10ERR_GENERAL
#define GPG_ERR_BAD_PIN G10ERR_BAD_PASS
#define GPG_ERR_CARD G10ERR_GENERAL
#define GPG_ERR_EEXIST G10ERR_FILE_EXISTS
@@ -107,6 +108,8 @@ typedef int gpg_err_code_t;
#define gnupg_get_time() make_timestamp ()
+void card_set_reader_port (const char *portstr);
+
char *serialno_and_fpr_from_sk (const unsigned char *sn, size_t snlen,
PKT_secret_key *sk);
void send_status_info (CTRL ctrl, const char *keyword, ...);
@@ -143,7 +146,7 @@ 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);
+ unsigned char **r_buf, size_t *r_buflen);
/* Send a PKDECRYPT command to the SCdaemon. */
int agent_scd_pkdecrypt (const char *serialno,
diff --git a/g10/g10.c b/g10/g10.c
index 70b9bd300..d925c364a 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -51,6 +51,7 @@
#include "g10defs.h"
#include "keyserver-internal.h"
#include "exec.h"
+#include "cardglue.h"
enum cmd_and_opt_values
{
@@ -1425,7 +1426,7 @@ main( int argc, char **argv )
case aCardEdit: set_cmd (&cmd, aCardEdit); break;
case aChangePIN: set_cmd (&cmd, aChangePIN); break;
case oReaderPort:
- app_set_default_reader_port (pargs.r.ret_str);
+ card_set_reader_port (pargs.r.ret_str);
break;
case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
case opcscDriver: opt.pcsc_driver = pargs.r.ret_str; break;
@@ -2603,12 +2604,12 @@ main( int argc, char **argv )
if( opt.batch ) {
if( argc > 1 )
wrong_args("--gen-key [parameterfile]");
- generate_keypair( argc? *argv : NULL );
+ generate_keypair( argc? *argv : NULL, NULL );
}
else {
if( argc )
wrong_args("--gen-key");
- generate_keypair(NULL);
+ generate_keypair(NULL, NULL);
}
break;
diff --git a/g10/gpgv.c b/g10/gpgv.c
index 0701ead8e..c01263fe4 100644
--- a/g10/gpgv.c
+++ b/g10/gpgv.c
@@ -385,9 +385,9 @@ void rndlinux_constructor(void) {}
/* Stubs to avoid linking to ../util/ttyio.c */
int tty_batchmode( int onoff ) { return 0; }
void tty_printf( const char *fmt, ... ) { }
-void tty_print_string( byte *p, size_t n ) { }
-void tty_print_utf8_string( byte *p, size_t n ) {}
-void tty_print_utf8_string2( byte *p, size_t n, size_t max_n ) {}
+void tty_print_string( const byte *p, size_t n ) { }
+void tty_print_utf8_string( const byte *p, size_t n ) {}
+void tty_print_utf8_string2( const byte *p, size_t n, size_t max_n ) {}
char *tty_get( const char *prompt ) { return NULL;}
char *tty_get_hidden( const char *prompt ) {return NULL; }
void tty_kill_prompt(void) {}
diff --git a/g10/keygen.c b/g10/keygen.c
index bcfdcfa67..a3cf67150 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -36,6 +36,7 @@
#include "trustdb.h"
#include "status.h"
#include "i18n.h"
+#include "cardglue.h"
#define MAX_PREFS 30
@@ -46,6 +47,7 @@ enum para_name {
pSUBKEYTYPE,
pSUBKEYLENGTH,
pSUBKEYUSAGE,
+ pAUTHKEYTYPE,
pNAMEREAL,
pNAMEEMAIL,
pNAMECOMMENT,
@@ -57,7 +59,8 @@ enum para_name {
pSUBKEYEXPIRE, /* in n seconds */
pPASSPHRASE,
pPASSPHRASE_DEK,
- pPASSPHRASE_S2K
+ pPASSPHRASE_S2K,
+ pSERIALNO
};
struct para_data_s {
@@ -109,9 +112,12 @@ 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 );
+ struct output_control_s *outctrl, int card );
static int write_keyblock( IOBUF out, KBNODE node );
-
+#ifdef ENABLE_CARD_SUPPORT
+static int gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
+ u32 expireval, struct para_data_s *para);
+#endif
static void
write_uid( KBNODE root, const char *s )
@@ -1762,7 +1768,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;
@@ -1874,7 +1880,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;
}
@@ -1958,7 +1964,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;
}
@@ -2018,7 +2024,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;
}
@@ -2046,7 +2052,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 */
@@ -2064,91 +2070,146 @@ read_parameter_file( const char *fname )
}
-/****************
- * Generate a keypair
- * (fname is only used in batch mode)
+/*
+ * Generate a keypair (fname is only used in batch mode) If
+ * CARD_SERIALNO is not NULL the fucntion will create the keys on an
+ * OpenPGP Card.
*/
void
-generate_keypair( const char *fname )
+generate_keypair( const char *fname, const char *card_serialno )
{
- 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;
- }
-
- algo = ask_algo( 0, &use );
- if( !algo ) { /* default: DSA with ElG subkey of the specified size */
- both = 1;
- r = m_alloc_clear( 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 = m_alloc_clear( sizeof *r + 20 );
- r->key = pKEYLENGTH;
- strcpy( r->u.value, "1024" );
- r->next = para;
- para = r;
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pKEYUSAGE;
- strcpy( r->u.value, "sign" );
- r->next = para;
- para = r;
-
- algo = PUBKEY_ALGO_ELGAMAL_E;
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pSUBKEYTYPE;
- sprintf( r->u.value, "%d", algo );
- r->next = para;
- para = r;
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pSUBKEYUSAGE;
- strcpy( r->u.value, "encrypt" );
- r->next = para;
- para = r;
- }
- else {
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = pKEYTYPE;
- sprintf( r->u.value, "%d", algo );
- r->next = para;
- para = r;
-
- if (use) {
- r = m_alloc_clear( 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;
- }
-
+ 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 && card_serialno)
+ {
+ /* We don't yet support unattended key generation. */
+ log_error (_("sorry, can't do this in batch mode\n"));
+ return;
}
-
- nbits = ask_keysize( algo );
- r = m_alloc_clear( sizeof *r + 20 );
- r->key = both? pSUBKEYLENGTH : pKEYLENGTH;
- sprintf( r->u.value, "%u", nbits);
- r->next = para;
- para = r;
-
- expire = ask_expire_interval(0);
+
+ if (opt.batch)
+ {
+ read_parameter_file( fname );
+ return;
+ }
+
+ if (card_serialno)
+ {
+#ifdef ENABLE_CARD_SUPPORT
+ r = xcalloc (1, sizeof *r + strlen (card_serialno) );
+ r->key = pSERIALNO;
+ strcpy( r->u.value, card_serialno);
+ r->next = para;
+ para = r;
+
+ algo = PUBKEY_ALGO_RSA;
+
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pKEYTYPE;
+ sprintf( r->u.value, "%d", algo );
+ r->next = para;
+ para = r;
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pKEYUSAGE;
+ strcpy (r->u.value, "sign");
+ r->next = para;
+ para = r;
+
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pSUBKEYTYPE;
+ sprintf( r->u.value, "%d", algo );
+ r->next = para;
+ para = r;
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pSUBKEYUSAGE;
+ strcpy (r->u.value, "encrypt");
+ r->next = para;
+ para = r;
+
+ r = xcalloc (1, sizeof *r + 20 );
+ r->key = pAUTHKEYTYPE;
+ sprintf( r->u.value, "%d", algo );
+ r->next = para;
+ para = r;
+#endif /*ENABLE_CARD_SUPPORT*/
+ }
+ else
+ {
+ algo = ask_algo( 0, &use );
+ if( !algo )
+ { /* default: DSA with ElG subkey of the specified size */
+ both = 1;
+ r = m_alloc_clear( 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 = m_alloc_clear( sizeof *r + 20 );
+ r->key = pKEYLENGTH;
+ strcpy( r->u.value, "1024" );
+ r->next = para;
+ para = r;
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pKEYUSAGE;
+ strcpy( r->u.value, "sign" );
+ r->next = para;
+ para = r;
+
+ algo = PUBKEY_ALGO_ELGAMAL_E;
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pSUBKEYTYPE;
+ sprintf( r->u.value, "%d", algo );
+ r->next = para;
+ para = r;
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pSUBKEYUSAGE;
+ strcpy( r->u.value, "encrypt" );
+ r->next = para;
+ para = r;
+ }
+ else
+ {
+ r = m_alloc_clear( sizeof *r + 20 );
+ r->key = pKEYTYPE;
+ sprintf( r->u.value, "%d", algo );
+ r->next = para;
+ para = r;
+
+ if (use)
+ {
+ r = m_alloc_clear( 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 = m_alloc_clear( 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 = m_alloc_clear( sizeof *r + 20 );
r->key = pKEYEXPIRE;
r->u.expire = expire;
@@ -2161,19 +2222,21 @@ generate_keypair( const char *fname )
para = r;
uid = ask_user_id(0);
- if( !uid ) {
+ if( !uid )
+ {
log_error(_("Key generation canceled.\n"));
release_parameter_list( para );
return;
- }
+ }
r = m_alloc_clear( sizeof *r + strlen(uid) );
r->key = pUSERID;
strcpy( r->u.value, uid );
r->next = para;
para = r;
-
- dek = do_ask_passphrase( &s2k );
- if( dek ) {
+
+ dek = card_serialno? NULL : do_ask_passphrase( &s2k );
+ if( dek )
+ {
r = m_alloc_clear( sizeof *r );
r->key = pPASSPHRASE_DEK;
r->u.dek = dek;
@@ -2184,9 +2247,9 @@ generate_keypair( const char *fname )
r->u.s2k = s2k;
r->next = para;
para = r;
- }
-
- proc_parameter_file( para, "[internal]", &outctrl );
+ }
+
+ proc_parameter_file( para, "[internal]", &outctrl, !!card_serialno);
release_parameter_list( para );
}
@@ -2211,7 +2274,7 @@ print_status_key_created (int letter, PKT_public_key *pk)
static void
do_generate_keypair( struct para_data_s *para,
- struct output_control_s *outctrl )
+ struct output_control_s *outctrl, int card )
{
KBNODE pub_root = NULL;
KBNODE sec_root = NULL;
@@ -2270,7 +2333,11 @@ do_generate_keypair( struct para_data_s *para,
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 );
+ 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 );
}
}
@@ -2283,13 +2350,26 @@ do_generate_keypair( struct para_data_s *para,
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 (!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), para);
+ if (!rc)
+ {
+ sk = sec_root->next->pkt->pkt.secret_key;
+ assert (sk);
+ }
+ }
if(!rc && (revkey=get_parameter_revkey(para,pREVOKER)))
{
@@ -2310,24 +2390,44 @@ do_generate_keypair( struct para_data_s *para,
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));
+ if( get_parameter( para, pSUBKEYTYPE ) )
+ {
+ if (!card)
+ {
+ 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 ) );
+ }
+ else
+ {
+ rc = gen_card_key (PUBKEY_ALGO_RSA, 2, pub_root, sec_root,
+ get_parameter_u32 (para, pKEYEXPIRE), para);
+ }
+
+ 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 (card && get_parameter (para, pAUTHKEYTYPE))
+ {
+ rc = gen_card_key (PUBKEY_ALGO_RSA, 3, pub_root, sec_root,
+ get_parameter_u32 (para, pKEYEXPIRE), para);
+
+ if (!rc)
+ rc = write_keybinding (pub_root, pub_root, sk, PUBKEY_USAGE_AUTH);
+ if (!rc)
+ rc = write_keybinding (sec_root, pub_root, sk, PUBKEY_USAGE_AUTH);
+ }
+
if( !rc && outctrl->use_files ) { /* direct write to specified files */
rc = write_keyblock( outctrl->pub.stream, pub_root );
if( rc )
@@ -2359,8 +2459,12 @@ do_generate_keypair( struct para_data_s *para,
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 (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) {
@@ -2426,8 +2530,8 @@ do_generate_keypair( struct para_data_s *para,
}
release_kbnode( pub_root );
release_kbnode( sec_root );
- if( sk ) /* the unprotected secret key */
- free_secret_key(sk);
+ if( sk && !card) /* the unprotected secret key unless we have a */
+ free_secret_key(sk); /* shallow copy in card mode. */
}
@@ -2554,3 +2658,81 @@ write_keyblock( IOBUF out, KBNODE node )
}
return 0;
}
+
+
+static int
+gen_card_key (int algo, int keyno, KBNODE pub_root, KBNODE sec_root,
+ u32 expireval, struct para_data_s *para)
+{
+#ifdef ENABLE_CARD_SUPPORT
+ int rc;
+ const char *s;
+ 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, 1);
+/* 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");
+ mpi_free (info.n);
+ mpi_free (info.e);
+ return gpg_error (GPG_ERR_GENERAL);
+ }
+
+
+ pk = xcalloc (1, sizeof *pk );
+ sk = xcalloc (1, sizeof *sk );
+ sk->timestamp = pk->timestamp = info.created_at;
+ 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;
+ s = get_parameter_value (para, pSERIALNO);
+ if (s)
+ {
+ for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
+ sk->protect.ivlen++, s += 2)
+ sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
+ }
+
+ 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;
+#else
+ return -1;
+#endif /*!ENABLE_CARD_SUPPORT*/
+}
diff --git a/g10/main.h b/g10/main.h
index ca37b620f..6bfa3cd00 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -143,7 +143,7 @@ void show_basic_key_info (KBNODE keyblock);
/*-- keygen.c --*/
u32 ask_expire_interval(int object);
u32 ask_expiredate(void);
-void generate_keypair( const char *fname );
+void generate_keypair( const char *fname, const char *card_serialno );
int keygen_set_std_prefs (const char *string,int personal);
PKT_user_id *keygen_get_std_prefs (void);
int keygen_add_key_expire( PKT_signature *sig, void *opaque );
@@ -241,4 +241,11 @@ void pause_on_sigusr( int which );
void block_all_signals(void);
void unblock_all_signals(void);
+#ifdef ENABLE_CARD_SUPPORT
+/*-- card-util.c --*/
+void change_pin (int no);
+void card_status (FILE *fp);
+void card_edit (STRLIST commands);
+#endif
+
#endif /*G10_MAIN_H*/
diff --git a/g10/sign.c b/g10/sign.c
index b7fd7bb20..9826c2abf 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -309,7 +309,7 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig,
#ifdef ENABLE_CARD_SUPPORT
if (sk->is_protected && sk->protect.s2k.mode == 1002)
{
- char *rbuf;
+ unsigned char *rbuf;
size_t rbuflen;
char *snbuf;