aboutsummaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
Diffstat (limited to 'g10')
-rw-r--r--g10/ChangeLog42
-rw-r--r--g10/build-packet.c2
-rw-r--r--g10/cipher.c24
-rw-r--r--g10/delkey.c14
-rw-r--r--g10/encode.c5
-rw-r--r--g10/getkey.c70
-rw-r--r--g10/kbnode.c5
-rw-r--r--g10/keydb.h8
-rw-r--r--g10/keyedit.c29
-rw-r--r--g10/keygen.c28
-rw-r--r--g10/packet.h11
-rw-r--r--g10/parse-packet.c34
-rw-r--r--g10/pkclist.c25
-rw-r--r--g10/ringedit.c259
-rw-r--r--g10/sig-check.c13
15 files changed, 308 insertions, 261 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 1499c0eaf..23fc5e3eb 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,45 @@
+2001-08-30 Werner Koch <[email protected]>
+
+ * packet.h (sigsubpkttype_t): Add SIGSUBPKT_FEATURES.
+ (PKT_public_key, PKT_user_id): Add a flag for it.
+ * parse-packet.c, build-packet.c: Add support for them.
+ * getkey.c (fixup_uidnode, merge_selfsigs): Set the MDC flags.
+ * keygen.c (add_feature_mdc): New.
+ (keygen_upd_std_prefs): Always set the MDC feature.
+ * keyedit.c (show_prefs): List the MDC flag
+ * pkclist.c (select_mdc_from_pklist): New.
+ * encode.c (encode_crypt, encrypt_filter): Test whether MDC
+ should be used.
+ * cipher.c (write_header): Set MDC use depending on the above test.
+ Print more status info.
+
+ * delkey.c (do_delete_key): Kludge to delete a secret key with no
+ public key available.
+
+ * ringedit.c (find_secret_keyblock_direct): New.
+ * getkey.c (seckey_available): Simplified.
+
+ * ringedit.c (cmp_seckey): Now compares the secret key against the
+ public key while ignoring all secret parts.
+ (keyring_search): Use a public key packet as arg. Allow to search
+ for subnkeys
+ (search): Likewise. Changed all callers.
+ (find_secret_keyblock_bypk): New.
+ (find_secret_keyblock_byname): First locate the pubkey and then
+ find the correponding secret key.
+ * parse-packet.c (parse): Renamed pkttype arg to onlykeypkts and
+ changed code accordingly. Changed all callers.
+ (search_packet): Removed pkttype arg.
+ * keyedit.c (keyedit_menu): First locate the public key and then
+ try to locate a secret key.
+
+ * ringedit.c (locate_keyblock_by_fpr): Removed.
+ (locate_keyblock_by_keyid): Removed.
+ (find_keyblock_bysk): Removed.
+
+ * sig-check.c (check_key_signature2): Print the keyid along with
+ the wrong sig class errors.
+
2001-08-24 Werner Koch <[email protected]>
* sign.c (sign_file): Stripped the disabled comment packet code.
diff --git a/g10/build-packet.c b/g10/build-packet.c
index 194ff16ce..1b7e0d838 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -747,6 +747,7 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
case SIGSUBPKT_PREF_SYM:
case SIGSUBPKT_PREF_HASH:
case SIGSUBPKT_PREF_COMPR:
+ case SIGSUBPKT_FEATURES:
delete_sig_subpkt (sig->hashed, type);
break;
default:
@@ -783,6 +784,7 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
case SIGSUBPKT_REVOC_REASON:
case SIGSUBPKT_PRIMARY_UID:
case SIGSUBPKT_KEY_FLAGS:
+ case SIGSUBPKT_FEATURES:
hashed = 1; break;
default: hashed = 0; break;
}
diff --git a/g10/cipher.c b/g10/cipher.c
index fbee543be..c1cf226a8 100644
--- a/g10/cipher.c
+++ b/g10/cipher.c
@@ -47,16 +47,27 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
byte temp[18];
unsigned blocksize;
unsigned nprefix;
- int use_mdc = opt.force_mdc;
+ int use_mdc;
blocksize = cipher_get_blocksize( cfx->dek->algo );
if( blocksize < 8 || blocksize > 16 )
log_fatal("unsupported blocksize %u\n", blocksize );
+
+ use_mdc = cfx->dek->use_mdc;
+
if( blocksize != 8 )
- use_mdc = 1; /* enable it for all modern ciphers */
+ use_mdc = 1; /* Hack: enable it for all modern ciphers */
+ /* Note: We should remove this hack as soon as a reasonable number of keys
+ are carrying the MDC flag. But always keep the hack for conventional
+ encryption */
+
+ if (opt.force_mdc)
+ use_mdc = 1;
+
if( opt.rfc2440 || opt.rfc1991 )
use_mdc = 0; /* override - rfc2440 does not know about MDC */
+
memset( &ed, 0, sizeof ed );
ed.len = cfx->datalen;
ed.extralen = blocksize+2;
@@ -67,6 +78,14 @@ write_header( cipher_filter_context_t *cfx, IOBUF a )
if ( DBG_HASHING )
md_start_debug( cfx->mdc_hash, "creatmdc" );
}
+
+ {
+ char buf[20];
+
+ sprintf (buf, "%d %d", ed.mdc_method, cfx->dek->algo);
+ write_status_text (STATUS_BEGIN_ENCRYPTION, buf);
+ }
+
init_packet( &pkt );
pkt.pkttype = use_mdc? PKT_ENCRYPTED_MDC : PKT_ENCRYPTED;
pkt.pkt.encrypted = &ed;
@@ -111,7 +130,6 @@ cipher_filter( void *opaque, int control,
else if( control == IOBUFCTRL_FLUSH ) { /* encrypt */
assert(a);
if( !cfx->header ) {
- write_status( STATUS_BEGIN_ENCRYPTION );
write_header( cfx, a );
}
if( cfx->mdc_hash )
diff --git a/g10/delkey.c b/g10/delkey.c
index 784fe03bf..777d4c174 100644
--- a/g10/delkey.c
+++ b/g10/delkey.c
@@ -61,8 +61,18 @@ do_delete_key( const char *username, int secret, int *r_sec_avail )
*r_sec_avail = 0;
/* search the userid */
- rc = secret? find_secret_keyblock_byname( &kbpos, username )
- : find_keyblock_byname( &kbpos, username );
+ if (secret
+ && classify_user_id (username, keyid, NULL, NULL, NULL) == 11) {
+ /* if the user supplied a long keyID we use the direct search
+ methods which allows us to delete a key if the
+ corresponding secret key is missing */
+ rc = find_secret_keyblock_direct (&kbpos, keyid);
+ }
+ else if (secret)
+ rc = find_secret_keyblock_byname (&kbpos, username);
+ else
+ rc = find_keyblock_byname (&kbpos, username);
+
if( rc ) {
log_error(_("%s: user not found\n"), username );
write_status_text( STATUS_DELETE_PROBLEM, "1" );
diff --git a/g10/encode.c b/g10/encode.c
index 8cc44c152..7d9f0952f 100644
--- a/g10/encode.c
+++ b/g10/encode.c
@@ -299,6 +299,8 @@ encode_crypt( const char *filename, STRLIST remusr )
}
else
cfx.dek->algo = opt.def_cipher_algo;
+ cfx.dek->use_mdc = select_mdc_from_pklist (pk_list);
+
make_session_key( cfx.dek );
if( DBG_CIPHER )
log_hexdump("DEK is: ", cfx.dek->key, cfx.dek->keylen );
@@ -428,6 +430,9 @@ encrypt_filter( void *opaque, int control,
}
else
efx->cfx.dek->algo = opt.def_cipher_algo;
+
+ efx->cfx.dek->use_mdc = select_mdc_from_pklist (efx->pk_list);
+
make_session_key( efx->cfx.dek );
if( DBG_CIPHER )
log_hexdump("DEK is: ",
diff --git a/g10/getkey.c b/g10/getkey.c
index c9d1b874b..8293fc673 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -542,55 +542,8 @@ get_seckey( PKT_secret_key *sk, u32 *keyid )
int
seckey_available( u32 *keyid )
{
-#if 0
- int rc;
- struct getkey_ctx_s ctx;
- KBNODE kb = NULL;
-
- memset( &ctx, 0, sizeof ctx );
- ctx.exact = 1; /* use the key ID exactly as given */
- 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( &ctx, &kb, 1 );
- get_seckey_end( &ctx );
- release_kbnode ( kb );
- return rc;
-#endif
- int rc;
- int found = 0;
- int oldmode = set_packet_list_mode (0);
- KBNODE keyblock = NULL;
- KBPOS kbpos;
-
- rc = enum_keyblocks ( 5, &kbpos, NULL );
- if ( !rc ) {
- while ( !(rc = enum_keyblocks (1, &kbpos, &keyblock)) ) {
- KBNODE k;
-
- 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( aki[1] == keyid[1] && aki[0] == keyid[0] ) {
- found = 1;
- goto leave;
- }
- }
- }
- release_kbnode (keyblock); keyblock = NULL;
- }
- }
- if( rc && rc != -1 )
- log_error ("enum_keyblocks failed: %s\n", g10_errstr(rc));
- leave:
- release_kbnode (keyblock);
- enum_keyblocks ( 2, &kbpos, NULL );
- set_packet_list_mode (oldmode);
- return found? 0 : G10ERR_NO_SECKEY;
+ KBPOS dummy_kbpos;
+ return find_secret_keyblock_direct (&dummy_kbpos, keyid)? G10ERR_NO_SECKEY:0;
}
@@ -1458,7 +1411,7 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated )
* from the hashed list but if there are no such preferences, we
* try to get them from the unhashed list. There is no risk with
* that, because our implementation comes only with strong
- * algorithms and it woulkd be fruitless for an attacker to insert
+ * algorithms and it would be fruitless for an attacker to insert
* an weak algorithm. */
p = parse_sig_subpkt2 ( sig, SIGSUBPKT_PREF_SYM, &n );
sym = p; nsym = p?n:0;
@@ -1490,6 +1443,18 @@ fixup_uidnode ( KBNODE uidnode, KBNODE signode, u32 keycreated )
uid->prefs[n].value = 0;
}
+ /* see whether we have the MDC feature */
+ uid->mdc_feature = 0;
+ p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n);
+ if (!p)
+ n=0;
+ for (; n; n--, p++) {
+ if (*p == 1) {
+ uid->mdc_feature = 1;
+ break;
+ }
+ }
+
}
static void
@@ -1846,6 +1811,7 @@ merge_selfsigs( KBNODE keyblock )
int revoked;
PKT_public_key *main_pk;
prefitem_t *prefs;
+ int mdc_feature;
if ( keyblock->pkt->pkttype != PKT_PUBLIC_KEY ) {
if (keyblock->pkt->pkttype == PKT_SECRET_KEY ) {
@@ -1890,12 +1856,15 @@ merge_selfsigs( KBNODE keyblock )
* use reference counting to optimize the preference lists storage.
* FIXME: it might be better to use the intersection of
* all preferences.
+ * Do a similar thing for the MDC feature flag.
*/
prefs = NULL;
+ mdc_feature = 0;
for (k=keyblock; k && k->pkt->pkttype != PKT_PUBLIC_SUBKEY; k = k->next) {
if (k->pkt->pkttype == PKT_USER_ID
&& k->pkt->pkt.user_id->is_primary) {
prefs = k->pkt->pkt.user_id->prefs;
+ mdc_feature = k->pkt->pkt.user_id->mdc_feature;
break;
}
}
@@ -1906,6 +1875,7 @@ merge_selfsigs( KBNODE keyblock )
if (pk->prefs)
m_free (pk->prefs);
pk->prefs = copy_prefs (prefs);
+ pk->mdc_feature = mdc_feature;
}
}
diff --git a/g10/kbnode.c b/g10/kbnode.c
index 4a031a09c..6a5543f67 100644
--- a/g10/kbnode.c
+++ b/g10/kbnode.c
@@ -385,12 +385,13 @@ dump_kbnode( KBNODE node )
else if( node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
PKT_public_key *pk = node->pkt->pkt.public_key;
- fprintf(stderr, " keyid=%08lX a=%d u=%d %c%c%c\n",
+ fprintf(stderr, " keyid=%08lX a=%d u=%d %c%c%c%c\n",
(ulong)keyid_from_pk( pk, NULL ),
pk->pubkey_algo, pk->pubkey_usage,
pk->has_expired? 'e':'.',
pk->is_revoked? 'r':'.',
- pk->is_valid? 'v':'.' );
+ pk->is_valid? 'v':'.',
+ pk->mdc_feature? 'm':'.');
}
else
fputs("\n", stderr);
diff --git a/g10/keydb.h b/g10/keydb.h
index e0dc178d4..8438a3f9d 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -124,6 +124,7 @@ int check_signatures_trust( PKT_signature *sig );
void release_pk_list( PK_LIST pk_list );
int build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use );
int select_algo_from_prefs( PK_LIST pk_list, int preftype );
+int select_mdc_from_pklist (PK_LIST pk_list);
/*-- skclist.c --*/
void release_sk_list( SK_LIST sk_list );
@@ -218,15 +219,12 @@ int add_keyblock_resource( const char *resname, int force, int secret );
const char *keyblock_resource_name( KBPOS *kbpos );
int get_keyblock_handle( const char *filename, int secret, KBPOS *kbpos );
char *get_writable_keyblock_file( int secret );
-int locate_keyblock_by_fpr( KBPOS *kbpos, const byte *fpr,
- int fprlen, int secret );
-int locate_keyblock_by_keyid( KBPOS *kbpos, u32 *keyid,
- int shortkid, int secret );
int find_keyblock( PUBKEY_FIND_INFO info, KBPOS *kbpos );
int find_keyblock_byname( KBPOS *kbpos, const char *username );
int find_keyblock_bypk( KBPOS *kbpos, PKT_public_key *pk );
-int find_keyblock_bysk( KBPOS *kbpos, PKT_secret_key *sk );
+int find_secret_keyblock_bypk( KBPOS *kbpos, PKT_public_key *pk );
int find_secret_keyblock_byname( KBPOS *kbpos, const char *username );
+int find_secret_keyblock_direct (KBPOS *kbpos, u32 *keyid);
int lock_keyblock( KBPOS *kbpos );
void unlock_keyblock( KBPOS *kbpos );
int read_keyblock( KBPOS *kbpos, KBNODE *ret_root );
diff --git a/g10/keyedit.c b/g10/keyedit.c
index fed390d6e..875e229e0 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -650,10 +650,19 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
have_commands = 1;
}
+ /* get the public key */
+ rc = get_keyblock_byname( &keyblock, &keyblockpos, username );
+ if( rc )
+ goto leave;
+ if( fix_keyblock( keyblock ) )
+ modified++;
+ if( collapse_uids( &keyblock ) )
+ modified++;
+
+ if( !sign_mode ) {/* see whether we have a matching secret key */
+ PKT_public_key *pk = keyblock->pkt->pkt.public_key;
- if( !sign_mode ) {
- /* first try to locate it as secret key */
- rc = find_secret_keyblock_byname( &sec_keyblockpos, username );
+ rc = find_secret_keyblock_bypk( &sec_keyblockpos, pk );
if( !rc ) {
rc = read_keyblock( &sec_keyblockpos, &sec_keyblock );
if( rc ) {
@@ -667,17 +676,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
}
}
- /* and now get the public key */
- rc = get_keyblock_byname( &keyblock, &keyblockpos, username );
- if( rc )
- goto leave;
- if( fix_keyblock( keyblock ) )
- modified++;
- if( collapse_uids( &keyblock ) )
- modified++;
-
- if( sec_keyblock ) { /* check that they match */
- /* fixme: check that they both match */
+ if( sec_keyblock ) {
tty_printf(_("Secret key is available.\n"));
}
@@ -1118,6 +1117,8 @@ show_prefs (PKT_user_id *uid, int verbose)
prefs[i].type == PREFTYPE_ZIP ? 'Z':'?',
prefs[i].value);
}
+ if (uid->mdc_feature)
+ tty_printf (" [mdc]");
tty_printf("\n");
}
}
diff --git a/g10/keygen.c b/g10/keygen.c
index ce9169be6..37d4a0740 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -280,6 +280,30 @@ keygen_get_std_prefs ()
}
+static void
+add_feature_mdc (PKT_signature *sig)
+{
+ const byte *s;
+ size_t i, n;
+ char *buf;
+
+ s = parse_sig_subpkt (sig->hashed, SIGSUBPKT_FEATURES, &n );
+ if (!s)
+ n = 0;
+
+ for (i=0; i < n; i++ ) {
+ if (s[i] == 1)
+ return; /* already set */
+ }
+
+ buf = m_alloc (n+1);
+ buf[0] = 1; /* MDC feature */
+ memcpy (buf+1, s, n);
+ build_sig_subpkt (sig, SIGSUBPKT_FEATURES, buf, n+1);
+ m_free (buf);
+}
+
+
int
keygen_upd_std_prefs( PKT_signature *sig, void *opaque )
{
@@ -298,6 +322,10 @@ keygen_upd_std_prefs( PKT_signature *sig, void *opaque )
build_sig_subpkt (sig, SIGSUBPKT_PREF_COMPR, zip_prefs, nzip_prefs);
else
delete_sig_subpkt (sig->hashed, SIGSUBPKT_PREF_COMPR);
+
+ /* Make sure that the MDC feature flag is set */
+ add_feature_mdc (sig);
+
return 0;
}
diff --git a/g10/packet.h b/g10/packet.h
index e80711759..5e4e89ea0 100644
--- a/g10/packet.h
+++ b/g10/packet.h
@@ -145,6 +145,7 @@ typedef struct {
int is_primary;
int is_revoked;
prefitem_t *prefs; /* list of preferences (may be NULL)*/
+ int mdc_feature;
u32 created; /* according to the self-signature */
char name[1];
} PKT_user_id;
@@ -172,6 +173,7 @@ typedef struct {
u32 main_keyid[2]; /* keyid of the primary key */
u32 keyid[2]; /* calculated by keyid_from_pk() */
prefitem_t *prefs; /* list of preferences (may be NULL) */
+ int mdc_feature; /* mdc feature set */
byte *namehash; /* if != NULL: found by this name */
PKT_user_id *user_id; /* if != NULL: found by that uid */
MPI pkey[PUBKEY_MAX_NPKEY];
@@ -303,6 +305,7 @@ typedef enum {
SIGSUBPKT_KEY_FLAGS =27, /* key flags */
SIGSUBPKT_SIGNERS_UID =28, /* signer's user id */
SIGSUBPKT_REVOC_REASON =29, /* reason for revocation */
+ SIGSUBPKT_FEATURES =30, /* feature flags */
SIGSUBPKT_PRIV_VERIFY_CACHE =101, /* cache verification result */
SIGSUBPKT_FLAG_CRITICAL=128
@@ -320,7 +323,7 @@ int list_packets( IOBUF a );
int set_packet_list_mode( int mode );
#if DEBUG_PARSE_PACKET
-int dbg_search_packet( IOBUF inp, PACKET *pkt, int pkttype, off_t *retpos,
+int dbg_search_packet( IOBUF inp, PACKET *pkt, off_t *retpos,
const char* file, int lineno );
int dbg_parse_packet( IOBUF inp, PACKET *ret_pkt,
const char* file, int lineno );
@@ -330,8 +333,8 @@ int dbg_copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff,
const char* file, int lineno );
int dbg_skip_some_packets( IOBUF inp, unsigned n,
const char* file, int lineno );
-#define search_packet( a,b,c,d ) \
- dbg_search_packet( (a), (b), (c), (d), __FILE__, __LINE__ )
+#define search_packet( a,b,c ) \
+ dbg_search_packet( (a), (b), (c), __FILE__, __LINE__ )
#define parse_packet( a, b ) \
dbg_parse_packet( (a), (b), __FILE__, __LINE__ )
#define copy_all_packets( a,b ) \
@@ -341,7 +344,7 @@ int dbg_skip_some_packets( IOBUF inp, unsigned n,
#define skip_some_packets( a,b ) \
dbg_skip_some_packets((a),(b), __FILE__, __LINE__ )
#else
-int search_packet( IOBUF inp, PACKET *pkt, int pkttype, off_t *retpos );
+int search_packet( IOBUF inp, PACKET *pkt, off_t *retpos );
int parse_packet( IOBUF inp, PACKET *ret_pkt);
int copy_all_packets( IOBUF inp, IOBUF out );
int copy_some_packets( IOBUF inp, IOBUF out, off_t stopoff );
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 5461664f0..50e293097 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -38,7 +38,7 @@
static int mpi_print_mode = 0;
static int list_mode = 0;
-static int parse( IOBUF inp, PACKET *pkt, int reqtype,
+static int parse( IOBUF inp, PACKET *pkt, int onlykeypkts,
off_t *retpos, int *skip, IOBUF out, int do_skip
#ifdef DEBUG_PARSE_PACKET
,const char *dbg_w, const char *dbg_f, int dbg_l
@@ -154,28 +154,28 @@ parse_packet( IOBUF inp, PACKET *pkt )
#endif
/****************
- * Like parse packet, but only return packets of the given type.
+ * Like parse packet, but only return secret or public (sub)key packets.
*/
#ifdef DEBUG_PARSE_PACKET
int
-dbg_search_packet( IOBUF inp, PACKET *pkt, int pkttype, off_t *retpos,
+dbg_search_packet( IOBUF inp, PACKET *pkt, off_t *retpos,
const char *dbg_f, int dbg_l )
{
int skip, rc;
do {
- rc = parse( inp, pkt, pkttype, retpos, &skip, NULL, 0, "search", dbg_f, dbg_l );
+ rc = parse( inp, pkt, 1, retpos, &skip, NULL, 0, "search", dbg_f, dbg_l );
} while( skip );
return rc;
}
#else
int
-search_packet( IOBUF inp, PACKET *pkt, int pkttype, off_t *retpos )
+search_packet( IOBUF inp, PACKET *pkt, off_t *retpos )
{
int skip, rc;
do {
- rc = parse( inp, pkt, pkttype, retpos, &skip, NULL, 0 );
+ rc = parse( inp, pkt, 1, retpos, &skip, NULL, 0 );
} while( skip );
return rc;
}
@@ -277,14 +277,14 @@ skip_some_packets( IOBUF inp, unsigned n )
/****************
- * Parse packet. Set the variable skip points to to 1 if the packet
- * should be skipped; this is the case if either there is a
- * requested packet type and the parsed packet doesn't match or the
+ * Parse packet. Set the variable skip points to 1 if the packet
+ * should be skipped; this is the case if either ONLYKEYPKTS is set
+ * and the parsed packet isn't one or the
* packet-type is 0, indicating deleted stuff.
* if OUT is not NULL, a special copymode is used.
*/
static int
-parse( IOBUF inp, PACKET *pkt, int reqtype, off_t *retpos,
+parse( IOBUF inp, PACKET *pkt, int onlykeypkts, off_t *retpos,
int *skip, IOBUF out, int do_skip
#ifdef DEBUG_PARSE_PACKET
,const char *dbg_w, const char *dbg_f, int dbg_l
@@ -375,7 +375,12 @@ parse( IOBUF inp, PACKET *pkt, int reqtype, off_t *retpos,
goto leave;
}
- if( do_skip || !pkttype || (reqtype && pkttype != reqtype) ) {
+ if( do_skip
+ || !pkttype
+ || (onlykeypkts && pkttype != PKT_PUBLIC_SUBKEY
+ && pkttype != PKT_PUBLIC_KEY
+ && pkttype != PKT_SECRET_SUBKEY
+ && pkttype != PKT_SECRET_KEY ) ) {
skip_rest(inp, pktlen);
*skip = 1;
rc = 0;
@@ -856,6 +861,11 @@ dump_sig_subpkt( int hashed, int type, int critical,
printf("%02X", buffer[i] );
}
break;
+ case SIGSUBPKT_FEATURES:
+ fputs ( "features:", stdout );
+ for( i=0; i < length; i++ )
+ printf(" %d", buffer[i] );
+ break;
case SIGSUBPKT_PRIV_VERIFY_CACHE:
p = "verification cache";
break;
@@ -903,6 +913,7 @@ parse_one_sig_subpkt( const byte *buffer, size_t n, int type )
case SIGSUBPKT_PREF_HASH:
case SIGSUBPKT_PREF_COMPR:
case SIGSUBPKT_POLICY:
+ case SIGSUBPKT_FEATURES:
return 0;
case SIGSUBPKT_PRIMARY_UID:
if ( n != 1 )
@@ -944,6 +955,7 @@ can_handle_critical( const byte *buffer, size_t n, int type )
case SIGSUBPKT_PREF_COMPR:
case SIGSUBPKT_KEY_FLAGS:
case SIGSUBPKT_PRIMARY_UID:
+ case SIGSUBPKT_FEATURES:
return 1;
case SIGSUBPKT_POLICY: /* Is it enough to show the policy? */
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 61b2c8000..e4e0f38a3 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -1146,4 +1146,29 @@ select_algo_from_prefs( PK_LIST pk_list, int preftype )
return i;
}
+/*
+ * Select the MDC flag from the pk_list. We can only use MDC if all recipients
+ * support this feature
+ */
+int
+select_mdc_from_pklist (PK_LIST pk_list)
+{
+ PK_LIST pkr;
+
+ if( !pk_list )
+ return 0;
+
+ for (pkr = pk_list; pkr; pkr = pkr->next) {
+ int mdc;
+
+ if (pkr->pk->user_id) /* selected by user ID */
+ mdc = pkr->pk->user_id->mdc_feature;
+ else
+ mdc = pkr->pk->mdc_feature;
+ if (!mdc)
+ return 0; /* at least on recipeint does not support it */
+ }
+ return 1; /* can be used */
+}
+
diff --git a/g10/ringedit.c b/g10/ringedit.c
index b2193e7e2..5e610e583 100644
--- a/g10/ringedit.c
+++ b/g10/ringedit.c
@@ -84,11 +84,12 @@ static RESTBL resource_table[MAX_RESOURCES];
static int default_public_resource;
static int default_secret_resource;
-static int search( PACKET *pkt, KBPOS *kbpos, int secret );
+static int search (PKT_public_key *req_pk, u32 *req_keyid,
+ KBPOS *kbpos, int secret);
-static int keyring_search( PACKET *pkt, KBPOS *kbpos, IOBUF iobuf,
- const char *fname );
+static int keyring_search (PKT_public_key *req_pk, u32 *req_keyid,
+ KBPOS *kbpos, IOBUF iobuf, const char *fname );
static int keyring_read( KBPOS *kbpos, KBNODE *ret_root );
static int keyring_enum( KBPOS *kbpos, KBNODE *ret_root, int skipsigs );
static int keyring_copy( KBPOS *kbpos, int mode, KBNODE root );
@@ -97,7 +98,7 @@ static int keyring_copy( KBPOS *kbpos, int mode, KBNODE root );
static int do_gdbm_store( KBPOS *kbpos, KBNODE root, int update );
static int do_gdbm_locate( GDBM_FILE dbf, KBPOS *kbpos,
const byte *fpr, int fprlen );
-static int do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid );
+/*static int do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid );*/
static int do_gdbm_read( KBPOS *kbpos, KBNODE *ret_root );
static int do_gdbm_enum( KBPOS *kbpos, KBNODE *ret_root );
#endif
@@ -464,26 +465,31 @@ get_writable_keyblock_file( int secret )
* Returns: 0 if found, -1 if not found or an errorcode.
*/
static int
-search( PACKET *pkt, KBPOS *kbpos, int secret )
+search (PKT_public_key *req_pk, u32 *req_keyid, KBPOS *kbpos, int secret)
{
int i, rc, last_rc=-1;
for(i=0; i < MAX_RESOURCES; i++ ) {
if( resource_table[i].used && !resource_table[i].secret == !secret ) {
switch( resource_table[i].rt ) {
- case rt_RING:
- rc = keyring_search( pkt, kbpos, resource_table[i].iobuf,
- resource_table[i].fname );
- break;
- #ifdef HAVE_LIBGDBM
+ case rt_RING:
+ rc = keyring_search (req_pk, req_keyid,
+ kbpos, resource_table[i].iobuf,
+ resource_table[i].fname );
+
+ break;
+ #ifdef HAVE_LIBGDBM
case rt_GDBM: {
- PKT_public_key *req_pk = pkt->pkt.public_key;
byte fpr[20];
size_t fprlen;
-
- fingerprint_from_pk( req_pk, fpr, &fprlen );
- rc = do_gdbm_locate( resource_table[i].dbf,
- kbpos, fpr, fprlen );
+
+ if (!req_pk)
+ rc = G10ERR_UNSUPPORTED;
+ else {
+ fingerprint_from_pk( req_pk, fpr, &fprlen );
+ rc = do_gdbm_locate( resource_table[i].dbf,
+ kbpos, fpr, fprlen );
+ }
}
break;
#endif
@@ -514,20 +520,12 @@ search( PACKET *pkt, KBPOS *kbpos, int secret )
int
find_keyblock_byname( KBPOS *kbpos, const char *username )
{
- PACKET pkt;
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
int rc;
rc = get_pubkey_byname( NULL, pk, username, NULL );
- if( rc ) {
- free_public_key(pk);
- return rc;
- }
-
- init_packet( &pkt );
- pkt.pkttype = PKT_PUBLIC_KEY;
- pkt.pkt.public_key = pk;
- rc = search( &pkt, kbpos, 0 );
+ if (!rc)
+ rc = search( pk, NULL, kbpos, 0 );
free_public_key(pk);
return rc;
}
@@ -540,30 +538,22 @@ find_keyblock_byname( KBPOS *kbpos, const char *username )
int
find_keyblock_bypk( KBPOS *kbpos, PKT_public_key *pk )
{
- PACKET pkt;
int rc;
- init_packet( &pkt );
- pkt.pkttype = PKT_PUBLIC_KEY;
- pkt.pkt.public_key = pk;
- rc = search( &pkt, kbpos, 0 );
+ rc = search( pk, NULL, kbpos, 0 );
return rc;
}
/****************
- * Combined function to search for a key and get the position
- * of the keyblock.
+ * Combined function to search for a secret key and get the position
+ * of the keyblock.
*/
int
-find_keyblock_bysk( KBPOS *kbpos, PKT_secret_key *sk )
+find_secret_keyblock_bypk (KBPOS *kbpos, PKT_public_key *pk)
{
- PACKET pkt;
int rc;
- init_packet( &pkt );
- pkt.pkttype = PKT_SECRET_KEY;
- pkt.pkt.secret_key = sk;
- rc = search( &pkt, kbpos, 0 );
+ rc = search (pk, NULL, kbpos, 1);
return rc;
}
@@ -575,113 +565,27 @@ find_keyblock_bysk( KBPOS *kbpos, PKT_secret_key *sk )
int
find_secret_keyblock_byname( KBPOS *kbpos, const char *username )
{
- PACKET pkt;
- PKT_secret_key *sk = m_alloc_clear( sizeof *sk );
+ PKT_public_key *pk = m_alloc_clear( sizeof *pk );
int rc;
- rc = get_seckey_byname( sk, username, 0 );
- if( rc ) {
- free_secret_key(sk);
- return rc;
- }
-
- init_packet( &pkt );
- pkt.pkttype = PKT_SECRET_KEY;
- pkt.pkt.secret_key = sk;
- rc = search( &pkt, kbpos, 1 );
- free_secret_key(sk);
+ rc = get_pubkey_byname( NULL, pk, username, NULL );
+ if (!rc)
+ rc = search (pk, NULL, kbpos, 1);
+ free_public_key (pk);
return rc;
}
-
-/****************
- * Locate a keyblock in a database which is capable of direct access
- * Put all information into KBPOS, which can be later be to access this
- * key block.
- * This function looks into all registered keyblock sources.
- *
- * Returns: 0 if found,
- * -1 if not found
- * G10ERR_UNSUPPORTED if no resource is able to handle this
- * or another errorcode.
+/*
+ * This function locates the secret keyblock without doing a public
+ * keyring check fist. It is useful in certain situations and much
+ * faster than the generic solution.
*/
int
-locate_keyblock_by_fpr( KBPOS *kbpos, const byte *fpr, int fprlen, int secret )
-{
- RESTBL *rentry;
- int i, rc, any=0, last_rc=-1;
-
-
- for(i=0, rentry = resource_table; i < MAX_RESOURCES; i++, rentry++ ) {
- if( rentry->used && !rentry->secret == !secret ) {
- kbpos->rt = rentry->rt;
- switch( rentry->rt ) {
- #ifdef HAVE_LIBGDBM
- case rt_GDBM:
- any = 1;
- rc = do_gdbm_locate( rentry->dbf, kbpos, fpr, fprlen );
- break;
- #endif
- default:
- rc = G10ERR_UNSUPPORTED;
- break;
- }
-
- if( !rc ) {
- kbpos->resno = i;
- kbpos->fp = NULL;
- return 0;
- }
- else if( rc != -1 && rc != G10ERR_UNSUPPORTED ) {
- log_error("error searching resource %d: %s\n",
- i, g10_errstr(rc));
- last_rc = rc;
- }
- }
- }
-
- return (last_rc == -1 && !any)? G10ERR_UNSUPPORTED : last_rc;
-}
-
-
-int
-locate_keyblock_by_keyid( KBPOS *kbpos, u32 *keyid, int shortkid, int secret )
+find_secret_keyblock_direct (KBPOS *kbpos, u32 *keyid)
{
- RESTBL *rentry;
- int i, rc, any=0, last_rc=-1;
-
- if( shortkid )
- return G10ERR_UNSUPPORTED;
-
- for(i=0, rentry = resource_table; i < MAX_RESOURCES; i++, rentry++ ) {
- if( rentry->used && !rentry->secret == !secret ) {
- kbpos->rt = rentry->rt;
- switch( rentry->rt ) {
- #ifdef HAVE_LIBGDBM
- case rt_GDBM:
- any = 1;
- rc = do_gdbm_locate_by_keyid( rentry->dbf, kbpos, keyid );
- break;
- #endif
- default:
- rc = G10ERR_UNSUPPORTED;
- break;
- }
-
- if( !rc ) {
- kbpos->resno = i;
- kbpos->fp = NULL;
- return 0;
- }
- else if( rc != -1 && rc != G10ERR_UNSUPPORTED ) {
- log_error("error searching resource %d: %s\n",
- i, g10_errstr(rc));
- last_rc = rc;
- }
- }
- }
-
- return (last_rc == -1 && !any)? G10ERR_UNSUPPORTED : last_rc;
+ int rc;
+ rc = search (NULL, keyid, kbpos, 1);
+ return rc;
}
@@ -1065,21 +969,16 @@ scan_user_file_read( SCAN_USER_HANDLE hd, byte *fpr )
****************************************************************/
static int
-cmp_seckey( PKT_secret_key *req_sk, PKT_secret_key *sk )
+cmp_seckey( PKT_public_key *req_pk, PKT_secret_key *sk )
{
int n,i;
- assert( req_sk->pubkey_algo == sk->pubkey_algo );
+ if (req_pk->pubkey_algo != sk->pubkey_algo)
+ return -1;
- n = pubkey_get_nskey( req_sk->pubkey_algo );
- for(i=0; i < n; i++ ) {
- /* Note: becuase 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] ) )
+ n = pubkey_get_npkey (req_pk->pubkey_algo);
+ for (i=0; i < n; i++ ) {
+ if( mpi_cmp (req_pk->pkey[i], sk->skey[i]) )
return -1;
}
return 0;
@@ -1104,16 +1003,15 @@ cmp_pubkey( PKT_public_key *req_pk, PKT_public_key *pk )
* search one keyring, return 0 if found, -1 if not found or an errorcode.
*/
static int
-keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname )
+keyring_search( PKT_public_key *req_pk, u32 *req_keyid,
+ KBPOS *kbpos, IOBUF iobuf, const char *fname )
{
int rc;
PACKET pkt;
int save_mode;
- off_t offset;
- int pkttype = req->pkttype;
- PKT_public_key *req_pk = req->pkt.public_key;
- PKT_secret_key *req_sk = req->pkt.secret_key;
+ off_t offset, main_offset;
+ assert (!!req_pk ^ !!req_keyid); /* exactly one must be specified */
init_packet(&pkt);
save_mode = set_packet_list_mode(0);
kbpos->rt = rt_RING;
@@ -1135,29 +1033,57 @@ keyring_search( PACKET *req, KBPOS *kbpos, IOBUF iobuf, const char *fname )
}
#endif
- while( !(rc=search_packet(iobuf, &pkt, pkttype, &offset)) ) {
- if( pkt.pkttype == PKT_SECRET_KEY ) {
+ main_offset = 0;
+ while ( !(rc=search_packet(iobuf, &pkt, &offset)) ) {
+ if (pkt.pkttype == PKT_PUBLIC_KEY || pkt.pkttype == PKT_SECRET_KEY) {
+ main_offset = offset;
+ }
+
+ if (pkt.pkttype == PKT_SECRET_KEY || pkt.pkttype == PKT_SECRET_SUBKEY) {
PKT_secret_key *sk = pkt.pkt.secret_key;
- if( req_sk->timestamp == sk->timestamp
- && req_sk->pubkey_algo == sk->pubkey_algo
- && !cmp_seckey( req_sk, sk) )
- break; /* found */
+ if (req_keyid) {
+ u32 aki[2];
+
+ keyid_from_sk (sk, aki);
+ if (aki[0] == req_keyid[0] && aki[1] == req_keyid[1])
+ break; /* found */
+ }
+ else {
+ /* We can't compare the timestamps here because they
+ might differ */
+ if( !cmp_seckey (req_pk, sk) )
+ break; /* found */
+ }
}
- else if( pkt.pkttype == PKT_PUBLIC_KEY ) {
+ else if (pkt.pkttype == PKT_PUBLIC_KEY
+ || pkt.pkttype == PKT_PUBLIC_SUBKEY) {
PKT_public_key *pk = pkt.pkt.public_key;
- if( req_pk->timestamp == pk->timestamp
- && req_pk->pubkey_algo == pk->pubkey_algo
- && !cmp_pubkey( req_pk, pk ) )
- break; /* found */
+ if (req_keyid) {
+ u32 aki[2];
+
+ keyid_from_pk (pk, aki);
+ if (aki[0] == req_keyid[0] && aki[1] == req_keyid[1])
+ break; /* found */
+ }
+ else {
+ if( req_pk->timestamp == pk->timestamp
+ && req_pk->pubkey_algo == pk->pubkey_algo
+ && !cmp_pubkey( req_pk, pk ) )
+ break; /* found */
+ }
}
else
BUG();
free_packet(&pkt);
}
if( !rc ) {
- kbpos->offset = offset;
+ if (pkt.pkttype == PKT_SECRET_SUBKEY
+ || pkt.pkttype == PKT_PUBLIC_SUBKEY)
+ kbpos->offset = main_offset;
+ else
+ kbpos->offset = offset;
kbpos->valid = 1;
}
@@ -1710,6 +1636,7 @@ do_gdbm_locate( GDBM_FILE dbf, KBPOS *kbpos, const byte *fpr, int fprlen )
* locate by keyid.
* FIXME: we must have a way to enumerate thru the list opf fingerprints
*/
+#if 0 /* not used */
static int
do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid )
{
@@ -1752,7 +1679,7 @@ do_gdbm_locate_by_keyid( GDBM_FILE dbf, KBPOS *kbpos, u32 *keyid )
free( content.dptr ); /* can't use m_free() here */
return rc;
}
-
+#endif /* not used */
static int
diff --git a/g10/sig-check.c b/g10/sig-check.c
index e517e6478..fe63a1381 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -551,7 +551,8 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
}
else {
if (!opt.quiet)
- log_info ("no subkey for subkey revocation packet\n");
+ log_info ("key %08lX: no subkey for subkey revocation packet\n",
+ (ulong)keyid_from_pk (pk, NULL));
rc = G10ERR_SIG_CLASS;
}
}
@@ -574,7 +575,9 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
md_close(md);
}
else {
- log_info ("no subkey for key signature packet\n");
+ if (!opt.quiet)
+ log_info ("key %08lX: no subkey for subkey binding packet\n",
+ (ulong)keyid_from_pk (pk, NULL));
rc = G10ERR_SIG_CLASS;
}
}
@@ -607,8 +610,10 @@ check_key_signature2( KBNODE root, KBNODE node, int *is_selfsig,
md_close(md);
}
else {
- log_info ("no user ID for key signature packet of class %02x\n",
- sig->sig_class );
+ if (!opt.quiet)
+ log_info ("key %08lX: no user ID for key signature packet "
+ "of class %02x\n",
+ (ulong)keyid_from_pk (pk, NULL), sig->sig_class );
rc = G10ERR_SIG_CLASS;
}
}