1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-10 13:04:23 +01:00

Photo ID support (actually generic "attribute packet" support, but there

is only one attribute packet defined thus far, and it's a picture)
This commit is contained in:
David Shaw 2001-12-21 23:06:02 +00:00
parent ca058399b0
commit d560bdac18
16 changed files with 522 additions and 350 deletions

View File

@ -1,3 +1,56 @@
2001-12-21 David Shaw <dshaw@jabberwocky.com>
* Makefile.am: add exec.c, exec.h, photoid.c, and photoid.h
* build-packet.c (build_attribute_subpkt): new function to build
the raw attribute subpacket. Note that attribute subpackets have
the same format as signature subpackets.
* exec.c: new file with generic exec-a-program functionality.
Used by both photo IDs and keyserver helpers. This is pretty much
the same code that used to be keyserver specific, with some
changes to be usable generically.
* free-packet.c (free_attributes (new)): function to free an
attribute packet.
* gpgv.c: added stub show_photo
* keyedit.c (keyedit_menu, menu_adduid, menu_showphoto): can add a
photo (calls generate_photo_id), or display a photo (calls
show_photo) from the --edit menu. New commands are "addphoto",
and "delphoto" (same as "deluid").
* keylist.c (list_keyblock_print): show photos during key list if
--show-photos enabled.
* keyserver.c (keyserver_spawn): use the generic exec_xxx
functions to call keyserver helper.
* g10.c, options.h: three new options - --{no-}show-photos, and
--photo-viewer to give the command line to display a picture.
* options.skel: instructions for the photo viewer
* parse-packet.c (parse_user_id, setup_user_id (new)): common code
for both user IDs and attribute IDs moved to setup_user_id.
* parse-packet.c (make_attribute_uidname (new)): constructs a fake
"name" for attribute packets (e.g. "[image of size ...]")
* parse-packet.c (parse_attribute (replaces parse_photo_id),
parse_attribute_subpkts): Builds an array of individual
attributes. Currently only handles attribute image / type jpeg
subpackets.
* sign.c (hash_uid): Fix bug in signing attribute (formerly
photo_id) packets.
* packet.h, and callers: globally change "photo_id" to "attribute"
and add structures for attributes. The packet format is generic
attributes, even though the only attribute type thus far defined
is jpeg.
2001-12-21 David Shaw <dshaw@jabberwocky.com> 2001-12-21 David Shaw <dshaw@jabberwocky.com>
* parse-packet.c (can_handle_critical): Can handle critical * parse-packet.c (can_handle_critical): Can handle critical

View File

@ -56,7 +56,7 @@ common_source = \
plaintext.c \ plaintext.c \
sig-check.c \ sig-check.c \
keylist.c \ keylist.c \
signal.c signal.c
gpg_SOURCES = g10.c \ gpg_SOURCES = g10.c \
$(common_source) \ $(common_source) \
@ -88,7 +88,11 @@ gpg_SOURCES = g10.c \
pipemode.c \ pipemode.c \
helptext.c \ helptext.c \
keyserver.c \ keyserver.c \
keyserver-internal.h keyserver-internal.h \
photoid.c photoid.h \
exec.c exec.h
gpgv_SOURCES = gpgv.c \ gpgv_SOURCES = gpgv.c \
$(common_source) \ $(common_source) \

View File

@ -81,8 +81,8 @@ build_packet( IOBUF out, PACKET *pkt )
case PKT_ENCRYPTED_MDC: new_ctb = pkt->pkt.encrypted->new_ctb; break; case PKT_ENCRYPTED_MDC: new_ctb = pkt->pkt.encrypted->new_ctb; break;
case PKT_COMPRESSED:new_ctb = pkt->pkt.compressed->new_ctb; break; case PKT_COMPRESSED:new_ctb = pkt->pkt.compressed->new_ctb; break;
case PKT_USER_ID: case PKT_USER_ID:
if( pkt->pkt.user_id->photo ) if( pkt->pkt.user_id->attrib_data )
pkttype = PKT_PHOTO_ID; pkttype = PKT_ATTRIBUTE;
break; break;
default: break; default: break;
} }
@ -92,7 +92,7 @@ build_packet( IOBUF out, PACKET *pkt )
else else
ctb = 0x80 | ((pkttype & 15)<<2); ctb = 0x80 | ((pkttype & 15)<<2);
switch( pkttype ) { switch( pkttype ) {
case PKT_PHOTO_ID: case PKT_ATTRIBUTE:
case PKT_USER_ID: case PKT_USER_ID:
rc = do_user_id( out, ctb, pkt->pkt.user_id ); rc = do_user_id( out, ctb, pkt->pkt.user_id );
break; break;
@ -159,7 +159,7 @@ calc_packet_length( PACKET *pkt )
n = calc_plaintext( pkt->pkt.plaintext ); n = calc_plaintext( pkt->pkt.plaintext );
new_ctb = pkt->pkt.plaintext->new_ctb; new_ctb = pkt->pkt.plaintext->new_ctb;
break; break;
case PKT_PHOTO_ID: case PKT_ATTRIBUTE:
case PKT_USER_ID: case PKT_USER_ID:
case PKT_COMMENT: case PKT_COMMENT:
case PKT_PUBLIC_KEY: case PKT_PUBLIC_KEY:
@ -207,9 +207,9 @@ do_comment( IOBUF out, int ctb, PKT_comment *rem )
static int static int
do_user_id( IOBUF out, int ctb, PKT_user_id *uid ) do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
{ {
if( uid->photo ) { if( uid->attrib_data ) {
write_header(out, ctb, uid->photolen); write_header(out, ctb, uid->attrib_len);
if( iobuf_write( out, uid->photo, uid->photolen ) ) if( iobuf_write( out, uid->attrib_data, uid->attrib_len ) )
return G10ERR_WRITE_FILE; return G10ERR_WRITE_FILE;
} }
else { else {
@ -910,6 +910,52 @@ build_sig_subpkt_from_sig( PKT_signature *sig )
} }
} }
void
build_attribute_subpkt(PKT_user_id *uid,byte type,
const void *buf,int buflen,
const void *header,int headerlen)
{
byte *attrib;
int index;
if(1+headerlen+buflen>8383)
index=5;
else if(1+headerlen+buflen>191)
index=2;
else
index=1;
/* realloc uid->attrib_data to the right size */
uid->attrib_data=m_realloc(uid->attrib_data,
uid->attrib_len+index+headerlen+buflen);
attrib=&uid->attrib_data[uid->attrib_len];
if(index==5)
{
attrib[0]=255;
attrib[1]=(1+headerlen+buflen) >> 24;
attrib[2]=(1+headerlen+buflen) >> 16;
attrib[3]=(1+headerlen+buflen) >> 8;
attrib[4]=1+headerlen+buflen;
}
else if(index==2)
{
attrib[0]=(1+headerlen+buflen-192) / 256 + 192;
attrib[1]=(1+headerlen+buflen-192) % 256;
}
else
attrib[0]=1+headerlen+buflen; /* Good luck finding a JPEG this small! */
attrib[index++]=type;
/* Tack on our data at the end */
memcpy(&attrib[index],header,headerlen);
memcpy(&attrib[index+headerlen],buf,buflen);
uid->attrib_len+=index+headerlen+buflen;
}
static int static int
do_signature( IOBUF out, int ctb, PKT_signature *sig ) do_signature( IOBUF out, int ctb, PKT_signature *sig )

View File

@ -261,6 +261,17 @@ free_comment( PKT_comment *rem )
m_free(rem); m_free(rem);
} }
void
free_attributes(PKT_user_id *uid)
{
m_free(uid->attribs);
m_free(uid->attrib_data);
uid->attribs=NULL;
uid->attrib_data=NULL;
uid->attrib_len=0;
}
void void
free_user_id (PKT_user_id *uid) free_user_id (PKT_user_id *uid)
{ {
@ -268,8 +279,8 @@ free_user_id (PKT_user_id *uid)
if (--uid->ref) if (--uid->ref)
return; return;
if (uid->photo) free_attributes(uid);
m_free (uid->photo);
if (uid->prefs) if (uid->prefs)
m_free (uid->prefs); m_free (uid->prefs);
m_free (uid); m_free (uid);

View File

@ -194,6 +194,9 @@ enum cmd_and_opt_values { aNull = 0,
oComment, oComment,
oDefaultComment, oDefaultComment,
oThrowKeyid, oThrowKeyid,
oShowPhotos,
oNoShowPhotos,
oPhotoViewer,
oForceV3Sigs, oForceV3Sigs,
oNoForceV3Sigs, oNoForceV3Sigs,
oForceV4Certs, oForceV4Certs,
@ -381,6 +384,9 @@ static ARGPARSE_OPTS opts[] = {
{ oDigestAlgo, "digest-algo", 2 , N_("|NAME|use message digest algorithm NAME")}, { oDigestAlgo, "digest-algo", 2 , N_("|NAME|use message digest algorithm NAME")},
{ oCompressAlgo, "compress-algo", 1 , N_("|N|use compress algorithm N")}, { oCompressAlgo, "compress-algo", 1 , N_("|N|use compress algorithm N")},
{ oThrowKeyid, "throw-keyid", 0, N_("throw keyid field of encrypted packets")}, { oThrowKeyid, "throw-keyid", 0, N_("throw keyid field of encrypted packets")},
{ oShowPhotos, "show-photos", 0, N_("Show Photo IDs")},
{ oNoShowPhotos, "no-show-photos", 0, N_("Don't show Photo IDs")},
{ oPhotoViewer, "photo-viewer", 2, N_("Set command line to view Photo IDs")},
{ oNotation, "notation-data", 2, N_("|NAME=VALUE|use this notation data")}, { oNotation, "notation-data", 2, N_("|NAME=VALUE|use this notation data")},
{ 302, NULL, 0, N_( { 302, NULL, 0, N_(
@ -827,13 +833,13 @@ main( int argc, char **argv )
{ {
add_to_strlist(&unsafe_files,configname); add_to_strlist(&unsafe_files,configname);
/* If any options file is unsafe, then disable the keyserver /* If any options file is unsafe, then disable any external
code. Since the keyserver code can call an external programs for keyserver calls or photo IDs. Since the
program, and the external program to call is set in the external program to call is set in the options file, a
options file, a unsafe options file can lead to an unsafe options file can lead to an arbitrary program
arbitrary program being run. */ being run. */
opt.keyserver_disable=1; opt.exec_disable=1;
} }
configlineno = 0; configlineno = 0;
@ -1069,6 +1075,9 @@ main( int argc, char **argv )
case oComment: opt.comment_string = pargs.r.ret_str; break; case oComment: opt.comment_string = pargs.r.ret_str; break;
case oDefaultComment: opt.comment_string = NULL; break; case oDefaultComment: opt.comment_string = NULL; break;
case oThrowKeyid: opt.throw_keyid = 1; break; case oThrowKeyid: opt.throw_keyid = 1; break;
case oShowPhotos: opt.show_photos = 1; break;
case oNoShowPhotos: opt.show_photos = 0; break;
case oPhotoViewer: opt.photo_viewer = pargs.r.ret_str; break;
case oForceV3Sigs: opt.force_v3_sigs = 1; break; case oForceV3Sigs: opt.force_v3_sigs = 1; break;
case oNoForceV3Sigs: opt.force_v3_sigs = 0; break; case oNoForceV3Sigs: opt.force_v3_sigs = 0; break;
case oForceV4Certs: opt.force_v4_certs = 1; break; case oForceV4Certs: opt.force_v4_certs = 1; break;

View File

@ -301,8 +301,10 @@ passphrase_to_dek( u32 *keyid, int pubkey_algo,
} }
/* Stub: no decrypting, so no IDEA needed */ /* Stub: no decrypting, so no IDEA needed */
void void idea_cipher_warn( int show ) {}
idea_cipher_warn( int show ) {}
/* Stub to avoid linking to photoid.c */
void show_photo(const struct user_attribute *attr,PKT_public_key *pk) {}
/* Stubs to void linking to ../cipher/cipher.c */ /* Stubs to void linking to ../cipher/cipher.c */
int string_to_cipher_algo( const char *string ) { return 0; } int string_to_cipher_algo( const char *string ) { return 0; }
@ -360,15 +362,3 @@ DOTLOCK create_dotlock( const char *file_to_lock ) { return NULL; }
int make_dotlock( DOTLOCK h, long timeout ) { return 0;} int make_dotlock( DOTLOCK h, long timeout ) { return 0;}
int release_dotlock( DOTLOCK h ) {return 0;} int release_dotlock( DOTLOCK h ) {return 0;}
void remove_lockfiles(void) {} void remove_lockfiles(void) {}

View File

@ -32,6 +32,7 @@
#include "iobuf.h" #include "iobuf.h"
#include "keydb.h" #include "keydb.h"
#include "memory.h" #include "memory.h"
#include "photoid.h"
#include "util.h" #include "util.h"
#include "main.h" #include "main.h"
#include "trustdb.h" #include "trustdb.h"
@ -44,7 +45,7 @@ static void show_prefs( PKT_user_id *uid, int verbose );
static void show_key_with_all_names( KBNODE keyblock, static void show_key_with_all_names( KBNODE keyblock,
int only_marked, int with_fpr, int with_subkeys, int with_prefs ); int only_marked, int with_fpr, int with_subkeys, int with_prefs );
static void show_key_and_fingerprint( KBNODE keyblock ); static void show_key_and_fingerprint( KBNODE keyblock );
static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock ); static int menu_adduid( KBNODE keyblock, KBNODE sec_keyblock, int photo );
static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock ); static void menu_deluid( KBNODE pub_keyblock, KBNODE sec_keyblock );
static int menu_delsig( KBNODE pub_keyblock ); static int menu_delsig( KBNODE pub_keyblock );
static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock ); static void menu_delkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
@ -61,6 +62,7 @@ static int count_selected_keys( KBNODE keyblock );
static int menu_revsig( KBNODE keyblock ); static int menu_revsig( KBNODE keyblock );
static int menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock ); static int menu_revkey( KBNODE pub_keyblock, KBNODE sec_keyblock );
static int enable_disable_key( KBNODE keyblock, int disable ); static int enable_disable_key( KBNODE keyblock, int disable );
static void menu_showphoto( KBNODE keyblock );
#define CONTROL_D ('D' - 'A' + 1) #define CONTROL_D ('D' - 'A' + 1)
@ -749,10 +751,10 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
enum cmdids { cmdNONE = 0, enum cmdids { cmdNONE = 0,
cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN, cmdQUIT, cmdHELP, cmdFPR, cmdLIST, cmdSELUID, cmdCHECK, cmdSIGN,
cmdLSIGN, cmdNRSIGN, cmdREVSIG, cmdREVKEY, cmdDELSIG, cmdPRIMARY, cmdLSIGN, cmdNRSIGN, cmdREVSIG, cmdREVKEY, cmdDELSIG, cmdPRIMARY,
cmdDEBUG, cmdSAVE, cmdADDUID, cmdDELUID, cmdADDKEY, cmdDELKEY, cmdDEBUG, cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY,
cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF, cmdEXPIRE, cmdDELKEY, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF, cmdUPDPREF, cmdEXPIRE, cmdENABLEKEY, cmdDISABLEKEY, cmdSHOWPREF, cmdSETPREF,
cmdINVCMD, cmdNOP }; cmdUPDPREF, cmdINVCMD, cmdSHOWPHOTO, cmdNOP };
static struct { const char *name; static struct { const char *name;
enum cmdids id; enum cmdids id;
int need_sk; int need_sk;
@ -778,7 +780,10 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
{ N_("nrsign") , cmdNRSIGN , 0,1,1, N_("sign the key non-revocably") }, { N_("nrsign") , cmdNRSIGN , 0,1,1, N_("sign the key non-revocably") },
{ N_("debug") , cmdDEBUG , 0,0,0, NULL }, { N_("debug") , cmdDEBUG , 0,0,0, NULL },
{ N_("adduid") , cmdADDUID , 1,1,0, N_("add a user ID") }, { N_("adduid") , cmdADDUID , 1,1,0, N_("add a user ID") },
{ N_("addphoto"), cmdADDPHOTO , 1,1,0, N_("add a photo ID") },
{ N_("deluid") , cmdDELUID , 0,1,0, N_("delete user ID") }, { N_("deluid") , cmdDELUID , 0,1,0, N_("delete user ID") },
/* delphoto is really deluid in disguise */
{ N_("delphoto"), cmdDELUID , 0,1,0, NULL },
{ N_("addkey") , cmdADDKEY , 1,1,0, N_("add a secondary key") }, { N_("addkey") , cmdADDKEY , 1,1,0, N_("add a secondary key") },
{ N_("delkey") , cmdDELKEY , 0,1,0, N_("delete a secondary key") }, { N_("delkey") , cmdDELKEY , 0,1,0, N_("delete a secondary key") },
{ N_("delsig") , cmdDELSIG , 0,1,0, N_("delete signatures") }, { N_("delsig") , cmdDELSIG , 0,1,0, N_("delete signatures") },
@ -797,6 +802,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
{ N_("revkey") , cmdREVKEY , 1,1,0, N_("revoke a secondary key") }, { N_("revkey") , cmdREVKEY , 1,1,0, N_("revoke a secondary key") },
{ N_("disable") , cmdDISABLEKEY, 0,1,0, N_("disable a key") }, { N_("disable") , cmdDISABLEKEY, 0,1,0, N_("disable a key") },
{ N_("enable") , cmdENABLEKEY , 0,1,0, N_("enable a key") }, { N_("enable") , cmdENABLEKEY , 0,1,0, N_("enable a key") },
{ N_("showphoto"),cmdSHOWPHOTO , 0,0,0, N_("show photo ID") },
{ NULL, cmdNONE } }; { NULL, cmdNONE } };
enum cmdids cmd = 0; enum cmdids cmd = 0;
@ -876,7 +882,7 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
toggle = 0; toggle = 0;
cur_keyblock = keyblock; cur_keyblock = keyblock;
for(;;) { /* main loop */ for(;;) { /* main loop */
int i, arg_number; int i, arg_number, photo;
const char *arg_string = ""; const char *arg_string = "";
char *p; char *p;
PKT_public_key *pk=keyblock->pkt->pkt.public_key; PKT_public_key *pk=keyblock->pkt->pkt.public_key;
@ -907,7 +913,8 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
trim_spaces(answer); trim_spaces(answer);
} while( *answer == '#' ); } while( *answer == '#' );
arg_number = 0; /* Yes, here is the init which egcc complains about*/ arg_number = 0; /* Yes, here is the init which egcc complains about */
photo = 0; /* This too */
if( !*answer ) if( !*answer )
cmd = cmdLIST; cmd = cmdLIST;
else if( *answer == CONTROL_D ) else if( *answer == CONTROL_D )
@ -1021,8 +1028,12 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
redisplay = 1; redisplay = 1;
break; break;
case cmdADDPHOTO:
photo=1;
/* fall through */
case cmdADDUID: case cmdADDUID:
if( menu_adduid( keyblock, sec_keyblock ) ) { if( menu_adduid( keyblock, sec_keyblock, photo ) ) {
redisplay = 1; redisplay = 1;
sec_modified = modified = 1; sec_modified = modified = 1;
merge_keys_and_selfsig( sec_keyblock ); merge_keys_and_selfsig( sec_keyblock );
@ -1199,6 +1210,10 @@ keyedit_menu( const char *username, STRLIST locusr, STRLIST commands,
} }
break; break;
case cmdSHOWPHOTO:
menu_showphoto(keyblock);
break;
case cmdQUIT: case cmdQUIT:
if( have_commands ) if( have_commands )
goto leave; goto leave;
@ -1492,7 +1507,7 @@ show_key_and_fingerprint( KBNODE keyblock )
* Return true if there is a new user id * Return true if there is a new user id
*/ */
static int static int
menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock ) menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock, int photo)
{ {
PKT_user_id *uid; PKT_user_id *uid;
PKT_public_key *pk=NULL; PKT_public_key *pk=NULL;
@ -1503,10 +1518,6 @@ menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
KBNODE pub_where=NULL, sec_where=NULL; KBNODE pub_where=NULL, sec_where=NULL;
int rc; int rc;
uid = generate_user_id();
if( !uid )
return 0;
for( node = pub_keyblock; node; pub_where = node, node = node->next ) { for( node = pub_keyblock; node; pub_where = node, node = node->next ) {
if( node->pkt->pkttype == PKT_PUBLIC_KEY ) if( node->pkt->pkttype == PKT_PUBLIC_KEY )
pk = node->pkt->pkt.public_key; pk = node->pkt->pkt.public_key;
@ -1523,7 +1534,29 @@ menu_adduid( KBNODE pub_keyblock, KBNODE sec_keyblock )
} }
if( !node ) /* no subkey */ if( !node ) /* no subkey */
sec_where = NULL; sec_where = NULL;
assert(pk && sk ); assert(pk && sk);
if(photo) {
/* PGP allows only one photo ID per key? */
for( node = pub_keyblock; node; node = node->next )
if( node->pkt->pkttype == PKT_USER_ID &&
node->pkt->pkt.user_id->attrib_data!=NULL) {
log_error("You may only have one photo ID on a key.\n");
return 0;
}
if(pk->version==3)
{
tty_printf(_("\nWARNING: This is a PGP2-style key\n"));
tty_printf(_(" Adding a photo ID may cause some versions "
"of PGP to not accept this key\n"));
}
uid = generate_photo_id(pk);
} else
uid = generate_user_id();
if( !uid )
return 0;
rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, 0, 0, 0, rc = make_keysig_packet( &sig, pk, uid, NULL, sk, 0x13, 0, 0, 0, 0,
keygen_add_std_prefs, pk ); keygen_add_std_prefs, pk );
@ -1856,8 +1889,6 @@ menu_expire( KBNODE pub_keyblock, KBNODE sec_keyblock )
return 1; return 1;
} }
static int static int
change_primary_uid_cb ( PKT_signature *sig, void *opaque ) change_primary_uid_cb ( PKT_signature *sig, void *opaque )
{ {
@ -2452,3 +2483,46 @@ enable_disable_key( KBNODE keyblock, int disable )
return 0; return 0;
} }
static void
menu_showphoto( KBNODE keyblock )
{
KBNODE node;
int select_all = !count_selected_uids(keyblock);
int count=0;
PKT_public_key *pk=NULL;
u32 keyid[2];
/* Look for the public key first. We have to be really, really,
explicit as to which photo this is, and what key it is a UID on
since people may want to sign it. */
for( node = keyblock; node; node = node->next )
{
if( node->pkt->pkttype == PKT_PUBLIC_KEY )
pk = node->pkt->pkt.public_key;
}
for( node = keyblock; node; node = node->next )
{
if( node->pkt->pkttype == PKT_USER_ID )
{
PKT_user_id *uid = node->pkt->pkt.user_id;
count++;
if((select_all || (node->flag & NODFLG_SELUID)) &&
uid->attribs!=NULL)
{
/* Can this really ever happen? */
if(pk==NULL)
keyid[1]=0;
else
keyid_from_pk(pk, keyid);
tty_printf("Displaying photo ID of size %ld for key 0x%08lX "
"(uid %d)\n",uid->attribs->len,(ulong)keyid[1],count);
show_photo(uid->attribs,pk);
}
}
}
}

View File

@ -30,6 +30,7 @@
#include "errors.h" #include "errors.h"
#include "keydb.h" #include "keydb.h"
#include "memory.h" #include "memory.h"
#include "photoid.h"
#include "util.h" #include "util.h"
#include "ttyio.h" #include "ttyio.h"
#include "trustdb.h" #include "trustdb.h"
@ -352,6 +353,10 @@ list_keyblock_print ( KBNODE keyblock, int secret )
print_key_data( pk, keyid ); print_key_data( pk, keyid );
any = 1; any = 1;
} }
if(opt.show_photos && node->pkt->pkt.user_id->attribs!=NULL &&
node->pkt->pkt.user_id->attribs->type==ATTRIB_JPEG)
show_photo(node->pkt->pkt.user_id->attribs,pk);
} }
else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) { else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
u32 keyid2[2]; u32 keyid2[2];
@ -576,10 +581,10 @@ list_keyblock_colon( KBNODE keyblock, int secret )
byte namehash[20]; byte namehash[20];
if( pk && !ulti_hack ) { if( pk && !ulti_hack ) {
if( node->pkt->pkt.user_id->photo ) if( node->pkt->pkt.user_id->attrib_data )
rmd160_hash_buffer( namehash, rmd160_hash_buffer( namehash,
node->pkt->pkt.user_id->photo, node->pkt->pkt.user_id->attrib_data,
node->pkt->pkt.user_id->photolen); node->pkt->pkt.user_id->attrib_len);
else else
rmd160_hash_buffer( namehash, rmd160_hash_buffer( namehash,
node->pkt->pkt.user_id->name, node->pkt->pkt.user_id->name,

View File

@ -34,21 +34,13 @@
#include "options.h" #include "options.h"
#include "memory.h" #include "memory.h"
#include "keydb.h" #include "keydb.h"
#include "cipher.h"
#include "status.h" #include "status.h"
#include "exec.h"
#include "i18n.h" #include "i18n.h"
#include "util.h" #include "util.h"
#include "main.h" #include "main.h"
#include "hkp.h" #include "hkp.h"
#ifndef HAVE_MKDTEMP
char *mkdtemp(char *template);
#endif
#if !(defined(HAVE_FORK) && defined(HAVE_PIPE))
#define KEYSERVER_TEMPFILE_ONLY
#endif
#define KEYSERVER_PROTO_VERSION 0 #define KEYSERVER_PROTO_VERSION 0
#define GET 0 #define GET 0
@ -74,7 +66,7 @@ parse_keyserver_options(char *options)
opt.keyserver_options.include_disabled=1; opt.keyserver_options.include_disabled=1;
else if(strcasecmp(tok,"no-include-disabled")==0) else if(strcasecmp(tok,"no-include-disabled")==0)
opt.keyserver_options.include_disabled=0; opt.keyserver_options.include_disabled=0;
#ifdef KEYSERVER_TEMPFILE_ONLY #ifdef EXEC_TEMPFILE_ONLY
else if(strcasecmp(tok,"use-temp-files")==0 || else if(strcasecmp(tok,"use-temp-files")==0 ||
strcasecmp(tok,"no-use-temp-files")==0) strcasecmp(tok,"no-use-temp-files")==0)
log_info(_("Warning: keyserver option \"%s\" is not used " log_info(_("Warning: keyserver option \"%s\" is not used "
@ -261,167 +253,75 @@ print_keyinfo(int count,char *keystring,u32 *keyid)
return 0; return 0;
} }
#define KEYSERVER_ARGS_KEEP " -o \"%O\" \"%I\""
#define KEYSERVER_ARGS_NOKEEP " -o \"%o\" \"%i\""
static int static int
keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count) keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count,int *prog)
{ {
int ret=KEYSERVER_INTERNAL_ERROR,i,to[2]={-1,-1},from[2]={-1,-1}; int ret=0,i,gotversion=0;
pid_t child=0;
STRLIST temp; STRLIST temp;
unsigned int maxlen=256,buflen; unsigned int maxlen=256,buflen;
char *filename=NULL,*tempfile_in=NULL,*tempfile_out=NULL,*searchstr=NULL; char *command=NULL,*searchstr=NULL;
char *tempdir=NULL;
byte *line=NULL; byte *line=NULL;
FILE *tochild=NULL; struct exec_info *spawn;
IOBUF fromchild=NULL;
int gotversion=0,madedir=0;
#ifndef __MINGW32__ #ifdef EXEC_TEMPFILE_ONLY
/* Don't allow to be setuid when we are going to create temporary opt.keyserver_options.use_temp_files=1;
files or directories - yes, this is a bit paranoid */
if (getuid() != geteuid() )
BUG ();
#endif #endif
if(opt.keyserver_disable && !opt.no_perm_warn)
{
log_info(_("keyserver scheme \"%s\" disabled due to unsafe "
"options file permissions\n"),opt.keyserver_scheme);
return KEYSERVER_SCHEME_NOT_FOUND;
}
/* Build the filename for the helper to execute */ /* Build the filename for the helper to execute */
filename=m_alloc(strlen("gpgkeys_")+strlen(opt.keyserver_scheme)+1); command=m_alloc(strlen("gpgkeys_")+strlen(opt.keyserver_scheme)+1);
strcpy(command,"gpgkeys_");
strcat(command,opt.keyserver_scheme);
strcpy(filename,"gpgkeys_");
strcat(filename,opt.keyserver_scheme);
if(opt.keyserver_options.use_temp_files) if(opt.keyserver_options.use_temp_files)
{ {
const char *tmp=get_temp_dir(); if(opt.keyserver_options.keep_temp_files)
tempdir=m_alloc(strlen(tmp)+1+10+1);
sprintf(tempdir,"%s" DIRSEP_S "gpg-XXXXXX",tmp);
if(mkdtemp(tempdir)==NULL)
{ {
log_error(_("%s: can't create temp directory: %s\n"), command=m_realloc(command,strlen(command)+
tempdir,strerror(errno)); strlen(KEYSERVER_ARGS_KEEP)+1);
goto fail; strcat(command,KEYSERVER_ARGS_KEEP);
}
else
{
command=m_realloc(command,strlen(command)+
strlen(KEYSERVER_ARGS_NOKEEP)+1);
strcat(command,KEYSERVER_ARGS_NOKEEP);
} }
madedir=1; ret=exec_write(&spawn,NULL,command,0,0);
tempfile_in=m_alloc(strlen(tempdir)+1+10+1);
sprintf(tempfile_in,"%s" DIRSEP_S "ksrvin" EXTSEP_S "txt",tempdir);
tempfile_out=m_alloc(strlen(tempdir)+1+11+1);
sprintf(tempfile_out,"%s" DIRSEP_S "ksrvout" EXTSEP_S "txt",tempdir);
tochild=fopen(tempfile_in,"w");
if(tochild==NULL)
{
log_error(_("%s: can't create: %s\n"),tempfile_in,strerror(errno));
goto fail;
}
} }
else else
{ ret=exec_write(&spawn,command,NULL,0,0);
if(pipe(to)==-1)
goto fail;
if(pipe(from)==-1) if(ret)
goto fail; goto fail;
if((child=fork())==-1) fprintf(spawn->tochild,"# This is a gpg keyserver communications file\n");
goto fail; fprintf(spawn->tochild,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
fprintf(spawn->tochild,"PROGRAM %s\n",VERSION);
if(child==0) fprintf(spawn->tochild,"HOST %s\n",opt.keyserver_host);
{
/* I'm the child */
/* implied close of STDERR */
if(dup2(STDOUT_FILENO,STDERR_FILENO)==-1)
_exit(KEYSERVER_INTERNAL_ERROR);
close(from[0]);
from[0]=-1;
/* implied close of STDOUT */
if(dup2(from[1],STDOUT_FILENO)==-1)
_exit(KEYSERVER_INTERNAL_ERROR);
close(to[1]);
to[1]=-1;
/* implied close of STDIN */
if(dup2(to[0],STDIN_FILENO)==-1)
_exit(KEYSERVER_INTERNAL_ERROR);
execlp(filename,filename,NULL);
/* If we get this far the exec failed. Clean up and return. */
if(opt.keyserver_options.verbose>2)
log_error(_("unable to execute %s: %s\n"),
filename,strerror(errno));
if(errno==ENOENT)
_exit(KEYSERVER_SCHEME_NOT_FOUND);
_exit(KEYSERVER_INTERNAL_ERROR);
}
/* I'm the parent */
close(to[0]);
to[0]=-1;
tochild=fdopen(to[1],"w");
if(tochild==NULL)
{
ret=G10ERR_WRITE_FILE;
close(to[1]);
goto fail;
}
close(from[1]);
from[1]=-1;
fromchild=iobuf_fdopen(from[0],"r");
if(fromchild==NULL)
{
ret=G10ERR_READ_FILE;
goto fail;
}
}
fprintf(tochild,"# This is a gpg keyserver communications file\n");
fprintf(tochild,"VERSION %d\n",KEYSERVER_PROTO_VERSION);
fprintf(tochild,"PROGRAM %s\n",VERSION);
fprintf(tochild,"HOST %s\n",opt.keyserver_host);
if(atoi(opt.keyserver_port)>0) if(atoi(opt.keyserver_port)>0)
fprintf(tochild,"PORT %s\n",opt.keyserver_port); fprintf(spawn->tochild,"PORT %s\n",opt.keyserver_port);
/* Write options */ /* Write options */
fprintf(tochild,"OPTION %sinclude-revoked\n", fprintf(spawn->tochild,"OPTION %sinclude-revoked\n",
opt.keyserver_options.include_revoked?"":"no-"); opt.keyserver_options.include_revoked?"":"no-");
fprintf(tochild,"OPTION %sinclude-disabled\n", fprintf(spawn->tochild,"OPTION %sinclude-disabled\n",
opt.keyserver_options.include_disabled?"":"no-"); opt.keyserver_options.include_disabled?"":"no-");
for(i=0;i<opt.keyserver_options.verbose;i++) for(i=0;i<opt.keyserver_options.verbose;i++)
fprintf(tochild,"OPTION verbose\n"); fprintf(spawn->tochild,"OPTION verbose\n");
temp=opt.keyserver_options.other; temp=opt.keyserver_options.other;
for(;temp;temp=temp->next) for(;temp;temp=temp->next)
fprintf(tochild,"OPTION %s\n",temp->d); fprintf(spawn->tochild,"OPTION %s\n",temp->d);
switch(action) switch(action)
{ {
@ -429,15 +329,15 @@ keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count)
{ {
int i; int i;
fprintf(tochild,"COMMAND GET\n\n"); fprintf(spawn->tochild,"COMMAND GET\n\n");
/* Which keys do we want? */ /* Which keys do we want? */
for(i=0;i<count;i++) for(i=0;i<count;i++)
fprintf(tochild,"0x%08lX%08lX\n", fprintf(spawn->tochild,"0x%08lX%08lX\n",
(ulong)kidlist[i][0],(ulong)kidlist[i][1]); (ulong)kidlist[i][0],(ulong)kidlist[i][1]);
fprintf(tochild,"\n"); fprintf(spawn->tochild,"\n");
break; break;
} }
@ -447,7 +347,7 @@ keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count)
STRLIST key,temp; STRLIST key,temp;
/* Note the extra \n here to send an empty keylist block */ /* Note the extra \n here to send an empty keylist block */
fprintf(tochild,"COMMAND SEND\n\n\n"); fprintf(spawn->tochild,"COMMAND SEND\n\n\n");
for(key=list;key!=NULL;key=key->next) for(key=list;key!=NULL;key=key->next)
{ {
@ -467,10 +367,10 @@ keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count)
{ {
iobuf_flush_temp(buffer); iobuf_flush_temp(buffer);
fprintf(tochild,"KEY %s BEGIN\n",key->d); fprintf(spawn->tochild,"KEY %s BEGIN\n",key->d);
fwrite(iobuf_get_temp_buffer(buffer), fwrite(iobuf_get_temp_buffer(buffer),
iobuf_get_temp_length(buffer),1,tochild); iobuf_get_temp_length(buffer),1,spawn->tochild);
fprintf(tochild,"KEY %s END\n",key->d); fprintf(spawn->tochild,"KEY %s END\n",key->d);
iobuf_close(buffer); iobuf_close(buffer);
} }
@ -485,14 +385,14 @@ keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count)
{ {
STRLIST key; STRLIST key;
fprintf(tochild,"COMMAND SEARCH\n\n"); fprintf(spawn->tochild,"COMMAND SEARCH\n\n");
/* Which keys do we want? Remember that the gpgkeys_ program /* Which keys do we want? Remember that the gpgkeys_ program
is going to lump these together into a search string. */ is going to lump these together into a search string. */
for(key=list;key!=NULL;key=key->next) for(key=list;key!=NULL;key=key->next)
{ {
fprintf(tochild,"%s\n",key->d); fprintf(spawn->tochild,"%s\n",key->d);
if(key!=list) if(key!=list)
{ {
searchstr=m_realloc(searchstr, searchstr=m_realloc(searchstr,
@ -508,7 +408,7 @@ keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count)
strcat(searchstr,key->d); strcat(searchstr,key->d);
} }
fprintf(tochild,"\n"); fprintf(spawn->tochild,"\n");
break; break;
} }
@ -518,52 +418,16 @@ keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count)
break; break;
} }
/* Done sending */ /* Done sending, so start reading. */
fclose(tochild); ret=exec_read(spawn);
tochild=NULL; if(ret)
to[1]=-1; goto fail;
if(opt.keyserver_options.use_temp_files)
{
char *command=m_alloc(strlen(filename)+2+
strlen(tempfile_in)+6+
strlen(tempfile_out)+2);
sprintf(command,"%s -o \"%s\" \"%s\"",filename,tempfile_out,tempfile_in);
ret=system(command);
m_free(command);
ret=WEXITSTATUS(ret);
if(ret==127)
{
log_error(_("unable to exec keyserver program\n"));
goto fail;
}
if(ret==-1)
{
log_error(_("internal system error while calling keyserver: %s\n"),
strerror(errno));
goto fail;
}
fromchild=iobuf_open(tempfile_out);
if(fromchild==NULL)
{
log_error(_("unable to read keyserver response: %s\n"),
strerror(errno));
goto fail;
}
}
/* Now handle the response */ /* Now handle the response */
do do
{ {
if(iobuf_read_line(fromchild,&line,&buflen,&maxlen)==0) if(iobuf_read_line(spawn->fromchild,&line,&buflen,&maxlen)==0)
{ {
ret=G10ERR_READ_FILE; ret=G10ERR_READ_FILE;
goto fail; /* i.e. EOF */ goto fail; /* i.e. EOF */
@ -612,7 +476,7 @@ keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count)
do this could be to continue parsing this line-by-line and do this could be to continue parsing this line-by-line and
make a temp iobuf for each key. */ make a temp iobuf for each key. */
import_keys_stream(fromchild, import_keys_stream(spawn->fromchild,
opt.keyserver_options.fast_import,stats_handle); opt.keyserver_options.fast_import,stats_handle);
import_print_stats(stats_handle); import_print_stats(stats_handle);
@ -634,7 +498,7 @@ keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count)
/* Look for the COUNT line */ /* Look for the COUNT line */
do do
{ {
if(iobuf_read_line(fromchild,&line,&buflen,&maxlen)==0) if(iobuf_read_line(spawn->fromchild,&line,&buflen,&maxlen)==0)
{ {
ret=G10ERR_READ_FILE; ret=G10ERR_READ_FILE;
goto fail; /* i.e. EOF */ goto fail; /* i.e. EOF */
@ -642,7 +506,7 @@ keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count)
} }
while(sscanf(line,"COUNT %d\n",&count)!=1); while(sscanf(line,"COUNT %d\n",&count)!=1);
keyserver_search_prompt(fromchild,count,searchstr); keyserver_search_prompt(spawn->fromchild,count,searchstr);
break; break;
} }
@ -652,54 +516,9 @@ keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count)
break; break;
} }
iobuf_close(fromchild); *prog=exec_finish(spawn);
fromchild=NULL;
ret=0;
fail: fail:
if(tochild!=NULL)
{
fclose(tochild);
to[1]=-1;
}
if(fromchild!=NULL)
{
iobuf_close(fromchild);
from[0]=-1;
}
if(from[0]>-1)
close(from[0]);
if(from[1]>-1)
close(from[1]);
if(to[0]>-1)
close(to[0]);
if(to[1]>-1)
close(to[1]);
if(child>0)
{
int rc;
waitpid(child,&rc,0);
if(ret==0 && WIFEXITED(rc))
ret=WEXITSTATUS(rc);
}
m_free(filename);
if(madedir && !opt.keyserver_options.keep_temp_files)
{
unlink(tempfile_in);
unlink(tempfile_out);
rmdir(tempdir);
}
m_free(tempfile_in);
m_free(tempfile_out);
m_free(tempdir);
return ret; return ret;
} }
@ -707,11 +526,7 @@ keyserver_spawn(int action,STRLIST list,u32 (*kidlist)[2],int count)
static int static int
keyserver_work(int action,STRLIST list,u32 (*kidlist)[2],int count) keyserver_work(int action,STRLIST list,u32 (*kidlist)[2],int count)
{ {
int rc=0; int rc=0,ret=0;
#ifdef KEYSERVER_TEMPFILE_ONLY
opt.keyserver_options.use_temp_files=1;
#endif
if(opt.keyserver_scheme==NULL || if(opt.keyserver_scheme==NULL ||
opt.keyserver_host==NULL || opt.keyserver_host==NULL ||
@ -749,10 +564,13 @@ keyserver_work(int action,STRLIST list,u32 (*kidlist)[2],int count)
/* It's not the internal HKP code, so try and spawn a handler for it */ /* It's not the internal HKP code, so try and spawn a handler for it */
if((rc=keyserver_spawn(action,list,kidlist,count))) if((rc=keyserver_spawn(action,list,kidlist,count,&ret))==0)
{ {
switch(rc) switch(ret)
{ {
case KEYSERVER_OK:
break;
case KEYSERVER_SCHEME_NOT_FOUND: case KEYSERVER_SCHEME_NOT_FOUND:
log_error(_("no handler for keyserver scheme \"%s\"\n"), log_error(_("no handler for keyserver scheme \"%s\"\n"),
opt.keyserver_scheme); opt.keyserver_scheme);
@ -767,6 +585,12 @@ keyserver_work(int action,STRLIST list,u32 (*kidlist)[2],int count)
/* This is not the best error code for this */ /* This is not the best error code for this */
return G10ERR_INVALID_URI; return G10ERR_INVALID_URI;
} }
else
{
log_error(_("keyserver communications error\n"));
return rc;
}
return 0; return 0;
} }

View File

@ -85,6 +85,8 @@ struct {
const char *set_filename; const char *set_filename;
const char *comment_string; const char *comment_string;
int throw_keyid; int throw_keyid;
int show_photos;
const char *photo_viewer;
int s2k_mode; int s2k_mode;
int s2k_digest_algo; int s2k_digest_algo;
int s2k_cipher_algo; int s2k_cipher_algo;
@ -104,7 +106,7 @@ struct {
int keep_temp_files:1; int keep_temp_files:1;
STRLIST other; STRLIST other;
} keyserver_options; } keyserver_options;
int keyserver_disable; int exec_disable;
int no_perm_warn; int no_perm_warn;
char *temp_dir; char *temp_dir;
int no_encrypt_to; int no_encrypt_to;

View File

@ -115,7 +115,7 @@ lock-once
# proxies (honor-http-proxy) # proxies (honor-http-proxy)
# #
# Most users just set the name and type of their preferred keyserver. # Most users just set the name and type of their preferred keyserver.
# Most servers do syncronize with each other and DNS round-robin may # Most servers do synchronize with each other and DNS round-robin may
# give you a quasi-random server each time. # give you a quasi-random server each time.
#keyserver mailto:pgp-public-keys@keys.nl.pgp.net #keyserver mailto:pgp-public-keys@keys.nl.pgp.net
@ -151,7 +151,32 @@ lock-once
#auto-key-retrieve #auto-key-retrieve
# The environment variable http_proxy is only used when the # Uncomment this line to display photo user IDs in key listings
# this option is set. #show-photos
#honor-http-proxy # Use this program to display photo user IDs
#
# %i is expanded to a temporary file that contains the photo.
# %I is the same as %i, but the file isn't deleted afterwards by GnuPG.
# %k is expanded to the key ID of the key.
# %K is expanded to the long OpenPGP key ID of the key.
# %f is expanded to the fingerprint of the key.
# %% is %, of course.
#
# If %i or %I are not present, then the photo is supplied to the
# viewer on standard input. Standard input is the best way to do
# this, as it avoids the time and effort in generating and then
# cleaning up a secure temp file.
#
# The default program is "xloadimage -fork -quiet -title 'KeyID 0x%k' stdin"
#
# Some other viewers:
# photo-viewer "xv -name \"KeyID 0x%k\" -"
# photo-viewer "ee %i"
# photo-viewer "display -title 'KeyID 0x%k'"
#
# This one saves a copy of the photo ID in your home directory:
# photo-viewer "cat > ~/photoid-for-key-%k.jpg"
#
# Use your MIME handler to view photos:
# photo-viewer "metamail -q -d -b -c image/jpeg -s 'KeyID 0x%k' -f GnuPG"

View File

@ -46,7 +46,7 @@ typedef enum {
PKT_USER_ID =13, /* user id packet */ PKT_USER_ID =13, /* user id packet */
PKT_PUBLIC_SUBKEY =14, /* public subkey (OpenPGP) */ PKT_PUBLIC_SUBKEY =14, /* public subkey (OpenPGP) */
PKT_OLD_COMMENT =16, /* comment packet from an OpenPGP draft */ PKT_OLD_COMMENT =16, /* comment packet from an OpenPGP draft */
PKT_PHOTO_ID =17, /* PGP's photo ID */ PKT_ATTRIBUTE =17, /* PGP's attribute packet */
PKT_ENCRYPTED_MDC =18, /* integrity protected encrypted data */ PKT_ENCRYPTED_MDC =18, /* integrity protected encrypted data */
PKT_MDC =19, /* manipulaion detection code packet */ PKT_MDC =19, /* manipulaion detection code packet */
PKT_COMMENT =61, /* new comment packet (private) */ PKT_COMMENT =61, /* new comment packet (private) */
@ -140,12 +140,26 @@ typedef struct {
MPI data[PUBKEY_MAX_NSIG]; MPI data[PUBKEY_MAX_NSIG];
} PKT_signature; } PKT_signature;
typedef enum
{
ATTRIB_UNKNOWN,
ATTRIB_JPEG
} attribtype_t;
/* This is the cooked form of attributes */
struct user_attribute {
attribtype_t type;
const byte *data;
unsigned long len;
};
typedef struct { typedef struct {
int ref; /* reference counter */ int ref; /* reference counter */
int len; /* length of the name */ int len; /* length of the name */
char *photo; /* if this is not NULL, the packet is a photo ID */ struct user_attribute *attribs;
int photolen; /* and the length of the photo */ int numattribs;
byte *attrib_data; /* if this is not NULL, the packet is an attribute */
unsigned long attrib_len;
int help_key_usage; int help_key_usage;
u32 help_key_expire; u32 help_key_expire;
int is_primary; int is_primary;
@ -367,6 +381,8 @@ const byte *parse_sig_subpkt ( const subpktarea_t *buffer,
const byte *parse_sig_subpkt2 ( PKT_signature *sig, const byte *parse_sig_subpkt2 ( PKT_signature *sig,
sigsubpkttype_t reqtype, sigsubpkttype_t reqtype,
size_t *ret_n ); size_t *ret_n );
int parse_attribute_subpkts(PKT_user_id *uid);
void make_attribute_uidname(PKT_user_id *uid);
PACKET *create_gpg_control ( ctrlpkttype_t type, PACKET *create_gpg_control ( ctrlpkttype_t type,
const byte *data, const byte *data,
size_t datalen ); size_t datalen );
@ -379,6 +395,9 @@ void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
const byte *buffer, size_t buflen ); const byte *buffer, size_t buflen );
void build_sig_subpkt_from_sig( PKT_signature *sig ); void build_sig_subpkt_from_sig( PKT_signature *sig );
int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type ); int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type );
void build_attribute_subpkt(PKT_user_id *uid,byte type,
const void *buf,int buflen,
const void *header,int headerlen);
/*-- free-packet.c --*/ /*-- free-packet.c --*/
void free_symkey_enc( PKT_symkey_enc *enc ); void free_symkey_enc( PKT_symkey_enc *enc );
@ -389,6 +408,7 @@ void release_public_key_parts( PKT_public_key *pk );
void free_public_key( PKT_public_key *key ); void free_public_key( PKT_public_key *key );
void release_secret_key_parts( PKT_secret_key *sk ); void release_secret_key_parts( PKT_secret_key *sk );
void free_secret_key( PKT_secret_key *sk ); void free_secret_key( PKT_secret_key *sk );
void free_attributes(PKT_user_id *uid);
void free_user_id( PKT_user_id *uid ); void free_user_id( PKT_user_id *uid );
void free_comment( PKT_comment *rem ); void free_comment( PKT_comment *rem );
void free_packet( PACKET *pkt ); void free_packet( PACKET *pkt );

View File

@ -61,7 +61,7 @@ static int parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
byte *hdr, int hdrlen, PACKET *packet ); byte *hdr, int hdrlen, PACKET *packet );
static int parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, static int parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen,
PACKET *packet ); PACKET *packet );
static int parse_photo_id( IOBUF inp, int pkttype, unsigned long pktlen, static int parse_attribute( IOBUF inp, int pkttype, unsigned long pktlen,
PACKET *packet ); PACKET *packet );
static int parse_comment( IOBUF inp, int pkttype, unsigned long pktlen, static int parse_comment( IOBUF inp, int pkttype, unsigned long pktlen,
PACKET *packet ); PACKET *packet );
@ -438,9 +438,9 @@ parse( IOBUF inp, PACKET *pkt, int onlykeypkts, off_t *retpos,
case PKT_USER_ID: case PKT_USER_ID:
rc = parse_user_id(inp, pkttype, pktlen, pkt ); rc = parse_user_id(inp, pkttype, pktlen, pkt );
break; break;
case PKT_PHOTO_ID: case PKT_ATTRIBUTE:
pkt->pkttype = pkttype = PKT_USER_ID; /* we store it in the userID */ pkt->pkttype = pkttype = PKT_USER_ID; /* we store it in the userID */
rc = parse_photo_id(inp, pkttype, pktlen, pkt); rc = parse_attribute(inp, pkttype, pktlen, pkt);
break; break;
case PKT_OLD_COMMENT: case PKT_OLD_COMMENT:
case PKT_COMMENT: case PKT_COMMENT:
@ -1657,6 +1657,98 @@ parse_key( IOBUF inp, int pkttype, unsigned long pktlen,
return rc; return rc;
} }
/* Attribute subpackets have the same format as v4 signature
subpackets. This is not part of OpenPGP, but is done in several
versions of PGP nevertheless. */
int
parse_attribute_subpkts(PKT_user_id *uid)
{
size_t n;
int count=0;
struct user_attribute *attribs=NULL;
const byte *buffer=uid->attrib_data;
int buflen=uid->attrib_len;
byte type;
m_free(uid->attribs);
while(buflen)
{
n = *buffer++; buflen--;
if( n == 255 ) { /* 4 byte length header */
if( buflen < 4 )
goto too_short;
n = (buffer[0] << 24) | (buffer[1] << 16)
| (buffer[2] << 8) | buffer[3];
buffer += 4;
buflen -= 4;
}
else if( n >= 192 ) { /* 2 byte special encoded length header */
if( buflen < 2 )
goto too_short;
n = (( n - 192 ) << 8) + *buffer + 192;
buffer++;
buflen--;
}
if( buflen < n )
goto too_short;
attribs=m_realloc(attribs,(count+1)*sizeof(struct user_attribute));
memset(&attribs[count],0,sizeof(struct user_attribute));
type=*buffer;
buffer++;
buflen--;
n--;
/* In order: is it an image, is it large enough to carry the
image header, is it version 1, and is it a JPEG? */
if(type==1 && n>=16 && buffer[2]==1 && buffer[3]==1)
{
/* For historical reasons (i.e. "oops!"), headerlen is
little endian. */
u16 headerlen=(buffer[1]<<8) | buffer[0];
attribs[count].type=ATTRIB_JPEG;
buffer+=headerlen;
buflen-=headerlen;
n-=headerlen;
}
else
attribs[count].type=ATTRIB_UNKNOWN;
attribs[count].data=buffer;
attribs[count].len=n;
buffer+=n;
buflen-=n;
count++;
}
uid->attribs=attribs;
uid->numattribs=count;
return count;
too_short:
log_error("buffer shorter than attribute subpacket\n");
uid->attribs=attribs;
uid->numattribs=count;
return count;
}
static void setup_user_id(PACKET *packet)
{
packet->pkt.user_id->ref = 1;
packet->pkt.user_id->attribs = NULL;
packet->pkt.user_id->attrib_data = NULL;
packet->pkt.user_id->attrib_len = 0;
packet->pkt.user_id->is_primary = 0;
packet->pkt.user_id->is_revoked = 0;
packet->pkt.user_id->created = 0;
packet->pkt.user_id->help_key_usage = 0;
packet->pkt.user_id->help_key_expire = 0;
packet->pkt.user_id->prefs = NULL;
}
static int static int
parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
@ -1664,16 +1756,9 @@ parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
byte *p; byte *p;
packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id + pktlen); packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id + pktlen);
packet->pkt.user_id->ref = 1;
packet->pkt.user_id->len = pktlen; packet->pkt.user_id->len = pktlen;
packet->pkt.user_id->photo = NULL;
packet->pkt.user_id->photolen = 0; setup_user_id(packet);
packet->pkt.user_id->is_primary = 0;
packet->pkt.user_id->is_revoked = 0;
packet->pkt.user_id->created = 0;
packet->pkt.user_id->help_key_usage = 0;
packet->pkt.user_id->help_key_expire = 0;
packet->pkt.user_id->prefs = NULL;
p = packet->pkt.user_id->name; p = packet->pkt.user_id->name;
for( ; pktlen; pktlen--, p++ ) for( ; pktlen; pktlen--, p++ )
@ -1695,35 +1780,45 @@ parse_user_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
return 0; return 0;
} }
void
make_attribute_uidname(PKT_user_id *uid)
{
/* List the first attribute as the "user id" */
if(uid->attribs)
sprintf( uid->name, "[%s of size %lu]",
uid->attribs->type==ATTRIB_JPEG?"image":"unknown attribute",
uid->attribs->len);
else
sprintf( uid->name, "[bad attribute of size %lu]",
uid->attrib_len );
uid->len = strlen(uid->name);
}
/****************
* PGP generates a packet of type 17. We assume this is a photo ID and
* simply store it here as a comment packet.
*/
static int static int
parse_photo_id( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet ) parse_attribute( IOBUF inp, int pkttype, unsigned long pktlen, PACKET *packet )
{ {
byte *p; byte *p;
packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id + 30); packet->pkt.user_id = m_alloc(sizeof *packet->pkt.user_id + 50);
packet->pkt.user_id->ref = 1;
sprintf( packet->pkt.user_id->name, "[image of size %lu]", pktlen );
packet->pkt.user_id->len = strlen(packet->pkt.user_id->name);
packet->pkt.user_id->is_primary = 0;
packet->pkt.user_id->is_revoked = 0;
packet->pkt.user_id->created = 0;
packet->pkt.user_id->help_key_usage = 0;
packet->pkt.user_id->help_key_expire = 0;
packet->pkt.user_id->prefs = NULL;
packet->pkt.user_id->photo = m_alloc(sizeof *packet->pkt.user_id + pktlen); setup_user_id(packet);
packet->pkt.user_id->photolen = pktlen;
p = packet->pkt.user_id->photo; packet->pkt.user_id->attrib_data = m_alloc(pktlen);
packet->pkt.user_id->attrib_len = pktlen;
p = packet->pkt.user_id->attrib_data;
for( ; pktlen; pktlen--, p++ ) for( ; pktlen; pktlen--, p++ )
*p = iobuf_get_noeof(inp); *p = iobuf_get_noeof(inp);
/* Now parse out the individual attribute subpackets. This is
somewhat pointless since there is only one currently defined
attribute type (jpeg), but it is correct by the spec. */
parse_attribute_subpkts(packet->pkt.user_id);
make_attribute_uidname(packet->pkt.user_id);
if( list_mode ) { if( list_mode ) {
printf(":photo_id packet: %s\n", packet->pkt.user_id->name ); printf(":attribute packet: %s\n", packet->pkt.user_id->name );
} }
return 0; return 0;
} }

