summaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>1998-11-03 20:38:58 +0100
committerWerner Koch <wk@gnupg.org>1998-11-03 20:38:58 +0100
commitb9dd2ebb2c08b457735f8acf997ff54965db91de (patch)
tree7d2408445104fa5135bd63b7e7bfc98d5a66688f /g10
parentsome random changes (diff)
downloadgnupg2-b9dd2ebb2c08b457735f8acf997ff54965db91de.tar.xz
gnupg2-b9dd2ebb2c08b457735f8acf997ff54965db91de.zip
(Does not compile yet)
Diffstat (limited to 'g10')
-rw-r--r--g10/ChangeLog27
-rw-r--r--g10/export.c9
-rw-r--r--g10/g10.c7
-rw-r--r--g10/import.c2
-rw-r--r--g10/keyedit.c4
-rw-r--r--g10/keygen.c5
-rw-r--r--g10/parse-packet.c7
-rw-r--r--g10/sig-check.c19
-rw-r--r--g10/signal.c39
-rw-r--r--g10/tdbio.c7
-rw-r--r--g10/trustdb.c600
-rw-r--r--g10/trustdb.h2
12 files changed, 474 insertions, 254 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 35afefa16..9109e6558 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,30 @@
+Tue Nov 3 16:19:21 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * keygen.c (ask_user_id): Now converted to UTF-8
+
+ * g10.c (main): Kludge for pgp clearsigs and textmode.
+
+Fri Oct 30 16:40:39 1998 me,,, (wk@tobold)
+
+ * signal.c (block_all_signals): New.
+ (unblock_all_signals): New
+ * tdbio.c (tdbio_end_transaction): Now blocks all signals.
+
+ * trustdb.c (new_lid_table): Changed the represenation of the
+ former local_lid_info stuff.
+
+ * trustdb.c (update_trust_record): Reorganized the whole thing.
+ * sig-check.c (check_key_signature): Now handles class 0x28
+
+
+Wed Oct 28 18:56:33 1998 me,,, (wk@tobold)
+
+ * export.c (do_export): Takes care of the exportable sig flag.
+
+Tue Oct 27 14:53:04 1998 Werner Koch (wk@isil.d.shuttle.de)
+
+ * trustdb.c (update_trust_record): New "fast" parameter.
+
Sun Oct 25 19:32:05 1998 Werner Koch (wk@isil.d.shuttle.de)
* openfile.c (copy_options_File): New.
diff --git a/g10/export.c b/g10/export.c
index 46413fff2..637f675f4 100644
--- a/g10/export.c
+++ b/g10/export.c
@@ -128,6 +128,15 @@ do_export( STRLIST users, int secret )
* secret keyring */
if( !secret && node->pkt->pkttype == PKT_COMMENT )
continue;
+ /* do not export packets which are marked as not exportable */
+ if( node->pkt->pkttype == PKT_SIGNATURE ) {
+ const char *p;
+ p = parse_sig_subpkt2( node->pkt->pkt.signature,
+ SIGSUBPKT_EXPORTABLE, NULL );
+ if( p && !*p )
+ continue; /* not exportable */
+ }
+
if( (rc = build_packet( out, node->pkt )) ) {
log_error("build_packet(%d) failed: %s\n",
node->pkt->pkttype, g10_errstr(rc) );
diff --git a/g10/g10.c b/g10/g10.c
index 3df9121b5..9d4f20d79 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -60,7 +60,7 @@ enum cmd_and_opt_values { aNull = 0,
oQuiet = 'q',
oRemote = 'r',
aSign = 's',
- oTextmode = 't',
+ oTextmodeShort= 't',
oUser = 'u',
oVerbose = 'v',
oCompress = 'z',
@@ -100,6 +100,7 @@ enum cmd_and_opt_values { aNull = 0,
aEnArmor,
aGenRandom,
+ oTextmode,
oFingerprint,
oAnswerYes,
oAnswerNo,
@@ -205,6 +206,7 @@ static ARGPARSE_OPTS opts[] = {
{ oUser, "local-user",2, N_("use this user-id to sign or decrypt")},
{ oRemote, "remote-user", 2, N_("use this user-id for encryption")},
{ oCompress, NULL, 1, N_("|N|set compress level N (0 disables)") },
+ { oTextmodeShort, NULL, 0, "@"},
{ oTextmode, "textmode", 0, N_("use canonical text mode")},
#endif
{ oOutput, "output", 2, N_("use as output file")},
@@ -734,6 +736,7 @@ main( int argc, char **argv )
sl->next = remusr;
remusr = sl;
break;
+ case oTextmodeShort: opt.textmode = 2; break;
case oTextmode: opt.textmode=1; break;
case oUser: /* store the local users */
sl = m_alloc( sizeof *sl + strlen(pargs.r.ret_str));
@@ -839,7 +842,7 @@ main( int argc, char **argv )
/* kludge to let -sat generate a clear text signature */
- if( opt.textmode && !detached_sig && opt.armor && cmd == aSign )
+ if( opt.textmode == 2 && !detached_sig && opt.armor && cmd == aSign )
cmd = aClearsign;
if( opt.verbose > 1 )
diff --git a/g10/import.c b/g10/import.c
index 075ecd358..0cd1353ef 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -465,7 +465,7 @@ import_one( const char *fname, KBNODE keyblock, int fast )
(ulong)keyid[1], g10_errstr(rc) );
}
else if( mod_key )
- rc = update_trust_record( keyblock_orig, NULL );
+ rc = update_trust_record( keyblock_orig, 1, NULL );
else
rc = clear_trust_checked_flag( new_key? pk : pk_orig );
}
diff --git a/g10/keyedit.c b/g10/keyedit.c
index 62921349c..a2b0a761f 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -647,7 +647,7 @@ keyedit_menu( const char *username, STRLIST locusr )
}
else
tty_printf(_("Key not changed so no update needed.\n"));
- rc = update_trust_record( keyblock, NULL );
+ rc = update_trust_record( keyblock, 0, NULL );
if( rc )
log_error(_("update of trust db failed: %s\n"),
g10_errstr(rc) );
@@ -705,7 +705,7 @@ keyedit_menu( const char *username, STRLIST locusr )
sec_modified = modified = 1;
/* must update the trustdb already here, so that preferences
* get listed correctly */
- rc = update_trust_record( keyblock, NULL );
+ rc = update_trust_record( keyblock, 0, NULL );
if( rc ) {
log_error(_("update of trust db failed: %s\n"),
g10_errstr(rc) );
diff --git a/g10/keygen.c b/g10/keygen.c
index 6b04971ca..a17d47927 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -689,6 +689,11 @@ ask_user_id( int mode )
break;
m_free(uid); uid = NULL;
}
+ if( uid ) {
+ char *p = native_to_utf8( uid );
+ m_free( uid );
+ uid = p;
+ }
return uid;
}
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 542676ccd..1f19b05de 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -633,7 +633,8 @@ dump_sig_subpkt( int hashed, int type, int critical,
printf("sig expires %s", strtimestamp( buffer_to_u32(buffer) ) );
break;
case SIGSUBPKT_EXPORTABLE:
- p = "exportable";
+ if( length )
+ printf("%sexportable", *buffer? "":"not ");
break;
case SIGSUBPKT_TRUST:
p = "trust signature";
@@ -759,6 +760,10 @@ parse_sig_subpkt( const byte *buffer, sigsubpkttype_t reqtype, size_t *ret_n )
if( n < 4 )
break;
return buffer;
+ case SIGSUBPKT_EXPORTABLE:
+ if( !n )
+ break;
+ return buffer;
case SIGSUBPKT_ISSUER:/* issuer key ID */
if( n < 8 )
break;
diff --git a/g10/sig-check.c b/g10/sig-check.c
index fd476f767..da732c451 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -278,12 +278,27 @@ check_key_signature( KBNODE root, KBNODE node, int *is_selfsig )
rc = do_check( pk, sig, md );
md_close(md);
}
+ else if( sig->sig_class == 0x28 ) { /* subkey revocation */
+ KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
+
+ if( snode ) {
+ md = md_open( algo, 0 );
+ hash_public_key( md, pk );
+ hash_public_key( md, snode->pkt->pkt.public_key );
+ rc = do_check( pk, sig, md );
+ md_close(md);
+ }
+ else {
+ log_error("no subkey for subkey revocation packet\n");
+ rc = G10ERR_SIG_CLASS;
+ }
+ }
else if( sig->sig_class == 0x18 ) {
KBNODE snode = find_prev_kbnode( root, node, PKT_PUBLIC_SUBKEY );
if( snode ) {
- if( is_selfsig ) {
- u32 keyid[2];
+ if( is_selfsig ) { /* does this make sense????? */
+ u32 keyid[2]; /* it should always be a selfsig */
keyid_from_pk( pk, keyid );
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] )
diff --git a/g10/signal.c b/g10/signal.c
index d89b548b1..8a0f3feee 100644
--- a/g10/signal.c
+++ b/g10/signal.c
@@ -121,3 +121,42 @@ pause_on_sigusr( int which )
#endif
}
+
+static void
+do_block( int block )
+{
+ #ifndef __MINGW32__
+ static int is_blocked;
+ static sigset_t oldmask;
+
+ if( block ) {
+ sigset_t newmask;
+
+ if( is_blocked )
+ log_bug("signals are already blocked\n");
+ sigfillset( &newmask );
+ sigprocmask( SIG_BLOCK, &newmask, &oldmask );
+ is_blocked = 1;
+ }
+ else {
+ if( !is_blocked )
+ log_bug("signals are not blocked\n");
+ sigprocmask( SIG_SETMASK, &oldmask, NULL );
+ is_blocked = 0;
+ }
+ #endif /*__MINGW32__*/
+}
+
+
+void
+block_all_signals()
+{
+ do_block(1);
+}
+
+void
+unblock_all_signals()
+{
+ do_block(0);
+}
+
diff --git a/g10/tdbio.c b/g10/tdbio.c
index 1954929ae..f4c97e85e 100644
--- a/g10/tdbio.c
+++ b/g10/tdbio.c
@@ -320,10 +320,15 @@ tdbio_begin_transaction()
int
tdbio_end_transaction()
{
+ int rc;
+
if( !in_transaction )
log_bug("tdbio: no active transaction\n");
+ block_all_signals();
in_transaction = 0;
- return tdbio_sync();
+ rc = tdbio_sync();
+ unblock_all_signals();
+ return rc;
}
int
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 7a6ec3bd1..43903a996 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -47,27 +47,33 @@
#error Must change structure of trustdb
#endif
-typedef struct local_id_info *LOCAL_ID_INFO;
-struct local_id_info {
- LOCAL_ID_INFO next;
+struct local_id_item {
+ struct local_id_item *next;
ulong lid;
unsigned flag;
};
+struct local_id_table {
+ struct local_id_table *next; /* only used to keep a list of unused tables */
+ struct local_id_item *items[16];
+};
+
+
+typedef struct local_id_table *LOCAL_ID_TABLE;
+
typedef struct trust_info TRUST_INFO;
struct trust_info {
ulong lid;
- unsigned trust;
+ byte otrust; /* ownertrust (assigned trust) */
+ byte trust; /* calculated trust (validity) */
};
-
typedef struct trust_seg_list *TRUST_SEG_LIST;
struct trust_seg_list {
TRUST_SEG_LIST next;
- int nseg; /* number of segments */
- int dup;
- TRUST_INFO seg[1]; /* segment list */
+ int pathlen;
+ TRUST_INFO path[1];
};
@@ -82,10 +88,10 @@ typedef struct recno_list_struct *RECNO_LIST;
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 ins_lid_table_item( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag );
-static int qry_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag );
+static LOCAL_ID_TABLE new_lid_table(void);
+static void release_lid_table( LOCAL_ID_TABLE tbl );
+static int ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag );
+static int qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag );
static void print_user_id( const char *text, u32 *keyid );
static int list_sigs( ulong pubkey_id );
@@ -95,8 +101,11 @@ static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec );
/* a table used to keep track of ultimately trusted keys
* which are the ones from our secrings */
-static LOCAL_ID_INFO *ultikey_table;
+static LOCAL_ID_TABLE ultikey_table;
+/* list of unused lid items and tables */
+static LOCAL_ID_TABLE unused_lid_tables;
+static struct local_id_item *unused_lid_items;
#define HEXTOBIN(a) ( (a) >= '0' && (a) <= '9' ? ((a)-'0') : \
@@ -215,53 +224,67 @@ rel_recno_list( RECNO_LIST *head )
*head = NULL;
}
-static LOCAL_ID_INFO *
+static LOCAL_ID_TABLE
new_lid_table(void)
{
- return m_alloc_clear( 16 * sizeof(LOCAL_ID_INFO));
+ LOCAL_ID_TABLE a;
+
+ a = unused_lid_tables;
+ if( a ) {
+ unused_lid_tables = a->next;
+ a->next = NULL;
+ }
+ else
+ a = m_alloc_clear( sizeof *a );
+ return a;
}
static void
-release_lid_table( LOCAL_ID_INFO *tbl )
+release_lid_table( LOCAL_ID_TABLE tbl )
{
- LOCAL_ID_INFO a, a2;
+ struct local_id_item *a, *a2;
int i;
for(i=0; i < 16; i++ ) {
- for(a=tbl[i]; a; a = a2 ) {
+ for(a=tbl->items[i]; a; a = a2 ) {
a2 = a->next;
- m_free(a);
+ a->next = unused_lid_items;
+ unused_lid_items = a;
}
}
- m_free(tbl);
+ tbl->next = unused_lid_tables;
+ unused_lid_tables = tbl;
}
/****************
* Add a new item to the table or return 1 if we already have this item
- * fixme: maybe it's a good idea to take items from an unused item list.
*/
static int
-ins_lid_table_item( LOCAL_ID_INFO *tbl, ulong lid, unsigned flag )
+ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag )
{
- LOCAL_ID_INFO a;
+ struct local_id_item *a;
- for( a = tbl[lid & 0x0f]; a; a = a->next )
+ for( a = tbl->items[lid & 0x0f]; a; a = a->next )
if( a->lid == lid )
return 1;
- a = m_alloc( sizeof *a );
+ a = unused_lid_items;
+ if( a )
+ unused_lid_items = a->next;
+ else
+ a = m_alloc( sizeof *a );
a->lid = lid;
a->flag = flag;
- a->next = tbl[lid & 0x0f];
- tbl[lid & 0x0f] = a;
+ a->next = tbl->items[lid & 0x0f];
+ tbl->items[lid & 0x0f] = a;
return 0;
}
static int
-qry_lid_table_flag( LOCAL_ID_INFO *tbl, ulong lid, unsigned *flag )
+qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag )
{
- LOCAL_ID_INFO a;
+ struct local_id_item *a;
- for( a = tbl[lid & 0x0f]; a; a = a->next )
+ for( a = tbl->items[lid & 0x0f]; a; a = a->next )
if( a->lid == lid ) {
if( flag )
*flag = a->flag;
@@ -493,7 +516,7 @@ print_user_id( const char *text, u32 *keyid )
m_free(p);
}
-
+#if 0
static int
print_keyid( FILE *fp, ulong lid )
{
@@ -521,7 +544,7 @@ print_trust( FILE *fp, unsigned trust )
putc(c, fp);
return 1;
}
-
+#endif
static int
print_sigflags( FILE *fp, unsigned flags )
@@ -542,7 +565,7 @@ print_sigflags( FILE *fp, unsigned flags )
/* (a non-recursive algorithm would be easier) */
static int
do_list_sigs( ulong root, ulong pk_lid, int depth,
- LOCAL_ID_INFO *lids, unsigned *lineno )
+ LOCAL_ID_TABLE lids, unsigned *lineno )
{
SIGREC_CONTEXT sx;
int rc;
@@ -551,8 +574,8 @@ do_list_sigs( ulong root, ulong pk_lid, int depth,
memset( &sx, 0, sizeof sx );
sx.lid = pk_lid;
for(;;) {
- rc = walk_sigrecs( &sx );
- if( rc )
+ rc = walk_sigrecs( &sx ); /* should we replace it and use */
+ if( rc ) /* use a loop like in collect_paths ??*/
break;
rc = keyid_from_lid( sx.sig_lid, keyid );
if( rc ) {
@@ -609,7 +632,7 @@ list_sigs( ulong pubkey_id )
{
int rc;
u32 keyid[2];
- LOCAL_ID_INFO *lids;
+ LOCAL_ID_TABLE lids;
unsigned lineno = 1;
rc = keyid_from_lid( pubkey_id, keyid );
@@ -692,40 +715,54 @@ list_records( ulong lid )
+
/****************
- * Given the directory record of a key, check whether we can
- * find a path to an ultimately trusted key. We do this by
- * checking all key signatures up to a some depth.
+ * stack is an array of (max_path+1) elements. If trust_seg_head is not
+ * NULL it is a pointer to a variable which will receive a linked list
+ * of trust paths - The caller has to free the memory.
*/
static int
-verify_key( int depth, int max_depth, TRUSTREC *drec )
+collect_paths( int depth, int max_depth, int all, TRUSTREC *drec,
+ TRUST_INFO *stack, TRUST_SEG_LIST *trust_seg_head )
{
ulong rn, uidrn;
int marginal=0;
int fully=0;
- size_t dbglen;
-
- /* Note: If used stack size is an issue, we could reuse the
- * trustrec vars and reread them as needed */
+ LOCAL_ID_TABLE sigs_seen = NULL;
- dbglen = printf("verify_key: depth=%d %*s", depth, depth*3,"" );
- dbglen += print_keyid( stdout, drec->recnum );
- dbglen += printf(" ot=");
- dbglen += print_trust(stdout, drec->r.dir.ownertrust );
- dbglen += printf(" -> ");
-
- if( depth >= max_depth ) {
- /* max cert_depth reached */
- puts("undefined (too deep)");
+ if( depth >= max_depth ) /* max cert_depth reached */
return TRUST_UNDEFINED;
+ { int i;
+
+ for(i=0; i < depth; i++ )
+ if( stack[i].lid == drec->r.dir.lid )
+ return TRUST_UNDEFINED; /* closed (we already visited this lid) */
}
+
+ stack[depth].lid = drec->r.dir.lid;
+ stack[depth].otrust = drec->r.dir.ownertrust;
+ stack[depth].trust = 0;
if( !qry_lid_table_flag( ultikey_table, drec->r.dir.lid, NULL ) ) {
/* we are at the end of a path */
- puts("ultimate");
+ TRUST_SEG_LIST tsl;
+ int i;
+
+ stack[depth].trust = TRUST_ULTIMATE;
+ if( trust_seg_head ) {
+ /* we can now put copy our current stack to the trust_seg_list */
+ tsl = m_alloc( sizeof *tsl + (depth+1)*sizeof( TRUST_INFO ) );
+ for(i=0; i <= depth; i++ )
+ tsl->path[i] = stack[i];
+ tsl->pathlen = i;
+ tsl->next = *trust_seg_head;
+ *trust_seg_head = tsl;
+ }
return TRUST_ULTIMATE;
}
/* loop over all user-ids */
+ if( !all )
+ sigs_seen = new_lid_table();
for( rn = drec->r.dir.uidlist; rn; rn = uidrn ) {
TRUSTREC rec; /* used for uids and sigs */
ulong sigrn;
@@ -755,40 +792,39 @@ verify_key( int depth, int max_depth, TRUSTREC *drec )
continue; /* skip expired signatures */
if( (rec.r.sig.sig[i].flag & SIGF_REVOKED) )
continue; /* skip revoked signatures */
- /* fixme: skip duplicates */
- read_record( rec.r.sig.sig[i].lid, &tmp, RECTYPE_DIR );
- ot = tmp.r.dir.ownertrust & TRUST_MASK;
- #if 0 /* Does not work, because the owner trust of our
- * own keys is not always set
- * -- fix this in verify_own_keys() ? */
- if( ot < TRUST_MARGINAL ) {
- printf(". ");
- continue; /* ownertrust is too low; don't need to check */
+ /* visit every signer only once (a signer may have
+ * signed multizple user IDs */
+ if( sigs_seen && ins_lid_table_item( sigs_seen,
+ rec.r.sig.sig[i].lid, 0) )
+ continue; /* we alread have this one */
+
+ read_record( rec.r.sig.sig[i].lid, &tmp, 0 );
+ if( tmp.rectype != RECTYPE_DIR ) {
+ log_info("oops: lid %lu: sig %lu has rectype %d"
+ " - skipped\n",
+ drec->r.dir.lid, tmp.recnum, tmp.rectype );
+ continue;
}
- #endif
+ ot = tmp.r.dir.ownertrust & TRUST_MASK;
if( ot >= TRUST_FULLY )
ot = TRUST_FULLY; /* just in case */
+ nt = collect_paths( depth+1, max_depth, all, &tmp, stack,
+ trust_seg_head );
+ nt &= TRUST_MASK;
- puts("");
- nt = verify_key( depth+1, max_depth, &tmp ) & TRUST_MASK;
if( nt < TRUST_MARGINAL ) {
- printf("%*s* ", dbglen, "");
- dbglen += 2;
continue;
}
if( nt == TRUST_ULTIMATE ) {
/* we have signed this key and only in this special case
- * we assume a completes-needed or marginals-needed of 1 */
- printf("%*s", dbglen, "");
- if( ot == TRUST_MARGINAL )
- puts("marginal (1st level)");
- else if( ot == TRUST_FULLY )
- puts("fully (1st level)");
- else
- puts("????? (1st level)");
- return ot;
+ * we assume that this one is fully trusted */
+ if( !all ) {
+ if( sigs_seen )
+ release_lid_table( sigs_seen );
+ return (stack[depth].trust = TRUST_FULLY);
+ }
}
if( nt >= TRUST_FULLY )
@@ -798,127 +834,45 @@ verify_key( int depth, int max_depth, TRUSTREC *drec )
if( fully >= opt.completes_needed
|| marginal >= opt.marginals_needed ) {
- printf("%*s", dbglen, "");
- puts("fully");
- return TRUST_FULLY;
+ if( !all ) {
+ if( sigs_seen )
+ release_lid_table( sigs_seen );
+ return (stack[depth].trust = TRUST_FULLY);
+ }
}
}
}
}
- printf("%*s", dbglen, "");
+ if( sigs_seen )
+ release_lid_table( sigs_seen );
+ if( all && ( fully >= opt.completes_needed
+ || marginal >= opt.marginals_needed ) ) {
+ return (stack[depth].trust = TRUST_FULLY );
+ }
if( marginal ) {
- puts("marginal");
- return TRUST_MARGINAL;
+ return (stack[depth].trust = TRUST_MARGINAL);
}
- puts("undefined");
- return TRUST_UNDEFINED;
+ return (stack[depth].trust=TRUST_UNDEFINED);
}
+/****************
+ * Given the directory record of a key, check whether we can
+ * find a path to an ultimately trusted key. We do this by
+ * checking all key signatures up to a some depth.
+ */
static int
-list_paths( int depth, int max_depth, TRUSTREC *drec )
+verify_key( int max_depth, TRUSTREC *drec )
{
- ulong rn, uidrn;
- int marginal=0;
- int fully=0;
- size_t dbglen;
+ TRUST_INFO *tmppath = m_alloc_clear( (max_depth+1)* sizeof *tmppath );
+ int tr;
- if( depth >= max_depth ) {
- /* max cert_depth reached */
- puts("undefined (too deep)");
- return TRUST_UNDEFINED;
- }
- if( !qry_lid_table_flag( ultikey_table, drec->r.dir.lid, NULL ) ) {
- /* we are at the end of a path */
- puts("ultimate");
- return TRUST_ULTIMATE;
- }
-
- /* loop over all user-ids */
- for( rn = drec->r.dir.uidlist; rn; rn = uidrn ) {
- TRUSTREC rec; /* used for uids and sigs */
- ulong sigrn;
-
- read_record( rn, &rec, RECTYPE_UID );
- uidrn = rec.r.uid.next;
- /* fixme: continue if the uidrec is not marked valid */
-
- /* loop over all signature records */
- for( rn = rec.r.uid.siglist; rn; rn = sigrn ) {
- int i;
-
- read_record( rn, &rec, RECTYPE_SIG );
- sigrn = rec.r.sig.next;
-
- for(i=0; i < SIGS_PER_RECORD; i++ ) {
- TRUSTREC tmp;
- int ot, nt;
-
- if( !rec.r.sig.sig[i].lid )
- continue; /* skip deleted sigs */
- if( !(rec.r.sig.sig[i].flag & SIGF_CHECKED) )
- continue; /* skip unchecked signatures */
- if( !(rec.r.sig.sig[i].flag & SIGF_VALID) )
- continue; /* skip invalid signatures */
- if( (rec.r.sig.sig[i].flag & SIGF_EXPIRED) )
- continue; /* skip expired signatures */
- if( (rec.r.sig.sig[i].flag & SIGF_REVOKED) )
- continue; /* skip revoked signatures */
- /* fixme: skip duplicates */
-
- read_record( rec.r.sig.sig[i].lid, &tmp, RECTYPE_DIR );
- ot = tmp.r.dir.ownertrust & TRUST_MASK;
- if( ot < TRUST_MARGINAL ) {
- printf(". ");
- continue; /* ownertrust is too low; don't need to check */
- }
-
- if( ot >= TRUST_FULLY )
- ot = TRUST_FULLY; /* just in case */
-
- puts("");
- nt = verify_key( depth+1, max_depth, &tmp ) & TRUST_MASK;
- if( nt < TRUST_MARGINAL ) {
- printf("%*s* ", dbglen, "");
- dbglen += 2;
- continue;
- }
-
- if( nt == TRUST_ULTIMATE ) {
- /* we have signed this key and only in this special case
- * we assume a completes-needed or marginals-needed of 1 */
- printf("%*s", dbglen, "");
- if( ot == TRUST_MARGINAL )
- puts("marginal (1st level)");
- else if( ot == TRUST_FULLY )
- puts("fully (1st level)");
- else
- puts("????? (1st level)");
- return ot;
- }
+ tr = collect_paths( 0, max_depth, 0, drec, tmppath, NULL );
+ m_free( tmppath );
+ return tr;
+}
- if( nt >= TRUST_FULLY )
- fully++;
- if( nt >= TRUST_MARGINAL )
- marginal++;
- if( fully >= opt.completes_needed
- || marginal >= opt.marginals_needed ) {
- printf("%*s", dbglen, "");
- puts("fully");
- return TRUST_FULLY;
- }
- }
- }
- }
- printf("%*s", dbglen, "");
- if( marginal ) {
- puts("marginal");
- return TRUST_MARGINAL;
- }
- puts("undefined");
- return TRUST_UNDEFINED;
-}
/****************
@@ -937,7 +891,7 @@ do_check( TRUSTREC *dr, unsigned *trustlevel )
return G10ERR_TRUSTDB;
}
- *trustlevel = verify_key( 1, 5, dr );
+ *trustlevel = verify_key( 5, dr );
if( dr->r.dir.dirflags & DIRF_REVOKED )
*trustlevel |= TRUST_FLAG_REVOKED;
@@ -1092,6 +1046,7 @@ import_ownertrust( const char *fname )
n = strlen(line);
if( line[n-1] != '\n' ) {
log_error_f(fname, "line to long\n" );
+ /* ... or last line does not have a LF */
break; /* can't continue */
}
for(p = line; *p && *p != ':' ; p++ )
@@ -1161,20 +1116,44 @@ import_ownertrust( const char *fname )
}
+
+
+static void
+print_path( int pathlen, TRUST_INFO *path )
+{
+ int rc, i;
+ u32 keyid[2];
+
+ fputs("path:", stdout);
+ for( i = 0; i < pathlen; i++ ) {
+ if( i && !(i%4) )
+ fputs(" ", stdout );
+ rc = keyid_from_lid( path[i].lid, keyid );
+ if( rc )
+ printf(" ????????.%lu:", path[i].lid );
+ else
+ printf(" %08lX.%lu:", (ulong)keyid[1], path[i].lid );
+ print_sigflags( stdout, path[i].otrust );
+ }
+ putchar('\n');
+}
+
+
+
void
list_trust_path( int max_depth, const char *username )
{
int rc;
int wipe=0;
TRUSTREC rec;
+ TRUST_INFO *tmppath;
+ TRUST_SEG_LIST trust_seg_list, tsl, tsl2;
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
if( max_depth < 0 ) {
wipe = 1;
max_depth = -max_depth;
}
- if( max_depth < 1 )
- max_depth = 1;
if( (rc = get_pubkey_byname( pk, username )) )
log_error("user '%s' not found: %s\n", username, g10_errstr(rc) );
@@ -1190,14 +1169,30 @@ list_trust_path( int max_depth, const char *username )
assert( pk->local_id );
}
}
+ free_public_key( pk );
+ /* collect the paths */
+ tmppath = m_alloc_clear( (max_depth+1)* sizeof *tmppath );
+ trust_seg_list = NULL;
+ collect_paths( 0, max_depth, 1, &rec, tmppath, &trust_seg_list );
+ m_free( tmppath );
+ /* and now print them */
+ for(tsl = trust_seg_list; tsl; tsl = tsl->next ) {
+ print_path( tsl->pathlen, tsl->path );
+ }
- free_public_key( pk );
+ /* release the list */
+ for(tsl = trust_seg_list; tsl; tsl = tsl2 ) {
+ tsl2 = tsl->next;
+ m_free( tsl );
+ }
+ trust_seg_list = NULL;
}
/****************
* Check the complete trustdb or only the entries for the given username.
+ * We check the complete database and recalculate all flags.
*/
void
check_trustdb( const char *username )
@@ -1218,7 +1213,7 @@ check_trustdb( const char *username )
else {
int modified;
- rc = update_trust_record( keyblock, &modified );
+ rc = update_trust_record( keyblock, 0, &modified );
if( rc == -1 ) { /* not yet in trustdb: insert */
rc = insert_trust_record(
find_kbnode( keyblock, PKT_PUBLIC_KEY
@@ -1265,7 +1260,7 @@ check_trustdb( const char *username )
continue;
}
- rc = update_trust_record( keyblock, &modified );
+ rc = update_trust_record( keyblock, 0, &modified );
if( rc ) {
log_error("lid %lu: update failed: %s\n",
recnum, g10_errstr(rc) );
@@ -1295,6 +1290,10 @@ check_trustdb( const char *username )
}
+/****************
+ * Put new entries from the pubrings into the trustdb.
+ * This function honors the sig flags to speed up the check.
+ */
void
update_trustdb( )
{
@@ -1309,7 +1308,7 @@ update_trustdb( )
while( !(rc = enum_keyblocks( 1, &kbpos, &keyblock )) ) {
int modified;
- rc = update_trust_record( keyblock, &modified );
+ rc = update_trust_record( keyblock, 1, &modified );
if( rc == -1 ) { /* not yet in trustdb: insert */
PKT_public_key *pk =
find_kbnode( keyblock, PKT_PUBLIC_KEY
@@ -1904,13 +1903,34 @@ create_shadow_dir( PKT_signature *sig, ulong lid )
}
+/****************
+ * This function checks the given public key and inserts or updates
+ * the keyrecord from the trustdb. Revocation certificates
+ * are handled here and the keybinding of subkeys is checked.
+ * Hmmm: Should we check here, that the key has at least one valid
+ * user ID or do we allow keys w/o user ID?
+ *
+ * keyblock points to the first node in the keyblock,
+ * keynode is the node with the public key to check
+ * (either primary or secondary), keyid is the keyid of
+ * the primary key, drec is the directory record and recno_list
+ * is a list used to keep track of visited records.
+ * Existing keyflags are recalculated if recheck is true.
+ */
static void
-upd_key_record( PKT_public_key *pk, TRUSTREC *drec, RECNO_LIST *recno_list )
+upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
+ TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
{
TRUSTREC krec;
+ KBNODE node;
+ PKT_public_key *pk = keynode->pkt->pkt.public_key,;
+ ulon lid = drec->recnum;
byte fpr[MAX_FINGERPRINT_LEN];
size_t fprlen;
ulong recno, newrecno;
+ int keybind_seen = 0;
+ int revoke_seen = 0;
+ int rc;
fingerprint_from_pk( pk, fpr, &fprlen );
/* do we already have this key? */
@@ -1924,9 +1944,10 @@ upd_key_record( PKT_public_key *pk, TRUSTREC *drec, RECNO_LIST *recno_list )
ins_recno_list( recno_list, recno, RECTYPE_KEY );
}
else { /* no: insert this new key */
+ recheck = 1;
memset( &krec, 0, sizeof(krec) );
krec.rectype = RECTYPE_KEY;
- krec.r.key.lid = drec->recnum;
+ krec.r.key.lid = lid;
krec.r.key.pubkey_algo = pk->pubkey_algo;
krec.r.key.fingerprint_len = fprlen;
memcpy(krec.r.key.fingerprint, fpr, fprlen );
@@ -1939,23 +1960,127 @@ upd_key_record( PKT_public_key *pk, TRUSTREC *drec, RECNO_LIST *recno_list )
drec->r.dir.keylist = newrecno;
drec->dirty = 1;
}
- else { /* we already have a key, append it to the list */
+ else { /* we already have a key, append the new one */
+ TRUSTREC save = krec;
for( ; recno; recno = krec.r.key.next )
read_record( recno, &krec, RECTYPE_KEY );
krec.r.key.next = newrecno;
write_record( &krec );
+ krec = save;
}
}
+
+ if( !recheck && (krec.r.key.keyflags & KEYF_CHECKED) )
+ return;
+
+ /* check keybindings and revocations */
+ krec.r.key.keyflags = 0;
+ if( keynode->pkt->pkttype == PKT_PUBLIC_KEY ) {
+ /* we assume that a primary key is always valid
+ * and check later whether we have a revocation */
+ krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID;
+ }
+
+ for( node=keynode->next; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ break; /* ready */
+ else if( node->pkt->pkttype == PKT_PUBLIC_SIGNATURE ) {
+ PKT_signature *sig = node->pkt->pkt.signature;
+
+ if( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
+ continue; /* not a self signature */
+ if( sig->sig_class == 0x18 && !keybind_seen ) { /* a keybinding */
+ if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
+ continue; /* oops, not for a main key */
+ /* we check until we find a valid keybinding */
+ rc = check_key_signature( keyblock, node, NULL );
+ if( !rc ) {
+ if( opt.verbose )
+ log_info(_(
+ "key %08lX.%lu: Good subkey binding\n"),
+ (ulong)keyid_from_pk(pk,NULL), lid );
+ krec.r.key.keyflags |= KEYF_CHECKED | KEYF_VALID;
+ }
+ else {
+ log_info(_(
+ "key %08lX.%lu: Invalid subkey binding: %s\n"),
+ (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
+ krec.r.key.keyflags |= KEYF_CHECKED;
+ krec.r.key.keyflags &= ~KEYF_VALID;
+ }
+ keybind_seen = 1;
+ }
+ else if( sig->sig_class == 0x20 && !revoke_seen ) {
+ if( keynode->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ continue; /* a subkey is not expected here */
+ /* This is a key revocation certificate: check it */
+ rc = check_key_signature( keyblock, node, NULL );
+ if( !rc ) {
+ if( opt.verbose )
+ log_info(_(
+ "key %08lX.%lu: Valid key revocation\n"),
+ (ulong)keyid_from_pk(pk,NULL), lid );
+ krec.r.key.keyflags |= KEYF_REVOKED;
+ }
+ else {
+ log_info(_(
+ "key %08lX.%lu: Invalid key revocation: %s\n"),
+ (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
+ }
+ revoke_seen = 1;
+ }
+ else if( sig->sig_class == 0x28 && !revoke_seen ) {
+ if( keynode->pkt->pkttype == PKT_PUBLIC_KEY )
+ continue; /* a mainkey is not expected here */
+ /* This is a subkey revocation certificate: check it */
+ /* fixme: we should also check the revocation
+ * is newer tha the key (OpenPGP) */
+ rc = check_key_signature( keyblock, node, NULL );
+ if( !rc ) {
+ if( opt.verbose )
+ log_info(_(
+ "key %08lX.%lu: Valid subkey revocation\n"),
+ (ulong)keyid_from_pk(pk,NULL), lid );
+ krec.r.key.keyflags |= KEYF_REVOKED;
+ }
+ else {
+ log_info(_(
+ "key %08lX.%lu: Invalid subkey binding: %s\n"),
+ (ulong)keyid_from_pk(pk,NULL), lid, g10_errstr(rc) );
+ }
+ revoke_seen = 1;
+ }
+ } /* end signature */
+ }
+
+ write_record( &krec );
}
+/****************
+ * This function checks the given user ID and inserts or updates
+ * the uid record of the trustdb. Revocation certificates
+ * are handled here.
+ *
+ * keyblock points to the first node in the keyblock,
+ * uidnode is the node with the user id to check
+ * keyid is the keyid of
+ * the primary key, drec is the directory record and recno_list
+ * is a list used to keep track of visited records.
+ * Existing uidflags are recalculated if recheck is true.
+ */
static void
-upd_uid_record( PKT_user_id *uid, TRUSTREC *drec, RECNO_LIST *recno_list,
- u32 *keyid, ulong *uidrecno, byte *uidhash )
+upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
+ TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
{
+ ulong lid = drec->recnum;
+ PKT_user_id *uid = uidnode->pkt->pkt.user_id;
TRUSTREC urec;
+ byte uidhash[20];
ulong recno, newrecno;
+ /* see whether we already have an uid record */
+ WORK WORK
rmd160_hash_buffer( uidhash, uid->name, uid->len );
for( recno=drec->r.dir.uidlist; recno; recno = urec.r.uid.next ) {
read_record( recno, &urec, RECTYPE_UID );
@@ -2014,7 +2139,7 @@ upd_pref_record( PKT_signature *sig, ulong lid, const u32 *keyid,
/* First delete all pref records
* This is much simpler than checking whether we have to
* do update the record at all - the record cache may care about it
- * FIXME: We never get correct statistics if we di it like this */
+ * FIXME: We never get correct statistics if we do it like this */
for( recno=urec->r.uid.prefrec; recno; recno = prec.r.pref.next ) {
read_record( recno, &prec, RECTYPE_PREF );
delete_record( recno );
@@ -2097,13 +2222,14 @@ upd_self_key_sigs( PKT_signature *sig, TRUSTREC *urec,
}
+
/****************
* update non-self key signatures (class 0x10..0x13)
*/
static void
upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec,
ulong lid, const u32 *keyid, const byte *uidhash,
- KBNODE keyblock, KBNODE signode)
+ KBNODE keyblock, KBNODE signode, int fast)
{
/* We simply insert the signature into the sig records but
* avoid duplicate ones. We do not check them here because
@@ -2178,9 +2304,9 @@ upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec,
}
found_sig = 1;
}
- if( rec.r.sig.sig[i].flag & SIGF_CHECKED )
+ if( fast && (rec.r.sig.sig[i].flag & SIGF_CHECKED) )
continue; /* we already checked this signature */
- if( rec.r.sig.sig[i].flag & SIGF_NOPUBKEY )
+ if( fast && (rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) )
continue; /* we do not have the public key */
read_record( rec.r.sig.sig[i].lid, &tmp, 0 );
@@ -2197,10 +2323,11 @@ upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec,
rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID;
}
else if( rc == G10ERR_NO_PUBKEY ) {
- log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: "
- "weird: no public key\n"),
- (ulong)keyid[1], lid, uidhash[18],
- uidhash[19], (ulong)sig->keyid[1] );
+ if( (rec.r.sig.sig[i].flag & SIGF_CHECKED) )
+ log_info(_("key %08lX.%lu, uid %02X%02X, sig %08lX: "
+ "public key lost\n"),
+ (ulong)keyid[1], lid, uidhash[18],
+ uidhash[19], (ulong)sig->keyid[1] );
rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
}
else {
@@ -2219,8 +2346,9 @@ upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec,
&& tmp.r.sdir.keyid[1] == sig->keyid[1]
&& (!tmp.r.sdir.pubkey_algo
|| tmp.r.sdir.pubkey_algo == sig->pubkey_algo )) {
- log_info(_("key %08lX.%lu, uid %02X%02X: "
- "has shadow dir %lu but not yet marked.\n"),
+ if( !(rec.r.sig.sig[i].flag & SIGF_NOPUBKEY) )
+ log_info(_("key %08lX.%lu, uid %02X%02X: "
+ "has shadow dir %lu but not yet marked.\n"),
(ulong)keyid[1], lid,
uidhash[18], uidhash[19], tmp.recnum );
rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
@@ -2314,7 +2442,7 @@ upd_nonself_key_sigs( PKT_signature *sig, TRUSTREC *urec,
static void
upd_sig_record( PKT_signature *sig, TRUSTREC *drec,
u32 *keyid, ulong *uidrecno, byte *uidhash,
- KBNODE keyblock, KBNODE signode)
+ KBNODE keyblock, KBNODE signode, int fast)
{
TRUSTREC urec;
ulong lid = drec->recnum;
@@ -2342,9 +2470,6 @@ upd_sig_record( PKT_signature *sig, TRUSTREC *drec,
keyblock, signode );
}
else if( sig->sig_class == 0x18 ) { /* key binding */
- /* get the corresponding key */
-
- /* FIXME */
}
else if( sig->sig_class == 0x20 ) { /* key revocation */
/* FIXME */
@@ -2358,7 +2483,7 @@ upd_sig_record( PKT_signature *sig, TRUSTREC *drec,
}
else if( (sig->sig_class&~3) == 0x10 ) {
upd_nonself_key_sigs( sig, &urec, lid, keyid, uidhash,
- keyblock, signode );
+ keyblock, signode, fast );
}
else if( sig->sig_class == 0x18 ) { /* key binding */
log_info(_("key %08lX: bogus key binding by %08lX\n"),
@@ -2387,11 +2512,11 @@ upd_sig_record( PKT_signature *sig, TRUSTREC *drec,
* Update all the info from the public keyblock.
* The key must already exist in the keydb.
* This function is responsible for checking the signatures in cases
- * where the public key is already available. If we no not have the public
+ * where the public key is already available. If we do not have the public
* key, the check is done by some special code in insert_trust_record().
*/
int
-update_trust_record( KBNODE keyblock, int *modified )
+update_trust_record( KBNODE keyblock, int recheck, int *modified )
{
PKT_public_key *primary_pk;
KBNODE node;
@@ -2421,44 +2546,31 @@ update_trust_record( KBNODE keyblock, int *modified )
keyid_from_pk( primary_pk, keyid );
+ /* fixme: check that the keyblock has a valid structure */
+
rc = tdbio_begin_transaction();
if( rc )
return rc;
- /* now update keys and user ids */
+ /* update the keys */
for( node=keyblock; node; node = node->next ) {
- switch( node->pkt->pkttype ) {
- case PKT_PUBLIC_KEY:
- case PKT_PUBLIC_SUBKEY:
- uidrecno = 0;
- upd_key_record( node->pkt->pkt.public_key, &drec, &recno_list );
- break;
-
- case PKT_USER_ID:
- if( drec.dirty ) { /* upd_pref_record may read the drec */
- write_record( &drec );
- drec.dirty = 0;
- }
- upd_uid_record( node->pkt->pkt.user_id, &drec, &recno_list,
- keyid, &uidrecno, uidhash );
- break;
-
- case PKT_SIGNATURE:
- if( drec.dirty ) { /* upd_sig_recory may read the drec */
- write_record( &drec );
- drec.dirty = 0;
- }
- upd_sig_record( node->pkt->pkt.signature, &drec, keyid,
- &uidrecno, uidhash, keyblock, node );
- break;
-
- default:
- break;
- }
- } /* end loop over all nodes */
+ if( node->pkt->pkttype == PKT_PUBLIC_KEY
+ || node->pkt->pkttype == PKT_PUBLIC_SUBKEY )
+ upd_key_record( keyblock, node, keyid,
+ &drec, &recno_list, recheck );
+ }
+ /* update the user IDs */
+ for( node=keyblock; node; node = node->next ) {
+ if( node->pkt->pkttype == PKT_USER_ID )
+ upd_uid_record( keyblock, node, keyid,
+ &drec, &recno_list, recheck );
+ }
+ WORk - WORK
/* delete keyrecords from the trustdb which are not anymore used */
+ /* should we really do this, or is it better to keep them and */
+ /* mark as unused? */
lastrecno = 0;
for( recno=drec.r.dir.keylist; recno; recno = krec.r.key.next ) {
read_record( recno, &krec, RECTYPE_KEY );
@@ -2623,7 +2735,7 @@ insert_trust_record( PKT_public_key *pk )
}
/* and put all the other stuff into the keydb */
- rc = update_trust_record( keyblock, NULL );
+ rc = update_trust_record( keyblock, 0, NULL );
if( !rc )
process_hintlist( hintlist, dirrec.r.dir.lid );
diff --git a/g10/trustdb.h b/g10/trustdb.h
index 01d3dab55..4dc8b2ccb 100644
--- a/g10/trustdb.h
+++ b/g10/trustdb.h
@@ -60,7 +60,7 @@ ulong lid_from_keyblock( KBNODE keyblock );
int query_trust_record( PKT_public_key *pk );
int clear_trust_checked_flag( PKT_public_key *pk );
int insert_trust_record( PKT_public_key *pk );
-int update_trust_record( KBNODE keyblock, int *modified );
+int update_trust_record( KBNODE keyblock, int fast, int *modified );
int update_ownertrust( ulong lid, unsigned new_trust );
/*-- pkclist.c --*/