1
0
Fork 0
mirror of git://git.gnupg.org/gnupg.git synced 2025-07-02 22:46:30 +02:00

edit-key is now complete

This commit is contained in:
Werner Koch 1998-07-29 19:35:05 +00:00
parent 1a80de41a5
commit 5ae562b41d
48 changed files with 2044 additions and 984 deletions

View file

@ -1,3 +1,26 @@
Wed Jul 29 12:53:03 1998 Werner Koch (wk@(none))
* free-packet.c (copy_signature): New.
* keygen.c (generate_subkeypair): rewritten
* g10.c (aKeyadd): Removed option --add-key
Mon Jul 27 10:37:28 1998 Werner Koch (wk@(none))
* seckey-cert.c (do_check): Additional check on cipher blocksize.
(protect_secret_key): Ditto.
* encr-data.c: Support for other blocksizes.
* cipher.c (write_header): Ditto.
Fri Jul 24 16:47:59 1998 Werner Koch (wk@(none))
* kbnode.c (insert_kbnode): Changed semantics and all callers.
* keyedit.c : More or less a complete rewrite
Wed Jul 22 17:10:04 1998 Werner Koch (wk@(none))
* build-packet.c (write_sign_packet_header): New.
Tue Jul 21 14:37:09 1998 Werner Koch (wk@(none))
* import.c (import_one): Now creates a trustdb record.

View file

@ -48,7 +48,6 @@ common_source = \
status.c \
status.h \
sign.c \
keyedit.c \
plaintext.c \
encr-data.c \
encode.c \
@ -61,6 +60,7 @@ gpg_SOURCES = g10.c \
$(common_source) \
verify.c \
decrypt.c \
keyedit.c \
keygen.c

View file

@ -57,3 +57,9 @@ compress-sigs
# Normally, compressing of signatures does not make sense; so this
# is disabled for detached signatures unless this option is used.
emulate-pgp-sign-bug
# PGP 2.x can only cope with 2 byte length headers of the
# signature packets, this option forces.

View file

