diff options
Diffstat (limited to 'g10')
-rw-r--r-- | g10/ChangeLog | 42 | ||||
-rw-r--r-- | g10/build-packet.c | 2 | ||||
-rw-r--r-- | g10/cipher.c | 24 | ||||
-rw-r--r-- | g10/delkey.c | 14 | ||||
-rw-r--r-- | g10/encode.c | 5 | ||||
-rw-r--r-- | g10/getkey.c | 70 | ||||
-rw-r--r-- | g10/kbnode.c | 5 | ||||
-rw-r--r-- | g10/keydb.h | 8 | ||||
-rw-r--r-- | g10/keyedit.c | 29 | ||||
-rw-r--r-- | g10/keygen.c | 28 | ||||
-rw-r--r-- | g10/packet.h | 11 | ||||
-rw-r--r-- | g10/parse-packet.c | 34 | ||||
-rw-r--r-- | g10/pkclist.c | 25 | ||||
-rw-r--r-- | g10/ringedit.c | 259 | ||||
-rw-r--r-- | g10/sig-check.c | 13 |
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; } } |