gpg: New options --recipient-file and --hidden-recipient-file.

* g10/gpg.c (oRecipientFile, oHiddenRecipientFile): New.
(opts): Add options --recipient-file and --hidden-recipient-file.
(main): Implement them.  Also remove duplicate code from similar
options.
* g10/keydb.h (PK_LIST_FROM_FILE): New.
(PK_LIST_SHIFT): Bump up.
* g10/pkclist.c (expand_group): Take care of PK_LIST_FROM_FILE.
(find_and_check_key): Add and implement arg FROM_FILE.
(build_pk_list): Pass new value for new arg.
* g10/getkey.c (get_pubkey_fromfile): New.
* g10/gpgv.c (read_key_from_file): New stub.
* g10/test-stubs.c (read_key_from_file): New stub.
* g10/server.c (cmd_recipient): Add flag --file.
* g10/import.c (read_key_from_file): New.

* tests/openpgp/defs.scm (key-file1): New.
(key-file2): New.
* tests/openpgp/setup.scm: Add their private keys and import the
key-file1.
* tests/openpgp/encrypt.scm: Add new test.

--

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2016-07-06 14:03:50 +02:00
parent 073be51a86
commit a479804c86
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
13 changed files with 330 additions and 82 deletions

View File

@ -2037,6 +2037,22 @@ limited countermeasure against traffic analysis. If this option or
@option{--recipient} is not specified, GnuPG asks for the user ID unless
@option{--default-recipient} is given.
@item --recipient-file @var{file}
@itemx -f
@opindex recipient-file
This option is similar to @option{--recipient} except that it
encrypts to a key stored in the given file. @var{file} must be the
name of a file containing exactly one key. @command{gpg} assumes that
the key in this file is fully valid.
@item --hidden-recipient-file @var{file}
@itemx -F
@opindex hidden-recipient-file
This option is similar to @option{--hidden-recipient} except that it
encrypts to a key stored in the given file. @var{file} must be the
name of a file containing exactly one key. @command{gpg} assumes that
the key in this file is fully valid.
@item --encrypt-to @code{name}
@opindex encrypt-to
Same as @option{--recipient} but this one is intended for use in the
@ -2055,11 +2071,6 @@ recipients given either by use of @option{--recipient} or by the asked user id.
No trust checking is performed for these user ids and even disabled
keys can be used.
@item --encrypt-to-default-key
@opindex encrypt-to-default-key
If the default secret key is taken from @option{--default-key}, then
also encrypt to that key.
@item --no-encrypt-to
@opindex no-encrypt-to
Disable the use of all @option{--encrypt-to} and

View File

