aboutsummaryrefslogtreecommitdiffstats
path: root/g10/trustdb.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>1998-01-16 21:15:24 +0000
committerWerner Koch <[email protected]>1998-01-16 21:15:24 +0000
commit4ec1775f3eaf8733a5285460b631253b90d3c6fb (patch)
tree3061decd5793f93c5a51dab58cb45c8e79a26403 /g10/trustdb.c
parent*** empty log message *** (diff)
downloadgnupg-4ec1775f3eaf8733a5285460b631253b90d3c6fb.tar.gz
gnupg-4ec1775f3eaf8733a5285460b631253b90d3c6fb.zip
added some trust model stuff
Diffstat (limited to '')
-rw-r--r--g10/trustdb.c859
1 files changed, 765 insertions, 94 deletions
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 092e98f61..9f5bef7a1 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -34,10 +34,13 @@
#include "util.h"
#include "trustdb.h"
#include "options.h"
+#include "packet.h"
+#include "main.h"
#define TRUST_RECORD_LEN 40
#define SIGS_PER_RECORD ((TRUST_RECORD_LEN-10)/5)
+#define MAX_LIST_SIGS_DEPTH 20
struct trust_record {
byte rectype;
@@ -47,27 +50,27 @@ struct trust_record {
byte magic[2];
byte version; /* should be 1 */
byte reserved[3];
- u32 locked; /* pid of process which holds a lock */
- u32 created; /* timestamp of trustdb creation */
- u32 modified; /* timestamp of last modification */
- u32 validated; /* timestamp of last validation */
- u32 local_id_counter;
+ ulong locked; /* pid of process which holds a lock */
+ ulong created; /* timestamp of trustdb creation */
+ ulong modified; /* timestamp of last modification */
+ ulong validated; /* timestamp of last validation */
+ ulong local_id_counter;
byte marginals_needed;
byte completes_needed;
byte max_cert_depth;
} version;
struct { /* public key record */
- u32 local_id;
- u32 keyid[2];
- byte algo;
+ ulong local_id;
+ u32 keyid[2];
+ byte pubkey_algo;
byte reserved;
byte fingerprint[20];
byte ownertrust;
/* fixme: indicate a flag to */
} pubkey;
struct { /* cache record */
- u32 owner;
- u32 keyid[2]; /* needed?? */
+ ulong owner;
+ u32 keyid[2]; /* needed?? */
byte valid;
byte reserved;
byte blockhash[20];
@@ -77,10 +80,10 @@ struct trust_record {
byte trustlevel;
} cache;
struct {
- u32 owner; /* local_id of record owner (pubkey record) */
- u32 chain; /* offset of next record or NULL for last one */
+ ulong owner; /* local_id of record owner (pubkey record) */
+ ulong chain; /* offset of next record or NULL for last one */
struct {
- u32 local_id; /* of pubkey record of signator (0=unused) */
+ ulong local_id; /* of pubkey record of signator (0=unused) */
byte flag; /* reserved */
} sig[SIGS_PER_RECORD];
} sigrec;
@@ -88,29 +91,67 @@ struct trust_record {
};
typedef struct trust_record TRUSTREC;
+typedef struct {
+ ulong pubkey_id; /* localid of the pubkey */
+ ulong sig_id; /* returned signature id */
+ unsigned sig_flag; /* returned signaure record flag */
+ struct { /* internal data */
+ int eof;
+ TRUSTREC rec;
+ int index;
+ } ctl;
+} SIGREC_CONTEXT;
+
+typedef struct local_id_info *LOCAL_ID_INFO;
+struct local_id_info {
+ LOCAL_ID_INFO next;
+ ulong lid;
+ unsigned flag;
+};
+
+
static void create_db( const char *fname );
static void open_db(void);
-static int read_record( u32 recnum, TRUSTREC *rec );
-static u32 new_local_id(void);
+static int read_record( ulong recnum, TRUSTREC *rec );
+static int write_record( ulong recnum, TRUSTREC *rec );
+static ulong new_recnum(void);
+static void dump_record( ulong rnum, TRUSTREC *rec, FILE *fp );
+static int walk_sigrecs( SIGREC_CONTEXT *c );
+
+static LOCAL_ID_INFO *new_lid_table(void);
+static void release_lid_table( LOCAL_ID_INFO *tbl );
+static int get_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag );
+
+static void print_user_id( const char *text, u32 *keyid );
+static int do_list_path( ulong pubkey, int depth, int max_depth,
+ LOCAL_ID_INFO *lids, ulong *stack );
+
+static int list_sigs( ulong pubkey_id );
+
static char *db_name;
static int db_fd = -1;
static int no_io_dbg = 0;
+/* a table used to keep track of ultimately trusted keys
+ * which are the ones from our secrings */
+static LOCAL_ID_INFO *ultikey_table;
-#define buftou32( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \
+#define buftoulong( p ) ((*(byte*)(p) << 24) | (*((byte*)(p)+1)<< 16) | \
(*((byte*)(p)+2) << 8) | (*((byte*)(p)+3)))
-#define buftou16( p ) ((*((byte*)(p)) << 8) | (*((byte*)(p)+1)))
-#define u32tobuf( p, a ) do { \
+#define buftoushort( p ) ((*((byte*)(p)) << 8) | (*((byte*)(p)+1)))
+#define ulongtobuf( p, a ) do { \
((byte*)p)[0] = a >> 24; \
((byte*)p)[1] = a >> 16; \
((byte*)p)[2] = a >> 8; \
((byte*)p)[3] = a ; \
} while(0)
-#define u16tobuf( p, a ) do { \
+#define ushorttobuf( p, a ) do { \
((byte*)p)[0] = a >> 8; \
((byte*)p)[1] = a ; \
} while(0)
+#define buftou32( p) buftoulong( (p) )
+#define u32tobuf( p, a) ulongtobuf( (p), (a) )
/**************************************************
@@ -124,25 +165,18 @@ fwrite_8(FILE *fp, byte a)
log_fatal("error writing byte to trustdb: %s\n", strerror(errno) );
}
-static void
-fwrite_16(FILE *fp, u16 a)
-{
- putc( (a>>8) & 0x0ff , fp );
- if( putc( a & 0xff, fp ) == EOF )
- log_fatal("error writing u16 to trustdb: %s\n", strerror(errno) );
-}
-static int
-fwrite_32( FILE*fp, u32 a)
+static void
+fwrite_32( FILE*fp, ulong a)
{
putc( (a>>24) & 0xff, fp );
putc( (a>>16) & 0xff, fp );
putc( (a>> 8) & 0xff, fp );
if( putc( a & 0xff, fp ) == EOF )
- log_fatal("error writing u32 to trustdb: %s\n", strerror(errno) );
+ log_fatal("error writing ulong to trustdb: %s\n", strerror(errno) );
}
-static int
+static void
fwrite_zeros( FILE *fp, size_t n)
{
while( n-- )
@@ -163,8 +197,6 @@ static void
create_db( const char *fname )
{
FILE *fp;
- u32 along;
- u16 ashort;
fp =fopen( fname, "w" );
if( !fp )
@@ -207,7 +239,7 @@ open_db()
* returns: -1 on error, 0 on success
*/
static int
-read_record( u32 recnum, TRUSTREC *rec )
+read_record( ulong recnum, TRUSTREC *rec )
{
byte buf[TRUST_RECORD_LEN], *p;
int rc = 0;
@@ -242,11 +274,11 @@ read_record( u32 recnum, TRUSTREC *rec )
rec->r.version.magic[1] = *p++;
rec->r.version.version = *p++;
memcpy( rec->r.version.reserved, p, 3); p += 3;
- rec->r.version.locked = buftou32(p); p += 4;
- rec->r.version.created = buftou32(p); p += 4;
- rec->r.version.modified = buftou32(p); p += 4;
- rec->r.version.validated= buftou32(p); p += 4;
- rec->r.version.local_id_counter = buftou32(p); p += 4;
+ rec->r.version.locked = buftoulong(p); p += 4;
+ rec->r.version.created = buftoulong(p); p += 4;
+ rec->r.version.modified = buftoulong(p); p += 4;
+ rec->r.version.validated= buftoulong(p); p += 4;
+ rec->r.version.local_id_counter = buftoulong(p); p += 4;
rec->r.version.marginals_needed = *p++;
rec->r.version.completes_needed = *p++;
rec->r.version.max_cert_depth = *p++;
@@ -267,10 +299,10 @@ read_record( u32 recnum, TRUSTREC *rec )
}
break;
case 2:
- rec->r.pubkey.local_id = buftou32(p); p += 4;
+ rec->r.pubkey.local_id = buftoulong(p); p += 4;
rec->r.pubkey.keyid[0] = buftou32(p); p += 4;
rec->r.pubkey.keyid[1] = buftou32(p); p += 4;
- rec->r.pubkey.algo = *p++;
+ rec->r.pubkey.pubkey_algo = *p++;
rec->r.pubkey.reserved = *p++;
memcpy( rec->r.pubkey.fingerprint, p, 20); p += 20;
rec->r.pubkey.ownertrust = *p++;
@@ -283,7 +315,7 @@ read_record( u32 recnum, TRUSTREC *rec )
}
break;
case 3:
- rec->r.cache.local_id = buftou32(p); p += 4;
+ rec->r.cache.owner = buftoulong(p); p += 4;
rec->r.cache.keyid[0] = buftou32(p); p += 4;
rec->r.cache.keyid[1] = buftou32(p); p += 4;
rec->r.cache.valid = *p++;
@@ -296,10 +328,10 @@ read_record( u32 recnum, TRUSTREC *rec )
break;
case 4:
case 5:
- rec->r.sigrec.owner = buftou32(p); p += 4;
- rec->r.sigrec.chain = buftou32(p); p += 4;
+ rec->r.sigrec.owner = buftoulong(p); p += 4;
+ rec->r.sigrec.chain = buftoulong(p); p += 4;
for(i=0; i < SIGS_PER_RECORD; i++ ) {
- rec->r.sigrec.sig[i].local_id = buftou32(p); p += 4;
+ rec->r.sigrec.sig[i].local_id = buftoulong(p); p += 4;
rec->r.sigrec.sig[i].flag = *p++;
}
break;
@@ -309,7 +341,10 @@ read_record( u32 recnum, TRUSTREC *rec )
rc = G10ERR_TRUSTDB;
break;
}
-
+ if( DBG_TRUST && !rc && !no_io_dbg ) {
+ log_debug("trustdb: ");
+ dump_record( recnum, rec, stderr);
+ }
return rc;
}
@@ -318,7 +353,7 @@ read_record( u32 recnum, TRUSTREC *rec )
* Write the record at RECNUM
*/
static int
-write_record( u32 recnum, TRUSTREC *rec )
+write_record( ulong recnum, TRUSTREC *rec )
{
byte buf[TRUST_RECORD_LEN], *p;
int rc = 0;
@@ -337,20 +372,20 @@ write_record( u32 recnum, TRUSTREC *rec )
case 0: /* unused record */
break;
case 1: /* version record */
- log_bug(NULL);
+ BUG();
break;
case 2:
- u32tobuf(p, rec->r.pubkey.local_id); p += 4;
+ ulongtobuf(p, rec->r.pubkey.local_id); p += 4;
u32tobuf(p, rec->r.pubkey.keyid[0]); p += 4;
u32tobuf(p, rec->r.pubkey.keyid[1]); p += 4;
- *p++ = rec->r.pubkey.algo;
+ *p++ = rec->r.pubkey.pubkey_algo;
*p++ = rec->r.pubkey.reserved;
memcpy( p, rec->r.pubkey.fingerprint, 20); p += 20;
*p++ = rec->r.pubkey.ownertrust;
assert( rec->r.pubkey.local_id == recnum );
break;
case 3:
- u32tobuf(p, rec->r.cache.local_id); p += 4;
+ ulongtobuf(p, rec->r.cache.owner); p += 4;
u32tobuf(p, rec->r.cache.keyid[0]); p += 4;
u32tobuf(p, rec->r.cache.keyid[1]); p += 4;
*p++ = rec->r.cache.valid;
@@ -363,15 +398,15 @@ write_record( u32 recnum, TRUSTREC *rec )
break;
case 4:
case 5:
- u32tobuf(p, rec->r.sigrec.owner); p += 4;
- u32tobuf(p, rec->r.sigrec.chain); p += 4;
+ ulongtobuf(p, rec->r.sigrec.owner); p += 4;
+ ulongtobuf(p, rec->r.sigrec.chain); p += 4;
for(i=0; i < SIGS_PER_RECORD; i++ ) {
- u32tobuf(p, rec->r.sigrec.sig[i].local_id); p += 4;
+ ulongtobuf(p, rec->r.sigrec.sig[i].local_id); p += 4;
*p++ = rec->r.sigrec.sig[i].flag;
}
break;
default:
- log_bug(NULL);
+ BUG();
}
if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
@@ -387,11 +422,18 @@ write_record( u32 recnum, TRUSTREC *rec )
return rc;
}
-static u32
-new_local_id()
+
+
+/****************
+ * create a new record and return its record number
+ */
+static ulong
+new_recnum()
{
off_t offset;
- u32 recnum;
+ ulong recnum;
+ TRUSTREC rec;
+ int rc;
/* fixme: look for unused records */
offset = lseek( db_fd, 0, SEEK_END );
@@ -399,6 +441,15 @@ new_local_id()
log_fatal("trustdb: lseek to end failed: %s\n", strerror(errno) );
recnum = offset / TRUST_RECORD_LEN;
assert(recnum); /* this is will never be the first record */
+
+ /* we must write a record, so that the next call to this function
+ * returns another recnum */
+ memset( &rec, 0, sizeof rec );
+ rec.rectype = 0; /* free record */
+ rc = write_record(recnum, &rec );
+ if( rc )
+ log_fatal("%s: failed to append a record: %s\n",
+ db_name, g10_errstr(rc));
return recnum ;
}
@@ -409,11 +460,10 @@ new_local_id()
static int
scan_record_by_pkc( PKT_public_cert *pkc, TRUSTREC *rec, int rectype )
{
- u32 recnum;
+ ulong recnum;
u32 keyid[2];
byte *fingerprint;
size_t fingerlen;
- int dbg = DBG_TRUST;
int rc;
assert( rectype == 2 || rectype == 3 );
@@ -431,7 +481,7 @@ scan_record_by_pkc( PKT_public_cert *pkc, TRUSTREC *rec, int rectype )
if( rec->rectype == 2 ) {
if( rec->r.pubkey.keyid[0] == keyid[0]
&& rec->r.pubkey.keyid[1] == keyid[1]
- && rec->r.pubkey.algo == pkc->pubkey_algo
+ && rec->r.pubkey.pubkey_algo == pkc->pubkey_algo
&& !memcmp(rec->r.pubkey.fingerprint, fingerprint, fingerlen)
) { /* found */
/* store the local_id */
@@ -460,11 +510,9 @@ scan_record_by_pkc( PKT_public_cert *pkc, TRUSTREC *rec, int rectype )
* with LOCAL_ID
*/
static int
-scan_record( u32 local_id, TRUSTREC *rec, int rectype, u32 *r_recnum )
+scan_record( ulong local_id, TRUSTREC *rec, int rectype, ulong *r_recnum )
{
- u32 recnum;
- u32 keyid[2];
- int dbg = DBG_TRUST;
+ ulong recnum;
int rc;
assert( rectype == 3 || rectype == 4 );
@@ -502,11 +550,292 @@ scan_record( u32 local_id, TRUSTREC *rec, int rectype, u32 *r_recnum )
}
+static void
+dump_record( ulong rnum, TRUSTREC *rec, FILE *fp )
+{
+ int i, any;
+
+ fprintf(fp, "trust record %lu, type=", rnum );
+
+ switch( rec->rectype ) {
+ case 0: fprintf(fp, "free\n");
+ break;
+ case 1: fprintf(fp, "version\n");
+ break;
+ case 2: fprintf(fp, "pubkey, keyid=%08lX, ownertrust=%02x\n",
+ rec->r.pubkey.keyid[1], rec->r.pubkey.ownertrust );
+ break;
+ case 3: fprintf(fp, "cache\n");
+ case 4:
+ case 5:
+ fprintf(fp, "sigrec, owner=%lu, chain=%lu%s\n",
+ rec->r.sigrec.owner, rec->r.sigrec.chain,
+ rec->rectype == 4?"":" (extend)");
+ for(i=any=0; i < SIGS_PER_RECORD; i++ ) {
+ if( rec->r.sigrec.sig[i].local_id ) {
+ if( !any ) {
+ putc('\t', fp);
+ any++;
+ }
+ fprintf(fp, " %lu:%02x", rec->r.sigrec.sig[i].local_id,
+ rec->r.sigrec.sig[i].flag );
+ }
+ }
+ if( any )
+ putc('\n', fp);
+ break;
+ default:
+ fprintf(fp, "%d (unknown)\n", rec->rectype );
+ break;
+ }
+}
+
+
+/****************
+ * If we do not have a local_id in a signature packet, find the owner of
+ * the signature packet in our trustdb or insert him into the trustdb
+ */
+static int
+set_signature_packets_local_id( PKT_signature *sig )
+{
+ PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
+ TRUSTREC rec;
+ int rc;
+
+ rc = get_pubkey( pkc, sig->keyid );
+ if( rc)
+ goto leave;
+ if( !pkc->local_id ) {
+ rc = scan_record_by_pkc( pkc, &rec, 2 );
+ if( rc == -1 )
+ rc = insert_trust_record( pkc );
+ if( rc )
+ goto leave;
+ /* fixme: we should propagate the local_id to all copies of the PKC */
+ }
+ sig->local_id = pkc->local_id;
+
+ leave:
+ free_public_cert( pkc );
+ return rc;
+}
+
+
+void
+list_trustdb( const char *username )
+{
+ TRUSTREC rec;
+
+ if( username ) {
+ PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
+ int rc;
+
+ if( (rc = get_pubkey_byname( pkc, username )) )
+ log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
+ else if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 )
+ log_error("problem finding '%s' in trustdb: %s\n",
+ username, g10_errstr(rc));
+ else if( rc == -1 )
+ log_error("user '%s' not in trustdb\n", username);
+ else if( (rc = list_sigs( pkc->local_id )) )
+ log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
+ free_public_cert( pkc );
+ }
+ else {
+ ulong recnum;
+ int i;
+
+ printf("TrustDB: %s\n", db_name );
+ for(i=9+strlen(db_name); i > 0; i-- )
+ putchar('-');
+ putchar('\n');
+ no_io_dbg = 1;
+ for(recnum=0; !read_record( recnum, &rec); recnum++ )
+ dump_record( recnum, &rec, stdout );
+ no_io_dbg = 0;
+ }
+}
+
+void
+list_trust_path( int max_depth, const char *username )
+{
+ int rc;
+ TRUSTREC rec;
+ PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
+
+ if( max_depth < 1 )
+ max_depth = MAX_LIST_SIGS_DEPTH+1;
+
+
+ if( (rc = get_pubkey_byname( pkc, username )) )
+ log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
+ else if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 )
+ log_error("problem finding '%s' in trustdb: %s\n",
+ username, g10_errstr(rc));
+ else if( rc == -1 )
+ log_error("user '%s' not in trustdb\n", username);
+ else {
+ LOCAL_ID_INFO *lids;
+ ulong stack[MAX_LIST_SIGS_DEPTH];
+
+ lids = new_lid_table();
+ stack[0] = pkc->local_id;
+ rc = do_list_path( pkc->local_id, 1, max_depth, lids, stack );
+ putchar('\n');
+
+ release_lid_table(lids);
+ if( rc )
+ log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
+ }
+
+ free_public_cert( pkc );
+}
+
+/****************
+ * Walk throug the signatures of a public key.
+ * The caller must provide a context structure, with all fields set
+ * to zero, but the pubkeyid filed set to the requested pubkey;
+ * This function does not change this field. On return the context
+ * is filled with the local-id of the signature and the signature flag.
+ * No fields should be changed (clearing all fields and setting
+ * pubkeyid is okay to continue with an other pubkey)
+ * Returns: 0 - okay, -1 for eof (no more sigs) or any other errorcode
+ */
+static int
+walk_sigrecs( SIGREC_CONTEXT *c )
+{
+ int rc=0;
+ TRUSTREC *r;
+ ulong rnum;
+
+ if( c->ctl.eof )
+ return -1;
+ r = &c->ctl.rec;
+ if( !r->rectype ) { /* this is the first call */
+ rc = scan_record( c->pubkey_id, r, 4, &rnum );
+ if( rc == -1 ) { /* no signature records */
+ c->ctl.eof = 1;
+ return -1; /* return eof */
+ }
+ if( rc ) {
+ log_error("scan_record(sigrec) failed: %s\n", g10_errstr(rc));
+ c->ctl.eof = 1;
+ return rc;
+ }
+ c->ctl.index = 0;
+ }
+ /* enter loop to skip deleted sigs */
+ do {
+ if( c->ctl.index >= SIGS_PER_RECORD ) {
+ /* read the next record */
+ if( !r->r.sigrec.chain ) {
+ c->ctl.eof = 1;
+ return -1; /* return eof */
+ }
+ rnum = r->r.sigrec.chain;
+ rc = read_record( rnum, r );
+ if( rc ) {
+ log_error("error reading next sigrec: %s\n", g10_errstr(rc));
+ c->ctl.eof = 1;
+ return rc;
+ }
+ if( r->r.sigrec.owner != c->pubkey_id ) {
+ log_error("chained sigrec %lu has a wrong owner\n", rnum );
+ c->ctl.eof = 1;
+ return G10ERR_TRUSTDB;
+ }
+ c->ctl.index = 0;
+ }
+ } while( !r->r.sigrec.sig[c->ctl.index++].local_id );
+ c->sig_id = r->r.sigrec.sig[c->ctl.index-1].local_id;
+ c->sig_flag = r->r.sigrec.sig[c->ctl.index-1].flag;
+ return 0;
+}
/***********************************************
************* trust logic *******************
***********************************************/
+static LOCAL_ID_INFO *
+new_lid_table(void)
+{
+ return m_alloc_clear( 16 * sizeof(LOCAL_ID_INFO));
+}
+
+static void
+release_lid_table( LOCAL_ID_INFO *tbl )
+{
+ LOCAL_ID_INFO a, a2;
+ int i;
+
+ for(i=0; i < 16; i++ ) {
+ for(a=tbl[i]; a; a = a2 ) {
+ a2 = a->next;
+ m_free(a);
+ }
+ }
+ m_free(tbl);
+}
+
+/****************
+ * Add a new item to the table or return 1 if we aread have this item
+ * fixme: maybe its a good idea to tage items from an unused item list.
+ */
+static int
+add_lid_table_item( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag )
+{
+ LOCAL_ID_INFO a;
+
+ for( a = tbl[lid & 0x0f]; a; a = a->next )
+ if( a->lid == lid )
+ return 1;
+ a = m_alloc( sizeof *a );
+ a->lid = lid;
+ a->flag = flag;
+ a->next = tbl[lid & 0x0f];
+ tbl[lid & 0x0f] = a;
+ return 0;
+}
+
+static int
+get_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag )
+{
+ LOCAL_ID_INFO a;
+
+ for( a = tbl[lid & 0x0f]; a; a = a->next )
+ if( a->lid == lid ) {
+ if( flag )
+ *flag = a->flag;
+ return 0;
+ }
+ return -1;
+}
+
+
+
+
+static int
+keyid_from_local_id( ulong lid, u32 *keyid )
+{
+ TRUSTREC rec;
+ int rc;
+
+ rc = read_record( lid, &rec );
+ if( rc ) {
+ log_error("error reading record with local_id %lu: %s\n",
+ lid, g10_errstr(rc));
+ return G10ERR_TRUSTDB;
+ }
+ if( rec.rectype != 2 ) {
+ log_error("record with local_id %lu is not a pubkey record\n", lid);
+ return G10ERR_TRUSTDB;
+ }
+ keyid[0] = rec.r.pubkey.keyid[0];
+ keyid[1] = rec.r.pubkey.keyid[1];
+ return 0;
+}
+
+
/****************
* Verify, that all our public keys are in the trustDB and marked as
* ultimately trusted.
@@ -522,7 +851,7 @@ verify_own_certs()
int trust;
while( !(rc=enum_secret_keys( &enum_context, skc) ) ) {
- /* fixme: to be sure that it is a secret key of our own,
+ /* fixed: to be sure that it is a secret key of our own,
* we should check it, but this needs a passphrase
* for every key and this boring for the user.
* Solution: Sign the secring and the trustring
@@ -557,12 +886,26 @@ verify_own_certs()
}
if( trust & TRUST_NO_PUBKEY ) {
log_info("keyid %08lX: not yet in trustdb\n", (ulong)keyid[1] );
- /* FIXME: insert */
+ rc = insert_trust_record( pkc );
+ if( rc )
+ log_error("keyid %08lX: insert failed: %s\n",
+ (ulong)keyid[1], g10_errstr(rc) );
+ else
+ log_info("keyid %08lX: inserted\n", (ulong)keyid[1] );
}
else if( (trust & TRUST_MASK) != TRUST_ULT_TRUST ) {
- log_error("keyid %08lX: not marked as ultimately trusted\n",
+ /*log_error("keyid %08lX: not marked as ultimately trusted\n",
(ulong)keyid[1] );
- /* FIXME: mark */
+ FIXME: mark */
+ }
+
+ if( !(trust & TRUST_NO_PUBKEY) ) {
+ if( DBG_TRUST )
+ log_debug("putting %08lX(%lu) into ultikey_table\n",
+ (ulong)keyid[1], pkc->local_id );
+ if( add_lid_table_item( ultikey_table, pkc->local_id, 0 ) )
+ log_error("keyid %08lX: already in ultikey_table\n",
+ (ulong)keyid[1]);
}
release_secret_cert_parts( skc );
@@ -579,6 +922,156 @@ verify_own_certs()
return rc;
}
+static void
+print_user_id( const char *text, u32 *keyid )
+{
+ char *p;
+ size_t n;
+
+ p = get_user_id( keyid, &n );
+ if( *text ) {
+ fputs( text, stdout);
+ putchar(' ');
+ }
+ putchar('\"');
+ print_string( stdout, p, n );
+ putchar('\"');
+ putchar('\n');
+ m_free(p);
+}
+
+/* (a non-recursive algorithm would be easier) */
+static int
+do_list_sigs( ulong root, ulong pubkey, int depth,
+ LOCAL_ID_INFO *lids, unsigned *lineno )
+{
+ SIGREC_CONTEXT sx;
+ int rc;
+ u32 keyid[2];
+
+ memset( &sx, 0, sizeof sx );
+ sx.pubkey_id = pubkey;
+ for(;;) {
+ rc = walk_sigrecs( &sx );
+ if( rc )
+ break;
+ rc = keyid_from_local_id( sx.sig_id, keyid );
+ if( rc ) {
+ printf("%6u: %*s????????(%lu:%02x)\n", *lineno, depth*4, "",
+ sx.sig_id, sx.sig_flag );
+ ++*lineno;
+ }
+ else {
+ printf("%6u: %*s%08lX(%lu:%02x) ", *lineno, depth*4, "",
+ (ulong)keyid[1], sx.sig_id, sx.sig_flag );
+ /* check wether we already checked this pubkey */
+ if( !get_lid_table_flag( ultikey_table, sx.sig_id, NULL ) ) {
+ print_user_id("[ultimately trusted]", keyid);
+ ++*lineno;
+ }
+ else if( sx.sig_id == pubkey ) {
+ printf("[self-signature]\n");
+ ++*lineno;
+ }
+ else if( sx.sig_id == root ) {
+ printf("[closed]\n");
+ ++*lineno;
+ }
+ else if( add_lid_table_item( lids, sx.sig_id, *lineno ) ) {
+ unsigned refline;
+ get_lid_table_flag( lids, sx.sig_id, &refline );
+ printf("[see line %u]\n", refline);
+ ++*lineno;
+ }
+ else if( depth+1 >= MAX_LIST_SIGS_DEPTH ) {
+ print_user_id( "[too deeply nested]", keyid );
+ ++*lineno;
+ }
+ else {
+ print_user_id( "", keyid );
+ ++*lineno;
+ rc = do_list_sigs( root, sx.sig_id, depth+1, lids, lineno );
+ if( rc )
+ break;
+ }
+ }
+ }
+ return rc==-1? 0 : rc;
+}
+
+/****************
+ * List all signatures of a public key
+ */
+static int
+list_sigs( ulong pubkey_id )
+{
+ int rc;
+ u32 keyid[2];
+ LOCAL_ID_INFO *lids;
+ unsigned lineno = 1;
+
+ rc = keyid_from_local_id( pubkey_id, keyid );
+ if( rc ) {
+ log_error("Hmmm, no pubkey record for local_id %lu\n", pubkey_id);
+ return rc;
+ }
+ printf("Signatures of %08lX(%lu) ", (ulong)keyid[1], pubkey_id );
+ print_user_id("", keyid);
+ printf("----------------------\n");
+
+ lids = new_lid_table();
+ rc = do_list_sigs( pubkey_id, pubkey_id, 0, lids, &lineno );
+ putchar('\n');
+ release_lid_table(lids);
+ return rc;
+}
+
+
+
+
+
+static int
+do_list_path( ulong pubkey, int depth, int max_depth,
+ LOCAL_ID_INFO *lids, ulong *stack )
+{
+ SIGREC_CONTEXT sx;
+ int rc;
+
+ if( depth > max_depth || depth >= MAX_LIST_SIGS_DEPTH )
+ return 0;
+ if( !get_lid_table_flag( ultikey_table, pubkey, NULL ) ) {
+ /* found a path */
+ int i;
+ u32 keyid[2];
+
+ for(i=0; i < depth; i++ ) {
+ if( keyid_from_local_id( stack[i], keyid ) )
+ printf("%*s????????(%lu) ", i*4,"", stack[i] );
+ else {
+ printf("%*s%08lX(%lu) ", i*4,"", keyid[1], stack[i] );
+ print_user_id("", keyid );
+ }
+ }
+ putchar('\n');
+ return 0;
+ }
+
+ if( add_lid_table_item( lids, pubkey, 0 ) )
+ return 0;
+
+ memset( &sx, 0, sizeof sx );
+ sx.pubkey_id = pubkey;
+ do {
+ rc = walk_sigrecs( &sx );
+ if( !rc ) {
+ stack[depth] = sx.sig_id;
+ rc = do_list_path( sx.sig_id, depth+1, max_depth, lids, stack );
+ }
+ } while( !rc );
+ return rc==-1? 0 : rc;
+}
+
+
/****************
@@ -586,23 +1079,30 @@ verify_own_certs()
* as checked.
*/
static int
-check_sigs( KBNODE keyblock )
+check_sigs( KBNODE keyblock, int *selfsig_okay )
{
KBNODE kbctx;
KBNODE node;
int rc;
+ *selfsig_okay = 0;
for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
if( node->pkt->pkttype == PKT_SIGNATURE
&& (node->pkt->pkt.signature->sig_class&~3) == 0x10 ) {
- PKT_signature *sig = node->pkt->pkt.signature;
-
- rc = check_key_signature( keyblock, node );
- if( !rc )
- node->flag |= 1; /* mark signature valid */
+ int selfsig;
+ rc = check_key_signature( keyblock, node, &selfsig );
+ if( !rc ) {
+ if( selfsig ) {
+ node->flag |= 2; /* mark signature valid */
+ *selfsig_okay = 1;
+ }
+ else
+ node->flag |= 1; /* mark signature valid */
+ }
if( DBG_TRUST )
log_debug("trustdb: sig from %08lX: %s\n",
- rc? g10_errstr(rc): "okay" );
+ (ulong)node->pkt->pkt.signature->keyid[1],
+ g10_errstr(rc) );
}
}
return 0;
@@ -614,8 +1114,124 @@ check_sigs( KBNODE keyblock )
* to the trustdb
*/
static int
-build_sigrecs( KBNODE keyblock )
+build_sigrecs( ulong pubkeyid )
{
+ TRUSTREC rec, rec2;
+ PUBKEY_FIND_INFO finfo=NULL;
+ KBPOS kbpos;
+ KBNODE keyblock = NULL;
+ KBNODE kbctx;
+ KBNODE node;
+ int rc=0;
+ int i, selfsig;
+ ulong rnum, rnum2;
+
+ if( DBG_TRUST )
+ log_debug("trustdb: build_sigrecs for pubkey %lu\n", (ulong)pubkeyid );
+
+ /* get the keyblock */
+ if( (rc=read_record( pubkeyid, &rec )) ) {
+ log_error("build_sigrecs: can't read pubkey record\n");
+ goto leave;
+ }
+ finfo = m_alloc_clear( sizeof *finfo );
+ finfo->keyid[0] = rec.r.pubkey.keyid[0];
+ finfo->keyid[1] = rec.r.pubkey.keyid[1];
+ finfo->pubkey_algo = rec.r.pubkey.pubkey_algo;
+ memcpy( finfo->fingerprint, rec.r.pubkey.fingerprint, 20);
+ rc = find_keyblock( finfo, &kbpos );
+ if( rc ) {
+ log_error("build_sigrecs: find_keyblock failed\n" );
+ goto leave;
+ }
+ rc = read_keyblock( &kbpos, &keyblock );
+ if( rc ) {
+ log_error("build_sigrecs: read_keyblock failed\n" );
+ goto leave;
+ }
+ /* check all key signatures */
+ rc = check_sigs( keyblock, &selfsig );
+ if( rc ) {
+ log_error("build_sigrecs: check_sigs failed\n" );
+ goto leave;
+ }
+ if( !selfsig ) {
+ log_error("build_sigrecs: self-certificate missing\n" );
+ rc = G10ERR_BAD_CERT;
+ goto leave;
+ }
+
+ /* valid key signatures are now marked; we can now build the
+ * sigrecs */
+ memset( &rec, 0, sizeof rec );
+ rec.rectype = 4;
+ i = 0;
+ rnum = rnum2 = 0;
+ for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
+ if( node->flag & 1 ) {
+ assert( node->pkt->pkttype == PKT_SIGNATURE );
+ if( !node->pkt->pkt.signature->local_id ) {
+ /* the next function should always succeed, because
+ * we have already checked the signature, and for this
+ * it was necessary to have the pubkey. The only reason
+ * this can fail are I/o erros of the trustdb. */
+ rc = set_signature_packets_local_id( node->pkt->pkt.signature );
+ if( rc )
+ log_fatal("set_signature_packets_local_id failed: %s\n",
+ g10_errstr(rc));
+ }
+ if( i == SIGS_PER_RECORD ) {
+ /* write the record */
+ rnum = new_recnum();
+ if( rnum2 ) { /* write the stored record */
+ rec2.r.sigrec.owner = pubkeyid;
+ rec2.r.sigrec.chain = rnum; /* the next record number */
+ rc = write_record( rnum2, &rec2 );
+ if( rc ) {
+ log_error("build_sigrecs: write_record failed\n" );
+ goto leave;
+ }
+ }
+ rec2 = rec;
+ rnum2 = rnum;
+ memset( &rec, 0, sizeof rec );
+ rec.rectype = 5;
+ i = 0;
+ }
+ rec.r.sigrec.sig[i].local_id = node->pkt->pkt.signature->local_id;
+ rec.r.sigrec.sig[i].flag = 0;
+ i++;
+ }
+ }
+ if( i || rnum2 ) {
+ /* write the record */
+ rnum = new_recnum();
+ if( rnum2 ) { /* write the stored record */
+ rec2.r.sigrec.owner = pubkeyid;
+ rec2.r.sigrec.chain = rnum;
+ rc = write_record( rnum2, &rec2 );
+ if( rc ) {
+ log_error("build_sigrecs: write_record failed\n" );
+ goto leave;
+ }
+ }
+ if( i ) { /* write the pending record */
+ rec.r.sigrec.owner = pubkeyid;
+ rec.r.sigrec.chain = 0;
+ rc = write_record( rnum, &rec );
+ if( rc ) {
+ log_error("build_sigrecs: write_record failed\n" );
+ goto leave;
+ }
+ }
+ }
+
+ leave:
+ m_free( finfo );
+ release_kbnode( keyblock );
+ if( DBG_TRUST )
+ log_debug("trustdb: build_sigrecs: %s\n", g10_errstr(rc) );
+ return rc;
}
@@ -624,6 +1240,7 @@ build_sigrecs( KBNODE keyblock )
/****************
* Recursive check the signatures.
*/
+ #if 0
static int
walk( KBNODE keyblock, int levels )
{
@@ -640,9 +1257,9 @@ walk( KBNODE keyblock, int levels )
}
}
}
-
+ return -1;
}
-
+#endif
@@ -651,10 +1268,25 @@ walk( KBNODE keyblock, int levels )
*
*/
static int
-check_trust()
+check_trust( ulong pubkeyid )
{
- /* check the ca
+ int rc=0;
+ ulong rnum;
+ TRUSTREC rec;
+
+ /* verify the cache */
+
+ /* do we have sigrecs */
+ rc = scan_record( pubkeyid, &rec, 4, &rnum );
+ if( rc == -1 ) { /* no sigrecs, so build them */
+ rc = build_sigrecs( pubkeyid );
+ if( !rc ) /* and read again */
+ rc = scan_record( pubkeyid, &rec, 4, &rnum );
+ }
+ if( rc )
+ return rc; /* error while looking for sigrec or building sigrecs */
+ return 0;
}
@@ -665,26 +1297,34 @@ check_trust()
/****************
* Perform some checks over the trustdb
- * level 0: used for initial program startup
+ * level 0: only open the db
+ * 1: used for initial program startup
*/
int
-check_trustdb( int level )
+init_trustdb( int level )
{
int rc=0;
- if( !level ) {
- char *fname = make_filename("~/.g10", "trustDB", NULL );
+ if( !ultikey_table )
+ ultikey_table = new_lid_table();
+
+ if( !level || level==1 ) {
+ char *fname = make_filename("~/.g10", "trustdb.g10", NULL );
if( access( fname, R_OK ) ) {
if( errno != ENOENT ) {
log_error("can't access %s: %s\n", fname, strerror(errno) );
m_free(fname);
return G10ERR_TRUSTDB;
}
- create_db( fname );
+ if( level )
+ create_db( fname );
}
m_free(db_name);
db_name = fname;
+ if( !level )
+ return 0;
+
/* we can verify a signature about our local data (secring and trustdb)
* in ~/.g10/ here */
rc = verify_private_data();
@@ -699,7 +1339,7 @@ check_trustdb( int level )
}
}
else
- log_bug(NULL);
+ BUG();
return rc;
}
@@ -747,7 +1387,7 @@ check_pkc_trust( PKT_public_cert *pkc, int *r_trustlevel )
if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) {
log_error("check_pkc_trust: scan_record_by_pkc(2) failed: %s\n",
g10_errstr(rc));
- return G10ERR_TRUSTDB;
+ return rc;
}
else if( rc == -1 ) {
log_error("check_pkc_trust: pubkey not in TrustDB\n");
@@ -757,7 +1397,11 @@ check_pkc_trust( PKT_public_cert *pkc, int *r_trustlevel )
}
/* fixme: do some additional checks on the pubkey record */
- /* see wether we have a cache record */
+ rc = check_trust( pkc->local_id );
+ if( rc ) {
+ log_error("check_pkc_trust: check_trust failed: %s\n", g10_errstr(rc));
+ return rc;
+ }
leave:
@@ -768,6 +1412,33 @@ check_pkc_trust( PKT_public_cert *pkc, int *r_trustlevel )
}
+int
+get_ownertrust( PKT_public_cert *pkc, int *r_otrust )
+{
+ TRUSTREC rec;
+ int rc;
+
+ /* get the pubkey record */
+ if( pkc->local_id ) {
+ if( read_record( pkc->local_id, &rec ) ) {
+ log_error("get_ownertrust: read record failed\n");
+ return G10ERR_TRUSTDB;
+ }
+ }
+ else { /* no local_id: scan the trustdb */
+ if( (rc=scan_record_by_pkc( pkc, &rec, 2 )) && rc != -1 ) {
+ log_error("get_ownertrust: scan_record_by_pkc(2) failed: %s\n",
+ g10_errstr(rc));
+ return rc;
+ }
+ else if( rc == -1 )
+ return rc;
+ }
+ *r_otrust = rec.r.pubkey.ownertrust;
+ return 0;
+}
+
+
/****************
* Insert a trust record into the TrustDB
* This function failes if this record already exists.
@@ -777,7 +1448,7 @@ insert_trust_record( PKT_public_cert *pkc )
{
TRUSTREC rec;
u32 keyid[2];
- u32 recnum;
+ ulong recnum;
byte *fingerprint;
size_t fingerlen;
@@ -785,21 +1456,22 @@ insert_trust_record( PKT_public_cert *pkc )
if( DBG_TRUST )
log_debug("trustdb: insert_record\n");
- assert( !pkc->local_id );
+ if( pkc->local_id )
+ log_bug("pkc->local_id=%lu\n", (ulong)pkc->local_id );
keyid_from_pkc( pkc, keyid );
fingerprint = fingerprint_from_pkc( pkc, &fingerlen );
/* FIXME: check that we do not have this record. */
- recnum = new_local_id();
+ recnum = new_recnum();
/* build record */
memset( &rec, 0, sizeof rec );
rec.rectype = 2; /* the pubkey record */
rec.r.pubkey.local_id = recnum;
rec.r.pubkey.keyid[0] = keyid[0];
rec.r.pubkey.keyid[1] = keyid[1];
- rec.r.pubkey.algo = pkc->pubkey_algo;
+ rec.r.pubkey.pubkey_algo = pkc->pubkey_algo;
memcpy(rec.r.pubkey.fingerprint, fingerprint, fingerlen );
rec.r.pubkey.ownertrust = 0;
if( write_record( recnum, &rec ) ) {
@@ -817,8 +1489,7 @@ int
update_trust_record( PKT_public_cert *pkc, int new_trust )
{
TRUSTREC rec;
- u32 keyid[2];
- u32 recnum;
+ ulong recnum;
if( DBG_TRUST )
log_debug("trustdb: update_record\n");