From faef9f929b845dc712c8d705620661b5bc6f6767 Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Fri, 25 Feb 2005 16:14:55 +0000 Subject: [PATCH] * 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. * xasprintf.c (xtryasprintf): New. * app-openpgp.c (get_public_key): Make sure not to return negative numbers. (do_sign): Allow passing of indata with algorithm prefix. (do_auth): Allow OPENPGP.3 as an alternative ID. * app.c (app_getattr): Return just the S/N but not the timestamp. * no-libgcrypt.c (gcry_strdup): New. --- agent/ChangeLog | 19 +++++ agent/agent.h | 3 + agent/call-scd.c | 22 +++--- agent/command-ssh.c | 156 +++++++++++++++++++++++++++++++------- agent/findkey.c | 15 +++- agent/keyformat.txt | 4 +- agent/learncard.c | 28 +------ agent/protect-tool.c | 2 +- agent/protect.c | 37 ++++++++- common/ChangeLog | 4 + common/util.h | 4 + common/xasprintf.c | 20 ++++- scd/ChangeLog | 9 +++ scd/app-openpgp.c | 86 ++++++++++++++++----- scd/app.c | 10 +-- tools/ChangeLog | 4 + tools/gpg-connect-agent.c | 47 +++++++++++- tools/no-libgcrypt.c | 6 ++ 18 files changed, 368 insertions(+), 108 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 + + * 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 * 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); diff --git a/common/ChangeLog b/common/ChangeLog index e323dc148..db0593176 100644 --- a/common/ChangeLog +++ b/common/ChangeLog @@ -1,3 +1,7 @@ +2005-02-25 Werner Koch + + * xasprintf.c (xtryasprintf): New. + 2005-01-26 Moritz Schulte * Makefile.am (libcommon_a_SOURCES): New source files: estream.c, diff --git a/common/util.h b/common/util.h index 4ab55acb4..bbf7241a3 100644 --- a/common/util.h +++ b/common/util.h @@ -131,6 +131,10 @@ const char *default_homedir (void); freed using xfree. This function simply dies on memory failure, thus no extra check is required. */ char *xasprintf (const char *fmt, ...) JNLIB_GCC_A_PRINTF(1,2); +/* Same as asprintf but return an allocated buffer suitable to be + freed using xfree. This function returns NULL on memory failure and + sets errno. */ +char *xtryasprintf (const char *fmt, ...) JNLIB_GCC_A_PRINTF(1,2); const char *print_fname_stdout (const char *s); const char *print_fname_stdin (const char *s); diff --git a/common/xasprintf.c b/common/xasprintf.c index 2c8fafc06..a3b5e27ac 100644 --- a/common/xasprintf.c +++ b/common/xasprintf.c @@ -1,5 +1,5 @@ /* xasprintf.c - * Copyright (C) 2003 Free Software Foundation, Inc. + * Copyright (C) 2003, 2005 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -42,3 +42,21 @@ xasprintf (const char *fmt, ...) free (buf); return p; } + +/* Same as above bit return NULL on memory failure. */ +char * +xtryasprintf (const char *fmt, ...) +{ + int rc; + va_list ap; + char *buf, *p; + + va_start (ap, fmt); + rc = vasprintf (&buf, fmt, ap); + va_end (ap); + if (rc < 0) + return NULL; + p = xtrystrdup (buf); + free (buf); + return p; +} diff --git a/scd/ChangeLog b/scd/ChangeLog index dc394b677..e3b4ae64c 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,12 @@ +2005-02-25 Werner Koch + + * app-openpgp.c (get_public_key): Make sure not to return negative + numbers. + (do_sign): Allow passing of indata with algorithm prefix. + (do_auth): Allow OPENPGP.3 as an alternative ID. + + * app.c (app_getattr): Return just the S/N but not the timestamp. + 2005-02-24 Werner Koch * app.c (app_getattr): Return APPTYPE or SERIALNO type even if the diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 14c802d10..6ebc13704 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -794,6 +794,8 @@ get_public_key (app_t app, int keyno) const unsigned char *keydata, *m, *e; size_t buflen, keydatalen, mlen, elen; gcry_sexp_t sexp; + unsigned char *mbuf = NULL; + unsigned char *ebuf = NULL; if (keyno < 1 || keyno > 3) return gpg_error (GPG_ERR_INV_ID); @@ -835,6 +837,7 @@ get_public_key (app_t app, int keyno) log_error (_("response does not contain the RSA modulus\n")); goto leave; } + e = find_tlv (keydata, keydatalen, 0x0082, &elen); if (!e) @@ -844,10 +847,38 @@ get_public_key (app_t app, int keyno) goto leave; } + /* Prepend numbers with a 0 if needed. */ + if (mlen && (*m & 0x80)) + { + mbuf = xtrymalloc ( mlen + 1); + if (!mbuf) + { + err = gpg_error_from_errno (errno); + goto leave; + } + *mbuf = 0; + memcpy (mbuf+1, m, mlen); + mlen++; + m = mbuf; + } + if (elen && (*e & 0x80)) + { + ebuf = xtrymalloc ( elen + 1); + if (!ebuf) + { + err = gpg_error_from_errno (errno); + goto leave; + } + *ebuf = 0; + memcpy (ebuf+1, e, elen); + elen++; + e = ebuf; + } + + err = gcry_sexp_build (&sexp, NULL, "(public-key (rsa (n %b) (e %b)))", (int)mlen, m,(int)elen, e); - if (err) { log_error ("error formatting the key into an S-expression: %s\n", @@ -874,6 +905,8 @@ get_public_key (app_t app, int keyno) app->app_local->pk[keyno].read_done = 1; xfree (buffer); + xfree (mbuf); + xfree (ebuf); return 0; } #endif /* GNUPG_MAJOR_VERSION > 1 */ @@ -1557,7 +1590,15 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, if (!keyidstr || !*keyidstr) return gpg_error (GPG_ERR_INV_VALUE); - if (indatalen != 20) + if (indatalen == 20) + ; + else if (indatalen == (15 + 20) && hashalgo == GCRY_MD_SHA1 + && !memcmp (indata, sha1_prefix, 15)) + ; + else if (indatalen == (15 + 20) && hashalgo == GCRY_MD_RMD160 + && !memcmp (indata, rmd160_prefix, 15)) + ; + else return gpg_error (GPG_ERR_INV_VALUE); /* Check whether an OpenPGP card of any version has been requested. */ @@ -1668,7 +1709,8 @@ do_sign (app_t app, const char *keyidstr, int hashalgo, /* Compute a digital signature using the INTERNAL AUTHENTICATE command on INDATA which is expected to be the raw message digest. For this application the KEYIDSTR consists of the serialnumber and the - fingerprint delimited by a slash. + fingerprint delimited by a slash. Optionally the id OPENPGP.3 may + be given. Note that this fucntion may return the error code GPG_ERR_WRONG_CARD to indicate that the card currently present does @@ -1693,27 +1735,31 @@ do_auth (app_t app, const char *keyidstr, return gpg_error (GPG_ERR_INV_VALUE); /* Check whether an OpenPGP card of any version has been requested. */ - if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) - return gpg_error (GPG_ERR_INV_ID); - - for (s=keyidstr, n=0; hexdigitp (s); s++, n++) + if (!strcmp (keyidstr, "OPENPGP.3")) ; - if (n != 32) + else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) return gpg_error (GPG_ERR_INV_ID); - else if (!*s) - ; /* no fingerprint given: we allow this for now. */ - else if (*s == '/') - fpr = s + 1; else - return gpg_error (GPG_ERR_INV_ID); + { + for (s=keyidstr, n=0; hexdigitp (s); s++, n++) + ; + if (n != 32) + return gpg_error (GPG_ERR_INV_ID); + else if (!*s) + ; /* no fingerprint given: we allow this for now. */ + else if (*s == '/') + fpr = s + 1; + else + return gpg_error (GPG_ERR_INV_ID); - for (s=keyidstr, n=0; n < 16; s += 2, n++) - tmp_sn[n] = xtoi_2 (s); - - if (app->serialnolen != 16) - return gpg_error (GPG_ERR_INV_CARD); - if (memcmp (app->serialno, tmp_sn, 16)) - return gpg_error (GPG_ERR_WRONG_CARD); + for (s=keyidstr, n=0; n < 16; s += 2, n++) + tmp_sn[n] = xtoi_2 (s); + + if (app->serialnolen != 16) + return gpg_error (GPG_ERR_INV_CARD); + if (memcmp (app->serialno, tmp_sn, 16)) + return gpg_error (GPG_ERR_WRONG_CARD); + } /* If a fingerprint has been specified check it against the one on the card. This is allows for a meaningful error message in case diff --git a/scd/app.c b/scd/app.c index 384ee2143..0625dc8ef 100644 --- a/scd/app.c +++ b/scd/app.c @@ -314,7 +314,6 @@ app_getattr (APP app, CTRL ctrl, const char *name) } if (name && !strcmp (name, "SERIALNO")) { - char *serial_and_stamp; char *serial; time_t stamp; int rc; @@ -322,15 +321,8 @@ app_getattr (APP app, CTRL ctrl, const char *name) rc = app_get_serial_and_stamp (app, &serial, &stamp); if (rc) return rc; - rc = asprintf (&serial_and_stamp, "%s %lu", - serial, (unsigned long)stamp); - rc = (rc < 0)? gpg_error_from_errno (errno) : 0; + send_status_info (ctrl, "SERIALNO", serial, strlen (serial), NULL, 0); xfree (serial); - if (rc) - return rc; - send_status_info (ctrl, "SERIALNO", - serial_and_stamp, strlen (serial_and_stamp), NULL, 0); - free (serial_and_stamp); return 0; } diff --git a/tools/ChangeLog b/tools/ChangeLog index 6895198c5..4d520cfca 100644 --- a/tools/ChangeLog +++ b/tools/ChangeLog @@ -1,3 +1,7 @@ +2005-02-25 Werner Koch + + * no-libgcrypt.c (gcry_strdup): New. + 2005-02-24 Werner Koch * gpg-connect-agent.c: New. diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c index 399a5d369..19ff160f0 100644 --- a/tools/gpg-connect-agent.c +++ b/tools/gpg-connect-agent.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "i18n.h" @@ -40,7 +41,8 @@ enum cmd_and_opt_values oVerbose = 'v', oNoVerbose = 500, - oHomedir + oHomedir, + oHex }; @@ -52,6 +54,7 @@ static ARGPARSE_OPTS opts[] = { oVerbose, "verbose", 0, N_("verbose") }, { oQuiet, "quiet", 0, N_("quiet") }, + { oHex, "hex", 0, N_("print data out hex encoded") }, /* hidden options */ { oNoVerbose, "no-verbose", 0, "@"}, @@ -66,7 +69,7 @@ struct int verbose; /* Verbosity level. */ int quiet; /* Be extra quiet. */ const char *homedir; /* Configuration directory name */ - + int hex; /* Print data lines in hex format. */ } opt; @@ -155,6 +158,7 @@ main (int argc, char **argv) case oVerbose: opt.verbose++; break; case oNoVerbose: opt.verbose = 0; break; case oHomedir: opt.homedir = pargs.r.ret_str; break; + case oHex: opt.hex = 1; break; default: pargs.err = 2; break; } @@ -220,6 +224,7 @@ read_and_print_response (assuan_context_t ctx) char *line; int linelen; assuan_error_t rc; + int i, j; for (;;) { @@ -234,8 +239,42 @@ read_and_print_response (assuan_context_t ctx) if (linelen >= 1 && line[0] == 'D' && line[1] == ' ') { - fwrite (line, linelen, 1, stdout); - putchar ('\n'); + if (opt.hex) + { + for (i=2; i < linelen; ) + { + int save_i = i; + + printf ("D[%04X] ", i-2); + for (j=0; j < 16 ; j++, i++) + { + if (j == 8) + putchar (' '); + if (i < linelen) + printf (" %02X", ((unsigned char*)line)[i]); + else + fputs (" ", stdout); + } + fputs (" ", stdout); + i= save_i; + for (j=0; j < 16; j++, i++) + { + unsigned int c = ((unsigned char*)line)[i]; + if ( i >= linelen ) + putchar (' '); + else if (isascii (c) && isprint (c) && !iscntrl (c)) + putchar (c); + else + putchar ('.'); + } + putchar ('\n'); + } + } + else + { + fwrite (line, linelen, 1, stdout); + putchar ('\n'); + } } else if (linelen >= 1 && line[0] == 'S' diff --git a/tools/no-libgcrypt.c b/tools/no-libgcrypt.c index 0fabec90d..82f6a8bb5 100644 --- a/tools/no-libgcrypt.c +++ b/tools/no-libgcrypt.c @@ -53,6 +53,12 @@ gcry_xmalloc (size_t n) return p; } +char * +gcry_strdup (const char *string) +{ + return malloc (strlen (string)+1); +} + void * gcry_realloc (void *a, size_t n)