@ -1,7 +1,7 @@
/* getkey.c - Get a key from the database
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
* 2007, 2008, 2010 Free Software Foundation, Inc.
* Copyright (C) 2015 g10 Code GmbH
* Copyright (C) 2015, 2016 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -143,6 +143,11 @@ static void merge_selfsigs (kbnode_t keyblock);
static int lookup (getkey_ctx_t ctx,
kbnode_t *ret_keyblock, kbnode_t *ret_found_key,
int want_secret);
static kbnode_t finish_lookup (kbnode_t keyblock,
unsigned int req_usage, int want_exact,
unsigned int *r_flags);
static void print_status_key_considered (kbnode_t keyblock, unsigned int flags);
#if 0
static void
@ -1454,6 +1459,53 @@ get_pubkey_byname (ctrl_t ctrl, GETKEY_CTX * retctx, PKT_public_key * pk,
}
/* Get a public key from a file.
*
* PK is the buffer to store the key. The caller needs to make sure
* that PK->REQ_USAGE is valid. PK->REQ_USAGE is passed through to
* the lookup function and is a mask of PUBKEY_USAGE_SIG,
* PUBKEY_USAGE_ENC and PUBKEY_USAGE_CERT. If this is non-zero, only
* keys with the specified usage will be returned.
*
* FNAME is the file name. That file should contain exactly one
* keyblock.
*
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY is returned if the key
* is not found.
*
* The self-signed data has already been merged into the public key
* using merge_selfsigs. The caller must release the content of PK by
* calling release_public_key_parts (or, if PK was malloced, using
* free_public_key).
*/
gpg_error_t
get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
{
gpg_error_t err;
kbnode_t keyblock;
kbnode_t found_key;
unsigned int infoflags;
err = read_key_from_file (ctrl, fname, &keyblock);
if (!err)
{
/* Warning: node flag bits 0 and 1 should be preserved by
* merge_selfsigs. FIXME: Check whether this still holds. */
merge_selfsigs (keyblock);
found_key = finish_lookup (keyblock, pk->req_usage, 0, &infoflags);
print_status_key_considered (keyblock, infoflags);
if (found_key)
pk_from_block (pk, keyblock, found_key);
else
err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
}
release_kbnode (keyblock);
return err;
}
/* Lookup a key with the specified fingerprint.
*
* If PK is not NULL, the public key of the first result is returned

View File

@ -81,6 +81,8 @@ enum cmd_and_opt_values
aSym = 'c',
aDecrypt = 'd',
aEncr = 'e',
oRecipientFile = 'f',
oHiddenRecipientFile = 'F',
oInteractive = 'i',
aListKeys = 'k',
oDryRun = 'n',
@ -506,6 +508,8 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_s (oRecipient, "recipient", N_("|USER-ID|encrypt for USER-ID")),
ARGPARSE_s_s (oHiddenRecipient, "hidden-recipient", "@"),
ARGPARSE_s_s (oRecipientFile, "recipient-file", "@"),
ARGPARSE_s_s (oHiddenRecipientFile, "hidden-recipient-file", "@"),
ARGPARSE_s_s (oRecipient, "remote-user", "@"), /* (old option name) */
ARGPARSE_s_s (oDefRecipient, "default-recipient", "@"),
ARGPARSE_s_n (oDefRecipientSelf, "default-recipient-self", "@"),
@ -2838,38 +2842,46 @@ main (int argc, char **argv)
else
opt.s2k_count = 0; /* Auto-calibrate when needed. */
break;
case oNoEncryptTo: opt.no_encrypt_to = 1; break;
case oEncryptTo: /* store the recipient in the second list */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
break;
case oHiddenEncryptTo: /* store the recipient in the second list */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = ((pargs.r_opt << PK_LIST_SHIFT)
| PK_LIST_ENCRYPT_TO|PK_LIST_HIDDEN);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
break;
case oEncryptToDefaultKey:
opt.encrypt_to_default_key = configfp ? 2 : 1;
break;
case oRecipient: /* store the recipient */
case oRecipient:
case oHiddenRecipient:
case oRecipientFile:
case oHiddenRecipientFile:
/* Store the recipient. Note that we also store the
* option as private data in the flags. This is achieved
* by shifting the option value to the left so to keep
* enough space for the flags. */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = (pargs.r_opt << PK_LIST_SHIFT);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
if (pargs.r_opt == oHiddenRecipient
|| pargs.r_opt == oHiddenRecipientFile)
sl->flags |= PK_LIST_HIDDEN;
if (pargs.r_opt == oRecipientFile
|| pargs.r_opt == oHiddenRecipientFile)
sl->flags |= PK_LIST_FROM_FILE;
any_explicit_recipient = 1;
break;
case oHiddenRecipient: /* store the recipient with a flag */
case oEncryptTo:
case oHiddenEncryptTo:
/* Store an additional recipient. */
sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_HIDDEN);
sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
any_explicit_recipient = 1;
if (pargs.r_opt == oHiddenEncryptTo)
sl->flags |= PK_LIST_HIDDEN;
break;
case oNoEncryptTo:
opt.no_encrypt_to = 1;
break;
case oEncryptToDefaultKey:
opt.encrypt_to_default_key = configfp ? 2 : 1;
break;
case oTrySecretKey:
add_to_strlist2 (&opt.secret_keys_to_try,
pargs.r.ret_str, utf8_strings);

View File

@ -416,6 +416,17 @@ keyserver_import_ldap (const char *name)
return -1;
}
gpg_error_t
read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
{
(void)ctrl;
(void)fname;
(void)r_keyblock;
return -1;
}
/* Stub:
* No encryption here but mainproc links to these functions.
*/

View File

