summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2000-09-18 16:35:34 +0200
committerWerner Koch <wk@gnupg.org>2000-09-18 16:35:34 +0200
commit986d928ce2a561b04fda7730de6a94f9b1e703d6 (patch)
tree9d815bcf427ee76f678153f4b000d8843816a2bd
parentSee ChangeLog: Tue Aug 22 14:31:15 CEST 2000 Werner Koch (diff)
downloadgnupg2-986d928ce2a561b04fda7730de6a94f9b1e703d6.tar.xz
gnupg2-986d928ce2a561b04fda7730de6a94f9b1e703d6.zip
See ChangeLog: Mon Sep 18 16:35:45 CEST 2000 Werner Koch
-rw-r--r--ChangeLog17
-rw-r--r--NEWS34
-rw-r--r--VERSION3
-rw-r--r--acconfig.h2
-rw-r--r--acinclude.m428
-rw-r--r--cipher/ChangeLog18
-rw-r--r--cipher/Makefile.am1
-rw-r--r--cipher/pubkey.c26
-rw-r--r--cipher/random.c4
-rw-r--r--cipher/rndlinux.c7
-rw-r--r--cipher/rndunix.c5
-rw-r--r--cipher/rsa.c136
-rw-r--r--configure.in33
-rw-r--r--g10/ChangeLog78
-rw-r--r--g10/build-packet.c1
-rw-r--r--g10/encode.c8
-rw-r--r--g10/free-packet.c30
-rw-r--r--g10/getkey.c1641
-rw-r--r--g10/gpg.c44
-rw-r--r--g10/import.c13
-rw-r--r--g10/keydb.h9
-rw-r--r--g10/keyedit.c2
-rw-r--r--g10/keygen.c10
-rw-r--r--g10/keyid.c10
-rw-r--r--g10/main.h3
-rw-r--r--g10/misc.c59
-rw-r--r--g10/openfile.c32
-rw-r--r--g10/options.h3
-rw-r--r--g10/packet.h23
-rw-r--r--g10/parse-packet.c44
-rw-r--r--g10/passphrase.c1
-rw-r--r--g10/pkclist.c11
-rw-r--r--g10/pubkey-enc.c5
-rw-r--r--g10/ringedit.c8
-rw-r--r--g10/seckey-cert.c15
-rw-r--r--g10/sig-check.c15
-rw-r--r--g10/sign.c4
-rw-r--r--g10/skclist.c4
-rw-r--r--g10/trustdb.c123
-rw-r--r--include/iobuf.h1
-rw-r--r--tools/ChangeLog5
-rwxr-xr-xtools/ring-a-party10
-rw-r--r--util/ChangeLog12
-rw-r--r--util/iobuf.c29
-rw-r--r--util/miscutil.c8
-rw-r--r--util/strgutil.c7
46 files changed, 1755 insertions, 827 deletions
diff --git a/ChangeLog b/ChangeLog
index 96c1e8107..f3fbca869 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+Mon Sep 18 16:35:45 CEST 2000 Werner Koch <wk@openit.de>
+
+ * acinclude.m4 (GNUPG_CHECK_MLOCK): Removed that silly mkdir().
+
+ * configure.in: Changes to allow for Solaris random device.
+ By Nils Ellmenreich.
+ (--with-egd-socket): New.
+
+ * configure.in (GNUPG_HOMEDIR): New.
+
+ * configure.in: Check for fstat64 and fopen64
+
+ * acinclude.m4 (GNUPG_CHECK_FAQPROG): New.
+ * configure.in: Test for this.
+
+ * configure.in (DYNLINK_MOD_CFLAGS): Fix by David Champion.
+
Tue Aug 22 14:31:15 CEST 2000 Werner Koch <wk@openit.de>
Version 1.1.1
diff --git a/NEWS b/NEWS
index 60180fc70..d5367ae1c 100644
--- a/NEWS
+++ b/NEWS
@@ -1,8 +1,38 @@
-Noteworthy changes in version 1.1.1
------------------------------------
+Noteworthy changes in the current CVS HEAD
+------------------------------------------
THIS IS A DEVELOPMENT VERSION; see README-alpha
+ * Fixed problems with piping to/from other MS-Windows software
+
+ * Expiration time of the primary key can be changed again.
+
+ * Revoked user IDs are now marked in the output of --list-key
+
+ * New options --merge-only and --try-all-secrets.
+
+ * New configuration option --with-egd-socket.
+
+ * The --trusted-key option is back after it left us with 0.9.5
+
+ * RSA is supported. Key generation does not yet work but will come
+ soon.
+
+ * CAST5 and SHA-1 are now the default algorithms to protect the key
+ and for symmetric-only encryption. This should solve a couple
+ of compatibility problems because the old algorithms are optional
+ according to RFC2440
+
+ * Twofish and MDC enhanced encryption is now used. PGP 7 supports
+ this. Older versions of GnuPG don't support it, so they should be
+ upgraded to at least 1.0.2
+
+
+
+
+Noteworthy changes in version 1.1.1
+-----------------------------------
+
* Add gpg-agent.
* Removed option --emulate-checksum-bug
diff --git a/VERSION b/VERSION
index 8cfbc905b..bff94ddaa 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1,2 @@
-1.1.1 \ No newline at end of file
+1.1.1a
+
diff --git a/acconfig.h b/acconfig.h
index a2c91283f..3c1d32e25 100644
--- a/acconfig.h
+++ b/acconfig.h
@@ -74,6 +74,8 @@
#undef NAME_OF_DEV_URANDOM
/* Linux has an ioctl */
#undef HAVE_DEV_RANDOM_IOCTL
+/* see cipher/rndegd.c */
+#undef EGD_SOCKET_NAME
#undef USE_DYNAMIC_LINKING
diff --git a/acinclude.m4 b/acinclude.m4
index 9f8bfd01d..7291c1dff 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -67,6 +67,32 @@ AC_DEFUN(GNUPG_CHECK_GNUMAKE,
fi
])
+dnl GNUPG_CHECK_FAQPROG
+dnl
+AC_DEFUN(GNUPG_CHECK_FAQPROG,
+ [ AC_MSG_CHECKING(for faqprog.pl)
+ if faqprog.pl -V 2>/dev/null | grep '^faqprog.pl ' >/dev/null 2>&1; then
+ working_faqprog=yes
+ FAQPROG="faqprog.pl"
+ else
+ working_faqprog=no
+ FAQPROG=": "
+ fi
+ AC_MSG_RESULT($working_faqprog)
+ AC_SUBST(FAQPROG)
+ AM_CONDITIONAL(WORKING_FAQPROG, test "$working_faqprog" = "yes" )
+
+ if test $working_faqprog = no; then
+ AC_MSG_WARN([[
+***
+*** It seems that the faqprog.pl program is not installed.
+*** Unless you do not change the source of the FAQs it is not required.
+*** The working version of this utility should be available at:
+*** ftp://ftp.gnupg.org/pub/gcrypt/contrib/faqprog.pl
+***]])
+ fi
+ ])
+
dnl GNUPG_LINK_FILES( SRC, DEST )
@@ -358,7 +384,7 @@ define(GNUPG_CHECK_MLOCK,
#endif
], [
int i;
- mkdir ("foo", 0);
+
/* glibc defines this for functions which it implements
* to always fail with ENOSYS. Some functions are actually
* named something starting with __ and the normal name
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index e37e3c351..2e4ebe53e 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,21 @@
+Mon Sep 18 16:35:45 CEST 2000 Werner Koch <wk@openit.de>
+
+ * rndlinux.c (open_device): Loose random device checking.
+ By Nils Ellmenreich.
+
+ * random.c (fast_random_poll): Check ENOSYS for getrusage.
+ * rndunix.c: Add 2 sources for QNX. By Sam Roberts.
+
+ * pubkey.c (gcry_pk_algo_info): Add GCRYCTL_GET_ALGO_USAGE.
+
+ * rsa.c: Changed the comment about the patent.
+ (secret): Speed up by using the CRT. For a 2k keys this
+ is about 3 times faster.
+ (stronger_key_check): New but unused code to check the secret key.
+ * Makefile.am: Included rsa.[ch].
+ * pubkey.c: Enabled RSA support.
+ (pubkey_get_npkey): Removed RSA workaround.
+
Mon Jul 31 10:04:47 CEST 2000 Werner Koch <wk@openit.de>
* pubkey.c: Replaced all gcry_sexp_{car,cdr}_{data,mpi} by the new
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 2ed370f05..26de92520 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -50,6 +50,7 @@ libcipher_la_SOURCES = cipher.c \
rmd.h \
dsa.h \
dsa.c \
+ rsa.c rsa.h \
smallprime.c \
construct.c
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index bbf592bb4..3dab336d7 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -30,9 +30,7 @@
#include "cipher.h"
#include "elgamal.h"
#include "dsa.h"
-#if 0
#include "rsa.h"
-#endif
#include "dynload.h"
/* FIXME: use set_lasterr() */
@@ -196,7 +194,6 @@ setup_pubkey_table(void)
BUG();
i++;
- #if 0
pubkey_table[i].algo = PUBKEY_ALGO_RSA;
pubkey_table[i].name = rsa_get_info( pubkey_table[i].algo,
&pubkey_table[i].npkey,
@@ -248,7 +245,6 @@ setup_pubkey_table(void)
if( !pubkey_table[i].name )
BUG();
i++;
- #endif
for( ; i < TABLE_SIZE; i++ )
pubkey_table[i].name = NULL;
@@ -433,8 +429,6 @@ pubkey_get_npkey( int algo )
if( pubkey_table[i].algo == algo )
return pubkey_table[i].npkey;
} while( load_pubkey_modules() );
- if( is_RSA(algo) ) /* special hack, so that we are able to */
- return 2; /* see the RSA keyids */
return 0;
}
@@ -450,8 +444,6 @@ pubkey_get_nskey( int algo )
if( pubkey_table[i].algo == algo )
return pubkey_table[i].nskey;
} while( load_pubkey_modules() );
- if( is_RSA(algo) ) /* special hack, so that we are able to */
- return 6; /* see the RSA keyids */
return 0;
}
@@ -467,8 +459,6 @@ pubkey_get_nsig( int algo )
if( pubkey_table[i].algo == algo )
return pubkey_table[i].nsig;
} while( load_pubkey_modules() );
- if( is_RSA(algo) ) /* special hack, so that we are able to */
- return 1; /* see the RSA keyids */
return 0;
}
@@ -484,8 +474,6 @@ pubkey_get_nenc( int algo )
if( pubkey_table[i].algo == algo )
return pubkey_table[i].nenc;
} while( load_pubkey_modules() );
- if( is_RSA(algo) ) /* special hack, so that we are able to */
- return 1; /* see the RSA keyids */
return 0;
}
@@ -1509,6 +1497,11 @@ gcry_pk_ctl( int cmd, void *buffer, size_t buflen)
* Buffer must be NULL, nbytes may have the address of a variable
* with the required usage of the algorithm. It may be 0 for don't
* care or a combination of the GCRY_PK_USAGE_xxx flags;
+ * GCRYCTL_GET_ALGO_USAGE:
+ * Return the usage glafs for the give algo. An invalid alog
+ * does return 0. Disabled algos are ignored here becuase we
+ * only want to know whether the algo is at all capable of
+ * the usage.
*
* On error the value -1 is returned and the error reason may be
* retrieved by gcry_errno().
@@ -1535,6 +1528,15 @@ gcry_pk_algo_info( int algo, int what, void *buffer, size_t *nbytes)
}
break;
+ case GCRYCTL_GET_ALGO_USAGE:
+ do {
+ int i;
+ for(i=0; pubkey_table[i].name; i++ )
+ if( pubkey_table[i].algo == algo )
+ return pubkey_table[i].use;
+ } while( load_pubkey_modules() );
+ return 0;
+
case GCRYCTL_GET_ALGO_NPKEY: return pubkey_get_npkey( algo );
case GCRYCTL_GET_ALGO_NSKEY: return pubkey_get_nskey( algo );
case GCRYCTL_GET_ALGO_NSIGN: return pubkey_get_nsig( algo );
diff --git a/cipher/random.c b/cipher/random.c
index 0258f5dd0..6f31b5625 100644
--- a/cipher/random.c
+++ b/cipher/random.c
@@ -604,7 +604,9 @@ fast_random_poll()
#endif
#else
{ struct rusage buf;
- if( getrusage( RUSAGE_SELF, &buf ) )
+ /* QNX/Neutrino does return ENOSYS - so we just ignore it and
+ * add whatever is in buf */
+ if( getrusage( RUSAGE_SELF, &buf ) && errno != ENOSYS )
BUG();
add_randomness( &buf, sizeof buf, 1 );
memset( &buf, 0, sizeof buf );
diff --git a/cipher/rndlinux.c b/cipher/rndlinux.c
index bca596fd1..c23269644 100644
--- a/cipher/rndlinux.c
+++ b/cipher/rndlinux.c
@@ -63,7 +63,7 @@ get_entropy_count( int fd )
#endif
/****************
- * Used to open the Linux and xBSD /dev/random devices
+ * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists), ...)
*/
static int
open_device( const char *name, int minor )
@@ -76,8 +76,9 @@ open_device( const char *name, int minor )
g10_log_fatal("can't open %s: %s\n", name, strerror(errno) );
if( fstat( fd, &sb ) )
g10_log_fatal("stat() off %s failed: %s\n", name, strerror(errno) );
- if( !S_ISCHR(sb.st_mode) )
- g10_log_fatal("invalid random device!\n" );
+ /* Don't check device type for better portability */
+ /* if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) )
+ g10_log_fatal("invalid random device!\n" ); */
return fd;
}
diff --git a/cipher/rndunix.c b/cipher/rndunix.c
index 99a416ea7..6c8e680b2 100644
--- a/cipher/rndunix.c
+++ b/cipher/rndunix.c
@@ -244,6 +244,7 @@ static struct RI {
{ "/usr/ucb/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1 },
{ "/usr/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1 },
{ "/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 0 },
+ { "/bin/ps", "-A", SC(0.3), NULL, 0, 0, 0, 0 }, /*QNX*/
{ "/usr/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 1 },
{ "/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 0 },
/* Unreliable source, depends on system usage */
@@ -292,6 +293,10 @@ static struct RI {
/* This is a complex and screwball program. Some systems have things
* like rX_dmn, x = integer, for RAID systems, but the statistics are
* pretty dodgy */
+#ifdef __QNXNTO__
+ { "/bin/pidin", "-F%A%B%c%d%E%I%J%K%m%M%n%N%p%P%S%s%T", SC(0.3),
+ NULL, 0, 0, 0, 0 },
+#endif
#if 0
/* The following aren't enabled since they're somewhat slow and not very
* unpredictable, however they give an indication of the sort of sources
diff --git a/cipher/rsa.c b/cipher/rsa.c
index 5d852cd88..2bb451002 100644
--- a/cipher/rsa.c
+++ b/cipher/rsa.c
@@ -1,10 +1,6 @@
/* rsa.c - RSA function
* Copyright (C) 1997, 1998, 1999 by Werner Koch (dd9jn)
* Copyright (C) 2000 Free Software Foundation, Inc.
- ***********************************************************************
- * ATTENTION: This code should not be used in the United States
- * before the U.S. Patent #4,405,829 expires on September 20, 2000!
- ***********************************************************************
*
* This file is part of GnuPG.
*
@@ -23,11 +19,16 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
+/* This code uses an algorithm protected by U.S. Patent #4,405,829
+ which expires on September 20, 2000. The patent holder placed that
+ patent into the public domain on Sep 6th, 2000.
+*/
+
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "util.h"
+#include "g10lib.h"
#include "mpi.h"
#include "cipher.h"
#include "rsa.h"
@@ -68,7 +69,7 @@ test_keys( RSA_secret_key *sk, unsigned nbits )
pk.e = sk->e;
{ char *p = get_random_bits( nbits, 0, 0 );
mpi_set_buffer( test, p, (nbits+7)/8, 0 );
- m_free(p);
+ g10_free(p);
}
public( out1, test, &pk );
@@ -200,22 +201,111 @@ public(MPI output, MPI input, RSA_public_key *pkey )
mpi_powm( output, input, pkey->e, pkey->n );
}
+#if 0
+static void
+stronger_key_check ( RSA_secret_key *skey )
+{
+ MPI t = mpi_alloc_secure ( 0 );
+ MPI t1 = mpi_alloc_secure ( 0 );
+ MPI t2 = mpi_alloc_secure ( 0 );
+ MPI phi = mpi_alloc_secure ( 0 );
+
+ /* check that n == p * q */
+ mpi_mul( t, skey->p, skey->q);
+ if (mpi_cmp( t, skey->n) )
+ log_info ( "RSA Oops: n != p * q\n" );
+
+ /* check that p is less than q */
+ if( mpi_cmp( skey->p, skey->q ) > 0 )
+ log_info ("RSA Oops: p >= q\n");
+
+
+ /* check that e divides neither p-1 nor q-1 */
+ mpi_sub_ui(t, skey->p, 1 );
+ mpi_fdiv_r(t, t, skey->e );
+ if ( !mpi_cmp_ui( t, 0) )
+ log_info ( "RSA Oops: e divides p-1\n" );
+ mpi_sub_ui(t, skey->q, 1 );
+ mpi_fdiv_r(t, t, skey->e );
+ if ( !mpi_cmp_ui( t, 0) )
+ log_info ( "RSA Oops: e divides q-1\n" );
+
+ /* check that d is correct */
+ mpi_sub_ui( t1, skey->p, 1 );
+ mpi_sub_ui( t2, skey->q, 1 );
+ mpi_mul( phi, t1, t2 );
+ mpi_gcd(t, t1, t2);
+ mpi_fdiv_q(t, phi, t);
+ mpi_invm(t, skey->e, t );
+ if ( mpi_cmp(t, skey->d ) )
+ log_info ( "RSA Oops: d is wrong\n");
+
+ /* check for crrectness of u */
+ mpi_invm(t, skey->p, skey->q );
+ if ( mpi_cmp(t, skey->u ) )
+ log_info ( "RSA Oops: u is wrong\n");
+
+ log_info ( "RSA secret key check finished\n");
+
+ mpi_free (t);
+ mpi_free (t1);
+ mpi_free (t2);
+ mpi_free (phi);
+}
+#endif
+
+
+
/****************
* Secret key operation. Encrypt INPUT with SKEY and put result into OUTPUT.
*
* m = c^d mod n
*
- * Where m is OUTPUT, c is INPUT and d,n are elements of PKEY.
+ * Or faster:
*
- * FIXME: We should better use the Chinese Remainder Theorem
+ * m1 = c ^ (d mod (p-1)) mod p
+ * m2 = c ^ (d mod (q-1)) mod q
+ * h = u * (m2 - m1) mod q
+ * m = m1 + h * p
+ *
+ * Where m is OUTPUT, c is INPUT and d,n,p,q,u are elements of SKEY.
*/
static void
secret(MPI output, MPI input, RSA_secret_key *skey )
{
+ #if 0
mpi_powm( output, input, skey->d, skey->n );
+ #else
+ MPI m1 = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 );
+ MPI m2 = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 );
+ MPI h = mpi_alloc_secure( mpi_get_nlimbs(skey->n)+1 );
+
+ /* m1 = c ^ (d mod (p-1)) mod p */
+ mpi_sub_ui( h, skey->p, 1 );
+ mpi_fdiv_r( h, skey->d, h );
+ mpi_powm( m1, input, h, skey->p );
+ /* m2 = c ^ (d mod (q-1)) mod q */
+ mpi_sub_ui( h, skey->q, 1 );
+ mpi_fdiv_r( h, skey->d, h );
+ mpi_powm( m2, input, h, skey->q );
+ /* h = u * ( m2 - m1 ) mod q */
+ mpi_sub( h, m2, m1 );
+ if ( mpi_is_neg( h ) )
+ mpi_add ( h, h, skey->q );
+ mpi_mulm( h, skey->u, h, skey->q );
+ /* m = m2 + h * p */
+ mpi_mul ( h, h, skey->p );
+ mpi_add ( output, m1, h );
+ /* ready */
+
+ mpi_free ( h );
+ mpi_free ( m1 );
+ mpi_free ( m2 );
+ #endif
}
+
/*********************************************
************** interface ******************
*********************************************/
@@ -226,7 +316,7 @@ rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
RSA_secret_key sk;
if( !is_RSA(algo) )
- return G10ERR_PUBKEY_ALGO;
+ return GCRYERR_INV_PK_ALGO;
generate( &sk, nbits );
skey[0] = sk.n;
@@ -236,7 +326,7 @@ rsa_generate( int algo, unsigned nbits, MPI *skey, MPI **retfactors )
skey[4] = sk.q;
skey[5] = sk.u;
/* make an empty list of factors */
- *retfactors = m_alloc_clear( 1 * sizeof **retfactors );
+ *retfactors = g10_xcalloc( 1, sizeof **retfactors );
return 0;
}
@@ -247,7 +337,7 @@ rsa_check_secret_key( int algo, MPI *skey )
RSA_secret_key sk;
if( !is_RSA(algo) )
- return G10ERR_PUBKEY_ALGO;
+ return GCRYERR_INV_PK_ALGO;
sk.n = skey[0];
sk.e = skey[1];
@@ -256,7 +346,7 @@ rsa_check_secret_key( int algo, MPI *skey )
sk.q = skey[4];
sk.u = skey[5];
if( !check_secret_key( &sk ) )
- return G10ERR_BAD_SECKEY;
+ return GCRYERR_INV_PK_ALGO;
return 0;
}
@@ -269,7 +359,7 @@ rsa_encrypt( int algo, MPI *resarr, MPI data, MPI *pkey )
RSA_public_key pk;
if( algo != 1 && algo != 2 )
- return G10ERR_PUBKEY_ALGO;
+ return GCRYERR_INV_PK_ALGO;
pk.n = pkey[0];
pk.e = pkey[1];
@@ -284,7 +374,7 @@ rsa_decrypt( int algo, MPI *result, MPI *data, MPI *skey )
RSA_secret_key sk;
if( algo != 1 && algo != 2 )
- return G10ERR_PUBKEY_ALGO;
+ return GCRYERR_INV_PK_ALGO;
sk.n = skey[0];
sk.e = skey[1];
@@ -303,7 +393,7 @@ rsa_sign( int algo, MPI *resarr, MPI data, MPI *skey )
RSA_secret_key sk;
if( algo != 1 && algo != 3 )
- return G10ERR_PUBKEY_ALGO;
+ return GCRYERR_INV_PK_ALGO;
sk.n = skey[0];
sk.e = skey[1];
@@ -326,13 +416,13 @@ rsa_verify( int algo, MPI hash, MPI *data, MPI *pkey,
int rc;
if( algo != 1 && algo != 3 )
- return G10ERR_PUBKEY_ALGO;
+ return GCRYERR_INV_PK_ALGO;
pk.n = pkey[0];
pk.e = pkey[1];
result = mpi_alloc( (160+BITS_PER_MPI_LIMB-1)/BITS_PER_MPI_LIMB);
public( result, data[0], &pk );
/*rc = (*cmp)( opaquev, result );*/
- rc = mpi_cmp( result, hash )? G10ERR_BAD_SIGN:0;
+ rc = mpi_cmp( result, hash )? GCRYERR_BAD_SIGNATURE:0;
mpi_free(result);
return rc;
@@ -366,10 +456,16 @@ rsa_get_info( int algo,
*nsig = 1;
switch( algo ) {
- case 1: *usage = PUBKEY_USAGE_SIG | PUBKEY_USAGE_ENC; return "RSA";
- case 2: *usage = PUBKEY_USAGE_ENC; return "RSA-E";
- case 3: *usage = PUBKEY_USAGE_SIG; return "RSA-S";
+ case 1: *usage = GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR; return "RSA";
+ case 2: *usage = GCRY_PK_USAGE_ENCR; return "RSA-E";
+ case 3: *usage = GCRY_PK_USAGE_SIGN; return "RSA-S";
default:*usage = 0; return NULL;
}
}
+
+
+
+
+
+
diff --git a/configure.in b/configure.in
index 65b6c8471..38d2c94db 100644
--- a/configure.in
+++ b/configure.in
@@ -48,6 +48,11 @@ case "$use_static_rnd" in
;;
esac
+AC_ARG_WITH(egd-socket,
+ [ --with-egd-socket=NAME Use NAME for the EGD socket)],
+ egd_socket_name="$withval", egd_socket_name="" )
+AC_DEFINE_UNQUOTED(EGD_SOCKET_NAME, "$egd_socket_name")
+
dnl
@@ -164,6 +169,7 @@ AC_ISC_POSIX
AC_PROG_INSTALL
AC_PROG_AWK
GPH_PROG_DOCBOOK
+GNUPG_CHECK_FAQPROG
dnl
@@ -271,19 +277,30 @@ case "${target}" in
*-openbsd*)
NAME_OF_DEV_RANDOM="/dev/srandom"
NAME_OF_DEV_URANDOM="/dev/urandom"
- DYNLINK_MOD_CFLAGS="-shared -rdynamic -fpic -Wl,-Bshareable -Wl,-x"
+ DYNLINK_MOD_CFLAGS="-shared -rdynamic $CFLAGS_PIC -Wl,-Bshareable -Wl,-x"
;;
*-netbsd*)
NAME_OF_DEV_RANDOM="/dev/random"
NAME_OF_DEV_URANDOM="/dev/urandom"
- DYNLINK_MOD_CFLAGS="-shared -rdynamic -fpic -Wl,-Bshareable -Wl,-x"
+ DYNLINK_MOD_CFLAGS="-shared -rdynamic $CFLAGS_PIC -Wl,-Bshareable -Wl,-x"
+ ;;
+
+ *-solaris*)
+ NAME_OF_DEV_RANDOM="/dev/random"
+ NAME_OF_DEV_URANDOM="/dev/random"
+ DYNLINK_MOD_CFLAGS="-shared $CFLAGS_PIC"
;;
*)
NAME_OF_DEV_RANDOM="/dev/random"
NAME_OF_DEV_URANDOM="/dev/urandom"
- DYNLINK_MOD_CFLAGS="-shared $CFLAGS_PIC"
+ # -shared is a gcc-ism. Find pic flags from GNUPG_CHECK_PIC.
+ if test -n "$GCC" ; then
+ DYNLINK_MOD_CFLAGS="-shared $CFLAGS_PIC"
+ else
+ DYNLINK_MOD_CFLAGS="$CFLAGS_PIC"
+ fi
;;
esac
AC_DEFINE_UNQUOTED(NAME_OF_DEV_RANDOM, "$NAME_OF_DEV_RANDOM")
@@ -429,7 +446,7 @@ AC_FUNC_VPRINTF
AC_CHECK_FUNCS(strerror stpcpy strlwr stricmp tcgetattr rand strtoul mmap)
AC_CHECK_FUNCS(memmove gettimeofday getrusage gethrtime setrlimit clock_gettime)
AC_CHECK_FUNCS(memicmp atexit raise getpagesize strftime nl_langinfo)
-AC_CHECK_FUNCS(waitpid wait4 sigaction sigprocmask)
+AC_CHECK_FUNCS(waitpid wait4 sigaction sigprocmask fopen64 fstat64)
GNUPG_CHECK_MLOCK
GNUPG_FUNC_MKDIR_TAKES_ONE_ARG
@@ -473,7 +490,7 @@ dnl check whether we have a random device
dnl
if test "$try_dev_random" = yes ; then
AC_CACHE_CHECK(for random device, ac_cv_have_dev_random,
- [if test -c "$NAME_OF_DEV_RANDOM" && test -c "$NAME_OF_DEV_URANDOM" ; then
+ [if test -r "$NAME_OF_DEV_RANDOM" && test -r "$NAME_OF_DEV_URANDOM" ; then
ac_cv_have_dev_random=yes; else ac_cv_have_dev_random=no; fi])
if test "$ac_cv_have_dev_random" = yes; then
AC_DEFINE(HAVE_DEV_RANDOM)
@@ -740,10 +757,16 @@ cat >gnupg-defs.tmp <<G10EOF
#define GNUPG_LOCALEDIR "c:/lib/gnupg/locale"
#define GNUPG_LIBDIR "c:/lib/gnupg"
#define GNUPG_DATADIR "c:/lib/gnupg"
+ #define GNUPG_HOMEDIR "c:/gnupg-test"
#else
#define GNUPG_LOCALEDIR "${prefix}/${DATADIRNAME}/locale"
#define GNUPG_LIBDIR "${libdir}/gnupg"
#define GNUPG_DATADIR "${datadir}/gnupg"
+ #ifdef __VMS
+ #define GNUPG_HOMEDIR "/SYS\$LOGIN/gnupg"
+ #else
+ #define GNUPG_HOMEDIR "~/.gnupg-test"
+ #endif
#endif
G10EOF
if cmp -s gnupg-defs.h gnupg-defs.tmp 2>/dev/null; then
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 74cf0d400..7cb0f17b7 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,81 @@
+Mon Sep 18 16:35:45 CEST 2000 Werner Koch <wk@openit.de>
+
+ * parse-packet.c (dump_sig_subpkt): Dump key flags.
+ (parse_one_sig_subpkt,can_handle_critical): Add KeyFlags support.
+ * build-packet.c (build_sig_subpkt): Ditto.
+
+ * g10.c: New option --allow-freeform-uid. By Jeroen C. van Gelderen.
+ * keygen.c (ask_user_id): Implemented here.
+
+ * parse-packet.c (dump_sig_subpkt): Print info about the ARR.
+
+ * openfile.c (overwrite_filep): Always return okay if the file is
+ called /dev/null.
+ (make_outfile_name): Add ".sign" to the list of know extensions.
+ (open_sigfile): Ditto.
+
+ * getkey.c: Large parts rewritten to have a better sub key selection
+ and handle some meta information from signatures more correctly.
+ (get_primary_seckey): Removed.
+ * seckey_cert.c (do_check): Set main keyid from the data in the sk.
+ * free-packet.c (copy_public_parts_to_secret_key): New.
+ * sig-check.c (check_key_signature2): Enabled shortcut for already
+ checked signatures.
+ * keydb.h: New macros IS_xxx_SIG, IS_xxx_REV.
+ * misc.c (openpgp_pk_algo_usage): New.
+ * packet.h: New field req_uage and do not use pubkey_usage anymore
+ to request a specific usage. Changed at all places.
+ * keyid.c (keyid_from_sk): Cache the keyid in the sk
+
+ * passphrase.c (hash_passphrase): Removed funny assert. Reported by
+ David Mathog.
+
+ * keyedit.c (keyedit_menu): Allow "debug" on secret keys.
+
+ * keygen.c (keygen_add_std_prefs): Changed order of preferences to
+ twofish, cast5, blowfish.
+
+ * gpg.c: The --trusted-key option is back.
+ * trustdb.c (verify_own_key): Handle this option.
+ (add_ultimate_key): Moved stuff from verify_own_key to this new func.
+ (register_trusted_key): New.
+
+ * openfile.c (try_make_homedir): Changes for non-Posix systems.
+ * gpg.c (main): Take the default homedir from macro.
+
+ * encode.c (encode_simple, encode_crypt): Fix for large files.
+ * sign.c (sign_file): Ditto.
+
+ * gpg.c (main): Don't set --quite along with --no-tty. By Frank Tobin.
+
+ * misc.c (disable_core_dump): Don't display a warning here but a return
+ a status value and ...
+ * gpg.c (main): ...print warning here. Suggested by Sam Roberts.
+
+ * misc.c (print_pubkey_algo_note): Do not print the RSA notice.
+ * sig-check.c (do_signature_check): Do not emit the RSA status message.
+ * pubkey-enc.c (get_session_key): Ditto.
+
+ * ringedit.c (cmp_seckey): Fix for v4 RSA keys.
+ * seckey-cert.c (do_check): Workaround for PGP 7 bug.
+
+ * pkclist.c (algo_available): Removed hack to disable Twofish.
+
+ * gpg.c (main): Default S2K algorithms are now SHA1 and CAST5 - this
+ should solve a lot of compatibility problems with other OpenPGP
+ apps because those algorithms are SHOULD and not optional. The old
+ way to force it was by using the --openpgp option whith the drawback
+ that this would disable a couple of workarounds for PGP.
+
+ * gpg.c: New option --merge-only. Suggested by Brendan O'Dea.
+ * import.c (import_one): Implemented it here.
+ (import_secret_one): Ditto.
+ (print_stats): and give some stats.
+
+ * gpg.c: New option --try-all-secrets on suggestion from
+ Matthias Urlichs.
+ * pubkey-enc.c (get_session_key): Quite easy to implement here.
+
Mon Aug 21 17:59:17 CEST 2000 Werner Koch <wk@openit.de>
* gpg.c: New option --use-agent
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 878158917..7291f74b2 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -701,6 +701,7 @@ build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
case SIGSUBPKT_NOTATION:
case SIGSUBPKT_POLICY:
case SIGSUBPKT_REVOC_REASON:
+ case SIGSUBPKT_KEY_FLAGS:
hashed = 1; break;
default: hashed = 0; break;
}
diff --git a/g10/encode.c b/g10/encode.c
index a0048379f..a817f9094 100644
--- a/g10/encode.c
+++ b/g10/encode.c
@@ -220,6 +220,10 @@ encode_simple( const char *filename, int mode )
if( filename && !opt.textmode && !mode ) {
if( !(filesize = iobuf_get_filelength(inp)) )
log_info(_("%s: WARNING: empty file\n"), filename );
+ /* we can't yet encode the length of very large files,
+ * so we switch to partial length encoding in this case */
+ if ( filesize >= IOBUF_FILELENGTH_LIMIT )
+ filesize = 0;
}
else
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
@@ -368,6 +372,10 @@ encode_crypt( const char *filename, STRLIST remusr )
if( filename && !opt.textmode ) {
if( !(filesize = iobuf_get_filelength(inp)) )
log_info(_("%s: WARNING: empty file\n"), filename );
+ /* we can't yet encode the length of very large files,
+ * so we switch to partial lengthn encoding in this case */
+ if ( filesize >= IOBUF_FILELENGTH_LIMIT )
+ filesize = 0;
}
else
filesize = opt.set_filesize ? opt.set_filesize : 0; /* stdin */
diff --git a/g10/free-packet.c b/g10/free-packet.c
index 1d9aacff6..2cc4e25e9 100644
--- a/g10/free-packet.c
+++ b/g10/free-packet.c
@@ -139,6 +139,32 @@ copy_public_key( PKT_public_key *d, PKT_public_key *s )
return copy_public_key_new_namehash( d, s, NULL );
}
+
+/****************
+ * Replace all common parts of a sk by the one from the public key.
+ * This is a hack and a better solution will be to just store the real secret
+ * parts somewhere and don't duplicate all the other stuff.
+ */
+void
+copy_public_parts_to_secret_key( PKT_public_key *pk, PKT_secret_key *sk )
+{
+ sk->expiredate = pk->expiredate;
+ sk->pubkey_algo = pk->pubkey_algo;
+ sk->pubkey_usage= pk->pubkey_usage;
+ sk->created = pk->created;
+ sk->req_usage = pk->req_usage;
+ sk->req_algo = pk->req_algo;
+ sk->has_expired = pk->has_expired;
+ sk->is_revoked = pk->is_revoked;
+ sk->is_valid = pk->is_valid;
+ sk->main_keyid[0]= pk->main_keyid[0];
+ sk->main_keyid[1]= pk->main_keyid[1];
+ sk->keyid[0] = pk->keyid[0];
+ sk->keyid[1] = pk->keyid[1];
+}
+
+
+
PKT_signature *
copy_signature( PKT_signature *d, PKT_signature *s )
{
@@ -450,3 +476,7 @@ cmp_user_ids( PKT_user_id *a, PKT_user_id *b )
}
+
+
+
+
diff --git a/g10/getkey.c b/g10/getkey.c
index e9b4a231a..17dc6fafb 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -35,9 +35,12 @@
#include "trustdb.h"
#include "i18n.h"
+
+#if 0
#define MAX_UNK_CACHE_ENTRIES 1000 /* we use a linked list - so I guess
* this is a reasonable limit */
#define MAX_PK_CACHE_ENTRIES 50
+#endif
#define MAX_UID_CACHE_ENTRIES 50
/* A map of the all characters valid used for word_match()
@@ -99,7 +102,10 @@ struct getkey_ctx_s {
int primary;
KBNODE keyblock;
KBPOS kbpos;
+ KBNODE found_key; /* pointer into some keyblock */
int last_rc;
+ int req_usage;
+ int req_algo;
ulong count;
int not_allocated;
int nitems;
@@ -119,13 +125,13 @@ static struct {
} lkup_stats[21];
#endif
+typedef struct keyid_list {
+ struct keyid_list *next;
+ u32 keyid[2];
+} *keyid_list_t;
#if MAX_UNK_CACHE_ENTRIES
- typedef struct keyid_list {
- struct keyid_list *next;
- u32 keyid[2];
- } *keyid_list_t;
static keyid_list_t unknown_keyids;
static int unk_cache_entries; /* number of entries in unknown keys cache */
static int unk_cache_disabled;
@@ -147,7 +153,7 @@ static struct {
#endif
typedef struct user_id_db {
struct user_id_db *next;
- u32 keyid[2];
+ keyid_list_t keyids;
int len;
char name[1];
} *user_id_db_t;
@@ -157,9 +163,7 @@ static int uid_cache_entries; /* number of entries in uid cache */
static char* prepare_word_match( const byte *name );
-static int lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_kb );
-static int lookup_sk( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_kb );
-static u32 subkeys_expiretime( KBNODE node, u32 *mainkid );
+static int lookup( GETKEY_CTX ctx, KBNODE *ret_kb, int secmode );
#if 0
@@ -222,34 +226,96 @@ cache_public_key( PKT_public_key *pk )
#endif
}
+/*
+ * Return the user ID from the given keyblock.
+ * We use the primary uid flag which has been set by the merge_selfsigs
+ * function. The returned value is only valid as long as then given
+ * keyblock is not changed
+ */
+static const char *
+get_primary_uid ( KBNODE keyblock, size_t *uidlen )
+{
+ KBNODE k;
+
+ for (k=keyblock; k; k=k->next ) {
+ if ( k->pkt->pkttype == PKT_USER_ID
+ && k->pkt->pkt.user_id->is_primary ) {
+ *uidlen = k->pkt->pkt.user_id->len;
+ return k->pkt->pkt.user_id->name;
+ }
+ }
+ *uidlen = 12;
+ return "[No user ID]";
+}
+
+
+static void
+release_keyid_list ( keyid_list_t k )
+{
+ while ( k ) {
+ keyid_list_t k2 = k->next;
+ gcry_free (k);
+ k = k2;
+ }
+}
/****************
* Store the association of keyid and userid
+ * Feed only public keys to this function.
*/
void
-cache_user_id( PKT_user_id *uid, u32 *keyid )
+cache_user_id( KBNODE keyblock )
{
user_id_db_t r;
+ const char *uid;
+ size_t uidlen;
+ keyid_list_t keyids = NULL;
+ KBNODE k;
- for(r=user_id_db; r; r = r->next )
- if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
- if( DBG_CACHE )
- log_debug("cache_user_id: already in cache\n");
- return;
- }
+ for (k=keyblock; k; k = k->next ) {
+ if ( k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+ keyid_list_t a = gcry_xcalloc ( 1, sizeof *a );
+ /* Hmmm: For a long list of keyids it might be an advantage
+ * to append the keys */
+ keyid_from_pk( k->pkt->pkt.public_key, a->keyid );
+ /* first check for duplicates */
+ for(r=user_id_db; r; r = r->next ) {
+ keyid_list_t b = r->keyids;
+ for ( b = r->keyids; b; b = b->next ) {
+ if( b->keyid[0] == a->keyid[0]
+ && b->keyid[1] == a->keyid[1] ) {
+ if( DBG_CACHE )
+ log_debug("cache_user_id: already in cache\n");
+ release_keyid_list ( keyids );
+ gcry_free ( a );
+ return;
+ }
+ }
+ }
+ /* now put it into the cache */
+ a->next = keyids;
+ keyids = a;
+ }
+ }
+ if ( !keyids )
+ BUG (); /* No key no fun */
+
+
+ uid = get_primary_uid ( keyblock, &uidlen );
if( uid_cache_entries >= MAX_UID_CACHE_ENTRIES ) {
/* fixme: use another algorithm to free some cache slots */
r = user_id_db;
user_id_db = r->next;
+ release_keyid_list ( r->keyids );
gcry_free(r);
uid_cache_entries--;
}
- r = gcry_xmalloc( sizeof *r + uid->len-1 );
- r->keyid[0] = keyid[0];
- r->keyid[1] = keyid[1];
- r->len = uid->len;
- memcpy(r->name, uid->name, r->len);
+ r = gcry_xmalloc( sizeof *r + uidlen-1 );
+ r->keyids = keyids;
+ r->len = uidlen;
+ memcpy(r->name, uid, r->len);
r->next = user_id_db;
user_id_db = r;
uid_cache_entries++;
@@ -288,6 +354,31 @@ getkey_disable_caches()
}
+static void
+pk_from_block ( GETKEY_CTX ctx,
+ PKT_public_key *pk, KBNODE keyblock, const char *namehash )
+{
+ KBNODE a = ctx->found_key ? ctx->found_key : keyblock;
+
+ assert ( a->pkt->pkttype == PKT_PUBLIC_KEY
+ || a->pkt->pkttype == PKT_PUBLIC_SUBKEY );
+
+ copy_public_key_new_namehash( pk, a->pkt->pkt.public_key, namehash);
+}
+
+static void
+sk_from_block ( GETKEY_CTX ctx,
+ PKT_secret_key *sk, KBNODE keyblock )
+{
+ KBNODE a = ctx->found_key ? ctx->found_key : keyblock;
+
+ assert ( a->pkt->pkttype == PKT_SECRET_KEY
+ || a->pkt->pkttype == PKT_SECRET_SUBKEY );
+
+ copy_secret_key( sk, a->pkt->pkt.secret_key);
+}
+
+
/****************
* Get a public key and store it into the allocated pk
* can be called with PK set to NULL to just read it into some
@@ -329,14 +420,21 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
/* do a lookup */
{ struct getkey_ctx_s ctx;
+ KBNODE kb = NULL;
memset( &ctx, 0, sizeof ctx );
ctx.not_allocated = 1;
ctx.nitems = 1;
ctx.items[0].mode = 11;
ctx.items[0].keyid[0] = keyid[0];
ctx.items[0].keyid[1] = keyid[1];
- rc = lookup_pk( &ctx, pk, NULL );
+ ctx.req_algo = pk->req_algo;
+ ctx.req_usage = pk->req_usage;
+ rc = lookup( &ctx, &kb, 0 );
+ if ( !rc ) {
+ pk_from_block ( &ctx, pk, kb, NULL );
+ }
get_pubkey_end( &ctx );
+ release_kbnode ( kb );
}
if( !rc )
goto leave;
@@ -374,7 +472,6 @@ get_pubkey( PKT_public_key *pk, u32 *keyid )
KBNODE
get_pubkeyblock( u32 *keyid )
{
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
struct getkey_ctx_s ctx;
int rc = 0;
KBNODE keyblock = NULL;
@@ -385,8 +482,7 @@ get_pubkeyblock( u32 *keyid )
ctx.items[0].mode = 11;
ctx.items[0].keyid[0] = keyid[0];
ctx.items[0].keyid[1] = keyid[1];
- rc = lookup_pk( &ctx, pk, &keyblock );
- free_public_key(pk);
+ rc = lookup( &ctx, &keyblock, 0 );
get_pubkey_end( &ctx );
return rc ? NULL : keyblock;
@@ -403,6 +499,7 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
{
int rc;
struct getkey_ctx_s ctx;
+ KBNODE kb = NULL;
memset( &ctx, 0, sizeof ctx );
ctx.not_allocated = 1;
@@ -410,8 +507,15 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
ctx.items[0].mode = 11;
ctx.items[0].keyid[0] = keyid[0];
ctx.items[0].keyid[1] = keyid[1];
- rc = lookup_sk( &ctx, sk, NULL );
+ ctx.req_algo = sk->req_algo;
+ ctx.req_usage = sk->req_usage;
+ rc = lookup( &ctx, &kb, 1 );
+ if ( !rc ) {
+ sk_from_block ( &ctx, sk, kb );
+ }
get_seckey_end( &ctx );
+ release_kbnode ( kb );
+
if( !rc ) {
/* check the secret key (this may prompt for a passprase to
* unlock the secret key
@@ -424,30 +528,6 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
/****************
- * Get the primary secret key and store it into sk
- * Note: This function does not unprotect the key!
- */
-int
-get_primary_seckey( PKT_secret_key *sk, u32 *keyid )
-{
- struct getkey_ctx_s ctx;
- int rc;
-
- memset( &ctx, 0, sizeof ctx );
- ctx.not_allocated = 1;
- ctx.primary = 1;
- ctx.nitems = 1;
- ctx.items[0].mode = 11;
- ctx.items[0].keyid[0] = keyid[0];
- ctx.items[0].keyid[1] = keyid[1];
- rc = lookup_sk( &ctx, sk, NULL );
- get_seckey_end( &ctx );
- return rc;
-}
-
-
-
-/****************
* Check whether the secret key is available
* Returns: 0 := key is available
* GPGERR_NO_SECKEY := not availabe
@@ -457,18 +537,17 @@ seckey_available( u32 *keyid )
{
int rc;
struct getkey_ctx_s ctx;
- PKT_secret_key *sk;
+ KBNODE kb = NULL;
- sk = gcry_xcalloc( 1, sizeof *sk );
memset( &ctx, 0, sizeof ctx );
ctx.not_allocated = 1;
ctx.nitems = 1;
ctx.items[0].mode = 11;
ctx.items[0].keyid[0] = keyid[0];
ctx.items[0].keyid[1] = keyid[1];
- rc = lookup_sk( &ctx, sk, NULL );
+ rc = lookup( &ctx, &kb, 1 );
get_seckey_end( &ctx );
- free_secret_key( sk );
+ release_kbnode ( kb );
return rc;
}
@@ -612,7 +691,8 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
hexlength = 0; /* a hex number, but really were not. */
}
- if (hexlength == 8 || (!hexprefix && hexlength == 9 && *s == '0')){
+ if (hexlength == 8
+ || (!hexprefix && hexlength == 9 && *s == '0')){
/* short keyid */
if (hexlength == 9)
s++;
@@ -622,8 +702,8 @@ classify_user_id( const char *name, u32 *keyid, byte *fprint,
}
mode = 10;
}
- else if (hexlength == 16 || (!hexprefix && hexlength == 17
- && *s == '0')) {
+ else if (hexlength == 16
+ || (!hexprefix && hexlength == 17 && *s == '0')) {
/* complete keyid */
char buf[9];
if (hexlength == 17)
@@ -701,10 +781,10 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
int n;
STRLIST r;
GETKEY_CTX ctx;
-
+ KBNODE help_kb = NULL;
+
if( retctx ) /* reset the returned context in case of error */
*retctx = NULL;
- assert( !pk ^ !sk );
/* build the search context */
/* Performance hint: Use a static buffer if there is only one name */
@@ -732,10 +812,25 @@ key_byname( GETKEY_CTX *retctx, STRLIST namelist,
/* and call the lookup function */
ctx->primary = 1; /* we want to look for the primary key only */
- if( sk )
- rc = lookup_sk( ctx, sk, ret_kb );
- else
- rc = lookup_pk( ctx, pk, ret_kb );
+
+ if ( !ret_kb )
+ ret_kb = &help_kb;
+
+ if( sk ) {
+ rc = lookup( ctx, ret_kb, 1 );
+ if ( !rc && sk ) {
+ sk_from_block ( ctx, sk, *ret_kb );
+ }
+ }
+ else {
+
+ rc = lookup( ctx, ret_kb, 0 );
+ if ( !rc && pk ) {
+ pk_from_block ( ctx, pk, *ret_kb, NULL /* FIXME need to get the namehash*/ );
+ }
+ }
+
+ release_kbnode ( help_kb );
if( retctx ) /* caller wants the context */
*retctx = ctx;
@@ -758,16 +853,7 @@ get_pubkey_byname( GETKEY_CTX *retctx, PKT_public_key *pk,
STRLIST namelist = NULL;
add_to_strlist( &namelist, name );
-
- if( !pk ) {
- /* Performance Hint: key_byname should not need a pk here */
- pk = gcry_xcalloc( 1, sizeof *pk );
- rc = key_byname( retctx, namelist, pk, NULL, ret_keyblock );
- free_public_key( pk );
- }
- else
- rc = key_byname( retctx, namelist, pk, NULL, ret_keyblock );
-
+ rc = key_byname( retctx, namelist, pk, NULL, ret_keyblock );
free_strlist( namelist );
return rc;
}
@@ -776,18 +862,7 @@ int
get_pubkey_bynames( GETKEY_CTX *retctx, PKT_public_key *pk,
STRLIST names, KBNODE *ret_keyblock )
{
- int rc;
-
- if( !pk ) {
- /* Performance Hint: key_byname should not need a pk here */
- pk = gcry_xcalloc( 1, sizeof *pk );
- rc = key_byname( retctx, names, pk, NULL, ret_keyblock );
- free_public_key( pk );
- }
- else
- rc = key_byname( retctx, names, pk, NULL, ret_keyblock );
-
- return rc;
+ return key_byname( retctx, names, pk, NULL, ret_keyblock );
}
int
@@ -795,14 +870,10 @@ get_pubkey_next( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
{
int rc;
- if( !pk ) {
- /* Performance Hint: lookup_read should not need a pk in this case */
- pk = gcry_xcalloc( 1, sizeof *pk );
- rc = lookup_pk( ctx, pk, ret_keyblock );
- free_public_key( pk );
- }
- else
- rc = lookup_pk( ctx, pk, ret_keyblock );
+ rc = lookup( ctx, ret_keyblock, 0 );
+ if ( !rc && pk && ret_keyblock )
+ pk_from_block ( ctx, pk, *ret_keyblock, NULL );
+
return rc;
}
@@ -824,18 +895,24 @@ get_pubkey_end( GETKEY_CTX ctx )
* Search for a key with the given fingerprint.
*/
int
-get_pubkey_byfprint( PKT_public_key *pk, const byte *fprint, size_t fprint_len)
+get_pubkey_byfprint( PKT_public_key *pk,
+ const byte *fprint, size_t fprint_len)
{
int rc;
if( fprint_len == 20 || fprint_len == 16 ) {
struct getkey_ctx_s ctx;
+ KBNODE kb = NULL;
+
memset( &ctx, 0, sizeof ctx );
ctx.not_allocated = 1;
ctx.nitems = 1;
ctx.items[0].mode = fprint_len;
memcpy( ctx.items[0].fprint, fprint, fprint_len );
- rc = lookup_pk( &ctx, pk, NULL );
+ rc = lookup( &ctx, &kb, 0 );
+ if (!rc && pk )
+ pk_from_block ( &ctx, pk, kb, NULL );
+ release_kbnode ( kb );
get_pubkey_end( &ctx );
}
else
@@ -852,35 +929,33 @@ get_keyblock_byfprint( KBNODE *ret_keyblock, const byte *fprint,
size_t fprint_len )
{
int rc;
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
if( fprint_len == 20 || fprint_len == 16 ) {
struct getkey_ctx_s ctx;
+
memset( &ctx, 0, sizeof ctx );
ctx.not_allocated = 1;
ctx.nitems = 1;
ctx.items[0].mode = fprint_len;
memcpy( ctx.items[0].fprint, fprint, fprint_len );
- rc = lookup_pk( &ctx, pk, ret_keyblock );
+ rc = lookup( &ctx, ret_keyblock, 0 );
get_pubkey_end( &ctx );
}
else
rc = GPGERR_GENERAL; /* Oops */
- free_public_key( pk );
return rc;
}
/****************
- * Search for a key with the given lid and return the complete keyblock
+ * Search for a key with the given lid and return the entire keyblock
*/
int
get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid )
{
int rc;
- PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
struct getkey_ctx_s ctx;
u32 kid[2];
@@ -892,10 +967,9 @@ get_keyblock_bylid( KBNODE *ret_keyblock, ulong lid )
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 );
+ rc = lookup( &ctx, ret_keyblock, 0 );
get_pubkey_end( &ctx );
- free_public_key( pk );
return rc;
}
@@ -919,13 +993,17 @@ get_seckey_byname( PKT_secret_key *sk, const char *name, int unprotect )
}
else if( !name ) { /* use the first one as default key */
struct getkey_ctx_s ctx;
+ KBNODE kb = NULL;
memset( &ctx, 0, sizeof ctx );
ctx.not_allocated = 1;
ctx.primary = 1;
ctx.nitems = 1;
ctx.items[0].mode = 15;
- rc = lookup_sk( &ctx, sk, NULL );
+ rc = lookup( &ctx, &kb, 1 );
+ if (!rc && sk )
+ sk_from_block ( &ctx, sk, kb );
+ release_kbnode ( kb );
get_seckey_end( &ctx );
}
else {
@@ -945,18 +1023,7 @@ int
get_seckey_bynames( GETKEY_CTX *retctx, PKT_secret_key *sk,
STRLIST names, KBNODE *ret_keyblock )
{
- int rc;
-
- if( !sk ) {
- /* Performance Hint: key_byname should not need a sk here */
- sk = gcry_xcalloc_secure( 1, sizeof *sk );
- rc = key_byname( retctx, names, NULL, sk, ret_keyblock );
- free_secret_key( sk );
- }
- else
- rc = key_byname( retctx, names, NULL, sk, ret_keyblock );
-
- return rc;
+ return key_byname( retctx, names, NULL, sk, ret_keyblock );
}
@@ -965,32 +1032,24 @@ get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock )
{
int rc;
- if( !sk ) {
- /* Performance Hint: lookup_read should not need a pk in this case */
- sk = gcry_xcalloc_secure( 1, sizeof *sk );
- rc = lookup_sk( ctx, sk, ret_keyblock );
- free_secret_key( sk );
- }
- else
- rc = lookup_sk( ctx, sk, ret_keyblock );
+ rc = lookup( ctx, ret_keyblock, 1 );
+ if ( !rc && sk && ret_keyblock )
+ sk_from_block ( ctx, sk, *ret_keyblock );
+
return rc;
}
void
get_seckey_end( GETKEY_CTX ctx )
{
- if( ctx ) {
- int n;
-
- enum_keyblocks( 2, &ctx->kbpos, NULL ); /* close */
- for(n=0; n < ctx->nitems; n++ )
- gcry_free( ctx->items[n].namebuf );
- if( !ctx->not_allocated )
- gcry_free( ctx );
- }
+ get_pubkey_end( ctx );
}
+
+/*******************************************************
+ ************** compare functions **********************
+ *******************************************************/
/****************
* Do a word match (original user id starts with a '+').
@@ -1130,73 +1189,15 @@ compare_name( const char *uid, size_t uidlen, const char *name, int mode )
-/****************
- * Assume that knode points to a public key packet and keyblock is
- * the entire keyblock. This function adds all relevant information from
- * a selfsignature to the public key.
- */
-
-static void
-merge_one_pk_and_selfsig( KBNODE keyblock, KBNODE knode,
- PKT_public_key *orig_pk )
-{
- PKT_public_key *pk = knode->pkt->pkt.public_key;
- PKT_signature *sig;
- KBNODE k;
- u32 kid[2];
- u32 sigdate = 0;
-
- assert( knode->pkt->pkttype == PKT_PUBLIC_KEY
- || knode->pkt->pkttype == PKT_PUBLIC_SUBKEY );
-
- if( pk->version < 4 )
- return; /* this is only needed for version >=4 packets */
-
-
- /* find the selfsignature */
- if( knode->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- k = find_kbnode( keyblock, PKT_PUBLIC_KEY );
- if( !k )
- BUG(); /* keyblock without primary key!!! */
- keyid_from_pk( k->pkt->pkt.public_key, kid );
- }
- else
- keyid_from_pk( pk, kid );
-
- for(k=knode->next; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_SIGNATURE
- && (sig=k->pkt->pkt.signature)->sig_class >= 0x10
- && sig->sig_class <= 0x30
- && sig->keyid[0] == kid[0]
- && sig->keyid[1] == kid[1]
- && sig->version > 3 ) {
- /* okay this is a self-signature which can be used.
- * We use the latest self-signature.
- * FIXME: We should only use this if the signature is valid
- * but this is time consuming - we must provide another
- * way to handle this
- */
- const byte *p;
- u32 ed;
-
- p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL );
- ed = p? pk->timestamp + buffer_to_u32(p):0;
- /* use the latest self signature */
- if( sig->timestamp > sigdate ) {
- pk->expiredate = ed;
- orig_pk->expiredate = ed;
- sigdate = sig->timestamp;
- }
- /* fixme: add usage etc. to pk */
- }
- else if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* stop here */
- }
-}
-
+
+/************************************************
+ ************* Merging stuff ********************
+ ************************************************/
/****************
* merge all selfsignatures with the keys.
+ * FIXME: replace this at least for the public key parts
+ * by merge_selfsigs
*/
void
merge_keys_and_selfsig( KBNODE keyblock )
@@ -1218,7 +1219,7 @@ merge_keys_and_selfsig( KBNODE keyblock )
keyid_from_pk( pk, kid );
else if( !pk->expiredate ) { /* and subkey */
/* insert the expiration date here */
- pk->expiredate = subkeys_expiretime( k, kid );
+ /*FIXME!!! pk->expiredate = subkeys_expiretime( k, kid );*/
}
sigdate = 0;
}
@@ -1266,510 +1267,850 @@ merge_keys_and_selfsig( KBNODE keyblock )
}
-static KBNODE
-find_by_name( KBNODE keyblock, PKT_public_key *pk, const char *name,
- int mode, byte *namehash, int *use_namehash )
+static void
+fixup_uidnode ( KBNODE uidnode, KBNODE signode )
{
- KBNODE k, kk;
+ PKT_user_id *uid = uidnode->pkt->pkt.user_id;
+ PKT_signature *sig = signode->pkt->pkt.signature;
+ const byte *p;
+ size_t n;
+
+ uid->created = 0; /* not created == invalid */
+ if ( !signode )
+ return; /* no self-signature */
+ if ( IS_UID_REV ( sig ) )
+ return; /* has been revoked */
+
+ uid->created = sig->timestamp; /* this one is okay */
+
+
+ /* store the key flags in the helper variable for later processing */
+ uid->help_key_usage = 0;
+ p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_FLAGS, &n );
+ if ( p && n ) {
+ /* first octet of the keyflags */
+ if ( (*p & 3) )
+ uid->help_key_usage |= GCRY_PK_USAGE_SIGN;
+ if ( (*p & 12) )
+ uid->help_key_usage |= GCRY_PK_USAGE_ENCR;
+ }
- for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_USER_ID
- && !compare_name( k->pkt->pkt.user_id->name,
- k->pkt->pkt.user_id->len, name, mode)) {
- /* we found a matching name, look for the key */
- for(kk=keyblock; kk; kk = kk->next ) {
- if( ( kk->pkt->pkttype == PKT_PUBLIC_KEY
- || kk->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- && ( !pk->pubkey_algo
- || pk->pubkey_algo
- == kk->pkt->pkt.public_key->pubkey_algo)
- && ( !pk->pubkey_usage
- || !openpgp_pk_test_algo(
- kk->pkt->pkt.public_key->pubkey_algo,
- pk->pubkey_usage ))
- )
- break;
- }
- if( kk ) {
- u32 aki[2];
- keyid_from_pk( kk->pkt->pkt.public_key, aki );
- cache_user_id( k->pkt->pkt.user_id, aki );
- if( k->pkt->pkt.user_id->photo ) {
- gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
- k->pkt->pkt.user_id->photo,
- k->pkt->pkt.user_id->photolen );
- }
- else {
- gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
- k->pkt->pkt.user_id->name,
- k->pkt->pkt.user_id->len );
- }
- *use_namehash = 1;
- return kk;
- }
- else if( is_RSA(pk->pubkey_algo) )
- log_error(_("RSA key cannot be used in this version\n"));
- else
- log_error(_("No key for user ID\n"));
- }
+ /* ditto or the key expiration */
+ uid->help_key_expire = 0;
+ p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL);
+ if ( p ) {
+ uid->help_key_expire = sig->timestamp + buffer_to_u32(p);
}
- return NULL;
+
+ /* Set the primary user ID flag - we will later wipe out some
+ * of them to only have one in out keyblock */
+ uid->is_primary = 0;
+ p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_PRIMARY_UID, NULL );
+ if ( p && *p )
+ uid->is_primary = 1;
+ /* We could also query this from the unhashed area if it is not in
+ * the hased area and then later try to decide which is the better
+ * there should be no security problem with this.
+ * For now we only look at the hashed one.
+ */
}
-static KBNODE
-find_by_name_sk( KBNODE keyblock, PKT_secret_key *sk, const char *name,
- int mode )
+static void
+merge_selfsigs_main( KBNODE keyblock, int *r_revoked )
{
- KBNODE k, kk;
+ PKT_public_key *pk = NULL;
+ KBNODE k;
+ u32 kid[2];
+ u32 sigdate = 0, uiddate=0, uiddate2;
+ KBNODE signode, uidnode, uidnode2;
+ u32 curtime = make_timestamp ();
+ unsigned int key_usage = 0;
+ u32 key_expire = 0;
+ int key_expire_seen = 0;
+
+ *r_revoked = 0;
+ if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY )
+ BUG ();
+ pk = keyblock->pkt->pkt.public_key;
+ pk->created = 0;
+ keyid_from_pk( pk, kid );
+ pk->main_keyid[0] = kid[0];
+ pk->main_keyid[1] = kid[1];
+
+ if ( pk->version < 4 )
+ return; /* nothing to do for old keys FIXME: This is wrong!!!!*/
+
+ /* first pass: find the latest direct key self-signature.
+ * We assume that the newest one overrides all others
+ */
+ signode = NULL;
+ sigdate = 0; /* helper to find the latest signature */
+ for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next ) {
+ if ( k->pkt->pkttype == PKT_SIGNATURE ) {
+ PKT_signature *sig = k->pkt->pkt.signature;
+ if ( sig->keyid[0] == kid[0] && sig->keyid[1]==kid[1] ) {
+ if ( check_key_signature( keyblock, k, NULL ) )
+ ; /* signature did not verify */
+ else if ( IS_KEY_REV (sig) ){
+ /* key has been revoked - there is no way to override
+ * such a revocation, so we can stop now.
+ * we can't cope with expiration times for revocations
+ * here because we have to assumethat an attacker can
+ * generate all kinds of signatures.
+ */
+ *r_revoked = 1;
+ return;
+ }
+ else if ( IS_KEY_SIG (sig) && sig->timestamp >= sigdate ) {
+ const byte *p;
+
+ p = parse_sig_subpkt( sig->hashed_data,
+ SIGSUBPKT_SIG_EXPIRE, NULL );
+ if ( p && (sig->timestamp + buffer_to_u32(p)) >= curtime )
+ ; /* signature has expired - ignore it */
+ else {
+ sigdate = sig->timestamp;
+ signode = k;
+ }
+ }
+ }
+ }
+ }
- for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_USER_ID
- && !compare_name( k->pkt->pkt.user_id->name,
- k->pkt->pkt.user_id->len, name, mode)) {
- /* we found a matching name, look for the key */
- for(kk=keyblock; kk; kk = kk->next ) {
- if( ( kk->pkt->pkttype == PKT_SECRET_KEY
- || kk->pkt->pkttype == PKT_SECRET_SUBKEY )
- && ( !sk->pubkey_algo
- || sk->pubkey_algo
- == kk->pkt->pkt.secret_key->pubkey_algo)
- && ( !sk->pubkey_usage
- || !openpgp_pk_test_algo(
- kk->pkt->pkt.secret_key->pubkey_algo,
- sk->pubkey_usage ))
- )
- break;
- }
- if( kk ) {
- u32 aki[2];
- keyid_from_sk( kk->pkt->pkt.secret_key, aki );
- cache_user_id( k->pkt->pkt.user_id, aki );
- return kk;
- }
- else if( is_RSA(sk->pubkey_algo) )
- log_error(_("RSA key cannot be used in this version\n"));
- else
- log_error(_("No key for user ID\n"));
- }
+ if ( signode ) {
+ /* some information from a direct key signature take precedence
+ * over the same information given in UID sigs.
+ */
+ PKT_signature *sig = signode->pkt->pkt.signature;
+ const byte *p;
+ size_t n;
+
+ p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_FLAGS, &n );
+ if ( p && n ) {
+ /* first octet of the keyflags */
+ if ( (*p & 3) )
+ key_usage |= GCRY_PK_USAGE_SIGN;
+ if ( (*p & 12) )
+ key_usage |= GCRY_PK_USAGE_ENCR;
+ }
+
+ p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL);
+ if ( p ) {
+ key_expire = sig->timestamp + buffer_to_u32(p);
+ key_expire_seen = 1;
+ }
+
+ /* and set the created field */
+ pk->created = sigdate;
+ /* and mark that key as valid: one direct key signature should
+ * render a key as valid */
+ pk->is_valid = 1;
}
- return NULL;
+
+
+ /* second pass: look at the self-signature of all user IDs */
+ signode = uidnode = NULL;
+ sigdate = 0; /* helper to find the latest signature in one user ID */
+ uiddate = 0; /* and over of all user IDs */
+ for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next ) {
+ if ( k->pkt->pkttype == PKT_USER_ID
+ || k->pkt->pkttype == PKT_PHOTO_ID ) {
+ if ( uidnode )
+ fixup_uidnode ( uidnode, signode );
+ uidnode = k;
+ signode = NULL;
+ if ( sigdate > uiddate )
+ uiddate = sigdate;
+ sigdate = 0;
+ }
+ else if ( k->pkt->pkttype == PKT_SIGNATURE && uidnode ) {
+ PKT_signature *sig = k->pkt->pkt.signature;
+ if ( sig->keyid[0] == kid[0] && sig->keyid[1]==kid[1] ) {
+ if ( check_key_signature( keyblock, k, NULL ) )
+ ; /* signature did not verify */
+ else if ( IS_UID_SIG (sig) || IS_UID_REV (sig)) {
+ /* Note: we allow to invalidated cert revocations
+ * by a newer signature. An attacker can't use this
+ * because a key should be revoced with a key revocation.
+ * The reason why we have to allow for that is that at
+ * one time an email address may become invalid but later
+ * the same email address may become valid again (hired,
+ * fired, hired again).
+ */
+ const byte *p;
+
+ p = parse_sig_subpkt( sig->hashed_data,
+ SIGSUBPKT_SIG_EXPIRE, NULL );
+ if ( p && (sig->timestamp + buffer_to_u32(p)) >= curtime )
+ ; /* signature/revocation has expired - ignore it */
+ else {
+ sigdate = sig->timestamp;
+ signode = k;
+ }
+ }
+ }
+ }
+ }
+ if ( uidnode ) {
+ fixup_uidnode ( uidnode, signode );
+ pk->is_valid = 1;
+ }
+ if ( sigdate > uiddate )
+ uiddate = sigdate;
+ /* if we do not have a direct key signature, take the key creation date
+ * from the latest user ID. Hmmm, another possibilty would be to take
+ * it from the latest primary user ID - but we don't implement it for
+ * now */
+ if ( !pk->created )
+ pk->created = uiddate;
+ if ( !pk->created ) {
+ /* oops, still no creation date: use the timestamp */
+ if (DBG_CACHE)
+ log_debug( "merge_selfsigs_main: "
+ "using timestamp as creation date\n");
+ pk->created = pk->timestamp;
+ }
+
+ /* Now that we had a look at all user IDs we can now get some information
+ * from those user IDs.
+ */
+
+ if ( !key_usage ) {
+ /* find the latest user ID with key flags set */
+ uiddate = 0; /* helper to find the latest user ID */
+ for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+ k = k->next ) {
+ if ( k->pkt->pkttype == PKT_USER_ID
+ || k->pkt->pkttype == PKT_PHOTO_ID ) {
+ PKT_user_id *uid = k->pkt->pkt.user_id;
+ if ( uid->help_key_usage && uid->created > uiddate ) {
+ key_usage = uid->help_key_usage;
+ uiddate = uid->created;
+ }
+ }
+ }
+ }
+ if ( !key_usage ) { /* no key flags at all: get it from the algo */
+ key_usage = openpgp_pk_algo_usage ( pk->pubkey_algo );
+ }
+ else { /* check that the usage matches the usage as given by the algo */
+ int x = openpgp_pk_algo_usage ( pk->pubkey_algo );
+ if ( x ) /* mask it down to the actual allowed usage */
+ key_usage &= x;
+ }
+ pk->pubkey_usage = key_usage;
+
+
+ if ( !key_expire_seen ) {
+ /* find the latest valid user ID with a key expiration set
+ * Note, that this may be a diferent one from the above because
+ * some user IDs may have no expiration date set */
+ uiddate = 0;
+ for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+ k = k->next ) {
+ if ( k->pkt->pkttype == PKT_USER_ID
+ || k->pkt->pkttype == PKT_PHOTO_ID ) {
+ PKT_user_id *uid = k->pkt->pkt.user_id;
+ if ( uid->help_key_expire && uid->created > uiddate ) {
+ key_expire = uid->help_key_expire;
+ uiddate = uid->created;
+ }
+ }
+ }
+ }
+ if ( key_expire >= curtime )
+ pk->has_expired = key_expire;
+ /* FIXME: we should see how to get rid of the expiretime fields */
+
+
+ /* and now find the real primary user ID and delete all others */
+ uiddate = uiddate2 = 0;
+ uidnode = uidnode2 = NULL;
+ for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next ) {
+ if ( k->pkt->pkttype == PKT_USER_ID
+ || k->pkt->pkttype == PKT_PHOTO_ID ) {
+ PKT_user_id *uid = k->pkt->pkt.user_id;
+ if ( uid->is_primary && uid->created > uiddate ) {
+ uiddate = uid->created;
+ uidnode = k;
+ }
+ if ( !uid->is_primary && uid->created > uiddate2 ) {
+ uiddate2 = uid->created;
+ uidnode2 = k;
+ }
+ }
+ }
+ if ( uidnode ) {
+ for(k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+ k = k->next ) {
+ if ( k->pkt->pkttype == PKT_USER_ID
+ || k->pkt->pkttype == PKT_PHOTO_ID ) {
+ PKT_user_id *uid = k->pkt->pkt.user_id;
+ if ( k != uidnode )
+ uid->is_primary = 0;
+ }
+ }
+ }
+ else if( uidnode2 ) {
+ /* none is flagged primary - use the latest user ID we have */
+ uidnode2->pkt->pkt.user_id->is_primary = 1;
+ }
+
}
-static KBNODE
-find_by_keyid( KBNODE keyblock, PKT_public_key *pk, u32 *keyid, int mode )
+static void
+merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode )
{
+ PKT_public_key *mainpk = NULL, *subpk = NULL;
+ PKT_signature *sig;
KBNODE k;
+ u32 mainkid[2];
+ u32 sigdate = 0;
+ KBNODE signode;
+ u32 curtime = make_timestamp ();
+ unsigned int key_usage = 0;
+ u32 key_expire = 0;
+ const byte *p;
+ size_t n;
+
+ if ( subnode->pkt->pkttype != PKT_PUBLIC_SUBKEY )
+ BUG ();
+ mainpk = keyblock->pkt->pkt.public_key;
+ if ( mainpk->version < 4 )
+ return; /* (actually this should never happen) */
+ keyid_from_pk( mainpk, mainkid );
+ subpk = subnode->pkt->pkt.public_key;
+ subpk->is_valid = 0;
+ subpk->main_keyid[0] = mainpk->main_keyid[0];
+ subpk->main_keyid[1] = mainpk->main_keyid[1];
+ if ( subpk->version < 4 )
+ return; /* there are no v3 subkeys */
+
+ /* find the latest key binding self-signature. */
+ signode = NULL;
+ sigdate = 0; /* helper to find the latest signature */
+ for(k=subnode->next; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY;
+ k = k->next ) {
+ if ( k->pkt->pkttype == PKT_SIGNATURE ) {
+ sig = k->pkt->pkt.signature;
+ if ( sig->keyid[0] == mainkid[0] && sig->keyid[1]==mainkid[1] ) {
+ if ( check_key_signature( keyblock, k, NULL ) )
+ ; /* signature did not verify */
+ else if ( IS_SUBKEY_REV (sig) ) {
+ /* key has been revoked - given the fact that it is easy
+ * to create a new subkey, it does not make sense to
+ * revive a revoked key. So we can stop here.
+ */
+ subpk->is_revoked = 1;
+ return;
+ }
+ else if ( IS_SUBKEY_SIG (sig) && sig->timestamp >= sigdate ) {
+ p = parse_sig_subpkt( sig->hashed_data,
+ SIGSUBPKT_SIG_EXPIRE, NULL );
+ if ( p && (sig->timestamp + buffer_to_u32(p)) >= curtime )
+ ; /* signature has expired - ignore it */
+ else {
+ sigdate = sig->timestamp;
+ signode = k;
+ }
+ }
+ }
+ }
+ }
- if( DBG_CACHE )
- log_debug("lookup keyid=%08lx%08lx req_algo=%d mode=%d\n",
- (ulong)keyid[0], (ulong)keyid[1], pk->pubkey_algo, mode );
+ if ( !signode ) {
+ subpk->created = subpk->timestamp;
+ return; /* no valid key binding */
+ }
- for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_PUBLIC_KEY
- || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- u32 aki[2];
- keyid_from_pk( k->pkt->pkt.public_key, aki );
- if( DBG_CACHE )
- log_debug(" aki=%08lx%08lx algo=%d\n",
- (ulong)aki[0], (ulong)aki[1],
- k->pkt->pkt.public_key->pubkey_algo );
-
- if( aki[1] == keyid[1]
- && ( mode == 10 || aki[0] == keyid[0] )
- && ( !pk->pubkey_algo
- || pk->pubkey_algo
- == k->pkt->pkt.public_key->pubkey_algo) ){
- KBNODE kk;
- /* cache the userid */
- for(kk=keyblock; kk; kk = kk->next )
- if( kk->pkt->pkttype == PKT_USER_ID )
- break;
- if( kk )
- cache_user_id( kk->pkt->pkt.user_id, aki );
- else
- log_error(_("No user ID for key\n"));
- return k; /* found */
- }
- }
+ subpk->is_valid = 1;
+ subpk->created = sigdate;
+ sig = signode->pkt->pkt.signature;
+
+ p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_FLAGS, &n );
+ if ( p && n ) {
+ /* first octet of the keyflags */
+ if ( (*p & 3) )
+ key_usage |= GCRY_PK_USAGE_SIGN;
+ if ( (*p & 12) )
+ key_usage |= GCRY_PK_USAGE_ENCR;
}
- return NULL;
+ if ( !key_usage ) { /* no key flags at all: get it from the algo */
+ key_usage = openpgp_pk_algo_usage ( subpk->pubkey_algo );
+ }
+ else { /* check that the usage matches the usage as given by the algo */
+ int x = openpgp_pk_algo_usage ( subpk->pubkey_algo );
+ if ( x ) /* mask it down to the actual allowed usage */
+ key_usage &= x;
+ }
+ subpk->pubkey_usage = key_usage;
+
+ p = parse_sig_subpkt ( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL);
+ if ( p )
+ key_expire = sig->timestamp + buffer_to_u32(p);
+ else
+ key_expire = 0;
+ subpk->has_expired = key_expire >= curtime? key_expire : 0;
}
-static KBNODE
-find_by_keyid_sk( KBNODE keyblock, PKT_secret_key *sk, u32 *keyid, int mode )
+
+
+/*
+ * Merge information from the self-signatures with the key, so that
+ * we can later use them more easy.
+ * The function works by first applying the self signatures to the
+ * primary key and the to each subkey.
+ * Here are the rules we use to decide which inormation from which
+ * self-signature is used:
+ * We check all self signatures or validity and ignore all invalid signatures.
+ * All signatures are then ordered by their creation date ....
+ * For the primary key:
+ * FIXME the docs
+ */
+static void
+merge_selfsigs( KBNODE keyblock )
{
KBNODE k;
+ int revoked;
+ PKT_public_key *main_pk;
+
+ if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY )
+ BUG ();
+
+ merge_selfsigs_main ( keyblock, &revoked );
+ main_pk = keyblock->pkt->pkt.public_key;
+ if ( revoked ) {
+ /* if the primary key has been revoked we better set the revoke
+ * flag on that key and all subkeys */
+ for(k=keyblock; k; k = k->next ) {
+ if ( k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+ PKT_public_key *pk = k->pkt->pkt.public_key;
+ pk->is_revoked = 1;
+ pk->main_keyid[0] = main_pk->main_keyid[0];
+ pk->main_keyid[1] = main_pk->main_keyid[1];
+ }
+ }
+ return;
+ }
- if( DBG_CACHE )
- log_debug("lookup_sk keyid=%08lx%08lx req_algo=%d mode=%d\n",
- (ulong)keyid[0], (ulong)keyid[1], sk->pubkey_algo, mode );
-
+ /* now merge in the data from each of the subkeys */
for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_SECRET_KEY
- || k->pkt->pkttype == PKT_SECRET_SUBKEY ) {
- u32 aki[2];
- keyid_from_sk( k->pkt->pkt.secret_key, aki );
- if( DBG_CACHE )
- log_debug(" aki=%08lx%08lx algo=%d\n",
- (ulong)aki[0], (ulong)aki[1],
- k->pkt->pkt.secret_key->pubkey_algo );
-
- if( aki[1] == keyid[1]
- && ( mode == 10 || aki[0] == keyid[0] )
- && ( !sk->pubkey_algo
- || sk->pubkey_algo
- == k->pkt->pkt.secret_key->pubkey_algo) ){
- KBNODE kk;
- /* cache the userid */
- for(kk=keyblock; kk; kk = kk->next )
- if( kk->pkt->pkttype == PKT_USER_ID )
- break;
- if( kk )
- cache_user_id( kk->pkt->pkt.user_id, aki );
- else
- log_error(_("No user ID for key\n"));
- return k; /* found */
- }
- }
+ if ( k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+ merge_selfsigs_subkey ( keyblock, k );
+ }
}
- return NULL;
}
-static KBNODE
-find_first( KBNODE keyblock, PKT_public_key *pk )
+/*
+ * Merge the secret keys from secblock into the pubblock thereby
+ * replacing the public (sub)keys with their secret counterparts Hmmm:
+ * It might be better to get away from the concept of entire secret
+ * keys at all and have a way to store just the real secret parts
+ * from the key.
+ */
+static void
+merge_public_with_secret ( KBNODE pubblock, KBNODE secblock )
{
- KBNODE k;
+ KBNODE pub;
+ int deleting = 0;
+ int any_deleted = 0;
+
+ assert ( pubblock->pkt->pkttype == PKT_PUBLIC_KEY );
+ assert ( secblock->pkt->pkttype == PKT_SECRET_KEY );
+
+ for (pub=pubblock; pub; pub = pub->next ) {
+ if ( pub->pkt->pkttype == PKT_PUBLIC_KEY ) {
+ PKT_public_key *pk = pub->pkt->pkt.public_key;
+ PKT_secret_key *sk = secblock->pkt->pkt.secret_key;
+ assert ( pub == pubblock ); /* only in the first node */
+ /* there is nothing to compare in this case, so just replace
+ * some information */
+ copy_public_parts_to_secret_key ( pk, sk );
+ free_public_key ( pk );
+ pub->pkt->pkttype = PKT_SECRET_KEY;
+ pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
+ }
+ else if ( pub->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
+ KBNODE sec;
+ PKT_public_key *pk = pub->pkt->pkt.public_key;
+
+ deleting = 0;
+ /* this is more complicated: it may happen that the sequence
+ * of the subkeys dosn't match, so we have to find the
+ * appropriate secret key */
+ for (sec=secblock->next; sec; sec = sec->next ) {
+ if ( sec->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+ PKT_secret_key *sk = sec->pkt->pkt.secret_key;
+ if ( !cmp_public_secret_key ( pk, sk ) ) {
+ copy_public_parts_to_secret_key ( pk, sk );
+ free_public_key ( pk );
+ pub->pkt->pkttype = PKT_SECRET_KEY;
+ pub->pkt->pkt.secret_key = copy_secret_key (NULL, sk);
+ break;
+ }
+ }
+ }
+ if ( !sec ) {
+ log_error ( "no corresponding secret subkey "
+ "for public subkey - removing\n" );
+ /* better remove the public subkey in this case */
+ delete_kbnode ( pub );
+ deleting = 1;
+ any_deleted = 1;
+ }
+ }
+ else if ( deleting ) {
+ delete_kbnode (pub);
+ }
+ }
- for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_PUBLIC_KEY
- || k->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- {
- if( !pk->pubkey_algo
- || pk->pubkey_algo == k->pkt->pkt.public_key->pubkey_algo )
- return k;
- }
+ if ( any_deleted ) {
+ /* because we have not deleted the root node, we don't need to
+ * update the pubblock */
+ pub = pubblock;
+ commit_kbnode ( &pubblock );
+ assert ( pub == pubblock );
}
- return NULL;
}
-static KBNODE
-find_first_sk( KBNODE keyblock, PKT_secret_key *sk )
+
+
+
+/************************************************
+ ************* Find stuff ***********************
+ ************************************************/
+
+static int
+find_by_name( KBNODE keyblock, const char *name,
+ int mode, byte *namehash )
{
KBNODE k;
for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_SECRET_KEY
- || k->pkt->pkttype == PKT_SECRET_SUBKEY )
- {
- if( !sk->pubkey_algo
- || sk->pubkey_algo == k->pkt->pkt.secret_key->pubkey_algo )
- return k;
- }
+ if( k->pkt->pkttype == PKT_USER_ID
+ && !compare_name( k->pkt->pkt.user_id->name,
+ k->pkt->pkt.user_id->len, name, mode)) {
+ /* we found a matching name, look for the key */
+ if( k->pkt->pkt.user_id->photo ) {
+ /* oops: this can never happen */
+ gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
+ k->pkt->pkt.user_id->photo,
+ k->pkt->pkt.user_id->photolen );
+ }
+ else {
+ gcry_md_hash_buffer( GCRY_MD_RMD160, namehash,
+ k->pkt->pkt.user_id->name,
+ k->pkt->pkt.user_id->len );
+ }
+ return 1;
+ }
}
- return NULL;
+
+ return 0;
}
+
static KBNODE
-find_by_fpr( KBNODE keyblock, PKT_public_key *pk, const char *name, int mode )
+find_by_keyid( KBNODE keyblock, u32 *keyid, int mode )
{
KBNODE k;
for(k=keyblock; k; k = k->next ) {
if( k->pkt->pkttype == PKT_PUBLIC_KEY
|| k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
- byte afp[MAX_FINGERPRINT_LEN];
- size_t an;
-
- fingerprint_from_pk(k->pkt->pkt.public_key, afp, &an );
-
- if( DBG_CACHE ) {
- u32 aki[2];
- keyid_from_pk( k->pkt->pkt.public_key, aki );
- log_debug(" aki=%08lx%08lx algo=%d mode=%d an=%u\n",
- (ulong)aki[0], (ulong)aki[1],
- k->pkt->pkt.public_key->pubkey_algo, mode,
- (unsigned)an );
+ u32 aki[2];
+ keyid_from_pk( k->pkt->pkt.public_key, aki );
+ if( aki[1] == keyid[1] && ( mode == 10 || aki[0] == keyid[0] ) ) {
+ return k; /* found */
}
-
- if( an == mode
- && !memcmp( afp, name, an)
- && ( !pk->pubkey_algo
- || pk->pubkey_algo == k->pkt->pkt.public_key->pubkey_algo) )
- return k;
}
}
return NULL;
}
+
+
static KBNODE
-find_by_fpr_sk( KBNODE keyblock, PKT_secret_key *sk,
- const char *name, int mode )
+find_by_fpr( KBNODE keyblock, const char *name, int mode )
{
KBNODE k;
for(k=keyblock; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_SECRET_KEY
- || k->pkt->pkttype == PKT_SECRET_SUBKEY ) {
+ if( k->pkt->pkttype == PKT_PUBLIC_KEY
+ || k->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
byte afp[MAX_FINGERPRINT_LEN];
size_t an;
- fingerprint_from_sk(k->pkt->pkt.secret_key, afp, &an );
-
- if( DBG_CACHE ) {
- u32 aki[2];
- keyid_from_sk( k->pkt->pkt.secret_key, aki );
- log_debug(" aki=%08lx%08lx algo=%d mode=%d an=%u\n",
- (ulong)aki[0], (ulong)aki[1],
- k->pkt->pkt.secret_key->pubkey_algo, mode,
- (unsigned)an );
- }
-
- if( an == mode
- && !memcmp( afp, name, an)
- && ( !sk->pubkey_algo
- || sk->pubkey_algo == k->pkt->pkt.secret_key->pubkey_algo) )
- return k;
+ fingerprint_from_pk(k->pkt->pkt.public_key, afp, &an );
+ if( an == mode && !memcmp( afp, name, an) ) {
+ return k;
+ }
}
}
return NULL;
}
-/****************
- * Return the expiretime of a subkey.
- */
-static u32
-subkeys_expiretime( KBNODE node, u32 *mainkid )
-{
- KBNODE k;
- PKT_signature *sig;
- u32 expires = 0, sigdate = 0;
-
- assert( node->pkt->pkttype == PKT_PUBLIC_SUBKEY );
- for(k=node->next; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_SIGNATURE
- && (sig=k->pkt->pkt.signature)->sig_class == 0x18
- && sig->keyid[0] == mainkid[0]
- && sig->keyid[1] == mainkid[1]
- && sig->version > 3
- && sig->timestamp > sigdate ) {
- /* okay this is a key-binding which can be used.
- * We use the latest self-signature.
- * FIXME: We should only use this if the binding signature is valid
- * but this is time consuming - we must provide another
- * way to handle this
- */
- const byte *p;
- u32 ed;
-
- p = parse_sig_subpkt( sig->hashed_data, SIGSUBPKT_KEY_EXPIRE, NULL );
- ed = p? node->pkt->pkt.public_key->timestamp + buffer_to_u32(p):0;
- sigdate = sig->timestamp;
- expires = ed;
- }
- else if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY )
- break; /* stop at the next subkey */
- }
-
- return expires;
-}
-/****************
- * Check whether the subkey has expired. Node must point to the subkey
+/* See see whether the key fits
+ * our requirements and in case we do not
+ * request a the primary key, we should select
+ * a suitable subkey.
+ * FIXME: Check against PGP 7 whether we still need a kludge
+ * to favor type 16 keys over type 20 keys when type 20
+ * has not been explitely requested.
+ * Returns: True when a suitable key has been found.
+ *
+ * We have to distinguish four cases:
+ * 1. No usage and no primary key requested
+ * Examples for this case are that we have a keyID to be used
+ * for decrytion or verification.
+ * 2. No usage but primary key requested
+ * This is the case for all functions which work on an
+ * entire keyblock, e.g. for editing or listing
+ * 3. Usage and primary key requested
+ * FXME
+ * 4. Usage but no primary key requested
+ * FIXME
+ * FIXME: Tell what is going to happen here and something about the rationale
+ *
*/
+
static int
-has_expired( KBNODE node, u32 *mainkid, u32 cur_time )
+finish_lookup( GETKEY_CTX ctx, KBNODE foundk )
{
- u32 expires = subkeys_expiretime( node, mainkid );
- return expires && expires <= cur_time;
-}
+ KBNODE keyblock = ctx->keyblock;
+ KBNODE k;
+ #define USAGE_MASK (GCRY_PK_USAGE_SIGN|GCRY_PK_USAGE_ENCR)
+ unsigned int req_usage = ( ctx->req_usage & USAGE_MASK );
+ u32 latest_date;
+ KBNODE latest_key;
-static void
-finish_lookup( KBNODE keyblock, PKT_public_key *pk, KBNODE k, byte *namehash,
- int use_namehash, int primary )
-{
- assert( k->pkt->pkttype == PKT_PUBLIC_KEY
- || k->pkt->pkttype == PKT_PUBLIC_SUBKEY );
+ assert( !foundk || foundk->pkt->pkttype == PKT_PUBLIC_KEY
+ || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY );
assert( keyblock->pkt->pkttype == PKT_PUBLIC_KEY );
- if( primary && !pk->pubkey_usage ) {
- copy_public_key_new_namehash( pk, keyblock->pkt->pkt.public_key,
- use_namehash? namehash:NULL);
- merge_one_pk_and_selfsig( keyblock, keyblock, pk );
+
+ ctx->found_key = NULL;
+
+ if ( DBG_CACHE )
+ log_debug( "finish_lookup: checking %s (req_usage=%x)\n",
+ foundk? "one key":"all keys", req_usage);
+
+ latest_date = 0;
+ latest_key = NULL;
+ /* We do check the subkeys only if we either have requested a specific
+ * usage or have not requested to get the primary key. */
+ if ( (req_usage || !ctx->primary)
+ && (!foundk || foundk->pkt->pkttype == PKT_PUBLIC_SUBKEY) ) {
+ KBNODE nextk;
+ /* either start a loop or check just this one subkey */
+ for (k=foundk?foundk:keyblock; k; k = nextk ) {
+ PKT_public_key *pk;
+ nextk = k->next;
+ if ( k->pkt->pkttype != PKT_PUBLIC_SUBKEY )
+ continue;
+ if ( foundk )
+ nextk = NULL; /* what a hack */
+ pk = k->pkt->pkt.public_key;
+ if ( !pk->is_valid ) {
+ if (DBG_CACHE)
+ log_debug( "\tsubkey not valid\n");
+ continue;
+ }
+ if ( pk->is_revoked ) {
+ if (DBG_CACHE)
+ log_debug( "\tsubkey has been revoked\n");
+ continue;
+ }
+ if ( pk->has_expired ) {
+ if (DBG_CACHE)
+ log_debug( "\tsubkey has expired\n");
+ continue;
+ }
+
+ if ( req_usage &&
+ !((pk->pubkey_usage&USAGE_MASK) & req_usage) ) {
+ if (DBG_CACHE)
+ log_debug( "\tusage does not match: want=%x have=%x\n",
+ req_usage, pk->pubkey_usage );
+ continue;
+ }
+
+ if (DBG_CACHE)
+ log_debug( "\tconsidering key created %lu\n",
+ (ulong)pk->created);
+ if ( pk->created > latest_date ) {
+ latest_date = pk->created;
+ latest_key = k;
+ }
+ }
}
- else {
- if( primary && pk->pubkey_usage
- && openpgp_pk_test_algo( k->pkt->pkt.public_key->pubkey_algo,
- pk->pubkey_usage ) == GPGERR_WR_PUBKEY_ALGO ) {
- /* if the usage is not correct, try to use a subkey */
- KBNODE save_k = k;
- u32 mainkid[2];
- u32 cur_time = make_timestamp();
-
- keyid_from_pk( keyblock->pkt->pkt.public_key, mainkid );
-
- k = NULL;
- /* kludge for pgp 5: which doesn't accept type 20:
- * try to use a type 16 subkey instead */
- if( pk->pubkey_usage == GCRY_PK_USAGE_ENCR ) {
- for( k = save_k; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY
- && k->pkt->pkt.public_key->pubkey_algo
- == GCRY_PK_ELG_E
- && !openpgp_pk_test_algo(
- k->pkt->pkt.public_key->pubkey_algo,
- pk->pubkey_usage )
- && !has_expired(k, mainkid, cur_time) )
- break;
- }
- }
- if( !k ) {
- for(k = save_k ; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_PUBLIC_SUBKEY
- && !openpgp_pk_test_algo(
- k->pkt->pkt.public_key->pubkey_algo,
- pk->pubkey_usage )
- && ( pk->pubkey_usage != GCRY_PK_USAGE_ENCR
- || !has_expired( k, mainkid, cur_time ) )
- )
- break;
- }
- }
- if( !k )
- k = save_k;
- else
- log_info(_("using secondary key %08lX "
- "instead of primary key %08lX\n"),
- (ulong)keyid_from_pk( k->pkt->pkt.public_key, NULL),
- (ulong)keyid_from_pk( save_k->pkt->pkt.public_key, NULL)
- );
- }
-
- copy_public_key_new_namehash( pk, k->pkt->pkt.public_key,
- use_namehash? namehash:NULL);
- merge_one_pk_and_selfsig( keyblock, k, pk );
+ if ( !latest_key ) {
+ PKT_public_key *pk;
+ if (DBG_CACHE && !foundk )
+ log_debug( "\tno suitable subkeys found - trying primary\n");
+ pk = keyblock->pkt->pkt.public_key;
+ if ( !pk->is_valid ) {
+ if (DBG_CACHE)
+ log_debug( "\tprimary key not valid\n");
+ }
+ else if ( pk->is_revoked ) {
+ if (DBG_CACHE)
+ log_debug( "\tprimary key has been revoked\n");
+ }
+ else if ( pk->has_expired ) {
+ if (DBG_CACHE)
+ log_debug( "\tprimary key has expired\n");
+ }
+ else if ( req_usage
+ && !((pk->pubkey_usage&USAGE_MASK) & req_usage) ) {
+ if (DBG_CACHE)
+ log_debug( "\tusage does not match: want=%x have=%x\n",
+ req_usage, pk->pubkey_usage );
+ }
+ else { /* okay */
+ if (DBG_CACHE)
+ log_debug( "\tprimary key may be used\n");
+ latest_key = keyblock;
+ latest_date = pk->created;
+ }
}
-}
-
-static void
-finish_lookup_sk( KBNODE keyblock, PKT_secret_key *sk, KBNODE k, int primary )
-{
- assert( k->pkt->pkttype == PKT_SECRET_KEY
- || k->pkt->pkttype == PKT_SECRET_SUBKEY );
- assert( keyblock->pkt->pkttype == PKT_SECRET_KEY );
- if( primary && !sk->pubkey_usage ) {
- copy_secret_key( sk, keyblock->pkt->pkt.secret_key );
+
+ if ( !latest_key ) {
+ if (DBG_CACHE)
+ log_debug("\tno suitable key found - giving up\n");
+ return 0;
}
- else {
- if( primary && sk->pubkey_usage
- && openpgp_pk_test_algo( k->pkt->pkt.secret_key->pubkey_algo,
- sk->pubkey_usage ) == GPGERR_WR_PUBKEY_ALGO ) {
- /* if the usage is not correct, try to use a subkey */
- KBNODE save_k = k;
-
- k = NULL;
- /* kludge for pgp 5: which doesn't accept type 20:
- * try to use a type 16 subkey instead */
- if( sk->pubkey_usage == GCRY_PK_USAGE_ENCR ) {
- for( k = save_k; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_SECRET_SUBKEY
- && k->pkt->pkt.secret_key->pubkey_algo
- == GCRY_PK_ELG_E
- && !openpgp_pk_test_algo(
- k->pkt->pkt.secret_key->pubkey_algo,
- sk->pubkey_usage ) )
- break;
- }
- }
- if( !k ) {
- for(k = save_k ; k; k = k->next ) {
- if( k->pkt->pkttype == PKT_SECRET_SUBKEY
- && !openpgp_pk_test_algo(
- k->pkt->pkt.secret_key->pubkey_algo,
- sk->pubkey_usage ) )
- break;
- }
- }
- if( !k )
- k = save_k;
- else
- log_info(_("using secondary key %08lX "
- "instead of primary key %08lX\n"),
- (ulong)keyid_from_sk( k->pkt->pkt.secret_key, NULL),
- (ulong)keyid_from_sk( save_k->pkt->pkt.secret_key, NULL)
- );
- }
+ if (DBG_CACHE)
+ log_debug( "\tusing key created %lu\n", (ulong)latest_date );
+
+ ctx->found_key = latest_key;
- copy_secret_key( sk, k->pkt->pkt.secret_key );
+ if ( latest_key != keyblock ) {
+ log_info(_("using secondary key %08lX "
+ "instead of primary key %08lX\n"),
+ (ulong)keyid_from_pk( latest_key->pkt->pkt.public_key, NULL),
+ (ulong)keyid_from_pk( keyblock->pkt->pkt.public_key, NULL) );
}
-}
+ cache_user_id( keyblock );
+
+ return 1; /* found */
+}
+
static int
-lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
+lookup( GETKEY_CTX ctx, KBNODE *ret_keyblock, int secmode )
{
int rc;
- KBNODE k;
int oldmode = set_packet_list_mode(0);
byte namehash[20];
int use_namehash=0;
+ KBNODE secblock = NULL; /* helper */
if( !ctx->count ) /* first time */
- rc = enum_keyblocks( 0, &ctx->kbpos, &ctx->keyblock );
+ rc = enum_keyblocks( secmode?5:0, &ctx->kbpos, &ctx->keyblock );
else
rc = 0;
if( !rc ) {
while( !(rc = enum_keyblocks( 1, &ctx->kbpos, &ctx->keyblock )) ) {
int n;
getkey_item_t *item;
- /* fixme: we don't enum the complete keyblock, but
- * use the first match and then continue with the next keyblock
- */
+
+ if ( secmode ) {
+ /* find the correspondig public key and use this
+ * this one for the selection process */
+ u32 aki[2];
+ KBNODE k = ctx->keyblock;
+
+ if ( k->pkt->pkttype != PKT_SECRET_KEY )
+ BUG();
+ keyid_from_sk( k->pkt->pkt.secret_key, aki );
+ k = get_pubkeyblock( aki );
+ if( !k ) {
+ log_info(_("key %08lX: secret key without public key "
+ "- skipped\n"), (ulong)aki[1] );
+ goto skip;
+ }
+ secblock = ctx->keyblock;
+ ctx->keyblock = k;
+ }
+
+
/* loop over all the user ids we want to look for */
item = ctx->items;
for(n=0; n < ctx->nitems; n++, item++ ) {
- if( item->mode < 10 )
- k = find_by_name( ctx->keyblock, pk,
- item->name, item->mode,
- namehash, &use_namehash );
- else if( item->mode >= 10 && item->mode <= 12 )
- k = find_by_keyid( ctx->keyblock, pk,
+ KBNODE k = NULL;
+ int found = 0;
+
+ if( item->mode < 10 ) {
+ found = find_by_name( ctx->keyblock,
+ item->name, item->mode,
+ namehash );
+ use_namehash = found;
+ }
+ else if( item->mode >= 10 && item->mode <= 12 ) {
+ k = find_by_keyid( ctx->keyblock,
item->keyid, item->mode );
- else if( item->mode == 15 )
- k = find_first( ctx->keyblock, pk );
- else if( item->mode == 16 || item->mode == 20 )
- k = find_by_fpr( ctx->keyblock, pk,
+ found = !!k;
+ }
+ else if( item->mode == 15 ) {
+ found = 1;
+ }
+ else if( item->mode == 16 || item->mode == 20 ) {
+ k = find_by_fpr( ctx->keyblock,
item->fprint, item->mode );
+ found = !!k;
+ }
else
BUG();
- if( k ) {
- finish_lookup( ctx->keyblock, pk, k, namehash,
- use_namehash, ctx->primary );
- goto found;
+ if( found ) {
+ /* this keyblock looks fine - do further investigation */
+ merge_selfsigs ( ctx->keyblock );
+ if ( finish_lookup( ctx, k ) ) {
+ if ( secmode ) {
+ merge_public_with_secret ( ctx->keyblock,
+ secblock);
+ release_kbnode (secblock);
+ secblock = NULL;
+ }
+ goto found;
+ }
}
}
+ skip:
+ /* release resources and try the next keyblock */
+ if ( secmode ) {
+ release_kbnode( secblock );
+ secblock = NULL;
+ }
release_kbnode( ctx->keyblock );
ctx->keyblock = NULL;
}
- found: ;
+ found:
+ ;
}
if( rc && rc != -1 )
log_error("enum_keyblocks failed: %s\n", gpg_errstr(rc));
if( !rc ) {
- if( ret_keyblock ) {
- *ret_keyblock = ctx->keyblock;
- ctx->keyblock = NULL;
- }
+ *ret_keyblock = ctx->keyblock; /* return the keyblock */
+ ctx->keyblock = NULL;
}
else if( rc == -1 )
- rc = GPGERR_NO_PUBKEY;
+ rc = secmode ? GPGERR_NO_SECKEY : GPGERR_NO_PUBKEY;
+ if ( secmode ) {
+ release_kbnode( secblock );
+ secblock = NULL;
+ }
release_kbnode( ctx->keyblock );
ctx->keyblock = NULL;
set_packet_list_mode(oldmode);
@@ -1786,7 +2127,7 @@ lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
lkup_stats[ctx->mode].any = 1;
if( !rc )
lkup_stats[ctx->mode].okay_count++;
- else if ( rc == GPGERR_NO_PUBKEY )
+ else if ( rc == GPGERR_NO_PUBKEY || rc == GPGERR_NO_SECKEY )
lkup_stats[ctx->mode].nokey_count++;
else
lkup_stats[ctx->mode].error_count++;
@@ -1800,75 +2141,14 @@ lookup_pk( GETKEY_CTX ctx, PKT_public_key *pk, KBNODE *ret_keyblock )
-static int
-lookup_sk( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock )
-{
- int rc;
- KBNODE k;
- int oldmode = set_packet_list_mode(0);
-
- if( !ctx->count ) /* first time */
- rc = enum_keyblocks( 5, &ctx->kbpos, &ctx->keyblock );
- else
- rc = 0;
- if( !rc ) {
- while( !(rc = enum_keyblocks( 1, &ctx->kbpos, &ctx->keyblock )) ) {
- int n;
- getkey_item_t *item;
- /* fixme: we don't enum the complete keyblock, but
- * use the first match and then continue with the next keyblock
- */
- /* loop over all the user ids we want to look for */
- item = ctx->items;
- for(n=0; n < ctx->nitems; n++, item++ ) {
- if( item->mode < 10 )
- k = find_by_name_sk( ctx->keyblock, sk,
- item->name, item->mode );
- else if( item->mode >= 10 && item->mode <= 12 )
- k = find_by_keyid_sk( ctx->keyblock, sk,
- item->keyid, item->mode );
- else if( item->mode == 15 )
- k = find_first_sk( ctx->keyblock, sk );
- else if( item->mode == 16 || item->mode == 20 )
- k = find_by_fpr_sk( ctx->keyblock, sk,
- item->fprint, item->mode );
- else
- BUG();
- if( k ) {
- finish_lookup_sk( ctx->keyblock, sk, k, ctx->primary );
- goto found;
- }
- }
- release_kbnode( ctx->keyblock );
- ctx->keyblock = NULL;
- }
- found: ;
- }
- if( rc && rc != -1 )
- log_error("enum_keyblocks failed: %s\n", gpg_errstr(rc));
-
- if( !rc ) {
- if( ret_keyblock ) {
- *ret_keyblock = ctx->keyblock;
- ctx->keyblock = NULL;
- }
- }
- else if( rc == -1 )
- rc = GPGERR_NO_SECKEY;
-
- release_kbnode( ctx->keyblock );
- ctx->keyblock = NULL;
- set_packet_list_mode(oldmode);
-
- ctx->last_rc = rc;
- ctx->count++;
- return rc;
-}
-
/****************
- * fixme: replace by the generic function
+ * FIXME: Replace by the generic function
+ * It does not work as it is right now - it is used at
+ * 2 places: a) to get the key for an anonyous recipient
+ * b) to get the ultimately trusted keys.
+ * The a) usage might have some problems.
*
* Enumerate all primary secret keys. Caller must use these procedure:
* 1) create a void pointer and initialize it to NULL
@@ -1943,6 +2223,11 @@ enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys )
}
+
+/*********************************************
+ *********** user ID printing helpers *******
+ *********************************************/
+
/****************
* Return a string with a printable representation of the user_id.
* this string must be freed by m_free.
@@ -1955,12 +2240,17 @@ get_user_id_string( u32 *keyid )
int pass=0;
/* try it two times; second pass reads from key resources */
do {
- for(r=user_id_db; r; r = r->next )
- if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
- p = gcry_xmalloc( r->len + 10 );
- sprintf(p, "%08lX %.*s", (ulong)keyid[1], r->len, r->name );
- return p;
- }
+ for(r=user_id_db; r; r = r->next ) {
+ keyid_list_t a;
+ for (a=r->keyids; a; a= a->next ) {
+ if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
+ p = gcry_xmalloc( r->len + 10 );
+ sprintf(p, "%08lX %.*s",
+ (ulong)keyid[1], r->len, r->name );
+ return p;
+ }
+ }
+ }
} while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
p = gcry_xmalloc( 15 );
sprintf(p, "%08lX [?]", (ulong)keyid[1] );
@@ -1987,13 +2277,18 @@ get_long_user_id_string( u32 *keyid )
int pass=0;
/* try it two times; second pass reads from key resources */
do {
- for(r=user_id_db; r; r = r->next )
- if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
- p = gcry_xmalloc( r->len + 20 );
- sprintf(p, "%08lX%08lX %.*s",
- (ulong)keyid[0], (ulong)keyid[1], r->len, r->name );
- return p;
- }
+ for(r=user_id_db; r; r = r->next ) {
+ keyid_list_t a;
+ for (a=r->keyids; a; a= a->next ) {
+ if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
+ p = gcry_xmalloc( r->len + 20 );
+ sprintf(p, "%08lX%08lX %.*s",
+ (ulong)keyid[0], (ulong)keyid[1],
+ r->len, r->name );
+ return p;
+ }
+ }
+ }
} while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
p = gcry_xmalloc( 25 );
sprintf(p, "%08lX%08lX [?]", (ulong)keyid[0], (ulong)keyid[1] );
@@ -2009,13 +2304,17 @@ get_user_id( u32 *keyid, size_t *rn )
/* try it two times; second pass reads from key resources */
do {
- for(r=user_id_db; r; r = r->next )
- if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] ) {
- p = gcry_xmalloc( r->len );
- memcpy(p, r->name, r->len );
- *rn = r->len;
- return p;
- }
+ for(r=user_id_db; r; r = r->next ) {
+ keyid_list_t a;
+ for (a=r->keyids; a; a= a->next ) {
+ if( a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1] ) {
+ p = gcry_xmalloc( r->len );
+ memcpy(p, r->name, r->len );
+ *rn = r->len;
+ return p;
+ }
+ }
+ }
} while( ++pass < 2 && !get_pubkey( NULL, keyid ) );
p = gcry_xstrdup( _("[User id not found]") );
*rn = strlen(p);
diff --git a/g10/gpg.c b/g10/gpg.c
index 73919ae92..be4ec98a7 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -179,6 +179,7 @@ enum cmd_and_opt_values { aNull = 0,
oDisableCipherAlgo,
oDisablePubkeyAlgo,
oAllowNonSelfsignedUID,
+ oAllowFreeformUID,
oNoLiteral,
oSetFilesize,
oHonorHttpProxy,
@@ -188,7 +189,9 @@ enum cmd_and_opt_values { aNull = 0,
oNoRandomSeedFile,
oNoAutoKeyRetrieve,
oUseAgent,
- oEmu3DESS2KBug, /* will be removed in 1.1 */
+ oMergeOnly,
+ oTryAllSecrets,
+ oTrustedKey,
oEmuMDEncodeBug,
aTest };
@@ -290,6 +293,7 @@ static ARGPARSE_OPTS opts[] = {
{ oCompletesNeeded, "completes-needed", 1, "@"},
{ oMarginalsNeeded, "marginals-needed", 1, "@"},
{ oMaxCertDepth, "max-cert-depth", 1, "@" },
+ { oTrustedKey, "trusted-key", 2, N_("|KEYID|ulimately trust this key")},
{ oLoadExtension, "load-extension" ,2, N_("|FILE|load extension module FILE")},
{ oRFC1991, "rfc1991", 0, N_("emulate the mode described in RFC1991")},
{ oOpenPGP, "openpgp", 0, N_("set all packet, cipher and digest options to OpenPGP behavior")},
@@ -362,6 +366,7 @@ static ARGPARSE_OPTS opts[] = {
{ oDisableCipherAlgo, "disable-cipher-algo", 2, "@" },
{ oDisablePubkeyAlgo, "disable-pubkey-algo", 2, "@" },
{ oAllowNonSelfsignedUID, "allow-non-selfsigned-uid", 0, "@" },
+ { oAllowFreeformUID, "allow-freeform-uid", 0, "@" },
{ oNoLiteral, "no-literal", 0, "@" },
{ oSetFilesize, "set-filesize", 20, "@" },
{ oHonorHttpProxy,"honor-http-proxy", 0, "@" },
@@ -370,7 +375,8 @@ static ARGPARSE_OPTS opts[] = {
{ oIgnoreTimeConflict, "ignore-time-conflict", 0, "@" },
{ oNoRandomSeedFile, "no-random-seed-file", 0, "@" },
{ oNoAutoKeyRetrieve, "no-auto-key-retrieve", 0, "@" },
- { oEmu3DESS2KBug, "emulate-3des-s2k-bug", 0, "@"},
+ { oMergeOnly, "merge-only", 0, "@" },
+ { oTryAllSecrets, "try-all-secrets", 0, "@" },
{ oEmuMDEncodeBug, "emulate-md-encode-bug", 0, "@"},
{0} };
@@ -601,6 +607,7 @@ main( int argc, char **argv )
char **orig_argv;
const char *fname;
char *username;
+ int may_coredump;
STRLIST sl, remusr= NULL, locusr=NULL;
STRLIST nrings=NULL, sec_nrings=NULL;
armor_filter_context_t afx;
@@ -642,7 +649,7 @@ main( int argc, char **argv )
}
gcry_control( GCRYCTL_USE_SECURE_RNDPOOL );
- disable_core_dumps();
+ may_coredump = disable_core_dumps();
init_signals();
create_dotlock(NULL); /* register locking cleanup */
i18n_init();
@@ -653,8 +660,8 @@ main( int argc, char **argv )
opt.def_digest_algo = 0;
opt.def_compress_algo = 2;
opt.s2k_mode = 3; /* iterated+salted */
- opt.s2k_digest_algo = GCRY_MD_RMD160;
- opt.s2k_cipher_algo = GCRY_CIPHER_BLOWFISH;
+ opt.s2k_digest_algo = GCRY_MD_SHA1;
+ opt.s2k_cipher_algo = GCRY_CIPHER_CAST5;
opt.completes_needed = 1;
opt.marginals_needed = 3;
opt.max_cert_depth = 5;
@@ -666,11 +673,7 @@ main( int argc, char **argv )
opt.homedir = getenv("GNUPGHOME");
#endif
if( !opt.homedir || !*opt.homedir ) {
- #ifdef HAVE_DRIVE_LETTERS
- opt.homedir = "c:/gnupg-test";
- #else
- opt.homedir = "~/.gnupg-test";
- #endif
+ opt.homedir = GNUPG_HOMEDIR;
}
/* check whether we have a config file on the commandline */
@@ -801,7 +804,7 @@ main( int argc, char **argv )
case oArmor: opt.armor = 1; opt.no_armor=0; break;
case oOutput: opt.outfile = pargs.r.ret_str; break;
case oQuiet: opt.quiet = 1; break;
- case oNoTTY: opt.quiet = 1; tty_no_terminal(1); break;
+ case oNoTTY: tty_no_terminal(1); break;
case oDryRun: opt.dry_run = 1; break;
case oInteractive: opt.interactive = 1; break;
case oVerbose:
@@ -894,7 +897,6 @@ main( int argc, char **argv )
opt.s2k_digest_algo = GCRY_MD_SHA1;
opt.s2k_cipher_algo = GCRY_CIPHER_CAST5;
break;
- case oEmu3DESS2KBug: opt.emulate_bugs |= EMUBUG_3DESS2K; break;
case oEmuMDEncodeBug: opt.emulate_bugs |= EMUBUG_MDENCODE; break;
case oCompressSigs: opt.compress_sigs = 1; break;
case oRunAsShmCP:
@@ -965,6 +967,7 @@ main( int argc, char **argv )
}
break;
case oAllowNonSelfsignedUID: opt.allow_non_selfsigned_uid = 1; break;
+ case oAllowFreeformUID: opt.allow_freeform_uid = 1; break;
case oNoLiteral: opt.no_literal = 1; break;
case oSetFilesize: opt.set_filesize = pargs.r.ret_ulong; break;
case oHonorHttpProxy: opt.honor_http_proxy = 1; break;
@@ -973,6 +976,9 @@ main( int argc, char **argv )
case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
case oNoRandomSeedFile: use_random_seed = 0; break;
case oNoAutoKeyRetrieve: opt.auto_key_retrieve = 0; break;
+ case oMergeOnly: opt.merge_only = 1; break;
+ case oTryAllSecrets: opt.try_all_secrets = 1; break;
+ case oTrustedKey: register_trusted_key( pargs.r.ret_str ); break;
default : pargs.err = configfp? 1:2; break;
}
@@ -1001,6 +1007,10 @@ main( int argc, char **argv )
log_info("used in a production environment or with production keys!\n");
}
#endif
+
+ if( may_coredump && !opt.quiet )
+ log_info(_("WARNING: program may create a core file!\n"));
+
if (opt.no_literal) {
log_info(_("NOTE: %s is not for normal use!\n"), "--no-literal");
if (opt.textmode)
@@ -1406,9 +1416,13 @@ main( int argc, char **argv )
case aPrimegen:
- { int mode = argc < 2 ? 0 : atoi(*argv);
+ {
+ #if 1
+ log_error( "command is currently not implemented\n");
+ #else
+ /* FIXME: disabled until we have an API to create primes */
+ int mode = argc < 2 ? 0 : atoi(*argv);
- #if 0 /* FIXME: disabled until we have an API to create primes */
if( mode == 1 && argc == 2 ) {
mpi_print( stdout, generate_public_prime( atoi(argv[1]) ), 1);
}
@@ -1435,9 +1449,9 @@ main( int argc, char **argv )
mpi_release(g);
}
else
- #endif
wrong_args("--gen-prime mode bits [qbits] ");
putchar('\n');
+ #endif
}
break;
diff --git a/g10/import.c b/g10/import.c
index 578082577..94b83f080 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -50,6 +50,7 @@ static struct {
ulong secret_read;
ulong secret_imported;
ulong secret_dups;
+ ulong skipped_new_keys;
} stats;
@@ -201,6 +202,9 @@ print_stats()
{
if( !opt.quiet ) {
log_info(_("Total number processed: %lu\n"), stats.count );
+ if( stats.skipped_new_keys )
+ log_info(_(" skipped new keys: %lu\n"),
+ stats.skipped_new_keys );
if( stats.no_user_id )
log_info(_(" w/o user IDs: %lu\n"), stats.no_user_id );
if( stats.imported || stats.imported_rsa ) {
@@ -413,6 +417,13 @@ import_one( const char *fname, KBNODE keyblock, int fast )
log_error( _("key %08lX: public key not found: %s\n"),
(ulong)keyid[1], gpg_errstr(rc));
}
+ else if ( rc && opt.merge_only ) {
+ if( opt.verbose )
+ log_info( _("key %08lX: new key - skipped\n"), (ulong)keyid[1] );
+ rc = 0;
+ fast = 1; /* so that we don't get into the trustdb update */
+ stats.skipped_new_keys++;
+ }
else if( rc ) { /* insert this key */
/* get default resource */
if( get_keyblock_handle( NULL, 0, &kbpos ) ) {
@@ -583,7 +594,7 @@ import_secret_one( const char *fname, KBNODE keyblock )
/* do we have this key already in one of our secrings ? */
rc = seckey_available( keyid );
- if( rc == GPGERR_NO_SECKEY ) { /* simply insert this key */
+ if( rc == GPGERR_NO_SECKEY && !opt.merge_only ) { /* simply insert this key */
/* get default resource */
if( get_keyblock_handle( NULL, 1, &kbpos ) ) {
log_error("no default secret keyring\n");
diff --git a/g10/keydb.h b/g10/keydb.h
index 75cb3d4cc..830a7db3c 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -31,6 +31,15 @@
#define MAX_FINGERPRINT_LEN 20
+#define IS_KEY_SIG(s) ((s)->sig_class == 0x1f)
+#define IS_UID_SIG(s) (((s)->sig_class & ~3) == 0x10)
+#define IS_SUBKEY_SIG(s) ((s)->sig_class == 0x18)
+#define IS_KEY_REV(s) ((s)->sig_class == 0x20)
+#define IS_UID_REV(s) ((s)->sig_class == 0x30)
+#define IS_SUBKEY_REV(s) ((s)->sig_class == 0x28)
+
+
+
struct getkey_ctx_s;
typedef struct getkey_ctx_s *GETKEY_CTX;
diff --git a/g10/keyedit.c b/g10/keyedit.c
index daf4fb41d..b7e836711 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -592,7 +592,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
{ N_("sign") , cmdSIGN , 0,1,1, N_("sign the key") },
{ N_("s") , cmdSIGN , 0,1,1, NULL },
{ N_("lsign") , cmdLSIGN , 0,1,1, N_("sign the key locally") },
- { N_("debug") , cmdDEBUG , 0,1,0, NULL },
+ { N_("debug") , cmdDEBUG , 0,0,0, NULL },
{ N_("adduid") , cmdADDUID , 1,1,0, N_("add a user ID") },
{ N_("deluid") , cmdDELUID , 0,1,0, N_("delete user ID") },
{ N_("addkey") , cmdADDKEY , 1,1,0, N_("add a secondary key") },
diff --git a/g10/keygen.c b/g10/keygen.c
index 8e29090c3..fc3b2cf8c 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -136,8 +136,8 @@ keygen_add_std_prefs( PKT_signature *sig, void *opaque )
keygen_add_key_expire( sig, opaque );
buf[0] = GCRY_CIPHER_TWOFISH;
- buf[1] = GCRY_CIPHER_BLOWFISH;
- buf[2] = GCRY_CIPHER_CAST5;
+ buf[1] = GCRY_CIPHER_CAST5;
+ buf[2] = GCRY_CIPHER_BLOWFISH;
build_sig_subpkt( sig, SIGSUBPKT_PREF_SYM, buf, 3 );
buf[0] = GCRY_MD_RMD160;
@@ -889,7 +889,11 @@ ask_user_id( int mode )
aname = cpr_get("keygen.name",_("Real name: "));
trim_spaces(aname);
cpr_kill_prompt();
- if( strpbrk( aname, "<([])>" ) )
+
+ if( opt.allow_freeform_uid )
+ break;
+
+ if( strpbrk( aname, "<>" ) )
tty_printf(_("Invalid character in name\n"));
else if( isdigit(*aname) )
tty_printf(_("Name may not start with a digit\n"));
diff --git a/g10/keyid.c b/g10/keyid.c
index 14406b60b..fb652e7b2 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -166,11 +166,17 @@ keyid_from_sk( PKT_secret_key *sk, u32 *keyid )
if( !keyid )
keyid = dummy_keyid;
- if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
+ if( sk->keyid[0] || sk->keyid[1] ) {
+ keyid[0] = sk->keyid[0];
+ keyid[1] = sk->keyid[1];
+ }
+ else if( sk->version < 4 && is_RSA(sk->pubkey_algo) ) {
if( pubkey_get_npkey(sk->pubkey_algo) )
v3_keyid( sk->skey[0], keyid ); /* take n */
else
keyid[0] = keyid[1] = 0;
+ sk->keyid[0] = keyid[0];
+ sk->keyid[1] = keyid[1];
}
else {
const byte *dp;
@@ -180,6 +186,8 @@ keyid_from_sk( PKT_secret_key *sk, u32 *keyid )
keyid[0] = dp[12] << 24 | dp[13] << 16 | dp[14] << 8 | dp[15] ;
keyid[1] = dp[16] << 24 | dp[17] << 16 | dp[18] << 8 | dp[19] ;
gcry_md_close(md);
+ sk->keyid[0] = keyid[0];
+ sk->keyid[1] = keyid[1];
}
return keyid[1];
diff --git a/g10/main.h b/g10/main.h
index 8e2436c70..d199c5484 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -51,7 +51,7 @@ char *make_radix64_string( const byte *data, size_t len );
/*-- misc.c --*/
void trap_unaligned(void);
-void disable_core_dumps(void);
+int disable_core_dumps(void);
u16 checksum_u16( unsigned n );
u16 checksum( byte *p, unsigned n );
u16 checksum_mpi( MPI a );
@@ -65,6 +65,7 @@ int mpi_print( FILE *fp, MPI a, int mode );
int openpgp_cipher_test_algo( int algo );
int openpgp_pk_test_algo( int algo, unsigned int usage_flags );
+int openpgp_pk_algo_usage ( int algo );
int openpgp_md_test_algo( int algo );
int pubkey_get_npkey( int algo );
diff --git a/g10/misc.c b/g10/misc.c
index 44a6f76b1..a62a04766 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -68,22 +68,24 @@ trap_unaligned(void)
#endif
-void
+
+int
disable_core_dumps()
{
- #ifndef HAVE_DOSISH_SYSTEM
+ #ifdef HAVE_DOSISH_SYSTEM
+ return 0;
+ #else
#ifdef HAVE_SETRLIMIT
struct rlimit limit;
limit.rlim_cur = 0;
limit.rlim_max = 0;
if( !setrlimit( RLIMIT_CORE, &limit ) )
- return;
- if( errno != EINVAL )
+ return 0;
+ if( errno != EINVAL && errno != ENOSYS )
log_fatal(_("can't disable core dumps: %s\n"), strerror(errno) );
#endif
- if( !opt.quiet )
- log_info(_("WARNING: program may create a core file!\n"));
+ return 1;
#endif
}
@@ -318,15 +320,6 @@ print_pubkey_algo_note( int algo )
{
if( algo >= 100 && algo <= 110 )
no_exp_algo();
- else if( is_RSA( algo ) ) {
- static int did_note = 0;
-
- if( !did_note ) {
- did_note = 1;
- log_info(_("RSA keys are deprecated; please consider "
- "creating a new key and use this key in the future\n"));
- }
- }
}
void
@@ -362,7 +355,7 @@ print_digest_algo_note( int algo )
/****************
* Wrapper around the libgcrypt function with addional checks on
- * openPGP contrainst for the algo ID.
+ * openPGP contraints for the algo ID.
*/
int
openpgp_cipher_test_algo( int algo )
@@ -382,6 +375,40 @@ openpgp_pk_test_algo( int algo, unsigned int usage_flags )
return gcry_pk_algo_info( algo, GCRYCTL_TEST_ALGO, NULL, &n );
}
+int
+openpgp_pk_algo_usage ( int algo )
+{
+ int usage = 0;
+
+ /* some are hardwired */
+ switch ( algo ) {
+ case GCRY_PK_RSA:
+ usage = GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR;
+ break;
+ case GCRY_PK_RSA_E:
+ usage = GCRY_PK_USAGE_ENCR;
+ break;
+ case GCRY_PK_RSA_S:
+ usage = GCRY_PK_USAGE_SIGN;
+ break;
+ case GCRY_PK_ELG_E:
+ usage = GCRY_PK_USAGE_ENCR;
+ break;
+ case GCRY_PK_DSA:
+ usage = GCRY_PK_USAGE_SIGN;
+ break;
+ case GCRY_PK_ELG:
+ usage = GCRY_PK_USAGE_SIGN | GCRY_PK_USAGE_ENCR;
+ break;
+ default:
+ usage = gcry_pk_algo_info ( algo, GCRYCTL_GET_ALGO_USAGE,
+ NULL, NULL);
+ }
+ return usage;
+
+}
+
+
int
openpgp_md_test_algo( int algo )
diff --git a/g10/openfile.c b/g10/openfile.c
index 47dca0e76..340cfd6fa 100644
--- a/g10/openfile.c
+++ b/g10/openfile.c
@@ -70,6 +70,11 @@ overwrite_filep( const char *fname )
if( access( fname, F_OK ) )
return 1; /* does not exist */
+#ifndef HAVE_DOSISH_SYSTEM
+ if ( !strcmp ( fname, "/dev/null" ) )
+ return 1; /* does not do any harm */
+#endif
+
/* fixme: add some backup stuff in case of overwrite */
if( opt.answer_yes )
return 1;
@@ -105,6 +110,12 @@ make_outfile_name( const char *iname )
buf[n-4] = 0;
return buf;
}
+ else if( n > 5 && !CMP_FILENAME(iname+n-5,".sign") ) {
+ char *buf = gcry_xstrdup( iname );
+ buf[n-5] = 0;
+ return buf;
+ }
+
log_info(_("%s: unknown suffix\n"), iname );
return NULL;
@@ -241,6 +252,7 @@ open_sigfile( const char *iname )
if( iname && !(*iname == '-' && !iname[1]) ) {
len = strlen(iname);
if( len > 4 && ( !strcmp(iname + len - 4, ".sig")
+ || ( len > 5 && !strcmp(iname + len - 5, ".sign") )
|| !strcmp(iname + len - 4, ".asc")) ) {
char *buf;
buf = gcry_xstrdup(iname);
@@ -305,10 +317,24 @@ copy_options_file( const char *destdir )
void
try_make_homedir( const char *fname )
{
+ const char *defhome = GNUPG_HOMEDIR;
+
+ /* Create the directory only if the supplied directory name
+ * is the same as the default one. This way we avoid to create
+ * arbitrary directories when a non-default homedirectory is used.
+ * To cope with HOME, we do compare only the suffix if we see that
+ * the default homedir does start with a tilde.
+ */
if( opt.dry_run )
return;
- if( strlen(fname) >= 7
- && !strcmp(fname+strlen(fname)-7, "/.gnupg" ) ) {
+
+ if ( ( *defhome == '~'
+ && ( strlen(fname) >= strlen (defhome+1)
+ && !strcmp(fname+strlen(defhome+1)-strlen(defhome+1),
+ defhome+1 ) ))
+ || ( *defhome != '~'
+ && !compare_filenames( fname, defhome ) )
+ ) {
if( mkdir( fname, S_IRUSR|S_IWUSR|S_IXUSR ) )
log_fatal( _("%s: can't create directory: %s\n"),
fname, strerror(errno) );
@@ -321,3 +347,5 @@ try_make_homedir( const char *fname )
}
}
+
+
diff --git a/g10/options.h b/g10/options.h
index 218e97694..b7ef09fe7 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -84,6 +84,7 @@ struct {
const char *set_policy_url;
int use_embedded_filename;
int allow_non_selfsigned_uid;
+ int allow_freeform_uid;
int no_literal;
ulong set_filesize;
int honor_http_proxy;
@@ -92,6 +93,8 @@ struct {
int command_fd;
int auto_key_retrieve;
int use_agent;
+ int merge_only;
+ int try_all_secrets;
} opt;
diff --git a/g10/packet.h b/g10/packet.h
index f6da15e17..03fa2ca6e 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -128,8 +128,15 @@ typedef struct {
byte hdrbytes; /* number of header bytes */
byte version;
byte pubkey_algo; /* algorithm used for public key scheme */
- byte pubkey_usage; /* for now only used to pass it to getkey() */
+ byte pubkey_usage; /* the actual allowed usage as set by getkey() */
+ u32 created; /* according to the self-signature */
+ byte req_usage; /* hack to pass a request to getkey() */
+ byte req_algo; /* Ditto */
+ u32 has_expired; /* set to the expiration date if expired */
+ int is_revoked; /* key has been revoked */
+ int is_valid; /* key (especially subkey) is valid */
ulong local_id; /* internal use, valid if > 0 */
+ u32 main_keyid[2]; /* keyid of the primary key */
u32 keyid[2]; /* calculated by keyid_from_pk() */
byte *namehash; /* if != NULL: found by this name */
MPI pkey[GNUPG_MAX_NPKEY];
@@ -142,6 +149,14 @@ typedef struct {
byte version;
byte pubkey_algo; /* algorithm used for public key scheme */
byte pubkey_usage;
+ u32 created; /* according to the self-signature */
+ byte req_usage;
+ byte req_algo;
+ u32 has_expired; /* set to the expiration date if expired */
+ int is_revoked; /* key has been revoked */
+ int is_valid; /* key (especially subkey) is valid */
+ u32 main_keyid[2]; /* keyid of the primary key */
+ u32 keyid[2];
byte is_primary;
byte is_protected; /* The secret info is protected and must */
/* be decrypted before use, the protected */
@@ -169,6 +184,10 @@ typedef struct {
int len; /* length of the name */
char *photo; /* if this is not NULL, the packet is a photo ID */
int photolen; /* and the length of the photo */
+ int help_key_usage;
+ u32 help_key_expire;
+ int is_primary;
+ u32 created; /* according to the self-signature */
char name[1];
} PKT_user_id;
@@ -322,6 +341,8 @@ PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
PKT_public_key *copy_public_key_new_namehash( PKT_public_key *d,
PKT_public_key *s,
const byte *namehash );
+void copy_public_parts_to_secret_key( PKT_public_key *pk,
+ PKT_secret_key *sk );
PKT_secret_key *copy_secret_key( PKT_secret_key *d, PKT_secret_key *s );
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
PKT_user_id *copy_user_id( PKT_user_id *d, PKT_user_id *s );
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 867f93d1d..3cabe77b1 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -700,6 +700,17 @@ dump_sig_subpkt( int hashed, int type, int critical,
const char *p=NULL;
int i;
+ /* The CERT has warning out with explains how to use GNUPG to
+ * detect the ARRs - we print our old message here when it is a faked
+ * ARR and add an additional notice */
+ if ( type == SIGSUBPKT_ARR && !hashed ) {
+ printf("\tsubpkt %d len %u (additional recipient request)\n"
+ "WARNING: PGP versions > 5.0 and < 6.5.8 will automagically "
+ "encrypt to this key and thereby reveal the plaintext to "
+ "the owner of this ARR key. Detailed info follows:\n",
+ type, (unsigned)length );
+ }
+
printf("\t%s%ssubpkt %d len %u (", /*)*/
critical ? "critical ":"",
hashed ? "hashed ":"", type, (unsigned)length );
@@ -737,9 +748,6 @@ dump_sig_subpkt( int hashed, int type, int critical,
printf("key expires after %s",
strtimevalue( buffer_to_u32(buffer) ) );
break;
- case SIGSUBPKT_ARR:
- p = "additional recipient request";
- break;
case SIGSUBPKT_PREF_SYM:
fputs("pref-sym-algos:", stdout );
for( i=0; i < length; i++ )
@@ -809,8 +817,10 @@ dump_sig_subpkt( int hashed, int type, int critical,
print_string( stdout, buffer, length, ')' );
break;
case SIGSUBPKT_KEY_FLAGS:
- p = "key flags";
- break;
+ fputs ( "key flags:", stdout );
+ for( i=0; i < length; i++ )
+ printf(" %02X", buffer[i] );
+ break;
case SIGSUBPKT_SIGNERS_UID:
p = "signer's user ID";
break;
@@ -821,6 +831,16 @@ dump_sig_subpkt( int hashed, int type, int critical,
p = ")";
}
break;
+ case SIGSUBPKT_ARR:
+ fputs("Big Brother's key (ignored): ", stdout );
+ if( length < 22 )
+ p = "[too short]";
+ else {
+ printf("c=%02x a=%d f=", buffer[0], buffer[1] );
+ for( i=2; i < length; i++ )
+ printf("%02X", buffer[i] );
+ }
+ break;
case SIGSUBPKT_PRIV_ADD_SIG:
p = "signs additional user ID";
break;
@@ -846,6 +866,8 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
if( n < 4 )
break;
return 0;
+ case SIGSUBPKT_KEY_FLAGS:
+ return 0;
case SIGSUBPKT_EXPORTABLE:
if( !n )
break;
@@ -867,6 +889,10 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
case SIGSUBPKT_PREF_COMPR:
case SIGSUBPKT_POLICY:
return 0;
+ case SIGSUBPKT_PRIMARY_UID:
+ if ( n != 1 )
+ break;
+ return 0;
case SIGSUBPKT_PRIV_ADD_SIG:
/* because we use private data, we check the GNUPG marker */
if( n < 24 )
@@ -897,6 +923,7 @@ can_handle_critical( const byte *buffer, size_t n, int type )
case SIGSUBPKT_PREF_SYM:
case SIGSUBPKT_PREF_HASH:
case SIGSUBPKT_PREF_COMPR:
+ case SIGSUBPKT_KEY_FLAGS:
return 1;
case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */
@@ -1288,7 +1315,8 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
sk->version = version;
sk->is_primary = pkttype == PKT_SECRET_KEY;
sk->pubkey_algo = algorithm;
- sk->pubkey_usage = 0; /* not yet used */
+ sk->req_usage = 0;
+ sk->pubkey_usage = 0; /* will be set by getkey functions */
}
else {
PKT_public_key *pk = pkt->pkt.public_key;
@@ -1298,7 +1326,9 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
pk->hdrbytes = hdrlen;
pk->version = version;
pk->pubkey_algo = algorithm;
- pk->pubkey_usage = 0; /* not yet used */
+ pk->req_usage = 0;
+ pk->pubkey_usage = 0; /* will be set bey getkey functions */
+ pk->is_revoked = 0;
pk->keyid[0] = 0;
pk->keyid[1] = 0;
}
diff --git a/g10/passphrase.c b/g10/passphrase.c
index 97ed3d189..6b06df72e 100644
--- a/g10/passphrase.c
+++ b/g10/passphrase.c
@@ -640,7 +640,6 @@ hash_passphrase( DEK *dek, char *pw, STRING2KEY *s2k, int create )
else {
gcry_md_write( md, s2k->salt, 8 );
count -= 8;
- assert( count >= 0 );
gcry_md_write( md, pw, count );
}
}
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 8e61ffdd0..d827ce653 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -814,13 +814,12 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
any_recipients = 1;
else if( (use & GCRY_PK_USAGE_ENCR) && !opt.no_encrypt_to ) {
pk = gcry_xcalloc( 1, sizeof *pk );
- pk->pubkey_usage = use;
+ pk->req_usage = use;
if( (rc = get_pubkey_byname( NULL, pk, rov->d, NULL )) ) {
free_public_key( pk ); pk = NULL;
log_error(_("%s: skipped: %s\n"), rov->d, gpg_errstr(rc) );
}
else if( !(rc=openpgp_pk_test_algo(pk->pubkey_algo, use )) ) {
-
/* Skip the actual key if the key is already present
* in the list */
if (key_present_in_pk_list(pk_list, pk) == 0) {
@@ -871,7 +870,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
if( pk )
free_public_key( pk );
pk = gcry_xcalloc( 1, sizeof *pk );
- pk->pubkey_usage = use;
+ pk->req_usage = use;
rc = get_pubkey_byname( NULL, pk, answer, NULL );
if( rc )
tty_printf(_("No such user ID.\n"));
@@ -937,7 +936,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
}
else if( !any_recipients && (def_rec = default_recipient()) ) {
pk = gcry_xcalloc( 1, sizeof *pk );
- pk->pubkey_usage = use;
+ pk->req_usage = use;
rc = get_pubkey_byname( NULL, pk, def_rec, NULL );
if( rc )
log_error(_("unknown default recipient `%s'\n"), def_rec );
@@ -962,7 +961,7 @@ build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
continue; /* encrypt-to keys are already handled */
pk = gcry_xcalloc( 1, sizeof *pk );
- pk->pubkey_usage = use;
+ pk->req_usage = use;
if( (rc = get_pubkey_byname( NULL, pk, remusr->d, NULL )) ) {
free_public_key( pk ); pk = NULL;
log_error(_("%s: skipped: %s\n"), remusr->d, gpg_errstr(rc) );
@@ -1033,8 +1032,6 @@ static int
algo_available( int preftype, int algo )
{
if( preftype == PREFTYPE_SYM ) {
- if( algo == GCRY_CIPHER_TWOFISH )
- return 0; /* we don't want to generate Twofish messages for now*/
return algo && !openpgp_cipher_test_algo( algo );
}
else if( preftype == PREFTYPE_HASH ) {
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index e6cbec4a0..646aca017 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -106,14 +106,11 @@ get_session_key( PKT_pubkey_enc *k, DEK *dek )
PKT_secret_key *sk = NULL;
int rc;
- if( is_RSA(k->pubkey_algo) ) /* warn about that */
- write_status(STATUS_RSA_OR_IDEA);
-
rc = openpgp_pk_test_algo( k->pubkey_algo, 0 );
if( rc )
goto leave;
- if( k->keyid[0] || k->keyid[1] ) {
+ if( (k->keyid[0] || k->keyid[1]) && !opt.try_all_secrets ) {
sk = gcry_xcalloc( 1, sizeof *sk );
sk->pubkey_algo = k->pubkey_algo; /* we want a pubkey with this algo*/
if( !(rc = get_seckey( sk, k->keyid )) )
diff --git a/g10/ringedit.c b/g10/ringedit.c
index 3a29654d2..311cf41fc 100644
--- a/g10/ringedit.c
+++ b/g10/ringedit.c
@@ -1114,7 +1114,13 @@ cmp_seckey( PKT_secret_key *req_sk, PKT_secret_key *sk )
n = pubkey_get_nskey( req_sk->pubkey_algo );
for(i=0; i < n; i++ ) {
- if( mpi_cmp( req_sk->skey[i], sk->skey[i] ) )
+ /* Note: because v4 protected keys have nothing in the
+ * mpis except for the first one, we skip all NULL MPIs.
+ * This might not be always correct in cases where the both
+ * keys do not match in their secret parts but we can ignore that
+ * because the need for this function is quite ugly. */
+ if( req_sk->skey[1] && sk->skey[i]
+ && mpi_cmp( req_sk->skey[i], sk->skey[i] ) )
return -1;
}
return 0;
diff --git a/g10/seckey-cert.c b/g10/seckey-cert.c
index 342dde06c..0be514eb3 100644
--- a/g10/seckey-cert.c
+++ b/g10/seckey-cert.c
@@ -100,10 +100,8 @@ do_check( PKT_secret_key *sk )
keyid_from_sk( sk, keyid );
keyid[2] = keyid[3] = 0;
if( !sk->is_primary ) {
- PKT_secret_key *sk2 = gcry_xcalloc( 1, sizeof *sk2 );
- if( !get_primary_seckey( sk2, keyid ) )
- keyid_from_sk( sk2, keyid+2 );
- free_secret_key( sk2 );
+ keyid[2] = sk->main_keyid[0];
+ keyid[3] = sk->main_keyid[1];
}
dek = passphrase_to_dek( keyid, sk->pubkey_algo, sk->protect.algo,
&sk->protect.s2k, 0 );
@@ -128,11 +126,14 @@ do_check( PKT_secret_key *sk )
size_t ndata;
unsigned int ndatabits;
byte *p, *data;
+ u16 csumc = 0;
i = pubkey_get_npkey(sk->pubkey_algo);
assert( gcry_mpi_get_flag( sk->skey[i], GCRYMPI_FLAG_OPAQUE ) );
p = gcry_mpi_get_opaque( sk->skey[i], &ndatabits );
ndata = (ndatabits+7)/8;
+ if ( ndata > 1 )
+ csumc = p[ndata-2] << 8 | p[ndata-1];
data = gcry_xmalloc_secure( ndata );
gcry_cipher_decrypt( cipher_hd, data, ndata, p, ndata );
mpi_release( sk->skey[i] ); sk->skey[i] = NULL ;
@@ -145,6 +146,10 @@ do_check( PKT_secret_key *sk )
else {
csum = checksum( data, ndata-2);
sk->csum = data[ndata-2] << 8 | data[ndata-1];
+ if ( sk->csum != csum ) {
+ /* This is a PGP 7.0.0 workaround */
+ sk->csum = csumc; /* take the encrypted one */
+ }
}
/* must check it here otherwise the mpi_read_xx would fail
* because the length may have an arbitrary value */
@@ -321,8 +326,6 @@ protect_secret_key( PKT_secret_key *sk, DEK *dek )
#warning FIXME: replace set/get buffer
if( sk->version >= 4 ) {
- /* FIXME: There is a bug in this function for all algorithms
- * where the secret MPIs are more than 1 */
byte *bufarr[GNUPG_MAX_NSKEY];
unsigned narr[GNUPG_MAX_NSKEY];
unsigned nbits[GNUPG_MAX_NSKEY];
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 85c8bfbc1..a3946a1e0 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -134,9 +134,6 @@ do_signature_check( PKT_signature *sig, GCRY_MD_HD digest,
PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
int rc=0;
- if( is_RSA(sig->pubkey_algo) )
- write_status(STATUS_RSA_OR_IDEA);
-
*r_expiredate = 0;
if( get_pubkey( pk, sig->keyid ) )
rc = GPGERR_NO_PUBKEY;
@@ -451,10 +448,18 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
sig = node->pkt->pkt.signature;
algo = sig->digest_algo;
- #if 0 /* I am not sure whether this is a good thing to do */
- if( sig->flags.checked )
+ #if 0
+ if( sig->flags.checked ) {
log_debug("check_key_signature: already checked: %s\n",
sig->flags.valid? "good":"bad" );
+ if ( sig->flags.valid )
+ return 0; /* shortcut already checked signatures */
+ /* FIXME: We should also do this with bad signatures but here we
+ * have to distinguish between several reasons; e.g. for a missing
+ * public key. the key may now be available.
+ * For now we simply don't shortcut bad signatures
+ */
+ }
#endif
if( (rc=openpgp_md_test_algo(algo)) )
diff --git a/g10/sign.c b/g10/sign.c
index d52010a4c..b53444b7c 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -485,6 +485,10 @@ sign_file( STRLIST filenames, int detached, STRLIST locusr,
if( fname ) {
if( !(filesize = iobuf_get_filelength(inp)) )
log_info(_("WARNING: `%s' is an empty file\n"), fname );
+ /* we can't yet encode the length of very large files,
+ * so we switch to partial length encoding in this case */
+ if ( filesize >= IOBUF_FILELENGTH_LIMIT )
+ filesize = 0;
/* because the text_filter modifies the length of the
* data, it is not possible to know the used length
diff --git a/g10/skclist.c b/g10/skclist.c
index 8fcb22aba..5c6d6fbd7 100644
--- a/g10/skclist.c
+++ b/g10/skclist.c
@@ -59,7 +59,7 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock,
PKT_secret_key *sk;
sk = gcry_xcalloc( 1, sizeof *sk );
- sk->pubkey_usage = use;
+ sk->req_usage = use;
if( (rc = get_seckey_byname( sk, NULL, unlock )) ) {
free_secret_key( sk ); sk = NULL;
log_error("no default secret key: %s\n", gpg_errstr(rc) );
@@ -90,7 +90,7 @@ build_sk_list( STRLIST locusr, SK_LIST *ret_sk_list, int unlock,
PKT_secret_key *sk;
sk = gcry_xcalloc( 1, sizeof *sk );
- sk->pubkey_usage = use;
+ sk->req_usage = use;
if( (rc = get_seckey_byname( sk, locusr->d, unlock )) ) {
free_secret_key( sk ); sk = NULL;
log_error(_("skipped `%s': %s\n"), locusr->d, gpg_errstr(rc) );
diff --git a/g10/trustdb.c b/g10/trustdb.c
index f75ccc52f..f3fcd4649 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -109,6 +109,7 @@ static TN used_tns;
static int alloced_tns;
static int max_alloced_tns;
+static struct keyid_list *trusted_key_list;
static LOCAL_ID_TABLE new_lid_table(void);
static int ins_lid_table_item( LOCAL_ID_TABLE tbl, ulong lid, unsigned flag );
@@ -463,6 +464,64 @@ lid_from_keyid_no_sdir( u32 *keyid )
************* Initialization ****************
***********************************************/
+void
+register_trusted_key( const char *string )
+{
+ u32 keyid[2];
+ struct keyid_list *r;
+
+ if( classify_user_id( string, keyid, NULL, NULL, NULL ) != 11 ) {
+ log_error(_("'%s' is not a valid long keyID\n"), string );
+ return;
+ }
+
+ for( r = trusted_key_list; r; r = r->next )
+ if( r->keyid[0] == keyid[0] && r->keyid[1] == keyid[1] )
+ return;
+ r = gcry_xmalloc( sizeof *r );
+ r->keyid[0] = keyid[0];
+ r->keyid[1] = keyid[1];
+ r->next = trusted_key_list;
+ trusted_key_list = r;
+}
+
+
+
+static void
+add_ultimate_key( PKT_public_key *pk, u32 *keyid )
+{
+ int rc;
+
+ /* first make sure that the pubkey is in the trustdb */
+ rc = query_trust_record( pk );
+ if( rc == -1 && opt.dry_run )
+ return;
+ if( rc == -1 ) { /* put it into the trustdb */
+ rc = insert_trust_record_by_pk( pk );
+ if( rc ) {
+ log_error(_("key %08lX: can't put it into the trustdb\n"),
+ (ulong)keyid[1] );
+ return;
+ }
+ }
+ else if( rc ) {
+ log_error(_("key %08lX: query record failed\n"), (ulong)keyid[1] );
+ return;
+ }
+
+ if( DBG_TRUST )
+ log_debug("key %08lX.%lu: stored into ultikey_table\n",
+ (ulong)keyid[1], pk->local_id );
+
+ if( ins_lid_table_item( ultikey_table, pk->local_id, 0 ) )
+ log_error(_("key %08lX: already in trusted key table\n"),
+ (ulong)keyid[1]);
+ else if( opt.verbose > 1 )
+ log_info(_("key %08lX: accepted as trusted key.\n"),
+ (ulong)keyid[1]);
+
+}
+
/****************
* Verify that all our public keys are in the trustdb.
*/
@@ -474,7 +533,27 @@ verify_own_keys(void)
PKT_secret_key *sk = gcry_xcalloc( 1, sizeof *sk );
PKT_public_key *pk = gcry_xcalloc( 1, sizeof *pk );
u32 keyid[2];
-
+ struct keyid_list *kl;
+
+
+ /* put the trusted keys into the ultikey table */
+ for( kl = trusted_key_list; kl; kl = kl->next ) {
+ keyid[0] = kl->keyid[0];
+ keyid[1] = kl->keyid[1];
+ /* get the public key */
+ memset( pk, 0, sizeof *pk );
+ rc = get_pubkey( pk, keyid );
+ if( rc ) {
+ log_info(_("key %08lX: no public key for trusted key - skipped\n"),
+ (ulong)keyid[1] );
+ }
+ else {
+ add_ultimate_key( pk, keyid );
+ release_public_key_parts( pk );
+ }
+ }
+
+ /* And now add all secret keys to the ultikey table */
while( !(rc=enum_secret_keys( &enum_context, sk, 0 ) ) ) {
int have_pk = 0;
@@ -487,6 +566,10 @@ verify_own_keys(void)
log_info(_("NOTE: secret key %08lX is NOT protected.\n"),
(ulong)keyid[1] );
+ for( kl = trusted_key_list; kl; kl = kl->next ) {
+ if( kl->keyid[0] == keyid[0] && kl->keyid[1] == keyid[1] )
+ goto skip; /* already in trusted key table */
+ }
/* see whether we can access the public key of this secret key */
memset( pk, 0, sizeof *pk );
@@ -504,33 +587,8 @@ verify_own_keys(void)
goto skip;
}
- /* make sure that the pubkey is in the trustdb */
- rc = query_trust_record( pk );
- if( rc == -1 && opt.dry_run )
- goto skip;
- if( rc == -1 ) { /* put it into the trustdb */
- rc = insert_trust_record_by_pk( pk );
- if( rc ) {
- log_error(_("key %08lX: can't put it into the trustdb\n"),
- (ulong)keyid[1] );
- goto skip;
- }
- }
- else if( rc ) {
- log_error(_("key %08lX: query record failed\n"), (ulong)keyid[1] );
- goto skip;
+ add_ultimate_key( pk, keyid );
- }
-
- if( DBG_TRUST )
- log_debug("key %08lX.%lu: stored into ultikey_table\n",
- (ulong)keyid[1], pk->local_id );
- if( ins_lid_table_item( ultikey_table, pk->local_id, 0 ) )
- log_error(_("key %08lX: already in trusted key table\n"),
- (ulong)keyid[1]);
- else if( opt.verbose > 1 )
- log_info(_("key %08lX: accepted as trusted key.\n"),
- (ulong)keyid[1]);
skip:
release_secret_key_parts( sk );
if( have_pk )
@@ -541,6 +599,15 @@ verify_own_keys(void)
else
rc = 0;
+ /* release the trusted keyid table */
+ { struct keyid_list *kl2;
+ for( kl = trusted_key_list; kl; kl = kl2 ) {
+ kl2 = kl->next;
+ gcry_free( kl );
+ }
+ trusted_key_list = NULL;
+ }
+
enum_secret_keys( &enum_context, NULL, 0 ); /* free context */
free_secret_key( sk );
free_public_key( pk );
@@ -548,6 +615,8 @@ verify_own_keys(void)
}
+
+
/****************
* Perform some checks over the trustdb
* level 0: only open the db
diff --git a/include/iobuf.h b/include/iobuf.h
index 7a7d825e6..2f35f9af9 100644
--- a/include/iobuf.h
+++ b/include/iobuf.h
@@ -116,6 +116,7 @@ size_t iobuf_temp_to_buffer( IOBUF a, byte *buffer, size_t buflen );
void iobuf_unget_and_close_temp( IOBUF a, IOBUF temp );
u32 iobuf_get_filelength( IOBUF a );
+#define IOBUF_FILELENGTH_LIMIT 0xffffffff
const char *iobuf_get_real_fname( IOBUF a );
const char *iobuf_get_fname( IOBUF a );
diff --git a/tools/ChangeLog b/tools/ChangeLog
index 79bba89f2..136caf56b 100644
--- a/tools/ChangeLog
+++ b/tools/ChangeLog
@@ -1,3 +1,8 @@
+Mon Sep 18 16:35:45 CEST 2000 Werner Koch <wk@openit.de>
+
+ * ring-a-party: substr starts at offset 1 not 0. Many thanks to Mike
+ for finding this bug. Flush the last key.
+
Mon Jul 17 16:35:47 CEST 2000 Werner Koch <wk@>
* mail-signed-keys: New.
diff --git a/tools/ring-a-party b/tools/ring-a-party
index 561b51336..7cf05d78d 100755
--- a/tools/ring-a-party
+++ b/tools/ring-a-party
@@ -31,6 +31,9 @@ BEGIN { FS=":"
page = 0;
now = strftime("%b %d %H:%M %Y");
}
+END {
+ if (any) myflush();
+}
$1 == "pub" {
if( any ) myflush();
uidcount = 0;
@@ -84,7 +87,7 @@ function printfpr16( s )
printf "f16 Fingerprint16 =";
for(i=0; i < 16; i++ ) {
if( i == 8 ) printf " ";
- printf " %s", substr( s, i*2, 2 );
+ printf " %s", substr( s, i*2+1, 2 );
}
printf "\n"
}
@@ -94,10 +97,13 @@ function printfpr20( s )
printf "f20 Fingerprint20 =";
for(i=0; i < 10; i++ ) {
if( i == 5 ) printf " ";
- printf " %s", substr( s, i*4, 4 );
+ printf " %s", substr( s, i*4+1, 4 );
}
printf "\n"
}
' | tee a.pub | gpg --print-mds
+
+
+
diff --git a/util/ChangeLog b/util/ChangeLog
index 956c2085d..20e9bda3e 100644
--- a/util/ChangeLog
+++ b/util/ChangeLog
@@ -1,3 +1,15 @@
+Mon Sep 18 16:35:45 CEST 2000 Werner Koch <wk@openit.de>
+
+ * strgutil.c (utf8_to_native): Fixed null ptr problem. By
+ Giampaolo Tomassoni.
+
+ * iobuf.c: Use fopen64 insead of fopen when available.
+ (iobuf_get_filelength): Use fstat64 when available but return
+ 2^32-1 if the file is larger than this value.
+
+ * miscutil.c (answer_is_yes_no_quit): Swapped order of yes/no test
+ so that no is returned for an empty input. By David Champion.
+
Fri Aug 18 14:27:14 CEST 2000 Werner Koch <wk@openit.de>
* logger.c (log_set_file): Allow to set the file by name.
diff --git a/util/iobuf.c b/util/iobuf.c
index f7035ae4c..5f70694c2 100644
--- a/util/iobuf.c
+++ b/util/iobuf.c
@@ -36,6 +36,14 @@
#include "util.h"
#include "iobuf.h"
+
+#if defined (HAVE_FOPEN64) && defined (HAVE_FSTAT64)
+ #define fopen(a,b) fopen64 ((a),(b))
+ #define fstat(a,b) fstat64 ((a),(b))
+#endif
+
+
+
typedef struct {
FILE *fp; /* open file handle */
int print_only_name; /* flags indicating that fname is not a real file*/
@@ -1312,25 +1320,40 @@ iobuf_set_limit( IOBUF a, unsigned long nlimit )
u32
iobuf_get_filelength( IOBUF a )
{
+#if defined (HAVE_FOPEN64) && defined (HAVE_FSTAT64)
+ struct stat64 st;
+#else
struct stat st;
+#endif
if( a->directfp ) {
FILE *fp = a->directfp;
- if( !fstat(fileno(fp), &st) )
- return st.st_size;
+ if( !fstat(fileno(fp), &st) ) {
+ #if defined (HAVE_FOPEN64) && defined (HAVE_FSTAT64)
+ if( st.st_size >= IOBUF_FILELENGTH_LIMIT )
+ return IOBUF_FILELENGTH_LIMIT;
+ #endif
+ return (u32)st.st_size;
+ }
log_error("fstat() failed: %s\n", strerror(errno) );
return 0;
}
+
/* Hmmm: file_filter may have already been removed */
for( ; a; a = a->chain )
if( !a->chain && a->filter == file_filter ) {
file_filter_ctx_t *b = a->filter_ov;
FILE *fp = b->fp;
- if( !fstat(fileno(fp), &st) )
+ if( !fstat(fileno(fp), &st) ) {
+ #if defined (HAVE_FOPEN64) && defined (HAVE_FSTAT64)
+ if( st.st_size >= IOBUF_FILELENGTH_LIMIT )
+ return IOBUF_FILELENGTH_LIMIT;
+ #endif
return st.st_size;
+ }
log_error("fstat() failed: %s\n", strerror(errno) );
break;
}
diff --git a/util/miscutil.c b/util/miscutil.c
index c1b8fa076..9b4a8379f 100644
--- a/util/miscutil.c
+++ b/util/miscutil.c
@@ -311,16 +311,16 @@ answer_is_yes_no_quit( const char *s )
char *short_no = _("nN");
char *short_quit = _("qQ");
- if( !stricmp(s, long_yes ) )
- return 1;
if( !stricmp(s, long_no ) )
return 0;
+ if( !stricmp(s, long_yes ) )
+ return 1;
if( !stricmp(s, long_quit ) )
return -1;
- if( strchr( short_yes, *s ) && !s[1] )
- return 1;
if( strchr( short_no, *s ) && !s[1] )
return 0;
+ if( strchr( short_yes, *s ) && !s[1] )
+ return 1;
if( strchr( short_quit, *s ) && !s[1] )
return -1;
if( !stricmp(s, "yes" ) )
diff --git a/util/strgutil.c b/util/strgutil.c
index a8abf7ba8..89722f8e4 100644
--- a/util/strgutil.c
+++ b/util/strgutil.c
@@ -389,7 +389,8 @@ utf8_to_native( const char *string, size_t length )
case 0 : n++; if( p ) *p++ = '0'; break;
default: n += 3;
sprintf( p, "x%02x", *s );
- p += 3;
+ if ( p )
+ p += 3;
break;
}
}
@@ -496,3 +497,7 @@ utf8_to_native( const char *string, size_t length )
}
+
+
+
+