@ -51,6 +51,7 @@ static int calc_header_length( u32 len );
static int write_16(IOBUF inp, u16 a);
static int write_32(IOBUF inp, u32 a);
static int write_header( IOBUF out, int ctb, u32 len );
static int write_sign_packet_header( IOBUF out, int ctb, u32 len );
static int write_header2( IOBUF out, int ctb, u32 len, int hdrlen, int blkmode );
static int write_new_header( IOBUF out, int ctb, u32 len, int hdrlen );
static int write_version( IOBUF out, int ctb );
@ -669,7 +670,10 @@ do_signature( IOBUF out, int ctb, PKT_signature *sig )
for(i=0; i < n; i++ )
mpi_write(a, sig->data[i] );
write_header(out, ctb, iobuf_get_temp_length(a) );
if( is_RSA(sig->pubkey_algo) && sig->version < 4 )
write_sign_packet_header(out, ctb, iobuf_get_temp_length(a) );
else
write_header(out, ctb, iobuf_get_temp_length(a) );
if( iobuf_write_temp( out, a ) )
rc = G10ERR_WRITE_FILE;
@ -747,6 +751,18 @@ write_header( IOBUF out, int ctb, u32 len )
return write_header2( out, ctb, len, 0, 1 );
}
static int
write_sign_packet_header( IOBUF out, int ctb, u32 len )
{
/* work around a bug in the pgp read function for signature packets,
* which are not correctly coded and silently assume at some
* point 2 byte length headers.*/
iobuf_put(out, 0x89 );
iobuf_put(out, len >> 8 );
return iobuf_put(out, len ) == -1 ? -1:0;
}
/****************
* if HDRLEN is > 0, try to build a header of this length.
* we need this, so that we can hash packets without reading them again.

View file

@ -42,7 +42,8 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
{
PACKET pkt;
PKT_encrypted ed;
byte temp[10];
byte temp[18];
unsigned blocksize;
memset( &ed, 0, sizeof ed );
ed.len = cfx->datalen;
@ -52,15 +53,18 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
pkt.pkt.encrypted = &ed;
if( build_packet( a, &pkt ))
log_bug("build_packet(ENCR_DATA) failed\n");
randomize_buffer( temp, 8, 1 );
temp[8] = temp[6];
temp[9] = temp[7];
blocksize = cipher_get_blocksize( cfx->dek->algo );
if( blocksize < 8 || blocksize > 16 )
log_fatal("unsupported blocksize %u\n", blocksize );
randomize_buffer( temp, blocksize, 1 );
temp[blocksize] = temp[blocksize-2];
temp[blocksize+1] = temp[blocksize-1];
cfx->cipher_hd = cipher_open( cfx->dek->algo, CIPHER_MODE_AUTO_CFB, 1 );
cipher_setkey( cfx->cipher_hd, cfx->dek->key, cfx->dek->keylen );
cipher_setiv( cfx->cipher_hd, NULL );
cipher_encrypt( cfx->cipher_hd, temp, temp, 10);
cipher_encrypt( cfx->cipher_hd, temp, temp, blocksize+2);
cipher_sync( cfx->cipher_hd );
iobuf_write(a, temp, 10);
iobuf_write(a, temp, blocksize+2);
cfx->header=1;
}

View file

@ -49,7 +49,8 @@ decrypt_data( PKT_encrypted *ed, DEK *dek )
decode_filter_ctx_t dfx;
byte *p;
int rc, c, i;
byte temp[16];
byte temp[32];
unsigned blocksize;
if( opt.verbose ) {
const char *s = cipher_algo_to_string( dek->algo );
@ -60,7 +61,10 @@ decrypt_data( PKT_encrypted *ed, DEK *dek )
}
if( (rc=check_cipher_algo(dek->algo)) )
return rc;
if( ed->len && ed->len < 10 )
blocksize = cipher_get_blocksize(dek->algo);
if( !blocksize || blocksize > 16 )
log_fatal("unsupported blocksize %u\n", blocksize );
if( ed->len && ed->len < (blocksize+2) )
log_bug("Nanu\n"); /* oops: found a bug */
dfx.cipher_hd = cipher_open( dek->algo, CIPHER_MODE_AUTO_CFB, 1 );
@ -70,20 +74,20 @@ decrypt_data( PKT_encrypted *ed, DEK *dek )
if( ed->len ) {
iobuf_set_limit( ed->buf, ed->len );
for(i=0; i < 10 && ed->len; i++, ed->len-- )
for(i=0; i < (blocksize+2) && ed->len; i++, ed->len-- )
temp[i] = iobuf_get(ed->buf);
}
else {
for(i=0; i < 10; i++ )
for(i=0; i < (blocksize+2); i++ )
if( (c=iobuf_get(ed->buf)) == -1 )
break;
else
temp[i] = c;
}
cipher_decrypt( dfx.cipher_hd, temp, temp, 10);
cipher_decrypt( dfx.cipher_hd, temp, temp, blocksize+2);
cipher_sync( dfx.cipher_hd );
p = temp;
if( p[6] != p[8] || p[7] != p[9] ) {
if( p[blocksize-2] != p[blocksize] || p[blocksize-1] != p[blocksize+1] ) {
cipher_close(dfx.cipher_hd);
return G10ERR_BAD_KEY;
}

View file

@ -55,7 +55,7 @@ void
free_seckey_enc( PKT_signature *sig )
{
int n, i;
n = pubkey_get_nenc( sig->pubkey_algo );
n = pubkey_get_nsig( sig->pubkey_algo );
if( !n ) {
m_free(sig->data[0]);
sig->data[0] = NULL;
@ -107,6 +107,20 @@ cp_fake_data( MPI a )
return d;
}
static void *
cp_data_block( byte *s )
{
byte *d;
u16 len;
if( !s )
return NULL;
len = (s[0] << 8) | s[1];
d = m_alloc( len+2 );
memcpy(d, s, len+2);
return d;
}
PKT_public_key *
copy_public_key( PKT_public_key *d, PKT_public_key *s )
@ -126,6 +140,39 @@ copy_public_key( PKT_public_key *d, PKT_public_key *s )
return d;
}
PKT_signature *
copy_signature( PKT_signature *d, PKT_signature *s )
{
int n, i;
if( !d )
d = m_alloc(sizeof *d);
memcpy( d, s, sizeof *d );
n = pubkey_get_nsig( s->pubkey_algo );
if( !n )
d->data[0] = cp_fake_data(s->data[0]);
else {
for(i=0; i < n; i++ )
d->data[i] = mpi_copy( s->data[i] );
}
d->hashed_data = cp_data_block(s->hashed_data);
d->unhashed_data = cp_data_block(s->unhashed_data);
return d;
}
PKT_user_id *
copy_user_id( PKT_user_id *d, PKT_user_id *s )
{
if( !d )
d = m_alloc(sizeof *d + s->len - 1 );
memcpy( d, s, sizeof *d + s->len - 1 );
return d;
}
void
release_secret_key_parts( PKT_secret_key *sk )
{

View file

@ -68,11 +68,8 @@ static ARGPARSE_OPTS opts[] = {
{ 558, "list-secret-keys", 256, N_("list secret keys")},
#ifdef IS_G10
{ 503, "gen-key", 256, N_("generate a new key pair")},
{ 554, "add-key", 256, N_("add a subkey to a key pair")},
{ 506, "sign-key" ,256, N_("make a signature on a key in the keyring")},
{ 505, "delete-key",256, N_("remove key from the public keyring")},
{ 524, "edit-key" ,256, N_("edit a key signature")},
{ 525, "change-passphrase", 256, N_("change the passphrase of your secret keyring")},
{ 524, "edit-key" ,256, N_("sign or edit a key")},
{ 542, "gen-revoke",256, N_("generate a revocation certificate")},
#endif
{ 537, "export" , 256, N_("export keys") },
@ -81,7 +78,8 @@ static ARGPARSE_OPTS opts[] = {
{ 530, "import", 256 , N_("import/merge keys")},
{ 521, "list-packets",256,N_("list only the sequence of packets")},
#ifdef IS_G10MAINT
{ 564, "list-ownertrust", 256, N_("list the ownertrust values")},
{ 564, "export-ownertrust", 256, N_("export the ownertrust values")},
{ 525, "import-ownertrust", 256 , N_("import ownertrust values")},
{ 567, "check-trustdb",0 , N_("|[NAMES]|check the trust database")},
{ 546, "dearmor", 256, N_("De-Armor a file or stdin") },
{ 547, "enarmor", 256, N_("En-Armor a file or stdin") },
@ -153,6 +151,7 @@ static ARGPARSE_OPTS opts[] = {
{ 504, "delete-secret-key",0, "@" },
{ 524, "edit-sig" ,0, "@"}, /* alias for edit-key */
{ 523, "passphrase-fd",1, "@" },
{ 506, "sign-key" ,256, "@" }, /* alias for edit-key */
#endif
{ 532, "quick-random", 0, "@"},
{ 526, "no-verbose", 0, "@"},
@ -173,18 +172,18 @@ static ARGPARSE_OPTS opts[] = {
{ 566, "compress-sigs",0, "@"},
{ 559, "always-trust", 0, "@"},
{ 562, "emulate-checksum-bug", 0, "@"},
/*554 is unused */
{0} };
enum cmd_values { aNull = 0,
aSym, aStore, aEncr, aKeygen, aSign, aSignEncr,
aSignKey, aClearsign, aListPackets, aEditKey, aDeleteKey, aDeleteSecretKey,
aKMode, aKModeC, aChangePass, aImport, aVerify, aDecrypt, aListKeys,
aListSigs, aKeyadd, aListSecretKeys,
aExport, aExportSecret,
aKMode, aKModeC, aImport, aVerify, aDecrypt, aListKeys,
aListSigs, aListSecretKeys, aExport, aExportSecret,
aCheckKeys, aGenRevoke, aPrimegen, aPrintMD, aPrintMDs,
aCheckTrustDB, aListTrustDB, aListTrustPath, aListOwnerTrust,
aCheckTrustDB, aListTrustDB, aListTrustPath,
aExportOwnerTrust, aImportOwnerTrust,
aDeArmor, aEnArmor, aGenRandom,
aTest };
@ -521,7 +520,6 @@ main( int argc, char **argv )
case 507: set_cmd( &cmd, aStore); break;
case 523: set_passphrase_fd( pargs.r.ret_int ); break;
case 524: set_cmd( &cmd, aEditKey); break;
case 525: set_cmd( &cmd, aChangePass); break;
case 527: def_cipher_string = m_strdup(pargs.r.ret_str); break;
case 529: def_digest_string = m_strdup(pargs.r.ret_str); break;
case 539: set_cmd( &cmd, aClearsign); break;
@ -548,7 +546,8 @@ main( int argc, char **argv )
case 546: set_cmd( &cmd, aDeArmor); break;
case 547: set_cmd( &cmd, aEnArmor); break;
case 555: set_cmd( &cmd, aPrintMD); break;
case 564: set_cmd( &cmd, aListOwnerTrust); break;
case 564: set_cmd( &cmd, aExportOwnerTrust); break;
case 525: set_cmd( &cmd, aImportOwnerTrust); break;
#endif /* IS_G10MAINT */
case 'o': opt.outfile = pargs.r.ret_str; break;
@ -564,7 +563,7 @@ main( int argc, char **argv )
case 510: opt.debug |= pargs.r.ret_ulong; break;
case 511: opt.debug = ~0; break;
case 512: set_status_fd( pargs.r.ret_int ); break;
case 515: opt.fingerprint = 1; break;
case 515: opt.fingerprint++; break;
case 517: append_to_strlist( &sec_nrings, pargs.r.ret_str); break;
case 518:
/* config files may not be nested (silently ignore them) */
@ -595,17 +594,17 @@ main( int argc, char **argv )
case 551: set_cmd( &cmd, aListKeys); break;
case 552: set_cmd( &cmd, aListSigs); break;
case 553: opt.skip_verify=1; break;
case 554: set_cmd( &cmd, aKeyadd); break;
case 556: opt.def_compress_algo = pargs.r.ret_int; break;
case 557: opt.compress_keys = 1; break;
case 558: set_cmd( &cmd, aListSecretKeys); break;
case 559: opt.always_trust = 1; break;
case 560: register_cipher_extension(pargs.r.ret_str); break;
case 561: opt.rfc1991 = 1; break;
case 562: opt.emulate_bugs |= 1; break;
case 561: opt.rfc1991 = 1; opt.no_comment = 1; break;
case 562: opt.emulate_bugs |= EMUBUG_GPGCHKSUM; break;
case 563: set_cmd( &cmd, aExportSecret); break;
case 565: opt.do_not_export_rsa = 1; break;
case 566: opt.compress_sigs = 1; break;
case 554:
default : errors++; pargs.err = configfp? 1:2; break;
}
}
@ -722,7 +721,7 @@ main( int argc, char **argv )
if( opt.with_colons ) /* need this to list the trust */
rc = init_trustdb(1, trustdb_name );
break;
case aListOwnerTrust: rc = init_trustdb( 0, trustdb_name ); break;
case aExportOwnerTrust: rc = init_trustdb( 0, trustdb_name ); break;
case aListTrustDB: rc = init_trustdb( argc? 1:0, trustdb_name ); break;
default: rc = init_trustdb(1, trustdb_name ); break;
}
@ -808,19 +807,10 @@ main( int argc, char **argv )
case aSignKey: /* sign the key given as argument */
if( argc != 1 )
wrong_args(_("--sign-key username"));
/* note: fname is the user id! */
if( (rc = sign_key(fname, locusr)) )
log_error("%s: sign key failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
break;
case aEditKey: /* Edit a key signature */
if( argc != 1 )
wrong_args(_("--edit-key username"));
/* note: fname is the user id! */
if( (rc = edit_keysigs(fname)) )
log_error("%s: edit signature failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
keyedit_menu(fname, locusr );
break;
case aDeleteSecretKey:
@ -834,14 +824,6 @@ main( int argc, char **argv )
log_error("%s: delete key failed: %s\n", print_fname_stdin(fname), g10_errstr(rc) );
break;
case aChangePass: /* Change the passphrase */
if( argc > 1 ) /* no arg: use default, 1 arg use this one */
wrong_args(_("--change-passphrase [username]"));
/* note: fname is the user id! */
if( (rc = change_passphrase(fname)) )
log_error("%s: change passphrase failed: %s\n", print_fname_stdin(fname),
g10_errstr(rc) );
break;
#endif /* IS_G10 */
case aCheckKeys:
@ -880,11 +862,6 @@ main( int argc, char **argv )
wrong_args("--gen-key");
generate_keypair();
break;
case aKeyadd: /* add a subkey (interactive) */
if( argc != 1 )
wrong_args("--add-key userid");
generate_subkeypair(*argv);
break;
#endif
case aImport:
@ -1049,10 +1026,16 @@ main( int argc, char **argv )
list_trust_path( atoi(*argv), argv[1] );
break;
case aListOwnerTrust:
case aExportOwnerTrust:
if( argc )
wrong_args("--list-ownertrust");
list_ownertrust();
wrong_args("--export-ownertrust");
export_ownertrust();
break;
case aImportOwnerTrust:
if( argc > 1 )
wrong_args("--import-ownertrust [file]");
import_ownertrust( argc? *argv:NULL );
break;
#endif /* IS_G10MAINT */

View file

@ -851,7 +851,7 @@ merge_sigs( KBNODE dst, KBNODE src, int *n_sigs,
* We add a clone to the original keyblock, because this
* one is released first */
n2 = clone_kbnode(n);
insert_kbnode( dst, n2, PKT_USER_ID );
insert_kbnode( dst, n2, PKT_SIGNATURE );
n2->flag |= 1;
n->flag |= 1;
++*n_sigs;

View file

@ -94,7 +94,8 @@ add_kbnode( KBNODE root, KBNODE node )
}
/****************
* Insert NODE into the list after root but before a packet with type PKTTYPE
* Insert NODE into the list after root but before a packet which is not of
* type PKTTYPE
* (only if PKTTYPE != 0)
*/
void
@ -108,7 +109,7 @@ insert_kbnode( KBNODE root, KBNODE node, int pkttype )
KBNODE n1;
for(n1=root; n1->next; n1 = n1->next)
if( pkttype == n1->next->pkt->pkttype ) {
if( pkttype != n1->next->pkt->pkttype ) {
node->next = n1->next;
n1->next = node;
return;

View file

@ -133,6 +133,8 @@ unsigned nbits_from_sk( PKT_secret_key *sk );
const char *datestr_from_pk( PKT_public_key *pk );
const char *datestr_from_sk( PKT_secret_key *sk );
const char *datestr_from_sig( PKT_signature *sig );
const char *expirestr_from_pk( PKT_public_key *pk );
const char *expirestr_from_sk( PKT_secret_key *sk );
byte *fingerprint_from_sk( PKT_secret_key *sk, byte *buf, size_t *ret_len );
byte *fingerprint_from_pk( PKT_public_key *pk, byte *buf, size_t *ret_len );
@ -149,6 +151,7 @@ KBNODE find_kbnode( KBNODE node, int pkttype );
KBNODE walk_kbnode( KBNODE root, KBNODE *context, int all );
void clear_kbnode_flags( KBNODE n );
int commit_kbnode( KBNODE *root );
void dump_kbnode( KBNODE node );
/*-- ringedit.c --*/
int add_keyblock_resource( const char *filename, int force, int secret );

File diff suppressed because it is too large Load diff

View file

@ -74,8 +74,8 @@ add_key_expire( PKT_signature *sig, void *opaque )
* Add preference to the self signature packet.
* This is only called for packets with version > 3.
*/
static int
add_prefs( PKT_signature *sig, void *opaque )
int
keygen_add_std_prefs( PKT_signature *sig, void *opaque )
{
byte buf[8];
@ -134,7 +134,7 @@ write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk )
/* and make the signature */
rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0,
add_prefs, sk );
keygen_add_std_prefs, sk );
if( rc ) {
log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) );
return rc;
@ -444,25 +444,18 @@ ask_keysize( int algo )
else if( nbits > 2048 ) {
tty_printf(_("Keysizes larger than 2048 are not suggested because "
"computations take REALLY long!\n"));
answer = tty_get(_("Are you sure that you want this keysize? "));
tty_kill_prompt();
if( answer_is_yes(answer) ) {
m_free(answer);
if( tty_get_answer_is_yes(_(
"Are you sure that you want this keysize? ")) ) {
tty_printf(_("Okay, but keep in mind that your monitor "
"and keyboard radiation is also very vulnerable "
"to attacks!\n"));
break;
}
m_free(answer);
}
else if( nbits > 1536 ) {
answer = tty_get(_("Do you really need such a large keysize? "));
tty_kill_prompt();
if( answer_is_yes(answer) ) {
m_free(answer);
if( tty_get_answer_is_yes(_(
"Do you really need such a large keysize? ")) )
break;
}
m_free(answer);
}
else
break;
@ -524,10 +517,7 @@ ask_valid_days()
add_days_to_timestamp( make_timestamp(), valid_days )));
}
m_free(answer);
answer = tty_get(_("Is this correct (y/n)? "));
tty_kill_prompt();
if( answer_is_yes(answer) )
if( tty_get_answer_is_yes(_("Is this correct (y/n)? ")) )
break;
}
m_free(answer);
@ -549,12 +539,13 @@ has_invalid_email_chars( const char *s )
static char *
ask_user_id()
ask_user_id( int mode )
{
char *answer;
char *aname, *acomment, *amail, *uid;
tty_printf( _("\n"
if( !mode )
tty_printf( _("\n"
"You need a User-ID to identify your key; the software constructs the user id\n"
"from Real Name, Comment and Email Address in this form:\n"
" \"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>\"\n\n") );
@ -630,28 +621,37 @@ ask_user_id()
tty_printf(_("You selected this USER-ID:\n \"%s\"\n\n"), uid);
/* fixme: add a warning if this user-id already exists */
for(;;) {
answer = tty_get(_("Edit (N)ame, (C)omment, (E)mail or (O)kay? "));
char *ansstr = N_("NnCcEeOoQq");
answer = tty_get(_(
"Change (N)ame, (C)omment, (E)mail or (O)kay/(Q)uit? "));
tty_kill_prompt();
if( strlen(answer) > 1 )
;
else if( *answer == 'N' || *answer == 'n' ) {
else if( *answer == ansstr[0] || *answer == ansstr[1] ) {
m_free(aname); aname = NULL;
break;
}
else if( *answer == 'C' || *answer == 'c' ) {
else if( *answer == ansstr[2] || *answer == ansstr[3] ) {
m_free(acomment); acomment = NULL;
break;
}
else if( *answer == 'E' || *answer == 'e' ) {
else if( *answer == ansstr[4] || *answer == ansstr[5] ) {
m_free(amail); amail = NULL;
break;
}
else if( *answer == 'O' || *answer == 'o' ) {
else if( *answer == ansstr[6] || *answer == ansstr[7] ) {
m_free(aname); aname = NULL;
m_free(acomment); acomment = NULL;
m_free(amail); amail = NULL;
break;
}
else if( *answer == ansstr[8] || *answer == ansstr[9] ) {
m_free(aname); aname = NULL;
m_free(acomment); acomment = NULL;
m_free(amail); amail = NULL;
m_free(uid); uid = NULL;
break;
}
m_free(answer);
}
m_free(answer);
@ -685,7 +685,7 @@ ask_passphrase( STRING2KEY **ret_s2k )
tty_printf(_(
"You don't want a passphrase - this is probably a *bad* idea!\n"
"I will do it anyway. You can change your passphrase at any time,\n"
"using this program with the option \"--change-passphrase\".\n\n"));
"using this program with the option \"--edit-key\".\n\n"));
break;
}
else
@ -728,6 +728,27 @@ do_create( int algo, unsigned nbits, KBNODE pub_root, KBNODE sec_root,
}
/****************
* Generate a new user id packet, or return NULL if cancelled
*/
PKT_user_id *
generate_user_id()
{
PKT_user_id *uid;
char *p;
size_t n;
p = ask_user_id( 1 );
if( !p )
return NULL;
n = strlen(p);
uid = m_alloc( sizeof *uid + n - 1 );
uid->len = n;
strcpy(uid->name, p);
return uid;
}
/****************
* Generate a keypair
*/
@ -762,7 +783,11 @@ generate_keypair()
}
nbits = ask_keysize( algo );
ndays = ask_valid_days();
uid = ask_user_id();
uid = ask_user_id(0);
if( !uid ) {
log_error(_("Key generation cancelled.\n"));
return;
}
dek = ask_passphrase( &s2k );
@ -879,88 +904,29 @@ generate_keypair()
/****************
* add a new subkey to an existing key.
* Returns true if a new key has been generated and put into the keyblocks.
*/
void
generate_subkeypair( const char *username )
int
generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock )
{
int rc=0;
KBPOS pub_kbpos, sec_kbpos;
KBNODE pub_keyblock = NULL;
KBNODE sec_keyblock = NULL;
int okay=0, rc=0;
KBNODE node;
PKT_secret_key *sk = NULL; /* this is the primary sk */
u32 keyid[2];
int v4, algo, ndays;
unsigned nbits;
char *passphrase = NULL;
DEK *dek = NULL;
STRING2KEY *s2k = NULL;
if( opt.batch || opt.answer_yes || opt.answer_no ) {
log_error(_("Key generation can only be used in interactive mode\n"));
return;
}
/* search the userid */
rc = find_secret_keyblock_byname( &sec_kbpos, username );
if( rc ) {
log_error("user '%s' not found\n", username );
goto leave;
}
rc = read_keyblock( &sec_kbpos, &sec_keyblock );
if( rc ) {
log_error("error reading the secret key: %s\n", g10_errstr(rc) );
goto leave;
}
/* and the public key */
rc = find_keyblock_byname( &pub_kbpos, username );
if( rc ) {
log_error("user '%s' not found in public ring\n", username );
goto leave;
}
rc = read_keyblock( &pub_kbpos, &pub_keyblock );
if( rc ) {
log_error("error reading the public key: %s\n", g10_errstr(rc) );
goto leave;
}
/* break out the primary key */
/* break out the primary secret key */
node = find_kbnode( sec_keyblock, PKT_SECRET_KEY );
if( !node ) {
log_error("Oops; secret key not found anymore!\n");
rc = G10ERR_GENERAL;
goto leave;
}
/* make a copy of the sk to keep the protected one in the keyblock */
sk = copy_secret_key( NULL, node->pkt->pkt.secret_key );
keyid_from_sk( sk, keyid );
/* display primary and all secondary keys */
tty_printf("sec %4u%c/%08lX %s ",
nbits_from_sk( sk ),
pubkey_letter( sk->pubkey_algo ),
keyid[1], datestr_from_sk(sk) );
{
size_t n;
char *p = get_user_id( keyid, &n );
tty_print_string( p, n );
m_free(p);
tty_printf("\n");
}
for(node=sec_keyblock; node; node = node->next ) {
if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
PKT_secret_key *subsk = node->pkt->pkt.secret_key;
keyid_from_sk( subsk, keyid );
tty_printf("sub %4u%c/%08lX %s\n",
nbits_from_sk( subsk ),
pubkey_letter( subsk->pubkey_algo ),
keyid[1], datestr_from_sk(subsk) );
}
}
tty_printf("\n");
/* unprotect to get the passphrase */
switch( is_secret_key_protected( sk ) ) {
case -1:
@ -984,6 +950,8 @@ generate_subkeypair( const char *username )
assert(algo);
nbits = ask_keysize( algo );
ndays = ask_valid_days();
if( !tty_get_answer_is_yes( _("Really create? ") ) )
goto leave;
if( passphrase ) {
s2k = m_alloc_secure( sizeof *s2k );
@ -999,31 +967,18 @@ generate_subkeypair( const char *username )
rc = write_keybinding(pub_keyblock, pub_keyblock, sk);
if( !rc )
rc = write_keybinding(sec_keyblock, pub_keyblock, sk);
/* write back */
if( !rc ) {
rc = update_keyblock( &pub_kbpos, pub_keyblock );
if( rc )
log_error("update_public_keyblock failed\n" );
}
if( !rc ) {
rc = update_keyblock( &sec_kbpos, sec_keyblock );
if( rc )
log_error("update_secret_keyblock failed\n" );
}
if( !rc )
tty_printf(_("public and secret subkey created.\n") );
okay = 1;
leave:
if( rc )
tty_printf(_("Key generation failed: %s\n"), g10_errstr(rc) );
log_error(_("Key generation failed: %s\n"), g10_errstr(rc) );
m_free( passphrase );
m_free( dek );
m_free( s2k );
if( sk ) /* release the copy of the (now unprotected) secret key */
free_secret_key(sk);
release_kbnode( sec_keyblock );
release_kbnode( pub_keyblock );
set_next_passphrase( NULL );
return okay;
}

View file

@ -296,6 +296,37 @@ datestr_from_sig( PKT_signature *sig )
}
const char *
expirestr_from_pk( PKT_public_key *pk )
{
static char buffer[11+5];
struct tm *tp;
time_t atime;
if( !pk->valid_days )
return "never ";
atime = add_days_to_timestamp( pk->timestamp, pk->valid_days );
tp = gmtime( &atime );
sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
return buffer;
}
const char *
expirestr_from_sk( PKT_secret_key *sk )
{
static char buffer[11+5];
struct tm *tp;
time_t atime;
if( !sk->valid_days )
return "never ";
atime = add_days_to_timestamp( sk->timestamp, sk->valid_days );
tp = gmtime( &atime );
sprintf(buffer,"%04d-%02d-%02d", 1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday );
return buffer;
}
/**************** .
* Return a byte array with the fingerprint for the given PK/SK
* The length of the array is returned in ret_len. Caller must free

View file

@ -202,6 +202,8 @@ list_one( const char *name, int secret )
any = 1;
}
keyid_from_pk( pk2, keyid2 );
if( opt.with_colons ) {
printf("sub:%c:%u:%d:%08lX%08lX:%s:%u:",
@ -224,6 +226,8 @@ list_one( const char *name, int secret )
pubkey_letter( pk2->pubkey_algo ),
(ulong)keyid2[1],
datestr_from_pk( pk2 ) );
if( opt.fingerprint > 1 )
fingerprint( pk2, NULL );
}
else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
u32 keyid2[2];
@ -251,6 +255,9 @@ list_one( const char *name, int secret )
pubkey_letter( sk2->pubkey_algo ),
(ulong)keyid2[1],
datestr_from_sk( sk2 ) );
if( opt.fingerprint > 1 )
fingerprint( NULL, sk2 );
}
else if( opt.list_sigs && node->pkt->pkttype == PKT_SIGNATURE ) {
PKT_signature *sig = node->pkt->pkt.signature;

View file

@ -72,14 +72,13 @@ int clearsign_file( const char *fname, STRLIST locusr, const char *outfile );
int check_key_signature( KBNODE root, KBNODE node, int *is_selfsig );
/*-- keyedit.c --*/
int sign_key( const char *username, STRLIST locusr );
int edit_keysigs( const char *username );
int delete_key( const char *username, int secure );
int change_passphrase( const char *username );
void keyedit_menu( const char *username, STRLIST locusr );
/*-- keygen.c --*/
void generate_keypair(void);
void generate_subkeypair(const char *userid);
int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock );
/*-- openfile.c --*/
int overwrite_filep( const char *fname );

View file

@ -520,6 +520,8 @@ list_node( CTX c, KBNODE node )
}
if( !any )
putchar('\n');
if( !mainkey && opt.fingerprint > 1 )
print_fingerprint( pk, NULL );
}
else if( (mainkey = (node->pkt->pkttype == PKT_SECRET_KEY) )
|| node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
@ -583,6 +585,8 @@ list_node( CTX c, KBNODE node )
}
if( !any )
putchar('\n');
if( !mainkey && opt.fingerprint > 1 )
print_fingerprint( NULL, sk );
}
else if( node->pkt->pkttype == PKT_SIGNATURE ) {
PKT_signature *sig = node->pkt->pkt.signature;

View file

@ -98,7 +98,7 @@ checksum_u16( unsigned n )
u16 a;
a = (n >> 8) & 0xff;
if( opt.emulate_bugs & 1 ) {
if( opt.emulate_bugs & EMUBUG_GPGCHKSUM ) {
a |= n & 0xff;
log_debug("csum_u16 emulated for n=%u\n", n);
}
@ -142,7 +142,7 @@ checksum_mpi( MPI a )
* this stored value if it is still available.
*/
if( opt.emulate_bugs & 1 )
if( opt.emulate_bugs & EMUBUG_GPGCHKSUM )
nbits = 0;
else
nbits = mpi_get_nbit_info(a);

View file

@ -50,10 +50,12 @@ struct {
int compress_sigs;
int always_trust;
int rfc1991;
unsigned emulate_bugs; /* bug emulation flags */
unsigned emulate_bugs; /* bug emulation flags EMUBUG_xxxx */
} opt;
#define EMUBUG_GPGCHKSUM 1
#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
#define DBG_MPI_VALUE 2 /* debug mpi details */
#define DBG_CIPHER_VALUE 4 /* debug cipher handling */

View file

@ -258,7 +258,9 @@ void free_comment( PKT_comment *rem );
void free_packet( PACKET *pkt );
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
PKT_secret_key *copy_secret_key( PKT_secret_key *d, PKT_secret_key *s );
int cmp_public_keys( PKT_public_key *a, PKT_public_key *b );
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
PKT_user_id *copy_user_id( PKT_user_id *d, PKT_user_id *s );
int cmp_public_keys( PKT_public_key *d, PKT_public_key *s );
int cmp_public_secret_key( PKT_public_key *pk, PKT_secret_key *sk );
int cmp_user_ids( PKT_user_id *a, PKT_user_id *b );
@ -298,4 +300,7 @@ int make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
int (*mksubpkt)(PKT_signature *, void *),
void *opaque );
/*-- keygen.c --*/
PKT_user_id *generate_user_id(void);
#endif /*G10_PACKET_H*/

View file

@ -349,7 +349,7 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, ulong *retpos,
}
leave:
if( rc == -1 && iobuf_error(inp) )
if( !rc && iobuf_error(inp) )
rc = G10ERR_INV_KEYRING;
return rc;
}
@ -434,7 +434,8 @@ skip_rest( IOBUF inp, unsigned long pktlen )
}
else {
for( ; pktlen; pktlen-- )
iobuf_get(inp);
if( iobuf_get(inp) == -1 )
break;
}
}
@ -1048,6 +1049,7 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
rc = G10ERR_INVALID_PACKET;
goto leave;
}
/* fixme: Add support for other blocksizes */
for(i=0; i < 8 && pktlen; i++, pktlen-- )
temp[i] = iobuf_get_noeof(inp);
if( list_mode ) {

View file

@ -53,6 +53,8 @@ do_check( PKT_secret_key *sk )
BUG();
if( check_cipher_algo( sk->protect.algo ) )
return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */
if( cipher_get_blocksize( sk->protect.algo ) != 8 )
return G10ERR_CIPHER_ALGO; /* unsupported protection algorithm */
keyid_from_sk( sk, keyid );
dek = passphrase_to_dek( keyid, sk->protect.algo,
&sk->protect.s2k, 0 );
@ -76,7 +78,7 @@ do_check( PKT_secret_key *sk )
csum += checksum_mpi( sk->skey[i] );
m_free( buffer );
}
if( opt.emulate_bugs & 1 ) {
if( opt.emulate_bugs & EMUBUG_GPGCHKSUM ) {
csum = sk->csum;
}
cipher_close( cipher_hd );
@ -180,6 +182,8 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
if( check_cipher_algo( sk->protect.algo ) )
rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
else if( cipher_get_blocksize( sk->protect.algo ) != 8 )
rc = G10ERR_CIPHER_ALGO; /* unsupport protection algorithm */
else {
cipher_hd = cipher_open( sk->protect.algo,
CIPHER_MODE_AUTO_CFB, 1 );

View file

@ -650,4 +650,112 @@ clearsign_file( const char *fname, STRLIST locusr, const char *outfile )
}
/****************
* Create a signature packet for the given public key certificate
* and the user id and return it in ret_sig. User signature class SIGCLASS
* user-id is not used (and may be NULL if sigclass is 0x20)
* If digest_algo is 0 the function selects an appropriate one.
*/
int
make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk,
PKT_user_id *uid, PKT_public_key *subpk,
PKT_secret_key *sk,
int sigclass, int digest_algo,
int (*mksubpkt)(PKT_signature *, void *), void *opaque
)
{
PKT_signature *sig;
int rc=0;
MD_HANDLE md;
assert( (sigclass >= 0x10 && sigclass <= 0x13)
|| sigclass == 0x20 || sigclass == 0x18 );
if( !digest_algo ) {
switch( sk->pubkey_algo ) {
case PUBKEY_ALGO_DSA: digest_algo = DIGEST_ALGO_SHA1; break;
case PUBKEY_ALGO_RSA_S:
case PUBKEY_ALGO_RSA: digest_algo = DIGEST_ALGO_MD5; break;
default: digest_algo = DIGEST_ALGO_RMD160; break;
}
}
md = md_open( digest_algo, 0 );
/* hash the public key certificate and the user id */
hash_public_key( md, pk );
if( sigclass == 0x18 ) { /* subkey binding */
hash_public_key( md, subpk );
}
else if( sigclass != 0x20 ) {
if( sk->version >=4 ) {
byte buf[5];
buf[0] = 0xb4; /* indicates a userid packet */
buf[1] = uid->len >> 24; /* always use 4 length bytes */
buf[2] = uid->len >> 16;
buf[3] = uid->len >> 8;
buf[4] = uid->len;
md_write( md, buf, 5 );
}
md_write( md, uid->name, uid->len );
}
/* and make the signature packet */
sig = m_alloc_clear( sizeof *sig );
sig->version = sk->version;
keyid_from_sk( sk, sig->keyid );
sig->pubkey_algo = sk->pubkey_algo;
sig->digest_algo = digest_algo;
sig->timestamp = make_timestamp();
sig->sig_class = sigclass;
if( sig->version >= 4 )
build_sig_subpkt_from_sig( sig );
if( sig->version >= 4 && mksubpkt )
rc = (*mksubpkt)( sig, opaque );
if( !rc ) {
if( sig->version >= 4 )
md_putc( md, sig->version );
md_putc( md, sig->sig_class );
if( sig->version < 4 ) {
u32 a = sig->timestamp;
md_putc( md, (a >> 24) & 0xff );
md_putc( md, (a >> 16) & 0xff );
md_putc( md, (a >> 8) & 0xff );
md_putc( md, a & 0xff );
}
else {
byte buf[6];
size_t n;
md_putc( md, sig->pubkey_algo );
md_putc( md, sig->digest_algo );
if( sig->hashed_data ) {
n = (sig->hashed_data[0] << 8) | sig->hashed_data[1];
md_write( md, sig->hashed_data, n+2 );
n += 6;
}
else
n = 6;
/* add some magic */
buf[0] = sig->version;
buf[1] = 0xff;
buf[2] = n >> 24; /* hmmm, n is only 16 bit, so this is always 0 */
buf[3] = n >> 16;
buf[4] = n >> 8;
buf[5] = n;
md_write( md, buf, 6 );
}
md_final(md);
rc = complete_sig( sig, sk, md );
}
md_close( md );
if( rc )
free_seckey_enc( sig );
else
*ret_sig = sig;
return rc;
}

