From 4dcdaa3b1b05bd632c122c16839181ba9a039a5c Mon Sep 17 00:00:00 2001 From: David Shaw Date: Thu, 16 May 2002 03:35:55 +0000 Subject: [PATCH] * main.h, keygen.c (keygen_add_revkey): Add revocation key subpackets to a signature (callable by make_keysig_packet). (write_direct_sig): Write a 1F direct key signature. (parse_revocation_key): Parse a string in algo:fpr:sensitive format into a revocation key. (get_parameter_revkey, do_generate_keypair): Call above functions when prompted from a batch key generation file. * build-packet.c (build_sig_subpkt): Allow multiple revocation key subpackets in a single sig. * keydb.h, getkey.c (get_seckey_byfprint): Same as get_pubkey_byfprint, except for secret keys. We only know the fingerprint of a revocation key, so this is needed to retrieve the secret key needed to issue a revokation. * packet.h, parse-packet.c (parse_signature, parse_revkeys): Split revkey parsing off into a new function that can be used to reparse after manipulating the revkey list. * sign.c (make_keysig_packet): Ability to make 1F direct key signatures. --- g10/ChangeLog | 25 ++++++++ g10/build-packet.c | 1 + g10/getkey.c | 35 ++++++++++++ g10/keydb.h | 2 + g10/keygen.c | 140 ++++++++++++++++++++++++++++++++++++++++++++- g10/main.h | 1 + g10/packet.h | 1 + g10/parse-packet.c | 48 +++++++++------- g10/sign.c | 6 +- 9 files changed, 232 insertions(+), 27 deletions(-) diff --git a/g10/ChangeLog b/g10/ChangeLog index 8660d5853..13208048d 100644 --- a/g10/ChangeLog +++ b/g10/ChangeLog @@ -1,3 +1,28 @@ +2002-05-16 David Shaw + + * main.h, keygen.c (keygen_add_revkey): Add revocation key + subpackets to a signature (callable by + make_keysig_packet). (write_direct_sig): Write a 1F direct key + signature. (parse_revocation_key): Parse a string in + algo:fpr:sensitive format into a revocation + key. (get_parameter_revkey, do_generate_keypair): Call above + functions when prompted from a batch key generation file. + + * build-packet.c (build_sig_subpkt): Allow multiple revocation key + subpackets in a single sig. + + * keydb.h, getkey.c (get_seckey_byfprint): Same as + get_pubkey_byfprint, except for secret keys. We only know the + fingerprint of a revocation key, so this is needed to retrieve the + secret key needed to issue a revokation. + + * packet.h, parse-packet.c (parse_signature, parse_revkeys): Split + revkey parsing off into a new function that can be used to reparse + after manipulating the revkey list. + + * sign.c (make_keysig_packet): Ability to make 1F direct key + signatures. + 2002-05-15 David Shaw * options.skel: keyserver.pgp.com is gone, so list pgp.surfnet.nl diff --git a/g10/build-packet.c b/g10/build-packet.c index 1efb4895f..0a4d97d8a 100644 --- a/g10/build-packet.c +++ b/g10/build-packet.c @@ -710,6 +710,7 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type, { case SIGSUBPKT_NOTATION: case SIGSUBPKT_POLICY: + case SIGSUBPKT_REV_KEY: /* we do allow multiple subpackets */ break; diff --git a/g10/getkey.c b/g10/getkey.c index a11d1b94b..88f01f9ba 100644 --- a/g10/getkey.c +++ b/g10/getkey.c @@ -963,6 +963,41 @@ get_seckey_end( GETKEY_CTX ctx ) } +/**************** + * Search for a key with the given fingerprint. + * FIXME: + * We should replace this with the _byname function. Thiscsan be done + * by creating a userID conforming to the unified fingerprint style. + */ +int +get_seckey_byfprint( PKT_secret_key *sk, + const byte *fprint, size_t fprint_len) +{ + int rc; + + if( fprint_len == 20 || fprint_len == 16 ) { + struct getkey_ctx_s ctx; + KBNODE kb = NULL; + + memset( &ctx, 0, sizeof ctx ); + ctx.exact = 1 ; + ctx.not_allocated = 1; + ctx.kr_handle = keydb_new (1); + ctx.nitems = 1; + ctx.items[0].mode = fprint_len==16? KEYDB_SEARCH_MODE_FPR16 + : KEYDB_SEARCH_MODE_FPR20; + memcpy( ctx.items[0].u.fpr, fprint, fprint_len ); + rc = lookup( &ctx, &kb, 1 ); + if (!rc && sk ) + sk_from_block ( &ctx, sk, kb ); + release_kbnode ( kb ); + get_pubkey_end( &ctx ); + } + else + rc = G10ERR_GENERAL; /* Oops */ + return rc; +} + /************************************************ ************* Merging stuff ******************** diff --git a/g10/keydb.h b/g10/keydb.h index 8432c93d2..620772c34 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -206,6 +206,8 @@ int seckey_available( u32 *keyid ); int get_seckey_byname( PKT_secret_key *sk, const char *name, int unlock ); int get_seckey_bynames( GETKEY_CTX *rx, PKT_secret_key *sk, STRLIST names, KBNODE *ret_keyblock ); +int get_seckey_byfprint( PKT_secret_key *sk, + const byte *fprint, size_t fprint_len); int get_seckey_next( GETKEY_CTX ctx, PKT_secret_key *sk, KBNODE *ret_keyblock ); void get_seckey_end( GETKEY_CTX ctx ); int enum_secret_keys( void **context, PKT_secret_key *sk, int with_subkeys ); diff --git a/g10/keygen.c b/g10/keygen.c index d5b647314..b8c95d942 100644 --- a/g10/keygen.c +++ b/g10/keygen.c @@ -50,6 +50,7 @@ enum para_name { pNAMEEMAIL, pNAMECOMMENT, pPREFERENCES, + pREVOKER, pUSERID, pEXPIREDATE, pKEYEXPIRE, /* in n seconds */ @@ -67,7 +68,8 @@ struct para_data_s { DEK *dek; STRING2KEY *s2k; u32 expire; - unsigned int usage; + unsigned int usage; + struct revocation_key revkey; char value[1]; } u; }; @@ -383,6 +385,68 @@ keygen_add_std_prefs( PKT_signature *sig, void *opaque ) return 0; } +int +keygen_add_revkey(PKT_signature *sig, void *opaque) +{ + struct revocation_key *revkey=opaque; + byte buf[2+MAX_FINGERPRINT_LEN]; + + buf[0]=revkey->class; + buf[1]=revkey->algid; + memcpy(&buf[2],revkey->fpr,MAX_FINGERPRINT_LEN); + + build_sig_subpkt(sig,SIGSUBPKT_REV_KEY,buf,2+MAX_FINGERPRINT_LEN); + + sig->revkey=m_realloc(sig->revkey, + sizeof(struct revocation_key *)*(sig->numrevkeys+1)); + + /* All sigs with revocation keys set are nonrevocable */ + sig->flags.revocable=0; + buf[0] = 0; + build_sig_subpkt( sig, SIGSUBPKT_REVOCABLE, buf, 1 ); + + parse_revkeys(sig); + + return 0; +} + +static int +write_direct_sig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk, + struct revocation_key *revkey ) +{ + PACKET *pkt; + PKT_signature *sig; + int rc=0; + KBNODE node; + PKT_public_key *pk; + + if( opt.verbose ) + log_info(_("writing direct signature\n")); + + /* get the pk packet from the pub_tree */ + node = find_kbnode( pub_root, PKT_PUBLIC_KEY ); + if( !node ) + BUG(); + pk = node->pkt->pkt.public_key; + + /* we have to cache the key, so that the verification of the signature + * creation is able to retrieve the public key */ + cache_public_key (pk); + + /* and make the signature */ + rc = make_keysig_packet(&sig,pk,NULL,NULL,sk,0x1F,0,0,0,0, + keygen_add_revkey,revkey); + if( rc ) { + log_error("make_keysig_packet failed: %s\n", g10_errstr(rc) ); + return rc; + } + + pkt = m_alloc_clear( sizeof *pkt ); + pkt->pkttype = PKT_SIGNATURE; + pkt->pkt.signature = sig; + add_kbnode( root, new_kbnode( pkt ) ); + return rc; +} static int write_selfsig( KBNODE root, KBNODE pub_root, PKT_secret_key *sk, @@ -1385,6 +1449,59 @@ parse_parameter_usage (const char *fname, return 0; } +static int +parse_revocation_key (const char *fname, + struct para_data_s *para, enum para_name key) +{ + struct para_data_s *r = get_parameter( para, key ); + struct revocation_key revkey; + char *pn; + int i; + + if( !r ) + return 0; /* none (this is an optional parameter) */ + + pn = r->u.value; + + revkey.class=0x80; + revkey.algid=atoi(pn); + if(!revkey.algid) + goto fail; + + /* Skip to the fpr */ + while(*pn && *pn!=':') + pn++; + + if(*pn!=':') + goto fail; + + pn++; + + for(i=0;iu.revkey,&revkey,sizeof(struct revocation_key)); + + return 0; + + fail: + log_error("%s:%d: invalid revocation key\n", fname, r->lnr ); + return -1; /* error */ +} + static u32 get_parameter_u32( struct para_data_s *para, enum para_name key ) @@ -1421,6 +1538,12 @@ get_parameter_s2k( struct para_data_s *para, enum para_name key ) return r? r->u.s2k : NULL; } +static struct revocation_key * +get_parameter_revkey( struct para_data_s *para, enum para_name key ) +{ + struct para_data_s *r = get_parameter( para, key ); + return r? &r->u.revkey : NULL; +} static int proc_parameter_file( struct para_data_s *para, const char *fname, @@ -1478,6 +1601,10 @@ proc_parameter_file( struct para_data_s *para, const char *fname, /* Set preferences, if any. */ keygen_set_std_prefs(get_parameter_value( para, pPREFERENCES )); + /* Set revoker, if any. */ + if (parse_revocation_key (fname, para, pREVOKER)) + return -1; + /* make DEK and S2K from the Passphrase */ r = get_parameter( para, pPASSPHRASE ); if( r && *r->u.value ) { @@ -1559,6 +1686,7 @@ read_parameter_file( const char *fname ) { "Expire-Date", pEXPIREDATE }, { "Passphrase", pPASSPHRASE }, { "Preferences", pPREFERENCES }, + { "Revoker", pREVOKER }, { NULL, 0 } }; FILE *fp; @@ -1845,6 +1973,7 @@ do_generate_keypair( struct para_data_s *para, KBNODE sec_root = NULL; PKT_secret_key *sk = NULL; const char *s; + struct revocation_key *revkey; int rc; int did_sub = 0; @@ -1917,6 +2046,14 @@ do_generate_keypair( struct para_data_s *para, get_parameter_s2k( para, pPASSPHRASE_S2K ), &sk, get_parameter_u32( para, pKEYEXPIRE ) ); + + if(!rc && (revkey=get_parameter_revkey(para,pREVOKER))) + { + rc=write_direct_sig(pub_root,pub_root,sk,revkey); + if(!rc) + write_direct_sig(sec_root,pub_root,sk,revkey); + } + if( !rc && (s=get_parameter_value(para, pUSERID)) ) { write_uid(pub_root, s ); if( !rc ) @@ -2170,4 +2307,3 @@ write_keyblock( IOBUF out, KBNODE node ) } return 0; } - diff --git a/g10/main.h b/g10/main.h index cba4d4d73..6400a5f99 100644 --- a/g10/main.h +++ b/g10/main.h @@ -117,6 +117,7 @@ char *keygen_get_std_prefs (void); int keygen_add_key_expire( PKT_signature *sig, void *opaque ); int keygen_add_std_prefs( PKT_signature *sig, void *opaque ); int keygen_upd_std_prefs( PKT_signature *sig, void *opaque ); +int keygen_add_revkey(PKT_signature *sig, void *opaque); int generate_subkeypair( KBNODE pub_keyblock, KBNODE sec_keyblock ); /*-- openfile.c --*/ diff --git a/g10/packet.h b/g10/packet.h index d4f022a7a..01d32db87 100644 --- a/g10/packet.h +++ b/g10/packet.h @@ -394,6 +394,7 @@ const byte *parse_sig_subpkt ( const subpktarea_t *buffer, const byte *parse_sig_subpkt2 ( PKT_signature *sig, sigsubpkttype_t reqtype, size_t *ret_n ); +void parse_revkeys(PKT_signature *sig); int parse_attribute_subpkts(PKT_user_id *uid); void make_attribute_uidname(PKT_user_id *uid); PACKET *create_gpg_control ( ctrlpkttype_t type, diff --git a/g10/parse-packet.c b/g10/parse-packet.c index 7f0d8fe0d..df42e6282 100644 --- a/g10/parse-packet.c +++ b/g10/parse-packet.c @@ -1121,6 +1121,31 @@ parse_sig_subpkt2 (PKT_signature *sig, sigsubpkttype_t reqtype, return p; } +/* Find all revocation keys. Look in hashed area only. */ +void parse_revkeys(PKT_signature *sig) +{ + struct revocation_key *revkey; + int seq=0; + size_t len; + + if(sig->sig_class!=0x1F) + return; + + while((revkey= + (struct revocation_key *)enum_sig_subpkt(sig->hashed, + SIGSUBPKT_REV_KEY, + &len,&seq))) + { + if(len==sizeof(struct revocation_key) && + (revkey->class&0x80)) /* 0x80 bit must be set */ + { + sig->revkey=m_realloc(sig->revkey, + sizeof(struct revocation_key *)*(sig->numrevkeys+1)); + sig->revkey[sig->numrevkeys]=revkey; + sig->numrevkeys++; + } + } +} static int parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, @@ -1261,28 +1286,9 @@ parse_signature( IOBUF inp, int pkttype, unsigned long pktlen, if(p && *p==0) sig->flags.exportable=0; - /* Find all revocation keys. Back to hashed area only. */ + /* Find all revocation keys. */ if(sig->sig_class==0x1F) - { - struct revocation_key *revkey; - int seq=0; - size_t len; - - while((revkey= - (struct revocation_key *)enum_sig_subpkt(sig->hashed, - SIGSUBPKT_REV_KEY, - &len,&seq))) - { - if(len==sizeof(struct revocation_key) && - (revkey->class&0x80)) /* 0x80 bit must be set */ - { - sig->revkey=m_realloc(sig->revkey, - sizeof(struct revocation_key *)*(sig->numrevkeys+1)); - sig->revkey[sig->numrevkeys]=revkey; - sig->numrevkeys++; - } - } - } + parse_revkeys(sig); } if( list_mode ) { diff --git a/g10/sign.c b/g10/sign.c index 59e517898..fe6e62312 100644 --- a/g10/sign.c +++ b/g10/sign.c @@ -1097,7 +1097,7 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk, int rc=0; MD_HANDLE md; - assert( (sigclass >= 0x10 && sigclass <= 0x13) + assert( (sigclass >= 0x10 && sigclass <= 0x13) || sigclass == 0x1F || sigclass == 0x20 || sigclass == 0x18 || sigclass == 0x30 || sigclass == 0x28 ); @@ -1140,7 +1140,7 @@ make_keysig_packet( PKT_signature **ret_sig, PKT_public_key *pk, if( sigclass == 0x18 || sigclass == 0x28 ) { /* subkey binding/revocation*/ hash_public_key( md, subpk ); } - else if( sigclass != 0x20 ) { + else if( sigclass != 0x1F && sigclass != 0x20 ) { hash_uid (md, sigversion, uid); } /* and make the signature packet */ @@ -1241,5 +1241,3 @@ update_keysig_packet( PKT_signature **ret_sig, *ret_sig = sig; return rc; } - -