static int do_export( strlist_t users, int secret, unsigned int options ) { IOBUF out = NULL; int any, rc; armor_filter_context_t *afx = NULL; compress_filter_context_t zfx; memset( &zfx, 0, sizeof zfx); rc = open_outfile( NULL, 0, &out ); if (rc) return rc; if (!(options & EXPORT_SEXP_FORMAT)) { if ( opt.armor ) { afx = new_armor_context (); afx->what = secret? 5 : 1; push_armor_filter (afx, out); } if ( opt.compress_keys ) push_compress_filter (out,&zfx,default_compress_algo()); } rc = do_export_stream ( out, users, secret, NULL, options, &any ); if ( rc || !any ) iobuf_cancel (out); else iobuf_close (out); release_armor_context (afx); return rc; }
static int do_public_key( IOBUF out, int ctb, PKT_public_key *pk ) { int rc = 0; int n, i; IOBUF a = iobuf_temp(); if( !pk->version ) iobuf_put( a, 3 ); else iobuf_put( a, pk->version ); write_32(a, pk->timestamp ); if( pk->version < 4 ) { u16 ndays; if( pk->expiredate ) ndays = (u16)((pk->expiredate - pk->timestamp) / 86400L); else ndays = 0; write_16(a, ndays ); } iobuf_put(a, pk->pubkey_algo ); n = pubkey_get_npkey( pk->pubkey_algo ); if( !n ) write_fake_data( a, pk->pkey[0] ); for(i=0; i < n; i++ ) mpi_write(a, pk->pkey[i] ); write_header2(out, ctb, iobuf_get_temp_length(a), pk->hdrbytes, 1 ); if( iobuf_write_temp( out, a ) ) rc = G10ERR_WRITE_FILE; iobuf_close(a); return rc; }
/* * Try to open a file without the extension ".sig" or ".asc" * Return NULL if such a file is not available. */ iobuf_t open_sigfile (const char *sigfilename, progress_filter_context_t *pfx) { iobuf_t a = NULL; char *buf; buf = get_matching_datafile (sigfilename); if (buf) { a = iobuf_open (buf); if (a && is_secured_file (iobuf_get_fd (a))) { iobuf_close (a); a = NULL; gpg_err_set_errno (EPERM); } if (a) log_info (_("assuming signed data in '%s'\n"), buf); if (a && pfx) handle_progress (pfx, a, buf); xfree (buf); } return a; }
static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc ) { int rc = 0; int n, i; IOBUF a = iobuf_temp(); write_version( a, ctb ); if ( enc->throw_keyid ) { write_32(a, 0 ); /* Don't tell Eve who can decrypt the message. */ write_32(a, 0 ); } else { write_32(a, enc->keyid[0] ); write_32(a, enc->keyid[1] ); } iobuf_put(a,enc->pubkey_algo ); n = pubkey_get_nenc( enc->pubkey_algo ); if ( !n ) write_fake_data( a, enc->data[0] ); for (i=0; i < n && !rc ; i++ ) rc = mpi_write(a, enc->data[i] ); if (!rc) { write_header(out, ctb, iobuf_get_temp_length(a) ); rc = iobuf_write_temp( out, a ); } iobuf_close(a); return rc; }
static int do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc ) { int rc = 0; IOBUF a = iobuf_temp(); assert( enc->version == 4 ); switch( enc->s2k.mode ) { case 0: case 1: case 3: break; default: log_bug("do_symkey_enc: s2k=%d\n", enc->s2k.mode ); } iobuf_put( a, enc->version ); iobuf_put( a, enc->cipher_algo ); iobuf_put( a, enc->s2k.mode ); iobuf_put( a, enc->s2k.hash_algo ); if( enc->s2k.mode == 1 || enc->s2k.mode == 3 ) { iobuf_write(a, enc->s2k.salt, 8 ); if( enc->s2k.mode == 3 ) iobuf_put(a, enc->s2k.count); } if( enc->seskeylen ) iobuf_write(a, enc->seskey, enc->seskeylen ); write_header(out, ctb, iobuf_get_temp_length(a) ); rc = iobuf_write_temp( out, a ); iobuf_close(a); return rc; }
int keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb) { int rc; const char *fname; if (!hd) fname = NULL; else if (hd->found.kr) fname = hd->found.kr->fname; else if (hd->current.kr) fname = hd->current.kr->fname; else fname = hd->resource? hd->resource->fname:NULL; if (!fname) return G10ERR_GENERAL; /* close this one otherwise we will lose the position for * a next search. Fixme: it would be better to adjust the position * after the write opertions. */ iobuf_close (hd->current.iobuf); hd->current.iobuf = NULL; /* do the insert */ rc = do_copy (1, fname, kb, hd->secret, 0, 0 ); if (!rc && !hd->secret && kr_offtbl) { update_offset_hash_table_from_kb (kr_offtbl, kb, 0); } return rc; }
int main(int argc, char **argv) { gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); int l; int ret; armor_filter_context_t *afx = NULL; while (fgets(passphrase, N, stdin) != NULL && status == 0) { IOBUF a; struct stat sb; unlink("output"); l = strlen(passphrase); passphrase[l - 1] = 0; status = 1; a = iobuf_open(argv[1]); if( use_armor_filter( a ) ) { afx = new_armor_context (); push_armor_filter (afx, a); } proc_packets(NULL, a); ret = stat("output", &sb); if (status == 1 && sb.st_size > 0 && ret != -1) { printf("Found Password : %s\n", passphrase); exit(0); } else { status = 0; } iobuf_close(a); } return -1; }
/**************** * Take file and write it out with armor */ int enarmor_file( const char *fname ) { armor_filter_context_t *afx; IOBUF inp = NULL, out = NULL; int rc = 0; int c; afx = new_armor_context (); /* prepare iobufs */ inp = iobuf_open(fname); if (inp && is_secured_file (iobuf_get_fd (inp))) { iobuf_close (inp); inp = NULL; errno = EPERM; } if (!inp) { rc = gpg_error_from_syserror (); log_error(_("can't open `%s': %s\n"), fname? fname: "[stdin]", strerror(errno) ); goto leave; } if( (rc = open_outfile( fname, 1, &out )) ) goto leave; afx->what = 4; afx->hdrlines = "Comment: Use \"gpg --dearmor\" for unpacking\n"; push_armor_filter ( afx, out ); while( (c = iobuf_get(inp)) != -1 ) iobuf_put( out, c ); leave: if( rc ) iobuf_cancel(out); else iobuf_close(out); iobuf_close(inp); release_armor_context (afx); return rc; }
/* * Insert a new KB into one of the resources. */ gpg_error_t keydb_insert_keyblock (KEYDB_HANDLE hd, kbnode_t kb) { gpg_error_t err; int idx; if (!hd) return gpg_error (GPG_ERR_INV_ARG); keyblock_cache_clear (); if (opt.dry_run) return 0; if (hd->found >= 0 && hd->found < hd->used) idx = hd->found; else if (hd->current >= 0 && hd->current < hd->used) idx = hd->current; else return gpg_error (GPG_ERR_GENERAL); err = lock_all (hd); if (err) return err; switch (hd->active[idx].type) { case KEYDB_RESOURCE_TYPE_NONE: err = gpg_error (GPG_ERR_GENERAL); /* oops */ break; case KEYDB_RESOURCE_TYPE_KEYRING: err = keyring_insert_keyblock (hd->active[idx].u.kr, kb); break; case KEYDB_RESOURCE_TYPE_KEYBOX: { /* We need to turn our kbnode_t list of packets into a proper keyblock first. This is required by the OpenPGP key parser included in the keybox code. Eventually we can change this kludge to have the caller pass the image. */ iobuf_t iobuf; u32 *sigstatus; err = build_keyblock_image (kb, &iobuf, &sigstatus); if (!err) { err = keybox_insert_keyblock (hd->active[idx].u.kb, iobuf_get_temp_buffer (iobuf), iobuf_get_temp_length (iobuf), sigstatus); xfree (sigstatus); iobuf_close (iobuf); } } break; } unlock_all (hd); return err; }
static int verify_one_file (ctrl_t ctrl, const char *name ) { IOBUF fp; armor_filter_context_t *afx = NULL; progress_filter_context_t *pfx = new_progress_context (); int rc; print_file_status( STATUS_FILE_START, name, 1 ); fp = iobuf_open(name); if (fp) iobuf_ioctl (fp, IOBUF_IOCTL_NO_CACHE, 1, NULL); if (fp && is_secured_file (iobuf_get_fd (fp))) { iobuf_close (fp); fp = NULL; gpg_err_set_errno (EPERM); } if( !fp ) { rc = gpg_error_from_syserror (); log_error(_("can't open '%s': %s\n"), print_fname_stdin(name), strerror (errno)); print_file_status( STATUS_FILE_ERROR, name, 1 ); goto leave; } handle_progress (pfx, fp, name); if( !opt.no_armor ) { if( use_armor_filter( fp ) ) { afx = new_armor_context (); push_armor_filter (afx, fp); } } rc = proc_signature_packets (ctrl, NULL, fp, NULL, name ); iobuf_close(fp); write_status( STATUS_FILE_DONE ); reset_literals_seen(); leave: release_armor_context (afx); release_progress_context (pfx); return rc; }
static void keyblock_cache_clear (void) { keyblock_cache.state = KEYBLOCK_CACHE_EMPTY; xfree (keyblock_cache.sigstatus); keyblock_cache.sigstatus = NULL; iobuf_close (keyblock_cache.iobuf); keyblock_cache.iobuf = NULL; }
int exec_finish(struct exec_info *info) { int ret=info->progreturn; if(info->fromchild) iobuf_close(info->fromchild); if(info->tochild) fclose(info->tochild); #ifndef EXEC_TEMPFILE_ONLY if(info->child>0) { if(waitpid(info->child,&info->progreturn,0)!=0 && WIFEXITED(info->progreturn)) ret=WEXITSTATUS(info->progreturn); else { log_error(_("unnatural exit of external program\n")); ret=127; } } #endif if(info->flags.madedir && !info->flags.keep_temp_files) { if(info->tempfile_in) { if(unlink(info->tempfile_in)==-1) log_info(_("WARNING: unable to remove tempfile (%s) `%s': %s\n"), "in",info->tempfile_in,strerror(errno)); } if(info->tempfile_out) { if(unlink(info->tempfile_out)==-1) log_info(_("WARNING: unable to remove tempfile (%s) `%s': %s\n"), "out",info->tempfile_out,strerror(errno)); } if(rmdir(info->tempdir)==-1) log_info(_("WARNING: unable to remove temp directory `%s': %s\n"), info->tempdir,strerror(errno)); } xfree(info->command); xfree(info->name); xfree(info->tempdir); xfree(info->tempfile_in); xfree(info->tempfile_out); xfree(info); return ret; }
void keyring_release (KEYRING_HANDLE hd) { if (!hd) return; assert (active_handles > 0); active_handles--; xfree (hd->word_match.name); xfree (hd->word_match.pattern); iobuf_close (hd->current.iobuf); xfree (hd); }
int main(int argc,char *argv[]) { unsigned char *fpr; size_t fpr_len; char *url; int rc; IOBUF iobuf; if(argc!=2) { printf("cert-test [name]\n"); return 1; } printf("CERT lookup on %s\n",argv[1]); rc=get_cert(argv[1],16384,&iobuf,&fpr,&fpr_len,&url); if(rc==-1) printf("error\n"); else if(rc==0) printf("no answer\n"); else if(rc==1) { printf("key found: %d bytes\n",(int)iobuf_get_temp_length(iobuf)); iobuf_close(iobuf); } else if(rc==2) { if(fpr) { size_t i; printf("Fingerprint found (%d bytes): ",(int)fpr_len); for(i=0;i<fpr_len;i++) printf("%02X",fpr[i]); printf("\n"); } else printf("No fingerprint found\n"); if(url) printf("URL found: %s\n",url); else printf("No URL found\n"); xfree(fpr); xfree(url); } return 0; }
/* * Start the next search on this handle right at the beginning */ int keyring_search_reset (KEYRING_HANDLE hd) { assert (hd); hd->current.kr = NULL; iobuf_close (hd->current.iobuf); hd->current.iobuf = NULL; hd->current.eof = 0; hd->current.error = 0; hd->found.kr = NULL; hd->found.offset = 0; return 0; }
static int do_public_key( IOBUF out, int ctb, PKT_public_key *pk ) { int rc = 0; int n, i; IOBUF a = iobuf_temp(); if ( !pk->version ) iobuf_put( a, 3 ); else iobuf_put( a, pk->version ); write_32(a, pk->timestamp ); if ( pk->version < 4 ) { u16 ndays; if ( pk->expiredate ) ndays = (u16)((pk->expiredate - pk->timestamp) / 86400L); else ndays = 0; write_16(a, ndays ); } iobuf_put (a, pk->pubkey_algo ); if ( pk->pubkey_algo == PUBKEY_ALGO_NTRU){ rc = sexp_write(a, pk->ntru_pkey); } else { n = pubkey_get_npkey ( pk->pubkey_algo ); if ( !n ) write_fake_data( a, pk->pkey[0] ); } if (!rc) { write_header2 (out, ctb, iobuf_get_temp_length(a), pk->hdrbytes); printf("write output\n"); rc = iobuf_write_temp ( out, a ); } printf("finished writing\n"); iobuf_close(a); return rc; }
/**************** * Check if the file is compressed. **/ int is_file_compressed( const char *s, int *ret_rc ) { IOBUF a; byte buf[4]; int i, rc = 0; struct magic_compress_s { size_t len; byte magic[4]; } magic[] = { { 3, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */ { 3, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */ { 4, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */ }; if ( !s || *s == '-' || !ret_rc ) return 0; /* We can't check stdin or no file was given */ a = iobuf_open( s ); if ( a == NULL ) { *ret_rc = G10ERR_OPEN_FILE; return 0; } if ( iobuf_get_filelength( a ) < 4 ) { *ret_rc = 0; goto leave; } if ( iobuf_read( a, buf, 4 ) == -1 ) { *ret_rc = G10ERR_READ_FILE; goto leave; } for ( i = 0; i < DIM( magic ); i++ ) { if ( !memcmp( buf, magic[i].magic, magic[i].len ) ) { *ret_rc = 0; rc = 1; break; } } leave: iobuf_close( a ); return rc; }
/* Perform a verify operation. To verify detached signatures, DATA_FD shall be the descriptor of the signed data; for regular signatures it needs to be -1. If OUT_FP is not NULL and DATA_FD is not -1 the the signed material gets written that stream. FIXME: OUTFP is not yet implemented. */ int gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp) { int rc; iobuf_t fp; armor_filter_context_t *afx = NULL; progress_filter_context_t *pfx = new_progress_context (); (void)ctrl; (void)out_fp; if (is_secured_file (sig_fd)) { fp = NULL; gpg_err_set_errno (EPERM); } else fp = iobuf_fdopen_nc (sig_fd, "rb"); if (!fp) { rc = gpg_error_from_syserror (); log_error (_("can't open fd %d: %s\n"), sig_fd, strerror (errno)); goto leave; } handle_progress (pfx, fp, NULL); if ( !opt.no_armor && use_armor_filter (fp) ) { afx = new_armor_context (); push_armor_filter (afx, fp); } rc = proc_signature_packets_by_fd (ctrl, NULL, fp, data_fd); if ( afx && afx->no_openpgp_data && (rc == -1 || gpg_err_code (rc) == GPG_ERR_EOF) ) rc = gpg_error (GPG_ERR_NO_DATA); leave: iobuf_close (fp); release_progress_context (pfx); release_armor_context (afx); return rc; }
int keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb) { printf("starting keyring_insert_keyblock\n" ); int rc; const char *fname; if (!hd) fname = NULL; else if (hd->found.kr) { fname = hd->found.kr->fname; if (hd->found.kr->readonly) return gpg_error (GPG_ERR_EACCES); } else if (hd->current.kr) { fname = hd->current.kr->fname; if (hd->current.kr->readonly) return gpg_error (GPG_ERR_EACCES); } else fname = hd->resource? hd->resource->fname:NULL; if (!fname) return G10ERR_GENERAL; /* Close this one otherwise we will lose the position for * a next search. Fixme: it would be better to adjust the position * after the write opertions. */ iobuf_close (hd->current.iobuf); hd->current.iobuf = NULL; printf("before do copy\n"); /* do the insert */ rc = do_copy (1, fname, kb, hd->secret, 0, 0 ); printf("after do copy\n"); if (!rc && !hd->secret && kr_offtbl) { update_offset_hash_table_from_kb (kr_offtbl, kb, 0); } printf("finish keyring_insert_keyblock\n" ); return rc; }
int keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb) { int rc; const char *fname; if (!hd) fname = NULL; else if (hd->found.kr) { fname = hd->found.kr->fname; if (hd->found.kr->read_only) return gpg_error (GPG_ERR_EACCES); } else if (hd->current.kr) { fname = hd->current.kr->fname; if (hd->current.kr->read_only) return gpg_error (GPG_ERR_EACCES); } else fname = hd->resource? hd->resource->fname:NULL; if (!fname) return GPG_ERR_GENERAL; /* Close this one otherwise we will lose the position for * a next search. Fixme: it would be better to adjust the position * after the write opertions. */ iobuf_close (hd->current.iobuf); hd->current.iobuf = NULL; /* do the insert */ rc = do_copy (1, fname, kb, 0, 0 ); if (!rc && key_present_hash) { key_present_hash_update_from_kb (key_present_hash, kb); } return rc; }
int keyring_update_keyblock (KEYRING_HANDLE hd, KBNODE kb) { int rc; if (!hd->found.kr) return -1; /* no successful prior search */ if (hd->found.kr->readonly) return gpg_error (GPG_ERR_EACCES); if (!hd->found.n_packets) { /* need to know the number of packets - do a dummy get_keyblock*/ rc = keyring_get_keyblock (hd, NULL); if (rc) { log_error ("re-reading keyblock failed: %s\n", g10_errstr (rc)); return rc; } if (!hd->found.n_packets) BUG (); } /* The open iobuf isn't needed anymore and in fact is a problem when it comes to renaming the keyring files on some operating systems, so close it here */ iobuf_close(hd->current.iobuf); hd->current.iobuf = NULL; /* do the update */ rc = do_copy (3, hd->found.kr->fname, kb, hd->secret, hd->found.offset, hd->found.n_packets ); if (!rc) { if (!hd->secret && kr_offtbl) { update_offset_hash_table_from_kb (kr_offtbl, kb, 0); } /* better reset the found info */ hd->found.kr = NULL; hd->found.offset = 0; } return rc; }
static int prepare_search (KEYRING_HANDLE hd) { if (hd->current.error) return hd->current.error; /* still in error state */ if (hd->current.kr && !hd->current.eof) { if ( !hd->current.iobuf ) return G10ERR_GENERAL; /* position invalid after a modify */ return 0; /* okay */ } if (!hd->current.kr && hd->current.eof) return -1; /* still EOF */ if (!hd->current.kr) { /* start search with first keyring */ hd->current.kr = hd->resource; if (!hd->current.kr) { hd->current.eof = 1; return -1; /* keyring not available */ } assert (!hd->current.iobuf); } else { /* EOF */ iobuf_close (hd->current.iobuf); hd->current.iobuf = NULL; hd->current.kr = NULL; hd->current.eof = 1; return -1; } hd->current.eof = 0; hd->current.iobuf = iobuf_open (hd->current.kr->fname); if (!hd->current.iobuf) { hd->current.error = gpg_error_from_syserror (); log_error(_("can't open `%s'\n"), hd->current.kr->fname ); return hd->current.error; } return 0; }
/* * Start the next search on this handle right at the beginning */ int keyring_search_reset (KEYRING_HANDLE hd) { log_assert (hd); iobuf_close (hd->current.iobuf); hd->current.iobuf = NULL; hd->current.eof = 0; hd->current.error = 0; hd->found.kr = NULL; hd->found.offset = 0; if (hd->current.kr) iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)hd->current.kr->fname); hd->current.kr = NULL; return 0; }
int keyring_delete_keyblock (KEYRING_HANDLE hd) { int rc; if (!hd->found.kr) return -1; /* no successful prior search */ if (hd->found.kr->readonly) return gpg_error (GPG_ERR_EACCES); if (!hd->found.n_packets) { /* need to know the number of packets - do a dummy get_keyblock*/ rc = keyring_get_keyblock (hd, NULL); if (rc) { log_error ("re-reading keyblock failed: %s\n", g10_errstr (rc)); return rc; } if (!hd->found.n_packets) BUG (); } /* close this one otherwise we will lose the position for * a next search. Fixme: it would be better to adjust the position * after the write opertions. */ iobuf_close (hd->current.iobuf); hd->current.iobuf = NULL; /* do the delete */ rc = do_copy (2, hd->found.kr->fname, NULL, hd->secret, hd->found.offset, hd->found.n_packets ); if (!rc) { /* better reset the found info */ hd->found.kr = NULL; hd->found.offset = 0; /* Delete is a rare operations, so we don't remove the keys * from the offset table */ } return rc; }
/* * Return the last found keyring. Caller must free it. * The returned keyblock has the kbode flag bit 0 set for the node with * the public key used to locate the keyblock or flag bit 1 set for * the user ID node. */ int keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb) { PACKET *pkt; int rc; KBNODE keyblock = NULL, node, lastnode; IOBUF a; int in_cert = 0; int pk_no = 0; int uid_no = 0; int save_mode; if (ret_kb) *ret_kb = NULL; if (!hd->found.kr) return -1; /* no successful search */ a = iobuf_open (hd->found.kr->fname); if (!a) { log_error(_("can't open `%s'\n"), hd->found.kr->fname); return G10ERR_KEYRING_OPEN; } if (iobuf_seek (a, hd->found.offset) ) { log_error ("can't seek `%s'\n", hd->found.kr->fname); iobuf_close(a); return G10ERR_KEYRING_OPEN; } pkt = xmalloc (sizeof *pkt); init_packet (pkt); hd->found.n_packets = 0;; lastnode = NULL; save_mode = set_packet_list_mode(0); while ((rc=parse_packet (a, pkt)) != -1) { hd->found.n_packets++; if (rc == G10ERR_UNKNOWN_PACKET) { free_packet (pkt); init_packet (pkt); continue; } if (rc) { log_error ("keyring_get_keyblock: read error: %s\n", g10_errstr(rc) ); rc = G10ERR_INV_KEYRING; break; } if (pkt->pkttype == PKT_COMPRESSED) { log_error ("skipped compressed packet in keyring\n"); free_packet(pkt); init_packet(pkt); continue; } if (in_cert && (pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_SECRET_KEY)) { hd->found.n_packets--; /* fix counter */ break; /* ready */ } in_cert = 1; if (pkt->pkttype == PKT_RING_TRUST) { /*(this code is duplicated after the loop)*/ if ( lastnode && lastnode->pkt->pkttype == PKT_SIGNATURE && (pkt->pkt.ring_trust->sigcache & 1) ) { /* this is a ring trust packet with a checked signature * status cache following directly a signature paket. * Set the cache status into that signature packet */ PKT_signature *sig = lastnode->pkt->pkt.signature; sig->flags.checked = 1; sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2); } /* reset lastnode, so that we set the cache status only from * the ring trust packet immediately folling a signature */ lastnode = NULL; } else { node = lastnode = new_kbnode (pkt); if (!keyblock) keyblock = node; else add_kbnode (keyblock, node); if ( pkt->pkttype == PKT_PUBLIC_KEY || pkt->pkttype == PKT_PUBLIC_SUBKEY || pkt->pkttype == PKT_SECRET_KEY || pkt->pkttype == PKT_SECRET_SUBKEY) { if (++pk_no == hd->found.pk_no) node->flag |= 1; } else if ( pkt->pkttype == PKT_USER_ID) { if (++uid_no == hd->found.uid_no) node->flag |= 2; } } pkt = xmalloc (sizeof *pkt); init_packet(pkt); } set_packet_list_mode(save_mode); if (rc == -1 && keyblock) rc = 0; /* got the entire keyblock */ if (rc || !ret_kb) release_kbnode (keyblock); else { /*(duplicated form the loop body)*/ if ( pkt && pkt->pkttype == PKT_RING_TRUST && lastnode && lastnode->pkt->pkttype == PKT_SIGNATURE && (pkt->pkt.ring_trust->sigcache & 1) ) { PKT_signature *sig = lastnode->pkt->pkt.signature; sig->flags.checked = 1; sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2); } *ret_kb = keyblock; } free_packet (pkt); xfree (pkt); iobuf_close(a); /* Make sure that future search operations fail immediately when * we know that we are working on a invalid keyring */ if (rc == G10ERR_INV_KEYRING) hd->current.error = rc; return rc; }
/* Build a keyblock image from KEYBLOCK. Returns 0 on success and only then stores a new iobuf object at R_IOBUF and a signature status vecotor at R_SIGSTATUS. */ static gpg_error_t build_keyblock_image (kbnode_t keyblock, iobuf_t *r_iobuf, u32 **r_sigstatus) { gpg_error_t err; iobuf_t iobuf; kbnode_t kbctx, node; u32 n_sigs; u32 *sigstatus; *r_iobuf = NULL; *r_sigstatus = NULL; /* Allocate a vector for the signature cache. This is an array of u32 values with the first value giving the number of elements to follow and each element descriping the cache status of the signature. */ for (kbctx = NULL, n_sigs = 0; (node = walk_kbnode (keyblock, &kbctx, 0));) if (node->pkt->pkttype == PKT_SIGNATURE) n_sigs++; sigstatus = xtrycalloc (1+n_sigs, sizeof *sigstatus); if (!sigstatus) return gpg_error_from_syserror (); iobuf = iobuf_temp (); for (kbctx = NULL, n_sigs = 0; (node = walk_kbnode (keyblock, &kbctx, 0));) { /* Make sure to use only packets valid on a keyblock. */ switch (node->pkt->pkttype) { case PKT_PUBLIC_KEY: case PKT_PUBLIC_SUBKEY: case PKT_SIGNATURE: case PKT_USER_ID: case PKT_ATTRIBUTE: /* Note that we don't want the ring trust packets. They are not useful. */ break; default: continue; } err = build_packet (iobuf, node->pkt); if (err) { iobuf_close (iobuf); return err; } /* Build signature status vector. */ if (node->pkt->pkttype == PKT_SIGNATURE) { PKT_signature *sig = node->pkt->pkt.signature; n_sigs++; /* Fixme: Detect tye "missing key" status. */ if (sig->flags.checked) { if (sig->flags.valid) { if (!sig->expiredate) sigstatus[n_sigs] = 0xffffffff; else if (sig->expiredate < 0x1000000) sigstatus[n_sigs] = 0x10000000; else sigstatus[n_sigs] = sig->expiredate; } else sigstatus[n_sigs] = 0x00000002; /* Bad signature. */ } } } sigstatus[0] = n_sigs; *r_iobuf = iobuf; *r_sigstatus = sigstatus; return 0; }
/* * Return the last found keyring. Caller must free it. * The returned keyblock has the kbode flag bit 0 set for the node with * the public key used to locate the keyblock or flag bit 1 set for * the user ID node. */ gpg_error_t keydb_get_keyblock (KEYDB_HANDLE hd, KBNODE *ret_kb) { gpg_error_t err = 0; *ret_kb = NULL; if (!hd) return gpg_error (GPG_ERR_INV_ARG); if (keyblock_cache.state == KEYBLOCK_CACHE_FILLED) { iobuf_seek (keyblock_cache.iobuf, 0); err = parse_keyblock_image (keyblock_cache.iobuf, keyblock_cache.pk_no, keyblock_cache.uid_no, keyblock_cache.sigstatus, ret_kb); if (err) keyblock_cache_clear (); return err; } if (hd->found < 0 || hd->found >= hd->used) return gpg_error (GPG_ERR_VALUE_NOT_FOUND); switch (hd->active[hd->found].type) { case KEYDB_RESOURCE_TYPE_NONE: err = gpg_error (GPG_ERR_GENERAL); /* oops */ break; case KEYDB_RESOURCE_TYPE_KEYRING: err = keyring_get_keyblock (hd->active[hd->found].u.kr, ret_kb); break; case KEYDB_RESOURCE_TYPE_KEYBOX: { iobuf_t iobuf; u32 *sigstatus; int pk_no, uid_no; err = keybox_get_keyblock (hd->active[hd->found].u.kb, &iobuf, &pk_no, &uid_no, &sigstatus); if (!err) { err = parse_keyblock_image (iobuf, pk_no, uid_no, sigstatus, ret_kb); if (!err && keyblock_cache.state == KEYBLOCK_CACHE_PREPARED) { keyblock_cache.state = KEYBLOCK_CACHE_FILLED; keyblock_cache.sigstatus = sigstatus; keyblock_cache.iobuf = iobuf; keyblock_cache.pk_no = pk_no; keyblock_cache.uid_no = uid_no; } else { xfree (sigstatus); iobuf_close (iobuf); } } } break; } if (keyblock_cache.state != KEYBLOCK_CACHE_FILLED) keyblock_cache_clear (); return err; }
/* Handle the creation of a keyring or a keybox if it does not yet exist. Take into acount that other processes might have the keyring/keybox already locked. This lock check does not work if the directory itself is not yet available. */ static int maybe_create_keyring_or_box (char *filename, int is_box, int force) { dotlock_t lockhd = NULL; IOBUF iobuf; int rc; mode_t oldmask; char *last_slash_in_filename; int save_slash; /* A quick test whether the filename already exists. */ if (!access (filename, F_OK)) return 0; /* If we don't want to create a new file at all, there is no need to go any further - bail out right here. */ if (!force) return gpg_error (GPG_ERR_ENOENT); /* First of all we try to create the home directory. Note, that we don't do any locking here because any sane application of gpg would create the home directory by itself and not rely on gpg's tricky auto-creation which is anyway only done for some home directory name patterns. */ last_slash_in_filename = strrchr (filename, DIRSEP_C); #if HAVE_W32_SYSTEM { /* Windows may either have a slash or a backslash. Take care of it. */ char *p = strrchr (filename, '/'); if (!last_slash_in_filename || p > last_slash_in_filename) last_slash_in_filename = p; } #endif /*HAVE_W32_SYSTEM*/ if (!last_slash_in_filename) return gpg_error (GPG_ERR_ENOENT); /* No slash at all - should not happen though. */ save_slash = *last_slash_in_filename; *last_slash_in_filename = 0; if (access(filename, F_OK)) { static int tried; if (!tried) { tried = 1; try_make_homedir (filename); } if (access (filename, F_OK)) { rc = gpg_error_from_syserror (); *last_slash_in_filename = save_slash; goto leave; } } *last_slash_in_filename = save_slash; /* To avoid races with other instances of gpg trying to create or update the keyring (it is removed during an update for a short time), we do the next stuff in a locked state. */ lockhd = dotlock_create (filename, 0); if (!lockhd) { rc = gpg_error_from_syserror (); /* A reason for this to fail is that the directory is not writable. However, this whole locking stuff does not make sense if this is the case. An empty non-writable directory with no keyring is not really useful at all. */ if (opt.verbose) log_info ("can't allocate lock for '%s': %s\n", filename, gpg_strerror (rc)); if (!force) return gpg_error (GPG_ERR_ENOENT); else return rc; } if ( dotlock_take (lockhd, -1) ) { rc = gpg_error_from_syserror (); /* This is something bad. Probably a stale lockfile. */ log_info ("can't lock '%s': %s\n", filename, gpg_strerror (rc)); goto leave; } /* Now the real test while we are locked. */ if (!access (filename, F_OK)) { rc = 0; /* Okay, we may access the file now. */ goto leave; } /* The file does not yet exist, create it now. */ oldmask = umask (077); if (is_secured_filename (filename)) { iobuf = NULL; gpg_err_set_errno (EPERM); } else iobuf = iobuf_create (filename); umask (oldmask); if (!iobuf) { rc = gpg_error_from_syserror (); if (is_box) log_error (_("error creating keybox '%s': %s\n"), filename, gpg_strerror (rc)); else log_error (_("error creating keyring '%s': %s\n"), filename, gpg_strerror (rc)); goto leave; } iobuf_close (iobuf); /* Must invalidate that ugly cache */ iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, filename); /* Make sure that at least one record is in a new keybox file, so that the detection magic will work the next time it is used. */ if (is_box) { FILE *fp = fopen (filename, "w"); if (!fp) rc = gpg_error_from_syserror (); else { rc = _keybox_write_header_blob (fp); fclose (fp); } if (rc) { if (is_box) log_error (_("error creating keybox '%s': %s\n"), filename, gpg_strerror (rc)); else log_error (_("error creating keyring '%s': %s\n"), filename, gpg_strerror (rc)); goto leave; } } if (!opt.quiet) { if (is_box) log_info (_("keybox '%s' created\n"), filename); else log_info (_("keyring '%s' created\n"), filename); } rc = 0; leave: if (lockhd) { dotlock_release (lockhd); dotlock_destroy (lockhd); } return rc; }
static int do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk ) { int rc = 0; int i, nskey, npkey; IOBUF a = iobuf_temp(); /* Build in a self-enlarging buffer. */ /* Write the version number - if none is specified, use 3 */ if ( !sk->version ) iobuf_put ( a, 3 ); else iobuf_put ( a, sk->version ); write_32 (a, sk->timestamp ); /* v3 needs the expiration time. */ if ( sk->version < 4 ) { u16 ndays; if ( sk->expiredate ) ndays = (u16)((sk->expiredate - sk->timestamp) / 86400L); else ndays = 0; write_16(a, ndays); } iobuf_put (a, sk->pubkey_algo ); /* Get number of secret and public parameters. They are held in one array first the public ones, then the secret ones. */ nskey = pubkey_get_nskey ( sk->pubkey_algo ); npkey = pubkey_get_npkey ( sk->pubkey_algo ); /* If we don't have any public parameters - which is the case if we don't know the algorithm used - the parameters are stored as one blob in a faked (opaque) MPI. */ if ( !npkey ) { write_fake_data( a, sk->skey[0] ); goto leave; } assert ( npkey < nskey ); /* Writing the public parameters is easy. */ for (i=0; i < npkey; i++ ) if ((rc = mpi_write (a, sk->skey[i]))) goto leave; /* Build the header for protected (encrypted) secret parameters. */ if ( sk->is_protected ) { if ( is_RSA(sk->pubkey_algo) && sk->version < 4 && !sk->protect.s2k.mode ) { /* The simple rfc1991 (v3) way. */ iobuf_put (a, sk->protect.algo ); iobuf_write (a, sk->protect.iv, sk->protect.ivlen ); } else { /* OpenPGP protection according to rfc2440. */ iobuf_put(a, sk->protect.sha1chk? 0xfe : 0xff ); iobuf_put(a, sk->protect.algo ); if ( sk->protect.s2k.mode >= 1000 ) { /* These modes are not possible in OpenPGP, we use them to implement our extensions, 101 can be seen as a private/experimental extension (this is not specified in rfc2440 but the same scheme is used for all other algorithm identifiers) */ iobuf_put(a, 101 ); iobuf_put(a, sk->protect.s2k.hash_algo ); iobuf_write(a, "GNU", 3 ); iobuf_put(a, sk->protect.s2k.mode - 1000 ); } else { iobuf_put(a, sk->protect.s2k.mode ); iobuf_put(a, sk->protect.s2k.hash_algo ); } if ( sk->protect.s2k.mode == 1 || sk->protect.s2k.mode == 3 ) iobuf_write (a, sk->protect.s2k.salt, 8 ); if ( sk->protect.s2k.mode == 3 ) iobuf_put (a, sk->protect.s2k.count ); /* For our special modes 1001, 1002 we do not need an IV. */ if ( sk->protect.s2k.mode != 1001 && sk->protect.s2k.mode != 1002 ) iobuf_write (a, sk->protect.iv, sk->protect.ivlen ); } } else iobuf_put (a, 0 ); if ( sk->protect.s2k.mode == 1001 ) ; /* GnuPG extension - don't write a secret key at all. */ else if ( sk->protect.s2k.mode == 1002 ) { /* GnuPG extension - divert to OpenPGP smartcard. */ iobuf_put(a, sk->protect.ivlen ); /* Length of the serial number or 0 for no serial number. */ /* The serial number gets stored in the IV field. */ iobuf_write(a, sk->protect.iv, sk->protect.ivlen); } else if ( sk->is_protected && sk->version >= 4 ) { /* The secret key is protected - write it out as it is. */ byte *p; unsigned int ndatabits; assert (gcry_mpi_get_flag (sk->skey[npkey], GCRYMPI_FLAG_OPAQUE)); p = gcry_mpi_get_opaque (sk->skey[npkey], &ndatabits ); iobuf_write (a, p, (ndatabits+7)/8 ); } else if ( sk->is_protected ) { /* The secret key is protected the old v4 way. */ for ( ; i < nskey; i++ ) { byte *p; unsigned int ndatabits; assert (gcry_mpi_get_flag (sk->skey[i], GCRYMPI_FLAG_OPAQUE)); p = gcry_mpi_get_opaque (sk->skey[i], &ndatabits); iobuf_write (a, p, (ndatabits+7)/8); } write_16(a, sk->csum ); } else { /* Non-protected key. */ for ( ; i < nskey; i++ ) if ( (rc = mpi_write (a, sk->skey[i]))) goto leave; write_16 (a, sk->csum ); } leave: if (!rc) { /* Build the header of the packet - which we must do after writing all the other stuff, so that we know the length of the packet */ write_header2(out, ctb, iobuf_get_temp_length(a), sk->hdrbytes); /* And finally write it out the real stream */ rc = iobuf_write_temp( out, a ); } iobuf_close(a); /* Close the remporary buffer */ return rc; }
/* Generate a new photo id packet, or return NULL if canceled. FIXME: Should we add a duplicates check similar to generate_user_id? */ PKT_user_id * generate_photo_id(PKT_public_key *pk,const char *photo_name) { PKT_user_id *uid; int error=1,i; unsigned int len; char *filename; byte *photo=NULL; byte header[16]; IOBUF file; int overflow; header[0]=0x10; /* little side of photo header length */ header[1]=0; /* big side of photo header length */ header[2]=1; /* 1 == version of photo header */ header[3]=1; /* 1 == JPEG */ for(i=4;i<16;i++) /* The reserved bytes */ header[i]=0; #define EXTRA_UID_NAME_SPACE 71 uid=xmalloc_clear(sizeof(*uid)+71); if(photo_name && *photo_name) filename=make_filename(photo_name,(void *)NULL); else { tty_printf(_("\nPick an image to use for your photo ID." " The image must be a JPEG file.\n" "Remember that the image is stored within your public key." " If you use a\n" "very large picture, your key will become very large" " as well!\n" "Keeping the image close to 240x288 is a good size" " to use.\n")); filename=NULL; } while(photo==NULL) { if(filename==NULL) { char *tempname; tty_printf("\n"); tty_enable_completion(NULL); tempname=cpr_get("photoid.jpeg.add", _("Enter JPEG filename for photo ID: ")); tty_disable_completion(); filename=make_filename(tempname,(void *)NULL); xfree(tempname); if(strlen(filename)==0) goto scram; } file=iobuf_open(filename); if (file && is_secured_file (iobuf_get_fd (file))) { iobuf_close (file); file = NULL; errno = EPERM; } if(!file) { log_error(_("unable to open JPEG file `%s': %s\n"), filename,strerror(errno)); xfree(filename); filename=NULL; continue; } len=iobuf_get_filelength(file, &overflow); if(len>6144 || overflow) { tty_printf( _("This JPEG is really large (%d bytes) !\n"),len); if(!cpr_get_answer_is_yes("photoid.jpeg.size", _("Are you sure you want to use it? (y/N) "))) { iobuf_close(file); xfree(filename); filename=NULL; continue; } } photo=xmalloc(len); iobuf_read(file,photo,len); iobuf_close(file); /* Is it a JPEG? */ if(photo[0]!=0xFF || photo[1]!=0xD8 || photo[6]!='J' || photo[7]!='F' || photo[8]!='I' || photo[9]!='F') { log_error(_("`%s' is not a JPEG file\n"),filename); xfree(photo); photo=NULL; xfree(filename); filename=NULL; continue; } /* Build the packet */ build_attribute_subpkt(uid,1,photo,len,header,16); parse_attribute_subpkts(uid); make_attribute_uidname(uid, EXTRA_UID_NAME_SPACE); /* Showing the photo is not safe when noninteractive since the "user" may not be able to dismiss a viewer window! */ if(opt.command_fd==-1) { show_photos(uid->attribs,uid->numattribs,pk,NULL,uid); switch(cpr_get_answer_yes_no_quit("photoid.jpeg.okay", _("Is this photo correct (y/N/q)? "))) { case -1: goto scram; case 0: free_attributes(uid); xfree(photo); photo=NULL; xfree(filename); filename=NULL; continue; } } } error=0; uid->ref=1; scram: xfree(filename); xfree(photo); if(error) { free_attributes(uid); xfree(uid); return NULL; } return uid; }