@ -220,6 +220,113 @@ import_release_stats_handle (import_stats_t p)
}
/* Read a key from a file. Only the first key in the file is
* considered and stored at R_KEYBLOCK. FNAME is the name of the
* file.
*/
gpg_error_t
read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
{
gpg_error_t err;
iobuf_t inp;
PACKET *pending_pkt = NULL;
kbnode_t keyblock = NULL;
u32 keyid[2];
int v3keys; /* Dummy */
int non_self; /* Dummy */
(void)ctrl;
*r_keyblock = NULL;
inp = iobuf_open (fname);
if (!inp)
err = gpg_error_from_syserror ();
else if (is_secured_file (iobuf_get_fd (inp)))
{
iobuf_close (inp);
inp = NULL;
err = gpg_error (GPG_ERR_EPERM);
}
else
err = 0;
if (err)
{
log_error (_("can't open '%s': %s\n"),
iobuf_is_pipe_filename (fname)? "[stdin]": fname,
gpg_strerror (err));
if (gpg_err_code (err) == GPG_ERR_ENOENT)
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
/* Push the armor filter. */
{
armor_filter_context_t *afx;
afx = new_armor_context ();
afx->only_keyblocks = 1;
push_armor_filter (afx, inp);
release_armor_context (afx);
}
/* Read the first non-v3 keyblock. */
while (!(err = read_block (inp, &pending_pkt, &keyblock, &v3keys)))
{
if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
break;
log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
release_kbnode (keyblock);
keyblock = NULL;
}
if (err)
{
if (gpg_err_code (err) != GPG_ERR_INV_KEYRING)
log_error (_("error reading '%s': %s\n"),
iobuf_is_pipe_filename (fname)? "[stdin]": fname,
gpg_strerror (err));
goto leave;
}
keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
if (!find_next_kbnode (keyblock, PKT_USER_ID))
{
err = gpg_error (GPG_ERR_NO_USER_ID);
goto leave;
}
collapse_uids (&keyblock);
clear_kbnode_flags (keyblock);
if (chk_self_sigs (keyblock, keyid, &non_self))
{
err = gpg_error (GPG_ERR_INV_KEYRING);
goto leave;
}
if (!delete_inv_parts (keyblock, keyid, 0) )
{
err = gpg_error (GPG_ERR_NO_USER_ID);
goto leave;
}
*r_keyblock = keyblock;
keyblock = NULL;
leave:
if (inp)
{
iobuf_close (inp);
/* Must invalidate that ugly cache to actually close the file. */
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
}
release_kbnode (keyblock);
/* FIXME: Do we need to free PENDING_PKT ? */
return err;
}
/*
* Import the public keys from the given filename. Input may be armored.
* This function rejects all keys which are not validly self signed on at

View File

@ -70,15 +70,16 @@ enum resource_type {
/* Bit flags used with build_pk_list. */
enum
{
PK_LIST_ENCRYPT_TO=1, /* This is an encrypt-to recipient. */
PK_LIST_HIDDEN=2, /* This is a hidden recipient. */
PK_LIST_CONFIG=4 /* Specified via config file. */
PK_LIST_ENCRYPT_TO = 1, /* This is an encrypt-to recipient. */
PK_LIST_HIDDEN = 2, /* This is a hidden recipient. */
PK_LIST_CONFIG = 4, /* Specified via config file. */
PK_LIST_FROM_FILE = 8 /* Take key from file with that name. */
};
/* To store private data in the flags they must be left shifted by
this value. */
/* To store private data in the flags the private data must be left
shifted by this value. */
enum
{
PK_LIST_SHIFT=3
PK_LIST_SHIFT = 4
};
/****************
@ -104,7 +105,7 @@ struct pk_list
{
PK_LIST next;
PKT_public_key *pk;
int flags; /* flag bit 1==throw_keyid */
int flags; /* See PK_LIST_ constants. */
};
/* Structure to hold a list of secret key certificates. */
@ -228,7 +229,8 @@ void release_pk_list (PK_LIST pk_list);
int build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list);
gpg_error_t find_and_check_key (ctrl_t ctrl,
const char *name, unsigned int use,
int mark_hidden, pk_list_t *pk_list_addr);
int mark_hidden, int from_file,
pk_list_t *pk_list_addr);
int algo_available( preftype_t preftype, int algo,
const union pref_hint *hint );
@ -322,6 +324,10 @@ int get_pubkey_byname (ctrl_t ctrl,
KBNODE *ret_keyblock, KEYDB_HANDLE *ret_kdbhd,
int include_unusable, int no_akl );
/* Get a public key directly from file FNAME. */
gpg_error_t get_pubkey_fromfile (ctrl_t ctrl,
PKT_public_key *pk, const char *fname);
/* Return the public key with the key id KEYID iff the secret key is
* available and store it at PK. */
gpg_error_t get_seckey (PKT_public_key *pk, u32 *keyid);

View File

