*** empty log message ***

This commit is contained in:
Werner Koch 1998-01-13 19:04:23 +00:00
parent ed36092588
commit 922e57dd57
16 changed files with 889 additions and 60 deletions

View File

@ -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");
}

View File

@ -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

View File

@ -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 );

View File

@ -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;
}

View File

@ -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;

View File

@ -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.
*/
@ -584,6 +594,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.

View File

@ -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 );

View File

@ -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 );

View File

@ -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*/

View File

@ -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 --*/

View File

@ -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 );

View File

@ -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 );

View File

@ -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,7 +434,150 @@ 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;
}

View File

@ -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*/

View File

@ -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 );

View File

@ -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.