mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Allow for a global trustlist.
This commit is contained in:
parent
03d3322e5f
commit
7f42987b07
2
NEWS
2
NEWS
@ -26,6 +26,8 @@ Noteworthy changes in version 1.9.23
|
|||||||
|
|
||||||
* gpg-connect-agent has new options to utilize descriptor passing.
|
* gpg-connect-agent has new options to utilize descriptor passing.
|
||||||
|
|
||||||
|
* A global trustlist may now be used. See doc/examples/trustlist.txt.
|
||||||
|
|
||||||
|
|
||||||
Noteworthy changes in version 1.9.22 (2006-07-27)
|
Noteworthy changes in version 1.9.22 (2006-07-27)
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
2006-09-15 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* trustlist.c: Entirely rewritten.
|
||||||
|
(agent_trustlist_housekeeping): Removed and removed all calls.
|
||||||
|
|
||||||
2006-09-14 Werner Koch <wk@g10code.com>
|
2006-09-14 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
Replaced all call gpg_error_from_errno(errno) by
|
Replaced all call gpg_error_from_errno(errno) by
|
||||||
|
@ -252,11 +252,10 @@ int agent_get_shadow_info (const unsigned char *shadowkey,
|
|||||||
|
|
||||||
|
|
||||||
/*-- trustlist.c --*/
|
/*-- trustlist.c --*/
|
||||||
int agent_istrusted (const char *fpr);
|
gpg_error_t agent_istrusted (const char *fpr);
|
||||||
int agent_listtrusted (void *assuan_context);
|
gpg_error_t agent_listtrusted (void *assuan_context);
|
||||||
int agent_marktrusted (ctrl_t ctrl, const char *name,
|
gpg_error_t agent_marktrusted (ctrl_t ctrl, const char *name,
|
||||||
const char *fpr, int flag);
|
const char *fpr, int flag);
|
||||||
void agent_trustlist_housekeeping (void);
|
|
||||||
void agent_reload_trustlist (void);
|
void agent_reload_trustlist (void);
|
||||||
|
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ plus_to_blank (char *s)
|
|||||||
static size_t
|
static size_t
|
||||||
percent_plus_unescape (char *string)
|
percent_plus_unescape (char *string)
|
||||||
{
|
{
|
||||||
unsigned char *p = string;
|
unsigned char *p = (unsigned char *)string;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
|
|
||||||
while (*string)
|
while (*string)
|
||||||
@ -240,7 +240,7 @@ cmd_istrusted (assuan_context_t ctx, char *line)
|
|||||||
char *p;
|
char *p;
|
||||||
char fpr[41];
|
char fpr[41];
|
||||||
|
|
||||||
/* parse the fingerprint value */
|
/* Parse the fingerprint value. */
|
||||||
for (p=line,n=0; hexdigitp (p); p++, n++)
|
for (p=line,n=0; hexdigitp (p); p++, n++)
|
||||||
;
|
;
|
||||||
if (*p || !(n == 40 || n == 32))
|
if (*p || !(n == 40 || n == 32))
|
||||||
|
@ -1427,11 +1427,6 @@ start_connection_thread (void *arg)
|
|||||||
log_info (_("handler 0x%lx for fd %d started\n"),
|
log_info (_("handler 0x%lx for fd %d started\n"),
|
||||||
(long)pth_self (), fd);
|
(long)pth_self (), fd);
|
||||||
|
|
||||||
/* FIXME: Move this housekeeping into a ticker function. Calling it
|
|
||||||
for each connection should work but won't work anymore if our
|
|
||||||
clients start to keep connections. */
|
|
||||||
agent_trustlist_housekeeping ();
|
|
||||||
|
|
||||||
start_command_handler (-1, fd);
|
start_command_handler (-1, fd);
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_info (_("handler 0x%lx for fd %d terminated\n"),
|
log_info (_("handler 0x%lx for fd %d terminated\n"),
|
||||||
@ -1451,8 +1446,6 @@ start_connection_thread_ssh (void *arg)
|
|||||||
log_info (_("ssh handler 0x%lx for fd %d started\n"),
|
log_info (_("ssh handler 0x%lx for fd %d started\n"),
|
||||||
(long)pth_self (), fd);
|
(long)pth_self (), fd);
|
||||||
|
|
||||||
agent_trustlist_housekeeping ();
|
|
||||||
|
|
||||||
start_command_handler_ssh (fd);
|
start_command_handler_ssh (fd);
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
|
log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* trustlist.c - Maintain the list of trusted keys
|
/* trustlist.c - Maintain the list of trusted keys
|
||||||
* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
|
* Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -28,213 +28,347 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <pth.h>
|
||||||
|
|
||||||
#include "agent.h"
|
#include "agent.h"
|
||||||
#include <assuan.h> /* fixme: need a way to avoid assuan calls here */
|
#include <assuan.h> /* fixme: need a way to avoid assuan calls here */
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* A structure to store the information from the trust file. */
|
||||||
|
struct trustitem_s
|
||||||
|
{
|
||||||
|
int keyflag; /* The keyflag: '*', 'P' or 'S'. */
|
||||||
|
unsigned char fpr[20]; /* The binary fingerprint. */
|
||||||
|
};
|
||||||
|
typedef struct trustitem_s trustitem_t;
|
||||||
|
|
||||||
|
/* Malloced table and its allocated size with all trust items. */
|
||||||
|
static trustitem_t *trusttable;
|
||||||
|
static size_t trusttablesize;
|
||||||
|
/* A mutex used to protect the table. */
|
||||||
|
static pth_mutex_t trusttable_lock = PTH_MUTEX_INIT;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const char headerblurb[] =
|
static const char headerblurb[] =
|
||||||
"# This is the list of trusted keys. Comment lines, like this one, as\n"
|
"# This is the list of trusted keys. Comment lines, like this one, as\n"
|
||||||
"# well as empty lines are ignored. The entire file may be integrity\n"
|
"# well as empty lines are ignored. Lines have a length limit but this\n"
|
||||||
"# protected by the use of a MAC, so changing the file does not make\n"
|
"# is not serious limitation as the format of the entries is fixed and\n"
|
||||||
"# sense without the knowledge of the MAC key. Lines do have a length\n"
|
"# checked by gpg-agent. A non-comment line starts with optional white\n"
|
||||||
"# limit but this is not serious limitation as the format of the\n"
|
"# space, followed by the SHA-1 fingerpint in hex, optionally followed\n"
|
||||||
"# entries is fixed and checked by gpg-agent: A non-comment line starts\n"
|
"# by a flag character which my either be 'P', 'S' or '*'. You should\n"
|
||||||
"# with optional white spaces, followed by the SHA-1 fingerpint in hex,\n"
|
"# give the gpg-agent a HUP after editing this file.\n"
|
||||||
"# optionally followed by a flag character which my either be 'P', 'S'\n"
|
"\n\n"
|
||||||
"# or '*'. Additional data, delimited by white space, is ignored.\n"
|
"# Include the default trust list\n"
|
||||||
"#\n"
|
"include-default\n"
|
||||||
"# NOTE: You should give the gpg-agent a HUP after editing this file.\n"
|
|
||||||
"\n";
|
"\n";
|
||||||
|
|
||||||
|
|
||||||
static FILE *trustfp;
|
|
||||||
static int trustfp_used; /* Counter to track usage of TRUSTFP. */
|
|
||||||
static int reload_trustlist_pending;
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
static void
|
||||||
open_list (int append)
|
lock_trusttable (void)
|
||||||
{
|
{
|
||||||
char *fname;
|
if (!pth_mutex_acquire (&trusttable_lock, 0, NULL))
|
||||||
|
log_fatal ("failed to acquire mutex in %s\n", __FILE__);
|
||||||
|
}
|
||||||
|
|
||||||
fname = make_filename (opt.homedir, "trustlist.txt", NULL);
|
static void
|
||||||
trustfp = fopen (fname, append? "a+":"r");
|
unlock_trusttable (void)
|
||||||
if (!trustfp && errno == ENOENT)
|
{
|
||||||
{
|
if (!pth_mutex_release (&trusttable_lock))
|
||||||
trustfp = fopen (fname, "wx");
|
log_fatal ("failed to release mutex in %s\n", __FILE__);
|
||||||
if (!trustfp)
|
|
||||||
{
|
|
||||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
|
||||||
log_error ("can't create `%s': %s\n", fname, strerror (errno));
|
|
||||||
xfree (fname);
|
|
||||||
return tmperr;
|
|
||||||
}
|
|
||||||
fputs (headerblurb, trustfp);
|
|
||||||
fclose (trustfp);
|
|
||||||
trustfp = fopen (fname, append? "a+":"r");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!trustfp)
|
|
||||||
{
|
|
||||||
gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
|
|
||||||
log_error ("can't open `%s': %s\n", fname, strerror (errno));
|
|
||||||
xfree (fname);
|
|
||||||
return tmperr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*FIXME: check the MAC */
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Read the trustlist and return entry by entry. KEY must point to a
|
static gpg_error_t
|
||||||
buffer of at least 41 characters. KEYFLAG does return either 'P',
|
read_one_trustfile (const char *fname, int allow_include,
|
||||||
'S' or '*'.
|
trustitem_t **addr_of_table,
|
||||||
|
size_t *addr_of_tablesize,
|
||||||
Reading a valid entry returns 0, EOF returns -1 any other error
|
int *addr_of_tableidx)
|
||||||
returns the appropriate error code. */
|
|
||||||
static int
|
|
||||||
read_list (char *key, int *keyflag)
|
|
||||||
{
|
{
|
||||||
int rc;
|
gpg_error_t err = 0;
|
||||||
int c, i, j;
|
FILE *fp;
|
||||||
|
int n, c;
|
||||||
char *p, line[256];
|
char *p, line[256];
|
||||||
|
trustitem_t *table, *ti;
|
||||||
if (!trustfp)
|
int tableidx;
|
||||||
|
size_t tablesize;
|
||||||
|
int lnr = 0;
|
||||||
|
|
||||||
|
table = *addr_of_table;
|
||||||
|
tablesize = *addr_of_tablesize;
|
||||||
|
tableidx = *addr_of_tableidx;
|
||||||
|
|
||||||
|
fp = fopen (fname, "r");
|
||||||
|
if (!fp)
|
||||||
{
|
{
|
||||||
rc = open_list (0);
|
err = gpg_error_from_syserror ();
|
||||||
if (rc)
|
log_error (_("error opening `%s': %s\n"), fname, gpg_strerror (err));
|
||||||
return rc;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
do
|
while (fgets (line, DIM(line)-1, fp))
|
||||||
{
|
{
|
||||||
if (!fgets (line, DIM(line)-1, trustfp) )
|
lnr++;
|
||||||
{
|
|
||||||
if (feof (trustfp))
|
|
||||||
return -1;
|
|
||||||
return gpg_error (gpg_err_code_from_errno (errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!*line || line[strlen(line)-1] != '\n')
|
if (!*line || line[strlen(line)-1] != '\n')
|
||||||
{
|
{
|
||||||
/* eat until end of line */
|
/* Eat until end of line. */
|
||||||
while ( (c=getc (trustfp)) != EOF && c != '\n')
|
while ( (c=getc (fp)) != EOF && c != '\n')
|
||||||
;
|
;
|
||||||
return gpg_error (*line? GPG_ERR_LINE_TOO_LONG
|
err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
|
||||||
: GPG_ERR_INCOMPLETE_LINE);
|
: GPG_ERR_INCOMPLETE_LINE);
|
||||||
|
log_error (_("file `%s', line %d: %s\n"),
|
||||||
|
fname, lnr, gpg_strerror (err));
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
line[strlen(line)-1] = 0; /* Chop the LF. */
|
||||||
|
|
||||||
/* Allow for empty lines and spaces */
|
/* Allow for empty lines and spaces */
|
||||||
for (p=line; spacep (p); p++)
|
for (p=line; spacep (p); p++)
|
||||||
;
|
;
|
||||||
}
|
if (!*p || *p == '#')
|
||||||
while (!*p || *p == '\n' || *p == '#');
|
continue;
|
||||||
|
|
||||||
for (i=j=0; (p[i] == ':' || hexdigitp (p+i)) && j < 40; i++)
|
if (!strncmp (p, "include-default", 15)
|
||||||
if ( p[i] != ':' )
|
&& (!p[15] || spacep (p+15)))
|
||||||
key[j++] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
|
{
|
||||||
key[j] = 0;
|
char *etcname;
|
||||||
if (j!=40 || !(spacep (p+i) || p[i] == '\n'))
|
gpg_error_t err2;
|
||||||
{
|
|
||||||
log_error ("invalid formatted fingerprint in trustlist\n");
|
if (!allow_include)
|
||||||
return gpg_error (GPG_ERR_BAD_DATA);
|
{
|
||||||
}
|
log_error (_("statement \"%s\" ignored in `%s', line %d\n"),
|
||||||
assert (p[i]);
|
"include-default", fname, lnr);
|
||||||
if (p[i] == '\n')
|
continue;
|
||||||
*keyflag = '*';
|
}
|
||||||
else
|
/* fixme: Should check for trailing garbage. */
|
||||||
{
|
|
||||||
i++;
|
etcname = make_filename (GNUPG_SYSCONFDIR, "trustlist.txt", NULL);
|
||||||
if ( p[i] == 'P' || p[i] == 'p')
|
if ( !strcmp (etcname, fname) ) /* Same file. */
|
||||||
*keyflag = 'P';
|
log_info (_("statement \"%s\" ignored in `%s', line %d\n"),
|
||||||
else if ( p[i] == 'S' || p[i] == 's')
|
"include-default", fname, lnr);
|
||||||
*keyflag = 'S';
|
else if ( access (etcname, F_OK) && errno == ENOENT )
|
||||||
else if ( p[i] == '*')
|
{
|
||||||
*keyflag = '*';
|
/* A non existent system trustlist is not an error.
|
||||||
|
Just print a note. */
|
||||||
|
log_info (_("system trustlist `%s' not available\n"), etcname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err2 = read_one_trustfile (etcname, 0,
|
||||||
|
&table, &tablesize, &tableidx);
|
||||||
|
if (err2)
|
||||||
|
err = err2;
|
||||||
|
}
|
||||||
|
xfree (etcname);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tableidx == tablesize) /* Need more space. */
|
||||||
|
{
|
||||||
|
trustitem_t *tmp;
|
||||||
|
size_t tmplen;
|
||||||
|
|
||||||
|
tmplen = tablesize + 20;
|
||||||
|
tmp = xtryrealloc (table, tmplen * sizeof *table);
|
||||||
|
if (!tmp)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
table = tmp;
|
||||||
|
tablesize = tmplen;
|
||||||
|
}
|
||||||
|
|
||||||
|
ti = table + tableidx;
|
||||||
|
|
||||||
|
n = hexcolon2bin (p, ti->fpr, 20);
|
||||||
|
if (n < 0)
|
||||||
|
{
|
||||||
|
log_error (_("bad fingerprint in `%s', line %d\n"), fname, lnr);
|
||||||
|
err = gpg_error (GPG_ERR_BAD_DATA);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
p += n;
|
||||||
|
for (; spacep (p); p++)
|
||||||
|
;
|
||||||
|
|
||||||
|
if (!*p)
|
||||||
|
ti->keyflag = '*';
|
||||||
|
else if ( *p == 'P' || *p == 'p')
|
||||||
|
ti->keyflag = 'P';
|
||||||
|
else if ( *p == 'S' || *p == 's')
|
||||||
|
ti->keyflag = 'S';
|
||||||
|
else if ( *p == '*')
|
||||||
|
ti->keyflag = '*';
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_error ("invalid keyflag in trustlist\n");
|
log_error (_("invalid keyflag in `%s', line %d\n"), fname, lnr);
|
||||||
return gpg_error (GPG_ERR_BAD_DATA);
|
err = gpg_error (GPG_ERR_BAD_DATA);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
i++;
|
p++;
|
||||||
if ( !(spacep (p+i) || p[i] == '\n'))
|
if ( *p && !spacep (p) )
|
||||||
{
|
{
|
||||||
log_error ("invalid keyflag in trustlist\n");
|
log_error (_("invalid keyflag in `%s', line %d\n"), fname, lnr);
|
||||||
return gpg_error (GPG_ERR_BAD_DATA);
|
err = gpg_error (GPG_ERR_BAD_DATA);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
/* Fixme: need to check for trailing garbage. */
|
||||||
|
tableidx++;
|
||||||
|
}
|
||||||
|
if ( !err && !feof (fp) )
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error (_("error reading `%s', line %d: %s\n"),
|
||||||
|
fname, lnr, gpg_strerror (err));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
leave:
|
||||||
|
if (fp)
|
||||||
|
fclose (fp);
|
||||||
|
*addr_of_table = table;
|
||||||
|
*addr_of_tablesize = tablesize;
|
||||||
|
*addr_of_tableidx = tableidx;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Read the trust files and update the global table on success. */
|
||||||
|
static gpg_error_t
|
||||||
|
read_trustfiles (void)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
trustitem_t *table, *ti;
|
||||||
|
int tableidx;
|
||||||
|
size_t tablesize;
|
||||||
|
char *fname;
|
||||||
|
int allow_include = 1;
|
||||||
|
|
||||||
|
tablesize = 10;
|
||||||
|
table = xtrycalloc (tablesize, sizeof *table);
|
||||||
|
if (!table)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
tableidx = 0;
|
||||||
|
|
||||||
|
fname = make_filename (opt.homedir, "trustlist.txt", NULL);
|
||||||
|
if ( access (fname, F_OK) )
|
||||||
|
{
|
||||||
|
if ( errno == ENOENT )
|
||||||
|
; /* Silently ignore a non-existing trustfile. */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error (_("error opening `%s': %s\n"), fname, gpg_strerror (err));
|
||||||
|
}
|
||||||
|
xfree (fname);
|
||||||
|
fname = make_filename (GNUPG_SYSCONFDIR, "trustlist.txt", NULL);
|
||||||
|
allow_include = 0;
|
||||||
|
}
|
||||||
|
err = read_one_trustfile (fname, allow_include,
|
||||||
|
&table, &tablesize, &tableidx);
|
||||||
|
xfree (fname);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
xfree (table);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fixme: we should drop duplicates and sort the table. */
|
||||||
|
|
||||||
|
ti = xtryrealloc (table, tableidx * sizeof *table);
|
||||||
|
if (!ti)
|
||||||
|
{
|
||||||
|
xfree (table);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_trusttable ();
|
||||||
|
xfree (trusttable);
|
||||||
|
trusttable = table;
|
||||||
|
trusttablesize = tableidx;
|
||||||
|
unlock_trusttable ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Check whether the given fpr is in our trustdb. We expect FPR to be
|
/* Check whether the given fpr is in our trustdb. We expect FPR to be
|
||||||
an all uppercase hexstring of 40 characters. */
|
an all uppercase hexstring of 40 characters. */
|
||||||
int
|
gpg_error_t
|
||||||
agent_istrusted (const char *fpr)
|
agent_istrusted (const char *fpr)
|
||||||
{
|
{
|
||||||
int rc;
|
gpg_error_t err;
|
||||||
static char key[41];
|
trustitem_t *ti;
|
||||||
int keyflag;
|
size_t len;
|
||||||
|
unsigned char fprbin[20];
|
||||||
|
|
||||||
trustfp_used++;
|
if ( hexcolon2bin (fpr, fprbin, 20) < 0 )
|
||||||
if (trustfp)
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
rewind (trustfp);
|
|
||||||
while (!(rc=read_list (key, &keyflag)))
|
if (!trusttable)
|
||||||
{
|
{
|
||||||
if (!strcmp (key, fpr))
|
err = read_trustfiles ();
|
||||||
|
if (err)
|
||||||
{
|
{
|
||||||
trustfp_used--;
|
log_error (_("error reading list of trusted root certificates\n"));
|
||||||
return 0;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rc != -1)
|
|
||||||
|
if (trusttable)
|
||||||
{
|
{
|
||||||
/* Error in the trustdb - close it to give the user a chance for
|
for (ti=trusttable, len = trusttablesize; len; ti++, len--)
|
||||||
correction */
|
if (!memcmp (ti->fpr, fprbin, 20))
|
||||||
if (trustfp)
|
return 0; /* Trusted. */
|
||||||
fclose (trustfp);
|
|
||||||
trustfp = NULL;
|
|
||||||
}
|
}
|
||||||
trustfp_used--;
|
return gpg_error (GPG_ERR_NOT_TRUSTED);
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Write all trust entries to FP. */
|
/* Write all trust entries to FP. */
|
||||||
int
|
gpg_error_t
|
||||||
agent_listtrusted (void *assuan_context)
|
agent_listtrusted (void *assuan_context)
|
||||||
{
|
{
|
||||||
int rc;
|
trustitem_t *ti;
|
||||||
static char key[51];
|
char key[51];
|
||||||
int keyflag;
|
gpg_error_t err;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
trustfp_used++;
|
if (!trusttable)
|
||||||
if (trustfp)
|
|
||||||
rewind (trustfp);
|
|
||||||
while (!(rc=read_list (key, &keyflag)))
|
|
||||||
{
|
{
|
||||||
key[40] = ' ';
|
err = read_trustfiles ();
|
||||||
key[41] = keyflag;
|
if (err)
|
||||||
key[42] = '\n';
|
{
|
||||||
assuan_send_data (assuan_context, key, 43);
|
log_error (_("error reading list of trusted root certificates\n"));
|
||||||
assuan_send_data (assuan_context, NULL, 0); /* flush */
|
return err;
|
||||||
}
|
}
|
||||||
if (rc == -1)
|
|
||||||
rc = 0;
|
|
||||||
if (rc)
|
|
||||||
{
|
|
||||||
/* Error in the trustdb - close it to give the user a chance for
|
|
||||||
correction */
|
|
||||||
if (trustfp)
|
|
||||||
fclose (trustfp);
|
|
||||||
trustfp = NULL;
|
|
||||||
}
|
}
|
||||||
trustfp_used--;
|
|
||||||
return rc;
|
if (trusttable)
|
||||||
|
{
|
||||||
|
/* We need to lock the table because the scheduler may interrupt
|
||||||
|
assuan_send_data and an other thread may then re-read the table. */
|
||||||
|
lock_trusttable ();
|
||||||
|
for (ti=trusttable, len = trusttablesize; len; ti++, len--)
|
||||||
|
{
|
||||||
|
bin2hex (ti->fpr, 20, key);
|
||||||
|
key[40] = ' ';
|
||||||
|
key[41] = ti->keyflag;
|
||||||
|
key[42] = '\n';
|
||||||
|
assuan_send_data (assuan_context, key, 43);
|
||||||
|
assuan_send_data (assuan_context, NULL, 0); /* flush */
|
||||||
|
}
|
||||||
|
unlock_trusttable ();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -245,52 +379,36 @@ agent_listtrusted (void *assuan_context)
|
|||||||
actually gets inserted, the user is asked by means of the pin-entry
|
actually gets inserted, the user is asked by means of the pin-entry
|
||||||
whether this is actual wants he want to do.
|
whether this is actual wants he want to do.
|
||||||
*/
|
*/
|
||||||
int
|
gpg_error_t
|
||||||
agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
||||||
{
|
{
|
||||||
int rc;
|
gpg_error_t err = 0;
|
||||||
static char key[41];
|
|
||||||
int keyflag;
|
|
||||||
char *desc;
|
char *desc;
|
||||||
char *fname;
|
char *fname;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
/* Check whether we are at all allowed to modify the trustlist.
|
/* Check whether we are at all allowed to modify the trustlist.
|
||||||
This is useful so that the trustlist may be a symlink to a global
|
This is useful so that the trustlist may be a symlink to a global
|
||||||
trustlist with only admin priviliges to modify it. Of course
|
trustlist with only admin priviliges to modify it. Of course
|
||||||
this is not a secure way of denying access, but it avoids the
|
this is not a secure way of denying access, but it avoids the
|
||||||
usual clicking on an Okay buttun thing most users are used to. */
|
usual clicking on an Okay button most users are used to. */
|
||||||
fname = make_filename (opt.homedir, "trustlist.txt", NULL);
|
fname = make_filename (opt.homedir, "trustlist.txt", NULL);
|
||||||
rc = access (fname, W_OK);
|
if ( access (fname, W_OK) && errno != ENOENT)
|
||||||
if (rc && errno != ENOENT)
|
|
||||||
{
|
{
|
||||||
xfree (fname);
|
xfree (fname);
|
||||||
return gpg_error (GPG_ERR_EPERM);
|
return gpg_error (GPG_ERR_EPERM);
|
||||||
}
|
}
|
||||||
xfree (fname);
|
xfree (fname);
|
||||||
|
|
||||||
trustfp_used++;
|
if (!agent_istrusted (fpr))
|
||||||
if (trustfp)
|
|
||||||
rewind (trustfp);
|
|
||||||
while (!(rc=read_list (key, &keyflag)))
|
|
||||||
{
|
{
|
||||||
if (!strcmp (key, fpr))
|
return 0; /* We already got this fingerprint. Silently return
|
||||||
return 0;
|
success. */
|
||||||
}
|
|
||||||
if (trustfp)
|
|
||||||
fclose (trustfp);
|
|
||||||
trustfp = NULL;
|
|
||||||
if (rc != -1)
|
|
||||||
{
|
|
||||||
trustfp_used--;
|
|
||||||
return rc; /* Error in the trustlist. */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This feature must explicitly been enabled. */
|
/* This feature must explicitly been enabled. */
|
||||||
if (!opt.allow_mark_trusted)
|
if (!opt.allow_mark_trusted)
|
||||||
{
|
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||||
trustfp_used--;
|
|
||||||
return gpg_error (GPG_ERR_NOT_SUPPORTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Insert a new one. */
|
/* Insert a new one. */
|
||||||
if (asprintf (&desc,
|
if (asprintf (&desc,
|
||||||
@ -307,21 +425,15 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
|||||||
" \"%s\"%%0A"
|
" \"%s\"%%0A"
|
||||||
"has the fingerprint:%%0A"
|
"has the fingerprint:%%0A"
|
||||||
" %s"), name, fpr) < 0 )
|
" %s"), name, fpr) < 0 )
|
||||||
{
|
return out_of_core ();
|
||||||
trustfp_used--;
|
|
||||||
return out_of_core ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* TRANSLATORS: "Correct" is the label of a button and intended to
|
/* TRANSLATORS: "Correct" is the label of a button and intended to
|
||||||
be hit if the fingerprint matches the one of the CA. The other
|
be hit if the fingerprint matches the one of the CA. The other
|
||||||
button is "the default "Cancel" of the Pinentry. */
|
button is "the default "Cancel" of the Pinentry. */
|
||||||
rc = agent_get_confirmation (ctrl, desc, _("Correct"), NULL);
|
err = agent_get_confirmation (ctrl, desc, _("Correct"), NULL);
|
||||||
free (desc);
|
free (desc);
|
||||||
if (rc)
|
if (err)
|
||||||
{
|
return err;
|
||||||
trustfp_used--;
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (asprintf (&desc,
|
if (asprintf (&desc,
|
||||||
/* TRANSLATORS: This prompt is shown by the Pinentry
|
/* TRANSLATORS: This prompt is shown by the Pinentry
|
||||||
@ -336,83 +448,78 @@ agent_marktrusted (ctrl_t ctrl, const char *name, const char *fpr, int flag)
|
|||||||
" \"%s\"%%0A"
|
" \"%s\"%%0A"
|
||||||
"to correctly certify user certificates?"),
|
"to correctly certify user certificates?"),
|
||||||
name) < 0 )
|
name) < 0 )
|
||||||
{
|
return out_of_core ();
|
||||||
trustfp_used--;
|
|
||||||
return out_of_core ();
|
err = agent_get_confirmation (ctrl, desc, _("Yes"), _("No"));
|
||||||
}
|
|
||||||
rc = agent_get_confirmation (ctrl, desc, _("Yes"), _("No"));
|
|
||||||
free (desc);
|
free (desc);
|
||||||
if (rc)
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
/* Now check again to avoid duplicates. We take the lock to make
|
||||||
|
sure that nobody else plays with our file. Frankly we don't work
|
||||||
|
with the trusttable but using this lock is just fine for our
|
||||||
|
purpose. */
|
||||||
|
lock_trusttable ();
|
||||||
|
if (!agent_istrusted (fpr))
|
||||||
{
|
{
|
||||||
trustfp_used--;
|
unlock_trusttable ();
|
||||||
return rc;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now check again to avoid duplicates. Also open in append mode now. */
|
|
||||||
rc = open_list (1);
|
fname = make_filename (opt.homedir, "trustlist.txt", NULL);
|
||||||
if (rc)
|
if ( access (fname, F_OK) && errno == ENOENT)
|
||||||
{
|
{
|
||||||
trustfp_used--;
|
fp = fopen (fname, "wx"); /* Warning: "x" is a GNU extension. */
|
||||||
return rc;
|
if (!fp)
|
||||||
}
|
|
||||||
rewind (trustfp);
|
|
||||||
while (!(rc=read_list (key, &keyflag)))
|
|
||||||
{
|
|
||||||
if (!strcmp (key, fpr))
|
|
||||||
{
|
{
|
||||||
trustfp_used--;
|
err = gpg_error_from_syserror ();
|
||||||
return 0;
|
log_error ("can't create `%s': %s\n", fname, gpg_strerror (err));
|
||||||
|
xfree (fname);
|
||||||
|
unlock_trusttable ();
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
fputs (headerblurb, fp);
|
||||||
|
fclose (fp);
|
||||||
}
|
}
|
||||||
if (rc != -1)
|
fp = fopen (fname, "a+");
|
||||||
|
if (!fp)
|
||||||
{
|
{
|
||||||
if (trustfp)
|
err = gpg_error_from_syserror ();
|
||||||
fclose (trustfp);
|
log_error ("can't open `%s': %s\n", fname, gpg_strerror (err));
|
||||||
trustfp = NULL;
|
xfree (fname);
|
||||||
trustfp_used--;
|
unlock_trusttable ();
|
||||||
return rc; /* Error in the trustlist. */
|
return err;
|
||||||
}
|
}
|
||||||
rc = 0;
|
|
||||||
|
|
||||||
/* Append the key. */
|
/* Append the key. */
|
||||||
fflush (trustfp);
|
fputs ("\n# ", fp);
|
||||||
fputs ("\n# ", trustfp);
|
print_sanitized_string (fp, name, 0);
|
||||||
print_sanitized_string (trustfp, name, 0);
|
fprintf (fp, "\n%s %c\n", fpr, flag);
|
||||||
fprintf (trustfp, "\n%s %c\n", fpr, flag);
|
if (ferror (fp))
|
||||||
if (ferror (trustfp))
|
err = gpg_error_from_syserror ();
|
||||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
|
||||||
|
|
||||||
/* close because we are in append mode */
|
if (fclose (fp))
|
||||||
if (fclose (trustfp))
|
err = gpg_error_from_syserror ();
|
||||||
rc = gpg_error (gpg_err_code_from_errno (errno));
|
|
||||||
trustfp = NULL;
|
if (!err)
|
||||||
trustfp_used--;
|
agent_reload_trustlist ();
|
||||||
return rc;
|
xfree (fname);
|
||||||
|
unlock_trusttable ();
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
/* This function may be called to force reloading of the
|
||||||
agent_trustlist_housekeeping (void)
|
trustlist. */
|
||||||
{
|
|
||||||
if (reload_trustlist_pending && !trustfp_used)
|
|
||||||
{
|
|
||||||
if (trustfp)
|
|
||||||
{
|
|
||||||
fclose (trustfp);
|
|
||||||
trustfp = NULL;
|
|
||||||
}
|
|
||||||
reload_trustlist_pending = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Not all editors are editing files in place, thus a changes
|
|
||||||
trustlist.txt won't be recognozed if we keep the file descriptor
|
|
||||||
open. This function may be used to explicitly close that file
|
|
||||||
descriptor, which will force a reopen in turn. */
|
|
||||||
void
|
void
|
||||||
agent_reload_trustlist (void)
|
agent_reload_trustlist (void)
|
||||||
{
|
{
|
||||||
reload_trustlist_pending = 1;
|
/* All we need to do is to delete the trusttable. At the next
|
||||||
agent_trustlist_housekeeping ();
|
access it will get re-read. */
|
||||||
|
lock_trusttable ();
|
||||||
|
xfree (trusttable);
|
||||||
|
trusttable = NULL;
|
||||||
|
trusttablesize = 0;
|
||||||
|
unlock_trusttable ();
|
||||||
}
|
}
|
||||||
|
@ -153,4 +153,4 @@ $AUTOMAKE --gnu;
|
|||||||
echo "Running autoconf..."
|
echo "Running autoconf..."
|
||||||
$AUTOCONF
|
$AUTOCONF
|
||||||
|
|
||||||
echo "You may now run \"./configure --enable-maintainer-mode && make\"."
|
echo "You may now run \"./configure --sysconfdir=/etc --enable-maintainer-mode && make\"."
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
2006-09-15 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* convert.c: New.
|
||||||
|
(hexcolon2bin): New.
|
||||||
|
(bin2hex, bin2hexcolon, do_binhex): New.
|
||||||
|
* t-convert.c: New
|
||||||
|
|
||||||
2006-09-14 Werner Koch <wk@g10code.com>
|
2006-09-14 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* util.h (out_of_core): Use new gpg_error_from_syserror function.
|
* util.h (out_of_core): Use new gpg_error_from_syserror function.
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
## Process this file with automake to produce Makefile.in
|
## Process this file with automake to produce Makefile.in
|
||||||
|
|
||||||
noinst_LIBRARIES = libcommon.a libsimple-pwquery.a
|
noinst_LIBRARIES = libcommon.a libsimple-pwquery.a
|
||||||
|
noinst_PROGRAMS = $(module_tests)
|
||||||
|
TESTS = $(module_tests)
|
||||||
|
|
||||||
AM_CPPFLAGS = -I$(top_srcdir)/gl
|
AM_CPPFLAGS = -I$(top_srcdir)/gl
|
||||||
|
|
||||||
@ -39,6 +41,7 @@ libcommon_a_SOURCES = \
|
|||||||
gettime.c \
|
gettime.c \
|
||||||
yesno.c \
|
yesno.c \
|
||||||
b64enc.c \
|
b64enc.c \
|
||||||
|
convert.c \
|
||||||
miscellaneous.c \
|
miscellaneous.c \
|
||||||
xasprintf.c \
|
xasprintf.c \
|
||||||
xreadline.c \
|
xreadline.c \
|
||||||
@ -60,3 +63,15 @@ libcommon_a_SOURCES = \
|
|||||||
libsimple_pwquery_a_SOURCES = \
|
libsimple_pwquery_a_SOURCES = \
|
||||||
simple-pwquery.c simple-pwquery.h asshelp.c asshelp.h
|
simple-pwquery.c simple-pwquery.h asshelp.c asshelp.h
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Module tests
|
||||||
|
#
|
||||||
|
module_tests = t-convert
|
||||||
|
|
||||||
|
t_common_ldadd = ../jnlib/libjnlib.a ../common/libcommon.a ../gl/libgnu.a \
|
||||||
|
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS)
|
||||||
|
|
||||||
|
t_convert_DEPENDENCIES = convert.c
|
||||||
|
t_convert_LDADD = $(t_common_ldadd)
|
||||||
|
|
||||||
|
136
common/convert.c
Normal file
136
common/convert.c
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
/* convert.c - Hex conversion functions.
|
||||||
|
* Copyright (C) 2006 Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* GnuPG is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GnuPG is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
|
||||||
|
|
||||||
|
|
||||||
|
/* Convert STRING consisting of hex characters into its binary representation
|
||||||
|
and store that at BUFFER. BUFFER needs to be of LENGTH bytes. The
|
||||||
|
function check that the STRING will convert exactly to LENGTH
|
||||||
|
bytes. Colons inbetween the hex digits are allowed, if one colon
|
||||||
|
has been given a colon is expected very 2 characters. The string
|
||||||
|
is delimited by either end of string or a white space character.
|
||||||
|
The function returns -1 on error or the length of the parsed
|
||||||
|
string. */
|
||||||
|
int
|
||||||
|
hexcolon2bin (const char *string, void *buffer, size_t length)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char *s = string;
|
||||||
|
int need_colon = 0;
|
||||||
|
|
||||||
|
for (i=0; i < length; )
|
||||||
|
{
|
||||||
|
if (i==1 && *s == ':') /* Skip colons between hex digits. */
|
||||||
|
{
|
||||||
|
need_colon = 1;
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
else if (need_colon && *s == ':')
|
||||||
|
s++;
|
||||||
|
else if (need_colon)
|
||||||
|
return -1; /* Colon expected. */
|
||||||
|
if (!hexdigitp (s) || !hexdigitp (s+1))
|
||||||
|
return -1; /* Invalid hex digits. */
|
||||||
|
((unsigned char*)buffer)[i++] = xtoi_2 (s);
|
||||||
|
s += 2;
|
||||||
|
}
|
||||||
|
if (*s == ':')
|
||||||
|
return -1; /* Trailing colons are not allowed. */
|
||||||
|
if (*s && (!isascii (*s) || !isspace (*s)) )
|
||||||
|
return -1; /* Not followed by Nul or white space. */
|
||||||
|
if (i != length)
|
||||||
|
return -1; /* Not of expected length. */
|
||||||
|
if (*s)
|
||||||
|
s++; /* Skip the delimiter. */
|
||||||
|
return s - string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static char *
|
||||||
|
do_bin2hex (const void *buffer, size_t length, char *stringbuf, int with_colon)
|
||||||
|
{
|
||||||
|
const unsigned char *s;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if (!stringbuf)
|
||||||
|
{
|
||||||
|
/* Not really correct for with_colon but we don't care about the
|
||||||
|
one wasted byte. */
|
||||||
|
size_t n = with_colon? 3:2;
|
||||||
|
size_t nbytes = n * length + 1;
|
||||||
|
if (length && (nbytes-1) / n != length)
|
||||||
|
{
|
||||||
|
errno = ENOMEM;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
stringbuf = xtrymalloc (nbytes);
|
||||||
|
if (!stringbuf)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (s = buffer, p = stringbuf; length; length--, s++)
|
||||||
|
{
|
||||||
|
if (with_colon && s != buffer)
|
||||||
|
*p++ = ':';
|
||||||
|
*p++ = tohex ((*s>>4)&15);
|
||||||
|
*p++ = tohex (*s&15);
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
return stringbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Convert LENGTH bytes of data in BUFFER into hex encoding and store
|
||||||
|
that at the provided STRINGBUF. STRINGBUF must be allocated of at
|
||||||
|
least (2*LENGTH+1) bytes or be NULL so that the function mallocs an
|
||||||
|
appropriate buffer. Returns STRINGBUF or NULL on error (which may
|
||||||
|
only occur if STRINGBUF has been NULL and the internal malloc
|
||||||
|
failed). */
|
||||||
|
char *
|
||||||
|
bin2hex (const void *buffer, size_t length, char *stringbuf)
|
||||||
|
{
|
||||||
|
return do_bin2hex (buffer, length, stringbuf, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert LENGTH bytes of data in BUFFER into hex encoding and store
|
||||||
|
that at the provided STRINGBUF. STRINGBUF must be allocated of at
|
||||||
|
least (3*LENGTH+1) bytes or be NULL so that the function mallocs an
|
||||||
|
appropriate buffer. Returns STRINGBUF or NULL on error (which may
|
||||||
|
only occur if STRINGBUF has been NULL and the internal malloc
|
||||||
|
failed). */
|
||||||
|
char *
|
||||||
|
bin2hexcolon (const void *buffer, size_t length, char *stringbuf)
|
||||||
|
{
|
||||||
|
return do_bin2hex (buffer, length, stringbuf, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
204
common/t-convert.c
Normal file
204
common/t-convert.c
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
/* t-convert.c - Module test for convert.c
|
||||||
|
* Copyright (C) 2006 Free Software Foundation, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* GnuPG is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GnuPG is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
* USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define pass() do { ; } while(0)
|
||||||
|
#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
|
||||||
|
__FILE__,__LINE__, (a)); \
|
||||||
|
exit (1); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_hexcolon2bin (void)
|
||||||
|
{
|
||||||
|
static const char *valid[] = {
|
||||||
|
"00112233445566778899aabbccddeeff11223344",
|
||||||
|
"00112233445566778899AABBCCDDEEFF11223344",
|
||||||
|
"00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44",
|
||||||
|
"00112233445566778899AABBCCDDEEFF11223344 blah",
|
||||||
|
"00112233445566778899AABBCCDDEEFF11223344\tblah",
|
||||||
|
"00112233445566778899AABBCCDDEEFF11223344\nblah",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
static const char *invalid[] = {
|
||||||
|
"00112233445566778899aabbccddeeff1122334",
|
||||||
|
"00112233445566778899AABBCCDDEEFF1122334",
|
||||||
|
"00112233445566778899AABBCCDDEEFG11223344",
|
||||||
|
":00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44",
|
||||||
|
"00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44:",
|
||||||
|
"00:11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:3344",
|
||||||
|
"00:1122:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44",
|
||||||
|
"0011:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44",
|
||||||
|
"00 11:22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44",
|
||||||
|
"00:11 22:33:44:55:66:77:88:99:aa:bb:cc:dd:ee:ff:11:22:33:44",
|
||||||
|
"00112233445566778899aabbccddeeff112233445",
|
||||||
|
"00112233445566778899aabbccddeeff1122334455",
|
||||||
|
"00112233445566778899aabbccddeeff11223344blah",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
static const char *valid2[] = {
|
||||||
|
"00",
|
||||||
|
"00 x",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
static const char *invalid2[] = {
|
||||||
|
"",
|
||||||
|
"0",
|
||||||
|
"00:",
|
||||||
|
":00",
|
||||||
|
"0:0",
|
||||||
|
"00x",
|
||||||
|
" 00",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
unsigned char buffer[20];
|
||||||
|
int len;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
|
||||||
|
for (i=0; valid[i]; i++)
|
||||||
|
{
|
||||||
|
len = hexcolon2bin (valid[i], buffer, sizeof buffer);
|
||||||
|
if (len < 0)
|
||||||
|
fail (i);
|
||||||
|
if (memcmp (buffer, ("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa"
|
||||||
|
"\xbb\xcc\xdd\xee\xff\x11\x22\x33\x44"), 20))
|
||||||
|
fail (i);
|
||||||
|
}
|
||||||
|
if (hexcolon2bin (valid[0], buffer, sizeof buffer) != 40)
|
||||||
|
fail (0);
|
||||||
|
if (hexcolon2bin (valid[3], buffer, sizeof buffer) != 41)
|
||||||
|
fail (0);
|
||||||
|
|
||||||
|
for (i=0; invalid[i]; i++)
|
||||||
|
{
|
||||||
|
len = hexcolon2bin (invalid[i], buffer, sizeof buffer);
|
||||||
|
if (!(len < 0))
|
||||||
|
fail (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; valid2[i]; i++)
|
||||||
|
{
|
||||||
|
len = hexcolon2bin (valid2[i], buffer, 1);
|
||||||
|
if (len < 0)
|
||||||
|
fail (i);
|
||||||
|
if (memcmp (buffer, "\x00", 1))
|
||||||
|
fail (i);
|
||||||
|
}
|
||||||
|
if (hexcolon2bin (valid2[0], buffer, 1) != 2)
|
||||||
|
fail (0);
|
||||||
|
if (hexcolon2bin (valid2[1], buffer, 1) != 3)
|
||||||
|
fail (0);
|
||||||
|
|
||||||
|
for (i=0; invalid2[i]; i++)
|
||||||
|
{
|
||||||
|
len = hexcolon2bin (invalid2[i], buffer, 1);
|
||||||
|
if (!(len < 0))
|
||||||
|
fail (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_bin2hex (void)
|
||||||
|
{
|
||||||
|
char stuff[20+1] = ("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa"
|
||||||
|
"\xbb\xcc\xdd\xee\xff\x01\x10\x02\xa3");
|
||||||
|
char hexstuff[] = "00112233445566778899AABBCCDDEEFF011002A3";
|
||||||
|
char buffer[2*20+1];
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
p = bin2hex (stuff, 20, buffer);
|
||||||
|
if (!p)
|
||||||
|
fail (0);
|
||||||
|
if (p != buffer)
|
||||||
|
fail (0);
|
||||||
|
if (strcmp (buffer, hexstuff))
|
||||||
|
fail (0);
|
||||||
|
|
||||||
|
p = bin2hex (stuff, 20, NULL);
|
||||||
|
if (!p)
|
||||||
|
fail (0);
|
||||||
|
if (strcmp (p, hexstuff))
|
||||||
|
fail (0);
|
||||||
|
|
||||||
|
p = bin2hex (stuff, (size_t)(-1), NULL);
|
||||||
|
if (p)
|
||||||
|
fail (0);
|
||||||
|
if (errno != ENOMEM)
|
||||||
|
fail (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_bin2hexcolon (void)
|
||||||
|
{
|
||||||
|
char stuff[20+1] = ("\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa"
|
||||||
|
"\xbb\xcc\xdd\xee\xff\x01\x10\x02\xa3");
|
||||||
|
char hexstuff[] = ("00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF"
|
||||||
|
":01:10:02:A3");
|
||||||
|
char buffer[3*20+1];
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
p = bin2hexcolon (stuff, 20, buffer);
|
||||||
|
if (!p)
|
||||||
|
fail (0);
|
||||||
|
if (p != buffer)
|
||||||
|
fail (0);
|
||||||
|
if (strcmp (buffer, hexstuff))
|
||||||
|
fail (0);
|
||||||
|
|
||||||
|
p = bin2hexcolon (stuff, 20, NULL);
|
||||||
|
if (!p)
|
||||||
|
fail (0);
|
||||||
|
if (strcmp (p, hexstuff))
|
||||||
|
fail (0);
|
||||||
|
|
||||||
|
p = bin2hexcolon (stuff, (size_t)(-1), NULL);
|
||||||
|
if (p)
|
||||||
|
fail (0);
|
||||||
|
if (errno != ENOMEM)
|
||||||
|
fail (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char **argv)
|
||||||
|
{
|
||||||
|
|
||||||
|
test_hexcolon2bin ();
|
||||||
|
test_bin2hex ();
|
||||||
|
test_bin2hexcolon ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
@ -144,6 +144,12 @@ int cmp_simple_canon_sexp (const unsigned char *a, const unsigned char *b);
|
|||||||
unsigned char *make_simple_sexp_from_hexstr (const char *line,
|
unsigned char *make_simple_sexp_from_hexstr (const char *line,
|
||||||
size_t *nscanned);
|
size_t *nscanned);
|
||||||
|
|
||||||
|
/*-- convert.c --*/
|
||||||
|
int hexcolon2bin (const char *string, void *buffer, size_t length);
|
||||||
|
char *bin2hex (const void *buffer, size_t length, char *stringbuf);
|
||||||
|
char *bin2hexcolon (const void *buffer, size_t length, char *stringbuf);
|
||||||
|
|
||||||
|
|
||||||
/*-- homedir.c --*/
|
/*-- homedir.c --*/
|
||||||
const char *default_homedir (void);
|
const char *default_homedir (void);
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
## Process this file with automake to produce Makefile.in
|
## Process this file with automake to produce Makefile.in
|
||||||
|
|
||||||
examples=examples/scd-event
|
examples = examples/README examples/scd-event examples/trustlist.txt
|
||||||
|
|
||||||
EXTRA_DIST = DETAILS HACKING TRANSLATE OpenPGP KEYSERVER samplekeys.asc \
|
EXTRA_DIST = DETAILS HACKING TRANSLATE OpenPGP KEYSERVER samplekeys.asc \
|
||||||
gnupg-badge-openpgp.eps gnupg-badge-openpgp.jpg \
|
gnupg-badge-openpgp.eps gnupg-badge-openpgp.jpg \
|
||||||
|
9
doc/examples/README
Normal file
9
doc/examples/README
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
Files in this directory:
|
||||||
|
|
||||||
|
|
||||||
|
scd-event A handler script used with scdaemon
|
||||||
|
|
||||||
|
trustlist.txt A list of trustworthy root certificates
|
||||||
|
(Please check yourself whether you actually trust them)
|
||||||
|
|
||||||
|
|
46
doc/examples/trustlist.txt
Normal file
46
doc/examples/trustlist.txt
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
# This is the global list of trusted keys. Comment lines, like this
|
||||||
|
# one, as well as empty lines are ignored. Lines have a length limit
|
||||||
|
# but this is not serious limitation as the format of the entries is
|
||||||
|
# fixed and checked by gpg-agent. A non-comment line starts with
|
||||||
|
# optional white space, followed by the SHA-1 fingerpint in hex,
|
||||||
|
# optionally followed by a flag character which my either be 'P', 'S'
|
||||||
|
# or '*'. This file will be read by gpg-agent if no local trustlist
|
||||||
|
# is available or if the statement "include-default" is used in the
|
||||||
|
# local list. You should give the gpg-agent(s) a HUP after editing
|
||||||
|
# this file.
|
||||||
|
|
||||||
|
|
||||||
|
#Serial number: 32D18D
|
||||||
|
# Issuer: /CN=6R-Ca 1:PN/NameDistinguisher=1/O=RegulierungsbehÈorde
|
||||||
|
# fÈur Telekommunikation und Post/C=DE
|
||||||
|
EA:8D:99:DD:36:AA:2D:07:1A:3C:7B:69:00:9E:51:B9:4A:2E:E7:60 S
|
||||||
|
|
||||||
|
#Serial number: 00C48C8D
|
||||||
|
# Issuer: /CN=7R-CA 1:PN/NameDistinguisher=1/O=RegulierungsbehÈorde
|
||||||
|
# fÈur Telekommunikation und Post/C=DE
|
||||||
|
DB:45:3D:1B:B0:1A:F3:23:10:6B:DE:D0:09:61:57:AA:F4:25:E0:5B S
|
||||||
|
|
||||||
|
#Serial number: 01
|
||||||
|
# Issuer: /CN=8R-CA 1:PN/O=Regulierungsbehörde für
|
||||||
|
# Telekommunikation und Post/C=DE
|
||||||
|
42:6A:F6:78:30:E9:CE:24:5B:EF:41:A2:C1:A8:51:DA:C5:0A:6D:F5 S
|
||||||
|
|
||||||
|
#Serial number: 02
|
||||||
|
# Issuer: /CN=9R-CA 1:PN/O=Regulierungsbehörde für
|
||||||
|
# Telekommunikation und Post/C=DE
|
||||||
|
75:9A:4A:CE:7C:DA:7E:89:1B:B2:72:4B:E3:76:EA:47:3A:96:97:24 S
|
||||||
|
|
||||||
|
#Serial number: 2A
|
||||||
|
# Issuer: /CN=10R-CA 1:PN/O=Bundesnetzagentur/C=DE
|
||||||
|
31:C9:D2:E6:31:4D:0B:CC:2C:1A:45:00:A6:6B:97:98:27:18:8E:CD S
|
||||||
|
|
||||||
|
#Serial number: 2D
|
||||||
|
# Issuer: /CN=11R-CA 1:PN/O=Bundesnetzagentur/C=DE
|
||||||
|
A0:8B:DF:3B:AA:EE:3F:9D:64:6C:47:81:23:21:D4:A6:18:81:67:1D S
|
||||||
|
|
||||||
|
#Serial number: 00
|
||||||
|
# Issuer: /CN=CA Cert Signing Authority/OU=http:\x2f\x2fwww.
|
||||||
|
# cacert.org/O=Root CA/EMail=support@cacert.org
|
||||||
|
13:5C:EC:36:F4:9C:B8:E9:3B:1A:B2:70:CD:80:88:46:76:CE:8F:33 S
|
||||||
|
|
||||||
|
|
@ -467,17 +467,22 @@ agent. By default they may all be found in the current home directory
|
|||||||
DC:BD:69:25:48:BD:BB:7E:31:6E:BB:80:D3:00:80:35:D4:F8:A6:CD S
|
DC:BD:69:25:48:BD:BB:7E:31:6E:BB:80:D3:00:80:35:D4:F8:A6:CD S
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
Before entering a key into this file, you need to ensure its
|
Before entering a key into this file, you need to ensure its
|
||||||
authenticity. How to do this depends on your organisation; your
|
authenticity. How to do this depends on your organisation; your
|
||||||
administrator might have already entered those keys which are deemed
|
administrator might have already entered those keys which are deemed
|
||||||
trustworthy enough into this file. Places where to look for the
|
trustworthy enough into this file. Places where to look for the
|
||||||
fingerprint of a root certificate are letters received from the CA or
|
fingerprint of a root certificate are letters received from the CA or
|
||||||
the website of the CA (after making 100% sure that this is indeed the
|
the website of the CA (after making 100% sure that this is indeed the
|
||||||
website of that CA). You may want to consider allowing interactive
|
website of that CA). You may want to consider allowing interactive
|
||||||
updates of this file by using the @xref{option --allow-mark-trusted}.
|
updates of this file by using the @xref{option --allow-mark-trusted}.
|
||||||
This is however not as secure as maintaining this file manually. It is
|
This is however not as secure as maintaining this file manually. It is
|
||||||
even advisable to change the permissions to read-only so that this file
|
even advisable to change the permissions to read-only so that this file
|
||||||
can't be changed inadvertently.
|
can't be changed inadvertently.
|
||||||
|
|
||||||
|
As a special feature a line @code{include-default} will include a global
|
||||||
|
list of trusted certificates (e.g. @file{/etc/gnupg/trustlist.txt}).
|
||||||
|
This global list is also used if the local list ios not available.
|
||||||
|
|
||||||
|
|
||||||
@item sshcontrol
|
@item sshcontrol
|
||||||
|
|
||||||
|
@ -52,7 +52,7 @@
|
|||||||
|
|
||||||
* pcsc-wrapper.c (handle_open, handle_close): Reset card and
|
* pcsc-wrapper.c (handle_open, handle_close): Reset card and
|
||||||
protocol on error/close.
|
protocol on error/close.
|
||||||
(handle_status): Don't set the stae if the state is unknown.
|
(handle_status): Don't set the state if the state is unknown.
|
||||||
(handle_reset): Ignore an error if already disconnected. May
|
(handle_reset): Ignore an error if already disconnected. May
|
||||||
happen due to system wake-up after hibernation. Suggested by Bob
|
happen due to system wake-up after hibernation. Suggested by Bob
|
||||||
Dunlop.
|
Dunlop.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user