* 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.
This commit is contained in:
Werner Koch 2005-02-25 16:14:55 +00:00
parent 1f1f28555a
commit faef9f929b
18 changed files with 368 additions and 108 deletions

View File

@ -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> 2005-02-24 Werner Koch <wk@g10code.com>
* call-scd.c (unescape_status_string): New. Actual a copy of * call-scd.c (unescape_status_string): New. Actual a copy of

View File

@ -116,6 +116,8 @@ struct server_control_s {
char keygrip[20]; char keygrip[20];
int have_keygrip; 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;
typedef struct server_control_s *ctrl_t; 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, int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
unsigned char **result, size_t *resultlen); unsigned char **result, size_t *resultlen);
int agent_private_key_type (const unsigned char *privatekey); 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, int agent_shadow_key (const unsigned char *pubkey,
const unsigned char *shadow_info, const unsigned char *shadow_info,
unsigned char **result); unsigned char **result);

View File

@ -225,15 +225,16 @@ start_scd (ctrl_t ctrl)
/* Tell the scdaemon that we want him to send us an event signal. /* 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 But only do this if we are running as a regular sever and not
simply as a pipe server. */ simply as a pipe server. */
if (ctrl->connection_fd != -1) /* Fixme: gpg-agent does not use this signal yet. */
{ /* if (ctrl->connection_fd != -1) */
#ifndef HAVE_W32_SYSTEM /* { */
char buf[100]; /* #ifndef HAVE_W32_SYSTEM */
/* char buf[100]; */
sprintf (buf, "OPTION event-signal=%d", SIGUSR2); /* sprintf (buf, "OPTION event-signal=%d", SIGUSR2); */
assuan_transact (scd_ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL); /* assuan_transact (scd_ctx, buf, NULL, NULL, NULL, NULL, NULL, NULL); */
#endif /* #endif */
} /* } */
return 0; return 0;
} }
@ -505,7 +506,8 @@ agent_card_pksign (ctrl_t ctrl,
inqparm.ctx = scd_ctx; inqparm.ctx = scd_ctx;
inqparm.getpin_cb = getpin_cb; inqparm.getpin_cb = getpin_cb;
inqparm.getpin_cb_arg = getpin_cb_arg; 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; line[DIM(line)-1] = 0;
rc = assuan_transact (scd_ctx, line, rc = assuan_transact (scd_ctx, line,
membuf_data_cb, &data, membuf_data_cb, &data,
@ -518,7 +520,7 @@ agent_card_pksign (ctrl_t ctrl,
} }
sigbuf = get_membuf (&data, &sigbuflen); 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)))" */ "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))" */
*r_buflen = 21 + 11 + sigbuflen + 4; *r_buflen = 21 + 11 + sigbuflen + 4;
*r_buf = xtrymalloc (*r_buflen); *r_buf = xtrymalloc (*r_buflen);

View File

