#define CONTROL_D ('D' - 'A' + 1)
+/* fixme: we have nearly the same code in keyedit.c */
+static void
+print_fpr( PKT_public_key *pk )
+{
+ byte array[MAX_FINGERPRINT_LEN], *p;
+ size_t i, n;
+
+ fingerprint_from_pk( pk, array, &n );
+ p = array;
+ /* Translators: this shoud fit into 24 bytes to that the fingerprint
+ * data is properly aligned with the user ID */
+ tty_printf(_(" Fingerprint:"));
+ if( n == 20 ) {
+ for(i=0; i < n ; i++, i++, p += 2 ) {
+ if( i == 10 )
+ tty_printf(" ");
+ tty_printf(" %02X%02X", *p, p[1] );
+ }
+ }
+ else {
+ for(i=0; i < n ; i++, p++ ) {
+ if( i && !(i%8) )
+ tty_printf(" ");
+ tty_printf(" %02X", *p );
+ }
+ }
+ tty_printf("\n");
+}
+
+static void
+fpr_info( PKT_public_key *pk )
+{
+ byte array[MAX_FINGERPRINT_LEN], *p;
+ size_t i, n;
+ FILE *fp = log_stream();
+
+ fingerprint_from_pk( pk, array, &n );
+ p = array;
+ log_info(_("Fingerprint:"));
+ if( n == 20 ) {
+ for(i=0; i < n ; i++, i++, p += 2 ) {
+ if( i == 10 )
+ putc(' ', fp);
+ fprintf(fp, " %02X%02X", *p, p[1] );
+ }
+ }
+ else {
+ for(i=0; i < n ; i++, p++ ) {
+ if( i && !(i%8) )
+ putc(' ', fp);
+ fprintf(fp, " %02X", *p );
+ }
+ }
+ putc('\n', fp );
+}
+
+
static void
show_paths( ulong lid, int only_first )
last_level = 0;
while( (level=enum_cert_paths( &context, &lid, &otrust, &validity)) != -1){
char *p;
- int rc;
+ int c, rc;
size_t n;
u32 keyid[2];
PKT_public_key *pk ;
level*2, "",
nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ),
(ulong)keyid[1], lid, datestr_from_pk( pk ) );
- #if 0
+
c = trust_letter(otrust);
if( c )
putchar( c );
else
printf( "%02x", validity );
putchar(' ');
- #endif
-
p = get_user_id( keyid, &n );
tty_print_string( p, n ),
/****************
* Returns true if an ownertrust has changed.
*/
-int
-edit_ownertrust( ulong lid, int mode )
+static int
+do_edit_ownertrust( ulong lid, int mode, unsigned *new_trust, int defer_help )
{
char *p;
int rc;
PKT_public_key *pk ;
int changed=0;
int quit=0;
+ int show=0;
+ int did_help=defer_help;
rc = keyid_from_lid( lid, keyid );
if( rc ) {
return 0;
}
- if( !mode ) {
- tty_printf(_("No trust value assigned to %lu:\n"
- "%4u%c/%08lX %s \""), lid,
- nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ),
- (ulong)keyid[1], datestr_from_pk( pk ) );
- p = get_user_id( keyid, &n );
- tty_print_string( p, n ),
- m_free(p);
- tty_printf("\"\n\n");
- }
- tty_printf(_(
+
+ for(;;) {
+ /* a string with valid answers */
+ char *ans = _("sSmMqQ");
+
+ if( !did_help ) {
+ if( !mode ) {
+ tty_printf(_("No trust value assigned to %lu:\n"
+ "%4u%c/%08lX %s \""), lid,
+ nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ),
+ (ulong)keyid[1], datestr_from_pk( pk ) );
+ p = get_user_id( keyid, &n );
+ tty_print_string( p, n ),
+ m_free(p);
+ tty_printf("\"\n");
+ print_fpr( pk );
+ tty_printf("\n");
+ }
+ tty_printf(_(
"Please decide how far you trust this user to correctly\n"
"verify other users' keys (by looking at passports,\n"
"checking fingerprints from different sources...)?\n\n"
" 3 = I trust marginally\n"
" 4 = I trust fully\n"
" s = please show me more information\n") );
- if( mode )
- tty_printf(_(" m = back to the main menu\n"));
- else
- tty_printf(_(" q = quit\n"));
- tty_printf("\n");
-
- for(;;) {
- /* a string with valid answers */
- char *ans = _("sSmMqQ");
-
+ if( mode )
+ tty_printf(_(" m = back to the main menu\n"));
+ else
+ tty_printf(_(" q = quit\n"));
+ tty_printf("\n");
+ did_help = 1;
+ }
if( strlen(ans) != 6 )
BUG();
p = cpr_get("edit_ownertrust.value",_("Your decision? "));
trim_spaces(p);
cpr_kill_prompt();
- if( *p && p[1] )
+ if( !*p )
+ did_help = 0;
+ else if( *p && p[1] )
;
else if( !p[1] && (*p >= '1' && *p <= '4') ) {
unsigned trust;
case '4': trust = TRUST_FULLY ; break;
default: BUG();
}
- if( !update_ownertrust( lid, trust ) )
- changed++;
+ *new_trust = trust;
+ changed = 1;
break;
}
else if( *p == ans[0] || *p == ans[1] ) {
tty_printf(_(
"Certificates leading to an ultimately trusted key:\n"));
- show_paths( lid, 1 );
+ show = 1;
+ break;
}
else if( mode && (*p == ans[2] || *p == ans[3] || *p == CONTROL_D ) ) {
break ; /* back to the menu */
}
m_free(p);
m_free(pk);
- return quit? -1 : changed;
+ return show? -2: quit? -1 : changed;
+}
+
+
+int
+edit_ownertrust( ulong lid, int mode )
+{
+ unsigned int trust;
+ int no_help = 0;
+
+ for(;;) {
+ switch( do_edit_ownertrust( lid, mode, &trust, no_help ) ) {
+ case -1:
+ return 0;
+ case -2:
+ show_paths( lid, 1 );
+ no_help = 1;
+ break;
+ case 1:
+ trust &= ~TRUST_FLAG_DISABLED;
+ trust |= get_ownertrust( lid ) & TRUST_FLAG_DISABLED;
+ if( !update_ownertrust( lid, trust ) )
+ return 1;
+ return 0;
+ default:
+ return 0;
+ }
+ }
}
+static int
+add_ownertrust_cb( ulong lid )
+{
+ unsigned trust;
+ int rc = do_edit_ownertrust( lid, 0, &trust, 0 );
+
+ if( rc == 1 )
+ return trust & TRUST_MASK;
+ return rc > 0? 0 : rc;
+}
/****************
* Try to add some more owner trusts (interactive)
* This function presents all the signator in a certificate
- * chain who have no trust value assigned.
+ * chain who have no ownertrust value assigned.
* Returns: -1 if no ownertrust were added.
*/
static int
-add_ownertrust( PKT_public_key *pk, int *quit )
+add_ownertrust( PKT_public_key *pk, int *quit, unsigned *trustlevel )
{
int rc;
- void *context = NULL;
- ulong lid;
- unsigned otrust, validity;
- int any=0, changed=0, any_undefined=0;
+ unsigned flags = 0;
*quit = 0;
+ *trustlevel = 0;
tty_printf(
_("Could not find a valid trust path to the key. Let's see whether we\n"
"can assign some missing owner trust values.\n\n"));
- rc = query_trust_record( pk );
- if( rc ) {
- log_error("Ooops: not in trustdb\n");
- return -1;
- }
-
- lid = pk->local_id;
- while( enum_cert_paths( &context, &lid, &otrust, &validity ) != -1 ) {
- if( lid == pk->local_id )
- continue;
- any=1;
- if( changed ) {
- /* because enum_cert_paths() makes a snapshop of the
- * trust paths, the otrust and validity are not anymore
- * valid after changing an entry - we have to reread
- * those values from then on
- */
- otrust = get_ownertrust( lid );
- }
- if( otrust == TRUST_UNDEFINED ) {
- any_undefined=1;
- enum_cert_paths_print( &context, NULL, changed, lid );
- tty_printf("\n");
- rc = edit_ownertrust( lid, 0 );
- if( rc == -1 ) {
- *quit = 1;
- break;
- }
- else if( rc > 0 )
- changed = 1;
- }
- }
- enum_cert_paths( &context, NULL, NULL, NULL ); /* release context */
+ rc = check_trust( pk, trustlevel, NULL, add_ownertrust_cb, &flags );
- if( !any )
+ if( !(flags & 1) )
tty_printf(_("No path leading to one of our keys found.\n\n") );
- else if( !any_undefined )
+ else if( !(flags & 2) )
tty_printf(_("No certificates with undefined trust found.\n\n") );
- else if( !changed )
+ else if( !(flags & 4) )
tty_printf(_("No trust values changed.\n\n") );
- return changed? 0:-1;
+ return (flags & 4)? 0:-1;
}
/****************
do_we_trust( PKT_public_key *pk, int trustlevel )
{
int rc;
+ int did_add = 0;
+ retry:
if( (trustlevel & TRUST_FLAG_REVOKED) ) {
log_info(_("key %08lX: key has been revoked!\n"),
(ulong)keyid_from_pk( pk, NULL) );
_("Use this key anyway? ")) )
return 0;
}
+ else if( (trustlevel & TRUST_FLAG_SUB_REVOKED) ) {
+ log_info(_("key %08lX: subkey has been revoked!\n"),
+ (ulong)keyid_from_pk( pk, NULL) );
+ if( opt.batch )
+ return 0;
+
+ if( !cpr_get_answer_is_yes("revoked_key.override",
+ _("Use this key anyway? ")) )
+ return 0;
+ }
switch( (trustlevel & TRUST_MASK) ) {
case TRUST_UNKNOWN: /* No pubkey in trustDB: Insert and check again */
- rc = insert_trust_record( pk );
+ rc = insert_trust_record_by_pk( pk );
if( rc ) {
log_error("failed to insert it into the trustdb: %s\n",
g10_errstr(rc) );
return 0; /* no */
}
- rc = check_trust( pk, &trustlevel );
+ rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
if( rc )
log_fatal("trust check after insert failed: %s\n",
g10_errstr(rc) );
- if( trustlevel == TRUST_UNKNOWN || trustlevel == TRUST_EXPIRED )
- BUG();
+ if( trustlevel == TRUST_UNKNOWN || trustlevel == TRUST_EXPIRED ) {
+ log_debug("do_we_trust: oops at %d\n", __LINE__ );
+ return 0;
+ }
return do_we_trust( pk, trustlevel );
case TRUST_EXPIRED:
else {
int quit;
- rc = add_ownertrust( pk, &quit );
- if( !rc && !quit ) {
- rc = check_trust( pk, &trustlevel );
- if( rc )
- log_fatal("trust check after add_ownertrust failed: %s\n",
- g10_errstr(rc) );
- /* fixme: this is recursive; we should unroll it */
- return do_we_trust( pk, trustlevel );
+ rc = add_ownertrust( pk, &quit, &trustlevel );
+ if( !rc && !did_add && !quit ) {
+ did_add = 1;
+ goto retry;
}
}
return 0;
default: BUG();
}
-
- /* Eventuell fragen falls der trustlevel nicht ausreichend ist */
-
-
return 1; /* yes */
}
+
/****************
* wrapper around do_we_trust, so we can ask whether to use the
* key anyway.
if( (trustlevel & TRUST_FLAG_REVOKED) && !rc )
return 0;
+ if( (trustlevel & TRUST_FLAG_SUB_REVOKED) && !rc )
+ return 0;
else if( !opt.batch && !rc ) {
+ char *p;
+ u32 keyid[2];
+ size_t n;
+
+ keyid_from_pk( pk, keyid);
+ tty_printf( "%4u%c/%08lX %s \"",
+ nbits_from_pk( pk ), pubkey_letter( pk->pubkey_algo ),
+ (ulong)keyid[1], datestr_from_pk( pk ) );
+ p = get_user_id( keyid, &n );
+ tty_print_string( p, n ),
+ m_free(p);
+ tty_printf("\"\n");
+ print_fpr( pk );
+ tty_printf("\n");
+
tty_printf(_(
"It is NOT certain that the key belongs to its owner.\n"
"If you *really* know what you are doing, you may answer\n"
if( cpr_get_answer_is_yes("untrusted_key.override",
_("Use this key anyway? ")) )
rc = 1;
+
+ /* Hmmm: Should we set a flag to tell the user the user about
+ * his decision the next time he encrypts for this recipient?
+ */
}
else if( opt.always_trust && !rc ) {
- log_info(_("WARNING: Using untrusted key!\n"));
+ if( !opt.quiet )
+ log_info(_("WARNING: Using untrusted key!\n"));
rc = 1;
}
return rc;
{
PKT_public_key *pk = m_alloc_clear( sizeof *pk );
int trustlevel;
- int dont_try = 0;
+ int did_add = 0;
int rc=0;
+
+ if( opt.always_trust ) {
+ if( !opt.quiet )
+ log_info(_("WARNING: Using untrusted key!\n"));
+ return 0;
+ }
+
+
rc = get_pubkey( pk, sig->keyid );
if( rc ) { /* this should not happen */
log_error("Ooops; the key vanished - can't check the trust\n");
goto leave;
}
- retry:
- rc = check_trust( pk, &trustlevel );
+ rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
if( rc ) {
log_error("check trust failed: %s\n", g10_errstr(rc));
goto leave;
}
+ retry:
if( (trustlevel & TRUST_FLAG_REVOKED) ) {
write_status( STATUS_KEYREVOKED );
log_info(_("WARNING: This key has been revoked by its owner!\n"));
log_info(_(" This could mean that the signature is forgery.\n"));
}
+ else if( (trustlevel & TRUST_FLAG_SUB_REVOKED) ) {
+ write_status( STATUS_KEYREVOKED );
+ log_info(_("WARNING: This subkey has been revoked by its owner!\n"));
+ }
switch( (trustlevel & TRUST_MASK) ) {
case TRUST_UNKNOWN: /* No pubkey in trustDB: Insert and check again */
- rc = insert_trust_record( pk );
+ rc = insert_trust_record_by_pk( pk );
if( rc ) {
log_error("failed to insert it into the trustdb: %s\n",
g10_errstr(rc) );
goto leave;
}
- rc = check_trust( pk, &trustlevel );
+ rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
if( rc )
log_fatal("trust check after insert failed: %s\n",
g10_errstr(rc) );
case TRUST_EXPIRED:
log_info(_("Note: This key has expired!\n"));
+ fpr_info( pk );
break;
case TRUST_UNDEFINED:
- if( dont_try || opt.batch || opt.answer_no ) {
+ if( did_add || opt.batch || opt.answer_no ) {
write_status( STATUS_TRUST_UNDEFINED );
log_info(_(
"WARNING: This key is not certified with a trusted signature!\n"));
log_info(_(
" There is no indication that the "
"signature belongs to the owner.\n" ));
+ fpr_info( pk );
}
else {
int quit;
- rc = add_ownertrust( pk, &quit );
+ rc = add_ownertrust( pk, &quit, &trustlevel );
if( rc || quit ) {
- dont_try = 1;
+ did_add = 1;
rc = 0;
}
goto retry;
log_info(_(
" It is not certain that the signature belongs to the owner.\n"
));
+ fpr_info( pk );
break;
case TRUST_FULLY:
}
}
+
+static int
+key_present_in_pk_list(PK_LIST pk_list, PKT_public_key *pk)
+{
+ for( ; pk_list; pk_list = pk_list->next)
+ if (cmp_public_keys(pk_list->pk, pk) == 0)
+ return 0;
+
+ return -1;
+}
+
+
+/****************
+ * Return a malloced string with a default reciepient if there is any
+ */
+static char *
+default_recipient(void)
+{
+ PKT_secret_key *sk;
+ byte fpr[MAX_FINGERPRINT_LEN+1];
+ size_t n;
+ char *p;
+ int i;
+
+ if( opt.def_recipient )
+ return m_strdup( opt.def_recipient );
+ if( !opt.def_recipient_self )
+ return NULL;
+ sk = m_alloc_clear( sizeof *sk );
+ i = get_seckey_byname( sk, NULL, 0 );
+ if( i ) {
+ free_secret_key( sk );
+ return NULL;
+ }
+ n = MAX_FINGERPRINT_LEN;
+ fingerprint_from_sk( sk, fpr, &n );
+ free_secret_key( sk );
+ p = m_alloc( 2*n+3 );
+ *p++ = '0';
+ *p++ = 'x';
+ for(i=0; i < n; i++ )
+ sprintf( p+2*i, "%02X", fpr[i] );
+ p -= 2;
+ return p;
+}
+
+
int
build_pk_list( STRLIST remusr, PK_LIST *ret_pk_list, unsigned use )
{
int rc=0;
int any_recipients=0;
STRLIST rov;
+ char *def_rec = NULL;
/* check whether there are any recipients in the list and build the
* list of the encrypt-to ones (we always trust them) */
log_error(_("%s: skipped: %s\n"), rov->d, g10_errstr(rc) );
}
else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) {
- PK_LIST r;
- r = m_alloc( sizeof *r );
- r->pk = pk; pk = NULL;
- r->next = pk_list;
- r->mark = 0;
- pk_list = r;
+ /* Skip the actual key if the key is already present
+ * in the list */
+ if (key_present_in_pk_list(pk_list, pk) == 0) {
+ free_public_key(pk); pk = NULL;
+ log_info(_("%s: skipped: public key already present\n"),
+ rov->d);
+ }
+ else {
+ PK_LIST r;
+ r = m_alloc( sizeof *r );
+ r->pk = pk; pk = NULL;
+ r->next = pk_list;
+ r->mark = 0;
+ pk_list = r;
+ }
}
else {
free_public_key( pk ); pk = NULL;
if( !any_recipients && !opt.batch ) { /* ask */
char *answer=NULL;
+ int have_def_rec;
- tty_printf(_(
+ def_rec = default_recipient();
+ have_def_rec = !!def_rec;
+ if( !have_def_rec )
+ tty_printf(_(
"You did not specify a user ID. (you may use \"-r\")\n\n"));
for(;;) {
rc = 0;
m_free(answer);
- answer = cpr_get_utf8("pklist.user_id.enter",
- _("Enter the user ID: "));
- trim_spaces(answer);
- cpr_kill_prompt();
+ if( have_def_rec ) {
+ answer = def_rec;
+ def_rec = NULL;
+ }
+ else {
+ answer = cpr_get_utf8("pklist.user_id.enter",
+ _("Enter the user ID: "));
+ trim_spaces(answer);
+ cpr_kill_prompt();
+ }
if( !*answer )
break;
if( pk )
if( rc )
tty_printf(_("No such user ID.\n"));
else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) {
- int trustlevel;
-
- rc = check_trust( pk, &trustlevel );
- if( rc ) {
- log_error("error checking pk of `%s': %s\n",
- answer, g10_errstr(rc) );
- }
- else if( do_we_trust_pre( pk, trustlevel ) ) {
- PK_LIST r;
-
- r = m_alloc( sizeof *r );
- r->pk = pk; pk = NULL;
- r->next = pk_list;
- r->mark = 0;
- pk_list = r;
+ if( have_def_rec ) {
+ if (key_present_in_pk_list(pk_list, pk) == 0) {
+ free_public_key(pk); pk = NULL;
+ log_info(_("skipped: public key "
+ "already set as default recipient\n") );
+ }
+ else {
+ PK_LIST r = m_alloc( sizeof *r );
+ r->pk = pk; pk = NULL;
+ r->next = pk_list;
+ r->mark = 0;
+ pk_list = r;
+ }
any_recipients = 1;
break;
}
+ else {
+ int trustlevel;
+
+ rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
+ if( rc ) {
+ log_error("error checking pk of `%s': %s\n",
+ answer, g10_errstr(rc) );
+ }
+ else if( (trustlevel & TRUST_FLAG_DISABLED) ) {
+ tty_printf(_("Public key is disabled.\n") );
+ }
+ else if( do_we_trust_pre( pk, trustlevel ) ) {
+ /* Skip the actual key if the key is already present
+ * in the list */
+ if (key_present_in_pk_list(pk_list, pk) == 0) {
+ free_public_key(pk); pk = NULL;
+ log_info(_("skipped: public key "
+ "already set with --encrypt-to\n") );
+ }
+ else {
+ PK_LIST r;
+
+ r = m_alloc( sizeof *r );
+ r->pk = pk; pk = NULL;
+ r->next = pk_list;
+ r->mark = 0;
+ pk_list = r;
+ }
+ any_recipients = 1;
+ break;
+ }
+ }
}
+ m_free(def_rec); def_rec = NULL;
+ have_def_rec = 0;
}
m_free(answer);
if( pk ) {
pk = NULL;
}
}
+ else if( !any_recipients && (def_rec = default_recipient()) ) {
+ pk = m_alloc_clear( sizeof *pk );
+ pk->pubkey_usage = use;
+ rc = get_pubkey_byname( NULL, pk, def_rec, NULL );
+ if( rc )
+ log_error(_("unknown default recipient `%s'\n"), def_rec );
+ else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use)) ) {
+ PK_LIST r = m_alloc( sizeof *r );
+ r->pk = pk; pk = NULL;
+ r->next = pk_list;
+ r->mark = 0;
+ pk_list = r;
+ any_recipients = 1;
+ }
+ if( pk ) {
+ free_public_key( pk );
+ pk = NULL;
+ }
+ m_free(def_rec); def_rec = NULL;
+ }
else {
+ any_recipients = 0;
for(; remusr; remusr = remusr->next ) {
if( (remusr->flags & 1) )
continue; /* encrypt-to keys are already handled */
else if( !(rc=check_pubkey_algo2(pk->pubkey_algo, use )) ) {
int trustlevel;
- rc = check_trust( pk, &trustlevel );
+ rc = check_trust( pk, &trustlevel, NULL, NULL, NULL );
if( rc ) {
free_public_key( pk ); pk = NULL;
log_error(_("%s: error checking key: %s\n"),
remusr->d, g10_errstr(rc) );
}
+ else if( (trustlevel & TRUST_FLAG_DISABLED) ) {
+ free_public_key(pk); pk = NULL;
+ log_info(_("%s: skipped: public key is disabled\n"),
+ remusr->d);
+ }
else if( do_we_trust_pre( pk, trustlevel ) ) {
/* note: do_we_trust may have changed the trustlevel */
- PK_LIST r;
- r = m_alloc( sizeof *r );
- r->pk = pk; pk = NULL;
- r->next = pk_list;
- r->mark = 0;
- pk_list = r;
+ /* We have at least one valid recipient. It doesn't matters
+ * if this recipient is already present. */
any_recipients = 1;
+
+ /* Skip the actual key if the key is already present
+ * in the list */
+ if (key_present_in_pk_list(pk_list, pk) == 0) {
+ free_public_key(pk); pk = NULL;
+ log_info(_("%s: skipped: public key already present\n"),
+ remusr->d);
+ }
+ else {
+ PK_LIST r;
+ r = m_alloc( sizeof *r );
+ r->pk = pk; pk = NULL;
+ r->next = pk_list;
+ r->mark = 0;
+ pk_list = r;
+ }
}
else { /* we don't trust this pk */
free_public_key( pk ); pk = NULL;
algo_available( int preftype, int algo )
{
if( preftype == PREFTYPE_SYM ) {
+ if( algo == CIPHER_ALGO_TWOFISH )
+ return 0; /* we don't want to generate Twofish messages for now*/
return algo && !check_cipher_algo( algo );
}
else if( preftype == PREFTYPE_HASH ) {
memset( mask, 0, 8 * sizeof *mask );
if( !pkr->pk->local_id ) { /* try to set the local id */
- query_trust_info( pkr->pk );
+ query_trust_info( pkr->pk, NULL );
if( !pkr->pk->local_id ) {
log_debug("select_algo_from_prefs: can't get LID\n");
continue;
if( pref ) {
for(j=0; j+1 < npref; j+=2 ) {
if( pref[j] == preftype ) {
- any = 1;
if( (bits[pref[j+1]/32] & (1<<(pref[j+1]%32))) ) {
if( algo_available( preftype, pref[j+1] ) ) {
+ any = 1;
i = pref[j+1];
break;
}