summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2005-02-25 17:14:55 +0100
committerWerner Koch <wk@gnupg.org>2005-02-25 17:14:55 +0100
commitfaef9f929b845dc712c8d705620661b5bc6f6767 (patch)
tree22de098892f72f0994a685e8710f11f7ab33e31a
parent* call-scd.c (unescape_status_string): New. Actual a copy of (diff)
downloadgnupg2-faef9f929b845dc712c8d705620661b5bc6f6767.tar.xz
gnupg2-faef9f929b845dc712c8d705620661b5bc6f6767.zip
* 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.
-rw-r--r--agent/ChangeLog19
-rw-r--r--agent/agent.h3
-rw-r--r--agent/call-scd.c22
-rw-r--r--agent/command-ssh.c156
-rw-r--r--agent/findkey.c15
-rw-r--r--agent/keyformat.txt4
-rw-r--r--agent/learncard.c28
-rw-r--r--agent/protect-tool.c2
-rw-r--r--agent/protect.c37
-rw-r--r--common/ChangeLog4
-rw-r--r--common/util.h4
-rw-r--r--common/xasprintf.c20
-rw-r--r--scd/ChangeLog9
-rw-r--r--scd/app-openpgp.c86
-rw-r--r--scd/app.c10
-rw-r--r--tools/ChangeLog4
-rw-r--r--tools/gpg-connect-agent.c47
-rw-r--r--tools/no-libgcrypt.c6
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 <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);
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 <wk@g10code.com>
+
+ * xasprintf.c (xtryasprintf): New.
+
2005-01-26 Moritz Schulte <moritz@g10code.com>
* 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 <wk@g10code.com>
+
+ * 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 <wk@g10code.com>
* 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; n < 16; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
+ {
+ 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);
- 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 <wk@g10code.com>
+
+ * no-libgcrypt.c (gcry_strdup): New.
+
2005-02-24 Werner Koch <wk@g10code.com>
* 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 <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <ctype.h>
#include <assuan.h>
#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)