@ -659,7 +659,9 @@ open_control_file (FILE **r_fp, int append)
(i.e. where Pth might switch threads) we need to employ a (i.e. where Pth might switch threads) we need to employ a
mutex. */ mutex. */
*r_fp = NULL; *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"); fp = fopen (fname, append? "a+":"r");
if (!fp && errno == ENOENT) if (!fp && errno == ENOENT)
{ {
@ -1146,7 +1148,9 @@ sexp_key_extract (gcry_sexp_t sexp,
break; 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) if (! mpi)
{ {
err = gpg_error (GPG_ERR_INV_SEXP); 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 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; ssh_key_type_spec_t spec;
gcry_mpi_t *mpi_list; gcry_mpi_t *mpi_list;
@ -1442,7 +1449,8 @@ ssh_send_key_public (estream_t stream, gcry_sexp_t key_public)
if (err) if (err)
goto out; goto out;
err = stream_write_cstring (stream, comment); err = stream_write_cstring (stream,
override_comment? override_comment : comment);
out: 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 /* 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 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 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; gpg_error_t err;
char *appname; char *appname;
unsigned char *sbuf; char *serialno = NULL;
size_t sbuflen; unsigned char *pkbuf;
gcry_sexp_t pk; size_t pkbuflen;
gcry_sexp_t s_pk;
unsigned char grip[20];
*r_pk = NULL; *r_pk = NULL;
if (cardsn)
*cardsn = NULL;
/* First see whether a card is available and whether the application /* First see whether a card is available and whether the application
is supported. */ 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 ) if ( gpg_err_code (err) == GPG_ERR_CARD_REMOVED )
{ {
/* Ask for the serial number to reset the card. */ /* Ask for the serial number to reset the card. */
err = agent_card_serialno (ctrl, &appname); err = agent_card_serialno (ctrl, &serialno);
if (err) if (err)
{ {
if (opt.verbose) 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)); gpg_strerror (err));
return err; return err;
} }
log_info (_("detected card with S/N: %s\n"), appname); log_info (_("detected card with S/N: %s\n"), serialno);
xfree (appname);
err = agent_card_getattr (ctrl, "APPTYPE", &appname); err = agent_card_getattr (ctrl, "APPTYPE", &appname);
} }
if (err) if (err)
{ {
log_error (_("error getting application type of card: %s\n"), log_error (_("error getting application type of card: %s\n"),
gpg_strerror (err)); gpg_strerror (err));
xfree (serialno);
return err; return err;
} }
if (strcmp (appname, "OPENPGP")) if (strcmp (appname, "OPENPGP"))
{ {
log_info (_("card application `%s' is not supported\n"), appname); log_info (_("card application `%s' is not supported\n"), appname);
xfree (appname); xfree (appname);
xfree (serialno);
return gpg_error (GPG_ERR_NOT_SUPPORTED); return gpg_error (GPG_ERR_NOT_SUPPORTED);
} }
xfree (appname); xfree (appname);
appname = NULL; 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. */ /* Read the public key. */
err = agent_card_readkey (ctrl, "OPENPGP.3", &sbuf); err = agent_card_readkey (ctrl, "OPENPGP.3", &pkbuf);
if (err) if (err)
{ {
if (opt.verbose) if (opt.verbose)
log_info (_("no suitable card key found: %s\n"), gpg_strerror (err)); log_info (_("no suitable card key found: %s\n"), gpg_strerror (err));
xfree (serialno);
return err; return err;
} }
sbuflen = gcry_sexp_canon_len (sbuf, 0, NULL, NULL); pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
err = gcry_sexp_sscan (&pk, NULL, sbuf, sbuflen); err = gcry_sexp_sscan (&s_pk, NULL, pkbuf, pkbuflen);
xfree (sbuf);
if (err) if (err)
{ {
log_error ("failed to build S-Exp from received card key: %s\n", log_error ("failed to build S-Exp from received card key: %s\n",
gpg_strerror (err)); gpg_strerror (err));
xfree (pkbuf);
xfree (serialno);
return err; 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; return 0;
} }
@ -1615,6 +1711,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
gpg_error_t ret_err; gpg_error_t ret_err;
int ret; int ret;
FILE *ctrl_fp = NULL; FILE *ctrl_fp = NULL;
char *cardsn;
/* Prepare buffer stream. */ /* 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 /* First check whether a key is currently available in the card
reader - this should be allowed even without being listed in 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); gcry_sexp_release (key_public);
key_public = NULL; key_public = NULL;
xfree (cardsn);
if (err) if (err)
goto out; goto out;
@ -1740,7 +1838,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
gcry_sexp_release (key_secret); gcry_sexp_release (key_secret);
key_secret = NULL; key_secret = NULL;
err = ssh_send_key_public (key_blobs, key_public); err = ssh_send_key_public (key_blobs, key_public, NULL);
if (err) if (err)
goto out; goto out;
@ -1845,9 +1943,11 @@ data_sign (ctrl_t ctrl, ssh_signature_encoder_t sig_encoder,
sig_value = NULL; sig_value = NULL;
mpis = NULL; mpis = NULL;
ctrl->use_auth_call = 1;
err = agent_pksign_do (ctrl, err = agent_pksign_do (ctrl,
_("Please provide the passphrase " _("Please enter the passphrase "
"for the ssh key `%c':"), &signature_sexp, 0); "for the ssh key%0A %c"), &signature_sexp, 0);
ctrl->use_auth_call = 0;
if (err) if (err)
goto out; 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?? */ 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. */ anything then. */
if ( !agent_key_available (key_grip_raw) ) if ( !agent_key_available (key_grip_raw) )
goto out; /* Yes, key is available. */ goto out; /* Yes, key is available. */
@ -2200,8 +2300,8 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
goto out; goto out;
if ( asprintf (&description, if ( asprintf (&description,
_("Please enter a passphrase to protect%%0A" _("Please enter a passphrase to protect"
"the received secret key%%0A" " the received secret key%%0A"
" %s%%0A" " %s%%0A"
"within gpg-agent's key storage"), "within gpg-agent's key storage"),
comment ? comment : "?") < 0) comment ? comment : "?") < 0)

