mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-21 14:47:03 +01:00
Support a confirm flag for ssh.
This implements the suggestion from bug#1349. With this change the fingerprint of the ssh key is also displayed in the pinentry prompts.
This commit is contained in:
parent
172c30bc1c
commit
d4c7a55958
2
NEWS
2
NEWS
@ -5,6 +5,8 @@ Noteworthy changes in version 2.0.18 (unreleased)
|
|||||||
|
|
||||||
* Bug fix for newer versions of Libgcrypt.
|
* Bug fix for newer versions of Libgcrypt.
|
||||||
|
|
||||||
|
* Support the SSH confirm flag.
|
||||||
|
|
||||||
* Improved dirmngr/gpgsm interaction for OCSP.
|
* Improved dirmngr/gpgsm interaction for OCSP.
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,18 @@
|
|||||||
|
2011-08-04 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* command-ssh.c (ssh_identity_register): Display the ssh
|
||||||
|
fingerprint in the prompt.
|
||||||
|
(add_control_entry): Add arg FMTFPR and use it as comment in
|
||||||
|
sshcontrol.
|
||||||
|
(confirm_flag_from_sshcontrol): New.
|
||||||
|
(data_sign): Ask for confirmaton if requested.
|
||||||
|
(search_control_file): Add new arg R_CONFIRM and enhance parser.
|
||||||
|
* findkey.c (agent_raw_key_from_file): New.
|
||||||
|
(modify_description): Add format letter %F.
|
||||||
|
|
||||||
|
* findkey.c (agent_key_from_file): Simplify comment extraction by
|
||||||
|
using gcry_sexp_nth_string.
|
||||||
|
|
||||||
2011-08-04 Werner Koch <wk@g10code.com>
|
2011-08-04 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* genkey.c (check_passphrase_pattern): Use gpg_strerror.
|
* genkey.c (check_passphrase_pattern): Use gpg_strerror.
|
||||||
|
@ -117,7 +117,7 @@ struct
|
|||||||
#define DBG_CACHE_VALUE 64 /* debug the caching */
|
#define DBG_CACHE_VALUE 64 /* debug the caching */
|
||||||
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
|
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
|
||||||
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
|
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
|
||||||
#define DBG_ASSUAN_VALUE 1024
|
#define DBG_ASSUAN_VALUE 1024
|
||||||
|
|
||||||
#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
|
#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
|
||||||
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
|
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
|
||||||
@ -130,14 +130,14 @@ struct server_local_s;
|
|||||||
struct scd_local_s;
|
struct scd_local_s;
|
||||||
|
|
||||||
/* Collection of data per session (aka connection). */
|
/* Collection of data per session (aka connection). */
|
||||||
struct server_control_s
|
struct server_control_s
|
||||||
{
|
{
|
||||||
/* Private data used to fire up the connection thread. We use this
|
/* Private data used to fire up the connection thread. We use this
|
||||||
structure do avoid an extra allocation for just a few bytes. */
|
structure do avoid an extra allocation for just a few bytes. */
|
||||||
struct {
|
struct {
|
||||||
gnupg_fd_t fd;
|
gnupg_fd_t fd;
|
||||||
} thread_startup;
|
} thread_startup;
|
||||||
|
|
||||||
/* Private data of the server (command.c). */
|
/* Private data of the server (command.c). */
|
||||||
struct server_local_s *server_local;
|
struct server_local_s *server_local;
|
||||||
|
|
||||||
@ -164,7 +164,7 @@ struct server_control_s
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct pin_entry_info_s
|
struct pin_entry_info_s
|
||||||
{
|
{
|
||||||
int min_digits; /* min. number of digits required or 0 for freeform entry */
|
int min_digits; /* min. number of digits required or 0 for freeform entry */
|
||||||
int max_digits; /* max. number of allowed digits allowed*/
|
int max_digits; /* max. number of allowed digits allowed*/
|
||||||
@ -179,7 +179,7 @@ struct pin_entry_info_s
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PRIVATE_KEY_UNKNOWN = 0,
|
PRIVATE_KEY_UNKNOWN = 0,
|
||||||
PRIVATE_KEY_CLEAR = 1,
|
PRIVATE_KEY_CLEAR = 1,
|
||||||
@ -189,7 +189,7 @@ enum
|
|||||||
|
|
||||||
|
|
||||||
/* Values for the cache_mode arguments. */
|
/* Values for the cache_mode arguments. */
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
CACHE_MODE_IGNORE = 0, /* Special mode to bypass the cache. */
|
CACHE_MODE_IGNORE = 0, /* Special mode to bypass the cache. */
|
||||||
CACHE_MODE_ANY, /* Any mode except ignore matches. */
|
CACHE_MODE_ANY, /* Any mode except ignore matches. */
|
||||||
@ -227,14 +227,16 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t);
|
|||||||
/*-- findkey.c --*/
|
/*-- findkey.c --*/
|
||||||
int agent_write_private_key (const unsigned char *grip,
|
int agent_write_private_key (const unsigned char *grip,
|
||||||
const void *buffer, size_t length, int force);
|
const void *buffer, size_t length, int force);
|
||||||
gpg_error_t agent_key_from_file (ctrl_t ctrl,
|
gpg_error_t agent_key_from_file (ctrl_t ctrl,
|
||||||
const char *desc_text,
|
const char *desc_text,
|
||||||
const unsigned char *grip,
|
const unsigned char *grip,
|
||||||
unsigned char **shadow_info,
|
unsigned char **shadow_info,
|
||||||
cache_mode_t cache_mode,
|
cache_mode_t cache_mode,
|
||||||
lookup_ttl_t lookup_ttl,
|
lookup_ttl_t lookup_ttl,
|
||||||
gcry_sexp_t *result);
|
gcry_sexp_t *result);
|
||||||
gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
|
gpg_error_t agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
|
||||||
|
gcry_sexp_t *result);
|
||||||
|
gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
|
||||||
const unsigned char *grip,
|
const unsigned char *grip,
|
||||||
gcry_sexp_t *result);
|
gcry_sexp_t *result);
|
||||||
int agent_key_available (const unsigned char *grip);
|
int agent_key_available (const unsigned char *grip);
|
||||||
@ -285,7 +287,7 @@ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
|||||||
|
|
||||||
/*-- genkey.c --*/
|
/*-- genkey.c --*/
|
||||||
int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent);
|
int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent);
|
||||||
int agent_genkey (ctrl_t ctrl,
|
int agent_genkey (ctrl_t ctrl,
|
||||||
const char *keyparam, size_t keyparmlen, membuf_t *outbuf);
|
const char *keyparam, size_t keyparmlen, membuf_t *outbuf);
|
||||||
int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);
|
int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);
|
||||||
|
|
||||||
@ -294,7 +296,7 @@ unsigned long get_standard_s2k_count (void);
|
|||||||
int agent_protect (const unsigned char *plainkey, const char *passphrase,
|
int agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||||
unsigned char **result, size_t *resultlen);
|
unsigned char **result, size_t *resultlen);
|
||||||
int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
||||||
gnupg_isotime_t protected_at,
|
gnupg_isotime_t protected_at,
|
||||||
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);
|
unsigned char *make_shadow_info (const char *serialno, const char *idstring);
|
||||||
@ -303,7 +305,7 @@ int agent_shadow_key (const unsigned char *pubkey,
|
|||||||
unsigned char **result);
|
unsigned char **result);
|
||||||
int agent_get_shadow_info (const unsigned char *shadowkey,
|
int agent_get_shadow_info (const unsigned char *shadowkey,
|
||||||
unsigned char const **shadow_info);
|
unsigned char const **shadow_info);
|
||||||
gpg_error_t parse_shadow_info (const unsigned char *shadow_info,
|
gpg_error_t parse_shadow_info (const unsigned char *shadow_info,
|
||||||
char **r_hexsn, char **r_idstr);
|
char **r_hexsn, char **r_idstr);
|
||||||
|
|
||||||
|
|
||||||
@ -317,7 +319,7 @@ void agent_reload_trustlist (void);
|
|||||||
|
|
||||||
|
|
||||||
/*-- divert-scd.c --*/
|
/*-- divert-scd.c --*/
|
||||||
int divert_pksign (ctrl_t ctrl,
|
int divert_pksign (ctrl_t ctrl,
|
||||||
const unsigned char *digest, size_t digestlen, int algo,
|
const unsigned char *digest, size_t digestlen, int algo,
|
||||||
const unsigned char *shadow_info, unsigned char **r_sig);
|
const unsigned char *shadow_info, unsigned char **r_sig);
|
||||||
int divert_pkdecrypt (ctrl_t ctrl,
|
int divert_pkdecrypt (ctrl_t ctrl,
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
|
|
||||||
#include "estream.h"
|
#include "estream.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
#include "../common/ssh-utils.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -711,18 +713,25 @@ open_control_file (FILE **r_fp, int append)
|
|||||||
/* Search the file at stream FP from the beginning until a matching
|
/* Search the file at stream FP from the beginning until a matching
|
||||||
HEXGRIP is found; return success in this case and store true at
|
HEXGRIP is found; return success in this case and store true at
|
||||||
DISABLED if the found key has been disabled. If R_TTL is not NULL
|
DISABLED if the found key has been disabled. If R_TTL is not NULL
|
||||||
a specified TTL for that key is stored there. */
|
a specified TTL for that key is stored there. If R_CONFIRM is not
|
||||||
|
NULL it is set to 1 if the key has the confirm flag set. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
search_control_file (FILE *fp, const char *hexgrip,
|
search_control_file (FILE *fp, const char *hexgrip,
|
||||||
int *r_disabled, int *r_ttl)
|
int *r_disabled, int *r_ttl, int *r_confirm)
|
||||||
{
|
{
|
||||||
int c, i;
|
int c, i, n;
|
||||||
char *p, *pend, line[256];
|
char *p, *pend, line[256];
|
||||||
long ttl;
|
long ttl;
|
||||||
|
int lnr = 0;
|
||||||
|
const char fname[] = "sshcontrol";
|
||||||
|
|
||||||
assert (strlen (hexgrip) == 40 );
|
assert (strlen (hexgrip) == 40 );
|
||||||
|
|
||||||
rewind (fp);
|
if (r_confirm)
|
||||||
|
*r_confirm = 0;
|
||||||
|
|
||||||
|
fseek (fp, 0, SEEK_SET);
|
||||||
|
clearerr (fp);
|
||||||
*r_disabled = 0;
|
*r_disabled = 0;
|
||||||
next_line:
|
next_line:
|
||||||
do
|
do
|
||||||
@ -733,6 +742,7 @@ search_control_file (FILE *fp, const char *hexgrip,
|
|||||||
return gpg_error (GPG_ERR_EOF);
|
return gpg_error (GPG_ERR_EOF);
|
||||||
return gpg_error (gpg_err_code_from_errno (errno));
|
return gpg_error (gpg_err_code_from_errno (errno));
|
||||||
}
|
}
|
||||||
|
lnr++;
|
||||||
|
|
||||||
if (!*line || line[strlen(line)-1] != '\n')
|
if (!*line || line[strlen(line)-1] != '\n')
|
||||||
{
|
{
|
||||||
@ -762,7 +772,7 @@ search_control_file (FILE *fp, const char *hexgrip,
|
|||||||
goto next_line;
|
goto next_line;
|
||||||
if (i != 40 || !(spacep (p) || *p == '\n'))
|
if (i != 40 || !(spacep (p) || *p == '\n'))
|
||||||
{
|
{
|
||||||
log_error ("invalid formatted line in ssh control file\n");
|
log_error ("invalid formatted line in `%s', line %d\n", fname, lnr);
|
||||||
return gpg_error (GPG_ERR_BAD_DATA);
|
return gpg_error (GPG_ERR_BAD_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -770,13 +780,37 @@ search_control_file (FILE *fp, const char *hexgrip,
|
|||||||
p = pend;
|
p = pend;
|
||||||
if (!(spacep (p) || *p == '\n') || ttl < -1)
|
if (!(spacep (p) || *p == '\n') || ttl < -1)
|
||||||
{
|
{
|
||||||
log_error ("invalid TTL value in ssh control file; assuming 0\n");
|
log_error ("invalid TTL value in `%s', line %d; assuming 0\n",
|
||||||
|
fname, lnr);
|
||||||
ttl = 0;
|
ttl = 0;
|
||||||
}
|
}
|
||||||
if (r_ttl)
|
if (r_ttl)
|
||||||
*r_ttl = ttl;
|
*r_ttl = ttl;
|
||||||
|
|
||||||
/* Here is the place to parse flags if we need them. */
|
/* Now check for key-value pairs of the form NAME[=VALUE]. */
|
||||||
|
while (*p)
|
||||||
|
{
|
||||||
|
for (; spacep (p) && *p != '\n'; p++)
|
||||||
|
;
|
||||||
|
if (!*p || *p == '\n')
|
||||||
|
break;
|
||||||
|
n = strcspn (p, "= \t\n");
|
||||||
|
if (p[n] == '=')
|
||||||
|
{
|
||||||
|
log_error ("assigning a value to a flag is not yet supported; "
|
||||||
|
"in `%s', line %d; flag ignored\n", fname, lnr);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
else if (n == 7 && !memcmp (p, "confirm", 7))
|
||||||
|
{
|
||||||
|
if (r_confirm)
|
||||||
|
*r_confirm = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_error ("invalid flag `%.*s' in `%s', line %d; ignored\n",
|
||||||
|
n, p, fname, lnr);
|
||||||
|
p += n;
|
||||||
|
}
|
||||||
|
|
||||||
return 0; /* Okay: found it. */
|
return 0; /* Okay: found it. */
|
||||||
}
|
}
|
||||||
@ -785,11 +819,12 @@ search_control_file (FILE *fp, const char *hexgrip,
|
|||||||
|
|
||||||
/* Add an entry to the control file to mark the key with the keygrip
|
/* Add an entry to the control file to mark the key with the keygrip
|
||||||
HEXGRIP as usable for SSH; i.e. it will be returned when ssh asks
|
HEXGRIP as usable for SSH; i.e. it will be returned when ssh asks
|
||||||
for it. This function is in general used to add a key received
|
for it. FMTFPR is the fingerprint string. This function is in
|
||||||
through the ssh-add function. We can assume that the user wants to
|
general used to add a key received through the ssh-add function.
|
||||||
allow ssh using this key. */
|
We can assume that the user wants to allow ssh using this key. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
add_control_entry (ctrl_t ctrl, const char *hexgrip, int ttl)
|
add_control_entry (ctrl_t ctrl, const char *hexgrip, const char *fmtfpr,
|
||||||
|
int ttl, int confirm)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@ -801,7 +836,7 @@ add_control_entry (ctrl_t ctrl, const char *hexgrip, int ttl)
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err = search_control_file (fp, hexgrip, &disabled, NULL);
|
err = search_control_file (fp, hexgrip, &disabled, NULL, NULL);
|
||||||
if (err && gpg_err_code(err) == GPG_ERR_EOF)
|
if (err && gpg_err_code(err) == GPG_ERR_EOF)
|
||||||
{
|
{
|
||||||
struct tm *tp;
|
struct tm *tp;
|
||||||
@ -810,10 +845,12 @@ add_control_entry (ctrl_t ctrl, const char *hexgrip, int ttl)
|
|||||||
/* Not yet in the file - add it. Because the file has been
|
/* Not yet in the file - add it. Because the file has been
|
||||||
opened in append mode, we simply need to write to it. */
|
opened in append mode, we simply need to write to it. */
|
||||||
tp = localtime (&atime);
|
tp = localtime (&atime);
|
||||||
fprintf (fp, "# Key added on %04d-%02d-%02d %02d:%02d:%02d\n%s %d\n",
|
fprintf (fp, ("# Key added on: %04d-%02d-%02d %02d:%02d:%02d\n"
|
||||||
|
"# Fingerprint: %s\n"
|
||||||
|
"%s %d%s\n"),
|
||||||
1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
|
1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
|
||||||
tp->tm_hour, tp->tm_min, tp->tm_sec,
|
tp->tm_hour, tp->tm_min, tp->tm_sec,
|
||||||
hexgrip, ttl);
|
fmtfpr, hexgrip, ttl, confirm? " confirm":"");
|
||||||
|
|
||||||
}
|
}
|
||||||
fclose (fp);
|
fclose (fp);
|
||||||
@ -834,7 +871,7 @@ ttl_from_sshcontrol (const char *hexgrip)
|
|||||||
if (open_control_file (&fp, 0))
|
if (open_control_file (&fp, 0))
|
||||||
return 0; /* Error: Use the global default TTL. */
|
return 0; /* Error: Use the global default TTL. */
|
||||||
|
|
||||||
if (search_control_file (fp, hexgrip, &disabled, &ttl)
|
if (search_control_file (fp, hexgrip, &disabled, &ttl, NULL)
|
||||||
|| disabled)
|
|| disabled)
|
||||||
ttl = 0; /* Use the global default if not found or disabled. */
|
ttl = 0; /* Use the global default if not found or disabled. */
|
||||||
|
|
||||||
@ -844,6 +881,30 @@ ttl_from_sshcontrol (const char *hexgrip)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Scan the sshcontrol file and return the confirm flag. */
|
||||||
|
static int
|
||||||
|
confirm_flag_from_sshcontrol (const char *hexgrip)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
int disabled, confirm;
|
||||||
|
|
||||||
|
if (!hexgrip || strlen (hexgrip) != 40)
|
||||||
|
return 1; /* Wrong input: Better ask for confirmation. */
|
||||||
|
|
||||||
|
if (open_control_file (&fp, 0))
|
||||||
|
return 1; /* Error: Better ask for confirmation. */
|
||||||
|
|
||||||
|
if (search_control_file (fp, hexgrip, &disabled, NULL, &confirm)
|
||||||
|
|| disabled)
|
||||||
|
confirm = 0; /* If not found or disabled, there is no reason to
|
||||||
|
ask for confirmation. */
|
||||||
|
|
||||||
|
fclose (fp);
|
||||||
|
|
||||||
|
return confirm;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1583,6 +1644,7 @@ ssh_key_grip (gcry_sexp_t key, unsigned char *buffer)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Converts the secret key KEY_SECRET into a public key, storing it in
|
/* Converts the secret key KEY_SECRET into a public key, storing it in
|
||||||
KEY_PUBLIC. SPEC is the according key specification. Returns zero
|
KEY_PUBLIC. SPEC is the according key specification. Returns zero
|
||||||
on success or an error code. */
|
on success or an error code. */
|
||||||
@ -1904,7 +1966,7 @@ ssh_handler_request_identities (ctrl_t ctrl,
|
|||||||
hexgrip[40] = 0;
|
hexgrip[40] = 0;
|
||||||
if ( strlen (hexgrip) != 40 )
|
if ( strlen (hexgrip) != 40 )
|
||||||
continue;
|
continue;
|
||||||
if (search_control_file (ctrl_fp, hexgrip, &disabled, NULL)
|
if (search_control_file (ctrl_fp, hexgrip, &disabled, NULL, NULL)
|
||||||
|| disabled)
|
|| disabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -2039,14 +2101,60 @@ data_sign (ctrl_t ctrl, ssh_signature_encoder_t sig_encoder,
|
|||||||
const char *elems;
|
const char *elems;
|
||||||
size_t elems_n;
|
size_t elems_n;
|
||||||
gcry_mpi_t *mpis = NULL;
|
gcry_mpi_t *mpis = NULL;
|
||||||
|
char hexgrip[40+1];
|
||||||
|
|
||||||
*sig = NULL;
|
*sig = NULL;
|
||||||
*sig_n = 0;
|
*sig_n = 0;
|
||||||
|
|
||||||
|
/* Quick check to see whether we have a valid keygrip and convert it
|
||||||
|
to hex. */
|
||||||
|
if (!ctrl->have_keygrip)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
bin2hex (ctrl->keygrip, 20, hexgrip);
|
||||||
|
|
||||||
|
/* Ask for confirmation if needed. */
|
||||||
|
if (confirm_flag_from_sshcontrol (hexgrip))
|
||||||
|
{
|
||||||
|
gcry_sexp_t key;
|
||||||
|
char *fpr, *prompt;
|
||||||
|
char *comment = NULL;
|
||||||
|
|
||||||
|
err = agent_raw_key_from_file (ctrl, ctrl->keygrip, &key);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
err = ssh_get_fingerprint_string (key, &fpr);
|
||||||
|
if (!err)
|
||||||
|
{
|
||||||
|
gcry_sexp_t tmpsxp = gcry_sexp_find_token (key, "comment", 0);
|
||||||
|
if (tmpsxp)
|
||||||
|
comment = gcry_sexp_nth_string (tmpsxp, 1);
|
||||||
|
gcry_sexp_release (tmpsxp);
|
||||||
|
}
|
||||||
|
gcry_sexp_release (key);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
prompt = xtryasprintf (_("An ssh process requested the use of key%%0A"
|
||||||
|
" %s%%0A"
|
||||||
|
" (%s)%%0A"
|
||||||
|
"Do you want to allow this?"),
|
||||||
|
fpr, comment? comment:"");
|
||||||
|
xfree (fpr);
|
||||||
|
gcry_free (comment);
|
||||||
|
err = agent_get_confirmation (ctrl, prompt, _("Allow"), _("Deny"), 0);
|
||||||
|
xfree (prompt);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create signature. */
|
||||||
ctrl->use_auth_call = 1;
|
ctrl->use_auth_call = 1;
|
||||||
err = agent_pksign_do (ctrl,
|
err = agent_pksign_do (ctrl,
|
||||||
_("Please enter the passphrase "
|
_("Please enter the passphrase "
|
||||||
"for the ssh key%0A %c"), &signature_sexp,
|
"for the ssh key%%0A %F%%0A (%c)"),
|
||||||
|
&signature_sexp,
|
||||||
CACHE_MODE_SSH, ttl_from_sshcontrol);
|
CACHE_MODE_SSH, ttl_from_sshcontrol);
|
||||||
ctrl->use_auth_call = 0;
|
ctrl->use_auth_call = 0;
|
||||||
if (err)
|
if (err)
|
||||||
@ -2365,7 +2473,7 @@ reenter_compare_cb (struct pin_entry_info_s *pi)
|
|||||||
our key storage, don't do anything. When entering a new key also
|
our key storage, don't do anything. When entering a new key also
|
||||||
add an entry to the sshcontrol file. */
|
add an entry to the sshcontrol file. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
|
ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl, int confirm)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
unsigned char key_grip_raw[20];
|
unsigned char key_grip_raw[20];
|
||||||
@ -2375,6 +2483,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
|
|||||||
char *description = NULL;
|
char *description = NULL;
|
||||||
const char *description2 = _("Please re-enter this passphrase");
|
const char *description2 = _("Please re-enter this passphrase");
|
||||||
char *comment = NULL;
|
char *comment = NULL;
|
||||||
|
char *key_fpr = NULL;
|
||||||
const char *initial_errtext = NULL;
|
const char *initial_errtext = NULL;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct pin_entry_info_s *pi = NULL, *pi2;
|
struct pin_entry_info_s *pi = NULL, *pi2;
|
||||||
@ -2388,6 +2497,9 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
|
|||||||
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. */
|
||||||
|
|
||||||
|
err = ssh_get_fingerprint_string (key, &key_fpr);
|
||||||
|
if (err)
|
||||||
|
goto out;
|
||||||
|
|
||||||
err = ssh_key_extract_comment (key, &comment);
|
err = ssh_key_extract_comment (key, &comment);
|
||||||
if (err)
|
if (err)
|
||||||
@ -2397,8 +2509,9 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
|
|||||||
_("Please enter a passphrase to protect"
|
_("Please enter a passphrase to protect"
|
||||||
" the received secret key%%0A"
|
" the received secret key%%0A"
|
||||||
" %s%%0A"
|
" %s%%0A"
|
||||||
|
" %s%%0A"
|
||||||
"within gpg-agent's key storage"),
|
"within gpg-agent's key storage"),
|
||||||
comment ? comment : "?") < 0)
|
key_fpr, comment ? comment : "") < 0)
|
||||||
{
|
{
|
||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
goto out;
|
goto out;
|
||||||
@ -2455,7 +2568,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* And add an entry to the sshcontrol file. */
|
/* And add an entry to the sshcontrol file. */
|
||||||
err = add_control_entry (ctrl, key_grip, ttl);
|
err = add_control_entry (ctrl, key_grip, key_fpr, ttl, confirm);
|
||||||
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -2464,6 +2577,7 @@ ssh_identity_register (ctrl_t ctrl, gcry_sexp_t key, int ttl)
|
|||||||
xfree (pi);
|
xfree (pi);
|
||||||
xfree (buffer);
|
xfree (buffer);
|
||||||
xfree (comment);
|
xfree (comment);
|
||||||
|
xfree (key_fpr);
|
||||||
xfree (description);
|
xfree (description);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@ -2548,9 +2662,7 @@ ssh_handler_add_identity (ctrl_t ctrl, estream_t request, estream_t response)
|
|||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* FIXME: are constraints used correctly? */
|
err = ssh_identity_register (ctrl, key, ttl, confirm);
|
||||||
|
|
||||||
err = ssh_identity_register (ctrl, key, ttl);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
|
155
agent/findkey.c
155
agent/findkey.c
@ -1,6 +1,6 @@
|
|||||||
/* findkey.c - Locate the secret key
|
/* findkey.c - Locate the secret key
|
||||||
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
|
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
|
||||||
* 2007 Free Software Foundation, Inc.
|
* 2010, 2011 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -33,13 +33,14 @@
|
|||||||
|
|
||||||
#include "agent.h"
|
#include "agent.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
#include "../common/ssh-utils.h"
|
||||||
|
|
||||||
#ifndef O_BINARY
|
#ifndef O_BINARY
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Helper to pass data to the check callback of the unprotect function. */
|
/* Helper to pass data to the check callback of the unprotect function. */
|
||||||
struct try_unprotect_arg_s
|
struct try_unprotect_arg_s
|
||||||
{
|
{
|
||||||
ctrl_t ctrl;
|
ctrl_t ctrl;
|
||||||
const unsigned char *protected_key;
|
const unsigned char *protected_key;
|
||||||
@ -60,7 +61,7 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
FILE *fp;
|
FILE *fp;
|
||||||
char hexgrip[40+4+1];
|
char hexgrip[40+4+1];
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
bin2hex (grip, 20, hexgrip);
|
||||||
strcpy (hexgrip+40, ".key");
|
strcpy (hexgrip+40, ".key");
|
||||||
|
|
||||||
@ -80,9 +81,9 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
then use fdopen to obtain a stream. */
|
then use fdopen to obtain a stream. */
|
||||||
fd = open (fname, force? (O_CREAT | O_TRUNC | O_WRONLY | O_BINARY)
|
fd = open (fname, force? (O_CREAT | O_TRUNC | O_WRONLY | O_BINARY)
|
||||||
: (O_CREAT | O_EXCL | O_WRONLY | O_BINARY),
|
: (O_CREAT | O_EXCL | O_WRONLY | O_BINARY),
|
||||||
S_IRUSR | S_IWUSR
|
S_IRUSR | S_IWUSR
|
||||||
#ifndef HAVE_W32_SYSTEM
|
#ifndef HAVE_W32_SYSTEM
|
||||||
| S_IRGRP
|
| S_IRGRP
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
@ -91,15 +92,15 @@ agent_write_private_key (const unsigned char *grip,
|
|||||||
{
|
{
|
||||||
fp = fdopen (fd, "wb");
|
fp = fdopen (fd, "wb");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
int save_e = errno;
|
int save_e = errno;
|
||||||
close (fd);
|
close (fd);
|
||||||
errno = save_e;
|
errno = save_e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!fp)
|
if (!fp)
|
||||||
{
|
{
|
||||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
||||||
log_error ("can't create `%s': %s\n", fname, strerror (errno));
|
log_error ("can't create `%s': %s\n", fname, strerror (errno));
|
||||||
xfree (fname);
|
xfree (fname);
|
||||||
@ -168,7 +169,7 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
|
|||||||
if (strcmp (now, tmptime) > 0 )
|
if (strcmp (now, tmptime) > 0 )
|
||||||
{
|
{
|
||||||
/* Passphrase "expired". */
|
/* Passphrase "expired". */
|
||||||
desc = xtryasprintf
|
desc = xtryasprintf
|
||||||
(_("This passphrase has not been changed%%0A"
|
(_("This passphrase has not been changed%%0A"
|
||||||
"since %.4s-%.2s-%.2s. Please change it now."),
|
"since %.4s-%.2s-%.2s. Please change it now."),
|
||||||
protected_at, protected_at+4, protected_at+6);
|
protected_at, protected_at+4, protected_at+6);
|
||||||
@ -209,12 +210,14 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
|
|||||||
|
|
||||||
%% - Replaced by a single %
|
%% - Replaced by a single %
|
||||||
%c - Replaced by the content of COMMENT.
|
%c - Replaced by the content of COMMENT.
|
||||||
|
%F - Replaced by an ssh style fingerprint computed from KEY.
|
||||||
|
|
||||||
The functions returns 0 on success or an error code. On success a
|
The functions returns 0 on success or an error code. On success a
|
||||||
newly allocated string is stored at the address of RESULT.
|
newly allocated string is stored at the address of RESULT.
|
||||||
*/
|
*/
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
modify_description (const char *in, const char *comment, char **result)
|
modify_description (const char *in, const char *comment, const gcry_sexp_t key,
|
||||||
|
char **result)
|
||||||
{
|
{
|
||||||
size_t comment_length;
|
size_t comment_length;
|
||||||
size_t in_len;
|
size_t in_len;
|
||||||
@ -222,6 +225,7 @@ modify_description (const char *in, const char *comment, char **result)
|
|||||||
char *out;
|
char *out;
|
||||||
size_t i;
|
size_t i;
|
||||||
int special, pass;
|
int special, pass;
|
||||||
|
char *ssh_fpr = NULL;
|
||||||
|
|
||||||
comment_length = strlen (comment);
|
comment_length = strlen (comment);
|
||||||
in_len = strlen (in);
|
in_len = strlen (in);
|
||||||
@ -257,6 +261,18 @@ modify_description (const char *in, const char *comment, char **result)
|
|||||||
out_len += comment_length;
|
out_len += comment_length;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'F': /* SSH style fingerprint. */
|
||||||
|
if (!ssh_fpr && key)
|
||||||
|
ssh_get_fingerprint_string (key, &ssh_fpr);
|
||||||
|
if (ssh_fpr)
|
||||||
|
{
|
||||||
|
if (out)
|
||||||
|
out = stpcpy (out, ssh_fpr);
|
||||||
|
else
|
||||||
|
out_len += strlen (ssh_fpr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default: /* Invalid special sequences are kept as they are. */
|
default: /* Invalid special sequences are kept as they are. */
|
||||||
if (out)
|
if (out)
|
||||||
{
|
{
|
||||||
@ -278,21 +294,25 @@ modify_description (const char *in, const char *comment, char **result)
|
|||||||
out_len++;
|
out_len++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pass)
|
if (!pass)
|
||||||
{
|
{
|
||||||
*result = out = xtrymalloc (out_len + 1);
|
*result = out = xtrymalloc (out_len + 1);
|
||||||
if (!out)
|
if (!out)
|
||||||
return gpg_error_from_syserror ();
|
{
|
||||||
|
xfree (ssh_fpr);
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = 0;
|
*out = 0;
|
||||||
assert (*result + out_len == out);
|
assert (*result + out_len == out);
|
||||||
|
xfree (ssh_fpr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Unprotect the canconical encoded S-expression key in KEYBUF. GRIP
|
/* Unprotect the canconical encoded S-expression key in KEYBUF. GRIP
|
||||||
should be the hex encoded keygrip of that key to be used with the
|
should be the hex encoded keygrip of that key to be used with the
|
||||||
@ -301,7 +321,7 @@ modify_description (const char *in, const char *comment, char **result)
|
|||||||
function is used to lookup the default ttl. */
|
function is used to lookup the default ttl. */
|
||||||
static int
|
static int
|
||||||
unprotect (ctrl_t ctrl, const char *desc_text,
|
unprotect (ctrl_t ctrl, const char *desc_text,
|
||||||
unsigned char **keybuf, const unsigned char *grip,
|
unsigned char **keybuf, const unsigned char *grip,
|
||||||
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl)
|
cache_mode_t cache_mode, lookup_ttl_t lookup_ttl)
|
||||||
{
|
{
|
||||||
struct pin_entry_info_s *pi;
|
struct pin_entry_info_s *pi;
|
||||||
@ -310,7 +330,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
|
|||||||
unsigned char *result;
|
unsigned char *result;
|
||||||
size_t resultlen;
|
size_t resultlen;
|
||||||
char hexgrip[40+1];
|
char hexgrip[40+1];
|
||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
bin2hex (grip, 20, hexgrip);
|
||||||
|
|
||||||
/* First try to get it from the cache - if there is none or we can't
|
/* First try to get it from the cache - if there is none or we can't
|
||||||
@ -319,7 +339,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
|
|||||||
{
|
{
|
||||||
void *cache_marker;
|
void *cache_marker;
|
||||||
const char *pw;
|
const char *pw;
|
||||||
|
|
||||||
retry:
|
retry:
|
||||||
pw = agent_get_cache (hexgrip, cache_mode, &cache_marker);
|
pw = agent_get_cache (hexgrip, cache_mode, &cache_marker);
|
||||||
if (pw)
|
if (pw)
|
||||||
@ -352,7 +372,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
|
|||||||
{
|
{
|
||||||
/* We need to give the other thread a chance to actually put
|
/* We need to give the other thread a chance to actually put
|
||||||
it into the cache. */
|
it into the cache. */
|
||||||
pth_sleep (1);
|
pth_sleep (1);
|
||||||
goto retry;
|
goto retry;
|
||||||
}
|
}
|
||||||
/* Timeout - better call pinentry now the plain way. */
|
/* Timeout - better call pinentry now the plain way. */
|
||||||
@ -381,7 +401,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
|
|||||||
{
|
{
|
||||||
size_t canlen, erroff;
|
size_t canlen, erroff;
|
||||||
gcry_sexp_t s_skey;
|
gcry_sexp_t s_skey;
|
||||||
|
|
||||||
assert (arg.unprotected_key);
|
assert (arg.unprotected_key);
|
||||||
canlen = gcry_sexp_canon_len (arg.unprotected_key, 0, NULL, NULL);
|
canlen = gcry_sexp_canon_len (arg.unprotected_key, 0, NULL, NULL);
|
||||||
rc = gcry_sexp_sscan (&s_skey, &erroff,
|
rc = gcry_sexp_sscan (&s_skey, &erroff,
|
||||||
@ -399,7 +419,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
|
|||||||
gcry_sexp_release (s_skey);
|
gcry_sexp_release (s_skey);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_error ("changing the passphrase failed: %s\n",
|
log_error ("changing the passphrase failed: %s\n",
|
||||||
gpg_strerror (rc));
|
gpg_strerror (rc));
|
||||||
wipememory (arg.unprotected_key, canlen);
|
wipememory (arg.unprotected_key, canlen);
|
||||||
xfree (arg.unprotected_key);
|
xfree (arg.unprotected_key);
|
||||||
@ -407,8 +427,8 @@ unprotect (ctrl_t ctrl, const char *desc_text,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
agent_put_cache (hexgrip, cache_mode, pi->pin,
|
agent_put_cache (hexgrip, cache_mode, pi->pin,
|
||||||
lookup_ttl? lookup_ttl (hexgrip) : 0);
|
lookup_ttl? lookup_ttl (hexgrip) : 0);
|
||||||
xfree (*keybuf);
|
xfree (*keybuf);
|
||||||
*keybuf = arg.unprotected_key;
|
*keybuf = arg.unprotected_key;
|
||||||
@ -432,7 +452,7 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
|
|||||||
size_t buflen, erroff;
|
size_t buflen, erroff;
|
||||||
gcry_sexp_t s_skey;
|
gcry_sexp_t s_skey;
|
||||||
char hexgrip[40+4+1];
|
char hexgrip[40+4+1];
|
||||||
|
|
||||||
*result = NULL;
|
*result = NULL;
|
||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
bin2hex (grip, 20, hexgrip);
|
||||||
@ -448,7 +468,7 @@ read_key_file (const unsigned char *grip, gcry_sexp_t *result)
|
|||||||
xfree (fname);
|
xfree (fname);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fstat (fileno(fp), &st))
|
if (fstat (fileno(fp), &st))
|
||||||
{
|
{
|
||||||
rc = gpg_error_from_syserror ();
|
rc = gpg_error_from_syserror ();
|
||||||
@ -507,7 +527,7 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text,
|
|||||||
size_t len, buflen, erroff;
|
size_t len, buflen, erroff;
|
||||||
gcry_sexp_t s_skey;
|
gcry_sexp_t s_skey;
|
||||||
int got_shadow_info = 0;
|
int got_shadow_info = 0;
|
||||||
|
|
||||||
*result = NULL;
|
*result = NULL;
|
||||||
if (shadow_info)
|
if (shadow_info)
|
||||||
*shadow_info = NULL;
|
*shadow_info = NULL;
|
||||||
@ -529,45 +549,26 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text,
|
|||||||
break; /* no unprotection needed */
|
break; /* no unprotection needed */
|
||||||
case PRIVATE_KEY_PROTECTED:
|
case PRIVATE_KEY_PROTECTED:
|
||||||
{
|
{
|
||||||
gcry_sexp_t comment_sexp;
|
|
||||||
size_t comment_length;
|
|
||||||
char *desc_text_final;
|
char *desc_text_final;
|
||||||
const char *comment = NULL;
|
char *comment = NULL;
|
||||||
|
|
||||||
/* Note, that we will take the comment as a C string for
|
/* Note, that we will take the comment as a C string for
|
||||||
display purposes; i.e. all stuff beyond a Nul character is
|
display purposes; i.e. all stuff beyond a Nul character is
|
||||||
ignored. */
|
ignored. */
|
||||||
comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
|
{
|
||||||
if (comment_sexp)
|
gcry_sexp_t comment_sexp;
|
||||||
comment = gcry_sexp_nth_data (comment_sexp, 1, &comment_length);
|
|
||||||
if (!comment)
|
comment_sexp = gcry_sexp_find_token (s_skey, "comment", 0);
|
||||||
{
|
if (comment_sexp)
|
||||||
comment = "";
|
comment = gcry_sexp_nth_string (comment_sexp, 1);
|
||||||
comment_length = 0;
|
gcry_sexp_release (comment_sexp);
|
||||||
}
|
}
|
||||||
|
|
||||||
desc_text_final = NULL;
|
desc_text_final = NULL;
|
||||||
if (desc_text)
|
if (desc_text)
|
||||||
{
|
rc = modify_description (desc_text, comment? comment:"", s_skey,
|
||||||
if (comment[comment_length])
|
&desc_text_final);
|
||||||
{
|
gcry_free (comment);
|
||||||
/* Not a C-string; create one. We might here allocate
|
|
||||||
more than actually displayed but well, that
|
|
||||||
shouldn't be a problem. */
|
|
||||||
char *tmp = xtrymalloc (comment_length+1);
|
|
||||||
if (!tmp)
|
|
||||||
rc = gpg_error_from_syserror ();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy (tmp, comment, comment_length);
|
|
||||||
tmp[comment_length] = 0;
|
|
||||||
rc = modify_description (desc_text, tmp, &desc_text_final);
|
|
||||||
xfree (tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
rc = modify_description (desc_text, comment, &desc_text_final);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rc)
|
if (!rc)
|
||||||
{
|
{
|
||||||
@ -577,8 +578,7 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text,
|
|||||||
log_error ("failed to unprotect the secret key: %s\n",
|
log_error ("failed to unprotect the secret key: %s\n",
|
||||||
gpg_strerror (rc));
|
gpg_strerror (rc));
|
||||||
}
|
}
|
||||||
|
|
||||||
gcry_sexp_release (comment_sexp);
|
|
||||||
xfree (desc_text_final);
|
xfree (desc_text_final);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -638,13 +638,34 @@ agent_key_from_file (ctrl_t ctrl, const char *desc_text,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the key for the keygrip GRIP. The result is stored at
|
||||||
|
RESULT. This function extracts the key from the private key
|
||||||
|
database and returns it as an S-expression object as it is. On
|
||||||
|
failure an error code is returned and NULL stored at RESULT. */
|
||||||
|
gpg_error_t
|
||||||
|
agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
|
||||||
|
gcry_sexp_t *result)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
gcry_sexp_t s_skey;
|
||||||
|
|
||||||
|
(void)ctrl;
|
||||||
|
|
||||||
|
*result = NULL;
|
||||||
|
|
||||||
|
err = read_key_file (grip, &s_skey);
|
||||||
|
if (!err)
|
||||||
|
*result = s_skey;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return the public key for the keygrip GRIP. The result is stored
|
/* Return the public key for the keygrip GRIP. The result is stored
|
||||||
at RESULT. This function extracts the public key from the private
|
at RESULT. This function extracts the public key from the private
|
||||||
key database. On failure an error code is returned and NULL stored
|
key database. On failure an error code is returned and NULL stored
|
||||||
at RESULT. */
|
at RESULT. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
agent_public_key_from_file (ctrl_t ctrl,
|
agent_public_key_from_file (ctrl_t ctrl,
|
||||||
const unsigned char *grip,
|
const unsigned char *grip,
|
||||||
gcry_sexp_t *result)
|
gcry_sexp_t *result)
|
||||||
{
|
{
|
||||||
@ -723,7 +744,7 @@ agent_public_key_from_file (ctrl_t ctrl,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (idx=0, s=elems; *s; s++, idx++ )
|
for (idx=0, s=elems; *s; s++, idx++ )
|
||||||
{
|
{
|
||||||
l2 = gcry_sexp_find_token (list, s, 1);
|
l2 = gcry_sexp_find_token (list, s, 1);
|
||||||
if (!l2)
|
if (!l2)
|
||||||
@ -790,7 +811,7 @@ agent_public_key_from_file (ctrl_t ctrl,
|
|||||||
|
|
||||||
argidx = 0;
|
argidx = 0;
|
||||||
p = stpcpy (stpcpy (format, "(public-key("), algoname);
|
p = stpcpy (stpcpy (format, "(public-key("), algoname);
|
||||||
for (idx=0, s=elems; *s; s++, idx++ )
|
for (idx=0, s=elems; *s; s++, idx++ )
|
||||||
{
|
{
|
||||||
*p++ = '(';
|
*p++ = '(';
|
||||||
*p++ = *s;
|
*p++ = *s;
|
||||||
@ -817,7 +838,7 @@ agent_public_key_from_file (ctrl_t ctrl,
|
|||||||
*p = 0;
|
*p = 0;
|
||||||
assert (argidx < DIM (args));
|
assert (argidx < DIM (args));
|
||||||
args[argidx] = NULL;
|
args[argidx] = NULL;
|
||||||
|
|
||||||
rc = gcry_sexp_build_array (&list, NULL, format, args);
|
rc = gcry_sexp_build_array (&list, NULL, format, args);
|
||||||
xfree (format);
|
xfree (format);
|
||||||
for (i=0; array[i]; i++)
|
for (i=0; array[i]; i++)
|
||||||
@ -841,7 +862,7 @@ agent_key_available (const unsigned char *grip)
|
|||||||
int result;
|
int result;
|
||||||
char *fname;
|
char *fname;
|
||||||
char hexgrip[40+4+1];
|
char hexgrip[40+4+1];
|
||||||
|
|
||||||
bin2hex (grip, 20, hexgrip);
|
bin2hex (grip, 20, hexgrip);
|
||||||
strcpy (hexgrip+40, ".key");
|
strcpy (hexgrip+40, ".key");
|
||||||
|
|
||||||
@ -867,7 +888,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
|
|||||||
int keytype;
|
int keytype;
|
||||||
|
|
||||||
(void)ctrl;
|
(void)ctrl;
|
||||||
|
|
||||||
if (r_keytype)
|
if (r_keytype)
|
||||||
*r_keytype = PRIVATE_KEY_UNKNOWN;
|
*r_keytype = PRIVATE_KEY_UNKNOWN;
|
||||||
if (r_shadow_info)
|
if (r_shadow_info)
|
||||||
@ -875,7 +896,7 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
|
|||||||
|
|
||||||
{
|
{
|
||||||
gcry_sexp_t sexp;
|
gcry_sexp_t sexp;
|
||||||
|
|
||||||
err = read_key_file (grip, &sexp);
|
err = read_key_file (grip, &sexp);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
@ -889,12 +910,12 @@ agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
keytype = agent_private_key_type (buf);
|
keytype = agent_private_key_type (buf);
|
||||||
switch (keytype)
|
switch (keytype)
|
||||||
{
|
{
|
||||||
case PRIVATE_KEY_CLEAR:
|
case PRIVATE_KEY_CLEAR:
|
||||||
break;
|
break;
|
||||||
case PRIVATE_KEY_PROTECTED:
|
case PRIVATE_KEY_PROTECTED:
|
||||||
/* If we ever require it we could retrieve the comment fields
|
/* If we ever require it we could retrieve the comment fields
|
||||||
from such a key. */
|
from such a key. */
|
||||||
|
@ -123,21 +123,8 @@ endif
|
|||||||
#
|
#
|
||||||
# Module tests
|
# Module tests
|
||||||
#
|
#
|
||||||
<<<<<<< HEAD
|
|
||||||
module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil t-exechelp \
|
module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil t-exechelp \
|
||||||
t-session-env
|
t-session-env t-ssh-utils
|
||||||
=======
|
|
||||||
t_jnlib_src = t-support.c t-support.h
|
|
||||||
jnlib_tests = t-stringhelp t-timestuff
|
|
||||||
if HAVE_W32_SYSTEM
|
|
||||||
jnlib_tests += t-w32-reg
|
|
||||||
endif
|
|
||||||
module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil \
|
|
||||||
t-session-env t-openpgp-oid t-ssh-utils
|
|
||||||
if !HAVE_W32CE_SYSTEM
|
|
||||||
module_tests += t-exechelp
|
|
||||||
endif
|
|
||||||
>>>>>>> New functions to compute an ssh style fingerprint.
|
|
||||||
module_maint_tests = t-helpfile t-b64
|
module_maint_tests = t-helpfile t-b64
|
||||||
|
|
||||||
t_common_ldadd = libcommon.a ../jnlib/libjnlib.a ../gl/libgnu.a \
|
t_common_ldadd = libcommon.a ../jnlib/libjnlib.a ../gl/libgnu.a \
|
||||||
@ -152,9 +139,4 @@ t_sexputil_LDADD = $(t_common_ldadd)
|
|||||||
t_b64_LDADD = $(t_common_ldadd)
|
t_b64_LDADD = $(t_common_ldadd)
|
||||||
t_exechelp_LDADD = $(t_common_ldadd)
|
t_exechelp_LDADD = $(t_common_ldadd)
|
||||||
t_session_env_LDADD = $(t_common_ldadd)
|
t_session_env_LDADD = $(t_common_ldadd)
|
||||||
<<<<<<< HEAD
|
|
||||||
|
|
||||||
=======
|
|
||||||
t_openpgp_oid_LDADD = $(t_common_ldadd)
|
|
||||||
t_ssh_utils_LDADD = $(t_common_ldadd)
|
t_ssh_utils_LDADD = $(t_common_ldadd)
|
||||||
>>>>>>> New functions to compute an ssh style fingerprint.
|
|
||||||
|
@ -27,13 +27,6 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "ssh-utils.h"
|
#include "ssh-utils.h"
|
||||||
|
|
||||||
#define pass() do { ; } while(0)
|
|
||||||
#define fail(a,e) \
|
|
||||||
do { fprintf (stderr, "%s:%d: test %d failed (%s)\n", \
|
|
||||||
__FILE__,__LINE__, (a), gpg_strerror (e)); \
|
|
||||||
exit (1); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
|
|
||||||
static struct { const char *key; const char *fpr; } sample_keys[] = {
|
static struct { const char *key; const char *fpr; } sample_keys[] = {
|
||||||
{ "(protected-private-key "
|
{ "(protected-private-key "
|
||||||
|
@ -640,6 +640,12 @@ digits, optionally followed by the caching TTL in seconds and another
|
|||||||
optional field for arbitrary flags. A non-zero TTL overrides the global
|
optional field for arbitrary flags. A non-zero TTL overrides the global
|
||||||
default as set by @option{--default-cache-ttl-ssh}.
|
default as set by @option{--default-cache-ttl-ssh}.
|
||||||
|
|
||||||
|
The only flag support is @code{confirm}. If this flag is found for a
|
||||||
|
key, each use of the key will pop up a pinentry to confirm the use of
|
||||||
|
that key. The flag is automatically set if a new key was loaded into
|
||||||
|
@code{gpg-agent} using the option @option{-c} of the @code{ssh-add}
|
||||||
|
command.
|
||||||
|
|
||||||
The keygrip may be prefixed with a @code{!} to disable an entry entry.
|
The keygrip may be prefixed with a @code{!} to disable an entry entry.
|
||||||
|
|
||||||
The following example lists exactly one key. Note that keys available
|
The following example lists exactly one key. Note that keys available
|
||||||
@ -647,8 +653,9 @@ through a OpenPGP smartcard in the active smartcard reader are
|
|||||||
implicitly added to this list; i.e. there is no need to list them.
|
implicitly added to this list; i.e. there is no need to list them.
|
||||||
|
|
||||||
@example
|
@example
|
||||||
# Key added on 2005-02-25 15:08:29
|
# Key added on: 2011-07-20 20:38:46
|
||||||
5A6592BF45DC73BD876874A28FD4639282E29B52 0
|
# Fingerprint: 5e:8d:c4:ad:e7:af:6e:27:8a:d6:13:e4:79:ad:0b:81
|
||||||
|
34B62F25E277CF13D3C6BCEBFD3F85D08F0A864B 0 confirm
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@item private-keys-v1.d/
|
@item private-keys-v1.d/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user