Compare commits

...

470 Commits

Author SHA1 Message Date
Werner Koch 351fc6e6fa
gpg: Algo "kyber" is now a shortcut for ky768_bp256.
* g10/keygen.c (parse_key_parameter_part): Change Kyber defaults.
--

Also kyber1024 is now a shortcut for ky1024_bp384.  This change is to
align it with the original wussler draft.
2024-05-06 10:47:01 +02:00
Werner Koch 473f37a53e
scd:piv: Support listing of retired keys with KEYINFO.
* scd/app-piv.c (data_objects): Mark returned key as having a keypair.
(do_with_keygrip): Check against encrusage and not used one tag.

* tools/gpg-card.c (piv_keyref_is_retired): New.
(list_all_kinfo): Pretty print retired keys.
--

This allows to list all existing retired keys without using separate
readkey commands.
2024-05-06 09:48:20 +02:00
Werner Koch 467239dccb
speedo: Update the instructions to use the gnupg26 tag.
--
2024-05-02 21:13:32 +02:00
Werner Koch f415d96fac
gpg: Add a notation to Kyber encryption subkeys
* g10/keygen.c (struct opaque_data_usage_and_pk): New.
(do_add_notation): New.
(keygen_add_key_flags_from_oduap): New.
(write_keybinding): Prepare for de-vs cplimance notation.  Add a
notation to Kyber subkeys.
--

This code is based on the 2.2
commit b284412786
However the de-vs notation is currently ineffective as long as
Libgcrypt won't claim compliance.

The new notation fips203.ipd.2023-08-24 has been added to allow
detection of subkeys which have been crated with a pre-final FIPS203
spec for Kyber.
2024-05-02 21:11:55 +02:00
Werner Koch 516b530126
speedo: Change install directory for Windows
--

Given that we will build only 64 bit versions, we need to switch where
stuff is installed on Windows.
2024-04-26 15:17:49 +02:00
Werner Koch c8a3b711f0
speedo: Do not use the gpg-error-config in the build system
--

With that installed we don't get proper suport for SYSROOT.
2024-04-26 15:17:49 +02:00
Werner Koch c1d62418d5
speedo: Prepare for building 64 bit Windows versions.
--
2024-04-26 15:17:48 +02:00
Werner Koch 351f5e814b
speedo: Set gnupg_ver macro to gnupg26_ver.
--

Also fixed a syntax erro rin AUTHENTICODE_sign
2024-04-26 15:17:48 +02:00
NIIBE Yutaka 9128d81bb7
agent:kem:ecc: Support a key on smartcard.
* agent/agent.h (agent_card_ecc_kem): New.
* agent/divert-scd.c (agent_card_ecc_kem): New.
* agent/pkdecrypt.c (ecc_extract_pk_from_key): New.
(ecc_extract_sk_from_key): New.
(ecc_raw_kem, get_cardkey, ecc_get_curve): New.
(ecc_pgp_kem_decrypt): Support a key on smartcard for ECC.
(composite_pgp_kem_decrypt): Handle a case of a key on smartcard.
* common/sexputil.c (get_ecc_curve_from_key): New.
* common/util.h (get_ecc_curve_from_key): New.

--

GnuPG-bug-id: 7097
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-26 14:18:03 +09:00
Werner Koch 83e2dede0a
speedo: Use gpg-authcode-sign.sh and change archive label to v2.5.
--
2024-04-25 11:37:53 +02:00
Werner Koch d3b41e7611
Install the new gpg-authcode-sign.sh script.
* tools/gpg-authcode-sign.sh: New.
* tools/Makefile.am (bin_SCRIPTS): Add that tool.
--

This script makes use of gpg anyway and thus it is best to have it
also installed with the gpg version used to cross-build our software.
The script was orginally developed for gpg4win.
2024-04-25 11:00:18 +02:00
NIIBE Yutaka 02b056ef77
agent:kem: Fix memory leaks.
* agent/pkdecrypt.c (composite_pgp_kem_decrypt): Release shadow_info
memory.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-25 13:51:47 +09:00
NIIBE Yutaka 2593dcbceb
agent: Allow NULL for R_PADDING, when calling scd and tpm2d.
* agent/call-scd.c (padding_info_cb): Allow NULL.
(agent_card_pkdecrypt): Likewise.
* agent/divert-scd.c (divert_pkdecrypt): Likewise.
* agent/divert-tpm2.c (divert_tpm2_pkdecrypt): Likewise.

--

It's for RSA PKCD#1 encoding if the decrypt operation removes padding
or not.  When caller knows it's not RSA, this information is no use
and it is better to allow NULL with the variable R_PADDING.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-25 13:13:04 +09:00
Werner Koch 2958e5e4cf
gpg: New option --require-pqc-encryption
* g10/gpg.c (oRequirePQCEncryption): New.
(opts): Add option.
(main): Set option.
* g10/mainproc.c (print_pkenc_list): Print a warning.
* g10/options.h (flags): Add flag require_pqc_encryption.
* g10/getkey.c (finish_lookup): Skip non-pqc keys if the option is
set.
--

GnuPG-bug-id: 6815
2024-04-24 09:57:07 +02:00
NIIBE Yutaka a45243548e
agent:kem: Factor out ECC KEM operation from composite KEM.
* agent/pkdecrypt.c (ecc_pgp_kem_decrypt): New.
(composite_pgp_kem_decrypt): Use ecc_pgp_kem_decrypt.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-24 15:08:41 +09:00
NIIBE Yutaka d1f8caafb4
agent: Simplify diverting operation to the smartcard.
* agent/pkdecrypt.c (agent_pkdecrypt): Remove no_shadow_info variable.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-24 14:01:41 +09:00
Werner Koch ab703eacf7
gpg: Split keygrip in a standard key listing.
* g10/keylist.c (print_keygrip): New.
(list_keyblock_print): Use new function to print the keygrip.
2024-04-23 20:12:57 +02:00
Werner Koch dd650b2c7b
gpg: Support Kyber with Brainpool512r1.
* common/openpgp-oid.c (oidtable): Add GCRY_KEM_RAW_BP512.
* agent/pkdecrypt.c (ecc_table): Support bp512
* g10/pkglue.c (do_encrypt_kem): Ditto.

* tests/openpgp/samplekeys: Add sample keys for kyber_bp256, bp384,
and bp512.
* tests/openpgp/privkeys: Add corresponding private keys.
* tests/openpgp/samplemsgs:  Add sample messages for those keys.
--

GnuPG-bug-id: 6815
2024-04-23 17:41:28 +02:00
Werner Koch 32ec480024
gpg: Support encryption with kyber_bp256 and kyber_bp384
* common/openpgp-oid.c (oidtable): Support KEM for bp256 and bp384.
* g10/pkglue.c (do_encrypt_kem): Ditto.
--

GnuPG-bug-id: 6815

Note, this needs the very latest Libgcrypt to work properly
2024-04-23 16:25:05 +02:00
Werner Koch 54741685ce
Remove the deprecated gcry_set_log_handler.
* common/miscellaneous.c (my_gcry_logger): Remove.
(setup_libgcrypt_logging): Do not call the deprecated
gcry_set_log_handler.
* kbx/kbxutil.c (my_gcry_logger): Remove.
* tools/no-libgcrypt.c (gcry_set_log_handler): Remove stub.
2024-04-23 16:21:49 +02:00
Werner Koch f325d3277e
tests: Add two Kyber sample keys and messages.
--

GnuPG-bug-id: 6815
2024-04-23 14:04:41 +02:00
Werner Koch e591fd25ad
gpg: Support encryption with kyber_cv448.
* g10/pkglue.c (do_encrypt_kem): Support cv25519 w/o 0x40
prefix. Support X448.
(ECC_POINT_LEN_MAX): New.
(ECC_HASH_LEN_MAX): New.
* common/openpgp-oid.c (oidtable): Support X448 KEM.
--

This needs more work.  For example we should use a parameter table
like what we do in agent/pkdecrypt.c.

GnuPG-bug-id: 6815
2024-04-23 11:31:49 +02:00
Werner Koch f305e703d5
Require Libgcrypt 1.11.0
* configure.ac (NEED_LIBGCRYPT_VERSION): Set to 1.11.0
* agent/pkdecrypt.c (struct ecc_params): Move constants to the top.
--

It does not make anymore sense to allow building with older Libgcrypt
versions.  After all PQ key support is a major feature and for this we
need Libgcrypt.
2024-04-23 11:09:40 +02:00
NIIBE Yutaka af98a3e5fa
agent:kem: More fix for PQC KEM with X448.
* agent/pkdecrypt.c (struct ecc_params): Remove NAME_LEN field.
(ecc_table): Update.
(get_ecc_params): Use strcmp.
(composite_pgp_kem_decrypt): Fix the call of gnupg_kem_combiner.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-23 16:09:02 +09:00
NIIBE Yutaka 65833eefb2
agent:kem: Support other ML-KEM variants.
* agent/pkdecrypt.c (composite_pgp_kem_decrypt): Care about
ML-KEM 512 and 1024.

--

Co-authored-by: Werner Koch <wk@gnupg.org>
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-23 14:40:27 +09:00
NIIBE Yutaka d5c6b52e59
agent:kem: Support other ECC curves.
* agent/pkdecrypt.c (ecc_table): New.
(get_ecc_params): New.
(composite_pgp_kem_decrypt): Support other curves.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-23 14:23:27 +09:00
Daniel Cerqueira aa15272ba1
po: Update Portuguese Translation.
Signed-off-by: Daniel Cerqueira <dan.git@lispclub.com>
2024-04-23 09:23:34 +09:00
Werner Koch f119444e64
tests: Avoid new C23 keyword true.
* tests/asschk.c (eval_boolean): s/true/tru/
--

GnuPG-bug-is: 7093
2024-04-22 08:04:27 +02:00
Werner Koch ba3c873934
gpg: Prepare Kyber encryption code for more variants.
* common/openpgp-oid.c (oidtable): Add field kem_algo.
(openpgp_oid_to_kem_algo): New.
* g10/pkglue.c (do_encrypt_kem): Add support for Kyber1024.
--
GnuPG-bug-id: 6815
2024-04-18 14:37:40 +02:00
Werner Koch 7d6ad28667
gpg: Mark disabled keys and add show-ownertrust list option.
* g10/options.h (LIST_SHOW_OWNERTRUST): New.
* g10/keylist.c (print_key_line): Show wonertrust and always show
whether a key is disabled.
* g10/gpg.c (parse_list_options): Add "show-ownertrust".

* g10/gpgv.c (get_ownertrust_string): Add stub.
* g10/test-stubs.c (get_ownertrust_string): Add stub.
--

Note that in a --with-colons listing the ownertrust has always been
emitted and the disabled state is marked in that listing with a
special 'D' usage.
2024-04-17 12:16:20 +02:00
Werner Koch 21f7ad563d
gpg: New command --quick-set-ownertrust.
* g10/gpg.c (aQuickSetOwnertrust): New.
(opts): Add new command.
(main): Implement it.
* g10/keyedit.c (keyedit_quick_set_ownertrust): New.
2024-04-17 11:42:20 +02:00
Werner Koch 2a71c3cf97
gpg: Make --with-subkey-fingerprint the default.
* g10/gpg.c (oWithoutSubkeyFingerprint): New.
(opts): Add "without-subkey-fingerprint".
(main): Make --with-subkey-fingerprint the default.  Implementation
the without option.
--

Given that the default for the keyid format is none, the subkey
fingerprints are important to do anything with a subkey.  Thus we make
the old option the default and provide a new option to revert it.
2024-04-16 18:31:29 +02:00
Werner Koch 4e32ff209d
gpg: Fix minor Kyber display things.
* common/compliance.c (gnupg_pk_is_compliant): Make Kyber known.
* g10/misc.c (openpgp_pk_algo_name): Add "Kyber".
2024-04-15 13:25:07 +02:00
Werner Koch c736052e9c
gpg: Implement Kyber encryption.
* g10/build-packet.c (do_pubkey_enc): Support Kyber.
* g10/pkglue.c (do_encrypt_kem): Implement.
--

Note that the code does only work for ky768_cv25519 for now.

GnuPG-bug-id: 6815
2024-04-15 12:18:09 +02:00
Werner Koch 4c20d2d273
gpg: Add arg session_algo to pk_decrypt.
* common/kem.c: Move constants to the top.  Add some documentation.
* g10/pkglue.c (pk_encrypt): Add arguments session_key and factor code
out to ...
(do_encrypt_rsa_elg): here,
(do_encrypt_ecdh): and here,
(do_encrypt_kem): and here.
* g10/encrypt.c (write_pubkey_enc): Call with session key algorithm.
--

This makes it easier to review the code.
2024-04-15 09:23:54 +02:00
NIIBE Yutaka 35ef87d8d9
scd:openpgp: Robust Data Object handling for constructed case.
* scd/app-openpgp.c (get_cached_data): When it comes with
its tag and length for the constructed Data Object, remove
them.

--

GnuPG-bug-id: 7058
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-15 10:23:25 +09:00
Werner Koch b48476bbef
gpg: Prepare to use the fingerprint as fixed-info for Kyber.
* g10/pubkey-enc.c (get_it): Use algo and fingerprint for the
fixed-info.  Keep a testing mode.
* g10/options.h (COMPAT_T7014_OLD): New.
* g10/gpg.c (compatibility_flags): Add "t71014-old" flag.
--

GnuPG-bug-id: 6815
2024-04-12 11:33:07 +02:00
Werner Koch 6f94fe01a9
gpg: Simplify the pk_encrypt function interface.
* g10/pkglue.c (pk_encrypt): Remove superfluous arguments and reanem
variable rc to err.
* g10/encrypt.c (write_pubkey_enc): Adjust for this change.
--

We used to pass PK as well as information which could be taken
directly from PK.  Using ERR instead of RC is just for more uniform
naming of variables.
2024-04-12 10:43:12 +02:00
Werner Koch 813f8d1b8e
gpg: Changed internal data format for Kyber.
* g10/packet.h (PKT_pubkey_enc): Add field seskey_algo.
(struct pubkey_enc_list): Ditto.
* g10/misc.c (pubkey_get_nenc): Change value for Kyber from 4 to 3.
* g10/parse-packet.c (parse_pubkeyenc): Store the Kyber algo in the
new field and adjust data.  Do not store the length byte in data[2].
* g10/build-packet.c (do_pubkey_enc): Take the session algo for Kyber
from the new field.
* g10/encrypt.c (write_pubkey_enc): Ses the seskey_algo.
* g10/mainproc.c (proc_pubkey_enc): Copy it.
* g10/pubkey-enc.c (get_it): Support Kyber decryption.

* g10/seskey.c (encode_session_key): Handle Kyber different from ECDH.
--

Having always the single byte in the packet data than to store and
retrieve it from an MPI is much easier.  Thus this patch changes the
original internal format.  With this chnages decryption of the slighly
modified test data works now. See the bug tracker for test data.

GnuPG-bug-id: 6815
2024-04-11 15:56:21 +02:00
Werner Koch 61717fb0a7
agent: Add more diagnostics to PQC decryption.
* agent/pkdecrypt.c (composite_pgp_kem_decrypt): Use %d for
correctness.  Add error diagnostics and one extra check.
--

GnuPG-bug-id: 7014
2024-04-11 15:48:16 +02:00
Werner Koch 869d1df270
indent: Re-indent a function
--
2024-04-11 11:33:37 +02:00
NIIBE Yutaka f2fd4f1a9e
agent: Rename the function using the word "composite"
* agent/pkdecrypt.c (composite_pgp_kem_decrypt): Rename.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-11 15:30:27 +09:00
NIIBE Yutaka 172d53d636
agent: Fix PQC decryption.
* agent/pkdecrypt.c (agent_hybrid_pgp_kem_decrypt): Change the format
of SEXP in the protocol for symmetric cipher algorithm identifier.

--

GnuPG-bug-id: 7014
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-11 15:30:16 +09:00
Werner Koch 6737e07a9b
doc: Move keyformat.txt to here.
--
2024-04-11 08:27:53 +02:00
Todd Zullinger via Gnupg-devel 87025e5da6
doc: Fix a few typos in agent/keyformat.txt
--

Signed-off-by: Todd Zullinger <tmz@pobox.com>
2024-04-11 08:17:20 +02:00
Werner Koch 84ddb24e30
gpg: Make Kyber creation more flexible.
* common/openpgp-oid.c (openpgp_is_curve_supported): Allow the
abbreviated curve name.
* g10/pkglue.c (pk_encrypt): Add debug output.
* g10/seskey.c (encode_session_key): Handle Kyber session key like
ECDH.  This is just a stub.
* g10/keygen.c (ecckey_from_sexp): Use the modern OID for cv25519.
(parse_key_parameter_part): Allow more Kyber variants.
--

Test by creating an ed25519 key and using

 gpg --quick-add-key --batch --passphrase ""  <fingerprint> <algo>

to create several subkeys.  Tested with ALGOs:

  kyber768
  kyber1024
  ky768_cv25519
  ky768_bp256
  kyber768_nistp256
  ky1024_cv448

All curves capable of encryption should work.

GnuPG-bug-id: 6815
2024-04-10 08:48:49 +02:00
NIIBE Yutaka c21237ac27
agent:kem: Externalize FIXED_INFO.
* agent/pkdecrypt.c (agent_hybrid_pgp_kem_decrypt): Don't hard code
the value of FIXED_INFO.  Get it from frontend.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-10 12:52:13 +09:00
NIIBE Yutaka aee6b1131b
common: Rename to kem.c from kmac.c.
* common/Makefile.am (common_sources): Fix to kem.c.
* common/kem.c: Rename.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-10 11:14:25 +09:00
NIIBE Yutaka 04b81ec236
common,agent: Factor out KEM functions into common/kem.c.
* common/util.h (compute_kmac256): Remove.
(gnupg_ecc_kem_kdf, gnupg_kem_combiner): New.
* common/kmac.c (compute_kmac256): Don't expose.
(gnupg_ecc_kem_kdf, gnupg_kem_combiner): New.
* agent/pkdecrypt.c (agent_hybrid_pgp_kem_decrypt): Use
gnupg_ecc_kem_kdf and gnupg_kem_combiner.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-10 11:09:29 +09:00
Werner Koch 52c4b09080
gpg: Some support to allow Kyber decryption.
* g10/call-agent.c (agent_pkdecrypt): Support dual keygrips and switch
to KEM mode.
* g10/ecdh.c (pk_ecdh_decrypt): Add an extra length check.
* g10/keyid.c (do_hash_public_key): Fix Kyber fingerprint computation.

* g10/mainproc.c (release_list): Free all 4 data elements.
(proc_pubkey_enc): Copy all 4 data elements.
* g10/misc.c (openpgp_pk_test_algo2): Map Kyber to KEM.

* g10/parse-packet.c (parse_pubkeyenc): Fix Kyber parser.
* g10/pubkey-enc.c (get_session_key): Allow Kyber.
(get_it): Support Kyber.
--

GnuPG-bug-id: 6815
2024-04-09 11:01:56 +02:00
Werner Koch 1a37f0080b
kbx: Support kyber in the blob parser.
* kbx/keybox-openpgp.c (keygrip_from_keyparm): Support Kyber.
(parse_key): Ditto.
--

GnuPG-bug-id: 6815
2024-04-09 11:01:56 +02:00
NIIBE Yutaka 3a344d6236
gpg: Allow no CRC24 checksum in armor.
* g10/armor.c (radix64_read): Detect the end of armor when
there is no CRC24 checksum.

--

GnuPG-bug-id: 7071
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-09 09:24:11 +09:00
Werner Koch f7a26aa8ad
kbx: Fix keyid search for mixed v4/v5 case.
* kbx/keybox-search.c (blob_cmp_fpr_part):  Reworked.
(has_short_kid, has_long_kid): Simplify.
--

The old code was too complicated and did not cope correctly a blob
having a mix of v5 and v4 keys.

Fixes-commit: 01329da8a7
GnuPG-bug-id: 5888
2024-04-08 20:32:47 +02:00
Werner Koch c5d7a332c8
gpg: Do not allow to accidently set the RENC usage.
* g10/keygen.c (print_key_flags): Print "RENC" if set.
(ask_key_flags_with_mask): Remove RENC from the possible set of
usages.  Add a direct way to set it iff the key is encryption capable.
--

This could be done by using "set your own capabilities" for an RSA
key.  In fact it was always set in this case.

GnuPG-bug-id: 7072
2024-04-05 16:18:34 +02:00
Werner Koch 03d53c88cc
gpg: Allow to create a Kyber key from keygrips.
* agent/cvt-openpgp.c (extract_private_key): Support Kyber algorithms.
* common/openpgp-oid.c (map_gcry_pk_to_openpgp): Map KEM to Kyber.
* common/sexputil.c (get_pk_algo_from_key): Increase buffer for use
with "kyber1024".
* g10/call-agent.c (agent_get_keyinfo): Fix warning.
* g10/keygen.c (do_create_from_keygrip): Support Kyber.
(ask_algo): Ditto.
--

To test create a standard key and the use --edit-key and "addkey" with
selection 13 and use the comma delimited keygrips.

GnuPG-bug-id: 7014
2024-04-05 16:16:53 +02:00
Werner Koch 68d9bc9c35
agent: Fix error handling of READKEY.
* agent/command.c (cmd_readkey): Jump to leave on reading error.
--

Fixes-commit: d7a3c455c5
2024-04-05 14:47:02 +02:00
Werner Koch 53c6b1e858
gpg: Support dual keygrips.
* g10/keyid.c (keygrip_from_pk): Add arg get_second to support dual
algos.  Implement for Kyber.
(hexkeygrip_from_pk): Extend for dual algos.
* g10/call-agent.c (agent_keytotpm): Bail out for dual algos.
(agent_keytocard): Ditto.
(agent_probe_secret_key): Handle dual algos.
(agent_probe_any_secret_key): Ditto.
(agent_get_keyinfo): Allow for dual algos but take only the first key.
* g10/export.c (do_export_one_keyblock): Bail out for dual algos.
--

This also adds some fixmes which we eventually need to address.

GnuPG-bug-id: 6815
2024-04-05 12:02:32 +02:00
Werner Koch ce8b25270b
agent: Make "PKDECRYPT --kem" with optional value work.
* agent/command.c (cmd_pkdecrypt): Fix comparison.

* agent/agent.h (enum kemids): Rename type and strip trailing comma.

* agent/pkdecrypt.c (agent_hybrid_pgp_kem_decrypt): Allow building
with Libgcrypt < 1.11
--

Eventually we should change the libgcrypt requirement in configure.
2024-04-05 11:22:38 +02:00
NIIBE Yutaka 131dd2a351
agent: Add initial support for hybrid ECC+PQC decryption with KEM.
* agent/agent.h (enum kemid): New.
(agent_kem_decrypt): New.
* agent/command.c (cmd_pkdecrypt): Support --kem option to call
agent_kem_decrypt.
* agent/pkdecrypt.c (reverse_buffer): New.
(agent_hybrid_pgp_kem_decrypt): New.
(agent_kem_decrypt): New.

--

Now, it only supports X25519 + ML-KEM.

GnuPG-bug-id: 7014
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-05 14:17:25 +09:00
Werner Koch 97f5159495
gpg: Initial support for generating Kyber subkeys.
* common/openpgpdefs.h (PUBKEY_ALGO_KY768_25519): Remove.
(PUBKEY_ALGO_KY1024_448): Remove.
(PUBKEY_ALGO_KYBER): New.  Use them everywhere instead of the removed.

* g10/build-packet.c (gpg_mpi_write_nohdr): Rename to
(gpg_mpi_write_opaque_nohdr): this.  Change callers.
(gpg_mpi_write_opaque_32): New.
(do_key): Support Kyber keys using the revised format.
* g10/gpg.h (MAX_EXTERN_KEYPARM_BITS): New.
* g10/parse-packet.c (read_octet_string): Add arg nbytes so support
reading with a length prefix.  Adjust callers.
(parse_key): Parse Kyber public keys.
* g10/misc.c (pubkey_get_npkey): Support Kyber.
(pubkey_get_nskey): Ditto.

* g10/keyid.c (pubkey_string): Support dual algorithms.
(do_hash_public_key): Support Kyber.
(nbits_from_pk): Ditto.
(keygrip_from_pk): Return the Kyber part for the ECC+Kyber dual algo.

* g10/keygen.c (struct common_gen_cb_parm_s): Add genkey_result2.
Note that this callback is not yet used.
(ecckey_from_sexp): Add optional arg sexp2 and use it for Kyber.
Change callers.
(ecckey_from_sexp): Do not leak LIST in case of an error.
(common_gen): Add arg keyparms2, change callers, and support Kyber.
(gen_kyber): New.
(get_keysize_range): Support Kyber.
(fixup_keysize): Simplify and support Kyber.
(do_create): Handle Kyber.
(parse_key_parameter_part): Remove algo strings "ky768" and "ky1024"
and add a generic "kyber" with default parameters.
--

This uses a revised format which is more aligned with the usual
OpenPGP structure.  A lot of things are still missing.  For example
support for handling two keygrips and checking both of them in a -K
listing.  There is also only ky768_bp384 as fixed algorithm for now.
No passphrase for the Kyber part of the dual algorithm is on purpose.

A test was done using

  gpg --quick-gen-key pqc1 nistp256

and then running

  gpg -v --quick-add-key <fingerprint> kyber

which creates a v5 subkey on a v4 primary key.  A second test using

  gpg --quick-gen-key pqc2 Ed448

followed by a --quick-add-key created a v5 key with a v5 subkey.

GnuPG-bug-id: 6815
2024-04-03 18:01:11 +02:00
Werner Koch 6c1dd3afd1
common: Extend openpgp_oid_to_curve to return an abbreviated name.
* common/openpgp-oid.c (oidtable): Add column "abbr" and set them for
Brainpool.
(openpgp_oid_to_curve): Rename arg "canon" to "mode" and implement
mode 2.
--

For dual algorithms (PQC) we need shorter versions of brainpool to
avoid names which otherwise might be capped when printed.
2024-04-03 14:13:57 +02:00
Werner Koch 4b981e415f
tests: Add a sample PDF with a signature
--
2024-04-03 09:52:14 +02:00
Werner Koch fa33b18940
common: Allow building with libgcrypt 1.10 for now.
* common/kmac.c (compute_kmac256): Return an error for older gcrypt
versions.
--

Except for the new KEM module there is no hard requirement for
libgcrypt 1.11 *yet*.
2024-04-03 09:43:37 +02:00
NIIBE Yutaka c69363e8c7
agent: Add --another option for hybrid crypto.
* agent/agent.h (struct server_control_s): Add have_keygrip1.
* agent/command.c (reset_notify): Clear have_keygrip1 field.
(cmd_havekey): Add --another option handling.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-04-01 14:38:51 +09:00
NIIBE Yutaka 1fa24e2841
common: Add KMAC.
* common/Makefile.am (common_sources): Add kmac.c.
* common/kmac.c: New.
* common/util.h (compute_kmac256): New.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-03-29 15:26:42 +09:00
Werner Koch 571a768ac6
gpgsm: Allow to add extensions at the --gen-key prompt.
* sm/certreqgen-ui.c (gpgsm_gencertreq_tty): Add a prompt for
extensions.
--

An example for an extension would be extKeyUsage for authentication:

   2.5.29.37 n 301406082B0601050507030206082B06010505070301
2024-03-27 12:12:52 +01:00
NIIBE Yutaka 984a0c6982
scd:openpgp: Fix data_objects specification for F9 and FA.
* scd/app-openpgp.c (data_objects): These are constructed objects.

--

GnuPG-bug-id: 7058
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-03-27 10:27:04 +09:00
Werner Koch f9919bcc48
gpg,gpgsm: New option --disable-fd-translation.
* common/sysutils.c (no_translate_sys2libc_fd) [W32]: New global.
(disable_translate_sys2libc_fd): New.
(translate_sys2libc_fd): Make static and cobuild only for Windows.
(translate_sys2libc_fd_int): Use no_translate_sys2libc_fd flag.

* g10/gpg.c, sm/gpgsm.c (oDisableFdTranslation): New const.
(opts): Add option "disable-fd-translation".
(main): Set option.
--

GnuPG-bug-id: 7060
2024-03-26 15:46:56 +01:00
Werner Koch cec1fde1bc
scd: Add new OpenPGP vendor
--
2024-03-26 14:57:52 +01:00
Werner Koch a0bfbdaaa2
Allow installation with a gpgconf.ctl changed homedir.
* common/homedir.c (gpgconf_ctl): Add field "gnupg".
(parse_gpgconf_ctl): Support keyword "gnupg".
(my_gnupg_dirname): New.
(my_fixed_default_homedir): New.
(gnupg_registry_dir): New.
(standard_homedir): Use my_gnupg_dirname and my_fixed_default_homedir.
(default_homedir): Use gnupg_registry_dir and
my_fixed_default_homedir.
(_gnupg_socketdir_internal): Use my_gnupg_dirname.  Increase size of
prefixbuffer.
(gnupg_sysconfdir): Use my_gnupg_dirname.
* tools/gpgconf.c (list_dirs): Use gnupg_registry_dir.
(show_other_registry_entries): Ditto.
--

This will be useful to install versions of GnuPG VS-Desktop and GnuPG
Desktop in addition to a standard GnuPG version.  Only basic tests on
Unix done; Windows testing is still outstanding.

GnuPG-bug-id: 7040
2024-03-21 17:41:10 +01:00
Werner Koch fb3fe38d28
common: Use a common gpgconf.ctl parser for Unix and Windows.
* common/homedir.c (gpgconf_ctl): new struct.
(string_is_true): New.
(parse_gpgconf_ctl): New.  Based on the former code in unix_rootdir.
(check_portable_app): Use parse_gpgconf_ctl and the new struct.
(unix_rootdir): Ditto.
--

This is a unification of the gpgconf.ctl mechanism.  For backward
compatibility we need to keep the empty (or actually only comments)
method as used formerly under Windows.  Iff one really wants a
portable application the new portable keyword should be used, though.

Noet that the Windows portable stuff has not been tested for quite
some time.
2024-03-21 15:47:43 +01:00
Werner Koch 50e81ad38d
gpg: Make sure a DECRYPTION_OKAY is never issued for a bad OCB tag.
* g10/mainproc.c (proc_encrypted): Force a decryption failure if any
error has been seen.
* g10/decrypt-data.c (aead_checktag): Issue an ERROR line.
--

GnuPG-bug-id: 7042

Note that gpg in any case returns a failure exit code but due to
double forking GPGME would not see it.
2024-03-14 21:41:48 +01:00
Werner Koch f78501c545
gpg: new list-option store-x509-notations.
* g10/options.h (LIST_STORE_X509_NOTATIONS): New.
* g10/gpg.c (parse_list_options): Add "store-x509-notations".
* g10/keylist.c (print_x509_notations): Add arg PK and code to write a
file.
(list_signature_print): Add arg lastpk and handle new option.
(list_keyblock_print): Track last key or subkey and pass to
list_signature_print.
2024-03-14 20:58:01 +01:00
Werner Koch 14c1b73093
gpg: new list-option show-x509-notations
* g10/gpg.c (parse_list_options): Add new option.
* g10/options.h (LIST_SHOW_X509_NOTATIONS): New.
* g10/build-packet.c (search_sig_notations): New.
* g10/keylist.c (print_x509_notations): New.
(list_signature_print): Use macros for the sig classes.  Call
print_x509_notations.
(list_keyblock_print): Call list_signature_print if x509 notation
printing is enabled.
2024-03-12 18:01:24 +01:00
Werner Koch 81536535f8
card: Use xstrdup for module names.
--
2024-03-12 16:04:19 +01:00
Werner Koch 4485930f9f
Merge branch 'STABLE-BRANCH-2-4'
--
Resolved conflicts:
	NEWS
	common/exechelp-w32.c
	configure.ac
2024-03-12 16:00:55 +01:00
Werner Koch 609b1ec0c6
Post release updates
--
2024-03-07 15:10:47 +01:00
Werner Koch cbff323b3b
Release 2.4.5 2024-03-07 14:03:25 +01:00
Werner Koch 348de4a829
po: msgmerge
--
2024-03-07 14:01:59 +01:00
Werner Koch 3ffcd533d4
po: Fix a fuzzy in the German, Polish and Japanese translation
--
2024-03-07 14:01:22 +01:00
Werner Koch 09431d1762
scd: Improve code reability of ccid-driver.c
* scd/ccid-driver.c (my_npth_unprotect, my_npth_protect): New.
Replace all direct uses by these wrappers.
2024-03-07 13:44:30 +01:00
Werner Koch 1682ca9f01
scd: Add support for ACR-122U
* scd/ccid-driver.h (VENDOR_ACR, ACR_122U): New.
* scd/ccid-driver.c (ccid_open_usb_reader): Do not call
libsub_set_interface_alt_setting for this reader.
--

Co-authored-by: markus.montkowski@gnupg.com
2024-03-07 13:44:00 +01:00
Werner Koch a1ea3b13e0
scd: Let the CCID module auto detach the kernel driver.
* scd/ccid-driver.c (ccid_open_usb_reader): Call
libusb_set_auto_detach_kernel_driver.

* scd/scdaemon.c (oCompatibilityFlags): New.
(opts): Add option "compatibility-flags".
(compatibility_flags): New.
(main): Parse flags.
* scd/scdaemon.h (opt): Add field compat_flags.
(COMPAT_CCID_NO_AUTO_DETACH): New.
2024-03-07 13:21:43 +01:00
Werner Koch 79d0e52b2d
gpg: Fix a possible segv due to an uninitialized gcrypt context.
* g10/sign.c (sign_symencrypt_file): Initialize MD for the error case.
--

Reported-by: Falko Strenzke
Fixes-commit: 1ddd69935d
in the not yet released master branch.
2024-03-06 15:49:51 +01:00
Werner Koch 00b877ecda
doc: Typo fix in comment
--
2024-03-06 11:54:33 +01:00
Werner Koch 37cc255e49
wks: Make gpg-wks-client --mirror work w/o args.
* tools/gpg-wks-client.c (mirror_one_key): Test for no domain
specified.
--

The code did not really work if no domain was given.  It worked but
filtered out all keys so that no key was actually exported.
2024-03-06 10:00:37 +01:00
Werner Koch 345794cfe6
gpg: Fix mixed invocation with --trusted-keys and --no-options.
* g10/trustdb.c: Move a function and some definitions around.
(user_utk_list): Rename to trusted_key_list.  Change all users.
(any_trusted_key_seen): New.
(tdb_register_trusted_key): Set it here.  Handle the new value "none".
(verify_own_keys): Do not delete a trusted key from the trustdb if a
trusted-key option was not used.
--

GnuPG-bug-id: 7025
2024-03-04 14:58:45 +01:00
Werner Koch 36a3550bff
wks: Add option --realclean to gpg-wks-client.
* tools/gpg-wks-client.c (oRealClean): New.
(opts): Add "realclean".
(parse_arguments): Implement.
(main): Take a copy of the module name to fix bad assignment from a
former patch.
* tools/gpg-wks-server.c (main): Ditto.
* tools/gpg-wks.h (opt): Add field realclean.
* tools/wks-util.c (wks_get_key): Call gpg with export-realclean
depending on the new option.
--

The default for gpg-wks-client is to install keys with all valid key
signatures.  The new option will eventually allow to install the keys
only with key signatures done by trusted-keys.  Also the export-option
is in gpg, it requires one more gpg patch to make it actually work.
2024-03-04 14:28:48 +01:00
Werner Koch 74e4dd3668
gpg: Prepare for a new export option export-realclean.
* g10/options.h (EXPORT_REALCLEAN): New.  Also re-assign other values
to keep them more in sync with the corresponding import values.
* g10/export.c (parse_export_options): Add "export-realclean".
(do_export_stream): Call clean_all_uids directly with the options
arg.
* g10/import.c (import_one_real): Change for direct use of options in
clean_all_uids.
* g10/key-clean.c (is_trusted_key_sig): New.  Stub for now.
(clean_sigs_from_uid): Re-purpose self_only to a general options arg.
Implement EXPORT_REALCLEAN code path.
(clean_one_uid): Re-purpose self_only to a general options arg.
(clean_all_uids): Ditto.
* g10/keyedit.c (keyedit_menu): Use EXPORT_MINIMAL instead of a simple
flag.
(menu_clean): Re-purpose self_only to a general options arg.

* g10/keyid.c (fpr20_from_pk): Factor code out to ....
(fpr20_from_fpr): new.  Remove useless case for ARRAY being NULL.
* g10/tdbio.c (tdbio_search_trust_byfpr): Add arg fprlen and use
fpr20_from_fpr if needed.
(tdbio_search_trust_bypk): Pass 20 for the fingerprint length.
--

Note that this code has no function yet.  Another patch will follow to
extract the trusted-keys flag from the trustdb.
2024-03-04 14:22:42 +01:00
Werner Koch 233bf39323
build: Extend getswdb.sh to allow a verified download
--
2024-02-29 15:35:27 +01:00
Werner Koch c27e5be50b
build: Make getswdb.sh usable outside the GniPG tree.
--
2024-02-29 10:21:33 +01:00
Werner Koch dcab895e4c
gpg: Emit status lines for errors in the compression layer.
* g10/compress-bz2.c: Replace all log_fatal by log_error,
write_status_error, and g10_exit.
(do_uncompress): Ditto.
--

This gives gpgme a better way to detect corrupted data in the
compression layer.
GnuPG-bug-id: 6977
2024-02-27 11:33:21 +01:00
Werner Koch 962058f704
Allow tilde expansion for the foo-program options.
* agent/gpg-agent.c (parse_rereadable_options): Use make_filename_try
for opt.pinentry_program.  Change definition accordingly.
* g10/gpg.c (main): Use make_filename for agent_program,
dirmngr_program, and keyboxd_program. Change definition accordingly.
* sm/gpgsm.c (main): Ditto.
* tools/gpg-card.c (parse_arguments): Ditto.
* tools/gpg-connect-agent.c (main): Ditto.
* tools/gpg-wks-client.c (parse_arguments): Likewise.  Do it also for
option --output.
(process_confirmation_request): Print a note for a successful sent.
--

GnuPG-bug-id: 7017
2024-02-27 10:36:22 +01:00
Werner Koch adf4db6e20
agent: Allow GET_PASSPHRASE in restricted mode.
* agent/command.c (cmd_get_passphrase): Allow use in restricted mode
but ignore the cacheid.
--

The use case is symmetric encryption via the extra-socket.  To avoid
that the gpg running on the server has access to the cache we set the
cache id to NULL so that the cache is not used at all.
2024-02-25 16:03:54 +01:00
Werner Koch 40227e42ea
doc: Document the "grp" record in colon listings.
--
2024-02-22 17:05:04 +01:00
Werner Koch 2372f6a403
gpg: Fix gpg_mpi_write for the unused opaque case.
* g10/build-packet.c (gpg_mpi_write): Take care of the fact that
get_opaque already returns a bit-exact value.
--

Fixes-commit: ab17f7b6c3
Reported-by: Falko Strenzke <falko.strenzke@mtg.de>
2024-02-21 15:55:14 +01:00
Werner Koch a09157ccb2
wks: Allow command style args for gpg-wks-client.
* tools/gpg-wks-client.c (wrong_args): Take two args.  Change all
callers.
(main): Pass ARGPARSE_FLAG_COMMAND for recent gpgrt version.
--

This requires gpgrt 1.48.  Of course "gpg-wks-client --create ..."
continues to work.
2024-02-21 14:07:06 +01:00
Werner Koch 95bc592ab5
g13: Allow command line style "g13 mount foo".
* g13/g13.c (main): Set flag ARGPARSE_FLAG_COMMAND.
--

This requires gpgrt 1.48.  Of course "g13 --mount foo" continues to
work.
2024-02-20 11:40:49 +01:00
Mario Haustein 3aa02027cd
scd:p15: Fix typo in a comment 2024-02-20 10:34:39 +01:00
Mario Haustein 557f29d2c1
scd:p15: Add ECC support for D-Trust Card 4.1/4.4
* scd/app-p15.c (do_sign): Add MSE RESTORE parameters for D-Trust ECC
cards.
(do_decipher): Ditto.
2024-02-20 10:32:08 +01:00
Werner Koch 1e496cf2e5
scd:p15: Take derive usage into account for decryption (2).
* scd/app-p15.c (do_getattr): Yet another palce to fix.
--
GnuPG-bug-id: 7000
Co-authored-by: Mario Haustein <mario.haustein@hrz.tu-chemnitz.de>
2024-02-20 10:29:25 +01:00
Werner Koch 3341017ff1
scd:p15: Handle duplicate certificate ids.
* scd/app-p15.c (struct app_local_s): Add field cdf_dup_counter.
(objid_in_cdflist_p): New.
(read_p15_info): Clear the counter.
(read_ef_cdf): Detect and fix duplicate IDs.
--

GnuPG-bug-id: 7001
Reported-by: Mario Haustein <mario.haustein@hrz.tu-chemnitz.de>
2024-02-20 09:17:38 +01:00
Werner Koch ad4bc3e04d
scd:p15: Take derive usage into account for decryption.
* scd/app-p15.c (set_usage_string): Map usageflags.derive also to 'e'.
(do_auth): Allow usageflags.sign_recover.
(do_decipher): Allow usageflags.derive.
(do_with_keygrip): Take usageflags.derive into account.
(do_gettatr): Ditto.
(do_decipher): Take a missing AODF for authentication not needed.
--

This is required for D-Trust ECC cards.

The AODF thing is unrelated but seems to be a good idea.

GnuPG-bug-id: 7000
2024-02-20 09:17:38 +01:00
NIIBE Yutaka 2810b93464
dirmngr: Fix keep-alive flag handling.
* dirmngr/http.c (run_proxy_connect): Set KEEP_ALIVE if not Basic
Authentication.  Fix resource leak of FP_WRITE.

--

GnuPG-bug-id: 6997
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-02-16 16:24:26 +09:00
NIIBE Yutaka 848546b05a
dirmngr: Fix the regression of use of proxy for TLS connection.
* dirmngr/http.c (run_proxy_connect): Don't set keep_alive, since it
causes resource leak of FP_WRITE.
Don't try to read response body to fix the hang.

--

GnuPG-bug-id: 6997
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-02-16 11:38:57 +09:00
Werner Koch 0370678536
speedo: Add config variable for the timestamp service.
--
2024-02-15 14:53:28 +01:00
NIIBE Yutaka 04cbc3074a
dirmngr: Fix proxy with TLS.
* dirmngr/http.c (proxy_get_token, run_proxy_connect): Always
available regardless of USE_TLS.
(run_proxy_connect): Use log_debug_string.
(send_request): Remove USE_TLS.

--

Since the commit of

	1009e4e5f7

Building with TLS library is mandatory.

GnuPG-bug-id: 6997
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-02-15 15:38:34 +09:00
NIIBE Yutaka 874918ab91
common,dirmngr:w32: Add include files.
* common/dynload.h: Include windows.h.  Don't define RTLD_LAZY, if
already defined.
* common/init.c: Include wctype.h.
* dirmngr/certcache.c: Include wincrypt.h.
* dirmngr/dns-stuff.c: Include ws2tcpip.h.

--

GnuPG-bug-id: 5894
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-02-15 14:40:33 +09:00
NIIBE Yutaka 27f66148f7
dirmngr:w32: Add include files.
* dirmngr/ks-engine-ldap.c: Include winldap.h and winber.h.

--

Definition of ber_free is in winber.h.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-02-15 14:38:10 +09:00
Werner Koch 302afcb6f6
gpg: Add option --assert-pubkey_algo.
* g10/keyid.c (parse_one_algo_string): New.
(compare_pubkey_string_part): New.
(compare_pubkey_string): New.
* g10/verify.c (check_assert_signer_list): New.
* g10/mainproc.c (check_sig_and_print): Call check_assert_pubkey_algo.
* g10/options.h (opt): Add field assert_pubkey_algos.
* g10/gpg.c (oAssertPubkeyAlgo): New.
(opts): Add "--assert-pubkey_algo".
(assert_pubkey_algo_false): New.
(main): Parse option.
(g10_exit): Reorder RC modifications.  Check assert_pubkey_algo_false.
* common/status.h (ASSERT_PUBKEY_ALGOS): new.
* common/t-support.h (LEAN_T_SUPPORT): Use a simplified version if
this macro is set.

* g10/gpgv.c (oAssertPubkeyAlgo): New.
(opts): Add "--assert-pubkey_algo".
(assert_pubkey_algo_false): New.
(main): Parse option.
(g10_exit): Check assert_pubkey_algo_false.

* g10/t-keyid.c: New.
* g10/Makefile.am: Add t-keyid.
* g10/test-stubs.c: Add assert_pubkey_algos and assert_signer_list and
remove from other tests.
(check_assert_signer_list): Ditto.
(check_assert_pubkey_algo): Ditto.
--

GnuPG-bug-id: 6946
2024-02-10 14:26:55 +01:00
Werner Koch 5842eee805
doc: Suggest the use of a fingerprint for --default-key.
--

GnuPG-bug-id: 6975
2024-02-05 08:53:06 +01:00
Werner Koch e5f24218fc
doc: Improve warning for --use-embedded-filename.
--

GnuPG-bug-id: 6972
2024-02-05 08:42:56 +01:00
Werner Koch 214d3ffe0f
gpgsm: Increase salt size in pkcs#12 parser.
* sm/minip12.c (parse_bag_encrypted_data): Need 32 bytes.
--

GnuPG-bug-id: 6757
2024-02-05 08:00:20 +01:00
Ángel González 375c3a238a
gpgsm: cleanup on error paths
* sm/minip12.c (p12_parse): set err on the different error paths

--

GnuPG-bug-id: 6973
Fixes-commit: 101433dfb4
Signed-off-by: Ángel González <angel@pgp.16bits.net>
2024-02-05 07:54:14 +01:00
Werner Koch 40b85d8e8c
scd:openpgp: Allow PIN length of 6 also with a reset code.
* scd/app-openpgp.c (do_change_pin): Fix PIN length check.  Add "R"
flag to the reset code prompt.
--

When using the reset code it was not possible to set a PIN of length
6.  The "R" flags fixes a funny prompt.

Fixes-commit: efe325ffdf
scd:openpgp: Allow PIN length of 6 also with a reset code.

* scd/app-openpgp.c (do_change_pin): Fix PIN length check.  Add "R"
flag to the reset code prompt.
--

When using the reset code it was not possible to set a PIN of length
6.  The "R" flags fixes a funny prompt.

Fixes-commit: 2376cdff13
2024-01-30 15:58:14 +01:00
Andre Heinecke d6dedda3f2
w32, msi: Fix directory of gpg-card, add keyboxd
* build-aux/speedo/w32/wixlib.wxs: Fix gpg-card directory id.
Add keyboxd.
2024-01-30 10:20:43 +01:00
Jakub Bogusz 300c9eeace
po: update Polish translation 2024-01-29 10:59:13 +01:00
Werner Koch 03207f62e8
gpg: Minor code cleanup for fingerprint computation.
* g10/keyid.c (do_hash_public_key): Simplify code for clarity.
2024-01-29 10:30:51 +01:00
Werner Koch ae0a755e0d
gpg: Hide --textmode from the help output.
--
2024-01-29 09:26:26 +01:00
Werner Koch 78eae9ffe8
doc: Mark --textmode as legacy option.
--
2024-01-29 09:24:19 +01:00
Werner Koch 2ed1f68b48
doc: Fix spelling errors found by lintian.
--

Reported-by: Andreas Metzler <ametzler@debian.org>
2024-01-29 09:16:21 +01:00
Werner Koch 97b2837653
speedo: Improve parsing of the ~./.gnupg-autogen.rc
--

We now allow spaces around the variable name and the value.
2024-01-26 16:01:06 +01:00
Werner Koch 4dc09bc5e7
dirmngr: For CRL issuer verification trust the system's root CA.
* dirmngr/crlcache.c (crl_parse_insert): Add
VALIDATE_FLAG_TRUST_SYSTEM.
--

GnuPG-bug-id: 6963
2024-01-26 13:14:35 +01:00
Werner Koch eaf6a7ab87
common,w32: Fix use of GNUPG_SPAWN_KEEP_STDERR.
* common/exechelp-w32.c (gnupg_spawn_process): Fix macro.
--

Fixes-commit: 6d6438a361
GnuPG-bug-id: 6961
2024-01-26 10:29:08 +01:00
Werner Koch dfa60c09f5
Merge branch 'STABLE-BRANCH-2-4'
--
Fixed conflicts:
	NEWS
	configure.ac
	doc/gpg.texi
2024-01-26 09:41:00 +01:00
NIIBE Yutaka af6ac2ac02
gpg: Clean up pk_ecdh_decrypt function.
* g10/ecdh.c (pk_ecdh_decrypt): Allocate just the right size of memory
for the session key, simplifying the decrypt process.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-01-26 14:13:01 +09:00
Werner Koch 367ae86019
Post release updates
--
2024-01-25 11:30:37 +01:00
Werner Koch a43271cc08
Release 2.4.4 2024-01-25 11:06:01 +01:00
Werner Koch c5429644e9
po: msgmerge
--
2024-01-25 11:05:58 +01:00
Werner Koch 2a4180812a
card: Tweak the checkcmds sub-command.
* tools/gpg-card.c (cmd_checkkeys): Skip not found keys.
2024-01-25 10:35:34 +01:00
NIIBE Yutaka 6481d410ec
po: Update Japanese Translation.
--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-01-25 09:07:11 +09:00
Werner Koch d4976e35d2
gpg: Add sub-option ignore-attributes to --import-options.
* g10/options.h (IMPORT_IGNORE_ATTRIBUTES): New.
* g10/import.c (parse_import_options): Add new sub-option.
(read_block): Implement sub-option.
--

Suggested-by: Robin H. Johnson

Tested using the import-export feature:

  gpg --export KEY_WITH_PICTURE \
   | gpg --import --import-options import-export,ignore-attributes \
   | gpg --show-key
2024-01-24 18:26:01 +01:00
Werner Koch a227a0d54d
po: Update German translation.
--

Just the new string for gpg-card's checkkeys.
2024-01-24 14:06:32 +01:00
Werner Koch 154ecf17bd
speedo: Build zlib, bzip2 and sqlite also on Unix.
--

This avoids extra build dependencies.  Note that bzip2 is not
necessary statically linked but an existing bzip2 SO might be used.
We would need to fix the bzip2 SO building and also provide a gnupg
configure option to build statically against bzip2.
2024-01-24 13:41:04 +01:00
Werner Koch bea31c845a
card: flush stdout to get checkcmd's info messages in order.
* tools/gpg-card.c (cmd_checkkeys): Insert an fflush.
2024-01-24 10:40:03 +01:00
NIIBE Yutaka ccfbb9ebdf
kbx: Have threads monitoring socket takeover and homedir if no inotify.
* kbx/keyboxd.c (CHECK_PROBLEMS_INTERVAL): New.
(have_homedir_inotify): Remove the global.
[HAVE_W32_SYSTEM] (create_an_event): New.
(handle_tick): Remove.
(handle_signal): Add handling SIGCONT.
(keyboxd_kick_the_loop): New.
(handle_connections): Spawn check_own_socket_thread and
check_others_thread if no inotify.
(check_own_socket_thread, check_others_thread): New.

--

This change follows the change of gpg-agent.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-01-24 13:45:49 +09:00
Werner Koch fd6c38605a
speedo: Add a hint to run ldconfig
--
2024-01-23 14:19:40 +01:00
Werner Koch 34d19d448d
tests: Add two more sample p12 files
--
GnuPG-bug-id: 6940
2024-01-23 13:55:43 +01:00
Werner Koch b7c1594861
speedo: Minor fix to the install target
--
2024-01-23 09:04:10 +01:00
NIIBE Yutaka 9408c6bf51
sm: Fix ECDH encryption with dhSinglePass-stdDH-sha384kdf-scheme.
* sm/encrypt.c (ecdh_encrypt): Cipher is AES192 for id-aes192-wrap.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2024-01-23 15:36:26 +09:00
Werner Koch ead2982286
gpg: Use ephemeral mode for generating card keys.
* g10/call-agent.c (agent_set_ephemeral_mode): New.
* g10/keyedit.c (keyedit_menu) <bkuptocard>: Switch to ephemeral mode.
* g10/keygen.c (do_generate_keypair): Switch to ephemeral mode for
card keys with backup.
--

GnuPG-bug-id: 6944
2024-01-22 16:52:22 +01:00
Werner Koch 434a641d40
agent: Add "ephemeral" Assuan option.
* agent/agent.h (struct ephemeral_private_key_s): New.
(struct server_control_s): Add ephemeral_mode and ephemeral_keys.
(GENKEY_FLAG_NO_PROTECTION, GENKEY_FLAG_PRESET): New.
* agent/genkey.c (clear_ephemeral_keys): New.
(store_key): Add arg ctrl and implement ephemeral_mode.  Change all
callers.
(agent_genkey): Replace args no_protection and preset by a generic new
flags arg.
* agent/findkey.c (wipe_and_fclose): New.
(agent_write_private_key): Add arg ctrl and implement ephemeral_mode.
Change all callers.
(agent_update_private_key): Ditto
(read_key_file): Ditto.
(agent_key_available): Ditto.
* agent/command-ssh.c (card_key_available): Do not update display s/n
in ephemeral mode.  This is however enver triggred.
* agent/gpg-agent.c (agent_deinit_default_ctrl): Cleanup ephemeral
keys.
* agent/command.c (cmd_genkey): Use the new flags instead of separate
vars.
(cmd_readkey): Create a shadow key only in non-ephemeral_mode.
(cmd_getinfo): Add sub-command "ephemeral".
(option_handler): Add option "ephemeral".
--

The idea here that a session can be switched in an ephemeral mode
which does not store or read keys from disk but keeps them local to
the session.

GnuPG-bug-id: 6944
2024-01-22 16:49:54 +01:00
Werner Koch 18320d692c
doc: Fix description of gpg --unwrap
--
2024-01-22 10:16:03 +01:00
Werner Koch ee56f71c8a
gpg: Add a communication object to the key generation code.
* g10/keygen.c (struct common_gen_cb_parm_s): New.
(common_gen): Add args common_gen_cb and common_gen_cb_parm.  Adjust
all callers.
(do_generate_keypair): Clarify the code by using a better var name.
--

We may eventually also replace the long arg list with that object.
The immediate reason for this change is the followup commit.
2024-01-22 10:16:03 +01:00
Werner Koch adeb17e375
card: New subcommand "checkkeys".
* agent/command.c (cmd_havekey): Add new option --info.
* tools/card-call-scd.c (scd_readkey): Allow using without result arg.
(struct havekey_status_parm_s): New.
(havekey_status_cb): New.
(scd_havekey_info): New.
(scd_delete_key): New.
* tools/gpg-card.c (print_keygrip): Add arg with_lf.
(cmd_checkkeys): New.
(cmdCHECKKEYS): New.
(cmds): Add command "checkkeys".
(dispatch_command, interactive_loop): Call cmd_checkkeys.
--

GnuPG-bug-id: 6943
2024-01-22 10:16:03 +01:00
Werner Koch c8060a8f23
doc: Document Backup-info in keyformat.txt
--

This name is used by Kleopatra for quite some time now but was missing
a specification.
2024-01-22 10:16:03 +01:00
Tobias Fella cb8eb366cb
Pass PINENTRY_GEOM_HINT environment variable to pinentry
* common/session-env.c: Add PINENTRY_GEOM_HINT to variables.

--

GnuPG-Bug-ID: 6930
2024-01-22 09:07:36 +01:00
Werner Koch 5402e6fb93
gpg: For v5 key generation for X448 also in parm file mode.
* g10/keygen.c (curve_is_448): New.
(do_create_from_keygrip): Pass arg keygen_flags byref so that it can
be updated.  Set v5 flag for X448.
(gen_ecc): Ditto.
(do_create): Change keygen_flags as above.  For robustness change
checking for Ed448.
(do_generate_keypair): Change keygen_flags as above
(generate_subkeypair): Ditto.
(gen_card_key): Ditto. Support v5 keys.
--

GnuPG-bug-id: 6942
2024-01-16 14:32:04 +01:00
Werner Koch 1a2c8267f5
gpg: When using a parm file w/o usage don't set the RENC usage.
* g10/keygen.c (proc_parameter_file): Don't include RENC in the
default usage.
--

Testplan:

  $ gpg --gen-key --batch <<EOF
  Key-Type: EDDSA
  Key-Curve: ed448
  Key-Usage: cert
  Name-Real: Meh Muh
  Name-Email: test-3@example.org
  Expire-Date: 2025-01-01
  Passphrase: abc
  subkey-type: ecdh
  Subkey-curve: cv448
  EOF

and check that the R flag does not show up in the usage.
2024-01-16 14:02:42 +01:00
Werner Koch daedb3c965
doc: Describe the ssh-agent protocol options for Windows.
--

Also fix a typo in a macro.
2024-01-15 17:21:24 +01:00
Jakub Bogusz 4cdfc1d0d9
po: Update parts of the Polish translation
--

Jakub provided the translation in October but at this time it did
cleanly apply anymore due to string changes.  Thus only parts of his
changes are here.  -wk
2024-01-15 11:28:00 +01:00
Werner Koch 0cb622d632
gpgsm: Allow parsing of PKCS#12 files with two private keys.
* sm/minip12.c (struct p12_parse_ctx_s): Add privatekey2.
(parse_shrouded_key_bag): Handle a second private key.
(p12_parse_free_kparms): New.

* sm/import.c (parse_p12): Factor some code out to ...
(p12_to_skey): this.
(parse_p12): Use p12_parse_free_kparms.
--

Take care: We allow parsing of a second private key but we are not yet
able to import the second private key.

The whole things is required to at least import the certificates of
current pkcs#12 files as created by the German Elster tax system.  No
test data, sorry.
2024-01-15 09:56:07 +01:00
Werner Koch 092154e17e
gpgsm: Improve the status line for --verify errors.
* sm/verify.c (gpgsm_verify): Improve verify.leave status line.
--

Suggested-by: Jakob Bohm
2024-01-15 09:13:46 +01:00
Mario Haustein 3d60ad5c8c
po: Fix indentation for key generation options
--
2024-01-15 09:02:03 +01:00
Werner Koch b97a36f52d
Prepare the NEWS
--
2024-01-12 16:53:53 +01:00
Werner Koch 3f12e3dacb
speedo: Add install target for Unix.
* build-aux/speedo.mk: Default to SELFCHECK=0.
(install, install-speedo): New targets.
--

GnuPG-bug-id: 6710
2024-01-12 13:50:50 +01:00
Werner Koch 5a6df94a9a
speedo: Patch ELF binaries to use built libraries
* build-aux/speedo.mk: Remove GUI stuff.  Add patchelf feature.
* Makefile.am (speedo): New target.
--

GnuPG-bug-id: 6710
2024-01-12 10:52:00 +01:00
Werner Koch bbad0a2644
gpg: Improve error message for expired default keys.
* g10/getkey.c (parse_def_secret_key): Track reason for skipping keys.
--

GnuPG-bug-id: 4704
2024-01-11 15:54:27 +01:00
Werner Koch e65720f286
doc: Document the gpgconf --unlock command.
* tools/gpgconf.c (main): Fix usage message.
--

GnuPG-bug-id: 6838
2024-01-11 15:30:12 +01:00
Werner Koch 8dfbad0c41
gpg: Fix regression in the Revoker keyword of the parmeter file.
* g10/keygen.c (parse_revocation_key): Actually allow for v4
fingerprints.
--

Note that the use of the parameter file is deprecated.

GnuPG-bug-id: 6923
2024-01-11 09:08:54 +01:00
Werner Koch b7f45ee6ad
gpg: Allow to create revocations even with non-compliant algos.
* g10/sign.c (do_sign): Skip compliance check for revocation certs.
--

It just does not make sense to inhibit the creation of revocations
depending on the compliance mode.  We do this only for key revocation
but not for another kind of revocation because the rationale for uid
or subkey revocation is more complicated to explain.
2024-01-10 17:18:34 +01:00
Werner Koch 275ced5067
scd:p15: Allow signing for CVISION cards
* scd/app-p15.c (do_sign): Add code for Starcos 3.2 and the CVISION
product.
--

The code for the Starcos cards has been implemented according to the
3.52 manual However, this does not work with my test cards.  Protocol
analysis shows that decryption can be used for the cryptovision
product.  Thus we do it the same for now.
2024-01-10 14:35:26 +01:00
Werner Koch 6233a17ac9
g13: New option --no-mount.
* g13/g13.c (oNoMount): New.
(opts): Add --no-mount.
(main): Implement this.
* g13/g13-common.h (opt): Add field no_mount.
* common/status.h (STATUS_PLAINDEV): New.
* g13/sh-cmd.c (has_option): Uncomment.
(cmd_mount): Add option --no-mount and pass down.
* g13/sh-dmcrypt.c (sh_dmcrypt_mount_container): Add arg nomount and
emit PLAINDEV status line.
(sh_dmcrypt_umount_container): Rund findmnt before umount.
--

This option can be used to decrypt a device but not to mount it.  For
example to run fsck first.  A command or option to run fsck before a
mount will eventually be added.

The use of findmnt is needed so that we can easily remove a device
which has not been mounted.
2024-01-09 19:52:04 +01:00
Werner Koch 4ca017e43b
gpg: Print a useful error id SKI algo 253 is found.
* g10/parse-packet.c (parse_key): Detect the SKI algo 253.
--

As long as we have not yet implemented this we should at least be
able to detect this case.
2024-01-09 17:25:48 +01:00
Werner Koch 880dde8e5b
scd:p15: Allow PIN verification and decryption for CVISION cards.
* scd/app-p15.c (CARD_PRODUCT_CVISION): New.
(IS_STARCOS_3): New.
(read_p15_info): Detect this product.
(prepare_verify_pin): Add special handling for this product.
(do_decipher): Use dedicated MSE for Starcos 3 cards.
--

To check the verification run

  gpg-card verify User_PIN

For our test cards the "Benutzer-PIN" must be given.  For decryption
tests gpgsm can be used; --always-trust helps to avoid chain issues.
2024-01-09 17:12:20 +01:00
Werner Koch 35fd89b168
gpgconf: Adjust -X command for the new VERSION file format
* tools/gpgconf.c (show_version_gnupg): Read and parse the entire
VERSION file.
--

GnuPG-bug-id: 6918
2024-01-09 12:52:57 +01:00
Werner Koch 45f6357881
common,w32: Remove duplicated backslashes when setting the homedir.
* common/homedir.c (copy_dir_with_fixup) [W32]: Fold double
backslashes.
--

This is in general no problem but when we hash or compare the directory
to test whether tit is the standard home directory, we may use a
different socket file and thus a second instance of a daemon.

GnuPG-bug-id: 6833
2024-01-09 10:13:54 +01:00
Werner Koch 2cb97713e9
gpg: Improve error return for --quick-add-subkey and -add-adsk.
* g10/keyedit.c (keyedit_quick_addkey): Emit a ERROR status line.
(keyedit_quick_addadsk): Ditto.
--

GnuPG-bug-id: 6880
2024-01-05 11:33:51 +01:00
Werner Koch 3f8cb9b339
scd: Add support for SCE 7.0
* scd/app-common.h (CARDTYPE_SCE7): New.
* scd/app.c (strcardtype): Support it.
(atr_to_cardtype): New.
(app_new_register): Try to get the cardtype from atr_to_cardtype.
* scd/app-piv.c (app_select_piv): Tweak for SCE7.  Add general method
to construct a S/N from the Card UUID.
--

The test cards I have are rsa2048 with X.509 certificates.  I don't
have the entire chain but loading the certificates work.  For testing
I created an OpenPGP key from the keys and tested signing and
decryption.

GnuPG-bug-id: 6919
2024-01-04 16:29:33 +01:00
Werner Koch 4c04143d81
gpg: Choose key from inserted card over a non-inserted card
* g10/call-agent.c (agent_probe_secret_key): Do not return an error
but 0.
* g10/getkey.c (finish_lookup): Improve the selection of secret keys.
--

GnuPG-bug-id: 6831
2024-01-02 10:19:57 +01:00
NIIBE Yutaka 591a53d716
gpg: Don't call keybox_compress when KEYDB_RESOURCE_FLAG_READONLY.
* g10/keydb.c (keydb_add_resource): Check the FLAGS to call
keybox_compress.

--

GnuPG-bug-id: 6811
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-29 10:57:26 +09:00
NIIBE Yutaka 6ddaf2be9f
common: Remove t-b64.c.
* common/Makefile.am (module_tests): Remove t-b64.
(t_b64_LDADD): Remove.
* common/t-b64.c: Remove.

--

GnuPG-bug-id: 6734
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-26 15:07:44 +09:00
NIIBE Yutaka 7cde533ce8
agent,kbx: Fix reliable_homedir_inotify (2/2).
* agent/gpg-agent.c (main): The value of reliable_homedir_inotify
doesn't not related to nodetach, and it's only zero in the specific
condition.
* kbx/keyboxd.c (handle_connections): Remove the last argument.
(main): Remove reliable_homedir_inotify, as it's always one.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-26 13:29:49 +09:00
NIIBE Yutaka c44f0bc91e
agent,kbx: Fix reliable_homedir_inotify (1/2).
* agent/gpg-agent.c (reliable_homedir_inotify): Remove the global.
(handle_connections): Add reliable_homedir_inotify as an arg.
Don't call gnupg_inotify_watch_delete_self when it's not reliable.
(check_others_thread): No check of reliable_homedir_inotify repeatedly
in the loop.
* kbx/keyboxd.c (reliable_homedir_inotify): Remove the global.
(handle_connections): Add reliable_homedir_inotify as an arg.
(handle_tick): No check of reliable_homedir_inotify in the loop.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-26 13:29:40 +09:00
NIIBE Yutaka 2be53b214d
tools: Fix argparse table of gpgconf.
* tools/gpgconf.c (opts): Use ARGPARSE macros.

--

GnuPG-bug-id: 6902
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-25 10:09:41 +09:00
Werner Koch 2764ee309a
Merge branch 'STABLE-BRANCH-2-4'
--

Fixed conflicts in
        NEWS
	g10/encrypt.c
	sm/encrypt.c
	sm/sign.c
2023-12-22 13:45:02 +01:00
Werner Koch 431239b83d
doc: Explain why socket activation is a problem
--
2023-12-22 13:19:40 +01:00
Werner Koch 239c1fdc28
common: Add keyword socketdir to gpgconf.ctl
* common/homedir.c (enum wantdir_values): New enums.
(unix_rootdir): Change arg to use the enums.  Adjust all callers.  Add
support for the socketdir keyword.
(_gnupg_socketdir_internal): Take care of the socketdir keyword in
gpgconf.ctl.

* doc/tools.texi (Files used by gpgconf): Briefly explain the
gpgconf.ctl syntax.
2023-12-22 12:47:39 +01:00
NIIBE Yutaka 2376cdff13
scd:openpgp: Add the length check for new PIN.
* scd/app-openpgp.c (do_change_pin): Make sure new PIN length
is longer than MINLEN.

--

GnuPG-bug-id: 6843
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-22 13:32:40 +09:00
Werner Koch 853f36e596
Register DCO for Mario Haustein
--
2023-12-21 11:50:16 +01:00
NIIBE Yutaka 91255c3afd
tools: Remove the dotlock tool.
* tools/Makefile.am (libexec_PROGRAMS): Remove dotlock.
* tools/dotlock.c: Remove.

--

It's integrated into gpgconf (--lock/--unlock).

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-21 12:35:55 +09:00
Werner Koch f2904737e5
scd:p15: Add a diagnostic for unsupported DTRUST4 features.
* scd/app-p15.c (do_sign): Add a diagnostic.
2023-12-20 16:52:47 +01:00
Mario Haustein via Gnupg-devel 0b85a9ac09
scd:p15: Add support for D-Trust Card 4.1/4.4
* scd/app-p15.c (CARD_PRODUCT_DTRUST4) New.
(app_select_p15): This cards uses a different AID for PKCS#15
application
(do_sign): The card doesn't support MSE SET, but requires MSE RESTORE to
a predefined template.
(do_decipher): Ditto.
2023-12-20 16:47:25 +01:00
Mario Haustein via Gnupg-devel 812f988059
scd:p15: Add support for CardOS 5.4
* scd/app-p15.c (CARD_TYPE_CARDOS_54): New.
2023-12-20 16:42:00 +01:00
Werner Koch 5d651fc8fd
doc: Explain what to put into mailcap for gpg-wks-client.
--
2023-12-20 15:30:37 +01:00
NIIBE Yutaka 4dd4e9d2f1
agent: Fix homedir check wrt --disable-check-own-socket option.
* agent/gpg-agent.c (handle_connections): Don't disable use of inotify
when it has the --disable-check-own-socket option.

--

Before the fix, it checks the homedir using the gnupg_stat function
when --disable-check-own-socket is enabled, without trying use of
inotify.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-20 16:13:49 +09:00
NIIBE Yutaka 93b5ba38dc
tools: Integrate the dotlock tool into gpgconf.
* tools/gpgconf.c (dotlock_tool): New.
(main): Add --lock and --unlock commands.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-20 11:06:03 +09:00
NIIBE Yutaka 1f04993cd0
common: Add dotlock util under libexec.
* tools/Makefile.am (libexec_PROGRAMS): Add dotlock.
* tools/dotlock.c: Finish the first implementation.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-20 11:05:50 +09:00
NIIBE Yutaka b298322d36
common: Clean up the temporary file at dotlock_destroy.
* common/dotlock.c (dotlock_destroy): Clean up the temporary file
created when it fails.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-20 11:05:36 +09:00
NIIBE Yutaka 2f6fec3f48
common: Support not-removing the lockfile by dotlock_destroy.
* common/dotlock.c (dotlock_destroy): Keep the lock
when DOTLOCK_LOCK_BY_PARENT.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-20 11:05:22 +09:00
NIIBE Yutaka 5488ad0517
common: Fix a possible resource leak for dotlock.
* common/dotlock.c (dotlock_destroy_unix): Don't release ->TNAME here.
(dotlock_destroy): Release the memory unconditionally.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-20 11:05:12 +09:00
Werner Koch 8eff1d4c51
common: Improve the parsing of gpgconf.ctl variables.
* common/homedir.c (unix_rootdir): Simplify.
--

This also relaxes the syntax in that the equal sign may now be
surrounded by any number of spaces.
2023-12-19 10:04:49 +01:00
NIIBE Yutaka 6b4fd3a5da
common: Enhance dotlock, so that we can have a CLI util.
* common/dotlock.h (DOTLOCK_LOCK_BY_PARENT, DOTLOCK_LOCKED): New.
* common/dotlock.c [HAVE_POSIX_SYSTEM]: Include <dirent.h>.
(dotlock_get_process_id, dotlock_detect_tname): New.
(dotlock_create_unix): Handle the case when no_write option is
specified.  Not creating the lock file, but detect the the file of
tname.
(dotlock_create) [HAVE_POSIX_SYSTEM]: Add support of
DOTLOCK_LOCK_BY_PARENT and DOTLOCK_LOCKED for dotlock CLI util.
(dotlock_take_unix): Support the case of DOTLOCK_LOCK_BY_PARENT.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-19 15:59:41 +09:00
NIIBE Yutaka 1c5584c395
kbx: Create public-keys.d, after creating the homedir.
* kbx/keyboxd.c (create_directories): Following the behavior of
gpg-agent, call create_public_keys_directory after mkdir.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-19 15:56:13 +09:00
Werner Koch bd8346f7ab
keyboxd: Pass lock info back to gpg and gpgsm.
* g10/call-keyboxd.c (keydb_default_status_cb): New.
(keydb_update_keyblock): Add new status callback.
(keydb_insert_keyblock): Ditto.
(keydb_delete_keyblock): Ditto.
(search_status_cb): Also try the new status callback.
* sm/keydb.c (keydb_default_status_cb): New.
(keydb_insert_cert): Add new status callback.
(keydb_delete): Ditto
(search_status_cb): Also try the new status callback.
--

GnuPG-bug-id: 6838
2023-12-18 16:23:19 +01:00
Werner Koch c99282fc78
keyboxd: Timeout on failure to get the database lock.
* kbx/backend-sqlite.c (dblock_info_cb): New.
(create_or_open_database): Add arg ctrl.  Add a 10 second timeout.
Avoid warning on error if not locked.
(be_sqlite_add_resource): Do not open the database here.
(be_sqlite_search): ... but do it here.
--

Note that we need to delay the initalization to the first use of the
database so that we actually have a recipient for the status messages.

GnuPG-bug-id: 6838
2023-12-18 15:25:45 +01:00
Werner Koch 937aeb1904
common: Add an info callback to dotlock.
* common/dotlock.h (enum dotlock_reasons): New.
(DOTLOCK_PREPARE_CREATE): New flag.
* common/dotlock.c (struct dotlock_handle): Add info_cb and
info_cb_value.
(dotlock_create): Support the new flag.
(dotlock_finish_create): New.
(read_lockfile): Silence in case of ENOENT.
(dotlock_set_info_cb): New.  Use callback after all error and info
messages.
(dotlock_take_unix, dotlock_take_w32): Allow termination by callback.
2023-12-18 15:21:26 +01:00
NIIBE Yutaka 4e94b004a6
scd: Debug output is only enabled with an option.
* scd/command.c (pin_cb): Check if DBG_IPC for log_debug.
(send_client_notifications): Check opt.verbose to output a message.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-18 11:25:01 +09:00
Werner Koch f57717bf23
common: Improve error return for dotlock.
* common/dotlock.c (dotlock_take_unix): Return a ETIMEDOUT insteaad of
EACCESS on timeout.
(dotlock_take_w32): Ditto.
2023-12-12 16:31:30 +01:00
NIIBE Yutaka 37fa36a329
doc: Fix description of scdaemon for --disable-ccid.
--

Cherry-picked from 2.4 branch of the commit:

	6b93b92111

GnuPG-bug-id: 6871
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-12 14:30:59 +09:00
NIIBE Yutaka 6b93b92111
doc: Fix description of scdaemon for --disable-ccid.
--

GnuPG-bug-id: 6871
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-12-12 14:26:49 +09:00
Ahelenia Ziemiańska 1ded50dd5b
po: Fix quotes in Polish Translation.
--

Cherry-pick from 2.4 commit of:
	fa677a37ce

Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
2023-12-07 12:01:25 +09:00
Ahelenia Ziemiańska fa677a37ce
po: Fix quotes in Polish Translation.
--

Signed-off-by: Ahelenia Ziemiańska <nabijaczleweli@nabijaczleweli.xyz>
2023-12-07 11:59:20 +09:00
Daniel Cerqueira 548d4aad5f
po: Update Portuguese Translation.
--

Cherry-picked from 2.4 branch of commit:
	a14f73a192

This commit log (with no ChangeLog entry) is written by gniibe,
following the practice; Translation update don't need a ChangeLog
entry in a commit log.

Signed-off-by: Daniel Cerqueira <dan.git@brilhante.top>
2023-12-01 15:23:49 +09:00
Daniel Cerqueira a14f73a192
po: Update Portuguese Translation.
--

This commit log (with no ChangeLog entry) is written by gniibe,
following the practice; Translation update don't need a ChangeLog
entry in a commit log.

Signed-off-by: Daniel Cerqueira <dan.git@brilhante.top>
2023-11-30 08:57:52 +09:00
Werner Koch 73aa6dc6e4
gpgsm: Set validity flag in keylisting to n for untrusted root cert.
* sm/keylist.c (list_cert_colon): Map not_trusted to 'n' for non-root
certs like we do for root certs.
--

GnuPG-bug-id: 6841
2023-11-27 13:39:45 +01:00
Werner Koch 4c456bf075
scd:openpgp: Fallback to default ECDH params in writekey.
* scd/app-openpgp.c (ecc_writekey): Use default ECDH parameters and
remove the now useless check.
--

This seems to be better than bailing out.  In almost all cases our
standard parameters are used and if not, well, the fingerprint will be
wrong.

GnuPG-bug-id: 6378
2023-11-23 16:01:58 +01:00
Werner Koch 09329d52b5
agent: Update the key file only if changed (slight return).
* agent/findkey.c (read_key_file): Add optional arg r_orig_key_value
to return the old Key value.  Change all callers.
(agent_write_private_key): Detect whether the Key entry was really
changed.
--

GnuPG-bug-id: 6829
2023-11-21 12:24:17 +01:00
Werner Koch 813bb65d95
common: Check wether to set the modified flag in nve_set.
* common/name-value.c (nvc_set): Factor code out to ...
(nve_set): here.
2023-11-21 08:56:24 +01:00
Werner Koch cf2d3f7ba0
agent: Update the key file only if not changed.
* common/name-value.c (struct name_value_container): Add flag
"modified".
(nvc_modified): New.
(nvc_new): Set flag.
(_nvc_add): Set flag.
(nvc_delete): Set flag.
(nvc_set): Set flag unless value did not change.
(nve_set): Add arg PK.  Change the caller.
* agent/findkey.c (agent_write_private_key): Update only if modified.
--

This helps software which uses a file system watcher to track changes
to private keys.  In particular smartcard triggered changes are a
problem for such software because this may at worst trigger another
smartcard read.

GnuPG-bug-id: 6829
2023-11-21 08:37:41 +01:00
Werner Koch e43bd2a7a7
scd: New option --debug-allow-pin-logging.
* scd/scdaemon.c (oDebugAllowPINLogging): New.
(opts): Add option.
(main): Set option.
* scd/scdaemon.h (opt): Add debug_allow_pin_logging.
* scd/apdu.c (pcsc_send_apdu): Do not hide the PIN dat in the debug
output if the option is set.
(send_apdu_ccid): Ditto.
--

This option is only required during development.
2023-11-21 08:35:01 +01:00
NIIBE Yutaka 2fa916ebff
po: Update Japanese Translation.
--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-20 10:53:09 +09:00
NIIBE Yutaka 960877b10f
gpg: Report BEGIN_* status before examining the input.
* common/miscellaneous.c (is_openpgp_compressed_packet)
(is_file_compressed): Moved to ...
* common/iobuf.c: ... in this file.
(is_file_compressed): Change the argument to INP, the iobuf.
* common/util.h (is_file_compressed): Remove.
* common/iobuf.h (is_file_compressed): Add.
* g10/cipher-aead.c (write_header): Don't call write_status_printf
here.
(cipher_filter_aead): Call write_status_printf when called with
IOBUFCTRL_INIT.
* g10/cipher-cfb.c (write_header): Don't call write_status_printf
here.
(cipher_filter_cfb): Call write_status_printf when called with
IOBUFCTRL_INIT.
* g10/encrypt.c (encrypt_simple): Use new is_file_compressed function,
after call of iobuf_push_filter.
(encrypt_crypt): Likewise.
* g10/sign.c (sign_file): Likewise.

--

Cherry-pick from master commit of:
	2f872fa68c

GnuPG-bug-id: 6481
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-17 08:40:49 +09:00
Werner Koch 5304c9b080
scd:p15: Basic support for Starcos 3.2.
* scd/app-p15.c (CARD_TYPE_STARCOS_32): New.
(card_atr_list): Add ATR for my sample card.
(cardtype2str): Add starcos string.
(select_ef_by_path): Factor all code out to ...
(select_by_path): this.  Add arg to request a directory.  Simplify the
case pathlen>1 case.  Fix error printing.
(select_df_by_path): New.
(prepare_verify_pin): For starcos select a DF.
(app_select_p15): Don't use extended mode for starcos.
--

This allows reading the certificates from my sample cards.  Signing
does not yet work; I need to do get some I/O traces using other
software.  The basic support for AET cards shut still work but I have
not found my AET card.
2023-11-16 17:10:08 +01:00
Werner Koch a33ad8f9bf
scd: Minor debug output tweak
* scd/apdu.c (send_le): Do not dump "[all zero]" if tehre is no data.
* scd/iso7816.c (iso7816_select_mf): Cosmetic fix.
2023-11-16 17:04:02 +01:00
NIIBE Yutaka 42ee841976
doc: Update for gpgv.
--

GnuPG-bug-id: 6810
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-16 13:31:42 +09:00
Max-Julian Pogner 2600047470
gpgv: Update used keyrings in doc FILES section
* doc/gpgv.texi: Explicitely list all searched default keyrings in the
  FILES section.
* doc/gpgv.texi: use ${GNUPGHOME} placeholder to be extra precise.
2023-11-16 11:46:22 +09:00
Werner Koch def8f5f3d2
gpg,gpgsm: Hide password in debug output also for asked passwords.
* g10/call-agent.c (agent_get_passphrase): Call
assuan_begin_confidential and assuan_end_confidential.
* sm/call-agent.c (gpgsm_agent_ask_passphrase): Ditto.
--

GnuPG-bug-id: 6654

The drawback of this solution is that we don't see any IPC lines from
the assuan_transact.  Everything else would require larger changes to
libassuan.
2023-11-14 15:09:27 +01:00
Werner Koch e6cedba119
gpgsm: Re-introduce the bad passphrase hint for pkcs#12.
* sm/minip12.c (parse_bag_encrypted_data): Set the badpass flag.
(parse_shrouded_key_bag): Ditto.
--
2023-11-14 09:47:13 +01:00
Werner Koch 6fab7b075a
gpg: Implement a parser for Kyber encrypted packets.
* g10/misc.c (pubkey_get_nenc): Add ky768 and ky1024 values.
* g10/parse-packet.c (read_octet_string): New.
(read_size_body): Rename to ...
(read_sized_octet_string): this and change args to update-able PKTLEN.
(parse_pubkeyenc): Split general parsing loop for easier reading.
Implement parser for the Kyber algorithms.
--

Take care: this has not been tested at all, it merely passes the
regression test for the other algos.

Kyber is also known as ML-KEM in FIPS-203.

The list mode is slighly changed: In case of a parsing error no data
is printed - before that already parsed data was printed.

GnuPG-bug-id: 6815
2023-11-13 16:13:30 +01:00
NIIBE Yutaka bafa7bf27f
gpg,sm: Set confidential in assuan communication for password.
* g10/call-agent.c (default_inq_cb): Call assuan_begin_confidential
and assuan_end_confidential.
* sm/call-agent.c (default_inq_cb): Likewise.

--

Cherry pick from master commit of:
	ec1446f944

GnuPG-bug-id: 6654
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-09 13:40:03 +09:00
NIIBE Yutaka ec1446f944
gpg,sm: Set confidential in assuan communication for password.
* g10/call-agent.c (default_inq_cb): Call assuan_begin_confidential
and assuan_end_confidential.
* sm/call-agent.c (default_inq_cb): Likewise.

--

GnuPG-bug-id: 6654
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-09 13:36:12 +09:00
Werner Koch 3572b19fbd
gpgsm: Support ECDSA in de-vs mode.
* common/compliance.h (PK_ALGO_FLAG_ECC18): New.
* common/compliance.c (gnupg_pk_is_allowed): Implement.
* sm/decrypt.c (gpgsm_decrypt): Pass new flag.
* sm/sign.c (gpgsm_sign): Ditto.
* sm/verify.c (gpgsm_verify): Ditto.
--

GnuPG-bug-id: 6802
2023-11-08 17:09:22 +01:00
Werner Koch bf7b785b0e
common: Declare two LibrePGP constants for future use
* common/openpgpdefs.h (SIGSUBPKT_META_HASH): New.
(SIGSUBPKT_TRUST_ALIAS): New.
2023-11-08 17:09:22 +01:00
Werner Koch 3a669f175f
gpgsm: Cleanup of legacy variable name use.
* sm/encrypt.c (gpgsm_encrypt): Unify use of RC and ERR.
* sm/sign.c (gpgsm_sign): ditto.
--

Initially we didn't used the gpg_error_t thingy and while migrating
we sometimes used RC and ERR for tracking the error.  This is pretty
error prone and thus we better remove it (after 20 years).
2023-11-08 17:09:22 +01:00
NIIBE Yutaka d6f738729f
gpg,tools: Handle GPG_ERR_PIN_BLOCKED and GPG_ERR_NO_RESET_CODE.
* g10/card-util.c (write_sc_op_status): Emit 3 and 4 in status line.
* tools/card-call-scd.c (status_sc_op_failure): Likewise.

--

Cherry-pick from master commit of:
	64f5f7b74e

GnuPG-bug-id: 6425
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-08 13:57:53 +09:00
NIIBE Yutaka 4db2e13e2c
tools:gpg-card: Fix an error code for Reset Code.
* tools/gpg-card.c (cmd_unblock): Use GPG_ERR_NO_RESET_CODE.

--

Cherry-pick from master commit of:
	65607fb81d

GnuPG-bug-id: 6425
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-08 13:57:15 +09:00
NIIBE Yutaka 64f5f7b74e
gpg,tools: Handle GPG_ERR_PIN_BLOCKED and GPG_ERR_NO_RESET_CODE.
* g10/card-util.c (write_sc_op_status): Emit 3 and 4 in status line.
* tools/card-call-scd.c (status_sc_op_failure): Likewise.

--

GnuPG-bug-id: 6425
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-08 13:41:16 +09:00
NIIBE Yutaka 65607fb81d
tools:gpg-card: Fix an error code for Reset Code.
* tools/gpg-card.c (cmd_unblock): Use GPG_ERR_NO_RESET_CODE.

--

GnuPG-bug-id: 6425
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-08 13:31:55 +09:00
NIIBE Yutaka 4257cbb06c
scd: Return GPG_ERR_PIN_BLOCKED when it's blocked.
* scd/app-openpgp.c (build_enter_admin_pin_prompt): Fix to use
GPG_ERR_PIN_BLOCKED.
(check_pin): Likewise.

--

Cherry-pick from master commit:
	e6b3d53db3

GnuPG-bug-id: 6425
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-08 11:49:27 +09:00
NIIBE Yutaka e6b3d53db3
scd: Return GPG_ERR_PIN_BLOCKED when it's blocked.
* scd/app-openpgp.c (build_enter_admin_pin_prompt): Fix to use
GPG_ERR_PIN_BLOCKED.
(check_pin): Likewise.

--

GnuPG-bug-id: 6425
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-08 11:44:06 +09:00
Werner Koch 387ee7dcbd
Merge branch 'STABLE-BRANCH-2-4'
* common/b64dec.c (b64decode): Move to ...
* common/miscellaneous.c: here.

* common/t-b64.c: Re-inroduce and keep only the b64decode test code.
2023-11-07 20:38:27 +01:00
NIIBE Yutaka 337de21f4b
doc: Use the em dash to mark a break in a sentence.
--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-07 13:55:29 +09:00
NIIBE Yutaka 00da0e9f93
doc: Remove stray .RE in doc/gpgsm.texi.
--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-06 14:47:21 +09:00
NIIBE Yutaka c2812a9bbc
doc: Fix to avoid using en-dash for command options.
--

GnuPG-bug-id: 6746
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-11-02 15:05:19 +09:00
Andre Heinecke 05ef8c0cc0
g10: Fix uninitalized variable use in sign_file
* g10/sign.c (sign_file): Initialize gcry_md_hd_t to NULL.

--
There are several jumps to leave before gcry_md_open is called so
md should be initialized to NULL to avoid calling gcry_md_close
on an uninitalized variable.

GnuPG-Bug-Id: T6780
2023-10-28 14:20:31 +02:00
Werner Koch 678c819027
w32: Use utf8 for the asctimestamp function.
* common/gettime.c (asctimestamp) [W32]: Use ".UTF8" for the locale.
--

This has been suggested by the reporter of
GnuPG-bug-id: 6741
2023-10-27 14:22:10 +02:00
Werner Koch 95b9a31f81
gpg: Fix minor memory leak during certain smartcard operations.
* g10/keygen.c (card_store_key_with_backup): Fix memory leak on error.
2023-10-27 14:20:47 +02:00
Werner Koch a4fe307b55
gpg: Allow expiration time after 2038-01-19 on 32 bit Windows.
* g10/keygen.c (parse_expire_string_with_ct): Use isotime2epoch_u64.
(parse_creation_string): Ditto.
--

GnuPG-bug-id: 6736
2023-10-26 12:45:50 +02:00
Werner Koch 164c687cb6
common: New functions timegm_u64, isotime2epoch_u64.
* common/mischelp.c (timegm): Move to ...
* common/gettime.c (timegm): here.  On Windows use timegm_u32.
(timegm_u32): New.
(isotime2epoch): Factor code out to ...
(isotime_make_tm): new helper.
(isotime2epoch_u64): New.
(_win32_timegm): Remove duplicated code.
(parse_timestamp): Use of timegm.
(scan_isodatestr): Fallback to isotime2epoch_u64.
--

This mainly helps on 32 bit Windows.  For Unix we assume everyone is
using 64 bit or shall wait until the libc hackers finally provide a
time64_t.

GnuPG-bug-id: 6736
2023-10-26 12:39:43 +02:00
Werner Koch 2c3c049fd8
sm: Flag Brainpool curves as compliant for all other operations.
* sm/fingerprint.c (gpgsm_get_key_algo_info2): Rename to
(gpgsm_get_key_algo_info): this.  Remove the old wrapper.  Adjust all
callers.
* sm/decrypt.c (gpgsm_decrypt): Pass the curve to the compliance
checker.
* sm/encrypt.c (gpgsm_encrypt): Ditto.
* sm/sign.c (gpgsm_sign): Ditto.
* sm/verify.c (gpgsm_verify): Ditto.
--

GnuPG-bug-id: 6253
2023-10-24 14:54:26 +02:00
Werner Koch 97708e2ac7
sm: Flag Brainpool curves as compliant.
* sm/keylist.c (print_compliance_flags): Add arg curve.
(list_cert_colon): Pass curve to the compliance check.
--

GnuPG-bug-id: 6253
2023-10-24 14:22:32 +02:00
Werner Koch 4448bc44f0
common: Provide API to parse BER/TLV encodings.
* sm/minip12.c: Factor parsing code out to ...
* common/tlv-parser.c: new.  Extend function names and provide a few
extra functions.
* common/Makefile.am (common_sources): Add new file.

* sm/minip12.c: Adjust to use the new parser API.
2023-10-24 13:25:10 +02:00
Werner Koch 7661d2fbc6
sm: Another partly rewrite of minip12.c
* sm/minip12.c (struct tlv_ctx_s): Add origbuffer and origbufsize.
Remove pop_count.  Rename offset to length.
(dump_tag_info, _dump_tag_info): Rewrite.
(dump_tlv_ctx, _dump_tlv_ctx): Rewrite.
(tlv_new): Init origbuffer.
(_tlv_peek): Add arg ti.
(tlv_peek): New.
(tlv_peek_null): New.
(_tlv_push): Rewrite.
(_tlv_pop): Rewrite.
(tlv_next): New macro.  Move old code to ...
(_tlv_next): this.  Add arg lno.  Pop remaining end tags.
(tlv_popped): Remove.
(tlv_expect_object): Handle ndef.
(tlv_expect_octet_string): Ditto.
(parse_bag_encrypted_data): Use nesting level to control the inner
loop.
(parse_shrouded_key_bag): Likewise.
(parse_bag_data): Handle surplus octet strings.
(p12_parse): Ditto.

* sm/minip12.c (decrypt_block): Strip the padding.
(tlv_expect_top_sequence): Remove.  Replace callers by
tlv_expect_sequence.

* tests/cms/samplekeys/t6752-ov-user-ff.p12: New sample key.
* tests/cms/samplekeys/Description-p12: Add its description
--

This patch improves the BER parser by simplifying it.  Now tlv_next
pops off and thus closes all containers regardless on whether they are
length bounded or ndef.  tlv_set_pending is now always used to undo
the effect of a tlv_next in a loop condition which was terminated by a
nesting level change.

Instead of using the length as seen in the decrypted container we now
remove the padding and let the BER parser do its work.  This might
have a negative effect on pkcs#12 objects which are not correctly
padded but we don't have any example of such broken objects.

GnuPG-bug-id: 6752
2023-10-24 09:33:35 +02:00
Werner Koch 873b2b0da1
doc: Minor typo fixes.
--
2023-10-18 15:43:22 +02:00
Werner Koch 956b1e1c26
build: Extend autobuild diagnostics by the username
* m4/autobuild.m4 (AB_INIT): Add username.
--

The old autobuild diagnostics show up in build logs.  What they are
missing is an information on the user who triggered a build.  EMAIL is
a common thing to denote the actual user using a service account.
2023-10-16 16:31:08 +02:00
Werner Koch 606933dfb4
gpg: Allow to specify seconds since Epoch beyond 2038.
* g10/keygen.c (parse_expire_string_with_ct): Use new function
scan_secondsstr.
(parse_creation_string): Ditto.
--

Noet that we cap the seconds at the year 2106.

GnuPG-bug-id: 6736
2023-10-14 17:23:42 +02:00
Werner Koch a17363e992
common: New function scan_secondsstr.
* common/gettime.c (scan_secondsstr): New.

* common/t-gettime.c (test_scan_secondsstr):
(main): Call it.
2023-10-14 17:14:22 +02:00
Werner Koch 5601f5db98
gpgsm: Improvements for NDEF in the pkcs#12 parser
* sm/minip12.c (_tlv_push): Handle NDEF more correctly.
(tlv_expect_octet_string): Do not bail out on NDEF.
(dump_tag_info): Print some more infos.
--

We do not have a complete test case for this.  We need to further
analyze T6752 to see what Mozilla is doing here.  In any case with
this patch we get a bit further and don't bail out at the ndef.

GnuPG-bug-id: 6536, 6752
2023-10-10 11:37:00 +02:00
Werner Koch 4963f13f8f
scd:openpgp: Return better error codes for the Reset Code.
* scd/app-openpgp.c (do_change_pin): Use GPG_ERR_BAD_RESET_CODE where
appropriate.
* common/util.h: Add error codes missing in gpgrt 1.46.

* agent/call-pinentry.c (unlock_pinentry): Handle
GPG_ERR_BAD_RESET_CODE.
(agent_askpin): Ditlo.  Also simply condition.
(agent_get_passphrase):  Ditto.
* g10/call-agent.c (status_sc_op_failure): Handle
GPG_ERR_BAD_RESET_CODE.
* g10/card-util.c (write_sc_op_status): Ditto.
* tools/card-call-scd.c (status_sc_op_failure): Ditto.
2023-10-06 12:15:10 +02:00
Werner Koch 24b3a5a579
sm: Support more HMAC algos in the pkcs#12 parser.
* sm/minip12.c (oid_hmacWithSHA1): New.  Also for the SHA-2 algos.
(digest_algo_from_oid): New.
(set_key_iv_pbes2): Add arg digest_algo.
(crypt_block): Ditto.
(decrypt_block): Ditto.
(parse_bag_encrypted_data): Parse the optional prf part and get the
hmac algorithm.
(parse_shrouded_key_bag): Ditto.
(p12_build): Pass SHA1 for digest_algo.

* sm/t-minip12.c (run_one_test): Print failed values in verbose mode.

* tests/cms/samplekeys/nistp256-openssl-self-signed.p12: New.
* tests/cms/samplekeys/Description-p12: Add this one.
* tests/cms/Makefile.am (EXTRA_DIST): Ditto.
--

This supports the modern algorithms, i.e. using SHA256 for the KDF
which is the default in openssl unless the -legacy option is used.

GnuPG-bug-id: 6536
2023-10-06 11:02:19 +02:00
NIIBE Yutaka 9353dc811a
tests:tpm2dtests: Modify tests with SWTPM and relax the condition.
* configure.ac (SWTPM_IOCTL): Remove.
(TEST_LIBTSS): Fix the condition.
* tests/tpm2dtests/Makefile.am (TESTS_ENVIRONMENT): Remove
SWTPM_IOCTL.
* tests/tpm2dtests/start_sw_tpm.sh: Add --flags to invoke SWTPM,
not requiring SWTPM_IOCTL and TSSSTARTUP any more.

--

Cherry-picked from master commit of:
	227b3b14f4

GnuPG-bug-id: 6052
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-06 09:56:09 +09:00
NIIBE Yutaka 0e200f2187
tests:tpm2dtests: Fix tests with SWTPM.
* configure.ac (TEST_LIBTSS): Fix the condition with SWTPM.
* tests/tpm2dtests/start_sw_tpm.sh: Use --daemon and --pid
to run SWTPM.

--

Cherry-picked from master commit of:
	98dd6f7af6

GnuPG-bug-id: 6052
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-06 09:55:36 +09:00
NIIBE Yutaka 0494ec8f4d
build: Simplify detecting a TPM emulator.
* configure.ac (TPMSERVER): Don't supply hard-coded path.
(SWTPM, SWTPM_IOCTL, TSSSTARTUP): Likewise.

--

Cherry-picked from master commit of:
	f2ca727978

Having hard-coded path has bad side effect; It may not be detected
even if it's available with PATH.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-06 09:54:44 +09:00
NIIBE Yutaka e783866f41
tools: Add TPM2DAEMON_SOCK_NAME for --remove-socketdir.
* tools/gpgconf.c (main): Care about tpm2d.  Emit correct ERR.

--

Cherry-picked from master commit of:
	25c84ffd10

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-06 09:54:06 +09:00
NIIBE Yutaka d17efdcd6f
tests:tpm2dtests: Fix tests with TPM2D.
* tests/tpm2dtests/Makefile.am (TESTS_ENVIRONMENT): Fix.
* tests/tpm2dtests/all-tests.scm: Follow the change of gpgscm.
* tests/tpm2dtests/run-tests.scm: Likewise.

--

Cherry-picked from master commit of:
	321f9c0a3f

GnuPG-bug-id: 6052
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-06 09:53:31 +09:00
NIIBE Yutaka 8d0819346d
tpm2d: Check SWTPM environment variable for swtpm support.
* tpm2d/intel-tss.h (TSS_Create): Check SWTPM.

--

Cherry-picked from master commit of:
	1da40db03e

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2023-10-06 09:52:26 +09:00
NIIBE Yutaka 9909f622f6
agent: fix tpm2d keytotpm handling
* agent/divert-tpm2.c (agent_write_tpm2_shadow_key): Call
agent_delete_key before agent_write_private_key.  Recover
from an error.

--

Cherry-picked from master commit of:
	eda3997b43

Fixes-commit: a1015bf2fc
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2023-10-06 09:51:33 +09:00
NIIBE Yutaka 19caa5c267
agent: Initialize FP for the case of error return.
* agent/findkey.c (agent_write_private_key): Initialize FP.

--

Cherry-picked from master commit of:
	a8618fdccd

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-06 09:50:12 +09:00
Werner Koch b4449ffabc
gpg-card: Give a hint on how to get help for the "yubikey" command.
* tools/card-yubikey.c (yubikey_commands): Print a hint.
2023-10-05 11:07:16 +02:00
Werner Koch c1f78634ec
sm: Improve the octet string cramming for pkcs#12
* sm/minip12.c (need_octet_string_cramming): New.
(tlv_expect_object, tlv_expect_octet_string): Run the test before
cramming.

* sm/minip12.c (ENABLE_DER_STRUCT_DUMPING): New but undefined macro
for debug purposes.
(bag_decrypted_data_p, bag_data_p): Use macro to allow dumping.
--

This bug was exhibited by importing a gpgsm exported EC certificate.

We use an extra test instead of retrying to allow retruning an error
from malloc failure.  And well, for easier reading of the code.

GnuPG-bug-id: 6536
2023-10-05 10:25:14 +02:00
NIIBE Yutaka 16b6b77532
Minor style fixes.
--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-05 14:00:46 +09:00
NIIBE Yutaka 227b3b14f4
tests:tpm2dtests: Modify tests with SWTPM and relax the condition.
* configure.ac (SWTPM_IOCTL): Remove.
(TEST_LIBTSS): Fix the condition.
* tests/tpm2dtests/Makefile.am (TESTS_ENVIRONMENT): Remove
SWTPM_IOCTL.
* tests/tpm2dtests/start_sw_tpm.sh: Add --flags to invoke SWTPM,
not requiring SWTPM_IOCTL and TSSSTARTUP any more.

--

GnuPG-bug-id: 6052
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-05 10:21:35 +09:00
NIIBE Yutaka 98dd6f7af6
tests:tpm2dtests: Fix tests with SWTPM.
* configure.ac (TEST_LIBTSS): Fix the condition with SWTPM.
* tests/tpm2dtests/start_sw_tpm.sh: Use --daemon and --pid
to run SWTPM.

--

GnuPG-bug-id: 6052
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-04 18:30:33 +09:00
NIIBE Yutaka 68b7aff9ce
agent: Fix agent_update_private_key.
* agent/findkey.c (agent_update_private_key): Check FNAME0.

--

Cherry-pick master commit of:
	08e529fa7c

Fixes-commit: a216e9c028
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-04 10:27:01 +09:00
NIIBE Yutaka 08e529fa7c
agent: Fix agent_update_private_key.
* agent/findkey.c (agent_update_private_key): Check FNAME0.

--

Fixes-commit: a216e9c028
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-04 10:25:30 +09:00
NIIBE Yutaka f2ca727978
build: Simplify detecting a TPM emulator.
* configure.ac (TPMSERVER): Don't supply hard-coded path.
(SWTPM, SWTPM_IOCTL, TSSSTARTUP): Likewise.

--

Having hard-coded path has bad side effect; It may not be detected
even if it's available with PATH.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-03 16:55:02 +09:00
NIIBE Yutaka 25c84ffd10
tools: Add TPM2DAEMON_SOCK_NAME for --remove-socketdir.
* tools/gpgconf.c (main): Care about tpm2d.  Emit correct ERR.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-03 16:54:19 +09:00
NIIBE Yutaka 321f9c0a3f
tests:tpm2dtests: Fix tests with TPM2D.
* tests/tpm2dtests/Makefile.am (TESTS_ENVIRONMENT): Fix.
* tests/tpm2dtests/all-tests.scm: Follow the change of gpgscm.
* tests/tpm2dtests/run-tests.scm: Likewise.

--

GnuPG-bug-id: 6052
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-03 11:53:00 +09:00
NIIBE Yutaka 4206d89003
tests:gpgscm: Fix process select loop.
* tests/gpgscm/ffi.c (do_process_spawn_io): Clear READ_FDSET in the
loop.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-03 11:44:11 +09:00
Werner Koch 9a3e41c151
common: Improve lock strategy for dotlock.
* common/dotlock.c (next_wait_interval): New.
(dotlock_take_unix): Use new function.
(dotlock_take_w32): Ditto.
--

In particular when using a dotlock file for protecting the spawning
and several processes try to spawn the agent or another component, we
often run into long delays.  The solution is to is to exponential
backoff and also to reduce the initial delay from 50ms to 4ms.  We
further limit the maximum wait period to about 2 seconds and then
repeat at intervals of 512, 1024 and 2048ms.  In the wait-forever case
we add a small random value to have different intervals per process.

GnuPG-bug-id: 3380

For testing this code snippet in the spawning function might be
useful:

          const char *s;
          if ((s=getenv("hold_gpg_file")))
            while (!gnupg_access (s, F_OK))
              gnupg_sleep (1);
2023-10-02 14:45:19 +02:00
Werner Koch d7a1577a25
dirmngr: Add code to support the negotiation auth method.
* dirmngr/http.c (enum auth_negotiate_states): New.
(struct proxy_info_s): Add new fields.
(release_proxy_info): Free Windows stuff.
(proxy_get_token): New. Implemented only for Windows for now.
(run_proxy_connect): Add support for auth method Negotiation.
(store_header): Keep some header lines separate.
--

The code does something but I have not yet been able to test it due
to problems setting up Squid with AD authentication.  As of now it
will respond with a failure but that should not be worse than not to
implement Negotiation.

Supporting Negotiation using GSS for Unix should eventually also be
done.

GnuPG-bug-id: 6719
2023-10-02 13:10:13 +02:00
Werner Koch 53bdb7440c
dirmngr: Extended the http_get_header function.
* dirmngr/http.c (send_request): Add arg 'skip'.  Adjust all callers.
--

GnuPG-bug-id: 6719
2023-10-02 13:05:49 +02:00
Werner Koch 52b7a60cf9
common: Add new function b64decode.
* common/b64dec.c (b64decode): New.
* common/t-b64.c: Change license to LGPL.
(oops): New macro.
(hex2buffer): New.
(test_b64decode): New.
(main): Default to run the new test.
* common/Makefile.am (module_maint_tests): Move t-b64 to ...
(module_tests): here.
--

Sometimes we have a short base64 encoded string we need todecode.
This function makes it simpler.

License change of the test module justified because I am the single
author of the code.
2023-10-02 13:03:03 +02:00
NIIBE Yutaka 78afc209cc
tpm2d: Fix call to assuan_control.
* tpm2d/tpm2daemon.c (main): Use ASSUAN_CONTROL_REINIT_SYSCALL_CLAMP.

--

Fixes-commit: 9e4d522239
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-10-02 10:32:04 +09:00
NIIBE Yutaka 1da40db03e
tpm2d: Check SWTPM environment variable for swtpm support.
* tpm2d/intel-tss.h (TSS_Create): Check SWTPM.

--

Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2023-09-28 13:26:52 +09:00
NIIBE Yutaka eda3997b43
agent: fix tpm2d keytotpm handling
* agent/divert-tpm2.c (agent_write_tpm2_shadow_key): Call
agent_delete_key before agent_write_private_key.  Recover
from an error.

--

Fixes-commit: a1015bf2fc
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
2023-09-28 11:59:14 +09:00
Werner Koch a5e33618f4
dirmngr: Fix handling of the HTTP Content-Length
* dirmngr/http.c (cookie_s): Add fields pending, up_to_empty_line,
last_was_lf, and last_was_lfcr.
(http_context_s): Add field keep-alive.
(http_wait_response): Set up_to_empty_line.  Take care of keep_alive
flag.
(coookie_read): Implement detection of empty lines.
(cookie_write): Free the pending buffer.
--

The problem we fix here is that we already buffered stuff beyond the
empty line which marks the start of the content-length counting.  Thus
we tried to wait for more bytes despite that everything had already
been read.  This bug might have showed up more often in the real world
since the we changed the BUFSIZ on Windows from 512 byte to 8k.  It
also depends on the length of the headers and whether the server
closed the connection so that we ignored the Content-Length.

The bug was introduced earlier than 2010 and could have the effect
that a connection got stuck until the network layer timed out.

Note that the keep-alive parts of the patch are not yet used.
2023-09-26 14:19:26 +02:00
Werner Koch c91f759baf
common: Add gnupg_memstr to replace static versions.
* common/stringhelp.c (gnupg_memstr): New.
* common/mbox-util.c (my_memstr): Remove.
(is_valid_mailbox_mem): Use gnupg_memstr.
* common/recsel.c (my_memstr): Remove.
(recsel_select): Use gnupg_memstr.
2023-09-26 14:17:37 +02:00
Werner Koch 3054016db9
dirmngr: Require gnutls 3.2
* dirmngr/http.c: Remove gnutls version specific code.
(send_request): Factor some code out to ...
(run_proxy_connect): new.
(mk_proxy_request): new.
(mk_std_request): new.
* configure.ac (NEED_GNUTLS_VERSION): Require 3.2.
--

This patch is to factor out some code and also to remove support for
legacy gnutls versions.  Note that gnutls 3.2 was released 10 years
ago.
2023-09-26 14:13:51 +02:00
Werner Koch 668deeded9
dirmngr: Improve error codes returned from http fetching.
* dirmngr/ks-engine-http.c (ks_http_fetch): Return better error codes.
* dirmngr/ks-engine-hkp.c (send_request): Ditto.
* dirmngr/t-http.c (main): New option --try-proxy.
2023-09-26 14:10:42 +02:00
Werner Koch 1e120f5a8d
dirmngr: Implement automatic proxy detection on Windows.
* dirmngr/http.c [W32]: Include winhttp.h
(w32_get_internet_session): New.
(w32_get_proxy): New.
(get_proxy_for_url): Implement automatic proxy detection and fix error
in last patch.
(http_reinitialize): New.
* dirmngr/dirmngr.c (dirmngr_sighup_action): Call reinitialize.
* dirmngr/Makefile.am (NETLIBS) [W32]: Link with winhttp.
--

GnuPG-bug-id: 5768
2023-09-26 14:10:13 +02:00
Werner Koch fed33baed1
dirmngr: Further simplify the http code and improve a message.
* dirmngr/http.c (make_fp_write, make_fp_read): New.
(http_raw_connect): Use new functions.
(http_wait_response): Ditto.
(send_request): Ditto.  Change proxy error diagnostic.
(connect_server): Improve error message for host not found.
--

GnuPG-bug-id: 5768
2023-09-26 14:06:47 +02:00
Werner Koch 845d5e61d8
dirmngr: Cleanup the http module.
* configure.ac (NEED_NTBTLS_VERSION): Require at least 0.2.0 so that
we can remove a conditional compilation.

* dirmngr/http.c (struct proxy_info_s): New.
(release_proxy_info): New to keep proxy information in one object.
(send_request): Factor some code out to ...
(get_proxy_for_url): this,
(send_request_basic_checks): this,
(send_request_set_sni): this,
(run_ntbtls_handshake): this,
(run_gnutls_handshake): and this.
--

Note that this also removes some never used code.  For example the
NTBTLS handshake has code taken from GNUTLS which was never used due
to the different ways on how the certificates are checked.

The proxy code has been factored out to make to prepare further
authentication methods.  The proxy_info_t was introduced for the same
reason.

Tested against gnutls and ntbtls builds.  No proxy tests yet done,
because we need more sophisticated tests anyway.

GnuPG-bug-id: 5768
2023-09-26 13:58:31 +02:00
NIIBE Yutaka 459bd577fc
agent,common,gpg: Use unsigned int for 1-bit field.
* agent/trustlist.c (struct trustitem_s): Use unsigned int.
* common/audit.c (struct log_item_s): Likewise.
* g10/packet.h (struct seckey_info): Likewise.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-09-26 13:43:24 +09:00
NIIBE Yutaka a8618fdccd
agent: Initialize FP for the case of error return.
* agent/findkey.c (agent_write_private_key): Initialize FP.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-09-26 13:42:37 +09:00
NIIBE Yutaka 26939ea222
Use gpgrt_b64* API of libgpg-error.
* common/Makefile.am (common_sources): Remove b64enc.c and b64dec.c.
(module_maint_tests): Remove t-b64.
(t_b64_LDADD): Remove.
* common/util.h: Remove the internal API.
* common/ssh-utils.c (get_fingerprint): Use the gpgrt_b64 API.
(ssh_public_key_in_base64): Likewise.
* dirmngr/crlfetch.c (my_es_read, crl_close_reader): Likewise.
* dirmngr/dirmngr-client.c (data_cb, do_lookup): Likewise.
* dirmngr/misc.c (armor_data): Likewise.
* g10/export.c (export_one_ssh_key, export_secret_ssh_key): Likewise.
* tools/gpg-card.c (cmd_writecert): Likewise.
* tools/mime-parser.c (parse_message_cb, mime_parser_release)
(process_part_data): Likewise.
* tools/wks-util.c (wks_armor_key): Likewise.

--

GnuPG-bug-id: 6734
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-09-26 13:34:50 +09:00
Werner Koch 2a2846959f
gpg: Fix --no-utf8-strings.
* g10/gpg.c (main): Ignore --no-utf8-strings only on Windows.
--

Fixes-commit: 8c41b8aac3
Reported-by: Ingo Klöcker
2023-09-18 11:26:56 +02:00
Robin H. Johnson via Gnupg-devel bf662d0f93
gpg: Add --list-filter properties sig_expires/sig_expires_d
Modelled after key_expires/key_expires_d.

This should be useful to detect upcoming certification expiry, so the
certifications can be renewed in advance of the expiry.

Signed-off-by: Robin H. Johnson <robbat2@gentoo.org>
2023-09-15 10:37:47 +02:00
Werner Koch 4fc745bc43
dirmngr: Relax the detection of the "none" keyserver.
* dirmngr/server.c (cmd_keyserver): Ignore also hkps://none.
(ensure_keyserver): Better ignore also "none" with a hkp or hpks
scheme.
--

GnuPG-bug-id: 6708
2023-09-11 11:24:00 +02:00
Werner Koch 7f9e05d73f
common: Never remove /dev/null.
* common/sysutils.c (gnupg_remove): Detect /dev/null.
--

GnuPG-bug-id: 6556
2023-09-07 17:21:05 +02:00
Werner Koch a02f3cc4e8
gpg: Fix validity of re-imported keys.
* g10/trustdb.c (tdb_clear_ownertrusts): Detect stale validity
records.
--

GnuPG-bug-id: 6399

This problem was introduced by an actually very useful patch

  2002-12-13  David Shaw  <dshaw@jabberwocky.com>
  [...]
  * import.c (import_keys_internal): Used here so we don't rebuild
  the trustdb if it is still clean.
  (import_one, chk_self_sigs): Only mark trustdb dirty if the key
  that is being imported has any sigs other than self-sigs.
  Suggested by Adrian von Bidder.

[the last part]

The bug exhibited itself only after signing a key, deleting that key
and then re-importing the original non-signed key.
2023-09-06 12:12:47 +02:00
Werner Koch 0aa32e2429
dirmngr: Allow conf files to disable default keyservers.
* dirmngr/server.c (ensure_keyserver): Detect special value "none"
(cmd_keyserver): Ignore "none" and "hkp://none".
--

GnuPG-bug-id: 6708
2023-09-06 09:50:28 +02:00
Werner Koch 34f812475e
gpg: Fix last commit.
* g10/keyid.c (hash_public_key): Do not pass the version.
--

Fixes-commit: 1be7882344
2023-09-05 08:10:36 +02:00
Werner Koch 362a6dfb0a
gpg: Fix last commit.
* g10/keyid.c (hash_public_key): Do not pass the version.
--

Fixes-commit: 1f76cbca35
2023-09-05 08:08:54 +02:00
Werner Koch 1f76cbca35
gpg: Add option --with-v5-fingerprint
* g10/gpg.c (oWithV5Fingerprint): New.
(opts): Add new option.
(main): Set option.
* g10/options.h (opt): Add with_v5_fingerprint.
* g10/keyid.c (hash_public_key): Factor out to ...
(do_hash_public_key): this.  Add new arg to foce v5 style hashing.
(v5_fingerprint_from_pk): New.
(v5hexfingerprint): New.
* g10/keylist.c (print_fingerprint): Print v5 fingerprint for v4 keys
if the option is set.
--

GnuPG-bug-id: 6705
2023-09-04 16:36:51 +02:00
Werner Koch 1be7882344
gpg: Add option --with-v5-fingerprint
* g10/gpg.c (oWithV5Fingerprint): New.
(opts): Add new option.
(main): Set option.
* g10/options.h (opt): Add with_v5_fingerprint.
* g10/keyid.c (hash_public_key): Factor out to ...
(do_hash_public_key): this.  Add new arg to foce v5 style hashing.
(v5_fingerprint_from_pk): New.
(v5hexfingerprint): New.
* g10/keylist.c (print_fingerprint): Print v5 fingerprint for v4 keys
if the option is set.
--

GnuPG-bug-id: 6705
2023-09-04 16:35:19 +02:00
NIIBE Yutaka d90f1e5fa4
agent: Fix timer round-up check when inserting an entry into cache.
* agent/cache.c (insert_to_timer_list): Round up when >= a half second.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-09-04 12:00:29 +09:00
NIIBE Yutaka 28364affa6
agent: Fix sock_inotify_fd handling.
* agent/gpg-agent.c (handle_connections): Also check SOCK_INOTIFY_FD
when spawning check_onw_socket_thread.  When removal of the socket
is detected, do same as AGENT_PROBLEM_SOCKET_TAKEOVER.

--

GnuPG-bug-id: 6692
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-09-04 10:34:42 +09:00
NIIBE Yutaka 5e47d5edd8
agent: Fix timer list management.
* agent/cache.c (insert_to_timer_list): Update TV_SEC of the top entry
when inserted.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-09-01 11:28:44 +09:00
NIIBE Yutaka 57125d3f5a
agent: Fix the previous commit.
* agent/cache.c (remove_from_timer_list_new): Fix cut&paste error.
TV_SEC field should not be touched.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-09-01 11:00:44 +09:00
Werner Koch 776876ce1c
gpgsm: Add --always-trust feature.
* sm/gpgsm.h (opt): Re-purpose unused flag always_trust.
(struct server_control_s): Add "always_trust".
(VALIDATE_FLAG_BYPASS): New.
* sm/gpgsm.c (oAlwaysTrust): New.
(opts): Add "--always-trust"
(main): Set option.
* sm/server.c (option_handler): Add option "always-trust".
(reset_notify): Clear that option.
(cmd_encrypt): Ditto.
(cmd_getinfo): Add sub-command always-trust.
* sm/certchain.c (gpgsm_validate_chain): Handle VALIDATE_FLAG_BYPASS.
* sm/certlist.c (gpgsm_add_to_certlist): Set that flag for recipients
in always-trust mode.
--

GnuPG-bug-id: 6559
2023-08-31 12:30:26 +02:00
NIIBE Yutaka 92de0387f0
agent: Introduce management of timer to expire cache entries.
* agent/cache.c (struct timer_s): New.
(struct cache_item_s): Add a member filed T for timer.
(the_timer_list, the_timer_list_new): New.
(insert_to_timer_list_new, insert_to_timer_list): New.
(remove_from_timer_list, remove_from_timer_list_new): New.
(housekeeping): Remove.
(compute_expiration, update_expiration): New.
(do_expire): New.
(TIMERTICK_INTERVAL): Remove.
(agent_cache_expiration): Use timer list to manage the expiration
of cache entries.
(agent_flush_cache): Call update_expiration when needed.
(agent_put_cache): Don't call housekeeping any more, but
update_expiration for an entry in question.
(agent_get_cache): Likewise.

--

GnuPG-bug-id: 6681
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-31 14:49:38 +09:00
NIIBE Yutaka 76a2f18028
agent: Better interaction between main loop and cache expiration.
* agent/agent.h (agent_cache_housekeeping): Remove.
(agent_cache_expiration): New.
* agent/cache.c (agent_cache_housekeeping): Remove.
(agent_cache_expiration): New.
* agent/gpg-agent.c (TIMERTICK_INTERVAL): Remove.
(handle_tick): Remove.
(handle_connections): Call agent_cache_expiration and use the timeout
value determined by the call.

--

GnuPG-bug-id: 6681
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-30 14:48:56 +09:00
NIIBE Yutaka 7025375e8b
agent: Have a thread monitoring parent PID and homedir.
* agent/gpg-agent.c (CHECK_PROBLEMS_INTERVAL): New.
(socket_takeover_detected): Remove.
(problem_detected): New.
(handle_tick): Don't check parent PID and homedir in this function.
(handle_connections): Spawn check_others_thread when needed.  Handle
AGENT_PROBLEM_PARENT_HAS_GONE and AGENT_PROBLEM_HOMEDIR_REMOVED.
(check_own_socket_thread): Check SHUTDOWN_PENDING variable in the
loop.  Use PROBLEM_DETECTED variable.
(check_others_thread): New.

--

GnuPG-bug-id: 6693
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-30 14:08:33 +09:00
NIIBE Yutaka 76896e2339
agent: Recover support CHECK_OWN_SOCKET_INTERVAL == 0.
* agent/gpg-agent.c (handle_connections): Only spawn the thread
when CHECK_OWN_SOCKET_INTERVAL > 0.
[CHECK_OWN_SOCKET_INTERVAL == 0] (check_own_socket_pid_cb)
(do_check_own_socket, check_own_socket_thread): Ifdef out.

--

GnuPG-bug-id: 6692
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-30 13:21:37 +09:00
NIIBE Yutaka b2826924ee
agent: Fix the handling of socket takeover.
* agent/gpg-agent.c (handle_connections): Check the takeover when
interrupted.
(check_own_socket_thread): Kick the loop when detected.

--

GnuPG-bug-id: 6692
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-30 11:26:07 +09:00
NIIBE Yutaka 95186ae92f
agent: Use a thread to monitor socket takeover.
* agent/gpg-agent.c (check_own_socket_running): Remove.
(socket_takeover_detected): New.
(check_own_socket): Remove.
(handle_tick): Don't call check_own_socket any more.
(handle_connections): Start off the check_own_socket_thread.
Check socket_takeover_detected to handle the event.
(do_check_own_socket): New, factoring out the task.
(check_own_socket_thread): Loop with the interval.

--

GnuPG-bug-id: 6692
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-30 10:57:36 +09:00
Werner Koch 9dd8fd4ae4
g13: Fix for new assuan_control.
* g13/g13.c (main): Fix assuan control code.
--

Fixes-commit: 1d73806972
GnuPG-bug-id: 6606
2023-08-29 13:23:48 +02:00
Werner Koch a430f22549
common: Prepare for more flags in start_new_service.
* common/asshelp.h (ASSHELP_FLAG_AUTOSTART): New.
* common/asshelp.c (start_new_service): Rename arg autostart to flags
and adjust checks.
(start_new_gpg_agent): Likewise.  Change all callers.
(start_new_keyboxd): Likewise.  Change all callers.
(start_new_dirmngr): Likewise.  Change all callers.
--

It is easier to have a generic flags arg instead of adding more and
more dedicated args.  verbose and debug are kept as they are because
they are not boolean.
2023-08-29 13:18:13 +02:00
Werner Koch ee27ac18ea
doc: Add some hints for AD queries.
--

This is repo only.
2023-08-24 11:28:12 +02:00
Werner Koch 32c55603df
dirmngr: Fix LDAP time parser.
* dirmngr/ldap-misc.c (rfc4517toisotime): Correct index.
--

Obviously the parser assumes the standard ISO format with the 'T'
before the hour.  That is not correct here.  We need this parser for
the modifyTimestamp thingy.
2023-08-24 11:25:30 +02:00
NIIBE Yutaka 716e59b0b6
agent: Add agent_kick_the_loop function.
* agent/agent.h (agent_kick_the_loop): New.
* agent/gpg-agent.c [HAVE_W32_SYSTEM] (the_event2): New.
[HAVE_PSELECT_NO_EINTR] (event_pipe_fd): New.
[!HAVE_PSELECT_NO_EINTR] (main_thread_pid): New.
(create_an_event): New, factored out.
(get_agent_daemon_notify_event): Use create_an_event.
(handle_signal): Add a case for SIGCONT.
(agent_kick_the_loop): New.
(handle_connections): Call pselect possibly with the pipe.
Call eselect with THE_EVENT2.

--

GnuPG-bug-id: 6682
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-24 16:07:26 +09:00
NIIBE Yutaka 9e4d522239
tpm2d: Fix call to assuan_control.
* tpm2d/tpm2daemon.c (main): Use ASSUAN_CONTROL_REINIT_SYSCALL_CLAMP.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-16 09:05:53 +09:00
NIIBE Yutaka 1d73806972
gpg,agent,kbx,sm,scd,tpm2d,g13: Use assuan_control.
* agent/gpg-agent.c (thread_init_once): Call assuan_control.
* g10/gpg.c (main): Likewise.
* g13/g13.c (main): Likewise.
* kbx/keyboxd.c (thread_init_once): Likewise.
* scd/scdaemon.c (main): Likewise.
* sm/gpgsm.c (main): Likewise.
* tpm2d/tpm2daemon.c (main): Likewise.

--

GnuPG-bug-id: 6606
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-03 16:34:18 +09:00
NIIBE Yutaka ed4050e011
agent: Use new libassuan API for pipe server process.
* agent/call-daemon.c (struct wait_child_thread_parm_s): Remove PID
field.
(wait_child_thread): Don't touch the internals but call
assuan_pipe_wait_server_termination.
(daemon_start): Don't use PID.
(agent_daemon_dump_state): Don't use PID.
* agent/call-pinentry.c (watch_sock): Call assuan_pipe_kill_server.
(agent_popup_message_stop): Likewise.

--

GnuPG-bug-id: 6487
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-03 16:34:08 +09:00
NIIBE Yutaka 0821ceebfb
agent,dirmgr,gpg,g13,kbx,scd,sm,tmp2d: Remove ASSUAN_SYSTEM_NPTH.
* agent/gpg-agent.c (ASSUAN_SYSTEM_NPTH_IMPL): Remove.
(initialize_modules): Don't call assuan_set_system_hooks.
(main): Don't call assuan_sock_set_system_hooks.
* dirmngr/dirmngr.c (ASSUAN_SYSTEM_NPTH_IMPL): Remove.
(thread_init): Don't call assuan_set_system_hooks.
* g10/gpg.c (ASSUAN_SYSTEM_NPTH_IMPL): Remove.
(main): Don't call assuan_set_system_hooks.
* g13/g13.c (ASSUAN_SYSTEM_NPTH_IMPL): Remove.
(main): Set the syscall clamp with gpgrt_set_syscall_clamp.
Don't call assuan_set_system_hooks.
* kbx/keyboxd.c (ASSUAN_SYSTEM_NPTH_IMPL): Remove.
(initialize_modules): Don't call assuan_set_system_hooks.
(main): Don't call assuan_sock_set_system_hooks.
* scd/scdaemon.c (ASSUAN_SYSTEM_NPTH_IMPL): Remove.
(main): Don't call assuan_set_system_hooks.
* sm/gpgsm.c (ASSUAN_SYSTEM_NPTH_IMPL): Remove.
(main): Don't call assuan_set_system_hooks.
* tpm2d/tpm2daemon.c (ASSUAN_SYSTEM_NPTH_IMPL): Remove.
(main): Don't call assuan_set_system_hooks.

--

GnuPG-bug-id: 6606
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-03 16:34:00 +09:00
NIIBE Yutaka 5cad5f903e
agent,dirmngr,kbx,scdaemon: Use assuan_sock_accept.
* agent/gpg-agent.c (handle_connections): Use assuan_sock_accept.
* dirmngr/dirmngr.c (handle_connections): Ditto.
* kbx/keyboxd.c (handle_connections): Ditto.
* scd/scdaemon.c (handle_connections): Ditto.
* tpm2d/tpm2daemon.c (handle_connections): Ditto.

--

GnuPG-bug-id: 6599
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-03 16:33:51 +09:00
NIIBE Yutaka 0d20b79ab7
build: Require libassuan 3.0.0 or later.
* configure.ac (NEED_LIBASSUAN_API): Require the API version 3.0.
(NEED_LIBASSUAN_VERSION): Require 3.0.0 or later.

--

GnuPG-bug-id: 6606
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-03 16:33:43 +09:00
NIIBE Yutaka fa29c86582
build: Update libassuan.m4 to allow build with libassuan 3.
* m4/libassuan.m4: Update from libassuan master.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-08-02 11:39:40 +09:00
NIIBE Yutaka dad880155e
build: Update libassuan.m4 for API compatibility.
* m4/libassuan.m4: Update from libassuan master.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-26 11:29:05 +09:00
NIIBE Yutaka 1ddd69935d
gpg: Add parallelized filter for hashing.
* g10/options.h (COMPAT_PARALLELIZED): New.
* g10/filter.h (md_thd_filter_context_t): New type.
(md_thd_filter_set_md, md_thd_filter): New.
* g10/gpg.c (compatibility_flags): Update to support
COMPAT_PARALLELIZED.
* g10/mdfilter.c (struct md_thd_filter_context): New.
(lock_md, unlock_md, get_buffer_to_hash, put_buffer_to_recv): New.
(get_buffer_to_fill, put_buffer_to_send, md_thread): New.
(md_thd_filter, md_thd_filter_set_md): New.
* g10/sign.c (sign_file): Add support for md_thd_filter.
(sign_symencrypt_file): Likewise.

--

GnuPG-bug-id: 6570
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-25 12:10:07 +09:00
NIIBE Yutaka 96b69c1866
gpg: Add support for Subkey-Expire-Date.
* g10/keygen.c (enum para_name): Add pSUBKEYEXPIREDATE.
(proc_parameter_file): Add support for pSUBKEYEXPIREDATE.
(read_parameter_file): Add "Subkey-Expire-Date".

--

Cherry-pick from master commit of:
	23bcb78d27

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-25 11:15:22 +09:00
NIIBE Yutaka 2258bcded6
gpg: Fix expiration time when Creation-Date is specified.
* g10/keygen.c (parse_expire_string_with_ct): New function, optionally
supply the creation time.
(parse_expire_string): Use parse_expire_string_with_ct with no
creation time.
(proc_parameter_file): Use parse_expire_string_with_ct possibly with
the creation time.

--

Cherry-pick from master commit of:
	b07b5144ff

GnuPG-bug-id: 5252
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-25 11:14:43 +09:00
NIIBE Yutaka 95d9761509
sm: Use estream for I/O.
* sm/decrypt.c (gpgsm_decrypt): Use estream for the input.
* sm/encrypt.c (gpgsm_encrypt): Likewise.
* sm/gpgsm.c (open_read): Remove.
(main): Use open_es_fread for gpgsm_import_files.  Fix call of
gpgsm_encrypt, gpgsm_sign, gpgsm_verify and gpgsm_decrypt.
(open_es_fread): Use gnupg_check_special_filename and open_stream_nc.
* sm/gpgsm.h: Fix function declarations.
* sm/import.c (import_one): Use estream for the input.
(reimport_one, gpgsm_import, gpgsm_import_files): Likewise.
* sm/server.c (struct server_local_s): Rename MESSAGE_FD to
MESSAGE_FP.
(close_message_fp): Rename from close_message_fd.
(reset_notify): Follow the change of close_message_fp.
(cmd_encrypt, cmd_decrypt, cmd_verify, cmd_sign): Follow the change of
close_message_fp.  Use open_stream_nc to get estream.
(cmd_import): Likewise.
(cmd_export, cmd_delkeys, gpgsm_server): Follow the change of
close_message_fp.
(cmd_message): Setup MESSAGE_FP with open_stream_nc.
* sm/sign.c (hash_data): Use estream for the input.
(hash_and_copy_data): Likewise.
(gpgsm_sign): Likewise.
* sm/verify.c (hash_data): Use estream_t for FP.
(gpgsm_verify): Use estream_t for IN_FP and DATA_FP.

--

GnuPG-bug-id: 6592
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-25 10:04:18 +09:00
Andre Heinecke c68b70ce9d
w32: Add keyboxd.exe to signed files
* build-aux/speedo.mk (AUTHENTICODE_FILES): Add keyboxd.exe

--
This should prevent that keyboxd.exe is blocked on systems that
only allow signed executables.
2023-07-21 10:29:22 +02:00
Andre Heinecke 083a16ae08
dirmngr: Add doc for faked-system-time
* dirmngr/dirmngr.c (gpgrt_opt_t): Use string for oFakedSystemTime.
(oFakedSystemTime): Use similar conversion as gpgsm has.
* dirmngr/dirmngr.texi (faked-system-time): Document it.

--
For testing X509 certificates this is usually required and
then confusing that the example from the gpgsm man page
does not work for dirmngr.
2023-07-21 10:26:44 +02:00
NIIBE Yutaka 30fc365124
dirmngr: Silence compiler when it's without LDAP.
* dirmngr/ks-action.c [!USE_LDAP] (ks_action_get): NEWER is not used.
* ks_action_query [!USE_LDAP] (ks_action_query): Ignore unused args.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-21 14:27:57 +09:00
NIIBE Yutaka eceba4f207
kbx: Fix error paths to fall back to D-lines.
* kbx/kbx-client-util.c (prepare_data_pipe): Return an error.
(kbx_client_data_new): Recover from an error by use of D-lines.
(kbx_client_data_release): Handle the case of use of D-lines.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-21 14:22:19 +09:00
Andre Heinecke 6e2412e74a
dirmngr: Add doc for faked-system-time
* dirmngr/dirmngr.c (gpgrt_opt_t): Use string for oFakedSystemTime.
(oFakedSystemTime): Use similar conversion as gpgsm has.
* dirmngr/dirmngr.texi (faked-system-time): Document it.

--
For testing X509 certificates this is usually required and
then confusing that the example from the gpgsm man page
does not work for dirmngr.
2023-07-19 11:27:08 +02:00
NIIBE Yutaka 6524becf28
Revert "kbx,w32: Disable the fd-passing."
This reverts commit 6944aefa3c.

--

The fd-passing works well on Windows with new libassuan (to be 3.0),
and it doesn't require ASSUAN_SOCKET_SERVER_FDPASSING actually.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-19 13:35:26 +09:00
NIIBE Yutaka ea1935252e
commond: Introduce FD2NUM to express conversion to number of fds.
* common/sysutils.h (FD2NUM): New.
* agent/call-pinentry.c (watch_sock): Use FD2NUM.
* agent/gpg-agent.c (handle_connections): Likewise.
* dirmngr/dirmngr.c (handle_connections): Likewise.
* dirmngr/http.c (connect_with_timeout): Likewise.
* kbx/keyboxd.c (handle_connections): Likewise.
* scd/scdaemon.c (handle_connections): Likewise.
* tpm2d/tpm2daemon.c (handle_connections): Likewise.

--

GnuPG-bug-id: 6598
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-18 14:43:36 +09:00
NIIBE Yutaka 521ec40aea
common,w32: Fix FD2INT macro.
* common/sysutils.h [HAVE_W32_SYSTEM] (FD2INT): Use intptr_t for
64-bit Windows.

--

GnuPG-bug-id: 6598
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-18 14:21:19 +09:00
NIIBE Yutaka ae188a3357
agent,build,w32: Fix use of SOCKET.
* configure.ac (HAVE_SOCKET): Detect SOCKET type.
* agent/command-ssh.c [HAVE_SOCKET] (start_command_handler_ssh): Use
SOCKET to cast.

--

GnuPG-bug-id: 6508
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-18 14:05:13 +09:00
NIIBE Yutaka 81055baf5c
dirmngr,kbk,tools: Fix type casting.
* dirmngr/http.c (send_request): Remove cast which is not needed.
* kbx/kbx-client-util.c (prepare_data_pipe): Cast to HANDLE.
* tools/gpg-connect-agent.c (do_open): Ditto.

--

GnuPG-bug-id: 6508
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-18 12:07:25 +09:00
NIIBE Yutaka b849c930e9
common: Introduce FD_DBG to display gnupg_fd_t value.
* common/sysutils.h (FD_DBG): New.
* agent/gpg-agent.c (check_nonce): Use FD_DBG.
(do_start_connection_thread, start_connection_thread_ssh): Likewise.
* common/iobuf.c (fd_cache_close, file_filter, do_open): Likewise.
(do_iobuf_fdopen): Likewise.
* dirmngr/dirmngr.c (check_nonce, start_connection_thread)
(handle_connections): Likewise.
* dirmngr/http.c (_my_socket_new, _my_socket_ref): Likewise.
(_my_socket_unref): Likewise.
* g10/decrypt.c (decrypt_message_fd): Likewise.
* g10/encrypt.c (encrypt_crypt): Likewise.
* g10/openfile.c (open_outfile): Likewise.
* g10/plaintext.c (get_output_file, hash_datafile_by_fd): Likewise.
* g10/verify.c (gpg_verify): Likewise.
* kbx/keyboxd.c (check_nonce, do_start_connection_thread): Likewise.
* scd/scdaemon.c (start_connection_thread): Likewise.
(handle_connections): Likewise.
* sm/gpgsm.c (open_es_fread, open_es_fwrite): Likewise.
* tpm2d/tpm2daemon.c (start_connection_thread): Likewise.
(handle_connections): Likewise.

--

GnuPG-bug-id: 6597
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-18 11:54:16 +09:00
NIIBE Yutaka ee9e3578ce
gpg: Use gnupg_fd_t for iobuf_get_fd and is_secured_file.
* common/iobuf.c (iobuf_get_fd): Return type is now gnupg_fd_t.
* common/iobuf.h (iobuf_get_fd): Fix the return type.
* g10/misc.c (is_secured_file): Argument is now gnupg_fd_t.
* g10/main.h (is_secured_file): Fix the argument type.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-14 15:52:08 +09:00
NIIBE Yutaka 5d375bb168
gpg: Use is_secured_filename before opening the file.
* g10/gpg.c (print_mds): Check by is_secured_filename, earlier.
* g10/tdbdump.c (import_ownertrust): Likewise.

--

GnuPG-bug-id: 6508
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-14 15:49:23 +09:00
NIIBE Yutaka cf270b0d30
sm: Fix open_es_fread and open_es_fwrite for gnupg_fd_t.
* sm/gpgsm.c (open_es_fread, open_es_fwrite): Use gnupg_fd_t
and open_stream_nc.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-13 14:37:20 +09:00
NIIBE Yutaka ea625c74f0
sm: Use open_stream_nc for do_listkeys.
* sm/server.c (do_listkeys): Use open_stream_nc.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-13 13:53:49 +09:00
NIIBE Yutaka 69c1d81284
sm: Use gnupg_fd_t and open_stream_nc for assuan_get_input_fd.
* sm/server.c (cmd_genkey): Use open_stream_nc for input and output.
(cmd_getauditlog): Use open_stream_nc for output.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-13 13:46:43 +09:00
NIIBE Yutaka fb046ccd93
sm: Use open_stream_nc for HANDLE by assuan_get_output_fd.
* sm/server.c (cmd_encrypt): Use gnupg_fd_t for OUT_FD.
Call open_stream_nc with OUT_FD.
(cmd_decrypt, cmd_verify, cmd_sign, cmd_export): Likewise.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-13 11:18:47 +09:00
NIIBE Yutaka 23bcb78d27
gpg: Add support for Subkey-Expire-Date.
* g10/keygen.c (enum para_name): Add pSUBKEYEXPIREDATE.
(proc_parameter_file): Add support for pSUBKEYEXPIREDATE.
(read_parameter_file): Add "Subkey-Expire-Date".

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-12 14:04:28 +09:00
NIIBE Yutaka b07b5144ff
gpg: Fix expiration time when Creation-Date is specified.
* g10/keygen.c (parse_expire_string_with_ct): New function, optionally
supply the creation time.
(parse_expire_string): Use parse_expire_string_with_ct with no
creation time.
(proc_parameter_file): Use parse_expire_string_with_ct possibly with
the creation time.

--

GnuPG-bug-id: 5252
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-12 13:34:19 +09:00
NIIBE Yutaka 067bc2ed4c
gpg: Move the check by is_secured_file earlier.
* g10/decrypt.c (decrypt_message_fd): Call is_secured_file here.
* g10/plaintext.c (get_output_file): Remove the call.

--

Fixes-commit: 71625f56fd
GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-11 13:49:41 +09:00
NIIBE Yutaka 16d135c396
common: Change iobuf_fdopen argument type to gnupg_fd_t.
* common/iobuf.h (iobuf_fdopen): Use gnupg_fd_t.
* common/iobuf.c (iobuf_fdopen): Use gnupg_fd_t.
(iobuf_sockopen): Call do_iobuf_fdopen.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-11 11:21:05 +09:00
NIIBE Yutaka 250733c0d8
common: Add gnupg_check_special_filename.
* common/sysutils.h (gnupg_check_special_filename): New.
* common/sysutils.c (gnupg_check_special_filename): New.
* common/iobuf.c (translate_file_handle): Remove.
(iobuf_is_pipe_filename): Use gnupg_check_special_filename.
(do_open): Use gnupg_check_special_filename.
* g10/plaintext.c (get_output_file): Use gnupg_check_special_filename
and open_stream_nc.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-11 10:46:36 +09:00
NIIBE Yutaka 37343db08f
common,gpg,kbx: Factor out open_stream_nc.
* common/sysutils.h (open_stream_nc): New.
* common/sysutils.c (open_stream_nc): New.
* g10/decrypt.c (decrypt_message_fd): Use open_stream_nc.
* g10/server.c (cmd_verify): Likewise.
* kbx/kbxserver.c (prepare_outstream): Likewise.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-10 11:22:43 +09:00
NIIBE Yutaka a3be97df4d
common:w32: Fix gnupg_w32_set_errno.
* common/sysutils.c (gnupg_w32_set_errno): Return EC.

--

Cherry-pick master commit of:
	4c6b759368bcf19a13df07c5c6080765ecac28ca

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-10 11:21:16 +09:00
NIIBE Yutaka 5bc949d230
common:w32: Fix gnupg_w32_set_errno.
* common/sysutils.c (gnupg_w32_set_errno): Return EC.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-10 11:20:13 +09:00
Werner Koch 9f39e4da29
gpg: Add algo constants for PQC.
* common/openpgpdefs.h (PUBKEY_ALGO_KY768_25519): New.
(PUBKEY_ALGO_KY1024_448): New.
(PUBKEY_ALGO_DIL3_25519): New.
(PUBKEY_ALGO_DIL5_448): New.
(PUBKEY_ALGO_SPHINX_SHA2): New.
* g10/keygen.c (parse_key_parameter_part): Force v5 keys for these
  algos.
* g10/keyid.c (pubkey_string): Add mapping.
* g10/misc.c (openpgp_pk_algo_usage): Add standard key usage.
--

See draft-wussler-openpgp-pqc-01.txt for the code points.  To limit
the number of algorithms, only MUST and SHOULD algorithms are
considered.
2023-07-07 10:21:39 +02:00
NIIBE Yutaka 8cacfce898
kbx: Fix memory leak at spawning a thread for data pipe.
* kbx/kbx-client-util.c (prepare_data_pipe): Release
the attribute for thread creation.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-06 16:02:14 +09:00
NIIBE Yutaka 2abea42d9c
kbx: Use es_sysopen_nc instead of es_fdopen_nc.
* kbx/kbxserver.c (prepare_outstream): Use es_sysopen_nc
and avoid the use of translate_sys2libc_fd.

--

On Windows, it's better directly use the system HANDLE.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-06 10:25:15 +09:00
NIIBE Yutaka f2dcd158a5
gpg: Fix gpg --server mode on Windows.
* g10/server.c (cmd_encrypt): Don't translate_sys2libc_fd, since it
requires HANDLE on Windows.
(cmd_decrypt): Likewise.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-05 13:22:16 +09:00
NIIBE Yutaka 577baf4af3
gpg: Format the value of type gnupg_fd_t by casting to int.
* g10/openfile.c (open_outfile): Cast to int.
* g10/encrypt.c (encrypt_crypt): Ditto.
* g10/decrypt.c (decrypt_message_fd): Ditto.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-05 13:11:16 +09:00
NIIBE Yutaka 9ae3cfcabe
dirmngr: Enable the call of ks_ldap_help_variables when USE_LDAP.
* dirmngr/server.c [USE_LDAP] (cmd_ad_query): Conditionalize.

--

Cherry-pick master commit of:
	dc13361524

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-05 10:46:45 +09:00
NIIBE Yutaka 3fb69641e8
gpg: Use gnupg_fd_t for decryption and sign.
* g10/decrypt.c (decrypt_message_fd): Use gnupg_fd_t.
* g10/plaintext.c (hash_datafile_by_fd): Use  gnupg_fd_t.
* g10/main.h: Fix the declarations.
* g10/mainproc.c (struct mainproc_context): Use gnupg_fd_t for
DATA_FD.
(proc_compressed_cb, proc_signature_packets): Follow the change.
(proc_signature_packets_by_fd): Use gnupg_fd_t.
* g10/packet.h: Fix the declaration.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-05 10:29:23 +09:00
NIIBE Yutaka 2c2516f03a
gpg: Use gnupg_fd_t for encrypt_crypt and gpg_verify.
* common/iobuf.h (iobuf_fdopen_nc): Use gnupg_t.
* common/iobuf.c (iobuf_fdopen_nc): Use gnupg_t.
* g10/main.h (encrypt_crypt, gpg_verify): Use gnupg_fd_t.
* g10/encrypt.c (encrypt_crypt): Use gnupg_fd_t.
(encrypt_crypt_files): Follow the change.
* g10/gpg.c (main): Follow the change.
* g10/verify.c (gpg_verify): Use gnupg_fd_t.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-05 10:05:31 +09:00
NIIBE Yutaka 68d3a73ea7
gpg: Use gnupg_fd_t for open_outfile.
* g10/main.h (open_outfile): Use gnupg_fd_t instead of int.
* g10/openfile.c (open_outfile): Likewise.  Use GNUPG_INVALID_FD.
* g10/dearmor.c (dearmor_file, enarmor_file): Follow the change.
* g10/encrypt.c (encrypt_simple): Likewise.
* g10/export.c (do_export): Likewise.
* g10/revoke.c (gen_desig_revoke, create_revocation): Likewise.
* g10/sign.c (sign_file, clearsign_file, sign_symencrypt_file):
Likewise.

--

GnuPG-bug-id: 6580
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-05 09:36:00 +09:00
NIIBE Yutaka dc13361524
dirmngr: Enable the call of ks_ldap_help_variables when USE_LDAP.
* dirmngr/server.c [USE_LDAP] (cmd_ad_query): Conditionalize.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-05 09:29:54 +09:00
NIIBE Yutaka 2c5a93e66e
gpg:card: Remove the code for GnuPG version 1.
* g10/card-util.c [GNUPG_MAJOR_VERSION == 1] (get_data_from_file):
Remove the old code.
(put_data_to_file): Likewise.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-05 09:26:16 +09:00
Werner Koch 334f5d95c8
Merge branch 'STABLE-BRANCH-2-4' into master 2023-07-04 17:37:54 +02:00
Werner Koch 2378ccf97c
Post release updates
--
2023-07-04 16:44:01 +02:00
Werner Koch d073f26d81
Release 2.4.3 2023-07-04 16:06:59 +02:00
Werner Koch 7c04a6a284
po: msgmerge
--
2023-07-04 16:06:57 +02:00
Emir SARI 7f8ea1c9be
po: Update Turkish translation
--
2023-07-04 15:52:05 +02:00
Werner Koch b83d86b988
scd:p15: Make signing work for Nexus cards.
* scd/app-p15.c (CARD_PRODUCT_NEXUS): New.
(read_p15_info): Detect Nexus cards.
(get_dispserialno): Use product_id instead of comparing the
manufacturer_id.
(do_sign): Handle Nexus like BELPIC.
2023-07-04 14:32:08 +02:00
Werner Koch 7a2831bc0e
gpgsm: Init a diagnostic var.
* sm/minip12.c (p12_parse): Init where.
--
2023-07-04 09:26:55 +02:00
Werner Koch 5e94470d05
common,w32: Add missing GetLastError->errno mapping.
* common/iobuf.c (file_filter, sock_filter): Add missing mapping.
--

GnuPG-bug-id: 6528
2023-07-04 09:19:05 +02:00
NIIBE Yutaka b5efb52d43
agent: Fix formatting thread ID of nPth.
* agent/call-pinentry.c (agent_query_dump_state): Use %lx to
format thread ID.

--

Fixes-commit: ba6f8b3d9e
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-03 10:46:46 +09:00
NIIBE Yutaka a0ff2919f7
tools:gpg-connect-agent: Fix use of HANDLE on Windows.
* tools/gpg-connect-agent.c [HAVE_W32_SYSTEM] (do_open): Use %p to
format the HANDLE.
[HAVE_W32_SYSTEM] (do_close): Use gnupg_parse_fdstr to parse the
string representation of the HANDLE.  Use %p.

--

GnuPG-bug-id: 6508
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-07-03 10:20:06 +09:00
Werner Koch 5377226ec0
Prepare NEWS for the next release
--
2023-06-30 10:59:06 +02:00
NIIBE Yutaka 250fff0f6e
common:iobuf: Avoid losing bits of HANDLE on Windows 64-bit.
* common/iobuf.c (translate_file_handle): Change the return type to
gnupg_fd_t, not to lose the bits for HANDLE silently.
(do_iobuf_fdopen): Use the type gnupg_fd_t for the first argument.
(do_open): Use do_iobuf_fdopen instead of iobuf_fdopen.
(iobuf_fdopen, iobuf_fdopen_nc): Follow the change of API.

--

GnuPG-bug-id: 6508
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-30 15:56:43 +09:00
Werner Koch 5f694dc0be
sm: Adding missing stuff to the PKCS#12 parser rewrite.
* sm/minip12.c (struct bufferlist_s): New.
(struct tlv_ctx_s): Add bufferlist.
(tlv_register_buffer): New.
(tlv_release): Release bufferlist.
(tlv_expect_object): Handle octet string cramming.
(tlv_expect_octet_string): Ditto.
(cram_octet_string): Changed interface.  We don't need the
input_consumed value anymore.

* sm/minip12.c (parse_shrouded_key_bag): Also parse the attribute set.

* sm/t-minip12.c (main): Add option --no-extra.
(cert_collect_cb, run_tests_from_file): Fix memory leak

* tests/cms/samplekeys/t5793-openssl.pfx: New from T5793.
* tests/cms/samplekeys/t5793-test.pfx: Ditto.
* tests/cms/samplekeys/Description-p12: Add them.
* tests/cms/Makefile.am (EXTRA_DIST): Add samplekeys.
--

This should finish the rewrite of the pkcsc#12 parser for now.  More
fun is likely to come.

GnuPG-bug-id: 6536, 5793
2023-06-29 17:49:10 +02:00
NIIBE Yutaka 6049d61991
common: Fix the cast for 64-bit Windows.
* common/sysutils.c (translate_sys2libc_fd_int): Fix the cast.

--

FD should have a valid value here.  For erroneous cases, it must be
rejected by argparse handling.

GnuPG-bug-id: 6551
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-29 14:04:32 +09:00
NIIBE Yutaka 3672c29156
common: Raise an error correctly in check_special_filename.
* common/sysutils.c (check_special_filename): Use gnupg_parse_fdstr
to check an error.

--

GnuPG-bug-id: 6551
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-29 14:01:40 +09:00
Werner Koch 101433dfb4
sm: Major rewrite of the PKCS#12 parser
* sm/minip12.c: Reworked most of the parser.
(p12_set_verbosity): Add arg debug and change all callers.

* sm/t-minip12.c: Major rewrite to run regression tests unattended.
* sm/Makefile.am (module_maint_tests): Move t-Minit to ...
(module_tests): here.
* tests/cms/samplekeys/Description-p12: New.
--

Note that cram_octet_string stuff has not yet been reworked.  I need
to locate the sample files first.

GnuPG-bug-id: 6536
2023-06-28 17:34:19 +02:00
Werner Koch c926967d85
sm: Remove duplicated code.
* sm/minip12.c (struct tag_info): Change type of length and nhdr.
(dump_tag_info): Adjust.
(parse_tag): Re-implement using the parse_ber_header.
2023-06-28 17:34:19 +02:00
NIIBE Yutaka 25b59cf6ce
scd:piv: Fix authentication with Administration Key.
* scd/app-piv.c (auth_adm_key): Fix the value of the Response Tag.
(do_setattr): Fix the comment.

--

Cherry-pick master commit of:
	7cfbf0dd72

Reported-by: Heiko Schäfer <heiko@schaefer.name>
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-28 14:03:45 +09:00
NIIBE Yutaka cacb018992
tools:gpgtar: Clean up the use of --status-fd.
* common/sysutils.c (gnupg_parse_fdstr): Rename from
gnupg_sys2libc_fdstr, as there is no translation any more.
* common/sysutils.h (gnupg_parse_fdstr): Rename from
gnupg_sys2libc_fdstr.
* tools/gpgtar.c (main): Use gnupg_parse_fdstr, in cleaner way.

--

GnuPG-bug-id: 6562
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-28 13:59:52 +09:00
NIIBE Yutaka 7cfbf0dd72
scd:piv: Fix authentication with Administration Key.
* scd/app-piv.c (auth_adm_key): Fix the value of the Response Tag.
(do_setattr): Fix the comment.

--

Reported-by: Heiko Schäfer <heiko@schaefer.name>
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-27 15:43:35 +09:00
NIIBE Yutaka 631c23b664
gpgtar: Use FD on POSIX.
* tools/gpgtar.c (main): Fix the use of the union.

--

Fixes-commit: 2756147e39
GnuPG-bug-id: 6562
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-27 14:58:13 +09:00
NIIBE Yutaka b9b0c18320
common,gpg,sm,tools: Don't remove translate_sys2libc_fd_int.
* common/sysutils.c (translate_sys2libc_fd_int): Recover.
(translate_sys2libc_fdstr): Remove.
(check_special_filename): Follow the change.
* common/sysutils.h (translate_sys2libc_fd_int): Recover.
(translate_sys2libc_fdstr): Remove.
* g10/gpg.c, g10/gpgv.c, sm/gpgsm.c: Revert the changes.
* tools/gpg-auth.c, tools/gpg-card.c, tools/gpg-pair-tool.c: Likewise.
* tools/gpg-wks-client.c, tools/gpgconf.c: Likewise.

--

GnuPG-bug-id: 6551
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-27 14:44:01 +09:00
NIIBE Yutaka 72ac77c4fa
agent: Fix cast mistake for Windows.
* agent/call-daemon.c [HAVE_W32_SYSTEM] (daemon_start): Use %p
for the format with a pointer.

--

GnuPG-bug-id: 6508
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-26 14:58:58 +09:00
NIIBE Yutaka 76df934929
tests:gpgscm: Add annotation for unreachable code for GCC.
* tests/gpgscm/scheme.c [__GNUC__] (type_to_string): Use
__builtin_unreachable for GCC.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-26 14:47:28 +09:00
NIIBE Yutaka 1f9a4fbc7e
gpg,w32: Add comment about debug output of ShellExecuteEx.
* g10/photoid.c (w32_system): Add comment about hInstApp, why we use
the integer value of possibly smaller size for the debug output.

--

GnuPG-bug-id: 6508
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-26 10:59:35 +09:00
NIIBE Yutaka f0ecc07c4e
tools: Fix use of EXCEPTS when spawning a process.
* tools/gpgtar-create.c (gpgtar_create) [HAVE_W32_SYSTEM]: Use HANDLE.
* tools/gpgtar-extract.c (gpgtar_extract) [HAVE_W32_SYSTEM]: Likewise.
* tools/gpgtar-list.c (gpgtar_list) [HAVE_W32_SYSTEM]: Likewise.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-26 10:17:23 +09:00
NIIBE Yutaka 87a73e8eb0
common: Remove translate_sys2libc_fd_int.
* common/sysutils.c (translate_sys2libc_fd_int): Remove.
(check_special_filename): Use translate_sys2libc_fdstr.
* common/sysutils.h (translate_sys2libc_fd_int): Remove.

--

GnuPG-bug-id: 6551
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-23 13:37:08 +09:00
NIIBE Yutaka 2756147e39
gpg,sm,tools: Use string for option --*-fd.
* g10/gpg.c (opts): Use string for oLoggerFD, oOverrideSessionKeyFD,
oStatusFD, oAttributeFD, oCommandFD, and oPassphraseFD.
(main): Use translate_sys2libc_fdstr.
* g10/gpgv.c (opts): Use string for oLoggerFD, and oStatusFD.
(main): Use translate_sys2libc_fdstr.
* sm/gpgsm.c (opts): Use string for oLoggerFD, oStatusFD, and
oPassphraseFD.
(main): Use translate_sys2libc_fdstr.
* tools/gpg-auth.c (opts): Use string for oStatusFD.
(main): Use translate_sys2libc_fdstr.
tools/gpg-card.c (opts): Use string for oStatusFD.
(main): Use translate_sys2libc_fdstr.
* tools/gpg-pair-tool.c (opts): Use string for oStatusFD.
(main): Use translate_sys2libc_fdstr.
* tools/gpg-wks-client.c (opts): Use string for oStatusFD.
(main): Use translate_sys2libc_fdstr.
* tools/gpgconf.c (opts): Use string for oStatusFD.
(main): Use translate_sys2libc_fdstr.
* tools/gpgtar-create.c (gpgtar_create): Fix for opt.status_fd.
* tools/gpgtar-extract.c (gpgtar_extract): Fix for opt.status_fd.
* tools/gpgtar-list.c (gpgtar_list): Fix for opt.status_fd.
* tools/gpgtar.c (opts): Use string for oStatusFD.
(main): Use translate_sys2libc_fdstr.
* tools/gpgtar.h (opts): Use string for oStatusFD.

--

GnuPG-bug-id: 6551
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-23 13:22:00 +09:00
NIIBE Yutaka 04d0851cca
common: Add gnupg_sys2libc_fdstr function.
* common/sysutils.c (gnupg_sys2libc_fdstr): New.
(translate_sys2libc_fdstr): Use gnupg_sys2libc_fdstr.

--

GnuPG-bug-id: 6551
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-23 13:05:29 +09:00
NIIBE Yutaka e9e7b5425f
common: Add translate_sys2libc_fdstr.
* common/sysutils.c (translate_sys2libc_fdstr): New.

--

GnuPG-bug-id: 6551
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-22 11:38:44 +09:00
Werner Koch 10c937ee68
wks: Make --add-revocs the default.
* tools/gpg-wks-client.c (opt): New option --no-add-revocs.
(main): Make --add-revocs the default.

(command_send): Rename to ...
(command_create): to match the command name.
2023-06-21 11:48:02 +02:00
Werner Koch 2c7f7a5a27
wks: Use export-clean for --mirror and --create.
* tools/wks-util.c (wks_get_key): Change from export-minimal to
export-clean
--

To properly work with tusted introducers et al. it is important to also
upload valid key signatures to the Web Key Directory.
2023-06-21 11:48:02 +02:00
zhangguangzhi 06aeb2b45c
kbx: Close file handle when return.
* kbx/keybox-dump.c (_keybox_dump_find_dups): Close FP on the error
paths.

--

GnuPG-bug-id: 6495
Signed-off-by: zhangguangzhi <zhangguangzhi3@huawei.com>
2023-06-20 09:20:49 +09:00
zhangguangzhi 28a4d0d4f5
kbx: Close file handle when return.
* kbx/keybox-dump.c (_keybox_dump_find_dups): Close FP on the error
paths.

--

GnuPG-bug-id: 6495
Signed-off-by: zhangguangzhi <zhangguangzhi3@huawei.com>
2023-06-20 09:18:37 +09:00
zhangguangzhi be77c05532
delete redundant characters
--

GnuPG-bug-id: 6482
Signed-off-by: zhangguangzhi <zhangguangzhi3@huawei.com>
2023-06-20 09:08:29 +09:00
zhangguangzhi 40090dbbf9
delete redundant characters
--

GnuPG-bug-id: 6482
Signed-off-by: zhangguangzhi <zhangguangzhi3@huawei.com>
2023-06-20 09:08:14 +09:00
Werner Koch b1ecc8353a
dirmngr: New option --ignore-crl-extensions.
* dirmngr/dirmngr.c (oIgnoreCRLExtension): New.
(opts): Add --ignore-crl-extension.
(parse_rereadable_options): Add to list/
* dirmngr/dirmngr.h (opt): Add ignored_crl_extensions.
* dirmngr/crlcache.c (crl_cache_insert): Implement option.
--

This option is is useful for debugging problems with new CRL
extensions.  It is similar to --ignore-cert-extension.

GnuPG-bug-id: 6545
2023-06-19 14:25:47 +02:00
Werner Koch 701a8b30f0
gpgsm: Support SENDCERT_SKI for --call-dirmngr
* sm/call-dirmngr.c (run_command_inq_cb): Support SENDCERT_SKI.

* dirmngr/crlcache.c (crl_cache_insert): Print the CRL name along with
the unknown OID nortice.
2023-06-19 14:05:22 +02:00
Werner Koch 0a63afc79a
dirmngr: Disable the HTTP redirect rewriting.
* dirmngr/http.h (struct http_redir_info_s): Add restrict_redir.
* dirmngr/ks-engine-hkp.c (send_request): Set it depending on flags.
* dirmngr/ks-engine-http.c (ks_http_fetch): Ditto.
* dirmngr/t-http-basic.c (test_http_prepare_redirect): Always set it.
* dirmngr/http.c (http_prepare_redirect): Remove location rewriting
unless the flag is set.
--

GnuPG-bug-id: 6477
2023-06-15 15:06:21 +02:00
Werner Koch bf04b07327
dirmngr: New option --compatibility-flags.
* dirmngr/dirmngr.c (oCompatibilityFlags): NEw.
(opts): Add option --compatibility-flags.
(compatibility_flags): New.
(parse_rereadable_options): Parse them.
2023-06-15 15:00:28 +02:00
Werner Koch 3bab25d7d5
gpgtar: New option --no-compress.
* tools/gpgtar.c: Add option --no-compress.
* tools/gpgtar.h (opt): Add field no_compress.
* tools/gpgtar-create.c (gpgtar_create): Pass -z0 to gpg.
--

This option is probably easier to remember than --gpg-args '-z0'.
2023-06-15 13:59:22 +02:00
Werner Koch 2178f35dff
gpg: New option --no-compress as alias for -z0. 2023-06-15 13:59:16 +02:00
Werner Koch e9c337c0b9
gpgsm: New option --input-size-hint.
* sm/gpgsm.c (oInputSizeHint): New.
(opts): Add "--input-size-hint".
(main): Set option.
* sm/server.c (option_handler): Add option "input-size-hint".
* sm/gpgsm.h (struct server_control_s): Add field input_size_hint.
* sm/encrypt.c (gpgsm_encrypt): Set the toatl file size.
* sm/decrypt.c (gpgsm_decrypt): Ditto.
* sm/sign.c (gpgsm_sign): Ditto.
* sm/verify.c (gpgsm_verify): Ditto.
--

This option allows to set a value for the progress output line.  Note
that as of now there is no other way to set the file size.

GnuPG-bug-id: 6534
2023-06-15 12:28:55 +02:00
Werner Koch a88aeee129
gpgsm: Fix last commit
--

There was some test code left over and a check reversed.
2023-06-15 12:20:11 +02:00
Werner Koch c58067415f
gpgsm: Print PROGRESS status lines.
* common/ksba-io-support.c (struct writer_cb_parm_s): Add field
progress.
(struct gnupg_ksba_io_s): Add field is_writer.
(update_write_progress): New.
(base64_writer_cb, plain_writer_cb): Call update_write_progress.
(base64_finish_write): Ditto.
(gnupg_ksba_create_writer): Set is_writer.
(gnupg_ksba_set_progress_cb): New.
(gnupg_ksba_set_total): New.
* common/ksba-io-support.h (gnupg_ksba_progress_cb_t): New type.
* sm/server.c (gpgsm_status2): Return error from statusfp writes.
(gpgsm_progress_cb): New.
* sm/decrypt.c (gpgsm_decrypt): Set progress handler.
* sm/encrypt.c (gpgsm_encrypt): Ditto.
* sm/sign.c (gpgsm_sign): Ditto.
* sm/verify.c (gpgsm_verify): Ditto.
--

GnuPG-bug-id: 6534
2023-06-15 10:37:07 +02:00
Werner Koch 808494b485
gpg: Make progress work for large files on Windows.
* common/iobuf.c (iobuf_get_filelength): Change return type to
uint64_t and remove the overflow args.  For Windows always use
GetFileSizeEx which is available since the long EOL-ed Windows XP.

* g10/sign.c (write_plaintext_packet): Adjust for changed
iobuf_get_filelength.
* g10/encrypt.c (encrypt_simple, encrypt_crypt): Ditto.
* g10/photoid.c (generate_photo_id): Ditto.  Also add an upper limit.

* g10/filter.h (progress_filter_context_t): Change amount values to
use uint64_t.
* g10/progress.c (write_status_progress): Change accordingly.

--
GnuPG-bug-id: 6534
2023-06-13 10:07:07 +02:00
Werner Koch 695cb04af5
gpg: Print status line and proper diagnostics for write errors.
* common/iobuf.c (file_filter): Improve diagnostics.
* g10/build-packet.c (do_plaintext): Make sure to cache all error
cases.
--

GnuPG-bug-id: 6528
2023-06-09 17:40:53 +02:00
Andre Heinecke 64509134d4
speedo,w32: Call gpgconf --kill all
* build-aux/speedo/w32/inst.nsi: Use kill all instead of
explicitly killing processes.
2023-06-09 16:29:11 +02:00
Werner Koch ca3f0e66bc
w32: Map ERROR_FILE_INVALID to EIO.
* common/sysutils.c (map_w32_to_errno): Add mapping.
--

We see this error sometimes when writing to an USB connected disk.
2023-06-09 16:29:04 +02:00
Werner Koch c68dd22872
gpg: Add --list-filter properties key_expires and key_expires_d.
* g10/import.c (impex_filter_getval): Support new filter properties.
--

Here is how to list all subkeys expiring in the year 2061:

 gpg --list-keys --list-filter
      'select= sub/key_expires_d -gt 2061-01-01 \
               && sub/key_expires_d -lt 2061-12-31'

To list all primary key expirations, use the "pub/" prefix and to list
all expiration dates use no prefix.

GnuPG-bug-id: 6509
2023-06-09 16:16:56 +02:00
Werner Koch e16fc3e19c
w32: Map ERROR_FILE_INVALID to EIO.
* common/sysutils.c (map_w32_to_errno): Add mapping.
--

We see this error sometimes when writing to an USB connected disk.
2023-06-09 13:46:56 +02:00
Andre Heinecke 3c57aee263
speedo,w32: Call gpgconf --kill all
* build-aux/speedo/w32/inst.nsi: Use kill all instead of
explicitly killing processes.
2023-06-09 12:42:25 +02:00
NIIBE Yutaka 5170c366ee
common: Update t-exechelp to write/read smaller chunks.
* common/t-exechelp.c (run_server): Use syshd.  Write with 4K buffer.
(test_pipe_stream): Read with 4K buffer.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-09 11:25:17 +09:00
NIIBE Yutaka 1b0ce9918c
tests: Fix call-with-io deadlock.
* tests/gpgscm/ffi.c (es_wrap): Ifdef-out.
[HAVE_W32_SYSTEM] (read_from_pipe): New.
(do_process_spawn_io): Rename from do_process_spawn.  Do I/O
with no deadlock.
* tests/gpgscm/tests.scm (call-with-io): Use process-spawn-io.
(es-read-all): Remove.

--

GnuPG-bug-id: 6523
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-08 14:39:50 +09:00
Werner Koch 207c99567c
dirmngr: Extend the AD_QUERY command.
* dirmngr/server.c (cmd_ad_query): Add options --help and --subst.
(cmd_getinfo): Add sub-command "sid".
* dirmngr/ks-engine.h (KS_GET_FLAG_SUBST): New.
* dirmngr/ks-engine-ldap.c (ks_ldap_help_variables): New.
(getval_for_filter): New.
(map_rid_to_dn): New.
(ks_ldap_query): Support variables.
--

The new variables features makes it easier to write AD queries without
requiring domain specific expressions.
2023-06-07 10:03:48 +02:00
NIIBE Yutaka f5656ff363
kbx: Fix datastream_thread and use the data pipe.
* g10/call-keyboxd.c (gpg_keyboxd_deinit_session_data): Release
the assuan connection before kbx_client_data_release.
(open_context): Enable use of the data pipe.
* sm/keydb.c (gpgsm_keydb_deinit_session_data): Release the
assuan connection before kbx_client_data_release.
(open_context): Enable use of the data pipe.
* kbx/kbx-client-util.c (struct kbx_client_data_s): Add THD field.
(prepare_data_pipe): Close the pipe output end as it's been sent
already.  Remember the KCD->THD, so that it can be joined later.
(datastream_thread): Finish when reading no data from the pipe.
(kbx_client_data_release): Join the thread.  Then, we can safely
call es_fclose on the FP.

--

GnuPG-bug-id: 6512
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-07 15:26:34 +09:00
NIIBE Yutaka 9433dfa5dd
common: Add test case for IPC with spawned process.
* common/Makefile.am (module_tests): Add t-exechelp.
* common/t-exechelp.c [HAVE_W32_SYSTEM] (print_open_fds)
(test_close_all_fds, main): Exclude the test_close_all_fds test.
(run_server, test_pipe_stream): New.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-07 09:08:58 +09:00
Werner Koch 7b7fdf45e5
common: New function substitute_vars.
* common/stringhelp.c (substitute_envvars): Factor code out to
(substitute_vars): new.
(subst_getenv): New.
--

This is a generalized version of substitute_envvars.
2023-06-06 18:19:37 +02:00
Werner Koch baa8883215
gpg: Set default expiration date to 3 years.
* g10/keygen.c (default_expiration_interval): Change.
--

This is a revision of
GnuPG-bug-id: 2701
2023-06-05 15:07:22 +02:00
Petr Pisar 2c1d5d5cd3
po: Update Czech translation
--
2023-06-05 14:38:26 +02:00
Werner Koch 22350d0768
doc: Replace remaining "gpg2" by "gpg".
--
2023-06-01 12:43:51 +02:00
Werner Koch 89da4a32ab
doc: Replace remaining "gpg2" by "gpg".
--
2023-06-01 12:42:51 +02:00
NIIBE Yutaka ef4f22b9d9
gpg: Graceful exit for signature checking with --batch.
* g10/mainproc.c (check_sig_and_print): Don't abort computation in
the function, but returns an error.
(proc_tree): Break the loop, when check_sig_and_print returns an
error.

--

GnuPG-bug-id: 6512
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-01 11:58:53 +09:00
NIIBE Yutaka 0fba0bbc62
w32: Fix use of assuan_sendfd.
* kbx/kbx-client-util.c (prepare_data_pipe): Use _get_osfhandle
for pipe to be used for sentfd.
[HAVE_W32_SYSTEM] (datastream_thread): Add the case of NREAD==0.
* tools/gpg-connect-agent.c (do_sendfd): Use es_syshd instead
of es_fileno.
[HAVE_W32_SYSTEM] (do_open): Use %p for formating HANDLE.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-06-01 09:10:14 +09:00
Werner Koch 6ed61d98a0
Add release dates of 2.4 versions to NEWS
--
2023-05-31 09:38:17 +02:00
Werner Koch c8f6fdcd35
build: Always build the wixlib with a release
--

Forgot it today again; better do it by default.  Also disable
sslsigncode verify due to missing certificate problem (for signing we
use Scute).
2023-05-30 17:38:27 +02:00
Werner Koch 3c97dc2714
Post release updates
--
2023-05-30 16:44:00 +02:00
Werner Koch 9e86dac84f
Release 2.4.2 2023-05-30 13:53:01 +02:00
Werner Koch 550bc15b00
po: msgmerge done
--
2023-05-30 13:49:57 +02:00
Werner Koch 4cfa2efdc6
po: Translated one new string to German.
--
2023-05-30 13:47:52 +02:00
Werner Koch f953d67446
Prepare the NEWS for the next release
--
2023-05-26 15:53:52 +02:00
Werner Koch 2783b786a9
agent: Do not overwrite a key file by a shadow key file.
* agent/findkey.c (agent_write_private_key): Partly rewrite to align
with 2.2 code and to make sure that we don't overwrite a real key.
(is_shadowed_key): New.
--

This change is now also needed in 2.4 due to the the former change
"Create and use Token entries to track the display s/n".

GnuPG-bug-id: 6386
2023-05-26 14:27:19 +02:00
Werner Koch a216e9c028
agent: Update key files by first writing to a temp file.
* agent/findkey.c (fname_from_keygrip): New.
(agent_write_private_key): Use here.  Use temp file for updating.
(agent_update_private_key): Use fname_from_keygrip and use gnupg
rename function instead of a vanilla rename.
2023-05-26 14:27:17 +02:00
Werner Koch 1d23dc9389
agent: Create and use Token entries to track the display s/n.
* agent/findkey.c (agent_write_private_key): Add arg dispserialno and
update the token.
(agent_write_shadow_key): Add arg dispserialno and adjust all callers.
--

GnuPG-bug-id: 6135

Note that this has been forward ported from 2.2
2023-05-26 14:27:16 +02:00
Werner Koch ec0c35d1b8
common: New function nve_set
* common/name-value.c (nve_set): New.
--

Taken from 2.2 commit 706adf6691
2023-05-26 14:27:15 +02:00
Werner Koch a1015bf2fc
agent: Do not overwrite a key file by a shadow key file.
* agent/findkey.c (agent_write_private_key): Partly rewrite to align
with 2.2 code and to make sure that we don't overwrite a real key.
(is_shadowed_key): New.
--

This change is now also needed in 2.4 due to the the former change
"Create and use Token entries to track the display s/n".

GnuPG-bug-id: 6386
2023-05-26 14:24:55 +02:00
Werner Koch 05f29b5c7c
agent: Update key files by first writing to a temp file.
* agent/findkey.c (fname_from_keygrip): New.
(agent_write_private_key): Use here.  Use temp file for updating.
(agent_update_private_key): Use fname_from_keygrip and use gnupg
rename function instead of a vanilla rename.
2023-05-26 13:57:36 +02:00
Werner Koch 13013ec1c0
agent: Create and use Token entries to track the display s/n.
* agent/findkey.c (agent_write_private_key): Add arg dispserialno and
update the token.
(agent_write_shadow_key): Add arg dispserialno and adjust all callers.
--

GnuPG-bug-id: 6135

Note that this has been forward ported from 2.2
2023-05-26 11:59:46 +02:00
Werner Koch a048a93ed2
common: New function nve_set
* common/name-value.c (nve_set): New.
--

Taken from 2.2 commit 706adf6691
2023-05-26 11:56:36 +02:00
NIIBE Yutaka f15a643a2d
agent,dirmngr: Shutdown fix for supervised mode.
* agent/gpg-agent.c (handle_connections): Break if supervised.
* dirmngr/dirmngr.c (is_supervised): New.
(handle_connections): Break if supervised.

--

For supervised agent/dirmngr, 'systemctl stop' behaves just like
'gpgconf --kill', ignoring existing connections.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-26 15:28:13 +09:00
Werner Koch 09a96c9e1b
gpg: Skip keys found via ADSKs.
* g10/encrypt.c (write_pubkey_enc): Indicate encryption to an ADSK.
* g10/getkey.c (finish_lookup): Skip ADKS keys.
--

If a key is searched by fingerprint or keyid and it happens that this
is an ADSK (subkey with the RENC usage), we need to skip this key
because it is not the key we actually want to encrypt to.  The actual
ADSK key is taken later by looking at all subkeys of the actual
selected key.

This is related to
GnuPG-bug-id: 6504
2023-05-25 16:50:00 +02:00
Werner Koch 9f2f7a51b2
gpg: Skip keys found via ADSKs.
* g10/encrypt.c (write_pubkey_enc): Indicate encryption to an ADSK.
* g10/getkey.c (finish_lookup): Skip ADKS keys.
--

If a key is searched by fingerprint or keyid and it happens that this
is an ADSK (subkey with the RENC usage), we need to skip this key
because it is not the key we actually want to encrypt to.  The actual
ADSK key is taken later by looking at all subkeys of the actual
selected key.

This is related to
GnuPG-bug-id: 6504
2023-05-25 16:43:44 +02:00
Werner Koch e9dd47d789
gpg: Fix searching for the ADSK key when adding an ADSK.
* g10/keyedit.c (menu_addadsk): Request an exact search.
* g10/getkey.c (finish_lookup): Add an debug output.
--

GnuPG-bug-id: 6504
2023-05-25 12:01:07 +02:00
Werner Koch 14828c75be
gpg: Fix searching for the ADSK key when adding an ADSK.
* g10/keyedit.c (menu_addadsk): Request an exact search.
* g10/getkey.c (finish_lookup): Add an debug output.
--

GnuPG-bug-id: 6504
2023-05-25 11:57:44 +02:00
NIIBE Yutaka 39a4373780
po: Update Japanese Translation.
--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-25 13:43:50 +09:00
NIIBE Yutaka 6984ddc6eb
common,w32: Fix gnupg_process_release.
* common/exechelp-w32.c: Close the handle of the process.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-25 13:43:41 +09:00
NIIBE Yutaka 0f8e5f1c1d
po: Update Japanese Translation.
--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-25 11:15:24 +09:00
NIIBE Yutaka 6a2cb8cfd7
agent,w32: Fix resource leak for a process.
* agent/call-daemon.c (wait_child_thread): Call assuan_set_flag only
for !HAVE_W32_SYSTEM.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-25 11:15:16 +09:00
Werner Koch 000b82ade7
gpg: Return ERROR status for --quick-sign-key.
* g10/keyedit.c (keyedit_quick_sign): Return an error status line.
--
2023-05-24 16:05:41 +02:00
Werner Koch 80097bc78b
gpg: Return ERROR status for --quick-sign-key.
* g10/keyedit.c (keyedit_quick_sign): Return an error status line.
--
2023-05-24 16:02:39 +02:00
Werner Koch 8295fb3f0b
w32: Add missing supportedOS Ids for Windows-10
--
2023-05-24 14:17:06 +02:00
Werner Koch 6657230f9e
w32: Add missing supportedOS Ids for Windows-10
--
2023-05-24 14:16:10 +02:00
Werner Koch 3a438a1cc3
w32: Add missing manifests and set a requestedExecutionLevel.
* agent/gpg-agent.w32-manifest.in: New.
* dirmngr/dirmngr-client-w32info.rc: New.
* dirmngr/dirmngr-client.w32-manifest.in: New.
* dirmngr/dirmngr-w32info.rc: New.
* dirmngr/dirmngr.w32-manifest.in: New.
* dirmngr/dirmngr_ldap-w32info.rc: New.
* dirmngr/dirmngr_ldap.w32-manifest.in: New.
* g10/gpgv-w32info.rc: New.
* g10/gpgv.w32-manifest.in: New.
* kbx/keyboxd.w32-manifest.in: New.
* scd/scdaemon.w32-manifest.in: New.
* sm/gpgsm.w32-manifest.in: New.
--

This avoids the use of the VirtualStore uner Windows.

GnuPG-bug-id: 6503
2023-05-24 12:14:06 +02:00
Werner Koch 42bea7de16
common,w32: Set a proper error code when creating an output file.
* common/iobuf.c (direct_open) [W32]: Set errno.
(fd_cache_open): Ditto.
--
2023-05-24 12:13:56 +02:00
Werner Koch 7e681da1b2
sm: Emit STATUS_FAILURE for non-implemented commands.
* sm/gpgsm.c (main): Do it here.
2023-05-24 12:13:53 +02:00
Werner Koch 097701e698
gpgtar: Emit FAILURE status line.
* tools/gpgtar.c (main): Write status line before exit.
--

Due to the new way we support gpgtar in GPGME we need status lines to
detect a final error.

GnuPG-bug-id: 6497
2023-05-24 12:13:48 +02:00
Werner Koch faf0a97b2e
gpg: Improve error code for file already exists.
* g10/plaintext.c (get_output_file): Fix error code.
2023-05-24 12:12:34 +02:00
Werner Koch 3fbe10172f
w32: Add missing manifests and set a requestedExecutionLevel.
* agent/gpg-agent.w32-manifest.in: New.
* dirmngr/dirmngr-client-w32info.rc: New.
* dirmngr/dirmngr-client.w32-manifest.in: New.
* dirmngr/dirmngr-w32info.rc: New.
* dirmngr/dirmngr.w32-manifest.in: New.
* dirmngr/dirmngr_ldap-w32info.rc: New.
* dirmngr/dirmngr_ldap.w32-manifest.in: New.
* g10/gpgv-w32info.rc: New.
* g10/gpgv.w32-manifest.in: New.
* kbx/keyboxd.w32-manifest.in: New.
* scd/scdaemon.w32-manifest.in: New.
* sm/gpgsm.w32-manifest.in: New.
--

This avoids the use of the VirtualStore uner Windows.

GnuPG-bug-id: 6503
2023-05-24 12:06:37 +02:00
NIIBE Yutaka 2f872fa68c
gpg: Report BEGIN_* status before examining the input.
* common/miscellaneous.c (is_openpgp_compressed_packet)
(is_file_compressed): Moved to ...
* common/iobuf.c: ... in this file.
(is_file_compressed): Change the argument to INP, the iobuf.
* common/util.h (is_file_compressed): Remove.
* common/iobuf.h (is_file_compressed): Add.
* g10/cipher-aead.c (write_header): Don't call write_status_printf
here.
(cipher_filter_aead): Call write_status_printf when called with
IOBUFCTRL_INIT.
* g10/cipher-cfb.c (write_header): Don't call write_status_printf
here.
(cipher_filter_cfb): Call write_status_printf when called with
IOBUFCTRL_INIT.
* g10/encrypt.c (encrypt_simple): Use new is_file_compressed function,
after call of iobuf_push_filter.
(encrypt_crypt): Likewise.
* g10/sign.c (sign_file): Likewise.

--

GnuPG-bug-id: 6481
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-24 10:36:04 +09:00
Werner Koch 48b5648554
common,w32: Set a proper error code when creating an output file.
* common/iobuf.c (direct_open) [W32]: Set errno.
(fd_cache_open): Ditto.
--
2023-05-23 14:50:22 +02:00
Werner Koch 5f46bcaaa0
sm: Emit STATUS_FAILURE for non-implemented commands.
* sm/gpgsm.c (main): Do it here.
2023-05-22 17:00:54 +02:00
Werner Koch cd7f286486
gpgtar: Emit FAILURE status line.
* tools/gpgtar.c (main): Write status line before exit.
--

Due to the new way we support gpgtar in GPGME we need status lines to
detect a final error.

GnuPG-bug-id: 6497
2023-05-19 13:06:18 +02:00
Werner Koch 6944aefa3c
kbx,w32: Disable the fd-passing.
* kbx/kbxserver.c (kbxd_start_command_handler): No fd-passing udner
Windows.
--

file descriptor passing does not work reliable in libassuan for
Windows and we actually don't need it here.  It is not even used by
gpg or gpgsm.  As soon as we enable fd-passing in gpgme for Windows
and see that it is robust enough we should back out this patch.
2023-05-17 15:54:40 +02:00
NIIBE Yutaka b789ada2b0
scd: Fix send_client_notifications for Windows.
* scd/command.c (send_client_notifications): Don't use assuan_get_pid
for Windows.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-17 15:28:01 +09:00
NIIBE Yutaka d221062769
w32: Also use _putenv_s for gnupg_unsetenv.
* common/sysutils.c (gnupg_setenv): Only enable use of _putenv_s with
Security Feature in the CRT.
(gnupg_unsetenv): Use _putenv_s when available.

--

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-16 19:11:16 +09:00
NIIBE Yutaka 86cdb49097
w32: Use _putenv_s.
* common/sysutils.c (gnupg_setenv): Use _putenv_s.

--

This may break build on original MinGW, but works well with MinGW-W64.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-16 16:25:13 +09:00
NIIBE Yutaka 5c7c6065f3
w32: Remove support of Windows 95/98/Me.
* g10/photoid.c (VER_PLATFORM_WIN32_WINDOWS): Remove fallback
definition.
(get_default_photo_command): Remove use of "start /w" for Windows 95.

Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-16 10:19:02 +09:00
Werner Koch 23bb92b755
common: Fix malloc nit in regression test.
* common/t-iobuf.c: Add boilerplate.
(xmalloc): New.  Use it everywhere.
--

GnuPG-bug-id: 6483
2023-05-11 15:52:05 +02:00
NIIBE Yutaka a035938216
common,agent,gpg,dirmngr,g13,scd,tests,tools: New spawn function.
* common/exechelp-posix.c (do_exec, gnupg_spawn_process): Remove.
(check_syscall_func, pre_syscall, post_syscall) : New.
(do_create_socketpair, posix_open_null, call_spawn_cb): New.
(my_exec, spawn_detached, gnupg_spawn_helper): New.
(gnupg_process_spawn, process_kill, gnupg_process_terminate): New.
(gnupg_process_get_fds, gnupg_process_get_streams): New.
(process_vctl, gnupg_process_ctl): New.
(gnupg_process_wait, gnupg_process_release): New.
(gnupg_process_wait_list): New.
* common/exechelp-w32.c: Add definition of _WIN32_WINNT as 0x600.
(check_syscall_func, pre_syscall, post_syscall): New.
(gnupg_spawn_process): Remove.
(check_windows_version): New.
(spawn_detached, gnupg_spawn_helper, gnupg_process_spawn): New.
(gnupg_process_get_fds, gnupg_process_get_streams): New.
(process_kill, process_vctl, gnupg_process_ctl): New.
(gnupg_process_wait, gnupg_process_terminate): New.
(gnupg_process_release, gnupg_process_wait_list): New.
* common/exechelp.h: Re-write for new API.
* common/exectool.c (gnupg_exec_tool_stream): Follow the change.
* common/asshelp.c (start_new_service): Likewise.
* agent/genkey.c (do_check_passphrase_pattern): Likewise.
* dirmngr/ldap-wrapper.c (struct wrapper_context_s): Use PROC.
(destroy_wrapper): Follow the change of API.
(read_log_data): Follow the change of API, use printable_pid.
(ldap_reaper_thread, ldap_wrapper_release_context): Likewise.
(ldap_wrapper_connection_cleanup, ldap_wrapper): Likewise.
* g10/photoid.c (run_with_pipe): Follow the change of API.
(show_photo): Likewise.
* g13/be-encfs.c (run_umount_helper): Likewise.
(run_encfs_tool): Likewise.
* g13/g13.c: Add including ./common/exechelp.h.
* g13/mount.c: Likewise.
* g13/runner.c: Follow the change of API.
* g13/runner.h: Follow the change of API.
* scd/app.c (setup_env): New.
(report_change): Follow the change of API.
* tests/gpgscm/ffi.c (proc_object_finalize): New.
(proc_object_to_string): New.
(proc_wrap, proc_unwrap): New.
(do_spawn_process): Remove.
(do_process_spawn): New.
(setup_std_fds): New.
(do_spawn_process_fd): Remove.
(do_process_spawn_fd): New.
(do_wait_process): Remove.
(do_process_wait): New.
(do_wait_processes): Remove.
* tests/gpgscm/t-child.scm: Follow the change of API.
* tests/gpgscm/tests.scm: Likewise.
* tests/openpgp/defs.scm: Likewise.
* tests/tpm2dtests/defs.scm: Likewise.
* tools/gpg-card.c: Likewise.
* tools/gpgconf-comp.c: Likewise.
* tools/gpgconf.c: Likewise.
* tools/gpgtar-create.c: Likewise.
* tools/gpgtar-extract.c: Likewise.
* tools/gpgtar-list.c: Likewise.

--

GnuPG-bug-id: 6275
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
2023-05-11 19:18:21 +09:00
373 changed files with 26431 additions and 16564 deletions

View File

@ -1,2 +1,6 @@
# indent: Modernize mem2str.
6a80d6f9206eae2c867c45daa5cd3e7d6c6ad114
# doc: Fix spelling errors found by lintian.
2ed1f68b48db7b5503045386de0500fddf70077e
# indent: Re-indent a function
869d1df270c0ccc3a9f792167b96d678a932b37e

View File

@ -16,7 +16,7 @@ List of Copyright holders
=========================
Copyright (C) 1997-2019 Werner Koch
Copyright (C) 2003-2023 g10 Code GmbH
Copyright (C) 2003-2024 g10 Code GmbH
Copyright (C) 1994-2021 Free Software Foundation, Inc.
Copyright (C) 2002 Klarälvdalens Datakonsult AB
Copyright (C) 1995-1997, 2000-2007 Ulrich Drepper <drepper@gnu.ai.mit.edu>
@ -220,6 +220,9 @@ Jussi Kivilinna <jussi.kivilinna@iki.fi>
Kyle Butt <kylebutt@gmail.com>
2013-05-29:CAAODAYLbCtqOG6msLLL0UTdASKWT6u2ptxsgUQ1JpusBESBoNQ@mail.gmail.com:
Mario Haustein <mario.haustein@hrz.tu-chemnitz.de>
2022-09-26:8149069.T7Z3S40VBb@localdomain:
Michael Haubenwallner <michael.haubenwallner@ssi-schaefer.com>
2018-07-13:c397e637-f1ce-34f0-7e6a-df04a76e1c35@ssi-schaefer.com:

View File

@ -18,13 +18,13 @@
## Process this file with automake to produce Makefile.in
# To include the wixlibs for building an MSI installer in a release use
# make release WITH_MSI=1
# We want to also build the wixlib for use by GnuPG Desktop
WITH_MSI=1
# Location of the released tarball archives. This is prefixed by
# the variable RELEASE_ARCHIVE in ~/.gnupg-autogen.rc. For example:
# RELEASE_ARCHIVE=user@host:archive/tarballs
RELEASE_ARCHIVE_SUFFIX = gnupg/v2.4
RELEASE_ARCHIVE_SUFFIX = gnupg/v2.5
# The variable RELEASE_SIGNKEY in ~/.gnupg-autogen.rc is used
# to specify the key for signing. For example:
# RELEASE_SIGNKEY=D8692123C4065DEA5E0F3AB5249B39D24F25E3B6
@ -191,7 +191,7 @@ endif
gen_start_date = 2011-12-01T06:00:00
.PHONY: gen-ChangeLog
.PHONY: gen-ChangeLog stowinstall speedo
gen-ChangeLog:
if test -e $(top_srcdir)/.git; then \
(cd $(top_srcdir) && \
@ -207,6 +207,11 @@ gen-ChangeLog:
stowinstall:
$(MAKE) $(AM_MAKEFLAGS) install prefix=/usr/local/stow/gnupg
speedo:
$(MAKE) -f $(top_srcdir)/build-aux/speedo.mk native SELFCHECK=0
TESTS_ENVIRONMENT = \
LC_ALL=C \
EXEEXT=$(EXEEXT) \
@ -242,8 +247,8 @@ release:
mkopt=""; \
if [ -n "$$CUSTOM_SWDB" ]; then \
mkopt="CUSTOM_SWB=1"; \
x=$$(grep '^OVERRIDE_TARBALLS=' \
$$HOME/.gnupg-autogen.rc|cut -d= -f2);\
x=$$(grep '^[[:blank:]]*OVERRIDE_TARBALLS[[:blank:]]*=' \
$$HOME/.gnupg-autogen.rc|cut -d= -f2|xargs);\
if [ -f "$$x/swdb.lst" ]; then \
echo "/* Copying swdb.lst from the overrides directory */"; \
cp "$$x/swdb.lst" . ; \
@ -270,13 +275,15 @@ release:
sign-release:
+(set -e; \
test $$(pwd | sed 's,.*/,,') = dist || cd dist; \
x=$$(grep '^RELEASE_ARCHIVE=' $$HOME/.gnupg-autogen.rc|cut -d= -f2);\
x=$$(grep '^[[:blank:]]*RELEASE_ARCHIVE[[:blank:]]*=' \
$$HOME/.gnupg-autogen.rc|cut -d= -f2|xargs);\
if [ -z "$$x" ]; then \
echo "error: RELEASE_ARCHIVE missing in ~/.gnupg-autogen.rc">&2; \
exit 2;\
fi;\
myarchive="$$x/$(RELEASE_ARCHIVE_SUFFIX)";\
x=$$(grep '^RELEASE_SIGNKEY=' $$HOME/.gnupg-autogen.rc|cut -d= -f2);\
x=$$(grep '^[[:blank:]]*RELEASE_SIGNKEY[[:blank:]]*=' \
$$HOME/.gnupg-autogen.rc|cut -d= -f2|xargs);\
if [ -z "$$x" ]; then \
echo "error: RELEASE_SIGNKEY missing in ~/.gnupg-autogen.rc">&2; \
exit 2;\

245
NEWS
View File

@ -1,6 +1,235 @@
Noteworthy changes in version 2.5.0 (unreleased)
------------------------------------------------
Changes also found in 2.4.5:
Noteworthy changes in version 2.4.5 (2024-03-07)
------------------------------------------------
* gpg,gpgv: New option --assert-pubkey-algo. [T6946]
* gpg: Emit status lines for errors in the compression layer.
[T6977]
* gpg: Fix invocation with --trusted-keys and --no-options. [T7025]
* gpgsm: Allow for a longer salt in PKCS#12 files. [T6757]
* gpgtar: Make --status-fd=2 work on Windows. [T6961]
* scd: Support for the ACR-122U NFC reader. [rG1682ca9f01]
* scd: Suport D-TRUST ECC cards. [T7000,T7001]
* scd: Allow auto detaching of kernel drivers; can be disabled with
the new compatibility-flag ccid-no-auto-detach. [rGa1ea3b13e0]
* scd: Allow setting a PIN length of 6 also with a reset code for
openpgp cards. [T6843]
* agent: Allow GET_PASSPHRASE in restricted mode. [rGadf4db6e20]
* dirmngr: Trust system's root CAs for checking CRL issuers.
[T6963]
* dirmngr: Fix regression in 2.4.4 in fetching keys via hkps.
[T6997]
* gpg-wks-client: Make option --mirror work properly w/o specifying
domains. [rG37cc255e49]
* g13,gpg-wks-client: Allow command style options as in "g13 mount
foo". [rGa09157ccb2]
* Allow tilde expansion for the foo-program options. [T7017]
* Make the getswdb.sh tool usable outside the GnuPG tree.
Changes also found in 2.4.4:
* gpg: Do not keep an unprotected smartcard backup key on disk. See
https://gnupg.org/blog/20240125-smartcard-backup-key.html for a
security advisory. [T6944]
* gpg: Allow to specify seconds since Epoch beyond 2038 on 32-bit
platforms. [T6736]
* gpg: Fix expiration time when Creation-Date is specified. [T5252]
* gpg: Add support for Subkey-Expire-Date. [rG96b69c1866]
* gpg: Add option --with-v5-fingerprint. [T6705]
* gpg: Add sub-option ignore-attributes to --import-options.
[rGd4976e35d2]
* gpg: Add --list-filter properties sig_expires/sig_expires_d.
[rGbf662d0f93af]
* gpg: Fix validity of re-imported keys. [T6399]
* gpg: Report BEGIN_ status before examining the input. [T6481]
* gpg: Don't try to compress a read-only keybox. [T6811]
* gpg: Choose key from inserted card over a non-inserted
card. [T6831]
* gpg: Allow to create revocations even with non-compliant algos.
[T6929]
* gpg: Fix regression in the Revoker keyword of the parameter file.
[T6923]
* gpg: Improve error message for expired default keys. [T4704]
* gpgsm: Add --always-trust feature. [T6559]
* gpgsm: Support ECC certificates in de-vs mode. [T6802]
* gpgsm: Major rewrite of the PKCS#12 parser. [T6536]
* gpgsm: No not show the pkcs#12 passphrase in debug output. [T6654]
* keyboxd: Timeout on failure to get the database lock. [T6838]
* agent: Update the key stubs only if really modified. [T6829]
* scd: Add support for certain Starcos 3.2 cards. [rG5304c9b080]
* scd: Add support for CardOS 5.4 cards. [rG812f988059]
* scd: Add support for D-Trust 4.1/4.4 cards. [rG0b85a9ac09]
* scd: Add support for Smartcafe Expert 7.0 cards. [T6919]
* scd: Add a length check for a new PIN. [T6843]
* tpm: Fix keytotpm handling in the agent. [rG9909f622f6]
* tpm: Fixes for the TPM test suite. [T6052]
* dirmngr: Avoid starting a second instance on Windows via GPGME
based launching. [T6833]
* dirmngr: New option --ignore-crl-extensions. [T6545]
* dirmngr: Support config value "none" to disable the default
keyserver. [T6708]
* dirmngr: Implement automatic proxy detection on Windows. [T5768]
* dirmngr: Fix handling of the HTTP Content-Length. [rGa5e33618f4]
* dirmngr: Add code to support proxy authentication using the
Negotiation method on Windows. [T6719]
* gpgconf: Add commands --lock and --unlock. [rG93b5ba38dc]
* gpgconf: Add keyword socketdir to gpgconf.ctl. [rG239c1fdc28]
* gpgconf: Adjust the -X command for the new VERSION file format.
[T6918]
* wkd: Use export-clean for gpg-wks-client's --mirror and --create
commands. [rG2c7f7a5a278c]
* wkd: Make --add-revocs the default in gpg-wks-client. New option
--no-add-revocs. [rG10c937ee68]
* Remove duplicated backslashes when setting the homedir. [T6833]
* Ignore attempts to remove the /dev/null device. [T6556]
* Improve advisory file lock retry strategy. [T3380]
* Improve the speedo build system for Unix. [T6710]
Changes also found in 2.4.3:
* gpg: Set default expiration date to 3 years. [T2701]
* gpg: Add --list-filter properties "key_expires" and
"key_expires_d". [T6529]
* gpg: Emit status line and proper diagnostics for write errors.
[T6528]
* gpg: Make progress work for large files on Windows. [T6534]
* gpg: New option --no-compress as alias for -z0.
* gpg: Show better error messages for blocked PINs. [T6425]
* gpgsm: Print PROGRESS status lines. Add new --input-size-hint.
[T6534]
* gpgsm: Support SENDCERT_SKI for --call-dirmngr. [rG701a8b30f0]
* gpgsm: Major rewrite of the PKCS#12 parser. [T6536]
* gpgtar: New option --no-compress.
* dirmngr: Extend the AD_QUERY command. [rG207c99567c]
* dirmngr: Disable the HTTP redirect rewriting. [T6477]
* dirmngr: New option --compatibility-flags. [rGbf04b07327]
* dirmngr: New option --ignore-crl-extensions. [T6545]
* dirmngr: Support config value "none" to disable the default
keyserver. [T6708]
* wkd: Use export-clean for gpg-wks-client's --mirror and --create
commands. [rG2c7f7a5a27]
* wkd: Make --add-revocs the default in gpg-wks-client. New option
--no-add-revocs. [rG10c937ee68]
* scd: Make signing work for Nexus cards. [rGb83d86b988]
* scd: Fix authentication with Administration Key for PIV.
[rG25b59cf6ce]
* Fix garbled time output in non-English Windows. [T6741]
Changes also found in 2.4.2:
* gpg: Print a warning if no more encryption subkeys are left over
after changing the expiration date. [rGef2c3d50fa]
* gpg: Fix searching for the ADSK key when adding an ADSK. [T6504]
* gpgsm: Speed up key listings on Windows. [rG08ff55bd44]
* gpgsm: Reduce the number of "failed to open policy file"
diagnostics. [rG68613a6a9d]
* agent: Make updating of private key files more robust and track
display S/N. [T6135]
* keyboxd: Avoid longish delays on Windows when listing keys.
[rG6944aefa3c]
* gpgtar: Emit extra status lines to help GPGME. [T6497]
* w32: Avoid using the VirtualStore. [T6403]
Release dates of 2.4 versions
-----------------------------
Version 2.4.5 (2024-03-07) https://dev.gnupg.org/T6960
Version 2.4.4 (2024-01-25) https://dev.gnupg.org/T6578
Version 2.4.3 (2023-07-04) https://dev.gnupg.org/T6509
Version 2.4.2 (2023-05-30) https://dev.gnupg.org/T6506
Version 2.4.1 (2023-04-28) https://dev.gnupg.org/T6454
Version 2.4.0 (2022-12-16) https://dev.gnupg.org/T6302
Noteworthy changes in version 2.4.1 (2023-04-28)
------------------------------------------------
@ -1209,7 +1438,7 @@ Noteworthy changes in version 2.3.0 (2021-04-07)
Changes also found in 2.2.12:
* tools: New commands --install-key and --remove-key for
gpg-wks-client. This allows to prepare a Web Key Directory on a
gpg-wks-client. This allows one to prepare a Web Key Directory on a
local file system for later upload to a web server.
* gpg: New --list-option "show-only-fpr-mbox". This makes the use
@ -1253,7 +1482,7 @@ Noteworthy changes in version 2.3.0 (2021-04-07)
query.
* gpg: Do not store the TOFU trust model in the trustdb. This
allows to enable or disable a TOFO model without triggering a
allows one to enable or disable a TOFO model without triggering a
trustdb rebuild. [#4134]
* scd: Fix cases of "Bad PIN" after using "forcesig". [#4177]
@ -1595,6 +1824,8 @@ Noteworthy changes in version 2.3.0 (2021-04-07)
Release dates of 2.2 versions
-----------------------------
Version 2.2.42 (2023-11-28) https://dev.gnupg.org/T6307
Version 2.2.41 (2022-12-09) https://dev.gnupg.org/T6280
Version 2.2.40 (2022-10-10) https://dev.gnupg.org/T6181
Version 2.2.39 (2022-09-02) https://dev.gnupg.org/T6175
Version 2.2.38 (2022-09-01) https://dev.gnupg.org/T6159
@ -1670,7 +1901,7 @@ Noteworthy changes in version 2.1.23 (2017-08-09)
to your gpg.conf.
* agent: Option --no-grab is now the default. The new option --grab
allows to revert this.
allows one to revert this.
* gpg: New import option "show-only".
@ -2800,7 +3031,7 @@ Noteworthy changes in version 2.1.0 (2014-11-06)
* gpg: Allow use of Brainpool curves.
* gpg: Accepts a space separated fingerprint as user ID. This
allows to copy and paste the fingerprint from the key listing.
allows one to copy and paste the fingerprint from the key listing.
* gpg: The hash algorithm is now printed for signature records in key
listings.
@ -3580,7 +3811,7 @@ Noteworthy changes in version 1.9.10 (2004-07-22)
* Fixed a serious bug in the checking of trusted root certificates.
* New configure option --enable-agent-pnly allows to build and
* New configure option --enable-agent-only allows one to build and
install just the agent.
* Fixed a problem with the log file handling.
@ -3975,7 +4206,7 @@ Noteworthy changes in version 1.1.92 (2002-09-11)
extension specified with --load-extension are checked, along
with their enclosing directories.
* The configure option --with-static-rnd=auto allows to build gpg
* The configure option --with-static-rnd=auto allows one to build gpg
with all available entropy gathering modules included. At
runtime the best usable one will be selected from the list
linux, egd, unix. This is also the default for systems lacking
@ -4358,7 +4589,7 @@ Noteworthy changes in version 1.0.2 (2000-07-12)
* New command --export-secret-subkeys which outputs the
the _primary_ key with it's secret parts deleted. This is
useful for automated decryption/signature creation as it
allows to keep the real secret primary key offline and
allows one to keep the real secret primary key offline and
thereby protecting the key certificates and allowing to
create revocations for the subkeys. See the FAQ for a
procedure to install such secret keys.

57
README
View File

@ -4,7 +4,7 @@
Copyright 1997-2019 Werner Koch
Copyright 1998-2021 Free Software Foundation, Inc.
Copyright 2003-2023 g10 Code GmbH
Copyright 2003-2024 g10 Code GmbH
* INTRODUCTION
@ -40,7 +40,7 @@
Several other standard libraries are also required. The configure
script prints diagnostic messages if one of these libraries is not
available and a feature will not be available..
available and a feature will not be available.
You also need the Pinentry package for most functions of GnuPG;
however it is not a build requirement. Pinentry is available at
@ -80,15 +80,24 @@
to view the directories used by GnuPG.
** Quick build method on Unix
To quickly build all required software without installing it, the
Speedo method may be used:
Speedo target may be used:
cd build
make -f ../build-aux/speedo.mk native
make -f build-aux/speedo.mk native
This target downloads all required libraries and does a native build
of GnuPG to PLAY/inst/. GNU make and the patchelf tool are
required. After the build the entire software including all
libraries can be installed into an arbitrary location using for
example:
make -f build-aux/speedo.mk install SYSROOT=/usr/local/gnupg24
ldconfig -n /usr/local/gnupg24/lib
and adding /usr/local/gnupg24/bin to PATH.
This method downloads all required libraries and does a native build
of GnuPG to PLAY/inst/. GNU make is required and you need to set
LD_LIBRARY_PATH to $(pwd)/PLAY/inst/lib to test the binaries.
** Specific build problems on some machines:
@ -144,6 +153,13 @@
gpg --import --import-options restore < allkeys.gpg
gpgsm --import < allcerts.crt
In case the keyboxd is not able to startup due to a stale lockfile
created by another host, the command
gpgconf --unlock pubring.db
can be used to remove the lock file.
** Socket directory
GnuPG uses Unix domain sockets to connect its components (on Windows
@ -166,11 +182,34 @@
fi
done )
** Conflicts with systemd socket activation
Some Linux distribution use the meanwhile deprecated --supervised
option with gpg-agent, dirmngr, and keyboxd. The idea is that the
systemd process launches the daemons as soon as gpg or gpgsm try to
access them. However, this creates a race condition with GnuPG's
own on-demand launching of these daemon. It also conflicts with the
remote use gpg-agent because the no-autostart feature on the remote
site will not work as expected.
Thus the recommendation is not to use the --supervised option. All
GnuPG components handle the startup of their daemons on their own.
The only problem is that for using GnuPG's ssh-agent protocol
support, the gpg-agent must have been started before ssh. This can
either be done with an ssh wrapper running
gpg-connect-agent updatestartuptty /bye
for each new tty or by using that command directly after login when
the anyway required SSH_AUTH_SOCK envvar is set (see the example in
the gpg-agent man page).
* DOCUMENTATION
The complete documentation is in the texinfo manual named
`gnupg.info'. Run "info gnupg" to read it. If you want a a
`gnupg.info'. Run "info gnupg" to read it. If you want a
printable copy of the manual, change to the "doc" directory and
enter "make pdf" For a HTML version enter "make html" and point your
browser to gnupg.html/index.html. Standard man pages for all

View File

@ -1,3 +1,4 @@
# Makefile.am - agent
# Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
#
# This file is part of GnuPG.
@ -23,8 +24,8 @@ libexec_PROGRAMS = gpg-protect-tool
libexec_PROGRAMS += gpg-preset-passphrase
noinst_PROGRAMS = $(TESTS)
EXTRA_DIST = ChangeLog-2011 gpg-agent-w32info.rc all-tests.scm
EXTRA_DIST = ChangeLog-2011 all-tests.scm \
gpg-agent-w32info.rc gpg-agent.w32-manifest.in
AM_CPPFLAGS =
@ -32,6 +33,8 @@ include $(top_srcdir)/am/cmacros.am
if HAVE_W32_SYSTEM
resource_objs += gpg-agent-w32info.o
gpg-agent-w32info.o : gpg-agent.w32-manifest ../common/w32info-rc.h
endif
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(GPG_ERROR_CFLAGS)

View File

@ -86,8 +86,8 @@ struct
/* Enable pinentry debugging (--debug 1024 should also be used). */
int debug_pinentry;
/* Filename of the program to start as pinentry. */
const char *pinentry_program;
/* Filename of the program to start as pinentry (malloced). */
char *pinentry_program;
/* Filename of the program to handle daemon tasks. */
const char *daemon_program[DAEMON_MAX_TYPE];
@ -225,6 +225,17 @@ typedef struct ssh_control_file_s *ssh_control_file_t;
/* Forward reference for local definitions in call-scd.c. */
struct daemon_local_s;
/* Object to hold ephemeral secret keys. */
struct ephemeral_private_key_s
{
struct ephemeral_private_key_s *next;
unsigned char grip[KEYGRIP_LEN];
unsigned char *keybuf; /* Canon-s-exp with the private key (malloced). */
size_t keybuflen;
};
typedef struct ephemeral_private_key_s *ephemeral_private_key_t;
/* Collection of data per session (aka connection). */
struct server_control_s
{
@ -246,6 +257,12 @@ struct server_control_s
/* Private data of the daemon (call-XXX.c). */
struct daemon_local_s *d_local[DAEMON_MAX_TYPE];
/* Linked list with ephemeral stored private keys. */
ephemeral_private_key_t ephemeral_keys;
/* If set functions will lookup keys in the ephemeral_keys list. */
int ephemeral_mode;
/* Environment settings for the connection. */
session_env_t session_env;
char *lc_ctype;
@ -271,8 +288,11 @@ struct server_control_s
unsigned int raw_value: 1;
unsigned int is_pss: 1; /* DATA holds PSS formated data. */
} digest;
unsigned int have_keygrip: 1;
unsigned int have_keygrip1: 1;
unsigned char keygrip[20];
int have_keygrip;
unsigned char keygrip1[20]; /* Another keygrip for hybrid crypto. */
/* A flag to enable a hack to send the PKAUTH command instead of the
PKSIGN command to the scdaemon. */
@ -411,6 +431,7 @@ void *get_agent_daemon_notify_event (void);
#endif
void agent_sighup_action (void);
int map_pk_openpgp_to_gcry (int openpgp_algo);
void agent_kick_the_loop (void);
/*-- command.c --*/
gpg_error_t agent_inq_pinentry_launched (ctrl_t ctrl, unsigned long pid,
@ -452,10 +473,13 @@ void start_command_handler_ssh (ctrl_t, gnupg_fd_t);
/*-- findkey.c --*/
gpg_error_t agent_modify_description (const char *in, const char *comment,
const gcry_sexp_t key, char **result);
int agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force,
const char *serialno, const char *keyref,
time_t timestamp);
gpg_error_t agent_write_private_key (ctrl_t ctrl,
const unsigned char *grip,
const void *buffer, size_t length,
int force,
const char *serialno, const char *keyref,
const char *dispserialno,
time_t timestamp);
gpg_error_t agent_key_from_file (ctrl_t ctrl,
const char *cache_nonce,
const char *desc_text,
@ -475,7 +499,7 @@ gpg_error_t agent_ssh_key_from_file (ctrl_t ctrl,
gcry_sexp_t *result, int *r_order);
int agent_pk_get_algo (gcry_sexp_t s_key);
int agent_is_tpm2_key(gcry_sexp_t s_key);
int agent_key_available (const unsigned char *grip);
int agent_key_available (ctrl_t ctrl, const unsigned char *grip);
gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
int *r_keytype,
unsigned char **r_shadow_info,
@ -483,7 +507,8 @@ gpg_error_t agent_key_info_from_file (ctrl_t ctrl, const unsigned char *grip,
gpg_error_t agent_delete_key (ctrl_t ctrl, const char *desc_text,
const unsigned char *grip,
int force, int only_stubs);
gpg_error_t agent_update_private_key (const unsigned char *grip, nvc_t pk);
gpg_error_t agent_update_private_key (ctrl_t ctrl,
const unsigned char *grip, nvc_t pk);
/*-- call-pinentry.c --*/
void initialize_module_call_pinentry (void);
@ -512,7 +537,7 @@ int agent_clear_passphrase (ctrl_t ctrl,
/*-- cache.c --*/
void initialize_module_cache (void);
void deinitialize_module_cache (void);
void agent_cache_housekeeping (void);
struct timespec *agent_cache_expiration (void);
void agent_flush_cache (int pincache_only);
int agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
const char *data, int ttl);
@ -535,19 +560,37 @@ gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
const unsigned char *ciphertext, size_t ciphertextlen,
membuf_t *outbuf, int *r_padding);
enum kemids
{
KEM_PQC_PGP,
KEM_PGP,
KEM_CMS
};
gpg_error_t agent_kem_decrypt (ctrl_t ctrl, const char *desc_text, int kemid,
const unsigned char *ct, size_t ctlen,
const unsigned char *option, size_t optionlen,
membuf_t *outbuf);
/*-- genkey.c --*/
#define CHECK_CONSTRAINTS_NOT_EMPTY 1
#define CHECK_CONSTRAINTS_NEW_SYMKEY 2
#define GENKEY_FLAG_NO_PROTECTION 1
#define GENKEY_FLAG_PRESET 2
void clear_ephemeral_keys (ctrl_t ctrl);
int check_passphrase_constraints (ctrl_t ctrl, const char *pw,
unsigned int flags,
char **failed_constraint);
gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
char **r_passphrase);
int agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
int agent_genkey (ctrl_t ctrl, unsigned int flags,
const char *cache_nonce, time_t timestamp,
const char *keyparam, size_t keyparmlen,
int no_protection, const char *override_passphrase,
int preset, membuf_t *outbuf);
const char *override_passphrase,
membuf_t *outbuf);
gpg_error_t agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
char **passphrase_addr);
@ -585,9 +628,10 @@ gpg_error_t s2k_hash_passphrase (const char *passphrase, int hashalgo,
const unsigned char *s2ksalt,
unsigned int s2kcount,
unsigned char *key, size_t keylen);
gpg_error_t agent_write_shadow_key (const unsigned char *grip,
gpg_error_t agent_write_shadow_key (ctrl_t ctrl, const unsigned char *grip,
const char *serialno, const char *keyid,
const unsigned char *pkbuf, int force);
const unsigned char *pkbuf, int force,
const char *dispserialno);
/*-- trustlist.c --*/
@ -661,6 +705,9 @@ gpg_error_t divert_writekey (ctrl_t ctrl, int force, const char *serialno,
const char *keyref,
const char *keydata, size_t keydatalen);
gpg_error_t agent_card_ecc_kem (ctrl_t ctrl, const unsigned char *ecc_ct,
size_t ecc_point_len, unsigned char *ecc_ecdh);
/*-- call-daemon.c --*/
gpg_error_t daemon_start (enum daemon_type type, ctrl_t ctrl);
assuan_context_t daemon_type_ctx (enum daemon_type type, ctrl_t ctrl);
@ -709,6 +756,7 @@ int agent_card_pkdecrypt (ctrl_t ctrl,
const char *desc_text,
const unsigned char *indata, size_t indatalen,
char **r_buf, size_t *r_buflen, int *r_padding);
int agent_card_readcert (ctrl_t ctrl,
const char *id, char **r_buf, size_t *r_buflen);
int agent_card_readkey (ctrl_t ctrl, const char *id,
@ -730,7 +778,6 @@ void agent_card_free_keyinfo (struct card_key_info_s *l);
gpg_error_t agent_card_keyinfo (ctrl_t ctrl, const char *keygrip,
int cap, struct card_key_info_s **result);
/*-- learncard.c --*/
int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force);

View File

@ -53,8 +53,20 @@ struct secret_data_s {
char data[1]; /* A string. */
};
/* The cache object. */
/* The type of cache object. */
typedef struct cache_item_s *ITEM;
/* The timer entry in a linked list. */
struct timer_s {
ITEM next;
int tv_sec;
int reason;
};
#define CACHE_EXPIRE_UNUSED 0
#define CACHE_EXPIRE_LAST_ACCESS 1
#define CACHE_EXPIRE_CREATION 2
/* The cache object. */
struct cache_item_s {
ITEM next;
time_t created;
@ -63,12 +75,18 @@ struct cache_item_s {
struct secret_data_s *pw;
cache_mode_t cache_mode;
int restricted; /* The value of ctrl->restricted is part of the key. */
struct timer_s t;
char key[1];
};
/* The cache himself. */
static ITEM thecache;
/* The timer list of expiration, in active. */
static ITEM the_timer_list;
/* Newly created entries, to be inserted into the timer list. */
static ITEM the_timer_list_new;
/* NULL or the last cache key stored by agent_store_cache_hit. */
static char *last_stored_cache_key;
@ -193,100 +211,302 @@ new_data (const char *string, struct secret_data_s **r_data)
}
/* Check whether there are items to expire. */
static void
housekeeping (void)
insert_to_timer_list_new (ITEM entry)
{
ITEM r, rprev;
entry->t.next = the_timer_list_new;
the_timer_list_new = entry;
}
/* Insert to the active timer list. */
static void
insert_to_timer_list (struct timespec *ts, ITEM entry)
{
ITEM e, eprev;
if (!the_timer_list || ts->tv_sec >= entry->t.tv_sec)
{
if (the_timer_list)
{
the_timer_list->t.tv_sec += ts->tv_sec - entry->t.tv_sec;
if (ts->tv_nsec >= 500000000)
the_timer_list->t.tv_sec++;
}
ts->tv_sec = entry->t.tv_sec;
ts->tv_nsec = 0;
entry->t.tv_sec = 0;
entry->t.next = the_timer_list;
the_timer_list = entry;
return;
}
entry->t.tv_sec -= ts->tv_sec;
eprev = NULL;
for (e = the_timer_list; e; e = e->t.next)
{
if (e->t.tv_sec > entry->t.tv_sec)
break;
eprev = e;
entry->t.tv_sec -= e->t.tv_sec;
}
entry->t.next = e;
if (e)
e->t.tv_sec -= entry->t.tv_sec;
if (eprev)
eprev->t.next = entry;
else
the_timer_list = entry;
}
static void
remove_from_timer_list (ITEM entry)
{
ITEM e, eprev;
eprev = NULL;
for (e = the_timer_list; e; e = e->t.next)
if (e != entry)
eprev = e;
else
{
if (e->t.next)
e->t.next->t.tv_sec += e->t.tv_sec;
if (eprev)
eprev->t.next = e->t.next;
else
the_timer_list = e->t.next;
break;
}
entry->t.next = NULL;
entry->t.tv_sec = 0;
}
static void
remove_from_timer_list_new (ITEM entry)
{
ITEM e, eprev;
eprev = NULL;
for (e = the_timer_list_new; e; e = e->t.next)
if (e != entry)
eprev = e;
else
{
if (eprev)
eprev->t.next = e->t.next;
else
the_timer_list_new = e->t.next;
break;
}
entry->t.next = NULL;
entry->t.tv_sec = 0;
}
static int
compute_expiration (ITEM r)
{
unsigned long maxttl;
time_t current = gnupg_get_time ();
time_t next;
/* First expire the actual data */
for (r=thecache; r; r = r->next)
if (r->cache_mode == CACHE_MODE_PIN)
return 0; /* Don't let it expire - scdaemon explicitly flushes them. */
if (!r->pw)
{
if (r->cache_mode == CACHE_MODE_PIN)
; /* Don't let it expire - scdaemon explicitly flushes them. */
else if (r->pw && r->ttl >= 0 && r->accessed + r->ttl < current)
{
if (DBG_CACHE)
log_debug (" expired '%s'.%d (%ds after last access)\n",
r->key, r->restricted, r->ttl);
release_data (r->pw);
r->pw = NULL;
r->accessed = current;
}
/* Expire an old and unused entry after 30 minutes. */
r->t.tv_sec = 60*30;
r->t.reason = CACHE_EXPIRE_UNUSED;
return 1;
}
/* Second, make sure that we also remove them based on the created
* stamp so that the user has to enter it from time to time. We
* don't do this for data items which are used to storage secrets in
* meory and are not user entered passphrases etc. */
for (r=thecache; r; r = r->next)
switch (r->cache_mode)
{
unsigned long maxttl;
switch (r->cache_mode)
{
case CACHE_MODE_DATA:
case CACHE_MODE_PIN:
continue; /* No MAX TTL here. */
case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
default: maxttl = opt.max_cache_ttl; break;
}
if (r->pw && r->created + maxttl < current)
{
if (DBG_CACHE)
log_debug (" expired '%s'.%d (%lus after creation)\n",
r->key, r->restricted, opt.max_cache_ttl);
release_data (r->pw);
r->pw = NULL;
r->accessed = current;
}
case CACHE_MODE_DATA:
case CACHE_MODE_PIN:
maxttl = 0; /* No MAX TTL here. */
break;
case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
default: maxttl = opt.max_cache_ttl; break;
}
/* Third, make sure that we don't have too many items in the list.
* Expire old and unused entries after 30 minutes. */
for (rprev=NULL, r=thecache; r; )
if (maxttl)
{
if (!r->pw && r->ttl >= 0 && r->accessed + 60*30 < current)
if (r->created + maxttl < current)
{
ITEM r2 = r->next;
if (DBG_CACHE)
log_debug (" removed '%s'.%d (mode %d) (slot not used for 30m)\n",
r->key, r->restricted, r->cache_mode);
xfree (r);
if (!rprev)
thecache = r2;
else
rprev->next = r2;
r = r2;
}
else
{
rprev = r;
r = r->next;
r->t.tv_sec = 0;
r->t.reason = CACHE_EXPIRE_CREATION;
return 1;
}
next = r->created + maxttl - current;
}
else
next = 0;
if (r->ttl >= 0 && (next == 0 || r->ttl < next))
{
r->t.tv_sec = r->ttl;
r->t.reason = CACHE_EXPIRE_LAST_ACCESS;
return 1;
}
if (next)
{
r->t.tv_sec = next;
r->t.reason = CACHE_EXPIRE_CREATION;
return 1;
}
return 0;
}
static void
update_expiration (ITEM entry, int is_new_entry)
{
if (!is_new_entry)
{
remove_from_timer_list (entry);
remove_from_timer_list_new (entry);
}
if (compute_expiration (entry))
{
insert_to_timer_list_new (entry);
agent_kick_the_loop ();
}
}
void
agent_cache_housekeeping (void)
/* Expire the cache entry. Returns 1 when the entry should be removed
* from the cache. */
static int
do_expire (ITEM e)
{
int res;
if (!e->pw)
/* Unused entry after 30 minutes. */
return 1;
if (DBG_CACHE)
log_debug ("agent_cache_housekeeping\n");
if (e->t.reason == CACHE_EXPIRE_LAST_ACCESS)
{
if (DBG_CACHE)
log_debug (" expired '%s'.%d (%ds after last access)\n",
e->key, e->restricted, e->ttl);
}
else
{
if (DBG_CACHE)
log_debug (" expired '%s'.%d (%lus after creation)\n",
e->key, e->restricted, opt.max_cache_ttl);
}
release_data (e->pw);
e->pw = NULL;
e->accessed = 0;
if (compute_expiration (e))
insert_to_timer_list_new (e);
return 0;
}
struct timespec *
agent_cache_expiration (void)
{
static struct timespec abstime;
static struct timespec timeout;
struct timespec *tp;
struct timespec curtime;
int res;
int expired = 0;
ITEM e, enext;
res = npth_mutex_lock (&cache_lock);
if (res)
log_fatal ("failed to acquire cache mutex: %s\n", strerror (res));
housekeeping ();
npth_clock_gettime (&curtime);
if (the_timer_list)
{
if (npth_timercmp (&abstime, &curtime, <))
expired = 1;
else
npth_timersub (&abstime, &curtime, &timeout);
}
if (expired && (e = the_timer_list) && e->t.tv_sec == 0)
{
the_timer_list = e->t.next;
e->t.next = NULL;
if (do_expire (e))
{
ITEM r, rprev;
if (DBG_CACHE)
log_debug (" removed '%s'.%d (mode %d) (slot not used for 30m)\n",
e->key, e->restricted, e->cache_mode);
rprev = NULL;
for (r = thecache; r; r = r->next)
if (r == e)
{
if (!rprev)
thecache = r->next;
else
rprev->next = r->next;
break;
}
else
rprev = r;
remove_from_timer_list_new (e);
xfree (e);
}
}
if (expired || !the_timer_list)
timeout.tv_sec = timeout.tv_nsec = 0;
for (e = the_timer_list_new; e; e = enext)
{
enext = e->t.next;
e->t.next = NULL;
insert_to_timer_list (&timeout, e);
}
the_timer_list_new = NULL;
if (!the_timer_list)
tp = NULL;
else
{
if (the_timer_list->t.tv_sec != 0)
{
timeout.tv_sec += the_timer_list->t.tv_sec;
the_timer_list->t.tv_sec = 0;
}
npth_timeradd (&timeout, &curtime, &abstime);
tp = &timeout;
}
res = npth_mutex_unlock (&cache_lock);
if (res)
log_fatal ("failed to release cache mutex: %s\n", strerror (res));
return tp;
}
@ -314,6 +534,7 @@ agent_flush_cache (int pincache_only)
release_data (r->pw);
r->pw = NULL;
r->accessed = 0;
update_expiration (r, 0);
}
}
@ -358,7 +579,6 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
if (DBG_CACHE)
log_debug ("agent_put_cache '%s'.%d (mode %d) requested ttl=%d\n",
key, restricted, cache_mode, ttl);
housekeeping ();
if (!ttl)
{
@ -410,6 +630,7 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
err = new_data (data, &r->pw);
if (err)
log_error ("error replacing cache item: %s\n", gpg_strerror (err));
update_expiration (r, 0);
}
}
else if (data) /* Insert. */
@ -431,6 +652,7 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
{
r->next = thecache;
thecache = r;
update_expiration (r, 1);
}
}
if (err)
@ -478,7 +700,6 @@ agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
log_debug ("agent_get_cache '%s'.%d (mode %d)%s ...\n",
key, restricted, cache_mode,
last_stored? " (stored cache key)":"");
housekeeping ();
for (r=thecache; r; r = r->next)
{
@ -500,7 +721,10 @@ agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
* below. Note also that we don't update the accessed time
* for data items. */
if (r->cache_mode != CACHE_MODE_DATA)
r->accessed = gnupg_get_time ();
{
r->accessed = gnupg_get_time ();
update_expiration (r, 0);
}
if (DBG_CACHE)
log_debug ("... hit\n");
if (r->pw->totallen < 32)

View File

@ -98,7 +98,6 @@ static npth_mutex_t start_daemon_lock;
struct wait_child_thread_parm_s
{
enum daemon_type type;
pid_t pid;
};
@ -109,52 +108,14 @@ wait_child_thread (void *arg)
int err;
struct wait_child_thread_parm_s *parm = arg;
enum daemon_type type = parm->type;
pid_t pid = parm->pid;
#ifndef HAVE_W32_SYSTEM
int wstatus;
#endif
const char *name = opt.daemon_program[type];
struct daemon_global_s *g = &daemon_global[type];
struct daemon_local_s *sl;
xfree (parm); /* We have copied all data to the stack. */
#ifdef HAVE_W32_SYSTEM
npth_unprotect ();
/* Note that although we use a pid_t here, it is actually a HANDLE. */
WaitForSingleObject ((HANDLE)pid, INFINITE);
npth_protect ();
assuan_pipe_wait_server_termination (g->primary_ctx, NULL, 0);
log_info ("daemon %s finished\n", name);
#else /* !HAVE_W32_SYSTEM*/
again:
npth_unprotect ();
err = waitpid (pid, &wstatus, 0);
npth_protect ();
if (err < 0)
{
if (errno == EINTR)
goto again;
log_error ("waitpid for %s failed: %s\n", name, strerror (errno));
return NULL;
}
else
{
if (WIFEXITED (wstatus))
log_info ("daemon %s finished (status %d)\n",
name, WEXITSTATUS (wstatus));
else if (WIFSIGNALED (wstatus))
log_info ("daemon %s killed by signal %d\n", name, WTERMSIG (wstatus));
else
{
if (WIFSTOPPED (wstatus))
log_info ("daemon %s stopped by signal %d\n",
name, WSTOPSIG (wstatus));
goto again;
}
}
#endif /*!HAVE_W32_SYSTEM*/
agent_flush_cache (1); /* Flush the PIN cache. */
@ -166,8 +127,6 @@ wait_child_thread (void *arg)
}
else
{
assuan_set_flag (g->primary_ctx, ASSUAN_NO_WAITPID, 1);
for (sl = g->local_list; sl; sl = sl->next_local)
{
sl->invalid = 1;
@ -471,8 +430,8 @@ daemon_start (enum daemon_type type, ctrl_t ctrl)
char buf[100];
#ifdef HAVE_W32_SYSTEM
snprintf (buf, sizeof buf, "OPTION event-signal=%lx",
(unsigned long)get_agent_daemon_notify_event ());
snprintf (buf, sizeof buf, "OPTION event-signal=%p",
get_agent_daemon_notify_event ());
#else
snprintf (buf, sizeof buf, "OPTION event-signal=%d", SIGUSR2);
#endif
@ -496,7 +455,6 @@ daemon_start (enum daemon_type type, ctrl_t ctrl)
}
wctp->type = type;
wctp->pid = assuan_get_pid (g->primary_ctx);
err = npth_attr_init (&tattr);
if (!err)
{
@ -561,10 +519,9 @@ agent_daemon_dump_state (void)
for (i = 0; i < DAEMON_MAX_TYPE; i++) {
struct daemon_global_s *g = &daemon_global[i];
log_info ("%s: name %s primary_ctx=%p pid=%ld reusable=%d\n", __func__,
log_info ("%s: name %s primary_ctx=%p reusable=%d\n", __func__,
gnupg_module_name (daemon_modules[i]),
g->primary_ctx,
(long)assuan_get_pid (g->primary_ctx),
g->primary_ctx_reusable);
if (g->socket_name)
log_info ("%s: socket='%s'\n", __func__, g->socket_name);

View File

@ -128,8 +128,9 @@ initialize_module_call_pinentry (void)
void
agent_query_dump_state (void)
{
log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
entry_ctx, (long)assuan_get_pid (entry_ctx), (void*)popup_tid);
log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%lx\n",
entry_ctx, (long)assuan_get_pid (entry_ctx),
(unsigned long)popup_tid);
}
/* Called to make sure that a popup window owned by the current
@ -174,6 +175,7 @@ unlock_pinentry (ctrl_t ctrl, gpg_error_t rc)
case GPG_ERR_NO_PASSPHRASE:
case GPG_ERR_BAD_PASSPHRASE:
case GPG_ERR_BAD_PIN:
case GPG_ERR_BAD_RESET_CODE:
break;
case GPG_ERR_CORRUPTED_PROTECTION:
@ -1287,8 +1289,6 @@ build_cmd_setdesc (char *line, size_t linelen, const char *desc)
static void *
watch_sock (void *arg)
{
pid_t pid = assuan_get_pid (entry_ctx);
while (1)
{
int err;
@ -1301,7 +1301,7 @@ watch_sock (void *arg)
FD_ZERO (&fdset);
FD_SET (FD2INT (sock), &fdset);
err = npth_select (FD2INT (sock)+1, &fdset, NULL, NULL, &timeout);
err = npth_select (FD2NUM (sock)+1, &fdset, NULL, NULL, &timeout);
if (err < 0)
{
@ -1316,17 +1316,7 @@ watch_sock (void *arg)
break;
}
if (pid == (pid_t)(-1))
; /* No pid available can't send a kill. */
#ifdef HAVE_W32_SYSTEM
/* Older versions of assuan set PID to 0 on Windows to indicate an
invalid value. */
else if (pid != (pid_t) INVALID_HANDLE_VALUE && pid != 0)
TerminateProcess ((HANDLE)pid, 1);
#else
else if (pid > 0)
kill (pid, SIGINT);
#endif
assuan_pipe_kill_server (entry_ctx);
return NULL;
}
@ -1621,12 +1611,13 @@ agent_askpin (ctrl_t ctrl,
&& (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
return unlock_pinentry (ctrl, rc);
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE)
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN
|| gpg_err_code (rc) == GPG_ERR_BAD_RESET_CODE)
{
if (pininfo->cb_errtext)
errtext = pininfo->cb_errtext;
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
else
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
}
else if (rc)
@ -1894,12 +1885,13 @@ agent_get_passphrase (ctrl_t ctrl,
if (rc && (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
return unlock_pinentry (ctrl, rc);
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE)
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN
|| gpg_err_code (rc) == GPG_ERR_BAD_RESET_CODE)
{
if (pininfo->cb_errtext)
errtext = pininfo->cb_errtext;
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
else
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
}
else if (rc)
@ -2121,7 +2113,6 @@ void
agent_popup_message_stop (ctrl_t ctrl)
{
int rc;
pid_t pid;
(void)ctrl;
@ -2134,26 +2125,10 @@ agent_popup_message_stop (ctrl_t ctrl)
return;
}
pid = assuan_get_pid (entry_ctx);
if (pid == (pid_t)(-1))
; /* No pid available can't send a kill. */
else if (popup_finished)
if (popup_finished)
; /* Already finished and ready for joining. */
#ifdef HAVE_W32_SYSTEM
/* Older versions of assuan set PID to 0 on Windows to indicate an
invalid value. */
else if (pid != (pid_t) INVALID_HANDLE_VALUE
&& pid != 0)
{
HANDLE process = (HANDLE) pid;
/* Arbitrary error code. */
TerminateProcess (process, 1);
}
#else
else if (pid > 0)
kill (pid, SIGINT);
#endif
else
assuan_pipe_kill_server (entry_ctx);
/* Now wait for the thread to terminate. */
rc = npth_join (popup_tid, NULL);

View File

@ -548,7 +548,8 @@ padding_info_cb (void *opaque, const char *line)
if ((s=has_leading_keyword (line, "PADDING")))
{
*r_padding = atoi (s);
if (r_padding)
*r_padding = atoi (s);
}
else if ((s=has_leading_keyword (line, "PINCACHE_PUT")))
err = handle_pincache_put (s);
@ -560,8 +561,8 @@ padding_info_cb (void *opaque, const char *line)
/* Decipher INDATA using the current card. Note that the returned
* value is not an s-expression but the raw data as returned by
* scdaemon. The padding information is stored at R_PADDING with -1
* for not known. DESC_TEXT is an additional parameter passed to
* GETPIN_CB. */
* for not known, when it's not NULL. DESC_TEXT is an additional
* parameter passed to GETPIN_CB. */
int
agent_card_pkdecrypt (ctrl_t ctrl,
const char *keyid,
@ -579,7 +580,8 @@ agent_card_pkdecrypt (ctrl_t ctrl,
size_t len;
*r_buf = NULL;
*r_padding = -1; /* Unknown. */
if (r_padding)
*r_padding = -1; /* Unknown. */
rc = start_scd (ctrl);
if (rc)
return rc;

View File

@ -2430,11 +2430,16 @@ card_key_available (ctrl_t ctrl, const struct card_key_info_s *keyinfo,
}
hex2bin (keyinfo->keygrip, grip, sizeof (grip));
if ( agent_key_available (grip) )
if (!ctrl->ephemeral_mode && agent_key_available (ctrl, grip) )
{
char *dispserialno;
/* (Shadow)-key is not available in our key storage. */
err = agent_write_shadow_key (grip, keyinfo->serialno,
keyinfo->idstr, pkbuf, 0);
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
keyinfo->keygrip);
err = agent_write_shadow_key (ctrl, grip, keyinfo->serialno,
keyinfo->idstr, pkbuf, 0, dispserialno);
xfree (dispserialno);
if (err)
{
xfree (pkbuf);
@ -3217,7 +3222,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
/* Check whether the key is already in our key storage. Don't do
anything then besides (re-)adding it to sshcontrol. */
if ( !agent_key_available (key_grip_raw) )
if ( !agent_key_available (ctrl, key_grip_raw) )
goto key_exists; /* Yes, key is available. */
err = ssh_key_extract_comment (key, &comment);
@ -3281,8 +3286,8 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
/* Store this key to our key storage. We do not store a creation
* timestamp because we simply do not know. */
err = agent_write_private_key (key_grip_raw, buffer, buffer_n, 0,
NULL, NULL, 0);
err = agent_write_private_key (ctrl, key_grip_raw, buffer, buffer_n, 0,
NULL, NULL, NULL, 0);
if (err)
goto out;
@ -3947,7 +3952,11 @@ start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
es_syshd_t syshd;
syshd.type = ES_SYSHD_SOCK;
#ifdef HAVE_SOCKET
syshd.u.sock = (SOCKET)sock_client;
#else
syshd.u.sock = sock_client;
#endif
get_client_info (sock_client, &peer_info);
ctrl->client_pid = peer_info.pid;

View File

@ -241,7 +241,7 @@ reset_notify (assuan_context_t ctx, char *line)
(void) line;
memset (ctrl->keygrip, 0, 20);
ctrl->have_keygrip = 0;
ctrl->have_keygrip = ctrl->have_keygrip1 = 0;
ctrl->digest.valuelen = 0;
xfree (ctrl->digest.data);
ctrl->digest.data = NULL;
@ -251,6 +251,9 @@ reset_notify (assuan_context_t ctx, char *line)
clear_nonce_cache (ctrl);
/* Note that a RESET does not clear the ephemeral store becuase
* clients are used to issue a RESET on a connection. */
return 0;
}
@ -634,34 +637,65 @@ cmd_marktrusted (assuan_context_t ctx, char *line)
static const char hlp_havekey[] =
"HAVEKEY <hexstrings_with_keygrips>\n"
"HAVEKEY --list[=<limit>]\n"
"HAVEKEY --info <hexkeygrip>\n"
"\n"
"Return success if at least one of the secret keys with the given\n"
"keygrips is available. With --list return all available keygrips\n"
"as binary data; with <limit> bail out at this number of keygrips";
"as binary data; with <limit> bail out at this number of keygrips.\n"
"In --info mode check just one keygrip.";
static gpg_error_t
cmd_havekey (assuan_context_t ctx, char *line)
{
ctrl_t ctrl;
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
unsigned char grip[20];
char *p;
int list_mode; /* Less than 0 for no limit. */
int list_mode = 0; /* Less than 0 for no limit. */
int info_mode = 0;
int counter;
char *dirname;
gnupg_dir_t dir;
char *dirname = NULL;
gnupg_dir_t dir = NULL;
gnupg_dirent_t dir_entry;
char hexgrip[41];
struct card_key_info_s *keyinfo_on_cards, *l;
if (has_option_name (line, "--list"))
if (has_option (line, "--info"))
info_mode = 1;
else if (has_option_name (line, "--list"))
{
if ((p = option_value (line, "--list")))
list_mode = atoi (p);
else
list_mode = -1;
}
else
list_mode = 0;
line = skip_options (line);
if (info_mode)
{
int keytype;
const char *infostring;
err = parse_keygrip (ctx, line, grip);
if (err)
goto leave;
err = agent_key_info_from_file (ctrl, grip, &keytype, NULL, NULL);
if (err)
goto leave;
switch (keytype)
{
case PRIVATE_KEY_CLEAR:
case PRIVATE_KEY_OPENPGP_NONE: infostring = "clear"; break;
case PRIVATE_KEY_PROTECTED: infostring = "protected"; break;
case PRIVATE_KEY_SHADOWED: infostring = "shadowed"; break;
default: infostring = "unknown"; break;
}
err = agent_write_status (ctrl, "KEYFILEINFO", infostring, NULL);
goto leave;
}
if (!list_mode)
@ -672,7 +706,7 @@ cmd_havekey (assuan_context_t ctx, char *line)
if (err)
return err;
if (!agent_key_available (grip))
if (!agent_key_available (ctrl, grip))
return 0; /* Found. */
while (*line && *line != ' ' && *line != '\t')
@ -690,7 +724,6 @@ cmd_havekey (assuan_context_t ctx, char *line)
/* List mode. */
dir = NULL;
dirname = NULL;
ctrl = assuan_get_pointer (ctx);
if (ctrl->restricted)
{
@ -763,8 +796,8 @@ cmd_havekey (assuan_context_t ctx, char *line)
static const char hlp_sigkey[] =
"SIGKEY <hexstring_with_keygrip>\n"
"SETKEY <hexstring_with_keygrip>\n"
"SIGKEY [--another] <hexstring_with_keygrip>\n"
"SETKEY [--another] <hexstring_with_keygrip>\n"
"\n"
"Set the key used for a sign or decrypt operation.";
static gpg_error_t
@ -772,11 +805,17 @@ cmd_sigkey (assuan_context_t ctx, char *line)
{
int rc;
ctrl_t ctrl = assuan_get_pointer (ctx);
int opt_another;
rc = parse_keygrip (ctx, line, ctrl->keygrip);
opt_another = has_option (line, "--another");
line = skip_options (line);
rc = parse_keygrip (ctx, line, opt_another? ctrl->keygrip1 : ctrl->keygrip);
if (rc)
return rc;
ctrl->have_keygrip = 1;
if (opt_another)
ctrl->have_keygrip1 = 1;
else
ctrl->have_keygrip = 1;
return 0;
}
@ -1010,10 +1049,14 @@ cmd_pksign (assuan_context_t ctx, char *line)
static const char hlp_pkdecrypt[] =
"PKDECRYPT [<options>]\n"
"PKDECRYPT [--kem[=<kemid>] [<options>]\n"
"\n"
"Perform the actual decrypt operation. Input is not\n"
"sensitive to eavesdropping.";
"sensitive to eavesdropping.\n"
"If the --kem option is used, decryption is done with the KEM,\n"
"inquiring upper-layer option, when needed. KEMID can be\n"
"specified with --kem option; Valid value is: PQC-PGP, PGP, or CMS.\n"
"Default is PQC-PGP.";
static gpg_error_t
cmd_pkdecrypt (assuan_context_t ctx, char *line)
{
@ -1022,22 +1065,52 @@ cmd_pkdecrypt (assuan_context_t ctx, char *line)
unsigned char *value;
size_t valuelen;
membuf_t outbuf;
int padding;
int padding = -1;
unsigned char *option = NULL;
size_t optionlen = 0;
const char *p;
int kemid = -1;
(void)line;
p = has_option_name (line, "--kem");
if (p)
{
kemid = KEM_PQC_PGP;
if (*p == '=')
{
p++;
if (!strcmp (p, "PQC-PGP"))
kemid = KEM_PQC_PGP;
else if (!strcmp (p, "PGP"))
kemid = KEM_PGP;
else if (!strcmp (p, "CMS"))
kemid = KEM_CMS;
else
return set_error (GPG_ERR_ASS_PARAMETER, "invalid KEM algorithm");
}
}
/* First inquire the data to decrypt */
rc = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u", MAXLEN_CIPHERTEXT);
if (!rc)
rc = assuan_inquire (ctx, "CIPHERTEXT",
&value, &valuelen, MAXLEN_CIPHERTEXT);
if (!rc && kemid > KEM_PQC_PGP)
rc = assuan_inquire (ctx, "OPTION",
&option, &optionlen, MAXLEN_CIPHERTEXT);
if (rc)
return rc;
init_membuf (&outbuf, 512);
rc = agent_pkdecrypt (ctrl, ctrl->server_local->keydesc,
value, valuelen, &outbuf, &padding);
if (kemid < 0)
rc = agent_pkdecrypt (ctrl, ctrl->server_local->keydesc,
value, valuelen, &outbuf, &padding);
else
{
rc = agent_kem_decrypt (ctrl, ctrl->server_local->keydesc, kemid,
value, valuelen, option, optionlen, &outbuf);
xfree (option);
}
xfree (value);
if (rc)
clear_outbuf (&outbuf);
@ -1083,26 +1156,27 @@ cmd_genkey (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
int no_protection;
unsigned char *value = NULL;
size_t valuelen;
unsigned char *newpasswd = NULL;
membuf_t outbuf;
char *cache_nonce = NULL;
char *passwd_nonce = NULL;
int opt_preset;
int opt_inq_passwd;
size_t n;
char *p, *pend;
const char *s;
time_t opt_timestamp;
int c;
unsigned int flags = 0;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
no_protection = has_option (line, "--no-protection");
opt_preset = has_option (line, "--preset");
if (has_option (line, "--no-protection"))
flags |= GENKEY_FLAG_NO_PROTECTION;
if (has_option (line, "--preset"))
flags |= GENKEY_FLAG_PRESET;
opt_inq_passwd = has_option (line, "--inq-passwd");
passwd_nonce = option_value (line, "--passwd-nonce");
if (passwd_nonce)
@ -1157,7 +1231,7 @@ cmd_genkey (assuan_context_t ctx, char *line)
/* If requested, ask for the password to be used for the key. If
this is not used the regular Pinentry mechanism is used. */
if (opt_inq_passwd && !no_protection)
if (opt_inq_passwd && !(flags & GENKEY_FLAG_NO_PROTECTION))
{
/* (N is used as a dummy) */
assuan_begin_confidential (ctx);
@ -1170,16 +1244,17 @@ cmd_genkey (assuan_context_t ctx, char *line)
/* Empty password given - switch to no-protection mode. */
xfree (newpasswd);
newpasswd = NULL;
no_protection = 1;
flags |= GENKEY_FLAG_NO_PROTECTION;
}
}
else if (passwd_nonce)
newpasswd = agent_get_cache (ctrl, passwd_nonce, CACHE_MODE_NONCE);
rc = agent_genkey (ctrl, cache_nonce, opt_timestamp,
(char*)value, valuelen, no_protection,
newpasswd, opt_preset, &outbuf);
rc = agent_genkey (ctrl, flags, cache_nonce, opt_timestamp,
(char*)value, valuelen,
newpasswd, &outbuf);
leave:
if (newpasswd)
@ -1283,7 +1358,7 @@ cmd_keyattr (assuan_context_t ctx, char *line)
if (!err)
err = nvc_set_private_key (keymeta, s_key);
if (!err)
err = agent_update_private_key (grip, keymeta);
err = agent_update_private_key (ctrl, grip, keymeta);
}
nvc_release (keymeta);
@ -1293,6 +1368,8 @@ cmd_keyattr (assuan_context_t ctx, char *line)
leave:
return leave_cmd (ctx, err);
}
static const char hlp_readkey[] =
"READKEY [--no-data] [--format=ssh] <hexstring_with_keygrip>\n"
@ -1356,10 +1433,17 @@ cmd_readkey (assuan_context_t ctx, char *line)
goto leave;
}
if (agent_key_available (grip))
if (!ctrl->ephemeral_mode && agent_key_available (ctrl, grip))
{
/* (Shadow)-key is not available in our key storage. */
rc = agent_write_shadow_key (grip, serialno, keyid, pkbuf, 0);
char *dispserialno;
char hexgrip[40+1];
bin2hex (grip, 20, hexgrip);
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno, hexgrip);
rc = agent_write_shadow_key (ctrl, grip, serialno, keyid, pkbuf, 0,
dispserialno);
xfree (dispserialno);
if (rc)
goto leave;
}
@ -1374,7 +1458,9 @@ cmd_readkey (assuan_context_t ctx, char *line)
goto leave;
rc = agent_public_key_from_file (ctrl, grip, &s_pkey);
if (!rc)
if (rc)
goto leave;
else
{
if (opt_format_ssh)
{
@ -1944,9 +2030,6 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
struct pin_entry_info_s *pi2 = NULL;
int is_generated;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
opt_data = has_option (line, "--data");
opt_check = has_option (line, "--check");
opt_no_ask = has_option (line, "--no-ask");
@ -1995,7 +2078,9 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
if (!desc)
return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
if (!strcmp (cacheid, "X"))
/* The only limitation in restricted mode is that we don't consider
* the cache. */
if (ctrl->restricted || !strcmp (cacheid, "X"))
cacheid = NULL;
if (!strcmp (errtext, "X"))
errtext = NULL;
@ -2077,7 +2162,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
entry_errtext = NULL;
is_generated = !!(pi->status & PINENTRY_STATUS_PASSWORD_GENERATED);
/* We don't allow an empty passpharse in this mode. */
/* We don't allow an empty passphrase in this mode. */
if (!is_generated
&& check_passphrase_constraints (ctrl, pi->pin,
pi->constraints_flags,
@ -2893,7 +2978,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
}
else
{
if (!force && !agent_key_available (grip))
if (!force && !agent_key_available (ctrl, grip))
err = gpg_error (GPG_ERR_EEXIST);
else
{
@ -2915,12 +3000,12 @@ cmd_import_key (assuan_context_t ctx, char *line)
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
ctrl->s2k_count);
if (!err)
err = agent_write_private_key (grip, finalkey, finalkeylen, force,
NULL, NULL, opt_timestamp);
err = agent_write_private_key (ctrl, grip, finalkey, finalkeylen, force,
NULL, NULL, NULL, opt_timestamp);
}
else
err = agent_write_private_key (grip, key, realkeylen, force, NULL, NULL,
opt_timestamp);
err = agent_write_private_key (ctrl, grip, key, realkeylen, force,
NULL, NULL, NULL, opt_timestamp);
leave:
gcry_sexp_release (openpgp_sexp);
@ -2938,7 +3023,8 @@ cmd_import_key (assuan_context_t ctx, char *line)
static const char hlp_export_key[] =
"EXPORT_KEY [--cache-nonce=<nonce>] [--openpgp|--mode1003] <hexkeygrip>\n"
"EXPORT_KEY [--cache-nonce=<nonce>] \\\n"
" [--openpgp|--mode1003] <hexkeygrip>\n"
"\n"
"Export a secret key from the key store. The key will be encrypted\n"
"using the current session's key wrapping key (cf. command KEYWRAP_KEY)\n"
@ -2946,8 +3032,8 @@ static const char hlp_export_key[] =
"prior to using this command. The function takes the keygrip as argument.\n"
"\n"
"If --openpgp is used, the secret key material will be exported in RFC 4880\n"
"compatible passphrase-protected form. If --mode1003 is use the secret key\n"
"is exported as s-expression as storred locally. Without those options,\n"
"compatible passphrase-protected form. In --mode1003 the secret key\n"
"is exported as s-expression as stored locally. Without those options,\n"
"the secret key material will be exported in the clear (after prompting\n"
"the user to unlock it, if needed).\n";
static gpg_error_t
@ -3004,7 +3090,7 @@ cmd_export_key (assuan_context_t ctx, char *line)
if (err)
goto leave;
if (agent_key_available (grip))
if (agent_key_available (ctrl, grip))
{
err = gpg_error (GPG_ERR_NO_SECKEY);
goto leave;
@ -3216,9 +3302,9 @@ cmd_keytocard (assuan_context_t ctx, char *line)
if (err)
goto leave;
if (agent_key_available (grip))
if (agent_key_available (ctrl, grip))
{
err =gpg_error (GPG_ERR_NO_SECKEY);
err = gpg_error (GPG_ERR_NO_SECKEY);
goto leave;
}
@ -3536,7 +3622,7 @@ cmd_keytotpm (assuan_context_t ctx, char *line)
if (err)
goto leave;
if (agent_key_available (grip))
if (agent_key_available (ctrl, grip))
{
err =gpg_error (GPG_ERR_NO_SECKEY);
goto leave;
@ -3828,6 +3914,7 @@ static const char hlp_getinfo[] =
" getenv NAME - Return value of envvar NAME.\n"
" connections - Return number of active connections.\n"
" jent_active - Returns OK if Libgcrypt's JENT is active.\n"
" ephemeral - Returns OK if the connection is in ephemeral mode.\n"
" restricted - Returns OK if the connection is in restricted mode.\n"
" cmd_has_option CMD OPT\n"
" - Returns OK if command CMD has option OPT.\n";
@ -3881,6 +3968,10 @@ cmd_getinfo (assuan_context_t ctx, char *line)
snprintf (numbuf, sizeof numbuf, "%lu", get_standard_s2k_count ());
rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
}
else if (!strcmp (line, "ephemeral"))
{
rc = ctrl->ephemeral_mode? 0 : gpg_error (GPG_ERR_FALSE);
}
else if (!strcmp (line, "restricted"))
{
rc = ctrl->restricted? 0 : gpg_error (GPG_ERR_FALSE);
@ -4037,6 +4128,10 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
ctrl->server_local->allow_fully_canceled =
gnupg_compare_version (value, "2.1.0");
}
else if (!strcmp (key, "ephemeral"))
{
ctrl->ephemeral_mode = *value? atoi (value) : 0;
}
else if (ctrl->restricted)
{
err = gpg_error (GPG_ERR_FORBIDDEN);

View File

@ -969,7 +969,7 @@ convert_from_openpgp_main (ctrl_t ctrl, gcry_sexp_t s_pgp, int dontcare_exist,
if (err)
goto leave;
if (!dontcare_exist && !from_native && !agent_key_available (grip))
if (!dontcare_exist && !from_native && !agent_key_available (ctrl, grip))
{
err = gpg_error (GPG_ERR_EEXIST);
goto leave;
@ -1147,17 +1147,19 @@ convert_from_openpgp_native (ctrl_t ctrl,
if (!agent_protect (*r_key, passphrase,
&protectedkey, &protectedkeylen,
ctrl->s2k_count))
agent_write_private_key (grip, protectedkey, protectedkeylen, 1,
NULL, NULL, 0);
agent_write_private_key (ctrl, grip,
protectedkey,
protectedkeylen,
1, NULL, NULL, NULL, 0);
xfree (protectedkey);
}
else
{
/* Empty passphrase: write key without protection. */
agent_write_private_key (grip,
agent_write_private_key (ctrl, grip,
*r_key,
gcry_sexp_canon_len (*r_key, 0, NULL,NULL),
1, NULL, NULL, 0);
1, NULL, NULL, NULL, 0);
}
}
@ -1382,6 +1384,17 @@ extract_private_key (gcry_sexp_t s_key, int req_private_key_data,
err = gcry_sexp_extract_param (list, NULL, format,
array+0, array+1, NULL);
}
else if ( !strcmp (name, (algoname = "kyber512"))
|| !strcmp (name, (algoname = "kyber768"))
|| !strcmp (name, (algoname = "kyber1024")))
{
format = "/ps?";
elems = "ps?";
npkey = 1;
nskey = 2;
err = gcry_sexp_extract_param (list, NULL, format,
array+0, array+1, NULL);
}
else
{
err = gpg_error (GPG_ERR_PUBKEY_ALGO);

View File

@ -377,10 +377,10 @@ divert_pksign (ctrl_t ctrl, const unsigned char *grip,
}
/* Decrypt the value given asn an S-expression in CIPHER using the
/* Decrypt the value given as an s-expression in CIPHER using the
key identified by SHADOW_INFO and return the plaintext in an
allocated buffer in R_BUF. The padding information is stored at
R_PADDING with -1 for not known. */
R_PADDING with -1 for not known, when it's not NULL. */
int
divert_pkdecrypt (ctrl_t ctrl,
const unsigned char *grip,
@ -399,7 +399,8 @@ divert_pkdecrypt (ctrl_t ctrl,
bin2hex (grip, 20, hexgrip);
*r_padding = -1;
if (r_padding)
*r_padding = -1;
s = cipher;
if (*s != '(')
return gpg_error (GPG_ERR_INV_SEXP);
@ -485,6 +486,34 @@ divert_pkdecrypt (ctrl_t ctrl,
return rc;
}
gpg_error_t
agent_card_ecc_kem (ctrl_t ctrl, const unsigned char *ecc_ct,
size_t ecc_point_len, unsigned char *ecc_ecdh)
{
gpg_error_t err = 0;
char *ecdh = NULL;
size_t len;
int rc;
rc = agent_card_pkdecrypt (ctrl, ctrl->keygrip, getpin_cb, ctrl, NULL,
ecc_ct, ecc_point_len, &ecdh, &len, NULL);
if (rc)
return rc;
if (len != ecc_point_len)
{
if (opt.verbose)
log_info ("%s: ECC result length invalid (%zu != %zu)\n",
__func__, len, ecc_point_len);
return gpg_error (GPG_ERR_INV_DATA);
}
else
memcpy (ecc_ecdh, ecdh, len);
xfree (ecdh);
return err;
}
gpg_error_t
divert_writekey (ctrl_t ctrl, int force, const char *serialno,

View File

@ -26,9 +26,10 @@ divert_tpm2_pksign (ctrl_t ctrl,
static gpg_error_t
agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip,
unsigned char *shadow_info)
unsigned char *shadow_info,
gcry_sexp_t s_key)
{
gpg_error_t err;
gpg_error_t err, err1;
unsigned char *shdkey;
unsigned char *pkbuf;
size_t len;
@ -44,16 +45,38 @@ agent_write_tpm2_shadow_key (ctrl_t ctrl, const unsigned char *grip,
xfree (pkbuf);
if (err)
{
log_error ("shadowing the key failed: %s\n", gpg_strerror (err));
log_error ("shadowing the tpm key failed: %s\n", gpg_strerror (err));
return err;
}
err = agent_delete_key (ctrl, NULL, grip, 1, 0);
if (err)
{
log_error ("failed to delete unshadowed key: %s\n", gpg_strerror (err));
return err;
}
len = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
err = agent_write_private_key (grip, shdkey, len, 1 /*force*/,
NULL, NULL, 0);
err = agent_write_private_key (ctrl, grip, shdkey, len, 1 /*force*/,
NULL, NULL, NULL, 0);
xfree (shdkey);
if (err)
log_error ("error writing key: %s\n", gpg_strerror (err));
{
log_error ("error writing tpm key: %s\n", gpg_strerror (err));
len = gcry_sexp_sprint(s_key, GCRYSEXP_FMT_CANON, NULL, 0);
pkbuf = xtrymalloc(len);
if (!pkbuf)
return GPG_ERR_ENOMEM;
gcry_sexp_sprint(s_key, GCRYSEXP_FMT_CANON, pkbuf, len);
err1 = agent_write_private_key (ctrl, grip, pkbuf, len, 1 /*force*/,
NULL, NULL, NULL, 0);
xfree(pkbuf);
if (err1)
log_error ("error trying to restore private key: %s\n",
gpg_strerror (err1));
}
return err;
}
@ -68,7 +91,7 @@ divert_tpm2_writekey (ctrl_t ctrl, const unsigned char *grip,
ret = agent_tpm2d_writekey(ctrl, &shadow_info, s_skey);
if (!ret) {
ret = agent_write_tpm2_shadow_key (ctrl, grip, shadow_info);
ret = agent_write_tpm2_shadow_key (ctrl, grip, shadow_info, s_skey);
xfree (shadow_info);
}
return ret;
@ -83,7 +106,8 @@ divert_tpm2_pkdecrypt (ctrl_t ctrl,
const unsigned char *s;
size_t n;
*r_padding = -1;
if (r_padding)
*r_padding = -1;
s = cipher;
if (*s != '(')
@ -102,7 +126,8 @@ divert_tpm2_pkdecrypt (ctrl_t ctrl,
return gpg_error (GPG_ERR_INV_SEXP);
if (smatch (&s, n, "rsa"))
{
*r_padding = 0;
if (r_padding)
*r_padding = 0;
if (*s != '(')
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
s++;

File diff suppressed because it is too large Load Diff

View File

@ -30,14 +30,36 @@
#include "../common/exechelp.h"
#include "../common/sysutils.h"
static int
store_key (gcry_sexp_t private, const char *passphrase, int force,
void
clear_ephemeral_keys (ctrl_t ctrl)
{
while (ctrl->ephemeral_keys)
{
ephemeral_private_key_t next = ctrl->ephemeral_keys->next;
if (ctrl->ephemeral_keys->keybuf)
{
wipememory (ctrl->ephemeral_keys->keybuf,
ctrl->ephemeral_keys->keybuflen);
xfree (ctrl->ephemeral_keys->keybuf);
}
xfree (ctrl->ephemeral_keys);
ctrl->ephemeral_keys = next;
}
}
/* Store the key either to a file, or in ctrl->ephemeral_mode in the
* session data. */
static gpg_error_t
store_key (ctrl_t ctrl, gcry_sexp_t private,
const char *passphrase, int force,
unsigned long s2k_count, time_t timestamp)
{
int rc;
gpg_error_t err;
unsigned char *buf;
size_t len;
unsigned char grip[20];
unsigned char grip[KEYGRIP_LEN];
if ( !gcry_pk_get_keygrip (private, grip) )
{
@ -49,7 +71,10 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
log_assert (len);
buf = gcry_malloc_secure (len);
if (!buf)
return out_of_core ();
{
err = gpg_error_from_syserror ();
goto leave;
}
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
log_assert (len);
@ -57,19 +82,56 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
{
unsigned char *p;
rc = agent_protect (buf, passphrase, &p, &len, s2k_count);
if (rc)
{
xfree (buf);
return rc;
}
err = agent_protect (buf, passphrase, &p, &len, s2k_count);
if (err)
goto leave;
xfree (buf);
buf = p;
}
rc = agent_write_private_key (grip, buf, len, force, NULL, NULL, timestamp);
if (ctrl->ephemeral_mode)
{
ephemeral_private_key_t ek;
for (ek = ctrl->ephemeral_keys; ek; ek = ek->next)
if (!memcmp (ek->grip, grip, KEYGRIP_LEN))
break;
if (!ek)
{
ek = xtrycalloc (1, sizeof *ek);
if (!ek)
{
err = gpg_error_from_syserror ();
goto leave;
}
memcpy (ek->grip, grip, KEYGRIP_LEN);
ek->next = ctrl->ephemeral_keys;
ctrl->ephemeral_keys = ek;
}
if (ek->keybuf)
{
wipememory (ek->keybuf, ek->keybuflen);
xfree (ek->keybuf);
}
ek->keybuf = buf;
buf = NULL;
ek->keybuflen = len;
}
else
err = agent_write_private_key (ctrl, grip, buf, len, force,
NULL, NULL, NULL, timestamp);
if (!err)
{
char hexgrip[2*KEYGRIP_LEN+1];
bin2hex (grip, KEYGRIP_LEN, hexgrip);
agent_write_status (ctrl, "KEYGRIP", hexgrip, NULL);
}
leave:
xfree (buf);
return rc;
return err;
}
@ -99,7 +161,7 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
const char *pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CHECK_PATTERN);
estream_t stream_to_check_pattern = NULL;
const char *argv[10];
pid_t pid;
gnupg_process_t proc;
int result, i;
const char *pattern;
char *patternfname;
@ -142,11 +204,17 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
argv[i] = NULL;
log_assert (i < sizeof argv);
if (gnupg_spawn_process (pgmname, argv, NULL, 0,
&stream_to_check_pattern, NULL, NULL, &pid))
if (gnupg_process_spawn (pgmname, argv,
GNUPG_PROCESS_STDIN_PIPE,
NULL, NULL, &proc))
result = 1; /* Execute error - assume password should no be used. */
else
{
int status;
gnupg_process_get_streams (proc, 0, &stream_to_check_pattern,
NULL, NULL);
es_set_binary (stream_to_check_pattern);
if (es_fwrite (pw, strlen (pw), 1, stream_to_check_pattern) != 1)
{
@ -157,11 +225,13 @@ do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
else
es_fflush (stream_to_check_pattern);
es_fclose (stream_to_check_pattern);
if (gnupg_wait_process (pgmname, pid, 1, NULL))
gnupg_process_wait (proc, 1);
gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &status);
if (status)
result = 1; /* Helper returned an error - probably a match. */
else
result = 0; /* Success; i.e. no match. */
gnupg_release_process (pid);
gnupg_process_release (proc);
}
xfree (patternfname);
@ -449,16 +519,19 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
/* Generate a new keypair according to the parameters given in
KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase
using the cache nonce. If NO_PROTECTION is true the key will not
be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
passphrase will be used for the new key. If TIMESTAMP is not zero
it will be recorded as creation date of the key (unless extended
format is disabled) . */
* KEYPARAM. If CACHE_NONCE is given first try to lookup a passphrase
* using the cache nonce. If NO_PROTECTION is true the key will not
* be protected by a passphrase. If OVERRIDE_PASSPHRASE is true that
* passphrase will be used for the new key. If TIMESTAMP is not zero
* it will be recorded as creation date of the key (unless extended
* format is disabled). In ctrl_ephemeral_mode the key is stored in
* the session data and an identifier is returned using a status
* line. */
int
agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
const char *keyparam, size_t keyparamlen, int no_protection,
const char *override_passphrase, int preset, membuf_t *outbuf)
agent_genkey (ctrl_t ctrl, unsigned int flags,
const char *cache_nonce, time_t timestamp,
const char *keyparam, size_t keyparamlen,
const char *override_passphrase, membuf_t *outbuf)
{
gcry_sexp_t s_keyparam, s_key, s_private, s_public;
char *passphrase_buffer = NULL;
@ -477,7 +550,7 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
/* Get the passphrase now, cause key generation may take a while. */
if (override_passphrase)
passphrase = override_passphrase;
else if (no_protection || !cache_nonce)
else if ((flags & GENKEY_FLAG_NO_PROTECTION) || !cache_nonce)
passphrase = NULL;
else
{
@ -485,8 +558,8 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
passphrase = passphrase_buffer;
}
if (passphrase || no_protection)
;
if (passphrase || (flags & GENKEY_FLAG_NO_PROTECTION))
; /* No need to ask for a passphrase. */
else
{
rc = agent_ask_new_passphrase (ctrl,
@ -531,11 +604,14 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
gcry_sexp_release (s_key); s_key = NULL;
/* store the secret key */
if (DBG_CRYPTO)
log_debug ("storing private key\n");
rc = store_key (s_private, passphrase, 0, ctrl->s2k_count, timestamp);
if (!rc)
if (opt.verbose)
log_info ("storing %sprivate key\n",
ctrl->ephemeral_mode?"ephemeral ":"");
rc = store_key (ctrl, s_private, passphrase, 0, ctrl->s2k_count, timestamp);
if (!rc && !ctrl->ephemeral_mode)
{
/* FIXME: or does it make sense to also cache passphrases in
* ephemeral mode using a dedicated cache? */
if (!cache_nonce)
{
char tmpbuf[12];
@ -543,21 +619,23 @@ agent_genkey (ctrl_t ctrl, const char *cache_nonce, time_t timestamp,
cache_nonce = bin2hex (tmpbuf, 12, NULL);
}
if (cache_nonce
&& !no_protection
&& !(flags & GENKEY_FLAG_NO_PROTECTION)
&& !agent_put_cache (ctrl, cache_nonce, CACHE_MODE_NONCE,
passphrase, ctrl->cache_ttl_opt_preset))
agent_write_status (ctrl, "CACHE_NONCE", cache_nonce, NULL);
if (preset && !no_protection)
{
unsigned char grip[20];
char hexgrip[40+1];
if (gcry_pk_get_keygrip (s_private, grip))
{
bin2hex(grip, 20, hexgrip);
rc = agent_put_cache (ctrl, hexgrip, CACHE_MODE_ANY, passphrase,
if ((flags & GENKEY_FLAG_PRESET)
&& !(flags & GENKEY_FLAG_NO_PROTECTION))
{
unsigned char grip[20];
char hexgrip[40+1];
if (gcry_pk_get_keygrip (s_private, grip))
{
bin2hex(grip, 20, hexgrip);
rc = agent_put_cache (ctrl, hexgrip,
CACHE_MODE_ANY, passphrase,
ctrl->cache_ttl_opt_preset);
}
}
}
}
}
xfree (passphrase_buffer);
passphrase_buffer = NULL;
@ -606,7 +684,8 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
if (passphrase_addr && *passphrase_addr)
{
/* Take an empty string as request not to protect the key. */
err = store_key (s_skey, **passphrase_addr? *passphrase_addr:NULL, 1,
err = store_key (ctrl, s_skey,
**passphrase_addr? *passphrase_addr:NULL, 1,
ctrl->s2k_count, 0);
}
else
@ -622,7 +701,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey,
L_("Please enter the new passphrase"),
&pass);
if (!err)
err = store_key (s_skey, pass, 1, ctrl->s2k_count, 0);
err = store_key (ctrl, s_skey, pass, 1, ctrl->s2k_count, 0);
if (!err && passphrase_addr)
*passphrase_addr = pass;
else

View File

@ -48,3 +48,5 @@
VALUE "Translation", 0x409, 0x4b0
END
END
1 RT_MANIFEST "gpg-agent.w32-manifest"

View File

@ -341,15 +341,13 @@ static struct debug_flags_s debug_flags [] =
#define MIN_PASSPHRASE_NONALPHA (1)
#define MAX_PASSPHRASE_DAYS (0)
/* The timer tick used for housekeeping stuff. Note that on Windows
* we use a SetWaitableTimer seems to signal earlier than about 2
* seconds. Thus we use 4 seconds on all platforms.
* CHECK_OWN_SOCKET_INTERVAL defines how often we check
* our own socket in standard socket mode. If that value is 0 we
* don't check at all. All values are in seconds. */
#define TIMERTICK_INTERVAL (4)
/* CHECK_OWN_SOCKET_INTERVAL defines how often we check our own socket
* in standard socket mode. If that value is 0 we don't check at all.
* Values is in seconds. */
#define CHECK_OWN_SOCKET_INTERVAL (60)
/* CHECK_PROBLEMS_INTERVAL defines how often we check the existence of
* parent process and homedir. Value is in seconds. */
#define CHECK_PROBLEMS_INTERVAL (4)
/* Flag indicating that the ssh-agent subsystem has been enabled. */
static int ssh_support;
@ -366,7 +364,7 @@ static int putty_support;
/* Path to the pipe, which handles requests from Win32-OpenSSH. */
static const char *win32_openssh_support;
#define W32_DEFAILT_AGENT_PIPE_NAME "\\\\.\\pipe\\openssh-ssh-agent"
#define W32_DEFAULT_AGENT_PIPE_NAME "\\\\.\\pipe\\openssh-ssh-agent"
#endif /*HAVE_W32_SYSTEM*/
/* The list of open file descriptors at startup. Note that this list
@ -384,9 +382,6 @@ static int startup_signal_mask_valid;
/* Flag to indicate that a shutdown was requested. */
static int shutdown_pending;
/* Counter for the currently running own socket checks. */
static int check_own_socket_running;
/* Flags to indicate that check_own_socket shall not be called. */
static int disable_check_own_socket;
@ -396,6 +391,12 @@ static int is_supervised;
/* Flag indicating to start the daemon even if one already runs. */
static int steal_socket;
/* Flag to monitor problems. */
static int problem_detected;
#define AGENT_PROBLEM_SOCKET_TAKEOVER (1 << 0)
#define AGENT_PROBLEM_PARENT_HAS_GONE (1 << 1)
#define AGENT_PROBLEM_HOMEDIR_REMOVED (1 << 2)
/* Flag to inhibit socket removal in cleanup. */
static int inhibit_socket_removal;
@ -432,6 +433,17 @@ static assuan_sock_nonce_t socket_nonce_ssh;
* Let's try this as default. Change at runtime with --listen-backlog. */
static int listen_backlog = 64;
#ifdef HAVE_W32_SYSTEM
/* The event to break the select call. */
static HANDLE the_event2;
#elif defined(HAVE_PSELECT_NO_EINTR)
/* An FD to break the select call. */
static int event_pipe_fd;
#else
/* PID of the main thread. */
static pid_t main_thread_pid;
#endif
/* Default values for options passed to the pinentry. */
static char *default_display;
static char *default_ttyname;
@ -452,9 +464,14 @@ static const char *debug_level;
the log file after a SIGHUP if it didn't changed. Malloced. */
static char *current_logfile;
/* The handle_tick() function may test whether a parent is still
* running. We record the PID of the parent here or -1 if it should
* be watched. */
#ifdef HAVE_W32_SYSTEM
#define HAVE_PARENT_PID_SUPPORT 0
#else
#define HAVE_PARENT_PID_SUPPORT 1
#endif
/* The check_others_thread() function may test whether a parent is
* still running. We record the PID of the parent here or -1 if it
* should be watched. */
static pid_t parent_pid = (pid_t)(-1);
/* This flag is true if the inotify mechanism for detecting the
@ -462,11 +479,6 @@ static pid_t parent_pid = (pid_t)(-1);
* alternative but portable stat based check. */
static int have_homedir_inotify;
/* Depending on how gpg-agent was started, the homedir inotify watch
* may not be reliable. This flag is set if we assume that inotify
* works reliable. */
static int reliable_homedir_inotify;
/* Number of active connections. */
static int active_connections;
@ -516,13 +528,13 @@ static void agent_deinit_default_ctrl (ctrl_t ctrl);
static void handle_connections (gnupg_fd_t listen_fd,
gnupg_fd_t listen_fd_extra,
gnupg_fd_t listen_fd_browser,
gnupg_fd_t listen_fd_ssh);
static void check_own_socket (void);
gnupg_fd_t listen_fd_ssh,
int reliable_homedir_inotify);
static int check_for_running_agent (int silent);
/* Pth wrapper function definitions. */
ASSUAN_SYSTEM_NPTH_IMPL;
#if CHECK_OWN_SOCKET_INTERVAL > 0
static void *check_own_socket_thread (void *arg);
#endif
static void *check_others_thread (void *arg);
/*
Functions.
@ -864,6 +876,7 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.debug = 0;
opt.no_grab = 1;
opt.debug_pinentry = 0;
xfree (opt.pinentry_program);
opt.pinentry_program = NULL;
opt.pinentry_touch_file = NULL;
xfree (opt.pinentry_invisible_char);
@ -924,7 +937,10 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
case oNoGrab: opt.no_grab |= 1; break;
case oGrab: opt.no_grab |= 2; break;
case oPinentryProgram: opt.pinentry_program = pargs->r.ret_str; break;
case oPinentryProgram:
xfree (opt.pinentry_program);
opt.pinentry_program = make_filename_try (pargs->r.ret_str, NULL);
break;
case oPinentryTouchFile: opt.pinentry_touch_file = pargs->r.ret_str; break;
case oPinentryInvisibleChar:
xfree (opt.pinentry_invisible_char);
@ -1046,6 +1062,7 @@ thread_init_once (void)
* initialized and thus Libgcrypt could not set its system call
* clamp. */
gcry_control (GCRYCTL_REINIT_SYSCALL_CLAMP, 0, 0);
assuan_control (ASSUAN_CONTROL_REINIT_SYSCALL_CLAMP, NULL);
}
@ -1053,7 +1070,6 @@ static void
initialize_modules (void)
{
thread_init_once ();
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
initialize_module_cache ();
initialize_module_call_pinentry ();
initialize_module_daemon ();
@ -1081,6 +1097,7 @@ main (int argc, char **argv)
int gpgconf_list = 0;
gpg_error_t err;
struct assuan_malloc_hooks malloc_hooks;
int reliable_homedir_inotify = 1;
early_system_init ();
@ -1113,7 +1130,6 @@ main (int argc, char **argv)
assuan_set_malloc_hooks (&malloc_hooks);
assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
assuan_sock_init ();
assuan_sock_set_system_hooks (ASSUAN_SYSTEM_NPTH);
setup_libassuan_logging (&opt.debug, NULL);
setup_libgcrypt_logging ();
@ -1295,7 +1311,7 @@ main (int argc, char **argv)
if (pargs.r_type)
win32_openssh_support = pargs.r.ret_str;
else
win32_openssh_support = W32_DEFAILT_AGENT_PIPE_NAME;
win32_openssh_support = W32_DEFAULT_AGENT_PIPE_NAME;
# endif
break;
@ -1579,7 +1595,7 @@ main (int argc, char **argv)
log_info ("listening on: std=%d extra=%d browser=%d ssh=%d\n",
fd, fd_extra, fd_browser, fd_ssh);
handle_connections (fd, fd_extra, fd_browser, fd_ssh);
handle_connections (fd, fd_extra, fd_browser, fd_ssh, 1);
#endif /*!HAVE_W32_SYSTEM*/
}
else if (!is_daemon)
@ -1807,14 +1823,14 @@ main (int argc, char **argv)
log_get_prefix (&oldflags);
log_set_prefix (NULL, oldflags | GPGRT_LOG_RUN_DETACHED);
opt.running_detached = 1;
/* Unless we are running with a program given on the command
* line we can assume that the inotify things works and thus
* we can avoid the regular stat calls. */
if (!argc)
reliable_homedir_inotify = 1;
}
/* When we are running with a program given on the command
* line, the inotify things may not work well and thus
* we cannot avoid the regular stat calls. */
if (argc)
reliable_homedir_inotify = 0;
{
struct sigaction sa;
@ -1833,7 +1849,8 @@ main (int argc, char **argv)
}
log_info ("%s %s started\n", gpgrt_strusage(11), gpgrt_strusage(13) );
handle_connections (fd, fd_extra, fd_browser, fd_ssh);
handle_connections (fd, fd_extra, fd_browser, fd_ssh,
reliable_homedir_inotify);
assuan_sock_close (fd);
}
@ -1989,6 +2006,7 @@ agent_deinit_default_ctrl (ctrl_t ctrl)
{
unregister_progress_cb ();
session_env_release (ctrl->session_env);
clear_ephemeral_keys (ctrl);
xfree (ctrl->digest.data);
ctrl->digest.data = NULL;
@ -2134,39 +2152,45 @@ get_agent_active_connection_count (void)
notification event. Calling it the first time creates that
event. */
#if defined(HAVE_W32_SYSTEM)
static void *
create_an_event (void)
{
HANDLE h, h2;
SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
/* We need to use a manual reset event object due to the way our
w32-pth wait function works: If we would use an automatic
reset event we are not able to figure out which handle has
been signaled because at the time we single out the signaled
handles using WFSO the event has already been reset due to
the WFMO. */
h = CreateEvent (&sa, TRUE, FALSE, NULL);
if (!h)
log_error ("can't create an event: %s\n", w32_strerror (-1) );
else if (!DuplicateHandle (GetCurrentProcess(), h,
GetCurrentProcess(), &h2,
EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
{
log_error ("setting synchronize for an event failed: %s\n",
w32_strerror (-1) );
CloseHandle (h);
}
else
{
CloseHandle (h);
return h2;
}
return INVALID_HANDLE_VALUE;
}
void *
get_agent_daemon_notify_event (void)
{
static HANDLE the_event = INVALID_HANDLE_VALUE;
if (the_event == INVALID_HANDLE_VALUE)
{
HANDLE h, h2;
SECURITY_ATTRIBUTES sa = { sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
/* We need to use a manual reset event object due to the way our
w32-pth wait function works: If we would use an automatic
reset event we are not able to figure out which handle has
been signaled because at the time we single out the signaled
handles using WFSO the event has already been reset due to
the WFMO. */
h = CreateEvent (&sa, TRUE, FALSE, NULL);
if (!h)
log_error ("can't create scd notify event: %s\n", w32_strerror (-1) );
else if (!DuplicateHandle (GetCurrentProcess(), h,
GetCurrentProcess(), &h2,
EVENT_MODIFY_STATE|SYNCHRONIZE, TRUE, 0))
{
log_error ("setting synchronize for scd notify event failed: %s\n",
w32_strerror (-1) );
CloseHandle (h);
}
else
{
CloseHandle (h);
the_event = h2;
}
}
the_event = create_an_event ();
return the_event;
}
@ -2423,57 +2447,6 @@ create_directories (void)
}
/* This is the worker for the ticker. It is called every few seconds
and may only do fast operations. */
static void
handle_tick (void)
{
static time_t last_minute;
struct stat statbuf;
if (!last_minute)
last_minute = time (NULL);
/* If we are running as a child of another process, check whether
the parent is still alive and shutdown if not. */
#ifndef HAVE_W32_SYSTEM
if (parent_pid != (pid_t)(-1))
{
if (kill (parent_pid, 0))
{
shutdown_pending = 2;
log_info ("parent process died - shutting down\n");
log_info ("%s %s stopped\n", gpgrt_strusage(11), gpgrt_strusage(13));
cleanup ();
agent_exit (0);
}
}
#endif /*HAVE_W32_SYSTEM*/
/* Code to be run from time to time. */
#if CHECK_OWN_SOCKET_INTERVAL > 0
if (last_minute + CHECK_OWN_SOCKET_INTERVAL <= time (NULL))
{
check_own_socket ();
last_minute = time (NULL);
}
#endif
/* Need to check for expired cache entries. */
agent_cache_housekeeping ();
/* Check whether the homedir is still available. */
if (!shutdown_pending
&& (!have_homedir_inotify || !reliable_homedir_inotify)
&& gnupg_stat (gnupg_homedir (), &statbuf) && errno == ENOENT)
{
shutdown_pending = 1;
log_info ("homedir has been removed - shutting down\n");
}
}
/* A global function which allows us to call the reload stuff from
other places too. This is only used when build for W32. */
void
@ -2532,6 +2505,11 @@ handle_signal (int signo)
agent_sigusr2_action ();
break;
case SIGCONT:
/* Do nothing, but break the syscall. */
log_debug ("SIGCONT received - breaking select\n");
break;
case SIGTERM:
if (!shutdown_pending)
log_info ("SIGTERM received - shutting down ...\n");
@ -2569,7 +2547,7 @@ check_nonce (ctrl_t ctrl, assuan_sock_nonce_t *nonce)
if (assuan_sock_check_nonce (ctrl->thread_startup.fd, nonce))
{
log_info (_("error reading nonce on fd %d: %s\n"),
FD2INT(ctrl->thread_startup.fd), strerror (errno));
FD_DBG (ctrl->thread_startup.fd), strerror (errno));
assuan_sock_close (ctrl->thread_startup.fd);
xfree (ctrl);
return -1;
@ -2869,12 +2847,12 @@ do_start_connection_thread (ctrl_t ctrl)
agent_init_default_ctrl (ctrl);
if (opt.verbose > 1 && !DBG_IPC)
log_info (_("handler 0x%lx for fd %d started\n"),
(unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
(unsigned long) npth_self(), FD_DBG (ctrl->thread_startup.fd));
start_command_handler (ctrl, GNUPG_INVALID_FD, ctrl->thread_startup.fd);
if (opt.verbose > 1 && !DBG_IPC)
log_info (_("handler 0x%lx for fd %d terminated\n"),
(unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
(unsigned long) npth_self(), FD_DBG (ctrl->thread_startup.fd));
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
@ -2949,12 +2927,12 @@ start_connection_thread_ssh (void *arg)
agent_init_default_ctrl (ctrl);
if (opt.verbose)
log_info (_("ssh handler 0x%lx for fd %d started\n"),
(unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
(unsigned long) npth_self(), FD_DBG (ctrl->thread_startup.fd));
start_command_handler_ssh (ctrl, ctrl->thread_startup.fd);
if (opt.verbose)
log_info (_("ssh handler 0x%lx for fd %d terminated\n"),
(unsigned long) npth_self(), FD2INT(ctrl->thread_startup.fd));
(unsigned long) npth_self(), FD_DBG (ctrl->thread_startup.fd));
agent_deinit_default_ctrl (ctrl);
xfree (ctrl);
@ -2963,13 +2941,36 @@ start_connection_thread_ssh (void *arg)
}
void
agent_kick_the_loop (void)
{
/* Kick the select loop. */
#ifdef HAVE_W32_SYSTEM
int ret = SetEvent (the_event2);
if (ret == 0)
log_error ("SetEvent for agent_kick_the_loop failed: %s\n",
w32_strerror (-1));
#else
# ifdef HAVE_PSELECT_NO_EINTR
write (event_pipe_fd, "", 1);
# else
int ret = kill (main_thread_pid, SIGCONT);
if (ret < 0)
log_error ("sending signal for agent_kick_the_loop failed: %s\n",
gpg_strerror (gpg_error_from_syserror ()));
# endif
#endif
}
/* Connection handler loop. Wait for connection requests and spawn a
thread after accepting a connection. */
static void
handle_connections (gnupg_fd_t listen_fd,
gnupg_fd_t listen_fd_extra,
gnupg_fd_t listen_fd_browser,
gnupg_fd_t listen_fd_ssh)
gnupg_fd_t listen_fd_ssh,
int reliable_homedir_inotify)
{
gpg_error_t err;
npth_attr_t tattr;
@ -2980,12 +2981,15 @@ handle_connections (gnupg_fd_t listen_fd,
gnupg_fd_t fd;
int nfd;
int saved_errno;
struct timespec abstime;
struct timespec curtime;
struct timespec timeout;
struct timespec *tp;
#ifdef HAVE_W32_SYSTEM
HANDLE events[2];
HANDLE events[3];
unsigned int events_set;
#else
int signo;
# ifdef HAVE_PSELECT_NO_EINTR
int pipe_fd[2];
# endif
#endif
int sock_inotify_fd = -1;
int home_inotify_fd = -1;
@ -3013,11 +3017,24 @@ handle_connections (gnupg_fd_t listen_fd,
npth_sigev_add (SIGUSR1);
npth_sigev_add (SIGUSR2);
npth_sigev_add (SIGINT);
npth_sigev_add (SIGCONT);
npth_sigev_add (SIGTERM);
npth_sigev_fini ();
# ifdef HAVE_PSELECT_NO_EINTR
ret = gnupg_create_pipe (pipe_fd);
if (ret)
{
log_error ("pipe creation failed: %s\n", gpg_strerror (ret));
return;
}
event_pipe_fd = pipe_fd[1];
# else
main_thread_pid = getpid ();
# endif
#else
events[0] = get_agent_daemon_notify_event ();
events[1] = INVALID_HANDLE_VALUE;
events[1] = the_event2 = create_an_event ();
events[2] = INVALID_HANDLE_VALUE;
#endif
if (disable_check_own_socket)
@ -3029,7 +3046,7 @@ handle_connections (gnupg_fd_t listen_fd,
gpg_strerror (err));
}
if (disable_check_own_socket)
if (!reliable_homedir_inotify)
home_inotify_fd = -1;
else if ((err = gnupg_inotify_watch_delete_self (&home_inotify_fd,
gnupg_homedir ())))
@ -3041,6 +3058,27 @@ handle_connections (gnupg_fd_t listen_fd,
else
have_homedir_inotify = 1;
#if CHECK_OWN_SOCKET_INTERVAL > 0
if (!disable_check_own_socket && sock_inotify_fd == -1)
{
npth_t thread;
err = npth_create (&thread, &tattr, check_own_socket_thread, NULL);
if (err)
log_error ("error spawning check_own_socket_thread: %s\n", strerror (err));
}
#endif
if ((HAVE_PARENT_PID_SUPPORT && parent_pid != (pid_t)(-1))
|| !have_homedir_inotify)
{
npth_t thread;
err = npth_create (&thread, &tattr, check_others_thread, NULL);
if (err)
log_error ("error spawning check_others_thread: %s\n", strerror (err));
}
/* On Windows we need to fire up a separate thread to listen for
requests from Putty (an SSH client), so we can replace Putty's
Pageant (its ssh-agent implementation). */
@ -3070,24 +3108,24 @@ handle_connections (gnupg_fd_t listen_fd,
FD_ZERO (&fdset);
FD_SET (FD2INT (listen_fd), &fdset);
nfd = FD2INT (listen_fd);
nfd = FD2NUM (listen_fd);
if (listen_fd_extra != GNUPG_INVALID_FD)
{
FD_SET ( FD2INT(listen_fd_extra), &fdset);
if (FD2INT (listen_fd_extra) > nfd)
nfd = FD2INT (listen_fd_extra);
nfd = FD2NUM (listen_fd_extra);
}
if (listen_fd_browser != GNUPG_INVALID_FD)
{
FD_SET ( FD2INT(listen_fd_browser), &fdset);
if (FD2INT (listen_fd_browser) > nfd)
nfd = FD2INT (listen_fd_browser);
nfd = FD2NUM (listen_fd_browser);
}
if (listen_fd_ssh != GNUPG_INVALID_FD)
{
FD_SET ( FD2INT(listen_fd_ssh), &fdset);
if (FD2INT (listen_fd_ssh) > nfd)
nfd = FD2INT (listen_fd_ssh);
nfd = FD2NUM (listen_fd_ssh);
}
if (sock_inotify_fd != -1)
{
@ -3107,15 +3145,12 @@ handle_connections (gnupg_fd_t listen_fd,
listentbl[2].l_fd = listen_fd_browser;
listentbl[3].l_fd = listen_fd_ssh;
npth_clock_gettime (&abstime);
abstime.tv_sec += TIMERTICK_INTERVAL;
for (;;)
{
/* Shutdown test. */
if (shutdown_pending)
{
if (active_connections == 0)
if (active_connections == 0 || is_supervised)
break; /* ready */
/* Do not accept new connections but keep on running the
@ -3144,28 +3179,23 @@ handle_connections (gnupg_fd_t listen_fd,
thus a simple assignment is fine to copy the entire set. */
read_fdset = fdset;
npth_clock_gettime (&curtime);
if (!(npth_timercmp (&curtime, &abstime, <)))
{
/* Timeout. */
handle_tick ();
npth_clock_gettime (&abstime);
abstime.tv_sec += TIMERTICK_INTERVAL;
}
npth_timersub (&abstime, &curtime, &timeout);
#ifdef HAVE_PSELECT_NO_EINTR
FD_SET (pipe_fd[0], &read_fdset);
if (nfd < pipe_fd[0])
nfd = pipe_fd[0];
#endif
tp = agent_cache_expiration ();
#ifndef HAVE_W32_SYSTEM
ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
ret = npth_pselect (nfd+1, &read_fdset, NULL, NULL, tp,
npth_sigev_sigmask ());
saved_errno = errno;
{
int signo;
while (npth_sigev_get_pending (&signo))
handle_signal (signo);
}
while (npth_sigev_get_pending (&signo))
handle_signal (signo);
#else
ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, &timeout,
ret = npth_eselect (nfd+1, &read_fdset, NULL, NULL, tp,
events, &events_set);
saved_errno = errno;
@ -3181,11 +3211,47 @@ handle_connections (gnupg_fd_t listen_fd,
gnupg_sleep (1);
continue;
}
#ifndef HAVE_W32_SYSTEM
if ((problem_detected & AGENT_PROBLEM_PARENT_HAS_GONE))
{
shutdown_pending = 2;
log_info ("parent process died - shutting down\n");
log_info ("%s %s stopped\n", gpgrt_strusage(11), gpgrt_strusage(13));
cleanup ();
agent_exit (0);
}
#endif
if ((problem_detected & AGENT_PROBLEM_SOCKET_TAKEOVER))
{
/* We may not remove the socket as it is now in use by another
server. */
inhibit_socket_removal = 1;
shutdown_pending = 2;
log_info ("this process is useless - shutting down\n");
}
if ((problem_detected & AGENT_PROBLEM_HOMEDIR_REMOVED))
{
shutdown_pending = 1;
log_info ("homedir has been removed - shutting down\n");
}
if (ret <= 0)
/* Interrupt or timeout. Will be handled when calculating the
next timeout. */
continue;
#ifdef HAVE_PSELECT_NO_EINTR
if (FD_ISSET (pipe_fd[0], &read_fdset))
{
char buf[256];
read (pipe_fd[0], buf, sizeof buf);
}
#endif
/* The inotify fds are set even when a shutdown is pending (see
* above). So we must handle them in any case. To avoid that
* they trigger a second time we close them immediately. */
@ -3193,7 +3259,10 @@ handle_connections (gnupg_fd_t listen_fd,
&& FD_ISSET (sock_inotify_fd, &read_fdset)
&& gnupg_inotify_has_name (sock_inotify_fd, GPG_AGENT_SOCK_NAME))
{
shutdown_pending = 1;
/* We may not remove the socket (if any), as it may be now
in use by another server. */
inhibit_socket_removal = 1;
shutdown_pending = 2;
close (sock_inotify_fd);
sock_inotify_fd = -1;
log_info ("socket file has been removed - shutting down\n");
@ -3222,8 +3291,8 @@ handle_connections (gnupg_fd_t listen_fd,
continue;
plen = sizeof paddr;
fd = INT2FD (npth_accept (FD2INT(listentbl[idx].l_fd),
(struct sockaddr *)&paddr, &plen));
fd = assuan_sock_accept (listentbl[idx].l_fd,
(struct sockaddr *)&paddr, &plen);
if (fd == GNUPG_INVALID_FD)
{
log_error ("accept failed for %s: %s\n",
@ -3263,13 +3332,21 @@ handle_connections (gnupg_fd_t listen_fd,
close (sock_inotify_fd);
if (home_inotify_fd != -1)
close (home_inotify_fd);
#ifdef HAVE_W32_SYSTEM
if (the_event2 != INVALID_HANDLE_VALUE)
CloseHandle (the_event2);
#endif
#ifdef HAVE_PSELECT_NO_EINTR
close (pipe_fd[0]);
close (pipe_fd[1]);
#endif
cleanup ();
log_info (_("%s %s stopped\n"), gpgrt_strusage(11), gpgrt_strusage(13));
npth_attr_destroy (&tattr);
}
#if CHECK_OWN_SOCKET_INTERVAL > 0
/* Helper for check_own_socket. */
static gpg_error_t
check_own_socket_pid_cb (void *opaque, const void *buffer, size_t length)
@ -3280,20 +3357,18 @@ check_own_socket_pid_cb (void *opaque, const void *buffer, size_t length)
}
/* The thread running the actual check. We need to run this in a
separate thread so that check_own_thread can be called from the
timer tick. */
static void *
check_own_socket_thread (void *arg)
/* Check whether we are still listening on our own socket. In case
another gpg-agent process started after us has taken ownership of
our socket, we would linger around without any real task. Thus we
better check once in a while whether we are really needed. */
static int
do_check_own_socket (const char *sockname)
{
int rc;
char *sockname = arg;
assuan_context_t ctx = NULL;
membuf_t mb;
char *buffer;
check_own_socket_running++;
rc = assuan_new (&ctx);
if (rc)
{
@ -3331,58 +3406,78 @@ check_own_socket_thread (void *arg)
xfree (buffer);
leave:
xfree (sockname);
if (ctx)
assuan_release (ctx);
if (rc)
{
/* We may not remove the socket as it is now in use by another
server. */
inhibit_socket_removal = 1;
shutdown_pending = 2;
log_info ("this process is useless - shutting down\n");
}
check_own_socket_running--;
return NULL;
return rc;
}
/* Check whether we are still listening on our own socket. In case
another gpg-agent process started after us has taken ownership of
our socket, we would linger around without any real task. Thus we
better check once in a while whether we are really needed. */
static void
check_own_socket (void)
/* The thread running the actual check. */
static void *
check_own_socket_thread (void *arg)
{
char *sockname;
npth_t thread;
npth_attr_t tattr;
int err;
if (disable_check_own_socket)
return;
if (check_own_socket_running || shutdown_pending)
return; /* Still running or already shutting down. */
(void)arg;
sockname = make_filename_try (gnupg_socketdir (), GPG_AGENT_SOCK_NAME, NULL);
if (!sockname)
return; /* Out of memory. */
return NULL; /* Out of memory. */
err = npth_attr_init (&tattr);
if (err)
while (!problem_detected)
{
xfree (sockname);
return;
if (shutdown_pending)
goto leave;
gnupg_sleep (CHECK_OWN_SOCKET_INTERVAL);
if (do_check_own_socket (sockname))
problem_detected |= AGENT_PROBLEM_SOCKET_TAKEOVER;
}
npth_attr_setdetachstate (&tattr, NPTH_CREATE_DETACHED);
err = npth_create (&thread, &tattr, check_own_socket_thread, sockname);
if (err)
log_error ("error spawning check_own_socket_thread: %s\n", strerror (err));
npth_attr_destroy (&tattr);
agent_kick_the_loop ();
leave:
xfree (sockname);
return NULL;
}
#endif
/* The thread running other checks. */
static void *
check_others_thread (void *arg)
{
const char *homedir = gnupg_homedir ();
(void)arg;
while (!problem_detected)
{
struct stat statbuf;
if (shutdown_pending)
goto leave;
gnupg_sleep (CHECK_PROBLEMS_INTERVAL);
/* If we are running as a child of another process, check whether
the parent is still alive and shutdown if not. */
#ifndef HAVE_W32_SYSTEM
if (parent_pid != (pid_t)(-1) && kill (parent_pid, 0))
problem_detected |= AGENT_PROBLEM_PARENT_HAS_GONE;
#endif /*HAVE_W32_SYSTEM*/
/* Check whether the homedir is still available. */
if (!have_homedir_inotify
&& gnupg_stat (homedir, &statbuf) && errno == ENOENT)
problem_detected |= AGENT_PROBLEM_HOMEDIR_REMOVED;
}
agent_kick_the_loop ();
leave:
return NULL;
}
/* Figure out whether an agent is available and running. Prints an
error if not. If SILENT is true, no messages are printed.

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<description>GNU Privacy Guard (Private Key Daemon)</description>
<assemblyIdentity
type="win32"
name="GnuPG.gpg-agent"
version="@BUILD_VERSION@"
/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/><!-- Vista -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/><!-- 7 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/><!-- 8 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/><!-- 8.1 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/><!-- 10 -->
</application>
</compatibility>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@ -397,7 +397,7 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
grip[i] = xtoi_2 (p);
if (!force && !agent_key_available (grip))
if (!force && !agent_key_available (ctrl, grip))
continue; /* The key is already available. */
/* Unknown key - store it. */
@ -408,7 +408,17 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
goto leave;
}
rc = agent_write_shadow_key (grip, serialno, item->id, pubkey, force);
if (!ctrl->ephemeral_mode)
{
char *dispserialno;
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
item->hexgrip);
rc = agent_write_shadow_key (ctrl,
grip, serialno, item->id, pubkey, force,
dispserialno);
xfree (dispserialno);
}
xfree (pubkey);
if (rc)
goto leave;

View File

@ -27,8 +27,83 @@
#include <sys/stat.h>
#include "agent.h"
#include "../common/openpgpdefs.h"
/* Table with parameters for KEM decryption. Use get_ecc_parms to
* find an entry. */
struct ecc_params
{
const char *curve; /* Canonical name of the curve. */
size_t pubkey_len; /* Pubkey in the SEXP representation. */
size_t scalar_len;
size_t point_len;
size_t shared_len;
int hash_algo;
int kem_algo;
int scalar_reverse;
};
static const struct ecc_params ecc_table[] =
{
{
"Curve25519",
33, 32, 32, 32,
GCRY_MD_SHA3_256, GCRY_KEM_RAW_X25519,
1
},
{
"X448",
56, 56, 56, 64,
GCRY_MD_SHA3_512, GCRY_KEM_RAW_X448,
0
},
{
"brainpoolP256r1",
65, 32, 65, 32,
GCRY_MD_SHA3_256, GCRY_KEM_RAW_BP256,
0
},
{
"brainpoolP384r1",
97, 48, 97, 64,
GCRY_MD_SHA3_512, GCRY_KEM_RAW_BP384,
0
},
{
"brainpoolP512r1",
129, 64, 129, 64,
GCRY_MD_SHA3_512, GCRY_KEM_RAW_BP512,
0
},
{ NULL, 0, 0, 0, 0, 0, 0, 0 }
};
/* Maximum buffer sizes required for ECC KEM. Keep this aligned to
* the ecc_table above. */
#define ECC_SCALAR_LEN_MAX 64
#define ECC_POINT_LEN_MAX (1+2*64)
#define ECC_HASH_LEN_MAX 64
/* Return the ECC parameters for CURVE. CURVE is expected to be the
* canonical name. */
static const struct ecc_params *
get_ecc_params (const char *curve)
{
int i;
for (i = 0; ecc_table[i].curve; i++)
if (!strcmp (ecc_table[i].curve, curve))
return &ecc_table[i];
return NULL;
}
/* DECRYPT the stuff in ciphertext which is expected to be a S-Exp.
Try to get the key from CTRL and write the decoded stuff back to
OUTFP. The padding information is stored at R_PADDING with -1
@ -41,7 +116,6 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
gcry_sexp_t s_skey = NULL, s_cipher = NULL, s_plain = NULL;
unsigned char *shadow_info = NULL;
gpg_error_t err = 0;
int no_shadow_info = 0;
char *buf = NULL;
size_t len;
@ -70,17 +144,13 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
err = agent_key_from_file (ctrl, NULL, desc_text,
NULL, &shadow_info,
CACHE_MODE_NORMAL, NULL, &s_skey, NULL, NULL);
if (gpg_err_code (err) == GPG_ERR_NO_SECKEY)
no_shadow_info = 1;
else if (err)
if (err && gpg_err_code (err) != GPG_ERR_NO_SECKEY)
{
log_error ("failed to read the secret key\n");
goto leave;
}
if (shadow_info || no_shadow_info)
else if (shadow_info
|| err /* gpg_err_code (err) == GPG_ERR_NO_SECKEY */)
{ /* divert operation to the smartcard */
if (!gcry_sexp_canon_len (ciphertext, ciphertextlen, NULL, NULL))
{
err = gpg_error (GPG_ERR_INV_SEXP);
@ -95,12 +165,12 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
&buf, &len, r_padding);
if (err)
{
/* We restore the original error (ie. no seckey) is no card
/* We restore the original error (ie. no seckey) as no card
* has been found and we have no shadow key. This avoids a
* surprising "card removed" error code. */
if ((gpg_err_code (err) == GPG_ERR_CARD_REMOVED
|| gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
&& no_shadow_info)
&& !shadow_info)
err = gpg_error (GPG_ERR_NO_SECKEY);
else
log_error ("smartcard decryption failed: %s\n", gpg_strerror (err));
@ -157,3 +227,597 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
xfree (shadow_info);
return err;
}
/* Reverse BUFFER to change the endianness. */
static void
reverse_buffer (unsigned char *buffer, unsigned int length)
{
unsigned int tmp, i;
for (i=0; i < length/2; i++)
{
tmp = buffer[i];
buffer[i] = buffer[length-1-i];
buffer[length-1-i] = tmp;
}
}
static gpg_error_t
ecc_extract_pk_from_key (const struct ecc_params *ecc, gcry_sexp_t s_skey,
unsigned char *ecc_pk)
{
gpg_error_t err;
unsigned int nbits;
const unsigned char *p;
size_t len;
gcry_mpi_t ecc_pk_mpi = NULL;
err = gcry_sexp_extract_param (s_skey, NULL, "/q", &ecc_pk_mpi, NULL);
if (err)
{
if (opt.verbose)
log_info ("%s: extracting q and d from ECC key failed\n", __func__);
return err;
}
p = gcry_mpi_get_opaque (ecc_pk_mpi, &nbits);
len = (nbits+7)/8;
if (len != ecc->pubkey_len)
{
if (opt.verbose)
log_info ("%s: ECC public key length invalid (%zu)\n", __func__, len);
err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
else if (len == ecc->point_len)
memcpy (ecc_pk, p, ecc->point_len);
else if (len == ecc->point_len + 1 && p[0] == 0x40)
/* Remove the 0x40 prefix (for Curve25519) */
memcpy (ecc_pk, p+1, ecc->point_len);
else
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
if (DBG_CRYPTO)
log_printhex (ecc_pk, ecc->pubkey_len, "ECC pubkey:");
leave:
mpi_release (ecc_pk_mpi);
return err;
}
static gpg_error_t
ecc_extract_sk_from_key (const struct ecc_params *ecc, gcry_sexp_t s_skey,
unsigned char *ecc_sk)
{
gpg_error_t err;
unsigned int nbits;
const unsigned char *p;
size_t len;
gcry_mpi_t ecc_sk_mpi = NULL;
err = gcry_sexp_extract_param (s_skey, NULL, "/d", &ecc_sk_mpi, NULL);
if (err)
{
if (opt.verbose)
log_info ("%s: extracting d from ECC key failed\n", __func__);
return err;
}
p = gcry_mpi_get_opaque (ecc_sk_mpi, &nbits);
len = (nbits+7)/8;
if (len > ecc->scalar_len)
{
if (opt.verbose)
log_info ("%s: ECC secret key too long (%zu)\n", __func__, len);
err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
memset (ecc_sk, 0, ecc->scalar_len - len);
memcpy (ecc_sk + ecc->scalar_len - len, p, len);
if (ecc->scalar_reverse)
reverse_buffer (ecc_sk, ecc->scalar_len);
mpi_release (ecc_sk_mpi);
ecc_sk_mpi = NULL;
if (DBG_CRYPTO)
log_printhex (ecc_sk, ecc->scalar_len, "ECC seckey:");
leave:
mpi_release (ecc_sk_mpi);
return err;
}
static gpg_error_t
ecc_raw_kem (const struct ecc_params *ecc, gcry_sexp_t s_skey,
const unsigned char *ecc_ct, unsigned char *ecc_ecdh)
{
gpg_error_t err = 0;
unsigned char ecc_sk[ECC_SCALAR_LEN_MAX];
if (ecc->scalar_len > ECC_SCALAR_LEN_MAX)
{
if (opt.verbose)
log_info ("%s: ECC scalar length invalid (%zu)\n",
__func__, ecc->scalar_len);
err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
err = ecc_extract_sk_from_key (ecc, s_skey, ecc_sk);
if (err)
goto leave;
err = gcry_kem_decap (ecc->kem_algo, ecc_sk, ecc->scalar_len,
ecc_ct, ecc->point_len, ecc_ecdh, ecc->point_len,
NULL, 0);
if (err)
{
if (opt.verbose)
log_info ("%s: gcry_kem_decap for ECC failed\n", __func__);
}
leave:
wipememory (ecc_sk, sizeof ecc_sk);
return err;
}
static gpg_error_t
get_cardkey (ctrl_t ctrl, const char *keygrip, gcry_sexp_t *r_s_pk)
{
gpg_error_t err;
unsigned char *pkbuf;
size_t pkbuflen;
err = agent_card_readkey (ctrl, keygrip, &pkbuf, NULL);
if (err)
return err;
pkbuflen = gcry_sexp_canon_len (pkbuf, 0, NULL, NULL);
err = gcry_sexp_sscan (r_s_pk, NULL, (char*)pkbuf, pkbuflen);
if (err)
log_error ("failed to build S-Exp from received card key: %s\n",
gpg_strerror (err));
xfree (pkbuf);
return err;
}
static gpg_error_t
ecc_get_curve (ctrl_t ctrl, gcry_sexp_t s_skey, const char **r_curve)
{
gpg_error_t err = 0;
gcry_sexp_t s_skey_card = NULL;
const char *curve = NULL;
gcry_sexp_t key;
*r_curve = NULL;
if (!s_skey)
{
err = get_cardkey (ctrl, ctrl->keygrip, &s_skey_card);
if (err)
goto leave;
key = s_skey_card;
}
else
key = s_skey;
curve = get_ecc_curve_from_key (key);
if (!curve)
{
err = gpg_error (GPG_ERR_BAD_SECKEY);
goto leave;
}
*r_curve = curve;
leave:
gcry_sexp_release (s_skey_card);
return err;
}
/* Given a private key in SEXP by S_SKEY0 and a cipher text by ECC_CT
* with length ECC_POINT_LEN, do ECC-KEM operation. Result is
* returned in the memory referred by ECC_SS. Shared secret length is
* returned in the memory referred by R_SHARED_LEN. CTRL is used to
* access smartcard, internally. */
static gpg_error_t
ecc_pgp_kem_decrypt (ctrl_t ctrl, gcry_sexp_t s_skey0,
unsigned char *shadow_info0,
const unsigned char *ecc_ct, size_t ecc_point_len,
unsigned char *ecc_ss, size_t *r_shared_len)
{
gpg_error_t err;
unsigned char ecc_ecdh[ECC_POINT_LEN_MAX];
unsigned char ecc_pk[ECC_POINT_LEN_MAX];
const char *curve;
const struct ecc_params *ecc = NULL;
if (ecc_point_len > ECC_POINT_LEN_MAX)
return gpg_error (GPG_ERR_INV_DATA);
err = ecc_get_curve (ctrl, s_skey0, &curve);
if (err)
{
if ((gpg_err_code (err) == GPG_ERR_CARD_REMOVED
|| gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
&& !s_skey0)
err = gpg_error (GPG_ERR_NO_SECKEY);
return err;
}
ecc = get_ecc_params (curve);
if (!ecc)
{
if (opt.verbose)
log_info ("%s: curve '%s' not supported\n", __func__, curve);
return gpg_error (GPG_ERR_BAD_SECKEY);
}
*r_shared_len = ecc->shared_len;
if (DBG_CRYPTO)
log_debug ("ECC curve: %s\n", curve);
if (ecc->point_len != ecc_point_len)
{
if (opt.verbose)
log_info ("%s: ECC cipher text length invalid (%zu != %zu)\n",
__func__, ecc->point_len, ecc_point_len);
return gpg_error (GPG_ERR_INV_DATA);
}
err = ecc_extract_pk_from_key (ecc, s_skey0, ecc_pk);
if (err)
return err;
if (DBG_CRYPTO)
log_printhex (ecc_ct, ecc->point_len, "ECC ephem:");
if (shadow_info0 || !s_skey0)
{
if (s_skey0 && agent_is_tpm2_key (s_skey0))
{
log_error ("TPM decryption failed: %s\n", gpg_strerror (err));
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
}
else
{
err = agent_card_ecc_kem (ctrl, ecc_ct, ecc->point_len, ecc_ecdh);
if (err)
{
log_error ("smartcard decryption failed: %s\n",
gpg_strerror (err));
return err;
}
}
}
else
err = ecc_raw_kem (ecc, s_skey0, ecc_ct, ecc_ecdh);
if (err)
return err;
if (DBG_CRYPTO)
log_printhex (ecc_ecdh, ecc_point_len, "ECC ecdh:");
err = gnupg_ecc_kem_kdf (ecc_ss, ecc->shared_len, ecc->hash_algo,
ecc_ecdh, ecc->point_len, ecc_ct, ecc->point_len,
ecc_pk, ecc->point_len);
wipememory (ecc_ecdh, sizeof ecc_ecdh);
if (err)
{
if (opt.verbose)
log_info ("%s: kdf for ECC failed\n", __func__);
return err;
}
if (DBG_CRYPTO)
log_printhex (ecc_ss, ecc->shared_len, "ECC shared:");
return 0;
}
/* For composite PGP KEM (ECC+ML-KEM), decrypt CIPHERTEXT using KEM API.
First keygrip is for ECC, second keygrip is for PQC. CIPHERTEXT
should follow the format of:
(enc-val(pqc(c%d)(e%m)(k%m)(s%m)(fixed-info&)))
c: cipher identifier (symmetric)
e: ECDH ciphertext
k: ML-KEM ciphertext
s: encrypted session key
fixed-info: A buffer with the fixed info.
FIXME: For now, possible keys on smartcard are not supported.
*/
static gpg_error_t
composite_pgp_kem_decrypt (ctrl_t ctrl, const char *desc_text,
gcry_sexp_t s_cipher, membuf_t *outbuf)
{
gcry_sexp_t s_skey0 = NULL;
gcry_sexp_t s_skey1 = NULL;
unsigned char *shadow_info0 = NULL;
unsigned char *shadow_info1 = NULL;
gpg_error_t err = 0;
unsigned int nbits;
size_t len;
int algo;
gcry_mpi_t encrypted_sessionkey_mpi = NULL;
const unsigned char *encrypted_sessionkey;
size_t encrypted_sessionkey_len;
gcry_mpi_t ecc_ct_mpi = NULL;
const unsigned char *ecc_ct;
size_t ecc_ct_len;
unsigned char ecc_ss[ECC_HASH_LEN_MAX];
size_t ecc_shared_len, ecc_point_len;
enum gcry_kem_algos mlkem_kem_algo;
gcry_mpi_t mlkem_sk_mpi = NULL;
gcry_mpi_t mlkem_ct_mpi = NULL;
const unsigned char *mlkem_sk;
size_t mlkem_sk_len;
const unsigned char *mlkem_ct;
size_t mlkem_ct_len;
unsigned char mlkem_ss[GCRY_KEM_MLKEM1024_SHARED_LEN];
size_t mlkem_ss_len;
unsigned char kek[32];
size_t kek_len = 32; /* AES-256 is mandatory */
gcry_cipher_hd_t hd;
unsigned char sessionkey[256];
size_t sessionkey_len;
gcry_buffer_t fixed_info = { 0, 0, 0, NULL };
err = agent_key_from_file (ctrl, NULL, desc_text,
ctrl->keygrip, &shadow_info0,
CACHE_MODE_NORMAL, NULL, &s_skey0, NULL, NULL);
if (err && gpg_err_code (err) != GPG_ERR_NO_SECKEY)
{
log_error ("failed to read the secret key\n");
goto leave;
}
err = agent_key_from_file (ctrl, NULL, desc_text,
ctrl->keygrip1, &shadow_info1,
CACHE_MODE_NORMAL, NULL, &s_skey1, NULL, NULL);
/* Here assumes no smartcard for ML-KEM, but private key in a file. */
if (err)
{
log_error ("failed to read the another secret key\n");
goto leave;
}
err = gcry_sexp_extract_param (s_cipher, NULL, "%dc/eks&'fixed-info'",
&algo, &ecc_ct_mpi, &mlkem_ct_mpi,
&encrypted_sessionkey_mpi, &fixed_info, NULL);
if (err)
{
if (opt.verbose)
log_info ("%s: extracting parameters failed\n", __func__);
goto leave;
}
ecc_ct = gcry_mpi_get_opaque (ecc_ct_mpi, &nbits);
ecc_ct_len = (nbits+7)/8;
len = gcry_cipher_get_algo_keylen (algo);
encrypted_sessionkey = gcry_mpi_get_opaque (encrypted_sessionkey_mpi, &nbits);
encrypted_sessionkey_len = (nbits+7)/8;
if (len == 0 || encrypted_sessionkey_len != len + 8)
{
if (opt.verbose)
log_info ("%s: encrypted session key length %zu"
" does not match the length for algo %d\n",
__func__, encrypted_sessionkey_len, algo);
err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
/* Firstly, ECC part. */
ecc_point_len = ecc_ct_len;
err = ecc_pgp_kem_decrypt (ctrl, s_skey0, shadow_info0, ecc_ct, ecc_point_len,
ecc_ss, &ecc_shared_len);
if (err)
goto leave;
/* Secondly, PQC part. For now, we assume ML-KEM. */
err = gcry_sexp_extract_param (s_skey1, NULL, "/s", &mlkem_sk_mpi, NULL);
if (err)
{
if (opt.verbose)
log_info ("%s: extracting s from PQ key failed\n", __func__);
goto leave;
}
mlkem_sk = gcry_mpi_get_opaque (mlkem_sk_mpi, &nbits);
mlkem_sk_len = (nbits+7)/8;
if (mlkem_sk_len == GCRY_KEM_MLKEM512_SECKEY_LEN)
{
mlkem_kem_algo = GCRY_KEM_MLKEM512;
mlkem_ss_len = GCRY_KEM_MLKEM512_SHARED_LEN;
mlkem_ct_len = GCRY_KEM_MLKEM512_CIPHER_LEN;
}
else if (mlkem_sk_len == GCRY_KEM_MLKEM768_SECKEY_LEN)
{
mlkem_kem_algo = GCRY_KEM_MLKEM768;
mlkem_ss_len = GCRY_KEM_MLKEM768_SHARED_LEN;
mlkem_ct_len = GCRY_KEM_MLKEM768_CIPHER_LEN;
}
else if (mlkem_sk_len == GCRY_KEM_MLKEM1024_SECKEY_LEN)
{
mlkem_kem_algo = GCRY_KEM_MLKEM1024;
mlkem_ss_len = GCRY_KEM_MLKEM1024_SHARED_LEN;
mlkem_ct_len = GCRY_KEM_MLKEM1024_CIPHER_LEN;
}
else
{
if (opt.verbose)
log_info ("%s: PQ key length invalid (%zu)\n", __func__, mlkem_sk_len);
err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
mlkem_ct = gcry_mpi_get_opaque (mlkem_ct_mpi, &nbits);
len = (nbits+7)/8;
if (len != mlkem_ct_len)
{
if (opt.verbose)
log_info ("%s: PQ cipher text length invalid (%zu)\n",
__func__, mlkem_ct_len);
err = gpg_error (GPG_ERR_INV_DATA);
goto leave;
}
err = gcry_kem_decap (mlkem_kem_algo, mlkem_sk, mlkem_sk_len,
mlkem_ct, mlkem_ct_len, mlkem_ss, mlkem_ss_len,
NULL, 0);
if (err)
{
if (opt.verbose)
log_info ("%s: gcry_kem_decap for PQ failed\n", __func__);
goto leave;
}
mpi_release (mlkem_sk_mpi);
mlkem_sk_mpi = NULL;
/* Then, combine two shared secrets and ciphertexts into one KEK */
err = gnupg_kem_combiner (kek, kek_len,
ecc_ss, ecc_shared_len, ecc_ct, ecc_point_len,
mlkem_ss, mlkem_ss_len, mlkem_ct, mlkem_ct_len,
fixed_info.data, fixed_info.size);
if (err)
{
if (opt.verbose)
log_info ("%s: KEM combiner failed\n", __func__);
goto leave;
}
mpi_release (ecc_ct_mpi);
ecc_ct_mpi = NULL;
mpi_release (mlkem_ct_mpi);
mlkem_ct_mpi = NULL;
if (DBG_CRYPTO)
{
log_printhex (kek, kek_len, "KEK key: ");
}
err = gcry_cipher_open (&hd, GCRY_CIPHER_AES256,
GCRY_CIPHER_MODE_AESWRAP, 0);
if (err)
{
if (opt.verbose)
log_error ("ecdh failed to initialize AESWRAP: %s\n",
gpg_strerror (err));
goto leave;
}
err = gcry_cipher_setkey (hd, kek, kek_len);
sessionkey_len = encrypted_sessionkey_len - 8;
err = gcry_cipher_decrypt (hd, sessionkey, sessionkey_len,
encrypted_sessionkey, encrypted_sessionkey_len);
gcry_cipher_close (hd);
mpi_release (encrypted_sessionkey_mpi);
encrypted_sessionkey_mpi = NULL;
if (err)
{
log_error ("KEM decrypt failed: %s\n", gpg_strerror (err));
goto leave;
}
put_membuf_printf (outbuf,
"(5:value%u:", (unsigned int)sessionkey_len);
put_membuf (outbuf, sessionkey, sessionkey_len);
put_membuf (outbuf, ")", 2);
leave:
wipememory (ecc_ss, sizeof ecc_ss);
wipememory (mlkem_ss, sizeof mlkem_ss);
wipememory (kek, sizeof kek);
wipememory (sessionkey, sizeof sessionkey);
mpi_release (ecc_ct_mpi);
mpi_release (mlkem_sk_mpi);
mpi_release (mlkem_ct_mpi);
mpi_release (encrypted_sessionkey_mpi);
gcry_free (fixed_info.data);
gcry_sexp_release (s_skey0);
gcry_sexp_release (s_skey1);
xfree (shadow_info0);
xfree (shadow_info1);
return err;
}
/* DECRYPT the encrypted stuff (like encrypted session key) in
CIPHERTEXT using KEM API, with KEMID. Keys (or a key) are
specified in CTRL. DESC_TEXT is used to retrieve private key.
OPTION can be specified for upper layer option for KEM. Decrypted
stuff (like session key) is written to OUTBUF.
*/
gpg_error_t
agent_kem_decrypt (ctrl_t ctrl, const char *desc_text, int kemid,
const unsigned char *ciphertext, size_t ciphertextlen,
const unsigned char *option, size_t optionlen,
membuf_t *outbuf)
{
gcry_sexp_t s_cipher = NULL;
gpg_error_t err = 0;
/* For now, only PQC-PGP is supported. */
if (kemid != KEM_PQC_PGP)
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
(void)optionlen;
if (kemid == KEM_PQC_PGP && option)
{
log_error ("PQC-PGP requires no option\n");
return gpg_error (GPG_ERR_INV_ARG);
}
if (!ctrl->have_keygrip)
{
log_error ("speculative decryption not yet supported\n");
return gpg_error (GPG_ERR_NO_SECKEY);
}
if (!ctrl->have_keygrip1)
{
log_error ("Composite KEM requires two KEYGRIPs\n");
return gpg_error (GPG_ERR_NO_SECKEY);
}
err = gcry_sexp_sscan (&s_cipher, NULL, (char*)ciphertext, ciphertextlen);
if (err)
{
log_error ("failed to convert ciphertext: %s\n", gpg_strerror (err));
return gpg_error (GPG_ERR_INV_DATA);
}
if (DBG_CRYPTO)
{
log_printhex (ctrl->keygrip, 20, "keygrip0:");
log_printhex (ctrl->keygrip1, 20, "keygrip1:");
gcry_log_debugsxp ("cipher", s_cipher);
}
err = composite_pgp_kem_decrypt (ctrl, desc_text, s_cipher, outbuf);
gcry_sexp_release (s_cipher);
return err;
}

View File

@ -371,9 +371,17 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
goto leave;
}
if (keyref)
agent_write_shadow_key (ctrl->keygrip, serialno, keyref, pkbuf, 0);
if (keyref && !ctrl->ephemeral_mode)
{
char *dispserialno;
agent_card_getattr (ctrl, "$DISPSERIALNO", &dispserialno,
hexgrip);
agent_write_shadow_key (ctrl,
ctrl->keygrip, serialno, keyref, pkbuf,
0, dispserialno);
xfree (dispserialno);
}
algo = get_pk_algo_from_key (s_pkey);
xfree (serialno);

View File

@ -755,8 +755,9 @@ release_passphrase (char *pw)
/* Stub function. */
int
agent_key_available (const unsigned char *grip)
agent_key_available (ctrl_t ctrl, const unsigned char *grip)
{
(void)ctrl;
(void)grip;
return -1; /* Not available. */
}
@ -813,19 +814,21 @@ agent_askpin (ctrl_t ctrl,
/* Replacement for the function in findkey.c. Here we write the key
* to stdout. */
int
agent_write_private_key (const unsigned char *grip,
gpg_error_t
agent_write_private_key (ctrl_t ctrl, const unsigned char *grip,
const void *buffer, size_t length, int force,
const char *serialno, const char *keyref,
time_t timestamp)
const char *dispserialno, time_t timestamp)
{
char hexgrip[40+4+1];
char *p;
(void)ctrl;
(void)force;
(void)serialno;
(void)keyref;
(void)timestamp;
(void)dispserialno;
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");

View File

@ -38,14 +38,14 @@ struct trustitem_s
{
struct
{
int disabled:1; /* This entry is disabled. */
int for_pgp:1; /* Set by '*' or 'P' as first flag. */
int for_smime:1; /* Set by '*' or 'S' as first flag. */
int relax:1; /* Relax checking of root certificate
unsigned int disabled:1; /* This entry is disabled. */
unsigned int for_pgp:1; /* Set by '*' or 'P' as first flag. */
unsigned int for_smime:1; /* Set by '*' or 'S' as first flag. */
unsigned int relax:1; /* Relax checking of root certificate
constraints. */
int cm:1; /* Use chain model for validation. */
int qual:1; /* Root CA for qualified signatures. */
int de_vs:1; /* Root CA for de-vs compliant PKI. */
unsigned int cm:1; /* Use chain model for validation. */
unsigned int qual:1; /* Root CA for qualified signatures. */
unsigned int de_vs:1; /* Root CA for de-vs compliant PKI. */
} flags;
unsigned char fpr[20]; /* The binary fingerprint. */
};

View File

@ -28,15 +28,24 @@ cvtver () {
usage()
{
cat <<EOF
Usage: $(basename $0) [OPTIONS]
Usage: $(basename $0) [OPTIONS] [packages]
Get the online version of the GnuPG software version database
and optionally download packages and verify their signatures.
Options:
--info Print only infos about packages
--skip-download Assume download has already been done.
--skip-verify Do not check signatures
--skip-selfcheck Do not check GnuPG version
(default if not used in the GnuPG tree)
--find-sha1sum Print the name of the sha1sum utility
--find-sha256sum Print the name of the sha256sum utility
--help Print this help.
Example:
getswdb.sh gnupg24 gpgme libksba libassuan
EOF
exit $1
}
@ -49,6 +58,9 @@ skip_verify=no
skip_selfcheck=no
find_sha1sum=no
find_sha256sum=no
info_mode=no
packages=
die=no
while test $# -gt 0; do
case "$1" in
# Set up `optarg'.
@ -79,13 +91,20 @@ while test $# -gt 0; do
--find-sha256sum)
find_sha256sum=yes
;;
*)
--info)
info_mode=yes
;;
--*)
usage 1 1>&2
;;
*)
packages="$packages $1"
;;
esac
shift
done
# Mac OSX has only a shasum and not sha1sum
if [ ${find_sha1sum} = yes ]; then
for i in sha1sum shasum ; do
@ -114,16 +133,37 @@ if [ ${find_sha256sum} = yes ]; then
fi
if [ $skip_verify = no ]; then
if [ ! -f "$distsigkey" ]; then
distsigkey="/usr/local/share/gnupg/distsigkey.gpg"
if [ ! -f "$distsigkey" ]; then
distsigkey="/usr/share/gnupg/distsigkey.gpg"
if [ ! -f "$distsigkey" ]; then
echo "no keyring with release keys found!" >&2
exit 1
fi
fi
echo "using release keys from $distsigkey" >&2
skip_selfcheck=yes
fi
fi
# Get GnuPG version from VERSION file. For a GIT checkout this means
# that ./autogen.sh must have been run first. For a regular tarball
# VERSION is always available.
if [ ! -f "$srcdir/../VERSION" ]; then
if [ $skip_selfcheck = no ]; then
if [ ! -f "$srcdir/../VERSION" ]; then
echo "VERSION file missing - run autogen.sh first." >&2
exit 1
fi
version=$(cat "$srcdir/../VERSION")
else
version="0.0.0"
fi
version=$(cat "$srcdir/../VERSION")
version_num=$(echo "$version" | cvtver)
if [ $skip_verify = no ]; then
if ! $GPGV --version >/dev/null 2>/dev/null ; then
echo "command \"gpgv\" is not installed" >&2
@ -164,10 +204,10 @@ else
fi
fi
if [ $skip_verify = no ]; then
if ! $GPGV --keyring "$distsigkey" swdb.lst.sig swdb.lst; then
if ! $GPGV --keyring "$distsigkey" swdb.lst.sig swdb.lst 2>/dev/null; then
echo "list of software versions is not valid!" >&2
exit 1
fi
fi
fi
#
@ -188,3 +228,73 @@ if [ $skip_selfcheck = no ]; then
exit 1
fi
fi
# Download a package and check its signature.
download_pkg () {
local url="$1"
local file="${url##*/}"
if ! $WGET -q -O - "$url" >"${file}.tmp" ; then
echo "download of $file failed." >&2
[ -f "${file}.tmp" ] && rm "${file}.tmp"
return 1
fi
if [ $skip_verify = no ]; then
if ! $WGET -q -O - "${url}.sig" >"${file}.tmpsig" ; then
echo "download of $file.sig failed." >&2
[ -f "${file}.tmpsig" ] && rm "${file}.tmpsig"
return 1
fi
if ! $GPGV -q --keyring "$distsigkey" \
"${file}.tmpsig" "${file}.tmp" 2>/dev/null; then
echo "signature of $file is not valid!" >&2
return 1
fi
mv "${file}.tmpsig" "${file}.sig"
else
[ -f "${file}.sig" ] && rm "${file}.sig"
fi
mv "${file}.tmp" "${file}"
return 0
}
baseurl=$(awk '$1=="gpgorg_base" {print $2; exit 0}' swdb.lst)
for p in $packages; do
pver=$(awk '$1=="'"$p"'_ver" {print $2}' swdb.lst)
if [ -z "$pver" ]; then
echo "package '$p' not found" >&2
die=yes
else
pdir=$(awk '$1=="'"$p"'_dir" {print $2":"$3":"$4}' swdb.lst)
if [ -n "$pdir" ]; then
psuf=$(echo "$pdir" | cut -d: -f3)
pname=$(echo "$pdir" | cut -d: -f2)
pdir=$(echo "$pdir" | cut -d: -f1)
else
psuf=
pdir="$p"
pname="$p"
fi
if [ -z "$psuf" ]; then
psuf=$(awk 'BEGIN {suf="bz2"};
$1=="'"$p"'_sha1_gz" {suf="gz"; exit 0};
$1=="'"$p"'_sha1_xz" {suf"xz"; exit 0};
END {print suf}' swdb.lst)
fi
pfullname="$pname-$pver.tar.$psuf"
if [ $info_mode = yes ]; then
echo "$baseurl/$pdir/$pfullname"
else
echo "downloading $pfullname"
download_pkg "$baseurl/$pdir/$pfullname" || die=yes
fi
fi
done
if [ $die = yes ]; then
echo "errors found!" >&2
exit 1
fi
exit 0

View File

@ -43,67 +43,21 @@
#
# The information required to sign the tarballs and binaries
# are expected in the developer specific file ~/.gnupg-autogen.rc".
# Here is an example:
#--8<---------------cut here---------------start------------->8---
# # Location of the released tarball archives. Note that this is an
# # internal archive and before uploading this to the public server,
# # manual tests should be run and the git release tagged and pushed.
# # This is greped by the Makefile.
# RELEASE_ARCHIVE=foo@somehost:tarball-archive
#
# # The key used to sign the released sources.
# # This is greped by the Makefile.
# RELEASE_SIGNKEY=6DAA6E64A76D2840571B4902528897B826403ADA
#
# # For signing Windows binaries we need to employ a Windows machine.
# # We connect to this machine via ssh and take the connection
# # parameters via .ssh/config. For example a VM could be specified
# # like this:
# #
# # Host authenticode-signhost
# # HostName localhost
# # Port 27042
# # User gpgsign
# #
# # Depending on the used token it might be necessary to allow single
# # signon and unlock the token before running the make. The following
# # variable references this entry. This is greped by the Makefile.
# AUTHENTICODE_SIGNHOST=authenticode-signhost
#
# # The name of the signtool as used on Windows.
# # This is greped by the Makefile.
# AUTHENTICODE_TOOL="C:\Program Files (x86)\Windows Kits\10\bin\signtool.exe"
#
# # To use osslsigncode the follwing entries are required and
# # an empty string must be given for AUTHENTICODE_SIGNHOST.
# # They are greped by the Makefile.
# AUTHENTICODE_KEY=/home/foo/.gnupg/my-authenticode-key.p12
# AUTHENTICODE_CERTS=/home/foo/.gnupg/my-authenticode-certs.pem
#
# # If a smartcard is used for the Authenticode signature these
# # entries are required instead:
# AUTHENTICODE_KEY=card
# AUTHENTICODE_CERTS=/home/foo/.gnupg/my_authenticode_cert.pem
# OSSLSIGNCODE=/usr/bin/osslsigncode
# OSSLPKCS11ENGINE=/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so
# SCUTEMODULE=/usr/local/lib/scute.so
#
#--8<---------------cut here---------------end--------------->8---
# Use "gpg-authcode-sign.sh --template" to create a template.
# We need to know our own name.
SPEEDO_MK := $(realpath $(lastword $(MAKEFILE_LIST)))
.PHONY : help native native-gui w32-installer w32-source w32-wixlib
.PHONY : git-native git-native-gui git-w32-installer git-w32-source
.PHONY : this-native this-native-gui this-w32-installer this-w32-source
.PHONY : help native w32-installer w32-source w32-wixlib
.PHONY : git-native git-w32-installer git-w32-source
.PHONY : this-native this-w32-installer this-w32-source
help:
@echo 'usage: make -f speedo.mk TARGET'
@echo ' with TARGET being one of:'
@echo ' help This help'
@echo ' native Native build of the GnuPG core'
@echo ' native-gui Ditto but with pinentry and GPA'
@echo ' w32-installer Build a Windows installer'
@echo ' w32-source Pack a source archive'
@echo ' w32-release Build a Windows release'
@ -114,11 +68,12 @@ help:
@echo 'Prepend TARGET with "git-" to build from GIT repos.'
@echo 'Prepend TARGET with "this-" to build from the source tarball.'
@echo 'Use STATIC=1 to build with statically linked libraries.'
@echo 'Use SELFCHECK=0 for a non-released version.'
@echo 'Use SELFCHECK=1 for additional check of the gnupg version.'
@echo 'Use CUSTOM_SWDB=1 for an already downloaded swdb.lst.'
@echo 'Use WIXPREFIX to provide the WIX binaries for the MSI package.'
@echo ' Using WIX also requires wine with installed wine mono.'
@echo ' See help-wixlib for more information'
@echo 'Set W32VERSION=w64 to build a 64 bit Windows version.'
help-wixlib:
@echo 'The buildsystem can create a wixlib to build MSI packages.'
@ -148,66 +103,52 @@ help-wixlib:
SPEEDOMAKE := $(MAKE) -f $(SPEEDO_MK) UPD_SWDB=1
native: check-tools
$(SPEEDOMAKE) TARGETOS=native WHAT=release WITH_GUI=0 all
$(SPEEDOMAKE) TARGETOS=native WHAT=release all
git-native: check-tools
$(SPEEDOMAKE) TARGETOS=native WHAT=git WITH_GUI=0 all
$(SPEEDOMAKE) TARGETOS=native WHAT=git all
this-native: check-tools
$(SPEEDOMAKE) TARGETOS=native WHAT=this WITH_GUI=0 all
native-gui: check-tools
$(SPEEDOMAKE) TARGETOS=native WHAT=release WITH_GUI=1 all
git-native-gui: check-tools
$(SPEEDOMAKE) TARGETOS=native WHAT=git WITH_GUI=1 all
this-native-gui: check-tools
$(SPEEDOMAKE) TARGETOS=native WHAT=this WITH_GUI=1 all
$(SPEEDOMAKE) TARGETOS=native WHAT=this all
w32-installer: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 installer
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release installer
git-w32-installer: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git WITH_GUI=0 installer
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git installer
this-w32-installer: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this WITH_GUI=0 \
CUSTOM_SWDB=1 installer
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this CUSTOM_SWDB=1 installer
w32-wixlib: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 wixlib
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release wixlib
git-w32-wixlib: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git WITH_GUI=0 wixlib
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git wixlib
this-w32-wixlib: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this WITH_GUI=0 \
CUSTOM_SWDB=1 wixlib
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this CUSTOM_SWDB=1 wixlib
w32-source: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 dist-source
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release dist-source
git-w32-source: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git WITH_GUI=0 dist-source
$(SPEEDOMAKE) TARGETOS=w32 WHAT=git dist-source
this-w32-source: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this WITH_GUI=0 \
CUSTOM_SWDB=1 dist-source
$(SPEEDOMAKE) TARGETOS=w32 WHAT=this CUSTOM_SWDB=1 dist-source
w32-release: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
installer-from-source
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release installer-from-source
w32-msi-release: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release \
WITH_WIXLIB=1 installer-from-source
w32-sign-installer: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
sign-installer
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release sign-installer
w32-release-offline: check-tools
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release WITH_GUI=0 SELFCHECK=0 \
$(SPEEDOMAKE) TARGETOS=w32 WHAT=release \
CUSTOM_SWDB=1 pkgrep=${HOME}/b pkg10rep=${HOME}/b \
installer-from-source
@ -217,11 +158,11 @@ w32-release-offline: check-tools
# to "this" from the unpacked sources.
WHAT=git
# Set target to "native" or "w32"
# Set target to "native" or "w32".
TARGETOS=
# Set to 1 to build the GUI tools
WITH_GUI=0
# To build a 64 bit Windows version also change this to "w64"
W32VERSION=w32
# Set to 1 to use a pre-installed swdb.lst instead of the online version.
CUSTOM_SWDB=0
@ -229,8 +170,8 @@ CUSTOM_SWDB=0
# Set to 1 to really download the swdb.
UPD_SWDB=0
# Set to 0 to skip the GnuPG version self-check
SELFCHECK=1
# Set to 1 to run an additional GnuPG version check
SELFCHECK=0
# Set to 1 to build with statically linked libraries.
STATIC=0
@ -240,9 +181,11 @@ STATIC=0
TARBALLS=$(shell pwd)/../tarballs
# Number of parallel make jobs for each package
MAKE_J=3
MAKE_J=6
# Name to use for the w32 installer and sources
INST_NAME=gnupg-w32
# Use this to override the installaion directory for native builds.
@ -251,17 +194,13 @@ INSTALL_PREFIX=none
# Set this to the location of wixtools
WIXPREFIX=$(shell readlink -f ~/w32root/wixtools)
# If patchelf(1) is not availale disable the command.
PATCHELF := $(shell patchelf --version 2>/dev/null >/dev/null || echo "echo please run: ")patchelf
# Read signing information from ~/.gnupg-autogen.rc
define READ_AUTOGEN_template
$(1) = $$(shell grep '^$(1)=' $$$$HOME/.gnupg-autogen.rc|cut -d= -f2)
$(1) = $$(shell grep '^[[:blank:]]*$(1)[[:blank:]]*=' $$$$HOME/.gnupg-autogen.rc|cut -d= -f2|xargs)
endef
$(eval $(call READ_AUTOGEN_template,AUTHENTICODE_SIGNHOST))
$(eval $(call READ_AUTOGEN_template,AUTHENTICODE_TOOL))
$(eval $(call READ_AUTOGEN_template,AUTHENTICODE_KEY))
$(eval $(call READ_AUTOGEN_template,AUTHENTICODE_CERTS))
$(eval $(call READ_AUTOGEN_template,OSSLSIGNCODE))
$(eval $(call READ_AUTOGEN_template,OSSLPKCS11ENGINE))
$(eval $(call READ_AUTOGEN_template,SCUTEMODULE))
$(eval $(call READ_AUTOGEN_template,OVERRIDE_TARBALLS))
@ -282,6 +221,7 @@ AUTHENTICODE_FILES= \
gpgtar.exe \
gpgv.exe \
gpg-card.exe \
keyboxd.exe \
libassuan-0.dll \
libgcrypt-20.dll \
libgpg-error-0.dll \
@ -318,60 +258,16 @@ w32src := $(topsrc)/build-aux/speedo/w32
# Fixme: Do we need to build pkg-config for cross-building?
speedo_spkgs = \
libgpg-error npth libgcrypt
ifeq ($(TARGETOS),w32)
speedo_spkgs += \
zlib bzip2 sqlite
ifeq ($(WITH_GUI),1)
speedo_spkgs += gettext libiconv
endif
endif
speedo_spkgs += \
libassuan libksba
ifeq ($(TARGETOS),w32)
speedo_spkgs += \
ntbtls
endif
speedo_spkgs += \
gnupg
ifeq ($(TARGETOS),w32)
ifeq ($(WITH_GUI),1)
speedo_spkgs += \
libffi glib pkg-config
endif
endif
libgpg-error npth libgcrypt \
zlib bzip2 sqlite \
libassuan libksba ntbtls gnupg
ifeq ($(STATIC),0)
speedo_spkgs += \
gpgme
speedo_spkgs += gpgme
endif
ifeq ($(TARGETOS),w32)
ifeq ($(WITH_GUI),1)
speedo_spkgs += \
libpng \
gdk-pixbuf atk pixman cairo pango gtk+
endif
endif
ifeq ($(TARGETOS),w32)
speedo_spkgs += pinentry
ifeq ($(WITH_GUI),1)
speedo_spkgs += gpa gpgex
endif
else
ifeq ($(WITH_GUI),1)
speedo_spkgs += pinentry gpa
endif
endif
@ -381,16 +277,18 @@ endif
# Packages which are additionally build for 64 bit Windows. They are
# only used for gpgex and thus we need to build them only if we want
# a full installer.
speedo_w64_spkgs =
ifeq ($(WITH_GUI),1)
speedo_w64_spkgs += libgpg-error libiconv gettext libassuan gpgex
ifeq ($(W32VERSION),w64)
# Keep this empty
speedo_w64_spkgs =
else
speedo_w64_spkgs =
endif
# Packages which use the gnupg autogen.sh build style
speedo_gnupg_style = \
libgpg-error npth libgcrypt \
libassuan libksba ntbtls gnupg gpgme \
pinentry gpa gpgex
pinentry
# Packages which use only make and no build directory
speedo_make_only_style = \
@ -416,7 +314,7 @@ endif
# Version numbers of the released packages
gnupg_ver_this = $(shell cat $(topsrc)/VERSION)
gnupg_ver := $(shell awk '$$1=="gnupg24_ver" {print $$2}' swdb.lst)
gnupg_ver := $(shell awk '$$1=="gnupg26_ver" {print $$2}' swdb.lst)
libgpg_error_ver := $(shell awk '$$1=="libgpg_error_ver" {print $$2}' swdb.lst)
libgpg_error_sha1:= $(shell awk '$$1=="libgpg_error_sha1" {print $$2}' swdb.lst)
@ -450,14 +348,6 @@ pinentry_ver := $(shell awk '$$1=="pinentry_ver" {print $$2}' swdb.lst)
pinentry_sha1 := $(shell awk '$$1=="pinentry_sha1" {print $$2}' swdb.lst)
pinentry_sha2 := $(shell awk '$$1=="pinentry_sha2" {print $$2}' swdb.lst)
gpa_ver := $(shell awk '$$1=="gpa_ver" {print $$2}' swdb.lst)
gpa_sha1 := $(shell awk '$$1=="gpa_sha1" {print $$2}' swdb.lst)
gpa_sha2 := $(shell awk '$$1=="gpa_sha2" {print $$2}' swdb.lst)
gpgex_ver := $(shell awk '$$1=="gpgex_ver" {print $$2}' swdb.lst)
gpgex_sha1 := $(shell awk '$$1=="gpgex_sha1" {print $$2}' swdb.lst)
gpgex_sha2 := $(shell awk '$$1=="gpgex_sha2" {print $$2}' swdb.lst)
zlib_ver := $(shell awk '$$1=="zlib_ver" {print $$2}' swdb.lst)
zlib_sha1 := $(shell awk '$$1=="zlib_sha1_gz" {print $$2}' swdb.lst)
zlib_sha2 := $(shell awk '$$1=="zlib_sha2_gz" {print $$2}' swdb.lst)
@ -471,9 +361,9 @@ sqlite_sha1 := $(shell awk '$$1=="sqlite_sha1_gz" {print $$2}' swdb.lst)
sqlite_sha2 := $(shell awk '$$1=="sqlite_sha2_gz" {print $$2}' swdb.lst)
$(info Information from the version database)
$(info Information from the version database:)
$(info GnuPG ..........: $(gnupg_ver) (building $(gnupg_ver_this)))
$(info Libgpg-error ...: $(libgpg_error_ver))
$(info GpgRT ..........: $(libgpg_error_ver))
$(info Npth ...........: $(npth_ver))
$(info Libgcrypt ......: $(libgcrypt_ver))
$(info Libassuan ......: $(libassuan_ver))
@ -484,23 +374,28 @@ $(info SQLite .........: $(sqlite_ver))
$(info NtbTLS .. ......: $(ntbtls_ver))
$(info GPGME ..........: $(gpgme_ver))
$(info Pinentry .......: $(pinentry_ver))
$(info GPA ............: $(gpa_ver))
$(info GpgEX.... ......: $(gpgex_ver))
endif
$(info Information for this run:)
$(info Build type .....: $(WHAT))
$(info Target .........: $(TARGETOS))
ifeq ($(TARGETOS),w32)
ifeq ($(W32VERSION),w64)
$(info Windows version : 64 bit)
else
$(info Windows version : 32 bit)
ifneq ($(W32VERSION),w32)
$(error W32VERSION is not set to a proper value: Use only w32 or w64)
endif
endif
endif
# Version number for external packages
pkg_config_ver = 0.23
libiconv_ver = 1.14
gettext_ver = 0.18.2.1
libffi_ver = 3.0.13
glib_ver = 2.34.3
libpng_ver = 1.4.12
gdk_pixbuf_ver = 2.26.5
atk_ver = 1.32.0
pango_ver = 1.29.4
pixman_ver = 0.32.4
cairo_ver = 1.12.16
gtk__ver = 2.24.17
# The GIT repository. Using a local repo is much faster.
#gitrep = git://git.gnupg.org
@ -551,10 +446,6 @@ else ifeq ($(WHAT),git)
speedo_pkg_gpgme_gitref = master
speedo_pkg_pinentry_git = $(gitrep)/pinentry
speedo_pkg_pinentry_gitref = master
speedo_pkg_gpa_git = $(gitrep)/gpa
speedo_pkg_gpa_gitref = master
speedo_pkg_gpgex_git = $(gitrep)/gpgex
speedo_pkg_gpgex_gitref = master
else ifeq ($(WHAT),release)
speedo_pkg_libgpg_error_tar = \
$(pkgrep)/libgpg-error/libgpg-error-$(libgpg_error_ver).tar.bz2
@ -572,10 +463,6 @@ else ifeq ($(WHAT),release)
$(pkgrep)/gpgme/gpgme-$(gpgme_ver).tar.bz2
speedo_pkg_pinentry_tar = \
$(pkgrep)/pinentry/pinentry-$(pinentry_ver).tar.bz2
speedo_pkg_gpa_tar = \
$(pkgrep)/gpa/gpa-$(gpa_ver).tar.bz2
speedo_pkg_gpgex_tar = \
$(pkg10rep)/gpgex/gpgex-$(gpgex_ver).tar.bz2
else
$(error invalid value for WHAT (use on of: git release this))
endif
@ -586,15 +473,6 @@ speedo_pkg_bzip2_tar = $(pkgrep)/bzip2/bzip2-$(bzip2_ver).tar.gz
speedo_pkg_sqlite_tar = $(pkgrep)/sqlite/sqlite-autoconf-$(sqlite_ver).tar.gz
speedo_pkg_libiconv_tar = $(pkg2rep)/libiconv-$(libiconv_ver).tar.gz
speedo_pkg_gettext_tar = $(pkg2rep)/gettext-$(gettext_ver).tar.gz
speedo_pkg_libffi_tar = $(pkg2rep)/libffi-$(libffi_ver).tar.gz
speedo_pkg_glib_tar = $(pkg2rep)/glib-$(glib_ver).tar.xz
speedo_pkg_libpng_tar = $(pkg2rep)/libpng-$(libpng_ver).tar.bz2
speedo_pkg_gdk_pixbuf_tar = $(pkg2rep)/gdk-pixbuf-$(gdk_pixbuf_ver).tar.xz
speedo_pkg_atk_tar = $(pkg2rep)/atk-$(atk_ver).tar.bz2
speedo_pkg_pango_tar = $(pkg2rep)/pango-$(pango_ver).tar.bz2
speedo_pkg_pixman_tar = $(pkg2rep)/pixman-$(pixman_ver).tar.gz
speedo_pkg_cairo_tar = $(pkg2rep)/cairo-$(cairo_ver).tar.xz
speedo_pkg_gtk__tar = $(pkg2rep)/gtk+-$(gtk__ver).tar.xz
#
@ -603,8 +481,8 @@ speedo_pkg_gtk__tar = $(pkg2rep)/gtk+-$(gtk__ver).tar.xz
speedo_pkg_npth_configure = --enable-static
speedo_pkg_libgpg_error_configure = --enable-static --enable-install-gpg-error-config
speedo_pkg_w64_libgpg_error_configure = --enable-static --enable-install-gpg-error-config
speedo_pkg_libgpg_error_configure = --enable-static
speedo_pkg_w64_libgpg_error_configure = --enable-static
speedo_pkg_libassuan_configure = --enable-static
speedo_pkg_w64_libassuan_configure = --enable-static
@ -637,7 +515,7 @@ speedo_pkg_gnupg_configure = \
else
speedo_pkg_gnupg_configure = --disable-g13 --enable-wks-tools
endif
speedo_pkg_gnupg_extracflags = -g
speedo_pkg_gnupg_extracflags =
# Create the version info files only for W32 so that they won't get
# installed if for example INSTALL_PREFIX=/usr/local is used.
@ -650,25 +528,13 @@ define speedo_pkg_gnupg_post_install
endef
endif
# The LDFLAGS is needed for -lintl for glib.
ifeq ($(WITH_GUI),1)
speedo_pkg_gpgme_configure = \
--enable-static --enable-w32-glib \
--with-gpg-error-prefix=$(idir) \
LDFLAGS=-L$(idir)/lib
else
# The LDFLAGS was needed for -lintl for glib.
speedo_pkg_gpgme_configure = \
--disable-static --disable-w32-glib \
--with-gpg-error-prefix=$(idir) \
LDFLAGS=-L$(idir)/lib
endif
ifeq ($(TARGETOS),w32)
speedo_pkg_pinentry_configure = --disable-pinentry-gtk2
else
speedo_pkg_pinentry_configure = --enable-pinentry-gtk2
endif
speedo_pkg_pinentry_configure += \
--disable-pinentry-qt5 \
--disable-pinentry-qt \
@ -679,22 +545,6 @@ speedo_pkg_pinentry_configure += \
CXXFLAGS=-static-libstdc++
speedo_pkg_gpa_configure = \
--with-libiconv-prefix=$(idir) --with-libintl-prefix=$(idir) \
--with-gpgme-prefix=$(idir) --with-zlib=$(idir) \
--with-libassuan-prefix=$(idir) --with-gpg-error-prefix=$(idir)
speedo_pkg_gpgex_configure = \
--with-gpg-error-prefix=$(idir) \
--with-libassuan-prefix=$(idir) \
--enable-gpa-only
speedo_pkg_w64_gpgex_configure = \
--with-gpg-error-prefix=$(idir6) \
--with-libassuan-prefix=$(idir6) \
--enable-gpa-only
#
# External packages
#
@ -758,74 +608,31 @@ speedo_pkg_gettext_extracflags = -O2
speedo_pkg_gettext_make_dir = gettext-runtime
speedo_pkg_glib_configure = \
--disable-modular-tests \
--with-libiconv=gnu \
CPPFLAGS=-I$(idir)/include \
LDFLAGS=-L$(idir)/lib \
CCC=$(host)-g++ \
LIBFFI_CFLAGS=-I$(idir)/lib/libffi-$(libffi_ver)/include \
LIBFFI_LIBS=\"-L$(idir)/lib -lffi\"
ifeq ($(TARGETOS),w32)
speedo_pkg_glib_extracflags = -march=i486
endif
ifeq ($(TARGETOS),w32)
speedo_pkg_libpng_configure = \
CPPFLAGS=\"-I$(idir)/include -DPNG_BUILD_DLL\" \
LDFLAGS=\"-L$(idir)/lib\" LIBPNG_DEFINES=\"-DPNG_BUILD_DLL\"
else
speedo_pkg_libpng_configure = \
CPPFLAGS=\"-I$(idir)/include\" \
LDFLAGS=\"-L$(idir)/lib\"
endif
ifneq ($(TARGETOS),w32)
speedo_pkg_gdk_pixbuf_configure = --without-libtiff --without-libjpeg
endif
speedo_pkg_pixman_configure = \
CPPFLAGS=-I$(idir)/include \
LDFLAGS=-L$(idir)/lib
ifeq ($(TARGETOS),w32)
speedo_pkg_cairo_configure = \
--disable-qt --disable-ft --disable-fc \
--enable-win32 --enable-win32-font \
CPPFLAGS=-I$(idir)/include \
LDFLAGS=-L$(idir)/lib
else
speedo_pkg_cairo_configure = \
--disable-qt \
CPPFLAGS=-I$(idir)/include \
LDFLAGS=-L$(idir)/lib
endif
speedo_pkg_pango_configure = \
--disable-gtk-doc \
CPPFLAGS=-I$(idir)/include \
LDFLAGS=-L$(idir)/lib
speedo_pkg_gtk__configure = \
--disable-cups \
CPPFLAGS=-I$(idir)/include \
LDFLAGS=-L$(idir)/lib
# ---------
all: all-speedo
install: install-speedo
report: report-speedo
clean: clean-speedo
ifeq ($(W32VERSION),w64)
W32CC_PREFIX = x86_64
else
W32CC_PREFIX = i686
endif
ifeq ($(TARGETOS),w32)
STRIP = i686-w64-mingw32-strip
STRIP = $(W32CC_PREFIX)-w64-mingw32-strip
W32STRIP32 = i686-w64-mingw32-strip
else
STRIP = strip
endif
W32CC = i686-w64-mingw32-gcc
W32CC = $(W32CC_PREFIX)-w64-mingw32-gcc
W32CC32 = i686-w64-mingw32-gcc
-include config.mk
@ -867,9 +674,9 @@ ifneq ($(TARGETOS),)
# Determine build and host system
build := $(shell $(topsrc)/autogen.sh --silent --print-build)
ifeq ($(TARGETOS),w32)
speedo_autogen_buildopt := --build-w32
speedo_autogen_buildopt := --build-$(W32VERSION)
speedo_autogen_buildopt6 := --build-w64
host := $(shell $(topsrc)/autogen.sh --silent --print-host --build-w32)
host := $(shell $(topsrc)/autogen.sh --silent --print-host --build-$(W32VERSION))
host6:= $(shell $(topsrc)/autogen.sh --silent --print-host --build-w64)
speedo_host_build_option := --host=$(host) --build=$(build)
speedo_host_build_option6 := --host=$(host6) --build=$(build)
@ -1093,7 +900,7 @@ else ifneq ($(findstring $(1),$(speedo_gnupg_style)),)
mkdir "$$$${pkgbdir}"; \
cd "$$$${pkgbdir}"; \
if [ -n "$(speedo_autogen_buildopt)" ]; then \
eval AUTOGEN_SH_SILENT=1 w32root="$(idir)" \
eval AUTOGEN_SH_SILENT=1 $(W32VERSION)root="$(idir)" \
"$$$${pkgsdir}/autogen.sh" \
$(speedo_autogen_buildopt) \
$$$${pkgcfg} $$$${pkgextracflags}; \
@ -1285,6 +1092,71 @@ clean-pkg-versions:
@: >$(bdir)/pkg-versions.txt
all-speedo: $(stampdir)/stamp-final
ifneq ($(TARGETOS),w32)
@(set -e;\
cd "$(idir)"; \
echo "speedo: Making RPATH relative";\
for d in bin sbin libexec lib; do \
for f in $$(find $$d -type f); do \
if file $$f | grep ELF >/dev/null; then \
$(PATCHELF) --set-rpath '$$ORIGIN/../lib' $$f; \
fi; \
done; \
done; \
echo "sysconfdir = /etc/gnupg" >bin/gpgconf.ctl ;\
echo "rootdir = $(idir)" >>bin/gpgconf.ctl ;\
echo "speedo: /*" ;\
echo "speedo: * Now copy $(idir)/ to the final location and" ;\
echo "speedo: * adjust $(idir)/bin/gpgconf.ctl accordingly" ;\
echo "speedo: * Or run:" ;\
echo "speedo: * make -f $(topsrc)/build-aux/speedo.mk install SYSROOT=/usr/local/gnupg26" ;\
echo "speedo: * ldconfig -n /usr/local/gnupg26/lib";\
echo "speedo: */")
endif
# No dependencies for the install target; instead we test whether
# some of the to be installed files are available. This avoids
# accidental rebuilds under a wrong account.
install-speedo:
ifneq ($(TARGETOS),w32)
@(set -e; \
cd "$(idir)"; \
if [ x"$$SYSROOT" = x ]; then \
echo "speedo: ERROR: SYSROOT has not been given";\
echo "speedo: Set SYSROOT to the desired install directory";\
echo "speedo: Example:";\
echo "speedo: make -f $(topsrc)/build-aux/speedo.mk install SYSROOT=/usr/local/gnupg26";\
echo "speedo: ldconfig -n /usr/local/gnupg26/lib";\
exit 1;\
fi;\
if [ ! -d "$$SYSROOT"/bin ]; then if ! mkdir "$$SYSROOT"/bin; then \
echo "speedo: error creating target directory";\
exit 1;\
fi; fi;\
if ! touch "$$SYSROOT"/bin/gpgconf.ctl; then \
echo "speedo: Error writing $$SYSROOT/bin/gpgconf.ctl";\
echo "speedo: Please check the permissions";\
exit 1;\
fi;\
if [ ! -f bin/gpgconf.ctl ]; then \
echo "speedo: ERROR: Nothing to install";\
echo "speedo: Please run a build first";\
echo "speedo: Example:";\
echo "speedo: make -f build-aux/speedo.mk native";\
exit 1;\
fi;\
echo "speedo: Installing files to $$SYSROOT";\
find . -type f -executable \
-exec install -Dm 755 "{}" "$$SYSROOT/{}" \; ;\
find . -type f \! -executable \
-exec install -Dm 644 "{}" "$$SYSROOT/{}" \; ;\
echo "sysconfdir = /etc/gnupg" > "$$SYSROOT"/bin/gpgconf.ctl ;\
echo "rootdir = $$SYSROOT" >> "$$SYSROOT"/bin/gpgconf.ctl ;\
echo '/*' ;\
echo " * Installation to $$SYSROOT done" ;\
echo ' */' )
endif
report-speedo: $(addprefix report-,$(speedo_build_list))
@ -1342,13 +1214,13 @@ $(bdir)/README.txt: $(bdir)/NEWS.tmp $(topsrc)/README $(w32src)/README.txt \
$(bdir)/g4wihelp.dll: $(w32src)/g4wihelp.c $(w32src)/exdll.h $(w32src)/exdll.c
(set -e; cd $(bdir); \
$(W32CC) -DUNICODE -static-libgcc -I . -O2 -c \
$(W32CC32) -DUNICODE -static-libgcc -I . -O2 -c \
-o exdll.o $(w32src)/exdll.c; \
$(W32CC) -DUNICODE -static-libgcc -I. -shared -O2 \
$(W32CC32) -DUNICODE -static-libgcc -I. -shared -O2 \
-o g4wihelp.dll $(w32src)/g4wihelp.c exdll.o \
-lwinmm -lgdi32 -luserenv \
-lshell32 -loleaut32 -lshlwapi -lmsimg32; \
$(STRIP) g4wihelp.dll)
$(W32STRIP32) g4wihelp.dll)
w32_insthelpers: $(bdir)/g4wihelp.dll
@ -1356,9 +1228,6 @@ $(bdir)/inst-options.ini: $(w32src)/inst-options.ini
cat $(w32src)/inst-options.ini >$(bdir)/inst-options.ini
extra_installer_options =
ifeq ($(WITH_GUI),1)
extra_installer_options += -DWITH_GUI=1
endif
# Note that we sign only when doing the final installer.
installer: all w32_insthelpers $(w32src)/inst-options.ini $(bdir)/README.txt
@ -1447,7 +1316,7 @@ wixlib: installer $(bdir)/README.txt $(w32src)/wixlib.wxs
)
define MKSWDB_commands
( pref="#+macro: gnupg24_w32_$(3)" ;\
( pref="#+macro: gnupg26_w32_$(3)" ;\
echo "$${pref}ver $(INST_VERSION)_$(BUILD_DATESTR)" ;\
echo "$${pref}date $(2)" ;\
echo "$${pref}size $$(wc -c <$(1)|awk '{print int($$1/1024)}')k";\
@ -1458,35 +1327,13 @@ endef
# Sign the file $1 and save the result as $2
define AUTHENTICODE_sign
set -e;\
if [ -n "$(AUTHENTICODE_SIGNHOST)" ]; then \
echo "speedo: Signing via host $(AUTHENTICODE_SIGNHOST)";\
scp $(1) "$(AUTHENTICODE_SIGNHOST):a.exe" ;\
ssh "$(AUTHENTICODE_SIGNHOST)" '$(AUTHENTICODE_TOOL)' sign \
/a /n '"g10 Code GmbH"' \
/tr 'http://rfc3161timestamp.globalsign.com/advanced' /td sha256 \
/fd sha256 /du https://gnupg.org a.exe ;\
scp "$(AUTHENTICODE_SIGNHOST):a.exe" $(2);\
echo "speedo: signed file is '$(2)'" ;\
elif [ "$(AUTHENTICODE_KEY)" = card ]; then \
echo "speedo: Signing using a card: '$(1)'";\
$(OSSLSIGNCODE) sign \
-pkcs11engine $(OSSLPKCS11ENGINE) \
-pkcs11module $(SCUTEMODULE) \
-certs $(AUTHENTICODE_CERTS) \
-h sha256 -n GnuPG -i https://gnupg.org \
-ts http://rfc3161timestamp.globalsign.com/advanced \
-in $(1) -out $(2).tmp ; mv $(2).tmp $(2) ; \
elif [ -e "$(AUTHENTICODE_KEY)" ]; then \
echo "speedo: Signing using key $(AUTHENTICODE_KEY)";\
osslsigncode sign -certs $(AUTHENTICODE_CERTS) \
-pkcs12 $(AUTHENTICODE_KEY) -askpass \
-ts "http://timestamp.globalsign.com/scripts/timstamp.dll" \
-h sha256 -n GnuPG -i https://gnupg.org \
-in $(1) -out $(2) ;\
(set -e; \
if gpg-authcode-sign.sh --version >/dev/null; then \
gpg-authcode-sign.sh "$(1)" "$(2)"; \
else \
echo "speedo: WARNING: Binaries are not signed"; \
fi
echo 2>&1 "warning: Please install gpg-authcode-sign.sh to sign files." ;\
[ "$(1)" != "$(2)" ] && cp "$(1)" "$(2)" ;\
fi)
endef
# Help target for testing to sign a file.
@ -1543,10 +1390,8 @@ sign-installer:
if [ -f "$${msifile}" ]; then \
$(call MKSWDB_commands,$${msifile},$${reldate},"wixlib_"); \
fi; \
echo "speedo: /*" ;\
echo "speedo: * Verification result" ;\
echo "speedo: */" ;\
osslsigncode verify $${exefile} \
echo "speedo: /* (osslsigncode verify disabled) */" ;\
echo osslsigncode verify $${exefile} \
)
@ -1566,4 +1411,4 @@ check-tools: $(stampdir)/stamp-directories
# Mark phony targets
#
.PHONY: all all-speedo report-speedo clean-stamps clean-speedo installer \
w32_insthelpers check-tools clean-pkg-versions
w32_insthelpers check-tools clean-pkg-versions install-speedo install

View File

@ -46,7 +46,7 @@ Unicode true
!define PRETTY_PACKAGE "GNU Privacy Guard"
!define PRETTY_PACKAGE_SHORT "GnuPG"
!define COMPANY "The GnuPG Project"
!define COPYRIGHT "Copyright (C) 2021 g10 Code GmbH"
!define COPYRIGHT "Copyright (C) 2024 g10 Code GmbH"
!define DESCRIPTION "GnuPG: The GNU Privacy Guard for Windows"
!define INSTALL_DIR "GnuPG"
@ -63,13 +63,13 @@ Unicode true
GnuPG includes an advanced key management facility and is compliant \
with the OpenPGP Internet standard as described in RFC-4880. \
\r\n\r\n$_CLICK \
\r\n\r\n\r\n\r\n\r\nThis is GnuPG version ${VERSION}.\r\n\
\r\n\r\n\r\n\r\n\r\nThis is GnuPG version ${VERSION} (64 bit).\r\n\
File version: ${PROD_VERSION}\r\n\
Release date: ${BUILD_ISODATE}"
!define ABOUT_GERMAN \
"GnuPG is die häufigst verwendete Software zur Mail- und Datenverschlüsselung.\
\r\n\r\n$_CLICK \
\r\n\r\n\r\n\r\n\r\nDies ist GnuPG Version ${VERSION}.\r\n\
\r\n\r\n\r\n\r\n\r\nDies ist GnuPG Version ${VERSION} (64 bit).\r\n\
Dateiversion: ${PROD_VERSION}\r\n\
Releasedatum: ${BUILD_ISODATE}"
@ -119,7 +119,7 @@ OutFile "${NAME}-${VERSION}_${BUILD_DATESTR}.exe"
!ifndef INSTALL_DIR
!define INSTALL_DIR "GnuPG"
!endif
InstallDir "$PROGRAMFILES\${INSTALL_DIR}"
InstallDir "$PROGRAMFILES64\${INSTALL_DIR}"
# Add version information to the file properties.
VIProductVersion "${PROD_VERSION}"
@ -1067,9 +1067,7 @@ Section "-un.gnupglast"
nsExec::ExecToLog '"$INSTDIR\bin\launch-gpa" "--stop-server"'
no_uiserver:
ifFileExists "$INSTDIR\bin\gpgconf.exe" 0 no_gpgconf
nsExec::ExecToLog '"$INSTDIR\bin\gpgconf" "--kill" "gpg-agent"'
nsExec::ExecToLog '"$INSTDIR\bin\gpgconf" "--kill" "dirmngr"'
nsExec::ExecToLog '"$INSTDIR\bin\gpgconf" "--kill" "keyboxd"'
nsExec::ExecToLog '"$INSTDIR\bin\gpgconf" "--kill" "all"'
no_gpgconf:
SectionEnd
@ -1467,7 +1465,12 @@ Function .onInit
Call G4wRunOnce
SetOutPath $TEMP
${IfNot} ${RunningX64}
MessageBox MB_OK "Sorry this version runs only on x64 machines"
Abort
${EndIf}
SetOutPath $TEMP
#!ifdef SOURCES
# File /oname=gpgspltmp.bmp "${TOP_SRCDIR}/doc/logo/gnupg-logo-400px.bmp"
# # We play the tune only for the soruce installer
@ -1488,7 +1491,7 @@ Function .onInit
Var /GLOBAL changed_dir
# Check if the install directory was modified on the command line
StrCmp "$INSTDIR" "$PROGRAMFILES\${INSTALL_DIR}" unmodified 0
StrCmp "$INSTDIR" "$PROGRAMFILES64\${INSTALL_DIR}" unmodified 0
# It is modified. Save that value.
StrCpy $changed_dir "$INSTDIR"

View File

@ -61,9 +61,12 @@ and then manually edited:
<Component Id="cmp74961776CCC7B203F500FE261DC12F92" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="FBA2569C-554D-4C06-88FC-0FD6541B5B4B">
<File Id="filB82A767EB9971018C006215A9FDE77EF" KeyPath="yes" Source="$(var.SourceDir)\bin\gpg-connect-agent.exe"/>
</Component>
<Component Id="cmp74961776CCC7B203F500FE261DC12F94" Directory="dirAA72FFDDFA224FB221D53750596B0144" Guid="FBA2569C-554D-4C06-88FC-0FD6541B5B4C">
<Component Id="cmp74961776CCC7B203F500FE261DC12F94" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="FBA2569C-554D-4C06-88FC-0FD6541B5B4C">
<File Id="filB82A767EB9971018C006215A9FDE77F1" KeyPath="yes" Source="$(var.SourceDir)\bin\gpg-card.exe"/>
</Component>
<Component Id="cmp74961776CCC7B203F500FE261DC12F95" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="3134BF55-46AF-4B76-A535-DC1EDDB0DBFD">
<File Id="filB82A767EB9971018C006215A9FDE77F2" KeyPath="yes" Source="$(var.SourceDir)\libexec\keyboxd.exe"/>
</Component>
<Component Id="cmp6C1FB70721B208E33DB24296B93AB93F" Directory="dirAA72FFDDFA224FB221D53750596B0142" Guid="FE29D2AA-3151-4421-B8C0-355F69F267A1">
<File Id="fil563D2C0464DCE7ECADE6E15C0FC65821" KeyPath="yes" Source="$(var.SourceDir)\libexec\gpg-preset-passphrase.exe"/>
</Component>

View File

@ -58,14 +58,14 @@ common_sources = \
openpgpdefs.h \
gc-opt-flags.h \
sexp-parse.h \
tlv.c tlv.h tlv-builder.c \
tlv.c tlv.h tlv-builder.c tlv-parser.c \
init.c init.h \
sexputil.c \
sysutils.c sysutils.h \
homedir.c \
gettime.c gettime.h \
yesno.c \
b64enc.c b64dec.c zb32.c zb32.h \
zb32.c zb32.h \
convert.c \
percent.c \
mbox-util.c mbox-util.h \
@ -97,8 +97,8 @@ common_sources = \
openpgp-fpr.c \
comopt.c comopt.h \
compliance.c compliance.h \
pkscreening.c pkscreening.h
pkscreening.c pkscreening.h \
kem.c
if HAVE_W32_SYSTEM
common_sources += w32-reg.c w32-cmdline.c
@ -161,15 +161,16 @@ module_tests = t-stringhelp t-timestuff \
t-convert t-percent t-gettime t-sysutils t-sexputil \
t-session-env t-openpgp-oid t-ssh-utils \
t-mapstrings t-zb32 t-mbox-util t-iobuf t-strlist \
t-name-value t-ccparray t-recsel t-w32-cmdline
t-name-value t-ccparray t-recsel t-w32-cmdline t-exechelp
if HAVE_W32_SYSTEM
module_tests += t-w32-reg
else
module_tests += t-exechelp t-exectool
module_tests += t-exectool
endif
if MAINTAINER_MODE
module_maint_tests = t-helpfile t-b64
module_maint_tests = t-helpfile
else
module_maint_tests =
endif
@ -196,7 +197,6 @@ t_gettime_LDADD = $(t_common_ldadd)
t_sysutils_LDADD = $(t_common_ldadd)
t_helpfile_LDADD = $(t_common_ldadd)
t_sexputil_LDADD = $(t_common_ldadd)
t_b64_LDADD = $(t_common_ldadd)
t_exechelp_LDADD = $(t_common_ldadd)
t_exectool_LDADD = $(t_common_ldadd)
t_session_env_LDADD = $(t_common_ldadd)

View File

@ -386,7 +386,8 @@ start_new_service (assuan_context_t *r_ctx,
const char *opt_lc_ctype,
const char *opt_lc_messages,
session_env_t session_env,
int autostart, int verbose, int debug,
unsigned int flags,
int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
@ -445,7 +446,7 @@ start_new_service (assuan_context_t *r_ctx,
}
err = assuan_socket_connect (ctx, sockname, 0, connect_flags);
if (err && autostart)
if (err && (flags & ASSHELP_FLAG_AUTOSTART))
{
char *abs_homedir;
lock_spawn_t lock;
@ -523,16 +524,12 @@ start_new_service (assuan_context_t *r_ctx,
&& assuan_socket_connect (ctx, sockname, 0, connect_flags))
{
#ifdef HAVE_W32_SYSTEM
err = gnupg_spawn_process_detached (program? program : program_name,
argv, NULL);
err = gnupg_process_spawn (program? program : program_name, argv,
GNUPG_PROCESS_DETACHED,
NULL, NULL, NULL);
#else /*!W32*/
pid_t pid;
err = gnupg_spawn_process_fd (program? program : program_name,
argv, -1, -1, -1, &pid);
if (!err)
err = gnupg_wait_process (program? program : program_name,
pid, 1, NULL);
err = gnupg_process_spawn (program? program : program_name, argv,
0, NULL, NULL, NULL);
#endif /*!W32*/
if (err)
log_error ("failed to start %s '%s': %s\n",
@ -551,7 +548,8 @@ start_new_service (assuan_context_t *r_ctx,
xfree (sockname);
if (err)
{
if (autostart || gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
if ((flags & ASSHELP_FLAG_AUTOSTART)
|| gpg_err_code (err) != GPG_ERR_ASS_CONNECT_FAILED)
log_error ("can't connect to the %s: %s\n",
printed_name, gpg_strerror (err));
assuan_release (ctx);
@ -603,55 +601,58 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
const char *opt_lc_ctype,
const char *opt_lc_messages,
session_env_t session_env,
int autostart, int verbose, int debug,
unsigned int flags,
int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
return start_new_service (r_ctx, GNUPG_MODULE_NAME_AGENT,
errsource, agent_program,
opt_lc_ctype, opt_lc_messages, session_env,
autostart, verbose, debug,
flags, verbose, debug,
status_cb, status_cb_arg);
}
/* Try to connect to the dirmngr via a socket. On platforms
supporting it, start it up if needed and if AUTOSTART is true.
supporting it, start it up if needed and if ASSHELP_FLAG_AUTOSTART is set.
Returns a new assuan context at R_CTX or an error code. */
gpg_error_t
start_new_keyboxd (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *keyboxd_program,
int autostart, int verbose, int debug,
unsigned int flags,
int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
return start_new_service (r_ctx, GNUPG_MODULE_NAME_KEYBOXD,
errsource, keyboxd_program,
NULL, NULL, NULL,
autostart, verbose, debug,
flags, verbose, debug,
status_cb, status_cb_arg);
}
/* Try to connect to the dirmngr via a socket. On platforms
supporting it, start it up if needed and if AUTOSTART is true.
supporting it, start it up if needed and if ASSHELP_FLAG_AUTOSTART is set.
Returns a new assuan context at R_CTX or an error code. */
gpg_error_t
start_new_dirmngr (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *dirmngr_program,
int autostart, int verbose, int debug,
unsigned int flags,
int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg)
{
#ifndef USE_DIRMNGR_AUTO_START
autostart = 0;
flags &= ~ASSHELP_FLAG_AUTOSTART; /* Clear flag. */
#endif
return start_new_service (r_ctx, GNUPG_MODULE_NAME_DIRMNGR,
errsource, dirmngr_program,
NULL, NULL, NULL,
autostart, verbose, debug,
flags, verbose, debug,
status_cb, status_cb_arg);
}

View File

@ -37,6 +37,8 @@
#include "util.h"
/*-- asshelp.c --*/
#define ASSHELP_FLAG_AUTOSTART 1 /* Autostart the new service. */
void setup_libassuan_logging (unsigned int *debug_var_address,
int (*log_monitor)(assuan_context_t ctx,
@ -61,7 +63,8 @@ start_new_gpg_agent (assuan_context_t *r_ctx,
const char *opt_lc_ctype,
const char *opt_lc_messages,
session_env_t session_env,
int autostart, int verbose, int debug,
unsigned int flags,
int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg);
@ -71,7 +74,8 @@ gpg_error_t
start_new_keyboxd (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *keyboxd_program,
int autostart, int verbose, int debug,
unsigned int flags,
int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg);
@ -81,7 +85,8 @@ gpg_error_t
start_new_dirmngr (assuan_context_t *r_ctx,
gpg_err_source_t errsource,
const char *dirmngr_program,
int autostart, int verbose, int debug,
unsigned int flags,
int verbose, int debug,
gpg_error_t (*status_cb)(ctrl_t, int, ...),
ctrl_t status_cb_arg);

View File

@ -45,8 +45,8 @@ struct log_item_s
int intvalue; /* A logged integer value. */
char *string; /* A malloced string or NULL. */
ksba_cert_t cert; /* A certifciate or NULL. */
int have_err:1;
int have_intvalue:1;
unsigned int have_err:1;
unsigned int have_intvalue:1;
};
typedef struct log_item_s *log_item_t;

View File

@ -1,254 +0,0 @@
/* b64dec.c - Simple Base64 decoder.
* Copyright (C) 2008, 2011 Free Software Foundation, Inc.
* Copyright (C) 2008, 2011, 2016 g10 Code GmbH
*
* This file is part of GnuPG.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "i18n.h"
#include "util.h"
/* The reverse base-64 list used for base-64 decoding. */
static unsigned char const asctobin[128] =
{
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
};
enum decoder_states
{
s_init, s_idle, s_lfseen, s_beginseen, s_waitheader, s_waitblank, s_begin,
s_b64_0, s_b64_1, s_b64_2, s_b64_3,
s_waitendtitle, s_waitend
};
/* Initialize the context for the base64 decoder. If TITLE is NULL a
plain base64 decoding is done. If it is the empty string the
decoder will skip everything until a "-----BEGIN " line has been
seen, decoding ends at a "----END " line. */
gpg_error_t
b64dec_start (struct b64state *state, const char *title)
{
memset (state, 0, sizeof *state);
if (title)
{
state->title = xtrystrdup (title);
if (!state->title)
state->lasterr = gpg_error_from_syserror ();
else
state->idx = s_init;
}
else
state->idx = s_b64_0;
return state->lasterr;
}
/* Do in-place decoding of base-64 data of LENGTH in BUFFER. Stores the
new length of the buffer at R_NBYTES. */
gpg_error_t
b64dec_proc (struct b64state *state, void *buffer, size_t length,
size_t *r_nbytes)
{
enum decoder_states ds = state->idx;
unsigned char val = state->radbuf[0];
int pos = state->quad_count;
char *d, *s;
if (state->lasterr)
return state->lasterr;
if (state->stop_seen)
{
*r_nbytes = 0;
state->lasterr = gpg_error (GPG_ERR_EOF);
xfree (state->title);
state->title = NULL;
return state->lasterr;
}
for (s=d=buffer; length && !state->stop_seen; length--, s++)
{
again:
switch (ds)
{
case s_idle:
if (*s == '\n')
{
ds = s_lfseen;
pos = 0;
}
break;
case s_init:
ds = s_lfseen;
/* fall through */
case s_lfseen:
if (*s != "-----BEGIN "[pos])
{
ds = s_idle;
goto again;
}
else if (pos == 10)
{
pos = 0;
ds = s_beginseen;
}
else
pos++;
break;
case s_beginseen:
if (*s != "PGP "[pos])
ds = s_begin; /* Not a PGP armor. */
else if (pos == 3)
ds = s_waitheader;
else
pos++;
break;
case s_waitheader:
if (*s == '\n')
ds = s_waitblank;
break;
case s_waitblank:
if (*s == '\n')
ds = s_b64_0; /* blank line found. */
else if (*s == ' ' || *s == '\r' || *s == '\t')
; /* Ignore spaces. */
else
{
/* Armor header line. Note that we don't care that our
* FSM accepts a header prefixed with spaces. */
ds = s_waitheader; /* Wait for next header. */
}
break;
case s_begin:
if (*s == '\n')
ds = s_b64_0;
break;
case s_b64_0:
case s_b64_1:
case s_b64_2:
case s_b64_3:
{
int c;
if (*s == '-' && state->title)
{
/* Not a valid Base64 character: assume end
header. */
ds = s_waitend;
}
else if (*s == '=')
{
/* Pad character: stop */
if (ds == s_b64_1)
*d++ = val;
ds = state->title? s_waitendtitle : s_waitend;
}
else if (*s == '\n' || *s == ' ' || *s == '\r' || *s == '\t')
; /* Skip white spaces. */
else if ( (*s & 0x80)
|| (c = asctobin[*(unsigned char *)s]) == 255)
{
/* Skip invalid encodings. */
state->invalid_encoding = 1;
}
else if (ds == s_b64_0)
{
val = c << 2;
ds = s_b64_1;
}
else if (ds == s_b64_1)
{
val |= (c>>4)&3;
*d++ = val;
val = (c<<4)&0xf0;
ds = s_b64_2;
}
else if (ds == s_b64_2)
{
val |= (c>>2)&15;
*d++ = val;
val = (c<<6)&0xc0;
ds = s_b64_3;
}
else
{
val |= c&0x3f;
*d++ = val;
ds = s_b64_0;
}
}
break;
case s_waitendtitle:
if (*s == '-')
ds = s_waitend;
break;
case s_waitend:
if ( *s == '\n')
state->stop_seen = 1;
break;
default:
BUG();
}
}
state->idx = ds;
state->radbuf[0] = val;
state->quad_count = pos;
*r_nbytes = (d -(char*) buffer);
return 0;
}
/* This function needs to be called before releasing the decoder
state. It may return an error code in case an encoding error has
been found during decoding. */
gpg_error_t
b64dec_finish (struct b64state *state)
{
xfree (state->title);
state->title = NULL;
if (state->lasterr)
return state->lasterr;
return state->invalid_encoding? gpg_error(GPG_ERR_BAD_DATA): 0;
}

View File

@ -1,422 +0,0 @@
/* b64enc.c - Simple Base64 encoder.
* Copyright (C) 2001, 2003, 2004, 2008, 2010,
* 2011 Free Software Foundation, Inc.
* Copyright (C) 2001, 2003, 2004, 2008, 2010,
* 2011 g10 Code GmbH
*
* This file is part of GnuPG.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "i18n.h"
#include "util.h"
#define B64ENC_DID_HEADER 1
#define B64ENC_DID_TRAILER 2
#define B64ENC_NO_LINEFEEDS 16
#define B64ENC_USE_PGPCRC 32
/* The base-64 character list */
static unsigned char bintoasc[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
/* Stuff required to create the OpenPGP CRC. This crc_table has been
created using this code:
#include <stdio.h>
#include <stdint.h>
#define CRCPOLY 0x864CFB
int
main (void)
{
int i, j;
uint32_t t;
uint32_t crc_table[256];
crc_table[0] = 0;
for (i=j=0; j < 128; j++ )
{
t = crc_table[j];
if ( (t & 0x00800000) )
{
t <<= 1;
crc_table[i++] = t ^ CRCPOLY;
crc_table[i++] = t;
}
else
{
t <<= 1;
crc_table[i++] = t;
crc_table[i++] = t ^ CRCPOLY;
}
}
puts ("static const u32 crc_table[256] = {");
for (i=j=0; i < 256; i++)
{
printf ("%s 0x%08lx", j? "":" ", (unsigned long)crc_table[i]);
if (i != 255)
{
putchar (',');
if ( ++j > 5)
{
j = 0;
putchar ('\n');
}
}
}
puts ("\n};");
return 0;
}
*/
#define CRCINIT 0xB704CE
static const u32 crc_table[256] = {
0x00000000, 0x00864cfb, 0x018ad50d, 0x010c99f6, 0x0393e6e1, 0x0315aa1a,
0x021933ec, 0x029f7f17, 0x07a18139, 0x0727cdc2, 0x062b5434, 0x06ad18cf,
0x043267d8, 0x04b42b23, 0x05b8b2d5, 0x053efe2e, 0x0fc54e89, 0x0f430272,
0x0e4f9b84, 0x0ec9d77f, 0x0c56a868, 0x0cd0e493, 0x0ddc7d65, 0x0d5a319e,
0x0864cfb0, 0x08e2834b, 0x09ee1abd, 0x09685646, 0x0bf72951, 0x0b7165aa,
0x0a7dfc5c, 0x0afbb0a7, 0x1f0cd1e9, 0x1f8a9d12, 0x1e8604e4, 0x1e00481f,
0x1c9f3708, 0x1c197bf3, 0x1d15e205, 0x1d93aefe, 0x18ad50d0, 0x182b1c2b,
0x192785dd, 0x19a1c926, 0x1b3eb631, 0x1bb8faca, 0x1ab4633c, 0x1a322fc7,
0x10c99f60, 0x104fd39b, 0x11434a6d, 0x11c50696, 0x135a7981, 0x13dc357a,
0x12d0ac8c, 0x1256e077, 0x17681e59, 0x17ee52a2, 0x16e2cb54, 0x166487af,
0x14fbf8b8, 0x147db443, 0x15712db5, 0x15f7614e, 0x3e19a3d2, 0x3e9fef29,
0x3f9376df, 0x3f153a24, 0x3d8a4533, 0x3d0c09c8, 0x3c00903e, 0x3c86dcc5,
0x39b822eb, 0x393e6e10, 0x3832f7e6, 0x38b4bb1d, 0x3a2bc40a, 0x3aad88f1,
0x3ba11107, 0x3b275dfc, 0x31dced5b, 0x315aa1a0, 0x30563856, 0x30d074ad,
0x324f0bba, 0x32c94741, 0x33c5deb7, 0x3343924c, 0x367d6c62, 0x36fb2099,
0x37f7b96f, 0x3771f594, 0x35ee8a83, 0x3568c678, 0x34645f8e, 0x34e21375,
0x2115723b, 0x21933ec0, 0x209fa736, 0x2019ebcd, 0x228694da, 0x2200d821,
0x230c41d7, 0x238a0d2c, 0x26b4f302, 0x2632bff9, 0x273e260f, 0x27b86af4,
0x252715e3, 0x25a15918, 0x24adc0ee, 0x242b8c15, 0x2ed03cb2, 0x2e567049,
0x2f5ae9bf, 0x2fdca544, 0x2d43da53, 0x2dc596a8, 0x2cc90f5e, 0x2c4f43a5,
0x2971bd8b, 0x29f7f170, 0x28fb6886, 0x287d247d, 0x2ae25b6a, 0x2a641791,
0x2b688e67, 0x2beec29c, 0x7c3347a4, 0x7cb50b5f, 0x7db992a9, 0x7d3fde52,
0x7fa0a145, 0x7f26edbe, 0x7e2a7448, 0x7eac38b3, 0x7b92c69d, 0x7b148a66,
0x7a181390, 0x7a9e5f6b, 0x7801207c, 0x78876c87, 0x798bf571, 0x790db98a,
0x73f6092d, 0x737045d6, 0x727cdc20, 0x72fa90db, 0x7065efcc, 0x70e3a337,
0x71ef3ac1, 0x7169763a, 0x74578814, 0x74d1c4ef, 0x75dd5d19, 0x755b11e2,
0x77c46ef5, 0x7742220e, 0x764ebbf8, 0x76c8f703, 0x633f964d, 0x63b9dab6,
0x62b54340, 0x62330fbb, 0x60ac70ac, 0x602a3c57, 0x6126a5a1, 0x61a0e95a,
0x649e1774, 0x64185b8f, 0x6514c279, 0x65928e82, 0x670df195, 0x678bbd6e,
0x66872498, 0x66016863, 0x6cfad8c4, 0x6c7c943f, 0x6d700dc9, 0x6df64132,
0x6f693e25, 0x6fef72de, 0x6ee3eb28, 0x6e65a7d3, 0x6b5b59fd, 0x6bdd1506,
0x6ad18cf0, 0x6a57c00b, 0x68c8bf1c, 0x684ef3e7, 0x69426a11, 0x69c426ea,
0x422ae476, 0x42aca88d, 0x43a0317b, 0x43267d80, 0x41b90297, 0x413f4e6c,
0x4033d79a, 0x40b59b61, 0x458b654f, 0x450d29b4, 0x4401b042, 0x4487fcb9,
0x461883ae, 0x469ecf55, 0x479256a3, 0x47141a58, 0x4defaaff, 0x4d69e604,
0x4c657ff2, 0x4ce33309, 0x4e7c4c1e, 0x4efa00e5, 0x4ff69913, 0x4f70d5e8,
0x4a4e2bc6, 0x4ac8673d, 0x4bc4fecb, 0x4b42b230, 0x49ddcd27, 0x495b81dc,
0x4857182a, 0x48d154d1, 0x5d26359f, 0x5da07964, 0x5cace092, 0x5c2aac69,
0x5eb5d37e, 0x5e339f85, 0x5f3f0673, 0x5fb94a88, 0x5a87b4a6, 0x5a01f85d,
0x5b0d61ab, 0x5b8b2d50, 0x59145247, 0x59921ebc, 0x589e874a, 0x5818cbb1,
0x52e37b16, 0x526537ed, 0x5369ae1b, 0x53efe2e0, 0x51709df7, 0x51f6d10c,
0x50fa48fa, 0x507c0401, 0x5542fa2f, 0x55c4b6d4, 0x54c82f22, 0x544e63d9,
0x56d11cce, 0x56575035, 0x575bc9c3, 0x57dd8538
};
static gpg_error_t
enc_start (struct b64state *state, FILE *fp, estream_t stream,
const char *title)
{
memset (state, 0, sizeof *state);
state->fp = fp;
state->stream = stream;
state->lasterr = 0;
if (title && !*title)
state->flags |= B64ENC_NO_LINEFEEDS;
else if (title)
{
if (!strncmp (title, "PGP ", 4))
{
state->flags |= B64ENC_USE_PGPCRC;
state->crc = CRCINIT;
}
state->title = xtrystrdup (title);
if (!state->title)
state->lasterr = gpg_error_from_syserror ();
}
return state->lasterr;
}
/* Prepare for base-64 writing to the stream FP. If TITLE is not NULL
and not an empty string, this string will be used as the title for
the armor lines, with TITLE being an empty string, we don't write
the header lines and furthermore even don't write any linefeeds.
If TITLE starts with "PGP " the OpenPGP CRC checksum will be
written as well. With TITLE being NULL, we merely don't write
header but make sure that lines are not too long. Note, that we
don't write any output unless at least one byte get written using
b64enc_write. */
gpg_error_t
b64enc_start (struct b64state *state, FILE *fp, const char *title)
{
return enc_start (state, fp, NULL, title);
}
/* Same as b64enc_start but takes an estream. */
gpg_error_t
b64enc_start_es (struct b64state *state, estream_t fp, const char *title)
{
return enc_start (state, NULL, fp, title);
}
static int
my_fputs (const char *string, struct b64state *state)
{
if (state->stream)
return es_fputs (string, state->stream);
else
return fputs (string, state->fp);
}
/* Write NBYTES from BUFFER to the Base 64 stream identified by
STATE. With BUFFER and NBYTES being 0, merely do a fflush on the
stream. */
gpg_error_t
b64enc_write (struct b64state *state, const void *buffer, size_t nbytes)
{
unsigned char radbuf[4];
int idx, quad_count;
const unsigned char *p;
if (state->lasterr)
return state->lasterr;
if (!nbytes)
{
if (buffer)
if (state->stream? es_fflush (state->stream) : fflush (state->fp))
goto write_error;
return 0;
}
if (!(state->flags & B64ENC_DID_HEADER))
{
if (state->title)
{
if ( my_fputs ("-----BEGIN ", state) == EOF
|| my_fputs (state->title, state) == EOF
|| my_fputs ("-----\n", state) == EOF)
goto write_error;
if ( (state->flags & B64ENC_USE_PGPCRC)
&& my_fputs ("\n", state) == EOF)
goto write_error;
}
state->flags |= B64ENC_DID_HEADER;
}
idx = state->idx;
quad_count = state->quad_count;
assert (idx < 4);
memcpy (radbuf, state->radbuf, idx);
if ( (state->flags & B64ENC_USE_PGPCRC) )
{
size_t n;
u32 crc = state->crc;
for (p=buffer, n=nbytes; n; p++, n-- )
crc = ((u32)crc << 8) ^ crc_table[((crc >> 16)&0xff) ^ *p];
state->crc = (crc & 0x00ffffff);
}
for (p=buffer; nbytes; p++, nbytes--)
{
radbuf[idx++] = *p;
if (idx > 2)
{
char tmp[4];
tmp[0] = bintoasc[(*radbuf >> 2) & 077];
tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
tmp[3] = bintoasc[radbuf[2]&077];
if (state->stream)
{
for (idx=0; idx < 4; idx++)
es_putc (tmp[idx], state->stream);
idx = 0;
if (es_ferror (state->stream))
goto write_error;
}
else
{
for (idx=0; idx < 4; idx++)
putc (tmp[idx], state->fp);
idx = 0;
if (ferror (state->fp))
goto write_error;
}
if (++quad_count >= (64/4))
{
quad_count = 0;
if (!(state->flags & B64ENC_NO_LINEFEEDS)
&& my_fputs ("\n", state) == EOF)
goto write_error;
}
}
}
memcpy (state->radbuf, radbuf, idx);
state->idx = idx;
state->quad_count = quad_count;
return 0;
write_error:
state->lasterr = gpg_error_from_syserror ();
if (state->title)
{
xfree (state->title);
state->title = NULL;
}
return state->lasterr;
}
gpg_error_t
b64enc_finish (struct b64state *state)
{
gpg_error_t err = 0;
unsigned char radbuf[4];
int idx, quad_count;
char tmp[4];
if (state->lasterr)
return state->lasterr;
if (!(state->flags & B64ENC_DID_HEADER))
goto cleanup;
/* Flush the base64 encoding */
idx = state->idx;
quad_count = state->quad_count;
assert (idx < 4);
memcpy (radbuf, state->radbuf, idx);
if (idx)
{
tmp[0] = bintoasc[(*radbuf>>2)&077];
if (idx == 1)
{
tmp[1] = bintoasc[((*radbuf << 4) & 060) & 077];
tmp[2] = '=';
tmp[3] = '=';
}
else
{
tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
tmp[2] = bintoasc[((radbuf[1] << 2) & 074) & 077];
tmp[3] = '=';
}
if (state->stream)
{
for (idx=0; idx < 4; idx++)
es_putc (tmp[idx], state->stream);
if (es_ferror (state->stream))
goto write_error;
}
else
{
for (idx=0; idx < 4; idx++)
putc (tmp[idx], state->fp);
if (ferror (state->fp))
goto write_error;
}
if (++quad_count >= (64/4))
{
quad_count = 0;
if (!(state->flags & B64ENC_NO_LINEFEEDS)
&& my_fputs ("\n", state) == EOF)
goto write_error;
}
}
/* Finish the last line and write the trailer. */
if (quad_count
&& !(state->flags & B64ENC_NO_LINEFEEDS)
&& my_fputs ("\n", state) == EOF)
goto write_error;
if ( (state->flags & B64ENC_USE_PGPCRC) )
{
/* Write the CRC. */
my_fputs ("=", state);
radbuf[0] = state->crc >>16;
radbuf[1] = state->crc >> 8;
radbuf[2] = state->crc;
tmp[0] = bintoasc[(*radbuf>>2)&077];
tmp[1] = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
tmp[2] = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
tmp[3] = bintoasc[radbuf[2]&077];
if (state->stream)
{
for (idx=0; idx < 4; idx++)
es_putc (tmp[idx], state->stream);
if (es_ferror (state->stream))
goto write_error;
}
else
{
for (idx=0; idx < 4; idx++)
putc (tmp[idx], state->fp);
if (ferror (state->fp))
goto write_error;
}
if (!(state->flags & B64ENC_NO_LINEFEEDS)
&& my_fputs ("\n", state) == EOF)
goto write_error;
}
if (state->title)
{
if ( my_fputs ("-----END ", state) == EOF
|| my_fputs (state->title, state) == EOF
|| my_fputs ("-----\n", state) == EOF)
goto write_error;
}
goto cleanup;
write_error:
err = gpg_error_from_syserror ();
cleanup:
if (state->title)
{
xfree (state->title);
state->title = NULL;
}
state->fp = NULL;
state->stream = NULL;
state->lasterr = err;
return err;
}

View File

@ -41,7 +41,7 @@ static int initialized;
static int module;
/* This value is used by DSA and RSA checks in addition to the hard
* coded length checks. It allows to increase the required key length
* coded length checks. It allows one to increase the required key length
* using a confue file. */
static unsigned int min_compliant_rsa_length;
@ -139,7 +139,7 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
gcry_mpi_t key[], unsigned int keylength,
const char *curvename)
{
enum { is_rsa, is_dsa, is_elg, is_ecc } algotype;
enum { is_rsa, is_dsa, is_elg, is_ecc, is_kem } algotype;
int result = 0;
if (! initialized)
@ -173,6 +173,10 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
case PUBKEY_ALGO_ELGAMAL:
return 0; /* Signing with Elgamal is not at all supported. */
case PUBKEY_ALGO_KYBER:
algotype = is_kem;
break;
default: /* Unknown. */
return 0;
}
@ -227,6 +231,10 @@ gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,
|| !strcmp (curvename, "brainpoolP512r1")));
break;
case is_kem:
result = 0;
break;
default:
result = 0;
}
@ -256,6 +264,13 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
if (! initialized)
return 1;
/* Map the the generic ECC algo to ECDSA if requested. */
if ((algo_flags & PK_ALGO_FLAG_ECC18)
&& algo == GCRY_PK_ECC
&& (use == PK_USE_VERIFICATION
|| use == PK_USE_SIGNING))
algo = GCRY_PK_ECDSA;
switch (compliance)
{
case CO_DE_VS:
@ -280,7 +295,6 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
default:
log_assert (!"reached");
}
(void)algo_flags;
break;
case PUBKEY_ALGO_DSA:
@ -301,7 +315,7 @@ gnupg_pk_is_allowed (enum gnupg_compliance_mode compliance,
result = (use == PK_USE_DECRYPTION);
break;
case PUBKEY_ALGO_ECDH:
case PUBKEY_ALGO_ECDH: /* Same value as GCRY_PK_ECC, i.e. 18 */
case GCRY_PK_ECDH:
if (use == PK_USE_DECRYPTION)
result = 1;
@ -549,6 +563,9 @@ gnupg_rng_is_compliant (enum gnupg_compliance_mode compliance)
int *result;
int res;
/* #warning debug code ahead */
/* return 1; */
result = get_compliance_cache (compliance, 1);
if (result && *result != -1)

View File

@ -50,6 +50,7 @@ enum pk_use_case
/* Flags to distinguish public key algorithm variants. */
#define PK_ALGO_FLAG_RSAPSS 1 /* Use rsaPSS padding. */
#define PK_ALGO_FLAG_ECC18 256 /* GCRY_PK_ECC is used in a generic way. */
int gnupg_pk_is_compliant (enum gnupg_compliance_mode compliance, int algo,

View File

@ -291,6 +291,7 @@
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/utsname.h>
# include <dirent.h>
#endif
#include <sys/types.h>
#include <sys/time.h>
@ -393,9 +394,18 @@ struct dotlock_handle
unsigned int locked:1; /* Lock status. */
unsigned int disable:1; /* If true, locking is disabled. */
unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking. */
unsigned int by_parent:1; /* Parent does the locking. */
unsigned int no_write:1; /* No write to the lockfile. */
int extra_fd; /* A place for the caller to store an FD. */
/* An optional info callback - see dotlock_set_info_cb. */
int (*info_cb)(dotlock_t, void *,
enum dotlock_reasons reason,
const char *,...);
void *info_cb_value;
#ifdef HAVE_DOSISH_SYSTEM
HANDLE lockhd; /* The W32 handle of the lock file. */
#else /*!HAVE_DOSISH_SYSTEM */
@ -545,8 +555,15 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
{
int e = errno;
my_info_2 ("error opening lockfile '%s': %s\n",
h->lockname, strerror(errno) );
if (errno != ENOENT)
{
my_info_2 ("error opening lockfile '%s': %s\n",
h->lockname, strerror(errno) );
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
"error opening lockfile '%s': %s\n",
h->lockname, strerror (errno) );
}
if (buffer != buffer_space)
xfree (buffer);
my_set_errno (e); /* Need to return ERRNO here. */
@ -564,6 +581,10 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
{
int e = errno;
my_info_1 ("error reading lockfile '%s'\n", h->lockname );
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
"error reading lockfile '%s': %s\n",
h->lockname, strerror (errno) );
close (fd);
if (buffer != buffer_space)
xfree (buffer);
@ -583,6 +604,9 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
if (nread < 11)
{
my_info_1 ("invalid size of lockfile '%s'\n", h->lockname);
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_INV_FILE,
"invalid size of lockfile '%s'\n", h->lockname);
if (buffer != buffer_space)
xfree (buffer);
my_set_errno (EINVAL);
@ -594,6 +618,9 @@ read_lockfile (dotlock_t h, int *same_node, int *r_fd)
|| !pid )
{
my_error_2 ("invalid pid %d in lockfile '%s'\n", pid, h->lockname);
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_INV_FILE,
"invalid pid %d in lockfile '%s'\n", pid, h->lockname);
if (buffer != buffer_space)
xfree (buffer);
my_set_errno (EINVAL);
@ -655,6 +682,80 @@ use_hardlinks_p (const char *tname)
#ifdef HAVE_POSIX_SYSTEM
static int
dotlock_get_process_id (dotlock_t h)
{
return h->by_parent? (int)getppid(): (int)getpid();
}
static int
dotlock_detect_tname (dotlock_t h)
{
struct stat sb;
DIR *dir;
char *dirname;
char *basename;
struct dirent *d;
int r;
if (stat (h->lockname, &sb))
return -1;
basename = make_basename (h->lockname, NULL);
dirname = make_dirname (h->lockname);
dir = opendir (dirname);
if (dir == NULL)
{
xfree (basename);
xfree (dirname);
return -1;
}
while ((d = readdir (dir)))
if (sb.st_ino == d->d_ino && strcmp (d->d_name, basename))
break;
if (d)
{
int len = strlen (h->tname);
int dlen = strlen (d->d_name);
const char *tname_path;
if (dlen > len)
{
xfree (basename);
xfree (dirname);
return -1;
}
strcpy (stpcpy (stpcpy (h->tname, dirname), DIRSEP_S), d->d_name);
h->use_o_excl = 0;
tname_path = strchr (h->tname + strlen (dirname) + 2, '.');
if (!tname_path)
{
xfree (basename);
xfree (dirname);
return -1;
}
h->nodename_off = tname_path - h->tname + 1;
}
else
h->use_o_excl = 1;
r = closedir (dir);
if (r)
{
xfree (basename);
xfree (dirname);
return r;
}
xfree (basename);
xfree (dirname);
return 0;
}
/* Locking core for Unix. It used a temporary file and the link
system call to make locking an atomic operation. */
static dotlock_t
@ -667,8 +768,10 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
int dirpartlen;
struct utsname utsbuf;
size_t tnamelen;
int pid;
snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
pid = dotlock_get_process_id (h);
snprintf (pidstr, sizeof pidstr, "%10d\n", pid);
/* Create a temporary file. */
if ( uname ( &utsbuf ) )
@ -702,10 +805,17 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
}
h->nodename_len = strlen (nodename);
if (h->no_write)
{
memset (h->tname, '_', tnamelen);
h->tname[tnamelen] = 0;
goto skip_write;
}
snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
h->nodename_off = strlen (h->tname);
snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
"%s.%d", nodename, (int)getpid ());
"%s.%d", nodename, pid);
do
{
@ -722,6 +832,10 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
UNLOCK_all_lockfiles ();
my_error_2 (_("failed to create temporary file '%s': %s\n"),
h->tname, strerror (errno));
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_WAITING,
_("failed to create temporary file '%s': %s\n"),
h->tname, strerror (errno));
xfree (h->tname);
xfree (h);
my_set_errno (saveerrno);
@ -755,11 +869,16 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
int saveerrno = errno;
my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n"
, h->tname, strerror (saveerrno));
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_CONFIG_TEST,
"can't check whether hardlinks are supported for '%s': %s\n"
, h->tname, strerror (saveerrno));
my_set_errno (saveerrno);
}
goto write_failed;
}
skip_write:
h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
if (!h->lockname)
{
@ -775,6 +894,20 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
UNLOCK_all_lockfiles ();
if (h->no_write)
{
if (dotlock_detect_tname (h) < 0)
{
xfree (h->lockname);
xfree (h->tname);
xfree (h);
my_set_errno (EACCES);
return NULL;
}
h->locked = 1;
}
return h;
write_failed:
@ -783,6 +916,11 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
all_lockfiles = h->next;
UNLOCK_all_lockfiles ();
my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
_("error writing to '%s': %s\n"),
h->tname, strerror (errno));
if ( fd != -1 )
close (fd);
unlink (h->tname);
@ -849,6 +987,10 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
all_lockfiles = h->next;
UNLOCK_all_lockfiles ();
my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
_("can't create '%s': %s\n"),
h->lockname, w32_strerror (-1));
xfree (h->lockname);
xfree (h);
my_set_errno (saveerrno);
@ -873,7 +1015,15 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
used.
FLAGS must be 0.
FLAGS may include DOTLOCK_PREPARE_CREATE bit, which only allocates
the handle and requires a further call to dotlock_finish_create.
This can be used to set a callback between these calls.
FLAGS may include DOTLOCK_LOCK_BY_PARENT bit, when it's the parent
process controlling the lock. This is used by dotlock util.
FLAGS may include DOTLOCK_LOCKED bit, when it should not create the
lockfile, but to unlock. This is used by dotlock util.
The function returns an new handle which needs to be released using
destroy_dotlock but gets also released at the termination of the
@ -885,8 +1035,13 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
{
static int initialized;
dotlock_t h;
#ifndef HAVE_DOSISH_SYSTEM
int by_parent = 0;
int no_write = 0;
#endif
if ( !initialized )
if ( !(flags & DOTLOCK_LOCK_BY_PARENT)
&& !initialized )
{
atexit (dotlock_remove_lockfiles);
initialized = 1;
@ -895,7 +1050,15 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
if ( !file_to_lock )
return NULL; /* Only initialization was requested. */
if (flags)
#ifndef HAVE_DOSISH_SYSTEM
if ((flags & DOTLOCK_LOCK_BY_PARENT) || (flags & DOTLOCK_LOCKED))
{
by_parent = !!(flags & DOTLOCK_LOCK_BY_PARENT);
no_write = !!(flags & DOTLOCK_LOCKED);
flags &= ~(DOTLOCK_LOCK_BY_PARENT | DOTLOCK_LOCKED);
}
#endif
if ((flags & ~DOTLOCK_PREPARE_CREATE))
{
my_set_errno (EINVAL);
return NULL;
@ -905,6 +1068,10 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
if (!h)
return NULL;
h->extra_fd = -1;
#ifndef HAVE_DOSISH_SYSTEM
h->by_parent = by_parent;
h->no_write = no_write;
#endif
if (never_lock)
{
@ -916,6 +1083,24 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
return h;
}
if ((flags & DOTLOCK_PREPARE_CREATE))
return h;
else
return dotlock_finish_create (h, file_to_lock);
}
/* This function may be used along with dotlock_create (file_name,
* DOTLOCK_PREPARE_CREATE) to finish the creation call. The given
* filename shall be the same as passed to dotlock_create. On success
* the same handle H is returned, on error NULL is returned and H is
* released. */
dotlock_t
dotlock_finish_create (dotlock_t h, const char *file_to_lock)
{
if (!h || !file_to_lock)
return NULL;
#ifdef HAVE_DOSISH_SYSTEM
return dotlock_create_w32 (h, file_to_lock);
#else /*!HAVE_DOSISH_SYSTEM */
@ -942,6 +1127,24 @@ dotlock_get_fd (dotlock_t h)
}
/* Set a callback function for info diagnostics. The callback
* function CB is called with the handle, the opaque value OPAQUE, a
* reason code, and a format string with its arguments. The callback
* shall return 0 to continue operation or true in which case the
* current function will be terminated with an error. */
void
dotlock_set_info_cb (dotlock_t h,
int (*cb)(dotlock_t, void *,
enum dotlock_reasons reason,
const char *,...),
void *opaque)
{
h->info_cb = cb;
h->info_cb_value = opaque;
}
#ifdef HAVE_POSIX_SYSTEM
/* Unix specific code of destroy_dotlock. */
@ -952,7 +1155,6 @@ dotlock_destroy_unix (dotlock_t h)
unlink (h->lockname);
if (h->tname && !h->use_o_excl)
unlink (h->tname);
xfree (h->tname);
}
#endif /*HAVE_POSIX_SYSTEM*/
@ -998,19 +1200,74 @@ dotlock_destroy (dotlock_t h)
UNLOCK_all_lockfiles ();
/* Then destroy the lock. */
if (!h->disable)
if (!h->disable
&& (!h->by_parent || h->no_write))
{
/* NOTE: under the condition of (by_parent && !no_write),
it doesn't come here. So, the lock file remains. */
#ifdef HAVE_DOSISH_SYSTEM
dotlock_destroy_w32 (h);
#else /* !HAVE_DOSISH_SYSTEM */
dotlock_destroy_unix (h);
#endif /* HAVE_DOSISH_SYSTEM */
xfree (h->lockname);
}
#ifdef HAVE_POSIX_SYSTEM
/* When DOTLOCK_LOCK_BY_PARENT and lock fails,
the temporary file created should be removed. */
if (h->by_parent && !h->no_write && !h->locked)
if (h->tname && !h->use_o_excl)
unlink (h->tname);
xfree (h->tname);
#endif
xfree (h->lockname);
xfree(h);
}
/* Return true if H has been taken. */
int
dotlock_is_locked (dotlock_t h)
{
return h && !!h->locked;
}
/* Return the next interval to wait. WTIME and TIMEOUT are pointers
* to the current state and are updated by this function. The
* returned value might be different from the value of WTIME. */
static int
next_wait_interval (int *wtime, long *timeout)
{
int result;
/* Wait until lock has been released. We use retry intervals of 4,
* 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 512, 1024, 2048ms, and
* so on. If wait-forever was requested we add a small random value
* to have different timeouts per process. */
if (!*wtime)
*wtime = 4;
else if (*wtime < 2048)
*wtime *= 2;
else
*wtime = 512;
result = *wtime;
if (*wtime > 8 && *timeout < 0)
result += ((unsigned int)getpid() % 37);
if (*timeout > 0)
{
if (result > *timeout)
result = *timeout;
*timeout -= result;
}
return result;
}
#ifdef HAVE_POSIX_SYSTEM
/* Unix specific code of make_dotlock. Returns 0 on success and -1 on
@ -1019,6 +1276,7 @@ static int
dotlock_take_unix (dotlock_t h, long timeout)
{
int wtime = 0;
int timedout = 0;
int sumtime = 0;
int pid;
int lastpid = -1;
@ -1047,6 +1305,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
saveerrno = errno;
my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
h->lockname, strerror (saveerrno));
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
"lock not made: open(O_EXCL) of '%s' failed: %s\n",
h->lockname, strerror (saveerrno));
my_set_errno (saveerrno);
return -1;
}
@ -1054,7 +1316,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
{
char pidstr[16];
snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
snprintf (pidstr, sizeof pidstr, "%10d\n",
dotlock_get_process_id (h));
if (write (fd, pidstr, 11 ) == 11
&& write (fd, h->tname + h->nodename_off,h->nodename_len)
== h->nodename_len
@ -1068,6 +1331,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
saveerrno = errno;
my_error_2 ("lock not made: writing to '%s' failed: %s\n",
h->lockname, strerror (errno));
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
"lock not made: writing to '%s' failed: %s\n",
h->lockname, strerror (errno));
close (fd);
unlink (h->lockname);
my_set_errno (saveerrno);
@ -1086,6 +1353,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
saveerrno = errno;
my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
strerror (errno));
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
"lock not made: Oops: stat of tmp file failed: %s\n",
strerror (errno));
/* In theory this might be a severe error: It is possible
that link succeeded but stat failed due to changed
permissions. We can't do anything about it, though. */
@ -1107,16 +1378,19 @@ dotlock_take_unix (dotlock_t h, long timeout)
{
saveerrno = errno;
my_info_0 ("cannot read lockfile\n");
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
"cannot read lockfile\n");
my_set_errno (saveerrno);
return -1;
}
my_info_0 ("lockfile disappeared\n");
goto again;
}
else if ( (pid == getpid() && same_node)
else if ( (pid == dotlock_get_process_id (h) && same_node && !h->by_parent)
|| (same_node && kill (pid, 0) && errno == ESRCH) )
/* Stale lockfile is detected. */
{
/* Stale lockfile is detected. */
struct stat sb;
/* Check if it's unlocked during examining the lockfile. */
@ -1159,6 +1433,9 @@ dotlock_take_unix (dotlock_t h, long timeout)
unlink (h->lockname);
my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
close (fd);
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_STALE_REMOVED,
_("removing stale lockfile (created by %d)\n"), pid);
goto again;
}
@ -1170,42 +1447,39 @@ dotlock_take_unix (dotlock_t h, long timeout)
if (timeout)
{
struct timeval tv;
int wtimereal;
/* Wait until lock has been released. We use increasing retry
intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
but reset it if the lock owner meanwhile changed. */
if (!wtime || ownerchanged)
wtime = 50;
else if (wtime < 800)
wtime *= 2;
else if (wtime == 800)
wtime = 2000;
else if (wtime < 8000)
wtime *= 2;
if (ownerchanged)
wtime = 0; /* Reset because owner chnaged. */
if (timeout > 0)
{
if (wtime > timeout)
wtime = timeout;
timeout -= wtime;
}
wtimereal = next_wait_interval (&wtime, &timeout);
if (!timeout)
timedout = 1; /* remember. */
sumtime += wtime;
sumtime += wtimereal;
if (sumtime >= 1500)
{
sumtime = 0;
my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
if (h->info_cb
&& h->info_cb (h, h->info_cb_value, DOTLOCK_WAITING,
_("waiting for lock (held by %d%s) %s...\n"),
pid, maybe_dead,
maybe_deadlock(h)? _("(deadlock?) "):""))
{
my_set_errno (ECANCELED);
return -1;
}
}
tv.tv_sec = wtime / 1000;
tv.tv_usec = (wtime % 1000) * 1000;
tv.tv_sec = wtimereal / 1000;
tv.tv_usec = (wtimereal % 1000) * 1000;
select (0, NULL, NULL, NULL, &tv);
goto again;
}
my_set_errno (EACCES);
my_set_errno (timedout? ETIMEDOUT : EACCES);
return -1;
}
#endif /*HAVE_POSIX_SYSTEM*/
@ -1218,6 +1492,7 @@ static int
dotlock_take_w32 (dotlock_t h, long timeout)
{
int wtime = 0;
int timedout = 0;
int w32err;
OVERLAPPED ovl;
@ -1236,38 +1511,39 @@ dotlock_take_w32 (dotlock_t h, long timeout)
{
my_error_2 (_("lock '%s' not made: %s\n"),
h->lockname, w32_strerror (w32err));
my_set_errno (map_w32_to_errno (w32err));
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
_("lock '%s' not made: %s\n"),
h->lockname, w32_strerror (w32err));
_set_errno (map_w32_to_errno (w32err));
return -1;
}
if (timeout)
{
/* Wait until lock has been released. We use retry intervals of
50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s. */
if (!wtime)
wtime = 50;
else if (wtime < 800)
wtime *= 2;
else if (wtime == 800)
wtime = 2000;
else if (wtime < 8000)
wtime *= 2;
int wtimereal;
if (timeout > 0)
{
if (wtime > timeout)
wtime = timeout;
timeout -= wtime;
}
wtimereal = next_wait_interval (&wtime, &timeout);
if (!timeout)
timedout = 1; /* remember. */
if (wtime >= 800)
my_info_1 (_("waiting for lock %s...\n"), h->lockname);
{
my_info_1 (_("waiting for lock %s...\n"), h->lockname);
if (h->info_cb
&& h->info_cb (h, h->info_cb_value, DOTLOCK_WAITING,
_("waiting for lock %s...\n"), h->lockname))
{
my_set_errno (ECANCELED);
return -1;
}
}
Sleep (wtime);
Sleep (wtimereal);
goto again;
}
my_set_errno (EACCES);
my_set_errno (timedout? ETIMEDOUT : EACCES);
return -1;
}
#endif /*HAVE_DOSISH_SYSTEM*/
@ -1314,12 +1590,18 @@ dotlock_release_unix (dotlock_t h)
{
saveerrno = errno;
my_error_0 ("release_dotlock: lockfile error\n");
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
"release_dotlock: lockfile error\n");
my_set_errno (saveerrno);
return -1;
}
if ( pid != getpid() || !same_node )
if ( pid != dotlock_get_process_id (h) || !same_node )
{
my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_CONFLICT,
"release_dotlock: not our lock (pid=%d)\n", pid);
my_set_errno (EACCES);
return -1;
}
@ -1329,6 +1611,10 @@ dotlock_release_unix (dotlock_t h)
saveerrno = errno;
my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
h->lockname);
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
"release_dotlock: error removing lockfile '%s'\n",
h->lockname);
my_set_errno (saveerrno);
return -1;
}
@ -1349,10 +1635,15 @@ dotlock_release_w32 (dotlock_t h)
memset (&ovl, 0, sizeof ovl);
if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
{
int saveerrno = map_w32_to_errno (GetLastError ());
int ec = (int)GetLastError ();
my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
h->lockname, w32_strerror (-1));
my_set_errno (saveerrno);
h->lockname, w32_strerror (ec));
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_FILE_ERROR,
"release_dotlock: error removing lockfile '%s': %s\n",
h->lockname, w32_strerror (ec));
my_set_errno (map_w32_to_errno (ec));
return -1;
}
@ -1383,6 +1674,9 @@ dotlock_release (dotlock_t h)
if ( !h->locked )
{
my_debug_1 ("Oops, '%s' is not locked\n", h->lockname);
if (h->info_cb)
h->info_cb (h, h->info_cb_value, DOTLOCK_NOT_LOCKED,
"Oops, '%s' is not locked\n", h->lockname);
return 0;
}

View File

@ -97,12 +97,35 @@ extern "C"
struct dotlock_handle;
typedef struct dotlock_handle *dotlock_t;
enum dotlock_reasons
{
DOTLOCK_CONFIG_TEST, /* Can't check system - function terminates. */
DOTLOCK_FILE_ERROR, /* General file error - function terminates. */
DOTLOCK_INV_FILE, /* Invalid file - function terminates. */
DOTLOCK_CONFLICT, /* Something is wrong - function terminates. */
DOTLOCK_NOT_LOCKED, /* Not locked - No action required. */
DOTLOCK_STALE_REMOVED, /* Stale lock file was removed - retrying. */
DOTLOCK_WAITING /* Waiting for the lock - may be terminated. */
};
/* Flags for dotlock_create. */
#define DOTLOCK_PREPARE_CREATE (1U << 5) /* Require dotlock_finish_create. */
#define DOTLOCK_LOCK_BY_PARENT (1U << 6) /* Used by dotlock util. */
#define DOTLOCK_LOCKED (1U << 7) /* Used by dotlock util. */
void dotlock_disable (void);
dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags);
dotlock_t dotlock_finish_create (dotlock_t h, const char *file_to_lock);
void dotlock_set_fd (dotlock_t h, int fd);
int dotlock_get_fd (dotlock_t h);
void dotlock_set_info_cb (dotlock_t h,
int (*cb)(dotlock_t, void *,
enum dotlock_reasons reason,
const char *,...),
void *opaque);
void dotlock_destroy (dotlock_t h);
int dotlock_take (dotlock_t h, long timeout);
int dotlock_is_locked (dotlock_t h);
int dotlock_release (dotlock_t h);
void dotlock_remove_lockfiles (void);

View File

@ -34,12 +34,15 @@
#ifndef __MINGW32__
# include <dlfcn.h>
#else
# include <errhandlingapi.h>
# include <handleapi.h>
# include <libloaderapi.h>
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# endif
# include <windows.h>
# include "utf8conv.h"
# include "mischelp.h"
# define RTLD_LAZY 0
# ifndef RTLD_LAZY
# define RTLD_LAZY 0
# endif
static inline void *
dlopen (const char *name, int flag)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -73,140 +73,103 @@ gpg_error_t gnupg_create_pipe (int filedes[2]);
void gnupg_close_pipe (int fd);
#define GNUPG_SPAWN_NONBLOCK 16
#define GNUPG_SPAWN_RUN_ASFW 64
#define GNUPG_SPAWN_DETACHED 128
#define GNUPG_SPAWN_KEEP_STDIN 256
#define GNUPG_SPAWN_KEEP_STDOUT 512
#define GNUPG_SPAWN_KEEP_STDERR 1024
/* The opaque type for a subprocess. */
typedef struct gnupg_process *gnupg_process_t;
#ifdef HAVE_W32_SYSTEM
struct spawn_cb_arg;
#ifdef NEED_STRUCT_SPAWN_CB_ARG
struct spawn_cb_arg {
HANDLE hd[3];
HANDLE *inherit_hds;
BOOL allow_foreground_window;
void *arg;
};
#endif
#else
struct spawn_cb_arg {
int fds[3];
int *except_fds;
void *arg;
};
#endif
/* Fork and exec the program PGMNAME.
#define GNUPG_PROCESS_DETACHED (1 << 1)
If R_INFP is NULL connect stdin of the new process to /dev/null; if
it is not NULL store the address of a pointer to a new estream
there. If R_OUTFP is NULL connect stdout of the new process to
/dev/null; if it is not NULL store the address of a pointer to a
new estream there. If R_ERRFP is NULL connect stderr of the new
process to /dev/null; if it is not NULL store the address of a
pointer to a new estream there. On success the pid of the new
process is stored at PID. On error -1 is stored at PID and if
R_OUTFP or R_ERRFP are not NULL, NULL is stored there.
/* Specify how to keep/connect standard fds. */
#define GNUPG_PROCESS_STDIN_PIPE (1 << 8)
#define GNUPG_PROCESS_STDOUT_PIPE (1 << 9)
#define GNUPG_PROCESS_STDERR_PIPE (1 << 10)
#define GNUPG_PROCESS_STDINOUT_SOCKETPAIR (1 << 11)
#define GNUPG_PROCESS_STDIN_KEEP (1 << 12)
#define GNUPG_PROCESS_STDOUT_KEEP (1 << 13)
#define GNUPG_PROCESS_STDERR_KEEP (1 << 14)
#define GNUPG_PROCESS_STDFDS_SETTING ( GNUPG_PROCESS_STDIN_PIPE \
| GNUPG_PROCESS_STDOUT_PIPE | GNUPG_PROCESS_STDERR_PIPE \
| GNUPG_PROCESS_STDINOUT_SOCKETPAIR | GNUPG_PROCESS_STDIN_KEEP \
| GNUPG_PROCESS_STDOUT_KEEP | GNUPG_PROCESS_STDERR_KEEP)
The arguments for the process are expected in the NULL terminated
array ARGV. The program name itself should not be included there.
If PREEXEC is not NULL, the given function will be called right
before the exec.
#define GNUPG_PROCESS_STREAM_NONBLOCK (1 << 16)
IF EXCEPT is not NULL, it is expected to be an ordered list of file
descriptors, terminated by an entry with the value (-1). These
file descriptors won't be closed before spawning a new program.
/* Spawn helper. */
void gnupg_spawn_helper (struct spawn_cb_arg *sca);
Returns 0 on success or an error code. Calling gnupg_wait_process
and gnupg_release_process is required if the function succeeded.
/* Spawn PGMNAME. */
gpg_err_code_t gnupg_process_spawn (const char *pgmname, const char *argv[],
unsigned int flags,
void (*spawn_cb) (struct spawn_cb_arg *),
void *spawn_cb_arg,
gnupg_process_t *r_process);
FLAGS is a bit vector:
/* Get FDs for subprocess I/O. It is the caller which should care
FDs (closing FDs). */
gpg_err_code_t gnupg_process_get_fds (gnupg_process_t process,
unsigned int flags,
int *r_fd_in, int *r_fd_out,
int *r_fd_err);
GNUPG_SPAWN_NONBLOCK
If set the two output streams are created in non-blocking
mode and the input stream is switched to non-blocking mode.
This is merely a convenience feature because the caller
could do the same with gpgrt_set_nonblock. Does not yet
work for Windows.
/* Get STREAMs for subprocess I/O. It is the caller which should care
STREAMs (closing STREAMs). */
gpg_err_code_t gnupg_process_get_streams (gnupg_process_t process,
unsigned int flags,
gpgrt_stream_t *r_fp_in,
gpgrt_stream_t *r_fp_out,
gpgrt_stream_t *r_fp_err);
GNUPG_SPAWN_DETACHED
If set the process will be started as a background process.
This flag is only useful under W32 (but not W32CE) systems,
so that no new console is created and pops up a console
window when starting the server. Does not work on W32CE.
enum gnupg_process_requests
{
/* Portable requests */
GNUPG_PROCESS_NOP = 0,
GNUPG_PROCESS_GET_PROC_ID = 1,
GNUPG_PROCESS_GET_EXIT_ID = 2,
GNUPG_SPAWN_RUN_ASFW
On W32 (but not on W32CE) run AllowSetForegroundWindow for
the child. Note that due to unknown problems this actually
allows SetForegroundWindow for all children of this process.
/* POSIX only */
GNUPG_PROCESS_GET_PID = 16,
GNUPG_PROCESS_GET_WSTATUS = 17,
GNUPG_PROCESS_KILL = 18,
GNUPG_SPAWN_KEEP_STDIN
GNUPG_SPAWN_KEEP_STDOUT
GNUPG_SPAWN_KEEP_STDERR
Do not assign /dev/null to a non-required standard file
descriptor.
/* Windows only */
GNUPG_PROCESS_GET_P_HANDLE = 32,
GNUPG_PROCESS_GET_HANDLES = 33,
GNUPG_PROCESS_GET_EXIT_CODE = 34,
GNUPG_PROCESS_KILL_WITH_EC = 35
};
*/
gpg_error_t
gnupg_spawn_process (const char *pgmname, const char *argv[],
int *execpt, unsigned int flags,
estream_t *r_infp,
estream_t *r_outfp,
estream_t *r_errfp,
pid_t *pid);
/* Control of a process. */
gpg_err_code_t gnupg_process_ctl (gnupg_process_t process,
unsigned int request, ...);
/* Wait for a single PROCESS. */
gpg_err_code_t gnupg_process_wait (gnupg_process_t process, int hang);
/* Simplified version of gnupg_spawn_process. This function forks and
then execs PGMNAME, while connecting INFD to stdin, OUTFD to stdout
and ERRFD to stderr (any of them may be -1 to connect them to
/dev/null). The arguments for the process are expected in the NULL
terminated array ARGV. The program name itself should not be
included there. Calling gnupg_wait_process and
gnupg_release_process is required. Returns 0 on success or an
error code. */
gpg_error_t gnupg_spawn_process_fd (const char *pgmname,
const char *argv[],
int infd, int outfd, int errfd,
pid_t *pid);
/* Terminate a PROCESS. */
gpg_err_code_t gnupg_process_terminate (gnupg_process_t process);
/* Release PROCESS resources. */
void gnupg_process_release (gnupg_process_t process);
/* If HANG is true, waits for the process identified by PID to exit;
if HANG is false, checks whether the process has terminated.
PGMNAME should be the same as supplied to the spawn function and is
only used for diagnostics. Return values:
0
The process exited successful. 0 is stored at R_EXITCODE.
GPG_ERR_GENERAL
The process exited without success. The exit code of process
is then stored at R_EXITCODE. An exit code of -1 indicates
that the process terminated abnormally (e.g. due to a signal).
GPG_ERR_TIMEOUT
The process is still running (returned only if HANG is false).
GPG_ERR_INV_VALUE
An invalid PID has been specified.
Other error codes may be returned as well. Unless otherwise noted,
-1 will be stored at R_EXITCODE. R_EXITCODE may be passed as NULL
if the exit code is not required (in that case an error message will
be printed). Note that under Windows PID is not the process id but
the handle of the process. */
gpg_error_t gnupg_wait_process (const char *pgmname, pid_t pid, int hang,
int *r_exitcode);
/* Like gnupg_wait_process, but for COUNT processes. */
gpg_error_t gnupg_wait_processes (const char **pgmnames, pid_t *pids,
size_t count, int hang, int *r_exitcodes);
/* Kill a process; that is send an appropriate signal to the process.
gnupg_wait_process must be called to actually remove the process
from the system. An invalid PID is ignored. */
void gnupg_kill_process (pid_t pid);
/* Release the process identified by PID. This function is actually
only required for Windows but it does not harm to always call it.
It is a nop if PID is invalid. */
void gnupg_release_process (pid_t pid);
/* Spawn a new process and immediately detach from it. The name of
the program to exec is PGMNAME and its arguments are in ARGV (the
programname is automatically passed as first argument).
Environment strings in ENVP are set. An error is returned if
pgmname is not executable; to make this work it is necessary to
provide an absolute file name. */
gpg_error_t gnupg_spawn_process_detached (const char *pgmname,
const char *argv[],
const char *envp[] );
/* Wait for a multiple processes. */
gpg_err_code_t gnupg_process_wait_list (gnupg_process_t *process_list,
int count, int hang);
#endif /*GNUPG_COMMON_EXECHELP_H*/

View File

@ -38,10 +38,14 @@
#include <gpg-error.h>
#include <assuan.h>
#include "i18n.h"
#include "logging.h"
#include "membuf.h"
#include "mischelp.h"
#ifdef HAVE_W32_SYSTEM
#define NEED_STRUCT_SPAWN_CB_ARG 1
#endif
#include "exechelp.h"
#include "sysutils.h"
#include "util.h"
@ -301,7 +305,6 @@ copy_buffer_flush (struct copy_buffer *c, estream_t sink)
}
/* Run the program PGMNAME with the command line arguments given in
* the NULL terminates array ARGV. If INPUT is not NULL it will be
* fed to stdin of the process. stderr is logged using log_info and
@ -321,7 +324,7 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
void *status_cb_value)
{
gpg_error_t err;
pid_t pid = (pid_t) -1;
gnupg_process_t proc = NULL;
estream_t infp = NULL;
estream_t extrafp = NULL;
estream_t outfp = NULL, errfp = NULL;
@ -335,7 +338,6 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
read_and_log_buffer_t fderrstate;
struct copy_buffer *cpbuf_in = NULL, *cpbuf_out = NULL, *cpbuf_extra = NULL;
int quiet = 0;
int dummy_exitcode;
memset (fds, 0, sizeof fds);
memset (&fderrstate, 0, sizeof fderrstate);
@ -411,10 +413,15 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
else
exceptclose[0] = -1;
err = gnupg_spawn_process (pgmname, argv,
exceptclose, GNUPG_SPAWN_NONBLOCK,
input? &infp : NULL,
&outfp, &errfp, &pid);
err = gnupg_process_spawn (pgmname, argv,
((input
? GNUPG_PROCESS_STDIN_PIPE
: 0)
| GNUPG_PROCESS_STDOUT_PIPE
| GNUPG_PROCESS_STDERR_PIPE),
gnupg_spawn_helper, exceptclose, &proc);
gnupg_process_get_streams (proc, GNUPG_PROCESS_STREAM_NONBLOCK,
input? &infp : NULL, &outfp, &errfp);
if (extrapipe[0] != -1)
close (extrapipe[0]);
if (argsave)
@ -546,20 +553,25 @@ gnupg_exec_tool_stream (const char *pgmname, const char *argv[],
es_fclose (outfp); outfp = NULL;
es_fclose (errfp); errfp = NULL;
err = gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
pid = (pid_t)(-1);
err = gnupg_process_wait (proc, 1);
if (!err)
{ /* To be compatible to old wait_process. */
int status;
gnupg_process_ctl (proc, GNUPG_PROCESS_GET_EXIT_ID, &status);
if (status)
err = gpg_error (GPG_ERR_GENERAL);
}
leave:
if (err && pid != (pid_t) -1)
gnupg_kill_process (pid);
if (err && proc)
gnupg_process_terminate (proc);
es_fclose (infp);
es_fclose (extrafp);
es_fclose (outfp);
es_fclose (errfp);
if (pid != (pid_t)(-1))
gnupg_wait_process (pgmname, pid, 1, quiet? &dummy_exitcode : NULL);
gnupg_release_process (pid);
gnupg_process_release (proc);
copy_buffer_shred (cpbuf_in);
xfree (cpbuf_in);

View File

@ -94,7 +94,8 @@ start_agent (void)
agentargs.lc_ctype,
agentargs.lc_messages,
agentargs.session_env,
1, agentargs.verbosity, 0, NULL, NULL);
ASSHELP_FLAG_AUTOSTART,
agentargs.verbosity, 0, NULL, NULL);
if (!err)
{
/* Tell the agent that we support Pinentry notifications. No

View File

@ -37,6 +37,11 @@
#ifdef HAVE_LANGINFO_H
#include <langinfo.h>
#endif
#ifdef HAVE_W32_SYSTEM
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
#endif /*!HAVE_W32_SYSTEM*/
#include <stdint.h> /* We use uint64_t. */
#include "util.h"
#include "i18n.h"
@ -61,6 +66,111 @@ static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
#define JD_DIFF 1721060L
/*
timegm() is a GNU function that might not be available everywhere.
It's basically the inverse of gmtime() - you give it a struct tm,
and get back a time_t. It differs from mktime() in that it handles
the case where the struct tm is UTC and the local environment isn't.
Note, that this replacement implementation might not be thread-safe!
Some BSDs don't handle the putenv("foo") case properly, so we use
unsetenv if the platform has it to remove environment variables.
*/
#ifndef HAVE_TIMEGM
time_t
timegm (struct tm *tm)
{
#ifdef HAVE_W32_SYSTEM
uint64_t val = timegm_u64 (tm);
if (val == (uint64_t)(-1))
return (time_t)(-1);
return (time_t)val;
#else /* (Non thread safe implementation!) */
time_t answer;
char *zone;
zone=getenv("TZ");
putenv("TZ=UTC");
tzset();
answer=mktime(tm);
if(zone)
{
static char *old_zone;
if (!old_zone)
{
old_zone = malloc(3+strlen(zone)+1);
if (old_zone)
{
strcpy(old_zone,"TZ=");
strcat(old_zone,zone);
}
}
if (old_zone)
putenv (old_zone);
}
else
gnupg_unsetenv("TZ");
tzset();
return answer;
#endif
}
#endif /*!HAVE_TIMEGM*/
/* Version of the GNU timegm which returns an unsigned 64 bit integer
* instead of the usually signed time_t. On error (uint64_t)(-1) is
* returned. This function is mostly here becuase on 32 bit Windows
* we have an internal API to get the system time even after
* 2023-01-19. For 32 bit Unix we need to suffer from the too short
* time_t and no system function to construct the time from a tm. */
uint64_t
timegm_u64 (struct tm *tm)
{
#ifdef HAVE_W32_SYSTEM
/* This one is thread safe. */
SYSTEMTIME st;
FILETIME ft;
unsigned long long cnsecs;
st.wYear = tm->tm_year + 1900;
st.wMonth = tm->tm_mon + 1;
st.wDay = tm->tm_mday;
st.wHour = tm->tm_hour;
st.wMinute = tm->tm_min;
st.wSecond = tm->tm_sec;
st.wMilliseconds = 0; /* Not available. */
st.wDayOfWeek = 0; /* Ignored. */
/* System time is UTC thus the conversion is pretty easy. */
if (!SystemTimeToFileTime (&st, &ft))
{
gpg_err_set_errno (EINVAL);
return (uint64_t)(-1);
}
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
| ft.dwLowDateTime);
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
return (uint64_t)(cnsecs / 10000000ULL);
#else /*Unix*/
time_t t = timegm (tm);
if (t == (time_t)(-1))
return (uint64_t)(-1);
if ((int64_t)t < 0)
return (uint64_t)(-1);
return (uint64_t)t;
#endif /*Unix*/
}
/* Wrapper for the time(3). We use this here so we can fake the time
for tests */
time_t
@ -172,6 +282,28 @@ make_timestamp (void)
}
/* Specialized version of atoi which returns an u32 instead of an int
* and caps the result at 2^32-2. Leading white space is skipped,
* scanning stops at at the first non-convertable byte. Note that we
* do not cap at 2^32-1 because that value is often used as error
* return. */
u32
scan_secondsstr (const char *string)
{
uint64_t value = 0;
while (*string == ' ' || *string == '\t')
string++;
for (; *string >= '0' && *string <= '9'; string++)
{
value *= 10;
value += atoi_1 (string);
if (value >= (u32)(-1))
return (u32)(-1) - 1;
}
return (u32)value;
}
/****************
* Scan a date string and return a timestamp.
@ -208,7 +340,21 @@ scan_isodatestr( const char *string )
tmbuf.tm_isdst = -1;
stamp = mktime( &tmbuf );
if( stamp == (time_t)-1 )
return 0;
{
/* mktime did not work. Construct an ISO timestring for noon
* of the given day instead. We keep the use of mktime for 64
* bit system to limit the risk of regressions. */
gnupg_isotime_t isobuf;
uint64_t tmp64;
snprintf (isobuf, 16, "%04d%02d%02dT120000", year, month, day);
tmp64 = isotime2epoch_u64 (isobuf);
if (tmp64 == (uint64_t)(-1))
return 0; /* Error. */
if (tmp64 >= (u32)(-1))
return 0; /* Error. */
return (u32)tmp64;
}
return stamp;
}
@ -363,18 +509,14 @@ string2isotime (gnupg_isotime_t atime, const char *string)
}
/* Scan an ISO timestamp and return an Epoch based timestamp. The
only supported format is "yyyymmddThhmmss[Z]" delimited by white
space, nul, a colon or a comma. Returns (time_t)(-1) for an
invalid string. */
time_t
isotime2epoch (const char *string)
/* Helper for isotime2epoch. Returns 0 on success. */
static int
isotime_make_tm (const char *string, struct tm *tmbuf)
{
int year, month, day, hour, minu, sec;
struct tm tmbuf;
if (!isotime_p (string))
return (time_t)(-1);
return -1;
year = atoi_4 (string);
month = atoi_2 (string + 4);
@ -386,20 +528,48 @@ isotime2epoch (const char *string)
/* Basic checks. */
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31
|| hour > 23 || minu > 59 || sec > 61 )
return -1;
memset (tmbuf, 0, sizeof *tmbuf);
tmbuf->tm_sec = sec;
tmbuf->tm_min = minu;
tmbuf->tm_hour = hour;
tmbuf->tm_mday = day;
tmbuf->tm_mon = month-1;
tmbuf->tm_year = year - 1900;
tmbuf->tm_isdst = -1;
return 0;
}
/* Scan an ISO timestamp and return an Epoch based timestamp. The
only supported format is "yyyymmddThhmmss[Z]" delimited by white
space, nul, a colon or a comma. Returns (time_t)(-1) for an
invalid string. */
time_t
isotime2epoch (const char *string)
{
struct tm tmbuf;
if (isotime_make_tm (string, &tmbuf))
return (time_t)(-1);
memset (&tmbuf, 0, sizeof tmbuf);
tmbuf.tm_sec = sec;
tmbuf.tm_min = minu;
tmbuf.tm_hour = hour;
tmbuf.tm_mday = day;
tmbuf.tm_mon = month-1;
tmbuf.tm_year = year - 1900;
tmbuf.tm_isdst = -1;
return timegm (&tmbuf);
}
uint64_t
isotime2epoch_u64 (const char *string)
{
struct tm tmbuf;
if (isotime_make_tm (string, &tmbuf))
return (uint64_t)(-1);
return timegm_u64 (&tmbuf);
}
/* Convert an Epoch time to an iso time stamp. */
void
epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
@ -453,41 +623,6 @@ isodate_human_to_tm (const char *string, struct tm *t)
}
/* This function is a copy of gpgme/src/conversion.c:_gpgme_timegm.
If you change it, then update the other one too. */
#ifdef HAVE_W32_SYSTEM
static time_t
_win32_timegm (struct tm *tm)
{
/* This one is thread safe. */
SYSTEMTIME st;
FILETIME ft;
unsigned long long cnsecs;
st.wYear = tm->tm_year + 1900;
st.wMonth = tm->tm_mon + 1;
st.wDay = tm->tm_mday;
st.wHour = tm->tm_hour;
st.wMinute = tm->tm_min;
st.wSecond = tm->tm_sec;
st.wMilliseconds = 0; /* Not available. */
st.wDayOfWeek = 0; /* Ignored. */
/* System time is UTC thus the conversion is pretty easy. */
if (!SystemTimeToFileTime (&st, &ft))
{
gpg_err_set_errno (EINVAL);
return (time_t)(-1);
}
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
| ft.dwLowDateTime);
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
return (time_t)(cnsecs / 10000000ULL);
}
#endif
/* Parse the string TIMESTAMP into a time_t. The string may either be
seconds since Epoch or in the ISO 8601 format like
"20390815T143012". Returns 0 for an empty string or seconds since
@ -496,7 +631,11 @@ _win32_timegm (struct tm *tm)
This function is a copy of
gpgme/src/conversion.c:_gpgme_parse_timestamp. If you change it,
then update the other one too. */
then update the other one too.
FIXME: Replace users of this function by one of the more modern
functions or change the return type to u64.
*/
time_t
parse_timestamp (const char *timestamp, char **endp)
{
@ -532,24 +671,7 @@ parse_timestamp (const char *timestamp, char **endp)
buf.tm_min = atoi_2 (timestamp+11);
buf.tm_sec = atoi_2 (timestamp+13);
#ifdef HAVE_W32_SYSTEM
return _win32_timegm (&buf);
#else
#ifdef HAVE_TIMEGM
return timegm (&buf);
#else
{
time_t tim;
putenv ("TZ=UTC");
tim = mktime (&buf);
#ifdef __GNUC__
#warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
#endif
return tim;
}
#endif /* !HAVE_TIMEGM */
#endif /* !HAVE_W32_SYSTEM */
}
else
return (time_t)strtoul (timestamp, endp, 10);
@ -728,7 +850,7 @@ asctimestamp (u32 stamp)
* 2018 has a lot of additional support but that will for sure
* break other things. We should move to ISO strings to get
* rid of such problems. */
setlocale (LC_TIME, "");
setlocale (LC_TIME, ".UTF8");
done = 1;
/* log_debug ("LC_ALL now '%s'\n", setlocale (LC_ALL, NULL)); */
/* log_debug ("LC_TIME now '%s'\n", setlocale (LC_TIME, NULL)); */

View File

@ -32,7 +32,7 @@
#include <time.h> /* We need time_t. */
#include <gpg-error.h> /* We need gpg_error_t. */
#include <stdint.h> /* We use uint64_t. */
/* A type to hold the ISO time. Note that this is the same as
the KSBA type ksba_isotime_t. */
@ -43,6 +43,11 @@ typedef char gnupg_isotime_t[16];
#define GNUPG_ISOTIME_NONE \
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
#ifndef HAVE_TIMEGM
time_t timegm (struct tm *tm);
#endif /*!HAVE_TIMEGM*/
uint64_t timegm_u64 (struct tm *tm);
time_t gnupg_get_time (void);
struct tm *gnupg_gmtime (const time_t *timep, struct tm *result);
void gnupg_get_isotime (gnupg_isotime_t timebuf);
@ -51,11 +56,13 @@ int gnupg_faked_time_p (void);
u32 make_timestamp (void);
char *elapsed_time_string (time_t since, time_t now);
u32 scan_secondsstr (const char *string);
u32 scan_isodatestr (const char *string);
int isotime_p (const char *string);
int isotime_human_p (const char *string, int date_only);
size_t string2isotime (gnupg_isotime_t atime, const char *string);
time_t isotime2epoch (const char *string);
uint64_t isotime2epoch_u64 (const char *string);
void epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
int isodate_human_to_tm (const char *string, struct tm *t);
time_t parse_timestamp (const char *timestamp, char **endp);

View File

@ -1,7 +1,7 @@
/* homedir.c - Setup the home directory.
* Copyright (C) 2004, 2006, 2007, 2010 Free Software Foundation, Inc.
* Copyright (C) 2013, 2016 Werner Koch
* Copyright (C) 2021 g10 Code GmbH
* Copyright (C) 2021, 2024 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -77,6 +77,14 @@
#endif
/* Mode flags for unix_rootdir. */
enum wantdir_values {
WANTDIR_ROOT = 0,
WANTDIR_SYSCONF,
WANTDIR_SOCKET
};
/* The GnuPG homedir. This is only accessed by the functions
* gnupg_homedir and gnupg_set_homedir. Malloced. */
static char *the_gnupg_homedir;
@ -85,6 +93,22 @@ static char *the_gnupg_homedir;
static byte non_default_homedir;
/* An object to store information taken from a gpgconf.ctl file. This
* is parsed early at startup time and never changed later. */
static struct
{
unsigned int checked:1; /* True if we have checked for a gpgconf.ctl. */
unsigned int found:1; /* True if a gpgconf.ctl was found. */
unsigned int empty:1; /* The file is empty except for comments. */
unsigned int valid:1; /* The entries in gpgconf.ctl are valid. */
unsigned int portable:1;/* Windows portable installation. */
char *gnupg; /* The "gnupg" directory part. */
char *rootdir; /* rootdir or NULL */
char *sysconfdir; /* sysconfdir or NULL */
char *socketdir; /* socketdir or NULL */
} gpgconf_ctl;
#ifdef HAVE_W32_SYSTEM
/* A flag used to indicate that a control file for gpgconf has been
* detected. Under Windows the presence of this file indicates a
@ -111,6 +135,87 @@ static byte w32_bin_is_bin;
static const char *w32_rootdir (void);
#endif
/* Return the name of the gnupg dir. This is usually "gnupg". */
static const char *
my_gnupg_dirname (void)
{
if (gpgconf_ctl.valid && gpgconf_ctl.gnupg)
return gpgconf_ctl.gnupg;
return "gnupg";
}
/* Return the hardwired home directory which is not anymore so
* hardwired because it may now be modified using the gpgconf.ctl
* "gnupg" keyword. */
static const char *
my_fixed_default_homedir (void)
{
if (gpgconf_ctl.valid && gpgconf_ctl.gnupg)
{
static char *name;
char *p;
if (!name)
{
name = xmalloc (strlen (GNUPG_DEFAULT_HOMEDIR)
+ strlen (gpgconf_ctl.gnupg) + 1);
strcpy (name, GNUPG_DEFAULT_HOMEDIR);
p = strrchr (name, '/');
if (p)
p++;
else
p = name;
if (*p == '.')
p++; /* Keep a leading dot. */
strcpy (p, gpgconf_ctl.gnupg);
gpgrt_annotate_leaked_object (name);
}
return name;
}
return GNUPG_DEFAULT_HOMEDIR;
}
/* Under Windows we need to modify the standard registry key with the
* "gnupg" keyword from a gpgconf.ctl. */
#ifdef HAVE_W32_SYSTEM
const char *
gnupg_registry_dir (void)
{
if (gpgconf_ctl.valid && gpgconf_ctl.gnupg)
{
static char *name;
char *p;
if (!name)
{
name = xmalloc (strlen (GNUPG_REGISTRY_DIR)
+ strlen (gpgconf_ctl.gnupg) + 1);
strcpy (name, GNUPG_REGISTRY_DIR);
p = strrchr (name, '\\');
if (p)
p++;
else
p = name;
strcpy (p, gpgconf_ctl.gnupg);
if (!strncmp (p, "gnupg", 5))
{
/* Registry keys are case-insensitive and we use a
* capitalized version of gnupg by default. So, if the
* new value starts with "gnupg" we apply the usual
* capitalization for this first part. */
p[0] = 'G';
p[3] = 'P';
p[4] = 'G';
}
gpgrt_annotate_leaked_object (name);
}
return name;
}
return GNUPG_REGISTRY_DIR;
}
#endif /*HAVE_W32_SYSTEM*/
/* This is a helper function to load and call a Windows function from
@ -214,6 +319,10 @@ copy_dir_with_fixup (const char *newdir)
{
char *result = NULL;
char *p;
#ifdef HAVE_W32_SYSTEM
char *p0;
const char *s;
#endif
if (!*newdir)
return NULL;
@ -245,6 +354,29 @@ copy_dir_with_fixup (const char *newdir)
*p-- = 0;
}
/* Hack to mitigate badly doubled backslashes. */
s = result? result : newdir;
if (s[0] == '\\' && s[1] == '\\' && s[2] != '\\')
{
/* UNC (\\Servername\file) or Long UNC (\\?\Servername\file)
* Does not seem to be double quoted. */
}
else if (strstr (s, "\\\\"))
{
/* Double quotes detected. Fold them into one because that is
* what what Windows does. This way we get a unique hash
* regardless of the number of doubled backslashes. */
if (!result)
result = xstrdup (newdir);
for (p0=p=result; *p; p++)
{
*p0++ = *p;
while (*p == '\\' && p[1] == '\\')
p++;
}
*p0 = 0;
}
#else /*!HAVE_W32_SYSTEM*/
if (newdir[strlen (newdir)-1] == '/')
@ -289,7 +421,7 @@ standard_homedir (void)
NULL, 0);
if (path)
{
dir = xstrconcat (path, "\\gnupg", NULL);
dir = xstrconcat (path, "\\", my_gnupg_dirname (), NULL);
xfree (path);
gpgrt_annotate_leaked_object (dir);
@ -300,12 +432,12 @@ standard_homedir (void)
}
else
dir = GNUPG_DEFAULT_HOMEDIR;
dir = my_fixed_default_homedir ();
}
}
return dir;
#else/*!HAVE_W32_SYSTEM*/
return GNUPG_DEFAULT_HOMEDIR;
return my_fixed_default_homedir ();
#endif /*!HAVE_W32_SYSTEM*/
}
@ -339,7 +471,7 @@ default_homedir (void)
* warning if the homedir has been taken from the
* registry. */
tmp = read_w32_registry_string (NULL,
GNUPG_REGISTRY_DIR,
gnupg_registry_dir (),
"HomeDir");
if (tmp && !*tmp)
{
@ -364,7 +496,7 @@ default_homedir (void)
#endif /*HAVE_W32_SYSTEM*/
if (!dir || !*dir)
dir = GNUPG_DEFAULT_HOMEDIR;
dir = my_fixed_default_homedir ();
else
{
char *p;
@ -392,6 +524,234 @@ default_homedir (void)
}
/* Return true if S can be inteprtated as true. This is uised for
* keywords in gpgconf.ctl. Spaces must have been trimmed. */
static int
string_is_true (const char *s)
{
return (atoi (s)
|| !ascii_strcasecmp (s, "yes")
|| !ascii_strcasecmp (s, "true")
|| !ascii_strcasecmp (s, "fact"));
}
/* This function is used to parse the gpgconf.ctl file and set the
* information ito the gpgconf_ctl structure. This is called once
* with the full filename of gpgconf.ctl. There are two callers: One
* used on Windows and one on Unix. No error return but diagnostics
* are printed. */
static void
parse_gpgconf_ctl (const char *fname)
{
gpg_error_t err;
char *p;
char *line;
size_t linelen;
ssize_t length;
estream_t fp;
const char *name;
int anyitem = 0;
int ignoreall = 0;
char *gnupgval = NULL;
char *rootdir = NULL;
char *sysconfdir = NULL;
char *socketdir = NULL;
if (gpgconf_ctl.checked)
return; /* Just in case this is called a second time. */
gpgconf_ctl.checked = 1;
gpgconf_ctl.found = 0;
gpgconf_ctl.valid = 0;
gpgconf_ctl.empty = 0;
if (gnupg_access (fname, F_OK))
return; /* No gpgconf.ctl file. */
/* log_info ("detected '%s'\n", buffer); */
fp = es_fopen (fname, "r");
if (!fp)
{
err = gpg_error_from_syserror ();
log_info ("error opening '%s': %s\n", fname, gpg_strerror (err));
return;
}
gpgconf_ctl.found = 1;
line = NULL;
linelen = 0;
while ((length = es_read_line (fp, &line, &linelen, NULL)) > 0)
{
static const char *names[] =
{
"gnupg",
"rootdir",
"sysconfdir",
"socketdir",
"portable",
".enable"
};
int i;
size_t n;
/* Strip NL and CR, if present. */
while (length > 0
&& (line[length - 1] == '\n' || line[length - 1] == '\r'))
line[--length] = 0;
trim_spaces (line);
if (*line == '#' || !*line)
continue;
anyitem = 1;
/* Find the keyword. */
name = NULL;
p = NULL;
for (i=0; i < DIM (names); i++)
{
n = strlen (names[i]);
if (!strncmp (line, names[i], n))
{
while (line[n] == ' ' || line[n] == '\t')
n++;
if (line[n] == '=')
{
name = names[i];
p = line + n + 1;
break;
}
}
}
if (!name)
continue; /* Keyword not known. */
trim_spaces (p);
p = substitute_envvars (p);
if (!p)
{
err = gpg_error_from_syserror ();
log_info ("error getting %s from gpgconf.ctl: %s\n",
name, gpg_strerror (err));
}
else if (!strcmp (name, ".enable"))
{
if (string_is_true (p))
; /* Yes, this file shall be used. */
else
ignoreall = 1; /* No, this file shall be ignored. */
xfree (p);
}
else if (!strcmp (name, "gnupg"))
{
xfree (gnupgval);
gnupgval = p;
}
else if (!strcmp (name, "sysconfdir"))
{
xfree (sysconfdir);
sysconfdir = p;
}
else if (!strcmp (name, "socketdir"))
{
xfree (socketdir);
socketdir = p;
}
else if (!strcmp (name, "rootdir"))
{
xfree (rootdir);
rootdir = p;
}
else if (!strcmp (name, "portable"))
{
gpgconf_ctl.portable = string_is_true (p);
xfree (p);
}
else /* Unknown keyword. */
xfree (p);
}
if (es_ferror (fp))
{
err = gpg_error_from_syserror ();
log_info ("error reading '%s': %s\n", fname, gpg_strerror (err));
ignoreall = 1; /* Force all entries to invalid. */
}
es_fclose (fp);
xfree (line);
if (ignoreall)
; /* Forced error. Note that .found is still set. */
else if (gnupgval && (!*gnupgval || strpbrk (gnupgval, "/\\")))
{
/* We don't allow a slash or backslash in the value because our
* code assumes this is a single directory name. */
log_info ("invalid %s '%s' specified in gpgconf.ctl\n",
"gnupg", gnupgval);
}
else if (rootdir && (!*rootdir || *rootdir != '/'))
{
log_info ("invalid %s '%s' specified in gpgconf.ctl\n",
"rootdir", rootdir);
}
else if (sysconfdir && (!*sysconfdir || *sysconfdir != '/'))
{
log_info ("invalid %s '%s' specified in gpgconf.ctl\n",
"sysconfdir", sysconfdir);
}
else if (socketdir && (!*socketdir || *socketdir != '/'))
{
log_info ("invalid %s '%s' specified in gpgconf.ctl\n",
"socketdir", socketdir);
}
else
{
if (gnupgval)
{
gpgconf_ctl.gnupg = gnupgval;
gpgrt_annotate_leaked_object (gpgconf_ctl.gnupg);
/* log_info ("want gnupg '%s'\n", dir); */
}
if (rootdir)
{
while (*rootdir && rootdir[strlen (rootdir)-1] == '/')
rootdir[strlen (rootdir)-1] = 0;
gpgconf_ctl.rootdir = rootdir;
gpgrt_annotate_leaked_object (gpgconf_ctl.rootdir);
/* log_info ("want rootdir '%s'\n", dir); */
}
if (sysconfdir)
{
while (*sysconfdir && sysconfdir[strlen (sysconfdir)-1] == '/')
sysconfdir[strlen (sysconfdir)-1] = 0;
gpgconf_ctl.sysconfdir = sysconfdir;
gpgrt_annotate_leaked_object (gpgconf_ctl.sysconfdir);
/* log_info ("want sysconfdir '%s'\n", sdir); */
}
if (socketdir)
{
while (*socketdir && socketdir[strlen (socketdir)-1] == '/')
socketdir[strlen (socketdir)-1] = 0;
gpgconf_ctl.socketdir = socketdir;
gpgrt_annotate_leaked_object (gpgconf_ctl.socketdir);
/* log_info ("want socketdir '%s'\n", s2dir); */
}
gpgconf_ctl.valid = 1;
}
gpgconf_ctl.empty = !anyitem;
if (!gpgconf_ctl.valid)
{
/* Error reading some entries - clear them all. */
xfree (gnupgval);
xfree (rootdir);
xfree (sysconfdir);
xfree (socketdir);
gpgconf_ctl.gnupg = NULL;
gpgconf_ctl.rootdir = NULL;
gpgconf_ctl.sysconfdir = NULL;
gpgconf_ctl.socketdir = NULL;
}
}
#ifdef HAVE_W32_SYSTEM
/* Check whether gpgconf is installed and if so read the gpgconf.ctl
file. */
@ -404,17 +764,20 @@ check_portable_app (const char *dir)
if (!gnupg_access (fname, F_OK))
{
strcpy (fname + strlen (fname) - 3, "ctl");
if (!gnupg_access (fname, F_OK))
parse_gpgconf_ctl (fname);
if ((gpgconf_ctl.found && gpgconf_ctl.empty)
|| (gpgconf_ctl.valid && gpgconf_ctl.portable))
{
/* gpgconf.ctl file found. Record this fact. */
unsigned int flags;
/* Classic gpgconf.ctl file found. This is a portable
* application. Note that if there are any items in that
* file we don't consider this a portable application unless
* the (later added) ".portable" keyword has also been
* seen. */
w32_portable_app = 1;
{
unsigned int flags;
log_get_prefix (&flags);
log_set_prefix (NULL, (flags | GPGRT_LOG_NO_REGISTRY));
}
/* FIXME: We should read the file to detect special flags
and print a warning if we don't understand them */
log_get_prefix (&flags);
log_set_prefix (NULL, (flags | GPGRT_LOG_NO_REGISTRY));
}
}
xfree (fname);
@ -491,27 +854,16 @@ w32_rootdir (void)
* file system. If WANT_SYSCONFDIR is true the optional sysconfdir
* entry is returned. */
static const char *
unix_rootdir (int want_sysconfdir)
unix_rootdir (enum wantdir_values wantdir)
{
static int checked;
static char *dir; /* for the rootdir */
static char *sdir; /* for the sysconfdir */
if (!checked)
if (!gpgconf_ctl.checked)
{
char *p;
char *buffer;
size_t bufsize = 256-1;
int nread;
gpg_error_t err;
char *line;
size_t linelen;
ssize_t length;
estream_t fp;
char *rootdir;
char *sysconfdir;
const char *name;
int ignoreall = 0;
for (;;)
{
@ -551,7 +903,7 @@ unix_rootdir (int want_sysconfdir)
if (!*buffer)
{
xfree (buffer);
checked = 1;
gpgconf_ctl.checked = 1;
return NULL; /* Error - assume no gpgconf.ctl. */
}
@ -559,175 +911,39 @@ unix_rootdir (int want_sysconfdir)
if (!p)
{
xfree (buffer);
checked = 1;
gpgconf_ctl.checked = 1;
return NULL; /* Erroneous /proc - assume no gpgconf.ctl. */
}
*p = 0; /* BUFFER has the directory. */
if ((p = strrchr (buffer, '/')))
{
/* Strip one part and expect the file below a bin dir. */
*p = 0;
p = xstrconcat (buffer, "/bin/gpgconf.ctl", NULL);
xfree (buffer);
buffer = p;
}
else /* !p */
if (!(p = strrchr (buffer, '/')))
{
/* Installed in the root which is not a good idea. Assume
* no gpgconf.ctl. */
xfree (buffer);
checked = 1;
gpgconf_ctl.checked = 1;
return NULL;
}
if (gnupg_access (buffer, F_OK))
{
/* No gpgconf.ctl file. */
xfree (buffer);
checked = 1;
return NULL;
}
/* log_info ("detected '%s'\n", buffer); */
fp = es_fopen (buffer, "r");
if (!fp)
{
err = gpg_error_from_syserror ();
log_info ("error opening '%s': %s\n", buffer, gpg_strerror (err));
xfree (buffer);
checked = 1;
return NULL;
}
line = NULL;
linelen = 0;
rootdir = NULL;
sysconfdir = NULL;
while ((length = es_read_line (fp, &line, &linelen, NULL)) > 0)
{
/* Strip NL and CR, if present. */
while (length > 0
&& (line[length - 1] == '\n' || line[length - 1] == '\r'))
line[--length] = 0;
trim_spaces (line);
if (!strncmp (line, "rootdir=", 8))
{
name = "rootdir";
p = line + 8;
}
else if (!strncmp (line, "rootdir =", 9)) /* (What a kludge) */
{
name = "rootdir";
p = line + 9;
}
else if (!strncmp (line, "sysconfdir=", 11))
{
name = "sysconfdir";
p = line + 11;
}
else if (!strncmp (line, "sysconfdir =", 12)) /* (What a kludge) */
{
name = "sysconfdir";
p = line + 12;
}
else if (!strncmp (line, ".enable=", 8))
{
name = ".enable";
p = line + 8;
}
else if (!strncmp (line, ".enable =", 9))
{
name = ".enable";
p = line + 9;
}
else
continue;
trim_spaces (p);
p = substitute_envvars (p);
if (!p)
{
err = gpg_error_from_syserror ();
log_info ("error getting %s from gpgconf.ctl: %s\n",
name, gpg_strerror (err));
}
else if (!strcmp (name, ".enable"))
{
if (atoi (p)
|| !ascii_strcasecmp (p, "yes")
|| !ascii_strcasecmp (p, "true")
|| !ascii_strcasecmp (p, "fact"))
; /* Yes, this file shall be used. */
else
ignoreall = 1; /* No, this file shall be ignored. */
xfree (p);
}
else if (!strcmp (name, "sysconfdir"))
{
xfree (sysconfdir);
sysconfdir = p;
}
else
{
xfree (rootdir);
rootdir = p;
}
}
if (es_ferror (fp))
{
err = gpg_error_from_syserror ();
log_info ("error reading '%s': %s\n", buffer, gpg_strerror (err));
es_fclose (fp);
xfree (buffer);
xfree (line);
xfree (rootdir);
xfree (sysconfdir);
checked = 1;
return NULL;
}
es_fclose (fp);
/* Strip one part and expect the file below a bin dir. */
*p = 0;
p = xstrconcat (buffer, "/bin/gpgconf.ctl", NULL);
xfree (buffer);
buffer = p;
parse_gpgconf_ctl (buffer);
xfree (buffer);
xfree (line);
if (ignoreall)
{
xfree (rootdir);
xfree (sysconfdir);
sdir = dir = NULL;
}
else if (!rootdir || !*rootdir || *rootdir != '/')
{
log_info ("invalid rootdir '%s' specified in gpgconf.ctl\n", rootdir);
xfree (rootdir);
xfree (sysconfdir);
dir = NULL;
}
else if (sysconfdir && (!*sysconfdir || *sysconfdir != '/'))
{
log_info ("invalid sysconfdir '%s' specified in gpgconf.ctl\n",
sysconfdir);
xfree (rootdir);
xfree (sysconfdir);
dir = NULL;
}
else
{
while (*rootdir && rootdir[strlen (rootdir)-1] == '/')
rootdir[strlen (rootdir)-1] = 0;
dir = rootdir;
gpgrt_annotate_leaked_object (dir);
/* log_info ("want rootdir '%s'\n", dir); */
if (sysconfdir)
{
while (*sysconfdir && sysconfdir[strlen (sysconfdir)-1] == '/')
sysconfdir[strlen (sysconfdir)-1] = 0;
sdir = sysconfdir;
gpgrt_annotate_leaked_object (sdir);
/* log_info ("want sysconfdir '%s'\n", sdir); */
}
}
checked = 1;
}
return want_sysconfdir? sdir : dir;
if (!gpgconf_ctl.valid)
return NULL; /* No valid entries in gpgconf.ctl */
switch (wantdir)
{
case WANTDIR_ROOT: return gpgconf_ctl.rootdir;
case WANTDIR_SYSCONF: return gpgconf_ctl.sysconfdir;
case WANTDIR_SOCKET: return gpgconf_ctl.socketdir;
}
return NULL; /* Not reached. */
}
#endif /* Unix */
@ -919,7 +1135,7 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
if (w32_portable_app)
{
name = xstrconcat (w32_rootdir (), DIRSEP_S, "gnupg", NULL);
name = xstrconcat (w32_rootdir (), DIRSEP_S, my_gnupg_dirname (), NULL);
}
else
{
@ -930,7 +1146,7 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
NULL, 0);
if (path)
{
name = xstrconcat (path, "\\gnupg", NULL);
name = xstrconcat (path, "\\", my_gnupg_dirname (), NULL);
xfree (path);
if (gnupg_access (name, F_OK))
gnupg_mkdir (name, "-rwx");
@ -1038,9 +1254,11 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
};
int i;
struct stat sb;
char prefix[19 + 1 + 20 + 6 + 1];
char prefixbuffer[256];
const char *prefix;
const char *s;
char *name = NULL;
const char *gnupgname = my_gnupg_dirname ();
*r_info = 0;
@ -1053,35 +1271,43 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
* as a background process with no (desktop) user logged in. Thus
* we better don't do that. */
/* Check whether we have a /run/[gnupg/]user dir. */
for (i=0; bases[i]; i++)
prefix = unix_rootdir (WANTDIR_SOCKET);
if (!prefix)
{
snprintf (prefix, sizeof prefix, "%s/user/%u",
bases[i], (unsigned int)getuid ());
if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
break;
}
if (!bases[i])
{
*r_info |= 2; /* No /run/user directory. */
goto leave;
/* gpgconf.ctl does not specify a directory. Check whether we
* have the usual /run/[gnupg/]user dir. */
for (i=0; bases[i]; i++)
{
snprintf (prefixbuffer, sizeof prefixbuffer, "%s/user/%u",
bases[i], (unsigned int)getuid ());
prefix = prefixbuffer;
if (!stat (prefix, &sb) && S_ISDIR(sb.st_mode))
break;
}
if (!bases[i])
{
*r_info |= 2; /* No /run/user directory. */
goto leave;
}
if (sb.st_uid != getuid ())
{
*r_info |= 4; /* Not owned by the user. */
if (!skip_checks)
goto leave;
}
if (strlen (prefix) + strlen (gnupgname) + 2 >= sizeof prefixbuffer)
{
*r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
goto leave;
}
strcat (prefixbuffer, "/");
strcat (prefixbuffer, gnupgname);
}
if (sb.st_uid != getuid ())
{
*r_info |= 4; /* Not owned by the user. */
if (!skip_checks)
goto leave;
}
if (strlen (prefix) + 7 >= sizeof prefix)
{
*r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
goto leave;
}
strcat (prefix, "/gnupg");
/* Check whether the gnupg sub directory has proper permissions. */
/* Check whether the gnupg sub directory (or the specified diretory)
* has proper permissions. */
if (stat (prefix, &sb))
{
if (errno != ENOENT)
@ -1232,16 +1458,13 @@ gnupg_sysconfdir (void)
if (!name)
{
const char *s1, *s2;
s1 = w32_commondir ();
s2 = DIRSEP_S "etc" DIRSEP_S "gnupg";
name = xmalloc (strlen (s1) + strlen (s2) + 1);
strcpy (stpcpy (name, s1), s2);
name = xstrconcat (w32_commondir (), DIRSEP_S, "etc", DIRSEP_S,
my_gnupg_dirname (), NULL);
gpgrt_annotate_leaked_object (name);
}
return name;
#else /*!HAVE_W32_SYSTEM*/
const char *dir = unix_rootdir (1);
const char *dir = unix_rootdir (WANTDIR_SYSCONF);
if (dir)
return dir;
else
@ -1270,7 +1493,7 @@ gnupg_bindir (void)
else
return rdir;
#else /*!HAVE_W32_SYSTEM*/
rdir = unix_rootdir (0);
rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
@ -1297,7 +1520,7 @@ gnupg_libexecdir (void)
static char *name;
const char *rdir;
rdir = unix_rootdir (0);
rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
@ -1327,7 +1550,7 @@ gnupg_libdir (void)
#else /*!HAVE_W32_SYSTEM*/
const char *rdir;
rdir = unix_rootdir (0);
rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
@ -1358,7 +1581,7 @@ gnupg_datadir (void)
#else /*!HAVE_W32_SYSTEM*/
const char *rdir;
rdir = unix_rootdir (0);
rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)
@ -1390,7 +1613,7 @@ gnupg_localedir (void)
#else /*!HAVE_W32_SYSTEM*/
const char *rdir;
rdir = unix_rootdir (0);
rdir = unix_rootdir (WANTDIR_ROOT);
if (rdir)
{
if (!name)

View File

@ -37,6 +37,7 @@
# include <winsock2.h>
# endif
# include <windows.h>
# include <wctype.h>
#endif
#include <gcrypt.h>

View File

@ -166,7 +166,8 @@ block_filter_ctx_t;
/* Local prototypes. */
static int underflow (iobuf_t a, int clear_pending_eof);
static int underflow_target (iobuf_t a, int clear_pending_eof, size_t target);
static int translate_file_handle (int fd, int for_write);
static iobuf_t do_iobuf_fdopen (gnupg_fd_t fp, const char *mode, int keep_open);
/* Sends any pending data to the filter's FILTER function. Note: this
works on the filter and not on the whole pipeline. That is,
@ -311,6 +312,13 @@ direct_open (const char *fname, const char *mode, int mode700)
{
hfile = CreateFileW (wfname, da, sm, NULL, cd,
FILE_ATTRIBUTE_NORMAL, NULL);
if (hfile == INVALID_HANDLE_VALUE)
{
gnupg_w32_set_errno (-1);
if (DBG_IOBUF)
log_debug ("iobuf:direct_open '%s' CreateFile failed: %s\n",
fname, gpg_strerror (gpg_error_from_syserror()));
}
xfree (wfname);
}
else
@ -382,7 +390,7 @@ fd_cache_close (const char *fname, gnupg_fd_t fp)
close (fp);
#endif
if (DBG_IOBUF)
log_debug ("fd_cache_close (%d) real\n", (int)fp);
log_debug ("fd_cache_close (%d) real\n", FD_DBG (fp));
return;
}
/* try to reuse a slot */
@ -426,8 +434,9 @@ fd_cache_open (const char *fname, const char *mode)
#ifdef HAVE_W32_SYSTEM
if (SetFilePointer (fp, 0, NULL, FILE_BEGIN) == 0xffffffff)
{
log_error ("rewind file failed on handle %p: ec=%d\n",
fp, (int) GetLastError ());
int ec = (int) GetLastError ();
log_error ("rewind file failed on handle %p: ec=%d\n", fp, ec);
gnupg_w32_set_errno (ec);
fp = GNUPG_INVALID_FD;
}
#else
@ -495,7 +504,8 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
if (ec != ERROR_BROKEN_PIPE)
{
rc = gpg_error_from_errno (ec);
log_error ("%s: read error: ec=%d\n", a->fname, ec);
log_error ("%s: read error: %s (ec=%d)\n",
a->fname, gpg_strerror (rc), ec);
}
}
else if (!nread)
@ -563,9 +573,10 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
{
if (size && !WriteFile (f, p, nbytes, &n, NULL))
{
int ec = (int) GetLastError ();
rc = gpg_error_from_errno (ec);
log_error ("%s: write error: ec=%d\n", a->fname, ec);
int ec = gnupg_w32_set_errno (-1);
rc = gpg_error_from_syserror ();
log_error ("%s: write error: %s (ec=%d)\n",
a->fname, gpg_strerror (rc), ec);
break;
}
p += n;
@ -624,7 +635,8 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
if (ec != ERROR_BROKEN_PIPE)
{
rc = gpg_error_from_errno (ec);
log_error ("%s: read error: ec=%d\n", a->fname, ec);
log_error ("%s: read error: %s (ec=%d)\n",
a->fname, gpg_strerror (rc), ec);
}
a->npeeked = 0;
}
@ -685,7 +697,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
if (f != FD_FOR_STDIN && f != FD_FOR_STDOUT)
{
if (DBG_IOBUF)
log_debug ("%s: close fd/handle %d\n", a->fname, FD2INT (f));
log_debug ("%s: close fd/handle %d\n", a->fname, FD_DBG (f));
if (!a->keep_open)
fd_cache_close (a->no_cache ? NULL : a->fname, f);
}
@ -873,7 +885,8 @@ sock_filter (void *opaque, int control, iobuf_t chain, byte * buf,
if (n == SOCKET_ERROR)
{
int ec = (int) WSAGetLastError ();
rc = gpg_error_from_errno (ec);
gnupg_w32_set_errno (ec);
rc = gpg_error_from_syserror ();
log_error ("socket write error: ec=%d\n", ec);
break;
}
@ -1398,7 +1411,7 @@ iobuf_is_pipe_filename (const char *fname)
{
if (!fname || (*fname=='-' && !fname[1]) )
return 1;
return check_special_filename (fname, 0, 1) != -1;
return gnupg_check_special_filename (fname) != GNUPG_INVALID_FD;
}
@ -1411,7 +1424,7 @@ do_open (const char *fname, int special_filenames,
file_filter_ctx_t *fcx;
size_t len = 0;
int print_only = 0;
int fd;
gnupg_fd_t fd;
byte desc[MAX_IOBUF_DESC];
log_assert (use == IOBUF_INPUT || use == IOBUF_OUTPUT);
@ -1435,9 +1448,8 @@ do_open (const char *fname, int special_filenames,
else if (!fname)
return NULL;
else if (special_filenames
&& (fd = check_special_filename (fname, 0, 1)) != -1)
return iobuf_fdopen (translate_file_handle (fd, use == IOBUF_INPUT ? 0 : 1),
opentype);
&& (fd = gnupg_check_special_filename (fname)) != GNUPG_INVALID_FD)
return do_iobuf_fdopen (fd, opentype, 0);
else
{
if (use == IOBUF_INPUT)
@ -1460,7 +1472,8 @@ do_open (const char *fname, int special_filenames,
file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
if (DBG_IOBUF)
log_debug ("iobuf-%d.%d: open '%s' desc=%s fd=%d\n",
a->no, a->subno, fname, iobuf_desc (a, desc), FD2INT (fcx->fp));
a->no, a->subno, fname, iobuf_desc (a, desc),
FD_DBG (fcx->fp));
return a;
}
@ -1485,22 +1498,19 @@ iobuf_openrw (const char *fname)
static iobuf_t
do_iobuf_fdopen (int fd, const char *mode, int keep_open)
do_iobuf_fdopen (gnupg_fd_t fp, const char *mode, int keep_open)
{
iobuf_t a;
gnupg_fd_t fp;
file_filter_ctx_t *fcx;
size_t len = 0;
fp = INT2FD (fd);
a = iobuf_alloc (strchr (mode, 'w') ? IOBUF_OUTPUT : IOBUF_INPUT,
iobuf_buffer_size);
fcx = xmalloc (sizeof *fcx + 20);
fcx->fp = fp;
fcx->print_only_name = 1;
fcx->keep_open = keep_open;
sprintf (fcx->fname, "[fd %d]", fd);
sprintf (fcx->fname, "[fd %d]", FD_DBG (fp));
a->filter = file_filter;
a->filter_ov = fcx;
file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
@ -1513,15 +1523,15 @@ do_iobuf_fdopen (int fd, const char *mode, int keep_open)
iobuf_t
iobuf_fdopen (int fd, const char *mode)
iobuf_fdopen (gnupg_fd_t fp, const char *mode)
{
return do_iobuf_fdopen (fd, mode, 0);
return do_iobuf_fdopen (fp, mode, 0);
}
iobuf_t
iobuf_fdopen_nc (int fd, const char *mode)
iobuf_fdopen_nc (gnupg_fd_t fp, const char *mode)
{
return do_iobuf_fdopen (fd, mode, 1);
return do_iobuf_fdopen (fp, mode, 1);
}
@ -1573,7 +1583,7 @@ iobuf_sockopen (int fd, const char *mode)
log_debug ("iobuf-%d.%d: sockopen '%s'\n", a->no, a->subno, scx->fname);
iobuf_ioctl (a, IOBUF_IOCTL_NO_CACHE, 1, NULL);
#else
a = iobuf_fdopen (fd, mode);
a = do_iobuf_fdopen (fd, mode, 0);
#endif
return a;
}
@ -2597,13 +2607,10 @@ iobuf_set_limit (iobuf_t a, off_t nlimit)
}
off_t
iobuf_get_filelength (iobuf_t a, int *overflow)
/* Return the length of the file behind A. If there is no file, return 0. */
uint64_t
iobuf_get_filelength (iobuf_t a)
{
if (overflow)
*overflow = 0;
/* Hmmm: file_filter may have already been removed */
for ( ; a->chain; a = a->chain )
;
@ -2616,56 +2623,18 @@ iobuf_get_filelength (iobuf_t a, int *overflow)
gnupg_fd_t fp = b->fp;
#if defined(HAVE_W32_SYSTEM)
ulong size;
static int (* __stdcall get_file_size_ex) (void *handle,
LARGE_INTEGER *r_size);
static int get_file_size_ex_initialized;
LARGE_INTEGER exsize;
if (!get_file_size_ex_initialized)
{
void *handle;
handle = dlopen ("kernel32.dll", RTLD_LAZY);
if (handle)
{
get_file_size_ex = dlsym (handle, "GetFileSizeEx");
if (!get_file_size_ex)
dlclose (handle);
}
get_file_size_ex_initialized = 1;
}
if (get_file_size_ex)
{
/* This is a newer system with GetFileSizeEx; we use this
then because it seem that GetFileSize won't return a
proper error in case a file is larger than 4GB. */
LARGE_INTEGER exsize;
if (get_file_size_ex (fp, &exsize))
{
if (!exsize.u.HighPart)
return exsize.u.LowPart;
if (overflow)
*overflow = 1;
return 0;
}
}
else
{
if ((size=GetFileSize (fp, NULL)) != 0xffffffff)
return size;
}
if (GetFileSizeEx (fp, &exsize))
return exsize.QuadPart;
log_error ("GetFileSize for handle %p failed: %s\n",
fp, w32_strerror (-1));
#else /*!HAVE_W32_SYSTEM*/
{
struct stat st;
struct stat st;
if ( !fstat (fp, &st) )
return st.st_size;
log_error("fstat() failed: %s\n", strerror(errno) );
}
if ( !fstat (fp, &st) )
return st.st_size;
log_error("fstat() failed: %s\n", strerror(errno) );
#endif /*!HAVE_W32_SYSTEM*/
}
@ -2673,20 +2642,20 @@ iobuf_get_filelength (iobuf_t a, int *overflow)
}
int
gnupg_fd_t
iobuf_get_fd (iobuf_t a)
{
for (; a->chain; a = a->chain)
;
if (a->filter != file_filter)
return -1;
return GNUPG_INVALID_FD;
{
file_filter_ctx_t *b = a->filter_ov;
gnupg_fd_t fp = b->fp;
return FD2INT (fp);
return fp;
}
}
@ -2977,36 +2946,6 @@ iobuf_read_line (iobuf_t a, byte ** addr_of_buffer,
return nbytes;
}
static int
translate_file_handle (int fd, int for_write)
{
#if defined(HAVE_W32_SYSTEM)
{
int x;
(void)for_write;
if (fd == 0)
x = (int) GetStdHandle (STD_INPUT_HANDLE);
else if (fd == 1)
x = (int) GetStdHandle (STD_OUTPUT_HANDLE);
else if (fd == 2)
x = (int) GetStdHandle (STD_ERROR_HANDLE);
else
x = fd;
if (x == -1)
log_debug ("GetStdHandle(%d) failed: ec=%d\n",
fd, (int) GetLastError ());
fd = x;
}
#else
(void)for_write;
#endif
return fd;
}
void
iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
@ -3057,3 +2996,123 @@ iobuf_skip_rest (iobuf_t a, unsigned long n, int partial)
}
}
}
/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
* packet. LEN should be at least 6. */
static int
is_openpgp_compressed_packet (const unsigned char *buf, size_t len)
{
int c, ctb, pkttype;
int lenbytes;
ctb = *buf++; len--;
if (!(ctb & 0x80))
return 0; /* Invalid packet. */
if ((ctb & 0x40)) /* New style (OpenPGP) CTB. */
{
pkttype = (ctb & 0x3f);
if (!len)
return 0; /* Expected first length octet missing. */
c = *buf++; len--;
if (c < 192)
;
else if (c < 224)
{
if (!len)
return 0; /* Expected second length octet missing. */
}
else if (c == 255)
{
if (len < 4)
return 0; /* Expected length octets missing */
}
}
else /* Old style CTB. */
{
pkttype = (ctb>>2)&0xf;
lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
if (len < lenbytes)
return 0; /* Not enough length bytes. */
}
return (pkttype == 8);
}
/*
* Check if the file is compressed, by peeking the iobuf. You need to
* pass the iobuf with INP. Returns true if the buffer seems to be
* compressed.
*/
int
is_file_compressed (iobuf_t inp)
{
int i;
char buf[32];
int buflen;
struct magic_compress_s
{
byte len;
byte extchk;
byte magic[5];
} magic[] =
{
{ 3, 0, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
{ 3, 0, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
{ 4, 0, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
{ 5, 0, { '%', 'P', 'D', 'F', '-'} }, /* PDF */
{ 4, 1, { 0xff, 0xd8, 0xff, 0xe0 } }, /* Maybe JFIF */
{ 5, 2, { 0x89, 'P','N','G', 0x0d} } /* Likely PNG */
};
if (!inp)
return 0;
for ( ; inp->chain; inp = inp->chain )
;
buflen = iobuf_ioctl (inp, IOBUF_IOCTL_PEEK, sizeof buf, buf);
if (buflen < 0)
{
buflen = 0;
log_debug ("peeking at input failed\n");
}
if ( buflen < 6 )
{
return 0; /* Too short to check - assume uncompressed. */
}
for ( i = 0; i < DIM (magic); i++ )
{
if (!memcmp( buf, magic[i].magic, magic[i].len))
{
switch (magic[i].extchk)
{
case 0:
return 1; /* Is compressed. */
case 1:
if (buflen > 11 && !memcmp (buf + 6, "JFIF", 5))
return 1; /* JFIF: this likely a compressed JPEG. */
break;
case 2:
if (buflen > 8
&& buf[5] == 0x0a && buf[6] == 0x1a && buf[7] == 0x0a)
return 1; /* This is a PNG. */
break;
default:
break;
}
}
}
if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen))
{
return 1; /* Already compressed. */
}
return 0; /* Not detected as compressed. */
}

View File

@ -333,11 +333,11 @@ iobuf_t iobuf_openrw (const char *fname);
creates an input filter. Note: MODE must reflect the file
descriptors actual mode! When the filter is destroyed, the file
descriptor is closed. */
iobuf_t iobuf_fdopen (int fd, const char *mode);
iobuf_t iobuf_fdopen (gnupg_fd_t fd, const char *mode);
/* Like iobuf_fdopen, but doesn't close the file descriptor when the
filter is destroyed. */
iobuf_t iobuf_fdopen_nc (int fd, const char *mode);
iobuf_t iobuf_fdopen_nc (gnupg_fd_t fd, const char *mode);
/* Create a filter using an existing estream. If MODE contains the
letter 'w', creates an output filter. Otherwise, creates an input
@ -584,17 +584,13 @@ size_t iobuf_temp_to_buffer (iobuf_t a, byte * buffer, size_t buflen);
size_t iobuf_copy (iobuf_t dest, iobuf_t source);
/* Return the size of any underlying file. This only works with
file_filter based pipelines.
On Win32, it is sometimes not possible to determine the size of
files larger than 4GB. In this case, *OVERFLOW (if not NULL) is
set to 1. Otherwise, *OVERFLOW is set to 0. */
off_t iobuf_get_filelength (iobuf_t a, int *overflow);
file_filter based pipelines. */
uint64_t iobuf_get_filelength (iobuf_t a);
#define IOBUF_FILELENGTH_LIMIT 0xffffffff
/* Return the file descriptor designating the underlying file. This
only works with file_filter based pipelines. */
int iobuf_get_fd (iobuf_t a);
gnupg_fd_t iobuf_get_fd (iobuf_t a);
/* Return the real filename, if available. This only supports
pipelines that end in file filters. Returns NULL if not
@ -629,6 +625,9 @@ void iobuf_set_partial_body_length_mode (iobuf_t a, size_t len);
from the following filter (which may or may not return EOF). */
void iobuf_skip_rest (iobuf_t a, unsigned long n, int partial);
/* Check if the file is compressed, by peeking the iobuf. */
int is_file_compressed (iobuf_t inp);
#define iobuf_where(a) "[don't know]"
/* Each time a filter is allocated (via iobuf_alloc()), a

220
common/kem.c Normal file
View File

@ -0,0 +1,220 @@
/* kem.c - KEM helper functions
* Copyright (C) 2024 g10 Code GmbH.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute and/or modify this
* part of GnuPG under the terms of either
*
* - the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at
* your option) any later version.
*
* or
*
* - the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* or both in parallel, as here.
*
* GnuPG is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received copies of the GNU General Public License
* and the GNU Lesser General Public License along with this program;
* if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
*/
#include <config.h>
#include <stdlib.h>
#include <string.h>
#include <gpg-error.h>
#include <gcrypt.h>
#include "mischelp.h"
/* domSeperation as per *PGP specs. */
#define KMAC_KEY "OpenPGPCompositeKeyDerivationFunction"
/* customizationString as per *PGP specs. */
#define KMAC_CUSTOM "KDF"
/* The blocksize used for Keccak by compute_kmac256. */
#define KECCAK512_BLOCKSIZE 136
static gpg_error_t
compute_kmac256 (void *digest, size_t digestlen,
const void *key, size_t keylen,
const void *custom, size_t customlen,
gcry_buffer_t *data_iov, int data_iovlen)
{
gpg_error_t err;
gcry_buffer_t iov[20];
const unsigned char headPAD[2] = { 1, KECCAK512_BLOCKSIZE };
unsigned char headK[3];
const unsigned char pad[KECCAK512_BLOCKSIZE] = { 0 };
unsigned char right_encode_L[3];
unsigned int len;
int iovcnt;
if (data_iovlen >= DIM(iov) - 6)
return gpg_error (GPG_ERR_TOO_LARGE);
/* Check the validity conditions of NIST SP 800-185 */
if (keylen >= 255 || customlen >= 255 || digestlen >= 255)
return gpg_error (GPG_ERR_TOO_LARGE);
iovcnt = 0;
iov[iovcnt].data = "KMAC";
iov[iovcnt].off = 0;
iov[iovcnt].len = 4;
iovcnt++;
iov[iovcnt].data = (void *)custom;
iov[iovcnt].off = 0;
iov[iovcnt].len = customlen;
iovcnt++;
iov[iovcnt].data = (void *)headPAD;
iov[iovcnt].off = 0;
iov[iovcnt].len = sizeof (headPAD);
iovcnt++;
if (keylen < 32)
{
headK[0] = 1;
headK[1] = (keylen*8)&0xff;
iov[iovcnt].data = headK;
iov[iovcnt].off = 0;
iov[iovcnt].len = 2;
}
else
{
headK[0] = 2;
headK[1] = (keylen*8)>>8;
headK[2] = (keylen*8)&0xff;
iov[iovcnt].data = headK;
iov[iovcnt].off = 0;
iov[iovcnt].len = 3;
}
iovcnt++;
iov[iovcnt].data = (void *)key;
iov[iovcnt].off = 0;
iov[iovcnt].len = keylen;
iovcnt++;
len = iov[2].len + iov[3].len + iov[4].len;
len %= KECCAK512_BLOCKSIZE;
iov[iovcnt].data = (unsigned char *)pad;
iov[iovcnt].off = 0;
iov[iovcnt].len = sizeof (pad) - len;
iovcnt++;
memcpy (&iov[iovcnt], data_iov, data_iovlen * sizeof (gcry_buffer_t));
iovcnt += data_iovlen;
if (digestlen < 32)
{
right_encode_L[0] = (digestlen * 8) & 0xff;
right_encode_L[1] = 1;
}
else
{
right_encode_L[0] = (digestlen * 8) >> 8;
right_encode_L[1] = (digestlen * 8) & 0xff;
right_encode_L[2] = 2;
}
iov[iovcnt].data = right_encode_L;
iov[iovcnt].off = 0;
iov[iovcnt].len = 3;
iovcnt++;
err = gcry_md_hash_buffers_ext (GCRY_MD_CSHAKE256, 0,
digest, digestlen, iov, iovcnt);
return err;
}
/* Compute KEK (shared secret) for ECC with HASHALGO, ECDH result,
ciphertext in ECC_CT, public key in ECC_PK. */
gpg_error_t
gnupg_ecc_kem_kdf (void *kek, size_t kek_len,
int hashalgo, const void *ecdh, size_t ecdh_len,
const void *ecc_ct, size_t ecc_ct_len,
const void *ecc_pk, size_t ecc_pk_len)
{
gcry_buffer_t iov[3];
unsigned int dlen;
dlen = gcry_md_get_algo_dlen (hashalgo);
if (kek_len != dlen)
return gpg_error (GPG_ERR_INV_LENGTH);
memset (iov, 0, sizeof (iov));
iov[0].data = (unsigned char *)ecdh;
iov[0].len = ecdh_len;
iov[1].data = (unsigned char *)ecc_ct;
iov[1].len = ecc_ct_len;
iov[2].data = (unsigned char *)ecc_pk;
iov[2].len = ecc_pk_len;
gcry_md_hash_buffers (hashalgo, 0, kek, iov, 3);
return 0;
}
/* Compute KEK by combining two KEMs. The caller provides a buffer
* KEK allocated with size KEK_LEN which will receive the computed
* KEK. (ECC_SS, ECC_SS_LEN) is the shared secret of the first key.
* (ECC_CT, ECC_CT_LEN) is the ciphertext of the first key.
* (MLKEM_SS, ECC_SS_LEN) is the shared secret of the second key.
* (MLKEM_CT, MLKEM_CT_LEN) is the ciphertext of the second key.
* (FIXEDINFO, FIXEDINFO_LEN) is an octet string used to bind the KEK
* to a the key; for PGP we use the concatenation of the session key's
* algorithm id and the v5 fingerprint of the key.
*/
gpg_error_t
gnupg_kem_combiner (void *kek, size_t kek_len,
const void *ecc_ss, size_t ecc_ss_len,
const void *ecc_ct, size_t ecc_ct_len,
const void *mlkem_ss, size_t mlkem_ss_len,
const void *mlkem_ct, size_t mlkem_ct_len,
const void *fixedinfo, size_t fixedinfo_len)
{
gpg_error_t err;
gcry_buffer_t iov[6];
memset (iov, 0, sizeof (iov));
iov[0].data = "\x00\x00\x00\x01"; /* Counter */
iov[0].len = 4;
iov[1].data = (unsigned char *)ecc_ss;
iov[1].len = ecc_ss_len;
iov[2].data = (unsigned char *)ecc_ct;
iov[2].len = ecc_ct_len;
iov[3].data = (unsigned char *)mlkem_ss;
iov[3].len = mlkem_ss_len;
iov[4].data = (unsigned char *)mlkem_ct;
iov[4].len = mlkem_ct_len;
iov[5].data = (unsigned char *)fixedinfo;
iov[5].len = fixedinfo_len;
err = compute_kmac256 (kek, kek_len,
KMAC_KEY, strlen (KMAC_KEY),
KMAC_CUSTOM, strlen (KMAC_CUSTOM), iov, 6);
return err;
}

View File

@ -1,6 +1,6 @@
/* kska-io-support.c - Supporting functions for ksba reader and writer
* Copyright (C) 2001-2005, 2007, 2010-2011, 2017 Werner Koch
* Copyright (C) 2006 g10 Code GmbH
* Copyright (C) 2006, 2023 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -26,6 +26,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
*/
#include <config.h>
@ -96,6 +97,15 @@ struct writer_cb_parm_s
char *pem_name; /* Malloced. */
struct {
gnupg_ksba_progress_cb_t cb;
ctrl_t ctrl;
u32 last_time; /* last time reported */
uint64_t last; /* last amount reported */
uint64_t current; /* current amount */
uint64_t total; /* total amount */
} progress;
int wrote_begin;
int did_finish;
@ -110,6 +120,7 @@ struct writer_cb_parm_s
/* Context for this module's functions. */
struct gnupg_ksba_io_s {
int is_writer; /* True if this context refers a writer object. */
union {
struct reader_cb_parm_s rparm;
struct writer_cb_parm_s wparm;
@ -527,6 +538,33 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
/* Call the progress callback if its time. We do this very 2 seconds
* or if FORCE is set. However, we also require that at least 64KiB
* have been written to avoid unnecessary progress lines for small
* files. */
static gpg_error_t
update_write_progress (struct writer_cb_parm_s *parm, size_t count, int force)
{
gpg_error_t err = 0;
u32 timestamp;
parm->progress.current += count;
if (parm->progress.current >= (64*1024))
{
timestamp = make_timestamp ();
if (force || (timestamp - parm->progress.last_time > 1))
{
parm->progress.last = parm->progress.current;
parm->progress.last_time = timestamp;
err = parm->progress.cb (parm->progress.ctrl,
parm->progress.current,
parm->progress.total);
}
}
return err;
}
static int
base64_writer_cb (void *cb_value, const void *buffer, size_t count)
{
@ -535,6 +573,8 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
int i, c, idx, quad_count;
const unsigned char *p;
estream_t stream = parm->stream;
int rc;
size_t nleft;
if (!count)
return 0;
@ -557,7 +597,7 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
for (i=0; i < idx; i++)
radbuf[i] = parm->base64.radbuf[i];
for (p=buffer; count; p++, count--)
for (p=buffer, nleft = count; nleft; p++, nleft--)
{
radbuf[idx++] = *p;
if (idx > 2)
@ -583,7 +623,11 @@ base64_writer_cb (void *cb_value, const void *buffer, size_t count)
parm->base64.idx = idx;
parm->base64.quad_count = quad_count;
return es_ferror (stream)? gpg_error_from_syserror () : 0;
rc = es_ferror (stream)? gpg_error_from_syserror () : 0;
/* Note that we use the unencoded count for the progress. */
if (!rc && parm->progress.cb)
rc = update_write_progress (parm, count, 0);
return rc;
}
@ -594,13 +638,16 @@ plain_writer_cb (void *cb_value, const void *buffer, size_t count)
{
struct writer_cb_parm_s *parm = cb_value;
estream_t stream = parm->stream;
int rc;
if (!count)
return 0;
es_write (stream, buffer, count, NULL);
return es_ferror (stream)? gpg_error_from_syserror () : 0;
rc = es_ferror (stream)? gpg_error_from_syserror () : 0;
if (!rc && parm->progress.cb)
rc = update_write_progress (parm, count, 0);
return rc;
}
@ -610,6 +657,7 @@ base64_finish_write (struct writer_cb_parm_s *parm)
unsigned char *radbuf;
int c, idx, quad_count;
estream_t stream = parm->stream;
int rc;
if (!parm->wrote_begin)
return 0; /* Nothing written or we are not called in base-64 mode. */
@ -656,7 +704,10 @@ base64_finish_write (struct writer_cb_parm_s *parm)
es_fputs ("-----\n", stream);
}
return es_ferror (stream)? gpg_error_from_syserror () : 0;
rc = es_ferror (stream)? gpg_error_from_syserror () : 0;
if (!rc && parm->progress.cb)
rc = update_write_progress (parm, 0, 1);
return rc;
}
@ -788,6 +839,7 @@ gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx, unsigned int flags,
*ctx = xtrycalloc (1, sizeof **ctx);
if (!*ctx)
return gpg_error_from_syserror ();
(*ctx)->is_writer = 1;
rc = ksba_writer_new (&w);
if (rc)
@ -865,3 +917,37 @@ gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx)
xfree (ctx->u.wparm.pem_name);
xfree (ctx);
}
/* Set a callback to the writer object. CTRL will be bassed to the
* callback. */
void
gnupg_ksba_set_progress_cb (gnupg_ksba_io_t ctx,
gnupg_ksba_progress_cb_t cb, ctrl_t ctrl)
{
struct writer_cb_parm_s *parm;
if (!ctx || !ctx->is_writer)
return; /* Currently only supported for writer objects. */
parm = &ctx->u.wparm;
parm->progress.cb = cb;
parm->progress.ctrl = ctrl;
parm->progress.last_time = 0;
parm->progress.last = 0;
parm->progress.current = 0;
parm->progress.total = 0;
}
/* Update the total count for the progress thingy. */
void
gnupg_ksba_set_total (gnupg_ksba_io_t ctx, uint64_t total)
{
struct writer_cb_parm_s *parm;
if (!ctx || !ctx->is_writer)
return; /* Currently only supported for writer objects. */
parm = &ctx->u.wparm;
parm->progress.total = total;
}

View File

@ -25,6 +25,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
*/
#ifndef GNUPG_KSBA_IO_SUPPORT_H
@ -42,6 +43,10 @@
/* Context object. */
typedef struct gnupg_ksba_io_s *gnupg_ksba_io_t;
/* Progress callback type. */
typedef gpg_error_t (*gnupg_ksba_progress_cb_t)(ctrl_t ctrl,
uint64_t current,
uint64_t total);
gpg_error_t gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx,
@ -57,10 +62,13 @@ gpg_error_t gnupg_ksba_create_writer (gnupg_ksba_io_t *ctx,
const char *pem_name,
estream_t stream,
ksba_writer_t *r_writer);
gpg_error_t gnupg_ksba_finish_writer (gnupg_ksba_io_t ctx);
void gnupg_ksba_destroy_writer (gnupg_ksba_io_t ctx);
void gnupg_ksba_set_progress_cb (gnupg_ksba_io_t ctx,
gnupg_ksba_progress_cb_t cb, ctrl_t ctrl);
void gnupg_ksba_set_total (gnupg_ksba_io_t ctx, uint64_t total);

View File

@ -57,35 +57,6 @@ mem_count_chr (const void *buffer, int c, size_t length)
}
/* This is a case-sensitive version of our memistr. I wonder why no
standard function memstr exists but I better do not use the name
memstr to avoid future conflicts. */
static const char *
my_memstr (const void *buffer, size_t buflen, const char *sub)
{
const unsigned char *buf = buffer;
const unsigned char *t = (const unsigned char *)buf;
const unsigned char *s = (const unsigned char *)sub;
size_t n = buflen;
for ( ; n ; t++, n-- )
{
if (*t == *s)
{
for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
;
if (!*s)
return (const char*)buf;
t = (const unsigned char *)buf;
s = (const unsigned char *)sub ;
n = buflen;
}
}
return NULL;
}
static int
string_has_ctrl_or_space (const char *string)
{
@ -159,7 +130,7 @@ is_valid_mailbox_mem (const void *name_arg, size_t namelen)
|| *name == '@'
|| name[namelen-1] == '@'
|| name[namelen-1] == '.'
|| my_memstr (name, namelen, ".."));
|| gnupg_memstr (name, namelen, ".."));
}

View File

@ -36,27 +36,6 @@
#include "iobuf.h"
#include "i18n.h"
/* Used by libgcrypt for logging. */
static void
my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
{
(void)dummy;
/* Map the log levels. */
switch (level)
{
case GCRY_LOG_CONT: level = GPGRT_LOGLVL_CONT; break;
case GCRY_LOG_INFO: level = GPGRT_LOGLVL_INFO; break;
case GCRY_LOG_WARN: level = GPGRT_LOGLVL_WARN; break;
case GCRY_LOG_ERROR:level = GPGRT_LOGLVL_ERROR; break;
case GCRY_LOG_FATAL:level = GPGRT_LOGLVL_FATAL; break;
case GCRY_LOG_BUG: level = GPGRT_LOGLVL_BUG; break;
case GCRY_LOG_DEBUG:level = GPGRT_LOGLVL_DEBUG; break;
default: level = GPGRT_LOGLVL_ERROR; break;
}
log_logv (level, fmt, arg_ptr);
}
/* This function is called by libgcrypt on a fatal error. */
static void
@ -100,7 +79,6 @@ my_gcry_outofcore_handler (void *opaque, size_t req_n, unsigned int flags)
void
setup_libgcrypt_logging (void)
{
gcry_set_log_handler (my_gcry_logger, NULL);
gcry_set_fatalerror_handler (my_gcry_fatalerror_handler, NULL);
gcry_set_outofcore_handler (my_gcry_outofcore_handler, NULL);
}
@ -415,112 +393,6 @@ decode_c_string (const char *src)
}
/* Check whether (BUF,LEN) is valid header for an OpenPGP compressed
* packet. LEN should be at least 6. */
static int
is_openpgp_compressed_packet (const unsigned char *buf, size_t len)
{
int c, ctb, pkttype;
int lenbytes;
ctb = *buf++; len--;
if (!(ctb & 0x80))
return 0; /* Invalid packet. */
if ((ctb & 0x40)) /* New style (OpenPGP) CTB. */
{
pkttype = (ctb & 0x3f);
if (!len)
return 0; /* Expected first length octet missing. */
c = *buf++; len--;
if (c < 192)
;
else if (c < 224)
{
if (!len)
return 0; /* Expected second length octet missing. */
}
else if (c == 255)
{
if (len < 4)
return 0; /* Expected length octets missing */
}
}
else /* Old style CTB. */
{
pkttype = (ctb>>2)&0xf;
lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
if (len < lenbytes)
return 0; /* Not enough length bytes. */
}
return (pkttype == 8);
}
/*
* Check if the file is compressed. You need to pass the first bytes
* of the file as (BUF,BUFLEN). Returns true if the buffer seems to
* be compressed.
*/
int
is_file_compressed (const byte *buf, unsigned int buflen)
{
int i;
struct magic_compress_s
{
byte len;
byte extchk;
byte magic[5];
} magic[] =
{
{ 3, 0, { 0x42, 0x5a, 0x68, 0x00 } }, /* bzip2 */
{ 3, 0, { 0x1f, 0x8b, 0x08, 0x00 } }, /* gzip */
{ 4, 0, { 0x50, 0x4b, 0x03, 0x04 } }, /* (pk)zip */
{ 5, 0, { '%', 'P', 'D', 'F', '-'} }, /* PDF */
{ 4, 1, { 0xff, 0xd8, 0xff, 0xe0 } }, /* Maybe JFIF */
{ 5, 2, { 0x89, 'P','N','G', 0x0d} } /* Likely PNG */
};
if ( buflen < 6 )
{
return 0; /* Too short to check - assume uncompressed. */
}
for ( i = 0; i < DIM (magic); i++ )
{
if (!memcmp( buf, magic[i].magic, magic[i].len))
{
switch (magic[i].extchk)
{
case 0:
return 1; /* Is compressed. */
case 1:
if (buflen > 11 && !memcmp (buf + 6, "JFIF", 5))
return 1; /* JFIF: this likely a compressed JPEG. */
break;
case 2:
if (buflen > 8
&& buf[5] == 0x0a && buf[6] == 0x1a && buf[7] == 0x0a)
return 1; /* This is a PNG. */
break;
default:
break;
}
}
}
if (buflen >= 6 && is_openpgp_compressed_packet (buf, buflen))
{
return 1; /* Already compressed. */
}
return 0; /* Not detected as compressed. */
}
/* Try match against each substring of multistr, delimited by | */
int
match_multistr (const char *multistr,const char *match)
@ -793,3 +665,53 @@ parse_compatibility_flags (const char *string, unsigned int *flagvar,
*flagvar |= result;
return 0;
}
/* Convert STRING consisting of base64 characters into its binary
* representation and store the result in a newly allocated buffer at
* R_BUFFER with its length at R_BUFLEN. If TITLE is NULL a plain
* base64 decoding is done. If it is the empty string the decoder
* will skip everything until a "-----BEGIN " line has been seen,
* decoding then ends at a "----END " line. On failure the function
* returns an error code and sets R_BUFFER to NULL. If the decoded
* data has a length of 0 a dummy buffer will still be allocated and
* the length is set to 0. */
gpg_error_t
b64decode (const char *string, const char *title,
void **r_buffer, size_t *r_buflen)
{
gpg_error_t err;
gpgrt_b64state_t state;
size_t nbytes;
char *buffer;
*r_buffer = NULL;
*r_buflen = 0;
buffer = xtrystrdup (string);
if (!buffer)
return gpg_error_from_syserror();
state = gpgrt_b64dec_start (title);
if (!state)
{
err = gpg_error_from_syserror ();
xfree (buffer);
return err;
}
err = gpgrt_b64dec_proc (state, buffer, strlen (buffer), &nbytes);
if (!err)
{
err = gpgrt_b64dec_finish (state);
state = NULL;
}
if (err)
xfree (buffer);
else
{
*r_buffer = buffer;
*r_buflen = nbytes;
}
gpgrt_b64dec_finish (state); /* Make sure it is released. */
return err;
}

View File

@ -126,80 +126,3 @@ same_file_p (const char *name1, const char *name2)
}
return yes;
}
/*
timegm() is a GNU function that might not be available everywhere.
It's basically the inverse of gmtime() - you give it a struct tm,
and get back a time_t. It differs from mktime() in that it handles
the case where the struct tm is UTC and the local environment isn't.
Note, that this replacement implementation might not be thread-safe!
Some BSDs don't handle the putenv("foo") case properly, so we use
unsetenv if the platform has it to remove environment variables.
*/
#ifndef HAVE_TIMEGM
time_t
timegm (struct tm *tm)
{
#ifdef HAVE_W32_SYSTEM
/* This one is thread safe. */
SYSTEMTIME st;
FILETIME ft;
unsigned long long cnsecs;
st.wYear = tm->tm_year + 1900;
st.wMonth = tm->tm_mon + 1;
st.wDay = tm->tm_mday;
st.wHour = tm->tm_hour;
st.wMinute = tm->tm_min;
st.wSecond = tm->tm_sec;
st.wMilliseconds = 0; /* Not available. */
st.wDayOfWeek = 0; /* Ignored. */
/* System time is UTC thus the conversion is pretty easy. */
if (!SystemTimeToFileTime (&st, &ft))
{
gpg_err_set_errno (EINVAL);
return (time_t)(-1);
}
cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
| ft.dwLowDateTime);
cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
return (time_t)(cnsecs / 10000000ULL);
#else /* (Non thread safe implementation!) */
time_t answer;
char *zone;
zone=getenv("TZ");
putenv("TZ=UTC");
tzset();
answer=mktime(tm);
if(zone)
{
static char *old_zone;
if (!old_zone)
{
old_zone = malloc(3+strlen(zone)+1);
if (old_zone)
{
strcpy(old_zone,"TZ=");
strcat(old_zone,zone);
}
}
if (old_zone)
putenv (old_zone);
}
else
gnupg_unsetenv("TZ");
tzset();
return answer;
#endif
}
#endif /*!HAVE_TIMEGM*/

View File

@ -38,12 +38,6 @@
int same_file_p (const char *name1, const char *name2);
#ifndef HAVE_TIMEGM
#include <time.h>
time_t timegm (struct tm *tm);
#endif /*!HAVE_TIMEGM*/
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
#define DIMof(type,member) DIM(((type *)0)->member)

View File

@ -48,6 +48,7 @@ struct name_value_container
struct name_value_entry *first;
struct name_value_entry *last;
unsigned int private_key_mode:1;
unsigned int modified:1;
};
@ -87,11 +88,15 @@ my_error (gpg_err_code_t ec)
/* Allocation and deallocation. */
/* Allocate a private key container structure. */
/* Allocate a name value container structure. */
nvc_t
nvc_new (void)
{
return xtrycalloc (1, sizeof (struct name_value_container));
nvc_t nvc;
nvc = xtrycalloc (1, sizeof (struct name_value_container));
if (nvc)
nvc->modified = 1;
return nvc;
}
@ -142,6 +147,24 @@ nvc_release (nvc_t pk)
xfree (pk);
}
/* Return the modified-flag of the container and clear it if CLEAR is
* set. That flag is set for a new container and set with each
* update. */
int
nvc_modified (nvc_t pk, int clear)
{
int modified;
if (!pk)
return 0;
modified = pk->modified;
if (clear)
pk->modified = 0;
return modified;
}
/* Dealing with names and values. */
@ -427,6 +450,8 @@ _nvc_add (nvc_t pk, char *name, char *value, strlist_t raw_value,
else
pk->first = pk->last = e;
pk->modified = 1;
leave:
if (err)
{
@ -476,27 +501,46 @@ nvc_set (nvc_t pk, const char *name, const char *value)
e = nvc_lookup (pk, name);
if (e)
{
char *v;
v = xtrystrdup (value);
if (v == NULL)
return my_error_from_syserror ();
free_strlist_wipe (e->raw_value);
e->raw_value = NULL;
if (e->value)
wipememory (e->value, strlen (e->value));
xfree (e->value);
e->value = v;
return 0;
}
return nve_set (pk, e, value);
else
return nvc_add (pk, name, value);
}
/* Update entry E to VALUE. PK is optional; if given its modified
* flag will be updated. */
gpg_error_t
nve_set (nvc_t pk, nve_t e, const char *value)
{
char *v;
if (!e)
return GPG_ERR_INV_ARG;
if (e->value && value && !strcmp (e->value, value))
{
/* Setting same value - ignore this call and don't set the
* modified flag (if PK is given). */
return 0;
}
v = xtrystrdup (value? value:"");
if (!v)
return my_error_from_syserror ();
free_strlist_wipe (e->raw_value);
e->raw_value = NULL;
if (e->value)
wipememory (e->value, strlen (e->value));
xfree (e->value);
e->value = v;
if (pk)
pk->modified = 1;
return 0;
}
/* Delete the given entry from PK. */
void
nvc_delete (nvc_t pk, nve_t entry)
@ -512,6 +556,7 @@ nvc_delete (nvc_t pk, nve_t entry)
pk->last = entry->prev;
nve_release (entry, pk->private_key_mode);
pk->modified = 1;
}
@ -592,7 +637,7 @@ nve_next_value (nve_t entry, const char *name)
/* Return the string for the first entry in NVC with NAME. If an
* entry with NAME is missing in NVC or its value is the empty string
* NULL is returned. Note that the The returned string is a pointer
* NULL is returned. Note that the the returned string is a pointer
* into NVC. */
const char *
nvc_get_string (nvc_t nvc, const char *name)

View File

@ -50,6 +50,9 @@ nvc_t nvc_new_private_key (void);
/* Release a name value container structure. */
void nvc_release (nvc_t pk);
/* Return the modified flag and optionally clear it. */
int nvc_modified (nvc_t pk, int clear);
/* Get the name. */
char *nve_name (nve_t pke);
@ -92,6 +95,9 @@ gpg_error_t nvc_add (nvc_t pk, const char *name, const char *value);
first entry is updated. */
gpg_error_t nvc_set (nvc_t pk, const char *name, const char *value);
/* Update entry E to VALUE. PK is optional. */
gpg_error_t nve_set (nvc_t pk, nve_t e, const char *value);
/* Delete the given entry from PK. */
void nvc_delete (nvc_t pk, nve_t pke);

View File

@ -43,23 +43,34 @@ static struct {
const char *oidstr; /* IETF formatted OID. */
unsigned int nbits; /* Nominal bit length of the curve. */
const char *alias; /* NULL or alternative name of the curve. */
const char *abbr; /* NULL or abbreviated name of the curve. */
int pubkey_algo; /* Required OpenPGP algo or 0 for ECDSA/ECDH. */
enum gcry_kem_algos kem_algo; /* 0 or the KEM algorithm for PQC. */
} oidtable[] = {
{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
{ "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
{ "Curve25519", "1.3.101.110", 255, "cv25519", PUBKEY_ALGO_ECDH },
{ "Ed25519", "1.3.101.112", 255, "ed25519", PUBKEY_ALGO_EDDSA },
{ "X448", "1.3.101.111", 448, "cv448", PUBKEY_ALGO_ECDH },
{ "Ed448", "1.3.101.113", 456, "ed448", PUBKEY_ALGO_EDDSA },
{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", NULL,
PUBKEY_ALGO_ECDH, GCRY_KEM_RAW_X25519 /* only during development */},
{ "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", NULL,
PUBKEY_ALGO_EDDSA },
{ "Curve25519", "1.3.101.110", 255, "cv25519", NULL,
PUBKEY_ALGO_ECDH, GCRY_KEM_RAW_X25519 },
{ "Ed25519", "1.3.101.112", 255, "ed25519", NULL,
PUBKEY_ALGO_EDDSA },
{ "X448", "1.3.101.111", 448, "cv448", NULL,
PUBKEY_ALGO_ECDH, GCRY_KEM_RAW_X448 },
{ "Ed448", "1.3.101.113", 456, "ed448", NULL,
PUBKEY_ALGO_EDDSA },
{ "NIST P-256", "1.2.840.10045.3.1.7", 256, "nistp256" },
{ "NIST P-384", "1.3.132.0.34", 384, "nistp384" },
{ "NIST P-521", "1.3.132.0.35", 521, "nistp521" },
{ "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", 256 },
{ "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", 384 },
{ "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", 512 },
{ "brainpoolP256r1", "1.3.36.3.3.2.8.1.1.7", 256, NULL, "bp256",
0, GCRY_KEM_RAW_BP256 },
{ "brainpoolP384r1", "1.3.36.3.3.2.8.1.1.11", 384, NULL, "bp384",
0, GCRY_KEM_RAW_BP384 },
{ "brainpoolP512r1", "1.3.36.3.3.2.8.1.1.13", 512, NULL, "bp512",
0, GCRY_KEM_RAW_BP512 },
{ "secp256k1", "1.3.132.0.10", 256 },
@ -477,10 +488,20 @@ openpgp_curve_to_oid (const char *name, unsigned int *r_nbits, int *r_algo)
/* Map an OpenPGP OID to the Libgcrypt curve name. Returns NULL for
* unknown curve names. Unless CANON is set we prefer an alias name
* here which is more suitable for printing. */
* unknown curve names. MODE defines which version of the curve name
* is returned. For example:
*
* | OID | mode=0 | mode=1 | mode=2 |
* |----------------------+-----------------+-----------------+----------|
* | 1.2.840.10045.3.1.7 | nistp256 | NIST P-256 | nistp256 |
* | 1.3.36.3.3.2.8.1.1.7 | brainpoolP256r1 | brainpoolP256r1 | bp256 |
*
* Thus mode 0 returns the name as commonly used gpg, mode 1 returns
* the canonical name, and mode 2 prefers an abbreviated name over the
* commonly used name.
*/
const char *
openpgp_oid_to_curve (const char *oidstr, int canon)
openpgp_oid_to_curve (const char *oidstr, int mode)
{
int i;
@ -489,7 +510,15 @@ openpgp_oid_to_curve (const char *oidstr, int canon)
for (i=0; oidtable[i].name; i++)
if (!strcmp (oidtable[i].oidstr, oidstr))
return !canon && oidtable[i].alias? oidtable[i].alias : oidtable[i].name;
{
if (mode == 2)
{
if (oidtable[i].abbr)
return oidtable[i].abbr;
mode = 0; /* No abbreviation - fallback to mode 0. */
}
return !mode && oidtable[i].alias? oidtable[i].alias : oidtable[i].name;
}
return NULL;
}
@ -517,6 +546,29 @@ openpgp_oid_or_name_to_curve (const char *oidname, int canon)
}
/* Return the KEM algorithm id for the curve with OIDNAME. */
enum gcry_kem_algos
openpgp_oid_to_kem_algo (const char *oidname)
{
int i;
if (!oidname)
return 0;
for (i=0; oidtable[i].name; i++)
if (!strcmp (oidtable[i].oidstr, oidname))
return oidtable[i].kem_algo;
for (i=0; oidtable[i].name; i++)
if (!ascii_strcasecmp (oidtable[i].name, oidname)
|| (oidtable[i].alias
&& !ascii_strcasecmp (oidtable[i].alias, oidname)))
return oidtable[i].kem_algo;
return 0;
}
/* Return true if the curve with NAME is supported. */
static int
curve_supported_p (const char *name)
@ -574,7 +626,9 @@ openpgp_is_curve_supported (const char *name, int *r_algo,
{
if ((!ascii_strcasecmp (name, oidtable[idx].name)
|| (oidtable[idx].alias
&& !ascii_strcasecmp (name, (oidtable[idx].alias))))
&& !ascii_strcasecmp (name, (oidtable[idx].alias)))
|| (oidtable[idx].abbr
&& !ascii_strcasecmp (name, (oidtable[idx].abbr))))
&& curve_supported_p (oidtable[idx].name))
{
if (r_algo)
@ -598,6 +652,7 @@ map_gcry_pk_to_openpgp (enum gcry_pk_algos algo)
case GCRY_PK_EDDSA: return PUBKEY_ALGO_EDDSA;
case GCRY_PK_ECDSA: return PUBKEY_ALGO_ECDSA;
case GCRY_PK_ECDH: return PUBKEY_ALGO_ECDH;
case GCRY_PK_KEM: return PUBKEY_ALGO_KYBER;
default: return algo < 110 ? (pubkey_algo_t)algo : 0;
}
}

View File

@ -122,6 +122,9 @@ typedef enum
SIGSUBPKT_ATTST_SIGS = 37, /* Attested Certifications. */
SIGSUBPKT_KEY_BLOCK = 38, /* Entire key used. */
SIGSUBPKT_META_HASH = 40, /* Literal Data Meta Hash. */
SIGSUBPKT_TRUST_ALIAS = 41, /* Trust Alias. */
SIGSUBPKT_FLAG_CRITICAL = 128
}
sigsubpkttype_t;
@ -168,7 +171,11 @@ typedef enum
PUBKEY_ALGO_ECDSA = 19, /* RFC-6637 */
PUBKEY_ALGO_ELGAMAL = 20, /* Elgamal encrypt+sign (legacy). */
/* 21 reserved by OpenPGP. */
PUBKEY_ALGO_EDDSA = 22, /* EdDSA (not yet assigned). */
PUBKEY_ALGO_EDDSA = 22, /* EdDSA. */
PUBKEY_ALGO_KYBER = 29, /* Kyber */
PUBKEY_ALGO_DIL3_25519 = 35, /* Dilithium3 + Ed25519 (aka ML-DSA-65) */
PUBKEY_ALGO_DIL5_448 = 36, /* Dilithium5 + Ed448 (aka ML-DSA-87) */
PUBKEY_ALGO_SPHINX_SHA2 = 41, /* SPHINX+-simple-SHA2 (aka SLH-DSA-SHA2) */
PUBKEY_ALGO_PRIVATE10 = 110
}
pubkey_algo_t;
@ -203,7 +210,7 @@ compress_algo_t;
#define OPENPGP_MAX_NPKEY 5 /* Maximum number of public key parameters. */
#define OPENPGP_MAX_NSKEY 7 /* Maximum number of secret key parameters. */
#define OPENPGP_MAX_NSIG 2 /* Maximum number of signature parameters. */
#define OPENPGP_MAX_NENC 2 /* Maximum number of encryption parameters. */
#define OPENPGP_MAX_NENC 4 /* Maximum number of encryption parameters. */
/* Decode an rfc4880 encoded S2K count. */

View File

@ -85,37 +85,6 @@ my_error (gpg_err_code_t ec)
}
/* This is a case-sensitive version of our memistr. I wonder why no
* standard function memstr exists but I better do not use the name
* memstr to avoid future conflicts.
*
* FIXME: Move this to a stringhelp.c
*/
static const char *
my_memstr (const void *buffer, size_t buflen, const char *sub)
{
const unsigned char *buf = buffer;
const unsigned char *t = (const unsigned char *)buf;
const unsigned char *s = (const unsigned char *)sub;
size_t n = buflen;
for ( ; n ; t++, n-- )
{
if (*t == *s)
{
for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
;
if (!*s)
return (const char*)buf;
t = (const unsigned char *)buf;
s = (const unsigned char *)sub ;
n = buflen;
}
}
return NULL;
}
/* Return a pointer to the next logical connection operator or NULL if
* none. */
static char *
@ -560,7 +529,7 @@ recsel_select (recsel_expr_t selector,
break;
case SELECT_SUB:
if (se->xcase)
result = !!my_memstr (value, valuelen, se->value);
result = !!gnupg_memstr (value, valuelen, se->value);
else
result = !!memistr (value, valuelen, se->value);
break;

View File

@ -84,9 +84,10 @@ static struct
modules (eg "xim"). */
{ "INSIDE_EMACS" }, /* Set by Emacs before running a
process. */
{ "PINENTRY_USER_DATA", "pinentry-user-data"}
{ "PINENTRY_USER_DATA", "pinentry-user-data"},
/* Used for communication with
non-standard Pinentries. */
{ "PINENTRY_GEOM_HINT" } /* Used to pass window information. */
};

View File

@ -992,7 +992,7 @@ get_pk_algo_from_key (gcry_sexp_t key)
gcry_sexp_t list;
const char *s;
size_t n;
char algoname[6];
char algoname[10];
int algo = 0;
list = gcry_sexp_nth (key, 1);
@ -1194,3 +1194,47 @@ cipher_mode_to_string (int mode)
default: return "[?]";
}
}
/* Return the cannonical name of the ECC curve in KEY. */
const char *
get_ecc_curve_from_key (gcry_sexp_t key)
{
gcry_sexp_t list = NULL;
gcry_sexp_t l2 = NULL;
const char *curve_name = NULL;
char *name = NULL;
/* Check that the first element is valid. */
list = gcry_sexp_find_token (key, "public-key", 0);
if (!list)
list = gcry_sexp_find_token (key, "private-key", 0);
if (!list)
list = gcry_sexp_find_token (key, "protected-private-key", 0);
if (!list)
list = gcry_sexp_find_token (key, "shadowed-private-key", 0);
if (!list)
goto leave;
l2 = gcry_sexp_cadr (list);
gcry_sexp_release (list);
list = l2;
l2 = NULL;
name = gcry_sexp_nth_string (list, 0);
if (!name)
goto leave;
if (gcry_pk_map_name (name) != GCRY_PK_ECC)
goto leave;
l2 = gcry_sexp_find_token (list, "curve", 0);
xfree (name);
name = gcry_sexp_nth_string (l2, 1);
curve_name = openpgp_oid_or_name_to_curve (name, 1);
gcry_sexp_release (l2);
leave:
xfree (name);
gcry_sexp_release (list);
return curve_name;
}

View File

@ -259,7 +259,7 @@ get_fingerprint (gcry_sexp_t key, int algo,
}
else
{
struct b64state b64s;
gpgrt_b64state_t b64s;
estream_t stream;
char *p;
long int len;
@ -273,15 +273,15 @@ get_fingerprint (gcry_sexp_t key, int algo,
goto leave;
}
err = b64enc_start_es (&b64s, stream, "");
if (err)
b64s = gpgrt_b64enc_start (stream, "");
if (!b64s)
{
es_fclose (stream);
goto leave;
}
err = b64enc_write (&b64s,
gcry_md_read (md, algo), gcry_md_get_algo_dlen (algo));
err = gpgrt_b64enc_write (b64s, gcry_md_read (md, algo),
gcry_md_get_algo_dlen (algo));
if (err)
{
es_fclose (stream);
@ -289,7 +289,7 @@ get_fingerprint (gcry_sexp_t key, int algo,
}
/* Finish, get the length, and close the stream. */
err = b64enc_finish (&b64s);
err = gpgrt_b64enc_finish (b64s);
len = es_ftell (stream);
es_fclose (stream);
if (err)
@ -566,7 +566,7 @@ ssh_public_key_in_base64 (gcry_sexp_t key, estream_t stream,
const char *identifier = NULL;
void *blob = NULL;
size_t bloblen;
struct b64state b64_state;
gpgrt_b64state_t b64_state;
algo = get_pk_algo_from_key (key);
if (algo == 0)
@ -624,15 +624,15 @@ ssh_public_key_in_base64 (gcry_sexp_t key, estream_t stream,
es_fprintf (stream, "%s ", identifier);
err = b64enc_start_es (&b64_state, stream, "");
if (err)
b64_state = gpgrt_b64enc_start (stream, "");
if (!b64_state)
{
es_free (blob);
return err;
return gpg_error_from_syserror ();
}
err = b64enc_write (&b64_state, blob, bloblen);
b64enc_finish (&b64_state);
err = gpgrt_b64enc_write (b64_state, blob, bloblen);
gpgrt_b64enc_finish (b64_state);
es_free (blob);
if (err)
return err;

View File

@ -54,6 +54,7 @@ enum
STATUS_NEED_PASSPHRASE,
STATUS_VALIDSIG,
STATUS_ASSERT_SIGNER,
STATUS_ASSERT_PUBKEY_ALGO,
STATUS_SIG_ID,
STATUS_ENC_TO,
STATUS_NODATA,
@ -152,6 +153,7 @@ enum
STATUS_TRUNCATED,
STATUS_MOUNTPOINT,
STATUS_BLOCKDEV,
STATUS_PLAINDEV, /* The decrypted virtual device. */
STATUS_PINENTRY_LAUNCHED,

View File

@ -161,6 +161,35 @@ ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
}
/* This is a case-sensitive version of our memistr. I wonder why no
* standard function memstr exists but we better do not use the name
* memstr to avoid future conflicts.
*/
const char *
gnupg_memstr (const void *buffer, size_t buflen, const char *sub)
{
const unsigned char *buf = buffer;
const unsigned char *t = (const unsigned char *)buf;
const unsigned char *s = (const unsigned char *)sub;
size_t n = buflen;
for ( ; n ; t++, n-- )
{
if (*t == *s)
{
for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
;
if (!*s)
return (const char*)buf;
t = (const unsigned char *)buf;
s = (const unsigned char *)sub ;
n = buflen;
}
}
return NULL;
}
/* This function is similar to strncpy(). However it won't copy more
* than N - 1 characters and makes sure that a '\0' is appended. With
* N given as 0, nothing will happen. With DEST given as NULL, memory
@ -696,7 +725,7 @@ compare_filenames (const char *a, const char *b)
/* Convert a base-10 number in STRING into a 64 bit unsigned int
* value. Leading white spaces are skipped but no error checking is
* done. Thus it is similar to atoi(). */
* done. Thus it is similar to atoi(). See also scan_secondsstr. */
uint64_t
string_to_u64 (const char *string)
{
@ -1689,10 +1718,16 @@ format_text (const char *text_in, int target_cols, int max_cols)
}
/* Substitute environment variables in STRING and return a new string.
* On error the function returns NULL. */
/* Substitute variables in STRING and return a new string. GETVAL is
* a function which maps NAME to its value; that value is a string
* which may not change during the execution time of this function.
* If GETVAL returns NULL substitute_vars returns NULL and the caller
* may inspect ERRNO for the reason. In all other error cases this
* function also returns NULL. Caller must free the returned string. */
char *
substitute_envvars (const char *string)
substitute_vars (const char *string,
const char *(*getval)(void *cookie, const char *name),
void *cookie)
{
char *line, *p, *pend;
const char *value;
@ -1743,19 +1778,22 @@ substitute_envvars (const char *string)
{
int save = *pend;
*pend = 0;
value = getenv (p+2);
value = getval (cookie, p+2);
*pend++ = save;
}
else
{
int save = *pend;
*pend = 0;
value = getenv (p+1);
value = getval (cookie, p+1);
*pend = save;
}
if (!value)
value = "";
{
xfree (result);
return NULL;
}
valuelen = strlen (value);
if (valuelen <= pend - p)
{
@ -1791,3 +1829,26 @@ substitute_envvars (const char *string)
leave:
return result;
}
/* Helper for substitute_envvars. */
static const char *
subst_getenv (void *cookie, const char *name)
{
const char *s;
(void)cookie;
s = getenv (name);
return s? s : "";
}
/* Substitute environment variables in STRING and return a new string.
* On error the function returns NULL. */
char *
substitute_envvars (const char *string)
{
return substitute_vars (string, subst_getenv, NULL);
}

View File

@ -40,6 +40,7 @@
char *has_leading_keyword (const char *string, const char *keyword);
const char *memistr (const void *buf, size_t buflen, const char *sub);
const char *gnupg_memstr (const void *buffer, size_t buflen, const char *sub);
char *mem2str( char *, const void *, size_t);
char *trim_spaces( char *string );
char *ascii_trim_spaces (char *string);
@ -169,7 +170,10 @@ int compare_version_strings (const char *my_version, const char *req_version);
/* Format a string so that it fits within about TARGET_COLS columns. */
char *format_text (const char *text, int target_cols, int max_cols);
/* Substitute environmen variabales in STRING. */
/* Substitute variables in STRING. */
char *substitute_vars (const char *string,
const char *(*getval)(void *cookie, const char *name),
void *cookie);
char *substitute_envvars (const char *string);

View File

@ -113,6 +113,8 @@ static int allow_special_filenames;
#ifdef HAVE_W32_SYSTEM
/* State of gnupg_inhibit_set_foregound_window. */
static int inhibit_set_foregound_window;
/* Disable the use of _open_osfhandle. */
static int no_translate_sys2libc_fd;
#endif
@ -252,6 +254,9 @@ map_w32_to_errno (DWORD w32_err)
case ERROR_ALREADY_EXISTS:
return EEXIST;
case ERROR_FILE_INVALID:
return EIO;
/* This mapping has been taken from reactOS. */
case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
case ERROR_ARENA_TRASHED: return ENOMEM;
@ -324,15 +329,17 @@ map_w32_to_errno (DWORD w32_err)
#endif /*HAVE_W32_SYSTEM*/
/* Set ERRNO from the Windows error. EC may be -1 to use the last error. */
/* Set ERRNO from the Windows error. EC may be -1 to use the last
* error. Returns the Windows error code. */
#ifdef HAVE_W32_SYSTEM
void
int
gnupg_w32_set_errno (int ec)
{
/* FIXME: Replace by gpgrt_w32_set_errno. */
if (ec == -1)
ec = GetLastError ();
_set_errno (map_w32_to_errno (ec));
return ec;
}
#endif /*HAVE_W32_SYSTEM*/
@ -346,6 +353,16 @@ enable_special_filenames (void)
}
/* Disable the use use of _open_osfhandle on Windows. */
void
disable_translate_sys2libc_fd (void)
{
#ifdef HAVE_W32_SYSTEM
no_translate_sys2libc_fd = 1;
#endif
}
/* Return a string which is used as a kind of process ID. */
const byte *
get_session_marker (size_t *rlen)
@ -532,10 +549,10 @@ gnupg_usleep (unsigned int usecs)
different from the libc file descriptors (like open). This function
translates system file handles to libc file handles. FOR_WRITE
gives the direction of the handle. */
int
#if defined(HAVE_W32_SYSTEM)
static int
translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
{
#if defined(HAVE_W32_SYSTEM)
int x;
if (fd == GNUPG_INVALID_FD)
@ -547,27 +564,87 @@ translate_sys2libc_fd (gnupg_fd_t fd, int for_write)
if (x == -1)
log_error ("failed to translate osfhandle %p\n", (void *) fd);
return x;
#else /*!HAVE_W32_SYSTEM */
}
#endif /*!HAVE_W32_SYSTEM */
/* This is the same as translate_sys2libc_fd but takes an integer
which is assumed to be such an system handle. */
int
translate_sys2libc_fd_int (int fd, int for_write)
{
#ifdef HAVE_W32_SYSTEM
if (fd <= 2 || no_translate_sys2libc_fd)
return fd; /* Do not do this for stdin, stdout, and stderr. */
return translate_sys2libc_fd ((void*)(intptr_t)fd, for_write);
#else
(void)for_write;
return fd;
#endif
}
/* This is the same as translate_sys2libc_fd but takes an integer
which is assumed to be such an system handle. On WindowsCE the
passed FD is a rendezvous ID and the function finishes the pipe
creation. */
int
translate_sys2libc_fd_int (int fd, int for_write)
{
#ifdef HAVE_W32_SYSTEM
if (fd <= 2)
return fd; /* Do not do this for error, stdin, stdout, stderr. */
return translate_sys2libc_fd ((void*)fd, for_write);
/*
* Parse the string representation of a file reference (file handle on
* Windows or file descriptor on POSIX) in FDSTR. The string
* representation may be either of folllowing:
* (1) 0, 1, or 2 which means stdin, stdout, and stderr, respectively.
* (2) Integer representation (by %d of printf).
* (3) Hex representation which starts as "0x".
*
* Then, fill R_SYSHD, according to the value of a file reference.
*
*/
gpg_error_t
gnupg_parse_fdstr (const char *fdstr, es_syshd_t *r_syshd)
{
int fd = -1;
#ifdef HAVE_W32_SYSTEM
gnupg_fd_t hd;
char *endptr;
int base;
if (!strcmp (fdstr, "0"))
fd = 0;
else if (!strcmp (fdstr, "1"))
fd = 1;
else if (!strcmp (fdstr, "2"))
fd = 2;
if (fd >= 0)
{
r_syshd->type = ES_SYSHD_FD;
r_syshd->u.fd = fd;
return 0;
}
if (!strncmp (fdstr, "0x", 2))
{
base = 16;
fdstr += 2;
}
else
base = 10;
gpg_err_set_errno (0);
#ifdef _WIN64
hd = (gnupg_fd_t)strtoll (fdstr, &endptr, base);
#else
(void)for_write;
return fd;
hd = (gnupg_fd_t)strtol (fdstr, &endptr, base);
#endif
if (errno != 0 || endptr == fdstr || *endptr != '\0')
return gpg_error (GPG_ERR_INV_ARG);
r_syshd->type = ES_SYSHD_HANDLE;
r_syshd->u.handle = hd;
return 0;
#else
fd = atoi (fdstr);
r_syshd->type = ES_SYSHD_FD;
r_syshd->u.fd = fd;
return 0;
#endif
}
@ -589,13 +666,74 @@ check_special_filename (const char *fname, int for_write, int notranslate)
for (i=0; digitp (fname+i); i++ )
;
if (!fname[i])
return notranslate? atoi (fname)
/**/ : translate_sys2libc_fd_int (atoi (fname), for_write);
{
if (notranslate)
return atoi (fname);
else
{
es_syshd_t syshd;
if (gnupg_parse_fdstr (fname, &syshd))
return -1;
#ifdef HAVE_W32_SYSTEM
if (syshd.type == ES_SYSHD_FD)
return syshd.u.fd;
else
return translate_sys2libc_fd ((gnupg_fd_t)syshd.u.handle, for_write);
#else
(void)for_write;
return syshd.u.fd;
#endif
}
}
}
return -1;
}
/* Check whether FNAME has the form "-&nnnn", where N is a number
* representing a file. Returns GNUPG_INVALID_FD if it is not the
* case. Returns a file descriptor on POSIX, a system handle on
* Windows. */
gnupg_fd_t
gnupg_check_special_filename (const char *fname)
{
if (allow_special_filenames
&& fname && *fname == '-' && fname[1] == '&')
{
int i;
fname += 2;
for (i=0; digitp (fname+i); i++ )
;
if (!fname[i])
{
es_syshd_t syshd;
if (gnupg_parse_fdstr (fname, &syshd))
return GNUPG_INVALID_FD;
#ifdef HAVE_W32_SYSTEM
if (syshd.type == ES_SYSHD_FD)
{
if (syshd.u.fd == 0)
return GetStdHandle (STD_INPUT_HANDLE);
else if (syshd.u.fd == 1)
return GetStdHandle (STD_OUTPUT_HANDLE);
else if (syshd.u.fd == 2)
return GetStdHandle (STD_ERROR_HANDLE);
}
else
return syshd.u.handle;
#else
return syshd.u.fd;
#endif
}
}
return GNUPG_INVALID_FD;
}
/* Replacement for tmpfile(). This is required because the tmpfile
function of Windows' runtime library is broken, insecure, ignores
TMPDIR and so on. In addition we create a file with an inheritable
@ -805,7 +943,12 @@ gnupg_remove (const char *fname)
return -1;
return 0;
#else
return remove (fname);
/* It is common to use /dev/null for testing. We better don't
* remove that file. */
if (fname && !strcmp (fname, "/dev/null"))
return 0;
else
return remove (fname);
#endif
}
@ -1148,6 +1291,19 @@ gnupg_setenv (const char *name, const char *value, int overwrite)
return setenv (name, value, overwrite);
#else /*!HAVE_SETENV*/
if (! getenv (name) || overwrite)
#if defined(HAVE_W32_SYSTEM) && defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
{
int e = _putenv_s (name, value);
if (e)
{
gpg_err_set_errno (e);
return -1;
}
else
return 0;
}
#else
{
char *buf;
@ -1165,6 +1321,7 @@ gnupg_setenv (const char *name, const char *value, int overwrite)
# endif
return putenv (buf);
}
#endif /*!HAVE_W32_SYSTEM*/
return 0;
#endif /*!HAVE_SETENV*/
}
@ -1189,6 +1346,18 @@ gnupg_unsetenv (const char *name)
#ifdef HAVE_UNSETENV
return unsetenv (name);
#elif defined(HAVE_W32_SYSTEM) && defined(_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES)
{
int e = _putenv_s (name, "");
if (e)
{
gpg_err_set_errno (e);
return -1;
}
else
return 0;
}
#else /*!HAVE_UNSETENV*/
{
char *buf;
@ -1819,3 +1988,22 @@ gnupg_fd_valid (int fd)
close (d);
return 1;
}
/* Open a stream from FD (a file descriptor on POSIX, a system
handle on Windows), non-closed. */
estream_t
open_stream_nc (gnupg_fd_t fd, const char *mode)
{
es_syshd_t syshd;
#ifdef HAVE_W32_SYSTEM
syshd.type = ES_SYSHD_HANDLE;
syshd.u.handle = fd;
#else
syshd.type = ES_SYSHD_FD;
syshd.u.fd = fd;
#endif
return es_sysopen_nc (&syshd, mode);
}

View File

@ -38,12 +38,20 @@
typedef void *gnupg_fd_t;
#define GNUPG_INVALID_FD ((void*)(-1))
#define INT2FD(s) ((void *)(s))
#define FD2INT(h) ((unsigned int)(h))
# ifdef _WIN64
# define FD2INT(h) ((intptr_t)(h))
# else
# define FD2INT(h) ((unsigned int)(h))
# endif
#define FD_DBG(h) ((int)(intptr_t)(h))
#define FD2NUM(h) ((int)(intptr_t)(h))
#else
typedef int gnupg_fd_t;
#define GNUPG_INVALID_FD (-1)
#define INT2FD(s) (s)
#define FD2INT(h) (h)
#define FD_DBG(h) (h)
#define FD2NUM(h) (h)
#endif
#ifdef HAVE_STAT
@ -67,14 +75,17 @@ void trap_unaligned (void);
int disable_core_dumps (void);
int enable_core_dumps (void);
void enable_special_filenames (void);
void disable_translate_sys2libc_fd (void);
const unsigned char *get_session_marker (size_t *rlen);
unsigned int get_uint_nonce (void);
/*int check_permissions (const char *path,int extension,int checkonly);*/
void gnupg_sleep (unsigned int seconds);
void gnupg_usleep (unsigned int usecs);
int translate_sys2libc_fd (gnupg_fd_t fd, int for_write);
int translate_sys2libc_fd_int (int fd, int for_write);
gpg_error_t gnupg_parse_fdstr (const char *fdstr, es_syshd_t *r_syshd);
int check_special_filename (const char *fname, int for_write, int notranslate);
gnupg_fd_t gnupg_check_special_filename (const char *fname);
FILE *gnupg_tmpfile (void);
void gnupg_reopen_std (const char *pgmname);
void gnupg_inhibit_set_foregound_window (int yes);
@ -108,9 +119,10 @@ gpg_error_t gnupg_inotify_watch_delete_self (int *r_fd, const char *fname);
gpg_error_t gnupg_inotify_watch_socket (int *r_fd, const char *socket_name);
int gnupg_inotify_has_name (int fd, const char *name);
estream_t open_stream_nc (gnupg_fd_t fd, const char *mode);
#ifdef HAVE_W32_SYSTEM
void gnupg_w32_set_errno (int ec);
int gnupg_w32_set_errno (int ec);
void *w32_get_user_sid (void);
#include "../common/w32help.h"

View File

@ -1,181 +0,0 @@
/* t-b64.c - Module tests for b64enc.c and b64dec.c
* Copyright (C) 2008 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* GnuPG is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
*/
/*
As of now this is only a test program for manual tests.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include "util.h"
#define pass() do { ; } while(0)
#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
__FILE__,__LINE__, (a)); \
errcount++; \
} while(0)
static int verbose;
static int errcount;
static void
test_b64enc_pgp (const char *string)
{
gpg_error_t err;
struct b64state state;
if (!string)
string = "a";
err = b64enc_start (&state, stdout, "PGP MESSAGE");
if (err)
fail (1);
err = b64enc_write (&state, string, strlen (string));
if (err)
fail (2);
err = b64enc_finish (&state);
if (err)
fail (3);
pass ();
}
static void
test_b64enc_file (const char *fname)
{
gpg_error_t err;
struct b64state state;
FILE *fp;
char buffer[50];
size_t nread;
fp = fname ? fopen (fname, "r") : stdin;
if (!fp)
{
fprintf (stderr, "%s:%d: can't open '%s': %s\n",
__FILE__, __LINE__, fname? fname:"[stdin]", strerror (errno));
fail (0);
}
err = b64enc_start (&state, stdout, "DATA");
if (err)
fail (1);
while ( (nread = fread (buffer, 1, sizeof buffer, fp)) )
{
err = b64enc_write (&state, buffer, nread);
if (err)
fail (2);
}
err = b64enc_finish (&state);
if (err)
fail (3);
fclose (fp);
pass ();
}
static void
test_b64dec_file (const char *fname)
{
gpg_error_t err;
struct b64state state;
FILE *fp;
char buffer[50];
size_t nread, nbytes;
fp = fname ? fopen (fname, "r") : stdin;
if (!fp)
{
fprintf (stderr, "%s:%d: can't open '%s': %s\n",
__FILE__, __LINE__, fname? fname:"[stdin]", strerror (errno));
fail (0);
}
err = b64dec_start (&state, "");
if (err)
fail (1);
while ( (nread = fread (buffer, 1, sizeof buffer, fp)) )
{
err = b64dec_proc (&state, buffer, nread, &nbytes);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_EOF)
break;
fail (2);
}
else if (nbytes)
fwrite (buffer, 1, nbytes, stdout);
}
err = b64dec_finish (&state);
if (err)
fail (3);
fclose (fp);
pass ();
}
int
main (int argc, char **argv)
{
int do_encode = 0;
int do_decode = 0;
if (argc)
{ argc--; argv++; }
if (argc && !strcmp (argv[0], "--verbose"))
{
verbose = 1;
argc--; argv++;
}
if (argc && !strcmp (argv[0], "--encode"))
{
do_encode = 1;
argc--; argv++;
}
else if (argc && !strcmp (argv[0], "--decode"))
{
do_decode = 1;
argc--; argv++;
}
if (do_encode)
test_b64enc_file (argc? *argv: NULL);
else if (do_decode)
test_b64dec_file (argc? *argv: NULL);
else
test_b64enc_pgp (argc? *argv: NULL);
return !!errcount;
}

View File

@ -52,6 +52,7 @@
#ifdef HAVE_W32_SYSTEM
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
const char *
w32_strerror (int ec)
{
@ -174,6 +175,11 @@ strconcat (const char *s1, ...)
#define PGM "t-dotlock"
static int opt_silent;
#ifndef HAVE_W32_SYSTEM
static volatile int ctrl_c_pending_flag;
static void
@ -217,6 +223,9 @@ inf (const char *format, ...)
{
va_list arg_ptr;
if (opt_silent)
return;
va_start (arg_ptr, format);
fprintf (stderr, PGM "[%lu]: ", (unsigned long)getpid ());
vfprintf (stderr, format, arg_ptr);
@ -225,15 +234,35 @@ inf (const char *format, ...)
}
static int
lock_info_cb (dotlock_t h, void *opaque, enum dotlock_reasons reason,
const char *format, ...)
{
va_list arg_ptr;
va_start (arg_ptr, format);
fprintf (stderr, PGM "[%lu]: info_cb: reason %d, ",
(unsigned long)getpid (), (int)reason);
vfprintf (stderr, format, arg_ptr);
va_end (arg_ptr);
return 0;
}
static void
lock_and_unlock (const char *fname)
{
dotlock_t h;
unsigned long usec;
h = dotlock_create (fname, 0);
h = dotlock_create (fname, DOTLOCK_PREPARE_CREATE);
if (!h)
die ("error creating lock file for '%s': %s", fname, strerror (errno));
dotlock_set_info_cb (h, lock_info_cb, NULL);
h = dotlock_finish_create (h, fname);
if (!h)
die ("error finishing lock file creation for '%s': %s",
fname, strerror (errno));
inf ("lock created");
do
@ -270,6 +299,11 @@ main (int argc, char **argv)
ctrl_c_pending_flag = 1;
argc--;
}
if (argc > 1 && !strcmp (argv[1], "--silent"))
{
opt_silent = 1;
argc--;
}
if (argc > 1)
fname = argv[argc-1];

View File

@ -29,7 +29,7 @@
static int verbose;
#ifndef HAVE_W32_SYSTEM
static void
print_open_fds (int *array)
{
@ -169,20 +169,168 @@ test_close_all_fds (void)
}
}
#endif
static char buff12k[1024*12];
static char buff4k[1024*4];
static void
run_server (void)
{
estream_t fp;
int i;
char *p;
unsigned int len;
int ret;
es_syshd_t syshd;
size_t n;
off_t o;
#ifdef HAVE_W32_SYSTEM
syshd.type = ES_SYSHD_HANDLE;
syshd.u.handle = (HANDLE)_get_osfhandle (1);
#else
syshd.type = ES_SYSHD_FD;
syshd.u.fd = 1;
#endif
fp = es_sysopen_nc (&syshd, "w");
if (fp == NULL)
{
fprintf (stderr, "es_fdopen failed\n");
exit (1);
}
/* Fill the buffer by ASCII chars. */
p = buff12k;
for (i = 0; i < sizeof (buff12k); i++)
if ((i % 64) == 63)
*p++ = '\n';
else
*p++ = (i % 64) + '@';
len = sizeof (buff12k);
ret = es_write (fp, (void *)&len, sizeof (len), NULL);
if (ret)
{
fprintf (stderr, "es_write (1) failed\n");
exit (1);
}
es_fflush (fp);
o = 0;
n = len;
while (1)
{
size_t n0, n1;
n0 = n > 4096 ? 4096 : n;
memcpy (buff4k, buff12k + o, n0);
ret = es_write (fp, buff4k, n0, &n1);
if (ret || n0 != n1)
{
fprintf (stderr, "es_write (2) failed\n");
exit (1);
}
o += n0;
n -= n0;
if (n == 0)
break;
}
es_fclose (fp);
exit (0);
}
static void
test_pipe_stream (const char *pgmname)
{
gpg_error_t err;
gnupg_process_t proc;
estream_t outfp;
const char *argv[2];
unsigned int len;
size_t n;
off_t o;
int ret;
argv[0] = "--server";
argv[1] = NULL;
err = gnupg_process_spawn (pgmname, argv,
(GNUPG_PROCESS_STDOUT_PIPE
|GNUPG_PROCESS_STDERR_KEEP),
NULL, NULL, &proc);
if (err)
{
fprintf (stderr, "gnupg_process_spawn failed\n");
exit (1);
}
gnupg_process_get_streams (proc, 0, NULL, &outfp, NULL);
ret = es_read (outfp, (void *)&len, sizeof (len), NULL);
if (ret)
{
fprintf (stderr, "es_read (1) failed\n");
exit (1);
}
o = 0;
while (1)
{
if (es_feof (outfp))
break;
ret = es_read (outfp, buff4k, sizeof (buff4k), &n);
if (ret)
{
fprintf (stderr, "es_read (2) failed\n");
exit (1);
}
memcpy (buff12k + o, buff4k, n);
o += n;
}
if (o != sizeof (buff12k))
{
fprintf (stderr, "received data with wrong length %d\n", (int)o);
exit (1);
}
es_fclose (outfp);
gnupg_process_release (proc);
}
int
main (int argc, char **argv)
{
const char *myname = "no-pgm";
if (argc)
{ argc--; argv++; }
{
myname = argv[0];
argc--; argv++;
}
if (argc && !strcmp (argv[0], "--verbose"))
{
verbose = 1;
argc--; argv++;
}
if (argc && !strcmp (argv[0], "--server"))
run_server ();
#ifndef HAVE_W32_SYSTEM
test_close_all_fds ();
#endif
test_pipe_stream (myname);
return 0;
}

View File

@ -43,6 +43,56 @@ static int errcount;
#define INVALID ((time_t)(-1))
static void
test_scan_secondsstr (void)
{
struct { const char *string; u32 expected; } array [] = {
{ "", 0 },
{ "0", 0 },
{ " 0", 0 },
{ " 0x", 0 },
{ " 1", 1 },
{ "-1", 0 },
{ " -1", 0 },
{ "2", 2 },
{ "11", 11 },
{ "011", 11 },
{ "3600 ", 3600 },
{ "65535", 65535 },
{ "65536", 65536 },
{ "65537", 65537 },
{ "4294967289", 4294967289 },
{ "4294967290", 4294967290 },
{ "4294967293", 4294967293 },
{ "4294967295", 4294967294 },
{ "4294967296", 4294967294 },
{ "4294967297", 4294967294 },
{ "4294967298", 4294967294 },
{ "4294967299", 4294967294 },
{ "4294967300", 4294967294 },
{ "5294967300", 4294967294 },
{ "9999999999", 4294967294 },
{ "99999999999",4294967294 },
{ NULL, 0 }
};
int idx;
u32 val;
for (idx=0; array[idx].string; idx++)
{
val = scan_secondsstr (array[idx].string);
if (val != array[idx].expected )
{
fail (idx);
if (verbose)
fprintf (stderr, "string '%s' exp: %ld got: %ld\n",
array[idx].string, (unsigned long)array[idx].expected,
(unsigned long)val);
}
}
}
static void
test_isotime2epoch (void)
{
@ -103,7 +153,6 @@ test_isotime2epoch (void)
}
static void
test_string2isotime (void)
{
@ -269,6 +318,7 @@ main (int argc, char **argv)
if (argc > 1 && !strcmp (argv[1], "--verbose"))
verbose = 1;
test_scan_secondsstr ();
test_isotime2epoch ();
test_string2isotime ();
test_isodate_human_to_tm ();

View File

@ -1,3 +1,36 @@
/* t-iobuf.c - Simple module test for iobuf.c
* Copyright (C) 2015 g10 Code GmbH
*
* This file is part of GnuPG.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of either
*
* - the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 3 of the License, or (at
* your option) any later version.
*
* or
*
* - the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* or both in parallel, as here.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
*/
/* The whole code here does not very fill into our general test frame
* work patter. But let's keep it as it is. */
#include <config.h>
#include <stdio.h>
#include <string.h>
@ -7,6 +40,20 @@
#include "iobuf.h"
#include "stringhelp.h"
static void *
xmalloc (size_t n)
{
void *p = malloc (n);
if (!p)
{
fprintf (stderr, "t-iobuf: out of core\n");
abort ();
}
return p;
}
/* Return every other byte. In particular, reads two bytes, returns
the second one. */
static int
@ -86,7 +133,7 @@ static struct content_filter_state *
content_filter_new (const char *buffer)
{
struct content_filter_state *state
= malloc (sizeof (struct content_filter_state));
= xmalloc (sizeof (struct content_filter_state));
state->pos = 0;
state->len = strlen (buffer);
@ -215,8 +262,7 @@ main (int argc, char *argv[])
allocate a buffer that is 5 bytes long, then no reallocation
should be required. */
size = 5;
buffer = malloc (size);
assert (buffer);
buffer = xmalloc (size);
max_len = 100;
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
assert (n == 4);
@ -229,7 +275,7 @@ main (int argc, char *argv[])
requires 6 bytes of storage. We pass a buffer that is 5 bytes
large and we allow the buffer to be grown. */
size = 5;
buffer = malloc (size);
buffer = xmalloc (size);
max_len = 100;
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
assert (n == 5);
@ -243,7 +289,7 @@ main (int argc, char *argv[])
requires 7 bytes of storage. We pass a buffer that is 5 bytes
large and we don't allow the buffer to be grown. */
size = 5;
buffer = malloc (size);
buffer = xmalloc (size);
max_len = 5;
n = iobuf_read_line (iobuf, &buffer, &size, &max_len);
assert (n == 4);

View File

@ -31,6 +31,8 @@
#ifndef GNUPG_COMMON_T_SUPPORT_H
#define GNUPG_COMMON_T_SUPPORT_H 1
#ifndef LEAN_T_SUPPORT
#ifdef GCRYPT_VERSION
#error The regression tests should not include with gcrypt.h
#endif
@ -45,11 +47,6 @@
# define getenv(a) (NULL)
#endif
#ifndef DIM
# define DIM(v) (sizeof(v)/sizeof((v)[0]))
# define DIMof(type,member) DIM(((type *)0)->member)
#endif
/* Replacement prototypes. */
void *gcry_xmalloc (size_t n);
@ -65,6 +62,12 @@ void gcry_free (void *a);
#define xstrdup(a) gcry_xstrdup ( (a) )
#define xfree(a) gcry_free ( (a) )
#endif /* LEAN_T_SUPPORT */
#ifndef DIM
# define DIM(v) (sizeof(v)/sizeof((v)[0]))
# define DIMof(type,member) DIM(((type *)0)->member)
#endif
/* Macros to print the result of a test. */
#define pass() do { ; } while(0)

788
common/tlv-parser.c Normal file
View File

@ -0,0 +1,788 @@
/* tlv-parser.c - Parse BER encoded objects
* Copyright (C) 2023 g10 Code GmbH
*
* This file is part of GnuPG.
*
* This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, see <https://www.gnu.org/licenses/>.
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gpg-error.h>
#include "util.h"
#include "tlv.h"
#define TLV_MAX_DEPTH 25
struct bufferlist_s
{
struct bufferlist_s *next;
char *buffer;
};
/* An object to control the ASN.1 parsing. */
struct tlv_parser_s
{
/* The orginal buffer with the entire pkcs#12 object and its length. */
const unsigned char *origbuffer;
size_t origbufsize;
/* The current buffer we are working on and its length. */
const unsigned char *buffer;
size_t bufsize;
int in_ndef; /* Flag indicating that we are in a NDEF. */
int pending; /* The last tlv_next has not yet been processed. */
struct tag_info ti; /* The current tag. */
gpg_error_t lasterr; /* Last error from tlv function. */
const char *lastfunc;/* Name of last called function. */
int verbosity; /* Arg from tlv_parser_new. */
struct bufferlist_s *bufferlist; /* To keep track of malloced buffers. */
unsigned int stacklen; /* Used size of the stack. */
struct {
const unsigned char *buffer; /* Saved value of BUFFER. */
size_t bufsize; /* Saved value of BUFSIZE. */
size_t length; /* Length of the container (ti.length). */
int in_ndef; /* Saved IN_NDEF flag (ti.ndef). */
} stack[TLV_MAX_DEPTH];
};
static unsigned char *cram_octet_string (const unsigned char *input,
size_t length, size_t *r_newlength);
static int need_octet_string_cramming (const unsigned char *input,
size_t length);
void
_tlv_parser_dump_tag (const char *text, int lno, tlv_parser_t tlv)
{
struct tag_info *ti;
if (!tlv || tlv->verbosity < 2)
return;
ti = &tlv->ti;
log_debug ("p12_parse:%s:%d: @%04zu class=%d tag=%lu len=%zu nhdr=%zu %s%s\n",
text, lno,
(size_t)(tlv->buffer - tlv->origbuffer) - ti->nhdr,
ti->class, ti->tag, ti->length, ti->nhdr,
ti->is_constructed?" cons":"",
ti->ndef?" ndef":"");
}
void
_tlv_parser_dump_state (const char *text, const char *text2,
int lno, tlv_parser_t tlv)
{
if (!tlv || tlv->verbosity < 2)
return;
log_debug ("p12_parse:%s%s%s:%d: @%04zu lvl=%u %s\n",
text,
text2? "/":"", text2? text2:"",
lno,
(size_t)(tlv->buffer - tlv->origbuffer),
tlv->stacklen,
tlv->in_ndef? " in-ndef":"");
}
/* Parse the buffer at the address BUFFER which is of SIZE and return
* the tag and the length part from the TLV triplet. Update BUFFER
* and SIZE on success. Checks that the encoded length does not
* exhaust the length of the provided buffer. */
static int
parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
{
gpg_error_t err;
int tag;
err = parse_ber_header (buffer, size,
&ti->class, &tag,
&ti->is_constructed, &ti->ndef,
&ti->length, &ti->nhdr);
if (err)
return err;
if (tag < 0)
return gpg_error (GPG_ERR_EOVERFLOW);
ti->tag = tag;
if (ti->length > *size)
return gpg_error (GPG_ERR_BUFFER_TOO_SHORT); /* data larger than buffer. */
return 0;
}
/* Public version of parse_tag. */
gpg_error_t
tlv_parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
{
return parse_tag (buffer, size, ti);
}
/* Create a new TLV object. */
tlv_parser_t
tlv_parser_new (const unsigned char *buffer, size_t bufsize, int verbosity)
{
tlv_parser_t tlv;
tlv = xtrycalloc (1, sizeof *tlv);
if (tlv)
{
tlv->origbuffer = buffer;
tlv->origbufsize = bufsize;
tlv->buffer = buffer;
tlv->bufsize = bufsize;
tlv->verbosity = verbosity;
}
return tlv;
}
/* This function can be used to store a malloced buffer into the TLV
* object. Ownership of BUFFER is thus transferred to TLV. This
* buffer will then only be released by tlv_release. */
static gpg_error_t
register_buffer (tlv_parser_t tlv, char *buffer)
{
struct bufferlist_s *item;
item = xtrycalloc (1, sizeof *item);
if (!item)
return gpg_error_from_syserror ();
item->buffer = buffer;
item->next = tlv->bufferlist;
tlv->bufferlist = item;
return 0;
}
void
tlv_parser_release (tlv_parser_t tlv)
{
if (!tlv)
return;
while (tlv->bufferlist)
{
struct bufferlist_s *save = tlv->bufferlist->next;
xfree (tlv->bufferlist->buffer);
xfree (tlv->bufferlist);
tlv->bufferlist = save;
}
xfree (tlv);
}
/* Helper for the tlv_peek functions. */
static gpg_error_t
_tlv_peek (tlv_parser_t tlv, struct tag_info *ti)
{
const unsigned char *p;
size_t n;
/* Note that we want to peek ahead of any current container but of
* course not beyond our entire buffer. */
p = tlv->buffer;
if ((p - tlv->origbuffer) > tlv->origbufsize)
return gpg_error (GPG_ERR_BUG);
n = tlv->origbufsize - (p - tlv->origbuffer);
return parse_tag (&p, &n, ti);
}
/* Look for the next tag and return true if it matches CLASS and TAG.
* Otherwise return false. No state is changed. */
int
_tlv_parser_peek (tlv_parser_t tlv, int class, int tag)
{
struct tag_info ti;
return (!_tlv_peek (tlv, &ti)
&& ti.class == class && ti.tag == tag);
}
/* Look for the next tag and return true if it is the Null tag.
* Otherwise return false. No state is changed. */
int
_tlv_parser_peek_null (tlv_parser_t tlv)
{
struct tag_info ti;
return (!_tlv_peek (tlv, &ti)
&& ti.class == CLASS_UNIVERSAL && ti.tag == TAG_NULL
&& !ti.is_constructed && !ti.length);
}
/* Helper for tlv_expect_sequence and tlv_expect_context_tag. */
static gpg_error_t
_tlv_push (tlv_parser_t tlv)
{
/* Right now our pointer is at the value of the current container.
* We push that info onto the stack. */
if (tlv->stacklen >= TLV_MAX_DEPTH)
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_MANY));
tlv->stack[tlv->stacklen].buffer = tlv->buffer;
tlv->stack[tlv->stacklen].bufsize = tlv->bufsize;
tlv->stack[tlv->stacklen].in_ndef = tlv->in_ndef;
tlv->stack[tlv->stacklen].length = tlv->ti.length;
tlv->stacklen++;
tlv->in_ndef = tlv->ti.ndef;
/* We set the size of the buffer to the TLV length if it is known or
* else to the size of the remaining entire buffer. */
if (tlv->in_ndef)
{
if ((tlv->buffer - tlv->origbuffer) > tlv->origbufsize)
return (tlv->lasterr = gpg_error (GPG_ERR_BUG));
tlv->bufsize = tlv->origbufsize - (tlv->buffer - tlv->origbuffer);
}
else
tlv->bufsize = tlv->ti.length;
_tlv_parser_dump_state (__func__, NULL, 0, tlv);
return 0;
}
/* Helper for tlv_next. */
static gpg_error_t
_tlv_pop (tlv_parser_t tlv)
{
size_t lastlen;
/* We reached the end of a container, either due to the size limit
* or due to an end tag. Now we pop the last container so that we
* are positioned at the value of the last container. */
if (!tlv->stacklen)
return gpg_error (GPG_ERR_EOF);
tlv->stacklen--;
tlv->in_ndef = tlv->stack[tlv->stacklen].in_ndef;
if (tlv->in_ndef)
{
/* We keep buffer but adjust bufsize to the end of the origbuffer. */
if ((tlv->buffer - tlv->origbuffer) > tlv->origbufsize)
return (tlv->lasterr = gpg_error (GPG_ERR_BUG));
tlv->bufsize = tlv->origbufsize - (tlv->buffer - tlv->origbuffer);
}
else
{
lastlen = tlv->stack[tlv->stacklen].length;
tlv->buffer = tlv->stack[tlv->stacklen].buffer;
tlv->bufsize = tlv->stack[tlv->stacklen].bufsize;
if (lastlen > tlv->bufsize)
{
log_debug ("%s: container length larger than buffer (%zu/%zu)\n",
__func__, lastlen, tlv->bufsize);
return gpg_error (GPG_ERR_INV_BER);
}
tlv->buffer += lastlen;
tlv->bufsize -= lastlen;
}
_tlv_parser_dump_state (__func__, NULL, 0, tlv);
return 0;
}
/* Parse the next tag and value. Also detect the end of a
* container. The caller should use the tlv_next macro. */
gpg_error_t
_tlv_parser_next (tlv_parser_t tlv, int lno)
{
gpg_error_t err;
tlv->lasterr = 0;
tlv->lastfunc = __func__;
if (tlv->pending)
{
tlv->pending = 0;
if (tlv->verbosity > 1)
log_debug ("%s: skipped\n", __func__);
return 0;
}
if (tlv->verbosity > 1)
log_debug ("%s: called\n", __func__);
/* If we are at the end of an ndef container pop the stack. */
if (!tlv->in_ndef && !tlv->bufsize)
{
do
err = _tlv_pop (tlv);
while (!err && !tlv->in_ndef && !tlv->bufsize);
if (err)
return (tlv->lasterr = err);
if (tlv->verbosity > 1)
log_debug ("%s: container(s) closed due to size\n", __func__);
}
again:
/* Get the next tag. */
err = parse_tag (&tlv->buffer, &tlv->bufsize, &tlv->ti);
if (err)
{
if (tlv->verbosity > 1)
log_debug ("%s: reading tag returned err=%d\n", __func__, err);
return err;
}
/* If there is an end tag in an ndef container pop the stack. Also
* pop other containers which are fully consumed. */
if (tlv->in_ndef && (tlv->ti.class == CLASS_UNIVERSAL
&& !tlv->ti.tag && !tlv->ti.is_constructed))
{
do
err = _tlv_pop (tlv);
while (!err && !tlv->in_ndef && !tlv->bufsize);
if (err)
return (tlv->lasterr = err);
if (tlv->verbosity > 1)
log_debug ("%s: container(s) closed due to end tag\n", __func__);
goto again;
}
_tlv_parser_dump_tag (__func__, lno, tlv);
return 0;
}
/* Return the current neting level of the TLV object. */
unsigned int
tlv_parser_level (tlv_parser_t tlv)
{
return tlv? tlv->stacklen : 0;
}
/* Returns the current offset of the parser. */
size_t
tlv_parser_offset (tlv_parser_t tlv)
{
return tlv? (size_t)(tlv->buffer - tlv->origbuffer) : 0;
}
/* Return a string with the last function used. If TLV is NULL an
* empty string is returned. */
const char *
tlv_parser_lastfunc (tlv_parser_t tlv)
{
return tlv? tlv->lastfunc:"";
}
const char *
tlv_parser_lasterrstr (tlv_parser_t tlv)
{
return tlv? gpg_strerror (tlv->lasterr) : "tlv parser not yet initialized";
}
/* Set a flag to indicate that the last tlv_next has not yet been
* consumed. */
void
tlv_parser_set_pending (tlv_parser_t tlv)
{
tlv->pending = 1;
}
/* Return the length of the last read tag. If with_header is 1 the
* lengtb of the header is added to the returned length. */
size_t
tlv_parser_tag_length (tlv_parser_t tlv, int with_header)
{
if (with_header)
return tlv->ti.length + tlv->ti.nhdr;
else
return tlv->ti.length;
}
/* Skip over the value of the current tag. Does not yet work for ndef
* containers. */
void
tlv_parser_skip (tlv_parser_t tlv)
{
tlv->lastfunc = __func__;
log_assert (tlv->bufsize >= tlv->ti.length);
tlv->buffer += tlv->ti.length;
tlv->bufsize -= tlv->ti.length;
}
/* Expect that the current tag is a sequence and setup the context for
* processing. */
gpg_error_t
tlv_expect_sequence (tlv_parser_t tlv)
{
tlv->lastfunc = __func__;
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_SEQUENCE
&& tlv->ti.is_constructed))
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
return _tlv_push (tlv);
}
/* Expect that the current tag is a context tag and setup the context
* for processing. The tag of the context is returned at R_TAG. */
gpg_error_t
tlv_expect_context_tag (tlv_parser_t tlv, int *r_tag)
{
tlv->lastfunc = __func__;
if (!(tlv->ti.class == CLASS_CONTEXT && tlv->ti.is_constructed))
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
*r_tag = tlv->ti.tag;
return _tlv_push (tlv);
}
/* Expect that the current tag is a SET and setup the context for
* processing. */
gpg_error_t
tlv_expect_set (tlv_parser_t tlv)
{
tlv->lastfunc = __func__;
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_SET
&& tlv->ti.is_constructed))
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
return _tlv_push (tlv);
}
/* Expect an object of CLASS with TAG and store its value at
* (R_DATA,R_DATALEN). Then skip over its value to the next tag.
* Note that the stored value is not allocated but points into
* TLV. */
gpg_error_t
tlv_expect_object (tlv_parser_t tlv, int class, int tag,
unsigned char const **r_data, size_t *r_datalen)
{
gpg_error_t err;
const unsigned char *p;
size_t n;
int needpush = 0;
tlv->lastfunc = __func__;
if (!(tlv->ti.class == class && tlv->ti.tag == tag))
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
p = tlv->buffer;
n = tlv->ti.length;
if (!n && tlv->ti.ndef)
{
n = tlv->bufsize;
needpush = 1;
}
else if (!tlv->ti.length)
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
if (class == CLASS_CONTEXT && tag == 0 && tlv->ti.is_constructed
&& need_octet_string_cramming (p, n))
{
char *newbuffer;
newbuffer = cram_octet_string (p, n, r_datalen);
if (!newbuffer)
return (tlv->lasterr = gpg_error (GPG_ERR_BAD_BER));
err = register_buffer (tlv, newbuffer);
if (err)
{
xfree (newbuffer);
return (tlv->lasterr = err);
}
*r_data = newbuffer;
}
else
{
*r_data = p;
*r_datalen = n;
}
if (needpush)
return _tlv_push (tlv);
if (!(tlv->bufsize >= tlv->ti.length))
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
tlv->buffer += tlv->ti.length;
tlv->bufsize -= tlv->ti.length;
return 0;
}
/* Expect that the current tag is an object string and store its value
* at (R_DATA,R_DATALEN). Then skip over its value to the next tag.
* Note that the stored value are not allocated but point into TLV.
* If ENCAPSULATES is set the octet string is used as a new
* container. R_DATA and R_DATALEN are optional. */
gpg_error_t
tlv_expect_octet_string (tlv_parser_t tlv, int encapsulates,
unsigned char const **r_data, size_t *r_datalen)
{
gpg_error_t err;
const unsigned char *p;
size_t n;
tlv->lastfunc = __func__;
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_OCTET_STRING
&& (!tlv->ti.is_constructed || encapsulates)))
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
p = tlv->buffer;
if (!(n=tlv->ti.length) && !tlv->ti.ndef)
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
if (encapsulates && tlv->ti.is_constructed
&& need_octet_string_cramming (p, n))
{
char *newbuffer;
newbuffer = cram_octet_string (p, n, r_datalen);
if (!newbuffer)
return (tlv->lasterr = gpg_error (GPG_ERR_BAD_BER));
err = register_buffer (tlv, newbuffer);
if (err)
{
xfree (newbuffer);
return (tlv->lasterr = err);
}
*r_data = newbuffer;
}
else
{
if (r_data)
*r_data = p;
if (r_datalen)
*r_datalen = tlv->ti.length;
}
if (encapsulates)
return _tlv_push (tlv);
if (!(tlv->bufsize >= tlv->ti.length))
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
tlv->buffer += tlv->ti.length;
tlv->bufsize -= tlv->ti.length;
return 0;
}
/* Expect that the current tag is an integer and return its value at
* R_VALUE. Then skip over its value to the next tag. */
gpg_error_t
tlv_expect_integer (tlv_parser_t tlv, int *r_value)
{
const unsigned char *p;
size_t n;
int value;
tlv->lastfunc = __func__;
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_INTEGER
&& !tlv->ti.is_constructed))
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
p = tlv->buffer;
if (!(n=tlv->ti.length))
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
/* We currently support only positive values. */
if ((*p & 0x80))
return (tlv->lasterr = gpg_error (GPG_ERR_ERANGE));
for (value = 0; n; n--)
{
value <<= 8;
value |= (*p++) & 0xff;
if (value < 0)
return (tlv->lasterr = gpg_error (GPG_ERR_EOVERFLOW));
}
*r_value = value;
if (!(tlv->bufsize >= tlv->ti.length))
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
tlv->buffer += tlv->ti.length;
tlv->bufsize -= tlv->ti.length;
return 0;
}
/* Variant of tlv_expect_integer which returns an MPI. If IGNORE_ZERO
* is set a value of 0 is ignored and R_VALUE not changed and the
* function returns GPG_ERR_FALSE. No check for negative encoded
* integers is done because the old code here worked the same and we
* can't foreclose invalid encoded PKCS#12 stuff - after all it is
* PKCS#12 see https://www.cs.auckland.ac.nz/~pgut001/pubs/pfx.html */
#ifdef GCRYPT_VERSION
gpg_error_t
tlv_expect_mpinteger (tlv_parser_t tlv, int ignore_zero,
gcry_mpi_t *r_value)
{
const unsigned char *p;
size_t n;
tlv->lastfunc = __func__;
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_INTEGER
&& !tlv->ti.is_constructed))
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
p = tlv->buffer;
if (!(n=tlv->ti.length))
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
if (!(tlv->bufsize >= tlv->ti.length))
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
tlv->buffer += tlv->ti.length;
tlv->bufsize -= tlv->ti.length;
if (ignore_zero && n == 1 && !*p)
return gpg_error (GPG_ERR_FALSE);
return gcry_mpi_scan (r_value, GCRYMPI_FMT_USG, p, n, NULL);
}
#endif /*GCRYPT_VERSION*/
/* Expect that the current tag is an object id and store its value at
* (R_OID,R_OIDLEN). Then skip over its value to the next tag. Note
* that the stored value is not allocated but points into TLV. */
gpg_error_t
tlv_expect_object_id (tlv_parser_t tlv,
unsigned char const **r_oid, size_t *r_oidlen)
{
const unsigned char *p;
size_t n;
tlv->lastfunc = __func__;
if (!(tlv->ti.class == CLASS_UNIVERSAL && tlv->ti.tag == TAG_OBJECT_ID
&& !tlv->ti.is_constructed))
return (tlv->lasterr = gpg_error (GPG_ERR_INV_OBJ));
p = tlv->buffer;
if (!(n=tlv->ti.length))
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
*r_oid = p;
*r_oidlen = tlv->ti.length;
if (!(tlv->bufsize >= tlv->ti.length))
return (tlv->lasterr = gpg_error (GPG_ERR_TOO_SHORT));
tlv->buffer += tlv->ti.length;
tlv->bufsize -= tlv->ti.length;
return 0;
}
/* Given an ASN.1 chunk of a structure like:
*
* 24 NDEF: OCTET STRING -- This is not passed to us
* 04 1: OCTET STRING -- INPUT point s to here
* : 30
* 04 1: OCTET STRING
* : 80
* [...]
* 04 2: OCTET STRING
* : 00 00
* : } -- This denotes a Null tag and are the last
* -- two bytes in INPUT.
*
* The example is from Mozilla Firefox 1.0.4 which actually exports
* certs as single byte chunks of octet strings.
*
* Create a new buffer with the content of that octet string. INPUT
* is the original buffer with a LENGTH. Returns
* NULL on error or a new malloced buffer with its actual used length
* stored at R_NEWLENGTH. */
static unsigned char *
cram_octet_string (const unsigned char *input, size_t length,
size_t *r_newlength)
{
const unsigned char *s = input;
size_t n = length;
unsigned char *output, *d;
struct tag_info ti;
/* Allocate output buf. We know that it won't be longer than the
input buffer. */
d = output = xtrymalloc (length);
if (!output)
goto bailout;
while (n)
{
if (parse_tag (&s, &n, &ti))
goto bailout;
if (ti.class == CLASS_UNIVERSAL && ti.tag == TAG_OCTET_STRING
&& !ti.ndef && !ti.is_constructed)
{
memcpy (d, s, ti.length);
s += ti.length;
d += ti.length;
n -= ti.length;
}
else if (ti.class == CLASS_UNIVERSAL && !ti.tag && !ti.is_constructed)
break; /* Ready */
else
goto bailout;
}
*r_newlength = d - output;
return output;
bailout:
xfree (output);
return NULL;
}
/* Return true if (INPUT,LENGTH) is a structure which should be passed
* to cram_octet_string. This is basically the same loop as in
* cram_octet_string but without any actual copying. */
static int
need_octet_string_cramming (const unsigned char *input, size_t length)
{
const unsigned char *s = input;
size_t n = length;
struct tag_info ti;
if (!length)
return 0;
while (n)
{
if (parse_tag (&s, &n, &ti))
return 0;
if (ti.class == CLASS_UNIVERSAL && ti.tag == TAG_OCTET_STRING
&& !ti.ndef && !ti.is_constructed)
{
s += ti.length;
n -= ti.length;
}
else if (ti.class == CLASS_UNIVERSAL && !ti.tag && !ti.is_constructed)
break; /* Ready */
else
return 0;
}
return 1;
}

View File

@ -150,13 +150,16 @@ find_tlv_unchecked (const unsigned char *buffer, size_t length,
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
and the length part from the TLV triplet. Update BUFFER and SIZE
on success. */
* and the length part from the TLV triplet. Update BUFFER and SIZE
* on success. Note that this function does not check that the value
* fits into the provided buffer; this allows one to work on the TL part
* of a TLV. */
gpg_error_t
parse_ber_header (unsigned char const **buffer, size_t *size,
int *r_class, int *r_tag,
int *r_constructed, int *r_ndef,
size_t *r_length, size_t *r_nhdr){
size_t *r_length, size_t *r_nhdr)
{
int c;
unsigned long tag;
const unsigned char *buf = *buffer;

View File

@ -71,10 +71,22 @@ enum tlv_tag_type {
TAG_BMP_STRING = 30
};
struct tag_info
{
int class;
int is_constructed;
unsigned long tag;
size_t length; /* length part of the TLV */
size_t nhdr;
int ndef; /* It is an indefinite length */
};
struct tlv_builder_s;
typedef struct tlv_builder_s *tlv_builder_t;
struct tlv_parser_s;
typedef struct tlv_parser_s *tlv_parser_t;
/*-- tlv.c --*/
/* Locate a TLV encoded data object in BUFFER of LENGTH and return a
@ -94,7 +106,7 @@ const unsigned char *find_tlv_unchecked (const unsigned char *buffer,
/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
and the length part from the TLV triplet. Update BUFFER and SIZE
on success. */
on success. See also tlv_parse_tag. */
gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size,
int *r_class, int *r_tag,
int *r_constructed,
@ -137,6 +149,59 @@ void put_tlv_to_membuf (membuf_t *membuf, int class, int tag,
size_t get_tlv_length (int class, int tag, int constructed, size_t length);
/*-- tlv-parser.c --*/
tlv_parser_t tlv_parser_new (const unsigned char *buffer, size_t bufsize,
int verbosity);
void tlv_parser_release (tlv_parser_t tlv);
void _tlv_parser_dump_tag (const char *text, int lno, tlv_parser_t tlv);
void _tlv_parser_dump_state (const char *text, const char *text2,
int lno, tlv_parser_t tlv);
int _tlv_parser_peek (tlv_parser_t tlv, int class, int tag);
int _tlv_parser_peek_null (tlv_parser_t tlv);
gpg_error_t _tlv_parser_next (tlv_parser_t tlv, int lno);
unsigned int tlv_parser_level (tlv_parser_t tlv);
size_t tlv_parser_offset (tlv_parser_t tlv);
const char *tlv_parser_lastfunc (tlv_parser_t tlv);
const char *tlv_parser_lasterrstr (tlv_parser_t tlv);
void tlv_parser_set_pending (tlv_parser_t tlv);
size_t tlv_parser_tag_length (tlv_parser_t tlv, int with_header);
void tlv_parser_skip (tlv_parser_t tlv);
gpg_error_t tlv_expect_sequence (tlv_parser_t tlv);
gpg_error_t tlv_expect_context_tag (tlv_parser_t tlv, int *r_tag);
gpg_error_t tlv_expect_set (tlv_parser_t tlv);
gpg_error_t tlv_expect_object (tlv_parser_t tlv, int class, int tag,
unsigned char const **r_data,
size_t *r_datalen);
gpg_error_t tlv_expect_octet_string (tlv_parser_t tlv, int encapsulates,
unsigned char const **r_data,
size_t *r_datalen);
gpg_error_t tlv_expect_integer (tlv_parser_t tlv, int *r_value);
#ifdef GCRYPT_VERSION
gpg_error_t tlv_expect_mpinteger (tlv_parser_t tlv, int ignore_zero,
gcry_mpi_t *r_value);
#endif
gpg_error_t tlv_expect_object_id (tlv_parser_t tlv,
unsigned char const **r_oid,
size_t *r_oidlen);
/* Easier to use wrapper around parse_ber_header. */
gpg_error_t tlv_parse_tag (unsigned char const **buffer,
size_t *size, struct tag_info *ti);
/* Convenience macro and macros to include the line number. */
#define tlv_parser_dump_tag(a,b) _tlv_parser_dump_tag ((a),__LINE__,(b))
#define tlv_parser_dump_state(a,b,c) \
_tlv_parser_dump_state ((a),(b),__LINE__,(c))
#define tlv_peek(a,b,c) _tlv_parser_peek ((a),(b),(c))
#define tlv_peek_null(a) _tlv_parser_peek_null ((a))
#define tlv_next(a) _tlv_parser_next ((a), __LINE__)
#endif /* SCD_TLV_H */

View File

@ -39,6 +39,11 @@
* libgpg-error version. Define them here.
* Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21)
*/
#if GPG_ERROR_VERSION_NUMBER < 0x012f00 /* 1.47 */
# define GPG_ERR_BAD_PUK 320
# define GPG_ERR_NO_RESET_CODE 321
# define GPG_ERR_BAD_RESET_CODE 322
#endif
#ifndef EXTERN_UNLESS_MAIN_MODULE
# if !defined (INCLUDED_BY_MAIN_MODULE)
@ -144,34 +149,6 @@ ssize_t read_line (FILE *fp,
size_t *max_length);
/*-- b64enc.c and b64dec.c --*/
struct b64state
{
unsigned int flags;
int idx;
int quad_count;
FILE *fp;
estream_t stream;
char *title;
unsigned char radbuf[4];
u32 crc;
int stop_seen:1;
int invalid_encoding:1;
gpg_error_t lasterr;
};
gpg_error_t b64enc_start (struct b64state *state, FILE *fp, const char *title);
gpg_error_t b64enc_start_es (struct b64state *state, estream_t fp,
const char *title);
gpg_error_t b64enc_write (struct b64state *state,
const void *buffer, size_t nbytes);
gpg_error_t b64enc_finish (struct b64state *state);
gpg_error_t b64dec_start (struct b64state *state, const char *title);
gpg_error_t b64dec_proc (struct b64state *state, void *buffer, size_t length,
size_t *r_nbytes);
gpg_error_t b64dec_finish (struct b64state *state);
/*-- sexputil.c */
char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen);
void log_printcanon (const char *text,
@ -219,6 +196,7 @@ char *pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid);
const char *pubkey_algo_to_string (int algo);
const char *hash_algo_to_string (int algo);
const char *cipher_mode_to_string (int mode);
const char *get_ecc_curve_from_key (gcry_sexp_t key);
/*-- convert.c --*/
int hex2bin (const char *string, void *buffer, size_t length);
@ -250,9 +228,10 @@ int openpgp_oidbuf_is_cv25519 (const void *buf, size_t len);
int openpgp_oid_is_cv25519 (gcry_mpi_t a);
int openpgp_oid_is_cv448 (gcry_mpi_t a);
int openpgp_oid_is_ed448 (gcry_mpi_t a);
enum gcry_kem_algos openpgp_oid_to_kem_algo (const char *oidname);
const char *openpgp_curve_to_oid (const char *name,
unsigned int *r_nbits, int *r_algo);
const char *openpgp_oid_to_curve (const char *oid, int canon);
const char *openpgp_oid_to_curve (const char *oid, int mode);
const char *openpgp_oid_or_name_to_curve (const char *oidname, int canon);
const char *openpgp_enum_curves (int *idxp);
const char *openpgp_is_curve_supported (const char *name,
@ -267,6 +246,7 @@ void gnupg_set_homedir (const char *newdir);
void gnupg_maybe_make_homedir (const char *fname, int quiet);
const char *gnupg_homedir (void);
int gnupg_default_homedir_p (void);
const char *gnupg_registry_dir (void);
const char *gnupg_daemon_rootdir (void);
const char *gnupg_socketdir (void);
const char *gnupg_sysconfdir (void);
@ -321,6 +301,19 @@ char *gnupg_get_help_string (const char *key, int only_current_locale);
/*-- localename.c --*/
const char *gnupg_messages_locale_name (void);
/*-- kem.c --*/
gpg_error_t gnupg_ecc_kem_kdf (void *kek, size_t kek_len,
int hashalgo, const void *ecdh, size_t ecdh_len,
const void *ecc_ct, size_t ecc_ct_len,
const void *ecc_pk, size_t ecc_pk_len);
gpg_error_t gnupg_kem_combiner (void *kek, size_t kek_len,
const void *ecc_ss, size_t ecc_ss_len,
const void *ecc_ct, size_t ecc_ct_len,
const void *mlkem_ss, size_t mlkem_ss_len,
const void *mlkem_ct, size_t mlkem_ct_len,
const void *fixedinfo, size_t fixedinfo_len);
/*-- miscellaneous.c --*/
/* This function is called at startup to tell libgcrypt to use our own
@ -360,8 +353,6 @@ char *try_make_printable_string (const void *p, size_t n, int delim);
char *make_printable_string (const void *p, size_t n, int delim);
char *decode_c_string (const char *src);
int is_file_compressed (const byte *buf, unsigned int buflen);
int match_multistr (const char *multistr,const char *match);
int gnupg_compare_version (const char *a, const char *b);
@ -383,11 +374,15 @@ struct compatibility_flags_s
int parse_compatibility_flags (const char *string, unsigned int *flagvar,
const struct compatibility_flags_s *flags);
gpg_error_t b64decode (const char *string, const char *title,
void **r_buffer, size_t *r_buflen);
/*-- Simple replacement functions. */
/* We use the gnupg_ttyname macro to be safe not to run into conflicts
which an extisting but broken ttyname. */
with an existing but broken ttyname. */
#if !defined(HAVE_TTYNAME) || defined(HAVE_BROKEN_TTYNAME)
# define gnupg_ttyname(n) _gnupg_ttyname ((n))
/* Systems without ttyname (W32) will merely return NULL. */

View File

@ -29,4 +29,4 @@ built on @BUILD_HOSTNAME@ at @BUILD_TIMESTAMP@\0"
#define W32INFO_PRODUCTVERSION "@VERSION@\0"
#define W32INFO_LEGALCOPYRIGHT "Copyright \xa9 \
2023 g10 Code GmbH\0"
2024 g10 Code GmbH\0"

View File

@ -58,22 +58,22 @@ AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg26", [swdb tag for this branch])
NEED_GPGRT_VERSION=1.46
NEED_LIBGCRYPT_API=1
NEED_LIBGCRYPT_VERSION=1.9.1
NEED_LIBGCRYPT_VERSION=1.11.0
NEED_LIBASSUAN_API=2
NEED_LIBASSUAN_VERSION=2.5.0
NEED_LIBASSUAN_API=3
NEED_LIBASSUAN_VERSION=3.0.0
NEED_KSBA_API=1
NEED_KSBA_VERSION=1.6.3
NEED_NTBTLS_API=1
NEED_NTBTLS_VERSION=0.1.0
NEED_NTBTLS_VERSION=0.2.0
NEED_NPTH_API=1
NEED_NPTH_VERSION=1.2
NEED_GNUTLS_VERSION=3.0
NEED_GNUTLS_VERSION=3.2
NEED_SQLITE_VERSION=3.27
@ -525,7 +525,7 @@ AH_BOTTOM([
#define GNUPG_OPENPGP_REVOC_DIR "openpgp-revocs.d"
#define GNUPG_CACHE_DIR "cache.d"
#define GNUPG_DEF_COPYRIGHT_LINE "Copyright (C) 2023 g10 Code GmbH"
#define GNUPG_DEF_COPYRIGHT_LINE "Copyright (C) 2024 g10 Code GmbH"
/* For some systems (DOS currently), we hardcode the path here. For
POSIX systems the values are constructed by the Makefiles, so that
@ -1385,6 +1385,8 @@ AC_CHECK_SIZEOF(time_t,,[[
]])
GNUPG_TIME_T_UNSIGNED
# Check SOCKET type for Windows.
AC_CHECK_TYPES([SOCKET], [], [], [[#include "winsock2.h"]])
if test "$ac_cv_sizeof_unsigned_short" = "0" \
|| test "$ac_cv_sizeof_unsigned_int" = "0" \
@ -1613,10 +1615,9 @@ if test "$build_tpm2d" = "yes"; then
if test "$have_libtss" != no; then
AC_DEFINE(HAVE_LIBTSS, 1, [Defined if we have TPM2 support library])
# look for a TPM emulator for testing
AC_PATH_PROG(TPMSERVER, tpm_server,,/bin:/usr/bin:/usr/lib/ibmtss:/usr/libexec/ibmtss)
AC_PATH_PROG(SWTPM, swtpm,,/bin:/usr/bin:/usr/lib/ibmtss:/usr/libexec/ibmtss)
AC_PATH_PROG(SWTPM_IOCTL, swtpm_ioctl,,/bin:/usr/bin:/usr/lib/ibmtss:/usr/libexec/ibmtss)
AC_PATH_PROG(TSSSTARTUP, tssstartup,,/bin:/usr/bin:/usr/lib/ibmtss:/usr/libexec/ibmtss)
AC_PATH_PROG(TPMSERVER, tpm_server)
AC_PATH_PROG(TSSSTARTUP, tssstartup)
AC_PATH_PROG(SWTPM, swtpm)
fi
fi
if test "$have_libtss" = no; then
@ -1625,7 +1626,7 @@ fi
AC_SUBST(LIBTSS_LIBS)
AC_SUBST(LIBTSS_CFLAGS)
AM_CONDITIONAL(HAVE_LIBTSS, test "$have_libtss" != no)
AM_CONDITIONAL(TEST_LIBTSS, test -n "$TPMSERVER" || test -n "$SWTPM" && test -n "$TSSSTARTUP")
AM_CONDITIONAL(TEST_LIBTSS, test -n "$SWTPM" -o -n "$TPMSERVER" -a -n "$TSSSTARTUP")
AC_SUBST(HAVE_LIBTSS)
#
@ -2102,6 +2103,14 @@ tests/tpm2dtests/Makefile
tests/gpgme/Makefile
tests/pkits/Makefile
g10/gpg.w32-manifest
g10/gpgv.w32-manifest
sm/gpgsm.w32-manifest
kbx/keyboxd.w32-manifest
agent/gpg-agent.w32-manifest
scd/scdaemon.w32-manifest
dirmngr/dirmngr.w32-manifest
dirmngr/dirmngr_ldap.w32-manifest
dirmngr/dirmngr-client.w32-manifest
tools/gpg-connect-agent.w32-manifest
tools/gpgconf.w32-manifest
tools/gpgtar.w32-manifest

View File

@ -1373,7 +1373,7 @@
truncated search.
* ldap.c (add_server_to_servers): Reactivated.
(url_fetch_ldap): Call it here and try all configured servers in
case of a a failed lookup.
case of a failed lookup.
(fetch_next_cert_ldap): Detect the truncation error flag.
* misc.c (host_and_port_from_url, remove_percent_escapes): New.

View File

@ -21,7 +21,14 @@
## Process this file with automake to produce Makefile.in
EXTRA_DIST = OAUTHORS ONEWS ChangeLog-2011 tls-ca.pem
EXTRA_DIST = OAUTHORS ONEWS ChangeLog-2011 tls-ca.pem \
dirmngr-w32info.rc dirmngr.w32-manifest.in \
dirmngr_ldap-w32info.rc dirmngr_ldap.w32-manifest.in \
dirmngr-client-w32info.rc dirmngr-client.w32-manifest.in
dist_pkgdata_DATA = sks-keyservers.netCA.pem
bin_PROGRAMS = dirmngr dirmngr-client
@ -43,6 +50,16 @@ AM_CPPFLAGS =
include $(top_srcdir)/am/cmacros.am
if HAVE_W32_SYSTEM
dirmngr_rc_objs = dirmngr-w32info.o
dirmngr_ldap_rc_objs = dirmngr_ldap-w32info.o
dirmngr_client_rc_objs = dirmngr-client-w32info.o
dirmngr-w32info.o : dirmngr.w32-manifest ../common/w32info-rc.h
dirmngr_ldap-w32info.o : dirmngr_ldap.w32-manifest ../common/w32info-rc.h
dirmngr-client-w32info.o : dirmngr-client.w32-manifest ../common/w32info-rc.h
endif
AM_CFLAGS = $(USE_C99_CFLAGS) \
$(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS) \
$(GPG_ERROR_CFLAGS) $(NPTH_CFLAGS) $(NTBTLS_CFLAGS) \
@ -51,6 +68,7 @@ AM_CFLAGS = $(USE_C99_CFLAGS) \
if HAVE_W32_SYSTEM
ldap_url = ldap-url.h ldap-url.c
NETLIBS += -lwinhttp -lsecurity
else
ldap_url =
endif
@ -89,12 +107,13 @@ dirmngr_LDADD = $(libcommonpth) \
$(DNSLIBS) $(LIBASSUAN_LIBS) \
$(KSBA_LIBS) $(NPTH_LIBS) $(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) \
$(LIBGCRYPT_LIBS) $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV) \
$(NETLIBS)
$(NETLIBS) $(dirmngr_rc_objs)
if USE_LDAP
dirmngr_LDADD += $(ldaplibs) $(LBER_LIBS)
endif
dirmngr_LDFLAGS =
dirmngr_DEPENDENCIES = $(dirmngr_rc_objs)
if USE_LDAP
dirmngr_ldap_SOURCES = dirmngr_ldap.c ldap-misc.c ldap-misc.h $(ldap_url)
@ -102,14 +121,18 @@ dirmngr_ldap_CFLAGS = $(GPG_ERROR_CFLAGS) $(LIBGCRYPT_CFLAGS)
dirmngr_ldap_LDFLAGS =
dirmngr_ldap_LDADD = $(libcommon) \
$(GPG_ERROR_LIBS) $(LIBGCRYPT_LIBS) $(LDAPLIBS) \
$(LBER_LIBS) $(LIBINTL) $(LIBICONV) $(NETLIBS)
$(LBER_LIBS) $(LIBINTL) $(LIBICONV) $(NETLIBS) \
$(dirmngr_ldap_rc_objs)
dirmngr_ldap_DEPENDENCIES = $(dirmngr_ldap_rc_objs)
endif
dirmngr_client_SOURCES = dirmngr-client.c
dirmngr_client_LDADD = $(libcommon) \
$(LIBASSUAN_LIBS) $(GPG_ERROR_LIBS) \
$(LIBGCRYPT_LIBS) $(NETLIBS) $(LIBINTL) $(LIBICONV)
$(LIBGCRYPT_LIBS) $(NETLIBS) $(LIBINTL) $(LIBICONV) \
$(dirmngr_client_rc_objs)
dirmngr_client_LDFLAGS =
dirmngr_client_DEPENDENCIES = $(dirmngr_client_rc_objs)
t_common_src = t-support.h t-support.c

View File

@ -100,7 +100,8 @@ static unsigned int any_cert_of_class;
#ifdef HAVE_W32_SYSTEM
/* We load some functions dynamically. Provide typedefs for tehse
#include <wincrypt.h>
/* We load some functions dynamically. Provide typedefs for these
* functions. */
typedef HCERTSTORE (WINAPI *CERTOPENSYSTEMSTORE)
(HCRYPTPROV hProv, LPCSTR szSubsystemProtocol);

View File

@ -2086,6 +2086,7 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl,
err = validate_cert_chain (ctrl, crlissuer_cert, NULL,
(VALIDATE_FLAG_TRUST_CONFIG
| VALIDATE_FLAG_TRUST_SYSTEM
| VALIDATE_FLAG_CRL
| VALIDATE_FLAG_RECURSIVE),
r_trust_anchor);
@ -2356,11 +2357,21 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader)
for (idx=0; !(err=ksba_crl_get_extension (crl, idx, &oid, &critical,
NULL, NULL)); idx++)
{
strlist_t sl;
if (!critical
|| !strcmp (oid, oidstr_authorityKeyIdentifier)
|| !strcmp (oid, oidstr_crlNumber) )
continue;
for (sl=opt.ignored_crl_extensions;
sl && strcmp (sl->d, oid); sl = sl->next)
;
if (sl)
continue; /* Is in ignored list. */
log_error (_("unknown critical CRL extension %s\n"), oid);
log_info ("(CRL='%s')\n", url);
if (!err2)
err2 = gpg_error (GPG_ERR_INV_CRL);
invalidate_crl |= INVCRL_UNKNOWN_EXTN;

View File

@ -39,10 +39,10 @@
2008) we need a context in the reader callback. */
struct reader_cb_context_s
{
estream_t fp; /* The stream used with the ksba reader. */
int checked:1; /* PEM/binary detection ahs been done. */
int is_pem:1; /* The file stream is PEM encoded. */
struct b64state b64state; /* The state used for Base64 decoding. */
estream_t fp; /* The stream used with the ksba reader. */
unsigned int checked:1; /* PEM/binary detection ahs been done. */
unsigned int is_pem:1; /* The file stream is PEM encoded. */
gpgrt_b64state_t b64state; /* The state used for Base64 decoding. */
};
@ -126,14 +126,16 @@ my_es_read (void *opaque, char *buffer, size_t nbytes, size_t *nread)
else
{
cb_ctx->is_pem = 1;
b64dec_start (&cb_ctx->b64state, "");
cb_ctx->b64state = gpgrt_b64dec_start ("");
if (!cb_ctx->b64state)
return gpg_error_from_syserror ();
}
}
if (cb_ctx->is_pem && *nread)
{
size_t nread2;
if (b64dec_proc (&cb_ctx->b64state, buffer, *nread, &nread2))
if (gpgrt_b64dec_proc (cb_ctx->b64state, buffer, *nread, &nread2))
{
/* EOF from decoder. */
*nread = 0;
@ -581,7 +583,7 @@ crl_close_reader (ksba_reader_t reader)
es_fclose (cb_ctx->fp);
/* Release the base64 decoder state. */
if (cb_ctx->is_pem)
b64dec_finish (&cb_ctx->b64state);
gpgrt_b64dec_finish (cb_ctx->b64state);
/* Release the callback context. */
xfree (cb_ctx);
}

View File

@ -0,0 +1,52 @@
/* dirmngr-client-w32info.rc -*- c -*-
* Copyright (C) 2023 g10 Code GmbH
*
* This file is free software; as a special exception the author gives
* unlimited permission to copy and/or distribute it, with or without
* modifications, as long as this notice is preserved.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "afxres.h"
#include "../common/w32info-rc.h"
1 ICON "../common/gnupg.ico"
1 VERSIONINFO
FILEVERSION W32INFO_VI_FILEVERSION
PRODUCTVERSION W32INFO_VI_PRODUCTVERSION
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x01L /* VS_FF_DEBUG (0x1)*/
#else
FILEFLAGS 0x00L
#endif
FILEOS 0x40004L /* VOS_NT (0x40000) | VOS__WINDOWS32 (0x4) */
FILETYPE 0x1L /* VFT_APP (0x1) */
FILESUBTYPE 0x0L /* VFT2_UNKNOWN */
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" /* US English (0409), Unicode (04b0) */
BEGIN
VALUE "FileDescription", L"GnuPG\x2019s dirmngr client\0"
VALUE "InternalName", "dirmngr-client\0"
VALUE "OriginalFilename", "dirmngr-client.exe\0"
VALUE "ProductName", W32INFO_PRODUCTNAME
VALUE "ProductVersion", W32INFO_PRODUCTVERSION
VALUE "CompanyName", W32INFO_COMPANYNAME
VALUE "FileVersion", W32INFO_FILEVERSION
VALUE "LegalCopyright", W32INFO_LEGALCOPYRIGHT
VALUE "Comments", W32INFO_COMMENTS
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 0x4b0
END
END
1 RT_MANIFEST "dirmngr-client.w32-manifest"

View File

@ -308,7 +308,7 @@ main (int argc, char **argv )
opt.dirmngr_program
? opt.dirmngr_program
: gnupg_module_name (GNUPG_MODULE_NAME_DIRMNGR),
! cmd_ping,
cmd_ping? 0 : ASSHELP_FLAG_AUTOSTART,
opt.verbose,
0,
NULL, NULL);
@ -441,11 +441,11 @@ static gpg_error_t
data_cb (void *opaque, const void *buffer, size_t length)
{
gpg_error_t err;
struct b64state *state = opaque;
gpgrt_b64state_t state = opaque;
if (buffer)
{
err = b64enc_write (state, buffer, length);
err = gpgrt_b64enc_write (state, buffer, length);
if (err)
log_error (_("error writing base64 encoding: %s\n"),
gpg_strerror (err));
@ -853,14 +853,14 @@ do_lookup (assuan_context_t ctx, const char *pattern)
gpg_error_t err;
const unsigned char *s;
char *line, *p;
struct b64state state;
gpgrt_b64state_t state;
if (opt.verbose)
log_info (_("looking up '%s'\n"), pattern);
err = b64enc_start (&state, stdout, NULL);
if (err)
return err;
state = gpgrt_b64enc_start (es_stdout, NULL);
if (!state)
return gpg_error_from_syserror ();
line = xmalloc (10 + 6 + 13 + strlen (pattern)*3 + 1);
@ -885,13 +885,13 @@ do_lookup (assuan_context_t ctx, const char *pattern)
err = assuan_transact (ctx, line,
data_cb, &state,
data_cb, state,
NULL, NULL,
status_cb, NULL);
if (opt.verbose > 1)
log_info ("response of dirmngr: %s\n", err? gpg_strerror (err): "okay");
err = b64enc_finish (&state);
err = gpgrt_b64enc_finish (state);
xfree (line);
return err;

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<description>GNU Privacy Guard (Dirmngr Client)</description>
<assemblyIdentity
type="win32"
name="GnuPG.dirmngr-client"
version="@BUILD_VERSION@"
/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/><!-- 10 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/><!-- 8.1 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/><!-- 8 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/><!-- 7 -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/><!-- Vista -->
</application>
</compatibility>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@ -0,0 +1,52 @@
/* dirmngr-w32info.rc -*- c -*-
* Copyright (C) 2023 g10 Code GmbH
*
* This file is free software; as a special exception the author gives
* unlimited permission to copy and/or distribute it, with or without
* modifications, as long as this notice is preserved.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "afxres.h"
#include "../common/w32info-rc.h"
1 ICON "../common/gnupg.ico"
1 VERSIONINFO
FILEVERSION W32INFO_VI_FILEVERSION
PRODUCTVERSION W32INFO_VI_PRODUCTVERSION
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x01L /* VS_FF_DEBUG (0x1)*/
#else
FILEFLAGS 0x00L
#endif
FILEOS 0x40004L /* VOS_NT (0x40000) | VOS__WINDOWS32 (0x4) */
FILETYPE 0x1L /* VFT_APP (0x1) */
FILESUBTYPE 0x0L /* VFT2_UNKNOWN */
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" /* US English (0409), Unicode (04b0) */
BEGIN
VALUE "FileDescription", L"GnuPG\x2019s network access daemon\0"
VALUE "InternalName", "dirmngr\0"
VALUE "OriginalFilename", "dirmngr.exe\0"
VALUE "ProductName", W32INFO_PRODUCTNAME
VALUE "ProductVersion", W32INFO_PRODUCTVERSION
VALUE "CompanyName", W32INFO_COMPANYNAME
VALUE "FileVersion", W32INFO_FILEVERSION
VALUE "LegalCopyright", W32INFO_LEGALCOPYRIGHT
VALUE "Comments", W32INFO_COMMENTS
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 0x4b0
END
END
1 RT_MANIFEST "dirmngr.w32-manifest"

View File

@ -147,6 +147,7 @@ enum cmd_and_opt_values {
oHTTPWrapperProgram,
oIgnoreCert,
oIgnoreCertExtension,
oIgnoreCRLExtension,
oUseTor,
oNoUseTor,
oKeyServer,
@ -159,6 +160,7 @@ enum cmd_and_opt_values {
oConnectQuickTimeout,
oListenBacklog,
oFakeCRL,
oCompatibilityFlags,
aTest
};
@ -219,10 +221,11 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"),
ARGPARSE_s_i (oMaxReplies, "max-replies",
N_("|N|do not return more than N items in one query")),
ARGPARSE_s_u (oFakedSystemTime, "faked-system-time", "@"), /*(epoch time)*/
ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
ARGPARSE_s_n (oDisableCheckOwnSocket, "disable-check-own-socket", "@"),
ARGPARSE_s_s (oIgnoreCert,"ignore-cert", "@"),
ARGPARSE_s_s (oIgnoreCertExtension,"ignore-cert-extension", "@"),
ARGPARSE_s_s (oIgnoreCRLExtension,"ignore-crl-extension", "@"),
ARGPARSE_header ("Network", N_("Network related options")),
@ -297,6 +300,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_s (oSocketName, "socket-name", "@"), /* Only for debugging. */
ARGPARSE_s_n (oDebugCacheExpiredCerts, "debug-cache-expired-certs", "@"),
ARGPARSE_s_s (oCompatibilityFlags, "compatibility-flags", "@"),
ARGPARSE_header (NULL, ""), /* Stop the header group. */
@ -329,6 +333,14 @@ static struct debug_flags_s debug_flags [] =
{ 77, NULL } /* 77 := Do not exit on "help" or "?". */
};
/* The list of compatibility flags. */
static struct compatibility_flags_s compatibility_flags [] =
{
{ COMPAT_RESTRICT_HTTP_REDIR, "restrict-http-redir" },
{ 0, NULL }
};
#define DEFAULT_MAX_REPLIES 10
#define DEFAULT_LDAP_TIMEOUT 15 /* seconds */
@ -382,6 +394,9 @@ static enum
} tor_mode;
/* Flag indicating that we are in supervised mode. */
static int is_supervised;
/* Counter for the active connections. */
static int active_connections;
@ -438,9 +453,6 @@ static void handle_connections (assuan_fd_t listen_fd);
static void gpgconf_versions (void);
/* NPth wrapper function definitions. */
ASSUAN_SYSTEM_NPTH_IMPL;
static const char *
my_strusage( int level )
{
@ -696,6 +708,7 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.ignored_certs = tmp;
}
FREE_STRLIST (opt.ignored_cert_extensions);
FREE_STRLIST (opt.ignored_crl_extensions);
http_register_tls_ca (NULL);
FREE_STRLIST (hkp_cacert_filenames);
FREE_STRLIST (opt.keyserver);
@ -712,6 +725,7 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.debug_cache_expired_certs = 0;
xfree (opt.fake_crl);
opt.fake_crl = NULL;
opt.compat_flags = 0;
return 1;
}
@ -808,6 +822,10 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
add_to_strlist (&opt.ignored_cert_extensions, pargs->r.ret_str);
break;
case oIgnoreCRLExtension:
add_to_strlist (&opt.ignored_crl_extensions, pargs->r.ret_str);
break;
case oUseTor:
tor_mode = TOR_MODE_FORCE;
break;
@ -879,6 +897,15 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.fake_crl = *pargs->r.ret_str? xstrdup (pargs->r.ret_str) : NULL;
break;
case oCompatibilityFlags:
if (parse_compatibility_flags (pargs->r.ret_str, &opt.compat_flags,
compatibility_flags))
{
pargs->r_opt = ARGPARSE_INVALID_ARG;
pargs->err = ARGPARSE_PRINT_WARNING;
}
break;
default:
return 0; /* Not handled. */
}
@ -953,7 +980,6 @@ static void
thread_init (void)
{
npth_init ();
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
/* Now with NPth running we can set the logging callback. Our
@ -1149,7 +1175,12 @@ main (int argc, char **argv)
case oLDAPAddServers: opt.add_new_ldapservers = 1; break;
case oFakedSystemTime:
gnupg_set_time ((time_t)pargs.r.ret_ulong, 0);
{
time_t faked_time = isotime2epoch (pargs.r.ret_str);
if (faked_time == (time_t)(-1))
faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
gnupg_set_time (faked_time, 0);
}
break;
case oForce: opt.force = 1; break;
@ -1303,6 +1334,8 @@ main (int argc, char **argv)
if (!opt.quiet)
log_info(_("WARNING: \"%s\" is a deprecated option\n"), "--supervised");
is_supervised = 1;
/* In supervised mode, we expect file descriptor 3 to be an
already opened, listening socket.
@ -2013,6 +2046,7 @@ dirmngr_sighup_action (void)
crl_cache_deinit ();
cert_cache_init (hkp_cacert_filenames);
crl_cache_init ();
http_reinitialize ();
reload_dns_stuff (0);
ks_hkp_reload ();
}
@ -2200,7 +2234,7 @@ check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
if (assuan_sock_check_nonce (fd, nonce))
{
log_info (_("error reading nonce on fd %d: %s\n"),
FD2INT (fd), strerror (errno));
FD_DBG (fd), strerror (errno));
assuan_sock_close (fd);
return -1;
}
@ -2234,7 +2268,7 @@ start_connection_thread (void *arg)
active_connections++;
if (opt.verbose)
log_info (_("handler for fd %d started\n"), FD2INT (fd));
log_info (_("handler for fd %d started\n"), FD_DBG (fd));
session_id = ++last_session_id;
if (!session_id)
@ -2242,7 +2276,7 @@ start_connection_thread (void *arg)
start_command_handler (fd, session_id);
if (opt.verbose)
log_info (_("handler for fd %d terminated\n"), FD2INT (fd));
log_info (_("handler for fd %d terminated\n"), FD_DBG (fd));
active_connections--;
workqueue_run_post_session_tasks (session_id);
@ -2345,7 +2379,7 @@ handle_connections (assuan_fd_t listen_fd)
to full second. */
FD_ZERO (&fdset);
FD_SET (FD2INT (listen_fd), &fdset);
nfd = FD2INT (listen_fd);
nfd = FD2NUM (listen_fd);
if (my_inotify_fd != -1)
{
FD_SET (my_inotify_fd, &fdset);
@ -2362,7 +2396,7 @@ handle_connections (assuan_fd_t listen_fd)
/* Shutdown test. */
if (shutdown_pending)
{
if (!active_connections)
if (!active_connections || is_supervised)
break; /* ready */
/* Do not accept new connections but keep on running the
@ -2446,8 +2480,8 @@ handle_connections (assuan_fd_t listen_fd)
gnupg_fd_t fd;
plen = sizeof paddr;
fd = INT2FD (npth_accept (FD2INT(listen_fd),
(struct sockaddr *)&paddr, &plen));
fd = assuan_sock_accept (listen_fd,
(struct sockaddr *)&paddr, &plen);
if (fd == GNUPG_INVALID_FD)
{
log_error ("accept failed: %s\n", strerror (errno));
@ -2461,7 +2495,7 @@ handle_connections (assuan_fd_t listen_fd)
memset (&argval, 0, sizeof argval);
argval.afd = fd;
snprintf (threadname, sizeof threadname,
"conn fd=%d", FD2INT(fd));
"conn fd=%d", FD_DBG (fd));
ret = npth_create (&thread, &tattr,
start_connection_thread, argval.aptr);

View File

@ -132,6 +132,11 @@ struct
OID per string. */
strlist_t ignored_cert_extensions;
/* A list of CRL extension OIDs which are ignored so that one can
* claim that a critical extension has been handled. One OID per
* string. */
strlist_t ignored_crl_extensions;
/* Allow expired certificates in the cache. */
int debug_cache_expired_certs;
@ -154,6 +159,9 @@ struct
current after nextUpdate. */
strlist_t keyserver; /* List of default keyservers. */
/* Compatibility flags (COMPAT_FLAG_xxxx). */
unsigned int compat_flags;
} opt;
@ -182,6 +190,18 @@ struct
#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
#define DBG_KEEPTMP (opt.debug & DBG_KEEPTMP_VALUE)
/* Compatibility flags */
/* Since version 2.2.12 dirmngr restricted HTTP redirection in an
* attempt to mitigate certain CSRF attacks. It turned out that this
* breaks too many WKD deployments and that the attack scenario is not
* due to gnupg's redirecting but due to insecure configured systems.
* Thus from 2.4.3 on we disable this restriction but allow to use the
* old behaviour by using this compatibility flag. For details see
* https://dev.gnupg.org/T6477. */
#define COMPAT_RESTRICT_HTTP_REDIR 1
/* A simple list of certificate references. FIXME: Better use
certlist_t also for references (Store NULL at .cert) */
struct cert_ref_s

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<description>GNU Privacy Guard (Archive tool)</description>
<assemblyIdentity
type="win32"
name="GnuPG.dirmngr"
version="@BUILD_VERSION@"
/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/><!-- 10 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/><!-- 8.1 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/><!-- 8 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/><!-- 7 -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/><!-- Vista -->
</application>
</compatibility>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@ -0,0 +1,52 @@
/* dirmngr_ldap-w32info.rc -*- c -*-
* Copyright (C) 2023 g10 Code GmbH
*
* This file is free software; as a special exception the author gives
* unlimited permission to copy and/or distribute it, with or without
* modifications, as long as this notice is preserved.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
#include "afxres.h"
#include "../common/w32info-rc.h"
1 ICON "../common/gnupg.ico"
1 VERSIONINFO
FILEVERSION W32INFO_VI_FILEVERSION
PRODUCTVERSION W32INFO_VI_PRODUCTVERSION
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x01L /* VS_FF_DEBUG (0x1)*/
#else
FILEFLAGS 0x00L
#endif
FILEOS 0x40004L /* VOS_NT (0x40000) | VOS__WINDOWS32 (0x4) */
FILETYPE 0x1L /* VFT_APP (0x1) */
FILESUBTYPE 0x0L /* VFT2_UNKNOWN */
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" /* US English (0409), Unicode (04b0) */
BEGIN
VALUE "FileDescription", L"GnuPG\x2019s LDAP helper\0"
VALUE "InternalName", "dirmngr_ldap\0"
VALUE "OriginalFilename", "dirmngr_ldap.exe\0"
VALUE "ProductName", W32INFO_PRODUCTNAME
VALUE "ProductVersion", W32INFO_PRODUCTVERSION
VALUE "CompanyName", W32INFO_COMPANYNAME
VALUE "FileVersion", W32INFO_FILEVERSION
VALUE "LegalCopyright", W32INFO_LEGALCOPYRIGHT
VALUE "Comments", W32INFO_COMMENTS
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 0x4b0
END
END
1 RT_MANIFEST "dirmngr_ldap.w32-manifest"

View File

@ -107,7 +107,7 @@ static gpgrt_opt_t opts[] = {
" a record oriented format"},
{ oProxy, "proxy", 2,
"|NAME|ignore host part and connect through NAME"},
{ oStartTLS, "starttls", 0, "use STARTLS for the conenction"},
{ oStartTLS, "starttls", 0, "use STARTLS for the connection"},
{ oLdapTLS, "ldaptls", 0, "use a TLS for the connection"},
{ oNtds, "ntds", 0, "authenticate using AD"},
{ oARecOnly, "areconly", 0, "do only an A record lookup"},

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<description>GNU Privacy Guard (LDAP Helper)</description>
<assemblyIdentity
type="win32"
name="GnuPG.dirmngr-ldap"
version="@BUILD_VERSION@"
/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/><!-- 10 -->
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/><!-- 8.1 -->
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/><!-- 8 -->
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/><!-- 7 -->
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/><!-- Vista -->
</application>
</compatibility>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View File

@ -34,6 +34,7 @@
# define WIN32_LEAN_AND_MEAN
# ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
# include <ws2tcpip.h>
# endif
# include <windows.h>
# include <iphlpapi.h>

Some files were not shown because too many files have changed in this diff Show More