View File

@ -323,17 +323,17 @@ hash_uid_node( KBNODE unode, MD_HANDLE md, PKT_signature *sig )
PKT_user_id *uid = unode->pkt->pkt.user_id; PKT_user_id *uid = unode->pkt->pkt.user_id;
assert( unode->pkt->pkttype == PKT_USER_ID ); assert( unode->pkt->pkttype == PKT_USER_ID );
if( uid->photo ) { if( uid->attrib_data ) {
if( sig->version >=4 ) { if( sig->version >=4 ) {
byte buf[5]; byte buf[5];
buf[0] = 0xd1; /* packet of type 17 */ buf[0] = 0xd1; /* packet of type 17 */
buf[1] = uid->photolen >> 24; /* always use 4 length bytes */ buf[1] = uid->attrib_len >> 24; /* always use 4 length bytes */
buf[2] = uid->photolen >> 16; buf[2] = uid->attrib_len >> 16;
buf[3] = uid->photolen >> 8; buf[3] = uid->attrib_len >> 8;
buf[4] = uid->photolen; buf[4] = uid->attrib_len;
md_write( md, buf, 5 ); md_write( md, buf, 5 );
} }
md_write( md, uid->photo, uid->photolen ); md_write( md, uid->attrib_data, uid->attrib_len );
} }
else { else {
if( sig->version >=4 ) { if( sig->version >=4 ) {

View File

@ -110,14 +110,28 @@ hash_uid (MD_HANDLE md, int sigversion, const PKT_user_id *uid)
{ {
if ( sigversion >= 4 ) { if ( sigversion >= 4 ) {
byte buf[5]; byte buf[5];
buf[0] = 0xb4; /* indicates a userid packet */
buf[1] = uid->len >> 24; /* always use 4 length bytes */ if(uid->attrib_data) {
buf[2] = uid->len >> 16; buf[0] = 0xd1; /* indicates an attribute packet */
buf[3] = uid->len >> 8; buf[1] = uid->attrib_len >> 24; /* always use 4 length bytes */
buf[4] = uid->len; buf[2] = uid->attrib_len >> 16;
buf[3] = uid->attrib_len >> 8;
buf[4] = uid->attrib_len;
}
else {
buf[0] = 0xb4; /* indicates a userid packet */
buf[1] = uid->len >> 24; /* always use 4 length bytes */
buf[2] = uid->len >> 16;
buf[3] = uid->len >> 8;
buf[4] = uid->len;
}
md_write( md, buf, 5 ); md_write( md, buf, 5 );
} }
md_write (md, uid->name, uid->len );
if(uid->attrib_data)
md_write (md, uid->attrib_data, uid->attrib_len );
else
md_write (md, uid->name, uid->len );
} }

View File

@ -951,8 +951,8 @@ store_validation_status (int depth, KBNODE keyblock)
if (status) if (status)
{ {
if( uid->photo ) if( uid->attrib_data )
rmd160_hash_buffer (namehash, uid->photo, uid->photolen); rmd160_hash_buffer (namehash,uid->attrib_data,uid->attrib_len);
else else
rmd160_hash_buffer (namehash, uid->name, uid->len ); rmd160_hash_buffer (namehash, uid->name, uid->len );
@ -1373,8 +1373,8 @@ validate_keys (int interactive)
byte namehash[20]; byte namehash[20];
PKT_user_id *uid = node->pkt->pkt.user_id; PKT_user_id *uid = node->pkt->pkt.user_id;
if( uid->photo ) if( uid->attrib_data )
rmd160_hash_buffer (namehash, uid->photo, uid->photolen); rmd160_hash_buffer (namehash,uid->attrib_data,uid->attrib_len);
else else
rmd160_hash_buffer (namehash, uid->name, uid->len ); rmd160_hash_buffer (namehash, uid->name, uid->len );
update_validity (pk, namehash, 0, TRUST_ULTIMATE); update_validity (pk, namehash, 0, TRUST_ULTIMATE);