diff -Naur gnupg-2.0.28-orig/g10/keyedit.c gnupg-2.0.28/g10/keyedit.c --- gnupg-2.0.28-orig/g10/keyedit.c 2015-06-02 10:13:55.000000000 +0200 +++ gnupg-2.0.28/g10/keyedit.c 2015-09-28 11:40:08.216132804 +0200 @@ -62,6 +62,7 @@ static int menu_addrevoker( KBNODE pub_keyblock, KBNODE sec_keyblock, int sensitive ); static int menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock ); +static int menu_usage( KBNODE pub_keyblock, KBNODE sec_keyblock ); static int menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock); static int menu_set_primary_uid( KBNODE pub_keyblock, KBNODE sec_keyblock ); static int menu_set_preferences( KBNODE pub_keyblock, KBNODE sec_keyblock ); @@ -107,6 +108,11 @@ char *trust_regexp; }; +/* Bad hack: Copy from keygen.c for menu_usage */ +struct opaque_data_usage_and_pk { + unsigned int usage; + PKT_public_key *pk; +}; #ifdef ENABLE_CARD_SUPPORT /* Given a node SEC_NODE with a secret key or subkey, locate the @@ -1366,7 +1372,7 @@ cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG, cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY, cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, - cmdEXPIRE, cmdBACKSIGN, cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, + cmdEXPIRE, cmdUSAGE, cmdBACKSIGN, cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF, cmdPREFKS, cmdNOTATION, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD, cmdCLEAN, cmdMINIMIZE, cmdNOP @@ -1436,6 +1442,8 @@ N_("delete signatures from the selected user IDs") }, { "expire" , cmdEXPIRE , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("change the expiration date for the key or selected subkeys") }, + { "usage" , cmdUSAGE , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, + N_("change the usage flag for the key or selected subkeys") }, { "primary" , cmdPRIMARY , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, N_("flag the selected user ID as primary")}, { "toggle" , cmdTOGGLE , KEYEDIT_NEED_SK, @@ -2120,6 +2128,17 @@ } break; + case cmdUSAGE: + if( menu_usage( keyblock, sec_keyblock ) ) + { + merge_keys_and_selfsig( sec_keyblock ); + merge_keys_and_selfsig( keyblock ); + sec_modified = 1; + modified = 1; + redisplay = 1; + } + break; + case cmdBACKSIGN: if(menu_backsign(keyblock,sec_keyblock)) { @@ -3792,6 +3811,286 @@ if( rc ) { log_error("make_keysig_packet failed: %s\n", g10_errstr(rc)); + free_secret_key( sk ); + return 0; + } + /* replace the packet */ + newpkt = xmalloc_clear( sizeof *newpkt ); + newpkt->pkttype = PKT_SIGNATURE; + newpkt->pkt.signature = newsig; + free_packet( node->pkt ); + xfree( node->pkt ); + node->pkt = newpkt; + if( sn ) { + newpkt = xmalloc_clear( sizeof *newpkt ); + newpkt->pkttype = PKT_SIGNATURE; + newpkt->pkt.signature = copy_signature( NULL, newsig ); + free_packet( sn->pkt ); + xfree( sn->pkt ); + sn->pkt = newpkt; + } + sub_pk = NULL; + } + } + } + + free_secret_key( sk ); + update_trust=1; + return 1; +} + +/* Bad hack: Copy from keygen.c for menu_usage */ +static void +print_key_flags(int flags) +{ + if(flags&PUBKEY_USAGE_SIG) + tty_printf("%s ",_("Sign")); + + if(flags&PUBKEY_USAGE_CERT) + tty_printf("%s ",_("Certify")); + + if(flags&PUBKEY_USAGE_ENC) + tty_printf("%s ",_("Encrypt")); + + if(flags&PUBKEY_USAGE_AUTH) + tty_printf("%s ",_("Authenticate")); +} + +/* Bad hack: Copy from keygen.c for menu_usage */ +static void +do_add_key_flags (PKT_signature *sig, unsigned int use) +{ + byte buf[1]; + + buf[0] = 0; + + /* The spec says that all primary keys MUST be able to certify. */ + if(sig->sig_class!=0x18) + buf[0] |= 0x01; + + if (use & PUBKEY_USAGE_SIG) + buf[0] |= 0x02; + if (use & PUBKEY_USAGE_ENC) + buf[0] |= 0x04 | 0x08; + if (use & PUBKEY_USAGE_AUTH) + buf[0] |= 0x20; + + build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1); +} + +static int +keygen_add_key_flags (PKT_signature *sig, void *opaque) +{ + struct opaque_data_usage_and_pk *oduap = opaque; + + do_add_key_flags (sig, oduap->usage); + return 0; +} + +/* Bad hack: Copy from keygen.c for menu_usage */ +static unsigned int +ask_key_flags(int algo,int subkey) +{ + /* TRANSLATORS: Please use only plain ASCII characters for the + translation. If this is not possible use single digits. The + string needs to 8 bytes long. Here is a description of the + functions: + + s = Toggle signing capability + e = Toggle encryption capability + a = Toggle authentication capability + q = Finish + */ + const char *togglers=_("SsEeAaQq"); + char *answer=NULL; + unsigned int current=0; + unsigned int possible=openpgp_pk_algo_usage(algo); + + if ( strlen(togglers) != 8 ) + { + tty_printf ("NOTE: Bad translation at %s:%d. " + "Please report.\n", __FILE__, __LINE__); + togglers = "11223300"; + } + + /* Only primary keys may certify. */ + if(subkey) + possible&=~PUBKEY_USAGE_CERT; + + /* Preload the current set with the possible set, minus + authentication, since nobody really uses auth yet. */ + current=possible&~PUBKEY_USAGE_AUTH; + + for(;;) + { + tty_printf("\n"); + tty_printf(_("Possible actions for a %s key: "), + gcry_pk_algo_name (algo)); + print_key_flags(possible); + tty_printf("\n"); + tty_printf(_("Current allowed actions: ")); + print_key_flags(current); + tty_printf("\n\n"); + + if(possible&PUBKEY_USAGE_SIG) + tty_printf(_(" (%c) Toggle the sign capability\n"), + togglers[0]); + if(possible&PUBKEY_USAGE_ENC) + tty_printf(_(" (%c) Toggle the encrypt capability\n"), + togglers[2]); + if(possible&PUBKEY_USAGE_AUTH) + tty_printf(_(" (%c) Toggle the authenticate capability\n"), + togglers[4]); + + tty_printf(_(" (%c) Finished\n"),togglers[6]); + tty_printf("\n"); + + xfree(answer); + answer = cpr_get("keygen.flags",_("Your selection? ")); + cpr_kill_prompt(); + + if(strlen(answer)>1) + tty_printf(_("Invalid selection.\n")); + else if(*answer=='\0' || *answer==togglers[6] || *answer==togglers[7]) + break; + else if((*answer==togglers[0] || *answer==togglers[1]) + && possible&PUBKEY_USAGE_SIG) + { + if(current&PUBKEY_USAGE_SIG) + current&=~PUBKEY_USAGE_SIG; + else + current|=PUBKEY_USAGE_SIG; + } + else if((*answer==togglers[2] || *answer==togglers[3]) + && possible&PUBKEY_USAGE_ENC) + { + if(current&PUBKEY_USAGE_ENC) + current&=~PUBKEY_USAGE_ENC; + else + current|=PUBKEY_USAGE_ENC; + } + else if((*answer==togglers[4] || *answer==togglers[5]) + && possible&PUBKEY_USAGE_AUTH) + { + if(current&PUBKEY_USAGE_AUTH) + current&=~PUBKEY_USAGE_AUTH; + else + current|=PUBKEY_USAGE_AUTH; + } + else + tty_printf(_("Invalid selection.\n")); + } + + xfree(answer); + + return current; +} + +/* Bad hack: mainly copy and paste of menu_expire */ +static int +menu_usage( KBNODE pub_keyblock, KBNODE sec_keyblock ) +{ + int n1, signumber, rc; + unsigned int use; + int mainkey=0; + PKT_secret_key *sk; /* copy of the main sk */ + PKT_public_key *main_pk, *sub_pk; + struct opaque_data_usage_and_pk oduap; + PKT_user_id *uid; + KBNODE node; + u32 keyid[2]; + + if( count_selected_keys( sec_keyblock ) ) { + tty_printf(_("Please remove selections from the secret keys.\n")); + return 0; + } + + n1 = count_selected_keys( pub_keyblock ); + if( n1 > 1 ) { + tty_printf(_("Please select at most one subkey.\n")); + return 0; + } + else if( n1 ) + tty_printf(_("Changing usage of a subkey.\n")); + else + { + tty_printf(_("Changing usage of the primary key.\n")); + mainkey=1; + no_primary_warning(pub_keyblock); + } + + use = ask_key_flags(PUBKEY_ALGO_RSA, n1); /* TODO: algo abfragen und einsetzen */ + node = find_kbnode( sec_keyblock, PKT_SECRET_KEY ); + sk = copy_secret_key( NULL, node->pkt->pkt.secret_key); + + /* Now we can actually change the self signature(s) */ + main_pk = sub_pk = NULL; + uid = NULL; + signumber = 0; + for( node=pub_keyblock; node; node = node->next ) { + if( node->pkt->pkttype == PKT_PUBLIC_KEY ) { + main_pk = node->pkt->pkt.public_key; + keyid_from_pk( main_pk, keyid ); + } + else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY + && (node->flag & NODFLG_SELKEY ) ) { + sub_pk = node->pkt->pkt.public_key; + } + else if( node->pkt->pkttype == PKT_USER_ID ) + uid = node->pkt->pkt.user_id; + else if( main_pk && node->pkt->pkttype == PKT_SIGNATURE + && ( mainkey || sub_pk ) ) { + PKT_signature *sig = node->pkt->pkt.signature; + if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] + && ( (mainkey && uid + && uid->created && (sig->sig_class&~3) == 0x10) + || (!mainkey && sig->sig_class == 0x18) ) + && sig->flags.chosen_selfsig ) + { + /* this is a selfsignature which is to be replaced */ + PKT_signature *newsig; + PACKET *newpkt; + KBNODE sn; + int signumber2 = 0; + + signumber++; + + if( (mainkey && main_pk->version < 4) + || (!mainkey && sub_pk->version < 4 ) ) { + log_info(_( + "You can't change the expiration date of a v3 key\n")); + free_secret_key( sk ); + return 0; + } + + /* find the corresponding secret self-signature */ + for( sn=sec_keyblock; sn; sn = sn->next ) { + if( sn->pkt->pkttype == PKT_SIGNATURE ) { + PKT_signature *b = sn->pkt->pkt.signature; + if( keyid[0] == b->keyid[0] && keyid[1] == b->keyid[1] + && sig->sig_class == b->sig_class + && ++signumber2 == signumber ) + break; + } + } + if( !sn ) + log_info(_("No corresponding signature in secret ring\n")); + + if( mainkey ) { + oduap.usage = use; + oduap.pk = main_pk; + rc = update_keysig_packet(&newsig, sig, main_pk, uid, NULL, + sk, keygen_add_key_flags, &oduap); + } + else { + oduap.usage = use; + oduap.pk = sub_pk; + rc = update_keysig_packet(&newsig, sig, main_pk, NULL, sub_pk, + sk, keygen_add_key_flags, &oduap); + } + if( rc ) { + log_error("make_keysig_packet failed: %s\n", + g10_errstr(rc)); free_secret_key( sk ); return 0; }