View file

@ -45,46 +45,8 @@ static char *db_name;
static int db_fd = -1;
static void create_db( const char *fname );
static void open_db(void);
/**************************************************
************** read and write helpers ************
**************************************************/
static void
fwrite_8(FILE *fp, byte a)
{
if( putc( a & 0xff, fp ) == EOF )
log_fatal("error writing byte to trustdb: %s\n", strerror(errno) );
}
static void
fwrite_32( FILE*fp, ulong a)
{
putc( (a>>24) & 0xff, fp );
putc( (a>>16) & 0xff, fp );
putc( (a>> 8) & 0xff, fp );
if( putc( a & 0xff, fp ) == EOF )
log_fatal("error writing ulong to trustdb: %s\n", strerror(errno) );
}
static void
fwrite_zeros( FILE *fp, size_t n)
{
while( n-- )
if( putc( 0, fp ) == EOF )
log_fatal("error writing zeros to trustdb: %s\n", strerror(errno) );
}
/**************************************************
************** read and write stuff **************
**************************************************/
int
tdbio_set_dbname( const char *new_dbname, int create )
@ -101,7 +63,11 @@ tdbio_set_dbname( const char *new_dbname, int create )
return G10ERR_TRUSTDB;
}
if( create ) {
FILE *fp;
TRUSTREC rec;
int rc;
char *p = strrchr( fname, '/' );
assert(p);
*p = 0;
if( access( fname, F_OK ) ) {
@ -119,7 +85,30 @@ tdbio_set_dbname( const char *new_dbname, int create )
log_fatal_f(fname, _("directory does not exist!\n") );
}
*p = '/';
create_db( fname );
fp =fopen( fname, "w" );
if( !fp )
log_fatal_f( fname, _("can't create: %s\n"), strerror(errno) );
fclose(fp);
m_free(db_name);
db_name = fname;
db_fd = open( db_name, O_RDWR );
if( db_fd == -1 )
log_fatal_f( db_name, _("can't open: %s\n"), strerror(errno) );
memset( &rec, 0, sizeof rec );
rec.r.ver.version = 2;
rec.r.ver.created = make_timestamp();
rec.rectype = RECTYPE_VER;
rec.recnum = 0;
rc = tdbio_write_record( &rec );
if( rc )
log_fatal_f( fname, _("failed to create version record: %s"),
g10_errstr(rc));
/* and read again to check that we are okay */
if( tdbio_read_record( 0, &rec, RECTYPE_VER ) )
log_fatal_f( db_name, "invalid trust-db created\n" );
return 0;
}
}
m_free(db_name);
@ -136,37 +125,6 @@ tdbio_get_dbname()
/****************
* Create a new trustdb
*/
static void
create_db( const char *fname )
{
FILE *fp;
fp =fopen( fname, "w" );
if( !fp )
log_fatal_f( fname, _("can't create %s: %s\n"), strerror(errno) );
fwrite_8( fp, 1 ); /* record type */
fwrite_8( fp, 'g' );
fwrite_8( fp, 'p' );
fwrite_8( fp, 'g' );
fwrite_8( fp, 2 ); /* version */
fwrite_zeros( fp, 3 ); /* reserved */
fwrite_32( fp, 0 ); /* not locked */
fwrite_32( fp, make_timestamp() ); /* created */
fwrite_32( fp, 0 ); /* not yet modified */
fwrite_32( fp, 0 ); /* not yet validated*/
fwrite_32( fp, 0 ); /* reserved */
fwrite_8( fp, 3 ); /* marginals needed */
fwrite_8( fp, 1 ); /* completes needed */
fwrite_8( fp, 4 ); /* max_cet_depth */
fwrite_zeros( fp, 9 ); /* filler */
fclose(fp);
}
static void
open_db()
{
@ -182,10 +140,221 @@ open_db()
}
/****************
* Return the record number of the keyhash tbl or create a new one.
*/
static ulong
get_keyhashrec()
{
static ulong keyhashtbl; /* record number of the key hashtable */
TRUSTREC vr;
int rc;
if( keyhashtbl )
return keyhashtbl;
rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
if( rc )
log_fatal_f( db_name, _("error reading version record: %s\n"),
g10_errstr(rc) );
if( vr.r.ver.keyhashtbl )
keyhashtbl = vr.r.ver.keyhashtbl;
else {
TRUSTREC rec;
off_t offset;
ulong recnum;
int i, n;
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 */
keyhashtbl = recnum;
/* Now write the records */
n = (256+ITEMS_PER_HTBL_RECORD-1) / ITEMS_PER_HTBL_RECORD;
for(i=0; i < n; i++, recnum++ ) {
memset( &rec, 0, sizeof rec );
rec.rectype = RECTYPE_HTBL; /* free record */
rec.recnum = recnum;
rc = tdbio_write_record( &rec );
if( rc )
log_fatal_f(db_name,_("failed to create hashtable: %s\n"),
g10_errstr(rc));
}
/* update the version record */
vr.r.ver.keyhashtbl = keyhashtbl;
rc = tdbio_write_record( &vr );
if( rc )
log_fatal_f( db_name, _("error updating version record: %s\n"),
g10_errstr(rc));
}
return keyhashtbl;
}
/****************
* Update the key hashtbl or create the table if it does not exist
*/
static int
update_keyhashtbl( TRUSTREC *kr )
{
TRUSTREC lastrec, rec;
ulong hashrec, item;
int msb;
int level=0;
int rc, i;
hashrec = get_keyhashrec();
next_level:
msb = kr->r.key.fingerprint[level];
hashrec += msb / ITEMS_PER_HTBL_RECORD;
rc = tdbio_read_record( hashrec, &rec, RECTYPE_HTBL );
if( rc ) {
log_error( db_name, "update_keyhashtbl read failed: %s\n",
g10_errstr(rc) );
return rc;
}
item = rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
if( !item ) { /* insert new one */
rec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = kr->recnum;
rc = tdbio_write_record( &rec );
if( rc ) {
log_error( db_name, "update_keyhashtbl write htbl failed: %s\n",
g10_errstr(rc) );
return rc;
}
}
else if( item != kr->recnum ) { /* must do an update */
lastrec = rec;
rc = tdbio_read_record( item, &rec, 0 );
if( rc ) {
log_error( db_name, "update_keyhashtbl read item failed: %s\n",
g10_errstr(rc) );
return rc;
}
if( rec.rectype == RECTYPE_HTBL ) {
hashrec = item;
level++;
if( level >= kr->r.key.fingerprint_len ) {
log_error( db_name, "keyhashtbl has invalid indirections\n");
return G10ERR_TRUSTDB;
}
goto next_level;
}
else if( rec.rectype == RECTYPE_HLST ) { /* extend list */
/* see whether the key is already in this list */
for(;;) {
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
if( rec.r.hlst.rnum[i] == kr->recnum ) {
log_debug("HTBL: no update needed for keyrec %lu\n",
kr->recnum );
return 0;
}
}
if( rec.r.hlst.next ) {
rc = tdbio_read_record( rec.r.hlst.next,
&rec, RECTYPE_HLST);
if( rc ) {
log_error( db_name,
"scan keyhashtbl read hlst failed: %s\n",
g10_errstr(rc) );
return rc;
}
}
else
break; /* not there */
}
/* find the next free entry and put it in */
for(;;) {
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
if( !rec.r.hlst.rnum[i] ) {
rec.r.hlst.rnum[i] = kr->recnum;
rc = tdbio_write_record( &rec );
if( rc )
log_error( db_name,
"update_keyhashtbl write hlst failed: %s\n",
g10_errstr(rc) );
return rc; /* ready */
}
}
if( rec.r.hlst.next ) {
rc = tdbio_read_record( rec.r.hlst.next,
&rec, RECTYPE_HLST );
if( rc ) {
log_error( db_name,
"update_keyhashtbl read hlst failed: %s\n",
g10_errstr(rc) );
return rc;
}
}
else { /* add a new list record */
rec.r.hlst.next = item = tdbio_new_recnum();
rc = tdbio_write_record( &rec );
if( rc ) {
log_error( db_name,
"update_keyhashtbl write hlst failed: %s\n",
g10_errstr(rc) );
return rc;
}
memset( &rec, 0, sizeof rec );
rec.rectype = RECTYPE_HLST;
rec.recnum = item;
rec.r.hlst.rnum[0] = kr->recnum;
if( rc )
log_error( db_name,
"update_keyhashtbl write ext hlst failed: %s\n",
g10_errstr(rc) );
return rc; /* ready */
}
}
}
else if( rec.rectype == RECTYPE_KEY ) { /* insert a list record */
if( rec.recnum == kr->recnum ) {
log_debug("HTBL: no update needed for keyrec %lu\n",
kr->recnum );
return 0;
}
item = rec.recnum; /* save number of key record */
memset( &rec, 0, sizeof rec );
rec.rectype = RECTYPE_HLST;
rec.recnum = tdbio_new_recnum();
rec.r.hlst.rnum[0] = item; /* old keyrecord */
rec.r.hlst.rnum[1] = kr->recnum; /* and new one */
rc = tdbio_write_record( &rec );
if( rc ) {
log_error( db_name,
"update_keyhashtbl write new hlst failed: %s\n",
g10_errstr(rc) );
return rc;
}
/* update the hashtable record */
lastrec.r.htbl.item[msb % ITEMS_PER_HTBL_RECORD] = rec.recnum;
rc = tdbio_write_record( &lastrec );
if( rc )
log_error( db_name,
"update_keyhashtbl update htbl failed: %s\n",
g10_errstr(rc) );
return rc; /* ready */
}
else {
log_error( db_name, "keyhashtbl %lu points to an invalid record\n",
item);
return G10ERR_TRUSTDB;
}
}
return 0;
}
void
tdbio_dump_record( TRUSTREC *rec, FILE *fp )
{
int i, any;
int i;
ulong rnum = rec->recnum;
fprintf(fp, "rec %5lu, ", rnum );
@ -193,7 +362,8 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
switch( rec->rectype ) {
case 0: fprintf(fp, "free\n");
break;
case RECTYPE_VER: fprintf(fp, "version\n");
case RECTYPE_VER: fprintf(fp, "version, keyhashtbl=%lu\n",
rec->r.ver.keyhashtbl );
break;
case RECTYPE_DIR:
fprintf(fp, "dir %lu, keys=%lu, uids=%lu, cach=%lu, ot=%02x",
@ -213,11 +383,12 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
putc('\n', fp);
break;
case RECTYPE_KEY:
fprintf(fp, "key %lu, next=%lu, algo=%d, flen=%d",
fprintf(fp, "key %lu, next=%lu, algo=%d, ",
rec->r.key.lid,
rec->r.key.next,
rec->r.key.pubkey_algo,
rec->r.key.fingerprint_len );
rec->r.key.pubkey_algo );
for(i=0; i < rec->r.key.fingerprint_len; i++ )
fprintf(fp, "%02X", rec->r.key.fingerprint[i] );
if( rec->r.key.keyflags & KEYF_REVOKED )
fputs(", revoked", fp );
putc('\n', fp);
@ -239,29 +410,29 @@ tdbio_dump_record( TRUSTREC *rec, FILE *fp )
rec->r.uid.next);
break;
case RECTYPE_SIG:
fprintf(fp, "sig %lu, next=%lu\n",
fprintf(fp, "sig %lu, next=%lu,",
rec->r.sig.lid, rec->r.sig.next );
for(i=any=0; i < SIGS_PER_RECORD; i++ ) {
if( rec->r.sig.sig[i].lid ) {
if( !any ) {
putc('\t', fp);
any++;
}
fprintf(fp, " %lu:%02x", rec->r.sig.sig[i].lid,
for(i=0; i < SIGS_PER_RECORD; i++ ) {
if( rec->r.sig.sig[i].lid )
fprintf(fp, " %lu:%02x", rec->r.sig.sig[i].lid,
rec->r.sig.sig[i].flag );
}
}
if( any )
putc('\n', fp);
putc('\n', fp);
break;
case RECTYPE_CACH:
fprintf(fp, "cach\n");
break;
case RECTYPE_HTBL:
fprintf(fp, "htbl\n");
fprintf(fp, "htbl,");
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ )
fprintf(fp, " %lu", rec->r.htbl.item[i] );
putc('\n', fp);
break;
case RECTYPE_HLST:
fprintf(fp, "hlst\n");
fprintf(fp, "hlst, next=%lu,", rec->r.hlst.next );
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ )
fprintf(fp, " %lu", rec->r.hlst.rnum[i] );
putc('\n', fp);
break;
default:
fprintf(fp, "unknown type %d\n", rec->rectype );
@ -302,30 +473,29 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
recnum, expected, rec->rectype );
return G10ERR_TRUSTDB;
}
p++;
p++; /* skip reserved byte */
switch( rec->rectype ) {
case 0: /* unused record */
case 0: /* unused (free) record */
break;
case RECTYPE_VER: /* version record */
if( memcmp(buf+1, "gpg", 3 ) ) {
log_error_f( db_name, _("not a trustdb file\n") );
rc = G10ERR_TRUSTDB;
}
p += 2; /* skip magic */
p += 2; /* skip "pgp" */
rec->r.ver.version = *p++;
rec->r.ver.locked = buftoulong(p); p += 4;
p += 3; /* reserved bytes */
p += 4; /* lock flags */
rec->r.ver.created = buftoulong(p); p += 4;
rec->r.ver.modified = buftoulong(p); p += 4;
rec->r.ver.validated= buftoulong(p); p += 4;
rec->r.ver.marginals_needed = *p++;
rec->r.ver.completes_needed = *p++;
rec->r.ver.max_cert_depth = *p++;
rec->r.ver.keyhashtbl=buftoulong(p); p += 4;
if( recnum ) {
log_error_f( db_name, "version record with recnum %lu\n",
(ulong)recnum );
rc = G10ERR_TRUSTDB;
}
if( rec->r.ver.version != 2 ) {
else if( rec->r.ver.version != 2 ) {
log_error_f( db_name, "invalid file version %d\n",
rec->r.ver.version );
rc = G10ERR_TRUSTDB;
@ -381,6 +551,17 @@ tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected )
memcpy(rec->r.cache.blockhash, p, 20); p += 20;
rec->r.cache.trustlevel = *p++;
break;
case RECTYPE_HTBL:
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
rec->r.htbl.item[i] = buftoulong(p); p += 4;
}
break;
case RECTYPE_HLST:
rec->r.hlst.next = buftoulong(p); p += 4;
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
rec->r.hlst.rnum[i] = buftoulong(p); p += 4;
}
break;
default:
log_error_f( db_name, "invalid record type %d at recnum %lu\n",
rec->rectype, (ulong)recnum );
@ -412,8 +593,16 @@ tdbio_write_record( TRUSTREC *rec )
switch( rec->rectype ) {
case 0: /* unused record */
break;
case 1: /* version record */
BUG();
case RECTYPE_VER: /* version record */
if( recnum )
BUG();
memcpy(p-1, "gpg", 3 ); p += 2;
*p++ = rec->r.ver.version;
p += 7; /* skip reserved bytes and lock flags */
ulongtobuf(p, rec->r.ver.created); p += 4;
ulongtobuf(p, rec->r.ver.modified); p += 4;
ulongtobuf(p, rec->r.ver.validated); p += 4;
ulongtobuf(p, rec->r.ver.keyhashtbl); p += 4;
break;
case RECTYPE_DIR: /*directory record */
@ -466,6 +655,19 @@ tdbio_write_record( TRUSTREC *rec )
*p++ = rec->r.cache.trustlevel;
break;
case RECTYPE_HTBL:
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ ) {
ulongtobuf( p, rec->r.htbl.item[i]); p += 4;
}
break;
case RECTYPE_HLST:
ulongtobuf( p, rec->r.hlst.next); p += 4;
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
ulongtobuf( p, rec->r.hlst.rnum[i]); p += 4;
}
break;
default:
BUG();
}
@ -479,6 +681,8 @@ tdbio_write_record( TRUSTREC *rec )
log_error(_("trustdb: write failed (n=%d): %s\n"), n, strerror(errno) );
return G10ERR_WRITE_FILE;
}
else if( rec->rectype == RECTYPE_KEY )
rc = update_keyhashtbl( rec );
return rc;
}
@ -528,9 +732,6 @@ tdbio_new_recnum()
/****************
* Search the trustdb for a key which matches PK and return the dir record
* The local_id of PK is set to the correct value
*
* Note: To increase performance, we could use a index search here.
* tdbio_write_record shoudl create this index automagically
*/
int
tdbio_search_dir_record( PKT_public_key *pk, TRUSTREC *rec )
@ -540,32 +741,111 @@ tdbio_search_dir_record( PKT_public_key *pk, TRUSTREC *rec )
byte *fingerprint;
size_t fingerlen;
int rc;
ulong hashrec, item;
int msb;
int level=0;
keyid_from_pk( pk, keyid );
fingerprint = fingerprint_from_pk( pk, NULL, &fingerlen );
assert( fingerlen == 20 || fingerlen == 16 );
for(recnum=1; !(rc=tdbio_read_record( recnum, rec, 0)); recnum++ ) {
if( rec->rectype != RECTYPE_KEY )
continue;
if( rec->r.key.pubkey_algo == pk->pubkey_algo
&& !memcmp(rec->r.key.fingerprint, fingerprint, fingerlen) ) {
/* found: read the dir record for this key */
recnum = rec->r.key.lid;
rc = tdbio_read_record( recnum, rec, RECTYPE_DIR);
if( rc )
break;
if( pk->local_id && pk->local_id != recnum )
log_error_f(db_name,
"found record, but LID from memory does "
"not match recnum (%lu,%lu)\n",
pk->local_id, recnum );
pk->local_id = recnum;
return 0;
}
/* locate the key using the hash table */
hashrec = get_keyhashrec();
next_level:
msb = fingerprint[level];
hashrec += msb / ITEMS_PER_HTBL_RECORD;
rc = tdbio_read_record( hashrec, rec, RECTYPE_HTBL );
if( rc ) {
log_error( db_name, "scan keyhashtbl failed: %s\n", g10_errstr(rc) );
return rc;
}
if( rc != -1 )
log_error_f( db_name, _("search_db failed: %s\n"), g10_errstr(rc) );
item = rec->r.htbl.item[msb % ITEMS_PER_HTBL_RECORD];
if( !item )
return -1; /* not found */
rc = tdbio_read_record( item, rec, 0 );
if( rc ) {
log_error( db_name, "keyhashtbl read failed: %s\n", g10_errstr(rc) );
return rc;
}
if( rec->rectype == RECTYPE_HTBL ) {
hashrec = item;
level++;
if( level >= fingerlen ) {
log_error( db_name, "keyhashtbl has invalid indirections\n");
return G10ERR_TRUSTDB;
}
goto next_level;
}
else if( rec->rectype == RECTYPE_HLST ) {
for(;;) {
int i;
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ ) {
if( rec->r.hlst.rnum[i] ) {
TRUSTREC tmp;
rc = tdbio_read_record( rec->r.hlst.rnum[i],
&tmp, RECTYPE_KEY );
if( rc ) {
log_error( db_name,
"scan keyhashtbl read key failed: %s\n",
g10_errstr(rc) );
return rc;
}
if( tmp.r.key.pubkey_algo == pk->pubkey_algo
&& tmp.r.key.fingerprint_len == fingerlen
&& !memcmp(tmp.r.key.fingerprint,
fingerprint, fingerlen) ) {
*rec = tmp;
goto found;
}
}
}
if( rec->r.hlst.next ) {
rc = tdbio_read_record( rec->r.hlst.next, rec, RECTYPE_HLST );
if( rc ) {
log_error( db_name,
"scan keyhashtbl read hlst failed: %s\n",
g10_errstr(rc) );
return rc;
}
}
else
return -1; /* not found */
}
found:
;
}
else if( rec->rectype == RECTYPE_KEY ) {
/* must check that it is the requested key */
if( rec->r.key.pubkey_algo != pk->pubkey_algo
|| rec->r.key.fingerprint_len != fingerlen
|| memcmp(rec->r.key.fingerprint, fingerprint, fingerlen) )
return -1; /* no: not found */
}
else {
log_error( db_name, "keyhashtbl %lu points to an invalid record\n",
item);
return G10ERR_TRUSTDB;
}
recnum = rec->r.key.lid;
if( pk->local_id && pk->local_id != recnum )
log_error_f(db_name,
"found record, but LID from memory does "
"not match recnum (%lu,%lu)\n",
pk->local_id, recnum );
pk->local_id = recnum;
/* Now read the dir record */
rc = tdbio_read_record( recnum, rec, RECTYPE_DIR);
if( rc )
log_error_f(db_name, "can't read dirrec %lu: %s\n",
recnum, g10_errstr(rc) );
return rc;
}

