mirror of git://git.gnupg.org/gnupg.git
Compare commits
230 Commits
gnupg-2.4.
...
master
Author | SHA1 | Date |
---|---|---|
Werner Koch | 351fc6e6fa | |
Werner Koch | 473f37a53e | |
Werner Koch | 467239dccb | |
Werner Koch | f415d96fac | |
Werner Koch | 516b530126 | |
Werner Koch | c8a3b711f0 | |
Werner Koch | c1d62418d5 | |
Werner Koch | 351f5e814b | |
NIIBE Yutaka | 9128d81bb7 | |
Werner Koch | 83e2dede0a | |
Werner Koch | d3b41e7611 | |
NIIBE Yutaka | 02b056ef77 | |
NIIBE Yutaka | 2593dcbceb | |
Werner Koch | 2958e5e4cf | |
NIIBE Yutaka | a45243548e | |
NIIBE Yutaka | d1f8caafb4 | |
Werner Koch | ab703eacf7 | |
Werner Koch | dd650b2c7b | |
Werner Koch | 32ec480024 | |
Werner Koch | 54741685ce | |
Werner Koch | f325d3277e | |
Werner Koch | e591fd25ad | |
Werner Koch | f305e703d5 | |
NIIBE Yutaka | af98a3e5fa | |
NIIBE Yutaka | 65833eefb2 | |
NIIBE Yutaka | d5c6b52e59 | |
Daniel Cerqueira | aa15272ba1 | |
Werner Koch | f119444e64 | |
Werner Koch | ba3c873934 | |
Werner Koch | 7d6ad28667 | |
Werner Koch | 21f7ad563d | |
Werner Koch | 2a71c3cf97 | |
Werner Koch | 4e32ff209d | |
Werner Koch | c736052e9c | |
Werner Koch | 4c20d2d273 | |
NIIBE Yutaka | 35ef87d8d9 | |
Werner Koch | b48476bbef | |
Werner Koch | 6f94fe01a9 | |
Werner Koch | 813f8d1b8e | |
Werner Koch | 61717fb0a7 | |
Werner Koch | 869d1df270 | |
NIIBE Yutaka | f2fd4f1a9e | |
NIIBE Yutaka | 172d53d636 | |
Werner Koch | 6737e07a9b | |
Todd Zullinger via Gnupg-devel | 87025e5da6 | |
Werner Koch | 84ddb24e30 | |
NIIBE Yutaka | c21237ac27 | |
NIIBE Yutaka | aee6b1131b | |
NIIBE Yutaka | 04b81ec236 | |
Werner Koch | 52c4b09080 | |
Werner Koch | 1a37f0080b | |
NIIBE Yutaka | 3a344d6236 | |
Werner Koch | f7a26aa8ad | |
Werner Koch | c5d7a332c8 | |
Werner Koch | 03d53c88cc | |
Werner Koch | 68d9bc9c35 | |
Werner Koch | 53c6b1e858 | |
Werner Koch | ce8b25270b | |
NIIBE Yutaka | 131dd2a351 | |
Werner Koch | 97f5159495 | |
Werner Koch | 6c1dd3afd1 | |
Werner Koch | 4b981e415f | |
Werner Koch | fa33b18940 | |
NIIBE Yutaka | c69363e8c7 | |
NIIBE Yutaka | 1fa24e2841 | |
Werner Koch | 571a768ac6 | |
NIIBE Yutaka | 984a0c6982 | |
Werner Koch | f9919bcc48 | |
Werner Koch | cec1fde1bc | |
Werner Koch | a0bfbdaaa2 | |
Werner Koch | fb3fe38d28 | |
Werner Koch | 50e81ad38d | |
Werner Koch | f78501c545 | |
Werner Koch | 14c1b73093 | |
Werner Koch | 81536535f8 | |
Werner Koch | 4485930f9f | |
Werner Koch | 609b1ec0c6 | |
Werner Koch | 79d0e52b2d | |
Werner Koch | 40227e42ea | |
NIIBE Yutaka | 874918ab91 | |
NIIBE Yutaka | 27f66148f7 | |
Werner Koch | dfa60c09f5 | |
NIIBE Yutaka | af6ac2ac02 | |
NIIBE Yutaka | ccfbb9ebdf | |
NIIBE Yutaka | 6ddaf2be9f | |
NIIBE Yutaka | 7cde533ce8 | |
NIIBE Yutaka | c44f0bc91e | |
Werner Koch | 2764ee309a | |
Werner Koch | 853f36e596 | |
NIIBE Yutaka | 4dd4e9d2f1 | |
NIIBE Yutaka | 4e94b004a6 | |
NIIBE Yutaka | 37fa36a329 | |
Ahelenia Ziemiańska | 1ded50dd5b | |
Daniel Cerqueira | 548d4aad5f | |
NIIBE Yutaka | 42ee841976 | |
Max-Julian Pogner | 2600047470 | |
Werner Koch | 6fab7b075a | |
NIIBE Yutaka | ec1446f944 | |
NIIBE Yutaka | 64f5f7b74e | |
NIIBE Yutaka | 65607fb81d | |
NIIBE Yutaka | e6b3d53db3 | |
Werner Koch | 387ee7dcbd | |
NIIBE Yutaka | 337de21f4b | |
NIIBE Yutaka | 00da0e9f93 | |
NIIBE Yutaka | c2812a9bbc | |
Andre Heinecke | 05ef8c0cc0 | |
NIIBE Yutaka | 16b6b77532 | |
NIIBE Yutaka | 227b3b14f4 | |
NIIBE Yutaka | 98dd6f7af6 | |
NIIBE Yutaka | 08e529fa7c | |
NIIBE Yutaka | f2ca727978 | |
NIIBE Yutaka | 25c84ffd10 | |
NIIBE Yutaka | 321f9c0a3f | |
NIIBE Yutaka | 4206d89003 | |
NIIBE Yutaka | 78afc209cc | |
NIIBE Yutaka | 1da40db03e | |
NIIBE Yutaka | eda3997b43 | |
NIIBE Yutaka | 459bd577fc | |
NIIBE Yutaka | a8618fdccd | |
NIIBE Yutaka | 26939ea222 | |
Werner Koch | 34f812475e | |
Werner Koch | 1be7882344 | |
NIIBE Yutaka | d90f1e5fa4 | |
NIIBE Yutaka | 28364affa6 | |
NIIBE Yutaka | 5e47d5edd8 | |
NIIBE Yutaka | 57125d3f5a | |
NIIBE Yutaka | 92de0387f0 | |
NIIBE Yutaka | 76a2f18028 | |
NIIBE Yutaka | 7025375e8b | |
NIIBE Yutaka | 76896e2339 | |
NIIBE Yutaka | b2826924ee | |
NIIBE Yutaka | 95186ae92f | |
Werner Koch | 9dd8fd4ae4 | |
Werner Koch | a430f22549 | |
NIIBE Yutaka | 716e59b0b6 | |
NIIBE Yutaka | 9e4d522239 | |
NIIBE Yutaka | 1d73806972 | |
NIIBE Yutaka | ed4050e011 | |
NIIBE Yutaka | 0821ceebfb | |
NIIBE Yutaka | 5cad5f903e | |
NIIBE Yutaka | 0d20b79ab7 | |
NIIBE Yutaka | dad880155e | |
NIIBE Yutaka | 1ddd69935d | |
NIIBE Yutaka | 95d9761509 | |
NIIBE Yutaka | 30fc365124 | |
NIIBE Yutaka | eceba4f207 | |
Andre Heinecke | 6e2412e74a | |
NIIBE Yutaka | 6524becf28 | |
NIIBE Yutaka | ea1935252e | |
NIIBE Yutaka | 521ec40aea | |
NIIBE Yutaka | ae188a3357 | |
NIIBE Yutaka | 81055baf5c | |
NIIBE Yutaka | b849c930e9 | |
NIIBE Yutaka | ee9e3578ce | |
NIIBE Yutaka | 5d375bb168 | |
NIIBE Yutaka | cf270b0d30 | |
NIIBE Yutaka | ea625c74f0 | |
NIIBE Yutaka | 69c1d81284 | |
NIIBE Yutaka | fb046ccd93 | |
NIIBE Yutaka | 23bcb78d27 | |
NIIBE Yutaka | b07b5144ff | |
NIIBE Yutaka | 067bc2ed4c | |
NIIBE Yutaka | 16d135c396 | |
NIIBE Yutaka | 250733c0d8 | |
NIIBE Yutaka | 37343db08f | |
NIIBE Yutaka | 5bc949d230 | |
Werner Koch | 9f39e4da29 | |
NIIBE Yutaka | 8cacfce898 | |
NIIBE Yutaka | 2abea42d9c | |
NIIBE Yutaka | f2dcd158a5 | |
NIIBE Yutaka | 577baf4af3 | |
NIIBE Yutaka | 3fb69641e8 | |
NIIBE Yutaka | 2c2516f03a | |
NIIBE Yutaka | 68d3a73ea7 | |
NIIBE Yutaka | dc13361524 | |
NIIBE Yutaka | 2c5a93e66e | |
Werner Koch | 334f5d95c8 | |
NIIBE Yutaka | b5efb52d43 | |
NIIBE Yutaka | a0ff2919f7 | |
NIIBE Yutaka | 250fff0f6e | |
NIIBE Yutaka | 6049d61991 | |
NIIBE Yutaka | 3672c29156 | |
NIIBE Yutaka | cacb018992 | |
NIIBE Yutaka | 7cfbf0dd72 | |
NIIBE Yutaka | 631c23b664 | |
NIIBE Yutaka | b9b0c18320 | |
NIIBE Yutaka | 72ac77c4fa | |
NIIBE Yutaka | 76df934929 | |
NIIBE Yutaka | 1f9a4fbc7e | |
NIIBE Yutaka | f0ecc07c4e | |
NIIBE Yutaka | 87a73e8eb0 | |
NIIBE Yutaka | 2756147e39 | |
NIIBE Yutaka | 04d0851cca | |
NIIBE Yutaka | e9e7b5425f | |
zhangguangzhi | 28a4d0d4f5 | |
zhangguangzhi | be77c05532 | |
Werner Koch | e16fc3e19c | |
Andre Heinecke | 3c57aee263 | |
NIIBE Yutaka | 5170c366ee | |
NIIBE Yutaka | 1b0ce9918c | |
NIIBE Yutaka | f5656ff363 | |
NIIBE Yutaka | 9433dfa5dd | |
Werner Koch | 22350d0768 | |
NIIBE Yutaka | ef4f22b9d9 | |
NIIBE Yutaka | 0fba0bbc62 | |
Werner Koch | 6ed61d98a0 | |
Werner Koch | 2783b786a9 | |
Werner Koch | a216e9c028 | |
Werner Koch | 1d23dc9389 | |
Werner Koch | ec0c35d1b8 | |
NIIBE Yutaka | f15a643a2d | |
Werner Koch | 09a96c9e1b | |
Werner Koch | e9dd47d789 | |
NIIBE Yutaka | 39a4373780 | |
NIIBE Yutaka | 6984ddc6eb | |
Werner Koch | 000b82ade7 | |
Werner Koch | 8295fb3f0b | |
Werner Koch | 3a438a1cc3 | |
Werner Koch | 42bea7de16 | |
Werner Koch | 7e681da1b2 | |
Werner Koch | 097701e698 | |
Werner Koch | faf0a97b2e | |
NIIBE Yutaka | 2f872fa68c | |
NIIBE Yutaka | b789ada2b0 | |
NIIBE Yutaka | d221062769 | |
NIIBE Yutaka | 86cdb49097 | |
NIIBE Yutaka | 5c7c6065f3 | |
Werner Koch | 23bb92b755 | |
NIIBE Yutaka | a035938216 | |
Werner Koch | 1e41878bf2 |
|
@ -2,3 +2,5 @@
|
|||
6a80d6f9206eae2c867c45daa5cd3e7d6c6ad114
|
||||
# doc: Fix spelling errors found by lintian.
|
||||
2ed1f68b48db7b5503045386de0500fddf70077e
|
||||
# indent: Re-indent a function
|
||||
869d1df270c0ccc3a9f792167b96d678a932b37e
|
||||
|
|
3
AUTHORS
3
AUTHORS
|
@ -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:
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ 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
|
||||
|
|
34
NEWS
34
NEWS
|
@ -1,3 +1,8 @@
|
|||
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)
|
||||
------------------------------------------------
|
||||
|
||||
|
@ -40,11 +45,8 @@ Noteworthy changes in version 2.4.5 (2024-03-07)
|
|||
|
||||
* Make the getswdb.sh tool usable outside the GnuPG tree.
|
||||
|
||||
Release-info: https://dev.gnupg.org/T6960
|
||||
|
||||
|
||||
Noteworthy changes in version 2.4.4 (2024-01-25)
|
||||
------------------------------------------------
|
||||
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
|
||||
|
@ -145,11 +147,7 @@ Noteworthy changes in version 2.4.4 (2024-01-25)
|
|||
* Improve the speedo build system for Unix. [T6710]
|
||||
|
||||
|
||||
Release-info: https://dev.gnupg.org/T6578
|
||||
|
||||
|
||||
Noteworthy changes in version 2.4.3 (2023-07-04)
|
||||
------------------------------------------------
|
||||
Changes also found in 2.4.3:
|
||||
|
||||
* gpg: Set default expiration date to 3 years. [T2701]
|
||||
|
||||
|
@ -198,12 +196,8 @@ Noteworthy changes in version 2.4.3 (2023-07-04)
|
|||
|
||||
* Fix garbled time output in non-English Windows. [T6741]
|
||||
|
||||
See-also: gnupg-announce/2023q3/000480.html
|
||||
Release-info: https://dev.gnupg.org/T6509
|
||||
|
||||
|
||||
Noteworthy changes in version 2.4.2 (2023-05-30)
|
||||
------------------------------------------------
|
||||
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]
|
||||
|
@ -225,8 +219,16 @@ Noteworthy changes in version 2.4.2 (2023-05-30)
|
|||
|
||||
* w32: Avoid using the VirtualStore. [T6403]
|
||||
|
||||
See-also: gnupg-announce/2023q2/000479.html
|
||||
Release-info: https://dev.gnupg.org/T6506
|
||||
|
||||
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)
|
||||
|
|
2
README
2
README
|
@ -1,6 +1,6 @@
|
|||
The GNU Privacy Guard
|
||||
=======================
|
||||
Version 2.4
|
||||
Version 2.5 (devel)
|
||||
|
||||
Copyright 1997-2019 Werner Koch
|
||||
Copyright 1998-2021 Free Software Foundation, Inc.
|
||||
|
|
|
@ -288,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. */
|
||||
|
@ -428,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,
|
||||
|
@ -533,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);
|
||||
|
@ -556,6 +560,18 @@ 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
|
||||
|
@ -689,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);
|
||||
|
@ -737,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,
|
||||
|
@ -758,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);
|
||||
|
||||
|
|
364
agent/cache.c
364
agent/cache.c
|
@ -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)
|
||||
|
|
|
@ -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,54 +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;
|
||||
}
|
||||
|
||||
assuan_set_flag (g->primary_ctx, ASSUAN_NO_WAITPID, 1);
|
||||
}
|
||||
#endif /*!HAVE_W32_SYSTEM*/
|
||||
|
||||
agent_flush_cache (1); /* Flush the PIN cache. */
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
@ -1288,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;
|
||||
|
@ -1302,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)
|
||||
{
|
||||
|
@ -1317,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;
|
||||
}
|
||||
|
@ -2124,7 +2113,6 @@ void
|
|||
agent_popup_message_stop (ctrl_t ctrl)
|
||||
{
|
||||
int rc;
|
||||
pid_t pid;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
|
@ -2137,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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -3952,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;
|
||||
|
|
|
@ -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;
|
||||
|
@ -796,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
|
||||
|
@ -805,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;
|
||||
}
|
||||
|
||||
|
@ -1043,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)
|
||||
{
|
||||
|
@ -1055,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);
|
||||
|
@ -1418,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)
|
||||
{
|
||||
|
|
|
@ -1384,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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -106,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 != '(')
|
||||
|
@ -125,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++;
|
||||
|
|
|
@ -161,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;
|
||||
|
@ -204,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)
|
||||
{
|
||||
|
@ -219,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);
|
||||
|
|
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -1050,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1057,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 ();
|
||||
|
@ -1085,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 ();
|
||||
|
||||
|
@ -1117,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 ();
|
||||
|
@ -1583,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)
|
||||
|
@ -1811,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;
|
||||
|
||||
|
@ -1837,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);
|
||||
}
|
||||
|
||||
|
@ -2139,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;
|
||||
}
|
||||
|
@ -2428,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
|
||||
|
@ -2537,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");
|
||||
|
@ -2574,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;
|
||||
|
@ -2874,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);
|
||||
|
@ -2954,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);
|
||||
|
@ -2968,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;
|
||||
|
@ -2985,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;
|
||||
|
@ -3018,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)
|
||||
|
@ -3034,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 ())))
|
||||
|
@ -3046,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). */
|
||||
|
@ -3075,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)
|
||||
{
|
||||
|
@ -3112,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
|
||||
|
@ -3149,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;
|
||||
|
||||
|
@ -3186,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. */
|
||||
|
@ -3198,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");
|
||||
|
@ -3227,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",
|
||||
|
@ -3268,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)
|
||||
|
@ -3285,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)
|
||||
{
|
||||
|
@ -3336,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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
};
|
||||
|
|
|
@ -43,58 +43,7 @@
|
|||
#
|
||||
# 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 GnuPG sources.
|
||||
# # This is greped by the Makefile.
|
||||
# RELEASE_SIGNKEY=6DAA6E64A76D2840571B4902528897B826403ADA
|
||||
#
|
||||
# # The key used to sign the VERSION files of some MSI installers.
|
||||
# VERSION_SIGNKEY=02F38DFF731FF97CB039A1DA549E695E905BA208
|
||||
#
|
||||
# # 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"
|
||||
#
|
||||
# # The URL for the timestamping service
|
||||
# AUTHENTICODE_TSURL=http://rfc3161timestamp.globalsign.com/advanced
|
||||
#
|
||||
# # 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.
|
||||
|
@ -124,6 +73,7 @@ help:
|
|||
@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.'
|
||||
|
@ -208,9 +158,12 @@ 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=
|
||||
|
||||
# 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
|
||||
|
||||
|
@ -231,6 +184,8 @@ TARBALLS=$(shell pwd)/../tarballs
|
|||
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.
|
||||
|
@ -246,14 +201,6 @@ PATCHELF := $(shell patchelf --version 2>/dev/null >/dev/null || echo "echo plea
|
|||
define READ_AUTOGEN_template
|
||||
$(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_TSURL))
|
||||
$(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))
|
||||
|
||||
|
||||
|
@ -330,7 +277,12 @@ 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 ($(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 = \
|
||||
|
@ -362,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)
|
||||
|
@ -409,7 +361,7 @@ 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 GpgRT ..........: $(libgpg_error_ver))
|
||||
$(info Npth ...........: $(npth_ver))
|
||||
|
@ -424,6 +376,21 @@ $(info GPGME ..........: $(gpgme_ver))
|
|||
$(info Pinentry .......: $(pinentry_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
|
||||
|
@ -514,8 +481,8 @@ speedo_pkg_gettext_tar = $(pkg2rep)/gettext-$(gettext_ver).tar.gz
|
|||
|
||||
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
|
||||
|
@ -651,12 +618,21 @@ 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
|
||||
|
||||
|
@ -698,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)
|
||||
|
@ -924,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}; \
|
||||
|
@ -1133,8 +1109,8 @@ ifneq ($(TARGETOS),w32)
|
|||
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/gnupg24" ;\
|
||||
echo "speedo: * ldconfig -n /usr/local/gnupg24/lib";\
|
||||
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
|
||||
|
||||
|
@ -1149,8 +1125,8 @@ ifneq ($(TARGETOS),w32)
|
|||
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/gnupg24";\
|
||||
echo "speedo: ldconfig -n /usr/local/gnupg24/lib";\
|
||||
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 \
|
||||
|
@ -1238,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
|
||||
|
||||
|
@ -1340,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";\
|
||||
|
@ -1351,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 '$(AUTHENTICODE_TSURL)' /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 $(AUTHENTICODE_TSURL) \
|
||||
-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 "$(AUTHENTICODE_TSURL)" \
|
||||
-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.
|
||||
|
|
|
@ -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}"
|
||||
|
@ -1465,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
|
||||
|
@ -1486,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"
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ common_sources = \
|
|||
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,11 +161,12 @@ 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-b64
|
||||
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
|
||||
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
299
common/b64dec.c
299
common/b64dec.c
|
@ -1,299 +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/>.
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
/* 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;
|
||||
struct b64state state;
|
||||
size_t nbytes;
|
||||
char *buffer;
|
||||
|
||||
*r_buffer = NULL;
|
||||
*r_buflen = 0;
|
||||
|
||||
buffer = xtrystrdup (string);
|
||||
if (!buffer)
|
||||
return gpg_error_from_syserror();
|
||||
|
||||
err = b64dec_start (&state, title);
|
||||
if (err)
|
||||
{
|
||||
xfree (buffer);
|
||||
return err;
|
||||
}
|
||||
b64dec_proc (&state, buffer, strlen (buffer), &nbytes);
|
||||
err = b64dec_finish (&state);
|
||||
if (err)
|
||||
xfree (buffer);
|
||||
else
|
||||
{
|
||||
*r_buffer = buffer;
|
||||
*r_buflen = nbytes;
|
||||
}
|
||||
return err;
|
||||
}
|
423
common/b64enc.c
423
common/b64enc.c
|
@ -1,423 +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/>.
|
||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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*/
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
586
common/homedir.c
586
common/homedir.c
|
@ -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.
|
||||
*
|
||||
|
@ -93,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
|
||||
|
@ -119,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
|
||||
|
@ -324,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);
|
||||
|
||||
|
@ -335,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*/
|
||||
}
|
||||
|
||||
|
@ -374,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)
|
||||
{
|
||||
|
@ -399,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;
|
||||
|
@ -427,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. */
|
||||
|
@ -439,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);
|
||||
|
@ -528,28 +856,14 @@ w32_rootdir (void)
|
|||
static const char *
|
||||
unix_rootdir (enum wantdir_values wantdir)
|
||||
{
|
||||
static int checked;
|
||||
static char *dir; /* for the rootdir */
|
||||
static char *sdir; /* for the sysconfdir */
|
||||
static char *s2dir; /* for the socketdir */
|
||||
|
||||
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;
|
||||
char *socketdir;
|
||||
const char *name;
|
||||
int ignoreall = 0;
|
||||
int okay;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
|
@ -589,7 +903,7 @@ unix_rootdir (enum wantdir_values wantdir)
|
|||
if (!*buffer)
|
||||
{
|
||||
xfree (buffer);
|
||||
checked = 1;
|
||||
gpgconf_ctl.checked = 1;
|
||||
return NULL; /* Error - assume no gpgconf.ctl. */
|
||||
}
|
||||
|
||||
|
@ -597,197 +911,36 @@ unix_rootdir (enum wantdir_values wantdir)
|
|||
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;
|
||||
socketdir = NULL;
|
||||
while ((length = es_read_line (fp, &line, &linelen, NULL)) > 0)
|
||||
{
|
||||
static const char *names[] =
|
||||
{
|
||||
"rootdir",
|
||||
"sysconfdir",
|
||||
"socketdir",
|
||||
".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);
|
||||
/* Find the stamement. */
|
||||
name = 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; /* Statement 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 (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 if (!strcmp (name, "socketdir"))
|
||||
{
|
||||
xfree (socketdir);
|
||||
socketdir = 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);
|
||||
xfree (socketdir);
|
||||
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);
|
||||
|
||||
okay = 0;
|
||||
if (ignoreall)
|
||||
;
|
||||
else if (!rootdir || !*rootdir || *rootdir != '/')
|
||||
{
|
||||
log_info ("invalid rootdir '%s' specified in gpgconf.ctl\n", rootdir);
|
||||
}
|
||||
else if (sysconfdir && (!*sysconfdir || *sysconfdir != '/'))
|
||||
{
|
||||
log_info ("invalid sysconfdir '%s' specified in gpgconf.ctl\n",
|
||||
sysconfdir);
|
||||
}
|
||||
else if (socketdir && (!*socketdir || *socketdir != '/'))
|
||||
{
|
||||
log_info ("invalid socketdir '%s' specified in gpgconf.ctl\n",
|
||||
socketdir);
|
||||
}
|
||||
else
|
||||
{
|
||||
okay = 1;
|
||||
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); */
|
||||
}
|
||||
if (socketdir)
|
||||
{
|
||||
while (*socketdir && socketdir[strlen (socketdir)-1] == '/')
|
||||
socketdir[strlen (socketdir)-1] = 0;
|
||||
s2dir = socketdir;
|
||||
gpgrt_annotate_leaked_object (s2dir);
|
||||
/* log_info ("want socketdir '%s'\n", s2dir); */
|
||||
}
|
||||
}
|
||||
|
||||
if (!okay)
|
||||
{
|
||||
xfree (rootdir);
|
||||
xfree (sysconfdir);
|
||||
xfree (socketdir);
|
||||
dir = sdir = s2dir = NULL;
|
||||
}
|
||||
checked = 1;
|
||||
}
|
||||
|
||||
if (!gpgconf_ctl.valid)
|
||||
return NULL; /* No valid entries in gpgconf.ctl */
|
||||
|
||||
switch (wantdir)
|
||||
{
|
||||
case WANTDIR_ROOT: return dir;
|
||||
case WANTDIR_SYSCONF: return sdir;
|
||||
case WANTDIR_SOCKET: return s2dir;
|
||||
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. */
|
||||
|
@ -982,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
|
||||
{
|
||||
|
@ -993,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");
|
||||
|
@ -1101,10 +1254,11 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
|
|||
};
|
||||
int i;
|
||||
struct stat sb;
|
||||
char prefixbuffer[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;
|
||||
|
||||
|
@ -1143,12 +1297,13 @@ _gnupg_socketdir_internal (int skip_checks, unsigned *r_info)
|
|||
goto leave;
|
||||
}
|
||||
|
||||
if (strlen (prefix) + 7 >= sizeof prefixbuffer)
|
||||
if (strlen (prefix) + strlen (gnupgname) + 2 >= sizeof prefixbuffer)
|
||||
{
|
||||
*r_info |= 1; /* Ooops: Buffer too short to append "/gnupg". */
|
||||
goto leave;
|
||||
}
|
||||
strcat (prefixbuffer, "/gnupg");
|
||||
strcat (prefixbuffer, "/");
|
||||
strcat (prefixbuffer, gnupgname);
|
||||
}
|
||||
|
||||
/* Check whether the gnupg sub directory (or the specified diretory)
|
||||
|
@ -1303,11 +1458,8 @@ 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;
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
# include <winsock2.h>
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# include <wctype.h>
|
||||
#endif
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
|
|
@ -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,
|
||||
|
@ -389,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 */
|
||||
|
@ -696,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);
|
||||
}
|
||||
|
@ -1410,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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1423,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);
|
||||
|
@ -1447,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)
|
||||
|
@ -1472,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;
|
||||
}
|
||||
|
@ -1497,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);
|
||||
|
@ -1525,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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1585,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;
|
||||
}
|
||||
|
@ -2644,20 +2642,20 @@ iobuf_get_filelength (iobuf_t a)
|
|||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2948,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)
|
||||
|
|
|
@ -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
|
||||
|
@ -590,7 +590,7 @@ uint64_t iobuf_get_filelength (iobuf_t a);
|
|||
|
||||
/* 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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
@ -687,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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,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;
|
||||
|
@ -206,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. */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
@ -351,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)
|
||||
|
@ -537,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)
|
||||
|
@ -552,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
|
||||
}
|
||||
|
||||
|
@ -594,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
|
||||
|
@ -1158,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;
|
||||
|
||||
|
@ -1175,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*/
|
||||
}
|
||||
|
@ -1199,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;
|
||||
|
@ -1829,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);
|
||||
}
|
||||
|
|
|
@ -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,6 +119,7 @@ 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
|
||||
int gnupg_w32_set_errno (int ec);
|
||||
|
|
283
common/t-b64.c
283
common/t-b64.c
|
@ -1,283 +0,0 @@
|
|||
/* t-b64.c - Module tests for b64enc.c and b64dec.c
|
||||
* Copyright (C) 2008 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2008, 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 "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)
|
||||
#define oops() do { fprintf (stderr, "%s:%d: ooops\n", \
|
||||
__FILE__,__LINE__); \
|
||||
exit (2); \
|
||||
} while(0)
|
||||
|
||||
static int verbose;
|
||||
static int errcount;
|
||||
|
||||
|
||||
/* Convert STRING consisting of hex characters into its binary
|
||||
* representation and return it as an allocated buffer. The valid
|
||||
* length of the buffer is returned at R_LENGTH. The string is
|
||||
* delimited by end of string. The function returns NULL on
|
||||
* error. */
|
||||
static void *
|
||||
hex2buffer (const char *string, size_t *r_length)
|
||||
{
|
||||
const char *s;
|
||||
unsigned char *buffer;
|
||||
size_t length;
|
||||
|
||||
buffer = xmalloc (strlen(string)/2+1);
|
||||
length = 0;
|
||||
for (s=string; *s; s +=2 )
|
||||
{
|
||||
if (!hexdigitp (s) || !hexdigitp (s+1))
|
||||
return NULL; /* Invalid hex digits. */
|
||||
((unsigned char*)buffer)[length++] = xtoi_2 (s);
|
||||
}
|
||||
*r_length = length;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_b64decode (void)
|
||||
{
|
||||
static struct {
|
||||
const char *string; /* String to test. */
|
||||
const char *title; /* title parameter. */
|
||||
gpg_error_t err; /* expected error. */
|
||||
const char *datastr; /* Expected data (hex encoded) */
|
||||
} tests[] = {
|
||||
{ "YQ==", NULL, 0,
|
||||
"61" },
|
||||
{ "YWE==", NULL, 0,
|
||||
"6161" },
|
||||
{ "YWFh", NULL, 0,
|
||||
"616161" },
|
||||
{ "YWFhYQ==", NULL, 0,
|
||||
"61616161" },
|
||||
{ "YWJjZA==", NULL, 0,
|
||||
"61626364" },
|
||||
{ "AA=", NULL, 0,
|
||||
"00" },
|
||||
{ "AAEA=", NULL, 0,
|
||||
"000100" },
|
||||
{ "/w==", NULL, 0,
|
||||
"ff" },
|
||||
{ "oRQwEqADCgEDoQsGCSqGSIL3EgECAg==", NULL, 0,
|
||||
"a1143012a0030a0103a10b06092a864882f712010202" },
|
||||
{ "oRQwEqADCgEDoQsGCSqGSIL3EgECA-==", NULL, GPG_ERR_BAD_DATA,
|
||||
"a1143012a0030a0103a10b06092a864882f712010202" },
|
||||
{ "oRQwEqADCgEDoQsGCSqGSIL3EgECAg==", "", 0,
|
||||
"" },
|
||||
{ "-----BEGIN PGP\n\n"
|
||||
"oRQwEqADCgEDoQsGCSqGSIL3EgECAg==\n"
|
||||
"-----END PGP\n", "", 0,
|
||||
"a1143012a0030a0103a10b06092a864882f712010202" },
|
||||
|
||||
{ "", NULL, 0,
|
||||
"" }
|
||||
};
|
||||
int tidx;
|
||||
gpg_error_t err;
|
||||
void *data = NULL;
|
||||
size_t datalen;
|
||||
char *wantdata = NULL;
|
||||
size_t wantdatalen;
|
||||
|
||||
for (tidx = 0; tidx < DIM(tests); tidx++)
|
||||
{
|
||||
xfree (wantdata);
|
||||
if (!(wantdata = hex2buffer (tests[tidx].datastr, &wantdatalen)))
|
||||
oops ();
|
||||
xfree (data);
|
||||
err = b64decode (tests[tidx].string, tests[tidx].title, &data, &datalen);
|
||||
if (verbose)
|
||||
fprintf (stderr, "%s:%d: test %d, err=%d, datalen=%zu\n",
|
||||
__FILE__, __LINE__, tidx, err, datalen);
|
||||
if (gpg_err_code (err) != tests[tidx].err)
|
||||
fail (tidx);
|
||||
else if (err)
|
||||
pass ();
|
||||
else if (wantdatalen != datalen)
|
||||
fail (tidx);
|
||||
else if (memcmp (wantdata, data, datalen))
|
||||
fail (tidx);
|
||||
else
|
||||
pass ();
|
||||
}
|
||||
xfree (wantdata);
|
||||
xfree (data);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
int do_pgpdecode = 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++;
|
||||
}
|
||||
else if (argc)
|
||||
do_pgpdecode = 1;
|
||||
|
||||
if (do_encode)
|
||||
test_b64enc_file (argc? *argv: NULL);
|
||||
else if (do_decode)
|
||||
test_b64dec_file (argc? *argv: NULL);
|
||||
else if (do_pgpdecode)
|
||||
test_b64enc_pgp (argc? *argv: NULL);
|
||||
else
|
||||
test_b64decode ();
|
||||
|
||||
return !!errcount;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -149,36 +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);
|
||||
gpg_error_t b64decode (const char *string, const char *title,
|
||||
void **r_buffer, size_t *r_buflen);
|
||||
|
||||
/*-- sexputil.c */
|
||||
char *canon_sexp_to_string (const unsigned char *canon, size_t canonlen);
|
||||
void log_printcanon (const char *text,
|
||||
|
@ -226,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);
|
||||
|
@ -257,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,
|
||||
|
@ -274,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);
|
||||
|
@ -328,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
|
||||
|
@ -388,6 +374,10 @@ 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. */
|
||||
|
||||
|
|
14
configure.ac
14
configure.ac
|
@ -28,8 +28,8 @@ min_automake_version="1.16.3"
|
|||
# another commit and push so that the git magic is able to work.
|
||||
m4_define([mym4_package],[gnupg])
|
||||
m4_define([mym4_major], [2])
|
||||
m4_define([mym4_minor], [4])
|
||||
m4_define([mym4_micro], [5])
|
||||
m4_define([mym4_minor], [5])
|
||||
m4_define([mym4_micro], [0])
|
||||
|
||||
# To start a new development series, i.e a new major or minor number
|
||||
# you need to mark an arbitrary commit before the first beta release
|
||||
|
@ -53,15 +53,15 @@ AC_INIT([mym4_package],[mym4_version],[https://bugs.gnupg.org])
|
|||
# When changing the SWDB tag please also adjust the hard coded tags in
|
||||
# build-aux/speedo.mk, build-aux/getswdb.sh, and Makefile.am
|
||||
# As well as the source info for the man pages.
|
||||
AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg24", [swdb tag for this branch])
|
||||
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
|
||||
|
@ -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" \
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -394,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;
|
||||
|
||||
|
@ -450,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 )
|
||||
{
|
||||
|
@ -980,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
|
||||
|
@ -1335,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.
|
||||
|
||||
|
@ -2233,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;
|
||||
}
|
||||
|
@ -2267,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)
|
||||
|
@ -2275,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);
|
||||
|
@ -2378,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);
|
||||
|
@ -2395,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
|
||||
|
@ -2479,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));
|
||||
|
@ -2494,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);
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -441,7 +441,7 @@ _my_socket_new (int lnr, assuan_fd_t fd)
|
|||
so->refcount = 1;
|
||||
if (opt_debug)
|
||||
log_debug ("http.c:%d:socket_new: object %p for fd %d created\n",
|
||||
lnr, so, (int)so->fd);
|
||||
lnr, so, FD_DBG (so->fd));
|
||||
return so;
|
||||
}
|
||||
#define my_socket_new(a) _my_socket_new (__LINE__, (a))
|
||||
|
@ -453,7 +453,7 @@ _my_socket_ref (int lnr, my_socket_t so)
|
|||
so->refcount++;
|
||||
if (opt_debug > 1)
|
||||
log_debug ("http.c:%d:socket_ref: object %p for fd %d refcount now %d\n",
|
||||
lnr, so, (int)so->fd, so->refcount);
|
||||
lnr, so, FD_DBG (so->fd), so->refcount);
|
||||
return so;
|
||||
}
|
||||
#define my_socket_ref(a) _my_socket_ref (__LINE__,(a))
|
||||
|
@ -471,7 +471,7 @@ _my_socket_unref (int lnr, my_socket_t so,
|
|||
so->refcount--;
|
||||
if (opt_debug > 1)
|
||||
log_debug ("http.c:%d:socket_unref: object %p for fd %d ref now %d\n",
|
||||
lnr, so, (int)so->fd, so->refcount);
|
||||
lnr, so, FD_DBG (so->fd), so->refcount);
|
||||
|
||||
if (!so->refcount)
|
||||
{
|
||||
|
@ -2200,7 +2200,7 @@ run_ntbtls_handshake (http_t hd)
|
|||
/* Until we support send/recv in estream under Windows we need
|
||||
* to use es_fopencookie. */
|
||||
# ifdef HAVE_W32_SYSTEM
|
||||
in = es_fopencookie ((void*)(unsigned int)hd->sock->fd, "rb",
|
||||
in = es_fopencookie (hd->sock->fd, "rb",
|
||||
simple_cookie_functions);
|
||||
# else
|
||||
in = es_fdopen_nc (hd->sock->fd, "rb");
|
||||
|
@ -2212,7 +2212,7 @@ run_ntbtls_handshake (http_t hd)
|
|||
}
|
||||
|
||||
# ifdef HAVE_W32_SYSTEM
|
||||
out = es_fopencookie ((void*)(unsigned int)hd->sock->fd, "wb",
|
||||
out = es_fopencookie (hd->sock->fd, "wb",
|
||||
simple_cookie_functions);
|
||||
# else
|
||||
out = es_fdopen_nc (hd->sock->fd, "wb");
|
||||
|
@ -3571,7 +3571,7 @@ connect_with_timeout (assuan_fd_t sock,
|
|||
tval.tv_sec = timeout / 1000;
|
||||
tval.tv_usec = (timeout % 1000) * 1000;
|
||||
|
||||
n = my_select (FD2INT(sock)+1, &rset, &wset, NULL, &tval);
|
||||
n = my_select (FD2NUM(sock)+1, &rset, &wset, NULL, &tval);
|
||||
if (n < 0)
|
||||
{
|
||||
err = gpg_err_make (default_errsource, gpg_err_code_from_syserror ());
|
||||
|
|
|
@ -373,6 +373,8 @@ ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
|
|||
|| !strcmp (uri->parsed_uri->scheme, "ldaps")
|
||||
|| !strcmp (uri->parsed_uri->scheme, "ldapi")
|
||||
|| uri->parsed_uri->opaque);
|
||||
#else
|
||||
(void)newer;
|
||||
#endif
|
||||
|
||||
if (is_hkp_s || is_http_s || is_ldap)
|
||||
|
@ -590,6 +592,13 @@ ks_action_query (ctrl_t ctrl, const char *url, unsigned int ks_get_flags,
|
|||
return err;
|
||||
|
||||
#else /* !USE_LDAP */
|
||||
(void)ctrl;
|
||||
(void)url;
|
||||
(void)ks_get_flags;
|
||||
(void)filter;
|
||||
(void)attrs;
|
||||
(void)newer;
|
||||
(void)outfp;
|
||||
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
# define WINVER 0x0500 /* Same as in common/sysutils.c */
|
||||
# endif
|
||||
# include <winsock2.h>
|
||||
# include <winldap.h>
|
||||
# include <winber.h>
|
||||
# include <sddl.h>
|
||||
#endif
|
||||
|
||||
|
|
|
@ -87,7 +87,7 @@ struct wrapper_context_s
|
|||
{
|
||||
struct wrapper_context_s *next;
|
||||
|
||||
pid_t pid; /* The pid of the wrapper process. */
|
||||
gnupg_process_t proc;/* The wrapper process. */
|
||||
int printable_pid; /* Helper to print diagnostics after the process has
|
||||
* been cleaned up. */
|
||||
estream_t fp; /* Connected with stdout of the ldap wrapper. */
|
||||
|
@ -170,10 +170,10 @@ read_buffer (ksba_reader_t reader, unsigned char *buffer, size_t count)
|
|||
static void
|
||||
destroy_wrapper (struct wrapper_context_s *ctx)
|
||||
{
|
||||
if (ctx->pid != (pid_t)(-1))
|
||||
if (ctx->proc)
|
||||
{
|
||||
gnupg_kill_process (ctx->pid);
|
||||
gnupg_release_process (ctx->pid);
|
||||
gnupg_process_terminate (ctx->proc);
|
||||
gnupg_process_release (ctx->proc);
|
||||
}
|
||||
ksba_reader_release (ctx->reader);
|
||||
SAFE_CLOSE (ctx->fp);
|
||||
|
@ -260,7 +260,7 @@ read_log_data (struct wrapper_context_s *ctx)
|
|||
if (gpg_err_code (err) == GPG_ERR_EAGAIN)
|
||||
return 0;
|
||||
log_error (_("error reading log from ldap wrapper %d: %s\n"),
|
||||
(int)ctx->pid, gpg_strerror (err));
|
||||
ctx->printable_pid, gpg_strerror (err));
|
||||
}
|
||||
print_log_line (ctx, NULL); /* Flush. */
|
||||
SAFE_CLOSE (ctx->log_fp);
|
||||
|
@ -438,50 +438,44 @@ ldap_reaper_thread (void *dummy)
|
|||
}
|
||||
|
||||
/* Check whether the process is still running. */
|
||||
if (ctx->pid != (pid_t)(-1))
|
||||
if (ctx->proc)
|
||||
{
|
||||
int status;
|
||||
|
||||
err = gnupg_wait_process ("[dirmngr_ldap]", ctx->pid, 0,
|
||||
&status);
|
||||
err = gnupg_process_wait (ctx->proc, 0);
|
||||
if (!err)
|
||||
{
|
||||
int status;
|
||||
|
||||
gnupg_process_ctl (ctx->proc, GNUPG_PROCESS_GET_EXIT_ID,
|
||||
&status);
|
||||
if (DBG_EXTPROG)
|
||||
log_info (_("ldap wrapper %d ready"), (int)ctx->pid);
|
||||
log_info (_("ldap wrapper %d ready"), ctx->printable_pid);
|
||||
ctx->ready = 1;
|
||||
gnupg_release_process (ctx->pid);
|
||||
ctx->pid = (pid_t)(-1);
|
||||
gnupg_process_release (ctx->proc);
|
||||
ctx->proc = NULL;
|
||||
any_action = 1;
|
||||
}
|
||||
else if (gpg_err_code (err) == GPG_ERR_GENERAL)
|
||||
{
|
||||
|
||||
if (status == 10)
|
||||
log_info (_("ldap wrapper %d ready: timeout\n"),
|
||||
(int)ctx->pid);
|
||||
ctx->printable_pid);
|
||||
else
|
||||
log_info (_("ldap wrapper %d ready: exitcode=%d\n"),
|
||||
(int)ctx->pid, status);
|
||||
ctx->ready = 1;
|
||||
gnupg_release_process (ctx->pid);
|
||||
ctx->pid = (pid_t)(-1);
|
||||
any_action = 1;
|
||||
ctx->printable_pid, status);
|
||||
}
|
||||
else if (gpg_err_code (err) != GPG_ERR_TIMEOUT)
|
||||
{
|
||||
log_error (_("waiting for ldap wrapper %d failed: %s\n"),
|
||||
(int)ctx->pid, gpg_strerror (err));
|
||||
ctx->printable_pid, gpg_strerror (err));
|
||||
any_action = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check whether we should terminate the process. */
|
||||
if (ctx->pid != (pid_t)(-1)
|
||||
&& ctx->stamp != (time_t)(-1) && ctx->stamp < exptime)
|
||||
if (ctx->proc && ctx->stamp != (time_t)(-1) && ctx->stamp < exptime)
|
||||
{
|
||||
gnupg_kill_process (ctx->pid);
|
||||
gnupg_process_terminate (ctx->proc);
|
||||
ctx->stamp = (time_t)(-1);
|
||||
log_info (_("ldap wrapper %d stalled - killing\n"),
|
||||
(int)ctx->pid);
|
||||
ctx->printable_pid);
|
||||
/* We need to close the log stream because the cleanup
|
||||
* loop waits for it. */
|
||||
SAFE_CLOSE (ctx->log_fp);
|
||||
|
@ -496,10 +490,10 @@ ldap_reaper_thread (void *dummy)
|
|||
{
|
||||
log_debug ("ldap worker states:\n");
|
||||
for (ctx = reaper_list; ctx; ctx = ctx->next)
|
||||
log_debug (" c=%p pid=%d/%d rdr=%p logfp=%p"
|
||||
log_debug (" c=%p pid=%d rdr=%p logfp=%p"
|
||||
" ctrl=%p/%d la=%lu rdy=%d\n",
|
||||
ctx,
|
||||
(int)ctx->pid, (int)ctx->printable_pid,
|
||||
ctx->printable_pid,
|
||||
ctx->reader, ctx->log_fp,
|
||||
ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0,
|
||||
(unsigned long)ctx->stamp, ctx->ready);
|
||||
|
@ -602,9 +596,9 @@ ldap_wrapper_release_context (ksba_reader_t reader)
|
|||
if (ctx->reader == reader)
|
||||
{
|
||||
if (DBG_EXTPROG)
|
||||
log_debug ("releasing ldap worker c=%p pid=%d/%d rdr=%p"
|
||||
log_debug ("releasing ldap worker c=%p pid=%d rdr=%p"
|
||||
" ctrl=%p/%d\n", ctx,
|
||||
(int)ctx->pid, (int)ctx->printable_pid,
|
||||
ctx->printable_pid,
|
||||
ctx->reader,
|
||||
ctx->ctrl, ctx->ctrl? ctx->ctrl->refcount:0);
|
||||
|
||||
|
@ -639,8 +633,8 @@ ldap_wrapper_connection_cleanup (ctrl_t ctrl)
|
|||
{
|
||||
ctx->ctrl->refcount--;
|
||||
ctx->ctrl = NULL;
|
||||
if (ctx->pid != (pid_t)(-1))
|
||||
gnupg_kill_process (ctx->pid);
|
||||
if (ctx->proc)
|
||||
gnupg_process_terminate (ctx->proc);
|
||||
if (ctx->fp_err)
|
||||
log_info ("%s: reading from ldap wrapper %d failed: %s\n",
|
||||
__func__, ctx->printable_pid, gpg_strerror (ctx->fp_err));
|
||||
|
@ -798,7 +792,7 @@ gpg_error_t
|
|||
ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
|
||||
{
|
||||
gpg_error_t err;
|
||||
pid_t pid;
|
||||
gnupg_process_t process;
|
||||
struct wrapper_context_s *ctx;
|
||||
int i;
|
||||
int j;
|
||||
|
@ -854,19 +848,22 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
|
|||
return err;
|
||||
}
|
||||
|
||||
err = gnupg_spawn_process (pgmname, arg_list,
|
||||
NULL, GNUPG_SPAWN_NONBLOCK,
|
||||
NULL, &outfp, &errfp, &pid);
|
||||
err = gnupg_process_spawn (pgmname, arg_list,
|
||||
(GNUPG_PROCESS_STDOUT_PIPE
|
||||
| GNUPG_PROCESS_STDERR_PIPE),
|
||||
NULL, NULL, &process);
|
||||
if (err)
|
||||
{
|
||||
xfree (arg_list);
|
||||
xfree (arg_list);
|
||||
xfree (ctx);
|
||||
log_error ("error running '%s': %s\n", pgmname, gpg_strerror (err));
|
||||
return err;
|
||||
}
|
||||
gnupg_process_get_streams (process, GNUPG_PROCESS_STREAM_NONBLOCK,
|
||||
NULL, &outfp, &errfp);
|
||||
gnupg_process_ctl (process, GNUPG_PROCESS_GET_PROC_ID, &ctx->printable_pid);
|
||||
|
||||
ctx->pid = pid;
|
||||
ctx->printable_pid = (int) pid;
|
||||
ctx->proc = process;
|
||||
ctx->fp = outfp;
|
||||
ctx->log_fp = errfp;
|
||||
ctx->ctrl = ctrl;
|
||||
|
@ -902,7 +899,7 @@ ldap_wrapper (ctrl_t ctrl, ksba_reader_t *reader, const char *argv[])
|
|||
if (DBG_EXTPROG)
|
||||
{
|
||||
log_debug ("ldap wrapper %d started (%p, %s)",
|
||||
(int)ctx->pid, ctx->reader, pgmname);
|
||||
ctx->printable_pid, ctx->reader, pgmname);
|
||||
for (i=0; arg_list[i]; i++)
|
||||
log_printf (" [%s]", arg_list[i]);
|
||||
log_printf ("\n");
|
||||
|
|
|
@ -583,7 +583,7 @@ gpg_error_t
|
|||
armor_data (char **r_string, const void *data, size_t datalen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
struct b64state b64state;
|
||||
gpgrt_b64state_t b64state;
|
||||
estream_t fp;
|
||||
long length;
|
||||
char *buffer;
|
||||
|
@ -595,9 +595,15 @@ armor_data (char **r_string, const void *data, size_t datalen)
|
|||
if (!fp)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK"))
|
||||
|| (err=b64enc_write (&b64state, data, datalen))
|
||||
|| (err = b64enc_finish (&b64state)))
|
||||
b64state = gpgrt_b64enc_start (fp, "PGP PUBLIC KEY BLOCK");
|
||||
if (!b64state)
|
||||
{
|
||||
es_fclose (fp);
|
||||
return gpg_error_from_syserror ();
|
||||
}
|
||||
|
||||
if ((err = gpgrt_b64enc_write (b64state, data, datalen))
|
||||
|| (err = gpgrt_b64enc_finish (b64state)))
|
||||
{
|
||||
es_fclose (fp);
|
||||
return err;
|
||||
|
|
13
doc/DETAILS
13
doc/DETAILS
|
@ -167,11 +167,13 @@ described here.
|
|||
|
||||
The value is quoted like a C string to avoid control characters
|
||||
(the colon is quoted =\x3a=). For a "pub" record this field is
|
||||
not used on --fixed-list-mode. A UAT record puts the attribute
|
||||
not used on --fixed-list-mode. A "uat" record puts the attribute
|
||||
subpacket count here, a space, and then the total attribute
|
||||
subpacket size. In gpgsm the issuer name comes here. The FPR and FP2
|
||||
records store the fingerprints here. The fingerprint of a
|
||||
revocation key is stored here.
|
||||
subpacket size. In gpgsm the issuer name comes here. The FPR and
|
||||
FP2 records store the fingerprints here. The fingerprint of a
|
||||
revocation key is also stored here. A "grp" records puts the
|
||||
keygrip here; for combined algorithms the keygrips are delimited
|
||||
by comma.
|
||||
|
||||
*** Field 11 - Signature class
|
||||
|
||||
|
@ -243,7 +245,8 @@ described here.
|
|||
*** Field 17 - Curve name
|
||||
|
||||
For pub, sub, sec, ssb, crt, and crs records this field is used
|
||||
for the ECC curve name.
|
||||
for the ECC curve name. For combined algorithms the first and the
|
||||
second algorithm name, delimited by an underscore are put here.
|
||||
|
||||
*** Field 18 - Compliance flags
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ EXTRA_DIST = samplekeys.asc mksamplekeys com-certs.pem \
|
|||
FAQ gnupg7.texi mkdefsinc.c defsincdate \
|
||||
opt-homedir.texi see-also-note.texi specify-user-id.texi \
|
||||
gpgv.texi yat2m.c ChangeLog-2011 whats-new-in-2.1.txt \
|
||||
trust-values.texi
|
||||
trust-values.texi keyformat.txt
|
||||
|
||||
BUILT_SOURCES = gnupg-module-overview.png gnupg-module-overview.pdf \
|
||||
gnupg-card-architecture.png gnupg-card-architecture.pdf \
|
||||
|
|
|
@ -91,7 +91,7 @@ should not occur but sometimes things go wrong), run it using
|
|||
@item How to find the IP address of a keyserver
|
||||
|
||||
If a round robin URL of is used for a keyserver
|
||||
(e.g. subkeys.gnupg.org); it is not easy to see what server is actually
|
||||
(e.g., subkeys.gnupg.org); it is not easy to see what server is actually
|
||||
used. Using the keyserver debug option as in
|
||||
|
||||
@smallexample
|
||||
|
@ -130,7 +130,7 @@ but Dirmngr's OCSP feature has not been enabled using
|
|||
The far most common reason for this is that the environment variable
|
||||
@code{GPG_TTY} has not been set correctly. Make sure that it has been
|
||||
set to a real tty device and not just to @samp{/dev/tty};
|
||||
i.e. @samp{GPG_TTY=tty} is plainly wrong; what you want is
|
||||
i.e., @samp{GPG_TTY=tty} is plainly wrong; what you want is
|
||||
@samp{GPG_TTY=`tty`} --- note the back ticks. Also make sure that
|
||||
this environment variable gets exported, that is you should follow up
|
||||
the setting with an @samp{export GPG_TTY} (assuming a Bourne style
|
||||
|
|
|
@ -213,7 +213,7 @@ however carefully selected to best aid in debugging.
|
|||
@item --debug @var{flags}
|
||||
@opindex debug
|
||||
Set debug flags. All flags are or-ed and @var{flags} may be given in
|
||||
C syntax (e.g. 0x0042) or as a comma separated list of flag names. To
|
||||
C syntax (e.g., 0x0042) or as a comma separated list of flag names. To
|
||||
get a list of all supported flags the single word "help" can be used.
|
||||
This option is only useful for debugging and the behavior may change
|
||||
at any time without notice.
|
||||
|
@ -295,7 +295,7 @@ seconds.
|
|||
@opindex connect-quick-timeout
|
||||
Set the timeout for HTTP and generic TCP connection attempts to N
|
||||
seconds. The value set with the quick variant is used when the
|
||||
--quick option has been given to certain Assuan commands. The quick
|
||||
@option{--quick} option has been given to certain Assuan commands. The quick
|
||||
value is capped at the value of the regular connect timeout. The
|
||||
default values are 15 and 2 seconds. Note that the timeout values are
|
||||
for each connection attempt; the connection code will attempt to
|
||||
|
@ -375,7 +375,7 @@ there for details; here is an example:
|
|||
as given. Replace USERNAME, PASSWORD, and the 'dc' parts
|
||||
according to the instructions received from your LDAP
|
||||
administrator. Note that only simple authentication
|
||||
(i.e. cleartext passwords) is supported and thus using ldaps is
|
||||
(i.e., cleartext passwords) is supported and thus using ldaps is
|
||||
strongly suggested (since 2.2.28 "ldaps" defaults to port 389
|
||||
and uses STARTTLS). On Windows authentication via AD can be
|
||||
requested by adding @code{gpgNtds=1} after the fourth question
|
||||
|
@ -468,7 +468,7 @@ Lines starting with a @samp{#} are comments.
|
|||
Note that as usual all strings entered are expected to be UTF-8 encoded.
|
||||
Obviously this will lead to problems if the password has originally been
|
||||
encoded as Latin-1. There is no other solution here than to put such a
|
||||
password in the binary encoding into the file (i.e. non-ascii characters
|
||||
password in the binary encoding into the file (i.e., non-ascii characters
|
||||
won't show up readable).@footnote{The @command{gpgconf} tool might be
|
||||
helpful for frontends as it enables editing this configuration file using
|
||||
percent-escaped strings.}
|
||||
|
@ -684,7 +684,7 @@ those certificates on startup and when given a SIGHUP. Certificates
|
|||
which are not readable or do not make up a proper X.509 certificate
|
||||
are ignored; see the log file for details.
|
||||
|
||||
Applications using dirmngr (e.g. gpgsm) can request these
|
||||
Applications using dirmngr (e.g., gpgsm) can request these
|
||||
certificates to complete a trust chain in the same way as with the
|
||||
extra-certs directory (see below).
|
||||
|
||||
|
@ -693,7 +693,7 @@ Note that for OCSP responses the certificate specified using the option
|
|||
|
||||
@item /etc/gnupg/extra-certs
|
||||
This directory may contain extra certificates which are preloaded
|
||||
into the internal cache on startup. Applications using dirmngr (e.g. gpgsm)
|
||||
into the internal cache on startup. Applications using dirmngr (e.g., gpgsm)
|
||||
can request cached certificates to complete a trust chain.
|
||||
This is convenient in cases you have a couple intermediate CA certificates
|
||||
or certificates usually used to sign OCSP responses.
|
||||
|
@ -752,7 +752,7 @@ certificate exists it is used to access the special keyservers
|
|||
|
||||
Please note that @command{gpgsm} accepts Root CA certificates for its
|
||||
own purposes only if they are listed in its file @file{trustlist.txt}.
|
||||
@command{dirmngr} does not make use of this list - except FIXME.
|
||||
@command{dirmngr} does not make use of this list --- except FIXME.
|
||||
|
||||
|
||||
@mansect notes
|
||||
|
@ -802,7 +802,7 @@ Enter @code{HELP} at the prompt to see a list of commands and enter
|
|||
@node Dirmngr Signals
|
||||
@section Use of signals
|
||||
|
||||
A running @command{dirmngr} may be controlled by signals, i.e. using
|
||||
A running @command{dirmngr} may be controlled by signals, i.e., using
|
||||
the @command{kill} command to send a signal to the process.
|
||||
|
||||
Here is a list of supported signals:
|
||||
|
@ -1034,7 +1034,7 @@ includes a local certificate store as well as a list of trusted root
|
|||
certificates.
|
||||
|
||||
@noindent
|
||||
The return code is 0 for success; i.e. the certificate has not been
|
||||
The return code is 0 for success; i.e., the certificate has not been
|
||||
revoked or one of the usual error codes from libgpg-error.
|
||||
|
||||
@node Dirmngr CHECKOCSP
|
||||
|
@ -1069,7 +1069,7 @@ of the global option @option{--ignore-ocsp-service-url}.
|
|||
|
||||
|
||||
@noindent
|
||||
The return code is 0 for success; i.e. the certificate has not been
|
||||
The return code is 0 for success; i.e., the certificate has not been
|
||||
revoked or one of the usual error codes from libgpg-error.
|
||||
|
||||
@node Dirmngr CACHECERT
|
||||
|
@ -1091,7 +1091,7 @@ Thus the caller is expected to return the certificate for the request
|
|||
as a binary blob.
|
||||
|
||||
@noindent
|
||||
The return code is 0 for success; i.e. the certificate has not been
|
||||
The return code is 0 for success; i.e., the certificate has not been
|
||||
successfully cached or one of the usual error codes from libgpg-error.
|
||||
|
||||
@node Dirmngr VALIDATE
|
||||
|
@ -1191,7 +1191,7 @@ as a binary blob.
|
|||
@c does not yet end up in memory.
|
||||
@c * @code{crl_cache_insert} is called with that descriptor to
|
||||
@c actually read the CRL into the cache. See below for a
|
||||
@c description of this function. If there is any error (e.g. read
|
||||
@c description of this function. If there is any error (e.g., read
|
||||
@c problem, CRL not correctly signed or verification of signature
|
||||
@c not possible), this descriptor is rejected and we continue
|
||||
@c with the next name. If the CRL has been successfully loaded,
|
||||
|
@ -1217,7 +1217,7 @@ as a binary blob.
|
|||
@c a) An authorityKeyIdentifier with an issuer and serialno exits: The
|
||||
@c certificate is retrieved using @code{find_cert_bysn}. If
|
||||
@c the certificate is in the certificate cache, it is directly
|
||||
@c returned. Then the requester (i.e. the client who requested the
|
||||
@c returned. Then the requester (i.e., the client who requested the
|
||||
@c CRL check) is asked via the Assuan inquiry ``SENDCERT'' whether
|
||||
@c he can provide this certificate. If this succeed the returned
|
||||
@c certificate gets cached and returned. Note, that dirmngr does not
|
||||
|
@ -1296,7 +1296,7 @@ as a binary blob.
|
|||
@c expiration time of all certificates in the chain.
|
||||
@c
|
||||
@c We first check that the certificate may be used for the requested
|
||||
@c purpose (i.e. OCSP or CRL signing). If this is not the case
|
||||
@c purpose (i.e., OCSP or CRL signing). If this is not the case
|
||||
@c GPG_ERR_WRONG_KEY_USAGE is returned.
|
||||
@c
|
||||
@c The next step is to find the trust anchor (root certificate) and to
|
||||
|
@ -1320,7 +1320,7 @@ as a binary blob.
|
|||
@c Now the issuer's certificate is looked up: If an
|
||||
@c authorityKeyIdentifier is available, this one is used to locate the
|
||||
@c certificate either using issuer and serialnumber or subject DN
|
||||
@c (i.e. the issuer's DN) and the keyID. The functions
|
||||
@c (i.e., the issuer's DN) and the keyID. The functions
|
||||
@c @code{find_cert_bysn) and @code{find_cert_bysubject} are used
|
||||
@c respectively. The have already been described above under the
|
||||
@c description of @code{crl_cache_insert}. If no certificate was found
|
||||
|
@ -1334,13 +1334,13 @@ as a binary blob.
|
|||
@c actual certificate is checked and in case this fails the error
|
||||
@c #code{GPG_ERR_BAD_CERT_CHAIN} is returned. If the signature checks out, the
|
||||
@c maximum chain length of the issuing certificate is checked as well as
|
||||
@c the capability of the certificate (i.e. whether he may be used for
|
||||
@c the capability of the certificate (i.e., whether he may be used for
|
||||
@c certificate signing). Then the certificate is prepended to our list
|
||||
@c representing the certificate chain. Finally the loop is continued now
|
||||
@c with the issuer's certificate as the current certificate.
|
||||
@c
|
||||
@c After the end of the loop and if no error as been encountered
|
||||
@c (i.e. the certificate chain has been assempled correctly), a check is
|
||||
@c (i.e., the certificate chain has been assempled correctly), a check is
|
||||
@c done whether any certificate expired or a critical policy has not been
|
||||
@c met. In any of these cases the validation terminates with an
|
||||
@c appropriate error.
|
||||
|
|
|
@ -72,7 +72,7 @@ the included Secure Shell Agent you may start the agent using:
|
|||
@c One way of enforcing this split is a per-key or per-session
|
||||
@c passphrase, known only by the owner, which must be supplied to the
|
||||
@c agent to permit the use of the secret key material. Another way is
|
||||
@c with an out-of-band permission mechanism (e.g. a button or GUI
|
||||
@c with an out-of-band permission mechanism (e.g@:. a button or GUI
|
||||
@c interface that the owner has access to, but the supplicant does not).
|
||||
@c
|
||||
@c The rationale for this separation is that it allows access to the
|
||||
|
@ -111,8 +111,8 @@ Please make sure that a proper pinentry program has been installed
|
|||
under the default filename (which is system dependent) or use the
|
||||
option @option{pinentry-program} to specify the full name of that program.
|
||||
It is often useful to install a symbolic link from the actual used
|
||||
pinentry (e.g. @file{@value{BINDIR}/pinentry-gtk}) to the expected
|
||||
one (e.g. @file{@value{BINDIR}/pinentry}).
|
||||
pinentry (e.g., @file{@value{BINDIR}/pinentry-gtk}) to the expected
|
||||
one (e.g., @file{@value{BINDIR}/pinentry}).
|
||||
|
||||
@manpause
|
||||
@noindent
|
||||
|
@ -177,8 +177,8 @@ Windows.
|
|||
If in @file{common.conf} the option @option{no-autostart} is set, any
|
||||
start attempts will be ignored.
|
||||
|
||||
In --supervised mode, different file descriptors can be provided for
|
||||
use as different socket types (e.g. ssh, extra) as long as they are
|
||||
In @option{--supervised} mode, different file descriptors can be provided for
|
||||
use as different socket types (e.g., ssh, extra) as long as they are
|
||||
identified in the environment variable @code{LISTEN_FDNAMES} (see
|
||||
sd_listen_fds(3) on some Linux distributions for more information on
|
||||
this convention).
|
||||
|
@ -259,7 +259,7 @@ however carefully selected to best aid in debugging.
|
|||
@item --debug @var{flags}
|
||||
@opindex debug
|
||||
Set debug flags. All flags are or-ed and @var{flags} may be given
|
||||
in C syntax (e.g. 0x0042) or as a comma separated list of flag names.
|
||||
in C syntax (e.g., 0x0042) or as a comma separated list of flag names.
|
||||
To get a list of all supported flags the single word "help" can be
|
||||
used. This option is only useful for debugging and the behavior may
|
||||
change at any time without notice.
|
||||
|
@ -345,7 +345,7 @@ specify the logging output.
|
|||
@anchor{option --no-allow-mark-trusted}
|
||||
@item --no-allow-mark-trusted
|
||||
@opindex no-allow-mark-trusted
|
||||
Do not allow clients to mark keys as trusted, i.e. put them into the
|
||||
Do not allow clients to mark keys as trusted, i.e., put them into the
|
||||
@file{trustlist.txt} file. This makes it harder for users to inadvertently
|
||||
accept Root-CA keys.
|
||||
|
||||
|
@ -716,7 +716,7 @@ The order in which keys are presented to ssh are:
|
|||
|
||||
Editing the "Use-for-ssh" values can be done with an editor or using
|
||||
@command{gpg-connect-agent} and "KEYATTR" (Remember to append a colon
|
||||
to the key; i.e. use "Use-for-ssh:").
|
||||
to the key; i.e., use "Use-for-ssh:").
|
||||
|
||||
|
||||
@anchor{option --ssh-fingerprint-digest}
|
||||
|
@ -724,7 +724,7 @@ to the key; i.e. use "Use-for-ssh:").
|
|||
@opindex ssh-fingerprint-digest
|
||||
|
||||
Select the digest algorithm used to compute ssh fingerprints that are
|
||||
communicated to the user, e.g. in pinentry dialogs. OpenSSH has
|
||||
communicated to the user, e.g., in pinentry dialogs. OpenSSH has
|
||||
transitioned from using MD5 to the more secure SHA256.
|
||||
|
||||
|
||||
|
@ -830,7 +830,7 @@ It might even be advisable to change the permissions to read-only so
|
|||
that this file can't be changed inadvertently.
|
||||
|
||||
As a special feature a line @code{include-default} will include a global
|
||||
list of trusted certificates (e.g. @file{@value{SYSCONFDIR}/trustlist.txt}).
|
||||
list of trusted certificates (e.g., @file{@value{SYSCONFDIR}/trustlist.txt}).
|
||||
This global list is also used if the local list is not available;
|
||||
the @ref{option --no-user-trustlist} enforces the use of only
|
||||
this global list.
|
||||
|
@ -892,7 +892,7 @@ The keygrip may be prefixed with a @code{!} to disable an entry.
|
|||
|
||||
The following example lists exactly one key. Note that keys available
|
||||
through a OpenPGP smartcard in the active smartcard reader are
|
||||
implicitly added to this list; i.e. there is no need to list them.
|
||||
implicitly added to this list; i.e., there is no need to list them.
|
||||
|
||||
@cartouche
|
||||
@smallexample
|
||||
|
@ -925,7 +925,7 @@ a small helper script is provided to create these files (@pxref{addgnupghome}).
|
|||
@mansect signals
|
||||
@node Agent Signals
|
||||
@section Use of some signals
|
||||
A running @command{gpg-agent} may be controlled by signals, i.e. using
|
||||
A running @command{gpg-agent} may be controlled by signals, i.e., using
|
||||
the @command{kill} command to send a signal to the process.
|
||||
|
||||
Here is a list of supported signals:
|
||||
|
@ -1407,7 +1407,7 @@ convention either the hexified fingerprint of the key shall be used for
|
|||
calling application and a colon: Like @code{gpg:somestring}.
|
||||
|
||||
@var{error_message} is either a single @code{X} for no error message or
|
||||
a string to be shown as an error message like (e.g. "invalid
|
||||
a string to be shown as an error message like (e.g., "invalid
|
||||
passphrase"). Blanks must be percent escaped or replaced by @code{+}'.
|
||||
|
||||
@var{prompt} is either a single @code{X} for a default prompt or the
|
||||
|
|
|
@ -546,7 +546,7 @@ be printed; to create a new key anyway the option @samp{--force} can be
|
|||
used. Note that only the private and public keys have been created
|
||||
but no certificates are stored in the key slots. In fact, GnuPG uses
|
||||
its own non-standard method to store just the public key in place of
|
||||
the the certificate. Other application will not be able to make use
|
||||
the certificate. Other application will not be able to make use
|
||||
these keys until @command{gpgsm} or another tool has been used to
|
||||
create and store the respective certificates. Let us see what the
|
||||
list command now shows:
|
||||
|
|
162
doc/gpg.texi
162
doc/gpg.texi
|
@ -330,21 +330,21 @@ The status of the verification is indicated by a flag directly
|
|||
following the "sig" tag (and thus before the flags described below. A
|
||||
"!" indicates that the signature has been successfully verified, a "-"
|
||||
denotes a bad signature and a "%" is used if an error occurred while
|
||||
checking the signature (e.g. a non supported algorithm). Signatures
|
||||
checking the signature (e.g., a non supported algorithm). Signatures
|
||||
where the public key is not available are not listed; to see their
|
||||
keyids the command @option{--list-sigs} can be used.
|
||||
|
||||
For each signature listed, there are several flags in between the
|
||||
signature status flag and keyid. These flags give additional
|
||||
information about each key signature. From left to right, they are
|
||||
the numbers 1-3 for certificate check level (see
|
||||
the numbers 1--3 for certificate check level (see
|
||||
@option{--ask-cert-level}), "L" for a local or non-exportable
|
||||
signature (see @option{--lsign-key}), "R" for a nonRevocable signature
|
||||
(see the @option{--edit-key} command "nrsign"), "P" for a signature
|
||||
that contains a policy URL (see @option{--cert-policy-url}), "N" for a
|
||||
signature that contains a notation (see @option{--cert-notation}), "X"
|
||||
for an eXpired signature (see @option{--ask-cert-expire}), and the
|
||||
numbers 1-9 or "T" for 10 and above to indicate trust signature levels
|
||||
numbers 1--9 or "T" for 10 and above to indicate trust signature levels
|
||||
(see the @option{--edit-key} command "tsign").
|
||||
|
||||
|
||||
|
@ -362,9 +362,9 @@ public keys are listed.
|
|||
The variant @option{--locate-external-keys} does not consider a
|
||||
locally existing key and can thus be used to force the refresh of a
|
||||
key via the defined external methods. If a fingerprint is given and
|
||||
and the methods defined by --auto-key-locate define LDAP servers, the
|
||||
key is fetched from these resources; defined non-LDAP keyservers are
|
||||
skipped.
|
||||
and the methods defined by @option{--auto-key-locate} define LDAP
|
||||
servers, the key is fetched from these resources; defined non-LDAP
|
||||
keyservers are skipped.
|
||||
|
||||
|
||||
@item --show-keys
|
||||
|
@ -405,7 +405,7 @@ description, please see the Card HOWTO at
|
|||
https://gnupg.org/documentation/howtos.html#GnuPG-cardHOWTO . Please
|
||||
note that the command "openpgp" can be used to switch to the OpenPGP
|
||||
application of cards which by default are presenting another
|
||||
application (e.g. PIV).
|
||||
application (e.g., PIV).
|
||||
|
||||
@item --card-status
|
||||
@opindex card-status
|
||||
|
@ -589,7 +589,7 @@ corrupted trustdb. Example:
|
|||
Update the trustdb with the ownertrust values stored in @code{files} (or
|
||||
STDIN if not given); existing values will be overwritten. In case of a
|
||||
severely damaged trustdb and if you have a recent backup of the
|
||||
ownertrust values (e.g. in the file @file{otrust.txt}), you may re-create
|
||||
ownertrust values (e.g., in the file @file{otrust.txt}), you may re-create
|
||||
the trustdb using these commands:
|
||||
@c man:.RS
|
||||
@example
|
||||
|
@ -892,7 +892,7 @@ signing.
|
|||
@item delsig
|
||||
@opindex keyedit:delsig
|
||||
Delete a signature. Note that it is not possible to retract a signature,
|
||||
once it has been send to the public (i.e. to a keyserver). In that case
|
||||
once it has been send to the public (i.e., to a keyserver). In that case
|
||||
you better use @code{revsig}.
|
||||
|
||||
@item revsig
|
||||
|
@ -926,7 +926,7 @@ signing.
|
|||
@opindex keyedit:deluid
|
||||
Delete a user ID or photographic user ID. Note that it is not
|
||||
possible to retract a user id, once it has been send to the public
|
||||
(i.e. to a keyserver). In that case you better use @code{revuid}.
|
||||
(i.e., to a keyserver). In that case you better use @code{revuid}.
|
||||
|
||||
@item revuid
|
||||
@opindex keyedit:revuid
|
||||
|
@ -1005,13 +1005,13 @@ signing.
|
|||
@item keytocard
|
||||
@opindex keyedit:keytocard
|
||||
Transfer the selected secret subkey (or the primary key if no subkey
|
||||
has been selected) to a smartcard. The secret key in the keyring will
|
||||
be replaced by a stub if the key could be stored successfully on the
|
||||
card and you use the save command later. Only certain key types may be
|
||||
transferred to the card. A sub menu allows you to select on what card
|
||||
to store the key. Note that it is not possible to get that key back
|
||||
from the card - if the card gets broken your secret key will be lost
|
||||
unless you have a backup somewhere.
|
||||
has been selected) to a smartcard. The secret key in the keyring
|
||||
will be replaced by a stub if the key could be stored successfully
|
||||
on the card and you use the save command later. Only certain key
|
||||
types may be transferred to the card. A sub menu allows you to
|
||||
select on what card to store the key. Note that it is not possible
|
||||
to get that key back from the card --- if the card gets broken your
|
||||
secret key will be lost unless you have a backup somewhere.
|
||||
|
||||
@item bkuptocard @var{file}
|
||||
@opindex keyedit:bkuptocard
|
||||
|
@ -1046,7 +1046,7 @@ signing.
|
|||
@item delkey
|
||||
@opindex keyedit:delkey
|
||||
Remove a subkey (secondary key). Note that it is not possible to retract
|
||||
a subkey, once it has been send to the public (i.e. to a keyserver). In
|
||||
a subkey, once it has been send to the public (i.e., to a keyserver). In
|
||||
that case you better use @code{revkey}. Also note that this only
|
||||
deletes the public part of a key.
|
||||
|
||||
|
@ -1098,7 +1098,7 @@ signing.
|
|||
@item clean
|
||||
@opindex keyedit:clean
|
||||
Compact (by removing all signatures except the selfsig) any user ID
|
||||
that is no longer usable (e.g. revoked, or expired). Then, remove any
|
||||
that is no longer usable (e.g., revoked, or expired). Then, remove any
|
||||
signatures that are not usable by the trust calculations.
|
||||
Specifically, this removes any signature that does not validate, any
|
||||
signature that is superseded by a later signature, revoked signatures,
|
||||
|
@ -1112,7 +1112,7 @@ signing.
|
|||
@item change-usage
|
||||
@opindex keyedit:change-usage
|
||||
Change the usage flags (capabilities) of the primary key or of
|
||||
subkeys. These usage flags (e.g. Certify, Sign, Authenticate,
|
||||
subkeys. These usage flags (e.g., Certify, Sign, Authenticate,
|
||||
Encrypt) are set during key creation. Sometimes it is useful to
|
||||
have the opportunity to change them (for example to add
|
||||
Authenticate) after they have been created. Please take care when
|
||||
|
@ -1223,12 +1223,19 @@ all affected self-signatures is set one second ahead.
|
|||
This command updates the preference list of the key to the current
|
||||
default value (either built-in or set via
|
||||
@option{--default-preference-list}). This is the unattended version
|
||||
of of using "setpref" in the @option{--key-edit} menu without giving a
|
||||
of using "setpref" in the @option{--key-edit} menu without giving a
|
||||
list. Note that you can show the preferences in a key listing by
|
||||
using @option{--list-options show-pref} or @option{--list-options
|
||||
show-pref-verbose}. You should also re-distribute updated keys to
|
||||
your peers.
|
||||
|
||||
@item --quick-set-ownertrust @var{user-id} @var{value}
|
||||
@opindex quick-set-ownertrust
|
||||
This command sets the ownertrust of a key and can also be used to set
|
||||
the disable flag of a key. This is the unattended version of using
|
||||
"trust", "disable", or "enable" in the @option{--key-edit} menu.
|
||||
|
||||
|
||||
@item --change-passphrase @var{user-id}
|
||||
@opindex change-passphrase
|
||||
@itemx --passwd @var{user-id}
|
||||
|
@ -1265,13 +1272,13 @@ behaviour and to change the default configuration.
|
|||
@end menu
|
||||
|
||||
Long options can be put in an options file (default
|
||||
"~/.gnupg/gpg.conf"). Short option names will not work - for example,
|
||||
"armor" is a valid option for the options file, while "a" is not. Do not
|
||||
write the 2 dashes, but simply the name of the option and any required
|
||||
arguments. Lines with a hash ('#') as the first non-white-space
|
||||
character are ignored. Commands may be put in this file too, but that is
|
||||
not generally useful as the command will execute automatically with
|
||||
every execution of gpg.
|
||||
"~/.gnupg/gpg.conf"). Short option names will not work --- for
|
||||
example, "armor" is a valid option for the options file, while "a" is
|
||||
not. Do not write the 2 dashes, but simply the name of the option and
|
||||
any required arguments. Lines with a hash ('#') as the first
|
||||
non-white-space character are ignored. Commands may be put in this
|
||||
file too, but that is not generally useful as the command will execute
|
||||
automatically with every execution of gpg.
|
||||
|
||||
Please remember that option parsing stops as soon as a non-option is
|
||||
encountered, you can explicitly stop parsing by using the special option
|
||||
|
@ -1396,6 +1403,11 @@ give the opposite meaning. The options are:
|
|||
key (@code{E}=encryption, @code{S}=signing, @code{C}=certification,
|
||||
@code{A}=authentication). Defaults to yes.
|
||||
|
||||
@item show-ownertrust
|
||||
@opindex list-options:show-ownertrust
|
||||
Show the ownertrust value for keys also in the standard key
|
||||
listing. Defaults to no.
|
||||
|
||||
@item show-policy-urls
|
||||
@opindex list-options:show-policy-urls
|
||||
Show policy URLs in the @option{--check-signatures}
|
||||
|
@ -1410,6 +1422,18 @@ give the opposite meaning. The options are:
|
|||
Show all, IETF standard, or user-defined signature notations in the
|
||||
@option{--check-signatures} listings. Defaults to no.
|
||||
|
||||
@item show-x509-notations
|
||||
@opindex list-options:show-x509-notations
|
||||
Print X.509 certificates embedded in key signatures as PEM data.
|
||||
This is intended for debugging and the output format may change
|
||||
without notice.
|
||||
|
||||
@item store-x509-notations
|
||||
@opindex list-options:store-x509-notations
|
||||
Store X.509 certificates embedded in key signatures as PEM data
|
||||
files. The filename consists the 4 byte key ID of the certificate,
|
||||
a dash, the fingerprint of the key or subkey, and the suffix ".pem".
|
||||
|
||||
@item show-keyserver-urls
|
||||
@opindex list-options:show-keyserver-urls
|
||||
Show any preferred keyserver URL in the
|
||||
|
@ -1457,10 +1481,10 @@ give the opposite meaning. The options are:
|
|||
|
||||
@item sort-sigs
|
||||
@opindex list-options:sort-sigs
|
||||
With --list-sigs and --check-sigs sort the signatures by keyID and
|
||||
creation time to make it easier to view the history of these
|
||||
signatures. The self-signature is also listed before other
|
||||
signatures. Defaults to yes.
|
||||
With @option{--list-sigs} and @option{--check-sigs} sort the
|
||||
signatures by keyID and creation time to make it easier to view the
|
||||
history of these signatures. The self-signature is also listed
|
||||
before other signatures. Defaults to yes.
|
||||
|
||||
@end table
|
||||
|
||||
|
@ -1517,12 +1541,12 @@ the opposite meaning. The options are:
|
|||
@itemx --disable-large-rsa
|
||||
@opindex enable-large-rsa
|
||||
@opindex disable-large-rsa
|
||||
With --generate-key and --batch, enable the creation of RSA secret keys as
|
||||
large as 8192 bit. Note: 8192 bit is more than is generally
|
||||
recommended. These large keys don't significantly improve security,
|
||||
but they are more expensive to use, and their signatures and
|
||||
certifications are larger. This option is only available if the
|
||||
binary was build with large-secmem support.
|
||||
With @option{--generate-key} and @option{--batch}, enable the creation
|
||||
of RSA secret keys as large as 8192 bit. Note: 8192 bit is more than
|
||||
is generally recommended. These large keys don't significantly
|
||||
improve security, but they are more expensive to use, and their
|
||||
signatures and certifications are larger. This option is only
|
||||
available if the binary was build with large-secmem support.
|
||||
|
||||
@item --enable-dsa2
|
||||
@itemx --disable-dsa2
|
||||
|
@ -1540,9 +1564,9 @@ will be expanded to a filename containing the photo. "%I" does the
|
|||
same, except the file will not be deleted once the viewer exits.
|
||||
Other flags are "%k" for the key ID, "%K" for the long key ID, "%f"
|
||||
for the key fingerprint, "%t" for the extension of the image type
|
||||
(e.g. "jpg"), "%T" for the MIME type of the image (e.g. "image/jpeg"),
|
||||
(e.g., "jpg"), "%T" for the MIME type of the image (e.g., "image/jpeg"),
|
||||
"%v" for the single-character calculated validity of the image being
|
||||
viewed (e.g. "f"), "%V" for the calculated validity as a string (e.g.
|
||||
viewed (e.g., "f"), "%V" for the calculated validity as a string (e.g.,
|
||||
"full"), "%U" for a base32 encoded hash of the user ID,
|
||||
and "%%" for an actual percent sign. If neither %i or %I are present,
|
||||
then the photo will be supplied to the viewer on standard input.
|
||||
|
@ -2046,7 +2070,7 @@ default), that keyserver is tried. Note that the creator of the
|
|||
signature uses the option @option{--sig-keyserver-url} to specify the
|
||||
preferred keyserver for data signatures.
|
||||
|
||||
3. If the signature has the Signer's UID set (e.g. using
|
||||
3. If the signature has the Signer's UID set (e.g., using
|
||||
@option{--sender} while creating the signature) a Web Key Directory
|
||||
(WKD) lookup is done. This is the default configuration but can be
|
||||
disabled by removing WKD from the auto-key-locate list or by using the
|
||||
|
@ -2074,7 +2098,7 @@ option is ignored if the option @option{--with-colons} is used.
|
|||
|
||||
@item --keyserver @var{name}
|
||||
@opindex keyserver
|
||||
This option is deprecated - please use the @option{--keyserver} in
|
||||
This option is deprecated --- please use the @option{--keyserver} in
|
||||
@file{dirmngr.conf} instead.
|
||||
|
||||
Use @var{name} as your keyserver. This is the server that
|
||||
|
@ -2294,7 +2318,7 @@ suppressed on the command line.
|
|||
@itemx --no-require-secmem
|
||||
@opindex require-secmem
|
||||
Refuse to run if GnuPG cannot get secure memory. Defaults to no
|
||||
(i.e. run, but give a warning).
|
||||
(i.e., run, but give a warning).
|
||||
|
||||
|
||||
@item --require-cross-certification
|
||||
|
@ -2426,7 +2450,7 @@ id used to make the signature and embeds that user ID into the created
|
|||
signature (using OpenPGP's ``Signer's User ID'' subpacket). If the
|
||||
option is given multiple times a suitable user ID is picked. However,
|
||||
if the signing key was specified directly by using a mail address
|
||||
(i.e. not by using a fingerprint or key ID) this option is used and
|
||||
(i.e., not by using a fingerprint or key ID) this option is used and
|
||||
the mail address is embedded in the created signature.
|
||||
|
||||
When verifying a signature @var{mbox} is used to restrict the
|
||||
|
@ -2535,7 +2559,7 @@ the @option{--status-fd} line ``PROGRESS'' to provide a value for
|
|||
@item --key-origin @var{string}[,@var{url}]
|
||||
@opindex key-origin
|
||||
gpg can track the origin of a key. Certain origins are implicitly
|
||||
known (e.g. keyserver, web key directory) and set. For a standard
|
||||
known (e.g., keyserver, web key directory) and set. For a standard
|
||||
import the origin of the keys imported can be set with this option.
|
||||
To list the possible values use "help" for @var{string}. Some origins
|
||||
can store an optional @var{url} argument. That URL can appended to
|
||||
|
@ -2657,12 +2681,12 @@ The available filter types are:
|
|||
|
||||
@item drop-subkey
|
||||
This filter drops the selected subkeys.
|
||||
Currently only implemented for --export-filter.
|
||||
Currently only implemented for @option{--export-filter}.
|
||||
|
||||
@item drop-sig
|
||||
This filter drops the selected key signatures on user ids.
|
||||
Self-signatures are not considered.
|
||||
Currently only implemented for --import-filter.
|
||||
Currently only implemented for @option{--import-filter}.
|
||||
|
||||
@item select
|
||||
This filter is only implemented by @option{--list-filter}. All
|
||||
|
@ -2707,13 +2731,13 @@ The available properties are:
|
|||
@itemx key_created_d
|
||||
The first is the timestamp a public key or subkey packet was
|
||||
created. The second is the same but given as an ISO string,
|
||||
e.g. "2016-08-17". (drop-subkey)
|
||||
e.g., "2016-08-17". (drop-subkey)
|
||||
|
||||
@item key_expires
|
||||
@itemx key_expires_d
|
||||
The expiration time of a public key or subkey or 0 if it does not
|
||||
expire. The second is the same but given as an ISO date string or
|
||||
an empty string e.g. "2038-01-19".
|
||||
an empty string e.g., "2038-01-19".
|
||||
|
||||
@item fpr
|
||||
The hexified fingerprint of the current subkey or primary key.
|
||||
|
@ -2746,7 +2770,7 @@ The available properties are:
|
|||
@itemx sig_created_d
|
||||
The first is the timestamp a signature packet was created. The
|
||||
second is the same but given as an ISO date string,
|
||||
e.g. "2016-08-17". (drop-sig)
|
||||
e.g., "2016-08-17". (drop-sig)
|
||||
|
||||
@item sig_expires
|
||||
@itemx sig_expires_d
|
||||
|
@ -2872,7 +2896,7 @@ obsolete; it does not harm to use it though.
|
|||
@opindex legacy-list-mode
|
||||
Revert to the pre-2.1 public key list mode. This only affects the
|
||||
human readable output and not the machine interface
|
||||
(i.e. @code{--with-colons}). Note that the legacy format does not
|
||||
(i.e., @code{--with-colons}). Note that the legacy format does not
|
||||
convey suitable information for elliptic curves.
|
||||
|
||||
@item --with-fingerprint
|
||||
|
@ -2881,12 +2905,15 @@ Same as the command @option{--fingerprint} but changes only the format
|
|||
of the output and may be used together with another command.
|
||||
|
||||
@item --with-subkey-fingerprint
|
||||
@itemx --without-subkey-fingerprint
|
||||
@opindex with-subkey-fingerprint
|
||||
@opindex without-subkey-fingerprint
|
||||
If a fingerprint is printed for the primary key, this option forces
|
||||
printing of the fingerprint for all subkeys. This could also be
|
||||
achieved by using the @option{--with-fingerprint} twice but by using
|
||||
this option along with keyid-format "none" a compact fingerprint is
|
||||
printed.
|
||||
this option along with the default keyid-format "none" a compact
|
||||
fingerprint is printed. Since version 2.6.0 this option is active by
|
||||
default; use the ``without'' variant to disable it.
|
||||
|
||||
@item --with-v5-fingerprint
|
||||
@opindex with-v5-fingerprint
|
||||
|
@ -2990,7 +3017,7 @@ to safely override the algorithm chosen by the recipient key
|
|||
preferences, as GPG will only select an algorithm that is usable by
|
||||
all recipients. The most highly ranked digest algorithm in this list
|
||||
is also used when signing without encryption
|
||||
(e.g. @option{--clear-sign} or @option{--sign}).
|
||||
(e.g., @option{--clear-sign} or @option{--sign}).
|
||||
|
||||
@item --personal-compress-preferences @var{string}
|
||||
@opindex personal-compress-preferences
|
||||
|
@ -3001,7 +3028,7 @@ allows the user to safely override the algorithm chosen by the
|
|||
recipient key preferences, as GPG will only select an algorithm that
|
||||
is usable by all recipients. The most highly ranked compression
|
||||
algorithm in this list is also used when there are no recipient keys
|
||||
to consider (e.g. @option{--symmetric}).
|
||||
to consider (e.g., @option{--symmetric}).
|
||||
|
||||
@item --s2k-cipher-algo @var{name}
|
||||
@opindex s2k-cipher-algo
|
||||
|
@ -3027,7 +3054,7 @@ of times (see @option{--s2k-count}).
|
|||
Specify how many times the passphrases mangling for symmetric
|
||||
encryption is repeated. This value may range between 1024 and
|
||||
65011712 inclusive. The default is inquired from gpg-agent. Note
|
||||
that not all values in the 1024-65011712 range are legal and if an
|
||||
that not all values in the 1024--65011712 range are legal and if an
|
||||
illegal value is selected, GnuPG will round up to the nearest legal
|
||||
value. This option is only meaningful if @option{--s2k-mode} is set
|
||||
to the default of 3.
|
||||
|
@ -3119,6 +3146,15 @@ This option adjusts the compliance mode "de-vs" for stricter key size
|
|||
requirements. For example, a value of 3000 turns rsa2048 and dsa2048
|
||||
keys into non-VS-NfD compliant keys.
|
||||
|
||||
@item --require-pqc-encryption
|
||||
@opindex require-pqc-encryption
|
||||
This option forces the use of quantum-resistant encryption algorithms.
|
||||
If not all public keys are quantum-resistant the encryption will fail.
|
||||
On decryption a warning is printed for all non-quantum-resistant keys.
|
||||
As of now the Kyber (ML-KEM768 and ML-KEM1024) algorithms are
|
||||
considered quantum-resistant; Kyber is always used in a composite
|
||||
scheme along with a classic ECC algorithm.
|
||||
|
||||
@item --require-compliance
|
||||
@opindex require-compliance
|
||||
To check that data has been encrypted according to the rules of the
|
||||
|
@ -3197,7 +3233,7 @@ however carefully selected to best aid in debugging.
|
|||
@item --debug @var{flags}
|
||||
@opindex debug
|
||||
Set debug flags. All flags are or-ed and @var{flags} may be given
|
||||
in C syntax (e.g. 0x0042) or as a comma separated list of flag names.
|
||||
in C syntax (e.g., 0x0042) or as a comma separated list of flag names.
|
||||
To get a list of all supported flags the single word "help" can be
|
||||
used. This option is only useful for debugging and the behavior may
|
||||
change at any time without notice.
|
||||
|
@ -3232,7 +3268,7 @@ only useful for certain regression tests.
|
|||
This option is only useful for testing; it sets the system time back
|
||||
or forth to @var{epoch} which is the number of seconds elapsed since
|
||||
the year 1970. Alternatively @var{epoch} may be given as a full ISO
|
||||
time string (e.g. "20070924T154812").
|
||||
time string (e.g., "20070924T154812").
|
||||
|
||||
If you suffix @var{epoch} with an exclamation mark (!), the system time
|
||||
will appear to be frozen at the specified time.
|
||||
|
@ -3572,7 +3608,7 @@ are:
|
|||
@opindex no-symkey-cache
|
||||
Disable the passphrase cache used for symmetrical en- and decryption.
|
||||
This cache is based on the message specific salt value
|
||||
(cf. @option{--s2k-mode}).
|
||||
(cf.@: @option{--s2k-mode}).
|
||||
|
||||
@item --request-origin @var{origin}
|
||||
@opindex request-origin
|
||||
|
@ -3844,6 +3880,12 @@ This option enables a mode in which filenames of the form
|
|||
@file{-&n}, where n is a non-negative decimal number,
|
||||
refer to the file descriptor n and not to a file with that name.
|
||||
|
||||
@item --disable-fd-translation
|
||||
@opindex disable-fd-translation
|
||||
This option changes the behaviour for all following options to expect
|
||||
libc file descriptors instead of HANDLE values on the command line.
|
||||
The option has an effect only on Windows.
|
||||
|
||||
@item --no-expensive-trust-checks
|
||||
@opindex no-expensive-trust-checks
|
||||
Experimental use only.
|
||||
|
@ -4660,7 +4702,7 @@ If you don't give any of them, no user ID is created.
|
|||
|
||||
@item Expire-Date: @var{iso-date}|(@var{number}[d|w|m|y])
|
||||
Set the expiration date for the key (and the subkey). It may either
|
||||
be entered in ISO date format (e.g. "20000815T145012") or as number of
|
||||
be entered in ISO date format (e.g., "20000815T145012") or as number of
|
||||
days, weeks, month or years after the creation date. The special
|
||||
notation "seconds=N" is also allowed to specify a number of seconds
|
||||
since creation. Without a letter days are assumed. Note that there
|
||||
|
|
|
@ -136,7 +136,7 @@ Run in server mode and wait for commands on the @code{stdin}.
|
|||
Behave as a Dirmngr client issuing the request @var{command} with the
|
||||
optional list of @var{args}. The output of the Dirmngr is printed
|
||||
stdout. Please note that file names given as arguments should have an
|
||||
absolute file name (i.e. commencing with @code{/}) because they are
|
||||
absolute file name (i.e., commencing with @code{/}) because they are
|
||||
passed verbatim to the Dirmngr and the working directory of the
|
||||
Dirmngr might not be the same as the one of this client. Currently it
|
||||
is not possible to pass data via stdin to the Dirmngr. @var{command}
|
||||
|
@ -259,7 +259,7 @@ optional @var{pattern}. Those pattern consist of a list of user ids
|
|||
@option{--armor} option a few informational lines are prepended before
|
||||
each block. There is one limitation: As there is no commonly agreed
|
||||
upon way to pack more than one certificate into an ASN.1 structure,
|
||||
the binary export (i.e. without using @option{armor}) works only for
|
||||
the binary export (i.e., without using @option{armor}) works only for
|
||||
the export of one certificate. Thus it is required to specify a
|
||||
@var{pattern} which yields exactly one certificate. Ephemeral
|
||||
certificate are only exported if all @var{pattern} are given as
|
||||
|
@ -462,7 +462,7 @@ line of the @file{trustlist.txt}
|
|||
@opindex force-crl-refresh
|
||||
Tell the dirmngr to reload the CRL for each request. For better
|
||||
performance, the dirmngr will actually optimize this by suppressing
|
||||
the loading for short time intervals (e.g. 30 minutes). This option
|
||||
the loading for short time intervals (e.g., 30 minutes). This option
|
||||
is useful to make sure that a fresh CRL is available for certificates
|
||||
hold in the keybox. The suggested way of doing this is by using it
|
||||
along with the option @option{--with-validation} for a key listing
|
||||
|
@ -539,7 +539,7 @@ Create PEM encoded output. Default is binary output.
|
|||
|
||||
@item --base64
|
||||
@opindex base64
|
||||
Create Base-64 encoded output; i.e. PEM without the header lines.
|
||||
Create Base-64 encoded output; i.e., PEM without the header lines.
|
||||
|
||||
@item --assume-armor
|
||||
@opindex assume-armor
|
||||
|
@ -639,11 +639,11 @@ done with @code{--with-colons}.
|
|||
@item --no-pretty-dn
|
||||
@opindex no-pretty-dn
|
||||
By default gpgsm prints distinguished names (DNs) like the Issuer or
|
||||
Subject in a more readable format (e.g. using a well defined order of
|
||||
Subject in a more readable format (e.g., using a well defined order of
|
||||
the parts). However, this format can't be used as input strings.
|
||||
This option reverts printing to standard RFC-2253 format and thus
|
||||
avoids the need to use --dump-cert or --with-colons to get the
|
||||
``real'' name.
|
||||
avoids the need to use @option{--dump-cert} or @option{--with-colons}
|
||||
to get the ``real'' name.
|
||||
|
||||
@end table
|
||||
|
||||
|
@ -754,7 +754,7 @@ key database clear of unneeded certificates stored on smartcards.
|
|||
This option is only useful for testing; it sets the system time back or
|
||||
forth to @var{epoch} which is the number of seconds elapsed since the year
|
||||
1970. Alternatively @var{epoch} may be given as a full ISO time string
|
||||
(e.g. "20070924T154812").
|
||||
(e.g., "20070924T154812").
|
||||
|
||||
@item --with-ephemeral-keys
|
||||
@opindex with-ephemeral-keys
|
||||
|
@ -770,6 +770,18 @@ list of flag names and are OR-ed together. The special flag "none"
|
|||
clears the list and allows one to start over with an empty list. To get a
|
||||
list of available flags the sole word "help" can be used.
|
||||
|
||||
@item --enable-special-filenames
|
||||
@opindex enable-special-filenames
|
||||
This option enables a mode in which filenames of the form
|
||||
@file{-&n}, where n is a non-negative decimal number,
|
||||
refer to the file descriptor n and not to a file with that name.
|
||||
|
||||
@item --disable-fd-translation
|
||||
@opindex disable-fd-translation
|
||||
This option changes the behaviour for all following options to expect
|
||||
libc file descriptors instead of HANDLE values on the command line.
|
||||
The option has an effect only on Windows.
|
||||
|
||||
@item --debug-level @var{level}
|
||||
@opindex debug-level
|
||||
Select the debug level for investigating problems. @var{level} may be
|
||||
|
@ -801,7 +813,7 @@ however carefully selected to best aid in debugging.
|
|||
@item --debug @var{flags}
|
||||
@opindex debug
|
||||
Set debug flags. All flags are or-ed and @var{flags} may be given
|
||||
in C syntax (e.g. 0x0042) or as a comma separated list of flag names.
|
||||
in C syntax (e.g., 0x0042) or as a comma separated list of flag names.
|
||||
To get a list of all supported flags the single word "help" can be
|
||||
used. This option is only useful for debugging and the behavior may
|
||||
change at any time without notice.
|
||||
|
@ -974,9 +986,9 @@ This is plain text file with a few help entries used with
|
|||
@command{gpg} and @command{gpgsm}. The standard file has English help
|
||||
texts; to install localized versions use filenames like @file{help.LL.txt}
|
||||
with LL denoting the locale. GnuPG comes with a set of predefined help
|
||||
files in the data directory (e.g. @file{@value{DATADIR}/gnupg/help.de.txt})
|
||||
files in the data directory (e.g., @file{@value{DATADIR}/gnupg/help.de.txt})
|
||||
and allows overriding of any help item by help files stored in the
|
||||
system configuration directory (e.g. @file{@value{SYSCONFDIR}/help.de.txt}).
|
||||
system configuration directory (e.g., @file{@value{SYSCONFDIR}/help.de.txt}).
|
||||
For a reference of the help file's syntax, please see the installed
|
||||
@file{help.txt} file.
|
||||
|
||||
|
@ -987,11 +999,10 @@ This file is a collection of common certificates used to populated a
|
|||
newly created @file{pubring.kbx}. An administrator may replace this
|
||||
file with a custom one. The format is a concatenation of PEM encoded
|
||||
X.509 certificates. This global file is installed in the data directory
|
||||
(e.g. @file{@value{DATADIR}/com-certs.pem}).
|
||||
(e.g., @file{@value{DATADIR}/com-certs.pem}).
|
||||
|
||||
@end table
|
||||
|
||||
@c man:.RE
|
||||
Note that on larger installations, it is useful to put predefined files
|
||||
into the directory @file{/etc/skel/.gnupg/} so that newly created users
|
||||
start up with a working configuration. For existing users a small
|
||||
|
@ -1100,7 +1111,7 @@ of a transfer error, a program error or tampering with the message).
|
|||
@end table
|
||||
|
||||
@item Error verifying a signature
|
||||
For some reason the signature could not be verified, i.e. it cannot be
|
||||
For some reason the signature could not be verified, i.e., it cannot be
|
||||
decided whether the signature is valid or invalid. A common reason for
|
||||
this is a missing certificate.
|
||||
|
||||
|
@ -1281,7 +1292,7 @@ provides a regular command line interface which exhibits a full client
|
|||
to this protocol (but uses internal linking). To start
|
||||
@command{gpgsm} as a server the command line the option
|
||||
@code{--server} must be used. Additional options are provided to
|
||||
select the communication method (i.e. the name of the socket).
|
||||
select the communication method (i.e., the name of the socket).
|
||||
|
||||
We assume that the connection has already been established; see the
|
||||
Assuan manual for details.
|
||||
|
@ -1345,7 +1356,7 @@ correct.
|
|||
OUTPUT FD[=@var{n}] [--armor|--base64]
|
||||
@end example
|
||||
|
||||
Set the file descriptor to be used for the output (i.e. the encrypted
|
||||
Set the file descriptor to be used for the output (i.e., the encrypted
|
||||
message). Obviously the pipe must be open at that point, the server
|
||||
establishes its own end. If the server returns an error the client
|
||||
should consider this session failed.
|
||||
|
@ -1388,11 +1399,11 @@ The decryption is done by using the command
|
|||
DECRYPT
|
||||
@end example
|
||||
|
||||
It performs the decrypt operation after doing some check on the internal
|
||||
state (e.g. that all needed data has been set). Because it utilizes
|
||||
the GPG-Agent for the session key decryption, there is no need to ask
|
||||
the client for a protecting passphrase - GpgAgent takes care of this by
|
||||
requesting this from the user.
|
||||
It performs the decrypt operation after doing some check on the
|
||||
internal state (e.g., that all needed data has been set). Because it
|
||||
utilizes the GPG-Agent for the session key decryption, there is no
|
||||
need to ask the client for a protecting passphrase --- GpgAgent takes
|
||||
care of this by requesting this from the user.
|
||||
|
||||
|
||||
@node GPGSM SIGN
|
||||
|
|
|
@ -91,7 +91,7 @@ Add @var{file} to the list of keyrings.
|
|||
If @var{file} begins with a tilde and a slash, these
|
||||
are replaced by the HOME directory. If the filename
|
||||
does not contain a slash, it is assumed to be in the
|
||||
home-directory ("~/.gnupg" if --homedir is not used).
|
||||
home-directory ("~/.gnupg" if @option{--homedir} is not used).
|
||||
|
||||
@item --output @var{file}
|
||||
@itemx -o @var{file}
|
||||
|
@ -184,10 +184,18 @@ If set directory used instead of "~/.gnupg".
|
|||
@mansect files
|
||||
@subsection FILES
|
||||
|
||||
@table @asis
|
||||
Default keyring file is expected in the GnuPG home directory
|
||||
(@pxref{option --homedir}, @code{GNUPGHOME}).
|
||||
|
||||
@table @file
|
||||
@item ~/.gnupg/trustedkeys.kbx
|
||||
@efindex trustedkeys.kbx
|
||||
The default keyring with the allowed keys, using the new keybox format.
|
||||
|
||||
@item ~/.gnupg/trustedkeys.gpg
|
||||
The default keyring with the allowed keys.
|
||||
@efindex trustedkeys.gpg
|
||||
When @file{trustedkeys.kbx} is not available, the default keyring with
|
||||
the allowed keys, using a legacy format.
|
||||
|
||||
@end table
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ would anyway ignore such a request. Thus just hit enter.
|
|||
|
||||
If you want to create a client certificate for email encryption, this
|
||||
would be the place to enter your mail address
|
||||
(e.g. @email{joe@@example.org}). You may enter as many addresses as you like,
|
||||
(e.g., @email{joe@@example.org}). You may enter as many addresses as you like,
|
||||
however the CA may not accept them all or reject the entire request.
|
||||
|
||||
@cartouche
|
||||
|
|
|
@ -59,7 +59,7 @@ A name must start with a letter and end with a colon. Valid
|
|||
characters are all ASCII letters, numbers and the hyphen. Comparison
|
||||
of names is done case insensitively. Names may be used several times
|
||||
to represent an array of values. Note that the name "Key" is special
|
||||
in that it is madandory must occur only once.
|
||||
in that it is mandatory and must occur only once.
|
||||
|
||||
*** Values
|
||||
Values are UTF-8 encoded strings. Values can be wrapped at any point,
|
||||
|
@ -156,7 +156,7 @@ dialog window when card is not available. When the value is "no", a
|
|||
card operation is refused with GPG_ERR_UNUSABLE_SECKEY error.
|
||||
|
||||
*** Backup-info
|
||||
This gives information for a backup of the key. The follwoing fields
|
||||
This gives information for a backup of the key. The following fields
|
||||
are space delimited:
|
||||
|
||||
- Hexified keygrip (uppercase) to make it easy to identify the
|
||||
|
@ -345,7 +345,7 @@ The currently defined protection modes are:
|
|||
** Shadowed Private Key Format
|
||||
|
||||
To keep track of keys stored on IC cards we use a third format for
|
||||
private kyes which are called shadow keys as they are only a reference
|
||||
private keys which are called shadow keys as they are only a reference
|
||||
to keys stored on a token:
|
||||
|
||||
(shadowed-private-key
|
||||
|
@ -395,7 +395,7 @@ This format is used to transfer keys between gpg and gpg-agent.
|
|||
* PUBKEYALGO is a Libgcrypt algo name
|
||||
* CURVENAME is the name of the curve - only used with ECC.
|
||||
* P1 .. PN are the parameters; the public parameters are never encrypted
|
||||
the secrect key parameters are encrypted if the "protection" list is
|
||||
the secret key parameters are encrypted if the "protection" list is
|
||||
given. To make this more explicit each parameter is preceded by a
|
||||
flag "_" for cleartext or "e" for encrypted text.
|
||||
* CSUM is the deprecated 16 bit checksum as defined by OpenPGP. This
|
||||
|
@ -404,7 +404,7 @@ This format is used to transfer keys between gpg and gpg-agent.
|
|||
the old 16 bit checksum (above) is used and if it is "none" no
|
||||
protection at all is used.
|
||||
* PROTALGO is a Libgcrypt style cipher algorithm name
|
||||
* IV is the initialization verctor.
|
||||
* IV is the initialization vector.
|
||||
* S2KMODE is the value from RFC-4880.
|
||||
* S2KHASH is a libgcrypt style hash algorithm identifier.
|
||||
* S2KSALT is the 8 byte salt
|
||||
|
@ -492,7 +492,7 @@ with "encrypted_octet_string" decoding to:
|
|||
(hash sha1 #0102030405060708091011121314151617181920#)
|
||||
)
|
||||
|
||||
To compute the hash this S-expression (in canoncical format) was
|
||||
To compute the hash this S-expression (in canonical format) was
|
||||
hashed:
|
||||
|
||||
((desc "List of system passphrases")
|
|
@ -161,7 +161,7 @@ helpers to debug problems.
|
|||
@item --debug @var{flags}
|
||||
@opindex debug
|
||||
Set debug flags. All flags are or-ed and @var{flags} may be given
|
||||
in C syntax (e.g. 0x0042) or as a comma separated list of flag names.
|
||||
in C syntax (e.g., 0x0042) or as a comma separated list of flag names.
|
||||
To get a list of all supported flags the single word "help" can be
|
||||
used. This option is only useful for debugging and the behavior may
|
||||
change at any time without notice.
|
||||
|
@ -238,7 +238,7 @@ this option only if you know what you are doing.
|
|||
Use @var{library} to access the smartcard reader. The current default
|
||||
on Unix is @file{libpcsclite.so} and on Windows @file{winscard.dll}.
|
||||
Instead of using this option you might also want to install a symbolic
|
||||
link to the default file name (e.g. from @file{libpcsclite.so.1}).
|
||||
link to the default file name (e.g., from @file{libpcsclite.so.1}).
|
||||
A Unicode file name may not be used on Windows.
|
||||
|
||||
@item --disable-ccid
|
||||
|
@ -503,7 +503,7 @@ will return an error when a card change has been detected and the use of
|
|||
this function is therefore required.
|
||||
|
||||
Background: We want to keep the client clear of handling card changes
|
||||
between operations; i.e. the client can assume that all operations are
|
||||
between operations; i.e., the client can assume that all operations are
|
||||
done on the same card unless he call this function.
|
||||
|
||||
@example
|
||||
|
@ -717,7 +717,7 @@ reset the card.
|
|||
|
||||
This is used by gpg-agent to reuse a primary pipe connection and
|
||||
may be used by clients to backup from a conflict in the serial
|
||||
command; i.e. to select another application.
|
||||
command; i.e., to select another application.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ using the option @option{--with-colons}.
|
|||
@item By fingerprint.
|
||||
This format is deduced from the length of the string and its content or
|
||||
the @code{0x} prefix. Note, that only the 20 byte version fingerprint
|
||||
is available with @command{gpgsm} (i.e. the SHA-1 hash of the
|
||||
is available with @command{gpgsm} (i.e., the SHA-1 hash of the
|
||||
certificate).
|
||||
|
||||
When using @command{gpg} an exclamation mark (!) may be appended to
|
||||
|
@ -88,7 +88,7 @@ with left and right angles.
|
|||
@item By partial match on an email address.
|
||||
This is indicated by prefixing the search string with an @code{@@}.
|
||||
This uses a substring search but considers only the mail address
|
||||
(i.e. inside the angle brackets).
|
||||
(i.e., inside the angle brackets).
|
||||
|
||||
@cartouche
|
||||
@example
|
||||
|
|
|
@ -124,7 +124,7 @@ $ watchgnupg --time-only
|
|||
@end example
|
||||
|
||||
This waits for connections on the local socket
|
||||
(e.g. @file{/var/run/user/1234/gnupg/S.log}) and shows all log
|
||||
(e.g., @file{/var/run/user/1234/gnupg/S.log}) and shows all log
|
||||
entries. To make this work the option @option{log-file} needs to be
|
||||
used with all modules which logs are to be shown. The suggested entry
|
||||
for the configuration files is:
|
||||
|
@ -133,8 +133,8 @@ for the configuration files is:
|
|||
log-file socket://
|
||||
@end example
|
||||
|
||||
If the default socket as given above and returned by "echo $(gpgconf
|
||||
--list-dirs socketdir)/S.log" is not desired an arbitrary socket name
|
||||
If the default socket as given above and returned by @code{"echo $(gpgconf
|
||||
--list-dirs socketdir)/S.log"} is not desired an arbitrary socket name
|
||||
can be specified, for example @file{socket:///home/foo/bar/mysocket}.
|
||||
For debugging purposes it is also possible to do remote logging. Take
|
||||
care if you use this feature because the information is send in the
|
||||
|
@ -1151,13 +1151,21 @@ More fields may be added in future to the output.
|
|||
|
||||
Under Windows this file is used to install GnuPG as a portable
|
||||
application. An empty file named @file{gpgconf.ctl} is expected in
|
||||
the same directory as the tool @file{gpgconf.exe}. The root of the
|
||||
the same directory as the tool @file{gpgconf.exe} or the file must
|
||||
have a keyword @code{portable} with the value true. The root of the
|
||||
installation is then that directory; or, if @file{gpgconf.exe} has
|
||||
been installed directly below a directory named @file{bin}, its parent
|
||||
directory. You also need to make sure that the following directories
|
||||
exist and are writable: @file{ROOT/home} for the GnuPG home and
|
||||
@file{ROOT@value{LOCALCACHEDIR}} for internal cache files.
|
||||
|
||||
On both platforms the keyword @code{gnupg} can be used to change the
|
||||
standard home directory. For example a value of "gnupg-vsd" will
|
||||
change the default home directory on unix from @file{~/.gnupg} to
|
||||
@file{~/.gnupg-vsd}. The socket directory is changed accordingly
|
||||
unless the @code{socketdir} keyword has been used. On Windows the
|
||||
Registry keys are modified as well.
|
||||
|
||||
|
||||
@item /etc/gnupg/gpgconf.conf
|
||||
@cindex gpgconf.conf
|
||||
|
@ -1284,7 +1292,7 @@ Alternatively an arbitrary string may be used to identify a
|
|||
passphrase; it is suggested that such a string is prefixed with the
|
||||
name of the application (e.g @code{foo:12346}). Scripts should always
|
||||
use the option @option{--with-colons}, which provides the keygrip in a
|
||||
"grp" line (cf. @file{doc/DETAILS})/
|
||||
"grp" line (cf.@: @file{doc/DETAILS})/
|
||||
|
||||
@noindent
|
||||
One of the following command options must be given:
|
||||
|
@ -1765,7 +1773,7 @@ The return value of this command is
|
|||
@table @code
|
||||
|
||||
@item 0
|
||||
The certificate under question is valid; i.e. there is a valid CRL
|
||||
The certificate under question is valid; i.e., there is a valid CRL
|
||||
available and it is not listed there or the OCSP request returned that
|
||||
that certificate is valid.
|
||||
|
||||
|
@ -2088,9 +2096,9 @@ This option is deprecated in favor of option @option{--directory}.
|
|||
|
||||
@item --no-compress
|
||||
@opindex no-compress
|
||||
This option tells gpg to disable compression (i.e. using option -z0).
|
||||
This option tells gpg to disable compression (i.e., using option -z0).
|
||||
It is useful for archiving only large files which are are already
|
||||
compressed (e.g. a set of videos).
|
||||
compressed (e.g., a set of videos).
|
||||
|
||||
@item --gpg @var{gpgcmd}
|
||||
@opindex gpg
|
||||
|
@ -2103,9 +2111,10 @@ Pass the specified extra options to @command{gpg}.
|
|||
@item --tar-args @var{args}
|
||||
@opindex tar-args
|
||||
Assume @var{args} are standard options of the command @command{tar}
|
||||
and parse them. The only supported tar options are "--directory",
|
||||
"--files-from", and "--null" This is an obsolete options because those
|
||||
supported tar options can also be given directly.
|
||||
and parse them. The only supported tar options are
|
||||
@option{--directory}, @option{--files-from}, and @option{--null}.
|
||||
This is an obsolete options because those supported tar options can
|
||||
also be given directly.
|
||||
|
||||
@item --tar @var{command}
|
||||
@opindex tar
|
||||
|
|
|
@ -214,7 +214,7 @@ The default is @file{openpgpkey}.
|
|||
@opindex blacklist
|
||||
This option is used to exclude certain mail addresses from a mirror
|
||||
operation. The format of @var{file} is one mail address (just the
|
||||
addrspec, e.g. "postel@@isi.edu") per line. Empty lines and lines
|
||||
addrspec, e.g., "postel@@isi.edu") per line. Empty lines and lines
|
||||
starting with a '#' are ignored.
|
||||
|
||||
@item --add-revocs
|
||||
|
|
|
@ -1031,10 +1031,10 @@ radix64_read( armor_filter_context_t *afx, IOBUF a, size_t *retn,
|
|||
checkcrc++;
|
||||
break;
|
||||
}
|
||||
else if (afx->dearmor_state && c == '-'
|
||||
else if (c == '-'
|
||||
&& afx->buffer_pos + 8 < afx->buffer_len
|
||||
&& !strncmp (afx->buffer, "-----END ", 8)) {
|
||||
break; /* End in --dearmor mode. */
|
||||
break; /* End in --dearmor mode or No CRC. */
|
||||
}
|
||||
else {
|
||||
log_error(_("invalid radix64 character %02X skipped\n"), c);
|
||||
|
|
|
@ -433,7 +433,7 @@ sos_write (iobuf_t out, gcry_mpi_t a, unsigned int *r_nwritten)
|
|||
* Write an opaque string to the output stream without length info.
|
||||
*/
|
||||
gpg_error_t
|
||||
gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a)
|
||||
gpg_mpi_write_opaque_nohdr (iobuf_t out, gcry_mpi_t a)
|
||||
{
|
||||
int rc;
|
||||
|
||||
|
@ -452,6 +452,45 @@ gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* Write an opaque MPI string with a four-byte octet count to the
|
||||
* output stream. If R_NWRITTEN is not NULL the number of written
|
||||
* bytes is stored there. OUT may be NULL in which case only
|
||||
* R_NWRITTEN is updated and error checking is done.
|
||||
*/
|
||||
gpg_error_t
|
||||
gpg_mpi_write_opaque_32 (iobuf_t out, gcry_mpi_t a, unsigned int *r_nwritten)
|
||||
{
|
||||
gpg_error_t err;
|
||||
|
||||
if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
unsigned int nbits, nbytes;
|
||||
const void *p;
|
||||
|
||||
p = gcry_mpi_get_opaque (a, &nbits);
|
||||
nbytes = (nbits + 7)/8;
|
||||
if (out)
|
||||
{
|
||||
write_32 (out, nbytes);
|
||||
err = p ? iobuf_write (out, p, nbytes) : 0;
|
||||
}
|
||||
else
|
||||
err = 0;
|
||||
if (r_nwritten)
|
||||
*r_nwritten = 4 + (p? nbytes : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
err = gpg_error (GPG_ERR_BAD_MPI);
|
||||
if (r_nwritten)
|
||||
*r_nwritten = 0;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Calculate the length of a packet described by PKT. */
|
||||
u32
|
||||
calc_packet_length( PACKET *pkt )
|
||||
|
@ -639,8 +678,14 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
|||
{
|
||||
if ( (pk->pubkey_algo == PUBKEY_ALGO_ECDSA && (i == 0))
|
||||
|| (pk->pubkey_algo == PUBKEY_ALGO_EDDSA && (i == 0))
|
||||
|| (pk->pubkey_algo == PUBKEY_ALGO_ECDH && (i == 0 || i == 2)))
|
||||
err = gpg_mpi_write_nohdr (a, pk->pkey[i]);
|
||||
|| (pk->pubkey_algo == PUBKEY_ALGO_ECDH && (i == 0 || i == 2))
|
||||
|| (pk->pubkey_algo == PUBKEY_ALGO_KYBER && (i == 0)))
|
||||
err = gpg_mpi_write_opaque_nohdr (a, pk->pkey[i]);
|
||||
else if (pk->pubkey_algo == PUBKEY_ALGO_KYBER && i == 2)
|
||||
{
|
||||
/* Write a four-octet count prefixed Kyber public key. */
|
||||
err = gpg_mpi_write_opaque_32 (a, pk->pkey[2], NULL);
|
||||
}
|
||||
else if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
|
@ -779,9 +824,15 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
|||
|
||||
for (j=i; j < nskey; j++ )
|
||||
{
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_KYBER && j == 4)
|
||||
{
|
||||
if ((err=gpg_mpi_write_opaque_32 (NULL,pk->pkey[j], &n)))
|
||||
goto leave;
|
||||
}
|
||||
else if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_KYBER)
|
||||
{
|
||||
if ((err = sos_write (NULL, pk->pkey[j], &n)))
|
||||
goto leave;
|
||||
|
@ -798,16 +849,26 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
|
|||
}
|
||||
|
||||
for ( ; i < nskey; i++ )
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
if ((err = sos_write (a, pk->pkey[i], NULL)))
|
||||
goto leave;
|
||||
}
|
||||
else
|
||||
if ((err = gpg_mpi_write (a, pk->pkey[i], NULL)))
|
||||
goto leave;
|
||||
{
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_KYBER && i == 4)
|
||||
{
|
||||
err = gpg_mpi_write_opaque_32 (a, pk->pkey[i], NULL);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
else if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA
|
||||
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
if ((err = sos_write (a, pk->pkey[i], NULL)))
|
||||
goto leave;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((err = gpg_mpi_write (a, pk->pkey[i], NULL)))
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
write_16 (a, ski->csum );
|
||||
}
|
||||
|
@ -921,9 +982,19 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
|
|||
|
||||
for (i=0; i < n && !rc ; i++ )
|
||||
{
|
||||
if (enc->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
|
||||
rc = gpg_mpi_write_nohdr (a, enc->data[i]);
|
||||
else if (enc->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
/* For Kyber we need to insert the algo before the final data
|
||||
* element because it is not stored in the data array. */
|
||||
if (enc->pubkey_algo == PUBKEY_ALGO_KYBER && i == 2)
|
||||
iobuf_put (a, enc->seskey_algo);
|
||||
|
||||
if (i == 1 && enc->pubkey_algo == PUBKEY_ALGO_ECDH)
|
||||
rc = gpg_mpi_write_opaque_nohdr (a, enc->data[i]);
|
||||
else if (i == 1 && enc->pubkey_algo == PUBKEY_ALGO_KYBER)
|
||||
rc = gpg_mpi_write_opaque_32 (a, enc->data[i], NULL);
|
||||
else if (i == 2 && enc->pubkey_algo == PUBKEY_ALGO_KYBER)
|
||||
rc = gpg_mpi_write_opaque_nohdr (a, enc->data[i]);
|
||||
else if (enc->pubkey_algo == PUBKEY_ALGO_ECDH
|
||||
|| enc->pubkey_algo == PUBKEY_ALGO_KYBER)
|
||||
rc = sos_write (a, enc->data[i], NULL);
|
||||
else
|
||||
rc = gpg_mpi_write (a, enc->data[i], NULL);
|
||||
|
@ -1748,6 +1819,72 @@ sig_to_notation(PKT_signature *sig)
|
|||
return list;
|
||||
}
|
||||
|
||||
|
||||
/* Return a list of notation data matching NAME. The caller needs to
|
||||
* to free the list using free_notation. Other than sig_to_notation
|
||||
* this function does not return the notation in human readable format
|
||||
* but always returns the raw data. The human readable flag is set
|
||||
* anyway set but .value is always NULL. */
|
||||
struct notation *
|
||||
search_sig_notations (PKT_signature *sig, const char *name)
|
||||
{
|
||||
const byte *p;
|
||||
size_t len;
|
||||
int seq = 0;
|
||||
int crit;
|
||||
notation_t list = NULL;
|
||||
|
||||
while((p=enum_sig_subpkt (sig, 1, SIGSUBPKT_NOTATION, &len, &seq, &crit)))
|
||||
{
|
||||
int n1,n2;
|
||||
struct notation *n=NULL;
|
||||
|
||||
if (len < 8)
|
||||
{
|
||||
log_info (_("WARNING: invalid notation data found\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
/* name length. */
|
||||
n1=(p[4]<<8)|p[5];
|
||||
/* value length. */
|
||||
n2=(p[6]<<8)|p[7];
|
||||
|
||||
if (8 + n1 + n2 != len)
|
||||
{
|
||||
log_info (_("WARNING: invalid notation data found\n"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!name)
|
||||
; /* Return everything. */
|
||||
else if (n1 != strlen (name) || memcmp (p+8, name, n1))
|
||||
continue; /* Not the requested name. */
|
||||
|
||||
|
||||
n = xmalloc_clear (sizeof *n);
|
||||
n->name = xmalloc (n1+1);
|
||||
|
||||
memcpy (n->name,p + 8, n1);
|
||||
n->name[n1]='\0';
|
||||
|
||||
/* In any case append a Nul. */
|
||||
n->bdat = xmalloc (n2+1);
|
||||
memcpy (n->bdat, p + 8 + n1, n2);
|
||||
n->bdat[n2] = '\0';
|
||||
n->blen = n2;
|
||||
n->flags.human = !!(p[0] & 0x80);
|
||||
|
||||
n->flags.critical = crit;
|
||||
|
||||
n->next = list;
|
||||
list = n;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
/* Release the resources associated with the *list* of notations. To
|
||||
release a single notation, make sure that notation->next is
|
||||
NULL. */
|
||||
|
|
153
g10/call-agent.c
153
g10/call-agent.c
|
@ -251,7 +251,8 @@ start_agent (ctrl_t ctrl, int flag_for_card)
|
|||
opt.agent_program,
|
||||
opt.lc_ctype, opt.lc_messages,
|
||||
opt.session_env,
|
||||
opt.autostart, opt.verbose, DBG_IPC,
|
||||
opt.autostart?ASSHELP_FLAG_AUTOSTART:0,
|
||||
opt.verbose, DBG_IPC,
|
||||
NULL, NULL);
|
||||
if (!opt.autostart && gpg_err_code (rc) == GPG_ERR_NO_AGENT)
|
||||
{
|
||||
|
@ -1079,6 +1080,12 @@ agent_keytotpm (ctrl_t ctrl, const char *hexgrip)
|
|||
|
||||
snprintf(line, DIM(line), "KEYTOTPM %s\n", hexgrip);
|
||||
|
||||
if (strchr (hexgrip, ','))
|
||||
{
|
||||
log_error ("storing a part of a dual key is not yet supported\n");
|
||||
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
rc = start_agent (ctrl, 0);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
@ -1108,6 +1115,13 @@ agent_keytocard (const char *hexgrip, int keyno, int force,
|
|||
|
||||
memset (&parm, 0, sizeof parm);
|
||||
|
||||
if (strchr (hexgrip, ','))
|
||||
{
|
||||
log_error ("storing a part of a dual key is not yet supported\n");
|
||||
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
|
||||
snprintf (line, DIM(line), "KEYTOCARD %s%s %s OPENPGP.%d %s%s%s",
|
||||
force?"--force ": "", hexgrip, serialno, keyno, timestamp,
|
||||
ecdh_param_str? " ":"", ecdh_param_str? ecdh_param_str:"");
|
||||
|
@ -2239,9 +2253,9 @@ agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk)
|
|||
{
|
||||
gpg_error_t err;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
char *hexgrip;
|
||||
|
||||
char *hexgrip, *p;
|
||||
struct keyinfo_data_parm_s keyinfo;
|
||||
int result, result2;
|
||||
|
||||
memset (&keyinfo, 0, sizeof keyinfo);
|
||||
|
||||
|
@ -2252,28 +2266,64 @@ agent_probe_secret_key (ctrl_t ctrl, PKT_public_key *pk)
|
|||
err = hexkeygrip_from_pk (pk, &hexgrip);
|
||||
if (err)
|
||||
return 0;
|
||||
if ((p=strchr (hexgrip, ',')))
|
||||
*p++ = 0;
|
||||
|
||||
snprintf (line, sizeof line, "KEYINFO %s", hexgrip);
|
||||
xfree (hexgrip);
|
||||
|
||||
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
|
||||
keyinfo_status_cb, &keyinfo);
|
||||
xfree (keyinfo.serialno);
|
||||
if (err)
|
||||
return 0;
|
||||
result = 0;
|
||||
else if (keyinfo.card_available)
|
||||
result = 4;
|
||||
else if (keyinfo.passphrase_cached)
|
||||
result = 3;
|
||||
else if (keyinfo.is_smartcard)
|
||||
result = 2;
|
||||
else
|
||||
result = 1;
|
||||
|
||||
if (keyinfo.card_available)
|
||||
return 4;
|
||||
if (!p)
|
||||
{
|
||||
xfree (hexgrip);
|
||||
return result; /* Not a dual algo - we are ready. */
|
||||
}
|
||||
|
||||
if (keyinfo.passphrase_cached)
|
||||
return 3;
|
||||
/* Now check the second keygrip. */
|
||||
memset (&keyinfo, 0, sizeof keyinfo);
|
||||
snprintf (line, sizeof line, "KEYINFO %s", p);
|
||||
|
||||
if (keyinfo.is_smartcard)
|
||||
return 2;
|
||||
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
|
||||
keyinfo_status_cb, &keyinfo);
|
||||
xfree (keyinfo.serialno);
|
||||
if (err)
|
||||
result2 = 0;
|
||||
else if (keyinfo.card_available)
|
||||
result2 = 4;
|
||||
else if (keyinfo.passphrase_cached)
|
||||
result2 = 3;
|
||||
else if (keyinfo.is_smartcard)
|
||||
result2 = 2;
|
||||
else
|
||||
result2 = 1;
|
||||
|
||||
return 1;
|
||||
xfree (hexgrip);
|
||||
|
||||
if (result == result2)
|
||||
return result; /* Both keys have the same status. */
|
||||
else if (!result && result2)
|
||||
return 0; /* Only first key available - return no key. */
|
||||
else if (result && !result2)
|
||||
return 0; /* Only second key not availabale - return no key. */
|
||||
else if (result == 4 || result == 2)
|
||||
return result; /* First key on card - don't care where the second is. */
|
||||
else
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* Ask the agent whether a secret key is available for any of the
|
||||
keys (primary or sub) in KEYBLOCK. Returns 0 if available. */
|
||||
gpg_error_t
|
||||
|
@ -2285,6 +2335,8 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
|
|||
kbnode_t kbctx, node;
|
||||
int nkeys; /* (always zero in secret_keygrips mode) */
|
||||
unsigned char grip[KEYGRIP_LEN];
|
||||
unsigned char grip2[KEYGRIP_LEN];
|
||||
int grip2_valid;
|
||||
const unsigned char *s;
|
||||
unsigned int n;
|
||||
|
||||
|
@ -2319,8 +2371,9 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
|
|||
}
|
||||
if (err)
|
||||
{
|
||||
log_info ("problem with fast path key listing: %s - ignored\n",
|
||||
gpg_strerror (err));
|
||||
if (opt.quiet)
|
||||
log_info ("problem with fast path key listing: %s - ignored\n",
|
||||
gpg_strerror (err));
|
||||
err = 0;
|
||||
}
|
||||
/* We want to do this only once. */
|
||||
|
@ -2339,22 +2392,30 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
|
|||
if (ctrl && ctrl->secret_keygrips)
|
||||
{
|
||||
/* We got an array with all secret keygrips. Check this. */
|
||||
err = keygrip_from_pk (node->pkt->pkt.public_key, grip);
|
||||
err = keygrip_from_pk (node->pkt->pkt.public_key, grip, 0);
|
||||
if (err)
|
||||
return err;
|
||||
err = keygrip_from_pk (node->pkt->pkt.public_key, grip2, 1);
|
||||
if (err && gpg_err_code (err) != GPG_ERR_FALSE)
|
||||
return err;
|
||||
grip2_valid = !err;
|
||||
|
||||
for (s=ctrl->secret_keygrips, n = 0;
|
||||
n < ctrl->secret_keygrips_len;
|
||||
s += 20, n += 20)
|
||||
{
|
||||
if (!memcmp (s, grip, 20))
|
||||
return 0;
|
||||
if (grip2_valid && !memcmp (s, grip2, 20))
|
||||
return 0;
|
||||
}
|
||||
err = gpg_error (GPG_ERR_NO_SECKEY);
|
||||
/* Keep on looping over the keyblock. Never bump nkeys. */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nkeys && ((p - line) + 41) > (ASSUAN_LINELENGTH - 2))
|
||||
if (nkeys
|
||||
&& ((p - line) + 4*KEYGRIP_LEN+1+1) > (ASSUAN_LINELENGTH - 2))
|
||||
{
|
||||
err = assuan_transact (agent_ctx, line,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
|
@ -2364,13 +2425,24 @@ agent_probe_any_secret_key (ctrl_t ctrl, kbnode_t keyblock)
|
|||
nkeys = 0;
|
||||
}
|
||||
|
||||
err = keygrip_from_pk (node->pkt->pkt.public_key, grip);
|
||||
err = keygrip_from_pk (node->pkt->pkt.public_key, grip, 0);
|
||||
if (err)
|
||||
return err;
|
||||
*p++ = ' ';
|
||||
bin2hex (grip, 20, p);
|
||||
p += 40;
|
||||
nkeys++;
|
||||
|
||||
err = keygrip_from_pk (node->pkt->pkt.public_key, grip2, 1);
|
||||
if (err && gpg_err_code (err) != GPG_ERR_FALSE)
|
||||
return err;
|
||||
if (!err) /* Add the second keygrip from dual algos. */
|
||||
{
|
||||
*p++ = ' ';
|
||||
bin2hex (grip2, 20, p);
|
||||
p += 40;
|
||||
nkeys++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2397,6 +2469,7 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
|
|||
gpg_error_t err;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
struct keyinfo_data_parm_s keyinfo;
|
||||
const char *s;
|
||||
|
||||
memset (&keyinfo, 0,sizeof keyinfo);
|
||||
|
||||
|
@ -2406,10 +2479,20 @@ agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
if (!hexkeygrip || strlen (hexkeygrip) != 40)
|
||||
/* FIXME: Support dual keys. Maybe under the assumption that the
|
||||
* first key might be on a card. */
|
||||
if (!hexkeygrip)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
s = strchr (hexkeygrip, ',');
|
||||
if (!s)
|
||||
s = hexkeygrip + strlen (hexkeygrip);
|
||||
if (s - hexkeygrip != 40)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
snprintf (line, DIM(line), "KEYINFO %s", hexkeygrip);
|
||||
/* Note that for a dual algo we only get info for the first key.
|
||||
* FIXME: We need to see how we can show the status of the second
|
||||
* key in a key listing. */
|
||||
snprintf (line, DIM(line), "KEYINFO %.40s", hexkeygrip);
|
||||
|
||||
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
|
||||
keyinfo_status_cb, &keyinfo);
|
||||
|
@ -2795,6 +2878,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
|
|||
membuf_t data;
|
||||
size_t n, len;
|
||||
char *p, *buf, *endp;
|
||||
const char *keygrip2 = NULL;
|
||||
struct default_inq_parm_s dfltparm;
|
||||
|
||||
memset (&dfltparm, 0, sizeof dfltparm);
|
||||
|
@ -2803,13 +2887,26 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
|
|||
dfltparm.keyinfo.mainkeyid = mainkeyid;
|
||||
dfltparm.keyinfo.pubkey_algo = pubkey_algo;
|
||||
|
||||
if (!keygrip || strlen(keygrip) != 40
|
||||
|| !s_ciphertext || !r_buf || !r_buflen || !r_padding)
|
||||
if (!keygrip || !s_ciphertext || !r_buf || !r_buflen || !r_padding)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
|
||||
*r_buf = NULL;
|
||||
*r_padding = -1;
|
||||
|
||||
/* Parse the keygrip in case of a dual algo. */
|
||||
keygrip2 = strchr (keygrip, ',');
|
||||
if (!keygrip2)
|
||||
keygrip2 = keygrip + strlen (keygrip);
|
||||
if (keygrip2 - keygrip != 40)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
if (*keygrip2)
|
||||
{
|
||||
keygrip2++;
|
||||
if (strlen (keygrip2) != 40)
|
||||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
}
|
||||
|
||||
|
||||
err = start_agent (ctrl, 0);
|
||||
if (err)
|
||||
return err;
|
||||
|
@ -2820,11 +2917,19 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
snprintf (line, sizeof line, "SETKEY %s", keygrip);
|
||||
snprintf (line, sizeof line, "SETKEY %.40s", keygrip);
|
||||
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (*keygrip2)
|
||||
{
|
||||
snprintf (line, sizeof line, "SETKEY --another %.40s", keygrip2);
|
||||
err = assuan_transact (agent_ctx, line, NULL, NULL,NULL,NULL,NULL,NULL);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (desc)
|
||||
{
|
||||
snprintf (line, DIM(line), "SETKEYDESC %s", desc);
|
||||
|
@ -2843,7 +2948,8 @@ agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
|
|||
err = make_canon_sexp (s_ciphertext, &parm.ciphertext, &parm.ciphertextlen);
|
||||
if (err)
|
||||
return err;
|
||||
err = assuan_transact (agent_ctx, "PKDECRYPT",
|
||||
err = assuan_transact (agent_ctx,
|
||||
*keygrip2? "PKDECRYPT --kem=PQC-PGP":"PKDECRYPT",
|
||||
put_membuf_cb, &data,
|
||||
inq_ciphertext_cb, &parm,
|
||||
padding_info_cb, r_padding);
|
||||
|
@ -3173,6 +3279,7 @@ agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
|
|||
return err;
|
||||
}
|
||||
|
||||
/* FIXME: Shall we add support to DELETE_KEY for dual keys? */
|
||||
snprintf (line, DIM(line), "DELETE_KEY%s %s",
|
||||
force? " --force":"", hexkeygrip);
|
||||
err = assuan_transact (agent_ctx, line, NULL, NULL,
|
||||
|
|
|
@ -166,7 +166,8 @@ create_context (ctrl_t ctrl, assuan_context_t *r_ctx)
|
|||
err = start_new_dirmngr (&ctx,
|
||||
GPG_ERR_SOURCE_DEFAULT,
|
||||
opt.dirmngr_program,
|
||||
opt.autostart, opt.verbose, DBG_IPC,
|
||||
opt.autostart?ASSHELP_FLAG_AUTOSTART:0,
|
||||
opt.verbose, DBG_IPC,
|
||||
NULL /*gpg_status2*/, ctrl);
|
||||
if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_DIRMNGR)
|
||||
{
|
||||
|
|
|
@ -94,8 +94,6 @@ gpg_keyboxd_deinit_session_data (ctrl_t ctrl)
|
|||
log_error ("oops: trying to cleanup an active keyboxd context\n");
|
||||
else
|
||||
{
|
||||
kbx_client_data_release (kbl->kcd);
|
||||
kbl->kcd = NULL;
|
||||
if (kbl->ctx && in_transaction)
|
||||
{
|
||||
/* This is our hack to commit the changes done during a
|
||||
|
@ -112,6 +110,15 @@ gpg_keyboxd_deinit_session_data (ctrl_t ctrl)
|
|||
}
|
||||
assuan_release (kbl->ctx);
|
||||
kbl->ctx = NULL;
|
||||
/*
|
||||
* Since there may be pipe output FD sent to the server (so
|
||||
* that it can receive data through the pipe), we should
|
||||
* release the assuan connection before releasing KBL->KCD.
|
||||
* This way, the data receiving thread can finish cleanly,
|
||||
* and we can join the thread.
|
||||
*/
|
||||
kbx_client_data_release (kbl->kcd);
|
||||
kbl->kcd = NULL;
|
||||
}
|
||||
xfree (kbl);
|
||||
}
|
||||
|
@ -143,7 +150,8 @@ create_new_context (ctrl_t ctrl, assuan_context_t *r_ctx)
|
|||
err = start_new_keyboxd (&ctx,
|
||||
GPG_ERR_SOURCE_DEFAULT,
|
||||
opt.keyboxd_program,
|
||||
opt.autostart, opt.verbose, DBG_IPC,
|
||||
opt.autostart?ASSHELP_FLAG_AUTOSTART:0,
|
||||
opt.verbose, DBG_IPC,
|
||||
NULL, ctrl);
|
||||
if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_KEYBOXD)
|
||||
{
|
||||
|
@ -223,7 +231,7 @@ open_context (ctrl_t ctrl, keyboxd_local_t *r_kbl)
|
|||
return err;
|
||||
}
|
||||
|
||||
err = kbx_client_data_new (&kbl->kcd, kbl->ctx, 1);
|
||||
err = kbx_client_data_new (&kbl->kcd, kbl->ctx, 0);
|
||||
if (err)
|
||||
{
|
||||
assuan_release (kbl->ctx);
|
||||
|
|
|
@ -28,9 +28,7 @@
|
|||
# include <readline/readline.h>
|
||||
#endif /*HAVE_LIBREADLINE*/
|
||||
|
||||
#if GNUPG_MAJOR_VERSION != 1
|
||||
# include "gpg.h"
|
||||
#endif /*GNUPG_MAJOR_VERSION != 1*/
|
||||
#include "../common/util.h"
|
||||
#include "../common/i18n.h"
|
||||
#include "../common/ttyio.h"
|
||||
|
@ -39,11 +37,7 @@
|
|||
#include "main.h"
|
||||
#include "keyserver-internal.h"
|
||||
|
||||
#if GNUPG_MAJOR_VERSION == 1
|
||||
# include "cardglue.h"
|
||||
#else /*GNUPG_MAJOR_VERSION!=1*/
|
||||
# include "call-agent.h"
|
||||
#endif /*GNUPG_MAJOR_VERSION!=1*/
|
||||
#include "call-agent.h"
|
||||
|
||||
#define CONTROL_D ('D' - 'A' + 1)
|
||||
|
||||
|
@ -949,14 +943,6 @@ get_data_from_file (const char *fname, char **r_buffer)
|
|||
*r_buffer = NULL;
|
||||
|
||||
fp = es_fopen (fname, "rb");
|
||||
#if GNUPG_MAJOR_VERSION == 1
|
||||
if (fp && is_secured_file (fileno (fp)))
|
||||
{
|
||||
fclose (fp);
|
||||
fp = NULL;
|
||||
errno = EPERM;
|
||||
}
|
||||
#endif
|
||||
if (!fp)
|
||||
{
|
||||
tty_printf (_("can't open '%s': %s\n"), fname, strerror (errno));
|
||||
|
@ -992,14 +978,6 @@ put_data_to_file (const char *fname, const void *buffer, size_t length)
|
|||
estream_t fp;
|
||||
|
||||
fp = es_fopen (fname, "wb");
|
||||
#if GNUPG_MAJOR_VERSION == 1
|
||||
if (fp && is_secured_file (fileno (fp)))
|
||||
{
|
||||
fclose (fp);
|
||||
fp = NULL;
|
||||
errno = EPERM;
|
||||
}
|
||||
#endif
|
||||
if (!fp)
|
||||
{
|
||||
tty_printf (_("can't create '%s': %s\n"), fname, strerror (errno));
|
||||
|
|
|
@ -63,7 +63,7 @@ dearmor_file( const char *fname )
|
|||
|
||||
push_armor_filter ( afx, inp );
|
||||
|
||||
if( (rc = open_outfile (-1, fname, 0, 0, &out)) )
|
||||
if( (rc = open_outfile (GNUPG_INVALID_FD, fname, 0, 0, &out)) )
|
||||
goto leave;
|
||||
|
||||
iobuf_copy (out, inp);
|
||||
|
@ -107,7 +107,7 @@ enarmor_file( const char *fname )
|
|||
}
|
||||
|
||||
|
||||
if( (rc = open_outfile (-1, fname, 1, 0, &out )) )
|
||||
if( (rc = open_outfile (GNUPG_INVALID_FD, fname, 1, 0, &out )) )
|
||||
goto leave;
|
||||
|
||||
afx->what = 4;
|
||||
|
|
|
@ -205,6 +205,7 @@ aead_checktag (decode_filter_ctx_t dfx, int final, const void *tagbuf)
|
|||
{
|
||||
log_error ("gcry_cipher_checktag%s failed: %s\n",
|
||||
final? " (final)":"", gpg_strerror (err));
|
||||
write_status_error ("aead_checktag", err);
|
||||
return err;
|
||||
}
|
||||
if (DBG_FILTER)
|
||||
|
|
|
@ -100,7 +100,8 @@ decrypt_message (ctrl_t ctrl, const char *filename)
|
|||
/* Same as decrypt_message but takes a file descriptor for input and
|
||||
output. */
|
||||
gpg_error_t
|
||||
decrypt_message_fd (ctrl_t ctrl, int input_fd, int output_fd)
|
||||
decrypt_message_fd (ctrl_t ctrl, gnupg_fd_t input_fd,
|
||||
gnupg_fd_t output_fd)
|
||||
{
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* No server mode yet. */
|
||||
|
@ -138,13 +139,25 @@ decrypt_message_fd (ctrl_t ctrl, int input_fd, int output_fd)
|
|||
return err;
|
||||
}
|
||||
|
||||
opt.outfp = es_fdopen_nc (output_fd, "wb");
|
||||
if (is_secured_file (output_fd))
|
||||
{
|
||||
char xname[64];
|
||||
|
||||
err = gpg_error (GPG_ERR_EPERM);
|
||||
snprintf (xname, sizeof xname, "[fd %d]", FD_DBG (output_fd));
|
||||
log_error (_("can't open '%s': %s\n"), xname, gpg_strerror (err));
|
||||
iobuf_close (fp);
|
||||
release_progress_context (pfx);
|
||||
return err;
|
||||
}
|
||||
|
||||
opt.outfp = open_stream_nc (output_fd, "w");
|
||||
if (!opt.outfp)
|
||||
{
|
||||
char xname[64];
|
||||
|
||||
err = gpg_error_from_syserror ();
|
||||
snprintf (xname, sizeof xname, "[fd %d]", output_fd);
|
||||
snprintf (xname, sizeof xname, "[fd %d]", FD_DBG (output_fd));
|
||||
log_error (_("can't open '%s': %s\n"), xname, gpg_strerror (err));
|
||||
iobuf_close (fp);
|
||||
release_progress_context (pfx);
|
||||
|
|
31
g10/ecdh.c
31
g10/ecdh.c
|
@ -156,11 +156,11 @@ build_kdf_params (unsigned char kdf_params[256], size_t *r_size,
|
|||
return gpg_error_from_syserror ();
|
||||
|
||||
/* variable-length field 1, curve name OID */
|
||||
err = gpg_mpi_write_nohdr (obuf, pkey[0]);
|
||||
err = gpg_mpi_write_opaque_nohdr (obuf, pkey[0]);
|
||||
/* fixed-length field 2 */
|
||||
iobuf_put (obuf, PUBKEY_ALGO_ECDH);
|
||||
/* variable-length field 3, KDF params */
|
||||
err = (err ? err : gpg_mpi_write_nohdr (obuf, pkey[2]));
|
||||
err = (err ? err : gpg_mpi_write_opaque_nohdr (obuf, pkey[2]));
|
||||
/* fixed-length field 4 */
|
||||
iobuf_write (obuf, "Anonymous Sender ", 20);
|
||||
/* fixed-length field 5, recipient fp (or first 20 octets of fp) */
|
||||
|
@ -524,8 +524,7 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN],
|
|||
size_t nbytes;
|
||||
byte *data_buf;
|
||||
int data_buf_size;
|
||||
byte *in;
|
||||
const void *p;
|
||||
const unsigned char *p;
|
||||
unsigned int nbits;
|
||||
|
||||
*r_result = NULL;
|
||||
|
@ -538,7 +537,7 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN],
|
|||
nbytes = (nbits+7)/8;
|
||||
|
||||
data_buf_size = nbytes;
|
||||
if ((data_buf_size & 7) != 1)
|
||||
if ((data_buf_size & 7) != 1 || data_buf_size <= 1 + 8)
|
||||
{
|
||||
log_error ("can't use a shared secret of %d bytes for ecdh\n",
|
||||
data_buf_size);
|
||||
|
@ -546,7 +545,10 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN],
|
|||
return gpg_error (GPG_ERR_BAD_DATA);
|
||||
}
|
||||
|
||||
data_buf = xtrymalloc_secure( 1 + 2*data_buf_size + 8);
|
||||
/* The first octet is for length. It's longer than the result
|
||||
because of one additional block of AESWRAP. */
|
||||
data_buf_size -= 1 + 8;
|
||||
data_buf = xtrymalloc_secure (data_buf_size);
|
||||
if (!data_buf)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
|
@ -560,22 +562,18 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN],
|
|||
gcry_cipher_close (hd);
|
||||
return gpg_error (GPG_ERR_BAD_MPI);
|
||||
}
|
||||
memcpy (data_buf, p, nbytes);
|
||||
if (data_buf[0] != nbytes-1)
|
||||
if (p[0] != nbytes-1)
|
||||
{
|
||||
log_error ("ecdh inconsistent size\n");
|
||||
xfree (data_buf);
|
||||
gcry_cipher_close (hd);
|
||||
return gpg_error (GPG_ERR_BAD_MPI);
|
||||
}
|
||||
in = data_buf+data_buf_size;
|
||||
data_buf_size = data_buf[0];
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
log_printhex (data_buf+1, data_buf_size, "ecdh decrypting :");
|
||||
log_printhex (p+1, nbytes-1, "ecdh decrypting :");
|
||||
|
||||
err = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1,
|
||||
data_buf_size);
|
||||
err = gcry_cipher_decrypt (hd, data_buf, data_buf_size, p+1, nbytes-1);
|
||||
gcry_cipher_close (hd);
|
||||
if (err)
|
||||
{
|
||||
|
@ -585,10 +583,8 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN],
|
|||
return err;
|
||||
}
|
||||
|
||||
data_buf_size -= 8;
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
log_printhex (in, data_buf_size, "ecdh decrypted to :");
|
||||
log_printhex (data_buf, data_buf_size, "ecdh decrypted to :");
|
||||
|
||||
/* Padding is removed later. */
|
||||
/* if (in[data_buf_size-1] > 8 ) */
|
||||
|
@ -598,7 +594,8 @@ pk_ecdh_decrypt (gcry_mpi_t *r_result, const byte sk_fp[MAX_FINGERPRINT_LEN],
|
|||
/* return gpg_error (GPG_ERR_BAD_KEY); */
|
||||
/* } */
|
||||
|
||||
err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, in, data_buf_size, NULL);
|
||||
err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, data_buf,
|
||||
data_buf_size, NULL);
|
||||
xfree (data_buf);
|
||||
if (err)
|
||||
{
|
||||
|
|
|
@ -507,7 +507,8 @@ encrypt_simple (const char *filename, int mode, int use_seskey)
|
|||
/**/ : "CFB");
|
||||
}
|
||||
|
||||
if ( rc || (rc = open_outfile (-1, filename, opt.armor? 1:0, 0, &out )))
|
||||
if (rc || (rc = open_outfile (GNUPG_INVALID_FD, filename, opt.armor? 1:0,
|
||||
0, &out )))
|
||||
{
|
||||
iobuf_cancel (inp);
|
||||
xfree (cfx.dek);
|
||||
|
@ -757,15 +758,15 @@ write_symkey_enc (STRING2KEY *symkey_s2k, aead_algo_t aead_algo,
|
|||
* Encrypt the file with the given userids (or ask if none is
|
||||
* supplied). Either FILENAME or FILEFD must be given, but not both.
|
||||
* The caller may provide a checked list of public keys in
|
||||
* PROVIDED_PKS; if not the function builds a list of keys on its own.
|
||||
* PROVIDED_KEYS; if not the function builds a list of keys on its own.
|
||||
*
|
||||
* Note that FILEFD is currently only used by cmd_encrypt in the
|
||||
* not yet finished server.c.
|
||||
*/
|
||||
int
|
||||
encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
|
||||
encrypt_crypt (ctrl_t ctrl, gnupg_fd_t filefd, const char *filename,
|
||||
strlist_t remusr, int use_symkey, pk_list_t provided_keys,
|
||||
int outputfd)
|
||||
gnupg_fd_t outputfd)
|
||||
{
|
||||
iobuf_t inp = NULL;
|
||||
iobuf_t out = NULL;
|
||||
|
@ -783,7 +784,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
|
|||
PK_LIST pk_list;
|
||||
int do_compress;
|
||||
|
||||
if (filefd != -1 && filename)
|
||||
if (filefd != GNUPG_INVALID_FD && filename)
|
||||
return gpg_error (GPG_ERR_INV_ARG); /* Both given. */
|
||||
|
||||
do_compress = !!opt.compress_algo;
|
||||
|
@ -814,7 +815,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
|
|||
|
||||
/* Prepare iobufs. */
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
if (filefd == -1)
|
||||
if (filefd == GNUPG_INVALID_FD)
|
||||
inp = iobuf_open (filename);
|
||||
else
|
||||
{
|
||||
|
@ -822,7 +823,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
|
|||
gpg_err_set_errno (ENOSYS);
|
||||
}
|
||||
#else
|
||||
if (filefd == -1)
|
||||
if (filefd == GNUPG_INVALID_FD)
|
||||
inp = iobuf_open (filename);
|
||||
else
|
||||
inp = iobuf_fdopen_nc (filefd, "rb");
|
||||
|
@ -840,8 +841,8 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
|
|||
char xname[64];
|
||||
|
||||
rc = gpg_error_from_syserror ();
|
||||
if (filefd != -1)
|
||||
snprintf (xname, sizeof xname, "[fd %d]", filefd);
|
||||
if (filefd != GNUPG_INVALID_FD)
|
||||
snprintf (xname, sizeof xname, "[fd %d]", FD_DBG (filefd));
|
||||
else if (!filename)
|
||||
strcpy (xname, "[stdin]");
|
||||
else
|
||||
|
@ -1121,6 +1122,7 @@ write_pubkey_enc (ctrl_t ctrl,
|
|||
enc->pubkey_algo = pk->pubkey_algo;
|
||||
keyid_from_pk( pk, enc->keyid );
|
||||
enc->throw_keyid = throw_keyid;
|
||||
enc->seskey_algo = dek->algo; /* (Used only by PUBKEY_ALGO_KYBER.) */
|
||||
|
||||
/* Okay, what's going on: We have the session key somewhere in
|
||||
* the structure DEK and want to encode this session key in an
|
||||
|
@ -1136,7 +1138,7 @@ write_pubkey_enc (ctrl_t ctrl,
|
|||
* build_packet(). */
|
||||
frame = encode_session_key (pk->pubkey_algo, dek,
|
||||
pubkey_nbits (pk->pubkey_algo, pk->pkey));
|
||||
rc = pk_encrypt (pk->pubkey_algo, enc->data, frame, pk, pk->pkey);
|
||||
rc = pk_encrypt (pk, frame, dek->algo, enc->data);
|
||||
gcry_mpi_release (frame);
|
||||
if (rc)
|
||||
log_error ("pubkey_encrypt failed: %s\n", gpg_strerror (rc) );
|
||||
|
@ -1224,7 +1226,8 @@ encrypt_crypt_files (ctrl_t ctrl, int nfiles, char **files, strlist_t remusr)
|
|||
}
|
||||
line[strlen(line)-1] = '\0';
|
||||
print_file_status(STATUS_FILE_START, line, 2);
|
||||
rc = encrypt_crypt (ctrl, -1, line, remusr, 0, NULL, -1);
|
||||
rc = encrypt_crypt (ctrl, GNUPG_INVALID_FD, line, remusr,
|
||||
0, NULL, GNUPG_INVALID_FD);
|
||||
if (rc)
|
||||
log_error ("encryption of '%s' failed: %s\n",
|
||||
print_fname_stdin(line), gpg_strerror (rc) );
|
||||
|
@ -1236,7 +1239,8 @@ encrypt_crypt_files (ctrl_t ctrl, int nfiles, char **files, strlist_t remusr)
|
|||
while (nfiles--)
|
||||
{
|
||||
print_file_status(STATUS_FILE_START, *files, 2);
|
||||
if ( (rc = encrypt_crypt (ctrl, -1, *files, remusr, 0, NULL, -1)) )
|
||||
if ((rc = encrypt_crypt (ctrl, GNUPG_INVALID_FD, *files, remusr,
|
||||
0, NULL, GNUPG_INVALID_FD)))
|
||||
log_error("encryption of '%s' failed: %s\n",
|
||||
print_fname_stdin(*files), gpg_strerror (rc) );
|
||||
write_status( STATUS_FILE_DONE );
|
||||
|
|
27
g10/export.c
27
g10/export.c
|
@ -428,7 +428,7 @@ do_export (ctrl_t ctrl, strlist_t users, int secret, unsigned int options,
|
|||
|
||||
memset( &zfx, 0, sizeof zfx);
|
||||
|
||||
rc = open_outfile (-1, NULL, 0, !!secret, &out );
|
||||
rc = open_outfile (GNUPG_INVALID_FD, NULL, 0, !!secret, &out);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
@ -1961,6 +1961,11 @@ do_export_one_keyblock (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
|||
err = 0;
|
||||
continue;
|
||||
}
|
||||
if (strchr (hexgrip, ','))
|
||||
{
|
||||
log_error ("exporting a secret dual key is not yet supported\n");
|
||||
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
xfree (serialno);
|
||||
serialno = NULL;
|
||||
|
@ -2707,18 +2712,18 @@ export_one_ssh_key (estream_t fp, PKT_public_key *pk)
|
|||
blob = get_membuf (&mb, &bloblen);
|
||||
if (blob)
|
||||
{
|
||||
struct b64state b64_state;
|
||||
gpgrt_b64state_t b64_state;
|
||||
|
||||
es_fprintf (fp, "%s ", identifier);
|
||||
err = b64enc_start_es (&b64_state, fp, "");
|
||||
if (err)
|
||||
b64_state = gpgrt_b64enc_start (fp, "");
|
||||
if (!b64_state)
|
||||
{
|
||||
xfree (blob);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
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_fprintf (fp, " openpgp:0x%08lX\n", (ulong)keyid_from_pk (pk, NULL));
|
||||
xfree (blob);
|
||||
|
@ -2962,7 +2967,7 @@ export_secret_ssh_key (ctrl_t ctrl, const char *userid)
|
|||
int pkalgo;
|
||||
int i;
|
||||
gcry_mpi_t keyparam[10] = { NULL };
|
||||
struct b64state b64_state;
|
||||
gpgrt_b64state_t b64_state;
|
||||
|
||||
init_membuf_secure (&mb, 1024);
|
||||
init_membuf_secure (&mb2, 1024);
|
||||
|
@ -3140,11 +3145,11 @@ export_secret_ssh_key (ctrl_t ctrl, const char *userid)
|
|||
goto leave;
|
||||
}
|
||||
|
||||
err = b64enc_start_es (&b64_state, fp, "OPENSSH PRIVATE_KEY");
|
||||
if (err)
|
||||
b64_state = gpgrt_b64enc_start (fp, "OPENSSH PRIVATE_KEY");
|
||||
if (!b64_state)
|
||||
goto leave;
|
||||
err = b64enc_write (&b64_state, blob, bloblen);
|
||||
b64enc_finish (&b64_state);
|
||||
err = gpgrt_b64enc_write (b64_state, blob, bloblen);
|
||||
gpgrt_b64enc_finish (b64_state);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
||||
|
|
|
@ -29,6 +29,9 @@ typedef struct {
|
|||
size_t maxbuf_size;
|
||||
} md_filter_context_t;
|
||||
|
||||
typedef struct md_thd_filter_context *md_thd_filter_context_t;
|
||||
void md_thd_filter_set_md (md_thd_filter_context_t mfx, gcry_md_hd_t md);
|
||||
|
||||
typedef struct {
|
||||
int refcount; /* Initialized to 1. */
|
||||
|
||||
|
@ -165,6 +168,7 @@ typedef struct {
|
|||
|
||||
/*-- mdfilter.c --*/
|
||||
int md_filter( void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len);
|
||||
int md_thd_filter( void *opaque, int control, iobuf_t a, byte *buf, size_t *ret_len);
|
||||
void free_md_filter_context( md_filter_context_t *mfx );
|
||||
|
||||
/*-- armor.c --*/
|
||||
|
|
17
g10/getkey.c
17
g10/getkey.c
|
@ -3779,6 +3779,16 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (opt.flags.require_pqc_encryption
|
||||
&& (req_usage & PUBKEY_USAGE_ENC)
|
||||
&& pk->pubkey_algo != PUBKEY_ALGO_KYBER)
|
||||
{
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("\tsubkey is not quantum-resistant\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (want_secret)
|
||||
{
|
||||
int secret_key_avail = agent_probe_secret_key (NULL, pk);
|
||||
|
@ -3857,6 +3867,13 @@ finish_lookup (kbnode_t keyblock, unsigned int req_usage, int want_exact,
|
|||
if (DBG_LOOKUP)
|
||||
log_debug ("\tprimary key has expired\n");
|
||||
}
|
||||
else if (opt.flags.require_pqc_encryption
|
||||
&& (req_usage & PUBKEY_USAGE_ENC)
|
||||
&& pk->pubkey_algo != PUBKEY_ALGO_KYBER)
|
||||
{
|
||||
if (DBG_LOOKUP)
|
||||
log_debug ("\tprimary key is not quantum-resistant\n");
|
||||
}
|
||||
else /* Okay. */
|
||||
{
|
||||
if (DBG_LOOKUP)
|
||||
|
|
57
g10/gpg.c
57
g10/gpg.c
|
@ -136,6 +136,7 @@ enum cmd_and_opt_values
|
|||
aQuickSetExpire,
|
||||
aQuickSetPrimaryUid,
|
||||
aQuickUpdatePref,
|
||||
aQuickSetOwnertrust,
|
||||
aListConfig,
|
||||
aListGcryptConfig,
|
||||
aGPGConfList,
|
||||
|
@ -206,6 +207,7 @@ enum cmd_and_opt_values
|
|||
oWithV5Fingerprint,
|
||||
oWithFingerprint,
|
||||
oWithSubkeyFingerprint,
|
||||
oWithoutSubkeyFingerprint,
|
||||
oWithICAOSpelling,
|
||||
oWithKeygrip,
|
||||
oWithKeyScreening,
|
||||
|
@ -354,6 +356,7 @@ enum cmd_and_opt_values
|
|||
oAllowSecretKeyImport,
|
||||
oAllowOldCipherAlgos,
|
||||
oEnableSpecialFilenames,
|
||||
oDisableFdTranslation,
|
||||
oNoLiteral,
|
||||
oSetFilesize,
|
||||
oHonorHttpProxy,
|
||||
|
@ -453,6 +456,7 @@ enum cmd_and_opt_values
|
|||
oAssertSigner,
|
||||
oAssertPubkeyAlgo,
|
||||
oKbxBufferSize,
|
||||
oRequirePQCEncryption,
|
||||
|
||||
oNoop
|
||||
};
|
||||
|
@ -502,6 +506,7 @@ static gpgrt_opt_t opts[] = {
|
|||
N_("quickly set a new expiration date")),
|
||||
ARGPARSE_c (aQuickSetPrimaryUid, "quick-set-primary-uid", "@"),
|
||||
ARGPARSE_c (aQuickUpdatePref, "quick-update-pref", "@"),
|
||||
ARGPARSE_c (aQuickSetOwnertrust, "quick-set-ownertrust", "@"),
|
||||
ARGPARSE_c (aFullKeygen, "full-generate-key" ,
|
||||
N_("full featured key pair generation")),
|
||||
ARGPARSE_c (aFullKeygen, "full-gen-key", "@"),
|
||||
|
@ -823,6 +828,7 @@ static gpgrt_opt_t opts[] = {
|
|||
ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"),
|
||||
ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprint", "@"),
|
||||
ARGPARSE_s_n (oWithSubkeyFingerprint, "with-subkey-fingerprints", "@"),
|
||||
ARGPARSE_s_n (oWithoutSubkeyFingerprint, "without-subkey-fingerprint", "@"),
|
||||
ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"),
|
||||
ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"),
|
||||
ARGPARSE_s_n (oWithKeyScreening,"with-key-screening", "@"),
|
||||
|
@ -880,7 +886,6 @@ static gpgrt_opt_t opts[] = {
|
|||
ARGPARSE_s_n (oAllowOldCipherAlgos, "allow-old-cipher-algos", "@"),
|
||||
ARGPARSE_s_s (oWeakDigest, "weak-digest","@"),
|
||||
ARGPARSE_s_s (oVerifyOptions, "verify-options", "@"),
|
||||
ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"),
|
||||
ARGPARSE_s_n (oNoRandomSeedFile, "no-random-seed-file", "@"),
|
||||
ARGPARSE_s_n (oNoSigCache, "no-sig-cache", "@"),
|
||||
ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"),
|
||||
|
@ -892,7 +897,7 @@ static gpgrt_opt_t opts[] = {
|
|||
ARGPARSE_s_s (oCipherAlgo, "cipher-algo", "@"),
|
||||
ARGPARSE_s_s (oDigestAlgo, "digest-algo", "@"),
|
||||
ARGPARSE_s_s (oCertDigestAlgo, "cert-digest-algo", "@"),
|
||||
|
||||
ARGPARSE_s_n (oRequirePQCEncryption, "require-pqc-encryption", "@"),
|
||||
|
||||
ARGPARSE_header (NULL, N_("Options for unattended use")),
|
||||
|
||||
|
@ -912,6 +917,8 @@ static gpgrt_opt_t opts[] = {
|
|||
ARGPARSE_s_i (oPassphraseRepeat,"passphrase-repeat", "@"),
|
||||
ARGPARSE_s_s (oPinentryMode, "pinentry-mode", "@"),
|
||||
ARGPARSE_s_n (oForceSignKey, "force-sign-key", "@"),
|
||||
ARGPARSE_s_n (oEnableSpecialFilenames, "enable-special-filenames", "@"),
|
||||
ARGPARSE_s_n (oDisableFdTranslation, "disable-fd-translation", "@"),
|
||||
|
||||
ARGPARSE_header (NULL, N_("Other options")),
|
||||
|
||||
|
@ -1031,6 +1038,8 @@ static struct debug_flags_s debug_flags [] =
|
|||
/* The list of compatibility flags. */
|
||||
static struct compatibility_flags_s compatibility_flags [] =
|
||||
{
|
||||
{ COMPAT_PARALLELIZED, "parallelized" },
|
||||
{ COMPAT_T7014_OLD, "t7014-old" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
|
@ -1085,10 +1094,6 @@ static void read_sessionkey_from_fd (int fd);
|
|||
|
||||
|
||||
|
||||
/* NPth wrapper function definitions. */
|
||||
ASSUAN_SYSTEM_NPTH_IMPL;
|
||||
|
||||
|
||||
static char *
|
||||
make_libversion (const char *libname, const char *(*getfnc)(const char*))
|
||||
{
|
||||
|
@ -2089,6 +2094,8 @@ parse_list_options(char *str)
|
|||
NULL},
|
||||
{"show-user-notations",LIST_SHOW_USER_NOTATIONS,NULL,
|
||||
N_("show user-supplied notations during signature listings")},
|
||||
{"show-x509-notations",LIST_SHOW_X509_NOTATIONS,NULL, NULL },
|
||||
{"store-x509-notations",LIST_STORE_X509_NOTATIONS,NULL, NULL },
|
||||
{"show-keyserver-urls",LIST_SHOW_KEYSERVER_URLS,NULL,
|
||||
N_("show preferred keyserver URLs during signature listings")},
|
||||
{"show-uid-validity",LIST_SHOW_UID_VALIDITY,NULL,
|
||||
|
@ -2107,6 +2114,8 @@ parse_list_options(char *str)
|
|||
N_("show preferences")},
|
||||
{"show-pref-verbose", LIST_SHOW_PREF_VERBOSE, NULL,
|
||||
N_("show preferences")},
|
||||
{"show-ownertrust", LIST_SHOW_OWNERTRUST, NULL,
|
||||
N_("show ownertrust")},
|
||||
{"show-only-fpr-mbox",LIST_SHOW_ONLY_FPR_MBOX, NULL,
|
||||
NULL},
|
||||
{"sort-sigs", LIST_SORT_SIGS, NULL,
|
||||
|
@ -2501,6 +2510,7 @@ main (int argc, char **argv)
|
|||
opt.passphrase_repeat = 1;
|
||||
opt.emit_version = 0;
|
||||
opt.weak_digests = NULL;
|
||||
opt.with_subkey_fingerprint = 1;
|
||||
opt.compliance = CO_GNUPG;
|
||||
|
||||
/* Check special options given on the command line. */
|
||||
|
@ -2717,6 +2727,7 @@ main (int argc, char **argv)
|
|||
case aQuickSetExpire:
|
||||
case aQuickSetPrimaryUid:
|
||||
case aQuickUpdatePref:
|
||||
case aQuickSetOwnertrust:
|
||||
case aExportOwnerTrust:
|
||||
case aImportOwnerTrust:
|
||||
case aRebuildKeydbCaches:
|
||||
|
@ -2907,6 +2918,9 @@ main (int argc, char **argv)
|
|||
case oWithSubkeyFingerprint:
|
||||
opt.with_subkey_fingerprint = 1;
|
||||
break;
|
||||
case oWithoutSubkeyFingerprint:
|
||||
opt.with_subkey_fingerprint = 0;
|
||||
break;
|
||||
case oWithICAOSpelling:
|
||||
opt.with_icao_spelling = 1;
|
||||
break;
|
||||
|
@ -3058,6 +3072,9 @@ main (int argc, char **argv)
|
|||
break;
|
||||
|
||||
case oMinRSALength: opt.min_rsa_length = pargs.r.ret_ulong; break;
|
||||
case oRequirePQCEncryption:
|
||||
opt.flags.require_pqc_encryption = 1;
|
||||
break;
|
||||
|
||||
case oRFC2440Text: opt.rfc2440_text=1; break;
|
||||
case oNoRFC2440Text: opt.rfc2440_text=0; break;
|
||||
|
@ -3564,6 +3581,10 @@ main (int argc, char **argv)
|
|||
enable_special_filenames ();
|
||||
break;
|
||||
|
||||
case oDisableFdTranslation:
|
||||
disable_translate_sys2libc_fd ();
|
||||
break;
|
||||
|
||||
case oNoExpensiveTrustChecks: opt.no_expensive_trust_checks=1; break;
|
||||
case oAutoCheckTrustDB: opt.no_auto_check_trustdb=0; break;
|
||||
case oNoAutoCheckTrustDB: opt.no_auto_check_trustdb=1; break;
|
||||
|
@ -3902,8 +3923,8 @@ main (int argc, char **argv)
|
|||
|
||||
/* Init threading which is used by some helper functions. */
|
||||
npth_init ();
|
||||
assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);
|
||||
gpgrt_set_syscall_clamp (npth_unprotect, npth_protect);
|
||||
assuan_control (ASSUAN_CONTROL_REINIT_SYSCALL_CLAMP, NULL);
|
||||
|
||||
if (logfile)
|
||||
{
|
||||
|
@ -4393,6 +4414,7 @@ main (int argc, char **argv)
|
|||
case aQuickRevUid:
|
||||
case aQuickSetPrimaryUid:
|
||||
case aQuickUpdatePref:
|
||||
case aQuickSetOwnertrust:
|
||||
case aFullKeygen:
|
||||
case aKeygen:
|
||||
case aImport:
|
||||
|
@ -4447,7 +4469,8 @@ main (int argc, char **argv)
|
|||
{
|
||||
if( argc > 1 )
|
||||
wrong_args("--encrypt [filename]");
|
||||
if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 0, NULL, -1)) )
|
||||
if ((rc = encrypt_crypt (ctrl, GNUPG_INVALID_FD, fname, remusr,
|
||||
0, NULL, GNUPG_INVALID_FD)))
|
||||
{
|
||||
write_status_failure ("encrypt", rc);
|
||||
log_error("%s: encryption failed: %s\n",
|
||||
|
@ -4472,7 +4495,8 @@ main (int argc, char **argv)
|
|||
gnupg_compliance_option_string (opt.compliance));
|
||||
else
|
||||
{
|
||||
if( (rc = encrypt_crypt (ctrl, -1, fname, remusr, 1, NULL, -1)) )
|
||||
if ((rc = encrypt_crypt (ctrl, GNUPG_INVALID_FD, fname, remusr,
|
||||
1, NULL, GNUPG_INVALID_FD)))
|
||||
{
|
||||
write_status_failure ("encrypt", rc);
|
||||
log_error ("%s: encryption failed: %s\n",
|
||||
|
@ -4912,6 +4936,15 @@ main (int argc, char **argv)
|
|||
}
|
||||
break;
|
||||
|
||||
case aQuickSetOwnertrust:
|
||||
{
|
||||
if (argc != 2)
|
||||
wrong_args ("--quick-set-ownertrust USER-ID"
|
||||
" [enable|disable|full|...]");
|
||||
keyedit_quick_set_ownertrust (ctrl, argv[0], argv[1]);
|
||||
}
|
||||
break;
|
||||
|
||||
case aFastImport:
|
||||
opt.import_options |= IMPORT_FAST; /* fall through */
|
||||
case aImport:
|
||||
|
@ -5661,13 +5694,13 @@ print_mds( const char *fname, int algo )
|
|||
}
|
||||
else
|
||||
{
|
||||
fp = es_fopen (fname, "rb" );
|
||||
if (fp && is_secured_file (es_fileno (fp)))
|
||||
if (is_secured_filename (fname))
|
||||
{
|
||||
es_fclose (fp);
|
||||
fp = NULL;
|
||||
gpg_err_set_errno (EPERM);
|
||||
}
|
||||
else
|
||||
fp = es_fopen (fname, "rb" );
|
||||
}
|
||||
if (!fp)
|
||||
{
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
/* Number of bits we accept when reading or writing MPIs. */
|
||||
#define MAX_EXTERN_MPI_BITS 16384
|
||||
|
||||
/* Number of bytes we accept when reading four-octet count prefixed
|
||||
* key parameters. Needs to fit as a positive number into an int. */
|
||||
#define MAX_EXTERN_KEYPARM_BITS (32768*8)
|
||||
|
||||
/* The maximum length of a binary fingerprints. This is used to
|
||||
* provide a static buffer and will be increased if we need to support
|
||||
* longer fingerprints. Warning: At some places we have some
|
||||
|
|
|
@ -426,6 +426,14 @@ get_ownertrust (ctrl_t ctrl, PKT_public_key *pk)
|
|||
return TRUST_UNKNOWN;
|
||||
}
|
||||
|
||||
const char *
|
||||
get_ownertrust_string (ctrl_t ctrl, PKT_public_key *pk, int no_create)
|
||||
{
|
||||
(void)ctrl;
|
||||
(void)pk;
|
||||
(void)no_create;
|
||||
return "";
|
||||
}
|
||||
|
||||
/* Stubs:
|
||||
* Because we only work with trusted keys, it does not make sense to
|
||||
|
|
|
@ -578,7 +578,8 @@ char *hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen);
|
|||
char *v5hexfingerprint (PKT_public_key *pk, char *buffer, size_t buflen);
|
||||
char *format_hexfingerprint (const char *fingerprint,
|
||||
char *buffer, size_t buflen);
|
||||
gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array);
|
||||
gpg_error_t keygrip_from_pk (PKT_public_key *pk, unsigned char *array,
|
||||
int get_second);
|
||||
gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip);
|
||||
char *ecdh_param_str_from_pk (PKT_public_key *pk);
|
||||
|
||||
|
|
|
@ -1103,6 +1103,7 @@ change_passphrase (ctrl_t ctrl, kbnode_t keyblock)
|
|||
err = hexkeygrip_from_pk (pk, &hexgrip);
|
||||
if (err)
|
||||
goto leave;
|
||||
/* FIXME: Handle dual keys. */
|
||||
err = agent_get_keyinfo (ctrl, hexgrip, &serialno, NULL);
|
||||
if (!err && serialno)
|
||||
; /* Key on card. */
|
||||
|
@ -2754,6 +2755,87 @@ keyedit_quick_update_pref (ctrl_t ctrl, const char *username)
|
|||
}
|
||||
|
||||
|
||||
/* Unattended updating of the ownertrust or disable/enable state of a key
|
||||
* USERNAME specifies the key. This is somewhat similar to
|
||||
* gpg --edit-key <userid> trust save
|
||||
* gpg --edit-key <userid> disable save
|
||||
*
|
||||
* VALUE is the new trust value which is one of:
|
||||
* "undefined" - Ownertrust is set to undefined
|
||||
* "never" - Ownertrust is set to never trust
|
||||
* "marginal" - Ownertrust is set to marginal trust
|
||||
* "full" - Ownertrust is set to full trust
|
||||
* "ultimate" - Ownertrust is set to ultimate trust
|
||||
* "enable" - The key is re-enabled.
|
||||
* "disable" - The key is disabled.
|
||||
* Trust settings do not change the ebable/disable state.
|
||||
*/
|
||||
void
|
||||
keyedit_quick_set_ownertrust (ctrl_t ctrl, const char *username,
|
||||
const char *value)
|
||||
{
|
||||
gpg_error_t err;
|
||||
KEYDB_HANDLE kdbhd = NULL;
|
||||
kbnode_t keyblock = NULL;
|
||||
PKT_public_key *pk;
|
||||
unsigned int trust, newtrust;
|
||||
int x;
|
||||
int maybe_update_trust = 0;
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* See keyedit_menu for why we need this. */
|
||||
check_trustdb_stale (ctrl);
|
||||
#endif
|
||||
|
||||
/* Search the key; we don't want the whole getkey stuff here. Note
|
||||
* that we are looking for the public key here. */
|
||||
err = quick_find_keyblock (ctrl, username, 0, &kdbhd, &keyblock);
|
||||
if (err)
|
||||
goto leave;
|
||||
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
||||
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
||||
pk = keyblock->pkt->pkt.public_key;
|
||||
|
||||
trust = newtrust = get_ownertrust (ctrl, pk);
|
||||
|
||||
if (!ascii_strcasecmp (value, "enable"))
|
||||
newtrust &= ~TRUST_FLAG_DISABLED;
|
||||
else if (!ascii_strcasecmp (value, "disable"))
|
||||
newtrust |= TRUST_FLAG_DISABLED;
|
||||
else if ((x = string_to_trust_value (value)) >= 0)
|
||||
{
|
||||
newtrust = x;
|
||||
newtrust &= TRUST_MASK;
|
||||
newtrust |= (trust & ~TRUST_MASK);
|
||||
maybe_update_trust = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_ARG);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (trust != newtrust)
|
||||
{
|
||||
update_ownertrust (ctrl, pk, newtrust);
|
||||
if (maybe_update_trust)
|
||||
revalidation_mark (ctrl);
|
||||
}
|
||||
else if (opt.verbose)
|
||||
log_info (_("Key not changed so no update needed.\n"));
|
||||
|
||||
leave:
|
||||
if (err)
|
||||
{
|
||||
log_error (_("setting the ownertrust to '%s' failed: %s\n"),
|
||||
value, gpg_strerror (err));
|
||||
write_status_error ("keyedit.setownertrust", err);
|
||||
}
|
||||
release_kbnode (keyblock);
|
||||
keydb_release (kdbhd);
|
||||
}
|
||||
|
||||
|
||||
/* Find a keyblock by fingerprint because only this uniquely
|
||||
* identifies a key and may thus be used to select a key for
|
||||
* unattended subkey creation os key signing. */
|
||||
|
@ -2998,7 +3080,7 @@ keyedit_quick_revsig (ctrl_t ctrl, const char *username, const char *sigtorev,
|
|||
check_trustdb_stale (ctrl);
|
||||
#endif
|
||||
|
||||
/* Search the key; we don't want the whole getkey stuff here. Noet
|
||||
/* Search the key; we don't want the whole getkey stuff here. Note
|
||||
* that we are looking for the public key here. */
|
||||
err = quick_find_keyblock (ctrl, username, 0, &kdbhd, &keyblock);
|
||||
if (err)
|
||||
|
|
|
@ -57,6 +57,8 @@ void keyedit_quick_set_expire (ctrl_t ctrl,
|
|||
void keyedit_quick_set_primary (ctrl_t ctrl, const char *username,
|
||||
const char *primaryuid);
|
||||
void keyedit_quick_update_pref (ctrl_t ctrl, const char *username);
|
||||
void keyedit_quick_set_ownertrust (ctrl_t ctrl, const char *username,
|
||||
const char *value);
|
||||
void show_basic_key_info (ctrl_t ctrl, kbnode_t keyblock, int print_sec);
|
||||
int keyedit_print_one_sig (ctrl_t ctrl, estream_t fp,
|
||||
int rc, kbnode_t keyblock,
|
||||
|
|
494
g10/keygen.c
494
g10/keygen.c
|
@ -1,7 +1,7 @@
|
|||
/* keygen.c - Generate a key pair
|
||||
* Copyright (C) 1998-2007, 2009-2011 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2014, 2015, 2016, 2017, 2018 Werner Koch
|
||||
* Copyright (C) 2020 g10 Code GmbH
|
||||
* Copyright (C) 2020, 2024 g10 Code GmbH
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
|
@ -139,10 +139,23 @@ struct common_gen_cb_parm_s
|
|||
* may take a copy of this so that the result can be used after we
|
||||
* are back from the deep key generation call stack. */
|
||||
gcry_sexp_t genkey_result;
|
||||
/* For a dual algorithms the result of the second algorithm
|
||||
* (e.g. Kyber). */
|
||||
gcry_sexp_t genkey_result2;
|
||||
};
|
||||
typedef struct common_gen_cb_parm_s *common_gen_cb_parm_t;
|
||||
|
||||
|
||||
/* A communication object to help adding certain notations to a key
|
||||
* binding signature. */
|
||||
struct opaque_data_usage_and_pk
|
||||
{
|
||||
unsigned int usage;
|
||||
const char *cpl_notation;
|
||||
PKT_public_key *pk;
|
||||
};
|
||||
|
||||
|
||||
/* FIXME: These globals vars are ugly. And using MAX_PREFS even for
|
||||
* aeads is useless, given that we don't expects more than a very few
|
||||
* algorithms. */
|
||||
|
@ -174,6 +187,9 @@ static gpg_error_t gen_card_key (int keyno, int algo, int is_primary,
|
|||
u32 expireval, int *keygen_flags);
|
||||
static unsigned int get_keysize_range (int algo,
|
||||
unsigned int *min, unsigned int *max);
|
||||
static void do_add_notation (PKT_signature *sig,
|
||||
const char *name, const char *value,
|
||||
int critical);
|
||||
|
||||
|
||||
|
||||
|
@ -338,6 +354,20 @@ keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
|
|||
}
|
||||
|
||||
|
||||
/* This is only used to write the key binding signature. It is not
|
||||
* used for the primary key. */
|
||||
static int
|
||||
keygen_add_key_flags_from_oduap (PKT_signature *sig, void *opaque)
|
||||
{
|
||||
struct opaque_data_usage_and_pk *oduap = opaque;
|
||||
|
||||
do_add_key_flags (sig, oduap->usage);
|
||||
if (oduap->cpl_notation)
|
||||
do_add_notation (sig, "cpl@gnupg.org", oduap->cpl_notation, 0);
|
||||
return keygen_add_key_expire (sig, oduap->pk);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
set_one_pref (int val, int type, const char *item, byte *buf, int *nbuf)
|
||||
{
|
||||
|
@ -943,6 +973,44 @@ keygen_add_keyserver_url(PKT_signature *sig, void *opaque)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* This function is used to add a notations to a signature. In
|
||||
* general the caller should have cleared exiting notations before
|
||||
* adding new ones. For example by calling:
|
||||
*
|
||||
* delete_sig_subpkt(sig->hashed,SIGSUBPKT_NOTATION);
|
||||
* delete_sig_subpkt(sig->unhashed,SIGSUBPKT_NOTATION);
|
||||
*
|
||||
* Only human readable notaions may be added. NAME and value are
|
||||
* expected to be UTF-* strings.
|
||||
*/
|
||||
static void
|
||||
do_add_notation (PKT_signature *sig, const char *name, const char *value,
|
||||
int critical)
|
||||
{
|
||||
unsigned char *buf;
|
||||
unsigned int n1,n2;
|
||||
|
||||
n1 = strlen (name);
|
||||
n2 = strlen (value);
|
||||
|
||||
buf = xmalloc (8 + n1 + n2);
|
||||
|
||||
buf[0] = 0x80; /* human readable. */
|
||||
buf[1] = buf[2] = buf[3] = 0;
|
||||
buf[4] = n1 >> 8;
|
||||
buf[5] = n1;
|
||||
buf[6] = n2 >> 8;
|
||||
buf[7] = n2;
|
||||
memcpy (buf+8, name, n1);
|
||||
memcpy (buf+8+n1, value, n2);
|
||||
build_sig_subpkt (sig,
|
||||
(SIGSUBPKT_NOTATION|(critical?SIGSUBPKT_FLAG_CRITICAL:0)),
|
||||
buf, 8+n1+n2 );
|
||||
xfree (buf);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
keygen_add_notations(PKT_signature *sig,void *opaque)
|
||||
{
|
||||
|
@ -992,6 +1060,7 @@ keygen_add_notations(PKT_signature *sig,void *opaque)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
keygen_add_revkey (PKT_signature *sig, void *opaque)
|
||||
{
|
||||
|
@ -1225,6 +1294,7 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
|
|||
PKT_signature *sig;
|
||||
KBNODE node;
|
||||
PKT_public_key *pri_pk, *sub_pk;
|
||||
struct opaque_data_usage_and_pk oduap;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info(_("writing key binding signature\n"));
|
||||
|
@ -1250,10 +1320,21 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
|
|||
BUG();
|
||||
|
||||
/* Make the signature. */
|
||||
sub_pk->pubkey_usage = use;
|
||||
oduap.usage = use;
|
||||
if ((use & PUBKEY_USAGE_ENC)
|
||||
&& opt.compliance == CO_DE_VS
|
||||
/* The required libgcrypt 1.11 won't yet claim a compliant RNG. */
|
||||
&& gnupg_rng_is_compliant (CO_DE_VS))
|
||||
oduap.cpl_notation = "de-vs";
|
||||
else if ((use & PUBKEY_USAGE_ENC)
|
||||
&& sub_pk->pubkey_algo == PUBKEY_ALGO_KYBER)
|
||||
oduap.cpl_notation = "fips203.ipd.2023-08-24";
|
||||
else
|
||||
oduap.cpl_notation = NULL;
|
||||
oduap.pk = sub_pk;
|
||||
err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
|
||||
timestamp, 0,
|
||||
keygen_add_key_flags_and_expire, sub_pk,
|
||||
keygen_add_key_flags_from_oduap, &oduap,
|
||||
cache_nonce);
|
||||
if (err)
|
||||
{
|
||||
|
@ -1311,8 +1392,12 @@ curve_is_448 (gcry_sexp_t sexp)
|
|||
}
|
||||
|
||||
|
||||
/* Extract the parameters in OpenPGP format from SEXP and put them
|
||||
* into the caller provided ARRAY. SEXP2 is used to provide the
|
||||
* parameters for dual algorithm (e.g. Kyber). */
|
||||
static gpg_error_t
|
||||
ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
|
||||
ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
|
||||
gcry_sexp_t sexp2, int algo, int pkversion)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gcry_sexp_t list, l2;
|
||||
|
@ -1355,6 +1440,10 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
|
|||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
/* For v5 keys we prefer the modern OID for cv25519. */
|
||||
if (pkversion > 4 && !strcmp (oidstr, "1.3.6.1.4.1.3029.1.5.1"))
|
||||
oidstr = "1.3.101.110";
|
||||
|
||||
err = openpgp_oid_from_str (oidstr, &array[0]);
|
||||
if (err)
|
||||
goto leave;
|
||||
|
@ -1364,8 +1453,46 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
|
|||
goto leave;
|
||||
|
||||
gcry_sexp_release (list);
|
||||
list = NULL;
|
||||
|
||||
if (algo == PUBKEY_ALGO_ECDH)
|
||||
if (algo == PUBKEY_ALGO_KYBER)
|
||||
{
|
||||
if (!sexp2)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_MISSING_VALUE);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
list = gcry_sexp_find_token (sexp2, "public-key", 0);
|
||||
if (!list)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
l2 = gcry_sexp_cadr (list);
|
||||
gcry_sexp_release (list);
|
||||
list = l2;
|
||||
if (!list)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NO_OBJ);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
l2 = gcry_sexp_find_token (list, "p", 1);
|
||||
if (!l2)
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NO_OBJ); /* required parameter not found */
|
||||
goto leave;
|
||||
}
|
||||
array[2] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_OPAQUE);
|
||||
gcry_sexp_release (l2);
|
||||
if (!array[2])
|
||||
{
|
||||
err = gpg_error (GPG_ERR_INV_OBJ); /* required parameter invalid */
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else if (algo == PUBKEY_ALGO_ECDH)
|
||||
{
|
||||
array[2] = pk_ecdh_default_params (nbits);
|
||||
if (!array[2])
|
||||
|
@ -1377,6 +1504,7 @@ ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
|
|||
|
||||
leave:
|
||||
xfree (curve);
|
||||
gcry_sexp_release (list);
|
||||
if (err)
|
||||
{
|
||||
for (i=0; i < 3; i++)
|
||||
|
@ -1455,10 +1583,24 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
|
|||
PACKET *pkt;
|
||||
PKT_public_key *pk;
|
||||
gcry_sexp_t s_key;
|
||||
gcry_sexp_t s_key2 = NULL;
|
||||
const char *algoelem;
|
||||
char *hexkeygrip_buffer = NULL;
|
||||
char *hexkeygrip2 = NULL;
|
||||
|
||||
if (hexkeygrip[0] == '&')
|
||||
hexkeygrip++;
|
||||
if (strchr (hexkeygrip, ','))
|
||||
{
|
||||
hexkeygrip_buffer = xtrystrdup (hexkeygrip);
|
||||
if (!hexkeygrip_buffer)
|
||||
return gpg_error_from_syserror ();
|
||||
hexkeygrip = hexkeygrip_buffer;
|
||||
hexkeygrip2 = strchr (hexkeygrip_buffer, ',');
|
||||
if (hexkeygrip2)
|
||||
*hexkeygrip2++ = 0;
|
||||
}
|
||||
|
||||
|
||||
switch (algo)
|
||||
{
|
||||
|
@ -1468,16 +1610,21 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
|
|||
case PUBKEY_ALGO_ECDH:
|
||||
case PUBKEY_ALGO_ECDSA: algoelem = ""; break;
|
||||
case PUBKEY_ALGO_EDDSA: algoelem = ""; break;
|
||||
default: return gpg_error (GPG_ERR_INTERNAL);
|
||||
case PUBKEY_ALGO_KYBER: algoelem = ""; break;
|
||||
default:
|
||||
xfree (hexkeygrip_buffer);
|
||||
return gpg_error (GPG_ERR_INTERNAL);
|
||||
}
|
||||
|
||||
|
||||
/* Ask the agent for the public key matching HEXKEYGRIP. */
|
||||
if (cardkey)
|
||||
{
|
||||
err = agent_scd_readkey (ctrl, hexkeygrip, &s_key, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
{
|
||||
xfree (hexkeygrip_buffer);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1485,16 +1632,41 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
|
|||
|
||||
err = agent_readkey (ctrl, 0, hexkeygrip, &public);
|
||||
if (err)
|
||||
return err;
|
||||
{
|
||||
xfree (hexkeygrip_buffer);
|
||||
return err;
|
||||
}
|
||||
err = gcry_sexp_sscan (&s_key, NULL, public,
|
||||
gcry_sexp_canon_len (public, 0, NULL, NULL));
|
||||
xfree (public);
|
||||
if (err)
|
||||
return err;
|
||||
{
|
||||
xfree (hexkeygrip_buffer);
|
||||
return err;
|
||||
}
|
||||
if (hexkeygrip2)
|
||||
{
|
||||
err = agent_readkey (ctrl, 0, hexkeygrip2, &public);
|
||||
if (err)
|
||||
{
|
||||
gcry_sexp_release (s_key);
|
||||
xfree (hexkeygrip_buffer);
|
||||
return err;
|
||||
}
|
||||
err = gcry_sexp_sscan (&s_key2, NULL, public,
|
||||
gcry_sexp_canon_len (public, 0, NULL, NULL));
|
||||
xfree (public);
|
||||
if (err)
|
||||
{
|
||||
gcry_sexp_release (s_key);
|
||||
xfree (hexkeygrip_buffer);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* For X448 we force the use of v5 packets. */
|
||||
if (curve_is_448 (s_key))
|
||||
/* For X448 and Kyber we force the use of v5 packets. */
|
||||
if (curve_is_448 (s_key) || algo == PUBKEY_ALGO_KYBER)
|
||||
*keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
|
||||
|
||||
/* Build a public key packet. */
|
||||
|
@ -1503,6 +1675,8 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
|
|||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
gcry_sexp_release (s_key);
|
||||
gcry_sexp_release (s_key2);
|
||||
xfree (hexkeygrip_buffer);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1512,26 +1686,32 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
|
|||
pk->expiredate = pk->timestamp + expireval;
|
||||
pk->pubkey_algo = algo;
|
||||
|
||||
if (algo == PUBKEY_ALGO_ECDSA
|
||||
if (algo == PUBKEY_ALGO_KYBER)
|
||||
err = ecckey_from_sexp (pk->pkey, s_key, s_key2, algo, pk->version);
|
||||
else if (algo == PUBKEY_ALGO_ECDSA
|
||||
|| algo == PUBKEY_ALGO_EDDSA
|
||||
|| algo == PUBKEY_ALGO_ECDH )
|
||||
err = ecckey_from_sexp (pk->pkey, s_key, algo);
|
||||
err = ecckey_from_sexp (pk->pkey, s_key, NULL, algo, pk->version);
|
||||
else
|
||||
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
|
||||
if (err)
|
||||
{
|
||||
log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
|
||||
gcry_sexp_release (s_key);
|
||||
gcry_sexp_release (s_key2);
|
||||
free_public_key (pk);
|
||||
xfree (hexkeygrip_buffer);
|
||||
return err;
|
||||
}
|
||||
gcry_sexp_release (s_key);
|
||||
gcry_sexp_release (s_key2);
|
||||
|
||||
pkt = xtrycalloc (1, sizeof *pkt);
|
||||
if (!pkt)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
free_public_key (pk);
|
||||
xfree (hexkeygrip_buffer);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1539,16 +1719,18 @@ do_create_from_keygrip (ctrl_t ctrl, int algo,
|
|||
pkt->pkt.public_key = pk;
|
||||
add_kbnode (pub_root, new_kbnode (pkt));
|
||||
|
||||
xfree (hexkeygrip_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Common code for the key generation function gen_xxx. The optinal
|
||||
/* Common code for the key generation function gen_xxx. The optional
|
||||
* (COMMON_GEN_CB,COMMON_GEN_CB_PARM) can be used as communication
|
||||
* object.
|
||||
* object. A KEYPARMS2 forces the use of a dual key (e.g. Kyber+ECC).
|
||||
*/
|
||||
static int
|
||||
common_gen (const char *keyparms, int algo, const char *algoelem,
|
||||
common_gen (const char *keyparms, const char *keyparms2,
|
||||
int algo, const char *algoelem,
|
||||
kbnode_t pub_root, u32 timestamp, u32 expireval, int is_subkey,
|
||||
int keygen_flags, const char *passphrase,
|
||||
char **cache_nonce_addr, char **passwd_nonce_addr,
|
||||
|
@ -1559,6 +1741,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
|
|||
PACKET *pkt;
|
||||
PKT_public_key *pk;
|
||||
gcry_sexp_t s_key;
|
||||
gcry_sexp_t s_key2 = NULL;
|
||||
|
||||
err = agent_genkey (NULL, cache_nonce_addr, passwd_nonce_addr, keyparms,
|
||||
!!(keygen_flags & KEYGEN_FLAG_NO_PROTECTION),
|
||||
|
@ -1570,14 +1753,32 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (keyparms2)
|
||||
{
|
||||
err = agent_genkey (NULL, NULL, NULL, keyparms2,
|
||||
1 /* No protection */,
|
||||
NULL, timestamp,
|
||||
&s_key2);
|
||||
if (err)
|
||||
{
|
||||
log_error ("agent_genkey failed for second algo: %s\n",
|
||||
gpg_strerror (err) );
|
||||
gcry_sexp_release (s_key);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (common_gen_cb && common_gen_cb_parm)
|
||||
{
|
||||
common_gen_cb_parm->genkey_result = s_key;
|
||||
common_gen_cb_parm->genkey_result2 = s_key2;
|
||||
err = common_gen_cb (common_gen_cb_parm);
|
||||
common_gen_cb_parm->genkey_result = NULL;
|
||||
common_gen_cb_parm->genkey_result2 = NULL;
|
||||
if (err)
|
||||
{
|
||||
gcry_sexp_release (s_key);
|
||||
gcry_sexp_release (s_key2);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
@ -1596,10 +1797,12 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
|
|||
pk->expiredate = pk->timestamp + expireval;
|
||||
pk->pubkey_algo = algo;
|
||||
|
||||
if (algo == PUBKEY_ALGO_ECDSA
|
||||
|| algo == PUBKEY_ALGO_EDDSA
|
||||
|| algo == PUBKEY_ALGO_ECDH )
|
||||
err = ecckey_from_sexp (pk->pkey, s_key, algo);
|
||||
if (algo == PUBKEY_ALGO_KYBER)
|
||||
err = ecckey_from_sexp (pk->pkey, s_key, s_key2, algo, pk->version);
|
||||
else if (algo == PUBKEY_ALGO_ECDSA
|
||||
|| algo == PUBKEY_ALGO_EDDSA
|
||||
|| algo == PUBKEY_ALGO_ECDH )
|
||||
err = ecckey_from_sexp (pk->pkey, s_key, NULL, algo, pk->version);
|
||||
else
|
||||
err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
|
||||
if (err)
|
||||
|
@ -1610,6 +1813,7 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
|
|||
return err;
|
||||
}
|
||||
gcry_sexp_release (s_key);
|
||||
gcry_sexp_release (s_key2);
|
||||
|
||||
pkt = xtrycalloc (1, sizeof *pkt);
|
||||
if (!pkt)
|
||||
|
@ -1675,7 +1879,7 @@ gen_elg (int algo, unsigned int nbits, KBNODE pub_root,
|
|||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
err = common_gen (keyparms, algo, "pgy",
|
||||
err = common_gen (keyparms, NULL, algo, "pgy",
|
||||
pub_root, timestamp, expireval, is_subkey,
|
||||
keygen_flags, passphrase,
|
||||
cache_nonce_addr, passwd_nonce_addr,
|
||||
|
@ -1767,7 +1971,7 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
|
|||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
err = common_gen (keyparms, PUBKEY_ALGO_DSA, "pqgy",
|
||||
err = common_gen (keyparms, NULL, PUBKEY_ALGO_DSA, "pqgy",
|
||||
pub_root, timestamp, expireval, is_subkey,
|
||||
keygen_flags, passphrase,
|
||||
cache_nonce_addr, passwd_nonce_addr,
|
||||
|
@ -1868,7 +2072,7 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
|
|||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
err = common_gen (keyparms, algo, "",
|
||||
err = common_gen (keyparms, NULL, algo, "",
|
||||
pub_root, timestamp, expireval, is_subkey,
|
||||
*keygen_flags, passphrase,
|
||||
cache_nonce_addr, passwd_nonce_addr,
|
||||
|
@ -1880,6 +2084,79 @@ gen_ecc (int algo, const char *curve, kbnode_t pub_root,
|
|||
}
|
||||
|
||||
|
||||
/* Generate a dual ECC+Kyber key. Note that KEYGEN_FLAGS will be
|
||||
* updated by this function to indicate the forced creation of a v5
|
||||
* key. */
|
||||
static gpg_error_t
|
||||
gen_kyber (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root,
|
||||
u32 timestamp, u32 expireval, int is_subkey,
|
||||
int *keygen_flags, const char *passphrase,
|
||||
char **cache_nonce_addr, char **passwd_nonce_addr,
|
||||
gpg_error_t (*common_gen_cb)(common_gen_cb_parm_t),
|
||||
common_gen_cb_parm_t common_gen_cb_parm)
|
||||
{
|
||||
gpg_error_t err;
|
||||
char *keyparms1;
|
||||
const char *keyparms2;
|
||||
|
||||
log_assert (algo == PUBKEY_ALGO_KYBER);
|
||||
|
||||
if (nbits == 768)
|
||||
keyparms2 = "(genkey(kyber768))";
|
||||
else if (nbits == 1024)
|
||||
keyparms2 = "(genkey(kyber1024))";
|
||||
else
|
||||
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
|
||||
|
||||
if (!curve || !*curve)
|
||||
return gpg_error (GPG_ERR_UNKNOWN_CURVE);
|
||||
|
||||
*keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
|
||||
|
||||
if (!strcmp (curve, "Curve25519"))
|
||||
{
|
||||
keyparms1 = xtryasprintf
|
||||
("(genkey(ecc(curve %zu:%s)(flags djb-tweak comp%s)))",
|
||||
strlen (curve), curve,
|
||||
(((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
|
||||
&& (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
|
||||
" transient-key" : ""));
|
||||
}
|
||||
else if (!strcmp (curve, "X448"))
|
||||
{
|
||||
keyparms1 = xtryasprintf
|
||||
("(genkey(ecc(curve %zu:%s)(flags comp%s)))",
|
||||
strlen (curve), curve,
|
||||
(((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
|
||||
&& (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
|
||||
" transient-key" : ""));
|
||||
}
|
||||
else /* Should we use the compressed format? Check smartcard support. */
|
||||
{
|
||||
keyparms1 = xtryasprintf
|
||||
("(genkey(ecc(curve %zu:%s)(flags nocomp%s)))",
|
||||
strlen (curve), curve,
|
||||
(((*keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
|
||||
&& (*keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
|
||||
" transient-key" : ""));
|
||||
}
|
||||
|
||||
if (!keyparms1)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
err = common_gen (keyparms1, keyparms2, algo, "",
|
||||
pub_root, timestamp, expireval, is_subkey,
|
||||
*keygen_flags, passphrase,
|
||||
cache_nonce_addr, passwd_nonce_addr,
|
||||
common_gen_cb, common_gen_cb_parm);
|
||||
xfree (keyparms1);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Generate an RSA key.
|
||||
*/
|
||||
|
@ -1928,7 +2205,7 @@ gen_rsa (int algo, unsigned int nbits, KBNODE pub_root,
|
|||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
err = common_gen (keyparms, algo, "ne",
|
||||
err = common_gen (keyparms, NULL, algo, "ne",
|
||||
pub_root, timestamp, expireval, is_subkey,
|
||||
keygen_flags, passphrase,
|
||||
cache_nonce_addr, passwd_nonce_addr,
|
||||
|
@ -1982,6 +2259,9 @@ print_key_flags(int flags)
|
|||
|
||||
if(flags&PUBKEY_USAGE_AUTH)
|
||||
tty_printf("%s ",_("Authenticate"));
|
||||
|
||||
if(flags&PUBKEY_USAGE_RENC)
|
||||
tty_printf("%s ", "RENC");
|
||||
}
|
||||
|
||||
|
||||
|
@ -2014,10 +2294,14 @@ ask_key_flags_with_mask (int algo, int subkey, unsigned int current,
|
|||
togglers = "11223300";
|
||||
}
|
||||
|
||||
/* restrict the mask to the actual useful bits. */
|
||||
|
||||
/* Mask the possible usage flags. This is for example used for a
|
||||
* card based key. For ECDH we need to allows additional usages if
|
||||
* they are provided. */
|
||||
* they are provided. RENC is not directly poissible here but see
|
||||
* below for a workaround. */
|
||||
possible = (openpgp_pk_algo_usage (algo) & mask);
|
||||
possible &= ~PUBKEY_USAGE_RENC;
|
||||
if (algo == PUBKEY_ALGO_ECDH)
|
||||
possible |= (current & (PUBKEY_USAGE_ENC
|
||||
|PUBKEY_USAGE_CERT
|
||||
|
@ -2086,6 +2370,12 @@ ask_key_flags_with_mask (int algo, int subkey, unsigned int current,
|
|||
want to experiment with a cert-only primary key. */
|
||||
current |= PUBKEY_USAGE_CERT;
|
||||
}
|
||||
else if ((*s == 'r' || *s == 'R') && (possible&PUBKEY_USAGE_ENC))
|
||||
{
|
||||
/* Allow to set RENC or an encryption capable key.
|
||||
* This is on purpose not shown in the menu. */
|
||||
current |= PUBKEY_USAGE_RENC;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2337,7 +2627,26 @@ ask_algo (ctrl_t ctrl, int addmode, int *r_subkey_algo, unsigned int *r_usage,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (strlen (answer) != 40 &&
|
||||
if (strlen (answer) == 40+1+40 && answer[40]==',')
|
||||
{
|
||||
int algo1, algo2;
|
||||
|
||||
answer[40] = 0;
|
||||
algo1 = check_keygrip (ctrl, answer);
|
||||
algo2 = check_keygrip (ctrl, answer+41);
|
||||
answer[40] = ',';
|
||||
if (algo1 == PUBKEY_ALGO_ECDH && algo2 == PUBKEY_ALGO_KYBER)
|
||||
{
|
||||
algo = PUBKEY_ALGO_KYBER;
|
||||
break;
|
||||
}
|
||||
else if (!algo1 || !algo2)
|
||||
tty_printf (_("No key with this keygrip\n"));
|
||||
else
|
||||
tty_printf ("Invalid combination for dual algo (%d,%d)\n",
|
||||
algo1, algo2);
|
||||
}
|
||||
else if (strlen (answer) != 40 &&
|
||||
!(answer[0] == '&' && strlen (answer+1) == 40))
|
||||
tty_printf
|
||||
(_("Not a valid keygrip (expecting 40 hex digits)\n"));
|
||||
|
@ -2547,6 +2856,12 @@ get_keysize_range (int algo, unsigned int *min, unsigned int *max)
|
|||
def=255;
|
||||
break;
|
||||
|
||||
case PUBKEY_ALGO_KYBER:
|
||||
*min = 768;
|
||||
*max = 1024;
|
||||
def = 768;
|
||||
break;
|
||||
|
||||
default:
|
||||
*min = opt.compliance == CO_DE_VS ? 2048: 1024;
|
||||
*max = 4096;
|
||||
|
@ -2562,45 +2877,44 @@ get_keysize_range (int algo, unsigned int *min, unsigned int *max)
|
|||
static unsigned int
|
||||
fixup_keysize (unsigned int nbits, int algo, int silent)
|
||||
{
|
||||
unsigned int orig_nbits = nbits;
|
||||
|
||||
if (algo == PUBKEY_ALGO_DSA && (nbits % 64))
|
||||
{
|
||||
nbits = ((nbits + 63) / 64) * 64;
|
||||
if (!silent)
|
||||
tty_printf (_("rounded up to %u bits\n"), nbits);
|
||||
}
|
||||
else if (algo == PUBKEY_ALGO_EDDSA)
|
||||
{
|
||||
if (nbits != 255 && nbits != 441)
|
||||
{
|
||||
if (nbits < 256)
|
||||
nbits = 255;
|
||||
else
|
||||
nbits = 441;
|
||||
if (!silent)
|
||||
tty_printf (_("rounded to %u bits\n"), nbits);
|
||||
}
|
||||
if (nbits < 256)
|
||||
nbits = 255;
|
||||
else
|
||||
nbits = 441;
|
||||
}
|
||||
else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA)
|
||||
{
|
||||
if (nbits != 256 && nbits != 384 && nbits != 521)
|
||||
{
|
||||
if (nbits < 256)
|
||||
nbits = 256;
|
||||
else if (nbits < 384)
|
||||
nbits = 384;
|
||||
else
|
||||
nbits = 521;
|
||||
if (!silent)
|
||||
tty_printf (_("rounded to %u bits\n"), nbits);
|
||||
}
|
||||
if (nbits < 256)
|
||||
nbits = 256;
|
||||
else if (nbits < 384)
|
||||
nbits = 384;
|
||||
else
|
||||
nbits = 521;
|
||||
}
|
||||
else if (algo == PUBKEY_ALGO_KYBER)
|
||||
{
|
||||
/* (in reality the numbers are not bits) */
|
||||
if (nbits < 768)
|
||||
nbits = 768;
|
||||
else if (nbits > 1024)
|
||||
nbits = 1024;
|
||||
}
|
||||
else if ((nbits % 32))
|
||||
{
|
||||
nbits = ((nbits + 31) / 32) * 32;
|
||||
if (!silent)
|
||||
tty_printf (_("rounded up to %u bits\n"), nbits );
|
||||
}
|
||||
|
||||
if (!silent && orig_nbits != nbits)
|
||||
tty_printf (_("rounded to %u bits\n"), nbits);
|
||||
|
||||
return nbits;
|
||||
}
|
||||
|
||||
|
@ -3330,6 +3644,12 @@ do_create (int algo, unsigned int nbits, const char *curve, kbnode_t pub_root,
|
|||
keygen_flags, passphrase,
|
||||
cache_nonce_addr, passwd_nonce_addr,
|
||||
common_gen_cb, common_gen_cb_parm);
|
||||
else if (algo == PUBKEY_ALGO_KYBER)
|
||||
err = gen_kyber (algo, nbits, curve,
|
||||
pub_root, timestamp, expiredate, is_subkey,
|
||||
keygen_flags, passphrase,
|
||||
cache_nonce_addr, passwd_nonce_addr,
|
||||
common_gen_cb, common_gen_cb_parm);
|
||||
else if (algo == PUBKEY_ALGO_RSA)
|
||||
err = gen_rsa (algo, nbits, pub_root, timestamp, expiredate, is_subkey,
|
||||
*keygen_flags, passphrase,
|
||||
|
@ -3408,6 +3728,7 @@ parse_key_parameter_part (ctrl_t ctrl,
|
|||
char *keygrip = NULL;
|
||||
u32 keytime = 0;
|
||||
int is_448 = 0;
|
||||
int is_pqc = 0;
|
||||
|
||||
if (!string || !*string)
|
||||
return 0; /* Success. */
|
||||
|
@ -3433,6 +3754,7 @@ parse_key_parameter_part (ctrl_t ctrl,
|
|||
; /* We need the flags before we can figure out the key to use. */
|
||||
else if (algo)
|
||||
{
|
||||
/* This is one of the algos parsed above (rsa, dsa, or elg). */
|
||||
if (!string[3])
|
||||
size = get_keysize_range (algo, NULL, NULL);
|
||||
else
|
||||
|
@ -3442,6 +3764,63 @@ parse_key_parameter_part (ctrl_t ctrl,
|
|||
return gpg_error (GPG_ERR_INV_VALUE);
|
||||
}
|
||||
}
|
||||
else if (!ascii_strcasecmp (string, "kyber")
|
||||
|| !ascii_strcasecmp (string, "kyber768"))
|
||||
{
|
||||
/* Get the curve and check that it can technically be used
|
||||
* (i.e. everything except the EdXXXX curves. */
|
||||
curve = openpgp_is_curve_supported ("brainpoolP256r1", &algo, NULL);
|
||||
if (!curve || algo == PUBKEY_ALGO_EDDSA)
|
||||
return gpg_error (GPG_ERR_UNKNOWN_CURVE);
|
||||
algo = PUBKEY_ALGO_KYBER;
|
||||
size = 768;
|
||||
is_pqc = 1;
|
||||
}
|
||||
else if (!ascii_strcasecmp (string, "kyber1024"))
|
||||
{
|
||||
/* Get the curve and check that it can technically be used
|
||||
* (i.e. everything except the EdXXXX curves. */
|
||||
curve = openpgp_is_curve_supported ("brainpoolP384r1", &algo, NULL);
|
||||
if (!curve || algo == PUBKEY_ALGO_EDDSA)
|
||||
return gpg_error (GPG_ERR_UNKNOWN_CURVE);
|
||||
algo = PUBKEY_ALGO_KYBER;
|
||||
size = 1024;
|
||||
is_pqc = 1;
|
||||
}
|
||||
else if (!ascii_strncasecmp (string, "ky768_", 6)
|
||||
|| !ascii_strncasecmp (string, "ky1024_", 7)
|
||||
|| !ascii_strncasecmp (string, "kyber768_", 9)
|
||||
|| !ascii_strncasecmp (string, "kyber1024_", 10)
|
||||
)
|
||||
{
|
||||
/* Get the curve and check that it can technically be used
|
||||
* (i.e. everything except the EdXXXX curves. */
|
||||
s = strchr (string, '_');
|
||||
log_assert (s);
|
||||
s++;
|
||||
curve = openpgp_is_curve_supported (s, &algo, NULL);
|
||||
if (!curve || algo == PUBKEY_ALGO_EDDSA)
|
||||
return gpg_error (GPG_ERR_UNKNOWN_CURVE);
|
||||
algo = PUBKEY_ALGO_KYBER;
|
||||
size = strstr (string, "768_")? 768 : 1024;
|
||||
is_pqc = 1;
|
||||
}
|
||||
else if (!ascii_strcasecmp (string, "dil3"))
|
||||
{
|
||||
algo = PUBKEY_ALGO_DIL3_25519;
|
||||
is_pqc = 1;
|
||||
}
|
||||
else if (!ascii_strcasecmp (string, "dil5"))
|
||||
{
|
||||
algo = PUBKEY_ALGO_DIL5_448;
|
||||
is_pqc = 1;
|
||||
}
|
||||
else if (!ascii_strcasecmp (string, "sphinx")
|
||||
|| !ascii_strcasecmp (string, "sphinx_sha2"))
|
||||
{
|
||||
algo = PUBKEY_ALGO_SPHINX_SHA2;
|
||||
is_pqc = 1;
|
||||
}
|
||||
else if ((curve = openpgp_is_curve_supported (string, &algo, &size)))
|
||||
{
|
||||
if (!algo)
|
||||
|
@ -3690,8 +4069,8 @@ parse_key_parameter_part (ctrl_t ctrl,
|
|||
return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
|
||||
}
|
||||
|
||||
/* Ed448 and X448 must only be used as v5 keys. */
|
||||
if (is_448)
|
||||
/* Ed448, X448 and the PQC algos must only be used as v5 keys. */
|
||||
if (is_448 || is_pqc)
|
||||
{
|
||||
if (keyversion == 4)
|
||||
log_info (_("WARNING: v4 is specified, but overridden by v5.\n"));
|
||||
|
@ -3755,6 +4134,8 @@ parse_key_parameter_part (ctrl_t ctrl,
|
|||
* cv25519 := ECDH using curve Curve25519.
|
||||
* cv448 := ECDH using curve X448.
|
||||
* nistp256:= ECDSA or ECDH using curve NIST P-256
|
||||
* kyber := Kyber with the default parameters
|
||||
* ky768_bp384 := Kyber-768 with BrainpoolP256r1 as second algo
|
||||
*
|
||||
* All strings with an unknown prefix are considered an elliptic
|
||||
* curve. Curves which have no implicit algorithm require that FLAGS
|
||||
|
@ -6124,6 +6505,8 @@ generate_subkeypair (ctrl_t ctrl, kbnode_t keyblock, const char *algostr,
|
|||
err = hexkeygrip_from_pk (pri_psk, &hexgrip);
|
||||
if (err)
|
||||
goto leave;
|
||||
/* FIXME: Right now the primary key won't be a dual key. But this
|
||||
* will change */
|
||||
if (agent_get_keyinfo (NULL, hexgrip, &serialno, NULL))
|
||||
{
|
||||
if (interactive)
|
||||
|
@ -6463,12 +6846,14 @@ gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
|
|||
if (curve_is_448 (s_key))
|
||||
*keygen_flags |= KEYGEN_FLAG_CREATE_V5_KEY;
|
||||
|
||||
pk->version = (*keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
|
||||
|
||||
if (algo == PUBKEY_ALGO_RSA)
|
||||
err = key_from_sexp (pk->pkey, s_key, "public-key", "ne");
|
||||
else if (algo == PUBKEY_ALGO_ECDSA
|
||||
|| algo == PUBKEY_ALGO_EDDSA
|
||||
|| algo == PUBKEY_ALGO_ECDH )
|
||||
err = ecckey_from_sexp (pk->pkey, s_key, algo);
|
||||
err = ecckey_from_sexp (pk->pkey, s_key, NULL, algo, pk->version);
|
||||
else
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
gcry_sexp_release (s_key);
|
||||
|
@ -6481,7 +6866,6 @@ gen_card_key (int keyno, int algo, int is_primary, kbnode_t pub_root,
|
|||
}
|
||||
|
||||
pk->timestamp = *timestamp;
|
||||
pk->version = (*keygen_flags & KEYGEN_FLAG_CREATE_V5_KEY)? 5 : 4;
|
||||
if (expireval)
|
||||
pk->expiredate = pk->timestamp + expireval;
|
||||
pk->pubkey_algo = algo;
|
||||
|
|
164
g10/keyid.c
164
g10/keyid.c
|
@ -74,12 +74,18 @@ pubkey_letter( int algo )
|
|||
is copied to the supplied buffer up a length of BUFSIZE-1.
|
||||
Examples for the output are:
|
||||
|
||||
"rsa3072" - RSA with 3072 bit
|
||||
"elg1024" - Elgamal with 1024 bit
|
||||
"ed25519" - ECC using the curve Ed25519.
|
||||
"E_1.2.3.4" - ECC using the unsupported curve with OID "1.2.3.4".
|
||||
"rsa3072" - RSA with 3072 bit
|
||||
"elg1024" - Elgamal with 1024 bit
|
||||
"ed25519" - EdDSA using the curve Ed25519.
|
||||
"cv25519" - ECDH using the curve X25519.
|
||||
"ky768_cv448 - Kyber-768 with X448 as second algo.
|
||||
"ky1025_bp512 - Kyber-1024 with BrainpoolP256r1 as second algo.
|
||||
"E_1.2.3.4" - ECC using the unsupported curve with OID "1.2.3.4".
|
||||
"unknown_N" - Unknown OpenPGP algorithm N.
|
||||
"E_1.3.6.1.4.1.11591.2.12242973" ECC with a bogus OID.
|
||||
"unknown_N" - Unknown OpenPGP algorithm N.
|
||||
|
||||
Note that with Kyber we use "bp" as abbreviation for BrainpoolP and
|
||||
ignore the final r1 part.
|
||||
|
||||
If the option --legacy-list-mode is active, the output use the
|
||||
legacy format:
|
||||
|
@ -97,6 +103,9 @@ char *
|
|||
pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize)
|
||||
{
|
||||
const char *prefix = NULL;
|
||||
int dual = 0;
|
||||
char *curve;
|
||||
const char *name;
|
||||
|
||||
if (opt.legacy_list_mode)
|
||||
{
|
||||
|
@ -116,14 +125,34 @@ pubkey_string (PKT_public_key *pk, char *buffer, size_t bufsize)
|
|||
case PUBKEY_ALGO_ECDH:
|
||||
case PUBKEY_ALGO_ECDSA:
|
||||
case PUBKEY_ALGO_EDDSA: prefix = ""; break;
|
||||
case PUBKEY_ALGO_KYBER: prefix = "ky"; dual = 1; break;
|
||||
case PUBKEY_ALGO_DIL3_25519: prefix = "dil3"; break;
|
||||
case PUBKEY_ALGO_DIL5_448: prefix = "dil5"; break;
|
||||
case PUBKEY_ALGO_SPHINX_SHA2: prefix = "sphinx_sha2"; break;
|
||||
}
|
||||
|
||||
|
||||
if (prefix && *prefix)
|
||||
snprintf (buffer, bufsize, "%s%u", prefix, nbits_from_pk (pk));
|
||||
{
|
||||
if (dual)
|
||||
{
|
||||
curve = openpgp_oid_to_str (pk->pkey[0]);
|
||||
/* Note that we prefer the abbreviated name of the curve. */
|
||||
name = openpgp_oid_to_curve (curve, 2);
|
||||
if (!name)
|
||||
name = "unknown";
|
||||
|
||||
snprintf (buffer, bufsize, "%s%u_%s",
|
||||
prefix, nbits_from_pk (pk), name);
|
||||
xfree (curve);
|
||||
}
|
||||
else
|
||||
snprintf (buffer, bufsize, "%s%u", prefix, nbits_from_pk (pk));
|
||||
}
|
||||
else if (prefix)
|
||||
{
|
||||
char *curve = openpgp_oid_to_str (pk->pkey[0]);
|
||||
const char *name = openpgp_oid_to_curve (curve, 0);
|
||||
curve = openpgp_oid_to_str (pk->pkey[0]);
|
||||
name = openpgp_oid_to_curve (curve, 0);
|
||||
|
||||
if (name)
|
||||
snprintf (buffer, bufsize, "%s", name);
|
||||
|
@ -303,6 +332,30 @@ do_hash_public_key (gcry_md_hd_t md, PKT_public_key *pk, int use_v5)
|
|||
pp[i] = NULL;
|
||||
nn[i] = 0;
|
||||
}
|
||||
else if (pk->pubkey_algo == PUBKEY_ALGO_KYBER && i == 2)
|
||||
{
|
||||
/* Ugly: We need to re-construct the wire format of the
|
||||
* key parameter. It would be easier to use a second
|
||||
* index for pp and nn which we could bump independet of
|
||||
* i. */
|
||||
const char *p;
|
||||
|
||||
p = gcry_mpi_get_opaque (pk->pkey[i], &nbits);
|
||||
nn[i] = (nbits+7)/8;
|
||||
pp[i] = xmalloc (4 + nn[i] + 1);
|
||||
if (p)
|
||||
{
|
||||
pp[i][0] = nn[i] >> 24;
|
||||
pp[i][1] = nn[i] >> 16;
|
||||
pp[i][2] = nn[i] >> 8;
|
||||
pp[i][3] = nn[i];
|
||||
memcpy (pp[i] + 4 , p, nn[i]);
|
||||
nn[i] += 4;
|
||||
}
|
||||
else
|
||||
pp[i] = NULL;
|
||||
n += nn[i];
|
||||
}
|
||||
else if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
|
||||
{
|
||||
const char *p;
|
||||
|
@ -800,11 +853,28 @@ namehash_from_uid (PKT_user_id *uid)
|
|||
|
||||
|
||||
/*
|
||||
* Return the number of bits used in PK.
|
||||
* Return the number of bits used in PK. For Kyber we return the
|
||||
* octet count of the Kyber part and not of the ECC (thus likely
|
||||
* values are 768 or 1024).
|
||||
*/
|
||||
unsigned int
|
||||
nbits_from_pk (PKT_public_key *pk)
|
||||
{
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_KYBER)
|
||||
{
|
||||
unsigned int nbits;
|
||||
if (!gcry_mpi_get_opaque (pk->pkey[2], &nbits))
|
||||
return 0;
|
||||
switch (nbits/8)
|
||||
{
|
||||
case 800: nbits = 512; break;
|
||||
case 1184: nbits = 768; break;
|
||||
case 1568: nbits = 1024; break;
|
||||
default: nbits = 0; break; /* Unkown version. */
|
||||
}
|
||||
return nbits;
|
||||
}
|
||||
else
|
||||
return pubkey_nbits (pk->pubkey_algo, pk->pkey);
|
||||
}
|
||||
|
||||
|
@ -1230,16 +1300,22 @@ format_hexfingerprint (const char *fingerprint, char *buffer, size_t buflen)
|
|||
|
||||
|
||||
/* Return the so called KEYGRIP which is the SHA-1 hash of the public
|
||||
key parameters expressed as an canonical encoded S-Exp. ARRAY must
|
||||
be 20 bytes long. Returns 0 on success or an error code. */
|
||||
* key parameters expressed as an canonical encoded S-Exp. ARRAY must
|
||||
* be 20 bytes long. Returns 0 on success or an error code. If
|
||||
* GET_SECOND Is one and PK has dual algorithm, the keygrip of the
|
||||
* second algorithm is return; GPG_ERR_FALSE is returned if the algo
|
||||
* is not a dual algorithm. */
|
||||
gpg_error_t
|
||||
keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
|
||||
keygrip_from_pk (PKT_public_key *pk, unsigned char *array, int get_second)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gcry_sexp_t s_pkey;
|
||||
|
||||
if (DBG_PACKET)
|
||||
log_debug ("get_keygrip for public key\n");
|
||||
log_debug ("get_keygrip for public key%s\n", get_second?" (second)":"");
|
||||
|
||||
if (get_second && pk->pubkey_algo != PUBKEY_ALGO_KYBER)
|
||||
return gpg_error (GPG_ERR_FALSE);
|
||||
|
||||
switch (pk->pubkey_algo)
|
||||
{
|
||||
|
@ -1287,6 +1363,33 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
|
|||
}
|
||||
break;
|
||||
|
||||
case PUBKEY_ALGO_KYBER:
|
||||
if (get_second)
|
||||
{
|
||||
char tmpname[15];
|
||||
|
||||
snprintf (tmpname, sizeof tmpname, "kyber%u", nbits_from_pk (pk));
|
||||
err = gcry_sexp_build (&s_pkey, NULL,
|
||||
"(public-key(%s(p%m)))",
|
||||
tmpname, pk->pkey[2]);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *curve = openpgp_oid_to_str (pk->pkey[0]);
|
||||
if (!curve)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
err = gcry_sexp_build (&s_pkey, NULL,
|
||||
openpgp_oid_is_cv25519 (pk->pkey[0])
|
||||
? "(public-key(ecc(curve%s)(flags djb-tweak)(q%m)))"
|
||||
: "(public-key(ecc(curve%s)(q%m)))",
|
||||
curve, pk->pkey[1]);
|
||||
xfree (curve);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_PUBKEY_ALGO);
|
||||
break;
|
||||
|
@ -1319,26 +1422,45 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
|
|||
|
||||
|
||||
/* Store an allocated buffer with the keygrip of PK encoded as a
|
||||
hexstring at r_GRIP. Returns 0 on success. */
|
||||
* hexstring at r_GRIP. Returns 0 on success. For dual algorithms
|
||||
* the keygrips are delimited by a comma. */
|
||||
gpg_error_t
|
||||
hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip)
|
||||
{
|
||||
gpg_error_t err;
|
||||
char *buf;
|
||||
unsigned char grip[KEYGRIP_LEN];
|
||||
unsigned char grip2[KEYGRIP_LEN];
|
||||
|
||||
*r_grip = NULL;
|
||||
err = keygrip_from_pk (pk, grip);
|
||||
err = keygrip_from_pk (pk, grip, 0);
|
||||
if (!err)
|
||||
{
|
||||
char * buf = xtrymalloc (KEYGRIP_LEN * 2 + 1);
|
||||
if (!buf)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_KYBER)
|
||||
{
|
||||
bin2hex (grip, KEYGRIP_LEN, buf);
|
||||
*r_grip = buf;
|
||||
err = keygrip_from_pk (pk, grip2, 1);
|
||||
if (err)
|
||||
goto leave;
|
||||
buf = xtrymalloc (2 * KEYGRIP_LEN * 2 + 1 + 1);
|
||||
}
|
||||
else
|
||||
buf = xtrymalloc (KEYGRIP_LEN * 2 + 1);
|
||||
|
||||
if (!buf)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
bin2hex (grip, KEYGRIP_LEN, buf);
|
||||
if (pk->pubkey_algo == PUBKEY_ALGO_KYBER)
|
||||
{
|
||||
buf[2*KEYGRIP_LEN] = ',';
|
||||
bin2hex (grip2, KEYGRIP_LEN, buf+2*KEYGRIP_LEN+1);
|
||||
}
|
||||
*r_grip = buf;
|
||||
}
|
||||
leave:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
429
g10/keylist.c
429
g10/keylist.c
|
@ -1171,6 +1171,77 @@ dump_attribs (const PKT_user_id *uid, PKT_public_key *pk)
|
|||
}
|
||||
|
||||
|
||||
static void
|
||||
print_keygrip (const char *keygrip)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
s = strchr (keygrip, ',');
|
||||
if (s)
|
||||
es_fprintf (es_stdout, " Keygrip = %.*s,\n%*s%s\n",
|
||||
(int)(s-keygrip), keygrip, 16, "", s+1);
|
||||
else
|
||||
es_fprintf (es_stdout, " Keygrip = %s\n", keygrip);
|
||||
}
|
||||
|
||||
|
||||
/* If PK is given the output is written to a new file instead of
|
||||
* stdout. */
|
||||
static void
|
||||
print_x509_notations (struct notation *nots, PKT_public_key *pk)
|
||||
{
|
||||
gpg_error_t err;
|
||||
gpgrt_b64state_t state = NULL;
|
||||
char hexfpr[2*4 + 1 + 2*MAX_FINGERPRINT_LEN+4+1];
|
||||
char sha1[20];
|
||||
estream_t fp;
|
||||
|
||||
for (; nots; nots = nots->next)
|
||||
{
|
||||
if (pk)
|
||||
{
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, sha1, nots->bdat, nots->blen);
|
||||
bin2hex (sha1+16, 4, hexfpr);
|
||||
hexfpr[2*4] = '-';
|
||||
hexfingerprint (pk, hexfpr + 2*4+1, 2*MAX_FINGERPRINT_LEN);
|
||||
strcat (hexfpr, ".pem");
|
||||
fp = es_fopen (hexfpr, "w");
|
||||
if (!fp)
|
||||
{
|
||||
err = gpg_err_code_from_syserror ();
|
||||
goto b64fail;
|
||||
}
|
||||
}
|
||||
else
|
||||
fp = es_stdout;
|
||||
state = gpgrt_b64enc_start (fp, "CERTIFICATE");
|
||||
if (!state)
|
||||
{
|
||||
err = gpg_err_code_from_syserror ();
|
||||
goto b64fail;
|
||||
}
|
||||
err = gpgrt_b64enc_write (state, nots->bdat, nots->blen);
|
||||
if (err)
|
||||
goto b64fail;
|
||||
err = gpgrt_b64enc_finish (state);
|
||||
if (err)
|
||||
goto b64fail;
|
||||
if (fp != es_stdout)
|
||||
{
|
||||
es_fclose (fp);
|
||||
fp = NULL;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
b64fail:
|
||||
log_error ("error writing base64 encoded notation: %s\n", gpg_strerror (err));
|
||||
gpgrt_b64enc_finish (state);
|
||||
if (fp && fp != es_stdout)
|
||||
gpgrt_fcancel (fp);
|
||||
}
|
||||
|
||||
|
||||
/* Order two signatures. We first order by keyid and then by creation
|
||||
* time. */
|
||||
int
|
||||
|
@ -1220,170 +1291,186 @@ cmp_signodes (const void *av, const void *bv)
|
|||
* NODFLG_MARK_B to indicate self-signatures. */
|
||||
static void
|
||||
list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
|
||||
struct keylist_context *listctx)
|
||||
struct keylist_context *listctx, PKT_public_key *lastpk)
|
||||
{
|
||||
/* (extra indentation to keep the diff history short) */
|
||||
PKT_signature *sig = node->pkt->pkt.signature;
|
||||
int rc, sigrc;
|
||||
char *sigstr;
|
||||
char *reason_text = NULL;
|
||||
char *reason_comment = NULL;
|
||||
size_t reason_commentlen;
|
||||
int reason_code = 0;
|
||||
PKT_signature *sig = node->pkt->pkt.signature;
|
||||
int rc, sigrc;
|
||||
char *sigstr;
|
||||
char *reason_text = NULL;
|
||||
char *reason_comment = NULL;
|
||||
size_t reason_commentlen;
|
||||
int reason_code = 0;
|
||||
|
||||
if (listctx->check_sigs)
|
||||
{
|
||||
rc = check_key_signature (ctrl, keyblock, node, NULL);
|
||||
switch (gpg_err_code (rc))
|
||||
{
|
||||
case 0:
|
||||
listctx->good_sigs++;
|
||||
sigrc = '!';
|
||||
break;
|
||||
case GPG_ERR_BAD_SIGNATURE:
|
||||
listctx->inv_sigs++;
|
||||
sigrc = '-';
|
||||
break;
|
||||
case GPG_ERR_NO_PUBKEY:
|
||||
case GPG_ERR_UNUSABLE_PUBKEY:
|
||||
listctx->no_key++;
|
||||
return;
|
||||
case GPG_ERR_DIGEST_ALGO:
|
||||
case GPG_ERR_PUBKEY_ALGO:
|
||||
if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS))
|
||||
return;
|
||||
/* fallthru. */
|
||||
default:
|
||||
listctx->oth_err++;
|
||||
sigrc = '%';
|
||||
break;
|
||||
}
|
||||
if (listctx->check_sigs)
|
||||
{
|
||||
rc = check_key_signature (ctrl, keyblock, node, NULL);
|
||||
switch (gpg_err_code (rc))
|
||||
{
|
||||
case 0:
|
||||
listctx->good_sigs++;
|
||||
sigrc = '!';
|
||||
break;
|
||||
case GPG_ERR_BAD_SIGNATURE:
|
||||
listctx->inv_sigs++;
|
||||
sigrc = '-';
|
||||
break;
|
||||
case GPG_ERR_NO_PUBKEY:
|
||||
case GPG_ERR_UNUSABLE_PUBKEY:
|
||||
listctx->no_key++;
|
||||
return;
|
||||
case GPG_ERR_DIGEST_ALGO:
|
||||
case GPG_ERR_PUBKEY_ALGO:
|
||||
if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS))
|
||||
return;
|
||||
/* fallthru. */
|
||||
default:
|
||||
listctx->oth_err++;
|
||||
sigrc = '%';
|
||||
break;
|
||||
}
|
||||
|
||||
/* TODO: Make sure a cached sig record here still has
|
||||
the pk that issued it. See also
|
||||
keyedit.c:print_and_check_one_sig */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS)
|
||||
&& (gpg_err_code (openpgp_pk_test_algo (sig->pubkey_algo)
|
||||
== GPG_ERR_PUBKEY_ALGO)
|
||||
|| gpg_err_code (openpgp_md_test_algo (sig->digest_algo)
|
||||
== GPG_ERR_DIGEST_ALGO)
|
||||
|| (sig->digest_algo == DIGEST_ALGO_SHA1
|
||||
&& !(node->flag & NODFLG_MARK_B) /*no selfsig*/
|
||||
&& !opt.flags.allow_weak_key_signatures)))
|
||||
return;
|
||||
rc = 0;
|
||||
sigrc = ' ';
|
||||
}
|
||||
/* TODO: Make sure a cached sig record here still has
|
||||
the pk that issued it. See also
|
||||
keyedit.c:print_and_check_one_sig */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS)
|
||||
&& (gpg_err_code (openpgp_pk_test_algo (sig->pubkey_algo)
|
||||
== GPG_ERR_PUBKEY_ALGO)
|
||||
|| gpg_err_code (openpgp_md_test_algo (sig->digest_algo)
|
||||
== GPG_ERR_DIGEST_ALGO)
|
||||
|| (sig->digest_algo == DIGEST_ALGO_SHA1
|
||||
&& !(node->flag & NODFLG_MARK_B) /*no selfsig*/
|
||||
&& !opt.flags.allow_weak_key_signatures)))
|
||||
return;
|
||||
rc = 0;
|
||||
sigrc = ' ';
|
||||
}
|
||||
|
||||
if (sig->sig_class == 0x20 || sig->sig_class == 0x28
|
||||
|| sig->sig_class == 0x30)
|
||||
if (IS_KEY_REV (sig) || IS_SUBKEY_REV (sig) || IS_UID_REV (sig))
|
||||
{
|
||||
sigstr = "rev";
|
||||
reason_code = get_revocation_reason (sig, &reason_text,
|
||||
&reason_comment,
|
||||
&reason_commentlen);
|
||||
}
|
||||
else if (IS_UID_SIG (sig))
|
||||
sigstr = "sig";
|
||||
else if (IS_SUBKEY_SIG (sig))
|
||||
sigstr = "sig";
|
||||
else if (IS_KEY_SIG (sig))
|
||||
sigstr = "sig";
|
||||
else
|
||||
{
|
||||
es_fprintf (es_stdout, "sig "
|
||||
"[unexpected signature class 0x%02x]\n",
|
||||
sig->sig_class);
|
||||
return;
|
||||
}
|
||||
|
||||
es_fputs (sigstr, es_stdout);
|
||||
es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s",
|
||||
sigrc, (sig->sig_class - 0x10 > 0 &&
|
||||
sig->sig_class - 0x10 <
|
||||
4) ? '0' + sig->sig_class - 0x10 : ' ',
|
||||
sig->flags.exportable ? ' ' : 'L',
|
||||
sig->flags.revocable ? ' ' : 'R',
|
||||
sig->flags.policy_url ? 'P' : ' ',
|
||||
sig->flags.notation ? 'N' : ' ',
|
||||
sig->flags.expired ? 'X' : ' ',
|
||||
(sig->trust_depth > 9) ? 'T' : (sig->trust_depth >
|
||||
0) ? '0' +
|
||||
sig->trust_depth : ' ', keystr (sig->keyid),
|
||||
datestr_from_sig (sig));
|
||||
if (opt.list_options & LIST_SHOW_SIG_EXPIRE)
|
||||
es_fprintf (es_stdout, " %s", expirestr_from_sig (sig));
|
||||
es_fprintf (es_stdout, " ");
|
||||
if (sigrc == '%')
|
||||
es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc));
|
||||
else if (sigrc == '?')
|
||||
;
|
||||
else if ((node->flag & NODFLG_MARK_B))
|
||||
es_fputs (_("[self-signature]"), es_stdout);
|
||||
else if (!opt.fast_list_mode )
|
||||
{
|
||||
size_t n;
|
||||
char *p = get_user_id (ctrl, sig->keyid, &n, NULL);
|
||||
print_utf8_buffer (es_stdout, p, n);
|
||||
xfree (p);
|
||||
}
|
||||
es_putc ('\n', es_stdout);
|
||||
|
||||
if (sig->flags.policy_url
|
||||
&& (opt.list_options & LIST_SHOW_POLICY_URLS))
|
||||
show_policy_url (sig, 3, 0);
|
||||
|
||||
if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS))
|
||||
show_notation (sig, 3, 0,
|
||||
((opt.
|
||||
list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0)
|
||||
+
|
||||
((opt.
|
||||
list_options & LIST_SHOW_USER_NOTATIONS) ? 2 :
|
||||
0));
|
||||
|
||||
if (sig->flags.notation
|
||||
&& (opt.list_options
|
||||
& (LIST_SHOW_X509_NOTATIONS|LIST_STORE_X509_NOTATIONS)))
|
||||
{
|
||||
struct notation *nots;
|
||||
|
||||
if ((IS_KEY_SIG (sig) || IS_SUBKEY_SIG (sig))
|
||||
&& (nots = search_sig_notations (sig,
|
||||
"x509certificate@pgp.com")))
|
||||
{
|
||||
if ((opt.list_options & LIST_STORE_X509_NOTATIONS))
|
||||
print_x509_notations (nots, lastpk);
|
||||
else
|
||||
print_x509_notations (nots, NULL);
|
||||
free_notation (nots);
|
||||
}
|
||||
}
|
||||
|
||||
if (sig->flags.pref_ks
|
||||
&& (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
|
||||
show_keyserver_url (sig, 3, 0);
|
||||
|
||||
if (reason_text && (reason_code || reason_comment))
|
||||
{
|
||||
es_fprintf (es_stdout, " %s%s\n",
|
||||
_("reason for revocation: "), reason_text);
|
||||
if (reason_comment)
|
||||
{
|
||||
const byte *s, *s_lf;
|
||||
size_t n, n_lf;
|
||||
|
||||
s = reason_comment;
|
||||
n = reason_commentlen;
|
||||
s_lf = NULL;
|
||||
do
|
||||
{
|
||||
sigstr = "rev";
|
||||
reason_code = get_revocation_reason (sig, &reason_text,
|
||||
&reason_comment,
|
||||
&reason_commentlen);
|
||||
}
|
||||
else if ((sig->sig_class & ~3) == 0x10)
|
||||
sigstr = "sig";
|
||||
else if (sig->sig_class == 0x18)
|
||||
sigstr = "sig";
|
||||
else if (sig->sig_class == 0x1F)
|
||||
sigstr = "sig";
|
||||
else
|
||||
{
|
||||
es_fprintf (es_stdout, "sig "
|
||||
"[unexpected signature class 0x%02x]\n",
|
||||
sig->sig_class);
|
||||
return;
|
||||
}
|
||||
|
||||
es_fputs (sigstr, es_stdout);
|
||||
es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s",
|
||||
sigrc, (sig->sig_class - 0x10 > 0 &&
|
||||
sig->sig_class - 0x10 <
|
||||
4) ? '0' + sig->sig_class - 0x10 : ' ',
|
||||
sig->flags.exportable ? ' ' : 'L',
|
||||
sig->flags.revocable ? ' ' : 'R',
|
||||
sig->flags.policy_url ? 'P' : ' ',
|
||||
sig->flags.notation ? 'N' : ' ',
|
||||
sig->flags.expired ? 'X' : ' ',
|
||||
(sig->trust_depth > 9) ? 'T' : (sig->trust_depth >
|
||||
0) ? '0' +
|
||||
sig->trust_depth : ' ', keystr (sig->keyid),
|
||||
datestr_from_sig (sig));
|
||||
if (opt.list_options & LIST_SHOW_SIG_EXPIRE)
|
||||
es_fprintf (es_stdout, " %s", expirestr_from_sig (sig));
|
||||
es_fprintf (es_stdout, " ");
|
||||
if (sigrc == '%')
|
||||
es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc));
|
||||
else if (sigrc == '?')
|
||||
;
|
||||
else if ((node->flag & NODFLG_MARK_B))
|
||||
es_fputs (_("[self-signature]"), es_stdout);
|
||||
else if (!opt.fast_list_mode )
|
||||
{
|
||||
size_t n;
|
||||
char *p = get_user_id (ctrl, sig->keyid, &n, NULL);
|
||||
print_utf8_buffer (es_stdout, p, n);
|
||||
xfree (p);
|
||||
}
|
||||
es_putc ('\n', es_stdout);
|
||||
|
||||
if (sig->flags.policy_url
|
||||
&& (opt.list_options & LIST_SHOW_POLICY_URLS))
|
||||
show_policy_url (sig, 3, 0);
|
||||
|
||||
if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS))
|
||||
show_notation (sig, 3, 0,
|
||||
((opt.
|
||||
list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0)
|
||||
+
|
||||
((opt.
|
||||
list_options & LIST_SHOW_USER_NOTATIONS) ? 2 :
|
||||
0));
|
||||
|
||||
if (sig->flags.pref_ks
|
||||
&& (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
|
||||
show_keyserver_url (sig, 3, 0);
|
||||
|
||||
if (reason_text && (reason_code || reason_comment))
|
||||
{
|
||||
es_fprintf (es_stdout, " %s%s\n",
|
||||
_("reason for revocation: "), reason_text);
|
||||
if (reason_comment)
|
||||
/* We don't want any empty lines, so we skip them. */
|
||||
for (;n && *s == '\n'; s++, n--)
|
||||
;
|
||||
if (n)
|
||||
{
|
||||
const byte *s, *s_lf;
|
||||
size_t n, n_lf;
|
||||
|
||||
s = reason_comment;
|
||||
n = reason_commentlen;
|
||||
s_lf = NULL;
|
||||
do
|
||||
{
|
||||
/* We don't want any empty lines, so we skip them. */
|
||||
for (;n && *s == '\n'; s++, n--)
|
||||
;
|
||||
if (n)
|
||||
{
|
||||
s_lf = memchr (s, '\n', n);
|
||||
n_lf = s_lf? s_lf - s : n;
|
||||
es_fprintf (es_stdout, " %s",
|
||||
_("revocation comment: "));
|
||||
es_write_sanitized (es_stdout, s, n_lf, NULL, NULL);
|
||||
es_putc ('\n', es_stdout);
|
||||
s += n_lf; n -= n_lf;
|
||||
}
|
||||
} while (s_lf);
|
||||
s_lf = memchr (s, '\n', n);
|
||||
n_lf = s_lf? s_lf - s : n;
|
||||
es_fprintf (es_stdout, " %s",
|
||||
_("revocation comment: "));
|
||||
es_write_sanitized (es_stdout, s, n_lf, NULL, NULL);
|
||||
es_putc ('\n', es_stdout);
|
||||
s += n_lf; n -= n_lf;
|
||||
}
|
||||
}
|
||||
} while (s_lf);
|
||||
}
|
||||
}
|
||||
|
||||
xfree (reason_text);
|
||||
xfree (reason_comment);
|
||||
xfree (reason_text);
|
||||
xfree (reason_comment);
|
||||
|
||||
/* fixme: check or list other sigs here */
|
||||
/* fixme: check or list other sigs here */
|
||||
}
|
||||
|
||||
|
||||
|
@ -1394,6 +1481,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
|||
int rc;
|
||||
kbnode_t node;
|
||||
PKT_public_key *pk;
|
||||
PKT_public_key *lastpk;
|
||||
u32 *mainkid;
|
||||
int skip_sigs = 0;
|
||||
char *hexgrip = NULL;
|
||||
|
@ -1410,6 +1498,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
|||
|
||||
pk = node->pkt->pkt.public_key;
|
||||
mainkid = pk_keyid (pk);
|
||||
lastpk = pk;
|
||||
|
||||
if (secret || opt.with_keygrip)
|
||||
{
|
||||
|
@ -1437,7 +1526,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
|||
print_fingerprint (ctrl, NULL, pk, 0);
|
||||
|
||||
if (opt.with_keygrip && hexgrip)
|
||||
es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip);
|
||||
print_keygrip (hexgrip);
|
||||
|
||||
if (serialno)
|
||||
print_card_serialno (serialno);
|
||||
|
@ -1558,6 +1647,7 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
|||
{
|
||||
PKT_public_key *pk2 = node->pkt->pkt.public_key;
|
||||
|
||||
lastpk = pk2;
|
||||
if ((pk2->flags.revoked || pk2->has_expired)
|
||||
&& !(opt.list_options & LIST_SHOW_UNUSABLE_SUBKEYS))
|
||||
{
|
||||
|
@ -1593,13 +1683,15 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
|||
print_card_serialno (serialno);
|
||||
}
|
||||
if (opt.with_keygrip && hexgrip)
|
||||
es_fprintf (es_stdout, " Keygrip = %s\n", hexgrip);
|
||||
print_keygrip (hexgrip);
|
||||
if (opt.with_key_data)
|
||||
print_key_data (pk2);
|
||||
if (opt.with_key_screening)
|
||||
print_pk_screening (pk2, 0);
|
||||
}
|
||||
else if (opt.list_sigs
|
||||
else if ((opt.list_sigs
|
||||
|| (opt.list_options
|
||||
& (LIST_SHOW_X509_NOTATIONS|LIST_STORE_X509_NOTATIONS)))
|
||||
&& node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs)
|
||||
{
|
||||
kbnode_t n;
|
||||
|
@ -1627,7 +1719,8 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
|||
qsort (sigarray, sigcount, sizeof *sigarray, cmp_signodes);
|
||||
|
||||
for (idx=0; idx < sigcount; idx++)
|
||||
list_signature_print (ctrl, keyblock, sigarray[idx], listctx);
|
||||
list_signature_print (ctrl, keyblock, sigarray[idx], listctx,
|
||||
lastpk);
|
||||
xfree (sigarray);
|
||||
}
|
||||
}
|
||||
|
@ -2520,6 +2613,11 @@ print_key_line (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int secret)
|
|||
tty_fprintf (fp, " [%s]", usagestr_from_pk (pk, 0));
|
||||
}
|
||||
|
||||
if (pk->flags.primary && (opt.list_options & LIST_SHOW_OWNERTRUST))
|
||||
{
|
||||
tty_fprintf (fp, " [%s]", get_ownertrust_string (ctrl, pk, 0));
|
||||
}
|
||||
|
||||
if (pk->flags.revoked)
|
||||
{
|
||||
tty_fprintf (fp, " [");
|
||||
|
@ -2539,21 +2637,14 @@ print_key_line (ctrl_t ctrl, estream_t fp, PKT_public_key *pk, int secret)
|
|||
tty_fprintf (fp, "]");
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* I need to think about this some more. It's easy enough to
|
||||
include, but it looks sort of confusing in the listing... */
|
||||
if (opt.list_options & LIST_SHOW_VALIDITY)
|
||||
{
|
||||
int validity = get_validity (ctrl, pk, NULL, NULL, 0);
|
||||
tty_fprintf (fp, " [%s]", trust_value_to_string (validity));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pk->pubkey_algo >= 100)
|
||||
tty_fprintf (fp, " [experimental algorithm %d]", pk->pubkey_algo);
|
||||
|
||||
tty_fprintf (fp, "\n");
|
||||
|
||||
if (pk->flags.primary && pk_is_disabled (pk))
|
||||
es_fprintf (es_stdout, " *** %s\n", _("This key has been disabled"));
|
||||
|
||||
/* if the user hasn't explicitly asked for human-readable
|
||||
fingerprints, show compact fpr of primary key: */
|
||||
if (pk->flags.primary &&
|
||||
|
|
|
@ -1148,7 +1148,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
|
|||
if (need_keyid)
|
||||
keyid_from_pk (pk, aki);
|
||||
if (need_grip)
|
||||
keygrip_from_pk (pk, grip);
|
||||
keygrip_from_pk (pk, grip, 0);
|
||||
|
||||
if (use_key_present_hash
|
||||
&& !key_present_hash_ready
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue