diff options
Diffstat (limited to 'agent')
-rw-r--r-- | agent/ChangeLog | 19 | ||||
-rw-r--r-- | agent/agent.h | 3 | ||||
-rw-r--r-- | agent/call-scd.c | 22 | ||||
-rw-r--r-- | agent/command-ssh.c | 156 | ||||
-rw-r--r-- | agent/findkey.c | 15 | ||||
-rw-r--r-- | agent/keyformat.txt | 4 | ||||
-rw-r--r-- | agent/learncard.c | 28 | ||||
-rw-r--r-- | agent/protect-tool.c | 2 | ||||
-rw-r--r-- | agent/protect.c | 37 |
9 files changed, 212 insertions, 74 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog index 118559c64..2138f6674 100644 --- a/agent/ChangeLog +++ b/agent/ChangeLog @@ -1,3 +1,22 @@ +2005-02-25 Werner Koch <wk@g10code.com> + + * findkey.c (modify_description): Keep invalid % escapes, so that + %0A may pass through. + + * agent.h (server_control_s): New field USE_AUTH_CALL. + * call-scd.c (agent_card_pksign): Make use of it. + * command-ssh.c (data_sign): Set the flag. + (ssh_send_key_public): New arg OVERRIDE_COMMENT. + (card_key_available): Add new arg CARDSN. + (ssh_handler_request_identities): Use the card s/n as comment. + (sexp_key_extract): Use GCRYMPI_FMT_STD. + (data_sign): Ditto. + + * learncard.c (make_shadow_info): Moved to .. + * protect.c (make_shadow_info): .. here. Return NULL on malloc + failure. Made global. + * agent.h: Add prototype. + 2005-02-24 Werner Koch <wk@g10code.com> * call-scd.c (unescape_status_string): New. Actual a copy of diff --git a/agent/agent.h b/agent/agent.h index 39e479e48..e12a02b6e 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -116,6 +116,8 @@ struct server_control_s { char keygrip[20]; int have_keygrip; + int use_auth_call; /* Hack to send the PKAUTH command instead of the + PKSIGN command tro scdaemon. */ }; typedef struct server_control_s *CTRL; typedef struct server_control_s *ctrl_t; @@ -204,6 +206,7 @@ int agent_protect (const unsigned char *plainkey, const char *passphrase, int agent_unprotect (const unsigned char *protectedkey, const char *passphrase, unsigned char **result, size_t *resultlen); int agent_private_key_type (const unsigned char *privatekey); +unsigned char *make_shadow_info (const char *serialno, const char *idstring); int agent_shadow_key (const unsigned char *pubkey, const unsigned char *shadow_info, unsigned char **result); diff --git a/agent/call-scd.c b/agent/call-scd.c index f7d32f7cf..904059291 100644 --- a/agent/call-scd.c +++ b/agent/call-scd.c @@ -225,15 +225,16 @@ start_scd (ctrl_t ctrl) /* Tell the scdaemon that we want him to send us an event signal. But only do this if we are running as a regular sever and not simply as a pipe server. */ - if (ctrl->connection_fd != -1) - { -#ifndef HAVE_W32_SYSTEM - char buf[100]; + /* Fixme: gpg-agent does not use this signal yet. */ +/* if (ctrl->connection_fd != -1) */ +/* { */ +/* #ifndef HAVE_W32_SYSTEM */ +/* char buf[100]; */ - sprintf (buf, "OPTION event-signal=%d", SIGUSR2); - assuan_transact (scd_ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL); -#endif - } +/* sprintf (buf, "OPTION event-signal=%d", SIGUSR2); */ +/* assuan_transact (scd_ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL); */ +/* #endif */ +/* } */ return 0; } @@ -505,7 +506,8 @@ agent_card_pksign (ctrl_t ctrl, inqparm.ctx = scd_ctx; inqparm.getpin_cb = getpin_cb; inqparm.getpin_cb_arg = getpin_cb_arg; - snprintf (line, DIM(line)-1, "PKSIGN %s", keyid); + snprintf (line, DIM(line)-1, + ctrl->use_auth_call? "PKAUTH %s":"PKSIGN %s", keyid); line[DIM(line)-1] = 0; rc = assuan_transact (scd_ctx, line, membuf_data_cb, &data, @@ -518,7 +520,7 @@ agent_card_pksign (ctrl_t ctrl, } sigbuf = get_membuf (&data, &sigbuflen); - /* create an S-expression from it which is formatted like this: + /* Create an S-expression from it which is formatted like this: "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))" */ *r_buflen = 21 + 11 + sigbuflen + 4; *r_buf = xtrymalloc (*r_buflen); diff --git a/agent/command-ssh.c b/agent/command-ssh.c index 2c0d25ef6..ebb44fa74 100644 --- a/agent/command-ssh.c +++ b/agent/command-ssh.c @@ -659,7 +659,9 @@ open_control_file (FILE **r_fp, int append) (i.e. where Pth might switch threads) we need to employ a mutex. */ *r_fp = NULL; - fname = make_filename (opt.homedir, "sshcontrol.txt", NULL); + fname = make_filename (opt.homedir, "sshcontrol", NULL); + /* FIXME: With "a+" we are not able to check whether this will will + be created and thus the blurb needs to be written first. */ fp = fopen (fname, append? "a+":"r"); if (!fp && errno == ENOENT) { @@ -1146,7 +1148,9 @@ sexp_key_extract (gcry_sexp_t sexp, break; } - mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_USG); + /* Note that we need to use STD format; i.e. prepend a 0x00 to + indicate a positive number if the high bit is set. */ + mpi = gcry_sexp_nth_mpi (value_pair, 1, GCRYMPI_FMT_STD); if (! mpi) { err = gpg_error (GPG_ERR_INV_SEXP); @@ -1404,9 +1408,12 @@ ssh_convert_key_to_blob (unsigned char **blob, size_t *blob_size, } -/* Write the public key KEY_PUBLIC to STREAM in SSH key format. */ +/* Write the public key KEY_PUBLIC to STREAM in SSH key format. If + OVERRIDE_COMMENT is not NULL, it will be used instead of the + comment stored in the key. */ static gpg_error_t -ssh_send_key_public (estream_t stream, gcry_sexp_t key_public) +ssh_send_key_public (estream_t stream, gcry_sexp_t key_public, + const char *override_comment) { ssh_key_type_spec_t spec; gcry_mpi_t *mpi_list; @@ -1442,7 +1449,8 @@ ssh_send_key_public (estream_t stream, gcry_sexp_t key_public) if (err) goto out; - err = stream_write_cstring (stream, comment); + err = stream_write_cstring (stream, + override_comment? override_comment : comment); out: @@ -1520,17 +1528,23 @@ key_secret_to_public (gcry_sexp_t *key_public, /* Chec whether a smartcard is available and whether it has a usable key. Store a copy of that key at R_PK and return 0. If no key is - available store NULL at R_PK and return an error code. */ + available store NULL at R_PK and return an error code. If CARDSN + is no NULL, a string with the serial number of the card will be + amalloced and stored there. */ static gpg_error_t -card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk) +card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk, char **cardsn) { gpg_error_t err; char *appname; - unsigned char *sbuf; - size_t sbuflen; - gcry_sexp_t pk; + char *serialno = NULL; + unsigned char *pkbuf; + size_t pkbuflen; + gcry_sexp_t s_pk; + unsigned char grip[20]; *r_pk = NULL; + if (cardsn) + *cardsn = NULL; /* First see whether a card is available and whether the application is supported. */ @@ -1538,53 +1552,135 @@ card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk) if ( gpg_err_code (err) == GPG_ERR_CARD_REMOVED ) { /* Ask for the serial number to reset the card. */ - err = agent_card_serialno (ctrl, &appname); + err = agent_card_serialno (ctrl, &serialno); if (err) { if (opt.verbose) - log_info (_("can't get serial number of card: %s\n"), + log_info (_("error getting serial number of card: %s\n"), gpg_strerror (err)); return err; } - log_info (_("detected card with S/N: %s\n"), appname); - xfree (appname); + log_info (_("detected card with S/N: %s\n"), serialno); err = agent_card_getattr (ctrl, "APPTYPE", &appname); } if (err) { log_error (_("error getting application type of card: %s\n"), gpg_strerror (err)); + xfree (serialno); return err; } if (strcmp (appname, "OPENPGP")) { log_info (_("card application `%s' is not supported\n"), appname); xfree (appname); + xfree (serialno); return gpg_error (GPG_ERR_NOT_SUPPORTED); } xfree (appname); appname = NULL; + /* Get the S/N if we don't have it yet. Use the fast getattr method. */ + if (!serialno && (err = agent_card_getattr (ctrl, "SERIALNO", &serialno)) ) + { + log_error (_("error getting serial number of card: %s\n"), + gpg_strerror (err)); + return err; + } + /* Read the public key. */ - err = agent_card_readkey (ctrl, "OPENPGP.3", &sbuf); + err = agent_card_readkey (ctrl, "OPENPGP.3", &pkbuf); if (err) { if (opt.verbose) log_info (_("no suitable card key found: %s\n"), gpg_strerror (err)); + xfree (serialno); return err; } - sbuflen = gcry_sexp_canon_len (sbuf, 0, NULL, NULL); - err = gcry_sexp_sscan (&pk, NULL, sbuf, sbuflen); - xfree (sbuf); + pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL); + err = gcry_sexp_sscan (&s_pk, NULL, pkbuf, pkbuflen); if (err) { log_error ("failed to build S-Exp from received card key: %s\n", gpg_strerror (err)); + xfree (pkbuf); + xfree (serialno); return err; } - *r_pk = pk; + if ( !gcry_pk_get_keygrip (s_pk, grip) ) + { + log_debug ("error computing keygrip from received card key\n"); + xfree (pkbuf); + gcry_sexp_release (s_pk); + xfree (serialno); + return gpg_error (GPG_ERR_INTERNAL); + } + + if ( agent_key_available (grip) ) + { + /* (Shadow)-key is not available in our key storage. */ + unsigned char *shadow_info; + unsigned char *tmp; + + shadow_info = make_shadow_info (serialno, "OPENPGP.3"); + if (!shadow_info) + { + err = gpg_error_from_errno (errno); + xfree (pkbuf); + gcry_sexp_release (s_pk); + xfree (serialno); + return err; + } + err = agent_shadow_key (pkbuf, shadow_info, &tmp); + xfree (shadow_info); + if (err) + { + log_error (_("shadowing the key failed: %s\n"), gpg_strerror (err)); + xfree (pkbuf); + gcry_sexp_release (s_pk); + xfree (serialno); + return err; + } + xfree (pkbuf); + pkbuf = tmp; + pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL); + assert (pkbuflen); + + err = agent_write_private_key (grip, pkbuf, pkbuflen, 0); + if (err) + { + log_error (_("error writing key: %s\n"), gpg_strerror (err)); + xfree (pkbuf); + gcry_sexp_release (s_pk); + xfree (serialno); + return err; + } + } + + if (cardsn) + { + size_t snlen = strlen (serialno); + + if (snlen == 32 + && !memcmp (serialno, "D27600012401", 12)) /* OpenPGP card. */ + *cardsn = xtryasprintf ("cardno:%.12s", serialno+16); + else /* Something is wrong: Print all. */ + *cardsn = xtryasprintf ("cardno:%s", serialno); + if (!*cardsn) + { + err = gpg_error_from_errno (errno); + xfree (pkbuf); + gcry_sexp_release (s_pk); + xfree (serialno); + return err; + } + } + + xfree (pkbuf); + xfree (serialno); + *r_pk = s_pk; return 0; } @@ -1615,6 +1711,7 @@ ssh_handler_request_identities (ctrl_t ctrl, gpg_error_t ret_err; int ret; FILE *ctrl_fp = NULL; + char *cardsn; /* Prepare buffer stream. */ @@ -1665,13 +1762,14 @@ ssh_handler_request_identities (ctrl_t ctrl, /* First check whether a key is currently available in the card reader - this should be allowed even without being listed in - sshcontrol.txt. */ + sshcontrol. */ - if (!card_key_available (ctrl, &key_public)) + if (!card_key_available (ctrl, &key_public, &cardsn)) { - err = ssh_send_key_public (key_blobs, key_public); + err = ssh_send_key_public (key_blobs, key_public, cardsn); gcry_sexp_release (key_public); key_public = NULL; + xfree (cardsn); if (err) goto out; @@ -1740,7 +1838,7 @@ ssh_handler_request_identities (ctrl_t ctrl, gcry_sexp_release (key_secret); key_secret = NULL; - err = ssh_send_key_public (key_blobs, key_public); + err = ssh_send_key_public (key_blobs, key_public, NULL); if (err) goto out; @@ -1845,9 +1943,11 @@ data_sign (ctrl_t ctrl, ssh_signature_encoder_t sig_encoder, sig_value = NULL; mpis = NULL; + ctrl->use_auth_call = 1; err = agent_pksign_do (ctrl, - _("Please provide the passphrase " - "for the ssh key `%c':"), &signature_sexp, 0); + _("Please enter the passphrase " + "for the ssh key%0A %c"), &signature_sexp, 0); + ctrl->use_auth_call = 0; if (err) goto out; @@ -2189,7 +2289,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl) key_grip_raw[sizeof (key_grip_raw) - 1] = 0; /* FIXME: Why?? */ - /* Check whether the key is alread in our key storage. Don't do + /* Check whether the key is already in our key storage. Don't do anything then. */ if ( !agent_key_available (key_grip_raw) ) goto out; /* Yes, key is available. */ @@ -2200,8 +2300,8 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl) goto out; if ( asprintf (&description, - _("Please enter a passphrase to protect%%0A" - "the received secret key%%0A" + _("Please enter a passphrase to protect" + " the received secret key%%0A" " %s%%0A" "within gpg-agent's key storage"), comment ? comment : "?") < 0) diff --git a/agent/findkey.c b/agent/findkey.c index 86a28d511..0b5816bf5 100644 --- a/agent/findkey.c +++ b/agent/findkey.c @@ -166,9 +166,7 @@ modify_description (const char *in, const char *comment, char **result) special = 0; for (i = 0; i < in_len; i++) { - if (in[i] == '%') - special = 1; - else if (special) + if (special) { special = 0; switch (in[i]) @@ -190,10 +188,19 @@ modify_description (const char *in, const char *comment, char **result) out_len += comment_length; break; - default: /* Invalid special sequences are ignored. */ + default: /* Invalid special sequences are kept as they are. */ + if (out) + { + *out++ = '%'; + *out++ = in[i]; + } + else + out_len+=2; break; } } + else if (in[i] == '%') + special = 1; else { if (out) diff --git a/agent/keyformat.txt b/agent/keyformat.txt index 726990315..7bdb94c0e 100644 --- a/agent/keyformat.txt +++ b/agent/keyformat.txt @@ -161,9 +161,9 @@ term secret key because it can be visually be better distinguished from the term public key. [2] The keygrip is a unique identifier for a key pair, it is -independent of any protocol, so that the same key can be ised with +independent of any protocol, so that the same key can be used with different protocols. PKCS-15 calls this a subjectKeyHash; it can be -calculate using Libgcrypt's gcry_pk_get_keygrip(). +calculated using Libgcrypt's gcry_pk_get_keygrip (). [3] Even when canonical representation are required we will show the S-expression here in a more readable representation. diff --git a/agent/learncard.c b/agent/learncard.c index 7dcacee28..72238507f 100644 --- a/agent/learncard.c +++ b/agent/learncard.c @@ -1,5 +1,5 @@ /* learncard.c - Handle the LEARN command - * Copyright (C) 2002, 2003 Free Software Foundation, Inc. + * Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -239,32 +239,6 @@ sinfo_cb (void *opaque, const char *keyword, size_t keywordlen, } -/* Create an S-expression with the shadow info. */ -static unsigned char * -make_shadow_info (const char *serialno, const char *idstring) -{ - const char *s; - unsigned char *info, *p; - char numbuf[21]; - int n; - - for (s=serialno, n=0; *s && s[1]; s += 2) - n++; - - info = p = xtrymalloc (1 + 21 + n - + 21 + strlen (idstring) + 1 + 1); - *p++ = '('; - sprintf (numbuf, "%d:", n); - p = stpcpy (p, numbuf); - for (s=serialno; *s && s[1]; s += 2) - *p++ = xtoi_2 (s); - sprintf (numbuf, "%d:", strlen (idstring)); - p = stpcpy (p, numbuf); - p = stpcpy (p, idstring); - *p++ = ')'; - *p = 0; - return info; -} static int send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context) diff --git a/agent/protect-tool.c b/agent/protect-tool.c index ee0276a43..c21aa0517 100644 --- a/agent/protect-tool.c +++ b/agent/protect-tool.c @@ -110,7 +110,7 @@ static ARGPARSE_OPTS opts[] = { { oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" }, { oProtect, "protect", 256, "protect a private key"}, { oUnprotect, "unprotect", 256, "unprotect a private key"}, - { oShadow, "shadow", 256, "create a shadow entry for a priblic key"}, + { oShadow, "shadow", 256, "create a shadow entry for a public key"}, { oShowShadowInfo, "show-shadow-info", 256, "return the shadow info"}, { oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""}, diff --git a/agent/protect.c b/agent/protect.c index cafeb4685..ae3061c77 100644 --- a/agent/protect.c +++ b/agent/protect.c @@ -831,10 +831,43 @@ hash_passphrase (const char *passphrase, int hashalgo, + +/* Create an canonical encoded S-expression with the shadow info from + a card's SERIALNO and the IDSTRING. */ +unsigned char * +make_shadow_info (const char *serialno, const char *idstring) +{ + const char *s; + unsigned char *info, *p; + char numbuf[21]; + int n; + + for (s=serialno, n=0; *s && s[1]; s += 2) + n++; + + info = p = xtrymalloc (1 + 21 + n + + 21 + strlen (idstring) + 1 + 1); + if (!info) + return NULL; + *p++ = '('; + sprintf (numbuf, "%d:", n); + p = stpcpy (p, numbuf); + for (s=serialno; *s && s[1]; s += 2) + *p++ = xtoi_2 (s); + sprintf (numbuf, "%d:", strlen (idstring)); + p = stpcpy (p, numbuf); + p = stpcpy (p, idstring); + *p++ = ')'; + *p = 0; + return info; +} + + + /* Create a shadow key from a public key. We use the shadow protocol "ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting S-expression is returned in an allocated buffer RESULT will point - to. The input parameters are expected to be valid canonilized + to. The input parameters are expected to be valid canonicalized S-expressions */ int agent_shadow_key (const unsigned char *pubkey, @@ -894,7 +927,7 @@ agent_shadow_key (const unsigned char *pubkey, s++; assert (depth == 1); - /* calculate required length by taking in account: the "shadowed-" + /* Calculate required length by taking in account: the "shadowed-" prefix, the "shadowed", "t1-v1" as well as some parenthesis */ n = 12 + pubkey_len + 1 + 3+8 + 2+5 + shadow_info_len + 1; *result = p = xtrymalloc (n); |