1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-19 00:52:46 +02:00

Merge branch 'master' into gniibe/t6275

This commit is contained in:
NIIBE Yutaka 2022-12-05 12:01:06 +09:00
commit ac87fc1a9b
No known key found for this signature in database
GPG Key ID: 640114AF89DE6054
50 changed files with 1123 additions and 292 deletions

View File

@ -131,24 +131,24 @@ all-local:
@cat $(srcdir)/tests/gpgconf.ctl.in > bin/gpgconf.ctl
(set -e; cd bin; \
for i in gpg gpgv; \
do ln -sf ../g10/$$i .; done; \
do ln -sf ../g10/$$i$(EXEEXT) .; done; \
for i in gpgsm; \
do ln -sf ../sm/$$i .; done; \
do ln -sf ../sm/$$i$(EXEEXT) .; done; \
for i in gpg-agent; \
do ln -sf ../agent/$$i .; done; \
do ln -sf ../agent/$$i$(EXEEXT) .; done; \
for i in dirmngr; \
do ln -sf ../dirmngr/$$i .; done; \
do ln -sf ../dirmngr/$$i$(EXEEXT) .; done; \
for i in gpgconf gpg-connect-agent gpgtar gpg-card; \
do ln -sf ../tools/$$i .; done; \
do ln -sf ../tools/$$i$(EXEEXT) .; done; \
cd ../libexec ; \
for i in keyboxd; \
do ln -sf ../kbx/$$i .; done; \
do ln -sf ../kbx/$$i$(EXEEXT) .; done; \
for i in scdaemon; \
do ln -sf ../scd/$$i .; done; \
do ln -sf ../scd/$$i$(EXEEXT) .; done; \
for i in gpg-preset-passphrase; \
do ln -sf ../agent/$$i .; done; \
do ln -sf ../agent/$$i$(EXEEXT) .; done; \
for i in tpm2daemon; \
do [ -f ../tpm2d/$$i ] && ln -sf ../tpm2d/$$i .; done; \
do [ -f ../tpm2d/$$i$(EXEEXT) ] && ln -sf ../tpm2d/$$i$(EXEEXT) .; done; \
echo "created links to binaries" )
@ -213,12 +213,13 @@ TESTS_ENVIRONMENT = \
abs_top_srcdir=$(abs_top_srcdir) \
objdir=$(abs_top_builddir) \
GNUPG_BUILD_ROOT="$(abs_top_builddir)" \
GNUPG_IN_TEST_SUITE=fact \
GPGSCM_PATH=$(abs_top_srcdir)/tests/gpgscm
.PHONY: check-all release sign-release
check-all:
$(TESTS_ENVIRONMENT) \
$(abs_top_builddir)/tests/gpgscm/gpgscm \
$(abs_top_builddir)/tests/gpgscm/gpgscm$(EXEEXT) \
$(abs_srcdir)/tests/run-tests.scm $(TESTFLAGS) $(TESTS)
# Names of to help the release target.

View File

@ -27,9 +27,10 @@
(parse-makefile-expand filename expander key))
(map (lambda (name)
(test::binary #f
(path-join "agent" name)
(path-join (getenv "objdir") "agent" name)))
(let ((name-ext (string-append name (getenv "EXEEXT"))))
(test::binary #f
(path-join "agent" name-ext)
(path-join (getenv "objdir") "agent" name-ext))))
(parse-makefile-expand (in-srcdir "agent" "Makefile.am")
(lambda (filename port key) (parse-makefile port key))
"module_tests")))

View File

@ -2935,7 +2935,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
static const char hlp_export_key[] =
"EXPORT_KEY [--cache-nonce=<nonce>] [--openpgp] <hexstring_with_keygrip>\n"
"EXPORT_KEY [--cache-nonce=<nonce>] [--openpgp|--mode1003] <hexkeygrip>\n"
"\n"
"Export a secret key from the key store. The key will be encrypted\n"
"using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
@ -2943,9 +2943,10 @@ static const char hlp_export_key[] =
"prior to using this command. The function takes the keygrip as argument.\n"
"\n"
"If --openpgp is used, the secret key material will be exported in RFC 4880\n"
"compatible passphrase-protected form. Without --openpgp, the secret key\n"
"material will be exported in the clear (after prompting the user to unlock\n"
"it, if needed).\n";
"compatible passphrase-protected form. If --mode1003 is use the secret key\n"
"is exported as s-expression as storred locally. Without those options,\n"
"the secret key material will be exported in the clear (after prompting\n"
"the user to unlock it, if needed).\n";
static gpg_error_t
cmd_export_key (assuan_context_t ctx, char *line)
{
@ -2958,7 +2959,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
gcry_cipher_hd_t cipherhd = NULL;
unsigned char *wrappedkey = NULL;
size_t wrappedkeylen;
int openpgp;
int openpgp, mode1003;
char *cache_nonce;
char *passphrase = NULL;
unsigned char *shadow_info = NULL;
@ -2969,6 +2970,10 @@ cmd_export_key (assuan_context_t ctx, char *line)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
openpgp = has_option (line, "--openpgp");
mode1003 = has_option (line, "--mode1003");
if (mode1003)
openpgp = 0;
cache_nonce = option_value (line, "--cache-nonce");
if (cache_nonce)
{
@ -3003,11 +3008,17 @@ cmd_export_key (assuan_context_t ctx, char *line)
}
/* Get the key from the file. With the openpgp flag we also ask for
the passphrase so that we can use it to re-encrypt it. */
err = agent_key_from_file (ctrl, cache_nonce,
ctrl->server_local->keydesc, grip,
&shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey,
openpgp ? &passphrase : NULL, NULL);
* the passphrase so that we can use it to re-encrypt it. In
* mode1003 we return the key as-is. FIXME: if the key is still in
* OpenPGP-native mode we should first convert it to our internal
* protection. */
if (mode1003)
err = agent_raw_key_from_file (ctrl, grip, &s_skey, NULL);
else
err = agent_key_from_file (ctrl, cache_nonce,
ctrl->server_local->keydesc, grip,
&shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey,
openpgp ? &passphrase : NULL, NULL);
if (err)
goto leave;
if (shadow_info)
@ -4150,6 +4161,11 @@ command_has_option (const char *cmd, const char *cmdopt)
if (!strcmp (cmdopt, "newsymkey"))
return 1;
}
else if (!strcmp (cmd, "EXPORT_KEY"))
{
if (!strcmp (cmdopt, "mode1003"))
return 1;
}
return 0;
}

View File

@ -802,9 +802,10 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist,
if (!list)
goto bad_seckey;
value = gcry_sexp_nth_data (list, 1, &valuelen);
if (!value || valuelen != 1 || !(value[0] == '3' || value[0] == '4'))
if (!value || valuelen != 1
|| !(value[0] == '3' || value[0] == '4' || value[0] == '5'))
goto bad_seckey;
is_v4 = (value[0] == '4');
is_v4 = (value[0] == '4' || value[0] == '5');
gcry_sexp_release (list);
list = gcry_sexp_find_token (top_list, "protection", 0);
@ -948,7 +949,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist,
gcry_sexp_release (top_list); top_list = NULL;
#if 0
log_debug ("XXX is_v4=%d\n", is_v4);
log_debug ("XXX is v4_or_later=%d\n", is_v4);
log_debug ("XXX pubkey_algo=%d\n", pubkey_algo);
log_debug ("XXX is_protected=%d\n", is_protected);
log_debug ("XXX protect_algo=%d\n", protect_algo);

View File