@ -350,6 +350,8 @@ typedef gpg_error_t (*import_screener_t)(kbnode_t keyblock, void *arg);
int parse_import_options(char *str,unsigned int *options,int noisy);
gpg_error_t parse_and_set_import_filter (const char *string);
gpg_error_t read_key_from_file (ctrl_t ctrl, const char *fname,
kbnode_t *r_keyblock);
void import_keys (ctrl_t ctrl, char **fnames, int nnames,
import_stats_t stats_hd, unsigned int options);
int import_keys_stream (ctrl_t ctrl, iobuf_t inp, import_stats_t stats_hd,

View File

@ -775,14 +775,16 @@ expand_id(const char *id,strlist_t *into,unsigned int flags)
}
/* For simplicity, and to avoid potential loops, we only expand once -
you can't make an alias that points to an alias. */
* you can't make an alias that points to an alias. */
static strlist_t
expand_group(strlist_t input)
expand_group (strlist_t input)
{
strlist_t sl,output=NULL,rover;
strlist_t output = NULL;
strlist_t sl, rover;
for(rover=input;rover;rover=rover->next)
if(expand_id(rover->d,&output,rover->flags)==0)
for (rover = input; rover; rover = rover->next)
if (!(rover->flags & PK_LIST_FROM_FILE)
&& !expand_id(rover->d,&output,rover->flags))
{
/* Didn't find any groups, so use the existing string */
sl=add_to_strlist(&output,rover->d);
@ -794,17 +796,18 @@ expand_group(strlist_t input)
/* Helper for build_pk_list to find and check one key. This helper is
also used directly in server mode by the RECIPIENTS command. On
success the new key is added to PK_LIST_ADDR. NAME is the user id
of the key. USE the requested usage and a set MARK_HIDDEN will mark
the key in the updated list as a hidden recipient. */
* also used directly in server mode by the RECIPIENTS command. On
* success the new key is added to PK_LIST_ADDR. NAME is the user id
* of the key. USE the requested usage and a set MARK_HIDDEN will
* mark the key in the updated list as a hidden recipient. If
* FROM_FILE is true, NAME is is not a user ID but the name of a file
* holding a key. */
gpg_error_t
find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
int mark_hidden, pk_list_t *pk_list_addr)
int mark_hidden, int from_file, pk_list_t *pk_list_addr)
{
int rc;
PKT_public_key *pk;
int trustlevel;
if (!name || !*name)
return gpg_error (GPG_ERR_INV_USER_ID);
@ -814,7 +817,10 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
return gpg_error_from_syserror ();
pk->req_usage = use;
rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0);
if (from_file)
rc = get_pubkey_fromfile (ctrl, pk, name);
else
rc = get_pubkey_byname (ctrl, NULL, pk, name, NULL, NULL, 0, 0);
if (rc)
{
int code;
@ -844,24 +850,28 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
}
/* Key found and usable. Check validity. */
trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
if ( (trustlevel & TRUST_FLAG_DISABLED) )
if (!from_file)
{
/* Key has been disabled. */
send_status_inv_recp (13, name);
log_info (_("%s: skipped: public key is disabled\n"), name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
}
int trustlevel;
if ( !do_we_trust_pre (pk, trustlevel) )
{
/* We don't trust this key. */
send_status_inv_recp (10, name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
trustlevel = get_validity (ctrl, pk, pk->user_id, NULL, 1);
if ( (trustlevel & TRUST_FLAG_DISABLED) )
{
/* Key has been disabled. */
send_status_inv_recp (13, name);
log_info (_("%s: skipped: public key is disabled\n"), name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
}
if ( !do_we_trust_pre (pk, trustlevel) )
{
/* We don't trust this key. */
send_status_inv_recp (10, name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
}
}
/* Note: do_we_trust may have changed the trustlevel. */
/* Skip the actual key if the key is already present in the
list. */
@ -894,22 +904,24 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
/* This is the central function to collect the keys for recipients.
It is thus used to prepare a public key encryption. encrypt-to
keys, default keys and the keys for the actual recipients are all
collected here. When not in batch mode and no recipient has been
passed on the commandline, the function will also ask for
recipients.
RCPTS is a string list with the recipients; NULL is an allowed
value but not very useful. Group expansion is done on these names;
they may be in any of the user Id formats we can handle. The flags
bits for each string in the string list are used for:
Bit 0 (PK_LIST_ENCRYPT_TO): This is an encrypt-to recipient.
Bit 1 (PK_LIST_HIDDEN) : This is a hidden recipient.
On success a list of keys is stored at the address RET_PK_LIST; the
caller must free this list. On error the value at this address is
not changed.
* It is thus used to prepare a public key encryption. encrypt-to
* keys, default keys and the keys for the actual recipients are all
* collected here. When not in batch mode and no recipient has been
* passed on the commandline, the function will also ask for
* recipients.
*
* RCPTS is a string list with the recipients; NULL is an allowed
* value but not very useful. Group expansion is done on these names;
* they may be in any of the user Id formats we can handle. The flags
* bits for each string in the string list are used for:
*
* - PK_LIST_ENCRYPT_TO :: This is an encrypt-to recipient.
* - PK_LIST_HIDDEN :: This is a hidden recipient.
* - PK_LIST_FROM_FILE :: The argument is a file with a key.
*
* On success a list of keys is stored at the address RET_PK_LIST; the
* caller must free this list. On error the value at this address is
* not changed.
*/
int
build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
@ -1269,6 +1281,7 @@ build_pk_list (ctrl_t ctrl, strlist_t rcpts, PK_LIST *ret_pk_list)
rc = find_and_check_key (ctrl, remusr->d, PUBKEY_USAGE_ENC,
!!(remusr->flags&PK_LIST_HIDDEN),
!!(remusr->flags&PK_LIST_FROM_FILE),
&pk_list);
if (rc)
goto fail;

View File

@ -177,6 +177,7 @@ output_notify (assuan_context_t ctx, char *line)
/* RECIPIENT [--hidden] <userID>
RECIPIENT [--hidden] --file <filename>
Set the recipient for the encryption. <userID> should be the
internal representation of the key; the server may accept any other
@ -192,9 +193,10 @@ cmd_recipient (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
int hidden;
int hidden, file;
hidden = has_option (line,"--hidden");
file = has_option (line,"--file");
line = skip_options (line);
/* FIXME: Expand groups
@ -204,7 +206,7 @@ cmd_recipient (assuan_context_t ctx, char *line)
remusr = rcpts;
*/
err = find_and_check_key (ctrl, line, PUBKEY_USAGE_ENC, hidden,
err = find_and_check_key (ctrl, line, PUBKEY_USAGE_ENC, hidden, file,
&ctrl->server_local->recplist);
if (err)

View File

@ -228,6 +228,15 @@ keyserver_import_ldap (const char *name)
return -1;
}
gpg_error_t
read_key_from_file (ctrl_t ctrl, const char *fname, kbnode_t *r_keyblock)
{
(void)ctrl;
(void)fname;
(void)r_keyblock;
return -1;
}
/* Stub:
* No encryption here but mainproc links to these functions.
*/

View File

@ -35,6 +35,9 @@
;; first and then search for the encryption subkey.)
(define dsa-usrname2 "0xCB879DE9")
(define key-file1 "samplekeys/rsa-rsa-sample-1.asc")
(define key-file2 "samplekeys/ed25519-cv25519-sample-1.asc")
(define plain-files '("plain-1" "plain-2" "plain-3"))
(define data-files '("data-500" "data-9000" "data-32000" "data-80000"))
(define exp-files '())

View File

@ -43,3 +43,18 @@
(tr:assert-identity source)))
(append plain-files data-files)))
all-cipher-algos)
;; We encrypt to two keys and we have also put the first key into our
;; pubring, so that decryption will work.
(for-each-p
"Checking encryption using a key from file"
(lambda (source)
(tr:do
(tr:open source)
(tr:gpg "" `(--yes -v --no-keyring --encrypt
--recipient-file ,(in-srcdir key-file1)
--hidden-recipient-file ,(in-srcdir key-file2)))
(tr:gpg "" '(--yes))
(tr:assert-identity source)))
plain-files)

View File

@ -91,12 +91,17 @@
"1DF48228FEFF3EC2481B106E0ACA8C465C662CC5"
"A2832820DC9F40751BDCD375BB0945BA33EC6B4C"
"ADE710D74409777B7729A7653373D820F67892E0"
"CEFC51AF91F68A2904FBFF62C4F075A4785B803F"))
"CEFC51AF91F68A2904FBFF62C4F075A4785B803F"
"1E28F20E41B54C2D1234D896096495FF57E08D18"
"EB33B687EB8581AB64D04852A54453E85F3DF62D"
"C6A6390E9388CDBAD71EAEA698233FE5E04F001E"
"D69102E0F5AC6B6DB8E4D16DA8E18CF46D88CAE3"))
(info "Importing public demo and test keys")
(call-check `(,@GPG --yes --import
,(in-srcdir "pubdemo.asc")
,(in-srcdir "pubring.asc")))
,(in-srcdir "pubring.asc")
,(in-srcdir key-file1)))
;; (letfd ((source (open (in-srcdir "pubring.pkr.asc") O_RDONLY)))
;; ((gpg-pipe '(--dearmor) '(--yes --import) STDERR_FILENO)
;; source CLOSED_FD))