summaryrefslogtreecommitdiffstats
path: root/g10
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2016-07-06 14:03:50 +0200
committerWerner Koch <wk@gnupg.org>2016-07-06 15:35:19 +0200
commita479804c86bc24bfab101f39464db3ecfbaedf6d (patch)
tree271ce0ff610431ecb0092d9cc017d27d37bd18d6 /g10
parentgpg: New option --no-keyring. (diff)
downloadgnupg2-a479804c86bc24bfab101f39464db3ecfbaedf6d.tar.xz
gnupg2-a479804c86bc24bfab101f39464db3ecfbaedf6d.zip
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>
Diffstat (limited to 'g10')
-rw-r--r--g10/getkey.c54
-rw-r--r--g10/gpg.c52
-rw-r--r--g10/gpgv.c11
-rw-r--r--g10/import.c107
-rw-r--r--g10/keydb.h22
-rw-r--r--g10/main.h2
-rw-r--r--g10/pkclist.c99
-rw-r--r--g10/server.c6
-rw-r--r--g10/test-stubs.c9
9 files changed, 288 insertions, 74 deletions
diff --git a/g10/getkey.c b/g10/getkey.c
index f34127de5..90fd175b4 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -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
diff --git a/g10/gpg.c b/g10/gpg.c
index cf0e64505..34009bb3a 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -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,37 +2842,45 @@ 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 */
+
+ 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) | PK_LIST_ENCRYPT_TO);
+ 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 oHiddenEncryptTo: /* store the recipient in the second list */
+
+ 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_ENCRYPT_TO|PK_LIST_HIDDEN);
+ sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_ENCRYPT_TO);
if (configfp)
sl->flags |= PK_LIST_CONFIG;
+ 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 oRecipient: /* store the recipient */
- 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;
- any_explicit_recipient = 1;
- break;
- case oHiddenRecipient: /* store the recipient with a flag */
- sl = add_to_strlist2( &remusr, pargs.r.ret_str, utf8_strings );
- sl->flags = ((pargs.r_opt << PK_LIST_SHIFT) | PK_LIST_HIDDEN);
- if (configfp)
- sl->flags |= PK_LIST_CONFIG;
- any_explicit_recipient = 1;
- break;
case oTrySecretKey:
add_to_strlist2 (&opt.secret_keys_to_try,
diff --git a/g10/gpgv.c b/g10/gpgv.c
index 9ccc0da99..d238ee06f 100644
--- a/g10/gpgv.c
+++ b/g10/gpgv.c
@@ -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.
*/
diff --git a/g10/import.c b/g10/import.c
index 8cfd6eae0..e03532834 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -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
diff --git a/g10/keydb.h b/g10/keydb.h
index a30cf7ac7..4e8f3f291 100644
--- a/g10/keydb.h
+++ b/g10/keydb.h
@@ -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);
diff --git a/g10/main.h b/g10/main.h
index 3ee276202..ec20b28df 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -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,
diff --git a/g10/pkclist.c b/g10/pkclist.c
index 8efa95432..6315a6d55 100644
--- a/g10/pkclist.c
+++ b/g10/pkclist.c
@@ -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;
diff --git a/g10/server.c b/g10/server.c
index 771a8a7a9..258f08a5d 100644
--- a/g10/server.c
+++ b/g10/server.c
@@ -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)
diff --git a/g10/test-stubs.c b/g10/test-stubs.c
index f4d952665..6f50759d5 100644
--- a/g10/test-stubs.c
+++ b/g10/test-stubs.c
@@ -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.
*/