@ -19,27 +19,31 @@
;; XXX: Currently, the makefile parser does not understand this
;; Makefile.am, so we hardcode the list of tests here.
(map (lambda (name)
(test::binary #f
(path-join "common" name)
(path-join (getenv "objdir") "common" name)))
(list "t-stringhelp"
"t-timestuff"
"t-convert"
"t-percent"
"t-gettime"
"t-sysutils"
"t-sexputil"
"t-session-env"
"t-openpgp-oid"
"t-ssh-utils"
"t-mapstrings"
"t-zb32"
"t-mbox-util"
"t-iobuf"
"t-strlist"
"t-name-value"
"t-ccparray"
"t-recsel"
"t-exechelp"
"t-exectool"
)))
(let ((name-ext (string-append name (getenv "EXEEXT"))))
(test::binary #f
(path-join "common" name-ext)
(path-join (getenv "objdir") "common" name-ext))))
`("t-stringhelp"
"t-timestuff"
"t-convert"
"t-percent"
"t-gettime"
"t-sysutils"
"t-sexputil"
"t-session-env"
"t-openpgp-oid"
"t-ssh-utils"
"t-mapstrings"
"t-zb32"
"t-mbox-util"
"t-iobuf"
"t-strlist"
"t-name-value"
"t-ccparray"
"t-recsel"
,@(if *win32*
'("t-w32-reg"
"t-w32-cmdline")
'("t-exechelp"
"t-exectool"))
)))

View File

@ -609,7 +609,7 @@ gnupg_tmpfile (void)
char *name, *p;
HANDLE file;
int pid = GetCurrentProcessId ();
unsigned int value;
unsigned int value = 0;
int i;
SECURITY_ATTRIBUTES sec_attr;
@ -634,12 +634,9 @@ gnupg_tmpfile (void)
for (attempts=0; attempts < 10; attempts++)
{
p = name;
value = (GetTickCount () ^ ((pid<<16) & 0xffff0000));
value += (GetTickCount () ^ ((pid<<16) & 0xffff0000));
for (i=0; i < 8; i++)
{
*p++ = tohex (((value >> 28) & 0x0f));
value <<= 4;
}
*p++ = tohex (((value >> (7 - i)*4) & 0x0f));
strcpy (p, ".tmp");
file = CreateFile (buffer,
GENERIC_READ | GENERIC_WRITE,
@ -1195,19 +1192,28 @@ gnupg_unsetenv (const char *name)
#else /*!HAVE_UNSETENV*/
{
char *buf;
int r;
if (!name)
{
gpg_err_set_errno (EINVAL);
return -1;
}
buf = xtrystrdup (name);
buf = strconcat (name, "=", NULL);
if (!buf)
return -1;
r = putenv (buf);
# ifdef HAVE_W32_SYSTEM
/* For Microsoft implementation, we can free the memory in this
use case. */
xfree (buf);
# else
# if __GNUC__
# warning no unsetenv - trying putenv but leaking memory.
# endif
return putenv (buf);
# endif
return r;
}
#endif /*!HAVE_UNSETENV*/
}

View File

@ -984,8 +984,8 @@ make_db_file_name (const char *issuer_hash)
/* Hash the file FNAME and return the MD5 digest in MD5BUFFER. The
caller must allocate MD%buffer wityh at least 16 bytes. Returns 0
on success. */
* caller must allocate MD5buffer with at least 16 bytes. Returns 0
* on success. */
static int
hash_dbfile (const char *fname, unsigned char *md5buffer)
{

View File

@ -504,8 +504,11 @@ check_signature_core (ctrl_t ctrl, ksba_cert_t cert, gcry_sexp_t s_sig,
goto leave;
}
gcry_log_debugsxp ("sig ", s_sig);
gcry_log_debugsxp ("hash", s_hash);
if (DBG_CRYPTO)
{
gcry_log_debugsxp ("sig ", s_sig);
gcry_log_debugsxp ("hash", s_hash);
}
err = gcry_pk_verify (s_sig, s_hash, s_pkey);
if (err)

View File

@ -1504,6 +1504,14 @@ CREATE TABLE signatures (
- One octet with the length of the following serial number.
- The serial number. Regardless of what the length octet
indicates no more than 16 octets are stored.
- 3 :: The internal representation of a private key: For v4 keys we
first write 4 octets big endian length of the following
s-expression with the protected or unprotected private key;
for v5 keys this is not necessarily because that length
header is always there. The actual data are N octets of
s-expression. Any protection (including the real S2K) is
part of that data. Note that the public key aparemters are
repeated in th s-expression.
Note that gpg stores the GNU S2K Extension Number internally as an
S2K Specifier with an offset of 1000.
@ -1694,6 +1702,10 @@ Description of some debug flags:
- RFC-6337 :: ECC in OpenPGP
- RFC-7292 :: PKCS #12: Personal Information Exchange Syntax v1.1
- RFC-8351 :: The PKCS #8 EncryptedPrivateKeyInfo Media Type
- RFC-8550 :: S/MIME Version 4.0 Certificate Handling
- RFC-8551 :: S/MIME Version 4.0 Message Specification
- RFC-2634 :: Enhanced Security Services for S/MIME
- RFC-5035 :: Enhanced Security Services (ESS) Update
- draft-koch-openpgp-2015-rfc4880bis :: Updates to RFC-4880

View File

@ -1338,6 +1338,13 @@ Assume "yes" on most questions. Should not be used in an option file.
Assume "no" on most questions. Should not be used in an option file.
@item --list-filter @{select=@var{expr}@}
@opindex list-filter
A list filter can be used to output only certain keys during key
listsin command. For the availbale property names, see the description
of @option{--import-filter}.
@item --list-options @var{parameters}
@opindex list-options
This is a space or comma delimited string that gives options used when
@ -2550,11 +2557,21 @@ The available filter types are:
Self-signatures are not considered.
Currently only implemented for --import-filter.
@item select
This filter is only implemented by @option{--list-filter}. All
property names may be used.
@end table
For the syntax of the expression see the chapter "FILTER EXPRESSIONS".
The property names for the expressions depend on the actual filter
type and are indicated in the following table.
type and are indicated in the following table. Note that all property
names may also be used by @option{--list-filter}.
Property names may be prefix with a scope delimited by a slash. Valid
scopes are "pub" for public and secret primary keys, "sub" for public
and secret subkeys, "uid" for for user-ID packets, and "sig" for
signature packets. Invalid scopes are currently ignored.
The available properties are:
@ -2567,10 +2584,18 @@ The available properties are:
The addr-spec part of a user id with mailbox or the empty string.
(keep-uid)
@item algostr
A string with the key algorithm description. For example "rsa3072"
or "ed25519".
@item key_algo
A number with the public key algorithm of a key or subkey packet.
(drop-subkey)
@item key_size
A number with the effective key size of a key or subkey packet.
(drop-subkey)
@item key_created
@itemx key_created_d
The first is the timestamp a public key or subkey packet was
@ -2593,7 +2618,7 @@ The available properties are:
been revoked.
@item disabled
Boolean indicating whether a primary key is disabled. (not used)
Boolean indicating whether a primary key is disabled.
@item secret
Boolean indicating whether a key or subkey is a secret one.
@ -2616,6 +2641,18 @@ The available properties are:
@item sig_digest_algo
A number with the digest algorithm of a signature packet. (drop-sig)
@item origin
A string with the key origin or a question mark. For example the
string ``wkd'' is used if a key originated from a Web Key Directory
lookup.
@item lastupd
The timestamp the key was last updated from a keyserver or the Web
Key Directory.
@item url
A string with the the URL associated wit the last key lookup.
@end table
@item --export-options @var{parameters}
@ -2673,12 +2710,27 @@ opposite meaning. The options are:
running the @option{--edit-key} command "minimize" before export except
that the local copy of the key is not modified. Defaults to no.
@item export-revocs
Export only standalone revocation certificates of the key. This
option does not export revocations of 3rd party certificate
revocations.
@item export-dane
Instead of outputting the key material output OpenPGP DANE records
suitable to put into DNS zone files. An ORIGIN line is printed before
each record to allow diverting the records to the corresponding zone
file.
@item mode1003
Enable the use of a new secret key export format. This format
avoids the re-encryption as required with the current OpenPGP format
and also improves the security of the secret key if it has been
protected with a passphrase. Note that an unprotected key is
exported as-is and thus not secure; the general rule to convey
secret keys in an OpenPGP encrypted file still applies with this
mode. Versions of GnuPG before 2.4.0 are not able to import such a
secret file.
@end table
@item --with-colons

View File

@ -433,7 +433,8 @@ name may be changed on the command line (@pxref{option --options}).
@cindex scd-event
If this file is present and executable, it will be called on every card
reader's status change. An example of this script is provided with the
distribution
source code distribution. This option is deprecated in favor of the
@command{DEVINFO --watch}.
@item reader_@var{n}.status
This file is created by @command{scdaemon} to let other applications now

View File

@ -213,6 +213,14 @@ operation. The format of @var{file} is one mail address (just the
addrspec, e.g. "postel@@isi.edu") per line. Empty lines and lines
starting with a '#' are ignored.
@item --add-revocs
@opindex add-revocs
If enabled append revocation certificates for the same addrspec as
used in the WKD to the key. Modern gpg version are able to import and
apply them for existing keys. Note that when used with the
@option{--mirror} command the revocation are searched in the local
keyring and not in an LDAP directory.
@item --verbose
@opindex verbose
Enable extra informational output.

View File

@ -27,9 +27,10 @@
(parse-makefile-expand filename expander key))
(map (lambda (name)
(test::binary #f
(path-join "g10" name)
(path-join (getenv "objdir") "g10" name)))
(let ((name-ext (string-append name (getenv "EXEEXT"))))
(test::binary #f
(path-join "g10" name-ext)
(path-join (getenv "objdir") "g10" name-ext))))
(parse-makefile-expand (in-srcdir "g10" "Makefile.am")
(lambda (filename port key) (parse-makefile port key))
"module_tests")))

View File

@ -674,7 +674,8 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
count += 8; /* Salt. */
if (ski->s2k.mode == 3)
count++; /* S2K.COUNT */
if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002)
if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002
&& ski->s2k.mode != 1003)
count += ski->ivlen;
iobuf_put (a, count);
@ -704,8 +705,9 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
if (ski->s2k.mode == 3)
iobuf_put (a, ski->s2k.count);
/* For our special modes 1001, 1002 we do not need an IV. */
if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002)
/* For our special modes 1001..1003 we do not need an IV. */
if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002
&& ski->s2k.mode != 1003)
iobuf_write (a, ski->iv, ski->ivlen);
}
@ -733,6 +735,22 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
/* The serial number gets stored in the IV field. */
iobuf_write (a, ski->iv, ski->ivlen);
}
else if (ski->s2k.mode == 1003)
{
/* GnuPG extension - Store raw s-expression. */
byte *p;
unsigned int ndatabits;
log_assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE));
p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits);
/* For v5 keys we first write the number of octets of the
* following key material. */
if (is_v5)
write_32 (a, p? (ndatabits+7)/8 : 0);
if (p)
iobuf_write (a, p, (ndatabits+7)/8 );
}
else if (ski->is_protected)
{
/* The secret key is protected - write it out as it is. */

View File

@ -2997,13 +2997,15 @@ agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
keygrip, DESC a prompt to be displayed with the agent's passphrase
question (needs to be plus+percent escaped). if OPENPGP_PROTECTED
is not zero, ensure that the key material is returned in RFC
4880-compatible passphrased-protected form. If CACHE_NONCE_ADDR is
not NULL the agent is advised to first try a passphrase associated
with that nonce. On success the key is stored as a canonical
S-expression at R_RESULT and R_RESULTLEN. */
4880-compatible passphrased-protected form; if instead MODE1003 is
not zero the raw gpg-agent private key format is requested (either
protected or unprotected). If CACHE_NONCE_ADDR is not NULL the
agent is advised to first try a passphrase associated with that
nonce. On success the key is stored as a canonical S-expression at
R_RESULT and R_RESULTLEN. */
gpg_error_t
agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
int openpgp_protected, char **cache_nonce_addr,
int openpgp_protected, int mode1003, char **cache_nonce_addr,
unsigned char **r_result, size_t *r_resultlen,
u32 *keyid, u32 *mainkeyid, int pubkey_algo)
{
@ -3028,6 +3030,12 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
return err;
dfltparm.ctx = agent_ctx;
/* Check that the gpg-agent supports the --mode1003 option. */
if (mode1003 && assuan_transact (agent_ctx,
"GETINFO cmd_has_option EXPORT_KEY mode1003",
NULL, NULL, NULL, NULL, NULL, NULL))
return gpg_error (GPG_ERR_NOT_SUPPORTED);
if (desc)
{
snprintf (line, DIM(line), "SETKEYDESC %s", desc);
@ -3038,7 +3046,7 @@ agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
}
snprintf (line, DIM(line), "EXPORT_KEY %s%s%s %s",
openpgp_protected ? "--openpgp ":"",
mode1003? "--mode1003" : openpgp_protected ? "--openpgp ":"",
cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
hexkeygrip);

View File

@ -231,7 +231,7 @@ gpg_error_t agent_import_key (ctrl_t ctrl, const char *desc,
/* Receive a key from the agent. */
gpg_error_t agent_export_key (ctrl_t ctrl, const char *keygrip,
const char *desc, int openpgp_protected,
char **cache_nonce_addr,
int mode1003, char **cache_nonce_addr,
unsigned char **r_result, size_t *r_resultlen,
u32 *keyid, u32 *mainkeyid, int pubkey_algo);

View File

@ -843,7 +843,6 @@ change_name (void)
{
tty_printf (_("Error: Combined name too long "
"(limit is %d characters).\n"), 39);
xfree (isoname);
rc = gpg_error (GPG_ERR_TOO_LARGE);
goto leave;
}

View File

@ -2,6 +2,7 @@
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
* 2005, 2010 Free Software Foundation, Inc.
* Copyright (C) 1998-2016 Werner Koch
* Copyright (C) 2022 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -63,15 +64,17 @@ struct export_stats_s
};
/* A global variable to store the selector created from
/* Global variables to store the selectors created from
* --export-filter keep-uid=EXPR.
* --export-filter drop-subkey=EXPR.
* --export-filter select=EXPR.
*
* FIXME: We should put this into the CTRL object but that requires a
* lot more changes right now.
*/
static recsel_expr_t export_keep_uid;
static recsel_expr_t export_drop_subkey;
static recsel_expr_t export_select_filter;
/* An object used for a linked list to implement the
@ -81,6 +84,7 @@ struct export_filter_attic_s
struct export_filter_attic_s *next;
recsel_expr_t export_keep_uid;
recsel_expr_t export_drop_subkey;
recsel_expr_t export_select_filter;
};
static struct export_filter_attic_s *export_filter_attic;
@ -105,6 +109,8 @@ cleanup_export_globals (void)
export_keep_uid = NULL;
recsel_release (export_drop_subkey);
export_drop_subkey = NULL;
recsel_release (export_select_filter);
export_select_filter = NULL;
}
@ -128,10 +134,16 @@ parse_export_options(char *str,unsigned int *options,int noisy)
{"export-dane", EXPORT_DANE_FORMAT, NULL, NULL },
{"export-revocs", EXPORT_REVOCS, NULL,
N_("export only revocation certificates") },
{"backup", EXPORT_BACKUP, NULL,
N_("use the GnuPG key backup format")},
{"export-backup", EXPORT_BACKUP, NULL, NULL },
{"mode1003", EXPORT_MODE1003, NULL,
N_("export secret keys using the GnuPG format") },
/* Aliases for backward compatibility */
{"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL},
{"include-attributes",EXPORT_ATTRIBUTES,NULL,NULL},
@ -184,6 +196,8 @@ parse_export_options(char *str,unsigned int *options,int noisy)
*
* - secret :: 1 for a secret subkey, else 0.
* - key_algo :: Public key algorithm id
*
* - select :: The key is only exported if the filter returns true.
*/
gpg_error_t
parse_and_set_export_filter (const char *string)
@ -197,6 +211,8 @@ parse_and_set_export_filter (const char *string)
err = recsel_parse_expr (&export_keep_uid, string+9);
else if (!strncmp (string, "drop-subkey=", 12))
err = recsel_parse_expr (&export_drop_subkey, string+12);
else if (!strncmp (string, "select=", 7))
err = recsel_parse_expr (&export_select_filter, string+7);
else
err = gpg_error (GPG_ERR_INV_NAME);
@ -217,6 +233,8 @@ push_export_filters (void)
export_keep_uid = NULL;
item->export_drop_subkey = export_drop_subkey;
export_drop_subkey = NULL;
item->export_select_filter = export_select_filter;
export_select_filter = NULL;
item->next = export_filter_attic;
export_filter_attic = item;
}
@ -235,6 +253,7 @@ pop_export_filters (void)
cleanup_export_globals ();
export_keep_uid = item->export_keep_uid;
export_drop_subkey = item->export_drop_subkey;
export_select_filter = item->export_select_filter;
}
@ -624,6 +643,183 @@ canon_pk_algo (enum gcry_pk_algos algo)
}
/* Take an s-expression wit the public and private key and change the
* parameter array in PK to include the secret parameters. */
static gpg_error_t
secret_key_to_mode1003 (gcry_sexp_t s_key, PKT_public_key *pk)
{
gpg_error_t err;
gcry_sexp_t list = NULL;
gcry_sexp_t l2;
enum gcry_pk_algos pk_algo;
struct seckey_info *ski;
int idx;
char *string;
size_t npkey, nskey;
gcry_mpi_t pub_params[10] = { NULL };
/* We look for a private-key, then the first element in it tells us
the type */
list = gcry_sexp_find_token (s_key, "protected-private-key", 0);
if (!list)
list = gcry_sexp_find_token (s_key, "private-key", 0);
if (!list)
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
log_assert (!pk->seckey_info);
/* Parse the gcrypt PK algo and check that it is okay. */
l2 = gcry_sexp_cadr (list);
if (!l2)
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
gcry_sexp_release (list);
list = l2;
string = gcry_sexp_nth_string (list, 0);
if (!string)
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
pk_algo = gcry_pk_map_name (string);
xfree (string); string = NULL;
if (gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &npkey)
|| gcry_pk_algo_info (pk_algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &nskey)
|| !npkey || npkey >= nskey)
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
/* Check that the pubkey algo and the received parameters matches
* those from the public key. */
switch (canon_pk_algo (pk_algo))
{
case GCRY_PK_RSA:
if (!is_RSA (pk->pubkey_algo) || npkey != 2)
err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Does not match. */
else
err = gcry_sexp_extract_param (list, NULL, "ne",
&pub_params[0],
&pub_params[1],
NULL);
break;
case GCRY_PK_DSA:
if (!is_DSA (pk->pubkey_algo) || npkey != 4)
err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Does not match. */
else
err = gcry_sexp_extract_param (list, NULL, "pqgy",
&pub_params[0],
&pub_params[1],
&pub_params[2],
&pub_params[3],
NULL);
break;
case GCRY_PK_ELG:
if (!is_ELGAMAL (pk->pubkey_algo) || npkey != 3)
err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Does not match. */
else
err = gcry_sexp_extract_param (list, NULL, "pgy",
&pub_params[0],
&pub_params[1],
&pub_params[2],
NULL);
break;
case GCRY_PK_ECC:
err = 0;
if (!(pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA))
{
err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Does not match. */
goto leave;
}
npkey = 2;
if (pk->pubkey_algo == PUBKEY_ALGO_ECDH)
npkey++;
/* Dedicated check of the curve. */
pub_params[0] = NULL;
err = match_curve_skey_pk (list, pk);
if (err)
goto leave;
/* ... and of the Q parameter. */
err = sexp_extract_param_sos (list, "q", &pub_params[1]);
if (!err && (gcry_mpi_cmp (pk->pkey[1], pub_params[1])))
err = gpg_error (GPG_ERR_BAD_PUBKEY);
break;
default:
err = gpg_error (GPG_ERR_PUBKEY_ALGO); /* Unknown. */
break;
}
if (err)
goto leave;
nskey = npkey + 1; /* We only have one skey param. */
if (nskey > PUBKEY_MAX_NSKEY)
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
/* Check that the public key parameters match. For ECC we already
* did this in the switch above. */
if (canon_pk_algo (pk_algo) != GCRY_PK_ECC)
{
for (idx=0; idx < npkey; idx++)
if (gcry_mpi_cmp (pk->pkey[idx], pub_params[idx]))
{
err = gpg_error (GPG_ERR_BAD_PUBKEY);
goto leave;
}
}
/* Store the maybe protected secret key as an s-expression. */
pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
if (!ski)
{
err = gpg_error_from_syserror ();
goto leave;
}
pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
if (!ski)
{
err = gpg_error_from_syserror ();
goto leave;
}
ski->is_protected = 1;
ski->s2k.mode = 1003;
{
unsigned char *buf;
size_t buflen;
err = make_canon_sexp (s_key, &buf, &buflen);
if (err)
goto leave;
pk->pkey[npkey] = gcry_mpi_set_opaque (NULL, buf, buflen*8);
for (idx=npkey+1; idx < PUBKEY_MAX_NSKEY; idx++)
pk->pkey[idx] = NULL;
}
leave:
gcry_sexp_release (list);
for (idx=0; idx < DIM(pub_params); idx++)
gcry_mpi_release (pub_params[idx]);
return err;
}
/* Take a cleartext dump of a secret key in PK and change the
* parameter array in PK to include the secret parameters. */
static gpg_error_t
@ -1233,29 +1429,51 @@ print_status_exported (PKT_public_key *pk)
* passphrase-protected. Otherwise, store secret key material in the
* clear.
*
* If MODE1003 is set, the key is requested in raw GnuPG format from
* the agent. This usually does not require a passphrase unless the
* gpg-agent has not yet used the key and needs to convert it to its
* internal format first.
*
* CACHE_NONCE_ADDR is used to share nonce for multiple key retrievals.
*
* If PK is NULL, the raw key is returned (e.g. for ssh export) at
* R_KEY. CLEARTEXT and CACHE_NONCE_ADDR ared ignored in this case.
*/
gpg_error_t
receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
int cleartext,
int cleartext, int mode1003,
char **cache_nonce_addr, const char *hexgrip,
PKT_public_key *pk)
PKT_public_key *pk, gcry_sexp_t *r_key)
{
gpg_error_t err = 0;
unsigned char *wrappedkey = NULL;
size_t wrappedkeylen;
unsigned char *key = NULL;
size_t keylen, realkeylen;
gcry_sexp_t s_skey;
gcry_sexp_t s_skey = NULL;
char *prompt;
if (r_key)
*r_key = NULL;
if (opt.verbose)
log_info ("key %s: asking agent for the secret parts\n", hexgrip);
prompt = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_EXPORT,1);
err = agent_export_key (ctrl, hexgrip, prompt, !cleartext, cache_nonce_addr,
&wrappedkey, &wrappedkeylen,
pk->keyid, pk->main_keyid, pk->pubkey_algo);
if (pk)
{
prompt = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_EXPORT, 1);
err = agent_export_key (ctrl, hexgrip, prompt, !cleartext, mode1003,
cache_nonce_addr,
&wrappedkey, &wrappedkeylen,
pk->keyid, pk->main_keyid, pk->pubkey_algo);
}
else
{
prompt = gpg_format_keydesc (ctrl, NULL, FORMAT_KEYDESC_KEYGRIP, 1);
err = agent_export_key (ctrl, hexgrip, prompt, 0, 0,
NULL,
&wrappedkey, &wrappedkeylen,
NULL, NULL, 0);
}
xfree (prompt);
if (err)
@ -1282,14 +1500,21 @@ receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen);
if (!err)
{
if (cleartext)
if (pk && mode1003)
err = secret_key_to_mode1003 (s_skey, pk);
else if (pk && cleartext)
err = cleartext_secret_key_to_openpgp (s_skey, pk);
else
else if (pk)
err = transfer_format_to_openpgp (s_skey, pk);
gcry_sexp_release (s_skey);
else if (r_key)
{
*r_key = s_skey;
s_skey = NULL;
}
}
unwraperror:
gcry_sexp_release (s_skey);
xfree (key);
xfree (wrappedkey);
if (err)
@ -1795,8 +2020,10 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
else if (!err)
{
err = receive_seckey_from_agent (ctrl, cipherhd,
cleartext, &cache_nonce,
hexgrip, pk);
cleartext,
!!(options & EXPORT_MODE1003),
&cache_nonce,
hexgrip, pk, NULL);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
@ -1872,6 +2099,78 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
}
/* Helper for do_export_stream which writes the own revocations
* certificates (if any) from KEYBLOCK to OUT. */
static gpg_error_t
do_export_revocs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
iobuf_t out, unsigned int options, int *any)
{
gpg_error_t err = 0;
kbnode_t kbctx, node;
PKT_signature *sig;
(void)ctrl;
/* NB: walk_kbnode skips packets marked as deleted. */
for (kbctx=NULL; (node = walk_kbnode (keyblock, &kbctx, 0)); )
{
if (node->pkt->pkttype != PKT_SIGNATURE)
continue;
sig = node->pkt->pkt.signature;
/* We are only interested in revocation certifcates. */
if (!(IS_KEY_REV (sig) || IS_UID_REV (sig) || IS_SUBKEY_REV (sig)))
continue;
if (!(sig->keyid[0] == keyid[0] && sig->keyid[1] == keyid[1]))
continue; /* Not a self-signature. */
/* Do not export signature packets which are marked as not
* exportable. */
if (!(options & EXPORT_LOCAL_SIGS)
&& !sig->flags.exportable)
continue; /* not exportable */
/* Do not export packets with a "sensitive" revocation key
* unless the user wants us to. */
if (!(options & EXPORT_SENSITIVE_REVKEYS)
&& sig->revkey)
{
int i;
for (i = 0; i < sig->numrevkeys; i++)
if ((sig->revkey[i].class & 0x40))
break;
if (i < sig->numrevkeys)
continue;
}
if (!sig->flags.checked)
{
log_info ("signature not marked as checked - ignored\n");
continue;
}
if (!sig->flags.valid)
{
log_info ("signature not not valid - ignored\n");
continue;
}
err = build_packet (out, node->pkt);
if (err)
{
log_error ("build_packet(%d) failed: %s\n",
node->pkt->pkttype, gpg_strerror (err));
goto leave;
}
*any = 1;
}
leave:
return err;
}
/* For secret key export we need to setup a decryption context.
* Returns 0 and the context at r_cipherhd. */
static gpg_error_t
@ -2066,13 +2365,33 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
NULL, NULL);
commit_kbnode (&keyblock);
}
else if (export_keep_uid || export_drop_subkey)
else if (export_keep_uid || export_drop_subkey || export_select_filter)
{
/* Need to merge so that for example the "usage" property
* has been setup. */
merge_keys_and_selfsig (ctrl, keyblock);
}
if (export_select_filter)
{
int selected = 0;
struct impex_filter_parm_s parm;
parm.ctrl = ctrl;
for (parm.node = keyblock; parm.node; parm.node = parm.node->next)
{
if (recsel_select (export_select_filter,
impex_filter_getval, &parm))
{
selected = 1;
break;
}
}
if (!selected)
continue; /* Skip this keyblock. */
}
if (export_keep_uid)
{
commit_kbnode (&keyblock);
@ -2088,10 +2407,15 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
}
/* And write it. */
err = do_export_one_keyblock (ctrl, keyblock, keyid,
out_help? out_help : out,
secret, options, stats, any,
desc, ndesc, descindex, cipherhd);
if ((options & EXPORT_REVOCS))
err = do_export_revocs (ctrl, keyblock, keyid,
out_help? out_help : out,
options, any);
else
err = do_export_one_keyblock (ctrl, keyblock, keyid,
out_help? out_help : out,
secret, options, stats, any,
desc, ndesc, descindex, cipherhd);
if (err)
break;
@ -2602,74 +2926,6 @@ export_ssh_key (ctrl_t ctrl, const char *userid)
}
/* Simplified version of receive_seckey_from_agent used to get the raw
* key. */
gpg_error_t
receive_raw_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
const char *hexgrip, gcry_sexp_t *r_key)
{
gpg_error_t err = 0;
unsigned char *wrappedkey = NULL;
size_t wrappedkeylen;
unsigned char *key = NULL;
size_t keylen, realkeylen;
gcry_sexp_t s_skey = NULL;
*r_key = NULL;
if (opt.verbose)
log_info ("key %s: asking agent for the secret parts\n", hexgrip);
{
char * prompt = gpg_format_keydesc (ctrl, NULL, FORMAT_KEYDESC_KEYGRIP, 1);
err = agent_export_key (ctrl, hexgrip, prompt, 0, NULL,
&wrappedkey, &wrappedkeylen,
NULL, NULL, 0);
xfree (prompt);
}
if (err)
goto leave;
if (wrappedkeylen < 24)
{
err = gpg_error (GPG_ERR_INV_LENGTH);
goto leave;
}
keylen = wrappedkeylen - 8;
key = xtrymalloc_secure (keylen);
if (!key)
{
err = gpg_error_from_syserror ();
goto leave;
}
err = gcry_cipher_decrypt (cipherhd, key, keylen, wrappedkey, wrappedkeylen);
if (err)
goto leave;
realkeylen = gcry_sexp_canon_len (key, keylen, NULL, &err);
if (!realkeylen)
goto leave; /* Invalid csexp. */
err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen);
if (!err)
{
gcry_log_debugsxp ("skey", s_skey);
*r_key = s_skey;
s_skey = NULL;
}
leave:
gcry_sexp_release (s_skey);
xfree (key);
xfree (wrappedkey);
if (err)
{
log_error ("key %s: error receiving key from agent:"
" %s%s\n", hexgrip, gpg_strerror (err),
"");
}
return err;
}
/* Export the key identified by USERID in the SSH secret key format.
* The USERID must be given in keygrip format (prefixed with a '&')
* and thus no OpenPGP key is required. The exported key is not
@ -2715,7 +2971,8 @@ export_secret_ssh_key (ctrl_t ctrl, const char *userid)
if ((err = get_keywrap_key (ctrl, &cipherhd)))
goto leave;
err = receive_raw_seckey_from_agent (ctrl, cipherhd, hexgrip, &skey);
err = receive_seckey_from_agent (ctrl, cipherhd, 0, 0, NULL, hexgrip, NULL,
&skey);
if (err)
goto leave;

View File

@ -327,6 +327,7 @@ enum cmd_and_opt_values
oExportOptions,
oExportFilter,
oListOptions,
oListFilter,
oVerifyOptions,
oTempDir,
oExecPath,
@ -794,6 +795,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_header ("Keylist", N_("Options controlling key listings")),
ARGPARSE_s_s (oListOptions, "list-options", "@"),
ARGPARSE_s_s (oListFilter, "list-filter", "@"),
ARGPARSE_s_n (oFullTimestrings, "full-timestrings", "@"),
ARGPARSE_s_n (oShowPhotos, "show-photos", "@"),
ARGPARSE_s_n (oNoShowPhotos, "no-show-photos", "@"),
@ -3357,6 +3359,11 @@ main (int argc, char **argv)
if (rc)
log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
break;
case oListFilter:
rc = parse_and_set_list_filter (pargs.r.ret_str);
if (rc)
log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
break;
case oListOptions:
if(!parse_list_options(pargs.r.ret_str))
{

View File

@ -812,3 +812,11 @@ get_revocation_reason (PKT_signature *sig, char **r_reason,
*r_comment = NULL;
return 0;
}
const char *
impex_filter_getval (void *cookie, const char *propname)
{
(void)cookie;
(void)propname;
return NULL;
}

View File

@ -1430,7 +1430,8 @@ check_prefs (ctrl_t ctrl, kbnode_t keyblock)
}
/* Helper for apply_*_filter in import.c and export.c. */
/* Helper for apply_*_filter in import.c and export.c and also used by
* keylist.c. */
const char *
impex_filter_getval (void *cookie, const char *propname)
{
@ -1440,11 +1441,32 @@ impex_filter_getval (void *cookie, const char *propname)
kbnode_t node = parm->node;
static char numbuf[20];
const char *result;
const char *s;
enum { scpNone = 0, scpPub, scpSub, scpUid, scpSig} scope = 0;
log_assert (ctrl && ctrl->magic == SERVER_CONTROL_MAGIC);
if (node->pkt->pkttype == PKT_USER_ID
|| node->pkt->pkttype == PKT_ATTRIBUTE)
/* We allow a prefix delimited by a slash to limit the scope of the
* keyword. Note that "pub" also includes "sec" and "sub" includes
* "ssb". */
if ((s=strchr (propname, '/')) && s != propname)
{
size_t n = s - propname;
if (!strncmp (propname, "pub", n))
scope = scpPub;
else if (!strncmp (propname, "sub", n))
scope = scpSub;
else if (!strncmp (propname, "uid", n))
scope = scpUid;
else if (!strncmp (propname, "sig", n))
scope = scpSig;
propname = s + 1;
}
if ((node->pkt->pkttype == PKT_USER_ID
|| node->pkt->pkttype == PKT_ATTRIBUTE)
&& (!scope || scope == scpUid))
{
PKT_user_id *uid = node->pkt->pkt.user_id;
@ -1473,7 +1495,8 @@ impex_filter_getval (void *cookie, const char *propname)
else
result = NULL;
}
else if (node->pkt->pkttype == PKT_SIGNATURE)
else if (node->pkt->pkttype == PKT_SIGNATURE
&& (!scope || scope == scpSig))
{
PKT_signature *sig = node->pkt->pkt.signature;
@ -1503,10 +1526,12 @@ impex_filter_getval (void *cookie, const char *propname)
else
result = NULL;
}
else if (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_SECRET_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
else if (((node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_SECRET_KEY)
&& (!scope || scope == scpPub))
|| ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
&& (!scope || scope == scpSub)))
{
PKT_public_key *pk = node->pkt->pkt.public_key;
@ -1520,6 +1545,16 @@ impex_filter_getval (void *cookie, const char *propname)
snprintf (numbuf, sizeof numbuf, "%d", pk->pubkey_algo);
result = numbuf;
}
else if (!strcmp (propname, "key_size"))
{
snprintf (numbuf, sizeof numbuf, "%u", nbits_from_pk (pk));
result = numbuf;
}
else if (!strcmp (propname, "algostr"))
{
pubkey_string (pk, parm->hexfpr, sizeof parm->hexfpr);
result = parm->hexfpr;
}
else if (!strcmp (propname, "key_created"))
{
snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->timestamp);
@ -1556,6 +1591,26 @@ impex_filter_getval (void *cookie, const char *propname)
hexfingerprint (pk, parm->hexfpr, sizeof parm->hexfpr);
result = parm->hexfpr;
}
else if (!strcmp (propname, "origin"))
{
result = key_origin_string (pk->keyorg);
}
else if (!strcmp (propname, "lastupd"))
{
snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->keyupdate);
result = numbuf;
}
else if (!strcmp (propname, "url"))
{
if (pk->updateurl && *pk->updateurl)
{
/* Fixme: This might get truncated. */
mem2str (parm->hexfpr, pk->updateurl, sizeof parm->hexfpr);
result = parm->hexfpr;
}
else
result = "";
}
else
result = NULL;
}

View File

@ -5286,8 +5286,8 @@ card_store_key_with_backup (ctrl_t ctrl, PKT_public_key *sub_psk,
goto leave;
}
err = receive_seckey_from_agent (ctrl, cipherhd, 0,
&cache_nonce, hexgrip, sk);
err = receive_seckey_from_agent (ctrl, cipherhd, 0, 0,
&cache_nonce, hexgrip, sk, NULL);
if (err)
{
log_error ("error getting secret key from agent: %s\n",

View File

@ -44,6 +44,8 @@
#include "../common/mbox-util.h"
#include "../common/zb32.h"
#include "tofu.h"
#include "../common/init.h"
#include "../common/recsel.h"
#include "../common/compliance.h"
#include "../common/pkscreening.h"
@ -64,16 +66,26 @@ struct keylist_context
int no_validity; /* Do not show validity. */
};
static void list_keyblock (ctrl_t ctrl,
kbnode_t keyblock, int secret, int has_secret,
int fpr, struct keylist_context *listctx);
/* An object and a global instance to store selectors created from
* --list-filter select=EXPR.
*/
struct list_filter_s
{
recsel_expr_t selkey;
};
struct list_filter_s list_filter;
/* The stream used to write attribute packets to. */
static estream_t attrib_fp;
static void list_keyblock (ctrl_t ctrl,
kbnode_t keyblock, int secret, int has_secret,
int fpr, struct keylist_context *listctx);
/* Release resources from a keylist context. */
static void
keylist_context_release (struct keylist_context *listctx)
@ -82,6 +94,49 @@ keylist_context_release (struct keylist_context *listctx)
}
static void
release_list_filter (struct list_filter_s *filt)
{
recsel_release (filt->selkey);
filt->selkey = NULL;
}
static void
cleanup_keylist_globals (void)
{
release_list_filter (&list_filter);
}
/* Parse and set an list filter from string. STRING has the format
* "NAME=EXPR" with NAME being the name of the filter. Spaces before
* and after NAME are not allowed. If this function is all called
* several times all expressions for the same NAME are concatenated.
* Supported filter names are:
*
* - select :: If the expression evaluates to true for a certain key
* this key will be listed. The expression may use any
* variable defined for the export and import filters.
*
*/
gpg_error_t
parse_and_set_list_filter (const char *string)
{
gpg_error_t err;
/* Auto register the cleanup function. */
register_mem_cleanup_func (cleanup_keylist_globals);
if (!strncmp (string, "select=", 7))
err = recsel_parse_expr (&list_filter.selkey, string+7);
else
err = gpg_error (GPG_ERR_INV_NAME);
return err;
}
/* List the keys. If list is NULL, all available keys are listed.
* With LOCATE_MODE set the locate algorithm is used to find a key; if
* in addition NO_LOCAL is set the locate does not look into the local
@ -2163,6 +2218,7 @@ reorder_keyblock (KBNODE keyblock)
do_reorder_keyblock (keyblock, 0);
}
static void
list_keyblock (ctrl_t ctrl,
KBNODE keyblock, int secret, int has_secret, int fpr,
@ -2170,6 +2226,24 @@ list_keyblock (ctrl_t ctrl,
{
reorder_keyblock (keyblock);
if (list_filter.selkey)
{
int selected = 0;
struct impex_filter_parm_s parm;
parm.ctrl = ctrl;
for (parm.node = keyblock; parm.node; parm.node = parm.node->next)
{
if (recsel_select (list_filter.selkey, impex_filter_getval, &parm))
{
selected = 1;
break;
}
}
if (!selected)
return; /* Skip this one. */
}
if (opt.with_colons)
list_keyblock_colon (ctrl, keyblock, secret, has_secret);
else if ((opt.list_options & LIST_SHOW_ONLY_FPR_MBOX))

View File

@ -431,10 +431,10 @@ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
void **r_data, size_t *r_datalen);
gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd,
int cleartext,
int cleartext, int mode1003,
char **cache_nonce_addr,
const char *hexgrip,
PKT_public_key *pk);
PKT_public_key *pk, gcry_sexp_t *r_key);
gpg_error_t write_keyblock_to_output (kbnode_t keyblock,
int with_armor, unsigned int options);
@ -464,6 +464,7 @@ void release_revocation_reason_info (struct revocation_reason_info *reason);
void public_key_list (ctrl_t ctrl, strlist_t list,
int locate_mode, int no_local);
void secret_key_list (ctrl_t ctrl, strlist_t list );
gpg_error_t parse_and_set_list_filter (const char *string);
void print_subpackets_colon(PKT_signature *sig);
void reorder_keyblock (KBNODE keyblock);
void list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret,

View File

@ -726,7 +726,7 @@ proc_encrypted (CTX c, PACKET *pkt)
}
/* Compute compliance with CO_DE_VS. */
if (!result && is_status_enabled ()
if (!result && (is_status_enabled () || opt.flags.require_compliance)
/* Overriding session key voids compliance. */
&& !opt.override_session_key
/* Check symmetric cipher. */

View File

@ -406,6 +406,8 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define EXPORT_CLEAN (1<<5)
#define EXPORT_DANE_FORMAT (1<<7)
#define EXPORT_BACKUP (1<<10)
#define EXPORT_REVOCS (1<<11)
#define EXPORT_MODE1003 (1<<12)
#define LIST_SHOW_PHOTOS (1<<0)
#define LIST_SHOW_POLICY_URLS (1<<1)

View File

@ -2752,11 +2752,15 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
break;
case 1001:
if (list_mode)
es_fprintf (listfp, "\tgnu-dummy S2K");
es_fprintf (listfp, "\tgnu-dummy");
break;
case 1002:
if (list_mode)
es_fprintf (listfp, "\tgnu-divert-to-card S2K");
es_fprintf (listfp, "\tgnu-divert-to-card");
break;
case 1003:
if (list_mode)
es_fprintf (listfp, "\tgnu-mode1003");
break;
default:
if (list_mode)
@ -2768,7 +2772,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
}
/* Print some info. */
if (list_mode)
if (list_mode && ski->s2k.mode != 1003)
{
es_fprintf (listfp, ", algo: %d,%s hash: %d",
ski->algo,
@ -2779,8 +2783,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
es_fprintf (listfp, ", salt: ");
es_write_hexstring (listfp, ski->s2k.salt, 8, 0, NULL);
}
es_putc ('\n', listfp);
}
}
if (list_mode)
es_putc ('\n', listfp);
/* Read remaining protection parameters. */
if (ski->s2k.mode == 3)
@ -2838,7 +2843,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
ski->ivlen = openpgp_cipher_blocklen (ski->algo);
log_assert (ski->ivlen <= sizeof (temp));
if (ski->s2k.mode == 1001)
if (ski->s2k.mode == 1001 || ski->s2k.mode == 1003)
ski->ivlen = 0;
else if (ski->s2k.mode == 1002)
ski->ivlen = snlen < 16 ? snlen : 16;
@ -2850,7 +2855,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
}
for (i = 0; i < ski->ivlen; i++, pktlen--)
temp[i] = iobuf_get_noeof (inp);
if (list_mode)
if (list_mode && ski->s2k.mode != 1003)
{
es_fprintf (listfp,
ski->s2k.mode == 1002 ? "\tserial-number: "
@ -2888,6 +2893,35 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
10 * 8);
pktlen = 0;
}
else if (ski->s2k.mode == 1003)
{
void *tmpp;
if (pktlen < 2) /* At least two bytes for parenthesis. */
{
err = gpg_error (GPG_ERR_INV_PACKET);
goto leave;
}
tmpp = read_rest (inp, pktlen);
if (list_mode)
{
if (mpi_print_mode)
{
char *tmpsxp = canon_sexp_to_string (tmpp, pktlen);
es_fprintf (listfp, "\tskey[%d]: %s\n", npkey,
tmpsxp? trim_trailing_spaces (tmpsxp)
/* */: "[invalid S-expression]");
xfree (tmpsxp);
}
else
es_fprintf (listfp, "\tskey[%d]: [s-expression %lu octets]\n",
npkey, pktlen);
}
pk->pkey[npkey] = gcry_mpi_set_opaque (NULL,
tmpp, tmpp? pktlen * 8 : 0);
pktlen = 0;
}
else if (ski->is_protected)
{
void *tmpp;

View File

@ -572,3 +572,11 @@ get_revocation_reason (PKT_signature *sig, char **r_reason,
*r_comment = NULL;
return 0;
}
const char *
impex_filter_getval (void *cookie, const char *propname)
{
(void)cookie;
(void)propname;
return NULL;
}

View File

@ -34,9 +34,10 @@
"g13"))))
(if g13-enabled?
(map (lambda (name)
(test::binary #f
(path-join "g13" name)
(path-join (getenv "objdir") "g13" name)))
(let ((name-ext (string-append name (getenv "EXEEXT"))))
(test::binary #f
(path-join "g13" name-ext)
(path-join (getenv "objdir") "g13" name-ext))))
(parse-makefile-expand (in-srcdir "g13" "Makefile.am")
(lambda (filename port key) (parse-makefile port key))
"module_tests"))

View File

@ -773,7 +773,14 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
return err;
if (DBG_CARD_IO)
log_printhex (apdu, apdulen, " PCSC_data:");
{
/* Do not dump the PIN in a VERIFY command. */
if (apdulen > 5 && apdu[1] == 0x20)
log_debug ("PCSC_data: %02X %02X %02X %02X %02X [redacted]\n",
apdu[0], apdu[1], apdu[2], apdu[3], apdu[4]);
else
log_printhex (apdu, apdulen, "PCSC_data:");
}
if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
send_pci.protocol = PCSC_PROTOCOL_T1;
@ -1555,7 +1562,14 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
return err;
if (DBG_CARD_IO)
log_printhex (apdu, apdulen, " raw apdu:");
{
/* Do not dump the PIN in a VERIFY command. */
if (apdulen > 5 && apdu[1] == 0x20)
log_debug (" raw apdu: %02x%02x%02x%02x%02x [redacted]\n",
apdu[0], apdu[1], apdu[2], apdu[3], apdu[4]);
else
log_printhex (apdu, apdulen, " raw apdu:");
}
maxbuflen = *buflen;
if (pininfo)

View File

@ -516,7 +516,7 @@ static int default_include_certs = DEFAULT_INCLUDE_CERTS;
static int default_validation_model;
/* The default cipher algo. */
#define DEFAULT_CIPHER_ALGO "AES"
#define DEFAULT_CIPHER_ALGO "AES256"
static char *build_list (const char *text,

View File

@ -634,8 +634,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
/* FIXME: INFO_PKALGO correctly shows ECDSA but PKALGO is then
* ECC. We should use the ECDSA here and need to find a way to
* figure this oult without using the bodus assumtion in
* gpgsm_check_cms_signature that ECC is alwas ECDSA. */
* figure this out without using the bogus assumption in
* gpgsm_check_cms_signature that ECC is always ECDSA. */
fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
tstr = strtimestamp_r (sigtime);

View File

@ -28,13 +28,15 @@ include $(top_srcdir)/am/cmacros.am
AM_CFLAGS =
GPGSM = ../../sm/gpgsm
# Note that we need to use /bin/pwd so that we don't get into trouble
# if the shell used for inittests would uses an internal version of
# pwd which handles symlinks differently.
OLD_TESTS_ENVIRONMENT = GNUPGHOME=`/bin/pwd` GPG_AGENT_INFO= LC_ALL=C \
GNUPG_BUILD_ROOT="$(abs_top_builddir)" \
GNUPG_IN_TEST_SUITE=fact \
GPGSM="$(GPGSM)" "$(srcdir)/runtest"
GPGSM="$(GPGSM)$(EXEEXT)" "$(srcdir)/runtest"
TESTS_ENVIRONMENT = LC_ALL=C \
EXEEXT=$(EXEEXT) \

View File

@ -29,6 +29,7 @@
(define setup
(make-environment-cache
(test::scm
#f
#f
(path-join "tests" "cms" "setup.scm")
(in-srcdir "tests" "cms" "setup.scm")
@ -36,6 +37,7 @@
(map (lambda (name)
(test::scm setup
#f
(path-join "tests" "cms" name)
(in-srcdir "tests" "cms" name)))
(parse-makefile-expand (in-srcdir "tests" "cms" "Makefile.am")

View File

@ -27,6 +27,7 @@
(define setup
(make-environment-cache (test::scm
#f
#f
(path-join "tests" "cms" "setup.scm")
(in-srcdir "tests" "cms" "setup.scm"))))
@ -35,5 +36,6 @@
(load-tests "tests" "cms")
(map (lambda (name)
(test::scm setup
#f
(path-join "tests" "cms" name)
(in-srcdir "tests" "cms" name))) tests)))

View File

@ -39,6 +39,7 @@
(define setup-c
(make-environment-cache
(test::scm
#f
#f
(path-join "tests" "gpgme" "setup.scm" "tests" "gpg")
(in-srcdir "tests" "gpgme" "setup.scm")
@ -46,6 +47,7 @@
(define setup-py
(make-environment-cache
(test::scm
#f
#f
(path-join "tests" "gpgme" "setup.scm" "lang" "python" "tests")
(in-srcdir "tests" "gpgme" "setup.scm")
@ -71,6 +73,7 @@
(map (lambda (name)
(apply test::scm
`(,(:setup cmpnts)
#f
,(apply path-join
`("tests" "gpgme" ,@(:path cmpnts) ,name))
,(in-srcdir "tests" "gpgme" "wrap.scm")

View File

@ -360,6 +360,11 @@ do_get_temp_path (scheme *sc, pointer args)
#ifdef HAVE_W32_SYSTEM
if (GetTempPath (MAX_PATH+1, buffer) == 0)
FFI_RETURN_STRING (sc, "/temp");
else
{
size_t len = strlen (buffer);
buffer[len-1] = 0;
}
FFI_RETURN_STRING (sc, buffer);
#else
FFI_RETURN_STRING (sc, "/tmp");

View File

@ -677,14 +677,14 @@
name))
(package
(define (scm setup name path . args)
(define (scm setup variant name path . args)
;; Start the process.
(define (spawn-scm args' in out err)
(process-spawn-fd `(,*argv0* ,@(verbosity (*verbose*))
,(locate-test (test-name path))
,@(if setup (force setup) '())
,@args' ,@args) in out err))
(new name #f spawn-scm #f #f CLOSED_FD (expect-failure? name)))
(new variant name #f spawn-scm #f #f CLOSED_FD (expect-failure? name)))
(define (binary setup name path . args)
;; Start the process.
@ -692,9 +692,9 @@
(process-spawn-fd `(,(test-name path)
,@(if setup (force setup) '()) ,@args' ,@args)
in out err))
(new name #f spawn-binary #f #f CLOSED_FD (expect-failure? name)))
(new #f name #f spawn-binary #f #f CLOSED_FD (expect-failure? name)))
(define (new name directory spawn proc retcode logfd expect-failure)
(define (new variant name directory spawn proc retcode logfd expect-failure)
(package
;; XXX: OO glue.
@ -723,7 +723,11 @@
(define (open-log-file)
(unless log-file-name
(set! log-file-name (string-append (basename name) ".log")))
(set! log-file-name (path-join
(getenv "objdir")
(if variant
(string-append name "." variant ".log")
(string-append name ".log")))))
(catch '() (unlink log-file-name))
(open log-file-name (logior O_RDWR O_BINARY O_CREAT) #o600))
@ -772,7 +776,10 @@
(seek logfd 0 SEEK_SET)
(splice logfd STDERR_FILENO)
(close logfd))
(echo (string-append (status-string) ":") name))
(echo (string-append (status-string) ":")
(if variant
(string-append "<" variant ">" name)
name)))
(define (xml)
(xx::tag

View File

@ -28,6 +28,7 @@
(map (lambda (name)
(test::scm #f
#f
(path-join "tests" "migrations" name)
(in-srcdir "tests" "migrations" name)))
(parse-makefile-expand (in-srcdir "tests" "migrations" "Makefile.am")

View File

@ -26,7 +26,7 @@
(call-check `(,@GPG --list-secret-keys)))
(define (assert-migrated)
(unless (file-exists? ".gpg-v21-migrated")
(unless (or (file-exists? ".gpg-v21-migrated") (file-exists? "gpg-v21-migrated"))
(error "Not migrated"))
(for-each

View File

@ -23,5 +23,6 @@
(load-tests "tests" "migrations")
(map (lambda (name)
(test::scm #f
#f
(path-join "tests" "migrations" name)
(in-srcdir "tests" "migrations" name))) tests)))

View File

@ -29,6 +29,7 @@
(define setup
(make-environment-cache
(test::scm
#f
#f
(path-join "tests" "openpgp" "setup.scm")
(in-srcdir "tests" "openpgp" "setup.scm"))))
@ -40,7 +41,8 @@
(make-environment-cache
(test::scm
#f
(qualify (path-join "tests" "openpgp" "setup.scm") variant)
variant
(path-join "tests" "openpgp" "setup.scm")
(in-srcdir "tests" "openpgp" "setup.scm")
(string-append "--" variant))))
@ -62,7 +64,8 @@
(define tests
(map (lambda (name)
(test::scm setup
(qualify (path-join "tests" "openpgp" name) "standard")
"standard"
(path-join "tests" "openpgp" name)
(in-srcdir "tests" "openpgp" name))) all-tests))
(when *run-all-tests*
@ -73,17 +76,16 @@
(if keyboxd-enabled?
(map (lambda (name)
(test::scm setup-use-keyboxd
(qualify (path-join "tests" "openpgp" name)
"keyboxd")
"keyboxd"
(path-join "tests" "openpgp" name)
(in-srcdir "tests" "openpgp" name)
"--use-keyboxd")) all-tests))
;; The third pass uses the legact pubring.gpg
(map (lambda (name)
(test::scm setup-use-keyring
(qualify (path-join "tests" "openpgp" name)
"keyring")
"keyring"
(path-join "tests" "openpgp" name)
(in-srcdir "tests" "openpgp" name)
"--use-keyring")) all-tests)
)))
"--use-keyring")) all-tests))))
tests)

