See ChangeLog: Wed Mar 17 13:09:03 CET 1999 Werner Koch

This commit is contained in:
Werner Koch 1999-03-17 12:13:04 +00:00
parent dafcce0177
commit 8d255ff264
27 changed files with 863 additions and 286 deletions

2
NEWS
View File

@ -4,6 +4,8 @@
* A bunch of changes to the key validation code.
* --list-trust-path now has an optional --with-colons format.
Noteworthy changes in version 0.9.4
-----------------------------------

25
TODO
View File

@ -1,17 +1,14 @@
* Replace --trusted-keys by a local certificate (which does not get
exported).
* add some status output put for signing and encryption.
replace the puc in primegen with some kind of status-fd outputs.
replace the putc in primegen with some kind of status-fd outputs.
* Finish the EGD module.
* Implement 256 bit key Twofish (wait until the 2nd AES conference).
* Implement 256 bit key Twofish.
* Check revocation and expire stuff. [I'm currently working on this.]
* Check revocation and expire stuff.
* Check calculation of key validity. [I'm currently working on this.]
* Check calculation of key validity.
* See why we always get this "Hmmm public key lost"
@ -25,17 +22,11 @@
* when decryptiong multiple key: print a warning only if no usable pubkey
encrypt package was found. Extension: display a list of all recipients.
* an ERRSIG argument like
ERRSIG <keyid>, where <keyid> is the id of the missing public key
or a new keyword
PUBLIC_MISSING <keyid>
* a status line complaining about a missing secret key like
SECRET_MISSING <keyid>, where <keyid> is the id of the missing secret key
* a status line complaining about a bad passphrase like
BADPASS
* Add NO_PUBKEY and NO_SECKEY status lines.
* Add more NODATA status lines
* gpg --keyserver wwwkeys.us.pgp.net --importserver 0x12345678
(or --importserver warner@lothar.com, etc)
Nice to have

View File

@ -343,4 +343,256 @@ define(GNUPG_CHECK_MLOCK,
])
################################################################
# GNUPG_PROG_NM - find the path to a BSD-compatible name lister
AC_DEFUN(GNUPG_PROG_NM,
[AC_MSG_CHECKING([for BSD-compatible nm])
AC_CACHE_VAL(ac_cv_path_NM,
[if test -n "$NM"; then
# Let the user override the test.
ac_cv_path_NM="$NM"
else
IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
for ac_dir in /usr/ucb /usr/ccs/bin $PATH /bin; do
test -z "$ac_dir" && ac_dir=.
if test -f $ac_dir/nm; then
# Check to see if the nm accepts a BSD-compat flag.
# Adding the `sed 1q' prevents false positives on HP-UX, which says:
# nm: unknown option "B" ignored
if ($ac_dir/nm -B /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
ac_cv_path_NM="$ac_dir/nm -B"
elif ($ac_dir/nm -p /dev/null 2>&1 | sed '1q'; exit 0) | egrep /dev/null >/dev/null; then
ac_cv_path_NM="$ac_dir/nm -p"
else
ac_cv_path_NM="$ac_dir/nm"
fi
break
fi
done
IFS="$ac_save_ifs"
test -z "$ac_cv_path_NM" && ac_cv_path_NM=nm
fi])
NM="$ac_cv_path_NM"
AC_MSG_RESULT([$NM])
AC_SUBST(NM)
])
# GNUPG_SYS_NM_PARSE - Check for command ro grab the raw symbol name followed
# by C symbol name from nm.
AC_DEFUN(GNUPG_SYS_NM_PARSE,
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
AC_REQUIRE([GNUPG_PROG_NM])dnl
# Check for command to grab the raw symbol name followed by C symbol from nm.
AC_MSG_CHECKING([command to parse $NM output])
AC_CACHE_VAL(ac_cv_sys_global_symbol_pipe,
[# These are sane defaults that work on at least a few old systems.
# {They come from Ultrix. What could be older than Ultrix?!! ;)}
changequote(,)dnl
# Character class describing NM global symbol codes.
ac_symcode='[BCDEGRSTU]'
# Regexp to match symbols that can be accessed directly from C.
ac_sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
# Transform the above into a raw symbol and a C symbol.
ac_symxfrm='\1 \1'
# Define system-specific variables.
case "$host_os" in
aix*)
ac_symcode='[BCDTU]'
;;
sunos* | cygwin32* | mingw32*)
ac_sympat='_\([_A-Za-z][_A-Za-z0-9]*\)'
ac_symxfrm='_\1 \1'
;;
irix*)
# Cannot use undefined symbols on IRIX because inlined functions mess us up.
ac_symcode='[BCDEGRST]'
;;
solaris*)
ac_symcode='[BDTU]'
;;
esac
# If we're using GNU nm, then use its standard symbol codes.
if $NM -V 2>&1 | egrep '(GNU|with BFD)' > /dev/null; then
ac_symcode='[ABCDGISTUW]'
fi
case "$host_os" in
cygwin32* | mingw32*)
# We do not want undefined symbols on cygwin32. The user must
# arrange to define them via -l arguments.
ac_symcode='[ABCDGISTW]'
;;
esac
changequote([,])dnl
# Write the raw and C identifiers.
ac_cv_sys_global_symbol_pipe="sed -n -e 's/^.* $ac_symcode $ac_sympat$/$ac_symxfrm/p'"
# Check to see that the pipe works correctly.
ac_pipe_works=no
cat > conftest.$ac_ext <<EOF
#ifdef __cplusplus
extern "C" {
#endif
char nm_test_var;
void nm_test_func(){}
#ifdef __cplusplus
}
#endif
int main(){nm_test_var='a';nm_test_func;return 0;}
EOF
if AC_TRY_EVAL(ac_compile); then
# Now try to grab the symbols.
ac_nlist=conftest.nm
if AC_TRY_EVAL(NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then
# Try sorting and uniquifying the output.
if sort "$ac_nlist" | uniq > "$ac_nlist"T; then
mv -f "$ac_nlist"T "$ac_nlist"
ac_wcout=`wc "$ac_nlist" 2>/dev/null`
changequote(,)dnl
ac_count=`echo "X$ac_wcout" | sed -e 's,^X,,' -e 's/^[ ]*\([0-9][0-9]*\).*$/\1/'`
changequote([,])dnl
(test "$ac_count" -ge 0) 2>/dev/null || ac_count=-1
else
rm -f "$ac_nlist"T
ac_count=-1
fi
# Make sure that we snagged all the symbols we need.
if egrep ' nm_test_var$' "$ac_nlist" >/dev/null; then
if egrep ' nm_test_func$' "$ac_nlist" >/dev/null; then
cat <<EOF > conftest.c
#ifdef __cplusplus
extern "C" {
#endif
EOF
# Now generate the symbol file.
sed 's/^.* \(.*\)$/extern char \1;/' < "$ac_nlist" >> conftest.c
cat <<EOF >> conftest.c
#if defined (__STDC__) && __STDC__
# define __ptr_t void *
#else
# define __ptr_t char *
#endif
/* The number of symbols in dld_preloaded_symbols, -1 if unsorted. */
int dld_preloaded_symbol_count = $ac_count;
/* The mapping between symbol names and symbols. */
struct {
char *name;
__ptr_t address;
}
changequote(,)dnl
dld_preloaded_symbols[] =
changequote([,])dnl
{
EOF
sed 's/^\(.*\) \(.*\)$/ {"\1", (__ptr_t) \&\2},/' < "$ac_nlist" >> conftest.c
cat <<\EOF >> conftest.c
{0, (__ptr_t) 0}
};
#ifdef __cplusplus
}
#endif
EOF
# Now try linking the two files.
mv conftest.$ac_objext conftestm.$ac_objext
ac_save_LIBS="$LIBS"
ac_save_CFLAGS="$CFLAGS"
LIBS="conftestm.$ac_objext"
CFLAGS="$CFLAGS$no_builtin_flag"
if AC_TRY_EVAL(ac_link) && test -s conftest; then
ac_pipe_works=yes
else
echo "configure: failed program was:" >&AC_FD_CC
cat conftest.c >&AC_FD_CC
fi
LIBS="$ac_save_LIBS"
CFLAGS="$ac_save_CFLAGS"
else
echo "cannot find nm_test_func in $ac_nlist" >&AC_FD_CC
fi
else
echo "cannot find nm_test_var in $ac_nlist" >&AC_FD_CC
fi
else
echo "cannot run $ac_cv_sys_global_symbol_pipe" >&AC_FD_CC
fi
else
echo "$progname: failed program was:" >&AC_FD_CC
cat conftest.c >&AC_FD_CC
fi
rm -rf conftest*
# Do not use the global_symbol_pipe unless it works.
test "$ac_pipe_works" = yes || ac_cv_sys_global_symbol_pipe=
])
ac_result=yes
if test -z "$ac_cv_sys_global_symbol_pipe"; then
ac_result=no
fi
AC_MSG_RESULT($ac_result)
])
# GNUPG_SYS_LIBTOOL_CYGWIN32 - find tools needed on cygwin32
AC_DEFUN(GNUPG_SYS_LIBTOOL_CYGWIN32,
[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(AS, as, false)
])
# GNUPG_SYS_SYMBOL_UNDERSCORE - does the compiler prefix global symbols
# with an underscore?
AC_DEFUN(GNUPG_SYS_SYMBOL_UNDERSCORE,
[AC_REQUIRE([GNUPG_PROG_NM])dnl
AC_REQUIRE([GNUPG_SYS_NM_PARSE])dnl
AC_MSG_CHECKING([for _ prefix in compiled symbols])
AC_CACHE_VAL(ac_cv_sys_symbol_underscore,
[ac_cv_sys_symbol_underscore=no
cat > conftest.$ac_ext <<EOF
void nm_test_func(){}
int main(){nm_test_func;return 0;}
EOF
if AC_TRY_EVAL(ac_compile); then
# Now try to grab the symbols.
ac_nlist=conftest.nm
if AC_TRY_EVAL(NM conftest.$ac_objext \| $ac_cv_sys_global_symbol_pipe \> $ac_nlist) && test -s "$ac_nlist"; then
# See whether the symbols have a leading underscore.
if egrep '^_nm_test_func' "$ac_nlist" >/dev/null; then
ac_cv_sys_symbol_underscore=yes
else
if egrep '^nm_test_func ' "$ac_nlist" >/dev/null; then
:
else
echo "configure: cannot find nm_test_func in $ac_nlist" >&AC_FD_CC
fi
fi
else
echo "configure: cannot run $ac_cv_sys_global_symbol_pipe" >&AC_FD_CC
fi
else
echo "configure: failed program was:" >&AC_FD_CC
cat conftest.c >&AC_FD_CC
fi
rm -rf conftest*
])
AC_MSG_RESULT($ac_cv_sys_symbol_underscore)
if test x$ac_cv_sys_symbol_underscore = xyes; then
AC_DEFINE(WITH_SYMBOL_UNDERSCORE,1,
[define if compiled symbols have a leading underscore])
fi
])
dnl *-*wedit:notab*-* Please keep this as the last line.

