diff --git a/g10/ChangeLog b/g10/ChangeLog index e3fe1e246..aff9c6bee 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,12 @@ +2005-10-13 David Shaw + + * keyedit.c (keyedit_menu, menu_backsign): New "backsign" command + to add 0x19 backsigs to old keys that don't have them. + + * misc.c (parse_options): Fix build warning. + + * main.h, keygen.c (make_backsig): Make public. + 2005-10-12 David Shaw * options.h, getkey.c (merge_selfsigs_subkey), gpg.c (main), diff --git a/g10/getkey.c b/g10/getkey.c index 241f1535c..2dde1bb51 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -2049,6 +2049,8 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode ) int seq=0; size_t n; + /* We do this while() since there may be other embedded + signatures in the future. We only want 0x19 here. */ while((p=enum_sig_subpkt(sig->hashed, SIGSUBPKT_SIGNATURE,&n,&seq,NULL))) if(n>3 && ((p[0]==3 && p[2]==0x19) || (p[0]==4 && p[1]==0x19))) @@ -2058,7 +2060,8 @@ merge_selfsigs_subkey( KBNODE keyblock, KBNODE subnode ) { seq=0; /* It is safe to have this in the unhashed area since the - 0x19 is located here for convenience, not security. */ + 0x19 is located on the selfsig for convenience, not + security. */ while((p=enum_sig_subpkt(sig->unhashed,SIGSUBPKT_SIGNATURE, &n,&seq,NULL))) if(n>3 && ((p[0]==3 && p[2]==0x19) || (p[0]==4 && p[1]==0x19))) diff --git a/g10/keyedit.c b/g10/keyedit.c index 346d0cbb8..55fc685c0 100644 --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -63,6 +63,7 @@ static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock ); 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_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 ); static int menu_set_keyserver_url (const char *url, @@ -1338,8 +1339,8 @@ enum cmdids cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG, cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY, cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, - cmdEXPIRE, cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF, - cmdPREFKS, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST, + cmdEXPIRE, cmdBACKSIGN, cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, + cmdSETPREF, cmdPREFKS, cmdINVCMD, cmdSHOWPHOTO, cmdUPDTRUST, cmdCHKTRUST, cmdADDCARDKEY, cmdKEYTOCARD, cmdBKUPTOCARD, cmdCLEAN, cmdNOP }; @@ -1363,6 +1364,7 @@ static struct { "key" , cmdSELKEY , 0, N_("select subkey N") }, { "check" , cmdCHECK , 0, N_("check signatures") }, { "c" , cmdCHECK , 0, NULL }, + { "backsign", cmdBACKSIGN , KEYEDIT_NOT_SK|KEYEDIT_NEED_SK, NULL }, { "sign" , cmdSIGN , KEYEDIT_NOT_SK|KEYEDIT_TAIL_MATCH, N_("sign selected user IDs [* see below for related commands]") }, { "s" , cmdSIGN , KEYEDIT_NOT_SK, NULL }, @@ -2051,6 +2053,15 @@ keyedit_menu( const char *username, STRLIST locusr, } break; + case cmdBACKSIGN: + if(menu_backsign(keyblock,sec_keyblock)) + { + sec_modified = 1; + modified = 1; + redisplay = 1; + } + break; + case cmdPRIMARY: if( menu_set_primary_uid ( keyblock, sec_keyblock ) ) { merge_keys_and_selfsig( keyblock ); @@ -3622,6 +3633,151 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock ) return 1; } +static int +menu_backsign(KBNODE pub_keyblock,KBNODE sec_keyblock) +{ + int rc,modified=0; + PKT_public_key *main_pk; + PKT_secret_key *main_sk,*sub_sk=NULL; + KBNODE node; + + assert(pub_keyblock->pkt->pkttype==PKT_PUBLIC_KEY); + assert(sec_keyblock->pkt->pkttype==PKT_SECRET_KEY); + + merge_keys_and_selfsig(pub_keyblock); + main_pk=pub_keyblock->pkt->pkt.public_key; + main_sk=copy_secret_key(NULL,sec_keyblock->pkt->pkt.secret_key); + keyid_from_pk(main_pk,NULL); + + for(node=pub_keyblock;node;node=node->next) + { + PKT_public_key *sub_pk=NULL; + KBNODE node2,sig_pk=NULL,sig_sk=NULL; + char *passphrase; + + if(sub_sk) + { + free_secret_key(sub_sk); + sub_sk=NULL; + } + + /* Find a signing subkey with no backsig */ + if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY + && (node->pkt->pkt.public_key->pubkey_usage&PUBKEY_USAGE_SIG) + && !node->pkt->pkt.public_key->backsig) + sub_pk=node->pkt->pkt.public_key; + + if(!sub_pk) + continue; + + /* Find the selected selfsig on this subkey */ + for(node2=node->next; + node2 && node2->pkt->pkttype==PKT_SIGNATURE; + node2=node2->next) + if(node2->pkt->pkt.signature->version>=4 + && node2->pkt->pkt.signature->flags.chosen_selfsig) + { + sig_pk=node2; + break; + } + + if(!sig_pk) + continue; + + /* Find the secret subkey that matches the public subkey */ + for(node2=sec_keyblock;node2;node2=node2->next) + if(node2->pkt->pkttype==PKT_SECRET_SUBKEY + && !cmp_public_secret_key(sub_pk,node2->pkt->pkt.secret_key)) + { + sub_sk=copy_secret_key(NULL,node2->pkt->pkt.secret_key); + break; + } + + if(!sub_sk) + continue; + + /* Now finally find the matching selfsig on the secret subkey. + We can't use chosen_selfsig here (it's not set for secret + keys), so we just pick the selfsig with the right class. + This is what menu_expire does as well. */ + for(node2=node2->next; + node2 && node2->pkt->pkttype==PKT_SIGNATURE; + node2=node2->next) + if(node2->pkt->pkt.signature->version>=4 + && node2->pkt->pkt.signature->keyid[0]==sig_pk->pkt->pkt.signature->keyid[0] + && node2->pkt->pkt.signature->keyid[1]==sig_pk->pkt->pkt.signature->keyid[1] + && node2->pkt->pkt.signature->sig_class==sig_pk->pkt->pkt.signature->sig_class) + { + sig_sk=node2; + break; + } + + if(!sig_sk) + continue; + + /* Now we can get to work. We have a main key and secret part, + a signing subkey with signature and secret part with + signature. */ + + passphrase=get_last_passphrase(); + set_next_passphrase(passphrase); + xfree(passphrase); + + rc=make_backsig(sig_pk->pkt->pkt.signature,main_pk,sub_pk,sub_sk); + if(rc==0) + { + PKT_signature *newsig; + PACKET *newpkt; + + passphrase=get_last_passphrase(); + set_next_passphrase(passphrase); + xfree(passphrase); + + rc=update_keysig_packet(&newsig,sig_pk->pkt->pkt.signature,main_pk, + NULL,sub_pk,main_sk,NULL,NULL); + if(rc==0) + { + /* Put the new sig into place on the pubkey */ + newpkt=xmalloc_clear(sizeof(*newpkt)); + newpkt->pkttype=PKT_SIGNATURE; + newpkt->pkt.signature=newsig; + free_packet(sig_pk->pkt); + xfree(sig_pk->pkt); + sig_pk->pkt=newpkt; + + /* Put the new sig into place on the seckey */ + newpkt=xmalloc_clear(sizeof(*newpkt)); + newpkt->pkttype=PKT_SIGNATURE; + newpkt->pkt.signature=copy_signature(NULL,newsig); + free_packet(sig_sk->pkt); + xfree(sig_sk->pkt); + sig_sk->pkt=newpkt; + + modified=1; + } + else + { + log_error("update_keysig_packet failed: %s\n",g10_errstr(rc)); + break; + } + } + else + { + log_error("make_backsig failed: %s\n",g10_errstr(rc)); + break; + } + } + + set_next_passphrase(NULL); + + free_secret_key(main_sk); + if(sub_sk) + free_secret_key(sub_sk); + + return modified; +} + + static int change_primary_uid_cb ( PKT_signature *sig, void *opaque ) { diff --git a/g10/keygen.c b/g10/keygen.c index 72df993c0..ae1ac6334 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -711,7 +711,7 @@ keygen_add_revkey(PKT_signature *sig, void *opaque) return 0; } -static int +int make_backsig(PKT_signature *sig,PKT_public_key *pk, PKT_public_key *sub_pk,PKT_secret_key *sub_sk) { diff --git a/g10/main.h b/g10/main.h index 07935dbed..9eda7c51d 100644 --- a/g10/main.h +++ b/g10/main.h @@ -182,6 +182,8 @@ int keygen_add_std_prefs( PKT_signature *sig, void *opaque ); int keygen_upd_std_prefs( PKT_signature *sig, void *opaque ); int keygen_add_keyserver_url(PKT_signature *sig, void *opaque); int keygen_add_revkey(PKT_signature *sig, void *opaque); +int make_backsig(PKT_signature *sig,PKT_public_key *pk, + PKT_public_key *sub_pk,PKT_secret_key *sub_sk); int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ); #ifdef ENABLE_CARD_SUPPORT int generate_card_subkeypair (KBNODE pub_keyblock, KBNODE sec_keyblock, diff --git a/g10/misc.c b/g10/misc.c index a50ab884e..c5b97740c 100644 --- a/g10/misc.c +++ b/g10/misc.c @@ -979,7 +979,7 @@ parse_options(char *str,unsigned int *options, for(i=0;opts[i].name;i++) if(opts[i].help) printf("%s%*s%s\n",opts[i].name, - maxlen+2-strlen(opts[i].name),"",_(opts[i].help)); + maxlen+2-(int)strlen(opts[i].name),"",_(opts[i].help)); g10_exit(0); }