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 + + * 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 * 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; + 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; } + + 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; + 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; + } - 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); + 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;