1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-01-18 14:17:03 +01: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 @cat $(srcdir)/tests/gpgconf.ctl.in > bin/gpgconf.ctl
(set -e; cd bin; \ (set -e; cd bin; \
for i in gpg gpgv; \ for i in gpg gpgv; \
do ln -sf ../g10/$$i .; done; \ do ln -sf ../g10/$$i$(EXEEXT) .; done; \
for i in gpgsm; \ for i in gpgsm; \
do ln -sf ../sm/$$i .; done; \ do ln -sf ../sm/$$i$(EXEEXT) .; done; \
for i in gpg-agent; \ for i in gpg-agent; \
do ln -sf ../agent/$$i .; done; \ do ln -sf ../agent/$$i$(EXEEXT) .; done; \
for i in dirmngr; \ 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; \ 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 ; \ cd ../libexec ; \
for i in keyboxd; \ for i in keyboxd; \
do ln -sf ../kbx/$$i .; done; \ do ln -sf ../kbx/$$i$(EXEEXT) .; done; \
for i in scdaemon; \ for i in scdaemon; \
do ln -sf ../scd/$$i .; done; \ do ln -sf ../scd/$$i$(EXEEXT) .; done; \
for i in gpg-preset-passphrase; \ for i in gpg-preset-passphrase; \
do ln -sf ../agent/$$i .; done; \ do ln -sf ../agent/$$i$(EXEEXT) .; done; \
for i in tpm2daemon; \ 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" ) echo "created links to binaries" )
@ -213,12 +213,13 @@ TESTS_ENVIRONMENT = \
abs_top_srcdir=$(abs_top_srcdir) \ abs_top_srcdir=$(abs_top_srcdir) \
objdir=$(abs_top_builddir) \ objdir=$(abs_top_builddir) \
GNUPG_BUILD_ROOT="$(abs_top_builddir)" \ GNUPG_BUILD_ROOT="$(abs_top_builddir)" \
GNUPG_IN_TEST_SUITE=fact \
GPGSCM_PATH=$(abs_top_srcdir)/tests/gpgscm GPGSCM_PATH=$(abs_top_srcdir)/tests/gpgscm
.PHONY: check-all release sign-release .PHONY: check-all release sign-release
check-all: check-all:
$(TESTS_ENVIRONMENT) \ $(TESTS_ENVIRONMENT) \
$(abs_top_builddir)/tests/gpgscm/gpgscm \ $(abs_top_builddir)/tests/gpgscm/gpgscm$(EXEEXT) \
$(abs_srcdir)/tests/run-tests.scm $(TESTFLAGS) $(TESTS) $(abs_srcdir)/tests/run-tests.scm $(TESTFLAGS) $(TESTS)
# Names of to help the release target. # Names of to help the release target.

View File

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

View File

@ -2935,7 +2935,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
static const char hlp_export_key[] = 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" "\n"
"Export a secret key from the key store. The key will be encrypted\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" "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" "prior to using this command. The function takes the keygrip as argument.\n"
"\n" "\n"
"If --openpgp is used, the secret key material will be exported in RFC 4880\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" "compatible passphrase-protected form. If --mode1003 is use the secret key\n"
"material will be exported in the clear (after prompting the user to unlock\n" "is exported as s-expression as storred locally. Without those options,\n"
"it, if needed).\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 static gpg_error_t
cmd_export_key (assuan_context_t ctx, char *line) 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; gcry_cipher_hd_t cipherhd = NULL;
unsigned char *wrappedkey = NULL; unsigned char *wrappedkey = NULL;
size_t wrappedkeylen; size_t wrappedkeylen;
int openpgp; int openpgp, mode1003;
char *cache_nonce; char *cache_nonce;
char *passphrase = NULL; char *passphrase = NULL;
unsigned char *shadow_info = 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)); return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
openpgp = has_option (line, "--openpgp"); openpgp = has_option (line, "--openpgp");
mode1003 = has_option (line, "--mode1003");
if (mode1003)
openpgp = 0;
cache_nonce = option_value (line, "--cache-nonce"); cache_nonce = option_value (line, "--cache-nonce");
if (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 /* 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
err = agent_key_from_file (ctrl, cache_nonce, * mode1003 we return the key as-is. FIXME: if the key is still in
ctrl->server_local->keydesc, grip, * OpenPGP-native mode we should first convert it to our internal
&shadow_info, CACHE_MODE_IGNORE, NULL, &s_skey, * protection. */
openpgp ? &passphrase : NULL, NULL); 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) if (err)
goto leave; goto leave;
if (shadow_info) if (shadow_info)
@ -4150,6 +4161,11 @@ command_has_option (const char *cmd, const char *cmdopt)
if (!strcmp (cmdopt, "newsymkey")) if (!strcmp (cmdopt, "newsymkey"))
return 1; return 1;
} }
else if (!strcmp (cmd, "EXPORT_KEY"))
{
if (!strcmp (cmdopt, "mode1003"))
return 1;
}
return 0; 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) if (!list)
goto bad_seckey; goto bad_seckey;
value = gcry_sexp_nth_data (list, 1, &valuelen); 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; goto bad_seckey;
is_v4 = (value[0] == '4'); is_v4 = (value[0] == '4' || value[0] == '5');
gcry_sexp_release (list); gcry_sexp_release (list);
list = gcry_sexp_find_token (top_list, "protection", 0); 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; gcry_sexp_release (top_list); top_list = NULL;
#if 0 #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 pubkey_algo=%d\n", pubkey_algo);
log_debug ("XXX is_protected=%d\n", is_protected); log_debug ("XXX is_protected=%d\n", is_protected);
log_debug ("XXX protect_algo=%d\n", protect_algo); log_debug ("XXX protect_algo=%d\n", protect_algo);

