mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
Merge branch 'master' into gniibe/t6275
This commit is contained in:
commit
ac87fc1a9b
21
Makefile.am
21
Makefile.am
@ -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.
|
||||
|
@ -27,9 +27,10 @@
|
||||
(parse-makefile-expand filename expander key))
|
||||
|
||||
(map (lambda (name)
|
||||
(let ((name-ext (string-append name (getenv "EXEEXT"))))
|
||||
(test::binary #f
|
||||
(path-join "agent" name)
|
||||
(path-join (getenv "objdir") "agent" name)))
|
||||
(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")))
|
||||
|
@ -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,7 +3008,13 @@ 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. */
|
||||
* 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,
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -19,10 +19,11 @@
|
||||
;; XXX: Currently, the makefile parser does not understand this
|
||||
;; Makefile.am, so we hardcode the list of tests here.
|
||||
(map (lambda (name)
|
||||
(let ((name-ext (string-append name (getenv "EXEEXT"))))
|
||||
(test::binary #f
|
||||
(path-join "common" name)
|
||||
(path-join (getenv "objdir") "common" name)))
|
||||
(list "t-stringhelp"
|
||||
(path-join "common" name-ext)
|
||||
(path-join (getenv "objdir") "common" name-ext))))
|
||||
`("t-stringhelp"
|
||||
"t-timestuff"
|
||||
"t-convert"
|
||||
"t-percent"
|
||||
@ -40,6 +41,9 @@
|
||||
"t-name-value"
|
||||
"t-ccparray"
|
||||
"t-recsel"
|
||||
"t-exechelp"
|
||||
"t-exectool"
|
||||
,@(if *win32*
|
||||
'("t-w32-reg"
|
||||
"t-w32-cmdline")
|
||||
'("t-exechelp"
|
||||
"t-exectool"))
|
||||
)))
|
||||
|
@ -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*/
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -504,8 +504,11 @@ check_signature_core (ctrl_t ctrl, ksba_cert_t cert, gcry_sexp_t s_sig,
|
||||
goto leave;
|
||||
}
|
||||
|
||||
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)
|
||||
|
12
doc/DETAILS
12
doc/DETAILS
@ -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
|
||||
|
||||
|
56
doc/gpg.texi
56
doc/gpg.texi
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -27,9 +27,10 @@
|
||||
(parse-makefile-expand filename expander key))
|
||||
|
||||
(map (lambda (name)
|
||||
(let ((name-ext (string-append name (getenv "EXEEXT"))))
|
||||
(test::binary #f
|
||||
(path-join "g10" name)
|
||||
(path-join (getenv "objdir") "g10" name)))
|
||||
(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")))
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
419
g10/export.c
419
g10/export.c
@ -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,
|
||||
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,6 +2407,11 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
|
||||
}
|
||||
|
||||
/* And write it. */
|
||||
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,
|
||||
@ -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;
|
||||
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
67
g10/import.c
67
g10/import.c
@ -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
|
||||
/* 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
|
||||
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;
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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))
|
||||
|
@ -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,
|
||||
|
@ -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. */
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -34,9 +34,10 @@
|
||||
"g13"))))
|
||||
(if g13-enabled?
|
||||
(map (lambda (name)
|
||||
(let ((name-ext (string-append name (getenv "EXEEXT"))))
|
||||
(test::binary #f
|
||||
(path-join "g13" name)
|
||||
(path-join (getenv "objdir") "g13" name)))
|
||||
(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"))
|
||||
|
16
scd/apdu.c
16
scd/apdu.c
@ -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)
|
||||
{
|
||||
/* 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)
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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) \
|
||||
|
@ -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")
|
||||
|
@ -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)))
|
||||
|
@ -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")
|
||||
|
@ -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");
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
|
@ -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
|
||||
|
@ -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)))
|
||||
|
@ -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)
|
||||
|
@ -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))))
|
||||
|
@ -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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -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"))
|
||||
|
@ -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))))
|
||||
|
@ -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 \
|
||||
|
@ -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, 0);
|
||||
err = wks_filter_uid (&newkey, key, thisuid->uid, 1);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error filtering key %s: %s\n", fpr, gpg_strerror (err));
|
||||
err = gpg_error (GPG_ERR_NO_PUBKEY);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
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? newkey : key, mbox);
|
||||
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++;
|
||||
|
@ -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);
|
||||
|
166
tools/wks-util.c
166
tools/wks-util.c
@ -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,6 +219,7 @@ wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec,
|
||||
}
|
||||
|
||||
/* Prefix the key with the MIME content type. */
|
||||
if (!binary)
|
||||
es_fputs ("Content-Type: application/pgp-keys\n"
|
||||
"\n", key);
|
||||
|
||||
@ -223,6 +241,7 @@ 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");
|
||||
if (!binary)
|
||||
ccparray_put (&ccp, "--armor");
|
||||
ccparray_put (&ccp, "--export-options=export-minimal");
|
||||
ccparray_put (&ccp, "--export-filter");
|
||||
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user