mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
* 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:
parent
1f1f28555a
commit
faef9f929b
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
|
@ -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\""},
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
10
scd/app.c
10
scd/app.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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'
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user