aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--g10/import.c69
-rw-r--r--g10/keyserver.c94
-rw-r--r--g10/main.h5
3 files changed, 143 insertions, 25 deletions
diff --git a/g10/import.c b/g10/import.c
index 774a727da..ca35ce1b9 100644
--- a/g10/import.c
+++ b/g10/import.c
@@ -63,16 +63,19 @@ struct stats_s {
static int import (ctrl_t ctrl,
IOBUF inp, const char* fname, struct stats_s *stats,
- unsigned char **fpr, size_t *fpr_len, unsigned int options);
+ unsigned char **fpr, size_t *fpr_len, unsigned int options,
+ import_screener_t screener, void *screener_arg);
static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root );
static void revocation_present (ctrl_t ctrl, kbnode_t keyblock);
static int import_one (ctrl_t ctrl,
const char *fname, KBNODE keyblock,struct stats_s *stats,
- unsigned char **fpr,size_t *fpr_len,
- unsigned int options,int from_sk, int silent);
+ unsigned char **fpr, size_t *fpr_len,
+ unsigned int options, int from_sk, int silent,
+ import_screener_t screener, void *screener_arg);
static int import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
struct stats_s *stats, int batch,
- unsigned int options, int for_migration);
+ unsigned int options, int for_migration,
+ import_screener_t screener, void *screener_arg);
static int import_revoke_cert( const char *fname, KBNODE node,
struct stats_s *stats);
static int chk_self_sigs( const char *fname, KBNODE keyblock,
@@ -169,7 +172,8 @@ import_release_stats_handle (void *p)
static int
import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
void *stats_handle, unsigned char **fpr, size_t *fpr_len,
- unsigned int options )
+ unsigned int options,
+ import_screener_t screener, void *screener_arg)
{
int i, rc = 0;
struct stats_s *stats = stats_handle;
@@ -178,7 +182,8 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
stats = import_new_stats_handle ();
if (inp) {
- rc = import (ctrl, inp, "[stream]", stats, fpr, fpr_len, options);
+ rc = import (ctrl, inp, "[stream]", stats, fpr, fpr_len, options,
+ screener, screener_arg);
}
else {
if( !fnames && !nnames )
@@ -199,7 +204,8 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
log_error(_("can't open '%s': %s\n"), fname, strerror(errno) );
else
{
- rc = import (ctrl, inp2, fname, stats, fpr, fpr_len, options);
+ rc = import (ctrl, inp2, fname, stats, fpr, fpr_len, options,
+ screener, screener_arg);
iobuf_close(inp2);
/* Must invalidate that ugly cache to actually close it. */
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE,
@@ -235,15 +241,15 @@ import_keys (ctrl_t ctrl, char **fnames, int nnames,
void *stats_handle, unsigned int options )
{
import_keys_internal (ctrl, NULL, fnames, nnames, stats_handle,
- NULL, NULL, options);
+ NULL, NULL, options, NULL, NULL);
}
int
import_keys_stream (ctrl_t ctrl, IOBUF inp, void *stats_handle,
- unsigned char **fpr, size_t *fpr_len,unsigned int options)
+ unsigned char **fpr, size_t *fpr_len, unsigned int options)
{
return import_keys_internal (ctrl, inp, NULL, 0, stats_handle,
- fpr, fpr_len, options);
+ fpr, fpr_len, options, NULL, NULL);
}
@@ -251,7 +257,8 @@ import_keys_stream (ctrl_t ctrl, IOBUF inp, void *stats_handle,
int
import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
unsigned char **fpr, size_t *fpr_len,
- unsigned int options)
+ unsigned int options,
+ import_screener_t screener, void *screener_arg)
{
int rc;
iobuf_t inp;
@@ -265,7 +272,8 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
}
rc = import_keys_internal (ctrl, inp, NULL, 0, stats_handle,
- fpr, fpr_len, options);
+ fpr, fpr_len, options,
+ screener, screener_arg);
iobuf_close (inp);
return rc;
@@ -274,7 +282,8 @@ import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
static int
import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
- unsigned char **fpr,size_t *fpr_len,unsigned int options )
+ unsigned char **fpr,size_t *fpr_len, unsigned int options,
+ import_screener_t screener, void *screener_arg)
{
PACKET *pending_pkt = NULL;
KBNODE keyblock = NULL; /* Need to initialize because gcc can't
@@ -296,10 +305,12 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct stats_s *stats,
while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) {
if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY )
rc = import_one (ctrl, fname, keyblock,
- stats, fpr, fpr_len, options, 0, 0);
+ stats, fpr, fpr_len, options, 0, 0,
+ screener, screener_arg);
else if( keyblock->pkt->pkttype == PKT_SECRET_KEY )
rc = import_secret_one (ctrl, fname, keyblock, stats,
- opt.batch, options, 0);
+ opt.batch, options, 0,
+ screener, screener_arg);
else if( keyblock->pkt->pkttype == PKT_SIGNATURE
&& keyblock->pkt->pkt.signature->sig_class == 0x20 )
rc = import_revoke_cert( fname, keyblock, stats );
@@ -355,7 +366,8 @@ import_old_secring (ctrl_t ctrl, const char *fname)
while (!(err = read_block (inp, &pending_pkt, &keyblock)))
{
if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
- err = import_secret_one (ctrl, fname, keyblock, stats, 1, 0, 1);
+ err = import_secret_one (ctrl, fname, keyblock, stats, 1, 0, 1,
+ NULL, NULL);
release_kbnode (keyblock);
if (err)
break;
@@ -835,8 +847,9 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
static int
import_one (ctrl_t ctrl,
const char *fname, KBNODE keyblock, struct stats_s *stats,
- unsigned char **fpr,size_t *fpr_len,unsigned int options,
- int from_sk, int silent)
+ unsigned char **fpr, size_t *fpr_len, unsigned int options,
+ int from_sk, int silent,
+ import_screener_t screener, void *screener_arg)
{
PKT_public_key *pk;
PKT_public_key *pk_orig;
@@ -880,6 +893,13 @@ import_one (ctrl_t ctrl,
return 0;
}
+ if (screener && screener (keyblock, screener_arg))
+ {
+ log_error (_("key %s: %s\n"), keystr_from_pk (pk),
+ _("rejected by import screener"));
+ return 0;
+ }
+
if (opt.interactive && !silent) {
if(is_status_enabled())
print_import_check (pk, uidnode->pkt->pkt.user_id);
@@ -1519,7 +1539,8 @@ sec_to_pub_keyblock (kbnode_t sec_keyblock)
static int
import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
struct stats_s *stats, int batch, unsigned int options,
- int for_migration)
+ int for_migration,
+ import_screener_t screener, void *screener_arg)
{
PKT_public_key *pk;
struct seckey_info *ski;
@@ -1540,6 +1561,13 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
keyid_from_pk (pk, keyid);
uidnode = find_next_kbnode (keyblock, PKT_USER_ID);
+ if (screener && screener (keyblock, screener_arg))
+ {
+ log_error (_("secret key %s: %s\n"), keystr_from_pk (pk),
+ _("rejected by import screener"));
+ return 0;
+ }
+
if (opt.verbose && !for_migration)
{
log_info ("sec %s/%s %s ",
@@ -1610,7 +1638,8 @@ import_secret_one (ctrl_t ctrl, const char *fname, KBNODE keyblock,
public key block, and below we will output another one for
the secret keys. FIXME? */
import_one (ctrl, fname, pub_keyblock, stats,
- NULL, NULL, options, 1, for_migration);
+ NULL, NULL, options, 1, for_migration,
+ screener, screener_arg);
/* Fixme: We should check for an invalid keyblock and
cancel the secret key import in this case. */
diff --git a/g10/keyserver.c b/g10/keyserver.c
index 4249caf0a..1b2e128ce 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -1042,6 +1042,85 @@ keyserver_export (ctrl_t ctrl, strlist_t users)
}
+/* Structure to convey the arg to keyserver_retrieval_screener. */
+struct ks_retrieval_screener_arg_s
+{
+ KEYDB_SEARCH_DESC *desc;
+ int ndesc;
+};
+
+
+/* Check whether a key matches the search description. The function
+ returns 0 if the key shall be imported. */
+static gpg_error_t
+keyserver_retrieval_screener (kbnode_t keyblock, void *opaque)
+{
+ struct ks_retrieval_screener_arg_s *arg = opaque;
+ KEYDB_SEARCH_DESC *desc = arg->desc;
+ int ndesc = arg->ndesc;
+ kbnode_t node;
+ PKT_public_key *pk;
+ int n;
+ u32 keyid[2];
+ byte fpr[MAX_FINGERPRINT_LEN];
+ size_t fpr_len = 0;
+
+ /* Secret keys are not expected from a keyserver. We do not
+ care about secret subkeys because the import code takes care
+ of skipping them. Not allowing an import of a public key
+ with a secret subkey would make it too easy to inhibit the
+ downloading of a public key. Recall that keyservers do only
+ limited checks. */
+ node = find_kbnode (keyblock, PKT_SECRET_KEY);
+ if (node)
+ return gpg_error (GPG_ERR_GENERAL); /* Do not import. */
+
+ if (!ndesc)
+ return 0; /* Okay if no description given. */
+
+ /* Loop over all key packets. */
+ for (node = keyblock; node; node = node->next)
+ {
+ if (node->pkt->pkttype != PKT_PUBLIC_KEY
+ && node->pkt->pkttype != PKT_PUBLIC_SUBKEY)
+ continue;
+
+ pk = node->pkt->pkt.public_key;
+ fingerprint_from_pk (pk, fpr, &fpr_len);
+ keyid_from_pk (pk, keyid);
+
+ /* Compare requested and returned fingerprints if available. */
+ for (n = 0; n < ndesc; n++)
+ {
+ if (desc[n].mode == KEYDB_SEARCH_MODE_FPR20)
+ {
+ if (fpr_len == 20 && !memcmp (fpr, desc[n].u.fpr, 20))
+ return 0;
+ }
+ else if (desc[n].mode == KEYDB_SEARCH_MODE_FPR16)
+ {
+ if (fpr_len == 16 && !memcmp (fpr, desc[n].u.fpr, 16))
+ return 0;
+ }
+ else if (desc[n].mode == KEYDB_SEARCH_MODE_LONG_KID)
+ {
+ if (keyid[0] == desc[n].u.kid[0] && keyid[1] == desc[n].u.kid[1])
+ return 0;
+ }
+ else if (desc[n].mode == KEYDB_SEARCH_MODE_SHORT_KID)
+ {
+ if (keyid[1] == desc[n].u.kid[1])
+ return 0;
+ }
+ else /* No keyid or fingerprint - can't check. */
+ return 0; /* allow import. */
+ }
+ }
+
+ return gpg_error (GPG_ERR_GENERAL);
+}
+
+
int
keyserver_import (ctrl_t ctrl, strlist_t users)
{
@@ -1601,6 +1680,7 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
if (!err)
{
void *stats_handle;
+ struct ks_retrieval_screener_arg_s screenerarg;
stats_handle = import_new_stats_handle();
@@ -1616,10 +1696,14 @@ keyserver_get (ctrl_t ctrl, KEYDB_SEARCH_DESC *desc, int ndesc,
never accept or send them but we better protect against rogue
keyservers. */
+ screenerarg.desc = desc;
+ screenerarg.ndesc = ndesc;
import_keys_es_stream (ctrl, datastream, stats_handle,
r_fpr, r_fprlen,
(opt.keyserver_options.import_options
- | IMPORT_NO_SECKEY));
+ | IMPORT_NO_SECKEY),
+ keyserver_retrieval_screener, &screenerarg);
+
import_print_stats (stats_handle);
import_release_stats_handle (stats_handle);
}
@@ -1684,7 +1768,7 @@ keyserver_put (ctrl_t ctrl, strlist_t keyspecs,
}
-/* Loop over all URLs in STRLIST and fetch the key that URL. Note
+/* Loop over all URLs in STRLIST and fetch the key at that URL. Note
that the fetch operation ignores the configured key servers and
instead directly retrieves the keys. */
int
@@ -1712,7 +1796,8 @@ keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
stats_handle = import_new_stats_handle();
import_keys_es_stream (ctrl, datastream, stats_handle, NULL, NULL,
- opt.keyserver_options.import_options);
+ opt.keyserver_options.import_options,
+ NULL, NULL);
import_print_stats (stats_handle);
import_release_stats_handle (stats_handle);
@@ -1762,7 +1847,8 @@ keyserver_import_cert (ctrl_t ctrl,
err = import_keys_es_stream (ctrl, key, NULL, fpr, fpr_len,
(opt.keyserver_options.import_options
- | IMPORT_NO_SECKEY));
+ | IMPORT_NO_SECKEY),
+ NULL, NULL);
opt.no_armor=armor_status;
diff --git a/g10/main.h b/g10/main.h
index 8fe03ac43..b2efaae3b 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -288,6 +288,8 @@ gcry_mpi_t encode_md_value (PKT_public_key *pk,
gcry_md_hd_t md, int hash_algo );
/*-- import.c --*/
+typedef gpg_error_t (*import_screener_t)(kbnode_t keyblock, void *arg);
+
int parse_import_options(char *str,unsigned int *options,int noisy);
void import_keys (ctrl_t ctrl, char **fnames, int nnames,
void *stats_hd, unsigned int options);
@@ -296,7 +298,8 @@ int import_keys_stream (ctrl_t ctrl, iobuf_t inp, void *stats_hd,
size_t *fpr_len, unsigned int options);
int import_keys_es_stream (ctrl_t ctrl, estream_t fp, void *stats_handle,
unsigned char **fpr, size_t *fpr_len,
- unsigned int options);
+ unsigned int options,
+ import_screener_t screener, void *screener_arg);
gpg_error_t import_old_secring (ctrl_t ctrl, const char *fname);
void *import_new_stats_handle (void);
void import_release_stats_handle (void *p);