View File

@ -1,3 +1,7 @@
Wed Mar 17 13:09:03 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* mds.test: replaced the "echo -n"
Mon Mar 8 20:47:17 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* pubdemo.asc, secdemo.asc: New.

View File

@ -13,7 +13,7 @@ fi
LANG=
LANGUAGE=
expect - <<EOF >/dev/null
expect - <<EOF >/dev/null
#set timeout -1
set timeout 8
match_max 100000
@ -89,10 +89,11 @@ Enter passphrase: " { sleep 1; send -- "abc\r" }
expect {
-ex "\r \rRepeat passphrase: " { sleep 1; send -- "abc\r" }
timeout { exit 1 } }
set timeout 600
expect {
-ex "\r \rWe need to generate a lot of random bytes. It is a good idea to perform\r
some other action (work in another window, move the mouse, utilize the\r
network and the disks) during the prime generation; this gives the random\r
the disks) during the prime generation; this gives the random\r
number generator a better chance to gain enough entropy.\r" {}
timeout { exit 1 } }
set timeout 600

View File

@ -13,7 +13,7 @@ test_one () {
failed=""
#info Checking message digests
echo -n "" | $srcdir/run-gpgm -v --print-mds >y
cat /dev/null | $srcdir/run-gpgm -v --print-mds >y
test_one "MD5" "D41D8CD98F00B204E9800998ECF8427E"
test_one "SHA1" "DA39A3EE5E6B4B0D3255BFEF95601890AFD80709"
test_one "RMD160" "9C1185A5C5E9FC54612808977EE8F548B2258D31"
@ -25,7 +25,7 @@ fi
[ "$failed" != "" ] && error "$failed failed for empty string"
echo -n "abcdefghijklmnopqrstuvwxyz" | $srcdir/run-gpgm --print-mds >y
/bin/echo "abcdefghijklmnopqrstuvwxyz\c" | $srcdir/run-gpgm --print-mds >y
test_one "MD5" "C3FCD3D76192E4007DFB496CCA67E13B"
test_one "SHA1" "32D10C7B8CF96570CA04CE37F2A19D84240D3A89"
test_one "RMD160" "F71C27109C692C1B56BBDCEB5B9D2865B3708DBC"

View File

@ -1,3 +1,8 @@
Wed Mar 17 13:09:03 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* rndegd.c (do_read): New.
(gather_random): Changed the implementation.
Mon Mar 8 20:47:17 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* dynload.c (DLSYM_NEEDS_UNDERSCORE): Renamed.

View File

@ -34,6 +34,7 @@
#include "util.h"
#include "ttyio.h"
#include "dynload.h"
#include "cipher.h"
#ifdef IS_MODULE
#define _(a) (a)
@ -64,18 +65,47 @@ do_write( int fd, void *buf, size_t nbytes )
return 0;
}
static int
do_read( int fd, void *buf, size_t nbytes )
{
int n, nread = 0;
do {
do {
n = read(fd, (char*)buf + nread, nbytes );
} while( n == -1 && errno == EINTR );
if( n == -1 )
return -1;
nread += n;
} while( nread < nbytes );
return nbytes;
}
/* fixme: level 1 is not yet handled */
static int
gather_random( void (*add)(const void*, size_t, int), int requester,
size_t length, int level )
{
static int fd = -1;
int n;
int warn=0;
byte buffer[256+2];
int nbytes;
int do_restart = 0;
if( !length )
return 0;
restart:
if( do_restart ) {
if( fd != -1 ) {
close( fd );
fd = -1;
}
}
if( fd == -1 ) {
const char *name = "/tmp/entropy";
char *name = make_filename( g10_opt_homedir, "entropy", NULL );
struct sockaddr_un addr;
int addr_len;
@ -92,73 +122,63 @@ gather_random( void (*add)(const void*, size_t, int), int requester,
if( connect( fd, (struct sockaddr*)&addr, addr_len) == -1 )
g10_log_fatal("can't connect to `%s': %s\n",
name, strerror(errno) );
m_free(name);
}
do_restart = 0;
nbytes = length < 255? length : 255;
/* first time we do it with a non blocking request */
buffer[0] = 1; /* non blocking */
buffer[1] = nbytes;
if( do_write( fd, buffer, 2 ) == -1 )
g10_log_fatal("can't write to the EGD: %s\n", strerror(errno) );
n = do_read( fd, buffer, 1 );
if( n == -1 ) {
g10_log_error("read error on EGD: %s\n", strerror(errno));
do_restart = 1;
goto restart;
}
if( !n ) {
g10_log_error("bad EGD reply: too short\n");
do_restart = 1;
goto restart;
}
if( n > 1 ) {
n--;
(*add)( buffer+1, n, requester );
length -= n;
}
if( length ) {
#ifdef IS_MODULE
fprintf( stderr,
#else
tty_printf(
#endif
_("Please wait, entropy is being gathered. Do some work if it would\n"
"keep you from getting bored, because it will improve the quality\n"
"of the entropy.\n") );
}
while( length ) {
fd_set rfds;
struct timeval tv;
int rc;
int nbytes;
int cmd;
nbytes = length < 255? length : 255;
/* send request */
cmd = level >= 2 ? 2 : 1;
buffer[0] = cmd;
buffer[0] = 2; /* blocking */
buffer[1] = nbytes;
if( do_write( fd, buffer, 2 ) == -1 )
g10_log_fatal("can't write to the EGD: %s\n", strerror(errno) );
/* wait on reply */
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
tv.tv_sec = 3;
tv.tv_usec = 0;
if( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) {
if( !warn )
#ifdef IS_MODULE
fprintf( stderr,
#else
tty_printf(
#endif
_(
"\n"
"Not enough random bytes available. Please do some other work to give\n"
"the OS a chance to collect more entropy! (Need %d more bytes)\n"), length );
warn = 1;
continue;
}
else if( rc == -1 ) {
g10_log_error("select error on EGD: %s\n", strerror(errno));
continue;
}
/* collect reply */
do {
n = read(fd, buffer, nbytes+2 );
} while( n == -1 && errno == EINTR );
/* process reply */
if( n == -1 )
n = do_read( fd, buffer, nbytes );
if( n == -1 ) {
g10_log_error("read error on EGD: %s\n", strerror(errno));
else if( cmd == 2 && n != nbytes ) {
do_restart = 1;
goto restart;
}
if( n != nbytes ) {
g10_log_error("bad EGD reply: too short %d/%d\n", nbytes, n );
do_restart = 1;
goto restart;
}
else if( cmd == 2 ) {
(*add)( buffer, n, requester );
length -= n;
}
else if( !n )
g10_log_error("bad EGD reply: too short\n");
else if( buffer[0] != n-1 )
g10_log_error("bad EGD reply: count mismatch %d/%d\n",
n-1, buffer[0] );
else if( n==1 )
g10_log_info("no data from EGD\n");
else {
n -= 1;
(*add)( buffer+1, n, requester );
length -= n;
}
(*add)( buffer, n, requester );
length -= n;
}
memset(buffer, 0, sizeof(buffer) );

View File

@ -28,11 +28,11 @@ dnl
dnl Check for random module options
dnl
dnl Fixme: get the list of available modules from MODULES_IN_CIPHER
dnl and check agiants this list
dnl and check against this list
AC_MSG_CHECKING([which static random module to use])
AC_ARG_ENABLE(static-rnd,
[ --enable-static-rnd=[egd|unix|linux|nonde] ],
[ --enable-static-rnd=[egd|unix|linux|none] ],
[use_static_rnd=$enableval], [use_static_rnd=default] )
if test "$use_static_rnd" = no; then
@ -169,7 +169,7 @@ case "${target}" in
esac
AC_SUBST(MPI_OPT_FLAGS)
AM_SYS_SYMBOL_UNDERSCORE
GNUPG_SYS_SYMBOL_UNDERSCORE
GNUPG_CHECK_PIC
GNUPG_CHECK_RDYNAMIC
if test "$NO_PIC" = yes; then

View File

@ -54,10 +54,9 @@ more arguments in future versions.
BADSIG <long keyid> <username>
The signature with the keyid has not been verified okay.
ERRSIG
ERRSIG <long keyid> <algorithm_number>
It was not possible to check the signature. This may be
caused by a missing public key or an unsupported algorithm.
No argument yet.
VALIDSIG <fingerprint in hex>
The signature with the keyid is good. This is the same
@ -72,6 +71,13 @@ more arguments in future versions.
unique ids - others may yield duplicated ones when they
have been created in the same second.
ENC_TO <long keyid>
The message is encrypted to this keyid.
NODATA <what>
No data has been found. Codes for what are:
1 - No armored data.
TRUST_UNDEFINED
TRUST_NEVER
TRUST_MARGINAL
@ -98,10 +104,16 @@ more arguments in future versions.
SHM_GET
SHM_GET_BOOL
SHM_GET_HIDDEN
NEED_PASSPHRASE
[Needs documentation]
NEED_PASSPHRASE <long keyid>
Issued whenever a passphrase is needed.
BAD_PASSPHRASE <long keyid>
The supplied passphrase was wrong
NO_PUBKEY <long keyid>
NO_SECKEY <long keyid>
The key is not available
Key generation
@ -282,31 +294,6 @@ Record type 8: (shadow directory record)
Record type 9: (cache record) NOT USED
--------------
Used to bind the trustDB to the concrete instance of keyblock in
a pubring. This is used to cache information.
1 byte value 9
1 byte reserved
1 u32 Local-Id.
8 bytes keyid of the primary key (needed?)
1 byte cache-is-valid the following stuff is only
valid if this is set.
1 byte reserved
20 bytes rmd160 hash value over the complete keyblock
This is used to detect any changes of the keyblock with all
CTBs and lengths headers. Calculation is easy if the keyblock
is obtained from a keyserver: simply create the hash from all
received data bytes.
1 byte number of untrusted signatures.
1 byte number of marginal trusted signatures.
1 byte number of fully trusted signatures.
(255 is stored for all values greater than 254)
1 byte Trustlevel (see trustdb.h)
Record Type 10 (hash table)
--------------
Due to the fact that we use fingerprints to lookup keys, we can

View File

@ -1,3 +1,31 @@
Wed Mar 17 13:09:03 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* trustdb.c (check_trust): add new arg add_fnc and changed all callers.
(do_check): Ditto.
(verify_key): Ditto.
(propagate_validity): Use the new add_fnc arg.
(print_user_id): Add the FILE arg.
(propagate_ownertrust): New.
* pkclist.c (add_ownertrust_cb): New and changed the add_ownertrust
logic.
* getkey.c (get_keyblock_bylid): New.
* trustdb.c (print_uid_from_keyblock): New.
(dump_tn_tree_with_colons): New.
(list_trust_path): Add colon print mode.
* trustdb.c (insert_trust_record): Always use the primary key.
* encode.c (encode_simple): Added text_mode filter (Rémi Guyomarch)
(encode_crypt): Ditto.
* mainproc.c (proc_pubkey_enc): Added status ENC_TO.
* armor.c (armor_filter): Added status NODATA.
* passphrase.c (passphrase_to_dek): Always print NEED_PASSPHRASE
* seckey_cert.c (check_secret_key): Added BAD_PASS status.
* g10.c (main): Set g10_opt_homedir.
Sun Mar 14 19:34:36 CET 1999 Werner Koch <wk@isil.d.shuttle.de>
* keygen.c (do_create): Changed wording of the note (Hugh Daniel)

View File

@ -989,8 +989,10 @@ armor_filter( void *opaque, int control,
iobuf_writestr(a, tail_strings[afx->what] );
iobuf_writestr(a, "-----\n");
}
else if( !afx->any_data && !afx->inp_bypass )
else if( !afx->any_data && !afx->inp_bypass ) {
log_error(_("no valid OpenPGP data found.\n"));
write_status_text( STATUS_NODATA, "1" );
}
if( afx->truncated )
log_info(_("invalid armor: line longer than %d characters\n"),
MAX_LINELEN );

View File

@ -76,11 +76,13 @@ encode_simple( const char *filename, int mode )
cipher_filter_context_t cfx;
armor_filter_context_t afx;
compress_filter_context_t zfx;
text_filter_context_t tfx;
int do_compress = opt.compress && !opt.rfc1991;
memset( &cfx, 0, sizeof cfx);
memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx);
memset( &tfx, 0, sizeof tfx);
init_packet(&pkt);
/* prepare iobufs */
@ -90,6 +92,9 @@ encode_simple( const char *filename, int mode )
return G10ERR_OPEN_FILE;
}
if( opt.textmode )
iobuf_push_filter( inp, text_filter, &tfx );
cfx.dek = NULL;
if( mode ) {
s2k = m_alloc_clear( sizeof *s2k );
@ -151,19 +156,19 @@ encode_simple( const char *filename, int mode )
pt->namelen = 0;
}
/* pgp5 has problems to decrypt symmetrically encrypted data from
* GnuPOG if the filelength is in the inner packet. It works
* GnuPG if the filelength is in the inner packet. It works
* when only partial length headers are use. Until we have
* tracked this problem down. We use this temporary fix
* (fixme: remove the && !mode )
*/
if( filename && !mode ) {
if( filename && !opt.textmode && !mode ) {
if( !(filesize = iobuf_get_filelength(inp)) )
log_info(_("%s: WARNING: empty file\n"), filename );
}
else
filesize = 0; /* stdin */
pt->timestamp = make_timestamp();
pt->mode = 'b';
pt->mode = opt.textmode? 't' : 'b';
pt->len = filesize;
pt->buf = inp;
pkt.pkttype = PKT_PLAINTEXT;
@ -206,12 +211,14 @@ encode_crypt( const char *filename, STRLIST remusr )
cipher_filter_context_t cfx;
armor_filter_context_t afx;
compress_filter_context_t zfx;
text_filter_context_t tfx;
PK_LIST pk_list;
int do_compress = opt.compress && !opt.rfc1991;
memset( &cfx, 0, sizeof cfx);
memset( &afx, 0, sizeof afx);
memset( &zfx, 0, sizeof zfx);
memset( &tfx, 0, sizeof tfx);
init_packet(&pkt);
if( (rc=build_pk_list( remusr, &pk_list, PUBKEY_USAGE_ENC)) )
@ -227,6 +234,9 @@ encode_crypt( const char *filename, STRLIST remusr )
else if( opt.verbose )
log_info(_("reading from `%s'\n"), filename? filename: "[stdin]");
if( opt.textmode )
iobuf_push_filter( inp, text_filter, &tfx );
if( (rc = open_outfile( filename, opt.armor? 1:0, &out )) )
goto leave;
@ -270,14 +280,14 @@ encode_crypt( const char *filename, STRLIST remusr )
pt = m_alloc( sizeof *pt - 1 );
pt->namelen = 0;
}
if( filename ) {
if( filename && !opt.textmode ) {
if( !(filesize = iobuf_get_filelength(inp)) )
log_info(_("%s: WARNING: empty file\n"), filename );
}
else
filesize = 0; /* stdin */
pt->timestamp = make_timestamp();
pt->mode = 'b';
pt->mode = opt.textmode ? 't' : 'b';
pt->len = filesize;
pt->new_ctb = !pt->len && !opt.rfc1991;
pt->buf = inp;

View File

@ -824,6 +824,7 @@ main( int argc, char **argv )
secmem_set_flags( secmem_get_flags() & ~2 ); /* resume warnings */
set_debug();
g10_opt_homedir = opt.homedir;
/* must do this after dropping setuid, because string_to...
* may try to load an module */

View File

@ -31,6 +31,7 @@
#include "keydb.h"
#include "options.h"
#include "main.h"
#include "trustdb.h"
#include "i18n.h"
#define MAX_UNK_CACHE_ENTRIES 1000 /* we use a linked list - so I guess
@ -832,6 +833,34 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
/****************
* Search for a key with the given lid and return the complete keyblock
*/
int
get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid )
{
int rc;
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
struct getkey_ctx_s ctx;
u32 kid[2];
if( keyid_from_lid( lid, kid ) )
kid[0] = kid[1] = 0;
memset( &ctx, 0, sizeof ctx );
ctx.not_allocated = 1;
ctx.nitems = 1;
ctx.items[0].mode = 12;
ctx.items[0].keyid[0] = kid[0];
ctx.items[0].keyid[1] = kid[1];
rc = lookup_pk( &ctx, pk, ret_keyblock );
get_pubkey_end( &ctx );
free_public_key( pk );
return rc;
}
/****************

View File

@ -144,6 +144,7 @@ int get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint,
size_t fprint_len );
int get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
size_t fprint_len );
int get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid );
int seckey_available( u32 *keyid );
int get_seckey_byname( PKT_secret_key *sk, const char *name, int unlock );
int get_seckey_bynames( GETKEY_CTX *rx, PKT_secret_key *sk,

View File

@ -182,6 +182,14 @@ proc_pubkey_enc( CTX c, PACKET *pkt )
* function to check it. */
if( opt.verbose )
log_info(_("public key is %08lX\n"), (ulong)enc->keyid[1] );
if( is_status_enabled() ) {
char buf[50];
sprintf(buf, "%08lX%08lX", (ulong)enc->keyid[0], (ulong)enc->keyid[1]);
write_status_text( STATUS_ENC_TO, buf );
}
if( is_ELGAMAL(enc->pubkey_algo)
|| enc->pubkey_algo == PUBKEY_ALGO_DSA
|| is_RSA(enc->pubkey_algo) ) {
@ -914,7 +922,11 @@ check_sig_and_print( CTX c, KBNODE node )
g10_exit(1);
}
else {
write_status( STATUS_ERRSIG );
char buf[50];
sprintf(buf, "%08lX%08lX %d",
(ulong)sig->keyid[0], (ulong)sig->keyid[1],
sig->pubkey_algo );
write_status_text( STATUS_ERRSIG, buf );
log_error(_("Can't check signature: %s\n"), g10_errstr(rc) );
}
return rc;

View File

@ -133,6 +133,16 @@ passphrase_to_dek( u32 *keyid, int cipher_algo, STRING2KEY *s2k, int mode )
:DEFAULT_DIGEST_ALGO;
}
if( keyid && !next_pw && is_status_enabled() ) {
char buf[50];
sprintf( buf, "%08lX%08lX", (ulong)keyid[0], (ulong)keyid[1] );
if( keyid[2] && keyid[3] && keyid[0] != keyid[2]
&& keyid[1] != keyid[3] )
sprintf( buf+strlen(buf), " %08lX%08lX",
(ulong)keyid[2], (ulong)keyid[3] );
write_status_text( STATUS_NEED_PASSPHRASE, buf );
}
if( keyid && !opt.batch && !next_pw ) {
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
size_t n;
@ -159,15 +169,6 @@ passphrase_to_dek( u32 *keyid, int cipher_algo, STRING2KEY *s2k, int mode )
tty_printf("\n");
free_public_key( pk );
}
else if( keyid && !next_pw ) {
char buf[50];
sprintf( buf, "%08lX%08lX", (ulong)keyid[0], (ulong)keyid[1] );
if( keyid[2] && keyid[3] && keyid[0] != keyid[2]
&& keyid[1] != keyid[3] )
sprintf( buf+strlen(buf), " %08lX%08lX",
(ulong)keyid[2], (ulong)keyid[3] );
write_status_text( STATUS_NEED_PASSPHRASE, buf );
}
if( next_pw ) {
pw = next_pw;

View File

@ -107,8 +107,8 @@ show_paths( ulong lid, int only_first )
/****************
* Returns true if an ownertrust has changed.
*/
int
edit_ownertrust( ulong lid, int mode )
static int
do_edit_ownertrust( ulong lid, int mode, unsigned *new_trust )
{
char *p;
int rc;
@ -117,6 +117,7 @@ edit_ownertrust( ulong lid, int mode )
PKT_public_key *pk ;
int changed=0;
int quit=0;
int show=0;
rc = keyid_from_lid( lid, keyid );
if( rc ) {
@ -177,14 +178,15 @@ edit_ownertrust( ulong lid, int mode )
case '4': trust = TRUST_FULLY ; break;
default: BUG();
}
if( !update_ownertrust( lid, trust ) )
changed++;
*new_trust = trust;
changed = 1;
break;
}
else if( *p == ans[0] || *p == ans[1] ) {
tty_printf(_(
"Certificates leading to an ultimately trusted key:\n"));
show_paths( lid, 1 );
show = 1;
break;
}
else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) ) {
break ; /* back to the menu */
@ -197,73 +199,71 @@ edit_ownertrust( ulong lid, int mode )
}
m_free(p);
m_free(pk);
return quit? -1 : changed;
return show? -2: quit? -1 : changed;
}
int
edit_ownertrust( ulong lid, int mode )
{
unsigned trust;
for(;;) {
switch( do_edit_ownertrust( lid, mode, &trust ) ) {
case -1:
return 0;
case -2:
show_paths( lid, 1 );
break;
case 1:
if( !update_ownertrust( lid, trust ) )
return 1;
return 0;
default:
return 0;
}
}
}
static int
add_ownertrust_cb( ulong lid )
{
unsigned trust;
int rc = do_edit_ownertrust( lid, 0, &trust );
if( rc == 1 )
return trust & TRUST_MASK;
return rc > 0? 0 : rc;
}
/****************
* Try to add some more owner trusts (interactive)
* This function presents all the signator in a certificate
* chain who have no trust value assigned.
* chain who have no ownertrust value assigned.
* Returns: -1 if no ownertrust were added.
*/
static int
add_ownertrust( PKT_public_key *pk, int *quit )
add_ownertrust( PKT_public_key *pk, int *quit, unsigned *trustlevel )
{
int rc;
void *context = NULL;
ulong lid;
unsigned otrust, validity;
int any=0, changed=0, any_undefined=0;
unsigned flags = 0;
*quit = 0;
*trustlevel = 0;
tty_printf(
_("Could not find a valid trust path to the key. Let's see whether we\n"
"can assign some missing owner trust values.\n\n"));
rc = query_trust_record( pk );
if( rc ) {
log_error("Ooops: not in trustdb\n");
return -1;
}
rc = check_trust( pk, trustlevel, NULL, add_ownertrust_cb, &flags );
lid = pk->local_id;
while( enum_cert_paths( &context, &lid, &otrust, &validity ) != -1 ) {
if( lid == pk->local_id )
continue;
any=1;
if( changed ) {
/* because enum_cert_paths() makes a snapshop of the
* trust paths, the otrust and validity are not anymore
* valid after changing an entry - we have to reread
* those values from then on
*/
otrust = get_ownertrust( lid );
/* fixme: and the validity? */
}
if( otrust == TRUST_UNDEFINED ) {
any_undefined=1;
enum_cert_paths_print( &context, NULL, changed, lid );
tty_printf("\n");
rc = edit_ownertrust( lid, 0 );
if( rc == -1 ) {
*quit = 1;
break;
}
else if( rc > 0 )
changed = 1;
}
}
enum_cert_paths( &context, NULL, NULL, NULL ); /* release context */
if( !any )
if( !(flags & 1) )
tty_printf(_("No path leading to one of our keys found.\n\n") );
else if( !any_undefined )
else if( !(flags & 2) )
tty_printf(_("No certificates with undefined trust found.\n\n") );
else if( !changed )
else if( !(flags & 4) )
tty_printf(_("No trust values changed.\n\n") );
return changed? 0:-1;
return (flags & 4)? 0:-1;
}
/****************
@ -274,7 +274,9 @@ static int
do_we_trust( PKT_public_key *pk, int trustlevel )
{
int rc;
int did_add = 0;
retry:
if( (trustlevel & TRUST_FLAG_REVOKED) ) {
log_info(_("key %08lX: key has been revoked!\n"),
(ulong)keyid_from_pk( pk, NULL) );
@ -295,7 +297,7 @@ do_we_trust( PKT_public_key *pk, int trustlevel )
g10_errstr(rc) );
return 0; /* no */
}
rc = check_trust( pk, &trustlevel, NULL );
rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
if( rc )
log_fatal("trust check after insert failed: %s\n",
g10_errstr(rc) );
@ -317,14 +319,10 @@ do_we_trust( PKT_public_key *pk, int trustlevel )
else {
int quit;
rc = add_ownertrust( pk, &quit );
if( !rc && !quit ) {
rc = check_trust( pk, &trustlevel, NULL );
if( rc )
log_fatal("trust check after add_ownertrust failed: %s\n",
g10_errstr(rc) );
/* fixme: this is recursive; we should unroll it */
return do_we_trust( pk, trustlevel );
rc = add_ownertrust( pk, &quit, &trustlevel );
if( !rc && !did_add && !quit ) {
did_add = 1;
goto retry;
}
}
return 0;
@ -353,10 +351,6 @@ do_we_trust( PKT_public_key *pk, int trustlevel )
default: BUG();
}
/* Eventuell fragen falls der trustlevel nicht ausreichend ist */
return 1; /* yes */
}
@ -419,7 +413,7 @@ check_signatures_trust( PKT_signature *sig )
{
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
int trustlevel;
int dont_try = 0;
int did_add = 0;
int rc=0;
rc = get_pubkey( pk, sig->keyid );
@ -429,13 +423,13 @@ check_signatures_trust( PKT_signature *sig )
goto leave;
}
retry:
rc = check_trust( pk, &trustlevel, NULL );
rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
if( rc ) {
log_error("check trust failed: %s\n", g10_errstr(rc));
goto leave;
}
retry:
if( (trustlevel & TRUST_FLAG_REVOKED) ) {
write_status( STATUS_KEYREVOKED );
log_info(_("WARNING: This key has been revoked by its owner!\n"));
@ -451,7 +445,7 @@ check_signatures_trust( PKT_signature *sig )
g10_errstr(rc) );
goto leave;
}
rc = check_trust( pk, &trustlevel, NULL );
rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
if( rc )
log_fatal("trust check after insert failed: %s\n",
g10_errstr(rc) );
@ -464,7 +458,7 @@ check_signatures_trust( PKT_signature *sig )
break;
case TRUST_UNDEFINED:
if( dont_try || opt.batch || opt.answer_no ) {
if( did_add || opt.batch || opt.answer_no ) {
write_status( STATUS_TRUST_UNDEFINED );
log_info(_(
"WARNING: This key is not certified with a trusted signature!\n"));
@ -474,9 +468,9 @@ check_signatures_trust( PKT_signature *sig )
}
else {
int quit;
rc = add_ownertrust( pk, &quit );
rc = add_ownertrust( pk, &quit, &trustlevel );
if( rc || quit ) {
dont_try = 1;
did_add = 1;
rc = 0;
}
goto retry;
@ -591,7 +585,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) {
int trustlevel;
rc = check_trust( pk, &trustlevel, NULL );
rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
if( rc ) {
log_error("error checking pk of `%s': %s\n",
answer, g10_errstr(rc) );
@ -630,7 +624,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) {
int trustlevel;
rc = check_trust( pk, &trustlevel, NULL );
rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
if( rc ) {
free_public_key( pk ); pk = NULL;
log_error(_("%s: error checking key: %s\n"),

View File

@ -32,6 +32,7 @@
#include "main.h"
#include "options.h"
#include "i18n.h"
#include "status.h"
static int
@ -175,6 +176,14 @@ check_secret_key( PKT_secret_key *sk, int n )
if( i )
log_info(_("Invalid passphrase; please try again ...\n"));
rc = do_check( sk );
if( rc == G10ERR_BAD_PASS && is_status_enabled() ) {
u32 kid[2];
char buf[50];
keyid_from_sk( sk, kid );
sprintf(buf, "%08lX%08lX", (ulong)kid[0], (ulong)kid[1]);
write_status_text( STATUS_BAD_PASSPHRASE, buf );
}
if( have_static_passphrase() )
break;
}

View File

@ -99,6 +99,11 @@ write_status_text ( int no, const char *text)
case STATUS_NEED_PASSPHRASE: s = "NEED_PASSPHRASE\n"; break;
case STATUS_VALIDSIG : s = "VALIDSIG\n"; break;
case STATUS_SIG_ID : s = "SIG_ID\n"; break;
case STATUS_ENC_TO : s = "ENC_TO\n"; break;
case STATUS_NODATA : s = "NODATA\n"; break;
case STATUS_BAD_PASSPHRASE : s = "BAD_PASSPHRASE\n"; break;
case STATUS_NO_PUBKEY : s = "NO_PUBKEY\n"; break;
case STATUS_NO_SECKEY : s = "NO_SECKEY\n"; break;
default: s = "?\n"; break;
}

View File

@ -50,6 +50,11 @@
#define STATUS_NEED_PASSPHRASE 20
#define STATUS_VALIDSIG 21
#define STATUS_SIG_ID 22
#define STATUS_ENC_TO 23
#define STATUS_NODATA 24
#define STATUS_BAD_PASSPHRASE 25
#define STATUS_NO_PUBKEY 26
#define STATUS_NO_SECKEY 27
/*-- status.c --*/
void set_status_fd ( int fd );

View File

@ -633,12 +633,15 @@ tdbio_read_modify_stamp( int modify_down )
}
void
tdbio_write_modify_stamp( int down, int up )
tdbio_write_modify_stamp( int up, int down )
{
TRUSTREC vr;
int rc;
ulong stamp;
if( !(up || down) )
return;
rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
if( rc )
log_fatal( _("%s: error reading version record: %s\n"),
@ -651,7 +654,7 @@ tdbio_write_modify_stamp( int down, int up )
vr.r.ver.mod_up = stamp;
rc = tdbio_write_record( &vr );
if( !rc )
if( rc )
log_fatal( _("%s: error writing version record: %s\n"),
db_name, g10_errstr(rc) );
}

View File

@ -176,7 +176,7 @@ int tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected );
int tdbio_write_record( TRUSTREC *rec );
int tdbio_db_matches_options(void);
ulong tdbio_read_modify_stamp( int modify_down );
void tdbio_write_modify_stamp( int down, int up );
void tdbio_write_modify_stamp( int up, int down );
int tdbio_is_dirty(void);
int tdbio_sync(void);
int tdbio_begin_transaction(void);

View File

@ -41,6 +41,7 @@
#include "main.h"
#include "i18n.h"
#include "tdbio.h"
#include "ttyio.h"
#if MAX_FINGERPRINT_LEN > 20
#error Must change structure of trustdb
@ -115,16 +116,20 @@ static int ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag );
static int qry_lid_table_flag( LOCAL_ID_TABLE tbl, ulong lid, unsigned *flag );
static void propagate_validity( TN node );
static int propagate_validity( TN root, TN node,
int (*add_fnc)(ulong), unsigned *retflgs );
static void print_user_id( const char *text, u32 *keyid );
static int do_check( TRUSTREC *drec, unsigned *trustlevel, const char *nhash);
static void print_user_id( FILE *fp, const char *text, u32 *keyid );
static int do_check( TRUSTREC *drec, unsigned *trustlevel,
const char *nhash, int (*add_fnc)(ulong),
unsigned *retflgs);
static int get_dir_record( PKT_public_key *pk, TRUSTREC *rec );
static void upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig );
static void upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
TRUSTREC *drec, RECNO_LIST *recno_list, int recheck,
TRUSTREC *urec, const byte *uidhash, int revoked );
TRUSTREC *urec, const byte *uidhash, int revoked,
int *mod_up, int *mod_down );
/* a table used to keep track of ultimately trusted keys
* which are the ones from our secrings and the trusted keys */
@ -375,6 +380,7 @@ keyid_from_lid( ulong lid, u32 *keyid )
int rc;
init_trustdb();
keyid[0] = keyid[1] = 0;
rc = tdbio_read_record( lid, &rec, 0 );
if( rc ) {
log_error(_("error reading dir record for LID %lu: %s\n"),
@ -622,20 +628,23 @@ init_trustdb()
************* Print helpers ****************
***********************************************/
static void
print_user_id( const char *text, u32 *keyid )
print_user_id( FILE *fp, const char *text, u32 *keyid )
{
char *p;
size_t n;
p = get_user_id( keyid, &n );
if( *text ) {
fputs( text, stdout);
putchar(' ');
if( fp ) {
fprintf( fp, "%s \"", text );
print_string( fp, p, n, 0 );
putc('\"', fp);
putc('\n', fp);
}
else {
tty_printf( "%s \"", text );
tty_print_string( p, n );
tty_printf( "\"\n" );
}
putchar('\"');
print_string( stdout, p, n, 0 );
putchar('\"');
putchar('\n');
m_free(p);
}
@ -699,35 +708,122 @@ print_path( int pathlen, TN ME .........., FILE *fp, ulong highlight )
static void
print_default_uid( ulong lid )
print_default_uid( FILE *fp, ulong lid )
{
u32 keyid[2];
if( !keyid_from_lid( lid, keyid ) )
print_user_id( "", keyid );
print_user_id( fp, "", keyid );
}
static void
dump_tn_tree( int indent, TN tree )
print_uid_from_keyblock( FILE *fp, KBNODE keyblock, ulong urecno )
{
TRUSTREC urec;
KBNODE node;
byte uhash[20];
read_record( urecno, &urec, RECTYPE_UID );
for( node=keyblock; node; node = node->next ) {
if( node->pkt->pkttype == PKT_USER_ID ) {
PKT_user_id *uidpkt = node->pkt->pkt.user_id;
rmd160_hash_buffer( uhash, uidpkt->name, uidpkt->len );
if( !memcmp( uhash, urec.r.uid.namehash, 20 ) ) {
print_string( fp, uidpkt->name, uidpkt->len, ':' );
return;
}
}
}
fputs("[?]", fp );
}
static void
dump_tn_tree( FILE *fp, int level, TN tree )
{
TN kr, ur;
for( kr=tree; kr; kr = kr->next ) {
printf("%*s", indent*4, "" );
printf("K%lu(ot=%d,val=%d) ", kr->lid,
kr->n.k.ownertrust,
kr->n.k.validity );
print_default_uid( kr->lid );
for( ur=kr->list; ur; ur = ur->next ) {
printf("%*s ", indent*4, "" );
printf("U%lu(mc=%d,fc=%d,val=%d)\n", ur->lid,
ur->n.u.marginal_count,
ur->n.u.fully_count,
ur->n.u.validity
);
dump_tn_tree( indent+1, ur->list );
if( fp ) {
fprintf( fp, "%*s", level*4, "" );
fprintf( fp, "K%lu(ot=%d,val=%d) ", kr->lid,
kr->n.k.ownertrust,
kr->n.k.validity );
}
else {
tty_printf("%*s", level*4, "" );
tty_printf("K%lu(ot=%d,val=%d) ", kr->lid,
kr->n.k.ownertrust,
kr->n.k.validity );
}
print_default_uid( fp, kr->lid );
for( ur=kr->list; ur; ur = ur->next ) {
if( fp ) {
fprintf(fp, "%*s ", level*4, "" );
fprintf(fp, "U%lu(mc=%d,fc=%d,val=%d)\n", ur->lid,
ur->n.u.marginal_count,
ur->n.u.fully_count,
ur->n.u.validity
);
}
else {
tty_printf("%*s ", level*4, "" );
tty_printf("U%lu(mc=%d,fc=%d,val=%d)\n", ur->lid,
ur->n.u.marginal_count,
ur->n.u.fully_count,
ur->n.u.validity
);
}
dump_tn_tree( fp, level+1, ur->list );
}
}
}
/****************
* Special version of dump_tn_tree, which prints it colon delimited.
* Format:
* level:keyid:type:recno:ot:val:mc:cc:name:
* With TYPE = U for a user ID
* K for a key
* The RECNO is either the one of the dir record or the one of the uid record.
* OT is the the usual trust letter and only availabel on K lines.
* VAL is the calcualted validity
* MC is the marginal trust counter and only available on U lines
* CC is the same for the complete count
* NAME ist the username and only printed on U lines
*/
static void
dump_tn_tree_with_colons( int level, TN tree )
{
TN kr, ur;
for( kr=tree; kr; kr = kr->next ) {
KBNODE kb = NULL;
u32 kid[2];
keyid_from_lid( kr->lid, kid );
get_keyblock_bylid( &kb, kr->lid );
printf( "%d:%08lX%08lX:K:%lu:%c:%c::::\n",
level, (ulong)kid[0], (ulong)kid[1], kr->lid,
trust_letter( kr->n.k.ownertrust ),
trust_letter( kr->n.k.validity ) );
for( ur=kr->list; ur; ur = ur->next ) {
printf( "%d:%08lX%08lX:U:%lu::%c:%d:%d:",
level, (ulong)kid[0], (ulong)kid[1], ur->lid,
trust_letter( kr->n.u.validity ),
ur->n.u.marginal_count,
ur->n.u.fully_count );
print_uid_from_keyblock( stdout, kb, ur->lid );
putchar(':');
putchar('\n');
dump_tn_tree_with_colons( level+1, ur->list );
}
release_kbnode( kb );
}
}
@ -851,6 +947,7 @@ check_hint_sig( ulong lid, KBNODE keyblock, u32 *keyid, byte *uidrec_hash,
* Process a hintlist.
* Fixme: this list is not anymore anchored to another
* record, so it should be put elsewehere in case of an error
* FIXME: add mod_up/down handling
*/
static void
process_hintlist( ulong hintlist, ulong hint_owner )
@ -1184,7 +1281,8 @@ upd_key_record( KBNODE keyblock, KBNODE keynode, u32 *keyid,
*/
static void
upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
TRUSTREC *drec, RECNO_LIST *recno_list, int recheck )
TRUSTREC *drec, RECNO_LIST *recno_list,
int recheck, int *mod_up, int *mod_down )
{
ulong lid = drec->recnum;
PKT_user_id *uid = uidnode->pkt->pkt.user_id;
@ -1327,10 +1425,10 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
write_record( &urec );
if( !( urec.r.uid.uidflags & UIDF_VALID )
|| ( urec.r.uid.uidflags & UIDF_REVOKED ) )
; /*FIXME: mark as modified down */
*mod_down=1;
else
; /*FIXME: mark as modified up (maybe a new uuser id)*/
*mod_up=1; /*(maybe a new user id)*/
/* Hmmm, did we catch changed expiration dates? */
}
} /* end check self-signatures */
@ -1362,11 +1460,11 @@ upd_uid_record( KBNODE keyblock, KBNODE uidnode, u32 *keyid,
if( (sig->sig_class&~3) == 0x10 ) { /* regular certification */
upd_cert_record( keyblock, node, keyid, drec, recno_list,
recheck, &urec, uidhash, 0 );
recheck, &urec, uidhash, 0, mod_up, mod_down );
}
else if( sig->sig_class == 0x30 ) { /* cert revocation */
upd_cert_record( keyblock, node, keyid, drec, recno_list,
recheck, &urec, uidhash, 1 );
recheck, &urec, uidhash, 1, mod_up, mod_down );
}
} /* end check certificates */
@ -1490,11 +1588,11 @@ upd_pref_record( TRUSTREC *urec, u32 *keyid, PKT_signature *sig )
}
/* FIXME: add logic to set the modify_{down,up} */
static void
upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
TRUSTREC *drec, RECNO_LIST *recno_list, int recheck,
TRUSTREC *urec, const byte *uidhash, int revoked )
TRUSTREC *urec, const byte *uidhash, int revoked,
int *mod_up, int *mod_down )
{
/* We simply insert the signature into the sig records but
* avoid duplicate ones. We do not check them here because
@ -1577,8 +1675,12 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
revoked? _("Valid certificate revocation")
: _("Good certificate") );
rec.r.sig.sig[i].flag = SIGF_CHECKED | SIGF_VALID;
if( revoked ) /* we are investigating revocations */
if( revoked ) { /* we are investigating revocations */
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
*mod_down = 1;
}
else
*mod_up = 1;
}
else if( rc == G10ERR_NO_PUBKEY ) {
/* This may happen if the key is still in the trustdb
@ -1589,6 +1691,7 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
uidhash[19], (ulong)sig->keyid[1],
_("public key not anymore available") );
rec.r.sig.sig[i].flag = SIGF_NOPUBKEY;
*mod_down = 1;
if( revoked )
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
}
@ -1600,8 +1703,10 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
: _("Invalid certificate"),
g10_errstr(rc));
rec.r.sig.sig[i].flag = SIGF_CHECKED;
if( revoked )
if( revoked ) {
rec.r.sig.sig[i].flag |= SIGF_REVOKED;
*mod_down = 1;
}
}
rec.dirty = 1;
}
@ -1662,8 +1767,12 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
: _("Good certificate") );
newlid = pk_lid; /* this is the pk of the signature */
newflag = SIGF_CHECKED | SIGF_VALID;
if( revoked )
if( revoked ) {
newflag |= SIGF_REVOKED;
*mod_down = 1;
}
else
*mod_up = 1;
}
else if( rc == G10ERR_NO_PUBKEY ) {
if( opt.verbose > 1 || DBG_TRUST )
@ -1686,6 +1795,7 @@ upd_cert_record( KBNODE keyblock, KBNODE signode, u32 *keyid,
newflag = SIGF_CHECKED;
if( revoked )
newflag |= SIGF_REVOKED;
*mod_down = 1;
}
if( delrec.recnum ) { /* we can reuse an unused slot */
@ -1730,6 +1840,8 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
int rc = 0;
u32 keyid[2]; /* keyid of primary key */
ulong recno, lastrecno;
int mod_up = 0;
int mod_down = 0;
RECNO_LIST recno_list = NULL; /* list of verified records */
/* fixme: replace recno_list by a lookup on node->recno */
@ -1767,7 +1879,7 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
for( node=keyblock; node; node = node->next ) {
if( node->pkt->pkttype == PKT_USER_ID )
upd_uid_record( keyblock, node, keyid,
&drec, &recno_list, recheck );
&drec, &recno_list, recheck, &mod_up, &mod_down );
}
/* delete keyrecords from the trustdb which are not anymore used */
@ -1842,6 +1954,7 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
drec.r.dir.dirflags |= DIRF_CHECKED;
drec.r.dir.valcheck = 0;
write_record( &drec );
tdbio_write_modify_stamp( mod_up, mod_down );
rc = tdbio_end_transaction();
}
rel_recno_list( &recno_list );
@ -1854,7 +1967,7 @@ update_trust_record( KBNODE keyblock, int recheck, int *modified )
* This function assumes that the record does not yet exist.
*/
int
insert_trust_record( PKT_public_key *pk )
insert_trust_record( PKT_public_key *orig_pk )
{
TRUSTREC dirrec;
TRUSTREC shadow;
@ -1864,6 +1977,7 @@ insert_trust_record( PKT_public_key *pk )
size_t fingerlen;
int rc = 0;
ulong hintlist = 0;
PKT_public_key *pk;
if( opt.dry_run )
@ -1871,7 +1985,7 @@ insert_trust_record( PKT_public_key *pk )
init_trustdb();
fingerprint_from_pk( pk, fingerprint, &fingerlen );
fingerprint_from_pk( orig_pk, fingerprint, &fingerlen );
/* fixme: assert that we do not have this record.
* we can do this by searching for the primary keyid
@ -1883,6 +1997,10 @@ insert_trust_record( PKT_public_key *pk )
* to the primary one which has the user ids etc.)
*/
if( orig_pk->local_id )
log_debug("insert_trust_record with pk->local_id=%lu (1)\n",
orig_pk->local_id );
/* get the keyblock which has the key */
rc = get_keyblock_byfprint( &keyblock, fingerprint, fingerlen );
if( rc ) { /* that should never happen */
@ -1891,32 +2009,18 @@ insert_trust_record( PKT_public_key *pk )
goto leave;
}
/* make sure that we use the primary key */
pk = find_kbnode( keyblock, PKT_PUBLIC_KEY )->pkt->pkt.public_key;
if( pk->local_id ) {
log_debug("insert_trust_reord with pk->local_id=%lu\n", pk->local_id );
orig_pk->local_id = pk->local_id;
log_debug("insert_trust_record with pk->local_id=%lu (2)\n",
pk->local_id );
rc = update_trust_record( keyblock, 1, NULL );
release_kbnode( keyblock );
return rc;
}
/* check that we used the primary key (we are little bit paranoid) */
{ PKT_public_key *a_pk;
u32 akid[2], bkid[2];
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
a_pk = node->pkt->pkt.public_key;
/* we can't use cmp_public_keys here because some parts (expiredate)
* might not be set in pk <--- but why (fixme) */
keyid_from_pk( a_pk, akid );
keyid_from_pk( pk, bkid );
if( akid[0] != bkid[0] || akid[1] != bkid[1] ) {
log_error(_("did not use primary key for insert_trust_record()\n"));
rc = G10ERR_GENERAL;
goto leave;
}
}
/* We have to look for a shadow dir record which must be reused
* as the dir record. And: check all signatures which are listed
* in the hintlist of the shadow dir record.
@ -1942,6 +2046,7 @@ insert_trust_record( PKT_public_key *pk )
/* out the LID into the keyblock */
pk->local_id = dirrec.r.dir.lid;
orig_pk->local_id = dirrec.r.dir.lid;
for( node=keyblock; node; node = node->next ) {
if( node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
@ -1954,7 +2059,8 @@ insert_trust_record( PKT_public_key *pk )
}
}
/* FIXME: mark tdb as modified upwards */
/* mark tdb as modified upwards */
tdbio_write_modify_stamp( 1, 0 );
/* and put all the other stuff into the keydb */
rc = update_trust_record( keyblock, 1, NULL );
@ -2100,9 +2206,57 @@ build_cert_tree( ulong lid, int depth, int max_depth, TN helproot )
}
static void
propagate_validity( TN node )
upd_one_ownertrust( ulong lid, unsigned new_trust, unsigned *retflgs )
{
TRUSTREC rec;
read_record( lid, &rec, RECTYPE_DIR );
if( DBG_TRUST )
log_debug("upd_one_ownertrust of %lu from %u to %u\n",
lid, (unsigned)rec.r.dir.ownertrust, new_trust );
if( retflgs ) {
if( new_trust > rec.r.dir.ownertrust )
*retflgs |= 16; /* modified up */
else
*retflgs |= 32; /* modified down */
}
rec.r.dir.ownertrust = new_trust;
write_record( &rec );
}
/****************
* Update the ownertrust in the complete tree.
*/
static void
propagate_ownertrust( TN kr, ulong lid, unsigned trust )
{
TN ur;
for( ; kr; kr = kr->next ) {
if( kr->lid == lid )
kr->n.k.ownertrust = trust;
for( ur=kr->list; ur; ur = ur->next )
propagate_ownertrust( ur->list, lid, trust );
}
}
/****************
* Calculate the validity of all keys in the tree and especially
* the one of the top key. If add_fnc is not NULL, it is used to
* ask for missing ownertrust values (but only if this will help
* us to increase the validity.
* add_fnc is expected to take the LID of the key under question
* and return a ownertrust value or an error: positive values
* are assumed to be the new ownertrust value; a 0 does mean no change,
* a -1 is a request to cancel this validation procedure, a -2 requests
* a listing of the sub-tree using the tty functions.
*
*
* Returns: 0 = okay
*/
static int
propagate_validity( TN root, TN node, int (*add_fnc)(ulong), unsigned *retflgs )
{
TN kr, ur;
int max_validity = 0;
@ -2112,7 +2266,9 @@ propagate_validity( TN node )
/* this is one of our keys */
assert( !node->list ); /* it should be a leaf */
node->n.k.validity = TRUST_ULTIMATE;
return;
if( retflgs )
*retflgs |= 1; /* found a path to an ultimately trusted key */
return 0;
}
/* loop over all user ids */
@ -2120,11 +2276,39 @@ propagate_validity( TN node )
assert( ur->is_uid );
/* loop over all signators */
for(kr=ur->list; kr; kr = kr->next ) {
propagate_validity( kr );
if( propagate_validity( root, kr, add_fnc, retflgs ) )
return -1; /* quit */
if( kr->n.k.validity == TRUST_ULTIMATE ) {
ur->n.u.fully_count = opt.completes_needed;
}
else if( kr->n.k.validity == TRUST_FULLY ) {
if( add_fnc && !kr->n.k.ownertrust ) {
int rc;
if( retflgs )
*retflgs |= 2; /* found key with undefined ownertrust*/
do {
rc = add_fnc( kr->lid );
switch( rc ) {
case TRUST_NEVER:
case TRUST_MARGINAL:
case TRUST_FULLY:
propagate_ownertrust( root, kr->lid, rc );
upd_one_ownertrust( kr->lid, rc, retflgs );
if( retflgs )
*retflgs |= 4; /* changed */
break;
case -1:
return -1; /* cancel */
case -2:
dump_tn_tree( NULL, 0, kr );
tty_printf("\n");
break;
default:
break;
}
} while( rc == -2 );
}
if( kr->n.k.ownertrust == TRUST_FULLY )
ur->n.u.fully_count++;
else if( kr->n.k.ownertrust == TRUST_MARGINAL )
@ -2145,6 +2329,7 @@ propagate_validity( TN node )
}
node->n.k.validity = max_validity;
return 0;
}
@ -2155,15 +2340,17 @@ propagate_validity( TN node )
* checking all key signatures up to a some depth.
*/
static int
verify_key( int max_depth, TRUSTREC *drec, const char *namehash )
verify_key( int max_depth, TRUSTREC *drec, const char *namehash,
int (*add_fnc)(ulong), unsigned *retflgs )
{
TN tree;
int keytrust;
int pv_result;
tree = build_cert_tree( drec->r.dir.lid, 0, opt.max_cert_depth, NULL );
if( !tree )
return TRUST_UNDEFINED;
propagate_validity( tree );
pv_result = propagate_validity( tree, tree, add_fnc, retflgs );
if( namehash ) {
/* find the matching user id.
* fixme: the way we handle this is too inefficient */
@ -2183,7 +2370,8 @@ verify_key( int max_depth, TRUSTREC *drec, const char *namehash )
keytrust = tree->n.k.validity;
/* update the cached validity values */
if( keytrust >= TRUST_UNDEFINED
if( !pv_result
&& keytrust >= TRUST_UNDEFINED
&& tdbio_db_matches_options()
&& ( !drec->r.dir.valcheck || drec->r.dir.validity != keytrust ) ) {
TN ur;
@ -2213,7 +2401,8 @@ verify_key( int max_depth, TRUSTREC *drec, const char *namehash )
* but nothing more is known.
*/
static int
do_check( TRUSTREC *dr, unsigned *validity, const char *namehash )
do_check( TRUSTREC *dr, unsigned *validity,
const char *namehash, int (*add_fnc)(ulong), unsigned *retflgs )
{
if( !dr->r.dir.keylist ) {
log_error(_("Ooops, no keys\n"));
@ -2224,22 +2413,39 @@ do_check( TRUSTREC *dr, unsigned *validity, const char *namehash )
return G10ERR_TRUSTDB;
}
if( retflgs )
*retflgs &= ~(16|32); /* reset the 2 special flags */
if( namehash ) {
/* Fixme: use the cache */
*validity = verify_key( opt.max_cert_depth, dr, namehash );
*validity = verify_key( opt.max_cert_depth, dr, namehash,
add_fnc, retflgs );
}
else if( tdbio_db_matches_options()
else if( !add_fnc
&& tdbio_db_matches_options()
&& dr->r.dir.valcheck
> tdbio_read_modify_stamp( (dr->r.dir.validity < TRUST_FULLY) )
&& dr->r.dir.validity )
*validity = dr->r.dir.validity;
else
*validity = verify_key( opt.max_cert_depth, dr, NULL );
*validity = verify_key( opt.max_cert_depth, dr, NULL,
add_fnc, retflgs );
if( !(*validity & TRUST_MASK) )
*validity = TRUST_UNDEFINED;
if( dr->r.dir.dirflags & DIRF_REVOKED )
*validity |= TRUST_FLAG_REVOKED;
/* If we have changed some ownertrusts, set the trustdb timestamps
* and do a sync */
if( retflgs && (*retflgs & (16|32)) ) {
tdbio_write_modify_stamp( (*retflgs & 16), (*retflgs & 32) );
do_sync();
}
return 0;
}
@ -2256,6 +2462,9 @@ update_ownertrust( ulong lid, unsigned new_trust )
init_trustdb();
read_record( lid, &rec, RECTYPE_DIR );
if( DBG_TRUST )
log_debug("update_ownertrust of %lu from %u to %u\n",
lid, (unsigned)rec.r.dir.ownertrust, new_trust );
rec.r.dir.ownertrust = new_trust;
write_record( &rec );
do_sync();
@ -2512,7 +2721,8 @@ query_trust_record( PKT_public_key *pk )
* is not necessary to check this if we use a local pubring. Hmmmm.
*/
int
check_trust( PKT_public_key *pk, unsigned *r_trustlevel, const byte *namehash )
check_trust( PKT_public_key *pk, unsigned *r_trustlevel,
const byte *namehash, int (*add_fnc)(ulong), unsigned *retflgs )
{
TRUSTREC rec;
unsigned trustlevel = TRUST_UNKNOWN;
@ -2562,7 +2772,7 @@ check_trust( PKT_public_key *pk, unsigned *r_trustlevel, const byte *namehash )
trustlevel = TRUST_EXPIRED;
}
else {
rc = do_check( &rec, &trustlevel, namehash );
rc = do_check( &rec, &trustlevel, namehash, add_fnc, retflgs );
if( rc ) {
log_error(_("key %08lX.%lu: trust check failed: %s\n"),
(ulong)keyid[1], pk->local_id, g10_errstr(rc));
@ -2586,7 +2796,7 @@ query_trust_info( PKT_public_key *pk, const byte *namehash )
int c;
init_trustdb();
if( check_trust( pk, &trustlevel, namehash ) )
if( check_trust( pk, &trustlevel, namehash, NULL, NULL ) )
return '?';
if( trustlevel & TRUST_FLAG_REVOKED )
return 'r';
@ -2656,12 +2866,15 @@ list_trust_path( const char *username )
tree = build_cert_tree( lid, 0, opt.max_cert_depth, NULL );
if( tree )
propagate_validity( tree );
dump_tn_tree( 0, tree );
printf("(alloced tns=%d max=%d)\n", alloced_tns, max_alloced_tns );
propagate_validity( tree, tree, NULL, NULL );
if( opt.with_colons )
dump_tn_tree_with_colons( 0, tree );
else
dump_tn_tree( stdout, 0, tree );
/*printf("(alloced tns=%d max=%d)\n", alloced_tns, max_alloced_tns );*/
release_tn_tree( tree );
printf("Ownertrust=%c Validity=%c\n", get_ownertrust_info( lid ),
query_trust_info( pk, NULL ) );
/*printf("Ownertrust=%c Validity=%c\n", get_ownertrust_info( lid ),
query_trust_info( pk, NULL ) ); */
free_public_key( pk );

View File

@ -47,7 +47,8 @@ void check_trustdb( const char *username );
void update_trustdb( void );
int setup_trustdb( int level, const char *dbname );
void init_trustdb( void );
int check_trust( PKT_public_key *pk, unsigned *r_trustlevel, const byte* nh );
int check_trust( PKT_public_key *pk, unsigned *r_trustlevel,
const byte* nh, int (*add_fnc)(ulong), unsigned *retflgs );
int query_trust_info( PKT_public_key *pk, const byte *nh );
int enum_cert_paths( void **context, ulong *lid,
unsigned *ownertrust, unsigned *validity );

View File

@ -88,6 +88,7 @@ typedef struct {
int g10c_debug_mode;
int g10_opt_verbose;
const char *g10_opt_homedir;
/*-- dynload.c --*/
void register_cipher_extension( const char *mainpgm, const char *fname );