View File

@ -146,6 +146,9 @@
(gpg-conf' "" args))
(define (gpg-conf' input args)
(let ((s (call-popen `(,(tool-hardcoded 'gpgconf)
,@(if *win32*
(list '--build-prefix (getenv "objdir"))
'())
,@args) input)))
(map (lambda (line) (map percent-decode (string-split line #\:)))
(string-split-newlines s))))

View File

@ -196,28 +196,20 @@ option_value (const char *line, const char *name)
return NULL;
}
int
main (int argc, char **argv)
static int
parse_pinentry_user_data (const char *args,
char **r_passphrase)
{
char *args;
char *option_user_data = NULL;
int got_environment_user_data;
char *logfile;
char *passphrasefile;
char *passphrase;
/* We get our options via PINENTRY_USER_DATA. */
(void) argc, (void) argv;
*r_passphrase = NULL;
setvbuf (stdin, NULL, _IOLBF, BUFSIZ);
setvbuf (stdout, NULL, _IOLBF, BUFSIZ);
if (log_stream)
fclose (log_stream);
log_stream = NULL;
args = getenv ("PINENTRY_USER_DATA");
got_environment_user_data = !!args;
if (! args)
args = "";
restart:
logfile = option_value (args, "--logfile");
if (logfile)
{
@ -232,7 +224,7 @@ main (int argc, char **argv)
if (! log_stream)
{
perror (logfile);
return 1;
return -1;
}
}
@ -251,20 +243,31 @@ main (int argc, char **argv)
{
reply ("# Passphrasefile '%s' is empty. Terminating.\n",
passphrasefile);
return 1;
return -1;
}
rstrip (passphrase);
}
else
{
passphrase = skip_options (args);
if (*passphrase == 0)
passphrase = "no PINENTRY_USER_DATA -- using default passphrase";
}
passphrase = strdup (skip_options (args));
reply ("# fake-pinentry(%u) started. Passphrase='%s'.\n",
(unsigned int)getpid (), passphrase);
*r_passphrase = passphrase;
return 0;
}
int
main (int argc, char **argv)
{
char *passphrase = NULL;
/* We get our options via PINENTRY_USER_DATA. */
(void) argc, (void) argv;
setvbuf (stdin, NULL, _IOLBF, BUFSIZ);
setvbuf (stdout, NULL, _IOLBF, BUFSIZ);
reply ("# fake-pinentry(%u) started.\n", (unsigned int)getpid ());
reply ("OK - what's up?\n");
while (! feof (stdin))
@ -282,7 +285,12 @@ main (int argc, char **argv)
#define OPT_USER_DATA "OPTION pinentry-user-data="
if (strncmp (buffer, "GETPIN", 6) == 0)
reply ("D %s\n", passphrase);
{
if (passphrase)
reply ("D %s\n", passphrase);
else
reply ("D deafult\n");
}
else if (strncmp (buffer, "BYE", 3) == 0)
{
reply ("OK\n");
@ -290,18 +298,12 @@ main (int argc, char **argv)
}
else if (strncmp (buffer, OPT_USER_DATA, strlen (OPT_USER_DATA)) == 0)
{
if (got_environment_user_data)
if (parse_pinentry_user_data (buffer + strlen (OPT_USER_DATA),
&passphrase) < 0)
{
reply ("OK - I already got the data from the environment.\n");
continue;
/* Failure. */
return 1;
}
if (log_stream)
fclose (log_stream);
log_stream = NULL;
free (option_user_data);
option_user_data = args = strdup (buffer + strlen (OPT_USER_DATA));
goto restart;
}
reply ("OK\n");
@ -313,6 +315,7 @@ main (int argc, char **argv)
if (log_stream)
fclose (log_stream);
free (option_user_data);
if (passphrase)
free (passphrase);
return 0;
}

View File

@ -29,6 +29,6 @@
(for-each-p
"Checking invocation with invalid file descriptors (issue2941)."
(lambda (option)
(check-failure `(,(string-append "--" option "=23") --sign gpg.conf)))
(check-failure `(,(string-append "--" option "=233") --sign gpg.conf)))
'("status-fd" "attribute-fd" "logger-fd"
"override-session-key-fd" "passphrase-fd" "command-fd"))

View File

@ -28,6 +28,7 @@
(define setup
(make-environment-cache (test::scm
#f
#f
(path-join "tests" "openpgp" "setup.scm")
(in-srcdir "tests" "openpgp" "setup.scm"))))
@ -55,11 +56,12 @@
(if use-keyboxd?
(map (lambda (name)
(test::scm setup-use-keyboxd
(qualify (path-join "tests" "openpgp" name)
"keyboxd")
"keyboxd"
(path-join "tests" "openpgp" name)
(in-srcdir "tests" "openpgp" name)
"--use-keyboxd")) tests)
(map (lambda (name)
(test::scm setup
#f
(path-join "tests" "openpgp" name)
(in-srcdir "tests" "openpgp" name))) tests))))

View File

@ -23,7 +23,7 @@ GPGSM = ../../sm/gpgsm
TESTS_ENVIRONMENT = GNUPGHOME=`/bin/pwd` GPG_AGENT_INFO= LC_ALL=C \
GNUPG_BUILD_ROOT="$(abs_top_builddir)" \
GNUPG_IN_TEST_SUITE=fact \
GPGSM=$(GPGSM) silent=yes
GPGSM=$(GPGSM)$(EXEEXT) silent=yes
testscripts = import-all-certs validate-all-certs \

View File

@ -76,6 +76,7 @@ enum cmd_and_opt_values
oWithColons,
oBlacklist,
oNoAutostart,
oAddRevocs,
oDummy
};
@ -102,9 +103,9 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_c (aRemoveKey, "remove-key",
"remove a key from a directory"),
ARGPARSE_c (aPrintWKDHash, "print-wkd-hash",
"Print the WKD identifier for the given user ids"),
"print the WKD identifier for the given user ids"),
ARGPARSE_c (aPrintWKDURL, "print-wkd-url",
"Print the WKD URL for the given user id"),
"print the WKD URL for the given user id"),
ARGPARSE_group (301, ("@\nOptions:\n ")),
@ -119,6 +120,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_n (oWithColons, "with-colons", "@"),
ARGPARSE_s_s (oBlacklist, "blacklist", "@"),
ARGPARSE_s_s (oDirectory, "directory", "@"),
ARGPARSE_s_n (oAddRevocs, "add-revocs", "add revocation certificates"),
ARGPARSE_s_s (oFakeSubmissionAddr, "fake-submission-addr", "@"),
@ -257,6 +259,9 @@ parse_arguments (gpgrt_argparse_t *pargs, gpgrt_opt_t *popts)
case oBlacklist:
add_blacklist (pargs->r.ret_str);
break;
case oAddRevocs:
opt.add_revocs = 1;
break;
case aSupported:
case aCreate:
@ -1164,7 +1169,7 @@ command_send (const char *fingerprint, const char *userid)
err = gpg_error (GPG_ERR_INV_USER_ID);
goto leave;
}
err = wks_get_key (&key, fingerprint, addrspec, 0);
err = wks_get_key (&key, fingerprint, addrspec, 0, 1);
if (err)
goto leave;
@ -1232,7 +1237,7 @@ command_send (const char *fingerprint, const char *userid)
estream_t newkey;
es_rewind (key);
err = wks_filter_uid (&newkey, key, thisuid->uid, 0);
err = wks_filter_uid (&newkey, key, thisuid->uid, 1);
if (err)
{
log_error ("error filtering key: %s\n", gpg_strerror (err));
@ -1257,11 +1262,47 @@ command_send (const char *fingerprint, const char *userid)
* the key again. */
es_fclose (key);
key = NULL;
err = wks_get_key (&key, fingerprint, addrspec, 1);
err = wks_get_key (&key, fingerprint, addrspec, 1, 1);
if (err)
goto leave;
}
if (opt.add_revocs)
{
if (es_fseek (key, 0, SEEK_END))
{
err = gpg_error_from_syserror ();
log_error ("error seeking stream: %s\n", gpg_strerror (err));
goto leave;
}
err = wks_find_add_revocs (key, addrspec);
if (err)
{
log_error ("error finding revocations for '%s': %s\n",
addrspec, gpg_strerror (err));
goto leave;
}
}
/* Now put the armor around the key. */
{
estream_t newkey;
es_rewind (key);
err = wks_armor_key (&newkey, key,
no_encrypt? NULL
/* */ : ("Content-Type: application/pgp-keys\n"
"\n"));
if (err)
{
log_error ("error armoring key: %s\n", gpg_strerror (err));
goto leave;
}
es_fclose (key);
key = newkey;
}
/* Hack to support posteo but let them disable this by setting the
* new policy-version flag. */
if (policy->protocol_version < 3
@ -1306,7 +1347,7 @@ command_send (const char *fingerprint, const char *userid)
if (no_encrypt)
{
void *data;
size_t datalen, n;
size_t datalen;
if (posteo_hack)
{
@ -1331,16 +1372,7 @@ command_send (const char *fingerprint, const char *userid)
goto leave;
}
key = NULL;
/* We need to skip over the first line which has a content-type
* header not needed here. */
for (n=0; n < datalen ; n++)
if (((const char *)data)[n] == '\n')
{
n++;
break;
}
err = mime_maker_add_body_data (mime, (char*)data + n, datalen - n);
err = mime_maker_add_body_data (mime, data, datalen);
xfree (data);
if (err)
goto leave;
@ -1827,7 +1859,7 @@ domain_matches_mbox (const char *domain, const char *mbox)
/* Core of mirror_one_key with the goal of mirroring just one uid.
* UIDLIST is used to figure out whether the given MBOX occurs several
* times in UIDLIST and then to single out the newwest one. This is
* times in UIDLIST and then to single out the newest one. This is
* so that for a key with
* uid: Joe Someone <joe@example.org>
* uid: Joe <joe@example.org>
@ -1868,24 +1900,36 @@ mirror_one_keys_userid (estream_t key, const char *mbox, uidinfo_list_t uidlist,
err = gpg_error (GPG_ERR_NO_USER_ID);
goto leave;
}
/* FIXME: Consult blacklist. */
/* Only if we have more than one user id we bother to run the
* filter. In this case the result will be put into NEWKEY*/
/* Always filter the key so that the result will be non-armored. */
es_rewind (key);
if (uidlist->next)
err = wks_filter_uid (&newkey, key, thisuid->uid, 1);
if (err)
{
err = wks_filter_uid (&newkey, key, thisuid->uid, 0);
if (err)
{
log_error ("error filtering key %s: %s\n", fpr, gpg_strerror (err));
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
log_error ("error filtering key %s: %s\n", fpr, gpg_strerror (err));
err = gpg_error (GPG_ERR_NO_PUBKEY);
goto leave;
}
err = wks_install_key_core (newkey? newkey : key, mbox);
if (opt.add_revocs)
{
if (es_fseek (newkey, 0, SEEK_END))
{
err = gpg_error_from_syserror ();
log_error ("error seeking stream: %s\n", gpg_strerror (err));
goto leave;
}
err = wks_find_add_revocs (newkey, mbox);
if (err)
{
log_error ("error finding revocations for '%s': %s\n",
mbox, gpg_strerror (err));
goto leave;
}
es_rewind (newkey);
}
err = wks_install_key_core (newkey, mbox);
if (opt.verbose)
log_info ("key %s published for '%s'\n", fpr, mbox);
mirror_one_key_parm.nuids++;

View File

@ -39,6 +39,7 @@ struct
int use_sendmail;
int with_colons;
int no_autostart;
int add_revocs;
const char *output;
const char *gpg_program;
const char *directory;
@ -91,11 +92,14 @@ void wks_set_status_fd (int fd);
void wks_write_status (int no, const char *format, ...) GPGRT_ATTR_PRINTF(2,3);
void free_uidinfo_list (uidinfo_list_t list);
gpg_error_t wks_get_key (estream_t *r_key, const char *fingerprint,
const char *addrspec, int exact);
const char *addrspec, int exact, int binary);
gpg_error_t wks_list_key (estream_t key, char **r_fpr,
uidinfo_list_t *r_mboxes);
gpg_error_t wks_filter_uid (estream_t *r_newkey, estream_t key,
const char *uid, int binary);
gpg_error_t wks_armor_key (estream_t *r_newkey, estream_t key,
const char *prefix);
gpg_error_t wks_find_add_revocs (estream_t key, const char *addrspec);
gpg_error_t wks_send_mime (mime_maker_t mime);
gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream,
int ignore_unknown);

View File

@ -150,6 +150,21 @@ free_uidinfo_list (uidinfo_list_t list)
}
static void
debug_gpg_invocation (const char *func, const char **argv)
{
int i;
if (!(opt.debug & DBG_EXTPROG_VALUE))
return;
log_debug ("%s: exec '%s' with", func, opt.gpg_program);
for (i=0; argv[i]; i++)
log_printf (" '%s'", argv[i]);
log_printf ("\n");
}
struct get_key_status_parm_s
{
@ -164,7 +179,8 @@ get_key_status_cb (void *opaque, const char *keyword, char *args)
{
struct get_key_status_parm_s *parm = opaque;
/*log_debug ("%s: %s\n", keyword, args);*/
if (DBG_CRYPTO)
log_debug ("%s: %s\n", keyword, args);
if (!strcmp (keyword, "EXPORTED"))
{
parm->count++;
@ -177,10 +193,11 @@ get_key_status_cb (void *opaque, const char *keyword, char *args)
* mail address ADDRSPEC is included in the key. If EXACT is set the
* returned user id must match Addrspec exactly and not just in the
* addr-spec (mailbox) part. The key is returned as a new memory
* stream at R_KEY. */
* stream at R_KEY. If BINARY is set the returned key is
* non-armored. */
gpg_error_t
wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec,
int exact)
int exact, int binary)
{
gpg_error_t err;
ccparray_t ccp;
@ -202,8 +219,9 @@ wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec,
}
/* Prefix the key with the MIME content type. */
es_fputs ("Content-Type: application/pgp-keys\n"
"\n", key);
if (!binary)
es_fputs ("Content-Type: application/pgp-keys\n"
"\n", key);
filterexp = es_bsprintf ("keep-uid=%s= %s", exact? "uid":"mbox", addrspec);
if (!filterexp)
@ -223,7 +241,8 @@ wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec,
ccparray_put (&ccp, "--batch");
ccparray_put (&ccp, "--status-fd=2");
ccparray_put (&ccp, "--always-trust");
ccparray_put (&ccp, "--armor");
if (!binary)
ccparray_put (&ccp, "--armor");
ccparray_put (&ccp, "--export-options=export-minimal");
ccparray_put (&ccp, "--export-filter");
ccparray_put (&ccp, filterexp);
@ -239,6 +258,7 @@ wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec,
goto leave;
}
parm.fpr = fingerprint;
debug_gpg_invocation (__func__, argv);
err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
NULL, key,
get_key_status_cb, &parm);
@ -332,6 +352,7 @@ wks_list_key (estream_t key, char **r_fpr, uidinfo_list_t *r_mboxes)
err = gpg_error_from_syserror ();
goto leave;
}
debug_gpg_invocation (__func__, argv);
err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
NULL, listing,
key_status_cb, NULL);
@ -510,6 +531,7 @@ wks_filter_uid (estream_t *r_newkey, estream_t key, const char *uid,
err = gpg_error_from_syserror ();
goto leave;
}
debug_gpg_invocation (__func__, argv);
err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
NULL, newkey,
key_status_cb, NULL);
@ -531,6 +553,124 @@ wks_filter_uid (estream_t *r_newkey, estream_t key, const char *uid,
}
/* Put the ascii-armor around KEY and return that as a new estream
* object at R_NEWKEY. Caller must make sure that KEY has been seeked
* to the right position (usually by calling es_rewind). The
* resulting NEWKEY has already been rewound. If PREFIX is not NULL,
* its content is written to NEWKEY propr to the armor; this may be
* used for MIME headers. */
gpg_error_t
wks_armor_key (estream_t *r_newkey, estream_t key, const char *prefix)
{
gpg_error_t err;
estream_t newkey;
struct b64state b64state;
char buffer[4096];
size_t nread;
*r_newkey = NULL;
newkey = es_fopenmem (0, "w+b");
if (!newkey)
{
err = gpg_error_from_syserror ();
return err;
}
if (prefix)
es_fputs (prefix, newkey);
err = b64enc_start_es (&b64state, newkey, "PGP PUBLIC KEY BLOCK");
if (err)
goto leave;
do
{
nread = es_fread (buffer, 1, sizeof buffer, key);
if (!nread)
break;
err = b64enc_write (&b64state, buffer, nread);
if (err)
goto leave;
}
while (!es_feof (key) && !es_ferror (key));
if (!es_feof (key) || es_ferror (key))
{
err = gpg_error_from_syserror ();
goto leave;
}
err = b64enc_finish (&b64state);
if (err)
goto leave;
es_rewind (newkey);
*r_newkey = newkey;
newkey = NULL;
leave:
es_fclose (newkey);
return err;
}
/* Run gpg to export the revocation certificates for ADDRSPEC. Add
* them to KEY which is expected to be non-armored keyblock. */
gpg_error_t
wks_find_add_revocs (estream_t key, const char *addrspec)
{
gpg_error_t err;
ccparray_t ccp;
const char **argv = NULL;
char *filterexp = NULL;
filterexp = es_bsprintf ("select=mbox= %s", addrspec);
if (!filterexp)
{
err = gpg_error_from_syserror ();
log_error ("error allocating memory buffer: %s\n", gpg_strerror (err));
goto leave;
}
ccparray_init (&ccp, 0);
ccparray_put (&ccp, "--no-options");
if (opt.verbose < 2)
ccparray_put (&ccp, "--quiet");
else
ccparray_put (&ccp, "--verbose");
ccparray_put (&ccp, "--batch");
ccparray_put (&ccp, "--status-fd=2");
ccparray_put (&ccp, "--export-options=export-revocs");
ccparray_put (&ccp, "--export-filter");
ccparray_put (&ccp, filterexp);
ccparray_put (&ccp, "--export");
ccparray_put (&ccp, addrspec);
ccparray_put (&ccp, NULL);
argv = ccparray_get (&ccp, NULL);
if (!argv)
{
err = gpg_error_from_syserror ();
goto leave;
}
debug_gpg_invocation (__func__, argv);
err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
NULL, key,
key_status_cb, NULL);
if (err)
{
log_error ("exporting revocs failed: %s\n", gpg_strerror (err));
goto leave;
}
leave:
xfree (filterexp);
xfree (argv);
return err;
}
/* Helper to write mail to the output(s). */
gpg_error_t
wks_send_mime (mime_maker_t mime)
@ -1102,7 +1242,7 @@ wks_cmd_install_key (const char *fname, const char *userid)
{
/* FNAME looks like a fingerprint. Get the key from the
* standard keyring. */
err = wks_get_key (&fp, fname, addrspec, 0);
err = wks_get_key (&fp, fname, addrspec, 0, 1);
if (err)
{
log_error ("error getting key '%s' (uid='%s'): %s\n",
@ -1174,6 +1314,24 @@ wks_cmd_install_key (const char *fname, const char *userid)
fp = fp2;
}
if (opt.add_revocs)
{
if (es_fseek (fp, 0, SEEK_END))
{
err = gpg_error_from_syserror ();
log_error ("error seeking stream: %s\n", gpg_strerror (err));
goto leave;
}
err = wks_find_add_revocs (fp, addrspec);
if (err)
{
log_error ("error finding revocations for '%s': %s\n",
addrspec, gpg_strerror (err));
goto leave;
}
es_rewind (fp);
}
err = wks_install_key_core (fp, addrspec);
if (!opt.quiet)
log_info ("key %s published for '%s'\n", fpr, addrspec);