2005-01-20 17:21:40 +00:00
|
|
|
/* import.c - import a key into our key storage.
|
2006-03-14 02:23:00 +00:00
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
|
|
|
|
* 2006 Free Software Foundation, Inc.
|
1998-01-16 21:15:24 +00:00
|
|
|
*
|
1998-12-08 12:20:53 +00:00
|
|
|
* This file is part of GnuPG.
|
1998-01-16 21:15:24 +00:00
|
|
|
*
|
1998-12-08 12:20:53 +00:00
|
|
|
* GnuPG is free software; you can redistribute it and/or modify
|
1998-01-16 21:15:24 +00:00
|
|
|
* it under the terms of the GNU General Public License as published by
|
2007-10-23 10:48:09 +00:00
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
1998-01-16 21:15:24 +00:00
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
1998-12-08 12:20:53 +00:00
|
|
|
* GnuPG is distributed in the hope that it will be useful,
|
1998-01-16 21:15:24 +00:00
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2007-10-23 10:48:09 +00:00
|
|
|
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
1998-01-16 21:15:24 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include "options.h"
|
|
|
|
#include "packet.h"
|
|
|
|
#include "errors.h"
|
|
|
|
#include "keydb.h"
|
2002-06-29 13:46:34 +00:00
|
|
|
#include "memory.h"
|
1998-01-16 21:15:24 +00:00
|
|
|
#include "util.h"
|
|
|
|
#include "trustdb.h"
|
1998-02-16 20:05:02 +00:00
|
|
|
#include "main.h"
|
1998-07-08 09:29:43 +00:00
|
|
|
#include "i18n.h"
|
2002-08-19 08:28:00 +00:00
|
|
|
#include "ttyio.h"
|
1999-07-14 17:47:23 +00:00
|
|
|
#include "status.h"
|
2002-06-29 13:46:34 +00:00
|
|
|
#include "keyserver-internal.h"
|
1998-02-16 20:05:02 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
struct stats_s {
|
2000-07-14 17:34:53 +00:00
|
|
|
ulong count;
|
1998-10-25 19:00:01 +00:00
|
|
|
ulong no_user_id;
|
|
|
|
ulong imported;
|
|
|
|
ulong imported_rsa;
|
|
|
|
ulong n_uids;
|
|
|
|
ulong n_sigs;
|
|
|
|
ulong n_subk;
|
|
|
|
ulong unchanged;
|
|
|
|
ulong n_revoc;
|
|
|
|
ulong secret_read;
|
|
|
|
ulong secret_imported;
|
|
|
|
ulong secret_dups;
|
2000-09-18 14:35:34 +00:00
|
|
|
ulong skipped_new_keys;
|
2002-08-21 14:59:05 +00:00
|
|
|
ulong not_imported;
|
2005-06-12 21:17:46 +00:00
|
|
|
ulong n_sigs_cleaned;
|
2005-06-14 03:55:19 +00:00
|
|
|
ulong n_uids_cleaned;
|
2002-06-29 13:46:34 +00:00
|
|
|
};
|
1998-10-25 19:00:01 +00:00
|
|
|
|
|
|
|
|
2006-03-14 02:23:00 +00:00
|
|
|
static int import( IOBUF inp, const char* fname,struct stats_s *stats,
|
|
|
|
unsigned char **fpr,size_t *fpr_len,unsigned int options );
|
1999-02-19 14:54:00 +00:00
|
|
|
static int read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root );
|
2002-06-29 13:46:34 +00:00
|
|
|
static void revocation_present(KBNODE keyblock);
|
2006-03-14 02:23:00 +00:00
|
|
|
static int import_one(const char *fname, KBNODE keyblock,struct stats_s *stats,
|
|
|
|
unsigned char **fpr,size_t *fpr_len,
|
2006-06-12 12:05:34 +00:00
|
|
|
unsigned int options,int from_sk);
|
2002-06-29 13:46:34 +00:00
|
|
|
static int import_secret_one( const char *fname, KBNODE keyblock,
|
2002-10-23 15:59:45 +00:00
|
|
|
struct stats_s *stats, unsigned int options);
|
2002-06-29 13:46:34 +00:00
|
|
|
static int import_revoke_cert( const char *fname, KBNODE node,
|
|
|
|
struct stats_s *stats);
|
1998-02-16 20:05:02 +00:00
|
|
|
static int chk_self_sigs( const char *fname, KBNODE keyblock,
|
2002-12-13 21:10:53 +00:00
|
|
|
PKT_public_key *pk, u32 *keyid, int *non_self );
|
* main.h, import.c (parse_import_options, fix_hkp_corruption, import_one,
delete_inv_parts), g10.c (main): New import-option
"repair-hkp-subkey-bug", which repairs as much as possible the HKP
mangling multiple subkeys bug. It is on by default for keyserver
receives, and off by default for regular --import.
* main.h, import.c (import, import_one, delete_inv_parts), hkp.c
(hkp_ask_import), keyserver.c (keyserver_spawn): Use keyserver import
options when doing keyserver receives.
2002-07-24 21:17:19 +00:00
|
|
|
static int delete_inv_parts( const char *fname, KBNODE keyblock,
|
|
|
|
u32 *keyid, unsigned int options );
|
1998-02-17 20:48:52 +00:00
|
|
|
static int merge_blocks( const char *fname, KBNODE keyblock_orig,
|
1998-05-26 13:38:00 +00:00
|
|
|
KBNODE keyblock, u32 *keyid,
|
|
|
|
int *n_uids, int *n_sigs, int *n_subk );
|
1998-02-17 20:48:52 +00:00
|
|
|
static int append_uid( KBNODE keyblock, KBNODE node, int *n_sigs,
|
|
|
|
const char *fname, u32 *keyid );
|
1998-12-08 12:20:53 +00:00
|
|
|
static int append_key( KBNODE keyblock, KBNODE node, int *n_sigs,
|
|
|
|
const char *fname, u32 *keyid );
|
1998-02-17 20:48:52 +00:00
|
|
|
static int merge_sigs( KBNODE dst, KBNODE src, int *n_sigs,
|
|
|
|
const char *fname, u32 *keyid );
|
1998-12-08 12:20:53 +00:00
|
|
|
static int merge_keysigs( KBNODE dst, KBNODE src, int *n_sigs,
|
|
|
|
const char *fname, u32 *keyid );
|
1998-01-16 21:15:24 +00:00
|
|
|
|
2002-07-22 22:26:14 +00:00
|
|
|
int
|
2003-12-28 03:46:43 +00:00
|
|
|
parse_import_options(char *str,unsigned int *options,int noisy)
|
2002-07-22 22:26:14 +00:00
|
|
|
{
|
2003-05-31 21:52:16 +00:00
|
|
|
struct parse_options import_opts[]=
|
2002-07-22 22:26:14 +00:00
|
|
|
{
|
2005-09-14 22:31:21 +00:00
|
|
|
{"import-local-sigs",IMPORT_LOCAL_SIGS,NULL,
|
|
|
|
N_("import signatures that are marked as local-only")},
|
|
|
|
{"repair-pks-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,
|
|
|
|
N_("repair damage from the pks keyserver during import")},
|
|
|
|
{"fast-import",IMPORT_FAST,NULL,
|
|
|
|
N_("do not update the trustdb after import")},
|
|
|
|
{"convert-sk-to-pk",IMPORT_SK2PK,NULL,
|
|
|
|
N_("create a public key when importing a secret key")},
|
|
|
|
{"merge-only",IMPORT_MERGE_ONLY,NULL,
|
|
|
|
N_("only accept updates to existing keys")},
|
2005-11-12 04:53:03 +00:00
|
|
|
{"import-clean",IMPORT_CLEAN,NULL,
|
2005-11-18 04:25:07 +00:00
|
|
|
N_("remove unusable parts from key after import")},
|
2005-11-12 04:53:03 +00:00
|
|
|
{"import-minimal",IMPORT_MINIMAL|IMPORT_CLEAN,NULL,
|
2005-11-18 04:25:07 +00:00
|
|
|
N_("remove as much as possible from key after import")},
|
2004-11-26 15:51:37 +00:00
|
|
|
/* Aliases for backward compatibility */
|
2005-09-14 22:31:21 +00:00
|
|
|
{"allow-local-sigs",IMPORT_LOCAL_SIGS,NULL,NULL},
|
|
|
|
{"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,NULL},
|
2005-06-10 03:15:25 +00:00
|
|
|
/* dummy */
|
2005-09-14 22:31:21 +00:00
|
|
|
{"import-unusable-sigs",0,NULL,NULL},
|
2005-11-18 04:25:07 +00:00
|
|
|
{"import-clean-sigs",0,NULL,NULL},
|
|
|
|
{"import-clean-uids",0,NULL,NULL},
|
2005-09-14 22:31:21 +00:00
|
|
|
{NULL,0,NULL,NULL}
|
2002-07-22 22:26:14 +00:00
|
|
|
};
|
|
|
|
|
2003-12-28 03:46:43 +00:00
|
|
|
return parse_options(str,options,import_opts,noisy);
|
2002-07-22 22:26:14 +00:00
|
|
|
}
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
void *
|
|
|
|
import_new_stats_handle (void)
|
|
|
|
{
|
2005-07-27 18:10:56 +00:00
|
|
|
return xmalloc_clear ( sizeof (struct stats_s) );
|
2002-06-29 13:46:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
import_release_stats_handle (void *p)
|
|
|
|
{
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree (p);
|
2002-06-29 13:46:34 +00:00
|
|
|
}
|
|
|
|
|
1998-01-16 21:15:24 +00:00
|
|
|
/****************
|
1998-02-13 20:58:50 +00:00
|
|
|
* Import the public keys from the given filename. Input may be armored.
|
1998-04-14 17:51:16 +00:00
|
|
|
* This function rejects all keys which are not validly self signed on at
|
1998-02-13 20:58:50 +00:00
|
|
|
* least one userid. Only user ids which are self signed will be imported.
|
1998-04-14 17:51:16 +00:00
|
|
|
* Other signatures are not checked.
|
1998-02-13 20:58:50 +00:00
|
|
|
*
|
1998-10-25 19:00:01 +00:00
|
|
|
* Actually this function does a merge. It works like this:
|
1998-02-13 20:58:50 +00:00
|
|
|
*
|
|
|
|
* - get the keyblock
|
1998-02-16 20:05:02 +00:00
|
|
|
* - check self-signatures and remove all userids and their signatures
|
1998-02-13 20:58:50 +00:00
|
|
|
* without/invalid self-signatures.
|
|
|
|
* - reject the keyblock, if we have no valid userid.
|
1998-04-14 17:51:16 +00:00
|
|
|
* - See whether we have this key already in one of our pubrings.
|
1998-02-13 20:58:50 +00:00
|
|
|
* If not, simply add it to the default keyring.
|
|
|
|
* - Compare the key and the self-signatures of the new and the one in
|
1998-04-14 17:51:16 +00:00
|
|
|
* our keyring. If they are different something weird is going on;
|
1998-02-13 20:58:50 +00:00
|
|
|
* ask what to do.
|
1998-04-14 17:51:16 +00:00
|
|
|
* - See whether we have only non-self-signature on one user id; if not
|
1998-02-13 20:58:50 +00:00
|
|
|
* ask the user what to do.
|
|
|
|
* - compare the signatures: If we already have this signature, check
|
1998-02-16 20:05:02 +00:00
|
|
|
* that they compare okay; if not, issue a warning and ask the user.
|
1998-04-14 17:51:16 +00:00
|
|
|
* (consider looking at the timestamp and use the newest?)
|
1998-02-13 20:58:50 +00:00
|
|
|
* - Simply add the signature. Can't verify here because we may not have
|
1998-04-14 17:51:16 +00:00
|
|
|
* the signature's public key yet; verification is done when putting it
|
1998-02-13 20:58:50 +00:00
|
|
|
* into the trustdb, which is done automagically as soon as this pubkey
|
|
|
|
* is used.
|
|
|
|
* - Proceed with next signature.
|
1998-01-16 21:15:24 +00:00
|
|
|
*
|
1998-04-14 17:51:16 +00:00
|
|
|
* Key revocation certificates have special handling.
|
1998-02-18 13:58:46 +00:00
|
|
|
*
|
1998-01-16 21:15:24 +00:00
|
|
|
*/
|
2002-09-22 09:20:08 +00:00
|
|
|
static int
|
2002-09-23 13:03:52 +00:00
|
|
|
import_keys_internal( IOBUF inp, char **fnames, int nnames,
|
2006-03-14 02:23:00 +00:00
|
|
|
void *stats_handle, unsigned char **fpr, size_t *fpr_len,
|
|
|
|
unsigned int options )
|
1999-01-16 08:29:29 +00:00
|
|
|
{
|
2002-09-22 09:20:08 +00:00
|
|
|
int i, rc = 0;
|
2002-06-29 13:46:34 +00:00
|
|
|
struct stats_s *stats = stats_handle;
|
1999-01-16 08:29:29 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
if (!stats)
|
|
|
|
stats = import_new_stats_handle ();
|
1999-01-16 08:29:29 +00:00
|
|
|
|
2002-09-22 09:20:08 +00:00
|
|
|
if (inp) {
|
2006-03-14 02:23:00 +00:00
|
|
|
rc = import( inp, "[stream]", stats, fpr, fpr_len, options);
|
2002-09-22 09:20:08 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
if( !fnames && !nnames )
|
|
|
|
nnames = 1; /* Ohh what a ugly hack to jump into the loop */
|
1999-01-16 08:29:29 +00:00
|
|
|
|
2002-09-22 09:20:08 +00:00
|
|
|
for(i=0; i < nnames; i++ ) {
|
|
|
|
const char *fname = fnames? fnames[i] : NULL;
|
2002-10-04 05:43:54 +00:00
|
|
|
IOBUF inp2 = iobuf_open(fname);
|
2002-09-22 09:20:08 +00:00
|
|
|
if( !fname )
|
|
|
|
fname = "[stdin]";
|
2004-10-13 18:10:06 +00:00
|
|
|
if (inp2 && is_secured_file (iobuf_get_fd (inp2)))
|
|
|
|
{
|
|
|
|
iobuf_close (inp2);
|
|
|
|
inp2 = NULL;
|
|
|
|
errno = EPERM;
|
|
|
|
}
|
2002-10-07 22:19:11 +00:00
|
|
|
if( !inp2 )
|
2002-09-22 09:20:08 +00:00
|
|
|
log_error(_("can't open `%s': %s\n"), fname, strerror(errno) );
|
2006-03-14 02:23:00 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
rc = import( inp2, fname, stats, fpr, fpr_len, options );
|
2002-10-04 05:43:54 +00:00
|
|
|
iobuf_close(inp2);
|
2003-06-08 21:35:25 +00:00
|
|
|
/* Must invalidate that ugly cache to actually close it. */
|
2003-06-08 21:23:48 +00:00
|
|
|
iobuf_ioctl (NULL, 2, 0, (char*)fname);
|
2002-09-22 09:20:08 +00:00
|
|
|
if( rc )
|
2006-03-14 02:23:00 +00:00
|
|
|
log_error("import from `%s' failed: %s\n", fname,
|
|
|
|
g10_errstr(rc) );
|
|
|
|
}
|
2002-09-22 09:20:08 +00:00
|
|
|
if( !fname )
|
|
|
|
break;
|
2000-07-14 17:34:53 +00:00
|
|
|
}
|
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
if (!stats_handle) {
|
|
|
|
import_print_stats (stats);
|
|
|
|
import_release_stats_handle (stats);
|
|
|
|
}
|
2005-02-06 17:38:43 +00:00
|
|
|
|
2002-12-13 21:10:53 +00:00
|
|
|
/* If no fast import and the trustdb is dirty (i.e. we added a key
|
|
|
|
or userID that had something other than a selfsig, a signature
|
|
|
|
that was other than a selfsig, or any revocation), then
|
|
|
|
update/check the trustdb if the user specified by setting
|
|
|
|
interactive or by not setting no-auto-check-trustdb */
|
2005-02-06 17:38:43 +00:00
|
|
|
|
|
|
|
if(!(options&IMPORT_FAST))
|
|
|
|
trustdb_check_or_update();
|
2002-12-13 21:10:53 +00:00
|
|
|
|
2002-09-22 09:20:08 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2002-09-23 13:03:52 +00:00
|
|
|
import_keys( char **fnames, int nnames,
|
2002-09-22 09:20:08 +00:00
|
|
|
void *stats_handle, unsigned int options )
|
|
|
|
{
|
2006-03-14 02:23:00 +00:00
|
|
|
import_keys_internal(NULL,fnames,nnames,stats_handle,NULL,NULL,options);
|
1999-01-16 08:29:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-03-14 02:23:00 +00:00
|
|
|
import_keys_stream( IOBUF inp, void *stats_handle,
|
|
|
|
unsigned char **fpr, size_t *fpr_len,unsigned int options )
|
1999-01-16 08:29:29 +00:00
|
|
|
{
|
2006-03-14 02:23:00 +00:00
|
|
|
return import_keys_internal(inp,NULL,0,stats_handle,fpr,fpr_len,options);
|
1999-01-16 08:29:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2006-03-14 02:23:00 +00:00
|
|
|
import( IOBUF inp, const char* fname,struct stats_s *stats,
|
|
|
|
unsigned char **fpr,size_t *fpr_len,unsigned int options )
|
1998-02-16 20:05:02 +00:00
|
|
|
{
|
|
|
|
PACKET *pending_pkt = NULL;
|
2006-07-26 11:25:36 +00:00
|
|
|
KBNODE keyblock = NULL;
|
1998-02-16 20:05:02 +00:00
|
|
|
int rc = 0;
|
1998-10-25 19:00:01 +00:00
|
|
|
|
1998-12-23 12:41:40 +00:00
|
|
|
getkey_disable_caches();
|
|
|
|
|
1999-02-19 14:54:00 +00:00
|
|
|
if( !opt.no_armor ) { /* armored reading is not disabled */
|
2006-12-06 09:52:40 +00:00
|
|
|
armor_filter_context_t *afx = new_armor_context ();
|
1999-02-19 14:54:00 +00:00
|
|
|
afx->only_keyblocks = 1;
|
2006-12-06 09:52:40 +00:00
|
|
|
push_armor_filter (afx, inp);
|
|
|
|
release_armor_context (afx);
|
1999-02-19 14:54:00 +00:00
|
|
|
}
|
1998-02-16 20:05:02 +00:00
|
|
|
|
1999-02-19 14:54:00 +00:00
|
|
|
while( !(rc = read_block( inp, &pending_pkt, &keyblock) )) {
|
1998-06-29 12:30:57 +00:00
|
|
|
if( keyblock->pkt->pkttype == PKT_PUBLIC_KEY )
|
2006-06-12 12:05:34 +00:00
|
|
|
rc = import_one( fname, keyblock, stats, fpr, fpr_len, options, 0);
|
2002-06-29 13:46:34 +00:00
|
|
|
else if( keyblock->pkt->pkttype == PKT_SECRET_KEY )
|
2002-10-23 15:59:45 +00:00
|
|
|
rc = import_secret_one( fname, keyblock, stats, options );
|
1998-02-18 13:58:46 +00:00
|
|
|
else if( keyblock->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
&& keyblock->pkt->pkt.signature->sig_class == 0x20 )
|
2002-06-29 13:46:34 +00:00
|
|
|
rc = import_revoke_cert( fname, keyblock, stats );
|
1998-07-08 09:29:43 +00:00
|
|
|
else {
|
1999-05-22 20:54:54 +00:00
|
|
|
log_info( _("skipping block of type %d\n"),
|
1998-07-08 09:29:43 +00:00
|
|
|
keyblock->pkt->pkttype );
|
|
|
|
}
|
1998-02-16 20:05:02 +00:00
|
|
|
release_kbnode(keyblock);
|
2002-08-21 14:59:05 +00:00
|
|
|
/* fixme: we should increment the not imported counter but this
|
|
|
|
does only make sense if we keep on going despite of errors. */
|
1998-02-16 20:05:02 +00:00
|
|
|
if( rc )
|
|
|
|
break;
|
2002-06-29 13:46:34 +00:00
|
|
|
if( !(++stats->count % 100) && !opt.quiet )
|
2002-09-24 21:20:48 +00:00
|
|
|
log_info(_("%lu keys processed so far\n"), stats->count );
|
1998-02-16 20:05:02 +00:00
|
|
|
}
|
|
|
|
if( rc == -1 )
|
|
|
|
rc = 0;
|
2002-06-29 13:46:34 +00:00
|
|
|
else if( rc && rc != G10ERR_INV_KEYRING )
|
|
|
|
log_error( _("error reading `%s': %s\n"), fname, g10_errstr(rc));
|
1998-02-16 20:05:02 +00:00
|
|
|
|
2000-07-14 17:34:53 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
void
|
|
|
|
import_print_stats (void *hd)
|
2000-07-14 17:34:53 +00:00
|
|
|
{
|
2002-06-29 13:46:34 +00:00
|
|
|
struct stats_s *stats = hd;
|
|
|
|
|
1999-04-18 08:18:52 +00:00
|
|
|
if( !opt.quiet ) {
|
2002-06-29 13:46:34 +00:00
|
|
|
log_info(_("Total number processed: %lu\n"), stats->count );
|
|
|
|
if( stats->skipped_new_keys )
|
2000-09-18 14:35:34 +00:00
|
|
|
log_info(_(" skipped new keys: %lu\n"),
|
2002-06-29 13:46:34 +00:00
|
|
|
stats->skipped_new_keys );
|
|
|
|
if( stats->no_user_id )
|
|
|
|
log_info(_(" w/o user IDs: %lu\n"), stats->no_user_id );
|
|
|
|
if( stats->imported || stats->imported_rsa ) {
|
|
|
|
log_info(_(" imported: %lu"), stats->imported );
|
|
|
|
if( stats->imported_rsa )
|
|
|
|
fprintf(stderr, " (RSA: %lu)", stats->imported_rsa );
|
1999-04-18 08:18:52 +00:00
|
|
|
putc('\n', stderr);
|
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
if( stats->unchanged )
|
|
|
|
log_info(_(" unchanged: %lu\n"), stats->unchanged );
|
|
|
|
if( stats->n_uids )
|
|
|
|
log_info(_(" new user IDs: %lu\n"), stats->n_uids );
|
|
|
|
if( stats->n_subk )
|
|
|
|
log_info(_(" new subkeys: %lu\n"), stats->n_subk );
|
|
|
|
if( stats->n_sigs )
|
|
|
|
log_info(_(" new signatures: %lu\n"), stats->n_sigs );
|
|
|
|
if( stats->n_revoc )
|
|
|
|
log_info(_(" new key revocations: %lu\n"), stats->n_revoc );
|
|
|
|
if( stats->secret_read )
|
|
|
|
log_info(_(" secret keys read: %lu\n"), stats->secret_read );
|
|
|
|
if( stats->secret_imported )
|
|
|
|
log_info(_(" secret keys imported: %lu\n"), stats->secret_imported );
|
|
|
|
if( stats->secret_dups )
|
|
|
|
log_info(_(" secret keys unchanged: %lu\n"), stats->secret_dups );
|
2002-08-21 14:59:05 +00:00
|
|
|
if( stats->not_imported )
|
|
|
|
log_info(_(" not imported: %lu\n"), stats->not_imported );
|
2005-06-12 21:17:46 +00:00
|
|
|
if( stats->n_sigs_cleaned)
|
|
|
|
log_info(_(" signatures cleaned: %lu\n"),stats->n_sigs_cleaned);
|
2005-06-14 03:55:19 +00:00
|
|
|
if( stats->n_uids_cleaned)
|
|
|
|
log_info(_(" user IDs cleaned: %lu\n"),stats->n_uids_cleaned);
|
1998-10-25 19:00:01 +00:00
|
|
|
}
|
|
|
|
|
1999-07-14 17:47:23 +00:00
|
|
|
if( is_status_enabled() ) {
|
2002-08-21 14:59:05 +00:00
|
|
|
char buf[14*20];
|
|
|
|
sprintf(buf, "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
|
2002-06-29 13:46:34 +00:00
|
|
|
stats->count,
|
|
|
|
stats->no_user_id,
|
|
|
|
stats->imported,
|
|
|
|
stats->imported_rsa,
|
|
|
|
stats->unchanged,
|
|
|
|
stats->n_uids,
|
|
|
|
stats->n_subk,
|
|
|
|
stats->n_sigs,
|
|
|
|
stats->n_revoc,
|
|
|
|
stats->secret_read,
|
|
|
|
stats->secret_imported,
|
|
|
|
stats->secret_dups,
|
2002-08-21 14:59:05 +00:00
|
|
|
stats->skipped_new_keys,
|
|
|
|
stats->not_imported );
|
1999-07-14 17:47:23 +00:00
|
|
|
write_status_text( STATUS_IMPORT_RES, buf );
|
|
|
|
}
|
1998-02-16 20:05:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
1999-02-19 14:54:00 +00:00
|
|
|
* Read the next keyblock from stream A.
|
|
|
|
* PENDING_PKT should be initialzed to NULL
|
1998-02-16 20:05:02 +00:00
|
|
|
* and not chnaged form the caller.
|
|
|
|
* Retunr: 0 = okay, -1 no more blocks or another errorcode.
|
|
|
|
*/
|
|
|
|
static int
|
1999-02-19 14:54:00 +00:00
|
|
|
read_block( IOBUF a, PACKET **pending_pkt, KBNODE *ret_root )
|
1998-01-16 21:15:24 +00:00
|
|
|
{
|
1998-02-16 20:05:02 +00:00
|
|
|
int rc;
|
|
|
|
PACKET *pkt;
|
|
|
|
KBNODE root = NULL;
|
1998-02-17 20:48:52 +00:00
|
|
|
int in_cert;
|
1998-02-16 20:05:02 +00:00
|
|
|
|
|
|
|
if( *pending_pkt ) {
|
|
|
|
root = new_kbnode( *pending_pkt );
|
|
|
|
*pending_pkt = NULL;
|
1998-02-17 20:48:52 +00:00
|
|
|
in_cert = 1;
|
1998-02-16 20:05:02 +00:00
|
|
|
}
|
1998-02-17 20:48:52 +00:00
|
|
|
else
|
|
|
|
in_cert = 0;
|
2005-07-27 18:10:56 +00:00
|
|
|
pkt = xmalloc( sizeof *pkt );
|
1998-02-16 20:05:02 +00:00
|
|
|
init_packet(pkt);
|
2002-06-29 13:46:34 +00:00
|
|
|
while( (rc=parse_packet(a, pkt)) != -1 ) {
|
1998-02-16 20:05:02 +00:00
|
|
|
if( rc ) { /* ignore errors */
|
2002-06-29 13:46:34 +00:00
|
|
|
if( rc != G10ERR_UNKNOWN_PACKET ) {
|
|
|
|
log_error("read_block: read error: %s\n", g10_errstr(rc) );
|
|
|
|
rc = G10ERR_INV_KEYRING;
|
1998-02-16 20:05:02 +00:00
|
|
|
goto ready;
|
|
|
|
}
|
|
|
|
free_packet( pkt );
|
|
|
|
init_packet(pkt);
|
|
|
|
continue;
|
|
|
|
}
|
1998-02-18 13:58:46 +00:00
|
|
|
|
|
|
|
if( !root && pkt->pkttype == PKT_SIGNATURE
|
|
|
|
&& pkt->pkt.signature->sig_class == 0x20 ) {
|
|
|
|
/* this is a revocation certificate which is handled
|
|
|
|
* in a special way */
|
|
|
|
root = new_kbnode( pkt );
|
|
|
|
pkt = NULL;
|
|
|
|
goto ready;
|
|
|
|
}
|
|
|
|
|
1998-02-16 20:05:02 +00:00
|
|
|
/* make a linked list of all packets */
|
|
|
|
switch( pkt->pkttype ) {
|
|
|
|
case PKT_COMPRESSED:
|
* misc.c (compress_algo_to_string, string_to_compress_algo,
check_compress_algo): Add bzip2.
* compress.c (compress_filter): Make static to help force the use of
push_compress_filter. Remove default algorithm setting since that is done
in push_compress_filter now.
* main.h: Use named algorithm.
* filter.h, compress.c (push_compress_filter, push_compress_filter2): New.
Figure out which is the appropriate compression filter to use, and push it
into place.
* compress.c (handle_compressed), encode.c (encode_simple, encode_crypt),
sign.c (sign_file, sign_symencrypt_file), import.c (read_block), export.c
(do_export): Use push_compress_filter instead of pushing the compression
filter ourselves.
* compress-bz2.c: New. Bzlib versions of the compression filter routines.
* Makefile.am: Include compress-bz2.c if bz2lib is available.
2003-10-31 05:39:02 +00:00
|
|
|
if(check_compress_algo(pkt->pkt.compressed->algorithm))
|
|
|
|
{
|
2002-06-29 13:46:34 +00:00
|
|
|
rc = G10ERR_COMPR_ALGO;
|
1998-02-16 20:05:02 +00:00
|
|
|
goto ready;
|
* misc.c (compress_algo_to_string, string_to_compress_algo,
check_compress_algo): Add bzip2.
* compress.c (compress_filter): Make static to help force the use of
push_compress_filter. Remove default algorithm setting since that is done
in push_compress_filter now.
* main.h: Use named algorithm.
* filter.h, compress.c (push_compress_filter, push_compress_filter2): New.
Figure out which is the appropriate compression filter to use, and push it
into place.
* compress.c (handle_compressed), encode.c (encode_simple, encode_crypt),
sign.c (sign_file, sign_symencrypt_file), import.c (read_block), export.c
(do_export): Use push_compress_filter instead of pushing the compression
filter ourselves.
* compress-bz2.c: New. Bzlib versions of the compression filter routines.
* Makefile.am: Include compress-bz2.c if bz2lib is available.
2003-10-31 05:39:02 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-07-27 18:10:56 +00:00
|
|
|
compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx );
|
1999-02-19 14:54:00 +00:00
|
|
|
pkt->pkt.compressed->buf = NULL;
|
* misc.c (compress_algo_to_string, string_to_compress_algo,
check_compress_algo): Add bzip2.
* compress.c (compress_filter): Make static to help force the use of
push_compress_filter. Remove default algorithm setting since that is done
in push_compress_filter now.
* main.h: Use named algorithm.
* filter.h, compress.c (push_compress_filter, push_compress_filter2): New.
Figure out which is the appropriate compression filter to use, and push it
into place.
* compress.c (handle_compressed), encode.c (encode_simple, encode_crypt),
sign.c (sign_file, sign_symencrypt_file), import.c (read_block), export.c
(do_export): Use push_compress_filter instead of pushing the compression
filter ourselves.
* compress-bz2.c: New. Bzlib versions of the compression filter routines.
* Makefile.am: Include compress-bz2.c if bz2lib is available.
2003-10-31 05:39:02 +00:00
|
|
|
push_compress_filter2(a,cfx,pkt->pkt.compressed->algorithm,1);
|
|
|
|
}
|
1998-02-16 20:05:02 +00:00
|
|
|
free_packet( pkt );
|
|
|
|
init_packet(pkt);
|
|
|
|
break;
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
case PKT_RING_TRUST:
|
|
|
|
/* skip those packets */
|
|
|
|
free_packet( pkt );
|
|
|
|
init_packet(pkt);
|
|
|
|
break;
|
1998-02-17 20:48:52 +00:00
|
|
|
|
1998-06-29 12:30:57 +00:00
|
|
|
case PKT_PUBLIC_KEY:
|
|
|
|
case PKT_SECRET_KEY:
|
1998-02-16 20:05:02 +00:00
|
|
|
if( in_cert ) { /* store this packet */
|
|
|
|
*pending_pkt = pkt;
|
|
|
|
pkt = NULL;
|
|
|
|
goto ready;
|
|
|
|
}
|
|
|
|
in_cert = 1;
|
|
|
|
default:
|
1998-02-17 20:48:52 +00:00
|
|
|
if( in_cert ) {
|
|
|
|
if( !root )
|
|
|
|
root = new_kbnode( pkt );
|
|
|
|
else
|
|
|
|
add_kbnode( root, new_kbnode( pkt ) );
|
2005-07-27 18:10:56 +00:00
|
|
|
pkt = xmalloc( sizeof *pkt );
|
1998-02-17 20:48:52 +00:00
|
|
|
}
|
1998-02-16 20:05:02 +00:00
|
|
|
init_packet(pkt);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ready:
|
|
|
|
if( rc == -1 && root )
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
if( rc )
|
|
|
|
release_kbnode( root );
|
|
|
|
else
|
|
|
|
*ret_root = root;
|
|
|
|
free_packet( pkt );
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree( pkt );
|
1998-02-16 20:05:02 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2003-04-09 01:57:46 +00:00
|
|
|
/* Walk through the subkeys on a pk to find if we have the PKS
|
* main.h, import.c (parse_import_options, fix_hkp_corruption, import_one,
delete_inv_parts), g10.c (main): New import-option
"repair-hkp-subkey-bug", which repairs as much as possible the HKP
mangling multiple subkeys bug. It is on by default for keyserver
receives, and off by default for regular --import.
* main.h, import.c (import, import_one, delete_inv_parts), hkp.c
(hkp_ask_import), keyserver.c (keyserver_spawn): Use keyserver import
options when doing keyserver receives.
2002-07-24 21:17:19 +00:00
|
|
|
disease: multiple subkeys with their binding sigs stripped, and the
|
|
|
|
sig for the first subkey placed after the last subkey. That is,
|
|
|
|
instead of "pk uid sig sub1 bind1 sub2 bind2 sub3 bind3" we have
|
|
|
|
"pk uid sig sub1 sub2 sub3 bind1". We can't do anything about sub2
|
|
|
|
and sub3, as they are already lost, but we can try and rescue sub1
|
|
|
|
by reordering the keyblock so that it reads "pk uid sig sub1 bind1
|
|
|
|
sub2 sub3". Returns TRUE if the keyblock was modified. */
|
|
|
|
|
|
|
|
static int
|
2003-04-09 01:57:46 +00:00
|
|
|
fix_pks_corruption(KBNODE keyblock)
|
* main.h, import.c (parse_import_options, fix_hkp_corruption, import_one,
delete_inv_parts), g10.c (main): New import-option
"repair-hkp-subkey-bug", which repairs as much as possible the HKP
mangling multiple subkeys bug. It is on by default for keyserver
receives, and off by default for regular --import.
* main.h, import.c (import, import_one, delete_inv_parts), hkp.c
(hkp_ask_import), keyserver.c (keyserver_spawn): Use keyserver import
options when doing keyserver receives.
2002-07-24 21:17:19 +00:00
|
|
|
{
|
|
|
|
int changed=0,keycount=0;
|
|
|
|
KBNODE node,last=NULL,sknode=NULL;
|
|
|
|
|
|
|
|
/* First determine if we have the problem at all. Look for 2 or
|
|
|
|
more subkeys in a row, followed by a single binding sig. */
|
|
|
|
for(node=keyblock;node;last=node,node=node->next)
|
|
|
|
{
|
|
|
|
if(node->pkt->pkttype==PKT_PUBLIC_SUBKEY)
|
|
|
|
{
|
|
|
|
keycount++;
|
|
|
|
if(!sknode)
|
|
|
|
sknode=node;
|
|
|
|
}
|
|
|
|
else if(node->pkt->pkttype==PKT_SIGNATURE &&
|
|
|
|
node->pkt->pkt.signature->sig_class==0x18 &&
|
|
|
|
keycount>=2 && node->next==NULL)
|
|
|
|
{
|
|
|
|
/* We might have the problem, as this key has two subkeys in
|
|
|
|
a row without any intervening packets. */
|
|
|
|
|
|
|
|
/* Sanity check */
|
|
|
|
if(last==NULL)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* Temporarily attach node to sknode. */
|
|
|
|
node->next=sknode->next;
|
|
|
|
sknode->next=node;
|
|
|
|
last->next=NULL;
|
|
|
|
|
2002-12-01 20:59:04 +00:00
|
|
|
/* Note we aren't checking whether this binding sig is a
|
|
|
|
selfsig. This is not necessary here as the subkey and
|
|
|
|
binding sig will be rejected later if that is the
|
|
|
|
case. */
|
* main.h, import.c (parse_import_options, fix_hkp_corruption, import_one,
delete_inv_parts), g10.c (main): New import-option
"repair-hkp-subkey-bug", which repairs as much as possible the HKP
mangling multiple subkeys bug. It is on by default for keyserver
receives, and off by default for regular --import.
* main.h, import.c (import, import_one, delete_inv_parts), hkp.c
(hkp_ask_import), keyserver.c (keyserver_spawn): Use keyserver import
options when doing keyserver receives.
2002-07-24 21:17:19 +00:00
|
|
|
if(check_key_signature(keyblock,node,NULL))
|
|
|
|
{
|
|
|
|
/* Not a match, so undo the changes. */
|
|
|
|
sknode->next=node->next;
|
|
|
|
last->next=node;
|
|
|
|
node->next=NULL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sknode->flag |= 1; /* Mark it good so we don't need to
|
|
|
|
check it again */
|
|
|
|
changed=1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
keycount=0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
2002-09-02 10:59:04 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
print_import_ok (PKT_public_key *pk, PKT_secret_key *sk, unsigned int reason)
|
|
|
|
{
|
|
|
|
byte array[MAX_FINGERPRINT_LEN], *s;
|
|
|
|
char buf[MAX_FINGERPRINT_LEN*2+30], *p;
|
|
|
|
size_t i, n;
|
|
|
|
|
|
|
|
sprintf (buf, "%u ", reason);
|
|
|
|
p = buf + strlen (buf);
|
|
|
|
|
|
|
|
if (pk)
|
|
|
|
fingerprint_from_pk (pk, array, &n);
|
|
|
|
else
|
|
|
|
fingerprint_from_sk (sk, array, &n);
|
|
|
|
s = array;
|
|
|
|
for (i=0; i < n ; i++, s++, p += 2)
|
|
|
|
sprintf (p, "%02X", *s);
|
|
|
|
|
|
|
|
write_status_text (STATUS_IMPORT_OK, buf);
|
|
|
|
}
|
|
|
|
|
2004-02-12 16:31:07 +00:00
|
|
|
static void
|
2002-12-22 20:53:20 +00:00
|
|
|
print_import_check (PKT_public_key * pk, PKT_user_id * id)
|
|
|
|
{
|
2003-02-02 15:47:43 +00:00
|
|
|
char * buf;
|
2002-12-22 20:53:20 +00:00
|
|
|
byte fpr[24];
|
|
|
|
u32 keyid[2];
|
2002-12-27 22:17:25 +00:00
|
|
|
size_t i, pos = 0, n;
|
2002-12-22 20:53:20 +00:00
|
|
|
|
2005-07-27 18:10:56 +00:00
|
|
|
buf = xmalloc (17+41+id->len+32);
|
2002-12-22 20:53:20 +00:00
|
|
|
keyid_from_pk (pk, keyid);
|
|
|
|
sprintf (buf, "%08X%08X ", keyid[0], keyid[1]);
|
|
|
|
pos = 17;
|
|
|
|
fingerprint_from_pk (pk, fpr, &n);
|
|
|
|
for (i = 0; i < n; i++, pos += 2)
|
|
|
|
sprintf (buf+pos, "%02X", fpr[i]);
|
|
|
|
strcat (buf, " ");
|
|
|
|
pos += 1;
|
2003-02-02 15:47:43 +00:00
|
|
|
strcat (buf, id->name);
|
2002-12-22 20:53:20 +00:00
|
|
|
write_status_text (STATUS_IMPORT_CHECK, buf);
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree (buf);
|
2002-12-22 20:53:20 +00:00
|
|
|
}
|
|
|
|
|
2004-03-15 20:00:42 +00:00
|
|
|
static void
|
|
|
|
check_prefs_warning(PKT_public_key *pk)
|
|
|
|
{
|
2006-06-28 19:33:14 +00:00
|
|
|
log_info(_("WARNING: key %s contains preferences for unavailable\n"),
|
|
|
|
keystr_from_pk(pk));
|
|
|
|
/* TRANSLATORS: This string is belongs to the previous one. They are
|
2006-07-26 11:25:36 +00:00
|
|
|
only split up to allow printing of a common prefix. */
|
|
|
|
log_info(_(" algorithms on these user IDs:\n"));
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
|
|
|
|
2004-02-12 19:18:27 +00:00
|
|
|
static void
|
|
|
|
check_prefs(KBNODE keyblock)
|
|
|
|
{
|
|
|
|
KBNODE node;
|
2004-03-15 20:00:42 +00:00
|
|
|
PKT_public_key *pk;
|
2004-02-12 19:18:27 +00:00
|
|
|
int problem=0;
|
|
|
|
|
|
|
|
merge_keys_and_selfsig(keyblock);
|
2004-03-15 20:00:42 +00:00
|
|
|
pk=keyblock->pkt->pkt.public_key;
|
2004-02-12 19:18:27 +00:00
|
|
|
|
|
|
|
for(node=keyblock;node;node=node->next)
|
|
|
|
{
|
|
|
|
if(node->pkt->pkttype==PKT_USER_ID
|
|
|
|
&& node->pkt->pkt.user_id->created
|
|
|
|
&& node->pkt->pkt.user_id->prefs)
|
|
|
|
{
|
|
|
|
PKT_user_id *uid=node->pkt->pkt.user_id;
|
|
|
|
prefitem_t *prefs=uid->prefs;
|
|
|
|
char *user=utf8_to_native(uid->name,strlen(uid->name),0);
|
|
|
|
|
|
|
|
for(;prefs->type;prefs++)
|
|
|
|
{
|
|
|
|
char num[10]; /* prefs->value is a byte, so we're over
|
|
|
|
safe here */
|
|
|
|
|
|
|
|
sprintf(num,"%u",prefs->value);
|
|
|
|
|
|
|
|
if(prefs->type==PREFTYPE_SYM)
|
|
|
|
{
|
|
|
|
if(check_cipher_algo(prefs->value))
|
|
|
|
{
|
|
|
|
const char *algo=cipher_algo_to_string(prefs->value);
|
|
|
|
if(!problem)
|
2004-03-15 20:00:42 +00:00
|
|
|
check_prefs_warning(pk);
|
2004-02-12 19:18:27 +00:00
|
|
|
log_info(_(" \"%s\": preference for cipher"
|
|
|
|
" algorithm %s\n"),user,algo?algo:num);
|
|
|
|
problem=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(prefs->type==PREFTYPE_HASH)
|
|
|
|
{
|
|
|
|
if(check_digest_algo(prefs->value))
|
|
|
|
{
|
|
|
|
const char *algo=digest_algo_to_string(prefs->value);
|
|
|
|
if(!problem)
|
2004-03-15 20:00:42 +00:00
|
|
|
check_prefs_warning(pk);
|
2004-02-12 19:18:27 +00:00
|
|
|
log_info(_(" \"%s\": preference for digest"
|
|
|
|
" algorithm %s\n"),user,algo?algo:num);
|
|
|
|
problem=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(prefs->type==PREFTYPE_ZIP)
|
|
|
|
{
|
|
|
|
if(check_compress_algo(prefs->value))
|
|
|
|
{
|
|
|
|
const char *algo=compress_algo_to_string(prefs->value);
|
|
|
|
if(!problem)
|
2004-03-15 20:00:42 +00:00
|
|
|
check_prefs_warning(pk);
|
2004-02-12 19:18:27 +00:00
|
|
|
log_info(_(" \"%s\": preference for compression"
|
|
|
|
" algorithm %s\n"),user,algo?algo:num);
|
|
|
|
problem=1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree(user);
|
2004-02-12 19:18:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-07-26 15:41:04 +00:00
|
|
|
if(problem)
|
2004-02-12 19:18:27 +00:00
|
|
|
{
|
2004-02-14 01:54:12 +00:00
|
|
|
log_info(_("it is strongly suggested that you update"
|
|
|
|
" your preferences and\n"));
|
|
|
|
log_info(_("re-distribute this key to avoid potential algorithm"
|
|
|
|
" mismatch problems\n"));
|
2004-02-12 19:18:27 +00:00
|
|
|
|
|
|
|
if(!opt.batch)
|
|
|
|
{
|
|
|
|
STRLIST sl=NULL,locusr=NULL;
|
|
|
|
size_t fprlen=0;
|
|
|
|
byte fpr[MAX_FINGERPRINT_LEN],*p;
|
|
|
|
char username[(MAX_FINGERPRINT_LEN*2)+1];
|
2004-02-14 05:03:45 +00:00
|
|
|
unsigned int i;
|
2004-02-12 19:18:27 +00:00
|
|
|
|
2004-03-15 20:00:42 +00:00
|
|
|
p=fingerprint_from_pk(pk,fpr,&fprlen);
|
2004-02-12 19:18:27 +00:00
|
|
|
for(i=0;i<fprlen;i++,p++)
|
|
|
|
sprintf(username+2*i,"%02X",*p);
|
|
|
|
add_to_strlist(&locusr,username);
|
|
|
|
|
|
|
|
append_to_strlist(&sl,"updpref");
|
|
|
|
append_to_strlist(&sl,"save");
|
|
|
|
|
|
|
|
keyedit_menu( username, locusr, sl, 1, 1 );
|
|
|
|
free_strlist(sl);
|
|
|
|
free_strlist(locusr);
|
|
|
|
}
|
|
|
|
else if(!opt.quiet)
|
|
|
|
log_info(_("you can update your preferences with:"
|
2004-03-15 20:00:42 +00:00
|
|
|
" gpg --edit-key %s updpref save\n"),keystr_from_pk(pk));
|
2004-02-12 19:18:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-02-16 20:05:02 +00:00
|
|
|
/****************
|
|
|
|
* Try to import one keyblock. Return an error only in serious cases, but
|
|
|
|
* never for an invalid keyblock. It uses log_error to increase the
|
|
|
|
* internal errorcount, so that invalid input can be detected by programs
|
2002-06-29 13:46:34 +00:00
|
|
|
* which called g10.
|
1998-02-16 20:05:02 +00:00
|
|
|
*/
|
|
|
|
static int
|
2006-03-14 02:23:00 +00:00
|
|
|
import_one( const char *fname, KBNODE keyblock, struct stats_s *stats,
|
2006-06-12 12:05:34 +00:00
|
|
|
unsigned char **fpr,size_t *fpr_len,unsigned int options,
|
|
|
|
int from_sk )
|
1998-02-16 20:05:02 +00:00
|
|
|
{
|
1998-06-29 12:30:57 +00:00
|
|
|
PKT_public_key *pk;
|
|
|
|
PKT_public_key *pk_orig;
|
1998-02-16 20:05:02 +00:00
|
|
|
KBNODE node, uidnode;
|
1998-02-17 20:48:52 +00:00
|
|
|
KBNODE keyblock_orig = NULL;
|
1998-02-16 20:05:02 +00:00
|
|
|
u32 keyid[2];
|
|
|
|
int rc = 0;
|
1998-08-11 17:29:34 +00:00
|
|
|
int new_key = 0;
|
1998-09-29 16:15:15 +00:00
|
|
|
int mod_key = 0;
|
2002-12-13 21:10:53 +00:00
|
|
|
int non_self = 0;
|
1998-02-16 20:05:02 +00:00
|
|
|
|
1998-04-14 17:51:16 +00:00
|
|
|
/* get the key and print some info about it */
|
1998-06-29 12:30:57 +00:00
|
|
|
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
|
|
|
|
if( !node )
|
|
|
|
BUG();
|
1998-02-16 20:05:02 +00:00
|
|
|
|
1998-06-29 12:30:57 +00:00
|
|
|
pk = node->pkt->pkt.public_key;
|
2006-03-14 02:23:00 +00:00
|
|
|
|
1998-06-29 12:30:57 +00:00
|
|
|
keyid_from_pk( pk, keyid );
|
1998-02-16 20:05:02 +00:00
|
|
|
uidnode = find_next_kbnode( keyblock, PKT_USER_ID );
|
|
|
|
|
2004-03-15 20:00:42 +00:00
|
|
|
if( opt.verbose && !opt.interactive )
|
|
|
|
{
|
|
|
|
log_info( "pub %4u%c/%s %s ",
|
1998-06-29 12:30:57 +00:00
|
|
|
nbits_from_pk( pk ),
|
|
|
|
pubkey_letter( pk->pubkey_algo ),
|
2004-03-15 20:00:42 +00:00
|
|
|
keystr_from_pk(pk), datestr_from_pk(pk) );
|
1998-02-16 20:05:02 +00:00
|
|
|
if( uidnode )
|
2004-03-15 20:00:42 +00:00
|
|
|
print_utf8_string( stderr, uidnode->pkt->pkt.user_id->name,
|
|
|
|
uidnode->pkt->pkt.user_id->len );
|
1998-02-16 20:05:02 +00:00
|
|
|
putc('\n', stderr);
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if( !uidnode )
|
|
|
|
{
|
|
|
|
log_error( _("key %s: no user ID\n"), keystr_from_pk(pk));
|
1998-02-16 20:05:02 +00:00
|
|
|
return 0;
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
2002-08-18 17:24:21 +00:00
|
|
|
|
2002-08-19 08:28:00 +00:00
|
|
|
if (opt.interactive) {
|
2003-01-03 21:41:53 +00:00
|
|
|
if(is_status_enabled())
|
|
|
|
print_import_check (pk, uidnode->pkt->pkt.user_id);
|
2003-02-02 15:47:43 +00:00
|
|
|
merge_keys_and_selfsig (keyblock);
|
2002-08-19 08:28:00 +00:00
|
|
|
tty_printf ("\n");
|
|
|
|
show_basic_key_info (keyblock);
|
|
|
|
tty_printf ("\n");
|
|
|
|
if (!cpr_get_answer_is_yes ("import.okay",
|
|
|
|
"Do you want to import this key? (y/N) "))
|
2002-08-18 17:24:21 +00:00
|
|
|
return 0;
|
|
|
|
}
|
1998-02-16 20:05:02 +00:00
|
|
|
|
2005-11-02 05:22:01 +00:00
|
|
|
collapse_uids(&keyblock);
|
|
|
|
|
2005-06-12 21:17:46 +00:00
|
|
|
/* Clean the key that we're about to import, to cut down on things
|
|
|
|
that we have to clean later. This has no practical impact on
|
|
|
|
the end result, but does result in less logging which might
|
|
|
|
confuse the user. */
|
2005-11-12 04:53:03 +00:00
|
|
|
if(options&IMPORT_CLEAN)
|
|
|
|
clean_key(keyblock,opt.verbose,options&IMPORT_MINIMAL,NULL,NULL);
|
2005-06-14 03:55:19 +00:00
|
|
|
|
1998-02-16 20:05:02 +00:00
|
|
|
clear_kbnode_flags( keyblock );
|
* main.h, import.c (parse_import_options, fix_hkp_corruption, import_one,
delete_inv_parts), g10.c (main): New import-option
"repair-hkp-subkey-bug", which repairs as much as possible the HKP
mangling multiple subkeys bug. It is on by default for keyserver
receives, and off by default for regular --import.
* main.h, import.c (import, import_one, delete_inv_parts), hkp.c
(hkp_ask_import), keyserver.c (keyserver_spawn): Use keyserver import
options when doing keyserver receives.
2002-07-24 21:17:19 +00:00
|
|
|
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if((options&IMPORT_REPAIR_PKS_SUBKEY_BUG) && fix_pks_corruption(keyblock)
|
|
|
|
&& opt.verbose)
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info(_("key %s: PKS subkey corruption repaired\n"),
|
|
|
|
keystr_from_pk(pk));
|
* main.h, import.c (parse_import_options, fix_hkp_corruption, import_one,
delete_inv_parts), g10.c (main): New import-option
"repair-hkp-subkey-bug", which repairs as much as possible the HKP
mangling multiple subkeys bug. It is on by default for keyserver
receives, and off by default for regular --import.
* main.h, import.c (import, import_one, delete_inv_parts), hkp.c
(hkp_ask_import), keyserver.c (keyserver_spawn): Use keyserver import
options when doing keyserver receives.
2002-07-24 21:17:19 +00:00
|
|
|
|
2002-12-13 21:10:53 +00:00
|
|
|
rc = chk_self_sigs( fname, keyblock , pk, keyid, &non_self );
|
1998-02-16 20:05:02 +00:00
|
|
|
if( rc )
|
|
|
|
return rc== -1? 0:rc;
|
1998-02-17 20:48:52 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
/* If we allow such a thing, mark unsigned uids as valid */
|
1999-07-22 18:11:55 +00:00
|
|
|
if( opt.allow_non_selfsigned_uid )
|
2002-06-29 13:46:34 +00:00
|
|
|
for( node=keyblock; node; node = node->next )
|
|
|
|
if( node->pkt->pkttype == PKT_USER_ID && !(node->flag & 1) )
|
|
|
|
{
|
|
|
|
char *user=utf8_to_native(node->pkt->pkt.user_id->name,
|
|
|
|
node->pkt->pkt.user_id->len,0);
|
|
|
|
node->flag |= 1;
|
* main.h: Create S2K_DIGEST_ALGO macro so we do not need to always set
opt.s2k_digest_algo. This helps fix a problem with PGP 2.x encrypted
symmetric messages. Change all callers (encode.c, g10.c, keyedit.c,
keygen.c, passphrase.c, sign.c).
* armor.c, cardglue.c, getkey.c, import.c, keygen.c: Be consistent in some
more quoted strings. Always use 'user ID', not 'user id', "quotes" for
user IDs, etc.
2004-09-24 20:34:38 +00:00
|
|
|
log_info( _("key %s: accepted non self-signed user ID \"%s\"\n"),
|
2004-03-15 20:00:42 +00:00
|
|
|
keystr_from_pk(pk),user);
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree(user);
|
2002-06-29 13:46:34 +00:00
|
|
|
}
|
1999-07-22 18:11:55 +00:00
|
|
|
|
* main.h, import.c (parse_import_options, fix_hkp_corruption, import_one,
delete_inv_parts), g10.c (main): New import-option
"repair-hkp-subkey-bug", which repairs as much as possible the HKP
mangling multiple subkeys bug. It is on by default for keyserver
receives, and off by default for regular --import.
* main.h, import.c (import, import_one, delete_inv_parts), hkp.c
(hkp_ask_import), keyserver.c (keyserver_spawn): Use keyserver import
options when doing keyserver receives.
2002-07-24 21:17:19 +00:00
|
|
|
if( !delete_inv_parts( fname, keyblock, keyid, options ) ) {
|
2004-03-15 20:00:42 +00:00
|
|
|
log_error( _("key %s: no valid user IDs\n"), keystr_from_pk(pk));
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if( !opt.quiet )
|
|
|
|
log_info(_("this may be caused by a missing self-signature\n"));
|
2002-06-29 13:46:34 +00:00
|
|
|
stats->no_user_id++;
|
1998-02-16 20:05:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* do we have this key already in one of our pubrings ? */
|
2005-07-27 18:10:56 +00:00
|
|
|
pk_orig = xmalloc_clear( sizeof *pk_orig );
|
2002-11-13 17:43:27 +00:00
|
|
|
rc = get_pubkey_fast ( pk_orig, keyid );
|
2004-03-15 20:00:42 +00:00
|
|
|
if( rc && rc != G10ERR_NO_PUBKEY && rc != G10ERR_UNU_PUBKEY )
|
|
|
|
{
|
|
|
|
log_error( _("key %s: public key not found: %s\n"),
|
|
|
|
keystr(keyid), g10_errstr(rc));
|
|
|
|
}
|
2003-12-31 04:58:52 +00:00
|
|
|
else if ( rc && (opt.import_options&IMPORT_MERGE_ONLY) )
|
|
|
|
{
|
2000-09-18 14:35:34 +00:00
|
|
|
if( opt.verbose )
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: new key - skipped\n"), keystr(keyid));
|
2000-09-18 14:35:34 +00:00
|
|
|
rc = 0;
|
2002-06-29 13:46:34 +00:00
|
|
|
stats->skipped_new_keys++;
|
2003-12-31 04:58:52 +00:00
|
|
|
}
|
1998-02-17 20:48:52 +00:00
|
|
|
else if( rc ) { /* insert this key */
|
2002-06-29 13:46:34 +00:00
|
|
|
KEYDB_HANDLE hd = keydb_new (0);
|
|
|
|
|
|
|
|
rc = keydb_locate_writable (hd, NULL);
|
|
|
|
if (rc) {
|
|
|
|
log_error (_("no writable keyring found: %s\n"), g10_errstr (rc));
|
|
|
|
keydb_release (hd);
|
|
|
|
return G10ERR_GENERAL;
|
|
|
|
}
|
1998-02-16 20:05:02 +00:00
|
|
|
if( opt.verbose > 1 )
|
2002-06-29 13:46:34 +00:00
|
|
|
log_info (_("writing to `%s'\n"), keydb_get_resource_name (hd) );
|
2004-03-19 23:15:27 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
rc = keydb_insert_keyblock (hd, keyblock );
|
|
|
|
if (rc)
|
|
|
|
log_error (_("error writing keyring `%s': %s\n"),
|
|
|
|
keydb_get_resource_name (hd), g10_errstr(rc));
|
|
|
|
else
|
2002-10-01 17:32:06 +00:00
|
|
|
{
|
|
|
|
/* This should not be possible since we delete the
|
|
|
|
ownertrust when a key is deleted, but it can happen if
|
|
|
|
the keyring and trustdb are out of sync. It can also
|
|
|
|
be made to happen with the trusted-key command. */
|
|
|
|
|
2002-10-30 03:11:57 +00:00
|
|
|
clear_ownertrusts (pk);
|
2002-12-13 21:10:53 +00:00
|
|
|
if(non_self)
|
|
|
|
revalidation_mark ();
|
2002-10-01 17:32:06 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
keydb_release (hd);
|
|
|
|
|
|
|
|
/* we are ready */
|
2004-03-15 20:00:42 +00:00
|
|
|
if( !opt.quiet )
|
|
|
|
{
|
2004-08-23 17:55:49 +00:00
|
|
|
char *p=get_user_id_native (keyid);
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: public key \"%s\" imported\n"),
|
|
|
|
keystr(keyid),p);
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree(p);
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
|
|
|
if( is_status_enabled() )
|
|
|
|
{
|
1999-07-14 17:47:23 +00:00
|
|
|
char *us = get_long_user_id_string( keyid );
|
|
|
|
write_status_text( STATUS_IMPORTED, us );
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree(us);
|
2002-09-02 10:59:04 +00:00
|
|
|
print_import_ok (pk,NULL, 1);
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
stats->imported++;
|
1998-10-25 19:00:01 +00:00
|
|
|
if( is_RSA( pk->pubkey_algo ) )
|
2002-06-29 13:46:34 +00:00
|
|
|
stats->imported_rsa++;
|
1998-08-11 17:29:34 +00:00
|
|
|
new_key = 1;
|
1998-02-16 20:05:02 +00:00
|
|
|
}
|
1998-02-17 20:48:52 +00:00
|
|
|
else { /* merge */
|
2002-06-29 13:46:34 +00:00
|
|
|
KEYDB_HANDLE hd;
|
2005-06-14 03:55:19 +00:00
|
|
|
int n_uids, n_sigs, n_subk, n_sigs_cleaned, n_uids_cleaned;
|
1998-02-17 20:48:52 +00:00
|
|
|
|
|
|
|
/* Compare the original against the new key; just to be sure nothing
|
|
|
|
* weird is going on */
|
2004-03-15 20:00:42 +00:00
|
|
|
if( cmp_public_keys( pk_orig, pk ) )
|
|
|
|
{
|
|
|
|
log_error( _("key %s: doesn't match our copy\n"),keystr(keyid));
|
1998-02-17 20:48:52 +00:00
|
|
|
goto leave;
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
1998-02-17 20:48:52 +00:00
|
|
|
|
|
|
|
/* now read the original keyblock */
|
2002-06-29 13:46:34 +00:00
|
|
|
hd = keydb_new (0);
|
|
|
|
{
|
|
|
|
byte afp[MAX_FINGERPRINT_LEN];
|
|
|
|
size_t an;
|
|
|
|
|
|
|
|
fingerprint_from_pk (pk_orig, afp, &an);
|
|
|
|
while (an < MAX_FINGERPRINT_LEN)
|
|
|
|
afp[an++] = 0;
|
|
|
|
rc = keydb_search_fpr (hd, afp);
|
|
|
|
}
|
2004-03-15 20:00:42 +00:00
|
|
|
if( rc )
|
|
|
|
{
|
|
|
|
log_error (_("key %s: can't locate original keyblock: %s\n"),
|
|
|
|
keystr(keyid), g10_errstr(rc));
|
2002-06-29 13:46:34 +00:00
|
|
|
keydb_release (hd);
|
|
|
|
goto leave;
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
rc = keydb_get_keyblock (hd, &keyblock_orig );
|
2004-03-15 20:00:42 +00:00
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
log_error (_("key %s: can't read original keyblock: %s\n"),
|
|
|
|
keystr(keyid), g10_errstr(rc));
|
2002-06-29 13:46:34 +00:00
|
|
|
keydb_release (hd);
|
1998-02-17 20:48:52 +00:00
|
|
|
goto leave;
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
1999-05-22 20:54:54 +00:00
|
|
|
|
1998-02-17 20:48:52 +00:00
|
|
|
/* and try to merge the block */
|
|
|
|
clear_kbnode_flags( keyblock_orig );
|
1999-05-19 14:12:26 +00:00
|
|
|
clear_kbnode_flags( keyblock );
|
2005-06-14 03:55:19 +00:00
|
|
|
n_uids = n_sigs = n_subk = n_sigs_cleaned = n_uids_cleaned = 0;
|
1998-02-17 20:48:52 +00:00
|
|
|
rc = merge_blocks( fname, keyblock_orig, keyblock,
|
2005-06-12 21:17:46 +00:00
|
|
|
keyid, &n_uids, &n_sigs, &n_subk );
|
|
|
|
if( rc )
|
|
|
|
{
|
2002-06-29 13:46:34 +00:00
|
|
|
keydb_release (hd);
|
1998-02-17 20:48:52 +00:00
|
|
|
goto leave;
|
2005-06-12 21:17:46 +00:00
|
|
|
}
|
|
|
|
|
2005-11-12 04:53:03 +00:00
|
|
|
if(options&IMPORT_CLEAN)
|
|
|
|
clean_key(keyblock_orig,opt.verbose,options&IMPORT_MINIMAL,
|
|
|
|
&n_uids_cleaned,&n_sigs_cleaned);
|
2005-06-14 03:55:19 +00:00
|
|
|
|
|
|
|
if( n_uids || n_sigs || n_subk || n_sigs_cleaned || n_uids_cleaned) {
|
1998-09-29 16:15:15 +00:00
|
|
|
mod_key = 1;
|
1998-05-26 13:38:00 +00:00
|
|
|
/* keyblock_orig has been updated; write */
|
2002-06-29 13:46:34 +00:00
|
|
|
rc = keydb_update_keyblock (hd, keyblock_orig);
|
|
|
|
if (rc)
|
|
|
|
log_error (_("error writing keyring `%s': %s\n"),
|
|
|
|
keydb_get_resource_name (hd), g10_errstr(rc) );
|
2002-12-13 21:10:53 +00:00
|
|
|
else if(non_self)
|
2002-06-29 13:46:34 +00:00
|
|
|
revalidation_mark ();
|
|
|
|
|
1998-02-17 20:48:52 +00:00
|
|
|
/* we are ready */
|
2004-03-15 20:00:42 +00:00
|
|
|
if( !opt.quiet )
|
|
|
|
{
|
2004-08-23 17:55:49 +00:00
|
|
|
char *p=get_user_id_native(keyid);
|
1998-10-25 19:00:01 +00:00
|
|
|
if( n_uids == 1 )
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: \"%s\" 1 new user ID\n"),
|
|
|
|
keystr(keyid),p);
|
1998-10-25 19:00:01 +00:00
|
|
|
else if( n_uids )
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: \"%s\" %d new user IDs\n"),
|
|
|
|
keystr(keyid),p,n_uids);
|
1998-10-25 19:00:01 +00:00
|
|
|
if( n_sigs == 1 )
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: \"%s\" 1 new signature\n"),
|
|
|
|
keystr(keyid), p);
|
1998-10-25 19:00:01 +00:00
|
|
|
else if( n_sigs )
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: \"%s\" %d new signatures\n"),
|
|
|
|
keystr(keyid), p, n_sigs );
|
1998-10-25 19:00:01 +00:00
|
|
|
if( n_subk == 1 )
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: \"%s\" 1 new subkey\n"),
|
|
|
|
keystr(keyid), p);
|
1998-10-25 19:00:01 +00:00
|
|
|
else if( n_subk )
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: \"%s\" %d new subkeys\n"),
|
|
|
|
keystr(keyid), p, n_subk );
|
2005-06-14 03:55:19 +00:00
|
|
|
if(n_sigs_cleaned==1)
|
|
|
|
log_info(_("key %s: \"%s\" %d signature cleaned\n"),
|
|
|
|
keystr(keyid),p,n_sigs_cleaned);
|
|
|
|
else if(n_sigs_cleaned)
|
2005-06-12 21:17:46 +00:00
|
|
|
log_info(_("key %s: \"%s\" %d signatures cleaned\n"),
|
|
|
|
keystr(keyid),p,n_sigs_cleaned);
|
2005-06-14 03:55:19 +00:00
|
|
|
if(n_uids_cleaned==1)
|
|
|
|
log_info(_("key %s: \"%s\" %d user ID cleaned\n"),
|
|
|
|
keystr(keyid),p,n_uids_cleaned);
|
|
|
|
else if(n_uids_cleaned)
|
|
|
|
log_info(_("key %s: \"%s\" %d user IDs cleaned\n"),
|
|
|
|
keystr(keyid),p,n_uids_cleaned);
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree(p);
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
1998-10-25 19:00:01 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
stats->n_uids +=n_uids;
|
|
|
|
stats->n_sigs +=n_sigs;
|
|
|
|
stats->n_subk +=n_subk;
|
2005-06-12 21:17:46 +00:00
|
|
|
stats->n_sigs_cleaned +=n_sigs_cleaned;
|
2005-06-14 03:55:19 +00:00
|
|
|
stats->n_uids_cleaned +=n_uids_cleaned;
|
2002-09-02 10:59:04 +00:00
|
|
|
|
|
|
|
if (is_status_enabled ())
|
|
|
|
print_import_ok (pk, NULL,
|
|
|
|
((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0)));
|
1998-10-25 19:00:01 +00:00
|
|
|
}
|
2004-02-12 19:18:27 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (is_status_enabled ())
|
|
|
|
print_import_ok (pk, NULL, 0);
|
|
|
|
|
|
|
|
if( !opt.quiet )
|
|
|
|
{
|
2004-08-23 17:55:49 +00:00
|
|
|
char *p=get_user_id_native(keyid);
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: \"%s\" not changed\n"),keystr(keyid),p);
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree(p);
|
2004-02-12 19:18:27 +00:00
|
|
|
}
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
stats->unchanged++;
|
2004-02-12 19:18:27 +00:00
|
|
|
}
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
keydb_release (hd); hd = NULL;
|
1998-07-21 12:53:38 +00:00
|
|
|
}
|
1998-02-16 20:05:02 +00:00
|
|
|
|
1998-02-17 20:48:52 +00:00
|
|
|
leave:
|
2004-02-12 19:18:27 +00:00
|
|
|
|
|
|
|
/* Now that the key is definitely incorporated into the keydb, we
|
|
|
|
need to check if a designated revocation is present or if the
|
|
|
|
prefs are not rational so we can warn the user. */
|
|
|
|
|
2004-02-12 16:31:07 +00:00
|
|
|
if(mod_key)
|
2004-02-12 19:18:27 +00:00
|
|
|
{
|
|
|
|
revocation_present(keyblock_orig);
|
2006-06-12 12:05:34 +00:00
|
|
|
if(!from_sk && seckey_available(keyid)==0)
|
2004-02-12 19:18:27 +00:00
|
|
|
check_prefs(keyblock_orig);
|
|
|
|
}
|
2004-02-12 16:31:07 +00:00
|
|
|
else if(new_key)
|
2004-02-12 19:18:27 +00:00
|
|
|
{
|
2006-05-25 19:39:03 +00:00
|
|
|
/* A little explanation for this: we fill in the fingerprint
|
|
|
|
when importing keys as it can be useful to know the
|
|
|
|
fingerprint in certain keyserver-related cases (a keyserver
|
|
|
|
asked for a particular name, but the key doesn't have that
|
|
|
|
name). However, in cases where we're importing more than
|
|
|
|
one key at a time, we cannot know which key to fingerprint.
|
|
|
|
In these cases, rather than guessing, we do not fingerpring
|
|
|
|
at all, and we must hope the user ID on the keys are
|
|
|
|
useful. */
|
2006-05-22 21:38:13 +00:00
|
|
|
if(fpr)
|
2006-05-22 16:53:09 +00:00
|
|
|
{
|
|
|
|
xfree(*fpr);
|
2006-05-22 21:38:13 +00:00
|
|
|
if(stats->imported==1)
|
|
|
|
*fpr=fingerprint_from_pk(pk,NULL,fpr_len);
|
|
|
|
else
|
|
|
|
*fpr=NULL;
|
2006-05-22 16:53:09 +00:00
|
|
|
}
|
|
|
|
|
2004-02-12 19:18:27 +00:00
|
|
|
revocation_present(keyblock);
|
2006-06-12 12:05:34 +00:00
|
|
|
if(!from_sk && seckey_available(keyid)==0)
|
2004-02-12 19:18:27 +00:00
|
|
|
check_prefs(keyblock);
|
|
|
|
}
|
2004-02-12 16:31:07 +00:00
|
|
|
|
1998-02-17 20:48:52 +00:00
|
|
|
release_kbnode( keyblock_orig );
|
1998-06-29 12:30:57 +00:00
|
|
|
free_public_key( pk_orig );
|
2002-06-29 13:46:34 +00:00
|
|
|
|
1998-06-29 12:30:57 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2002-10-23 15:59:45 +00:00
|
|
|
/* Walk a secret keyblock and produce a public keyblock out of it. */
|
|
|
|
static KBNODE
|
|
|
|
sec_to_pub_keyblock(KBNODE sec_keyblock)
|
|
|
|
{
|
|
|
|
KBNODE secnode,pub_keyblock=NULL,ctx=NULL;
|
|
|
|
|
|
|
|
while((secnode=walk_kbnode(sec_keyblock,&ctx,0)))
|
|
|
|
{
|
|
|
|
KBNODE pubnode;
|
|
|
|
|
|
|
|
if(secnode->pkt->pkttype==PKT_SECRET_KEY ||
|
|
|
|
secnode->pkt->pkttype==PKT_SECRET_SUBKEY)
|
|
|
|
{
|
|
|
|
/* Make a public key. We only need to convert enough to
|
|
|
|
write the keyblock out. */
|
|
|
|
|
|
|
|
PKT_secret_key *sk=secnode->pkt->pkt.secret_key;
|
2005-07-27 18:10:56 +00:00
|
|
|
PACKET *pkt=xmalloc_clear(sizeof(PACKET));
|
|
|
|
PKT_public_key *pk=xmalloc_clear(sizeof(PKT_public_key));
|
2002-10-23 15:59:45 +00:00
|
|
|
int n;
|
|
|
|
|
|
|
|
if(secnode->pkt->pkttype==PKT_SECRET_KEY)
|
|
|
|
pkt->pkttype=PKT_PUBLIC_KEY;
|
|
|
|
else
|
|
|
|
pkt->pkttype=PKT_PUBLIC_SUBKEY;
|
|
|
|
|
|
|
|
pkt->pkt.public_key=pk;
|
|
|
|
|
|
|
|
pk->version=sk->version;
|
|
|
|
pk->timestamp=sk->timestamp;
|
|
|
|
pk->expiredate=sk->expiredate;
|
|
|
|
pk->pubkey_algo=sk->pubkey_algo;
|
|
|
|
|
|
|
|
n=pubkey_get_npkey(pk->pubkey_algo);
|
|
|
|
if(n==0)
|
2004-02-14 01:54:12 +00:00
|
|
|
{
|
|
|
|
/* we can't properly extract the pubkey without knowing
|
|
|
|
the number of MPIs */
|
|
|
|
release_kbnode(pub_keyblock);
|
|
|
|
return NULL;
|
|
|
|
}
|
2002-10-23 15:59:45 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i=0;i<n;i++)
|
|
|
|
pk->pkey[i]=mpi_copy(sk->skey[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
pubnode=new_kbnode(pkt);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pubnode=clone_kbnode(secnode);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pub_keyblock==NULL)
|
|
|
|
pub_keyblock=pubnode;
|
|
|
|
else
|
|
|
|
add_kbnode(pub_keyblock,pubnode);
|
|
|
|
}
|
|
|
|
|
|
|
|
return pub_keyblock;
|
|
|
|
}
|
1998-06-29 12:30:57 +00:00
|
|
|
|
|
|
|
/****************
|
|
|
|
* Ditto for secret keys. Handling is simpler than for public keys.
|
2002-06-29 13:46:34 +00:00
|
|
|
* We allow secret key importing only when allow is true, this is so
|
|
|
|
* that a secret key can not be imported accidently and thereby tampering
|
|
|
|
* with the trust calculation.
|
1998-06-29 12:30:57 +00:00
|
|
|
*/
|
|
|
|
static int
|
2002-06-29 13:46:34 +00:00
|
|
|
import_secret_one( const char *fname, KBNODE keyblock,
|
2002-10-23 15:59:45 +00:00
|
|
|
struct stats_s *stats, unsigned int options)
|
1998-06-29 12:30:57 +00:00
|
|
|
{
|
|
|
|
PKT_secret_key *sk;
|
|
|
|
KBNODE node, uidnode;
|
|
|
|
u32 keyid[2];
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
/* get the key and print some info about it */
|
|
|
|
node = find_kbnode( keyblock, PKT_SECRET_KEY );
|
|
|
|
if( !node )
|
|
|
|
BUG();
|
|
|
|
|
|
|
|
sk = node->pkt->pkt.secret_key;
|
|
|
|
keyid_from_sk( sk, keyid );
|
|
|
|
uidnode = find_next_kbnode( keyblock, PKT_USER_ID );
|
|
|
|
|
2004-03-15 20:00:42 +00:00
|
|
|
if( opt.verbose )
|
|
|
|
{
|
|
|
|
log_info( "sec %4u%c/%s %s ",
|
1998-06-29 12:30:57 +00:00
|
|
|
nbits_from_sk( sk ),
|
|
|
|
pubkey_letter( sk->pubkey_algo ),
|
2004-03-15 20:00:42 +00:00
|
|
|
keystr_from_sk(sk), datestr_from_sk(sk) );
|
1998-06-29 12:30:57 +00:00
|
|
|
if( uidnode )
|
2004-03-15 20:00:42 +00:00
|
|
|
print_utf8_string( stderr, uidnode->pkt->pkt.user_id->name,
|
|
|
|
uidnode->pkt->pkt.user_id->len );
|
1998-06-29 12:30:57 +00:00
|
|
|
putc('\n', stderr);
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
stats->secret_read++;
|
|
|
|
|
2004-03-15 20:00:42 +00:00
|
|
|
if( !uidnode )
|
|
|
|
{
|
|
|
|
log_error( _("key %s: no user ID\n"), keystr_from_sk(sk));
|
1998-06-29 12:30:57 +00:00
|
|
|
return 0;
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
1998-06-29 12:30:57 +00:00
|
|
|
|
2002-10-02 22:01:29 +00:00
|
|
|
if(sk->protect.algo>110)
|
|
|
|
{
|
2004-03-15 20:00:42 +00:00
|
|
|
log_error(_("key %s: secret key with invalid cipher %d"
|
|
|
|
" - skipped\n"),keystr_from_sk(sk),sk->protect.algo);
|
2002-10-02 22:01:29 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-10-14 10:48:15 +00:00
|
|
|
#ifdef ENABLE_SELINUX_HACKS
|
|
|
|
if (1)
|
|
|
|
{
|
|
|
|
/* We don't allow to import secret keys because that may be used
|
|
|
|
to put a secret key into the keyring and the user might later
|
|
|
|
be tricked into signing stuff with that key. */
|
|
|
|
log_error (_("importing secret keys not allowed\n"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1998-06-29 12:30:57 +00:00
|
|
|
clear_kbnode_flags( keyblock );
|
|
|
|
|
|
|
|
/* do we have this key already in one of our secrings ? */
|
|
|
|
rc = seckey_available( keyid );
|
2003-12-31 04:58:52 +00:00
|
|
|
if( rc == G10ERR_NO_SECKEY && !(opt.import_options&IMPORT_MERGE_ONLY) )
|
|
|
|
{
|
|
|
|
/* simply insert this key */
|
2002-06-29 13:46:34 +00:00
|
|
|
KEYDB_HANDLE hd = keydb_new (1);
|
|
|
|
|
|
|
|
/* get default resource */
|
|
|
|
rc = keydb_locate_writable (hd, NULL);
|
|
|
|
if (rc) {
|
2003-12-31 04:58:52 +00:00
|
|
|
log_error (_("no default secret keyring: %s\n"), g10_errstr (rc));
|
|
|
|
keydb_release (hd);
|
|
|
|
return G10ERR_GENERAL;
|
2002-06-29 13:46:34 +00:00
|
|
|
}
|
|
|
|
rc = keydb_insert_keyblock (hd, keyblock );
|
|
|
|
if (rc)
|
2003-12-31 04:58:52 +00:00
|
|
|
log_error (_("error writing keyring `%s': %s\n"),
|
|
|
|
keydb_get_resource_name (hd), g10_errstr(rc) );
|
2002-06-29 13:46:34 +00:00
|
|
|
keydb_release (hd);
|
1998-06-29 12:30:57 +00:00
|
|
|
/* we are ready */
|
1999-04-18 08:18:52 +00:00
|
|
|
if( !opt.quiet )
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: secret key imported\n"), keystr_from_sk(sk));
|
2002-06-29 13:46:34 +00:00
|
|
|
stats->secret_imported++;
|
2002-09-02 10:59:04 +00:00
|
|
|
if (is_status_enabled ())
|
2003-12-31 04:58:52 +00:00
|
|
|
print_import_ok (NULL, sk, 1|16);
|
2002-10-23 15:59:45 +00:00
|
|
|
|
|
|
|
if(options&IMPORT_SK2PK)
|
|
|
|
{
|
|
|
|
/* Try and make a public key out of this. */
|
|
|
|
|
|
|
|
KBNODE pub_keyblock=sec_to_pub_keyblock(keyblock);
|
2004-02-14 01:54:12 +00:00
|
|
|
if(pub_keyblock)
|
|
|
|
{
|
2006-03-14 02:23:00 +00:00
|
|
|
import_one(fname,pub_keyblock,stats,
|
2006-06-12 12:05:34 +00:00
|
|
|
NULL,NULL,opt.import_options,1);
|
2004-02-14 01:54:12 +00:00
|
|
|
release_kbnode(pub_keyblock);
|
|
|
|
}
|
2002-10-23 15:59:45 +00:00
|
|
|
}
|
|
|
|
|
2004-02-12 19:18:27 +00:00
|
|
|
/* Now that the key is definitely incorporated into the keydb,
|
|
|
|
if we have the public part of this key, we need to check if
|
|
|
|
the prefs are rational. */
|
|
|
|
node=get_pubkeyblock(keyid);
|
|
|
|
if(node)
|
|
|
|
{
|
|
|
|
check_prefs(node);
|
|
|
|
release_kbnode(node);
|
|
|
|
}
|
2003-12-31 04:58:52 +00:00
|
|
|
}
|
2004-03-15 20:00:42 +00:00
|
|
|
else if( !rc )
|
|
|
|
{ /* we can't merge secret keys */
|
|
|
|
log_error( _("key %s: already in secret keyring\n"),
|
|
|
|
keystr_from_sk(sk));
|
2002-06-29 13:46:34 +00:00
|
|
|
stats->secret_dups++;
|
2002-09-02 10:59:04 +00:00
|
|
|
if (is_status_enabled ())
|
2004-03-15 20:00:42 +00:00
|
|
|
print_import_ok (NULL, sk, 16);
|
2002-10-23 15:59:45 +00:00
|
|
|
|
|
|
|
/* TODO: if we ever do merge secret keys, make sure to handle
|
|
|
|
the sec_to_pub_keyblock feature as well. */
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
1998-06-29 12:30:57 +00:00
|
|
|
else
|
2004-03-15 20:00:42 +00:00
|
|
|
log_error( _("key %s: secret key not found: %s\n"),
|
|
|
|
keystr_from_sk(sk), g10_errstr(rc));
|
1998-06-29 12:30:57 +00:00
|
|
|
|
1998-02-16 20:05:02 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
1998-02-17 20:48:52 +00:00
|
|
|
|
1998-02-18 13:58:46 +00:00
|
|
|
/****************
|
1998-04-14 17:51:16 +00:00
|
|
|
* Import a revocation certificate; this is a single signature packet.
|
1998-02-18 13:58:46 +00:00
|
|
|
*/
|
|
|
|
static int
|
2002-06-29 13:46:34 +00:00
|
|
|
import_revoke_cert( const char *fname, KBNODE node, struct stats_s *stats )
|
1998-02-18 13:58:46 +00:00
|
|
|
{
|
1998-06-29 12:30:57 +00:00
|
|
|
PKT_public_key *pk=NULL;
|
1998-02-18 13:58:46 +00:00
|
|
|
KBNODE onode, keyblock = NULL;
|
2002-06-29 13:46:34 +00:00
|
|
|
KEYDB_HANDLE hd = NULL;
|
1998-02-18 13:58:46 +00:00
|
|
|
u32 keyid[2];
|
|
|
|
int rc = 0;
|
|
|
|
|
|
|
|
assert( !node->next );
|
|
|
|
assert( node->pkt->pkttype == PKT_SIGNATURE );
|
|
|
|
assert( node->pkt->pkt.signature->sig_class == 0x20 );
|
|
|
|
|
|
|
|
keyid[0] = node->pkt->pkt.signature->keyid[0];
|
|
|
|
keyid[1] = node->pkt->pkt.signature->keyid[1];
|
|
|
|
|
2005-07-27 18:10:56 +00:00
|
|
|
pk = xmalloc_clear( sizeof *pk );
|
1998-06-29 12:30:57 +00:00
|
|
|
rc = get_pubkey( pk, keyid );
|
2004-03-15 20:00:42 +00:00
|
|
|
if( rc == G10ERR_NO_PUBKEY )
|
|
|
|
{
|
|
|
|
log_error(_("key %s: no public key -"
|
|
|
|
" can't apply revocation certificate\n"), keystr(keyid));
|
1998-02-18 13:58:46 +00:00
|
|
|
rc = 0;
|
|
|
|
goto leave;
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
|
|
|
else if( rc )
|
|
|
|
{
|
|
|
|
log_error(_("key %s: public key not found: %s\n"),
|
|
|
|
keystr(keyid), g10_errstr(rc));
|
1998-02-18 13:58:46 +00:00
|
|
|
goto leave;
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
1998-02-18 13:58:46 +00:00
|
|
|
|
|
|
|
/* read the original keyblock */
|
2002-06-29 13:46:34 +00:00
|
|
|
hd = keydb_new (0);
|
|
|
|
{
|
|
|
|
byte afp[MAX_FINGERPRINT_LEN];
|
|
|
|
size_t an;
|
|
|
|
|
|
|
|
fingerprint_from_pk (pk, afp, &an);
|
|
|
|
while (an < MAX_FINGERPRINT_LEN)
|
|
|
|
afp[an++] = 0;
|
|
|
|
rc = keydb_search_fpr (hd, afp);
|
|
|
|
}
|
2004-03-15 20:00:42 +00:00
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
log_error (_("key %s: can't locate original keyblock: %s\n"),
|
|
|
|
keystr(keyid), g10_errstr(rc));
|
2002-06-29 13:46:34 +00:00
|
|
|
goto leave;
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
rc = keydb_get_keyblock (hd, &keyblock );
|
2004-03-15 20:00:42 +00:00
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
log_error (_("key %s: can't read original keyblock: %s\n"),
|
|
|
|
keystr(keyid), g10_errstr(rc));
|
1998-02-18 13:58:46 +00:00
|
|
|
goto leave;
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
1998-02-18 13:58:46 +00:00
|
|
|
|
|
|
|
/* it is okay, that node is not in keyblock because
|
|
|
|
* check_key_signature works fine for sig_class 0x20 in this
|
|
|
|
* special case. */
|
|
|
|
rc = check_key_signature( keyblock, node, NULL);
|
2004-03-15 20:00:42 +00:00
|
|
|
if( rc )
|
|
|
|
{
|
|
|
|
log_error( _("key %s: invalid revocation certificate"
|
|
|
|
": %s - rejected\n"), keystr(keyid), g10_errstr(rc));
|
2002-06-29 13:46:34 +00:00
|
|
|
goto leave;
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
1998-02-18 13:58:46 +00:00
|
|
|
|
1998-04-14 17:51:16 +00:00
|
|
|
/* check whether we already have this */
|
1998-02-18 13:58:46 +00:00
|
|
|
for(onode=keyblock->next; onode; onode=onode->next ) {
|
|
|
|
if( onode->pkt->pkttype == PKT_USER_ID )
|
|
|
|
break;
|
|
|
|
else if( onode->pkt->pkttype == PKT_SIGNATURE
|
2003-08-13 03:31:36 +00:00
|
|
|
&& !cmp_signatures(node->pkt->pkt.signature,
|
|
|
|
onode->pkt->pkt.signature))
|
|
|
|
{
|
1998-02-18 13:58:46 +00:00
|
|
|
rc = 0;
|
|
|
|
goto leave; /* yes, we already know about it */
|
2003-08-13 03:31:36 +00:00
|
|
|
}
|
1998-02-18 13:58:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* insert it */
|
|
|
|
insert_kbnode( keyblock, clone_kbnode(node), 0 );
|
|
|
|
|
|
|
|
/* and write the keyblock back */
|
2002-06-29 13:46:34 +00:00
|
|
|
rc = keydb_update_keyblock (hd, keyblock );
|
|
|
|
if (rc)
|
|
|
|
log_error (_("error writing keyring `%s': %s\n"),
|
|
|
|
keydb_get_resource_name (hd), g10_errstr(rc) );
|
|
|
|
keydb_release (hd); hd = NULL;
|
1998-02-18 13:58:46 +00:00
|
|
|
/* we are ready */
|
2004-03-15 20:00:42 +00:00
|
|
|
if( !opt.quiet )
|
|
|
|
{
|
2004-08-23 17:55:49 +00:00
|
|
|
char *p=get_user_id_native (keyid);
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: \"%s\" revocation certificate imported\n"),
|
|
|
|
keystr(keyid),p);
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree(p);
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
stats->n_revoc++;
|
2003-04-23 21:18:39 +00:00
|
|
|
|
|
|
|
/* If the key we just revoked was ultimately trusted, remove its
|
|
|
|
ultimate trust. This doesn't stop the user from putting the
|
|
|
|
ultimate trust back, but is a reasonable solution for now. */
|
|
|
|
if(get_ownertrust(pk)==TRUST_ULTIMATE)
|
|
|
|
clear_ownertrusts(pk);
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
revalidation_mark ();
|
1998-02-18 13:58:46 +00:00
|
|
|
|
|
|
|
leave:
|
2002-06-29 13:46:34 +00:00
|
|
|
keydb_release (hd);
|
1998-02-18 13:58:46 +00:00
|
|
|
release_kbnode( keyblock );
|
1998-06-29 12:30:57 +00:00
|
|
|
free_public_key( pk );
|
1998-02-18 13:58:46 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-16 20:05:02 +00:00
|
|
|
/****************
|
1998-04-14 17:51:16 +00:00
|
|
|
* loop over the keyblock and check all self signatures.
|
1998-02-16 20:05:02 +00:00
|
|
|
* Mark all user-ids with a self-signature by setting flag bit 0.
|
|
|
|
* Mark all user-ids with an invalid self-signature by setting bit 1.
|
2002-08-22 17:47:42 +00:00
|
|
|
* This works also for subkeys, here the subkey is marked. Invalid or
|
|
|
|
* extra subkey sigs (binding or revocation) are marked for deletion.
|
2002-12-13 21:10:53 +00:00
|
|
|
* non_self is set to true if there are any sigs other than self-sigs
|
|
|
|
* in this keyblock.
|
1998-02-16 20:05:02 +00:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
chk_self_sigs( const char *fname, KBNODE keyblock,
|
2002-12-13 21:10:53 +00:00
|
|
|
PKT_public_key *pk, u32 *keyid, int *non_self )
|
1998-02-16 20:05:02 +00:00
|
|
|
{
|
2002-08-22 17:47:42 +00:00
|
|
|
KBNODE n,knode=NULL;
|
1998-02-16 20:05:02 +00:00
|
|
|
PKT_signature *sig;
|
|
|
|
int rc;
|
2002-08-22 17:47:42 +00:00
|
|
|
u32 bsdate=0,rsdate=0;
|
|
|
|
KBNODE bsnode=NULL,rsnode=NULL;
|
1998-02-16 20:05:02 +00:00
|
|
|
|
|
|
|
for( n=keyblock; (n = find_next_kbnode(n, 0)); ) {
|
2002-08-22 17:47:42 +00:00
|
|
|
if(n->pkt->pkttype==PKT_PUBLIC_SUBKEY)
|
|
|
|
{
|
|
|
|
knode=n;
|
|
|
|
bsdate=0;
|
|
|
|
rsdate=0;
|
|
|
|
bsnode=NULL;
|
|
|
|
rsnode=NULL;
|
2002-12-13 21:10:53 +00:00
|
|
|
continue;
|
2002-08-22 17:47:42 +00:00
|
|
|
}
|
|
|
|
else if( n->pkt->pkttype != PKT_SIGNATURE )
|
1998-02-16 20:05:02 +00:00
|
|
|
continue;
|
|
|
|
sig = n->pkt->pkt.signature;
|
|
|
|
if( keyid[0] == sig->keyid[0] && keyid[1] == sig->keyid[1] ) {
|
2002-12-11 17:50:38 +00:00
|
|
|
|
2005-07-09 02:34:04 +00:00
|
|
|
/* This just caches the sigs for later use. That way we
|
|
|
|
import a fully-cached key which speeds things up. */
|
|
|
|
if(!opt.no_sig_cache)
|
|
|
|
check_key_signature(keyblock,n,NULL);
|
2002-12-11 17:50:38 +00:00
|
|
|
|
2005-07-09 02:34:04 +00:00
|
|
|
if( IS_UID_SIG(sig) || IS_UID_REV(sig) )
|
|
|
|
{
|
1999-01-12 10:20:24 +00:00
|
|
|
KBNODE unode = find_prev_kbnode( keyblock, n, PKT_USER_ID );
|
2004-03-15 20:00:42 +00:00
|
|
|
if( !unode )
|
|
|
|
{
|
|
|
|
log_error( _("key %s: no user ID for signature\n"),
|
|
|
|
keystr(keyid));
|
1999-01-12 10:20:24 +00:00
|
|
|
return -1; /* the complete keyblock is invalid */
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
1999-01-12 10:20:24 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
/* If it hasn't been marked valid yet, keep trying */
|
|
|
|
if(!(unode->flag&1)) {
|
|
|
|
rc = check_key_signature( keyblock, n, NULL);
|
|
|
|
if( rc )
|
|
|
|
{
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if( opt.verbose )
|
|
|
|
{
|
|
|
|
char *p=utf8_to_native(unode->pkt->pkt.user_id->name,
|
2002-06-29 13:46:34 +00:00
|
|
|
strlen(unode->pkt->pkt.user_id->name),0);
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
log_info( rc == G10ERR_PUBKEY_ALGO ?
|
2004-03-15 20:00:42 +00:00
|
|
|
_("key %s: unsupported public key "
|
* main.h: Create S2K_DIGEST_ALGO macro so we do not need to always set
opt.s2k_digest_algo. This helps fix a problem with PGP 2.x encrypted
symmetric messages. Change all callers (encode.c, g10.c, keyedit.c,
keygen.c, passphrase.c, sign.c).
* armor.c, cardglue.c, getkey.c, import.c, keygen.c: Be consistent in some
more quoted strings. Always use 'user ID', not 'user id', "quotes" for
user IDs, etc.
2004-09-24 20:34:38 +00:00
|
|
|
"algorithm on user ID \"%s\"\n"):
|
2004-03-15 20:00:42 +00:00
|
|
|
_("key %s: invalid self-signature "
|
* main.h: Create S2K_DIGEST_ALGO macro so we do not need to always set
opt.s2k_digest_algo. This helps fix a problem with PGP 2.x encrypted
symmetric messages. Change all callers (encode.c, g10.c, keyedit.c,
keygen.c, passphrase.c, sign.c).
* armor.c, cardglue.c, getkey.c, import.c, keygen.c: Be consistent in some
more quoted strings. Always use 'user ID', not 'user id', "quotes" for
user IDs, etc.
2004-09-24 20:34:38 +00:00
|
|
|
"on user ID \"%s\"\n"),
|
2004-03-15 20:00:42 +00:00
|
|
|
keystr(keyid),p);
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree(p);
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
unode->flag |= 1; /* mark that signature checked */
|
1999-01-12 10:20:24 +00:00
|
|
|
}
|
2005-07-09 02:34:04 +00:00
|
|
|
}
|
1999-01-12 10:20:24 +00:00
|
|
|
else if( sig->sig_class == 0x18 ) {
|
2002-08-22 17:47:42 +00:00
|
|
|
/* Note that this works based solely on the timestamps
|
|
|
|
like the rest of gpg. If the standard gets
|
|
|
|
revocation targets, this may need to be revised. */
|
1999-01-12 10:20:24 +00:00
|
|
|
|
2004-03-15 20:00:42 +00:00
|
|
|
if( !knode )
|
|
|
|
{
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if(opt.verbose)
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: no subkey for key binding\n"),
|
|
|
|
keystr(keyid));
|
1999-02-19 14:54:00 +00:00
|
|
|
n->flag |= 4; /* delete this */
|
2002-08-22 17:47:42 +00:00
|
|
|
}
|
2004-03-15 20:00:42 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
rc = check_key_signature( keyblock, n, NULL);
|
|
|
|
if( rc )
|
|
|
|
{
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if(opt.verbose)
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info(rc == G10ERR_PUBKEY_ALGO ?
|
|
|
|
_("key %s: unsupported public key"
|
|
|
|
" algorithm\n"):
|
|
|
|
_("key %s: invalid subkey binding\n"),
|
|
|
|
keystr(keyid));
|
|
|
|
n->flag|=4;
|
2002-08-22 17:47:42 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
else
|
2004-03-15 20:00:42 +00:00
|
|
|
{
|
|
|
|
/* It's valid, so is it newer? */
|
|
|
|
if(sig->timestamp>=bsdate) {
|
|
|
|
knode->flag |= 1; /* the subkey is valid */
|
|
|
|
if(bsnode)
|
|
|
|
{
|
|
|
|
bsnode->flag|=4; /* Delete the last binding
|
|
|
|
sig since this one is
|
|
|
|
newer */
|
|
|
|
if(opt.verbose)
|
|
|
|
log_info(_("key %s: removed multiple subkey"
|
|
|
|
" binding\n"),keystr(keyid));
|
|
|
|
}
|
|
|
|
|
|
|
|
bsnode=n;
|
|
|
|
bsdate=sig->timestamp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
n->flag|=4; /* older */
|
|
|
|
}
|
2002-08-22 17:47:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( sig->sig_class == 0x28 ) {
|
|
|
|
/* We don't actually mark the subkey as revoked right
|
|
|
|
now, so just check that the revocation sig is the
|
|
|
|
most recent valid one. Note that we don't care if
|
|
|
|
the binding sig is newer than the revocation sig.
|
|
|
|
See the comment in getkey.c:merge_selfsigs_subkey for
|
|
|
|
more */
|
2004-03-15 20:00:42 +00:00
|
|
|
if( !knode )
|
|
|
|
{
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if(opt.verbose)
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: no subkey for key revocation\n"),
|
|
|
|
keystr(keyid));
|
2002-08-22 17:47:42 +00:00
|
|
|
n->flag |= 4; /* delete this */
|
|
|
|
}
|
2004-03-15 20:00:42 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
rc = check_key_signature( keyblock, n, NULL);
|
|
|
|
if( rc )
|
|
|
|
{
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if(opt.verbose)
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info(rc == G10ERR_PUBKEY_ALGO ?
|
|
|
|
_("key %s: unsupported public"
|
|
|
|
" key algorithm\n"):
|
|
|
|
_("key %s: invalid subkey revocation\n"),
|
|
|
|
keystr(keyid));
|
|
|
|
n->flag|=4;
|
2002-08-22 17:47:42 +00:00
|
|
|
}
|
|
|
|
else
|
2004-03-15 20:00:42 +00:00
|
|
|
{
|
|
|
|
/* It's valid, so is it newer? */
|
|
|
|
if(sig->timestamp>=rsdate)
|
|
|
|
{
|
|
|
|
if(rsnode)
|
|
|
|
{
|
|
|
|
rsnode->flag|=4; /* Delete the last revocation
|
|
|
|
sig since this one is
|
|
|
|
newer */
|
|
|
|
if(opt.verbose)
|
|
|
|
log_info(_("key %s: removed multiple subkey"
|
|
|
|
" revocation\n"),keystr(keyid));
|
|
|
|
}
|
|
|
|
|
|
|
|
rsnode=n;
|
|
|
|
rsdate=sig->timestamp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
n->flag|=4; /* older */
|
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
}
|
1998-02-16 20:05:02 +00:00
|
|
|
}
|
|
|
|
}
|
2002-12-13 21:10:53 +00:00
|
|
|
else
|
|
|
|
*non_self=1;
|
1998-02-16 20:05:02 +00:00
|
|
|
}
|
2002-08-22 17:47:42 +00:00
|
|
|
|
1998-01-19 18:54:44 +00:00
|
|
|
return 0;
|
1998-01-16 21:15:24 +00:00
|
|
|
}
|
|
|
|
|
1998-02-16 20:05:02 +00:00
|
|
|
/****************
|
1998-04-14 17:51:16 +00:00
|
|
|
* delete all parts which are invalid and those signatures whose
|
|
|
|
* public key algorithm is not available in this implemenation;
|
1998-02-17 20:48:52 +00:00
|
|
|
* but consider RSA as valid, because parse/build_packets knows
|
|
|
|
* about it.
|
1998-02-16 20:05:02 +00:00
|
|
|
* returns: true if at least one valid user-id is left over.
|
|
|
|
*/
|
|
|
|
static int
|
* main.h, import.c (parse_import_options, fix_hkp_corruption, import_one,
delete_inv_parts), g10.c (main): New import-option
"repair-hkp-subkey-bug", which repairs as much as possible the HKP
mangling multiple subkeys bug. It is on by default for keyserver
receives, and off by default for regular --import.
* main.h, import.c (import, import_one, delete_inv_parts), hkp.c
(hkp_ask_import), keyserver.c (keyserver_spawn): Use keyserver import
options when doing keyserver receives.
2002-07-24 21:17:19 +00:00
|
|
|
delete_inv_parts( const char *fname, KBNODE keyblock,
|
|
|
|
u32 *keyid, unsigned int options)
|
1998-02-16 20:05:02 +00:00
|
|
|
{
|
|
|
|
KBNODE node;
|
2002-07-24 03:29:02 +00:00
|
|
|
int nvalid=0, uid_seen=0, subkey_seen=0;
|
1998-01-16 21:15:24 +00:00
|
|
|
|
1998-02-16 20:05:02 +00:00
|
|
|
for(node=keyblock->next; node; node = node->next ) {
|
|
|
|
if( node->pkt->pkttype == PKT_USER_ID ) {
|
1998-02-18 13:58:46 +00:00
|
|
|
uid_seen = 1;
|
1998-02-16 20:05:02 +00:00
|
|
|
if( (node->flag & 2) || !(node->flag & 1) ) {
|
2004-03-15 20:00:42 +00:00
|
|
|
if( opt.verbose )
|
|
|
|
{
|
|
|
|
char *p=utf8_to_native(node->pkt->pkt.user_id->name,
|
|
|
|
node->pkt->pkt.user_id->len,0);
|
* main.h: Create S2K_DIGEST_ALGO macro so we do not need to always set
opt.s2k_digest_algo. This helps fix a problem with PGP 2.x encrypted
symmetric messages. Change all callers (encode.c, g10.c, keyedit.c,
keygen.c, passphrase.c, sign.c).
* armor.c, cardglue.c, getkey.c, import.c, keygen.c: Be consistent in some
more quoted strings. Always use 'user ID', not 'user id', "quotes" for
user IDs, etc.
2004-09-24 20:34:38 +00:00
|
|
|
log_info( _("key %s: skipped user ID \"%s\"\n"),
|
2004-03-15 20:00:42 +00:00
|
|
|
keystr(keyid),p);
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree(p);
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
1998-02-16 20:05:02 +00:00
|
|
|
delete_kbnode( node ); /* the user-id */
|
|
|
|
/* and all following packets up to the next user-id */
|
1999-04-07 18:58:34 +00:00
|
|
|
while( node->next
|
|
|
|
&& node->next->pkt->pkttype != PKT_USER_ID
|
|
|
|
&& node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY
|
|
|
|
&& node->next->pkt->pkttype != PKT_SECRET_SUBKEY ){
|
1998-02-16 20:05:02 +00:00
|
|
|
delete_kbnode( node->next );
|
|
|
|
node = node->next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
nvalid++;
|
|
|
|
}
|
1999-01-12 10:20:24 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
|
|
|
|
if( (node->flag & 2) || !(node->flag & 1) ) {
|
2004-03-15 20:00:42 +00:00
|
|
|
if( opt.verbose )
|
|
|
|
log_info( _("key %s: skipped subkey\n"),keystr(keyid));
|
|
|
|
|
1999-01-12 10:20:24 +00:00
|
|
|
delete_kbnode( node ); /* the subkey */
|
|
|
|
/* and all following signature packets */
|
|
|
|
while( node->next
|
|
|
|
&& node->next->pkt->pkttype == PKT_SIGNATURE ) {
|
|
|
|
delete_kbnode( node->next );
|
|
|
|
node = node->next;
|
|
|
|
}
|
|
|
|
}
|
2002-07-24 03:29:02 +00:00
|
|
|
else
|
|
|
|
subkey_seen = 1;
|
1999-01-12 10:20:24 +00:00
|
|
|
}
|
1998-02-17 20:48:52 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_SIGNATURE
|
2002-06-29 13:46:34 +00:00
|
|
|
&& check_pubkey_algo( node->pkt->pkt.signature->pubkey_algo)
|
|
|
|
&& node->pkt->pkt.signature->pubkey_algo != PUBKEY_ALGO_RSA )
|
1998-02-17 20:48:52 +00:00
|
|
|
delete_kbnode( node ); /* build_packet() can't handle this */
|
2002-06-29 13:46:34 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_SIGNATURE &&
|
|
|
|
!node->pkt->pkt.signature->flags.exportable &&
|
2004-11-26 15:51:37 +00:00
|
|
|
!(options&IMPORT_LOCAL_SIGS) &&
|
2004-03-15 20:00:42 +00:00
|
|
|
seckey_available( node->pkt->pkt.signature->keyid ) )
|
|
|
|
{
|
1999-04-06 18:04:55 +00:00
|
|
|
/* here we violate the rfc a bit by still allowing
|
|
|
|
* to import non-exportable signature when we have the
|
|
|
|
* the secret key used to create this signature - it
|
|
|
|
* seems that this makes sense */
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if(opt.verbose)
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: non exportable signature"
|
* main.h: Create S2K_DIGEST_ALGO macro so we do not need to always set
opt.s2k_digest_algo. This helps fix a problem with PGP 2.x encrypted
symmetric messages. Change all callers (encode.c, g10.c, keyedit.c,
keygen.c, passphrase.c, sign.c).
* armor.c, cardglue.c, getkey.c, import.c, keygen.c: Be consistent in some
more quoted strings. Always use 'user ID', not 'user id', "quotes" for
user IDs, etc.
2004-09-24 20:34:38 +00:00
|
|
|
" (class 0x%02X) - skipped\n"),
|
2004-03-15 20:00:42 +00:00
|
|
|
keystr(keyid), node->pkt->pkt.signature->sig_class );
|
1999-03-11 15:42:06 +00:00
|
|
|
delete_kbnode( node );
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
1998-02-18 13:58:46 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
&& node->pkt->pkt.signature->sig_class == 0x20 ) {
|
2004-03-15 20:00:42 +00:00
|
|
|
if( uid_seen )
|
|
|
|
{
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if(opt.verbose)
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: revocation certificate"
|
|
|
|
" at wrong place - skipped\n"),keystr(keyid));
|
1998-02-18 13:58:46 +00:00
|
|
|
delete_kbnode( node );
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
1998-02-18 13:58:46 +00:00
|
|
|
else {
|
2002-06-29 13:46:34 +00:00
|
|
|
/* If the revocation cert is from a different key than
|
|
|
|
the one we're working on don't check it - it's
|
|
|
|
probably from a revocation key and won't be
|
|
|
|
verifiable with this key anyway. */
|
|
|
|
|
|
|
|
if(node->pkt->pkt.signature->keyid[0]==keyid[0] &&
|
|
|
|
node->pkt->pkt.signature->keyid[1]==keyid[1])
|
|
|
|
{
|
|
|
|
int rc = check_key_signature( keyblock, node, NULL);
|
|
|
|
if( rc )
|
|
|
|
{
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if(opt.verbose)
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: invalid revocation"
|
|
|
|
" certificate: %s - skipped\n"),
|
|
|
|
keystr(keyid), g10_errstr(rc));
|
2002-06-29 13:46:34 +00:00
|
|
|
delete_kbnode( node );
|
|
|
|
}
|
1998-02-18 13:58:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-07-24 03:29:02 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_SIGNATURE &&
|
|
|
|
(node->pkt->pkt.signature->sig_class == 0x18 ||
|
|
|
|
node->pkt->pkt.signature->sig_class == 0x28) &&
|
2004-03-15 20:00:42 +00:00
|
|
|
!subkey_seen )
|
|
|
|
{
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if(opt.verbose)
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: subkey signature"
|
|
|
|
" in wrong place - skipped\n"), keystr(keyid));
|
2002-07-24 03:29:02 +00:00
|
|
|
delete_kbnode( node );
|
2004-03-15 20:00:42 +00:00
|
|
|
}
|
2003-03-24 20:05:53 +00:00
|
|
|
else if( node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
&& !IS_CERT(node->pkt->pkt.signature))
|
|
|
|
{
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if(opt.verbose)
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info(_("key %s: unexpected signature class (0x%02X) -"
|
|
|
|
" skipped\n"),keystr(keyid),
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
node->pkt->pkt.signature->sig_class);
|
2003-03-24 20:05:53 +00:00
|
|
|
delete_kbnode(node);
|
|
|
|
}
|
1999-02-19 14:54:00 +00:00
|
|
|
else if( (node->flag & 4) ) /* marked for deletion */
|
2005-01-01 21:21:11 +00:00
|
|
|
delete_kbnode( node );
|
1998-02-16 20:05:02 +00:00
|
|
|
}
|
|
|
|
|
1998-02-17 20:48:52 +00:00
|
|
|
/* note: because keyblock is the public key, it is never marked
|
|
|
|
* for deletion and so keyblock cannot change */
|
1998-02-16 20:05:02 +00:00
|
|
|
commit_kbnode( &keyblock );
|
|
|
|
return nvalid;
|
|
|
|
}
|
1998-02-17 20:48:52 +00:00
|
|
|
|
|
|
|
|
1999-05-19 14:12:26 +00:00
|
|
|
/****************
|
|
|
|
* It may happen that the imported keyblock has duplicated user IDs.
|
|
|
|
* We check this here and collapse those user IDs together with their
|
|
|
|
* sigs into one.
|
2007-09-02 14:09:24 +00:00
|
|
|
* Returns: True if the keyblock has changed.
|
1999-05-19 14:12:26 +00:00
|
|
|
*/
|
1999-05-22 20:54:54 +00:00
|
|
|
int
|
|
|
|
collapse_uids( KBNODE *keyblock )
|
1999-05-19 14:12:26 +00:00
|
|
|
{
|
2007-09-02 14:09:24 +00:00
|
|
|
KBNODE uid1;
|
|
|
|
int any=0;
|
1999-05-19 14:12:26 +00:00
|
|
|
|
2007-09-02 14:09:24 +00:00
|
|
|
for(uid1=*keyblock;uid1;uid1=uid1->next)
|
|
|
|
{
|
|
|
|
KBNODE uid2;
|
|
|
|
|
|
|
|
if(uid1->pkt->pkttype!=PKT_USER_ID)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for(uid2=uid1->next;uid2;uid2=uid2->next)
|
|
|
|
{
|
|
|
|
if(uid2->pkt->pkttype!=PKT_USER_ID)
|
1999-05-22 20:54:54 +00:00
|
|
|
continue;
|
2007-09-02 14:09:24 +00:00
|
|
|
|
|
|
|
if(cmp_user_ids(uid1->pkt->pkt.user_id,
|
|
|
|
uid2->pkt->pkt.user_id)==0)
|
|
|
|
{
|
|
|
|
/* We have a duplicated uid */
|
|
|
|
KBNODE sig1,last;
|
|
|
|
|
|
|
|
any=1;
|
|
|
|
|
|
|
|
/* Now take uid2's signatures, and attach them to
|
|
|
|
uid1 */
|
|
|
|
for(last=uid2;last->next;last=last->next)
|
|
|
|
{
|
|
|
|
if(last->next->pkt->pkttype==PKT_USER_ID
|
|
|
|
|| last->next->pkt->pkttype==PKT_PUBLIC_SUBKEY
|
|
|
|
|| last->next->pkt->pkttype==PKT_SECRET_SUBKEY)
|
|
|
|
break;
|
1999-05-19 14:12:26 +00:00
|
|
|
}
|
|
|
|
|
2007-09-02 14:09:24 +00:00
|
|
|
/* Snip out uid2 */
|
|
|
|
(find_prev_kbnode(*keyblock,uid2,0))->next=last->next;
|
|
|
|
|
|
|
|
/* Now put uid2 in place as part of uid1 */
|
|
|
|
last->next=uid1->next;
|
|
|
|
uid1->next=uid2;
|
|
|
|
remove_kbnode(keyblock,uid2);
|
|
|
|
|
|
|
|
/* Now dedupe uid1 */
|
|
|
|
for(sig1=uid1->next;sig1;sig1=sig1->next)
|
|
|
|
{
|
|
|
|
KBNODE sig2;
|
|
|
|
|
|
|
|
if(sig1->pkt->pkttype==PKT_USER_ID
|
|
|
|
|| sig1->pkt->pkttype==PKT_PUBLIC_SUBKEY
|
|
|
|
|| sig1->pkt->pkttype==PKT_SECRET_SUBKEY)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(sig1->pkt->pkttype!=PKT_SIGNATURE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for(sig2=sig1->next,last=sig1;sig2;last=sig2,sig2=sig2->next)
|
|
|
|
{
|
|
|
|
if(sig2->pkt->pkttype==PKT_USER_ID
|
|
|
|
|| sig2->pkt->pkttype==PKT_PUBLIC_SUBKEY
|
|
|
|
|| sig2->pkt->pkttype==PKT_SECRET_SUBKEY)
|
1999-05-22 20:54:54 +00:00
|
|
|
break;
|
2007-09-02 14:09:24 +00:00
|
|
|
|
|
|
|
if(sig2->pkt->pkttype!=PKT_SIGNATURE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if(cmp_signatures(sig1->pkt->pkt.signature,
|
|
|
|
sig2->pkt->pkt.signature)==0)
|
|
|
|
{
|
|
|
|
/* We have a match, so delete the second
|
|
|
|
signature */
|
|
|
|
remove_kbnode(&uid1,sig2);
|
|
|
|
sig2=last;
|
|
|
|
}
|
1999-05-22 20:54:54 +00:00
|
|
|
}
|
|
|
|
}
|
2007-09-02 14:09:24 +00:00
|
|
|
}
|
1999-05-22 20:54:54 +00:00
|
|
|
}
|
|
|
|
}
|
1999-05-19 14:12:26 +00:00
|
|
|
|
2007-09-02 14:09:24 +00:00
|
|
|
if(any && !opt.quiet)
|
|
|
|
{
|
|
|
|
const char *key="???";
|
2004-03-15 20:00:42 +00:00
|
|
|
|
2007-09-02 14:09:24 +00:00
|
|
|
if( (uid1=find_kbnode( *keyblock, PKT_PUBLIC_KEY )) )
|
|
|
|
key=keystr_from_pk(uid1->pkt->pkt.public_key);
|
|
|
|
else if( (uid1 = find_kbnode( *keyblock, PKT_SECRET_KEY )) )
|
|
|
|
key=keystr_from_sk(uid1->pkt->pkt.secret_key);
|
2004-03-15 20:00:42 +00:00
|
|
|
|
2007-09-02 14:09:24 +00:00
|
|
|
log_info(_("key %s: duplicated user ID detected - merged\n"),key);
|
|
|
|
}
|
1999-05-19 14:12:26 +00:00
|
|
|
|
2007-09-02 14:09:24 +00:00
|
|
|
return any;
|
1999-05-19 14:12:26 +00:00
|
|
|
}
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
/* Check for a 0x20 revocation from a revocation key that is not
|
2004-02-12 16:31:07 +00:00
|
|
|
present. This may be called without the benefit of merge_xxxx so
|
|
|
|
you can't rely on pk->revkey and friends. */
|
2002-06-29 13:46:34 +00:00
|
|
|
static void
|
|
|
|
revocation_present(KBNODE keyblock)
|
|
|
|
{
|
|
|
|
KBNODE onode,inode;
|
|
|
|
PKT_public_key *pk=keyblock->pkt->pkt.public_key;
|
|
|
|
|
|
|
|
for(onode=keyblock->next;onode;onode=onode->next)
|
|
|
|
{
|
|
|
|
/* If we reach user IDs, we're done. */
|
|
|
|
if(onode->pkt->pkttype==PKT_USER_ID)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(onode->pkt->pkttype==PKT_SIGNATURE &&
|
|
|
|
onode->pkt->pkt.signature->sig_class==0x1F &&
|
|
|
|
onode->pkt->pkt.signature->revkey)
|
|
|
|
{
|
|
|
|
int idx;
|
|
|
|
PKT_signature *sig=onode->pkt->pkt.signature;
|
|
|
|
|
|
|
|
for(idx=0;idx<sig->numrevkeys;idx++)
|
|
|
|
{
|
|
|
|
u32 keyid[2];
|
|
|
|
|
|
|
|
keyid_from_fingerprint(sig->revkey[idx]->fpr,
|
|
|
|
MAX_FINGERPRINT_LEN,keyid);
|
|
|
|
|
|
|
|
for(inode=keyblock->next;inode;inode=inode->next)
|
|
|
|
{
|
|
|
|
/* If we reach user IDs, we're done. */
|
|
|
|
if(inode->pkt->pkttype==PKT_USER_ID)
|
|
|
|
break;
|
1999-05-19 14:12:26 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
if(inode->pkt->pkttype==PKT_SIGNATURE &&
|
|
|
|
inode->pkt->pkt.signature->sig_class==0x20 &&
|
|
|
|
inode->pkt->pkt.signature->keyid[0]==keyid[0] &&
|
|
|
|
inode->pkt->pkt.signature->keyid[1]==keyid[1])
|
|
|
|
{
|
|
|
|
/* Okay, we have a revocation key, and a
|
|
|
|
revocation issued by it. Do we have the key
|
|
|
|
itself? */
|
|
|
|
int rc;
|
|
|
|
|
2002-11-13 17:43:27 +00:00
|
|
|
rc=get_pubkey_byfprint_fast (NULL,sig->revkey[idx]->fpr,
|
|
|
|
MAX_FINGERPRINT_LEN);
|
2002-06-29 13:46:34 +00:00
|
|
|
if(rc==G10ERR_NO_PUBKEY || rc==G10ERR_UNU_PUBKEY)
|
|
|
|
{
|
2005-07-27 18:10:56 +00:00
|
|
|
char *tempkeystr=xstrdup(keystr_from_pk(pk));
|
2004-03-15 20:00:42 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
/* No, so try and get it */
|
2004-04-14 21:33:45 +00:00
|
|
|
if(opt.keyserver
|
2004-04-15 18:16:17 +00:00
|
|
|
&& (opt.keyserver_options.options
|
|
|
|
& KEYSERVER_AUTO_KEY_RETRIEVE))
|
2002-06-29 13:46:34 +00:00
|
|
|
{
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info(_("WARNING: key %s may be revoked:"
|
|
|
|
" fetching revocation key %s\n"),
|
|
|
|
tempkeystr,keystr(keyid));
|
2002-06-29 13:46:34 +00:00
|
|
|
keyserver_import_fprint(sig->revkey[idx]->fpr,
|
2004-09-11 15:42:19 +00:00
|
|
|
MAX_FINGERPRINT_LEN,
|
|
|
|
opt.keyserver);
|
2002-06-29 13:46:34 +00:00
|
|
|
|
|
|
|
/* Do we have it now? */
|
2002-11-13 17:43:27 +00:00
|
|
|
rc=get_pubkey_byfprint_fast (NULL,
|
2002-06-29 13:46:34 +00:00
|
|
|
sig->revkey[idx]->fpr,
|
|
|
|
MAX_FINGERPRINT_LEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(rc==G10ERR_NO_PUBKEY || rc==G10ERR_UNU_PUBKEY)
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info(_("WARNING: key %s may be revoked:"
|
|
|
|
" revocation key %s not present.\n"),
|
|
|
|
tempkeystr,keystr(keyid));
|
|
|
|
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree(tempkeystr);
|
2002-06-29 13:46:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1999-05-19 14:12:26 +00:00
|
|
|
|
1998-02-17 20:48:52 +00:00
|
|
|
/****************
|
|
|
|
* compare and merge the blocks
|
|
|
|
*
|
|
|
|
* o compare the signatures: If we already have this signature, check
|
|
|
|
* that they compare okay; if not, issue a warning and ask the user.
|
|
|
|
* o Simply add the signature. Can't verify here because we may not have
|
1998-04-14 17:51:16 +00:00
|
|
|
* the signature's public key yet; verification is done when putting it
|
1998-02-17 20:48:52 +00:00
|
|
|
* into the trustdb, which is done automagically as soon as this pubkey
|
|
|
|
* is used.
|
|
|
|
* Note: We indicate newly inserted packets with flag bit 0
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
merge_blocks( const char *fname, KBNODE keyblock_orig, KBNODE keyblock,
|
1998-05-26 13:38:00 +00:00
|
|
|
u32 *keyid, int *n_uids, int *n_sigs, int *n_subk )
|
1998-02-17 20:48:52 +00:00
|
|
|
{
|
1998-02-18 13:58:46 +00:00
|
|
|
KBNODE onode, node;
|
|
|
|
int rc, found;
|
|
|
|
|
|
|
|
/* 1st: handle revocation certificates */
|
|
|
|
for(node=keyblock->next; node; node=node->next ) {
|
|
|
|
if( node->pkt->pkttype == PKT_USER_ID )
|
|
|
|
break;
|
|
|
|
else if( node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
&& node->pkt->pkt.signature->sig_class == 0x20 ) {
|
1998-04-14 17:51:16 +00:00
|
|
|
/* check whether we already have this */
|
1998-02-18 13:58:46 +00:00
|
|
|
found = 0;
|
|
|
|
for(onode=keyblock_orig->next; onode; onode=onode->next ) {
|
|
|
|
if( onode->pkt->pkttype == PKT_USER_ID )
|
|
|
|
break;
|
|
|
|
else if( onode->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
&& onode->pkt->pkt.signature->sig_class == 0x20
|
2003-08-13 03:31:36 +00:00
|
|
|
&& !cmp_signatures(onode->pkt->pkt.signature,
|
|
|
|
node->pkt->pkt.signature))
|
|
|
|
{
|
1998-02-18 13:58:46 +00:00
|
|
|
found = 1;
|
|
|
|
break;
|
2003-08-13 03:31:36 +00:00
|
|
|
}
|
1998-02-18 13:58:46 +00:00
|
|
|
}
|
|
|
|
if( !found ) {
|
|
|
|
KBNODE n2 = clone_kbnode(node);
|
|
|
|
insert_kbnode( keyblock_orig, n2, 0 );
|
|
|
|
n2->flag |= 1;
|
2002-06-29 13:46:34 +00:00
|
|
|
++*n_sigs;
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if(!opt.quiet)
|
|
|
|
{
|
2004-08-23 17:55:49 +00:00
|
|
|
char *p=get_user_id_native (keyid);
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info(_("key %s: \"%s\" revocation"
|
|
|
|
" certificate added\n"), keystr(keyid),p);
|
2005-07-27 18:10:56 +00:00
|
|
|
xfree(p);
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
}
|
2002-06-29 13:46:34 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 2nd: merge in any direct key (0x1F) sigs */
|
|
|
|
for(node=keyblock->next; node; node=node->next ) {
|
|
|
|
if( node->pkt->pkttype == PKT_USER_ID )
|
|
|
|
break;
|
|
|
|
else if( node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
&& node->pkt->pkt.signature->sig_class == 0x1F ) {
|
|
|
|
/* check whether we already have this */
|
|
|
|
found = 0;
|
|
|
|
for(onode=keyblock_orig->next; onode; onode=onode->next ) {
|
|
|
|
if( onode->pkt->pkttype == PKT_USER_ID )
|
|
|
|
break;
|
|
|
|
else if( onode->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
&& onode->pkt->pkt.signature->sig_class == 0x1F
|
|
|
|
&& !cmp_signatures(onode->pkt->pkt.signature,
|
|
|
|
node->pkt->pkt.signature)) {
|
|
|
|
found = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2004-03-15 20:00:42 +00:00
|
|
|
if( !found )
|
|
|
|
{
|
2002-06-29 13:46:34 +00:00
|
|
|
KBNODE n2 = clone_kbnode(node);
|
|
|
|
insert_kbnode( keyblock_orig, n2, 0 );
|
|
|
|
n2->flag |= 1;
|
|
|
|
++*n_sigs;
|
* gpgv.c: Remove extra semicolon (typo).
* options.skel: Note that keyserver.pgp.com isn't synchronized, and
explain the roundrobin a bit better.
* sig-check.c (check_key_signature2), import.c (import_one,
import_revoke_cert, chk_self_sigs, delete_inv_parts, collapse_uids,
merge_blocks): Make much quieter during import of slightly munged, but
recoverable, keys. Use log_error for unrecoverable import failures.
* keyring.c (keyring_rebuild_cache): Comment.
* sign.c (mk_notation_and_policy): Making a v3 signature with notations or
policy urls is an error, not an info (i.e. increment the errorcount).
Don't print the notation or policy url to stdout since it can be mixed
into the output stream when piping and munge the stream.
2003-08-21 23:20:58 +00:00
|
|
|
if(!opt.quiet)
|
2004-03-15 20:00:42 +00:00
|
|
|
log_info( _("key %s: direct key signature added\n"),
|
|
|
|
keystr(keyid));
|
|
|
|
}
|
1998-02-18 13:58:46 +00:00
|
|
|
}
|
|
|
|
}
|
1998-02-17 20:48:52 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
/* 3rd: try to merge new certificates in */
|
1998-02-18 13:58:46 +00:00
|
|
|
for(onode=keyblock_orig->next; onode; onode=onode->next ) {
|
|
|
|
if( !(onode->flag & 1) && onode->pkt->pkttype == PKT_USER_ID) {
|
1998-02-17 20:48:52 +00:00
|
|
|
/* find the user id in the imported keyblock */
|
|
|
|
for(node=keyblock->next; node; node=node->next )
|
1998-12-08 12:20:53 +00:00
|
|
|
if( node->pkt->pkttype == PKT_USER_ID
|
1998-02-18 13:58:46 +00:00
|
|
|
&& !cmp_user_ids( onode->pkt->pkt.user_id,
|
1998-02-17 20:48:52 +00:00
|
|
|
node->pkt->pkt.user_id ) )
|
|
|
|
break;
|
|
|
|
if( node ) { /* found: merge */
|
1998-02-18 13:58:46 +00:00
|
|
|
rc = merge_sigs( onode, node, n_sigs, fname, keyid );
|
1998-02-17 20:48:52 +00:00
|
|
|
if( rc )
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
/* 4th: add new user-ids */
|
1998-02-17 20:48:52 +00:00
|
|
|
for(node=keyblock->next; node; node=node->next ) {
|
1998-12-08 12:20:53 +00:00
|
|
|
if( node->pkt->pkttype == PKT_USER_ID) {
|
1998-02-17 20:48:52 +00:00
|
|
|
/* do we have this in the original keyblock */
|
1998-02-18 13:58:46 +00:00
|
|
|
for(onode=keyblock_orig->next; onode; onode=onode->next )
|
1998-12-08 12:20:53 +00:00
|
|
|
if( onode->pkt->pkttype == PKT_USER_ID
|
|
|
|
&& !cmp_user_ids( onode->pkt->pkt.user_id,
|
|
|
|
node->pkt->pkt.user_id ) )
|
1998-02-17 20:48:52 +00:00
|
|
|
break;
|
1998-12-08 12:20:53 +00:00
|
|
|
if( !onode ) { /* this is a new user id: append */
|
1998-02-17 20:48:52 +00:00
|
|
|
rc = append_uid( keyblock_orig, node, n_sigs, fname, keyid);
|
|
|
|
if( rc )
|
|
|
|
return rc;
|
|
|
|
++*n_uids;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
/* 5th: add new subkeys */
|
1998-12-08 12:20:53 +00:00
|
|
|
for(node=keyblock->next; node; node=node->next ) {
|
|
|
|
onode = NULL;
|
|
|
|
if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
|
|
|
|
/* do we have this in the original keyblock? */
|
|
|
|
for(onode=keyblock_orig->next; onode; onode=onode->next )
|
|
|
|
if( onode->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
&& !cmp_public_keys( onode->pkt->pkt.public_key,
|
|
|
|
node->pkt->pkt.public_key ) )
|
|
|
|
break;
|
|
|
|
if( !onode ) { /* this is a new subkey: append */
|
|
|
|
rc = append_key( keyblock_orig, node, n_sigs, fname, keyid);
|
|
|
|
if( rc )
|
|
|
|
return rc;
|
|
|
|
++*n_subk;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( node->pkt->pkttype == PKT_SECRET_SUBKEY ) {
|
|
|
|
/* do we have this in the original keyblock? */
|
|
|
|
for(onode=keyblock_orig->next; onode; onode=onode->next )
|
|
|
|
if( onode->pkt->pkttype == PKT_SECRET_SUBKEY
|
|
|
|
&& !cmp_secret_keys( onode->pkt->pkt.secret_key,
|
|
|
|
node->pkt->pkt.secret_key ) )
|
|
|
|
break;
|
|
|
|
if( !onode ) { /* this is a new subkey: append */
|
|
|
|
rc = append_key( keyblock_orig, node, n_sigs, fname, keyid);
|
|
|
|
if( rc )
|
|
|
|
return rc;
|
|
|
|
++*n_subk;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-05-26 13:38:00 +00:00
|
|
|
|
2002-06-29 13:46:34 +00:00
|
|
|
/* 6th: merge subkey certificates */
|
1999-09-02 14:50:38 +00:00
|
|
|
for(onode=keyblock_orig->next; onode; onode=onode->next ) {
|
|
|
|
if( !(onode->flag & 1)
|
|
|
|
&& ( onode->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|| onode->pkt->pkttype == PKT_SECRET_SUBKEY) ) {
|
|
|
|
/* find the subkey in the imported keyblock */
|
|
|
|
for(node=keyblock->next; node; node=node->next ) {
|
|
|
|
if( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
&& !cmp_public_keys( onode->pkt->pkt.public_key,
|
|
|
|
node->pkt->pkt.public_key ) )
|
|
|
|
break;
|
|
|
|
else if( node->pkt->pkttype == PKT_SECRET_SUBKEY
|
|
|
|
&& !cmp_secret_keys( onode->pkt->pkt.secret_key,
|
|
|
|
node->pkt->pkt.secret_key ) )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( node ) { /* found: merge */
|
|
|
|
rc = merge_keysigs( onode, node, n_sigs, fname, keyid );
|
|
|
|
if( rc )
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-02-17 20:48:52 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* append the userid starting with NODE and all signatures to KEYBLOCK.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
append_uid( KBNODE keyblock, KBNODE node, int *n_sigs,
|
|
|
|
const char *fname, u32 *keyid )
|
|
|
|
{
|
1998-12-08 12:20:53 +00:00
|
|
|
KBNODE n, n_where=NULL;
|
1998-02-17 20:48:52 +00:00
|
|
|
|
|
|
|
assert(node->pkt->pkttype == PKT_USER_ID );
|
|
|
|
|
1998-12-08 12:20:53 +00:00
|
|
|
/* find the position */
|
|
|
|
for( n = keyblock; n; n_where = n, n = n->next ) {
|
|
|
|
if( n->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|| n->pkt->pkttype == PKT_SECRET_SUBKEY )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( !n )
|
|
|
|
n_where = NULL;
|
|
|
|
|
|
|
|
/* and append/insert */
|
|
|
|
while( node ) {
|
1998-02-17 20:48:52 +00:00
|
|
|
/* we add a clone to the original keyblock, because this
|
|
|
|
* one is released first */
|
|
|
|
n = clone_kbnode(node);
|
1998-12-08 12:20:53 +00:00
|
|
|
if( n_where ) {
|
|
|
|
insert_kbnode( n_where, n, 0 );
|
|
|
|
n_where = n;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
add_kbnode( keyblock, n );
|
1998-02-17 20:48:52 +00:00
|
|
|
n->flag |= 1;
|
1998-12-08 12:20:53 +00:00
|
|
|
node->flag |= 1;
|
1998-02-17 20:48:52 +00:00
|
|
|
if( n->pkt->pkttype == PKT_SIGNATURE )
|
|
|
|
++*n_sigs;
|
1998-12-08 12:20:53 +00:00
|
|
|
|
|
|
|
node = node->next;
|
|
|
|
if( node && node->pkt->pkttype != PKT_SIGNATURE )
|
|
|
|
break;
|
1998-02-17 20:48:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* Merge the sigs from SRC onto DST. SRC and DST are both a PKT_USER_ID.
|
|
|
|
* (how should we handle comment packets here?)
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
merge_sigs( KBNODE dst, KBNODE src, int *n_sigs,
|
|
|
|
const char *fname, u32 *keyid )
|
|
|
|
{
|
|
|
|
KBNODE n, n2;
|
|
|
|
int found=0;
|
|
|
|
|
|
|
|
assert(dst->pkt->pkttype == PKT_USER_ID );
|
|
|
|
assert(src->pkt->pkttype == PKT_USER_ID );
|
|
|
|
|
|
|
|
for(n=src->next; n && n->pkt->pkttype != PKT_USER_ID; n = n->next ) {
|
|
|
|
if( n->pkt->pkttype != PKT_SIGNATURE )
|
|
|
|
continue;
|
1999-09-02 14:50:38 +00:00
|
|
|
if( n->pkt->pkt.signature->sig_class == 0x18
|
|
|
|
|| n->pkt->pkt.signature->sig_class == 0x28 )
|
|
|
|
continue; /* skip signatures which are only valid on subkeys */
|
1998-02-17 20:48:52 +00:00
|
|
|
found = 0;
|
2003-08-13 03:31:36 +00:00
|
|
|
for(n2=dst->next; n2 && n2->pkt->pkttype != PKT_USER_ID; n2 = n2->next)
|
|
|
|
if(!cmp_signatures(n->pkt->pkt.signature,n2->pkt->pkt.signature))
|
|
|
|
{
|
|
|
|
found++;
|
|
|
|
break;
|
1998-12-08 12:20:53 +00:00
|
|
|
}
|
|
|
|
if( !found ) {
|
|
|
|
/* This signature is new or newer, append N to DST.
|
|
|
|
* We add a clone to the original keyblock, because this
|
|
|
|
* one is released first */
|
|
|
|
n2 = clone_kbnode(n);
|
|
|
|
insert_kbnode( dst, n2, PKT_SIGNATURE );
|
|
|
|
n2->flag |= 1;
|
|
|
|
n->flag |= 1;
|
|
|
|
++*n_sigs;
|
|
|
|
}
|
|
|
|
}
|
1998-02-17 20:48:52 +00:00
|
|
|
|
1998-12-08 12:20:53 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****************
|
|
|
|
* Merge the sigs from SRC onto DST. SRC and DST are both a PKT_xxx_SUBKEY.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
merge_keysigs( KBNODE dst, KBNODE src, int *n_sigs,
|
|
|
|
const char *fname, u32 *keyid )
|
|
|
|
{
|
|
|
|
KBNODE n, n2;
|
|
|
|
int found=0;
|
|
|
|
|
|
|
|
assert( dst->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|| dst->pkt->pkttype == PKT_SECRET_SUBKEY );
|
|
|
|
|
|
|
|
for(n=src->next; n ; n = n->next ) {
|
|
|
|
if( n->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|| n->pkt->pkttype == PKT_PUBLIC_KEY )
|
|
|
|
break;
|
|
|
|
if( n->pkt->pkttype != PKT_SIGNATURE )
|
1998-02-17 20:48:52 +00:00
|
|
|
continue;
|
1998-12-08 12:20:53 +00:00
|
|
|
found = 0;
|
|
|
|
for(n2=dst->next; n2; n2 = n2->next){
|
|
|
|
if( n2->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|| n2->pkt->pkttype == PKT_PUBLIC_KEY )
|
|
|
|
break;
|
|
|
|
if( n2->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
&& n->pkt->pkt.signature->keyid[0]
|
|
|
|
== n2->pkt->pkt.signature->keyid[0]
|
|
|
|
&& n->pkt->pkt.signature->keyid[1]
|
|
|
|
== n2->pkt->pkt.signature->keyid[1]
|
|
|
|
&& n->pkt->pkt.signature->timestamp
|
|
|
|
<= n2->pkt->pkt.signature->timestamp
|
|
|
|
&& n->pkt->pkt.signature->sig_class
|
|
|
|
== n2->pkt->pkt.signature->sig_class ) {
|
|
|
|
found++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if( !found ) {
|
|
|
|
/* This signature is new or newer, append N to DST.
|
|
|
|
* We add a clone to the original keyblock, because this
|
|
|
|
* one is released first */
|
|
|
|
n2 = clone_kbnode(n);
|
|
|
|
insert_kbnode( dst, n2, PKT_SIGNATURE );
|
|
|
|
n2->flag |= 1;
|
|
|
|
n->flag |= 1;
|
|
|
|
++*n_sigs;
|
1998-02-17 20:48:52 +00:00
|
|
|
}
|
1998-12-08 12:20:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
1998-02-17 20:48:52 +00:00
|
|
|
|
1998-12-08 12:20:53 +00:00
|
|
|
/****************
|
|
|
|
* append the subkey starting with NODE and all signatures to KEYBLOCK.
|
|
|
|
* Mark all new and copied packets by setting flag bit 0.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
append_key( KBNODE keyblock, KBNODE node, int *n_sigs,
|
|
|
|
const char *fname, u32 *keyid )
|
|
|
|
{
|
|
|
|
KBNODE n;
|
|
|
|
|
|
|
|
assert( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY );
|
|
|
|
|
|
|
|
while( node ) {
|
|
|
|
/* we add a clone to the original keyblock, because this
|
1998-02-17 20:48:52 +00:00
|
|
|
* one is released first */
|
1998-12-08 12:20:53 +00:00
|
|
|
n = clone_kbnode(node);
|
|
|
|
add_kbnode( keyblock, n );
|
1998-02-17 20:48:52 +00:00
|
|
|
n->flag |= 1;
|
1998-12-08 12:20:53 +00:00
|
|
|
node->flag |= 1;
|
|
|
|
if( n->pkt->pkttype == PKT_SIGNATURE )
|
|
|
|
++*n_sigs;
|
|
|
|
|
|
|
|
node = node->next;
|
|
|
|
if( node && node->pkt->pkttype != PKT_SIGNATURE )
|
|
|
|
break;
|
1998-02-17 20:48:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
2005-01-20 17:21:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Walk a public keyblock and produce a secret keyblock out of it.
|
|
|
|
Instead of inserting the secret key parameters (which we don't
|
|
|
|
have), we insert a stub. */
|
|
|
|
static KBNODE
|
|
|
|
pub_to_sec_keyblock (KBNODE pub_keyblock)
|
|
|
|
{
|
|
|
|
KBNODE pubnode, secnode;
|
|
|
|
KBNODE sec_keyblock = NULL;
|
|
|
|
KBNODE walkctx = NULL;
|
|
|
|
|
|
|
|
while((pubnode = walk_kbnode (pub_keyblock,&walkctx,0)))
|
|
|
|
{
|
|
|
|
if (pubnode->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|| pubnode->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
{
|
|
|
|
/* Make a secret key. We only need to convert enough to
|
|
|
|
write the keyblock out. */
|
|
|
|
PKT_public_key *pk = pubnode->pkt->pkt.public_key;
|
2005-07-27 18:10:56 +00:00
|
|
|
PACKET *pkt = xmalloc_clear (sizeof *pkt);
|
|
|
|
PKT_secret_key *sk = xmalloc_clear (sizeof *sk);
|
2005-01-20 17:21:40 +00:00
|
|
|
int i, n;
|
|
|
|
|
|
|
|
if (pubnode->pkt->pkttype == PKT_PUBLIC_KEY)
|
|
|
|
pkt->pkttype = PKT_SECRET_KEY;
|
|
|
|
else
|
|
|
|
pkt->pkttype = PKT_SECRET_SUBKEY;
|
|
|
|
|
|
|
|
pkt->pkt.secret_key = sk;
|
|
|
|
|
|
|
|
copy_public_parts_to_secret_key ( pk, sk );
|
|
|
|
sk->version = pk->version;
|
|
|
|
sk->timestamp = pk->timestamp;
|
|
|
|
|
|
|
|
n = pubkey_get_npkey (pk->pubkey_algo);
|
|
|
|
if (!n)
|
|
|
|
n = 1; /* Unknown number of parameters, however the data
|
|
|
|
is stored in the first mpi. */
|
|
|
|
for (i=0; i < n; i++ )
|
|
|
|
sk->skey[i] = mpi_copy (pk->pkey[i]);
|
|
|
|
|
|
|
|
sk->is_protected = 1;
|
|
|
|
sk->protect.s2k.mode = 1001;
|
|
|
|
|
|
|
|
secnode = new_kbnode (pkt);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
secnode = clone_kbnode (pubnode);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!sec_keyblock)
|
|
|
|
sec_keyblock = secnode;
|
|
|
|
else
|
|
|
|
add_kbnode (sec_keyblock, secnode);
|
|
|
|
}
|
|
|
|
|
|
|
|
return sec_keyblock;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Walk over the secret keyring SEC_KEYBLOCK and update any simple
|
|
|
|
stub keys with the serial number SNNUM of the card if one of the
|
|
|
|
fingerprints FPR1, FPR2 or FPR3 match. Print a note if the key is
|
|
|
|
a duplicate (may happen in case of backed uped keys).
|
|
|
|
|
|
|
|
Returns: True if anything changed.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
update_sec_keyblock_with_cardinfo (KBNODE sec_keyblock,
|
|
|
|
const unsigned char *fpr1,
|
|
|
|
const unsigned char *fpr2,
|
|
|
|
const unsigned char *fpr3,
|
|
|
|
const char *serialnostr)
|
|
|
|
{
|
|
|
|
KBNODE node;
|
|
|
|
KBNODE walkctx = NULL;
|
|
|
|
PKT_secret_key *sk;
|
|
|
|
byte array[MAX_FINGERPRINT_LEN];
|
|
|
|
size_t n;
|
|
|
|
int result = 0;
|
|
|
|
const char *s;
|
|
|
|
|
|
|
|
while((node = walk_kbnode (sec_keyblock, &walkctx, 0)))
|
|
|
|
{
|
|
|
|
if (node->pkt->pkttype != PKT_SECRET_KEY
|
|
|
|
&& node->pkt->pkttype != PKT_SECRET_SUBKEY)
|
|
|
|
continue;
|
|
|
|
sk = node->pkt->pkt.secret_key;
|
|
|
|
|
|
|
|
fingerprint_from_sk (sk, array, &n);
|
|
|
|
if (n != 20)
|
|
|
|
continue; /* Can't be a card key. */
|
|
|
|
if ( !((fpr1 && !memcmp (array, fpr1, 20))
|
|
|
|
|| (fpr2 && !memcmp (array, fpr2, 20))
|
|
|
|
|| (fpr3 && !memcmp (array, fpr3, 20))) )
|
|
|
|
continue; /* No match. */
|
|
|
|
|
|
|
|
if (sk->is_protected == 1 && sk->protect.s2k.mode == 1001)
|
|
|
|
{
|
|
|
|
/* Standard case: migrate that stub to a key stub. */
|
|
|
|
sk->protect.s2k.mode = 1002;
|
|
|
|
s = serialnostr;
|
|
|
|
for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
|
|
|
|
sk->protect.ivlen++, s += 2)
|
|
|
|
sk->protect.iv[sk->protect.ivlen] = xtoi_2 (s);
|
|
|
|
result = 1;
|
|
|
|
}
|
|
|
|
else if (sk->is_protected == 1 && sk->protect.s2k.mode == 1002)
|
|
|
|
{
|
|
|
|
s = serialnostr;
|
|
|
|
for (sk->protect.ivlen=0; sk->protect.ivlen < 16 && *s && s[1];
|
|
|
|
sk->protect.ivlen++, s += 2)
|
|
|
|
if (sk->protect.iv[sk->protect.ivlen] != xtoi_2 (s))
|
|
|
|
{
|
|
|
|
log_info (_("NOTE: a key's S/N does not "
|
|
|
|
"match the card's one\n"));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (node->pkt->pkttype != PKT_SECRET_KEY)
|
|
|
|
log_info (_("NOTE: primary key is online and stored on card\n"));
|
|
|
|
else
|
|
|
|
log_info (_("NOTE: secondary key is online and stored on card\n"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Check whether a secret key stub exists for the public key PK. If
|
|
|
|
not create such a stub key and store it into the secring. If it
|
|
|
|
exists, add appropriate subkey stubs and update the secring.
|
|
|
|
Return 0 if the key could be created. */
|
|
|
|
int
|
|
|
|
auto_create_card_key_stub ( const char *serialnostr,
|
|
|
|
const unsigned char *fpr1,
|
|
|
|
const unsigned char *fpr2,
|
|
|
|
const unsigned char *fpr3)
|
|
|
|
{
|
|
|
|
KBNODE pub_keyblock;
|
|
|
|
KBNODE sec_keyblock;
|
|
|
|
KEYDB_HANDLE hd;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* We only want to do this for an OpenPGP card. */
|
|
|
|
if (!serialnostr || strncmp (serialnostr, "D27600012401", 12)
|
|
|
|
|| strlen (serialnostr) != 32 )
|
|
|
|
return G10ERR_GENERAL;
|
|
|
|
|
|
|
|
/* First get the public keyring from any of the provided fingerprints. */
|
|
|
|
if ( (fpr1 && !get_keyblock_byfprint (&pub_keyblock, fpr1, 20))
|
|
|
|
|| (fpr2 && !get_keyblock_byfprint (&pub_keyblock, fpr2, 20))
|
|
|
|
|| (fpr3 && !get_keyblock_byfprint (&pub_keyblock, fpr3, 20)))
|
|
|
|
;
|
|
|
|
else
|
|
|
|
return G10ERR_GENERAL;
|
|
|
|
|
|
|
|
hd = keydb_new (1);
|
|
|
|
|
|
|
|
/* Now check whether there is a secret keyring. */
|
|
|
|
{
|
|
|
|
PKT_public_key *pk = pub_keyblock->pkt->pkt.public_key;
|
|
|
|
byte afp[MAX_FINGERPRINT_LEN];
|
|
|
|
size_t an;
|
|
|
|
|
|
|
|
fingerprint_from_pk (pk, afp, &an);
|
2007-12-10 15:34:20 +00:00
|
|
|
if (an < MAX_FINGERPRINT_LEN)
|
|
|
|
memset (afp+an, 0, MAX_FINGERPRINT_LEN-an);
|
2005-01-20 17:21:40 +00:00
|
|
|
rc = keydb_search_fpr (hd, afp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!rc)
|
|
|
|
{
|
|
|
|
rc = keydb_get_keyblock (hd, &sec_keyblock);
|
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
log_error (_("error reading keyblock: %s\n"), g10_errstr(rc) );
|
|
|
|
rc = G10ERR_GENERAL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
merge_keys_and_selfsig (sec_keyblock);
|
|
|
|
|
|
|
|
/* FIXME: We need to add new subkeys first. */
|
|
|
|
if (update_sec_keyblock_with_cardinfo (sec_keyblock,
|
|
|
|
fpr1, fpr2, fpr3,
|
|
|
|
serialnostr))
|
|
|
|
{
|
|
|
|
rc = keydb_update_keyblock (hd, sec_keyblock );
|
|
|
|
if (rc)
|
|
|
|
log_error (_("error writing keyring `%s': %s\n"),
|
|
|
|
keydb_get_resource_name (hd), g10_errstr(rc) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else /* A secret key does not exists - create it. */
|
|
|
|
{
|
|
|
|
sec_keyblock = pub_to_sec_keyblock (pub_keyblock);
|
|
|
|
update_sec_keyblock_with_cardinfo (sec_keyblock,
|
|
|
|
fpr1, fpr2, fpr3,
|
|
|
|
serialnostr);
|
|
|
|
|
|
|
|
rc = keydb_locate_writable (hd, NULL);
|
|
|
|
if (rc)
|
|
|
|
{
|
|
|
|
log_error (_("no default secret keyring: %s\n"), g10_errstr (rc));
|
|
|
|
rc = G10ERR_GENERAL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rc = keydb_insert_keyblock (hd, sec_keyblock );
|
|
|
|
if (rc)
|
|
|
|
log_error (_("error writing keyring `%s': %s\n"),
|
|
|
|
keydb_get_resource_name (hd), g10_errstr(rc) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
release_kbnode (sec_keyblock);
|
|
|
|
release_kbnode (pub_keyblock);
|
|
|
|
keydb_release (hd);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|