View file

@ -60,15 +60,12 @@ struct trust_record {
int mark;
ulong recnum;
union {
struct { /* version record: */
byte version; /* should be 1 */
ulong locked; /* pid of process which holds a lock */
struct { /* version record: */
byte version; /* should be 2 */
ulong created; /* timestamp of trustdb creation */
ulong modified; /* timestamp of last modification */
ulong validated; /* timestamp of last validation */
byte marginals_needed;
byte completes_needed;
byte max_cert_depth;
ulong keyhashtbl;
} ver;
struct { /* directory record */
ulong lid;
@ -117,10 +114,7 @@ struct trust_record {
} htbl;
struct {
ulong next;
struct {
byte hash;
ulong rnum;
} item[ITEMS_PER_HLST_RECORD];
ulong rnum[ITEMS_PER_HLST_RECORD]; /* of a key record */
} hlst;
} r;
};

View file

@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
@ -102,6 +103,9 @@ static ulong last_trust_web_key;
static TRUST_SEG_LIST last_trust_web_tslist;
#define HEXTOBIN(a) ( (a) >= '0' && (a) <= '9' ? ((a)-'0') : \
(a) >= 'A' && (a) <= 'F' ? ((a)-'A'+10) : ((a)-'a'+10))
/**********************************************
************* list helpers *******************
**********************************************/
@ -945,6 +949,7 @@ update_sigs( TRUSTREC *dir )
}
else {
/* fixme: handle other sig classes here */
/* FIXME: Revocations!!! */
}
}
}
@ -1243,7 +1248,16 @@ list_trustdb( const char *username )
{
TRUSTREC rec;
if( username ) {
if( username && *username == '#' ) {
int rc;
ulong lid = atoi(username+1);
if( (rc = list_records( lid)) )
log_error("user '%s' read problem: %s\n", username, g10_errstr(rc));
else if( (rc = list_sigs( lid )) )
log_error("user '%s' list problem: %s\n", username, g10_errstr(rc));
}
else if( username ) {
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
int rc;
@ -1274,10 +1288,10 @@ list_trustdb( const char *username )
}
/****************
* make a list of all defined owner trust value.
* Print a list of all defined owner trust value.
*/
void
list_ownertrust()
export_ownertrust()
{
TRUSTREC rec;
TRUSTREC rec2;
@ -1307,6 +1321,67 @@ list_ownertrust()
}
}
void
import_ownertrust( const char *fname )
{
FILE *fp;
int is_stdin=0;
char line[256];
char *p;
size_t n, fprlen;
unsigned otrust;
if( !fname || (*fname == '-' && !fname[1]) ) {
fp = stdin;
fname = "[stdin]";
is_stdin = 1;
}
else if( !(fp = fopen( fname, "r" )) ) {
log_error_f(fname, _("can't open file: %s\n"), strerror(errno) );
return;
}
while( fgets( line, DIM(line)-1, fp ) ) {
if( !*line || *line == '#' )
continue;
n = strlen(line);
if( line[n-1] != '\n' ) {
log_error_f(fname, "line to long\n" );
break; /* can't continue */
}
for(p = line; *p && *p != ':' ; p++ )
if( !isxdigit(*p) )
break;
if( *p != ':' ) {
log_error_f(fname, "error: missing colon\n" );
continue;
}
fprlen = p - line;
if( fprlen != 32 && fprlen != 40 ) {
log_error_f(fname, "error: invalid fingerprint\n" );
continue;
}
if( sscanf(p, ":%u:", &otrust ) != 1 ) {
log_error_f(fname, "error: no otrust value\n" );
continue;
}
if( !otrust )
continue; /* no otrust defined - no need to update or insert */
/* convert the ascii fingerprint to binary */
for(p=line, fprlen=0; *p != ':'; p += 2 )
line[fprlen++] = HEXTOBIN(p[0]) * 16 + HEXTOBIN(p[1]);
line[fprlen] = 0;
log_hexdump("found: ", line, fprlen );
}
if( ferror(fp) )
log_error_f(fname, _("read error: %s\n"), strerror(errno) );
if( !is_stdin )
fclose(fp);
}
void
list_trust_path( int max_depth, const char *username )
{
@ -1405,7 +1480,17 @@ check_trustdb( const char *username )
TRUSTREC rec;
int rc;
if( username ) {
if( username && *username == '#' ) {
int rc;
ulong lid = atoi(username+1);
if( (rc = update_sigs_by_lid( lid )) )
log_error("lid %lu: check failed: %s\n",
lid, g10_errstr(rc));
else
log_info("lid %lu: checked: %s\n", lid, g10_errstr(rc));
}
else if( username ) {
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
if( (rc = get_pubkey_byname( pk, username )) )
@ -1724,7 +1809,7 @@ insert_trust_record( PKT_public_key *orig_pk )
BUG(); /* more than one primary key */
keyid_from_pk( pk, keyid );
}
fingerprint = fingerprint_from_pk( orig_pk, NULL, &fingerlen );
fingerprint = fingerprint_from_pk( pk, NULL, &fingerlen );
rec = m_alloc_clear( sizeof *rec );
rec->rectype = RECTYPE_KEY;
rec->r.key.pubkey_algo = pk->pubkey_algo;

View file

@ -38,7 +38,8 @@
/*-- trustdb.c --*/
void list_trustdb(const char *username);
void list_trust_path( int max_depth, const char *username );
void list_ownertrust(void);
void export_ownertrust(void);
void import_ownertrust(const char *fname);
void check_trustdb( const char *username );
int init_trustdb( int level, const char *dbname );
int check_trust( PKT_public_key *pk, unsigned *r_trustlevel );