aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--cipher/blowfish.c12
-rw-r--r--doc/DETAILS11
-rw-r--r--g10/encode.c5
-rw-r--r--g10/free-packet.c78
-rw-r--r--g10/g10.c29
-rw-r--r--g10/getkey.c73
-rw-r--r--g10/keydb.h1
-rw-r--r--g10/main.h4
-rw-r--r--g10/options.h2
-rw-r--r--g10/packet.h4
-rw-r--r--g10/pkclist.c20
-rw-r--r--g10/sign.c95
-rw-r--r--g10/trustdb.c588
-rw-r--r--g10/trustdb.h14
-rw-r--r--include/util.h1
-rw-r--r--util/strgutil.c12
16 files changed, 889 insertions, 60 deletions
diff --git a/cipher/blowfish.c b/cipher/blowfish.c
index 72d617a5c..5dbaf7195 100644
--- a/cipher/blowfish.c
+++ b/cipher/blowfish.c
@@ -26,6 +26,7 @@
* key "abcdefghijklmnopqrstuvwxyz";
* plain "BLOWFISH"
* cipher 32 4E D0 FE F4 13 A2 03
+ *
*/
#include <config.h>
@@ -385,6 +386,9 @@ selftest()
BLOWFISH_context c;
byte plain[] = "BLOWFISH";
byte buffer[8];
+ byte plain3[] = { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 };
+ byte key3[] = { 0x41, 0x79, 0x6E, 0xA0, 0x52, 0x61, 0x6E, 0xE4 };
+ byte cipher3[] = { 0xE1, 0x13, 0xF4, 0x10, 0x2C, 0xFC, 0xCE, 0x43 };
blowfish_setkey( &c, "abcdefghijklmnopqrstuvwxyz", 26 );
encrypt_block( &c, buffer, plain );
@@ -393,6 +397,14 @@ selftest()
decrypt_block( &c, buffer, buffer );
if( memcmp( buffer, plain, 8 ) )
log_bug("blowfish failed\n");
+
+ blowfish_setkey( &c, key3, 8 );
+ encrypt_block( &c, buffer, plain3 );
+ if( memcmp( buffer, cipher3, 8 ) )
+ log_error("wrong blowfish encryption (3)\n");
+ decrypt_block( &c, buffer, buffer );
+ if( memcmp( buffer, plain3, 8 ) )
+ log_bug("blowfish failed (3)\n");
}
diff --git a/doc/DETAILS b/doc/DETAILS
index a3a2773fb..81aff2912 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -36,7 +36,7 @@ Record type 1:
against the pubring)
1 u32 Local-Id-Counter. Used to keep track of Local-IDs.
32 bits are enough numbers for all practial purposes; if this
- counter rolls over (due to deleted keyblock,an d new ones),
+ counter rolls over (due to deleted keyblock and new ones),
the software should reassign new Local-Ids to the whole
database (not expected to ever occur).
1 byte marginals needed
@@ -49,6 +49,7 @@ Record type 1:
Record type 2:
--------------
Informations about a public key certificate.
+ These are static values which are never changed without user interaction.
1 byte value 2
1 byte reserved
@@ -57,7 +58,7 @@ Record type 2:
and usefull if we have duplicate keyids
It is not defined, how an implementaion selects such
a Local-Id, but it may use the local-ID counter from
- record type 1
+ record type 1, or simply use the offset of Record type 2
8 bytes keyid (of the primary key)
1 byte pubkey algorithm
1 byte reserved
@@ -67,9 +68,9 @@ Record type 2:
0 = undefined (not yet initialized)
1 = unknown owner (could not initialize it)
2 = do not trust this owner
- 3 = usually trust this owner
- 4 = always trust this owner
- 5 = ultimately trust this owner. This can only be set if
+ 4 = usually trust this owner
+ 5 = always trust this owner
+ 7 = ultimately trust this owner. This can only be set if
we have control over the secret key too.
Bit 3: set if key is revoked; do not use it.
Bit 7-4: reserved
diff --git a/g10/encode.c b/g10/encode.c
index 688cbfc08..ff125079e 100644
--- a/g10/encode.c
+++ b/g10/encode.c
@@ -159,7 +159,7 @@ encode_crypt( const char *filename, STRLIST remusr )
{
IOBUF inp = NULL, out = NULL;
PACKET pkt;
- PKT_plaintext *pt;
+ PKT_plaintext *pt = NULL;
int rc = 0;
u32 filesize;
cipher_filter_context_t cfx;
@@ -244,7 +244,8 @@ encode_crypt( const char *filename, STRLIST remusr )
iobuf_cancel(out);
else
iobuf_close(out); /* fixme: check returncode */
- pt->buf = NULL;
+ if( pt )
+ pt->buf = NULL;
free_packet(&pkt);
m_free(cfx.dek);
release_pkc_list( pkc_list );
diff --git a/g10/free-packet.c b/g10/free-packet.c
index fb5949a8f..e2efa5a66 100644
--- a/g10/free-packet.c
+++ b/g10/free-packet.c
@@ -57,18 +57,24 @@ free_seckey_enc( PKT_signature *enc )
}
void
-free_public_cert( PKT_public_cert *cert )
+release_public_cert_parts( PKT_public_cert *cert )
{
if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
- mpi_free( cert->d.elg.p );
- mpi_free( cert->d.elg.g );
- mpi_free( cert->d.elg.y );
+ mpi_free( cert->d.elg.p ); cert->d.elg.p = NULL;
+ mpi_free( cert->d.elg.g ); cert->d.elg.g = NULL;
+ mpi_free( cert->d.elg.y ); cert->d.elg.y = NULL;
}
else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) {
- mpi_free( cert->d.rsa.rsa_n );
- mpi_free( cert->d.rsa.rsa_e );
+ mpi_free( cert->d.rsa.rsa_n ); cert->d.rsa.rsa_n = NULL;
+ mpi_free( cert->d.rsa.rsa_e ); cert->d.rsa.rsa_e = NULL;
}
- md_close( cert->mfx.md );
+ md_close( cert->mfx.md ); cert->mfx.md = NULL;
+}
+
+void
+free_public_cert( PKT_public_cert *cert )
+{
+ release_public_cert_parts( cert );
m_free(cert);
}
@@ -92,22 +98,28 @@ copy_public_cert( PKT_public_cert *d, PKT_public_cert *s )
}
void
-free_secret_cert( PKT_secret_cert *cert )
+release_secret_cert_parts( PKT_secret_cert *cert )
{
if( cert->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
- mpi_free( cert->d.elg.p );
- mpi_free( cert->d.elg.g );
- mpi_free( cert->d.elg.y );
- mpi_free( cert->d.elg.x );
+ mpi_free( cert->d.elg.p ); cert->d.elg.p = NULL;
+ mpi_free( cert->d.elg.g ); cert->d.elg.g = NULL;
+ mpi_free( cert->d.elg.y ); cert->d.elg.y = NULL;
+ mpi_free( cert->d.elg.x ); cert->d.elg.x = NULL;
}
else if( cert->pubkey_algo == PUBKEY_ALGO_RSA ) {
- mpi_free( cert->d.rsa.rsa_n );
- mpi_free( cert->d.rsa.rsa_e );
- mpi_free( cert->d.rsa.rsa_d );
- mpi_free( cert->d.rsa.rsa_p );
- mpi_free( cert->d.rsa.rsa_q );
- mpi_free( cert->d.rsa.rsa_u );
+ mpi_free( cert->d.rsa.rsa_n ); cert->d.rsa.rsa_n = NULL;
+ mpi_free( cert->d.rsa.rsa_e ); cert->d.rsa.rsa_e = NULL;
+ mpi_free( cert->d.rsa.rsa_d ); cert->d.rsa.rsa_d = NULL;
+ mpi_free( cert->d.rsa.rsa_p ); cert->d.rsa.rsa_p = NULL;
+ mpi_free( cert->d.rsa.rsa_q ); cert->d.rsa.rsa_q = NULL;
+ mpi_free( cert->d.rsa.rsa_u ); cert->d.rsa.rsa_u = NULL;
}
+}
+
+void
+free_secret_cert( PKT_secret_cert *cert )
+{
+ release_secret_cert_parts( cert );
m_free(cert);
}
@@ -240,4 +252,34 @@ free_packet( PACKET *pkt )
pkt->pkt.generic = NULL;
}
+/****************
+ * Returns 0 if they match.
+ */
+int
+cmp_public_secret_cert( PKT_public_cert *pkc, PKT_secret_cert *skc )
+{
+ if( pkc->timestamp != skc->timestamp )
+ return -1;
+ if( pkc->valid_days != skc->valid_days )
+ return -1;
+ if( pkc->pubkey_algo != skc->pubkey_algo )
+ return -1;
+
+ if( pkc->pubkey_algo == PUBKEY_ALGO_ELGAMAL ) {
+ if( mpi_cmp( pkc->d.elg.p , skc->d.elg.p ) )
+ return -1;
+ if( mpi_cmp( pkc->d.elg.g , skc->d.elg.g ) )
+ return -1;
+ if( mpi_cmp( pkc->d.elg.y , skc->d.elg.y ) )
+ return -1;
+ }
+ else if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ if( mpi_cmp( pkc->d.rsa.rsa_n , skc->d.rsa.rsa_n ) )
+ return -1;
+ if( mpi_cmp( pkc->d.rsa.rsa_e , skc->d.rsa.rsa_e ) )
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/g10/g10.c b/g10/g10.c
index e5c7139d1..2002e69e1 100644
--- a/g10/g10.c
+++ b/g10/g10.c
@@ -424,17 +424,36 @@ main( int argc, char **argv )
break;
case aSign: /* sign the given file */
- if( argc > 1 )
- usage(1);
- if( (rc = sign_file(fname, detached_sig, locusr, 0, NULL)) )
- log_error("sign_file('%s'): %s\n", fname_print, g10_errstr(rc) );
+ sl = NULL;
+ if( detached_sig ) { /* sign all files */
+ for( ; argc; argc--, argv++ )
+ add_to_strlist( &sl, *argv );
+ }
+ else {
+ if( argc > 1 )
+ usage(1);
+ if( argc ) {
+ sl = m_alloc_clear( sizeof *sl + strlen(fname));
+ strcpy(sl->d, fname);
+ }
+ }
+ if( (rc = sign_file( sl, detached_sig, locusr, 0, NULL, NULL)) )
+ log_error("sign_file: %s\n", g10_errstr(rc) );
+ free_strlist(sl);
break;
case aSignEncr: /* sign and encrypt the given file */
if( argc > 1 )
usage(1);
- if( (rc = sign_file(fname, detached_sig, locusr, 1, remusr)) )
+ if( argc ) {
+ sl = m_alloc_clear( sizeof *sl + strlen(fname));
+ strcpy(sl->d, fname);
+ }
+ else
+ sl = NULL;
+ if( (rc = sign_file(sl, detached_sig, locusr, 1, remusr, NULL)) )
log_error("sign_file('%s'): %s\n", fname_print, g10_errstr(rc) );
+ free_strlist(sl);
break;
diff --git a/g10/getkey.c b/g10/getkey.c
index 3ec6a6bf4..b1cb64a29 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -51,6 +51,13 @@ typedef struct pkc_cache_entry {
PKT_public_cert *pkc;
} *pkc_cache_entry_t;
+typedef struct enum_seckey_context {
+ int eof;
+ STRLIST sl;
+ IOBUF iobuf;
+} enum_seckey_context_t;
+
+
static STRLIST keyrings;
static STRLIST secret_keyrings;
@@ -351,6 +358,9 @@ get_seckey_byname( PKT_secret_cert *skc, const char *name, int unprotect )
}
+
+
+
/****************
* scan the keyring and look for either the keyid or the name.
*/
@@ -585,6 +595,69 @@ scan_secret_keyring( PKT_secret_cert *skc, u32 *keyid,
/****************
+ * Enumerate all secret keys. Caller must use these procedure:
+ * 1) create a void pointer and initialize it to NULL
+ * 2) pass this void pointer by reference to this function
+ * and provide space for the secret key (pass a buffer for skc)
+ * 3) call this function as long as it does not return -1
+ * to indicate EOF.
+ * 4) Always call this function a last time with SKC set to NULL,
+ * so that can free it's context.
+ *
+ * Return
+ */
+int
+enum_secret_keys( void **context, PKT_secret_cert *skc )
+{
+ int rc=0;
+ PACKET pkt;
+ int save_mode;
+ enum_seckey_context_t *c = *context;
+
+ if( !c ) { /* make a new context */
+ c = m_alloc_clear( sizeof *c );
+ *context = c;
+ c->sl = secret_keyrings;
+ }
+
+ if( !skc ) { /* free the context */
+ m_free( c );
+ *context = NULL;
+ return 0;
+ }
+
+ if( c->eof )
+ return -1;
+
+ for( ; c->sl; c->sl = c->sl->next ) {
+ if( !c->iobuf ) {
+ if( !(c->iobuf = iobuf_open( c->sl->d ) ) ) {
+ log_error("enum_secret_keys: can't open '%s'\n", c->sl->d );
+ continue; /* try next file */
+ }
+ }
+
+ save_mode = set_packet_list_mode(0);
+ init_packet(&pkt);
+ while( (rc=parse_packet(c->iobuf, &pkt)) != -1 ) {
+ if( rc )
+ ; /* e.g. unknown packet */
+ else if( pkt.pkttype == PKT_SECRET_CERT ) {
+ copy_secret_cert( skc, pkt.pkt.secret_cert );
+ set_packet_list_mode(save_mode);
+ return 0; /* found */
+ }
+ free_packet(&pkt);
+ }
+ set_packet_list_mode(save_mode);
+ iobuf_close(c->iobuf); c->iobuf = NULL;
+ }
+ c->eof = 1;
+ return -1;
+}
+
+
+/****************
* Return a string with a printable representation of the user_id.
* this string must be freed by m_free.
*/
diff --git a/g10/keydb.h b/g10/keydb.h
index 6770f866e..8eb49478d 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -97,6 +97,7 @@ int get_pubkey( PKT_public_cert *pkc, u32 *keyid );
int get_pubkey_byname( PKT_public_cert *pkc, const char *name );
int get_seckey( PKT_secret_cert *skc, u32 *keyid );
int get_seckey_byname( PKT_secret_cert *skc, const char *name, int unlock );
+int enum_secret_keys( void **context, PKT_secret_cert *skc );
char*get_user_id_string( u32 *keyid );
char*get_user_id( u32 *keyid, size_t *rn );
diff --git a/g10/main.h b/g10/main.h
index a10ce4ba3..a1a13e41e 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -41,8 +41,8 @@ int encrypt_filter( void *opaque, int control,
/*-- sign.c --*/
-int sign_file( const char *filename, int detached, STRLIST locusr,
- int encrypt, STRLIST remusr );
+int sign_file( STRLIST filenames, int detached, STRLIST locusr,
+ int encrypt, STRLIST remusr, const char *outfile );
int sign_key( const char *username, STRLIST locusr );
int edit_keysigs( const char *username );
int change_passphrase( const char *username );
diff --git a/g10/options.h b/g10/options.h
index 0df1f41ea..3b72547ce 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -58,11 +58,13 @@ struct {
#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
#define DBG_CACHE_VALUE 64 /* debug the cacheing */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
+#define DBG_TRUST_VALUE 256 /* debug the trustdb */
#define DBG_PACKET (opt.debug & DBG_PACKET_VALUE)
#define DBG_FILTER (opt.debug & DBG_FILTER_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
+#define DBG_TRUST (opt.debug & DBG_TRUST_VALUE)
#endif /*G10_OPTIONS_H*/
diff --git a/g10/packet.h b/g10/packet.h
index e82248a85..6326c43d4 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -98,6 +98,7 @@ typedef struct {
u16 valid_days; /* valid for this number of days */
byte pubkey_algo; /* algorithm used for public key scheme */
md_filter_context_t mfx;
+ u32 local_id; /* internal use, valid if > 0 */
union {
struct {
MPI p; /* prime */
@@ -225,13 +226,16 @@ void hash_public_cert( MD_HANDLE md, PKT_public_cert *pkc );
/*-- free-packet.c --*/
void free_pubkey_enc( PKT_pubkey_enc *enc );
void free_seckey_enc( PKT_signature *enc );
+void release_public_cert_parts( PKT_public_cert *cert );
void free_public_cert( PKT_public_cert *cert );
+void release_secret_cert_parts( PKT_secret_cert *cert );
void free_secret_cert( PKT_secret_cert *cert );
void free_user_id( PKT_user_id *uid );
void free_comment( PKT_comment *rem );
void free_packet( PACKET *pkt );
PKT_public_cert *copy_public_cert( PKT_public_cert *d, PKT_public_cert *s );
PKT_secret_cert *copy_secret_cert( PKT_secret_cert *d, PKT_secret_cert *s );
+int cmp_public_secret_cert( PKT_public_cert *pkc, PKT_secret_cert *skc );
/*-- sig-check.c --*/
diff --git a/g10/pkclist.c b/g10/pkclist.c
index f753eb6fc..3fd22549c 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -41,6 +41,25 @@
static int
do_we_trust( PKT_public_cert *pkc, int trustlevel )
{
+ int rc;
+
+ if( trustlevel & TRUST_NO_PUBKEY ) {
+ /* No pubkey in trustDB: Insert and check again */
+ rc = insert_trust_record( pkc );
+ if( rc ) {
+ log_error("failed to insert it into the trustdb: %s\n",
+ g10_errstr(rc) );
+ return 0; /* no */
+ }
+ rc = check_pkc_trust( pkc, &trustlevel );
+ if( rc )
+ log_fatal("trust check after insert failed: %s\n",
+ g10_errstr(rc) );
+ if( trustlevel & TRUST_NO_PUBKEY )
+ log_bug(NULL);
+ }
+
+
/* Eventuell fragen falls der trustlevel nicht ausreichend ist */
@@ -90,6 +109,7 @@ build_pkc_list( STRLIST remusr, PKC_LIST *ret_pkc_list )
remusr->d, g10_errstr(rc) );
}
else if( do_we_trust( pkc, trustlevel ) ) {
+ /* note: do_we_trust may have changed the trustlevel */
PKC_LIST r;
r = m_alloc( sizeof *r );
diff --git a/g10/sign.c b/g10/sign.c
index 04ae72a2f..9e8275ae9 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -64,17 +64,22 @@ complete_sig( PKT_signature *sig, PKT_secret_cert *skc, MD_HANDLE md )
/****************
- * Sign the file with name FILENAME. If DETACHED has the value true,
- * make a detached signature. If FILENAME is NULL read from stdin
+ * Sign the files whose names are in FILENAME.
+ * If DETACHED has the value true,
+ * make a detached signature. If FILENAMES->d is NULL read from stdin
* and ignore the detached mode. Sign the file with all secret keys
* which can be taken from LOCUSR, if this is NULL, use the default one
* If ENCRYPT is true, use REMUSER (or ask if it is NULL) to encrypt the
* signed data for these users.
+ * If OUTFILE is not NULL; this file is used for output and the function
+ * does not ask for overwrite permission; output is then always
+ * uncompressed, non-armored and in binary mode.
*/
int
-sign_file( const char *filename, int detached, STRLIST locusr,
- int encrypt, STRLIST remusr )
+sign_file( STRLIST filenames, int detached, STRLIST locusr,
+ int encrypt, STRLIST remusr, const char *outfile )
{
+ const char *fname;
armor_filter_context_t afx;
compress_filter_context_t zfx;
md_filter_context_t mfx;
@@ -88,6 +93,7 @@ sign_file( const char *filename, int detached, STRLIST locusr,
PKC_LIST pkc_list = NULL;
SKC_LIST skc_list = NULL;
SKC_LIST skc_rover = NULL;
+ int multifile = 0;
memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx);
@@ -96,6 +102,16 @@ sign_file( const char *filename, int detached, STRLIST locusr,
memset( &efx, 0, sizeof efx);
init_packet( &pkt );
+ if( filenames ) {
+ fname = filenames->d;
+ multifile = !!filenames->next;
+ }
+ else
+ fname = NULL;
+
+ if( fname && filenames->next && (!detached || encrypt) )
+ log_bug("multiple files can only be detached signed");
+
if( (rc=build_skc_list( locusr, &skc_list, 1 )) )
goto leave;
if( encrypt ) {
@@ -104,28 +120,40 @@ sign_file( const char *filename, int detached, STRLIST locusr,
}
/* prepare iobufs */
- if( !(inp = iobuf_open(filename)) ) {
- log_error("can't open %s: %s\n", filename? filename: "[stdin]",
+ if( multifile ) /* have list of filenames */
+ inp = NULL; /* we do it later */
+ else if( !(inp = iobuf_open(fname)) ) {
+ log_error("can't open %s: %s\n", fname? fname: "[stdin]",
strerror(errno) );
rc = G10ERR_OPEN_FILE;
goto leave;
}
- if( !(out = open_outfile( filename, opt.armor? 1: detached? 2:0 )) ) {
+ if( outfile ) {
+ if( !(out = iobuf_create( outfile )) ) {
+ log_error("can't create %s: %s\n", outfile, strerror(errno) );
+ rc = G10ERR_CREATE_FILE;
+ goto leave;
+ }
+ else if( opt.verbose )
+ log_info("writing to '%s'\n", outfile );
+ }
+ else if( !(out = open_outfile( fname, opt.armor? 1: detached? 2:0 )) ) {
rc = G10ERR_CREATE_FILE;
goto leave;
}
/* prepare to calculate the MD over the input */
- if( opt.textmode && opt.armor )
+ if( opt.textmode && opt.armor && !outfile )
iobuf_push_filter( inp, text_filter, &tfx );
mfx.md = md_open(DIGEST_ALGO_RMD160, 0);
- iobuf_push_filter( inp, md_filter, &mfx );
+ if( !multifile )
+ iobuf_push_filter( inp, md_filter, &mfx );
- if( opt.armor )
+ if( opt.armor && !outfile )
iobuf_push_filter( out, armor_filter, &afx );
write_comment( out, "#Created by G10 pre-release " VERSION );
- if( opt.compress )
+ if( opt.compress && !outfile )
iobuf_push_filter( out, compress_filter, &zfx );
if( encrypt ) {
@@ -141,7 +169,7 @@ sign_file( const char *filename, int detached, STRLIST locusr,
skc = skc_rover->skc;
ops = m_alloc_clear( sizeof *ops );
- ops->sig_class = opt.textmode? 0x01 : 0x00;
+ ops->sig_class = opt.textmode && !outfile ? 0x01 : 0x00;
ops->digest_algo = DIGEST_ALGO_RMD160;
ops->pubkey_algo = skc->pubkey_algo;
keyid_from_skc( skc, ops->keyid );
@@ -161,17 +189,40 @@ sign_file( const char *filename, int detached, STRLIST locusr,
/* setup the inner packet */
if( detached ) {
- /* read, so that the filter can calculate the digest */
- while( iobuf_get(inp) != -1 )
- ;
+ if( multifile ) {
+ STRLIST sl = filenames;
+
+ if( opt.verbose )
+ log_info("signing:" );
+ for(; sl; sl = sl->next ) {
+ if( !(inp = iobuf_open(sl->d)) ) {
+ log_error("can't open %s: %s\n", sl->d, strerror(errno) );
+ rc = G10ERR_OPEN_FILE;
+ goto leave;
+ }
+ if( opt.verbose )
+ fprintf(stderr, " '%s'", sl->d );
+ iobuf_push_filter( inp, md_filter, &mfx );
+ while( iobuf_get(inp) != -1 )
+ ;
+ iobuf_close(inp); inp = NULL;
+ }
+ if( opt.verbose )
+ putc( '\n', stderr );
+ }
+ else {
+ /* read, so that the filter can calculate the digest */
+ while( iobuf_get(inp) != -1 )
+ ;
+ }
}
else {
- if( filename ) {
- pt = m_alloc( sizeof *pt + strlen(filename) - 1 );
- pt->namelen = strlen(filename);
- memcpy(pt->name, filename, pt->namelen );
+ if( fname ) {
+ pt = m_alloc( sizeof *pt + strlen(fname) - 1 );
+ pt->namelen = strlen(fname);
+ memcpy(pt->name, fname, pt->namelen );
if( !(filesize = iobuf_get_filelength(inp)) )
- log_info("warning: '%s' is an empty file\n", filename );
+ log_info("warning: '%s' is an empty file\n", fname );
}
else { /* no filename */
pt = m_alloc( sizeof *pt - 1 );
@@ -179,7 +230,7 @@ sign_file( const char *filename, int detached, STRLIST locusr,
filesize = 0; /* stdin */
}
pt->timestamp = make_timestamp();
- pt->mode = opt.textmode? 't':'b';
+ pt->mode = opt.textmode && !outfile ? 't':'b';
pt->len = filesize;
pt->buf = inp;
pkt.pkttype = PKT_PLAINTEXT;
@@ -203,7 +254,7 @@ sign_file( const char *filename, int detached, STRLIST locusr,
sig = m_alloc_clear( sizeof *sig );
sig->pubkey_algo = skc->pubkey_algo;
sig->timestamp = make_timestamp();
- sig->sig_class = opt.textmode? 0x01 : 0x00;
+ sig->sig_class = opt.textmode && !outfile? 0x01 : 0x00;
md = md_copy( mfx.md );
md_putc( md, sig->sig_class );
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 46c950021..1dfaaa570 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <errno.h>
#include <assert.h>
+#include <fcntl.h>
#include "errors.h"
#include "iobuf.h"
@@ -41,7 +42,6 @@ struct trust_record {
byte rectype;
byte reserved;
union {
- byte raw[TRUST_RECORD_LEN-2];
struct { /* version record: */
byte magic[2];
byte version; /* should be 1 */
@@ -76,10 +76,32 @@ struct trust_record {
} cache;
} r;
};
+typedef struct trust_record TRUSTREC;
+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 char *db_name;
+static int db_fd = -1;
+static int no_io_dbg = 0;
+
+#define buftou32( 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 { \
+ ((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 { \
+ ((byte*)p)[0] = a >> 8; \
+ ((byte*)p)[1] = a ; \
+ } while(0)
+
/**************************************************
************** read and write helpers ************
@@ -147,7 +169,7 @@ create_db( const char *fname )
fwrite_32( fp, make_timestamp() ); /* created */
fwrite_32( fp, 0 ); /* not yet modified */
fwrite_32( fp, 0 ); /* not yet validated*/
- fwrite_32( fp, 0 ); /* local-id-counter */
+ fwrite_32( fp, 0 ); /* local-id-counter (not used) */
fwrite_8( fp, 3 ); /* marginals needed */
fwrite_8( fp, 1 ); /* completes needed */
fwrite_8( fp, 4 ); /* max_cet_depth */
@@ -155,14 +177,255 @@ create_db( const char *fname )
fclose(fp);
}
+static void
+open_db()
+{
+ TRUSTREC rec;
+ assert( db_fd == -1 );
+
+ db_fd = open( db_name, O_RDWR );
+ if( db_fd == -1 )
+ log_fatal("can't open %s: %s\n", db_name, strerror(errno) );
+ if( read_record( 0, &rec ) )
+ log_fatal("TrustDB %s is invalid\n", db_name );
+ /* fixme: check ->locked and other stuff */
+}
+/****************
+ * read the record with number recnum
+ * returns: -1 on error, 0 on success
+ */
+static int
+read_record( u32 recnum, TRUSTREC *rec )
+{
+ byte buf[TRUST_RECORD_LEN], *p;
+ int rc = 0;
+ int n;
+
+ if( db_fd == -1 )
+ open_db();
+ if( DBG_TRUST && !no_io_dbg )
+ log_debug("trustdb: read_record(%lu)\n", (ulong)recnum);
+ if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
+ log_error("trustdb: lseek failed: %s\n", strerror(errno) );
+ return G10ERR_READ_FILE;
+ }
+ n = read( db_fd, buf, TRUST_RECORD_LEN);
+ if( !n ) {
+ if( DBG_TRUST )
+ log_debug("trustdb: no record at %lu\n", (ulong)recnum );
+ return -1; /* eof */
+ }
+ else if( n != TRUST_RECORD_LEN ) {
+ log_error("trustdb: read failed (n=%d): %s\n", n, strerror(errno) );
+ return G10ERR_READ_FILE;
+ }
+ p = buf;
+ rec->rectype = *p++;
+ rec->reserved = *p++;
+ switch( rec->rectype ) {
+ case 0: /* unused record */
+ break;
+ case 1: /* version record */
+ rec->r.version.magic[0] = *p++;
+ 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.marginals_needed = *p++;
+ rec->r.version.completes_needed = *p++;
+ rec->r.version.max_cert_depth = *p++;
+ if( recnum ) {
+ log_error("%s: version record with recnum %lu\n",
+ db_name, (ulong)recnum );
+ rc = G10ERR_TRUSTDB;
+ }
+ if( rec->reserved != 'g' || rec->r.version.magic[0] != '1'
+ || rec->r.version.magic[1] != '0' ) {
+ log_error("%s: not a trustdb file\n", db_name );
+ rc = G10ERR_TRUSTDB;
+ }
+ if( rec->r.version.version != 1 ) {
+ log_error("%s: invalid file version %d\n",
+ db_name, rec->r.version.version );
+ rc = G10ERR_TRUSTDB;
+ }
+ break;
+ case 2:
+ rec->r.pubkey.local_id = buftou32(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.reserved = *p++;
+ memcpy( rec->r.pubkey.fingerprint, p, 20); p += 20;
+ rec->r.pubkey.ownertrust = *p++;
+ if( rec->r.pubkey.local_id != recnum ) {
+ log_error("%s: pubkey local_id != recnum (%lu,%lu)\n",
+ db_name,
+ (ulong)rec->r.pubkey.local_id,
+ (ulong)recnum );
+ rc = G10ERR_TRUSTDB;
+ }
+ break;
+ case 3:
+ rec->r.cache.local_id = buftou32(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++;
+ rec->r.cache.reserved = *p++;
+ memcpy(rec->r.cache.blockhash, p, 20); p += 20;
+ rec->r.cache.n_untrusted = *p++;
+ rec->r.cache.n_marginal = *p++;
+ rec->r.cache.n_fully = *p++;
+ rec->r.cache.trustlevel = *p++;
+ break;
+ default:
+ log_error("%s: invalid record type %d at recnum %lu\n",
+ db_name, rec->rectype, (ulong)recnum );
+ rc = G10ERR_TRUSTDB;
+ break;
+ }
+ return rc;
+}
+/****************
+ * Write the record at RECNUM
+ */
+static int
+write_record( u32 recnum, TRUSTREC *rec )
+{
+ byte buf[TRUST_RECORD_LEN], *p;
+ int rc = 0;
+ int n;
+
+ if( db_fd == -1 )
+ open_db();
+
+ if( DBG_TRUST && !no_io_dbg )
+ log_debug("trustdb: write_record(%lu)\n", (ulong)recnum);
+ memset(buf, 0, TRUST_RECORD_LEN);
+ p = buf;
+ *p++ = rec->rectype;
+ *p++ = rec->reserved;
+ switch( rec->rectype ) {
+ case 0: /* unused record */
+ break;
+ case 1: /* version record */
+ log_bug(NULL);
+ break;
+ case 2:
+ u32tobuf(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.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;
+ u32tobuf(p, rec->r.cache.keyid[0]); p += 4;
+ u32tobuf(p, rec->r.cache.keyid[1]); p += 4;
+ *p++ = rec->r.cache.valid;
+ *p++ = rec->r.cache.reserved;
+ memcpy(p, rec->r.cache.blockhash, 20); p += 20;
+ *p++ = rec->r.cache.n_untrusted;
+ *p++ = rec->r.cache.n_marginal;
+ *p++ = rec->r.cache.n_fully;
+ *p++ = rec->r.cache.trustlevel;
+ break;
+ default:
+ log_bug(NULL);
+ }
+ if( lseek( db_fd, recnum * TRUST_RECORD_LEN, SEEK_SET ) == -1 ) {
+ log_error("trustdb: lseek failed: %s\n", strerror(errno) );
+ return G10ERR_WRITE_FILE;
+ }
+ n = write( db_fd, buf, TRUST_RECORD_LEN);
+ if( n != TRUST_RECORD_LEN ) {
+ log_error("trustdb: write failed (n=%d): %s\n", n, strerror(errno) );
+ return G10ERR_WRITE_FILE;
+ }
+ return rc;
+}
+static u32
+new_local_id()
+{
+ off_t offset;
+ u32 recnum;
+
+ /* fixme: look for unused records */
+ offset = lseek( db_fd, 0, SEEK_END );
+ if( offset == -1 )
+ 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 */
+ return recnum ;
+}
+
+/****************
+ * Scan the trustdb for a record of type RECTYPE which maches PKC
+ * The local_id is set to the correct value
+ */
+static int
+scan_record( PKT_public_cert *pkc, TRUSTREC *rec, int rectype )
+{
+ u32 recnum;
+ u32 keyid[2];
+ byte *fingerprint;
+ size_t fingerlen;
+ int dbg = DBG_TRUST;
+ int rc;
+
+ assert( rectype == 2 || rectype == 3 );
+
+ if( DBG_TRUST )
+ log_debug("trustdb: scan_record\n");
+ keyid_from_pkc( pkc, keyid );
+ fingerprint = fingerprint_from_pkc( pkc, &fingerlen );
+ assert( fingerlen == 20 || fingerlen == 16 );
+
+ no_io_dbg = 1;
+ for(recnum=1; !(rc=read_record( recnum, rec)); recnum++ ) {
+ if( rec->rectype != rectype )
+ continue;
+ 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
+ && !memcmp(rec->r.pubkey.fingerprint, fingerprint, fingerlen)
+ ) { /* found */
+ /* store the local_id */
+ if( pkc->local_id && pkc->local_id != recnum )
+ log_error("%s: found record, but local_id from mem does "
+ "not match recnum (%lu,%lu)\n", db_name,
+ (ulong)pkc->local_id, (ulong)recnum );
+ pkc->local_id = recnum;
+ no_io_dbg = 0;
+ return 0;
+ }
+ }
+ else
+ log_bug("not yet implemented\n");
+ }
+ no_io_dbg = 0;
+ if( DBG_TRUST )
+ log_debug("trustdb: scan_record: eof or error\n");
+ if( rc != -1 )
+ log_error("%s: scan_record failed: %s\n",db_name, g10_errstr(rc) );
+ return rc;
+}
@@ -171,8 +434,151 @@ create_db( const char *fname )
************* trust logic *******************
***********************************************/
+/****************
+ * Verify, that all our public keys are in the trustDB and marked as
+ * ultimately trusted.
+ */
+static int
+verify_own_certs()
+{
+ int rc;
+ void *enum_context = NULL;
+ PKT_secret_cert *skc = m_alloc_clear( sizeof *skc );
+ PKT_public_cert *pkc = m_alloc_clear( sizeof *pkc );
+ u32 keyid[2];
+ int trust;
+
+ while( !(rc=enum_secret_keys( &enum_context, skc) ) ) {
+ /* fixme: 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
+ * and verify this signature during
+ * startup
+ */
+
+ keyid_from_skc( skc, keyid );
+
+ if( DBG_TRUST )
+ log_debug("checking secret key %08lX\n", (ulong)keyid[1] );
+
+ /* look wether we can access the public key of this secret key */
+ rc = get_pubkey( pkc, keyid );
+ if( rc ) {
+ log_error("keyid %08lX: secret key without public key\n",
+ (ulong)keyid[1] );
+ goto leave;
+ }
+ if( cmp_public_secret_cert( pkc, skc ) ) {
+ log_error("keyid %08lX: secret and public key don't match\n",
+ (ulong)keyid[1] );
+ rc = G10ERR_GENERAL;
+ goto leave;
+ }
+ /* look into the trustdb */
+ rc = check_pkc_trust( pkc, &trust );
+ if( rc ) {
+ log_info("keyid %08lX: problem in trustdb: %s\n", (ulong)keyid[1],
+ g10_errstr(rc) );
+ goto leave;
+ }
+ if( trust & TRUST_NO_PUBKEY ) {
+ log_info("keyid %08lX: not yet in trustdb\n", (ulong)keyid[1] );
+ /* FIXME: insert */
+ }
+ else if( (trust & TRUST_MASK) != TRUST_ULT_TRUST ) {
+ log_error("keyid %08lX: not marked as ultimately trusted\n",
+ (ulong)keyid[1] );
+ /* FIXME: mark */
+ }
+
+ release_secret_cert_parts( skc );
+ release_public_cert_parts( pkc );
+ }
+ if( rc != -1 )
+ log_error("enum_secret_keys failed: %s\n", g10_errstr(rc) );
+ else
+ rc = 0;
+
+ leave:
+ free_secret_cert( skc );
+ free_public_cert( pkc );
+ return rc;
+}
+
+/****************
+ * Check all the sigs of the given keyblock and mark them
+ * as checked.
+ */
+static int
+check_sigs( KBNODE keyblock )
+{
+ KBNODE kbctx;
+ KBNODE node;
+ int rc;
+
+ 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 */
+ if( DBG_TRUST )
+ log_debug("trustdb: sig from %08lX: %s\n",
+ rc? g10_errstr(rc): "okay" );
+ }
+ }
+ return 0;
+}
+
+
+/****************
+ * Recursive check the signatures.
+ */
+static int
+walk( KBNODE keyblock, int levels )
+{
+ KBNODE kbctx, node;
+
+ check_sigs( keyblock );
+ if( levels ) { /* check the next level */
+ for( kbctx=NULL; (node=walk_kbtree( keyblock, &kbctx)) ; ) {
+ if( node->pkt->pkttype == PKT_SIGNATURE && (node->flag & 1) ) {
+ /* read the keyblock for this signator */
+
+ /* and check his signatures */
+ /*walk( his_keyblock, levels-1)*/
+ }
+ }
+ }
+
+}
+
+
+
+
+
+/****************
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+static int
+check_trust()
+{
+}
+
/*********************************************************
@@ -181,11 +587,13 @@ create_db( const char *fname )
/****************
* Perform some checks over the trustdb
- * level 0: used on initial program startup
+ * level 0: used for initial program startup
*/
int
check_trustdb( int level )
{
+ int rc=0;
+
if( !level ) {
char *fname = make_filename("~/.g10", "trustDB", NULL );
if( access( fname, R_OK ) ) {
@@ -200,13 +608,22 @@ check_trustdb( int level )
db_name = fname;
/* we can verify a signature about our local data (secring and trustdb)
- * in ~/.g10/ here
- */
+ * in ~/.g10/ here */
+ rc = verify_private_data();
+ if( !rc ) {
+ /* verify, that our own certificates are in the trustDB
+ * or move them to the trustdb. */
+ rc = verify_own_certs();
+
+ /* should we check wether there is no other ultimately trusted
+ * key in the database? */
+
+ }
}
else
log_bug(NULL);
- return 0;
+ return rc;
}
@@ -234,12 +651,171 @@ check_trustdb( int level )
int
check_pkc_trust( PKT_public_cert *pkc, int *r_trustlevel )
{
+ TRUSTREC rec;
int trustlevel = 0;
+ int rc=0;
if( opt.verbose )
log_info("check_pkc_trust() called.\n");
+ /* get the pubkey record */
+ if( pkc->local_id ) {
+ if( read_record( pkc->local_id, &rec ) ) {
+ log_error("check_pkc_trust: read record failed\n");
+ return G10ERR_TRUSTDB;
+ }
+ }
+ else { /* no local_id: scan the trustdb */
+ if( (rc=scan_record( pkc, &rec, 2 )) && rc != -1 ) {
+ log_error("check_pkc_trust: scan_record(2) failed: %s\n",
+ g10_errstr(rc));
+ return G10ERR_TRUSTDB;
+ }
+ else if( rc == -1 ) {
+ log_error("check_pkc_trust: pubkey not in TrustDB\n");
+ trustlevel = TRUST_NO_PUBKEY;
+ goto leave;
+ }
+ }
+ /* fixme: do some additional checks on the pubkey record */
+
+
+ leave:
+ if( opt.verbose )
+ log_info("check_pkc_trust() returns trustlevel %04x.\n", trustlevel);
*r_trustlevel = trustlevel;
return 0;
}
+
+/****************
+ * Insert a trust record into the TrustDB
+ * This function failes if this record already exists.
+ */
+int
+insert_trust_record( PKT_public_cert *pkc )
+{
+ TRUSTREC rec;
+ u32 keyid[2];
+ u32 recnum;
+ byte *fingerprint;
+ size_t fingerlen;
+
+
+ if( DBG_TRUST )
+ log_debug("trustdb: insert_record\n");
+
+ assert( !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();
+ /* 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;
+ memcpy(rec.r.pubkey.fingerprint, fingerprint, fingerlen );
+ rec.r.pubkey.ownertrust = 0;
+ if( write_record( recnum, &rec ) ) {
+ log_error("insert_trust_record: write failed\n");
+ return G10ERR_TRUSTDB;
+ }
+
+ pkc->local_id = recnum;
+
+ return 0;
+}
+
+
+int
+update_trust_record( PKT_public_cert *pkc, int new_trust )
+{
+ TRUSTREC rec;
+ u32 keyid[2];
+ u32 recnum;
+
+ if( DBG_TRUST )
+ log_debug("trustdb: update_record\n");
+
+ assert( pkc->local_id );
+
+ if( read_record( pkc->local_id, &rec ) ) {
+ log_error("update_trust_record: read failed\n");
+ return G10ERR_TRUSTDB;
+ }
+ /* check keyid, fingerprint etc ? */
+
+ recnum = new_local_id();
+ /* 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;
+ memcpy(rec.r.pubkey.fingerprint, fingerprint, fingerlen );
+ rec.r.pubkey.ownertrust = 0;
+ if( write_record( recnum, &rec ) ) {
+ log_error("insert_trust_record: write failed\n");
+ return G10ERR_TRUSTDB;
+ }
+
+ pkc->local_id = recnum;
+
+ return 0;
+}
+
+
+int
+verify_private_data()
+{
+ int rc = 0;
+ char *sigfile = make_filename("~/.g10", "sig", NULL );
+
+ if( access( sigfile, R_OK ) ) {
+ if( errno != ENOENT ) {
+ log_error("can't access %s: %s\n", sigfile, strerror(errno) );
+ rc = G10ERR_TRUSTDB;
+ goto leave;
+ }
+ log_info("private data signature missing; creating ...\n");
+ rc = sign_private_data();
+ if( rc ) {
+ log_error("error creating %s: %s\n", sigfile, g10_errstr(rc) );
+ goto leave;
+ }
+ }
+
+ /* FIXME: verify this signature */
+
+ leave:
+ m_free(sigfile);
+ return rc;
+}
+
+
+int
+sign_private_data()
+{
+ int rc;
+ char *sigfile = make_filename("~/.g10", "sig", NULL );
+ char *secring = make_filename("~/.g10", "secring.g10", NULL );
+ STRLIST list = NULL;
+
+ add_to_strlist( &list, db_name );
+ add_to_strlist( &list, secring );
+
+ rc = sign_file( list, 1, NULL, 0, NULL, sigfile);
+
+ m_free(sigfile);
+ m_free(secring);
+ free_strlist(list);
+ return rc;
+}
+
diff --git a/g10/trustdb.h b/g10/trustdb.h
index 01f126808..aff668e84 100644
--- a/g10/trustdb.h
+++ b/g10/trustdb.h
@@ -21,8 +21,22 @@
#ifndef G10_TRUSTDB_H
#define G10_TRUSTDB_H
+
+
+#define TRUST_MASK 0x07 /* for the trust leveles */
+#define TRUST_UNKNOWN 1 /* unknown */
+#define TRUST_NO_TRUST 2 /* not trusted */
+#define TRUST_MARG_TRUST 4 /* marginally trusted */
+#define TRUST_FULL_TRUST 5 /* fully trusted */
+#define TRUST_ULT_TRUST 7 /* ultimately trusted */
+ /* other bits used with the trustlevel */
+#define TRUST_NO_PUBKEY 0x10 /* we do not have the pubkey in out trustDB */
+
+
/*-- trustdb.c --*/
int check_trustdb( int level );
int check_pkc_trust( PKT_public_cert *pkc, int *r_trustlevel );
+int verify_private_data(void);
+int sign_private_data(void);
#endif /*G10_TRUSTDB_H*/
diff --git a/include/util.h b/include/util.h
index 34015ffe6..7f2593022 100644
--- a/include/util.h
+++ b/include/util.h
@@ -91,6 +91,7 @@ int answer_is_yes( const char *s );
/*-- strgutil.c --*/
void free_strlist( STRLIST sl );
#define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0)
+void add_to_strlist( STRLIST *list, const char *string );
char *memistr( char *buf, size_t buflen, const char *sub );
char *trim_spaces( char *string );
int string_count_chr( const char *string, int c );
diff --git a/util/strgutil.c b/util/strgutil.c
index ecdcb750c..cb80c57ab 100644
--- a/util/strgutil.c
+++ b/util/strgutil.c
@@ -37,6 +37,18 @@ free_strlist( STRLIST sl )
}
}
+
+void
+add_to_strlist( STRLIST *list, const char *string )
+{
+ STRLIST sl;
+
+ sl = m_alloc( sizeof *sl + strlen(string));
+ strcpy(sl->d, string);
+ sl->next = *list;
+ *list = sl;
+}
+
/****************
* look for the substring SUB in buffer and return a pointer to that
* substring in BUF or NULL if not found.