View File

@ -166,9 +166,7 @@ modify_description (const char *in, const char *comment, char **result)
special = 0; special = 0;
for (i = 0; i < in_len; i++) for (i = 0; i < in_len; i++)
{ {
if (in[i] == '%') if (special)
special = 1;
else if (special)
{ {
special = 0; special = 0;
switch (in[i]) switch (in[i])
@ -190,10 +188,19 @@ modify_description (const char *in, const char *comment, char **result)
out_len += comment_length; out_len += comment_length;
break; 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; break;
} }
} }
else if (in[i] == '%')
special = 1;
else else
{ {
if (out) if (out)

View File

@ -161,9 +161,9 @@ term secret key because it can be visually be better distinguished
from the term public key. from the term public key.
[2] The keygrip is a unique identifier for a key pair, it is [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 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 [3] Even when canonical representation are required we will show the
S-expression here in a more readable representation. S-expression here in a more readable representation.

View File

@ -1,5 +1,5 @@
/* learncard.c - Handle the LEARN command /* 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. * 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 static int
send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context) send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)

View File

@ -110,7 +110,7 @@ static ARGPARSE_OPTS opts[] = {
{ oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" }, { oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" },
{ oProtect, "protect", 256, "protect a private key"}, { oProtect, "protect", 256, "protect a private key"},
{ oUnprotect, "unprotect", 256, "unprotect 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"}, { oShowShadowInfo, "show-shadow-info", 256, "return the shadow info"},
{ oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""}, { oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""},

View File

@ -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 /* Create a shadow key from a public key. We use the shadow protocol
"ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting "ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting
S-expression is returned in an allocated buffer RESULT will point 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 */ S-expressions */
int int
agent_shadow_key (const unsigned char *pubkey, agent_shadow_key (const unsigned char *pubkey,
@ -894,7 +927,7 @@ agent_shadow_key (const unsigned char *pubkey,
s++; s++;
assert (depth == 1); 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 */ prefix, the "shadowed", "t1-v1" as well as some parenthesis */
n = 12 + pubkey_len + 1 + 3+8 + 2+5 + shadow_info_len + 1; n = 12 + pubkey_len + 1 + 3+8 + 2+5 + shadow_info_len + 1;
*result = p = xtrymalloc (n); *result = p = xtrymalloc (n);

View File

@ -1,3 +1,7 @@
2005-02-25 Werner Koch <wk@g10code.com>
* xasprintf.c (xtryasprintf): New.
2005-01-26 Moritz Schulte <moritz@g10code.com> 2005-01-26 Moritz Schulte <moritz@g10code.com>
* Makefile.am (libcommon_a_SOURCES): New source files: estream.c, * Makefile.am (libcommon_a_SOURCES): New source files: estream.c,

View File

@ -131,6 +131,10 @@ const char *default_homedir (void);
freed using xfree. This function simply dies on memory failure, freed using xfree. This function simply dies on memory failure,
thus no extra check is required. */ thus no extra check is required. */
char *xasprintf (const char *fmt, ...) JNLIB_GCC_A_PRINTF(1,2); 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_stdout (const char *s);
const char *print_fname_stdin (const char *s); const char *print_fname_stdin (const char *s);

View File

@ -1,5 +1,5 @@
/* xasprintf.c /* xasprintf.c
* Copyright (C) 2003 Free Software Foundation, Inc. * Copyright (C) 2003, 2005 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -42,3 +42,21 @@ xasprintf (const char *fmt, ...)
free (buf); free (buf);
return p; 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;
}

View File

@ -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> 2005-02-24 Werner Koch <wk@g10code.com>
* app.c (app_getattr): Return APPTYPE or SERIALNO type even if the * app.c (app_getattr): Return APPTYPE or SERIALNO type even if the

View File

@ -794,6 +794,8 @@ get_public_key (app_t app, int keyno)
const unsigned char *keydata, *m, *e; const unsigned char *keydata, *m, *e;
size_t buflen, keydatalen, mlen, elen; size_t buflen, keydatalen, mlen, elen;
gcry_sexp_t sexp; gcry_sexp_t sexp;
unsigned char *mbuf = NULL;
unsigned char *ebuf = NULL;
if (keyno < 1 || keyno > 3) if (keyno < 1 || keyno > 3)
return gpg_error (GPG_ERR_INV_ID); 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")); log_error (_("response does not contain the RSA modulus\n"));
goto leave; goto leave;
} }
e = find_tlv (keydata, keydatalen, 0x0082, &elen); e = find_tlv (keydata, keydatalen, 0x0082, &elen);
if (!e) if (!e)
@ -844,10 +847,38 @@ get_public_key (app_t app, int keyno)
goto leave; 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, err = gcry_sexp_build (&sexp, NULL,
"(public-key (rsa (n %b) (e %b)))", "(public-key (rsa (n %b) (e %b)))",
(int)mlen, m,(int)elen, e); (int)mlen, m,(int)elen, e);
if (err) if (err)
{ {
log_error ("error formatting the key into an S-expression: %s\n", 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; app->app_local->pk[keyno].read_done = 1;
xfree (buffer); xfree (buffer);
xfree (mbuf);
xfree (ebuf);
return 0; return 0;
} }
#endif /* GNUPG_MAJOR_VERSION > 1 */ #endif /* GNUPG_MAJOR_VERSION > 1 */
@ -1557,7 +1590,15 @@ do_sign (app_t app, const char *keyidstr, int hashalgo,
if (!keyidstr || !*keyidstr) if (!keyidstr || !*keyidstr)
return gpg_error (GPG_ERR_INV_VALUE); 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); return gpg_error (GPG_ERR_INV_VALUE);
/* Check whether an OpenPGP card of any version has been requested. */ /* 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 /* Compute a digital signature using the INTERNAL AUTHENTICATE command
on INDATA which is expected to be the raw message digest. For this on INDATA which is expected to be the raw message digest. For this
application the KEYIDSTR consists of the serialnumber and the 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 Note that this fucntion may return the error code
GPG_ERR_WRONG_CARD to indicate that the card currently present does 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); return gpg_error (GPG_ERR_INV_VALUE);
/* Check whether an OpenPGP card of any version has been requested. */ /* Check whether an OpenPGP card of any version has been requested. */
if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12)) if (!strcmp (keyidstr, "OPENPGP.3"))
return gpg_error (GPG_ERR_INV_ID);
for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
; ;
if (n != 32) else if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
return gpg_error (GPG_ERR_INV_ID); 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 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++) for (s=keyidstr, n=0; n < 16; s += 2, n++)
tmp_sn[n] = xtoi_2 (s); tmp_sn[n] = xtoi_2 (s);
if (app->serialnolen != 16) if (app->serialnolen != 16)
return gpg_error (GPG_ERR_INV_CARD); return gpg_error (GPG_ERR_INV_CARD);
if (memcmp (app->serialno, tmp_sn, 16)) if (memcmp (app->serialno, tmp_sn, 16))
return gpg_error (GPG_ERR_WRONG_CARD); return gpg_error (GPG_ERR_WRONG_CARD);
}
/* If a fingerprint has been specified check it against the one on /* If a fingerprint has been specified check it against the one on
the card. This is allows for a meaningful error message in case the card. This is allows for a meaningful error message in case

View File

@ -314,7 +314,6 @@ app_getattr (APP app, CTRL ctrl, const char *name)
} }
if (name && !strcmp (name, "SERIALNO")) if (name && !strcmp (name, "SERIALNO"))
{ {
char *serial_and_stamp;
char *serial; char *serial;
time_t stamp; time_t stamp;
int rc; int rc;
@ -322,15 +321,8 @@ app_getattr (APP app, CTRL ctrl, const char *name)
rc = app_get_serial_and_stamp (app, &serial, &stamp); rc = app_get_serial_and_stamp (app, &serial, &stamp);
if (rc) if (rc)
return rc; return rc;
rc = asprintf (&serial_and_stamp, "%s %lu", send_status_info (ctrl, "SERIALNO", serial, strlen (serial), NULL, 0);
serial, (unsigned long)stamp);
rc = (rc < 0)? gpg_error_from_errno (errno) : 0;
xfree (serial); 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; return 0;
} }

View File

@ -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> 2005-02-24 Werner Koch <wk@g10code.com>
* gpg-connect-agent.c: New. * gpg-connect-agent.c: New.

View File

@ -24,6 +24,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <ctype.h>
#include <assuan.h> #include <assuan.h>
#include "i18n.h" #include "i18n.h"
@ -40,7 +41,8 @@ enum cmd_and_opt_values
oVerbose = 'v', oVerbose = 'v',
oNoVerbose = 500, oNoVerbose = 500,
oHomedir oHomedir,
oHex
}; };
@ -52,6 +54,7 @@ static ARGPARSE_OPTS opts[] =
{ oVerbose, "verbose", 0, N_("verbose") }, { oVerbose, "verbose", 0, N_("verbose") },
{ oQuiet, "quiet", 0, N_("quiet") }, { oQuiet, "quiet", 0, N_("quiet") },
{ oHex, "hex", 0, N_("print data out hex encoded") },
/* hidden options */ /* hidden options */
{ oNoVerbose, "no-verbose", 0, "@"}, { oNoVerbose, "no-verbose", 0, "@"},
@ -66,7 +69,7 @@ struct
int verbose; /* Verbosity level. */ int verbose; /* Verbosity level. */
int quiet; /* Be extra quiet. */ int quiet; /* Be extra quiet. */
const char *homedir; /* Configuration directory name */ const char *homedir; /* Configuration directory name */
int hex; /* Print data lines in hex format. */
} opt; } opt;
@ -155,6 +158,7 @@ main (int argc, char **argv)
case oVerbose: opt.verbose++; break; case oVerbose: opt.verbose++; break;
case oNoVerbose: opt.verbose = 0; break; case oNoVerbose: opt.verbose = 0; break;
case oHomedir: opt.homedir = pargs.r.ret_str; break; case oHomedir: opt.homedir = pargs.r.ret_str; break;
case oHex: opt.hex = 1; break;
default: pargs.err = 2; break; default: pargs.err = 2; break;
} }
@ -220,6 +224,7 @@ read_and_print_response (assuan_context_t ctx)
char *line; char *line;
int linelen; int linelen;
assuan_error_t rc; assuan_error_t rc;
int i, j;
for (;;) for (;;)
{ {
@ -234,8 +239,42 @@ read_and_print_response (assuan_context_t ctx)
if (linelen >= 1 if (linelen >= 1
&& line[0] == 'D' && line[1] == ' ') && line[0] == 'D' && line[1] == ' ')
{ {
fwrite (line, linelen, 1, stdout); if (opt.hex)
putchar ('\n'); {
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 else if (linelen >= 1
&& line[0] == 'S' && line[0] == 'S'

View File

@ -53,6 +53,12 @@ gcry_xmalloc (size_t n)
return p; return p;
} }
char *
gcry_strdup (const char *string)
{
return malloc (strlen (string)+1);
}
void * void *
gcry_realloc (void *a, size_t n) gcry_realloc (void *a, size_t n)