diff --git a/g10/ChangeLog b/g10/ChangeLog index a0905eda4..7b0448de4 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,20 @@ +2003-09-29 Werner Koch + + * keygen.c (do_add_key_flags, parse_parameter_usage): Add support + the proposed AUTH key flag. + * getkey.c (fixup_uidnode, merge_selfsigs_main) + (merge_selfsigs_subkey, premerge_public_with_secret): Ditto. + * keylist.c (print_capabilities): Ditto. + + * parse-packet.c (parse_key): Allow to parse the divert-to-card + S2K mode. + * build-packet.c (do_secret_key): Handle divert-to-card S2K + * seckey-cert.c (is_secret_key_protected): Ditto. + (check_secret_key): Ditto. + + * keygen.c (do_ask_passphrase): Renamed from ask_passphrase. + * passphrase.c (ask_passphrase): New. + 2003-09-28 Werner Koch * g10.c (main): New commands --card-edit, --card-status and diff --git a/g10/build-packet.c b/g10/build-packet.c index af97be423..cd0bb8a81 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -410,8 +410,9 @@ do_secret_key( IOBUF 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, 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 ); } } @@ -420,6 +421,14 @@ do_secret_key( IOBUF 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, sk->protect.ivlen ); /* length of the serial + number or 0 for no serial + number. */ + /* The serial number gets stored in the IV field. */ + iobuf_write(a, sk->protect.iv, sk->protect.ivlen); + } 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/cardglue.c b/g10/cardglue.c index 8924889dd..358eb90f6 100644 --- a/g10/cardglue.c +++ b/g10/cardglue.c @@ -53,7 +53,7 @@ struct ctrl_ctx_s { static char *default_reader_port; - +static APP current_app; @@ -246,6 +246,7 @@ open_card (void) int rc; APP app; + current_app = NULL;/* FIXME: Release it first.*/ slot = apdu_open_reader (default_reader_port); if (slot == -1) { @@ -265,6 +266,7 @@ open_card (void) } app->initialized = 1; + current_app = app; return app; } @@ -443,7 +445,7 @@ agent_learn (struct agent_card_info_s *info) time_t stamp; char *serial; - app = open_card (); + app = current_app? current_app : open_card (); if (!app) return gpg_error (GPG_ERR_CARD); @@ -462,13 +464,39 @@ agent_learn (struct agent_card_info_s *info) return rc; } +static int +pin_cb (void *opaque, const char *info, char **retstr) +{ + char *value; + int canceled; + + *retstr = NULL; + log_debug ("asking for PIN '%s'\n", info); + + value = ask_passphrase (info, "Enter PIN: ", &canceled); + if (!value && canceled) + return -1; + else if (!value) + return G10ERR_GENERAL; + + *retstr = value; + return 0; +} + + + /* Send a SETATTR command to the SCdaemon. */ int agent_scd_setattr (const char *name, const unsigned char *value, size_t valuelen) { + APP app; - return gpg_error (GPG_ERR_CARD); + app = current_app? current_app : open_card (); + if (!app) + return gpg_error (GPG_ERR_CARD); + + return app->fnc.setattr (app, name, pin_cb, NULL, value, valuelen); } /* Send a GENKEY command to the SCdaemon. */ @@ -481,12 +509,24 @@ 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, +agent_scd_pksign (const char *serialno, int hashalgo, const unsigned char *indata, size_t indatalen, char **r_buf, size_t *r_buflen) { + APP app; - return gpg_error (GPG_ERR_CARD); + *r_buf = NULL; + *r_buflen = 0; + app = current_app? current_app : open_card (); + if (!app) + return gpg_error (GPG_ERR_CARD); + + /* Check that the card's serialnumber is as required.*/ + + return app->fnc.sign (app, serialno, hashalgo, + pin_cb, NULL, + indata, indatalen, + r_buf, r_buflen); } diff --git a/g10/getkey.c b/g10/getkey.c index 5e4ca44e2..72b80ba76 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -1279,6 +1279,8 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated ) uid->help_key_usage |= PUBKEY_USAGE_ENC; /* Note: we do not set the CERT flag here because it can be assumed * that thre is no real policy to set it. */ + if ( (*p & 0x20) ) + uid->help_key_usage |= PUBKEY_USAGE_AUTH; } /* ditto or the key expiration */ @@ -1490,6 +1492,8 @@ merge_selfsigs_main( KBNODE keyblock, int *r_revoked ) key_usage |= PUBKEY_USAGE_SIG; if ( (*p & 12) ) key_usage |= PUBKEY_USAGE_ENC; + if ( (*p & 0x20) ) + key_usage |= PUBKEY_USAGE_AUTH; } p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_KEY_EXPIRE, NULL); @@ -1878,6 +1882,8 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode ) key_usage |= PUBKEY_USAGE_SIG; if ( (*p & 12) ) key_usage |= PUBKEY_USAGE_ENC; + if ( (*p & 0x20) ) + key_usage |= PUBKEY_USAGE_AUTH; } if ( !key_usage ) { /* no key flags at all: get it from the algo */ key_usage = openpgp_pk_algo_usage ( subpk->pubkey_algo ); @@ -2075,7 +2081,8 @@ premerge_public_with_secret ( KBNODE pubblock, KBNODE secblock ) /* The secret parts are not available so we can't use that key for signing etc. Fix the pubkey usage */ - pk->pubkey_usage &= ~PUBKEY_USAGE_SIG; + pk->pubkey_usage &= ~(PUBKEY_USAGE_SIG + |PUBKEY_USAGE_AUTH); } /* transfer flag bits 0 and 1 to the pubblock */ pub->flag |= (sec->flag &3); diff --git a/g10/keydb.h b/g10/keydb.h index 216add2e9..d02e427d8 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -186,6 +186,8 @@ int build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int have_static_passphrase(void); void read_passphrase_from_fd( int fd ); void passphrase_clear_cache ( u32 *keyid, int algo ); +char *ask_passphrase (const char *description, const char *prompt, + int *canceled); DEK *passphrase_to_dek( u32 *keyid, int pubkey_algo, int cipher_algo, STRING2KEY *s2k, int mode, const char *tryagain_text, int *canceled); diff --git a/g10/keygen.c b/g10/keygen.c index 4b736e16d..bcfdcfa67 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -145,6 +145,8 @@ do_add_key_flags (PKT_signature *sig, unsigned int use) } if (use & PUBKEY_USAGE_ENC) buf[0] |= 0x04 | 0x08; + if (use & PUBKEY_USAGE_AUTH) + buf[0] |= 0x20; build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1); } @@ -1486,7 +1488,7 @@ ask_user_id( int mode ) static DEK * -ask_passphrase( STRING2KEY **ret_s2k ) +do_ask_passphrase( STRING2KEY **ret_s2k ) { DEK *dek = NULL; STRING2KEY *s2k; @@ -1651,6 +1653,8 @@ parse_parameter_usage (const char *fname, use |= PUBKEY_USAGE_SIG; else if ( !ascii_strcasecmp (p, "encrypt") ) use |= PUBKEY_USAGE_ENC; + else if ( !ascii_strcasecmp (p, "auth") ) + use |= PUBKEY_USAGE_AUTH; else { log_error("%s:%d: invalid usage list\n", fname, r->lnr ); return -1; /* error */ @@ -2168,7 +2172,7 @@ generate_keypair( const char *fname ) r->next = para; para = r; - dek = ask_passphrase( &s2k ); + dek = do_ask_passphrase( &s2k ); if( dek ) { r = m_alloc_clear( sizeof *r ); r->key = pPASSPHRASE_DEK; diff --git a/g10/keylist.c b/g10/keylist.c index 262888102..de5b57572 100644 --- a/g10/keylist.c +++ b/g10/keylist.c @@ -475,11 +475,14 @@ print_capabilities (PKT_public_key *pk, PKT_secret_key *sk, KBNODE keyblock) if( pk? pk->is_primary : sk->is_primary ) putchar ('c'); } + + if ( (use & PUBKEY_USAGE_AUTH) ) + putchar ('a'); } if ( keyblock ) { /* figure out the usable capabilities */ KBNODE k; - int enc=0, sign=0, cert=0, disabled=0; + int enc=0, sign=0, cert=0, auth=0, disabled=0; for (k=keyblock; k; k = k->next ) { if ( k->pkt->pkttype == PKT_PUBLIC_KEY @@ -498,6 +501,8 @@ print_capabilities (PKT_public_key *pk, PKT_secret_key *sk, KBNODE keyblock) if(pk->is_primary) cert = 1; } + if ( (pk->pubkey_usage & PUBKEY_USAGE_AUTH) ) + auth = 1; } } else if ( k->pkt->pkttype == PKT_SECRET_KEY @@ -513,6 +518,8 @@ print_capabilities (PKT_public_key *pk, PKT_secret_key *sk, KBNODE keyblock) if(sk->is_primary) cert = 1; } + if ( (sk->pubkey_usage & PUBKEY_USAGE_AUTH) ) + auth = 1; } } } @@ -522,6 +529,8 @@ print_capabilities (PKT_public_key *pk, PKT_secret_key *sk, KBNODE keyblock) putchar ('S'); if (cert) putchar ('C'); + if (auth) + putchar ('A'); if (disabled) putchar ('D'); } diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 0831d26f4..e84609e47 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1590,6 +1590,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, if( pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY ) { PKT_secret_key *sk = pkt->pkt.secret_key; byte temp[16]; + size_t snlen = 0; if( !npkey ) { sk->skey[0] = mpi_set_opaque( NULL, @@ -1662,6 +1663,8 @@ parse_key( IOBUF 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", @@ -1697,6 +1700,19 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, printf("\tprotect count: %lu\n", (ulong)sk->protect.s2k.count); } + else if( sk->protect.s2k.mode == 1002 ) { + /* Read the serial number. */ + if (pktlen < 1) { + rc = G10ERR_INVALID_PACKET; + goto leave; + } + snlen = iobuf_get (inp); + pktlen--; + if (pktlen < snlen || snlen == -1) { + rc = G10ERR_INVALID_PACKET; + goto leave; + } + } } /* Note that a sk->protect.algo > 110 is illegal, but I'm not erroring on it here as otherwise there would be no @@ -1726,6 +1742,8 @@ parse_key( IOBUF 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 = snlen < 16? snlen : 16; if( pktlen < sk->protect.ivlen ) { rc = G10ERR_INVALID_PACKET; @@ -1734,7 +1752,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen, for(i=0; i < sk->protect.ivlen && pktlen; i++, pktlen-- ) temp[i] = iobuf_get_noeof(inp); if( list_mode ) { - printf( "\tprotect IV: "); + printf( sk->protect.s2k.mode == 1002? "\tserial-number: " + : "\tprotect IV: "); for(i=0; i < sk->protect.ivlen; i++ ) printf(" %02x", temp[i] ); putchar('\n'); @@ -1747,7 +1766,8 @@ parse_key( IOBUF 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, m_strdup("dummydata"), 10); pktlen = 0; diff --git a/g10/passphrase.c b/g10/passphrase.c index a48f220a2..10dd3ff81 100644 --- a/g10/passphrase.c +++ b/g10/passphrase.c @@ -1004,22 +1004,57 @@ passphrase_clear_cache ( u32 *keyid, int algo ) /**************** - * Get a passphrase for the secret key with KEYID, display TEXT - * if the user needs to enter the passphrase. - * mode 0 = standard, 1 = same but don't show key info, - * 2 = create new passphrase - * Returns: a DEK with a session key; caller must free - * or NULL if the passphrase was not correctly repeated. - * (only for mode 2) - * a dek->keylen of 0 means: no passphrase entered. - * (only for mode 2) - * - * pubkey_algo is only informational. Note that TRYAGAIN_TEXT must - * not be translated as this is done within this function (required to - * switch to utf-8 when the agent is in use). If CANCELED is not - * NULL, it is set to 1 if the user choosed to cancel the operation, - * otherwise it will be set to 0. + * Ask for a passphrase and return that string. */ +char * +ask_passphrase (const char *description, const char *prompt, int *canceled) +{ + char *pw = NULL; + + if (canceled) + *canceled = 0; + + if (is_status_enabled()) + write_status_text( STATUS_NEED_PASSPHRASE_SYM, "0 0 0"); + + if (!opt.batch && description) + tty_printf ("\n%s\n",description); + + agent_died: + if ( opt.use_agent ) + { + pw = agent_get_passphrase (NULL, 0, description, canceled ); + if (!pw) + { + if (!opt.use_agent) + goto agent_died; + pw = NULL; + } + } + else if (fd_passwd) + { + pw = m_alloc_secure (strlen(fd_passwd)+1); + strcpy (pw, fd_passwd); + } + else if (opt.batch) + { + log_error(_("can't query password in batchmode\n")); + pw = NULL; + } + else { + pw = cpr_get_hidden("passphrase.ask", + prompt?prompt : _("Enter passphrase: ") ); + tty_kill_prompt(); + } + + if (!pw || !*pw) + write_status( STATUS_MISSING_PASSPHRASE ); + + return pw; +} + + + DEK * passphrase_to_dek( u32 *keyid, int pubkey_algo, int cipher_algo, STRING2KEY *s2k, int mode, diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c index 76f0ee28d..5730735b8 100644 --- a/g10/seckey-cert.c +++ b/g10/seckey-cert.c @@ -225,6 +225,9 @@ check_secret_key( PKT_secret_key *sk, int n ) int rc = G10ERR_BAD_PASS; int i,mode; + if (sk && sk->is_protected && sk->protect.s2k.mode == 1002) + return 0; /* Let the card support stuff handle this. */ + if(n<0) { n=abs(n); @@ -265,11 +268,14 @@ check_secret_key( PKT_secret_key *sk, int n ) /**************** * check whether the secret key is protected. * Returns: 0 not protected, -1 on error or the protection algorithm + * -2 indicates a card stub. */ int is_secret_key_protected( PKT_secret_key *sk ) { - return sk->is_protected? sk->protect.algo : 0; + return sk->is_protected? + sk->protect.s2k.mode == 1002? -2 + : sk->protect.algo : 0; } diff --git a/g10/sign.c b/g10/sign.c index d1d981480..b7fd7bb20 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -313,18 +313,19 @@ do_sign( PKT_secret_key *sk, PKT_signature *sig, size_t rbuflen; char *snbuf; - snbuf = serialno_and_fpr_from_sk (sk->protect.iv, sk->protect.ivlen,sk); - rc = G10ERR_GENERAL; -/* agent_scd_pksign (snbuf, digest_algo, */ -/* gcry_md_read (md, digest_algo), */ -/* gcry_md_get_algo_dlen (digest_algo), */ -/* &rbuf, &rbuflen); */ + snbuf = serialno_and_fpr_from_sk (sk->protect.iv, + sk->protect.ivlen, sk); + rc = agent_scd_pksign (snbuf, digest_algo, + md_read (md, digest_algo), + md_digest_length (digest_algo), + &rbuf, &rbuflen); xfree (snbuf); if (!rc) { -/* if (gcry_mpi_scan (&sig->data[0], GCRYMPI_FMT_USG, */ -/* rbuf, rbuflen, NULL)) */ - BUG (); + sig->data[0] = mpi_alloc ( (rbuflen+BYTES_PER_MPI_LIMB-1) + / BYTES_PER_MPI_LIMB ); + mpi_set_buffer (sig->data[0], rbuf, rbuflen, 0); + xfree (rbuf); } } else diff --git a/include/ChangeLog b/include/ChangeLog index e9f720fe9..e0e1f35f0 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,3 +1,7 @@ +2003-09-29 Werner Koch + + * cipher.h (PUBKEY_USAGE_AUTH): New. + 2003-09-28 Timo Schulz * util.h [WIN32]: Prototype for asprintf. diff --git a/include/cipher.h b/include/cipher.h index e450c1449..1a29c715c 100644 --- a/include/cipher.h +++ b/include/cipher.h @@ -54,6 +54,7 @@ #define PUBKEY_USAGE_SIG 1 /* key is good for signatures */ #define PUBKEY_USAGE_ENC 2 /* key is good for encryption */ #define PUBKEY_USAGE_CERT 4 /* key is also good to certify other keys*/ +#define PUBKEY_USAGE_AUTH 8 /* key is good for authentication */ #define DIGEST_ALGO_MD5 1 #define DIGEST_ALGO_SHA1 2