View File

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

View File

@ -609,7 +609,7 @@ gnupg_tmpfile (void)
char *name, *p; char *name, *p;
HANDLE file; HANDLE file;
int pid = GetCurrentProcessId (); int pid = GetCurrentProcessId ();
unsigned int value; unsigned int value = 0;
int i; int i;
SECURITY_ATTRIBUTES sec_attr; SECURITY_ATTRIBUTES sec_attr;
@ -634,12 +634,9 @@ gnupg_tmpfile (void)
for (attempts=0; attempts < 10; attempts++) for (attempts=0; attempts < 10; attempts++)
{ {
p = name; p = name;
value = (GetTickCount () ^ ((pid<<16) & 0xffff0000)); value += (GetTickCount () ^ ((pid<<16) & 0xffff0000));
for (i=0; i < 8; i++) for (i=0; i < 8; i++)
{ *p++ = tohex (((value >> (7 - i)*4) & 0x0f));
*p++ = tohex (((value >> 28) & 0x0f));
value <<= 4;
}
strcpy (p, ".tmp"); strcpy (p, ".tmp");
file = CreateFile (buffer, file = CreateFile (buffer,
GENERIC_READ | GENERIC_WRITE, GENERIC_READ | GENERIC_WRITE,
@ -1195,19 +1192,28 @@ gnupg_unsetenv (const char *name)
#else /*!HAVE_UNSETENV*/ #else /*!HAVE_UNSETENV*/
{ {
char *buf; char *buf;
int r;
if (!name) if (!name)
{ {
gpg_err_set_errno (EINVAL); gpg_err_set_errno (EINVAL);
return -1; return -1;
} }
buf = xtrystrdup (name); buf = strconcat (name, "=", NULL);
if (!buf) if (!buf)
return -1; 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__ # if __GNUC__
# warning no unsetenv - trying putenv but leaking memory. # warning no unsetenv - trying putenv but leaking memory.
# endif # endif
return putenv (buf); # endif
return r;
} }
#endif /*!HAVE_UNSETENV*/ #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 /* Hash the file FNAME and return the MD5 digest in MD5BUFFER. The
caller must allocate MD%buffer wityh at least 16 bytes. Returns 0 * caller must allocate MD5buffer with at least 16 bytes. Returns 0
on success. */ * on success. */
static int static int
hash_dbfile (const char *fname, unsigned char *md5buffer) 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; goto leave;
} }
gcry_log_debugsxp ("sig ", s_sig); if (DBG_CRYPTO)
gcry_log_debugsxp ("hash", s_hash); {
gcry_log_debugsxp ("sig ", s_sig);
gcry_log_debugsxp ("hash", s_hash);
}
err = gcry_pk_verify (s_sig, s_hash, s_pkey); err = gcry_pk_verify (s_sig, s_hash, s_pkey);
if (err) if (err)

View File

@ -1504,6 +1504,14 @@ CREATE TABLE signatures (
- One octet with the length of the following serial number. - One octet with the length of the following serial number.
- The serial number. Regardless of what the length octet - The serial number. Regardless of what the length octet
indicates no more than 16 octets are stored. 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 Note that gpg stores the GNU S2K Extension Number internally as an
S2K Specifier with an offset of 1000. S2K Specifier with an offset of 1000.
@ -1694,6 +1702,10 @@ Description of some debug flags:
- RFC-6337 :: ECC in OpenPGP - RFC-6337 :: ECC in OpenPGP
- RFC-7292 :: PKCS #12: Personal Information Exchange Syntax v1.1 - RFC-7292 :: PKCS #12: Personal Information Exchange Syntax v1.1
- RFC-8351 :: The PKCS #8 EncryptedPrivateKeyInfo Media Type - 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 - 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. 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} @item --list-options @var{parameters}
@opindex list-options @opindex list-options
This is a space or comma delimited string that gives options used when 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. Self-signatures are not considered.
Currently only implemented for --import-filter. 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 @end table
For the syntax of the expression see the chapter "FILTER EXPRESSIONS". For the syntax of the expression see the chapter "FILTER EXPRESSIONS".
The property names for the expressions depend on the actual filter 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: 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. The addr-spec part of a user id with mailbox or the empty string.
(keep-uid) (keep-uid)
@item algostr
A string with the key algorithm description. For example "rsa3072"
or "ed25519".
@item key_algo @item key_algo
A number with the public key algorithm of a key or subkey packet. A number with the public key algorithm of a key or subkey packet.
(drop-subkey) (drop-subkey)
@item key_size
A number with the effective key size of a key or subkey packet.
(drop-subkey)
@item key_created @item key_created
@itemx key_created_d @itemx key_created_d
The first is the timestamp a public key or subkey packet was The first is the timestamp a public key or subkey packet was
@ -2593,7 +2618,7 @@ The available properties are:
been revoked. been revoked.
@item disabled @item disabled
Boolean indicating whether a primary key is disabled. (not used) Boolean indicating whether a primary key is disabled.
@item secret @item secret
Boolean indicating whether a key or subkey is a secret one. Boolean indicating whether a key or subkey is a secret one.
@ -2616,6 +2641,18 @@ The available properties are:
@item sig_digest_algo @item sig_digest_algo
A number with the digest algorithm of a signature packet. (drop-sig) 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 @end table
@item --export-options @var{parameters} @item --export-options @var{parameters}
@ -2673,12 +2710,27 @@ opposite meaning. The options are:
running the @option{--edit-key} command "minimize" before export except running the @option{--edit-key} command "minimize" before export except
that the local copy of the key is not modified. Defaults to no. 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 @item export-dane
Instead of outputting the key material output OpenPGP DANE records Instead of outputting the key material output OpenPGP DANE records
suitable to put into DNS zone files. An ORIGIN line is printed before suitable to put into DNS zone files. An ORIGIN line is printed before
each record to allow diverting the records to the corresponding zone each record to allow diverting the records to the corresponding zone
file. 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 @end table
@item --with-colons @item --with-colons

View File

@ -433,7 +433,8 @@ name may be changed on the command line (@pxref{option --options}).
@cindex scd-event @cindex scd-event
If this file is present and executable, it will be called on every card 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 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 @item reader_@var{n}.status
This file is created by @command{scdaemon} to let other applications now 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 addrspec, e.g. "postel@@isi.edu") per line. Empty lines and lines
starting with a '#' are ignored. 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 @item --verbose
@opindex verbose @opindex verbose
Enable extra informational output. Enable extra informational output.

View File

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

View File

@ -674,7 +674,8 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
count += 8; /* Salt. */ count += 8; /* Salt. */
if (ski->s2k.mode == 3) if (ski->s2k.mode == 3)
count++; /* S2K.COUNT */ 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; count += ski->ivlen;
iobuf_put (a, count); iobuf_put (a, count);
@ -704,8 +705,9 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
if (ski->s2k.mode == 3) if (ski->s2k.mode == 3)
iobuf_put (a, ski->s2k.count); iobuf_put (a, ski->s2k.count);
/* For our special modes 1001, 1002 we do not need an IV. */ /* For our special modes 1001..1003 we do not need an IV. */
if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002) if (ski->s2k.mode != 1001 && ski->s2k.mode != 1002
&& ski->s2k.mode != 1003)
iobuf_write (a, ski->iv, ski->ivlen); 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. */ /* The serial number gets stored in the IV field. */
iobuf_write (a, ski->iv, ski->ivlen); 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) else if (ski->is_protected)
{ {
/* The secret key is protected - write it out as it is. */ /* 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 keygrip, DESC a prompt to be displayed with the agent's passphrase
question (needs to be plus+percent escaped). if OPENPGP_PROTECTED question (needs to be plus+percent escaped). if OPENPGP_PROTECTED
is not zero, ensure that the key material is returned in RFC is not zero, ensure that the key material is returned in RFC
4880-compatible passphrased-protected form. If CACHE_NONCE_ADDR is 4880-compatible passphrased-protected form; if instead MODE1003 is
not NULL the agent is advised to first try a passphrase associated not zero the raw gpg-agent private key format is requested (either
with that nonce. On success the key is stored as a canonical protected or unprotected). If CACHE_NONCE_ADDR is not NULL the
S-expression at R_RESULT and R_RESULTLEN. */ 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 gpg_error_t
agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc, 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, unsigned char **r_result, size_t *r_resultlen,
u32 *keyid, u32 *mainkeyid, int pubkey_algo) 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; return err;
dfltparm.ctx = agent_ctx; 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) if (desc)
{ {
snprintf (line, DIM(line), "SETKEYDESC %s", 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", 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=":"",
cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"", cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
hexkeygrip); 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. */ /* Receive a key from the agent. */
gpg_error_t agent_export_key (ctrl_t ctrl, const char *keygrip, gpg_error_t agent_export_key (ctrl_t ctrl, const char *keygrip,
const char *desc, int openpgp_protected, const char *desc, int openpgp_protected,
char **cache_nonce_addr, int mode1003, char **cache_nonce_addr,
unsigned char **r_result, size_t *r_resultlen, unsigned char **r_result, size_t *r_resultlen,
u32 *keyid, u32 *mainkeyid, int pubkey_algo); u32 *keyid, u32 *mainkeyid, int pubkey_algo);

View File

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

View File

@ -2,6 +2,7 @@
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004,
* 2005, 2010 Free Software Foundation, Inc. * 2005, 2010 Free Software Foundation, Inc.
* Copyright (C) 1998-2016 Werner Koch * Copyright (C) 1998-2016 Werner Koch
* Copyright (C) 2022 g10 Code GmbH
* *
* This file is part of GnuPG. * 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 keep-uid=EXPR.
* --export-filter drop-subkey=EXPR. * --export-filter drop-subkey=EXPR.
* --export-filter select=EXPR.
* *
* FIXME: We should put this into the CTRL object but that requires a * FIXME: We should put this into the CTRL object but that requires a
* lot more changes right now. * lot more changes right now.
*/ */
static recsel_expr_t export_keep_uid; static recsel_expr_t export_keep_uid;
static recsel_expr_t export_drop_subkey; static recsel_expr_t export_drop_subkey;
static recsel_expr_t export_select_filter;
/* An object used for a linked list to implement the /* 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; struct export_filter_attic_s *next;
recsel_expr_t export_keep_uid; recsel_expr_t export_keep_uid;
recsel_expr_t export_drop_subkey; recsel_expr_t export_drop_subkey;
recsel_expr_t export_select_filter;
}; };
static struct export_filter_attic_s *export_filter_attic; static struct export_filter_attic_s *export_filter_attic;
@ -105,6 +109,8 @@ cleanup_export_globals (void)
export_keep_uid = NULL; export_keep_uid = NULL;
recsel_release (export_drop_subkey); recsel_release (export_drop_subkey);
export_drop_subkey = NULL; 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-dane", EXPORT_DANE_FORMAT, NULL, NULL },
{"export-revocs", EXPORT_REVOCS, NULL,
N_("export only revocation certificates") },
{"backup", EXPORT_BACKUP, NULL, {"backup", EXPORT_BACKUP, NULL,
N_("use the GnuPG key backup format")}, N_("use the GnuPG key backup format")},
{"export-backup", EXPORT_BACKUP, NULL, NULL }, {"export-backup", EXPORT_BACKUP, NULL, NULL },
{"mode1003", EXPORT_MODE1003, NULL,
N_("export secret keys using the GnuPG format") },
/* Aliases for backward compatibility */ /* Aliases for backward compatibility */
{"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL}, {"include-local-sigs",EXPORT_LOCAL_SIGS,NULL,NULL},
{"include-attributes",EXPORT_ATTRIBUTES,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. * - secret :: 1 for a secret subkey, else 0.
* - key_algo :: Public key algorithm id * - key_algo :: Public key algorithm id
*
* - select :: The key is only exported if the filter returns true.
*/ */
gpg_error_t gpg_error_t
parse_and_set_export_filter (const char *string) 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); err = recsel_parse_expr (&export_keep_uid, string+9);
else if (!strncmp (string, "drop-subkey=", 12)) else if (!strncmp (string, "drop-subkey=", 12))
err = recsel_parse_expr (&export_drop_subkey, string+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 else
err = gpg_error (GPG_ERR_INV_NAME); err = gpg_error (GPG_ERR_INV_NAME);
@ -217,6 +233,8 @@ push_export_filters (void)
export_keep_uid = NULL; export_keep_uid = NULL;
item->export_drop_subkey = export_drop_subkey; item->export_drop_subkey = export_drop_subkey;
export_drop_subkey = NULL; export_drop_subkey = NULL;
item->export_select_filter = export_select_filter;
export_select_filter = NULL;
item->next = export_filter_attic; item->next = export_filter_attic;
export_filter_attic = item; export_filter_attic = item;
} }
@ -235,6 +253,7 @@ pop_export_filters (void)
cleanup_export_globals (); cleanup_export_globals ();
export_keep_uid = item->export_keep_uid; export_keep_uid = item->export_keep_uid;
export_drop_subkey = item->export_drop_subkey; 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 /* Take a cleartext dump of a secret key in PK and change the
* parameter array in PK to include the secret parameters. */ * parameter array in PK to include the secret parameters. */
static gpg_error_t static gpg_error_t
@ -1233,29 +1429,51 @@ print_status_exported (PKT_public_key *pk)
* passphrase-protected. Otherwise, store secret key material in the * passphrase-protected. Otherwise, store secret key material in the
* clear. * 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. * 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 gpg_error_t
receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, 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, 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; gpg_error_t err = 0;
unsigned char *wrappedkey = NULL; unsigned char *wrappedkey = NULL;
size_t wrappedkeylen; size_t wrappedkeylen;
unsigned char *key = NULL; unsigned char *key = NULL;
size_t keylen, realkeylen; size_t keylen, realkeylen;
gcry_sexp_t s_skey; gcry_sexp_t s_skey = NULL;
char *prompt; char *prompt;
if (r_key)
*r_key = NULL;
if (opt.verbose) if (opt.verbose)
log_info ("key %s: asking agent for the secret parts\n", hexgrip); log_info ("key %s: asking agent for the secret parts\n", hexgrip);
prompt = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_EXPORT,1); if (pk)
err = agent_export_key (ctrl, hexgrip, prompt, !cleartext, cache_nonce_addr, {
&wrappedkey, &wrappedkeylen, prompt = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_EXPORT, 1);
pk->keyid, pk->main_keyid, pk->pubkey_algo); 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); xfree (prompt);
if (err) 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); err = gcry_sexp_sscan (&s_skey, NULL, key, realkeylen);
if (!err) 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); err = cleartext_secret_key_to_openpgp (s_skey, pk);
else else if (pk)
err = transfer_format_to_openpgp (s_skey, 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: unwraperror:
gcry_sexp_release (s_skey);
xfree (key); xfree (key);
xfree (wrappedkey); xfree (wrappedkey);
if (err) if (err)
@ -1795,8 +2020,10 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
else if (!err) else if (!err)
{ {
err = receive_seckey_from_agent (ctrl, cipherhd, err = receive_seckey_from_agent (ctrl, cipherhd,
cleartext, &cache_nonce, cleartext,
hexgrip, pk); !!(options & EXPORT_MODE1003),
&cache_nonce,
hexgrip, pk, NULL);
if (err) if (err)
{ {
if (gpg_err_code (err) == GPG_ERR_FULLY_CANCELED) 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. /* For secret key export we need to setup a decryption context.
* Returns 0 and the context at r_cipherhd. */ * Returns 0 and the context at r_cipherhd. */
static gpg_error_t static gpg_error_t
@ -2066,13 +2365,33 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
NULL, NULL); NULL, NULL);
commit_kbnode (&keyblock); 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 /* Need to merge so that for example the "usage" property
* has been setup. */ * has been setup. */
merge_keys_and_selfsig (ctrl, keyblock); 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) if (export_keep_uid)
{ {
commit_kbnode (&keyblock); commit_kbnode (&keyblock);
@ -2088,10 +2407,15 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
} }
/* And write it. */ /* And write it. */
err = do_export_one_keyblock (ctrl, keyblock, keyid, if ((options & EXPORT_REVOCS))
out_help? out_help : out, err = do_export_revocs (ctrl, keyblock, keyid,
secret, options, stats, any, out_help? out_help : out,
desc, ndesc, descindex, cipherhd); 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) if (err)
break; 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. /* Export the key identified by USERID in the SSH secret key format.
* The USERID must be given in keygrip format (prefixed with a '&') * The USERID must be given in keygrip format (prefixed with a '&')
* and thus no OpenPGP key is required. The exported key is not * 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))) if ((err = get_keywrap_key (ctrl, &cipherhd)))
goto leave; 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) if (err)
goto leave; goto leave;

View File

@ -327,6 +327,7 @@ enum cmd_and_opt_values
oExportOptions, oExportOptions,
oExportFilter, oExportFilter,
oListOptions, oListOptions,
oListFilter,
oVerifyOptions, oVerifyOptions,
oTempDir, oTempDir,
oExecPath, oExecPath,
@ -794,6 +795,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_header ("Keylist", N_("Options controlling key listings")), ARGPARSE_header ("Keylist", N_("Options controlling key listings")),
ARGPARSE_s_s (oListOptions, "list-options", "@"), ARGPARSE_s_s (oListOptions, "list-options", "@"),
ARGPARSE_s_s (oListFilter, "list-filter", "@"),
ARGPARSE_s_n (oFullTimestrings, "full-timestrings", "@"), ARGPARSE_s_n (oFullTimestrings, "full-timestrings", "@"),
ARGPARSE_s_n (oShowPhotos, "show-photos", "@"), ARGPARSE_s_n (oShowPhotos, "show-photos", "@"),
ARGPARSE_s_n (oNoShowPhotos, "no-show-photos", "@"), ARGPARSE_s_n (oNoShowPhotos, "no-show-photos", "@"),
@ -3357,6 +3359,11 @@ main (int argc, char **argv)
if (rc) if (rc)
log_error (_("invalid filter option: %s\n"), gpg_strerror (rc)); log_error (_("invalid filter option: %s\n"), gpg_strerror (rc));
break; 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: case oListOptions:
if(!parse_list_options(pargs.r.ret_str)) 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; *r_comment = NULL;
return 0; 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 * const char *
impex_filter_getval (void *cookie, const char *propname) 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; kbnode_t node = parm->node;
static char numbuf[20]; static char numbuf[20];
const char *result; const char *result;
const char *s;
enum { scpNone = 0, scpPub, scpSub, scpUid, scpSig} scope = 0;
log_assert (ctrl && ctrl->magic == SERVER_CONTROL_MAGIC); 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
|| node->pkt->pkttype == PKT_ATTRIBUTE) * 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; PKT_user_id *uid = node->pkt->pkt.user_id;
@ -1473,7 +1495,8 @@ impex_filter_getval (void *cookie, const char *propname)
else else
result = NULL; 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; PKT_signature *sig = node->pkt->pkt.signature;
@ -1503,10 +1526,12 @@ impex_filter_getval (void *cookie, const char *propname)
else else
result = NULL; result = NULL;
} }
else if (node->pkt->pkttype == PKT_PUBLIC_KEY else if (((node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_SECRET_KEY || node->pkt->pkttype == PKT_SECRET_KEY)
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY && (!scope || scope == scpPub))
|| node->pkt->pkttype == PKT_SECRET_SUBKEY) || ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
&& (!scope || scope == scpSub)))
{ {
PKT_public_key *pk = node->pkt->pkt.public_key; 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); snprintf (numbuf, sizeof numbuf, "%d", pk->pubkey_algo);
result = numbuf; 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")) else if (!strcmp (propname, "key_created"))
{ {
snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->timestamp); 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); hexfingerprint (pk, parm->hexfpr, sizeof parm->hexfpr);
result = 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 else
result = NULL; result = NULL;
} }

View File

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

View File

@ -44,6 +44,8 @@
#include "../common/mbox-util.h" #include "../common/mbox-util.h"
#include "../common/zb32.h" #include "../common/zb32.h"
#include "tofu.h" #include "tofu.h"
#include "../common/init.h"
#include "../common/recsel.h"
#include "../common/compliance.h" #include "../common/compliance.h"
#include "../common/pkscreening.h" #include "../common/pkscreening.h"
@ -64,16 +66,26 @@ struct keylist_context
int no_validity; /* Do not show validity. */ int no_validity; /* Do not show validity. */
}; };
/* An object and a global instance to store selectors created from
static void list_keyblock (ctrl_t ctrl, * --list-filter select=EXPR.
kbnode_t keyblock, int secret, int has_secret, */
int fpr, struct keylist_context *listctx); struct list_filter_s
{
recsel_expr_t selkey;
};
struct list_filter_s list_filter;
/* The stream used to write attribute packets to. */ /* The stream used to write attribute packets to. */
static estream_t attrib_fp; 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. */ /* Release resources from a keylist context. */
static void static void
keylist_context_release (struct keylist_context *listctx) 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. /* 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 * 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 * 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); do_reorder_keyblock (keyblock, 0);
} }
static void static void
list_keyblock (ctrl_t ctrl, list_keyblock (ctrl_t ctrl,
KBNODE keyblock, int secret, int has_secret, int fpr, KBNODE keyblock, int secret, int has_secret, int fpr,
@ -2170,6 +2226,24 @@ list_keyblock (ctrl_t ctrl,
{ {
reorder_keyblock (keyblock); 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) if (opt.with_colons)
list_keyblock_colon (ctrl, keyblock, secret, has_secret); list_keyblock_colon (ctrl, keyblock, secret, has_secret);
else if ((opt.list_options & LIST_SHOW_ONLY_FPR_MBOX)) 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); void **r_data, size_t *r_datalen);
gpg_error_t receive_seckey_from_agent (ctrl_t ctrl, gcry_cipher_hd_t cipherhd, 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, char **cache_nonce_addr,
const char *hexgrip, 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, gpg_error_t write_keyblock_to_output (kbnode_t keyblock,
int with_armor, unsigned int options); 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, void public_key_list (ctrl_t ctrl, strlist_t list,
int locate_mode, int no_local); int locate_mode, int no_local);
void secret_key_list (ctrl_t ctrl, strlist_t list ); 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 print_subpackets_colon(PKT_signature *sig);
void reorder_keyblock (KBNODE keyblock); void reorder_keyblock (KBNODE keyblock);
void list_keyblock_direct (ctrl_t ctrl, kbnode_t keyblock, int secret, 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. */ /* 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. */ /* Overriding session key voids compliance. */
&& !opt.override_session_key && !opt.override_session_key
/* Check symmetric cipher. */ /* 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_CLEAN (1<<5)
#define EXPORT_DANE_FORMAT (1<<7) #define EXPORT_DANE_FORMAT (1<<7)
#define EXPORT_BACKUP (1<<10) #define EXPORT_BACKUP (1<<10)
#define EXPORT_REVOCS (1<<11)
#define EXPORT_MODE1003 (1<<12)
#define LIST_SHOW_PHOTOS (1<<0) #define LIST_SHOW_PHOTOS (1<<0)
#define LIST_SHOW_POLICY_URLS (1<<1) #define LIST_SHOW_POLICY_URLS (1<<1)

View File

@ -2752,11 +2752,15 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
break; break;
case 1001: case 1001:
if (list_mode) if (list_mode)
es_fprintf (listfp, "\tgnu-dummy S2K"); es_fprintf (listfp, "\tgnu-dummy");
break; break;
case 1002: case 1002:
if (list_mode) 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; break;
default: default:
if (list_mode) if (list_mode)
@ -2768,7 +2772,7 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
} }
/* Print some info. */ /* Print some info. */
if (list_mode) if (list_mode && ski->s2k.mode != 1003)
{ {
es_fprintf (listfp, ", algo: %d,%s hash: %d", es_fprintf (listfp, ", algo: %d,%s hash: %d",
ski->algo, ski->algo,
@ -2779,8 +2783,9 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
es_fprintf (listfp, ", salt: "); es_fprintf (listfp, ", salt: ");
es_write_hexstring (listfp, ski->s2k.salt, 8, 0, NULL); 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. */ /* Read remaining protection parameters. */
if (ski->s2k.mode == 3) 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); ski->ivlen = openpgp_cipher_blocklen (ski->algo);
log_assert (ski->ivlen <= sizeof (temp)); log_assert (ski->ivlen <= sizeof (temp));
if (ski->s2k.mode == 1001) if (ski->s2k.mode == 1001 || ski->s2k.mode == 1003)
ski->ivlen = 0; ski->ivlen = 0;
else if (ski->s2k.mode == 1002) else if (ski->s2k.mode == 1002)
ski->ivlen = snlen < 16 ? snlen : 16; 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--) for (i = 0; i < ski->ivlen; i++, pktlen--)
temp[i] = iobuf_get_noeof (inp); temp[i] = iobuf_get_noeof (inp);
if (list_mode) if (list_mode && ski->s2k.mode != 1003)
{ {
es_fprintf (listfp, es_fprintf (listfp,
ski->s2k.mode == 1002 ? "\tserial-number: " ski->s2k.mode == 1002 ? "\tserial-number: "
@ -2888,6 +2893,35 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
10 * 8); 10 * 8);
pktlen = 0; 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) else if (ski->is_protected)
{ {
void *tmpp; void *tmpp;

View File

@ -572,3 +572,11 @@ get_revocation_reason (PKT_signature *sig, char **r_reason,
*r_comment = NULL; *r_comment = NULL;
return 0; 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")))) "g13"))))
(if g13-enabled? (if g13-enabled?
(map (lambda (name) (map (lambda (name)
(test::binary #f (let ((name-ext (string-append name (getenv "EXEEXT"))))
(path-join "g13" name) (test::binary #f
(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") (parse-makefile-expand (in-srcdir "g13" "Makefile.am")
(lambda (filename port key) (parse-makefile port key)) (lambda (filename port key) (parse-makefile port key))
"module_tests")) "module_tests"))

View File

@ -773,7 +773,14 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
return err; return err;
if (DBG_CARD_IO) 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)) if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
send_pci.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; return err;
if (DBG_CARD_IO) 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; maxbuflen = *buflen;
if (pininfo) if (pininfo)

View File

@ -516,7 +516,7 @@ static int default_include_certs = DEFAULT_INCLUDE_CERTS;
static int default_validation_model; static int default_validation_model;
/* The default cipher algo. */ /* The default cipher algo. */
#define DEFAULT_CIPHER_ALGO "AES" #define DEFAULT_CIPHER_ALGO "AES256"
static char *build_list (const char *text, 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 /* FIXME: INFO_PKALGO correctly shows ECDSA but PKALGO is then
* ECC. We should use the ECDSA here and need to find a way to * ECC. We should use the ECDSA here and need to find a way to
* figure this oult without using the bodus assumtion in * figure this out without using the bogus assumption in
* gpgsm_check_cms_signature that ECC is alwas ECDSA. */ * gpgsm_check_cms_signature that ECC is always ECDSA. */
fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1); fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
tstr = strtimestamp_r (sigtime); tstr = strtimestamp_r (sigtime);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -29,6 +29,6 @@
(for-each-p (for-each-p
"Checking invocation with invalid file descriptors (issue2941)." "Checking invocation with invalid file descriptors (issue2941)."
(lambda (option) (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" '("status-fd" "attribute-fd" "logger-fd"
"override-session-key-fd" "passphrase-fd" "command-fd")) "override-session-key-fd" "passphrase-fd" "command-fd"))

View File

@ -28,6 +28,7 @@
(define setup (define setup
(make-environment-cache (test::scm (make-environment-cache (test::scm
#f
#f #f
(path-join "tests" "openpgp" "setup.scm") (path-join "tests" "openpgp" "setup.scm")
(in-srcdir "tests" "openpgp" "setup.scm")))) (in-srcdir "tests" "openpgp" "setup.scm"))))
@ -55,11 +56,12 @@
(if use-keyboxd? (if use-keyboxd?
(map (lambda (name) (map (lambda (name)
(test::scm setup-use-keyboxd (test::scm setup-use-keyboxd
(qualify (path-join "tests" "openpgp" name) "keyboxd"
"keyboxd") (path-join "tests" "openpgp" name)
(in-srcdir "tests" "openpgp" name) (in-srcdir "tests" "openpgp" name)
"--use-keyboxd")) tests) "--use-keyboxd")) tests)
(map (lambda (name) (map (lambda (name)
(test::scm setup (test::scm setup
#f
(path-join "tests" "openpgp" name) (path-join "tests" "openpgp" name)
(in-srcdir "tests" "openpgp" name))) tests)))) (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 \ TESTS_ENVIRONMENT = GNUPGHOME=`/bin/pwd` GPG_AGENT_INFO= LC_ALL=C \
GNUPG_BUILD_ROOT="$(abs_top_builddir)" \ GNUPG_BUILD_ROOT="$(abs_top_builddir)" \
GNUPG_IN_TEST_SUITE=fact \ GNUPG_IN_TEST_SUITE=fact \
GPGSM=$(GPGSM) silent=yes GPGSM=$(GPGSM)$(EXEEXT) silent=yes
testscripts = import-all-certs validate-all-certs \ testscripts = import-all-certs validate-all-certs \

View File

@ -76,6 +76,7 @@ enum cmd_and_opt_values
oWithColons, oWithColons,
oBlacklist, oBlacklist,
oNoAutostart, oNoAutostart,
oAddRevocs,
oDummy oDummy
}; };
@ -102,9 +103,9 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_c (aRemoveKey, "remove-key", ARGPARSE_c (aRemoveKey, "remove-key",
"remove a key from a directory"), "remove a key from a directory"),
ARGPARSE_c (aPrintWKDHash, "print-wkd-hash", 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", 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 ")), ARGPARSE_group (301, ("@\nOptions:\n ")),
@ -119,6 +120,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_n (oWithColons, "with-colons", "@"), ARGPARSE_s_n (oWithColons, "with-colons", "@"),
ARGPARSE_s_s (oBlacklist, "blacklist", "@"), ARGPARSE_s_s (oBlacklist, "blacklist", "@"),
ARGPARSE_s_s (oDirectory, "directory", "@"), ARGPARSE_s_s (oDirectory, "directory", "@"),
ARGPARSE_s_n (oAddRevocs, "add-revocs", "add revocation certificates"),
ARGPARSE_s_s (oFakeSubmissionAddr, "fake-submission-addr", "@"), ARGPARSE_s_s (oFakeSubmissionAddr, "fake-submission-addr", "@"),
@ -257,6 +259,9 @@ parse_arguments (gpgrt_argparse_t *pargs, gpgrt_opt_t *popts)
case oBlacklist: case oBlacklist:
add_blacklist (pargs->r.ret_str); add_blacklist (pargs->r.ret_str);
break; break;
case oAddRevocs:
opt.add_revocs = 1;
break;
case aSupported: case aSupported:
case aCreate: case aCreate:
@ -1164,7 +1169,7 @@ command_send (const char *fingerprint, const char *userid)
err = gpg_error (GPG_ERR_INV_USER_ID); err = gpg_error (GPG_ERR_INV_USER_ID);
goto leave; goto leave;
} }
err = wks_get_key (&key, fingerprint, addrspec, 0); err = wks_get_key (&key, fingerprint, addrspec, 0, 1);
if (err) if (err)
goto leave; goto leave;
@ -1232,7 +1237,7 @@ command_send (const char *fingerprint, const char *userid)
estream_t newkey; estream_t newkey;
es_rewind (key); es_rewind (key);
err = wks_filter_uid (&newkey, key, thisuid->uid, 0); err = wks_filter_uid (&newkey, key, thisuid->uid, 1);
if (err) if (err)
{ {
log_error ("error filtering key: %s\n", gpg_strerror (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. */ * the key again. */
es_fclose (key); es_fclose (key);
key = NULL; key = NULL;
err = wks_get_key (&key, fingerprint, addrspec, 1); err = wks_get_key (&key, fingerprint, addrspec, 1, 1);
if (err) if (err)
goto leave; 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 /* Hack to support posteo but let them disable this by setting the
* new policy-version flag. */ * new policy-version flag. */
if (policy->protocol_version < 3 if (policy->protocol_version < 3
@ -1306,7 +1347,7 @@ command_send (const char *fingerprint, const char *userid)
if (no_encrypt) if (no_encrypt)
{ {
void *data; void *data;
size_t datalen, n; size_t datalen;
if (posteo_hack) if (posteo_hack)
{ {
@ -1331,16 +1372,7 @@ command_send (const char *fingerprint, const char *userid)
goto leave; goto leave;
} }
key = NULL; key = NULL;
/* We need to skip over the first line which has a content-type err = mime_maker_add_body_data (mime, data, datalen);
* 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);
xfree (data); xfree (data);
if (err) if (err)
goto leave; 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. /* 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 * 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 * so that for a key with
* uid: Joe Someone <joe@example.org> * uid: Joe Someone <joe@example.org>
* uid: Joe <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); err = gpg_error (GPG_ERR_NO_USER_ID);
goto leave; goto leave;
} }
/* FIXME: Consult blacklist. */
/* Always filter the key so that the result will be non-armored. */
/* 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*/
es_rewind (key); 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); log_error ("error filtering key %s: %s\n", fpr, gpg_strerror (err));
if (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) if (opt.verbose)
log_info ("key %s published for '%s'\n", fpr, mbox); log_info ("key %s published for '%s'\n", fpr, mbox);
mirror_one_key_parm.nuids++; mirror_one_key_parm.nuids++;

View File

@ -39,6 +39,7 @@ struct
int use_sendmail; int use_sendmail;
int with_colons; int with_colons;
int no_autostart; int no_autostart;
int add_revocs;
const char *output; const char *output;
const char *gpg_program; const char *gpg_program;
const char *directory; 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 wks_write_status (int no, const char *format, ...) GPGRT_ATTR_PRINTF(2,3);
void free_uidinfo_list (uidinfo_list_t list); void free_uidinfo_list (uidinfo_list_t list);
gpg_error_t wks_get_key (estream_t *r_key, const char *fingerprint, 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, gpg_error_t wks_list_key (estream_t key, char **r_fpr,
uidinfo_list_t *r_mboxes); uidinfo_list_t *r_mboxes);
gpg_error_t wks_filter_uid (estream_t *r_newkey, estream_t key, gpg_error_t wks_filter_uid (estream_t *r_newkey, estream_t key,
const char *uid, int binary); 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_send_mime (mime_maker_t mime);
gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream, gpg_error_t wks_parse_policy (policy_flags_t flags, estream_t stream,
int ignore_unknown); 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 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; 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")) if (!strcmp (keyword, "EXPORTED"))
{ {
parm->count++; 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 * 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 * returned user id must match Addrspec exactly and not just in the
* addr-spec (mailbox) part. The key is returned as a new memory * 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 gpg_error_t
wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec, wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec,
int exact) int exact, int binary)
{ {
gpg_error_t err; gpg_error_t err;
ccparray_t ccp; 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. */ /* Prefix the key with the MIME content type. */
es_fputs ("Content-Type: application/pgp-keys\n" if (!binary)
"\n", key); es_fputs ("Content-Type: application/pgp-keys\n"
"\n", key);
filterexp = es_bsprintf ("keep-uid=%s= %s", exact? "uid":"mbox", addrspec); filterexp = es_bsprintf ("keep-uid=%s= %s", exact? "uid":"mbox", addrspec);
if (!filterexp) 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, "--batch");
ccparray_put (&ccp, "--status-fd=2"); ccparray_put (&ccp, "--status-fd=2");
ccparray_put (&ccp, "--always-trust"); 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-options=export-minimal");
ccparray_put (&ccp, "--export-filter"); ccparray_put (&ccp, "--export-filter");
ccparray_put (&ccp, filterexp); ccparray_put (&ccp, filterexp);
@ -239,6 +258,7 @@ wks_get_key (estream_t *r_key, const char *fingerprint, const char *addrspec,
goto leave; goto leave;
} }
parm.fpr = fingerprint; parm.fpr = fingerprint;
debug_gpg_invocation (__func__, argv);
err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL, err = gnupg_exec_tool_stream (opt.gpg_program, argv, NULL,
NULL, key, NULL, key,
get_key_status_cb, &parm); 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 (); err = gpg_error_from_syserror ();
goto leave; goto leave;
} }
debug_gpg_invocation (__func__, argv);
err = gnupg_exec_tool_stream (opt.gpg_program, argv, key, err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
NULL, listing, NULL, listing,
key_status_cb, NULL); 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 (); err = gpg_error_from_syserror ();
goto leave; goto leave;
} }
debug_gpg_invocation (__func__, argv);
err = gnupg_exec_tool_stream (opt.gpg_program, argv, key, err = gnupg_exec_tool_stream (opt.gpg_program, argv, key,
NULL, newkey, NULL, newkey,
key_status_cb, NULL); 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). */ /* Helper to write mail to the output(s). */
gpg_error_t gpg_error_t
wks_send_mime (mime_maker_t mime) 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 /* FNAME looks like a fingerprint. Get the key from the
* standard keyring. */ * standard keyring. */
err = wks_get_key (&fp, fname, addrspec, 0); err = wks_get_key (&fp, fname, addrspec, 0, 1);
if (err) if (err)
{ {
log_error ("error getting key '%s' (uid='%s'): %s\n", 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; 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); err = wks_install_key_core (fp, addrspec);
if (!opt.quiet) if (!opt.quiet)
log_info ("key %s published for '%s'\n", fpr, addrspec); log_info ("key %s published for '%s'\n", fpr, addrspec);